@hivecommons/promptargs 0.7.0 → 0.9.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.
Files changed (81) hide show
  1. package/README.md +106 -20
  2. package/dist/autodetect.js +39 -12
  3. package/dist/autodetect.js.map +1 -1
  4. package/dist/cli.js +78 -147
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands.d.ts +4 -0
  7. package/dist/commands.js +148 -0
  8. package/dist/commands.js.map +1 -0
  9. package/dist/flags.d.ts +20 -0
  10. package/dist/flags.js +101 -0
  11. package/dist/flags.js.map +1 -0
  12. package/dist/loader.d.ts +2 -0
  13. package/dist/loader.js +84 -11
  14. package/dist/loader.js.map +1 -1
  15. package/dist/log.d.ts +19 -0
  16. package/dist/log.js +41 -0
  17. package/dist/log.js.map +1 -0
  18. package/dist/parser.js +39 -9
  19. package/dist/parser.js.map +1 -1
  20. package/dist/resolver.d.ts +3 -1
  21. package/dist/resolver.js +105 -34
  22. package/dist/resolver.js.map +1 -1
  23. package/dist/status.d.ts +1 -1
  24. package/dist/status.js +5 -4
  25. package/dist/status.js.map +1 -1
  26. package/dist/ui.d.ts +3 -0
  27. package/dist/ui.html +21 -6
  28. package/dist/ui.js +89 -12
  29. package/dist/ui.js.map +1 -1
  30. package/package.json +13 -4
  31. package/dist/autodetect.test.d.ts +0 -1
  32. package/dist/autodetect.test.js +0 -207
  33. package/dist/autodetect.test.js.map +0 -1
  34. package/dist/cli.test.d.ts +0 -1
  35. package/dist/cli.test.js +0 -310
  36. package/dist/cli.test.js.map +0 -1
  37. package/dist/index.test.d.ts +0 -1
  38. package/dist/index.test.js +0 -59
  39. package/dist/index.test.js.map +0 -1
  40. package/dist/iterate.test.d.ts +0 -1
  41. package/dist/iterate.test.js +0 -20
  42. package/dist/iterate.test.js.map +0 -1
  43. package/dist/loader.test.d.ts +0 -1
  44. package/dist/loader.test.js +0 -65
  45. package/dist/loader.test.js.map +0 -1
  46. package/dist/parser.test.d.ts +0 -1
  47. package/dist/parser.test.js +0 -93
  48. package/dist/parser.test.js.map +0 -1
  49. package/dist/resolver.test.d.ts +0 -1
  50. package/dist/resolver.test.js +0 -184
  51. package/dist/resolver.test.js.map +0 -1
  52. package/dist/sanitize.test.d.ts +0 -1
  53. package/dist/sanitize.test.js +0 -38
  54. package/dist/sanitize.test.js.map +0 -1
  55. package/dist/status.test.d.ts +0 -1
  56. package/dist/status.test.js +0 -33
  57. package/dist/status.test.js.map +0 -1
  58. package/dist/ui-bootstrap.test.d.ts +0 -1
  59. package/dist/ui-bootstrap.test.js +0 -479
  60. package/dist/ui-bootstrap.test.js.map +0 -1
  61. package/dist/ui-builder.test.d.ts +0 -1
  62. package/dist/ui-builder.test.js +0 -272
  63. package/dist/ui-builder.test.js.map +0 -1
  64. package/dist/ui-command-quoting.test.d.ts +0 -1
  65. package/dist/ui-command-quoting.test.js +0 -95
  66. package/dist/ui-command-quoting.test.js.map +0 -1
  67. package/dist/ui-harness.d.ts +0 -20
  68. package/dist/ui-harness.js +0 -40
  69. package/dist/ui-harness.js.map +0 -1
  70. package/dist/ui-harness.test.d.ts +0 -1
  71. package/dist/ui-harness.test.js +0 -30
  72. package/dist/ui-harness.test.js.map +0 -1
  73. package/dist/ui-inline.test.d.ts +0 -1
  74. package/dist/ui-inline.test.js +0 -90
  75. package/dist/ui-inline.test.js.map +0 -1
  76. package/dist/ui-interactions.test.d.ts +0 -1
  77. package/dist/ui-interactions.test.js +0 -489
  78. package/dist/ui-interactions.test.js.map +0 -1
  79. package/dist/ui.test.d.ts +0 -1
  80. package/dist/ui.test.js +0 -283
  81. package/dist/ui.test.js.map +0 -1
