@hivecommons/promptargs 0.6.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 +139 -14
- package/dist/autodetect.d.ts +2 -0
- package/dist/autodetect.js +72 -7
- package/dist/autodetect.js.map +1 -1
- package/dist/cli.js +50 -141
- 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/iterate.d.ts +8 -0
- package/dist/iterate.js +28 -0
- package/dist/iterate.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/mustache.mjs +764 -0
- package/dist/parser.d.ts +1 -0
- package/dist/parser.js +48 -10
- package/dist/parser.js.map +1 -1
- package/dist/resolver.d.ts +2 -0
- package/dist/resolver.js +110 -66
- package/dist/resolver.js.map +1 -1
- package/dist/sanitize.d.ts +10 -0
- package/dist/sanitize.js +21 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/status.d.ts +1 -1
- package/dist/status.js +9 -5
- package/dist/status.js.map +1 -1
- package/dist/ui.d.ts +13 -1
- package/dist/ui.html +46 -60
- package/dist/ui.js +89 -21
- package/dist/ui.js.map +1 -1
- package/package.json +16 -6
- package/dist/parser.test.d.ts +0 -1
- package/dist/parser.test.js +0 -56
- package/dist/parser.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/promptargs-logo.svg" alt="Promptargs" width="120" height="120">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# promptargs 🏴☠️
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
Template arguments for AI prompts.
|
|
4
10
|
|
|
5
11
|
You write a prompt with blanks (`{{like_this}}`), and promptargs fills them in.
|
|
6
12
|
|
|
@@ -22,6 +28,8 @@ Works as a **CLI** and as a **skill** in Claude Code, Copilot, Goose, and Bob.
|
|
|
22
28
|
|
|
23
29
|
## Install
|
|
24
30
|
|
|
31
|
+
Requires Node.js 22 or newer.
|
|
32
|
+
|
|
25
33
|
### CLI
|
|
26
34
|
|
|
27
35
|
```bash
|
|
@@ -34,9 +42,29 @@ Or just run it without installing:
|
|
|
34
42
|
npx @hivecommons/promptargs help
|
|
35
43
|
```
|
|
36
44
|
|
|
37
|
-
### As
|
|
45
|
+
### As an Agent Skill
|
|
46
|
+
|
|
47
|
+
promptargs ships an [Agent Skill](https://agentskills.io/specification) at [`skills/promptargs/SKILL.md`](skills/promptargs/SKILL.md), loaded by GitHub Copilot (CLI, cloud agent, VS Code agent mode) and Claude Code.
|
|
48
|
+
|
|
49
|
+
**With the GitHub CLI** (2.90.0 or later):
|
|
50
|
+
```bash
|
|
51
|
+
gh skill install hivecommons/promptargs promptargs
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Manually** (copy the `skills/promptargs/` directory):
|
|
55
|
+
```bash
|
|
56
|
+
# Copilot
|
|
57
|
+
mkdir -p ~/.copilot/skills
|
|
58
|
+
cp -r skills/promptargs ~/.copilot/skills/
|
|
59
|
+
|
|
60
|
+
# Claude Code
|
|
61
|
+
mkdir -p ~/.claude/skills
|
|
62
|
+
cp -r skills/promptargs ~/.claude/skills/
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Use `.github/skills/` or `.claude/skills/` inside a project instead to share it with your team.
|
|
38
66
|
|
|
39
|
-
|
|
67
|
+
### As a Slash Command (other tools)
|
|
40
68
|
|
|
41
69
|
**Claude Code:**
|
|
42
70
|
```bash
|
|
@@ -59,8 +87,6 @@ curl -o ~/.bob/skills/promptargs.md \
|
|
|
59
87
|
https://raw.githubusercontent.com/hivecommons/promptargs/main/.bob/skills/promptargs.md
|
|
60
88
|
```
|
|
61
89
|
|
|
62
|
-
**Copilot:** Automatically detected from `.github/copilot-instructions.md` when you clone this repo.
|
|
63
|
-
|
|
64
90
|
---
|
|
65
91
|
|
|
66
92
|
## Quick Start (3 steps)
|
|
@@ -116,7 +142,15 @@ A blank looks like this: `{{name}}`
|
|
|
116
142
|
|
|
117
143
|
A blank with a default looks like this: `{{name=hello}}` (promptargs extension)
|
|
118
144
|
|
|
119
|
-
|
|
145
|
+
Padding inside the braces is fine too — `{{ name }}` and `{{ name=hello }}` mean the same thing.
|
|
146
|
+
|
|
147
|
+
Names may use letters, digits, `_` and `-` (`{{file-name}}`). Dotted names such as `{{repo.owner}}` are rejected with an error — use `{{repo_owner}}`; the switch names `no-interactive`, `cross`, `json` and `status` are also rejected, as they are reserved for CLI switches. Likewise, the template file names `help`, `env`, `ui`, `init`, `list` and `show` are reserved for the subcommands of the same name; such a template is listed as unreachable by `promptargs list` (and `show` warns), because the subcommand always wins.
|
|
148
|
+
|
|
149
|
+
A default may appear on any occurrence of a blank (`{{name}} … {{name=hello}}`); if two occurrences give different defaults, the first one wins.
|
|
150
|
+
|
|
151
|
+
That's the basics. Mustache comments (`{{! ignore me}}`) work as documented and are safe to use.
|
|
152
|
+
|
|
153
|
+
Mustache **sections** (`{{#flag}}...{{/flag}}`) and **partials** (`{{>name}}`) are parsed too, but aren't practically usable yet: promptargs only resolves plain `{{name}}` / `{{name=default}}` tags from `--flag=value`, auto-detected context, defaults, or interactive fill — a section's condition name is never filled this way (so its content is always dropped, or always kept for an inverted `{{^name}}` section), and partial content is never supplied, so `{{>name}}` always expands to nothing. Stick to plain blanks and comments; avoid sections and partials for now.
|
|
120
154
|
|
|
121
155
|
### Red means "you need to fill this in"
|
|
122
156
|
|
|
@@ -212,6 +246,34 @@ promptargs "Review {{file}} for {{focus}}" \
|
|
|
212
246
|
✅ [3/3]: file=db.go focus=correctness
|
|
213
247
|
```
|
|
214
248
|
|
|
249
|
+
When arrays have different lengths, the number of runs is the length of the longest array, and shorter arrays repeat (cycle around):
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
promptargs "Review {{file}} for {{focus}}" \
|
|
253
|
+
--file=api.go,auth.go,db.go \
|
|
254
|
+
--focus=security
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
✅ [1/3]: file=api.go focus=security
|
|
259
|
+
✅ [2/3]: file=auth.go focus=security
|
|
260
|
+
✅ [3/3]: file=db.go focus=security
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Or with two unequal arrays:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
promptargs "Review {{file}} for {{focus}}" \
|
|
267
|
+
--file=a.go,b.go,c.go \
|
|
268
|
+
--focus=x,y
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
✅ [1/3]: file=a.go focus=x
|
|
273
|
+
✅ [2/3]: file=b.go focus=y
|
|
274
|
+
✅ [3/3]: file=c.go focus=x
|
|
275
|
+
```
|
|
276
|
+
|
|
215
277
|
**Cross-product mode (`--cross`):** every combination of every value:
|
|
216
278
|
|
|
217
279
|
```bash
|
|
@@ -246,12 +308,20 @@ promptargs "Review {{file}} for {{focus}}" \
|
|
|
246
308
|
|
|
247
309
|
Project templates override personal ones with the same name.
|
|
248
310
|
|
|
311
|
+
Symlinked `*.md` entries are followed only when their real target is inside the same `.prompts/` directory (a sub-directory is fine); a symlink whose target escapes the directory is listed with an error and refused when run, so a cloned repo cannot make `promptargs` read files elsewhere on your machine. Symlinks to directories and dangling symlinks are skipped.
|
|
312
|
+
|
|
249
313
|
---
|
|
250
314
|
|
|
251
315
|
## Auto-Magic Variables ✨
|
|
252
316
|
|
|
253
317
|
promptargs discovers variables from two sources:
|
|
254
318
|
|
|
319
|
+
Run `promptargs env` any time to preview exactly what's auto-detected in your current shell before you run a template:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
promptargs env
|
|
323
|
+
```
|
|
324
|
+
|
|
255
325
|
### 1. Git context (always detected)
|
|
256
326
|
|
|
257
327
|
These variable names fill themselves automatically when you're in a git repo:
|
|
@@ -277,16 +347,20 @@ promptargs "Connect to {{DATABASE_URL}} in {{AWS_REGION}}"
|
|
|
277
347
|
|
|
278
348
|
In the **Builder UI** (`promptargs ui`), click "Show terminal env" to see all available env vars from your shell. Click any one to insert it at the cursor.
|
|
279
349
|
|
|
280
|
-
Common useful env vars: `NODE_ENV`, `AWS_REGION`, `
|
|
350
|
+
Common useful env vars: `NODE_ENV`, `AWS_REGION`, `CI`, `USER`, `EDITOR`, `PATH`, `SHELL`.
|
|
351
|
+
|
|
352
|
+
Credential-looking names are intentionally **excluded** from auto-detection: anything containing `TOKEN`, `SECRET`, `PASSWORD`/`PASSWD`/`PASSPHRASE`, `CREDENTIAL`, `API_KEY`/`ACCESS_KEY`/`PRIVATE_KEY`, `BEARER`, `COOKIE`, `WEBHOOK`, `JWT`, `HMAC`, `OAUTH`, `CONNECTION_STRING`, or the `_`-delimited words `AUTH`, `KEY`/`KEYS`, `PWD`, `PAT`, `PASS`, `DSN` (so `GITHUB_TOKEN`, `SIGNING_KEY`, `MYSQL_PWD`, `GITHUB_PAT` and `SLACK_WEBHOOK_URL` are all refused, while `PATH`, `PWD`, `KEYBOARD` and `AUTHOR` still work). Credential-**shaped** values are excluded whatever the name: URLs with a password in them (`postgres://user:pass@host/db`), PEM blocks, JWTs, and well-known token prefixes (`ghp_`, `github_pat_`, `glpat-`, `sk-`, `xoxb-`, `AKIA…`, `npm_…`, …). A repo-controlled template can therefore never expand `{{GITHUB_TOKEN}}` or `{{DATABASE_URL}}` into a secret, even though an explicit `--flag=value` can still pass any value you choose. This also applies to the Builder UI's "Show terminal env" list.
|
|
281
353
|
|
|
282
354
|
### Priority
|
|
283
355
|
|
|
284
356
|
You can always override any auto-detected value with a flag. The order is:
|
|
285
357
|
|
|
286
358
|
1. `--flag=value` (explicit, always wins)
|
|
287
|
-
2.
|
|
288
|
-
3.
|
|
289
|
-
4.
|
|
359
|
+
2. Auto-detect from environment (git context and terminal env vars)
|
|
360
|
+
3. Template default (`{{name=fallback}}`)
|
|
361
|
+
4. Interactive prompt — only for variables still unfilled, and only without `--no-interactive`
|
|
362
|
+
|
|
363
|
+
A variable that auto-detects or has a default is never prompted for; pass `--name=value` to override it.
|
|
290
364
|
|
|
291
365
|
---
|
|
292
366
|
|
|
@@ -343,6 +417,41 @@ promptargs ui --port=4000
|
|
|
343
417
|
|
|
344
418
|
---
|
|
345
419
|
|
|
420
|
+
## Privacy & Diagnostics
|
|
421
|
+
|
|
422
|
+
promptargs does not collect or export telemetry. There is no telemetry SDK, metrics endpoint, or observability backend configured anywhere in this package — nothing you run ever phones home.
|
|
423
|
+
|
|
424
|
+
All runtime diagnostics are human-readable console output (CLI status/errors, UI startup/port messages). The **Builder UI** (`promptargs ui`) binds to loopback only (`127.0.0.1`) and rejects requests with a non-local `Host` header, so the page — including the auto-detected Git and terminal environment values it embeds (see [Auto-Magic Variables](#auto-magic-variables-)) — is never reachable from other machines on your network.
|
|
425
|
+
|
|
426
|
+
**Opt-in structured diagnostics:** set `PROMPTARGS_LOG=json` to make diagnostics (CLI errors and iteration progress, UI Host rejections, asset failures, unreadable prompts directories, and one line per UI request) print as JSON lines on stderr with a fixed field set: `event`, plus `status`, `duration_ms`, `error_class` (`usage`, `not_found`, `io`, `port_in_use`, `unknown`), `count`, `current`, `total` where relevant. Template contents, argument values, paths and error messages are never logged. When unset, output is unchanged. Nothing is sent over the network.
|
|
427
|
+
|
|
428
|
+
If observability is ever added in the future, it will be explicit opt-in, bounded to local diagnostics, and will exclude environment values, template/prompt content, file paths, diffs, and user identifiers. No network exporter will be added unless you explicitly configure a backend yourself.
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Use as a Library
|
|
433
|
+
|
|
434
|
+
The package also exports its building blocks as an ES module (Node.js 22+). Install it first with `npm install @hivecommons/promptargs`.
|
|
435
|
+
|
|
436
|
+
```js
|
|
437
|
+
import { parseVars, expand } from '@hivecommons/promptargs';
|
|
438
|
+
|
|
439
|
+
const template = 'Review {{file}} for {{focus=correctness}} issues.';
|
|
440
|
+
|
|
441
|
+
parseVars(template);
|
|
442
|
+
// [{ name: 'file', ... }, { name: 'focus', defaultValue: 'correctness', ... }]
|
|
443
|
+
|
|
444
|
+
expand(template, { file: 'src/app.ts', focus: 'security' });
|
|
445
|
+
// 'Review src/app.ts for security issues.'
|
|
446
|
+
|
|
447
|
+
expand(template, { file: 'src/app.ts' });
|
|
448
|
+
// 'Review src/app.ts for correctness issues.' (defaults fill missing values)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Variables with no value and no default are left as `{{name}}` in the output. Other exports: `autodetect`, `autodetectAll`, `AUTODETECT_VARS`, `loadTemplates`, `findTemplate`, `resolve` and `renderStatus`.
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
346
455
|
## Write Your Own Template
|
|
347
456
|
|
|
348
457
|
Create a file in `.prompts/` with any name ending in `.md`:
|
|
@@ -379,13 +488,13 @@ promptargs review --file=src/main.ts --no-interactive | claude -p "do this revie
|
|
|
379
488
|
# Goose
|
|
380
489
|
promptargs review --file=src/main.ts --no-interactive | goose run
|
|
381
490
|
|
|
382
|
-
# Copilot
|
|
383
|
-
promptargs review --file=src/main.ts --no-interactive
|
|
491
|
+
# Copilot CLI (needs the standalone `copilot` CLI, installed and signed in)
|
|
492
|
+
copilot -p "$(promptargs review --file=src/main.ts --no-interactive)"
|
|
384
493
|
```
|
|
385
494
|
|
|
386
495
|
### As a skill inside your AI tool
|
|
387
496
|
|
|
388
|
-
If you installed the skill (see [Install](#as-
|
|
497
|
+
If you installed the skill (see [Install](#as-an-agent-skill)), use it directly inside your session:
|
|
389
498
|
|
|
390
499
|
**Claude Code:**
|
|
391
500
|
```
|
|
@@ -394,7 +503,7 @@ If you installed the skill (see [Install](#as-a-skill)), use it directly inside
|
|
|
394
503
|
|
|
395
504
|
**Goose / Bob:** The skill is automatically available after install — ask your agent to "use promptargs" or run a template.
|
|
396
505
|
|
|
397
|
-
**Copilot:**
|
|
506
|
+
**Copilot:** Installed skills load automatically; ask Copilot to use promptargs.
|
|
398
507
|
|
|
399
508
|
---
|
|
400
509
|
|
|
@@ -409,6 +518,7 @@ If you installed the skill (see [Install](#as-a-skill)), use it directly inside
|
|
|
409
518
|
| `promptargs review --file=x` | Run template with flags |
|
|
410
519
|
| `promptargs review` | Run template interactively |
|
|
411
520
|
| `promptargs "inline {{var}}"` | Use inline template |
|
|
521
|
+
| `promptargs env` | Show auto-detected variable values |
|
|
412
522
|
| `--no-interactive` | Skip questions, use defaults only |
|
|
413
523
|
| `--cross` | Cross-product mode (all combinations) |
|
|
414
524
|
| `--json` | Output as JSON |
|
|
@@ -416,8 +526,23 @@ If you installed the skill (see [Install](#as-a-skill)), use it directly inside
|
|
|
416
526
|
| `... \| claude -p "do this"` | Pipe to Claude |
|
|
417
527
|
| `... \| goose run` | Pipe to Goose |
|
|
418
528
|
|
|
529
|
+
The switch names `no-interactive`, `cross`, `json` and `status` are reserved and cannot be used as template variable names.
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## Contributing & Community
|
|
534
|
+
|
|
535
|
+
promptargs is part of [Hive Commons](https://hivecommons.dev), a family of tools for working with AI agents.
|
|
536
|
+
|
|
537
|
+
- Want to contribute? See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, checks, and pull request guidelines.
|
|
538
|
+
- Found a bug or have an idea? Open an [issue](https://github.com/hivecommons/promptargs/issues).
|
|
539
|
+
- Reporting a security vulnerability? Follow [SECURITY.md](SECURITY.md) to report it privately, not through public issues.
|
|
540
|
+
- Please follow the [Hive Commons Code of Conduct](https://github.com/hivecommons/.github/blob/main/CODE_OF_CONDUCT.md).
|
|
541
|
+
|
|
419
542
|
---
|
|
420
543
|
|
|
421
544
|
## License
|
|
422
545
|
|
|
423
546
|
Apache-2.0
|
|
547
|
+
|
|
548
|
+
Pirate flag icon: [Twemoji](https://twemoji.twitter.com/), [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
package/dist/autodetect.d.ts
CHANGED
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
* Auto-detect variable values from the current environment.
|
|
3
3
|
*/
|
|
4
4
|
export declare const AUTODETECT_VARS: string[];
|
|
5
|
+
export declare function isSensitiveEnvName(name: string): boolean;
|
|
6
|
+
export declare function isSensitiveEnvValue(value: string): boolean;
|
|
5
7
|
export declare function autodetect(varName: string): string | undefined;
|
|
6
8
|
export declare function autodetectAll(varNames: string[]): Record<string, string>;
|
package/dist/autodetect.js
CHANGED
|
@@ -2,9 +2,24 @@
|
|
|
2
2
|
* Auto-detect variable values from the current environment.
|
|
3
3
|
*/
|
|
4
4
|
import { execSync } from 'node:child_process';
|
|
5
|
+
// gh is the only network call on the UI startup path; bound it so a stalled gh
|
|
6
|
+
// (hung proxy, expired auth) cannot hang startup.
|
|
7
|
+
const GH_TIMEOUT_MS = 5000;
|
|
8
|
+
// execSync's default 1 MiB maxBuffer makes `git diff` on a large staged change
|
|
9
|
+
// throw ENOBUFS, which the catch below turns into a silent "nothing detected"
|
|
10
|
+
// (#281). Raise it so large diffs are returned rather than dropped.
|
|
11
|
+
const GIT_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
|
|
5
12
|
function git(cmd) {
|
|
6
13
|
try {
|
|
7
|
-
|
|
14
|
+
const out = execSync(`git ${cmd}`, {
|
|
15
|
+
encoding: 'utf8',
|
|
16
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
17
|
+
maxBuffer: GIT_MAX_BUFFER_BYTES,
|
|
18
|
+
}).trim();
|
|
19
|
+
// Success with empty output (detached HEAD for `branch --show-current`,
|
|
20
|
+
// clean tree for `diff`) is "nothing detected", not an empty value —
|
|
21
|
+
// otherwise it would override the template default and skip the prompt.
|
|
22
|
+
return out || undefined;
|
|
8
23
|
}
|
|
9
24
|
catch {
|
|
10
25
|
return undefined;
|
|
@@ -32,6 +47,7 @@ const DETECTORS = {
|
|
|
32
47
|
const out = execSync('gh pr view --json number --jq .number', {
|
|
33
48
|
encoding: 'utf8',
|
|
34
49
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
50
|
+
timeout: GH_TIMEOUT_MS,
|
|
35
51
|
}).trim();
|
|
36
52
|
return out || undefined;
|
|
37
53
|
}
|
|
@@ -40,15 +56,64 @@ const DETECTORS = {
|
|
|
40
56
|
}
|
|
41
57
|
},
|
|
42
58
|
user: () => git('config user.name'),
|
|
43
|
-
date: () => new Date().
|
|
59
|
+
date: () => new Date().toLocaleDateString('sv-SE'),
|
|
44
60
|
};
|
|
45
61
|
export const AUTODETECT_VARS = Object.keys(DETECTORS);
|
|
62
|
+
// Env var names that look like credentials. The implicit process.env fallback
|
|
63
|
+
// must never expand these into prompt output (templates are repo-controlled),
|
|
64
|
+
// and the builder UI must never embed them in the served page.
|
|
65
|
+
//
|
|
66
|
+
// Word-bounded alternatives use (^|_)…(_|$) so PATH, KEYBOARD, PWD (the shell
|
|
67
|
+
// cwd) and AUTHOR stay detectable while GITHUB_PAT, SIGNING_KEY, MYSQL_PWD and
|
|
68
|
+
// AUTH_HEADER do not.
|
|
69
|
+
const SENSITIVE_ENV_PATTERN = new RegExp([
|
|
70
|
+
'TOKEN', 'SECRET', 'PASSWORD', 'PASSWD', 'PASSPHRASE', 'CREDENTIAL',
|
|
71
|
+
'API_?KEY', 'ACCESS_KEY', 'PRIVATE_KEY', 'BEARER', 'COOKIE', 'WEBHOOK',
|
|
72
|
+
'JWT', 'HMAC', 'OAUTH', 'AUTHORI[SZ]ATION', 'CONN(?:ECTION)?_?STR(?:ING)?',
|
|
73
|
+
'(?:^|_)AUTH(?:_|$)', '(?:^|_)KEYS?(?:_|$)', '_PWD(?:_|$)',
|
|
74
|
+
'(?:^|_)PAT(?:_|$)', '(?:^|_)PASS(?:_|$)', '(?:^|_)DSN(?:_|$)',
|
|
75
|
+
].join('|'), 'i');
|
|
76
|
+
export function isSensitiveEnvName(name) {
|
|
77
|
+
return SENSITIVE_ENV_PATTERN.test(name);
|
|
78
|
+
}
|
|
79
|
+
// Values that are credentials regardless of what the variable is called:
|
|
80
|
+
// a URL carrying a password in its userinfo (DATABASE_URL, REDIS_URL,
|
|
81
|
+
// MONGO_URI, SENTRY_DSN), PEM blocks, JWTs, HTTP Authorization header values
|
|
82
|
+
// (Bearer/Basic), and the fixed prefixes vendors stamp on their tokens so
|
|
83
|
+
// scanners can recognise them.
|
|
84
|
+
const SENSITIVE_ENV_VALUE_PATTERN = new RegExp([
|
|
85
|
+
'^[a-z][a-z0-9+.-]*://[^/\\s:@]*:[^/\\s@]+@',
|
|
86
|
+
'-----BEGIN ',
|
|
87
|
+
'^eyJ[\\w-]+\\.eyJ[\\w-]+\\.',
|
|
88
|
+
'^(?:Bearer|Basic)\\s+\\S+',
|
|
89
|
+
'^(?:gh[pousr]_|github_pat_)[A-Za-z0-9_]{20,}',
|
|
90
|
+
'^glpat-[\\w-]{20,}',
|
|
91
|
+
'^sk-[A-Za-z0-9_-]{20,}',
|
|
92
|
+
'^sk_(?:live|test)_[A-Za-z0-9]{10,}',
|
|
93
|
+
'^xox[abprs]-[\\w-]{10,}',
|
|
94
|
+
'^AKIA[0-9A-Z]{16}$',
|
|
95
|
+
'^AIza[\\w-]{35}$',
|
|
96
|
+
'^npm_[A-Za-z0-9]{36}$',
|
|
97
|
+
'^hvs\\.[\\w-]{20,}',
|
|
98
|
+
].join('|'), 'i');
|
|
99
|
+
export function isSensitiveEnvValue(value) {
|
|
100
|
+
return SENSITIVE_ENV_VALUE_PATTERN.test(value);
|
|
101
|
+
}
|
|
46
102
|
export function autodetect(varName) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
103
|
+
// Own-property check: {{constructor}} / {{toString}} must not resolve to
|
|
104
|
+
// Object.prototype members.
|
|
105
|
+
if (Object.hasOwn(DETECTORS, varName))
|
|
106
|
+
return DETECTORS[varName]();
|
|
107
|
+
// Fall back to terminal environment variables — but never implicitly expand
|
|
108
|
+
// credential-looking names ({{GITHUB_TOKEN}} in a repo template must not
|
|
109
|
+
// exfiltrate secrets into the generated prompt) or credential-shaped values
|
|
110
|
+
// under innocuous names ({{DATABASE_URL}}). Explicit --flags still work.
|
|
111
|
+
if (isSensitiveEnvName(varName) || !Object.hasOwn(process.env, varName))
|
|
112
|
+
return undefined;
|
|
113
|
+
const value = process.env[varName];
|
|
114
|
+
if (value === undefined || isSensitiveEnvValue(value))
|
|
115
|
+
return undefined;
|
|
116
|
+
return value;
|
|
52
117
|
}
|
|
53
118
|
export function autodetectAll(varNames) {
|
|
54
119
|
const result = {};
|
package/dist/autodetect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autodetect.js","sourceRoot":"","sources":["../src/autodetect.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,SAAS,GAAG,CAAC,GAAW;IACtB,IAAI,CAAC;QACH,
|
|
1
|
+
{"version":3,"file":"autodetect.js","sourceRoot":"","sources":["../src/autodetect.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -9,14 +9,15 @@
|
|
|
9
9
|
* promptargs init # create .prompts/ with examples
|
|
10
10
|
* promptargs show <template> # show template with vars highlighted
|
|
11
11
|
*/
|
|
12
|
-
import { mkdirSync, writeFileSync, existsSync } from 'node:fs';
|
|
13
|
-
import { join } from 'node:path';
|
|
14
12
|
import { parseVars, expand } from './parser.js';
|
|
15
|
-
import { findTemplate
|
|
13
|
+
import { findTemplate } from './loader.js';
|
|
16
14
|
import { resolve } from './resolver.js';
|
|
17
15
|
import { renderStatus } from './status.js';
|
|
18
|
-
import { autodetect, AUTODETECT_VARS } from './autodetect.js';
|
|
19
16
|
import { startUI } from './ui.js';
|
|
17
|
+
import { UsageError, assertNoReservedVars, parseFlags, parsePort, SUBCOMMANDS } from './flags.js';
|
|
18
|
+
import { diag, classifyError } from './log.js';
|
|
19
|
+
import { doInit, doList, doShow, printEnv } from './commands.js';
|
|
20
|
+
import { sanitizeForTerminal } from './sanitize.js';
|
|
20
21
|
const HELP = `
|
|
21
22
|
promptargs — Template arguments for AI prompts 🏴☠️
|
|
22
23
|
|
|
@@ -33,9 +34,9 @@ Usage:
|
|
|
33
34
|
Flags:
|
|
34
35
|
--no-interactive Skip interactive prompts (use defaults/auto only)
|
|
35
36
|
--cross Cross-product mode: all combinations of array values
|
|
36
|
-
--parallel Run array iterations in parallel (print all at once)
|
|
37
37
|
--json Output as JSON instead of plain text
|
|
38
38
|
--status Print status line only (for IDE integration)
|
|
39
|
+
--var value Same as --var=value (switches above take no value)
|
|
39
40
|
|
|
40
41
|
Array values:
|
|
41
42
|
--file=a.go,b.go Comma-separated → one run per value
|
|
@@ -43,54 +44,48 @@ Array values:
|
|
|
43
44
|
--file=@list.txt File → one value per line
|
|
44
45
|
|
|
45
46
|
Iteration modes:
|
|
46
|
-
Default (zip): --file=a,b --focus=x,y → 2 runs (a+x, b+y)
|
|
47
|
+
Default (zip): --file=a,b --focus=x,y → 2 runs (a+x, b+y); shorter arrays repeat
|
|
47
48
|
Cross-product: --file=a,b --focus=x,y --cross → 4 runs (a+x, a+y, b+x, b+y)
|
|
48
49
|
|
|
49
50
|
Templates live in:
|
|
50
51
|
.prompts/ Project-level (checked into repo)
|
|
51
52
|
~/.prompts/ User-level (personal templates)
|
|
52
53
|
`;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
// The shared set supplies the runtime gate and its names supply the key union.
|
|
55
|
+
// The Record makes adding a subcommand without a handler (or vice versa) a type error.
|
|
56
|
+
const SUBCOMMAND_HANDLERS = {
|
|
57
|
+
help: () => {
|
|
58
|
+
console.log(HELP);
|
|
59
|
+
printEnv();
|
|
60
|
+
},
|
|
61
|
+
env: () => printEnv(),
|
|
62
|
+
ui: (args) => {
|
|
63
|
+
const flags = parseFlags(args);
|
|
64
|
+
startUI(parsePort(flags));
|
|
65
|
+
},
|
|
66
|
+
init: () => doInit(),
|
|
67
|
+
list: () => doList(),
|
|
68
|
+
show: (args) => doShow(args[0]),
|
|
69
|
+
};
|
|
70
|
+
function isSubcommand(value) {
|
|
71
|
+
return SUBCOMMANDS.has(value);
|
|
72
|
+
}
|
|
64
73
|
async function main() {
|
|
65
74
|
const args = process.argv.slice(2);
|
|
66
|
-
if (args.length === 0 || args[0] === '
|
|
75
|
+
if (args.length === 0 || args[0] === '--help') {
|
|
67
76
|
console.log(HELP);
|
|
68
77
|
printEnv();
|
|
69
78
|
return;
|
|
70
79
|
}
|
|
71
|
-
|
|
72
|
-
|
|
80
|
+
const command = args[0];
|
|
81
|
+
if (isSubcommand(command)) {
|
|
82
|
+
await SUBCOMMAND_HANDLERS[command](args.slice(1));
|
|
73
83
|
return;
|
|
74
84
|
}
|
|
75
|
-
if (args[0] === 'ui') {
|
|
76
|
-
const flags = parseFlags(args.slice(1));
|
|
77
|
-
const port = flags['port'] ? Number(flags['port']) : undefined;
|
|
78
|
-
startUI(port);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
if (args[0] === 'init') {
|
|
82
|
-
return doInit();
|
|
83
|
-
}
|
|
84
|
-
if (args[0] === 'list') {
|
|
85
|
-
return doList();
|
|
86
|
-
}
|
|
87
|
-
if (args[0] === 'show') {
|
|
88
|
-
return doShow(args[1]);
|
|
89
|
-
}
|
|
90
85
|
// Run a template
|
|
91
86
|
const templateName = args[0];
|
|
92
87
|
const flags = parseFlags(args.slice(1));
|
|
93
|
-
const interactive = !flags['no-interactive'];
|
|
88
|
+
const interactive = !flags['no-interactive'] && process.stdin.isTTY === true;
|
|
94
89
|
const cross = 'cross' in flags;
|
|
95
90
|
const asJson = 'json' in flags;
|
|
96
91
|
const statusOnly = 'status' in flags;
|
|
@@ -104,24 +99,31 @@ async function main() {
|
|
|
104
99
|
else {
|
|
105
100
|
const tpl = findTemplate(templateName);
|
|
106
101
|
if (!tpl) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
process.exit(1);
|
|
111
|
-
return;
|
|
102
|
+
throw new UsageError(`Template "${templateName}" not found.\n` +
|
|
103
|
+
'Run "promptargs list" to see available templates.\n' +
|
|
104
|
+
'Run "promptargs init" to create example templates.');
|
|
112
105
|
}
|
|
113
106
|
content = tpl.content;
|
|
114
107
|
name = tpl.name;
|
|
115
108
|
}
|
|
116
109
|
const vars = parseVars(content);
|
|
110
|
+
assertNoReservedVars(vars);
|
|
117
111
|
if (vars.length === 0) {
|
|
118
|
-
// No variables —
|
|
119
|
-
|
|
112
|
+
// No variables — skip expand() so Mustache-style content that is not a promptargs blank stays untouched
|
|
113
|
+
if (statusOnly) {
|
|
114
|
+
console.log(renderStatus(name, vars, {}, undefined, new Set()));
|
|
115
|
+
}
|
|
116
|
+
else if (asJson) {
|
|
117
|
+
console.log(JSON.stringify(content, null, 2));
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.log(content);
|
|
121
|
+
}
|
|
120
122
|
return;
|
|
121
123
|
}
|
|
122
|
-
const { iterations } = await resolve(vars, flags, interactive, cross);
|
|
124
|
+
const { iterations, defaulted } = await resolve(vars, flags, interactive, cross);
|
|
123
125
|
if (statusOnly) {
|
|
124
|
-
const status = renderStatus(name, vars, iterations[0]);
|
|
126
|
+
const status = renderStatus(name, vars, iterations[0], undefined, defaulted);
|
|
125
127
|
console.log(status);
|
|
126
128
|
return;
|
|
127
129
|
}
|
|
@@ -133,8 +135,8 @@ async function main() {
|
|
|
133
135
|
const status = renderStatus(name, vars, values, {
|
|
134
136
|
current: i + 1,
|
|
135
137
|
total: iterations.length,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
+
}, defaulted);
|
|
139
|
+
diag('cli_iteration', { current: i + 1, total: iterations.length }, status);
|
|
138
140
|
}
|
|
139
141
|
results.push(expanded);
|
|
140
142
|
}
|
|
@@ -145,101 +147,8 @@ async function main() {
|
|
|
145
147
|
console.log(results.join('\n---\n'));
|
|
146
148
|
}
|
|
147
149
|
}
|
|
148
|
-
function parseFlags(args) {
|
|
149
|
-
const flags = {};
|
|
150
|
-
for (const arg of args) {
|
|
151
|
-
if (arg.startsWith('--')) {
|
|
152
|
-
const eq = arg.indexOf('=');
|
|
153
|
-
if (eq > 0) {
|
|
154
|
-
flags[arg.slice(2, eq)] = arg.slice(eq + 1);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
flags[arg.slice(2)] = 'true';
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return flags;
|
|
162
|
-
}
|
|
163
|
-
function doInit() {
|
|
164
|
-
const dir = join(process.cwd(), '.prompts');
|
|
165
|
-
if (existsSync(dir)) {
|
|
166
|
-
console.log('.prompts/ already exists!');
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
mkdirSync(dir, { recursive: true });
|
|
170
|
-
writeFileSync(join(dir, 'review.md'), EXAMPLE_REVIEW);
|
|
171
|
-
writeFileSync(join(dir, 'explain.md'), EXAMPLE_EXPLAIN);
|
|
172
|
-
writeFileSync(join(dir, 'fix.md'), EXAMPLE_FIX);
|
|
173
|
-
console.log('Created .prompts/ with 3 example templates:');
|
|
174
|
-
console.log(' review.md — Code review with focus area');
|
|
175
|
-
console.log(' explain.md — Explain code simply');
|
|
176
|
-
console.log(' fix.md — Bug fix template');
|
|
177
|
-
console.log('');
|
|
178
|
-
console.log('Try it: promptargs review --file=src/main.ts');
|
|
179
|
-
}
|
|
180
|
-
function doList() {
|
|
181
|
-
const templates = loadTemplates();
|
|
182
|
-
if (templates.length === 0) {
|
|
183
|
-
console.log('No templates found.');
|
|
184
|
-
console.log('Run "promptargs init" to create example templates.');
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
console.log('Available templates:\n');
|
|
188
|
-
for (const t of templates) {
|
|
189
|
-
const vars = parseVars(t.content);
|
|
190
|
-
const varNames = vars.map(v => {
|
|
191
|
-
if (v.defaultValue !== undefined)
|
|
192
|
-
return `${v.name}=${v.defaultValue}`;
|
|
193
|
-
return v.name;
|
|
194
|
-
});
|
|
195
|
-
const source = t.source === 'user' ? ' (user)' : '';
|
|
196
|
-
console.log(` ${t.name}${source}`);
|
|
197
|
-
console.log(` vars: {{${varNames.join('}} {{')}}}`);
|
|
198
|
-
console.log('');
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
function doShow(templateName) {
|
|
202
|
-
if (!templateName) {
|
|
203
|
-
console.error('Usage: promptargs show <template>');
|
|
204
|
-
process.exit(1);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
const tpl = findTemplate(templateName);
|
|
208
|
-
if (!tpl) {
|
|
209
|
-
console.error(`Template "${templateName}" not found.`);
|
|
210
|
-
process.exit(1);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
const highlighted = tpl.content.replace(/\{\{(\w+)(?:=([^}]*))?\}\}/g, (_m, varName, defaultVal) => {
|
|
214
|
-
if (defaultVal !== undefined) {
|
|
215
|
-
return `\x1b[33m{{${varName}=${defaultVal}}}\x1b[0m`;
|
|
216
|
-
}
|
|
217
|
-
return `\x1b[31m{{${varName}}}\x1b[0m`;
|
|
218
|
-
});
|
|
219
|
-
console.log(`Template: ${tpl.name} (${tpl.path})\n`);
|
|
220
|
-
console.log(highlighted);
|
|
221
|
-
console.log('\n\x1b[31mred\x1b[0m = required \x1b[33myellow\x1b[0m = has default');
|
|
222
|
-
}
|
|
223
|
-
const DIFF_PREVIEW_MAX_CHARS = 60;
|
|
224
|
-
function printEnv() {
|
|
225
|
-
console.log('Auto-detected variables:\n');
|
|
226
|
-
for (const name of AUTODETECT_VARS) {
|
|
227
|
-
const value = autodetect(name);
|
|
228
|
-
if (value !== undefined) {
|
|
229
|
-
let display = value;
|
|
230
|
-
if (name === 'diff' && display.length > DIFF_PREVIEW_MAX_CHARS) {
|
|
231
|
-
display = display.slice(0, DIFF_PREVIEW_MAX_CHARS) + '...';
|
|
232
|
-
}
|
|
233
|
-
console.log(` \x1b[32m{{${name}}}\x1b[0m = ${display}`);
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
console.log(` \x1b[90m{{${name}}}\x1b[0m = (not detected)`);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
console.log('');
|
|
240
|
-
}
|
|
241
150
|
main().catch(err => {
|
|
242
|
-
|
|
151
|
+
diag('cli_error', { error_class: classifyError(err) }, sanitizeForTerminal(String(err.message)));
|
|
243
152
|
process.exit(1);
|
|
244
153
|
});
|
|
245
154
|
//# sourceMappingURL=cli.js.map
|