@chriscode/hush 5.0.0 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +39 -26
- package/dist/commands/check.d.ts +3 -3
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +27 -31
- package/dist/commands/decrypt.d.ts +2 -2
- package/dist/commands/decrypt.d.ts.map +1 -1
- package/dist/commands/decrypt.js +52 -55
- package/dist/commands/edit.d.ts +2 -2
- package/dist/commands/edit.d.ts.map +1 -1
- package/dist/commands/edit.js +10 -12
- package/dist/commands/encrypt.d.ts +2 -2
- package/dist/commands/encrypt.d.ts.map +1 -1
- package/dist/commands/encrypt.js +27 -29
- package/dist/commands/expansions.d.ts +2 -2
- package/dist/commands/expansions.d.ts.map +1 -1
- package/dist/commands/expansions.js +46 -44
- package/dist/commands/has.d.ts +2 -2
- package/dist/commands/has.d.ts.map +1 -1
- package/dist/commands/has.js +12 -15
- package/dist/commands/init.d.ts +2 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +92 -100
- package/dist/commands/inspect.d.ts +2 -2
- package/dist/commands/inspect.d.ts.map +1 -1
- package/dist/commands/inspect.js +14 -16
- package/dist/commands/keys.d.ts +2 -1
- package/dist/commands/keys.d.ts.map +1 -1
- package/dist/commands/keys.js +47 -49
- package/dist/commands/list.d.ts +2 -2
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +11 -14
- package/dist/commands/migrate.d.ts +2 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +38 -37
- package/dist/commands/push.d.ts +2 -2
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +41 -45
- package/dist/commands/resolve.d.ts +2 -2
- package/dist/commands/resolve.d.ts.map +1 -1
- package/dist/commands/resolve.js +25 -28
- package/dist/commands/run.d.ts +2 -2
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +35 -39
- package/dist/commands/set.d.ts +2 -2
- package/dist/commands/set.d.ts.map +1 -1
- package/dist/commands/set.js +61 -70
- package/dist/commands/skill.d.ts +2 -2
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +149 -459
- package/dist/commands/status.d.ts +2 -2
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +48 -52
- package/dist/commands/template.d.ts +2 -2
- package/dist/commands/template.d.ts.map +1 -1
- package/dist/commands/template.js +36 -39
- package/dist/commands/trace.d.ts +2 -2
- package/dist/commands/trace.d.ts.map +1 -1
- package/dist/commands/trace.js +16 -19
- package/dist/config/loader.js +3 -3
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +60 -0
- package/dist/core/parse.js +3 -3
- package/dist/core/sops.js +9 -9
- package/dist/core/template.d.ts +2 -2
- package/dist/core/template.d.ts.map +1 -1
- package/dist/core/template.js +11 -12
- package/dist/lib/age.js +9 -9
- package/dist/lib/fs.d.ts +25 -0
- package/dist/lib/fs.d.ts.map +1 -0
- package/dist/lib/fs.js +36 -0
- package/dist/lib/onepassword.d.ts.map +1 -1
- package/dist/lib/onepassword.js +41 -4
- package/dist/types.d.ts +92 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/version-check.js +5 -5
- package/package.json +3 -2
package/dist/commands/run.js
CHANGED
|
@@ -1,32 +1,28 @@
|
|
|
1
|
-
import { spawnSync } from 'node:child_process';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
1
|
import { join, resolve } from 'node:path';
|
|
4
2
|
import pc from 'picocolors';
|
|
5
|
-
import { loadConfig, findProjectRoot } from '../config/loader.js';
|
|
6
3
|
import { filterVarsForTarget } from '../core/filter.js';
|
|
7
4
|
import { interpolateVars, getUnresolvedVars } from '../core/interpolate.js';
|
|
8
5
|
import { mergeVars } from '../core/merge.js';
|
|
9
6
|
import { parseEnvContent } from '../core/parse.js';
|
|
10
|
-
import { decrypt as sopsDecrypt } from '../core/sops.js';
|
|
11
7
|
import { loadLocalTemplates, resolveTemplateVars } from '../core/template.js';
|
|
12
8
|
function getEncryptedPath(sourcePath) {
|
|
13
9
|
return sourcePath + '.encrypted';
|
|
14
10
|
}
|
|
15
|
-
function getDecryptedSecrets(projectRoot, env, config) {
|
|
11
|
+
function getDecryptedSecrets(ctx, projectRoot, env, config) {
|
|
16
12
|
const sharedEncrypted = join(projectRoot, getEncryptedPath(config.sources.shared));
|
|
17
13
|
const envEncrypted = join(projectRoot, getEncryptedPath(config.sources[env]));
|
|
18
14
|
const localEncrypted = join(projectRoot, getEncryptedPath(config.sources.local));
|
|
19
15
|
const varSources = [];
|
|
20
|
-
if (existsSync(sharedEncrypted)) {
|
|
21
|
-
const content =
|
|
16
|
+
if (ctx.fs.existsSync(sharedEncrypted)) {
|
|
17
|
+
const content = ctx.sops.decrypt(sharedEncrypted);
|
|
22
18
|
varSources.push(parseEnvContent(content));
|
|
23
19
|
}
|
|
24
|
-
if (existsSync(envEncrypted)) {
|
|
25
|
-
const content =
|
|
20
|
+
if (ctx.fs.existsSync(envEncrypted)) {
|
|
21
|
+
const content = ctx.sops.decrypt(envEncrypted);
|
|
26
22
|
varSources.push(parseEnvContent(content));
|
|
27
23
|
}
|
|
28
|
-
if (existsSync(localEncrypted)) {
|
|
29
|
-
const content =
|
|
24
|
+
if (ctx.fs.existsSync(localEncrypted)) {
|
|
25
|
+
const content = ctx.sops.decrypt(localEncrypted);
|
|
30
26
|
varSources.push(parseEnvContent(content));
|
|
31
27
|
}
|
|
32
28
|
if (varSources.length === 0) {
|
|
@@ -46,31 +42,31 @@ function getRootSecretsAsRecord(vars) {
|
|
|
46
42
|
}
|
|
47
43
|
return record;
|
|
48
44
|
}
|
|
49
|
-
export async function runCommand(options) {
|
|
45
|
+
export async function runCommand(ctx, options) {
|
|
50
46
|
const { root, env, target, command } = options;
|
|
51
47
|
if (!command || command.length === 0) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
process.exit(1);
|
|
48
|
+
ctx.logger.error('Usage: hush run -- <command>');
|
|
49
|
+
ctx.logger.error(pc.dim('Example: hush run -- npm start'));
|
|
50
|
+
ctx.logger.error(pc.dim(' hush run -e production -- npm run build'));
|
|
51
|
+
ctx.logger.error(pc.dim(' hush run --target api -- wrangler dev'));
|
|
52
|
+
ctx.process.exit(1);
|
|
57
53
|
}
|
|
58
54
|
const contextDir = root;
|
|
59
|
-
const projectInfo = findProjectRoot(contextDir);
|
|
55
|
+
const projectInfo = ctx.config.findProjectRoot(contextDir);
|
|
60
56
|
if (!projectInfo) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
process.exit(1);
|
|
57
|
+
ctx.logger.error('No hush.yaml found in current directory or any parent directory.');
|
|
58
|
+
ctx.logger.error(pc.dim('Run: npx hush init'));
|
|
59
|
+
ctx.process.exit(1);
|
|
64
60
|
}
|
|
65
61
|
const { projectRoot } = projectInfo;
|
|
66
|
-
const config = loadConfig(projectRoot);
|
|
67
|
-
const rootSecrets = getDecryptedSecrets(projectRoot, env, config);
|
|
62
|
+
const config = ctx.config.loadConfig(projectRoot);
|
|
63
|
+
const rootSecrets = getDecryptedSecrets(ctx, projectRoot, env, config);
|
|
68
64
|
const rootSecretsRecord = getRootSecretsAsRecord(rootSecrets);
|
|
69
|
-
const localTemplate = loadLocalTemplates(contextDir, env);
|
|
65
|
+
const localTemplate = loadLocalTemplates(contextDir, env, ctx.fs);
|
|
70
66
|
// 1. Resolve Template Vars
|
|
71
67
|
let templateVars = [];
|
|
72
68
|
if (localTemplate.hasTemplate) {
|
|
73
|
-
templateVars = resolveTemplateVars(localTemplate.vars, rootSecretsRecord, { processEnv: process.env });
|
|
69
|
+
templateVars = resolveTemplateVars(localTemplate.vars, rootSecretsRecord, { processEnv: ctx.process.env });
|
|
74
70
|
}
|
|
75
71
|
// 2. Resolve Target Vars
|
|
76
72
|
let targetVars = [];
|
|
@@ -79,9 +75,9 @@ export async function runCommand(options) {
|
|
|
79
75
|
? config.targets.find(t => t.name === target)
|
|
80
76
|
: config.targets.find(t => resolve(projectRoot, t.path) === resolve(contextDir));
|
|
81
77
|
if (target && !targetConfig) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
process.exit(1);
|
|
78
|
+
ctx.logger.error(`Target "${target}" not found in hush.yaml`);
|
|
79
|
+
ctx.logger.error(pc.dim(`Available targets: ${config.targets.map(t => t.name).join(', ')}`));
|
|
80
|
+
ctx.process.exit(1);
|
|
85
81
|
}
|
|
86
82
|
if (targetConfig) {
|
|
87
83
|
targetVars = filterVarsForTarget(rootSecrets, targetConfig);
|
|
@@ -89,11 +85,11 @@ export async function runCommand(options) {
|
|
|
89
85
|
targetVars.push({ key: 'CLOUDFLARE_INCLUDE_PROCESS_ENV', value: 'true' });
|
|
90
86
|
const devVarsPath = join(targetConfig.path, '.dev.vars');
|
|
91
87
|
const absDevVarsPath = join(projectRoot, devVarsPath);
|
|
92
|
-
if (existsSync(absDevVarsPath)) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
if (ctx.fs.existsSync(absDevVarsPath)) {
|
|
89
|
+
ctx.logger.warn('\n⚠️ Wrangler Conflict Detected');
|
|
90
|
+
ctx.logger.warn(` Found .dev.vars in ${targetConfig.path}`);
|
|
91
|
+
ctx.logger.warn(' Wrangler will IGNORE Hush secrets while this file exists.');
|
|
92
|
+
ctx.logger.warn(pc.bold(` Fix: rm ${devVarsPath}\n`));
|
|
97
93
|
}
|
|
98
94
|
}
|
|
99
95
|
}
|
|
@@ -115,22 +111,22 @@ export async function runCommand(options) {
|
|
|
115
111
|
}
|
|
116
112
|
const unresolved = getUnresolvedVars(vars);
|
|
117
113
|
if (unresolved.length > 0) {
|
|
118
|
-
|
|
114
|
+
ctx.logger.warn(`Warning: ${unresolved.length} vars have unresolved references: ${unresolved.join(', ')}`);
|
|
119
115
|
}
|
|
120
116
|
const childEnv = {
|
|
121
|
-
...process.env,
|
|
117
|
+
...ctx.process.env,
|
|
122
118
|
...Object.fromEntries(vars.map(v => [v.key, v.value])),
|
|
123
119
|
};
|
|
124
120
|
const [cmd, ...args] = command;
|
|
125
|
-
const result = spawnSync(cmd, args, {
|
|
121
|
+
const result = ctx.exec.spawnSync(cmd, args, {
|
|
126
122
|
stdio: 'inherit',
|
|
127
123
|
env: childEnv,
|
|
128
124
|
shell: true,
|
|
129
125
|
cwd: contextDir,
|
|
130
126
|
});
|
|
131
127
|
if (result.error) {
|
|
132
|
-
|
|
133
|
-
process.exit(1);
|
|
128
|
+
ctx.logger.error(`Failed to execute: ${result.error.message}`);
|
|
129
|
+
ctx.process.exit(1);
|
|
134
130
|
}
|
|
135
|
-
process.exit(result.status ?? 1);
|
|
131
|
+
ctx.process.exit(result.status ?? 1);
|
|
136
132
|
}
|
package/dist/commands/set.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { SetOptions } from '../types.js';
|
|
2
|
-
export declare function setCommand(options: SetOptions): Promise<void>;
|
|
1
|
+
import type { HushContext, SetOptions } from '../types.js';
|
|
2
|
+
export declare function setCommand(ctx: HushContext, options: SetOptions): Promise<void>;
|
|
3
3
|
//# sourceMappingURL=set.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../src/commands/set.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../src/commands/set.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAoM3D,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CrF"}
|
package/dist/commands/set.js
CHANGED
|
@@ -1,74 +1,65 @@
|
|
|
1
|
-
import { execSync } from 'node:child_process';
|
|
2
|
-
import { existsSync, fstatSync } from 'node:fs';
|
|
3
1
|
import { join } from 'node:path';
|
|
4
2
|
import { platform } from 'node:os';
|
|
5
3
|
import pc from 'picocolors';
|
|
6
|
-
import { loadConfig } from '../config/loader.js';
|
|
7
4
|
import { setKey } from '../core/sops.js';
|
|
8
|
-
|
|
9
|
-
function hasStdinPipe() {
|
|
5
|
+
function hasStdinPipe(ctx) {
|
|
10
6
|
try {
|
|
11
|
-
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
const stat = fstatSync(STDIN_FD);
|
|
15
|
-
return stat.isFIFO() || stat.isFile();
|
|
7
|
+
return !ctx.process.stdin.isTTY;
|
|
16
8
|
}
|
|
17
9
|
catch {
|
|
18
10
|
return false;
|
|
19
11
|
}
|
|
20
12
|
}
|
|
21
|
-
function readFromStdinPipe() {
|
|
13
|
+
function readFromStdinPipe(ctx) {
|
|
22
14
|
return new Promise((resolve, reject) => {
|
|
23
15
|
let data = '';
|
|
24
|
-
process.stdin.setEncoding('utf8');
|
|
25
|
-
process.stdin.on('data', (chunk) => {
|
|
16
|
+
ctx.process.stdin.setEncoding('utf8');
|
|
17
|
+
ctx.process.stdin.on('data', (chunk) => {
|
|
26
18
|
data += chunk;
|
|
27
19
|
});
|
|
28
|
-
process.stdin.on('end', () => {
|
|
20
|
+
ctx.process.stdin.on('end', () => {
|
|
29
21
|
const trimTrailingNewlines = /\n+$/;
|
|
30
22
|
resolve(data.replace(trimTrailingNewlines, ''));
|
|
31
23
|
});
|
|
32
|
-
process.stdin.on('error', reject);
|
|
33
|
-
process.stdin.resume();
|
|
24
|
+
ctx.process.stdin.on('error', reject);
|
|
25
|
+
ctx.process.stdin.resume();
|
|
34
26
|
});
|
|
35
27
|
}
|
|
36
|
-
function promptViaMacOSDialog(key) {
|
|
28
|
+
function promptViaMacOSDialog(ctx, key) {
|
|
37
29
|
try {
|
|
38
|
-
const script = `display dialog "Enter value for ${key}:" default answer "" with
|
|
39
|
-
const result = execSync(`osascript -e '${script}' -e 'text returned of result'`, {
|
|
30
|
+
const script = `display dialog "Enter value for ${key}:" default answer "" with title "Hush - Set Secret"`;
|
|
31
|
+
const result = ctx.exec.execSync(`osascript -e '${script}' -e 'text returned of result'`, {
|
|
40
32
|
encoding: 'utf-8',
|
|
41
33
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
42
34
|
});
|
|
43
|
-
return result.trim();
|
|
35
|
+
return result.toString().trim();
|
|
44
36
|
}
|
|
45
37
|
catch {
|
|
46
38
|
return null;
|
|
47
39
|
}
|
|
48
40
|
}
|
|
49
|
-
function promptViaWindowsDialog(key) {
|
|
41
|
+
function promptViaWindowsDialog(ctx, key) {
|
|
50
42
|
try {
|
|
51
43
|
const psScript = `
|
|
52
44
|
Add-Type -AssemblyName System.Windows.Forms
|
|
53
45
|
Add-Type -AssemblyName System.Drawing
|
|
54
|
-
|
|
46
|
+
|
|
55
47
|
$form = New-Object System.Windows.Forms.Form
|
|
56
48
|
$form.Text = 'Hush - Set Secret'
|
|
57
49
|
$form.Size = New-Object System.Drawing.Size(300,150)
|
|
58
50
|
$form.StartPosition = 'CenterScreen'
|
|
59
|
-
|
|
51
|
+
|
|
60
52
|
$label = New-Object System.Windows.Forms.Label
|
|
61
53
|
$label.Location = New-Object System.Drawing.Point(10,20)
|
|
62
54
|
$label.Size = New-Object System.Drawing.Size(280,20)
|
|
63
55
|
$label.Text = 'Enter value for ${key}:'
|
|
64
56
|
$form.Controls.Add($label)
|
|
65
|
-
|
|
57
|
+
|
|
66
58
|
$textBox = New-Object System.Windows.Forms.TextBox
|
|
67
59
|
$textBox.Location = New-Object System.Drawing.Point(10,50)
|
|
68
60
|
$textBox.Size = New-Object System.Drawing.Size(260,20)
|
|
69
|
-
$textBox.PasswordChar = '*'
|
|
70
61
|
$form.Controls.Add($textBox)
|
|
71
|
-
|
|
62
|
+
|
|
72
63
|
$okButton = New-Object System.Windows.Forms.Button
|
|
73
64
|
$okButton.Location = New-Object System.Drawing.Point(10,80)
|
|
74
65
|
$okButton.Size = New-Object System.Drawing.Size(75,23)
|
|
@@ -76,11 +67,11 @@ function promptViaWindowsDialog(key) {
|
|
|
76
67
|
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
|
|
77
68
|
$form.AcceptButton = $okButton
|
|
78
69
|
$form.Controls.Add($okButton)
|
|
79
|
-
|
|
70
|
+
|
|
80
71
|
$form.TopMost = $true
|
|
81
|
-
|
|
72
|
+
|
|
82
73
|
$result = $form.ShowDialog()
|
|
83
|
-
|
|
74
|
+
|
|
84
75
|
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
|
|
85
76
|
Write-Output $textBox.Text
|
|
86
77
|
} else {
|
|
@@ -88,41 +79,41 @@ function promptViaWindowsDialog(key) {
|
|
|
88
79
|
}
|
|
89
80
|
`;
|
|
90
81
|
const encodedCommand = Buffer.from(psScript, 'utf16le').toString('base64');
|
|
91
|
-
const result = execSync(`powershell -EncodedCommand "${encodedCommand}"`, {
|
|
82
|
+
const result = ctx.exec.execSync(`powershell -EncodedCommand "${encodedCommand}"`, {
|
|
92
83
|
encoding: 'utf-8',
|
|
93
84
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
94
85
|
});
|
|
95
|
-
return result.trim();
|
|
86
|
+
return result.toString().trim();
|
|
96
87
|
}
|
|
97
88
|
catch {
|
|
98
89
|
return null;
|
|
99
90
|
}
|
|
100
91
|
}
|
|
101
|
-
function promptViaLinuxDialog(key) {
|
|
92
|
+
function promptViaLinuxDialog(ctx, key) {
|
|
102
93
|
try {
|
|
103
|
-
const result = execSync(`zenity --
|
|
94
|
+
const result = ctx.exec.execSync(`zenity --entry --title="Hush - Set Secret" --text="Enter value for ${key}:"`, {
|
|
104
95
|
encoding: 'utf-8',
|
|
105
96
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
106
97
|
});
|
|
107
|
-
return result.trim();
|
|
98
|
+
return result.toString().trim();
|
|
108
99
|
}
|
|
109
100
|
catch {
|
|
110
101
|
try {
|
|
111
|
-
const result = execSync(`kdialog --
|
|
102
|
+
const result = ctx.exec.execSync(`kdialog --inputbox "Enter value for ${key}:" --title "Hush - Set Secret"`, {
|
|
112
103
|
encoding: 'utf-8',
|
|
113
104
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
114
105
|
});
|
|
115
|
-
return result.trim();
|
|
106
|
+
return result.toString().trim();
|
|
116
107
|
}
|
|
117
108
|
catch {
|
|
118
109
|
return null;
|
|
119
110
|
}
|
|
120
111
|
}
|
|
121
112
|
}
|
|
122
|
-
function promptViaTTY(key) {
|
|
113
|
+
function promptViaTTY(ctx, key) {
|
|
123
114
|
return new Promise((resolve, reject) => {
|
|
124
|
-
process.stdout.write(`Enter value for ${pc.cyan(key)}: `);
|
|
125
|
-
const stdin = process.stdin;
|
|
115
|
+
ctx.process.stdout.write(`Enter value for ${pc.cyan(key)}: `);
|
|
116
|
+
const stdin = ctx.process.stdin;
|
|
126
117
|
stdin.setRawMode(true);
|
|
127
118
|
stdin.resume();
|
|
128
119
|
stdin.setEncoding('utf8');
|
|
@@ -135,49 +126,49 @@ function promptViaTTY(key) {
|
|
|
135
126
|
stdin.setRawMode(false);
|
|
136
127
|
stdin.pause();
|
|
137
128
|
stdin.removeListener('data', onData);
|
|
138
|
-
process.stdout.write('\n');
|
|
129
|
+
ctx.process.stdout.write('\n');
|
|
139
130
|
resolve(value);
|
|
140
131
|
break;
|
|
141
132
|
case '\u0003':
|
|
142
133
|
stdin.setRawMode(false);
|
|
143
134
|
stdin.pause();
|
|
144
135
|
stdin.removeListener('data', onData);
|
|
145
|
-
process.stdout.write('\n');
|
|
136
|
+
ctx.process.stdout.write('\n');
|
|
146
137
|
reject(new Error('Cancelled'));
|
|
147
138
|
break;
|
|
148
139
|
case '\u007F':
|
|
149
140
|
case '\b':
|
|
150
141
|
if (value.length > 0) {
|
|
151
142
|
value = value.slice(0, -1);
|
|
152
|
-
process.stdout.write('\b \b');
|
|
143
|
+
ctx.process.stdout.write('\b \b');
|
|
153
144
|
}
|
|
154
145
|
break;
|
|
155
146
|
default:
|
|
156
147
|
value += char;
|
|
157
|
-
process.stdout.write('\u2022');
|
|
148
|
+
ctx.process.stdout.write('\u2022');
|
|
158
149
|
}
|
|
159
150
|
};
|
|
160
151
|
stdin.on('data', onData);
|
|
161
152
|
});
|
|
162
153
|
}
|
|
163
|
-
async function promptForValue(key, forceGui) {
|
|
164
|
-
if (hasStdinPipe()) {
|
|
165
|
-
return readFromStdinPipe();
|
|
154
|
+
async function promptForValue(ctx, key, forceGui) {
|
|
155
|
+
if (hasStdinPipe(ctx)) {
|
|
156
|
+
return readFromStdinPipe(ctx);
|
|
166
157
|
}
|
|
167
|
-
if (process.stdin.isTTY && !forceGui) {
|
|
168
|
-
return promptViaTTY(key);
|
|
158
|
+
if (ctx.process.stdin.isTTY && !forceGui) {
|
|
159
|
+
return promptViaTTY(ctx, key);
|
|
169
160
|
}
|
|
170
|
-
|
|
161
|
+
ctx.logger.log(pc.dim('Opening dialog for secret input...'));
|
|
171
162
|
let value = null;
|
|
172
163
|
switch (platform()) {
|
|
173
164
|
case 'darwin':
|
|
174
|
-
value = promptViaMacOSDialog(key);
|
|
165
|
+
value = promptViaMacOSDialog(ctx, key);
|
|
175
166
|
break;
|
|
176
167
|
case 'win32':
|
|
177
|
-
value = promptViaWindowsDialog(key);
|
|
168
|
+
value = promptViaWindowsDialog(ctx, key);
|
|
178
169
|
break;
|
|
179
170
|
case 'linux':
|
|
180
|
-
value = promptViaLinuxDialog(key);
|
|
171
|
+
value = promptViaLinuxDialog(ctx, key);
|
|
181
172
|
break;
|
|
182
173
|
}
|
|
183
174
|
if (value !== null) {
|
|
@@ -188,39 +179,39 @@ async function promptForValue(key, forceGui) {
|
|
|
188
179
|
}
|
|
189
180
|
throw new Error('Dialog cancelled or failed. Interactive input requires a terminal (TTY) or a supported GUI environment.');
|
|
190
181
|
}
|
|
191
|
-
export async function setCommand(options) {
|
|
192
|
-
const { root, file, key, gui } = options;
|
|
193
|
-
const config = loadConfig(root);
|
|
182
|
+
export async function setCommand(ctx, options) {
|
|
183
|
+
const { root, file, key, value: inlineValue, gui } = options;
|
|
184
|
+
const config = ctx.config.loadConfig(root);
|
|
194
185
|
const fileKey = file ?? 'shared';
|
|
195
186
|
const sourcePath = config.sources[fileKey];
|
|
196
187
|
const encryptedPath = join(root, sourcePath + '.encrypted');
|
|
197
188
|
if (!key) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
process.exit(1);
|
|
189
|
+
ctx.logger.error(pc.red('Usage: hush set <KEY> [-e environment]'));
|
|
190
|
+
ctx.logger.error(pc.dim('Example: hush set DATABASE_URL'));
|
|
191
|
+
ctx.logger.error(pc.dim(' hush set API_KEY -e production'));
|
|
192
|
+
ctx.logger.error(pc.dim('\nTo edit all secrets in an editor, use: hush edit'));
|
|
193
|
+
ctx.process.exit(1);
|
|
203
194
|
}
|
|
204
|
-
if (!existsSync(encryptedPath) && !existsSync(join(root, '.sops.yaml'))) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
process.exit(1);
|
|
195
|
+
if (!ctx.fs.existsSync(encryptedPath) && !ctx.fs.existsSync(join(root, '.sops.yaml'))) {
|
|
196
|
+
ctx.logger.error(pc.red('Hush is not initialized in this directory'));
|
|
197
|
+
ctx.logger.error(pc.dim('Run "hush init" first, then "hush encrypt"'));
|
|
198
|
+
ctx.process.exit(1);
|
|
208
199
|
}
|
|
209
200
|
try {
|
|
210
|
-
const value = await promptForValue(key, gui ?? false);
|
|
201
|
+
const value = inlineValue ?? await promptForValue(ctx, key, gui ?? false);
|
|
211
202
|
if (!value) {
|
|
212
|
-
|
|
213
|
-
process.exit(1);
|
|
203
|
+
ctx.logger.error(pc.yellow('No value entered, aborting'));
|
|
204
|
+
ctx.process.exit(1);
|
|
214
205
|
}
|
|
215
206
|
setKey(encryptedPath, key, value);
|
|
216
207
|
const envLabel = fileKey === 'shared' ? '' : ` in ${fileKey}`;
|
|
217
|
-
|
|
208
|
+
ctx.logger.log(pc.green(`\n${key} set${envLabel} (${value.length} chars, encrypted)`));
|
|
218
209
|
}
|
|
219
210
|
catch (error) {
|
|
220
211
|
const err = error;
|
|
221
212
|
if (err.message === 'Cancelled') {
|
|
222
|
-
|
|
223
|
-
process.exit(1);
|
|
213
|
+
ctx.logger.log(pc.yellow('Cancelled'));
|
|
214
|
+
ctx.process.exit(1);
|
|
224
215
|
}
|
|
225
216
|
throw err;
|
|
226
217
|
}
|
package/dist/commands/skill.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { SkillOptions } from '../types.js';
|
|
2
|
-
export declare function skillCommand(options: SkillOptions): Promise<void>;
|
|
1
|
+
import type { HushContext, SkillOptions } from '../types.js';
|
|
2
|
+
export declare function skillCommand(ctx: HushContext, options: SkillOptions): Promise<void>;
|
|
3
3
|
//# sourceMappingURL=skill.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/commands/skill.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/commands/skill.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAkvC7D,wBAAsB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CzF"}
|