@hivecommons/promptargs 0.7.0 → 0.8.0
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/README.md +100 -15
- package/dist/autodetect.js +24 -9
- package/dist/autodetect.js.map +1 -1
- package/dist/cli.js +51 -147
- package/dist/cli.js.map +1 -1
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +130 -0
- package/dist/commands.js.map +1 -0
- package/dist/flags.d.ts +14 -0
- package/dist/flags.js +57 -0
- package/dist/flags.js.map +1 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.js +64 -11
- package/dist/loader.js.map +1 -1
- package/dist/log.d.ts +19 -0
- package/dist/log.js +41 -0
- package/dist/log.js.map +1 -0
- package/dist/parser.js +33 -7
- package/dist/parser.js.map +1 -1
- package/dist/resolver.d.ts +2 -0
- package/dist/resolver.js +60 -30
- package/dist/resolver.js.map +1 -1
- package/dist/status.d.ts +1 -1
- package/dist/status.js +5 -4
- package/dist/status.js.map +1 -1
- package/dist/ui.html +18 -5
- package/dist/ui.js +36 -11
- package/dist/ui.js.map +1 -1
- package/package.json +13 -4
- package/dist/autodetect.test.d.ts +0 -1
- package/dist/autodetect.test.js +0 -207
- package/dist/autodetect.test.js.map +0 -1
- package/dist/cli.test.d.ts +0 -1
- package/dist/cli.test.js +0 -310
- package/dist/cli.test.js.map +0 -1
- package/dist/index.test.d.ts +0 -1
- package/dist/index.test.js +0 -59
- package/dist/index.test.js.map +0 -1
- package/dist/iterate.test.d.ts +0 -1
- package/dist/iterate.test.js +0 -20
- package/dist/iterate.test.js.map +0 -1
- package/dist/loader.test.d.ts +0 -1
- package/dist/loader.test.js +0 -65
- package/dist/loader.test.js.map +0 -1
- package/dist/parser.test.d.ts +0 -1
- package/dist/parser.test.js +0 -93
- package/dist/parser.test.js.map +0 -1
- package/dist/resolver.test.d.ts +0 -1
- package/dist/resolver.test.js +0 -184
- package/dist/resolver.test.js.map +0 -1
- package/dist/sanitize.test.d.ts +0 -1
- package/dist/sanitize.test.js +0 -38
- package/dist/sanitize.test.js.map +0 -1
- package/dist/status.test.d.ts +0 -1
- package/dist/status.test.js +0 -33
- package/dist/status.test.js.map +0 -1
- package/dist/ui-bootstrap.test.d.ts +0 -1
- package/dist/ui-bootstrap.test.js +0 -479
- package/dist/ui-bootstrap.test.js.map +0 -1
- package/dist/ui-builder.test.d.ts +0 -1
- package/dist/ui-builder.test.js +0 -272
- package/dist/ui-builder.test.js.map +0 -1
- package/dist/ui-command-quoting.test.d.ts +0 -1
- package/dist/ui-command-quoting.test.js +0 -95
- package/dist/ui-command-quoting.test.js.map +0 -1
- package/dist/ui-harness.d.ts +0 -20
- package/dist/ui-harness.js +0 -40
- package/dist/ui-harness.js.map +0 -1
- package/dist/ui-harness.test.d.ts +0 -1
- package/dist/ui-harness.test.js +0 -30
- package/dist/ui-harness.test.js.map +0 -1
- package/dist/ui-inline.test.d.ts +0 -1
- package/dist/ui-inline.test.js +0 -90
- package/dist/ui-inline.test.js.map +0 -1
- package/dist/ui-interactions.test.d.ts +0 -1
- package/dist/ui-interactions.test.js +0 -489
- package/dist/ui-interactions.test.js.map +0 -1
- package/dist/ui.test.d.ts +0 -1
- package/dist/ui.test.js +0 -283
- package/dist/ui.test.js.map +0 -1
package/dist/resolver.js
CHANGED
|
@@ -6,31 +6,46 @@ import { createInterface } from 'node:readline';
|
|
|
6
6
|
import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
|
7
7
|
import { join } from 'node:path';
|
|
8
8
|
import { autodetect } from './autodetect.js';
|
|
9
|
+
import { UsageError } from './flags.js';
|
|
9
10
|
import { cartesian, zip } from './iterate.js';
|
|
10
|
-
function
|
|
11
|
-
// @file — read lines from file
|
|
12
|
-
if (raw.startsWith('@') && existsSync(raw.slice(1))) {
|
|
13
|
-
return readFileSync(raw.slice(1), 'utf8')
|
|
14
|
-
.split('\n')
|
|
15
|
-
.map((l) => l.trim())
|
|
16
|
-
.filter(Boolean);
|
|
17
|
-
}
|
|
18
|
-
// - (stdin) handled at CLI level before this
|
|
19
|
-
if (raw === '-')
|
|
20
|
-
return [raw];
|
|
11
|
+
function expandPiece(piece) {
|
|
21
12
|
// Glob pattern — expanded in-process (never via a shell) to avoid
|
|
22
13
|
// command injection through crafted values.
|
|
23
|
-
if (
|
|
24
|
-
const files = expandGlob(
|
|
14
|
+
if (piece.includes('*') || piece.includes('?')) {
|
|
15
|
+
const files = expandGlob(piece);
|
|
25
16
|
if (files.length > 0)
|
|
26
17
|
return files;
|
|
27
18
|
// Not a valid glob, treat as literal
|
|
28
19
|
}
|
|
29
|
-
|
|
20
|
+
return [piece];
|
|
21
|
+
}
|
|
22
|
+
function expandArrayValue(raw, varName) {
|
|
23
|
+
// @file — read lines from file
|
|
24
|
+
if (raw.startsWith('@') && existsSync(raw.slice(1))) {
|
|
25
|
+
const filePath = raw.slice(1);
|
|
26
|
+
try {
|
|
27
|
+
return readFileSync(filePath, 'utf8')
|
|
28
|
+
.split('\n')
|
|
29
|
+
.map((l) => l.trim())
|
|
30
|
+
.filter(Boolean)
|
|
31
|
+
.flatMap(expandPiece);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const e = err;
|
|
35
|
+
if (e.code === 'EISDIR') {
|
|
36
|
+
throw new UsageError(`Variable "${varName}": @${filePath} is a directory, not a file; pass @FILE with one value per line`);
|
|
37
|
+
}
|
|
38
|
+
throw new UsageError(`Variable "${varName}": could not read @${filePath}: ${e.message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// - (stdin) handled at CLI level before this
|
|
42
|
+
if (raw === '-')
|
|
43
|
+
return [raw];
|
|
44
|
+
// Comma-separated: split first so each piece can be a glob
|
|
30
45
|
if (raw.includes(',')) {
|
|
31
|
-
return raw.split(',').map(s => s.trim()).filter(Boolean);
|
|
46
|
+
return raw.split(',').map(s => s.trim()).filter(Boolean).flatMap(expandPiece);
|
|
32
47
|
}
|
|
33
|
-
return
|
|
48
|
+
return expandPiece(raw);
|
|
34
49
|
}
|
|
35
50
|
function segmentToRegExp(segment) {
|
|
36
51
|
const escaped = segment
|
|
@@ -78,21 +93,24 @@ function expandGlob(pattern) {
|
|
|
78
93
|
return bases.sort();
|
|
79
94
|
}
|
|
80
95
|
export async function resolve(vars, flags, interactive, cross = false) {
|
|
81
|
-
const values =
|
|
82
|
-
const arrayVars =
|
|
96
|
+
const values = Object.create(null);
|
|
97
|
+
const arrayVars = Object.create(null);
|
|
98
|
+
const defaulted = new Set();
|
|
83
99
|
let hasArrays = false;
|
|
84
100
|
for (const v of vars) {
|
|
85
101
|
// 1. Check flags
|
|
86
|
-
if (v.name
|
|
87
|
-
const expanded = expandArrayValue(flags[v.name]);
|
|
102
|
+
if (Object.hasOwn(flags, v.name)) {
|
|
103
|
+
const expanded = expandArrayValue(flags[v.name], v.name);
|
|
88
104
|
if (expanded.length > 1) {
|
|
89
105
|
arrayVars[v.name] = expanded;
|
|
90
106
|
hasArrays = true;
|
|
107
|
+
continue;
|
|
91
108
|
}
|
|
92
|
-
|
|
109
|
+
// An empty expansion falls through as if the flag were absent
|
|
110
|
+
if (expanded.length === 1) {
|
|
93
111
|
values[v.name] = expanded[0];
|
|
112
|
+
continue;
|
|
94
113
|
}
|
|
95
|
-
continue;
|
|
96
114
|
}
|
|
97
115
|
// 2. Auto-detect
|
|
98
116
|
const auto = autodetect(v.name);
|
|
@@ -103,42 +121,54 @@ export async function resolve(vars, flags, interactive, cross = false) {
|
|
|
103
121
|
// 3. Default
|
|
104
122
|
if (v.defaultValue !== undefined) {
|
|
105
123
|
values[v.name] = v.defaultValue;
|
|
124
|
+
defaulted.add(v.name);
|
|
106
125
|
continue;
|
|
107
126
|
}
|
|
108
127
|
// 4. Ask interactively
|
|
109
128
|
if (interactive) {
|
|
110
|
-
const answer = await ask(` ${v.name}:
|
|
111
|
-
const expanded = expandArrayValue(answer);
|
|
129
|
+
const answer = await ask(` ${v.name}: `, v.name);
|
|
130
|
+
const expanded = expandArrayValue(answer, v.name);
|
|
112
131
|
if (expanded.length > 1) {
|
|
113
132
|
arrayVars[v.name] = expanded;
|
|
114
133
|
hasArrays = true;
|
|
115
134
|
}
|
|
116
135
|
else {
|
|
117
|
-
values[v.name] = expanded[0];
|
|
136
|
+
values[v.name] = expanded[0] ?? '';
|
|
118
137
|
}
|
|
119
138
|
}
|
|
120
139
|
}
|
|
121
140
|
// Build iterations
|
|
122
141
|
if (!hasArrays) {
|
|
123
|
-
return { values, iterations: [values] };
|
|
142
|
+
return { values, iterations: [values], defaulted };
|
|
124
143
|
}
|
|
125
144
|
const arrayNames = Object.keys(arrayVars);
|
|
126
145
|
const iterations = [];
|
|
127
146
|
const arrays = arrayNames.map(n => arrayVars[n]);
|
|
128
147
|
const combos = cross ? cartesian(arrays) : zip(arrays);
|
|
129
148
|
for (const combo of combos) {
|
|
130
|
-
const iter =
|
|
149
|
+
const iter = Object.assign(Object.create(null), values);
|
|
131
150
|
for (let j = 0; j < arrayNames.length; j++) {
|
|
132
151
|
iter[arrayNames[j]] = combo[j];
|
|
133
152
|
}
|
|
134
153
|
iterations.push(iter);
|
|
135
154
|
}
|
|
136
|
-
return { values, iterations };
|
|
155
|
+
return { values, iterations, defaulted };
|
|
137
156
|
}
|
|
138
|
-
function ask(prompt) {
|
|
157
|
+
function ask(prompt, name) {
|
|
139
158
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
140
|
-
return new Promise(resolve => {
|
|
159
|
+
return new Promise((resolve, reject) => {
|
|
160
|
+
let settled = false;
|
|
161
|
+
// Fires on stdin EOF before an answer; without it the Promise never settles.
|
|
162
|
+
rl.on('close', () => {
|
|
163
|
+
if (settled)
|
|
164
|
+
return;
|
|
165
|
+
settled = true;
|
|
166
|
+
reject(new UsageError(`Variable "${name}" has no value and stdin is closed; pass --${name}=<value> or --no-interactive`));
|
|
167
|
+
});
|
|
141
168
|
rl.question(prompt, (answer) => {
|
|
169
|
+
if (settled)
|
|
170
|
+
return;
|
|
171
|
+
settled = true;
|
|
142
172
|
rl.close();
|
|
143
173
|
resolve(answer.trim());
|
|
144
174
|
});
|
package/dist/resolver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAU9C,SAAS,WAAW,CAAC,KAAa;IAChC,kEAAkE;IAClE,4CAA4C;IAC5C,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACnC,qCAAqC;IACvC,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAW,EAAE,OAAgB;IACrD,+BAA+B;IAC/B,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC;YACH,OAAO,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC;iBAClC,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBAC5B,MAAM,CAAC,OAAO,CAAC;iBACf,OAAO,CAAC,WAAW,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,GAA4B,CAAC;YACvC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACxB,MAAM,IAAI,UAAU,CAClB,aAAa,OAAO,OAAO,QAAQ,iEAAiE,CACrG,CAAC;YACJ,CAAC;YACD,MAAM,IAAI,UAAU,CAClB,aAAa,OAAO,sBAAsB,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CACnE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,IAAI,GAAG,KAAK,GAAG;QAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAE9B,2DAA2D;IAC3D,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,OAAO,GAAG,OAAO;SACpB,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC;SACpC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;SACvB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvB,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,UAAU,CAAC,OAAe;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACpD,IAAI,KAAK,GAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE5C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,CAAC,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACtD,IAAI,UAAU,CAAC,CAAC,CAAC;oBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAC5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,OAAiB,CAAC;gBACtB,IAAI,CAAC;oBACH,OAAO,GAAG,WAAW,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAClD,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;gBACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;oBAC5B,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;wBAAE,SAAS;oBACpD,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;wBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;gBACzE,CAAC;YACH,CAAC;QACH,CAAC;QACD,KAAK,GAAG,IAAI,CAAC;QACb,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM;IAChC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,IAAmB,EACnB,KAA6B,EAC7B,WAAoB,EACpB,KAAK,GAAG,KAAK;IAEb,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAA2B,CAAC;IAC7D,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAA6B,CAAC;IAClE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,iBAAiB;QACjB,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACzD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;gBAC7B,SAAS,GAAG,IAAI,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,8DAA8D;YAC9D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1B,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAC7B,SAAS;YACX,CAAC;QACH,CAAC;QAED,iBAAiB;QACjB,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YACtB,SAAS;QACX,CAAC;QAED,aAAa;QACb,IAAI,CAAC,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC;YAChC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QAED,uBAAuB;QACvB,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAClD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;gBAC7B,SAAS,GAAG,IAAI,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAED,mBAAmB;IACnB,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrD,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,UAAU,GAA6B,EAAE,CAAC;IAChD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAEvD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAA2B,EAAE,MAAM,CAAC,CAAC;QAClF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC;AAED,SAAS,GAAG,CAAC,MAAc,EAAE,IAAY;IACvC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,6EAA6E;QAC7E,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAClB,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,CACJ,IAAI,UAAU,CACZ,aAAa,IAAI,8CAA8C,IAAI,8BAA8B,CAClG,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAc,EAAE,EAAE;YACrC,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/status.d.ts
CHANGED
package/dist/status.js
CHANGED
|
@@ -3,19 +3,20 @@
|
|
|
3
3
|
* Shows current template state: filled vars, unfilled vars, progress.
|
|
4
4
|
*/
|
|
5
5
|
import { sanitizeForTerminal } from './sanitize.js';
|
|
6
|
-
export function renderStatus(templateName, vars, values, iteration) {
|
|
6
|
+
export function renderStatus(templateName, vars, values, iteration, defaulted) {
|
|
7
7
|
const parts = [];
|
|
8
8
|
for (const v of vars) {
|
|
9
|
-
const val = values[v.name];
|
|
9
|
+
const val = Object.hasOwn(values, v.name) ? values[v.name] : undefined;
|
|
10
10
|
if (val !== undefined) {
|
|
11
|
-
const
|
|
11
|
+
const isDefault = defaulted ? defaulted.has(v.name) : v.defaultValue === val;
|
|
12
|
+
const source = isDefault ? '(default)' : '';
|
|
12
13
|
parts.push(`${v.name}=${val}${source}`);
|
|
13
14
|
}
|
|
14
15
|
else {
|
|
15
16
|
parts.push(`${v.name}=___`);
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
|
-
const allFilled = vars.every(v => v.name
|
|
19
|
+
const allFilled = vars.every(v => Object.hasOwn(values, v.name));
|
|
19
20
|
const icon = allFilled ? '✅' : '📋';
|
|
20
21
|
const progress = iteration ? ` [${iteration.current}/${iteration.total}]` : '';
|
|
21
22
|
// Values may come from repo-controlled sources (templates, git diff);
|
package/dist/status.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,MAAM,UAAU,YAAY,CAC1B,YAAoB,EACpB,IAAmB,EACnB,MAA8B,EAC9B,SAA8C;
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,MAAM,UAAU,YAAY,CAC1B,YAAoB,EACpB,IAAmB,EACnB,MAA8B,EAC9B,SAA8C,EAC9C,SAA+B;IAE/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACvE,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,GAAG,CAAC;YAC7E,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,GAAG,MAAM,EAAE,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IACpC,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/E,sEAAsE;IACtE,+DAA+D;IAC/D,OAAO,mBAAmB,CAAC,GAAG,IAAI,IAAI,YAAY,GAAG,QAAQ,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxF,CAAC"}
|
package/dist/ui.html
CHANGED
|
@@ -749,7 +749,12 @@ import { cartesian as sharedCartesian, zip as sharedZip } from './iterate.js';
|
|
|
749
749
|
|
|
750
750
|
function syncVarsFromTemplate() {
|
|
751
751
|
const text = tmpl.value;
|
|
752
|
-
|
|
752
|
+
let parsed;
|
|
753
|
+
try {
|
|
754
|
+
parsed = parseVars(text);
|
|
755
|
+
} catch {
|
|
756
|
+
return; // update() reports the parse error in the preview
|
|
757
|
+
}
|
|
753
758
|
const existing = getRowData();
|
|
754
759
|
const existingNames = new Set(existing.map(r => r.name));
|
|
755
760
|
|
|
@@ -849,10 +854,18 @@ import { cartesian as sharedCartesian, zip as sharedZip } from './iterate.js';
|
|
|
849
854
|
}
|
|
850
855
|
|
|
851
856
|
const results = [];
|
|
852
|
-
|
|
853
|
-
const
|
|
854
|
-
|
|
855
|
-
|
|
857
|
+
try {
|
|
858
|
+
for (const combo of combos) {
|
|
859
|
+
const vals = { ...scalarValues };
|
|
860
|
+
arrayVars.forEach((v, i) => { vals[v.name] = combo[i]; });
|
|
861
|
+
results.push({ values: { ...vals }, expanded: sharedExpand(text, vals) });
|
|
862
|
+
}
|
|
863
|
+
} catch (err) {
|
|
864
|
+
previewBody.innerHTML = `<span class="preview-empty">${escHtml(err instanceof Error ? err.message : String(err))}</span>`;
|
|
865
|
+
previewCount.textContent = 'error';
|
|
866
|
+
previewCount.className = 'preview-count empty';
|
|
867
|
+
cliText.innerHTML = '<span class="dollar">$</span>promptargs';
|
|
868
|
+
return;
|
|
856
869
|
}
|
|
857
870
|
|
|
858
871
|
const count = results.length;
|
package/dist/ui.js
CHANGED
|
@@ -3,6 +3,7 @@ import { readFileSync } from 'node:fs';
|
|
|
3
3
|
import { join, dirname } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { autodetect, isSensitiveEnvName, isSensitiveEnvValue, AUTODETECT_VARS } from './autodetect.js';
|
|
6
|
+
import { diag, classifyError, jsonLogEnabled, logRequest } from './log.js';
|
|
6
7
|
const DEFAULT_PORT = 3700;
|
|
7
8
|
const OPEN_DELAY_MS = 500;
|
|
8
9
|
const DIFF_PREVIEW_MAX_CHARS = 60;
|
|
@@ -50,7 +51,9 @@ export function buildUIHtml(rawHtml, envVars) {
|
|
|
50
51
|
// Escape "<" so env values cannot break out of the script tag (e.g. "</script>").
|
|
51
52
|
const envJson = JSON.stringify(envVars).replace(/</g, '\\u003c');
|
|
52
53
|
const envScript = `<script>window.__PROMPTARGS_ENV__ = ${envJson};</script>`;
|
|
53
|
-
|
|
54
|
+
// Function replacer: a replacement *string* would expand `$&`, "$`" and "$'"
|
|
55
|
+
// found in env values into surrounding raw HTML, undoing the escaping above.
|
|
56
|
+
return rawHtml.replace(/<script\b/, (match) => `${envScript}\n${match}`);
|
|
54
57
|
}
|
|
55
58
|
// Browser-facing modules the builder UI imports directly instead of
|
|
56
59
|
// hand-reimplementing their logic (see buildUIHtml / ui.html). Serving the
|
|
@@ -68,18 +71,24 @@ export function startUI(port = DEFAULT_PORT, options = {}) {
|
|
|
68
71
|
rawHtml = readFileSync(htmlPath, 'utf-8');
|
|
69
72
|
}
|
|
70
73
|
catch {
|
|
71
|
-
|
|
74
|
+
diag('ui_start_error', { error_class: 'not_found' }, 'UI file not found. Reinstall @hivecommons/promptargs.');
|
|
72
75
|
process.exit(1);
|
|
73
76
|
}
|
|
74
77
|
const html = buildUIHtml(rawHtml, collectEnvVars());
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
`[::1]:${port}`,
|
|
79
|
-
]);
|
|
78
|
+
// Filled once the server is bound, because port 0 means the OS picks one.
|
|
79
|
+
const ALLOWED_HOSTS = new Set();
|
|
80
|
+
let rejectedHosts = 0;
|
|
80
81
|
const server = createServer((req, res) => {
|
|
82
|
+
if (jsonLogEnabled()) {
|
|
83
|
+
const startedAt = process.hrtime.bigint();
|
|
84
|
+
res.on('finish', () => logRequest(res.statusCode, startedAt));
|
|
85
|
+
}
|
|
81
86
|
// Reject non-local Host headers to block DNS-rebinding reads of env data.
|
|
82
87
|
if (!req.headers.host || !ALLOWED_HOSTS.has(req.headers.host)) {
|
|
88
|
+
// Never log the Host header or URL: both are attacker-controlled.
|
|
89
|
+
if (rejectedHosts++ === 0) {
|
|
90
|
+
diag('ui_host_rejected', { status: 403 }, 'promptargs: rejected request with unexpected Host header (further rejections suppressed)');
|
|
91
|
+
}
|
|
83
92
|
res.writeHead(403, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
84
93
|
res.end('Forbidden');
|
|
85
94
|
return;
|
|
@@ -91,7 +100,8 @@ export function startUI(port = DEFAULT_PORT, options = {}) {
|
|
|
91
100
|
res.writeHead(200, { 'Content-Type': 'text/javascript; charset=utf-8' });
|
|
92
101
|
res.end(js);
|
|
93
102
|
}
|
|
94
|
-
catch {
|
|
103
|
+
catch (err) {
|
|
104
|
+
diag('ui_asset_error', { status: 404, error_class: classifyError(err) }, `promptargs: failed to load static asset ${req.url} (${err.code ?? 'unknown'})`);
|
|
95
105
|
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
96
106
|
res.end('Not found');
|
|
97
107
|
}
|
|
@@ -103,7 +113,11 @@ export function startUI(port = DEFAULT_PORT, options = {}) {
|
|
|
103
113
|
// Bind loopback only: the page embeds environment variables and must never
|
|
104
114
|
// be reachable from other machines on the network.
|
|
105
115
|
server.listen(port, '127.0.0.1', () => {
|
|
106
|
-
const
|
|
116
|
+
const boundPort = server.address().port;
|
|
117
|
+
ALLOWED_HOSTS.add(`localhost:${boundPort}`);
|
|
118
|
+
ALLOWED_HOSTS.add(`127.0.0.1:${boundPort}`);
|
|
119
|
+
ALLOWED_HOSTS.add(`[::1]:${boundPort}`);
|
|
120
|
+
const url = `http://localhost:${boundPort}`;
|
|
107
121
|
console.log(`promptargs builder running at ${url}`);
|
|
108
122
|
console.log('Press Ctrl+C to stop.\n');
|
|
109
123
|
if (options.openBrowser ?? true) {
|
|
@@ -111,14 +125,25 @@ export function startUI(port = DEFAULT_PORT, options = {}) {
|
|
|
111
125
|
import('node:child_process').then(({ exec }) => {
|
|
112
126
|
const cmd = process.platform === 'darwin' ? 'open' :
|
|
113
127
|
process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
114
|
-
exec(`${cmd} ${url}
|
|
128
|
+
exec(`${cmd} ${url}`, err => {
|
|
129
|
+
if (!err)
|
|
130
|
+
return;
|
|
131
|
+
// Through a shell, a missing opener surfaces as exit status 127 rather than ENOENT.
|
|
132
|
+
const why = err.code === 127 ? 'not found' : String(err.code ?? err.message);
|
|
133
|
+
diag('ui_browser_open_failed', { error_class: classifyError(err) }, `promptargs: could not open a browser (${cmd}: ${why}); open ${url} manually`);
|
|
134
|
+
});
|
|
115
135
|
});
|
|
116
136
|
}, OPEN_DELAY_MS);
|
|
117
137
|
}
|
|
118
138
|
});
|
|
139
|
+
server.on('close', () => {
|
|
140
|
+
if (rejectedHosts > 1) {
|
|
141
|
+
diag('ui_host_rejected_total', { count: rejectedHosts }, `promptargs: rejected ${rejectedHosts} requests with unexpected Host headers in total`);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
119
144
|
server.on('error', (err) => {
|
|
120
145
|
if (err.code === 'EADDRINUSE') {
|
|
121
|
-
|
|
146
|
+
diag('ui_start_error', { error_class: 'port_in_use' }, `Port ${port} is in use. Try: promptargs ui --port=${port + 1}`);
|
|
122
147
|
process.exit(1);
|
|
123
148
|
}
|
|
124
149
|
throw err;
|
package/dist/ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hivecommons/promptargs",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Template arguments for AI prompts — variable substitution for Claude Code, Copilot, and more",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "Template arguments for AI prompts — variable substitution for Claude Code, Copilot, Goose, Bob, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -21,7 +21,12 @@
|
|
|
21
21
|
"claude",
|
|
22
22
|
"copilot",
|
|
23
23
|
"args",
|
|
24
|
-
"cli"
|
|
24
|
+
"cli",
|
|
25
|
+
"claude-code",
|
|
26
|
+
"goose",
|
|
27
|
+
"bob",
|
|
28
|
+
"agent-skills",
|
|
29
|
+
"prompt-templates"
|
|
25
30
|
],
|
|
26
31
|
"author": "hivecommons",
|
|
27
32
|
"license": "Apache-2.0",
|
|
@@ -34,10 +39,14 @@
|
|
|
34
39
|
},
|
|
35
40
|
"homepage": "https://github.com/hivecommons/promptargs#readme",
|
|
36
41
|
"engines": {
|
|
37
|
-
"node": ">=
|
|
42
|
+
"node": ">=22"
|
|
38
43
|
},
|
|
39
44
|
"files": [
|
|
40
45
|
"dist",
|
|
46
|
+
"!dist/**/*.test.js",
|
|
47
|
+
"!dist/**/*.test.js.map",
|
|
48
|
+
"!dist/**/*.test.d.ts",
|
|
49
|
+
"!dist/ui-harness.*",
|
|
41
50
|
"README.md",
|
|
42
51
|
"LICENSE"
|
|
43
52
|
],
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/autodetect.test.js
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import { describe, it, before, after } from 'node:test';
|
|
2
|
-
import assert from 'node:assert';
|
|
3
|
-
import { execSync } from 'node:child_process';
|
|
4
|
-
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
|
-
import { join, delimiter } from 'node:path';
|
|
6
|
-
import { tmpdir } from 'node:os';
|
|
7
|
-
import { autodetect, autodetectAll, isSensitiveEnvName, isSensitiveEnvValue, AUTODETECT_VARS } from './autodetect.js';
|
|
8
|
-
// git-backed detectors read the process cwd, so run them inside a scratch
|
|
9
|
-
// repo with a known origin remote (each test file is its own process).
|
|
10
|
-
let repo;
|
|
11
|
-
let prevCwd;
|
|
12
|
-
before(() => {
|
|
13
|
-
prevCwd = process.cwd();
|
|
14
|
-
repo = mkdtempSync(join(process.cwd(), '.pa-auto-'));
|
|
15
|
-
process.chdir(repo);
|
|
16
|
-
const run = (cmd) => execSync(cmd, { stdio: 'pipe' });
|
|
17
|
-
run('git init -q -b pa-test-branch');
|
|
18
|
-
run('git config user.email pa@test.local');
|
|
19
|
-
run('git config user.name "PA Tester"');
|
|
20
|
-
run('git remote add origin https://github.com/pa-test-org/pa-test-repo.git');
|
|
21
|
-
run('git commit -q --allow-empty -m init');
|
|
22
|
-
});
|
|
23
|
-
after(() => {
|
|
24
|
-
process.chdir(prevCwd);
|
|
25
|
-
rmSync(repo, { recursive: true, force: true });
|
|
26
|
-
});
|
|
27
|
-
describe('git detectors', () => {
|
|
28
|
-
it('detects the current branch', () => {
|
|
29
|
-
assert.strictEqual(autodetect('branch'), 'pa-test-branch');
|
|
30
|
-
});
|
|
31
|
-
it('detects repo name from the origin remote, stripping .git', () => {
|
|
32
|
-
assert.strictEqual(autodetect('repo'), 'pa-test-repo');
|
|
33
|
-
});
|
|
34
|
-
it('detects the org from the origin remote', () => {
|
|
35
|
-
assert.strictEqual(autodetect('org'), 'pa-test-org');
|
|
36
|
-
});
|
|
37
|
-
it('detects repo/org from ssh-style remotes', () => {
|
|
38
|
-
execSync('git remote set-url origin git@github.com:ssh-org/ssh-repo.git', { stdio: 'pipe' });
|
|
39
|
-
try {
|
|
40
|
-
assert.strictEqual(autodetect('repo'), 'ssh-repo');
|
|
41
|
-
assert.strictEqual(autodetect('org'), 'ssh-org');
|
|
42
|
-
}
|
|
43
|
-
finally {
|
|
44
|
-
execSync('git remote set-url origin https://github.com/pa-test-org/pa-test-repo.git', { stdio: 'pipe' });
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
it('detects the git user name', () => {
|
|
48
|
-
assert.strictEqual(autodetect('user'), 'PA Tester');
|
|
49
|
-
});
|
|
50
|
-
it('returns undefined for branch on a detached HEAD', () => {
|
|
51
|
-
// `git branch --show-current` exits 0 and prints nothing when detached;
|
|
52
|
-
// that must not become an empty value that beats the template default.
|
|
53
|
-
execSync('git checkout -q --detach', { stdio: 'pipe' });
|
|
54
|
-
try {
|
|
55
|
-
assert.strictEqual(autodetect('branch'), undefined);
|
|
56
|
-
assert.ok(!('branch' in autodetectAll(['branch'])));
|
|
57
|
-
}
|
|
58
|
-
finally {
|
|
59
|
-
execSync('git checkout -q pa-test-branch', { stdio: 'pipe' });
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
it('returns undefined for diff on a clean tree and the diff once there is one', () => {
|
|
63
|
-
assert.strictEqual(autodetect('diff'), undefined);
|
|
64
|
-
writeFileSync(join(repo, 'tracked.txt'), 'one\n');
|
|
65
|
-
execSync('git add tracked.txt && git commit -q -m add', { stdio: 'pipe' });
|
|
66
|
-
writeFileSync(join(repo, 'tracked.txt'), 'two\n');
|
|
67
|
-
try {
|
|
68
|
-
assert.match(autodetect('diff') ?? '', /^diff --git a\/tracked\.txt/);
|
|
69
|
-
}
|
|
70
|
-
finally {
|
|
71
|
-
execSync('git checkout -q -- tracked.txt', { stdio: 'pipe' });
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
describe('date detector', () => {
|
|
76
|
-
it('returns an ISO date (YYYY-MM-DD)', () => {
|
|
77
|
-
assert.match(autodetect('date'), /^\d{4}-\d{2}-\d{2}$/);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
describe('environment fallback', () => {
|
|
81
|
-
it('falls back to environment variables for unknown names', () => {
|
|
82
|
-
process.env.pa_custom_var = 'env-value';
|
|
83
|
-
try {
|
|
84
|
-
assert.strictEqual(autodetect('pa_custom_var'), 'env-value');
|
|
85
|
-
}
|
|
86
|
-
finally {
|
|
87
|
-
delete process.env.pa_custom_var;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
it('returns undefined for unknown names not in the environment', () => {
|
|
91
|
-
assert.strictEqual(autodetect('pa_definitely_not_set'), undefined);
|
|
92
|
-
});
|
|
93
|
-
it('never expands credential-looking env vars', () => {
|
|
94
|
-
process.env.PA_TEST_TOKEN = 'sekrit';
|
|
95
|
-
process.env.PA_TEST_API_KEY = 'sekrit';
|
|
96
|
-
try {
|
|
97
|
-
assert.strictEqual(autodetect('PA_TEST_TOKEN'), undefined);
|
|
98
|
-
assert.strictEqual(autodetect('PA_TEST_API_KEY'), undefined);
|
|
99
|
-
}
|
|
100
|
-
finally {
|
|
101
|
-
delete process.env.PA_TEST_TOKEN;
|
|
102
|
-
delete process.env.PA_TEST_API_KEY;
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
it('never expands credential-shaped values under innocuous names', () => {
|
|
106
|
-
process.env.PA_TEST_DATABASE_URL = 'postgres://app:hunter2@db.internal/app';
|
|
107
|
-
process.env.PA_TEST_PLAIN_URL = 'postgres://db.internal/app';
|
|
108
|
-
try {
|
|
109
|
-
assert.strictEqual(autodetect('PA_TEST_DATABASE_URL'), undefined);
|
|
110
|
-
assert.strictEqual(autodetect('PA_TEST_PLAIN_URL'), 'postgres://db.internal/app');
|
|
111
|
-
}
|
|
112
|
-
finally {
|
|
113
|
-
delete process.env.PA_TEST_DATABASE_URL;
|
|
114
|
-
delete process.env.PA_TEST_PLAIN_URL;
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
describe('isSensitiveEnvName', () => {
|
|
119
|
-
it('flags credential-looking names', () => {
|
|
120
|
-
for (const name of [
|
|
121
|
-
'GITHUB_TOKEN', 'GH_TOKEN', 'NPM_TOKEN', 'MY_SECRET', 'DB_PASSWORD',
|
|
122
|
-
'PGPASSWD', 'AWS_SECRET_ACCESS_KEY', 'OPENAI_API_KEY', 'APIKEY',
|
|
123
|
-
'GOOGLE_APPLICATION_CREDENTIALS', 'SSH_PRIVATE_KEY', 'AUTH_HEADER',
|
|
124
|
-
'X_AUTH', 'SESSION_COOKIE', 'BEARER_VALUE', 'gh_token',
|
|
125
|
-
// Suffix conventions outside API_/ACCESS_/PRIVATE_KEY
|
|
126
|
-
'OPENAI_KEY', 'STRIPE_KEY', 'SIGNING_KEY', 'ENCRYPTION_KEY', 'HIVE_HEARTBEAT_KEY',
|
|
127
|
-
'LICENSE_KEY', 'SSH_KEYS', 'KEY', 'MYSQL_PWD', 'ORACLE_PWD', 'GITHUB_PAT', 'AZURE_DEVOPS_PAT',
|
|
128
|
-
'PAT', 'GIT_PASS', 'SSH_PASSPHRASE', 'SLACK_WEBHOOK_URL', 'DISCORD_WEBHOOK', 'SENTRY_DSN',
|
|
129
|
-
'DB_CONNECTION_STRING', 'AZURE_CONN_STR', 'JWT_SIGNING', 'HMAC_VALUE', 'OAUTH_CLIENT_ID',
|
|
130
|
-
]) {
|
|
131
|
-
assert.strictEqual(isSensitiveEnvName(name), true, `should flag ${name}`);
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
it('does not flag ordinary names', () => {
|
|
135
|
-
for (const name of [
|
|
136
|
-
'EDITOR', 'PATH', 'GOPATH', 'AUTHOR', 'AUTHORIZED_USERS_FILE', 'branch', 'KEYBOARD',
|
|
137
|
-
'PWD', 'OLDPWD', 'PATTERN', 'PATCH_LEVEL', 'PASSENGER_COUNT', 'MONKEY', 'DSNAME', 'COMPASS',
|
|
138
|
-
]) {
|
|
139
|
-
assert.strictEqual(isSensitiveEnvName(name), false, `should not flag ${name}`);
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
describe('isSensitiveEnvValue', () => {
|
|
144
|
-
it('flags credential-shaped values regardless of name', () => {
|
|
145
|
-
for (const value of [
|
|
146
|
-
'postgres://app:hunter2@db.internal:5432/app',
|
|
147
|
-
'redis://:p4ss@cache.internal/0',
|
|
148
|
-
'mongodb+srv://user:pw@cluster0.example.net/db',
|
|
149
|
-
'-----BEGIN OPENSSH PRIVATE KEY-----\nabc',
|
|
150
|
-
'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.sig',
|
|
151
|
-
'ghp_' + 'A'.repeat(36),
|
|
152
|
-
'github_pat_' + 'A'.repeat(22) + '_' + 'b'.repeat(59),
|
|
153
|
-
'glpat-' + 'x'.repeat(20),
|
|
154
|
-
'sk-' + 'x'.repeat(48),
|
|
155
|
-
'sk_live_' + 'x'.repeat(24),
|
|
156
|
-
'xoxb-' + '1'.repeat(12) + '-abc',
|
|
157
|
-
'AKIA' + 'A'.repeat(16),
|
|
158
|
-
'AIza' + 'a'.repeat(35),
|
|
159
|
-
'npm_' + 'a'.repeat(36),
|
|
160
|
-
'hvs.' + 'a'.repeat(24),
|
|
161
|
-
]) {
|
|
162
|
-
assert.strictEqual(isSensitiveEnvValue(value), true, `should flag ${value.slice(0, 12)}...`);
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
it('does not flag ordinary values', () => {
|
|
166
|
-
for (const value of [
|
|
167
|
-
'main', '/usr/local/bin:/usr/bin', 'https://github.com/hivecommons/promptargs',
|
|
168
|
-
'postgres://db.internal/app', 'https://user@example.com/path', 'user@example.com',
|
|
169
|
-
'skills', 'sk-short', 'eyJ-not-a-jwt', 'AKIA-nope', 'Hello, world', '42',
|
|
170
|
-
]) {
|
|
171
|
-
assert.strictEqual(isSensitiveEnvValue(value), false, `should not flag ${value}`);
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
describe('autodetectAll', () => {
|
|
176
|
-
it('collects only detectable values', () => {
|
|
177
|
-
const result = autodetectAll(['branch', 'pa_definitely_not_set', 'date']);
|
|
178
|
-
assert.strictEqual(result.branch, 'pa-test-branch');
|
|
179
|
-
assert.ok('date' in result);
|
|
180
|
-
assert.ok(!('pa_definitely_not_set' in result));
|
|
181
|
-
});
|
|
182
|
-
it('AUTODETECT_VARS lists the built-in detectors', () => {
|
|
183
|
-
for (const name of ['branch', 'repo', 'org', 'diff', 'pr', 'user', 'date']) {
|
|
184
|
-
assert.ok(AUTODETECT_VARS.includes(name), `missing ${name}`);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
describe('pr detector', () => {
|
|
189
|
-
it('returns undefined when gh exits 0 with empty output', t => {
|
|
190
|
-
// A branch with no PR: gh succeeds but prints nothing, so the detector
|
|
191
|
-
// must map '' to undefined rather than returning an empty value.
|
|
192
|
-
if (process.platform === 'win32')
|
|
193
|
-
return t.skip('POSIX shim script');
|
|
194
|
-
const shim = mkdtempSync(join(tmpdir(), 'pa-gh-shim-'));
|
|
195
|
-
writeFileSync(join(shim, 'gh'), '#!/bin/sh\nexit 0\n', { mode: 0o755 });
|
|
196
|
-
const prevPath = process.env.PATH;
|
|
197
|
-
process.env.PATH = `${shim}${delimiter}${prevPath ?? ''}`;
|
|
198
|
-
try {
|
|
199
|
-
assert.strictEqual(autodetect('pr'), undefined);
|
|
200
|
-
}
|
|
201
|
-
finally {
|
|
202
|
-
process.env.PATH = prevPath;
|
|
203
|
-
rmSync(shim, { recursive: true, force: true });
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
//# sourceMappingURL=autodetect.test.js.map
|