@hivecommons/promptargs 0.6.0 → 0.7.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 +46 -6
- package/dist/autodetect.d.ts +2 -0
- package/dist/autodetect.js +53 -3
- package/dist/autodetect.js.map +1 -1
- package/dist/autodetect.test.d.ts +1 -0
- package/dist/autodetect.test.js +207 -0
- package/dist/autodetect.test.js.map +1 -0
- package/dist/cli.js +13 -8
- package/dist/cli.js.map +1 -1
- package/dist/cli.test.d.ts +1 -0
- package/dist/cli.test.js +310 -0
- package/dist/cli.test.js.map +1 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +59 -0
- package/dist/index.test.js.map +1 -0
- package/dist/iterate.d.ts +8 -0
- package/dist/iterate.js +28 -0
- package/dist/iterate.js.map +1 -0
- package/dist/iterate.test.d.ts +1 -0
- package/dist/iterate.test.js +20 -0
- package/dist/iterate.test.js.map +1 -0
- package/dist/loader.test.d.ts +1 -0
- package/dist/loader.test.js +65 -0
- package/dist/loader.test.js.map +1 -0
- package/dist/mustache.mjs +764 -0
- package/dist/parser.d.ts +1 -0
- package/dist/parser.js +16 -4
- package/dist/parser.js.map +1 -1
- package/dist/parser.test.js +37 -0
- package/dist/parser.test.js.map +1 -1
- package/dist/resolver.js +58 -44
- package/dist/resolver.js.map +1 -1
- package/dist/resolver.test.d.ts +1 -0
- package/dist/resolver.test.js +184 -0
- package/dist/resolver.test.js.map +1 -0
- package/dist/sanitize.d.ts +10 -0
- package/dist/sanitize.js +21 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/sanitize.test.d.ts +1 -0
- package/dist/sanitize.test.js +38 -0
- package/dist/sanitize.test.js.map +1 -0
- package/dist/status.js +4 -1
- package/dist/status.js.map +1 -1
- package/dist/status.test.d.ts +1 -0
- package/dist/status.test.js +33 -0
- package/dist/status.test.js.map +1 -0
- package/dist/ui-bootstrap.test.d.ts +1 -0
- package/dist/ui-bootstrap.test.js +479 -0
- package/dist/ui-bootstrap.test.js.map +1 -0
- package/dist/ui-builder.test.d.ts +1 -0
- package/dist/ui-builder.test.js +272 -0
- package/dist/ui-builder.test.js.map +1 -0
- package/dist/ui-command-quoting.test.d.ts +1 -0
- package/dist/ui-command-quoting.test.js +95 -0
- package/dist/ui-command-quoting.test.js.map +1 -0
- package/dist/ui-harness.d.ts +20 -0
- package/dist/ui-harness.js +40 -0
- package/dist/ui-harness.js.map +1 -0
- package/dist/ui-harness.test.d.ts +1 -0
- package/dist/ui-harness.test.js +30 -0
- package/dist/ui-harness.test.js.map +1 -0
- package/dist/ui-inline.test.d.ts +1 -0
- package/dist/ui-inline.test.js +90 -0
- package/dist/ui-inline.test.js.map +1 -0
- package/dist/ui-interactions.test.d.ts +1 -0
- package/dist/ui-interactions.test.js +489 -0
- package/dist/ui-interactions.test.js.map +1 -0
- package/dist/ui.d.ts +13 -1
- package/dist/ui.html +30 -57
- package/dist/ui.js +61 -18
- package/dist/ui.js.map +1 -1
- package/dist/ui.test.d.ts +1 -0
- package/dist/ui.test.js +283 -0
- package/dist/ui.test.js.map +1 -0
- package/package.json +4 -3
package/dist/ui.html
CHANGED
|
@@ -649,9 +649,19 @@
|
|
|
649
649
|
</div>
|
|
650
650
|
</div>
|
|
651
651
|
|
|
652
|
-
<script>
|
|
652
|
+
<script type="importmap">
|
|
653
|
+
{ "imports": { "mustache": "./mustache.mjs" } }
|
|
654
|
+
</script>
|
|
655
|
+
<script type="module">
|
|
656
|
+
// Import the canonical {{var}} grammar and iteration logic from the same
|
|
657
|
+
// compiled modules the CLI runs, instead of hand-reimplementing them here
|
|
658
|
+
// (see issue #69). Only splitValues/esc/escHtml stay UI-local: they encode
|
|
659
|
+
// browser-only concerns (no glob/file access, HTML escaping) with no CLI
|
|
660
|
+
// counterpart to drift from.
|
|
661
|
+
import { parseVars, expand as sharedExpand, VAR_PATTERN } from './parser.js';
|
|
662
|
+
import { cartesian as sharedCartesian, zip as sharedZip } from './iterate.js';
|
|
663
|
+
|
|
653
664
|
(function () {
|
|
654
|
-
const VAR_RE = /\{\{(\w+)(?:=([^}]*))?\}\}/g;
|
|
655
665
|
const DEBOUNCE_MS = 120;
|
|
656
666
|
|
|
657
667
|
const PRESETS = [
|
|
@@ -726,20 +736,6 @@
|
|
|
726
736
|
const copyBtn = document.getElementById('copy-btn');
|
|
727
737
|
const modeDesc = document.getElementById('mode-desc');
|
|
728
738
|
|
|
729
|
-
function parseVarsFromTemplate(text) {
|
|
730
|
-
const seen = new Set();
|
|
731
|
-
const vars = [];
|
|
732
|
-
let m;
|
|
733
|
-
VAR_RE.lastIndex = 0;
|
|
734
|
-
while ((m = VAR_RE.exec(text)) !== null) {
|
|
735
|
-
if (!seen.has(m[1])) {
|
|
736
|
-
seen.add(m[1]);
|
|
737
|
-
vars.push({ name: m[1], defaultValue: m[2] });
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
return vars;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
739
|
function getRowData() {
|
|
744
740
|
const rows = [];
|
|
745
741
|
for (const tr of varBody.querySelectorAll('tr')) {
|
|
@@ -753,7 +749,7 @@
|
|
|
753
749
|
|
|
754
750
|
function syncVarsFromTemplate() {
|
|
755
751
|
const text = tmpl.value;
|
|
756
|
-
const parsed =
|
|
752
|
+
const parsed = parseVars(text);
|
|
757
753
|
const existing = getRowData();
|
|
758
754
|
const existingNames = new Set(existing.map(r => r.name));
|
|
759
755
|
|
|
@@ -814,41 +810,9 @@
|
|
|
814
810
|
return raw.split(',').map(s => s.trim()).filter(Boolean);
|
|
815
811
|
}
|
|
816
812
|
|
|
817
|
-
function cartesian(arrays) {
|
|
818
|
-
if (arrays.length === 0) return [[]];
|
|
819
|
-
const first = arrays[0];
|
|
820
|
-
const rest = cartesian(arrays.slice(1));
|
|
821
|
-
const out = [];
|
|
822
|
-
for (const v of first) {
|
|
823
|
-
for (const r of rest) {
|
|
824
|
-
out.push([v, ...r]);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
return out;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
function zip(arrays) {
|
|
831
|
-
const maxLen = Math.max(...arrays.map(a => a.length), 1);
|
|
832
|
-
const out = [];
|
|
833
|
-
for (let i = 0; i < maxLen; i++) {
|
|
834
|
-
out.push(arrays.map(a => a[Math.min(i, a.length - 1)]));
|
|
835
|
-
}
|
|
836
|
-
return out;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
function expand(template, values) {
|
|
840
|
-
let result = template;
|
|
841
|
-
VAR_RE.lastIndex = 0;
|
|
842
|
-
result = result.replace(VAR_RE, (match, name, def) => {
|
|
843
|
-
if (name in values) return values[name];
|
|
844
|
-
if (def !== undefined) return def;
|
|
845
|
-
return match;
|
|
846
|
-
});
|
|
847
|
-
return result;
|
|
848
|
-
}
|
|
849
|
-
|
|
850
813
|
function highlightUnfilled(html) {
|
|
851
|
-
|
|
814
|
+
VAR_PATTERN.lastIndex = 0;
|
|
815
|
+
return html.replace(VAR_PATTERN, '<span class="unfilled">$&</span>');
|
|
852
816
|
}
|
|
853
817
|
|
|
854
818
|
function update() {
|
|
@@ -879,16 +843,16 @@
|
|
|
879
843
|
if (arrayVars.length === 0) {
|
|
880
844
|
combos = [[]];
|
|
881
845
|
} else if (mode === 'cross') {
|
|
882
|
-
combos =
|
|
846
|
+
combos = sharedCartesian(arrayVars.map(v => v.values));
|
|
883
847
|
} else {
|
|
884
|
-
combos =
|
|
848
|
+
combos = sharedZip(arrayVars.map(v => v.values));
|
|
885
849
|
}
|
|
886
850
|
|
|
887
851
|
const results = [];
|
|
888
852
|
for (const combo of combos) {
|
|
889
853
|
const vals = { ...scalarValues };
|
|
890
854
|
arrayVars.forEach((v, i) => { vals[v.name] = combo[i]; });
|
|
891
|
-
results.push({ values: { ...vals }, expanded:
|
|
855
|
+
results.push({ values: { ...vals }, expanded: sharedExpand(text, vals) });
|
|
892
856
|
}
|
|
893
857
|
|
|
894
858
|
const count = results.length;
|
|
@@ -908,16 +872,25 @@
|
|
|
908
872
|
}
|
|
909
873
|
previewBody.innerHTML = html || '<span class="preview-empty">No output</span>';
|
|
910
874
|
|
|
911
|
-
// Build CLI command
|
|
875
|
+
// Build CLI command. Every value must survive a POSIX shell unchanged:
|
|
876
|
+
// a bare word is left as-is, anything else is single-quoted (the only
|
|
877
|
+
// quoting under which $, backtick, backslash and whitespace are all
|
|
878
|
+
// literal). The inlined template stays double-quoted but also escapes
|
|
879
|
+
// the characters the shell expands inside double quotes.
|
|
880
|
+
const bareWord = /^[A-Za-z0-9_@%+=:,.\/-]+$/;
|
|
881
|
+
const shellQuote = s => bareWord.test(s) ? s : `'${s.replace(/'/g, `'\\''`)}'`;
|
|
882
|
+
const dquote = s => `"${s.replace(/[\\"$`]/g, '\\$&')}"`;
|
|
912
883
|
let cli = 'promptargs';
|
|
913
884
|
const hasInline = !text.includes('\n') && text.length < 200;
|
|
914
885
|
if (hasInline) {
|
|
915
|
-
cli += `
|
|
886
|
+
cli += ` ${dquote(text)}`;
|
|
916
887
|
}
|
|
917
888
|
for (const row of rows) {
|
|
918
889
|
if (!row.values) continue;
|
|
919
890
|
const prefix = row.source === 'file' ? '@' : '';
|
|
920
|
-
|
|
891
|
+
// Globs keep their double quotes so the CLI, not the shell, expands them;
|
|
892
|
+
// the same escaping as the template keeps the pattern itself literal.
|
|
893
|
+
const val = row.source === 'glob' ? dquote(row.values) : shellQuote(`${prefix}${row.values}`);
|
|
921
894
|
cli += ` --${row.name}=${val}`;
|
|
922
895
|
}
|
|
923
896
|
if (mode === 'cross' && arrayVars.length > 1) {
|
package/dist/ui.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createServer } from 'node:http';
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { join, dirname } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { autodetect, AUTODETECT_VARS } from './autodetect.js';
|
|
5
|
+
import { autodetect, isSensitiveEnvName, isSensitiveEnvValue, AUTODETECT_VARS } from './autodetect.js';
|
|
6
6
|
const DEFAULT_PORT = 3700;
|
|
7
7
|
const OPEN_DELAY_MS = 500;
|
|
8
8
|
const DIFF_PREVIEW_MAX_CHARS = 60;
|
|
@@ -18,15 +18,15 @@ const SKIP_ENV_EXACT = new Set([
|
|
|
18
18
|
'TERM_PROGRAM_VERSION', 'TERM_SESSION_ID', 'Apple_PubSub_Socket_Render',
|
|
19
19
|
'MallocNanoZone', 'ORIGINAL_XDG_CURRENT_DESKTOP', 'GIT_ASKPASS',
|
|
20
20
|
]);
|
|
21
|
-
function shouldSkipEnv(key) {
|
|
21
|
+
export function shouldSkipEnv(key) {
|
|
22
22
|
if (SKIP_ENV_EXACT.has(key))
|
|
23
23
|
return true;
|
|
24
24
|
return SKIP_ENV_PREFIXES.some(p => key.startsWith(p));
|
|
25
25
|
}
|
|
26
|
-
function truncateValue(val, max) {
|
|
26
|
+
export function truncateValue(val, max) {
|
|
27
27
|
return val.length > max ? val.slice(0, max) + '...' : val;
|
|
28
28
|
}
|
|
29
|
-
function collectEnvVars() {
|
|
29
|
+
export function collectEnvVars() {
|
|
30
30
|
const git = {};
|
|
31
31
|
for (const name of AUTODETECT_VARS) {
|
|
32
32
|
const value = autodetect(name);
|
|
@@ -38,13 +38,29 @@ function collectEnvVars() {
|
|
|
38
38
|
}
|
|
39
39
|
const terminal = {};
|
|
40
40
|
for (const [key, val] of Object.entries(process.env)) {
|
|
41
|
-
|
|
41
|
+
// Never embed credential-looking names or credential-shaped values in the
|
|
42
|
+
// served page.
|
|
43
|
+
if (!val || shouldSkipEnv(key) || isSensitiveEnvName(key) || isSensitiveEnvValue(val))
|
|
42
44
|
continue;
|
|
43
45
|
terminal[key] = truncateValue(val, ENV_VAL_PREVIEW_MAX_CHARS);
|
|
44
46
|
}
|
|
45
47
|
return { git, terminal };
|
|
46
48
|
}
|
|
47
|
-
export function
|
|
49
|
+
export function buildUIHtml(rawHtml, envVars) {
|
|
50
|
+
// Escape "<" so env values cannot break out of the script tag (e.g. "</script>").
|
|
51
|
+
const envJson = JSON.stringify(envVars).replace(/</g, '\\u003c');
|
|
52
|
+
const envScript = `<script>window.__PROMPTARGS_ENV__ = ${envJson};</script>`;
|
|
53
|
+
return rawHtml.replace('<script>', envScript + '\n<script>');
|
|
54
|
+
}
|
|
55
|
+
// Browser-facing modules the builder UI imports directly instead of
|
|
56
|
+
// hand-reimplementing their logic (see buildUIHtml / ui.html). Serving the
|
|
57
|
+
// exact compiled files means the browser runs the same code the CLI does.
|
|
58
|
+
const STATIC_JS_ROUTES = {
|
|
59
|
+
'/parser.js': 'parser.js',
|
|
60
|
+
'/iterate.js': 'iterate.js',
|
|
61
|
+
'/mustache.mjs': 'mustache.mjs',
|
|
62
|
+
};
|
|
63
|
+
export function startUI(port = DEFAULT_PORT, options = {}) {
|
|
48
64
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
49
65
|
const htmlPath = join(__dirname, 'ui.html');
|
|
50
66
|
let rawHtml;
|
|
@@ -55,24 +71,50 @@ export function startUI(port = DEFAULT_PORT) {
|
|
|
55
71
|
console.error('UI file not found. Reinstall @hivecommons/promptargs.');
|
|
56
72
|
process.exit(1);
|
|
57
73
|
}
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
74
|
+
const html = buildUIHtml(rawHtml, collectEnvVars());
|
|
75
|
+
const ALLOWED_HOSTS = new Set([
|
|
76
|
+
`localhost:${port}`,
|
|
77
|
+
`127.0.0.1:${port}`,
|
|
78
|
+
`[::1]:${port}`,
|
|
79
|
+
]);
|
|
80
|
+
const server = createServer((req, res) => {
|
|
81
|
+
// Reject non-local Host headers to block DNS-rebinding reads of env data.
|
|
82
|
+
if (!req.headers.host || !ALLOWED_HOSTS.has(req.headers.host)) {
|
|
83
|
+
res.writeHead(403, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
84
|
+
res.end('Forbidden');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const file = req.url ? STATIC_JS_ROUTES[req.url] : undefined;
|
|
88
|
+
if (file) {
|
|
89
|
+
try {
|
|
90
|
+
const js = readFileSync(join(__dirname, file), 'utf-8');
|
|
91
|
+
res.writeHead(200, { 'Content-Type': 'text/javascript; charset=utf-8' });
|
|
92
|
+
res.end(js);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
96
|
+
res.end('Not found');
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
62
100
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
63
101
|
res.end(html);
|
|
64
102
|
});
|
|
65
|
-
|
|
103
|
+
// Bind loopback only: the page embeds environment variables and must never
|
|
104
|
+
// be reachable from other machines on the network.
|
|
105
|
+
server.listen(port, '127.0.0.1', () => {
|
|
66
106
|
const url = `http://localhost:${port}`;
|
|
67
107
|
console.log(`promptargs builder running at ${url}`);
|
|
68
108
|
console.log('Press Ctrl+C to stop.\n');
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
process.platform === '
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
109
|
+
if (options.openBrowser ?? true) {
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
import('node:child_process').then(({ exec }) => {
|
|
112
|
+
const cmd = process.platform === 'darwin' ? 'open' :
|
|
113
|
+
process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
114
|
+
exec(`${cmd} ${url}`);
|
|
115
|
+
});
|
|
116
|
+
}, OPEN_DELAY_MS);
|
|
117
|
+
}
|
|
76
118
|
});
|
|
77
119
|
server.on('error', (err) => {
|
|
78
120
|
if (err.code === 'EADDRINUSE') {
|
|
@@ -81,5 +123,6 @@ export function startUI(port = DEFAULT_PORT) {
|
|
|
81
123
|
}
|
|
82
124
|
throw err;
|
|
83
125
|
});
|
|
126
|
+
return server;
|
|
84
127
|
}
|
|
85
128
|
//# sourceMappingURL=ui.js.map
|
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,
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/ui.test.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { get } from 'node:http';
|
|
4
|
+
import { createServer as createNetServer } from 'node:net';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { copyFileSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { join, dirname } from 'node:path';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
10
|
+
import { buildUIHtml, collectEnvVars, shouldSkipEnv, startUI, truncateValue, } from './ui.js';
|
|
11
|
+
test('shouldSkipEnv filters noisy shell and tooling variables', () => {
|
|
12
|
+
assert.equal(shouldSkipEnv('HOME'), true);
|
|
13
|
+
assert.equal(shouldSkipEnv('npm_config_cache'), true);
|
|
14
|
+
assert.equal(shouldSkipEnv('VSCODE_PID'), true);
|
|
15
|
+
assert.equal(shouldSkipEnv('PROMPTARGS_VISIBLE'), false);
|
|
16
|
+
});
|
|
17
|
+
test('truncateValue shortens long values and leaves short values unchanged', () => {
|
|
18
|
+
assert.equal(truncateValue('short', 10), 'short');
|
|
19
|
+
assert.equal(truncateValue('abcdefghijklmnopqrstuvwxyz', 8), 'abcdefgh...');
|
|
20
|
+
});
|
|
21
|
+
test('collectEnvVars includes terminal env values without skipped keys', () => {
|
|
22
|
+
const savedVisible = process.env['PROMPTARGS_TEST_VISIBLE'];
|
|
23
|
+
const savedHome = process.env['HOME'];
|
|
24
|
+
process.env['PROMPTARGS_TEST_VISIBLE'] = 'visible-value';
|
|
25
|
+
process.env['HOME'] = 'hidden-home';
|
|
26
|
+
try {
|
|
27
|
+
const env = collectEnvVars();
|
|
28
|
+
assert.equal(env.terminal['PROMPTARGS_TEST_VISIBLE'], 'visible-value');
|
|
29
|
+
assert.equal(env.terminal['HOME'], undefined);
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
if (savedVisible === undefined)
|
|
33
|
+
delete process.env['PROMPTARGS_TEST_VISIBLE'];
|
|
34
|
+
else
|
|
35
|
+
process.env['PROMPTARGS_TEST_VISIBLE'] = savedVisible;
|
|
36
|
+
if (savedHome === undefined)
|
|
37
|
+
delete process.env['HOME'];
|
|
38
|
+
else
|
|
39
|
+
process.env['HOME'] = savedHome;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
test('collectEnvVars omits credential-looking names and credential-shaped values', () => {
|
|
43
|
+
const keys = ['PROMPTARGS_TEST_SIGNING_KEY', 'PROMPTARGS_TEST_DB_URL', 'PROMPTARGS_TEST_PLAIN'];
|
|
44
|
+
const saved = Object.fromEntries(keys.map(k => [k, process.env[k]]));
|
|
45
|
+
process.env['PROMPTARGS_TEST_SIGNING_KEY'] = 'sig';
|
|
46
|
+
process.env['PROMPTARGS_TEST_DB_URL'] = 'postgres://app:hunter2@db.internal/app';
|
|
47
|
+
process.env['PROMPTARGS_TEST_PLAIN'] = 'plain';
|
|
48
|
+
try {
|
|
49
|
+
const env = collectEnvVars();
|
|
50
|
+
assert.equal(env.terminal['PROMPTARGS_TEST_SIGNING_KEY'], undefined);
|
|
51
|
+
assert.equal(env.terminal['PROMPTARGS_TEST_DB_URL'], undefined);
|
|
52
|
+
assert.equal(env.terminal['PROMPTARGS_TEST_PLAIN'], 'plain');
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
for (const k of keys) {
|
|
56
|
+
if (saved[k] === undefined)
|
|
57
|
+
delete process.env[k];
|
|
58
|
+
else
|
|
59
|
+
process.env[k] = saved[k];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
test('buildUIHtml escapes env JSON so values cannot escape the script tag', () => {
|
|
64
|
+
const html = buildUIHtml('<html><head><script></script></head></html>', {
|
|
65
|
+
git: {},
|
|
66
|
+
terminal: { PROMPTARGS_TEST: '</script><script>alert(1)</script>' },
|
|
67
|
+
});
|
|
68
|
+
assert.match(html, /window\.__PROMPTARGS_ENV__/);
|
|
69
|
+
assert.doesNotMatch(html, /<\/script><script>alert\(1\)<\/script>/);
|
|
70
|
+
assert.match(html, /\\u003c\/script>\\u003cscript>alert\(1\)\\u003c\/script>/);
|
|
71
|
+
});
|
|
72
|
+
test('startUI binds a server that rejects non-local Host headers', async () => {
|
|
73
|
+
const server = startUI(0, { openBrowser: false });
|
|
74
|
+
await onceListening(server);
|
|
75
|
+
const { port } = server.address();
|
|
76
|
+
try {
|
|
77
|
+
const allowed = await request(port, '127.0.0.1:0');
|
|
78
|
+
assert.equal(allowed.statusCode, 200);
|
|
79
|
+
assert.match(allowed.body, /window\.__PROMPTARGS_ENV__/);
|
|
80
|
+
const forbidden = await request(port, 'evil.example');
|
|
81
|
+
assert.equal(forbidden.statusCode, 403);
|
|
82
|
+
assert.equal(forbidden.body, 'Forbidden');
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
await closeServer(server);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
test('startUI serves the parser/iterate/mustache modules the browser imports', async () => {
|
|
89
|
+
const server = startUI(0, { openBrowser: false });
|
|
90
|
+
await onceListening(server);
|
|
91
|
+
const { port } = server.address();
|
|
92
|
+
try {
|
|
93
|
+
const parser = await request(port, '127.0.0.1:0', '/parser.js');
|
|
94
|
+
assert.equal(parser.statusCode, 200);
|
|
95
|
+
assert.match(parser.contentType ?? '', /text\/javascript/);
|
|
96
|
+
assert.match(parser.body, /export function parseVars/);
|
|
97
|
+
assert.match(parser.body, /export const VAR_PATTERN/);
|
|
98
|
+
const iterate = await request(port, '127.0.0.1:0', '/iterate.js');
|
|
99
|
+
assert.equal(iterate.statusCode, 200);
|
|
100
|
+
assert.match(iterate.body, /export function cartesian/);
|
|
101
|
+
assert.match(iterate.body, /export function zip/);
|
|
102
|
+
const mustache = await request(port, '127.0.0.1:0', '/mustache.mjs');
|
|
103
|
+
assert.equal(mustache.statusCode, 200);
|
|
104
|
+
assert.match(mustache.body, /export default mustache/);
|
|
105
|
+
const missing = await request(port, '127.0.0.1:0', '/does-not-exist.js');
|
|
106
|
+
assert.equal(missing.statusCode, 200);
|
|
107
|
+
assert.match(missing.body, /window\.__PROMPTARGS_ENV__/);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
await closeServer(server);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
test('startUI answers 404 for a static route whose backing file is missing', () => {
|
|
114
|
+
// Copy the compiled ui.js (plus its one local dep) into a directory
|
|
115
|
+
// without parser.js/iterate.js/mustache.mjs, so requesting a known static
|
|
116
|
+
// route hits the readFileSync catch branch.
|
|
117
|
+
const __dirnameUi = dirname(fileURLToPath(import.meta.url));
|
|
118
|
+
const dir = mkdtempSync(join(tmpdir(), 'promptargs-ui-static-'));
|
|
119
|
+
try {
|
|
120
|
+
for (const f of ['ui.js', 'ui.html', 'autodetect.js']) {
|
|
121
|
+
copyFileSync(join(__dirnameUi, f), join(dir, f));
|
|
122
|
+
}
|
|
123
|
+
writeFileSync(join(dir, 'package.json'), '{"type":"module"}');
|
|
124
|
+
// Intentionally omit parser.js/iterate.js/mustache.mjs so the route 404s.
|
|
125
|
+
const script = `
|
|
126
|
+
import { get } from 'node:http';
|
|
127
|
+
import(${JSON.stringify(pathToFileURL(join(dir, 'ui.js')).href)})
|
|
128
|
+
.then(m => {
|
|
129
|
+
const server = m.startUI(0, { openBrowser: false });
|
|
130
|
+
server.once('listening', () => {
|
|
131
|
+
const { port } = server.address();
|
|
132
|
+
get({
|
|
133
|
+
hostname: '127.0.0.1', port, path: '/parser.js',
|
|
134
|
+
headers: { Host: '127.0.0.1:0' },
|
|
135
|
+
}, res => {
|
|
136
|
+
process.stdout.write('STATUS:' + res.statusCode);
|
|
137
|
+
server.close(() => process.exit(0));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
`;
|
|
142
|
+
const res = spawnSync(process.execPath, ['--input-type=module', '-e', script], {
|
|
143
|
+
encoding: 'utf-8',
|
|
144
|
+
timeout: 15000,
|
|
145
|
+
});
|
|
146
|
+
assert.match(res.stdout, /STATUS:404/, res.stderr);
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
rmSync(dir, { recursive: true, force: true });
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
function onceListening(server) {
|
|
153
|
+
if (server.listening)
|
|
154
|
+
return Promise.resolve();
|
|
155
|
+
return new Promise(resolve => server.once('listening', resolve));
|
|
156
|
+
}
|
|
157
|
+
function closeServer(server) {
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
server.close(err => err ? reject(err) : resolve());
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function request(port, host, path = '/') {
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
const req = get({
|
|
165
|
+
hostname: '127.0.0.1',
|
|
166
|
+
port,
|
|
167
|
+
path,
|
|
168
|
+
headers: { Host: host },
|
|
169
|
+
}, res => {
|
|
170
|
+
let body = '';
|
|
171
|
+
res.setEncoding('utf8');
|
|
172
|
+
res.on('data', chunk => { body += chunk; });
|
|
173
|
+
res.on('end', () => resolve({
|
|
174
|
+
statusCode: res.statusCode ?? 0,
|
|
175
|
+
body,
|
|
176
|
+
contentType: res.headers['content-type'],
|
|
177
|
+
}));
|
|
178
|
+
});
|
|
179
|
+
req.on('error', reject);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// startUI exits the process on fatal errors, so those branches are
|
|
183
|
+
// exercised in a child node process rather than in-process.
|
|
184
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
185
|
+
function runStartUI(uiModulePath, port) {
|
|
186
|
+
const script = `
|
|
187
|
+
import(${JSON.stringify(pathToFileURL(uiModulePath).href)})
|
|
188
|
+
.then(m => m.startUI(${port}, { openBrowser: false }));
|
|
189
|
+
`;
|
|
190
|
+
const res = spawnSync(process.execPath, ['--input-type=module', '-e', script], {
|
|
191
|
+
encoding: 'utf-8',
|
|
192
|
+
timeout: 15000,
|
|
193
|
+
});
|
|
194
|
+
return { status: res.status, stderr: res.stderr };
|
|
195
|
+
}
|
|
196
|
+
test('startUI exits 1 with a port hint when the port is in use', async () => {
|
|
197
|
+
const blocker = createNetServer();
|
|
198
|
+
await new Promise(resolve => blocker.listen(0, '127.0.0.1', resolve));
|
|
199
|
+
const { port } = blocker.address();
|
|
200
|
+
try {
|
|
201
|
+
const res = runStartUI(join(__dirname, 'ui.js'), port);
|
|
202
|
+
assert.strictEqual(res.status, 1);
|
|
203
|
+
assert.match(res.stderr, new RegExp(`Port ${port} is in use`));
|
|
204
|
+
assert.match(res.stderr, new RegExp(`--port=${port + 1}`));
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
await new Promise(resolve => blocker.close(resolve));
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
test('startUI exits 1 with a reinstall hint when ui.html is missing', () => {
|
|
211
|
+
// Copy the compiled module (and its one local dep) somewhere without
|
|
212
|
+
// ui.html so the readFileSync catch branch runs.
|
|
213
|
+
const dir = mkdtempSync(join(tmpdir(), 'promptargs-ui-test-'));
|
|
214
|
+
try {
|
|
215
|
+
copyFileSync(join(__dirname, 'ui.js'), join(dir, 'ui.js'));
|
|
216
|
+
copyFileSync(join(__dirname, 'autodetect.js'), join(dir, 'autodetect.js'));
|
|
217
|
+
// Node 18 has no ESM syntax detection; mark the temp dir as ESM.
|
|
218
|
+
writeFileSync(join(dir, 'package.json'), '{"type":"module"}');
|
|
219
|
+
const res = runStartUI(join(dir, 'ui.js'), 0);
|
|
220
|
+
assert.strictEqual(res.status, 1);
|
|
221
|
+
assert.match(res.stderr, /UI file not found\. Reinstall @hivecommons\/promptargs\./);
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
rmSync(dir, { recursive: true, force: true });
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
test('startUI schedules a browser open by default', () => {
|
|
228
|
+
// openBrowser defaults to true; run in a child with an empty PATH so the
|
|
229
|
+
// platform open command is a harmless shell failure, never a real browser.
|
|
230
|
+
const script = `
|
|
231
|
+
import(${JSON.stringify(pathToFileURL(join(__dirname, 'ui.js')).href)})
|
|
232
|
+
.then(m => {
|
|
233
|
+
const server = m.startUI(0);
|
|
234
|
+
setTimeout(() => server.close(() => process.exit(0)), 900);
|
|
235
|
+
});
|
|
236
|
+
`;
|
|
237
|
+
const res = spawnSync(process.execPath, ['--input-type=module', '-e', script], {
|
|
238
|
+
encoding: 'utf-8',
|
|
239
|
+
timeout: 15000,
|
|
240
|
+
env: { ...process.env, PATH: '' },
|
|
241
|
+
});
|
|
242
|
+
assert.strictEqual(res.status, 0);
|
|
243
|
+
assert.match(res.stdout, /promptargs builder running at http:\/\/localhost:\d+/);
|
|
244
|
+
});
|
|
245
|
+
test('browser open picks the right command for each platform', () => {
|
|
246
|
+
// The darwin/win32 arms of the open-command ternary never run on Linux CI;
|
|
247
|
+
// force each platform value in a child and let the command fail on PATH=''.
|
|
248
|
+
for (const platform of ['darwin', 'win32', 'linux']) {
|
|
249
|
+
const script = `
|
|
250
|
+
Object.defineProperty(process, 'platform', { value: ${JSON.stringify(platform)} });
|
|
251
|
+
import(${JSON.stringify(pathToFileURL(join(__dirname, 'ui.js')).href)})
|
|
252
|
+
.then(m => {
|
|
253
|
+
const server = m.startUI(0);
|
|
254
|
+
setTimeout(() => server.close(() => process.exit(0)), 900);
|
|
255
|
+
});
|
|
256
|
+
`;
|
|
257
|
+
const res = spawnSync(process.execPath, ['--input-type=module', '-e', script], {
|
|
258
|
+
encoding: 'utf-8',
|
|
259
|
+
timeout: 15000,
|
|
260
|
+
env: { ...process.env, PATH: '' },
|
|
261
|
+
});
|
|
262
|
+
assert.strictEqual(res.status, 0, `platform ${platform}: ${res.stderr}`);
|
|
263
|
+
assert.match(res.stdout, /promptargs builder running at http:\/\/localhost:\d+/);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
test('startUI rethrows non-EADDRINUSE server errors', async (t) => {
|
|
267
|
+
// Only run where binding port 1 really fails with EACCES; containers with
|
|
268
|
+
// ip_unprivileged_port_start=0 (or root) can bind it and would hang instead.
|
|
269
|
+
const probeErr = await new Promise(resolve => {
|
|
270
|
+
const probe = createNetServer();
|
|
271
|
+
probe.once('error', err => resolve(err));
|
|
272
|
+
probe.listen(1, '127.0.0.1', () => probe.close(() => resolve(null)));
|
|
273
|
+
});
|
|
274
|
+
if (probeErr?.code !== 'EACCES') {
|
|
275
|
+
t.skip('binding port 1 did not fail with EACCES');
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const res = runStartUI(join(__dirname, 'ui.js'), 1);
|
|
279
|
+
assert.notStrictEqual(res.status, 0);
|
|
280
|
+
assert.match(res.stderr, /EACCES/);
|
|
281
|
+
assert.doesNotMatch(res.stderr, /is in use/);
|
|
282
|
+
});
|
|
283
|
+
//# sourceMappingURL=ui.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.test.js","sourceRoot":"","sources":["../src/ui.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hivecommons/promptargs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Template arguments for AI prompts — variable substitution for Claude Code, Copilot, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
"promptargs": "dist/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "tsc && cp src/ui.html dist/ui.html",
|
|
11
|
+
"build": "tsc && cp src/ui.html dist/ui.html && cp node_modules/mustache/mustache.mjs dist/mustache.mjs",
|
|
12
12
|
"dev": "tsc --watch",
|
|
13
|
-
"test": "node
|
|
13
|
+
"test": "node scripts/run-tests.mjs",
|
|
14
|
+
"test:coverage": "node scripts/run-tests.mjs --coverage",
|
|
14
15
|
"lint": "tsc --noEmit"
|
|
15
16
|
},
|
|
16
17
|
"keywords": [
|