package/dist/loader.js CHANGED
@@ -1,22 +1,91 @@
1
1
  /**
2
2
  * Find and load prompt templates from .prompts/ directories.
3
3
  */
4
- import { readFileSync, readdirSync, existsSync } from 'node:fs';
5
- import { join, basename, extname } from 'node:path';
4
+ import { readFileSync, readdirSync, existsSync, statSync, lstatSync, realpathSync } from 'node:fs';
5
+ import { join, basename, extname, sep } from 'node:path';
6
6
  import { homedir } from 'node:os';
7
+ import { UsageError } from './flags.js';
8
+ import { diag, classifyError } from './log.js';
9
+ import { sanitizeForTerminal } from './sanitize.js';
7
10
  const PROJECT_DIR = '.prompts';
8
11
  const USER_DIR = join(homedir(), '.prompts');
9
12
  function loadFromDir(dir, source) {
13
+ // The per-file escape check below trusts the resolved directory as its root,
14
+ // so a checked-out repo must not be able to replace the project .prompts
15
+ // entry itself with a link to somewhere else on the machine. ~/.prompts is
16
+ // the user's own and may be a link. lstat runs before existsSync (which
17
+ // follows links) so a dangling project link is explained rather than skipped.
18
+ if (source === 'project') {
19
+ try {
20
+ if (lstatSync(dir).isSymbolicLink()) {
21
+ diag('loader_dir_symlink', { status: 'refused' }, sanitizeForTerminal(`promptargs: ${dir} is a symlink; the project .prompts directory must be a real directory`));
22
+ return [];
23
+ }
24
+ }
25
+ catch (err) {
26
+ if (err.code === 'ENOENT')
27
+ return [];
28
+ const msg = err instanceof Error ? err.message : String(err);
29
+ diag('loader_dir_unreadable', { error_class: classifyError(err) }, sanitizeForTerminal(`promptargs: cannot stat ${dir}: ${msg}`));
30
+ return [];
31
+ }
32
+ }
10
33
  if (!existsSync(dir))
11
34
  return [];
12
- return readdirSync(dir)
13
- .filter((f) => f.endsWith('.md'))
14
- .map((f) => ({
15
- name: basename(f, extname(f)),
16
- content: readFileSync(join(dir, f), 'utf8'),
17
- path: join(dir, f),
18
- source,
19
- }));
35
+ let entries;
36
+ try {
37
+ entries = readdirSync(dir, { withFileTypes: true });
38
+ }
39
+ catch (err) {
40
+ const msg = err instanceof Error ? err.message : String(err);
41
+ diag('loader_dir_unreadable', { error_class: classifyError(err) }, sanitizeForTerminal(`promptargs: cannot read ${dir}: ${msg}`));
42
+ return [];
43
+ }
44
+ // Symlinked templates must resolve to a file inside this .prompts dir; a
45
+ // cloned repo must not be able to make `promptargs x` read ~/.ssh/id_rsa.
46
+ let realDir;
47
+ try {
48
+ realDir = realpathSync(dir);
49
+ }
50
+ catch (err) {
51
+ const msg = err instanceof Error ? err.message : String(err);
52
+ diag('loader_dir_unreadable', { error_class: classifyError(err) }, sanitizeForTerminal(`promptargs: cannot resolve ${dir}: ${msg}`));
53
+ return [];
54
+ }
55
+ const realDirPrefix = realDir.endsWith(sep) ? realDir : realDir + sep;
56
+ const templates = [];
57
+ for (const entry of entries) {
58
+ const f = entry.name;
59
+ if (!f.endsWith('.md'))
60
+ continue;
61
+ const path = join(dir, f);
62
+ const isLink = entry.isSymbolicLink();
63
+ try {
64
+ const isFile = isLink ? statSync(path).isFile() : entry.isFile();
65
+ if (!isFile)
66
+ continue;
67
+ }
68
+ catch {
69
+ continue; // dangling symlink
70
+ }
71
+ const template = { name: basename(f, extname(f)), content: '', path, source };
72
+ try {
73
+ if (isLink) {
74
+ const target = realpathSync(path);
75
+ if (!target.startsWith(realDirPrefix)) {
76
+ template.error = `symlink target ${target} is outside ${dir}; templates must stay inside the .prompts directory`;
77
+ templates.push(template);
78
+ continue;
79
+ }
80
+ }
81
+ template.content = readFileSync(path, 'utf8');
82
+ }
83
+ catch (err) {
84
+ template.error = err instanceof Error ? err.message : String(err);
85
+ }
86
+ templates.push(template);
87
+ }
88
+ return templates;
20
89
  }
