@@ -24,7 +24,7 @@ class CommandEdit extends CommandPolykey {
2424 this . addOption ( binOptions . clientPort ) ;
2525 this . action ( async ( secretPath , options ) => {
2626 const os = await import ( 'os' ) ;
27- const { execSync } = await import ( 'child_process' ) ;
27+ const { spawn } = await import ( 'child_process' ) ;
2828 const vaultsErrors = await import ( 'polykey/dist/vaults/errors' ) ;
2929 const { default : PolykeyClient } = await import (
3030 'polykey/dist/PolykeyClient'
@@ -64,17 +64,14 @@ class CommandEdit extends CommandPolykey {
6464 const secretExists = await binUtils . retryAuthentication (
6565 async ( auth ) => {
6666 let exists = true ;
67- const res = await pkClient . rpcClient . methods . vaultsSecretsGet ( ) ;
68- const writer = res . writable . getWriter ( ) ;
69- await writer . write ( {
67+ const response = await pkClient . rpcClient . methods . vaultsSecretsGet ( {
7068 nameOrId : secretPath [ 0 ] ,
7169 secretName : secretPath [ 1 ] ?? '/' ,
7270 metadata : auth ,
7371 } ) ;
74- await writer . close ( ) ;
7572 try {
7673 let rawSecretContent : string = '' ;
77- for await ( const chunk of res . readable ) {
74+ for await ( const chunk of response ) {
7875 rawSecretContent += chunk . secretContent ;
7976 }
8077 const secretContent = Buffer . from ( rawSecretContent , 'binary' ) ;
@@ -83,6 +80,20 @@ class CommandEdit extends CommandPolykey {
8380 const [ cause , _ ] = binUtils . remoteErrorCause ( e ) ;
8481 if ( cause instanceof vaultsErrors . ErrorSecretsSecretUndefined ) {
8582 exists = false ;
83+ } else if (
84+ cause instanceof vaultsErrors . ErrorSecretsIsDirectory
85+ ) {
86+ // First, write the inline error to standard error like other
87+ // secrets commands do.
88+ process . stderr . write (
89+ `edit: ${ secretPath [ 1 ] ?? '/' } : No such file or directory\n` ,
90+ ) ;
91+ // Then, throw an error to get the non-zero exit code. As this
92+ // command is Polykey-specific, the code doesn't really matter
93+ // that much.
94+ throw new errors . ErrorPolykeyCLIEditSecret (
95+ 'Failed to edit secret' ,
96+ ) ;
8697 } else {
8798 throw e ;
8899 }
@@ -94,7 +105,29 @@ class CommandEdit extends CommandPolykey {
94105 // If the editor exited with a code other than zero, then execSync
95106 // will throw an error. So, in the case of saving the file but the
96107 // editor crashing, the program won't save the updated secret.
97- execSync ( `${ process . env . EDITOR } \"${ tmpFile } \"` , { stdio : 'inherit' } ) ;
108+ await new Promise < void > ( ( resolve , reject ) => {
109+ // If $EDITOR is unset, default to nano. If that doesn't exist, then
110+ // the command will raise an error.
111+ const editorProc = spawn ( process . env . EDITOR ?? 'nano' , [ tmpFile ] , {
112+ stdio : 'inherit' ,
113+ } ) ;
114+ editorProc . on ( 'error' , ( e ) => {
115+ const error = new errors . ErrorPolykeyCLIEditSecret (
116+ `Failed to run command ${ process . env . EDITOR } ` ,
117+ { cause : e } ,
118+ ) ;
119+ reject ( error ) ;
120+ } ) ;
121+ editorProc . on ( 'close' , ( code ) => {
122+ if ( code !== 0 ) {
123+ const error = new errors . ErrorPolykeyCLIEditSecret (
124+ `Editor exited with code ${ code } ` ,
125+ ) ;
126+ reject ( error ) ;
127+ }
128+ resolve ( ) ;
129+ } ) ;
130+ } ) ;
98131 let content : string ;
99132 try {
100133 const buffer = await this . fs . promises . readFile ( tmpFile ) ;
0 commit comments