21
90
  export function loadTemplates(cwd) {
22
91
  const projectDir = join(cwd || process.cwd(), PROJECT_DIR);
@@ -31,6 +100,10 @@ export function loadTemplates(cwd) {
31
100
  return Array.from(byName.values());
32
101
  }
33
102
  export function findTemplate(name, cwd) {
34
- return loadTemplates(cwd).find(t => t.name === name);
103
+ const tpl = loadTemplates(cwd).find(t => t.name === name);
104
+ if (tpl?.error) {
105
+ throw new UsageError(`Template "${tpl.name}" at ${tpl.path} could not be read: ${tpl.error}`);
106
+ }
107
+ return tpl;
35
108
  }
36
109
  //# sourceMappingURL=loader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,WAAW,GAAG,UAAU,CAAC;AAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAS7C,SAAS,WAAW,CAAC,GAAW,EAAE,MAA0B;IAC1D,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhC,OAAO,WAAW,CAAC,GAAG,CAAC;SACpB,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SACxC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC;QACnB,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7B,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAC3C,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAClB,MAAM;KACP,CAAC,CAAC,CAAC;AACR,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;IAC3D,MAAM,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAC5D,MAAM,aAAa,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEpD,2DAA2D;IAC3D,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;IACjD,KAAK,MAAM,CAAC,IAAI,aAAa;QAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,gBAAgB;QAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAExD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,GAAY;IACrD,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnG,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,MAAM,WAAW,GAAG,UAAU,CAAC;AAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAW7C,SAAS,WAAW,CAAC,GAAW,EAAE,MAA0B;IAC1D,6EAA6E;IAC7E,yEAAyE;IACzE,2EAA2E;IAC3E,wEAAwE;IACxE,8EAA8E;IAC9E,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC;gBACpC,IAAI,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,mBAAmB,CAAC,eAAe,GAAG,wEAAwE,CAAC,CAAC,CAAC;gBACnK,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,EAAE,CAAC;YAChE,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,IAAI,CAAC,uBAAuB,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,mBAAmB,CAAC,2BAA2B,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC;YAClI,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhC,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,CAAC,uBAAuB,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,mBAAmB,CAAC,2BAA2B,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC;QAClI,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,yEAAyE;IACzE,0EAA0E;IAC1E,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,CAAC,uBAAuB,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,mBAAmB,CAAC,8BAA8B,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC;QACrI,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC;IAEtE,MAAM,SAAS,GAAqB,EAAE,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACjE,IAAI,CAAC,MAAM;gBAAE,SAAS;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,CAAC,mBAAmB;QAC/B,CAAC;QACD,MAAM,QAAQ,GAAmB,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC9F,IAAI,CAAC;YACH,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;gBAClC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;oBACtC,QAAQ,CAAC,KAAK,GAAG,kBAAkB,MAAM,eAAe,GAAG,qDAAqD,CAAC;oBACjH,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACzB,SAAS;gBACX,CAAC;YACH,CAAC;YACD,QAAQ,CAAC,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACpE,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;IAC3D,MAAM,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAC5D,MAAM,aAAa,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEpD,2DAA2D;IAC3D,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;IACjD,KAAK,MAAM,CAAC,IAAI,aAAa;QAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,gBAAgB;QAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAExD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,GAAY;IACrD,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC1D,IAAI,GAAG,EAAE,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,UAAU,CAAC,aAAa,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,uBAAuB,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
package/dist/log.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Opt-in structured diagnostics. With PROMPTARGS_LOG=json, diagnostics are
3
+ * written to stderr as one JSON object per line with a fixed, bounded field
4
+ * set. Template contents, argument values, paths and URLs are never logged.
5
+ */
6
+ export type LogEvent = 'ui_host_rejected' | 'ui_host_rejected_total' | 'ui_token_rejected' | 'ui_token_rejected_total' | 'ui_asset_error' | 'ui_request' | 'ui_start_error' | 'ui_browser_open_failed' | 'cli_iteration' | 'cli_error' | 'loader_dir_unreadable' | 'loader_dir_symlink';
7
+ export type ErrorClass = 'usage' | 'not_found' | 'io' | 'port_in_use' | 'unknown';
8
+ export interface LogFields {
9
+ status?: number | string;
10
+ duration_ms?: number;
11
+ error_class?: ErrorClass;
12
+ count?: number;
13
+ current?: number;
14
+ total?: number;
15
+ }
16
+ export declare function jsonLogEnabled(env?: NodeJS.ProcessEnv): boolean;
17
+ export declare function classifyError(err: unknown): ErrorClass;
18
+ export declare function diag(event: LogEvent, fields: LogFields, legacy?: string): void;
19
+ export declare function logRequest(status: number, startedAt: bigint): void;
package/dist/log.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Opt-in structured diagnostics. With PROMPTARGS_LOG=json, diagnostics are
3
+ * written to stderr as one JSON object per line with a fixed, bounded field
4
+ * set. Template contents, argument values, paths and URLs are never logged.
5
+ */
6
+ export function jsonLogEnabled(env = process.env) {
7
+ return env.PROMPTARGS_LOG === 'json';
8
+ }
9
+ export function classifyError(err) {
10
+ const code = err?.code;
11
+ if (code === 'ENOENT')
12
+ return 'not_found';
13
+ if (code === 'EADDRINUSE')
14
+ return 'port_in_use';
15
+ if (typeof code === 'string' && code.startsWith('E'))
16
+ return 'io';
17
+ if (err?.name === 'UsageError')
18
+ return 'usage';
19
+ return 'unknown';
20
+ }
21
+ // Writes a JSON line when enabled; otherwise prints the legacy text fallback
22
+ // (when given) so default output stays byte-for-byte unchanged.
23
+ export function diag(event, fields, legacy) {
24
+ if (!jsonLogEnabled()) {
25
+ if (legacy !== undefined)
26
+ console.error(legacy);
27
+ return;
28
+ }
29
+ const line = { event };
30
+ for (const key of ['status', 'duration_ms', 'error_class', 'count', 'current', 'total']) {
31
+ if (fields[key] !== undefined)
32
+ line[key] = fields[key];
33
+ }
34
+ console.error(JSON.stringify(line));
35
+ }
36
+ // Request logging has no legacy output, so it is silent unless enabled.
37
+ export function logRequest(status, startedAt) {
38
+ const duration_ms = Number((process.hrtime.bigint() - startedAt) / 1000n) / 1000;
39
+ diag('ui_request', { status, duration_ms });
40
+ }
41
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2BH,MAAM,UAAU,cAAc,CAAC,MAAyB,OAAO,CAAC,GAAG;IACjE,OAAO,GAAG,CAAC,cAAc,KAAK,MAAM,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,MAAM,IAAI,GAAI,GAAyC,EAAE,IAAI,CAAC;IAC9D,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,WAAW,CAAC;IAC1C,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,aAAa,CAAC;IAChD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,IAAK,GAAyB,EAAE,IAAI,KAAK,YAAY;QAAE,OAAO,OAAO,CAAC;IACtE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,6EAA6E;AAC7E,gEAAgE;AAChE,MAAM,UAAU,IAAI,CAAC,KAAe,EAAE,MAAiB,EAAE,MAAe;IACtE,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;QACtB,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IACD,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,CAAC;IAChD,KAAK,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAU,EAAE,CAAC;QACjG,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,SAAiB;IAC1D,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC;IACjF,IAAI,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;AAC9C,CAAC"}
package/dist/parser.js CHANGED
@@ -3,6 +3,13 @@
3
3
  * Uses Mustache for expansion, with a promptargs extension for defaults.
4
4
  */
5
5
  import Mustache from 'mustache';
6
+ // Kept local (not imported from flags.ts) because ui.html loads parser.js in the browser,
7
+ // where only parser.js/iterate.js/mustache.mjs are served (see STATIC_JS_ROUTES in ui.ts).
8
+ function usageError(message) {
9
+ const e = new Error(message);
10
+ e.name = 'UsageError';
11
+ return e;
12
+ }
6
13
  // Exported so any code that needs to recognize the same {{var}} / {{var=default}}
7
14
  // grammar (e.g. CLI syntax highlighting) reuses this single definition instead
8
15
  // of re-declaring the pattern and risking drift.
@@ -12,16 +19,38 @@ import Mustache from 'mustache';
12
19
  // recognize would still be handed to Mustache as a variable, which renders it
13
20
  // as an empty string — the blank silently vanished instead of being asked for,
14
21
  // filled from --flags, highlighted by `show`, or preserved as {{name}}.
15
- // Trailing padding after a default is not part of the default.
16
- export const VAR_PATTERN = /\{\{\s*(\w+)(?:=([^}]*?))?\s*\}\}/g;
22
+ // Padding around the = and trailing padding after a default are not part of
23
+ // the default ({{ name = value }} has the default "value").
24
+ // Ampersand tags ({{&name}}) are Mustache's unescaped-variable alias and are
25
+ // the same blank as {{name}}.
26
+ export const VAR_PATTERN = /\{\{\s*(?:&\s*)?([\w-]+)(?:\s*=\s*([^}]*?))?\s*\}\}/g;
27
+ // Dotted names ({{repo.owner}}) are Mustache context paths, which promptargs
28
+ // never fills; they would silently render empty, so they are rejected.
29
+ // The lookbehind skips triple-mustache tags; sigil tags ({{#x}}, {{!c}}) do
30
+ // not start with a name character and never match.
31
+ const DOTTED_PATTERN = /(?<!\{)\{\{\s*(?:&\s*)?([\w-]+\.[\w.-]*)\s*(?:=[^}]*)?\}\}/;
17
32
  export function parseVars(template) {
18
- const seen = new Set();
19
33
  const vars = [];
34
+ // The first offending tag aborts; the message is built from the name only
35
+ // (restricted to [\w.-]) so raw template bytes never reach the terminal.
36
+ const dotted = DOTTED_PATTERN.exec(template);
37
+ if (dotted) {
38
+ const name = dotted[1];
39
+ throw usageError(`Unsupported variable name "${name}": dotted names are not supported; use {{${name.replace(/\./g, '_')}}}`);
40
+ }
20
41
  for (const match of template.matchAll(VAR_PATTERN)) {
21
42
  const name = match[1];
22
- if (seen.has(name))
43
+ const existing = vars.find((v) => v.name === name);
44
+ if (existing) {
45
+ const dflt = match[2];
46
+ if (dflt === undefined)
47
+ continue;
48
+ // First default wins; later occurrences may restate it (e.g. a code
49
+ // fence using a different casing) without being an error.
50
+ if (existing.defaultValue === undefined)
51
+ existing.defaultValue = dflt;
23
52
  continue;
24
- seen.add(name);
53
+ }
25
54
  vars.push({
26
55
  name,
27
56
  defaultValue: match[2],
@@ -32,18 +61,19 @@ export function parseVars(template) {
32
61
  }
33
62
  export function expand(template, values) {
34
63
  const vars = parseVars(template);
35
- const view = { ...values };
64
+ const view = Object.assign(Object.create(null), values);
36
65
  for (const v of vars) {
37
- if (!(v.name in view) && v.defaultValue !== undefined) {
66
+ if (!Object.hasOwn(view, v.name) && v.defaultValue !== undefined) {
38
67
  view[v.name] = v.defaultValue;
39
68
  }
40
69
  // Preserve unfilled vars as {{name}} in output
41
- if (!(v.name in view)) {
70
+ if (!Object.hasOwn(view, v.name)) {
42
71
  view[v.name] = `{{${v.name}}}`;
43
72
  }
44
73
  }
45
74
  // Convert {{var=default}} to {{var}} so Mustache can handle it
46
- const normalized = template.replace(VAR_PATTERN, (_match, name) => `{{${name}}}`);
75
+ // The & sigil is kept so Mustache still sees an unescaped variable tag.
76
+ const normalized = template.replace(VAR_PATTERN, (match, name) => /^\{\{\s*&/.test(match) ? `{{&${name}}}` : `{{${name}}}`);
47
77
  // Disable HTML escaping for this render only — we want raw text output.
48
78
  // Passed via the per-call config (4th arg) rather than assigning to the
49
79
  // module-level Mustache.escape, which would permanently disable escaping
@@ -1 +1 @@
1
- {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,QAAQ,MAAM,UAAU,CAAC;AAQhC,kFAAkF;AAClF,+EAA+E;AAC/E,iDAAiD;AACjD,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,wEAAwE;AACxE,+DAA+D;AAC/D,MAAM,CAAC,MAAM,WAAW,GAAG,oCAAoC,CAAC;AAEhE,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,IAAI,GAAkB,EAAE,CAAC;IAE/B,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAC7B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,CAAC;YACR,IAAI;YACJ,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC;YACtB,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;SACd,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,QAAgB,EAAE,MAA8B;IACrE,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,IAAI,GAA2B,EAAE,GAAG,MAAM,EAAE,CAAC;IAEnD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACtD,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC;QAChC,CAAC;QACD,+CAA+C;QAC/C,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC;QACjC,CAAC;IACH,CAAC;IAED,+DAA+D;IAC/D,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;IAE1F,wEAAwE;IACxE,wEAAwE;IACxE,yEAAyE;IACzE,4EAA4E;IAC5E,OAAO,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC1F,CAAC"}
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * Resolve variable values: flags → auto-detect → defaults → ask.
3
- * Handles array expansion (comma-separated, globs, @file, stdin).
3
+ * Handles array expansion (comma-separated, globs, @file).
4
4
  */
5
5
  import type { TemplateVar } from './parser.js';
6
6
  export interface ResolvedValues {
7
7
  values: Record<string, string>;
8
8
  iterations: Record<string, string>[];
9
+ /** Names whose value was filled from the template default. */
10
+ defaulted: Set<string>;
9
11
  }
10
12
  export declare function resolve(vars: TemplateVar[], flags: Record<string, string>, interactive: boolean, cross?: boolean): Promise<ResolvedValues>;
package/dist/resolver.js CHANGED
@@ -1,36 +1,51 @@
1
1
  /**
2
2
  * Resolve variable values: flags → auto-detect → defaults → ask.
3
- * Handles array expansion (comma-separated, globs, @file, stdin).
3
+ * Handles array expansion (comma-separated, globs, @file).
4
4
  */
5
5
  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 expandArrayValue(raw) {
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 (raw.includes('*') || raw.includes('?')) {
24
- const files = expandGlob(raw);
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
- // Comma-separated
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
+ // A bare '-' is a literal value, not stdin.
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 [raw];
48
+ return expandPiece(raw);
34
49
  }
35
50
  function segmentToRegExp(segment) {
36
51
  const escaped = segment
@@ -39,13 +54,54 @@ function segmentToRegExp(segment) {
39
54
  .replace(/\?/g, '.');
40
55
  return new RegExp(`^${escaped}$`);
41
56
  }
57
+ function descendantDirs(base) {
58
+ const out = [];
59
+ let entries;
60
+ try {
61
+ entries = readdirSync(base === '' ? '.' : base, { withFileTypes: true });
62
+ }
63
+ catch {
64
+ return out;
65
+ }
66
+ for (const entry of entries) {
67
+ if (entry.name.startsWith('.') || !entry.isDirectory())
68
+ continue;
69
+ const p = base === '' ? entry.name : join(base, entry.name);
70
+ out.push(p, ...descendantDirs(p));
71
+ }
72
+ return out;
73
+ }
74
+ function filesIn(base) {
75
+ try {
76
+ return readdirSync(base === '' ? '.' : base, { withFileTypes: true })
77
+ .filter(e => !e.name.startsWith('.') && !e.isDirectory())
78
+ .map(e => (base === '' ? e.name : join(base, e.name)));
79
+ }
80
+ catch {
81
+ return [];
82
+ }
83
+ }
42
84
  function expandGlob(pattern) {
43
85
  const absolute = pattern.startsWith('/');
44
86
  const segments = pattern.split('/').filter(Boolean);
45
87
  let bases = [absolute ? '/' : ''];
46
- for (const segment of segments) {
88
+ for (let i = 0; i < segments.length; i++) {
89
+ const segment = segments[i];
47
90
  const next = [];
48
- if (!segment.includes('*') && !segment.includes('?')) {
91
+ if (segment === '**') {
92
+ // Consecutive ** segments behave as one
93
+ if (segments[i + 1] === '**')
94
+ continue;
95
+ const trailing = i === segments.length - 1;
96
+ for (const base of bases) {
97
+ const dirs = [base, ...descendantDirs(base)];
98
+ next.push(...dirs);
99
+ if (trailing)
100
+ for (const d of dirs)
101
+ next.push(...filesIn(d));
102
+ }
103
+ }
104
+ else if (!segment.includes('*') && !segment.includes('?')) {
49
105
  for (const base of bases) {
50
106
  const p = base === '' ? segment : join(base, segment);
51
107
  if (existsSync(p))
@@ -75,24 +131,27 @@ function expandGlob(pattern) {
75
131
  if (bases.length === 0)
76
132
  break;
77
133
  }
78
- return bases.sort();
134
+ return [...new Set(bases)].sort();
79
135
  }
80
136
  export async function resolve(vars, flags, interactive, cross = false) {
81
- const values = {};
82
- const arrayVars = {};
137
+ const values = Object.create(null);
138
+ const arrayVars = Object.create(null);
139
+ const defaulted = new Set();
83
140
  let hasArrays = false;
84
141
  for (const v of vars) {
85
142
  // 1. Check flags
86
- if (v.name in flags) {
87
- const expanded = expandArrayValue(flags[v.name]);
143
+ if (Object.hasOwn(flags, v.name)) {
144
+ const expanded = expandArrayValue(flags[v.name], v.name);
88
145
  if (expanded.length > 1) {
89
146
  arrayVars[v.name] = expanded;
90
147
  hasArrays = true;
148
+ continue;
91
149
  }
92
- else {
150
+ // An empty expansion falls through as if the flag were absent
151
+ if (expanded.length === 1) {
93
152
  values[v.name] = expanded[0];
153
+ continue;
94
154
  }
95
- continue;
96
155
  }
97
156
  // 2. Auto-detect
98
157
  const auto = autodetect(v.name);
@@ -103,42 +162,54 @@ export async function resolve(vars, flags, interactive, cross = false) {
103
162
  // 3. Default
104
163
  if (v.defaultValue !== undefined) {
105
164
  values[v.name] = v.defaultValue;
165
+ defaulted.add(v.name);
106
166
  continue;
107
167
  }
108
168
  // 4. Ask interactively
109
169
  if (interactive) {
110
- const answer = await ask(` ${v.name}: `);
111
- const expanded = expandArrayValue(answer);
170
+ const answer = await ask(` ${v.name}: `, v.name);
171
+ const expanded = expandArrayValue(answer, v.name);
112
172
  if (expanded.length > 1) {
113
173
  arrayVars[v.name] = expanded;
114
174
  hasArrays = true;
115
175
  }
116
176
  else {
117
- values[v.name] = expanded[0];
177
+ values[v.name] = expanded[0] ?? '';
118
178
  }
119
179
  }
120
180
  }
121
181
  // Build iterations
122
182
  if (!hasArrays) {
123
- return { values, iterations: [values] };
183
+ return { values, iterations: [values], defaulted };
124
184
  }
125
185
  const arrayNames = Object.keys(arrayVars);
126
186
  const iterations = [];
127
187
  const arrays = arrayNames.map(n => arrayVars[n]);
128
188
  const combos = cross ? cartesian(arrays) : zip(arrays);
129
189
  for (const combo of combos) {
130
- const iter = { ...values };
190
+ const iter = Object.assign(Object.create(null), values);
131
191
  for (let j = 0; j < arrayNames.length; j++) {
132
192
  iter[arrayNames[j]] = combo[j];
133
193
  }
134
194
  iterations.push(iter);
135
195
  }
136
- return { values, iterations };
196
+ return { values, iterations, defaulted };
137
197
  }
138
- function ask(prompt) {
198
+ function ask(prompt, name) {
139
199
  const rl = createInterface({ input: process.stdin, output: process.stderr });
140
- return new Promise(resolve => {
200
+ return new Promise((resolve, reject) => {
201
+ let settled = false;
202
+ // Fires on stdin EOF before an answer; without it the Promise never settles.
203
+ rl.on('close', () => {
204
+ if (settled)
205
+ return;
206
+ settled = true;
207
+ reject(new UsageError(`Variable "${name}" has no value and stdin is closed; pass --${name}=<value> or give the blank a default`));
208
+ });
141
209
  rl.question(prompt, (answer) => {
210
+ if (settled)
211
+ return;
212
+ settled = true;
142
213
  rl.close();
143
214
  resolve(answer.trim());
144
215
  });
@@ -1 +1 @@
1
- {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
package/dist/status.d.ts CHANGED
@@ -6,4 +6,4 @@ import type { TemplateVar } from './parser.js';
6
6
  export declare function renderStatus(templateName: string, vars: TemplateVar[], values: Record<string, string>, iteration?: {
7
7
  current: number;
8
8
  total: number;
9
- }): string;
9
+ }, defaulted?: ReadonlySet<string>): string;
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 source = v.defaultValue === val ? '(default)' : '';
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 in values);
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);
@@ -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;IAE9C,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,KAAK,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,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,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC;IACpD,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"}
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.d.ts CHANGED
@@ -10,4 +10,7 @@ export interface StartUIOptions {
10
10
  openBrowser?: boolean;
11
11
  }
12
12
  export declare function buildUIHtml(rawHtml: string, envVars: EnvData): string;
13
+ export declare const UI_TOKEN_PARAM = "t";
14
+ export declare const PAGE_HEADERS: Readonly<Record<string, string>>;
15
+ export declare function requestCarriesToken(url: string | undefined, token: string): boolean;
13
16
  export declare function startUI(port?: number, options?: StartUIOptions): Server;