@imdeadpool/guardex 7.0.43 → 7.1.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 (63) hide show
  1. package/README.md +26 -0
  2. package/package.json +2 -1
  3. package/skills/gx-act/SKILL.md +82 -0
  4. package/src/agents/inspect.js +17 -4
  5. package/src/agents/launch.js +10 -1
  6. package/src/agents/status.js +9 -6
  7. package/src/budget/index.js +2 -1
  8. package/src/cli/args.js +52 -2
  9. package/src/cli/commands/agents.js +364 -0
  10. package/src/cli/commands/bootstrap.js +92 -0
  11. package/src/cli/commands/branch.js +127 -0
  12. package/src/cli/commands/claude.js +674 -0
  13. package/src/cli/commands/doctor.js +268 -0
  14. package/src/cli/commands/finish.js +26 -0
  15. package/src/cli/commands/mcp.js +122 -0
  16. package/src/cli/commands/misc.js +304 -0
  17. package/src/cli/commands/pr.js +439 -0
  18. package/src/cli/commands/prompt.js +92 -0
  19. package/src/cli/commands/release.js +305 -0
  20. package/src/cli/commands/report.js +244 -0
  21. package/src/cli/commands/review.js +32 -0
  22. package/src/cli/commands/setup.js +242 -0
  23. package/src/cli/commands/status.js +338 -0
  24. package/src/cli/commands/watch.js +234 -0
  25. package/src/cli/main.js +68 -3726
  26. package/src/cli/shared/repo-env.js +161 -0
  27. package/src/cli/shared/sandbox.js +417 -0
  28. package/src/cli/shared/scaffolding.js +535 -0
  29. package/src/cli/shared/toolchain-shims.js +420 -0
  30. package/src/context.js +229 -11
  31. package/src/core/runtime.js +6 -1
  32. package/src/doctor/index.js +42 -13
  33. package/src/finish/index.js +147 -5
  34. package/src/finish/preflight.js +177 -0
  35. package/src/finish/review-gate.js +182 -0
  36. package/src/git/index.js +446 -4
  37. package/src/hooks/index.js +0 -64
  38. package/src/mcp/collect.js +370 -0
  39. package/src/mcp/server.js +157 -0
  40. package/src/output/index.js +67 -1
  41. package/src/pr-review.js +23 -0
  42. package/src/pr.js +381 -0
  43. package/src/sandbox/index.js +13 -2
  44. package/src/scaffold/agent-worktree-prep.js +213 -0
  45. package/src/scaffold/index.js +108 -10
  46. package/src/speckit/index.js +226 -0
  47. package/src/terminal/index.js +1 -76
  48. package/src/terminal/tmux.js +0 -1
  49. package/src/toolchain/index.js +20 -0
  50. package/templates/AGENTS.monorepo-apps.md +26 -0
  51. package/templates/AGENTS.multiagent-safety.md +61 -347
  52. package/templates/AGENTS.multiagent-safety.min.md +11 -0
  53. package/templates/codex/skills/gx-act/SKILL.md +82 -0
  54. package/templates/githooks/pre-commit +22 -19
  55. package/templates/scripts/agent-branch-finish.sh +8 -30
  56. package/templates/scripts/agent-branch-merge.sh +4 -1
  57. package/templates/scripts/agent-branch-start.sh +88 -3
  58. package/templates/scripts/agent-preflight.sh +31 -5
  59. package/templates/scripts/agent-worktree-prune.sh +1 -1
  60. package/templates/scripts/codex-agent.sh +0 -91
  61. package/src/agents/detect.js +0 -160
  62. package/src/cockpit/keybindings.js +0 -224
  63. package/src/cockpit/layout.js +0 -224
@@ -0,0 +1,439 @@
1
+ // `gx pr` — drive a pull request for the current worktree branch.
2
+ //
3
+ // Subcommands:
4
+ // gx pr status (alias)
5
+ // gx pr status show PR state + CI rollup
6
+ // gx pr open create draft PR if none exists (idempotent)
7
+ // gx pr sync push branch, ensure PR exists, optionally enable auto-merge
8
+ // gx pr watch poll PR state until merged / failed / timeout
9
+ // gx pr list list open PRs for the current repo
10
+ // gx pr ready promote draft -> ready for review
11
+ // gx pr review hand off to existing pr-review provider flow
12
+ //
13
+ // This is the thin glue layer; logic lives in src/pr.js.
14
+
15
+ const { TOOL_NAME, SHORT_TOOL_NAME } = require('../../context');
16
+ const prModule = require('../../pr');
17
+ const { prReview } = require('./review');
18
+
19
+ function logInfo(message) {
20
+ console.log(`[${TOOL_NAME}] ${message}`);
21
+ }
22
+
23
+ function logWarn(message) {
24
+ console.log(`[${TOOL_NAME}] ⚠️ ${message}`);
25
+ }
26
+
27
+ function logError(message) {
28
+ console.error(`[${TOOL_NAME}] ❌ ${message}`);
29
+ }
30
+
31
+ function logOk(message) {
32
+ console.log(`[${TOOL_NAME}] ✅ ${message}`);
33
+ }
34
+
35
+ function parsePrArgs(rawArgs) {
36
+ const opts = {
37
+ target: process.cwd(),
38
+ base: null,
39
+ title: null,
40
+ body: null,
41
+ draft: true,
42
+ push: true,
43
+ json: false,
44
+ autoMerge: false,
45
+ mergeStrategy: 'squash',
46
+ ready: false,
47
+ timeoutMs: 10 * 60 * 1000,
48
+ intervalMs: 5000,
49
+ headBranch: null,
50
+ };
51
+ const passthrough = [];
52
+
53
+ for (let index = 0; index < rawArgs.length; index += 1) {
54
+ const arg = rawArgs[index];
55
+ if (arg === '--target') {
56
+ opts.target = rawArgs[++index];
57
+ continue;
58
+ }
59
+ if (arg === '--branch' || arg === '--head') {
60
+ opts.headBranch = rawArgs[++index];
61
+ continue;
62
+ }
63
+ if (arg === '--base') {
64
+ opts.base = rawArgs[++index];
65
+ continue;
66
+ }
67
+ if (arg === '--title') {
68
+ opts.title = rawArgs[++index];
69
+ continue;
70
+ }
71
+ if (arg === '--body') {
72
+ opts.body = rawArgs[++index];
73
+ continue;
74
+ }
75
+ if (arg === '--no-draft') { opts.draft = false; continue; }
76
+ if (arg === '--draft') { opts.draft = true; continue; }
77
+ if (arg === '--no-push') { opts.push = false; continue; }
78
+ if (arg === '--json') { opts.json = true; continue; }
79
+ if (arg === '--auto-merge') { opts.autoMerge = true; continue; }
80
+ if (arg === '--ready') { opts.ready = true; continue; }
81
+ if (arg === '--merge-strategy') {
82
+ const next = rawArgs[++index];
83
+ if (!['squash', 'merge', 'rebase'].includes(next)) {
84
+ throw new Error(`Invalid --merge-strategy: ${next}`);
85
+ }
86
+ opts.mergeStrategy = next;
87
+ continue;
88
+ }
89
+ if (arg === '--timeout') {
90
+ const next = rawArgs[++index];
91
+ const seconds = parseFloat(next);
92
+ if (!Number.isFinite(seconds) || seconds <= 0) {
93
+ throw new Error(`Invalid --timeout: ${next}`);
94
+ }
95
+ opts.timeoutMs = Math.round(seconds * 1000);
96
+ continue;
97
+ }
98
+ if (arg === '--interval') {
99
+ const next = rawArgs[++index];
100
+ const seconds = parseFloat(next);
101
+ if (!Number.isFinite(seconds) || seconds <= 0) {
102
+ throw new Error(`Invalid --interval: ${next}`);
103
+ }
104
+ opts.intervalMs = Math.round(seconds * 1000);
105
+ continue;
106
+ }
107
+ passthrough.push(arg);
108
+ }
109
+
110
+ return { opts, passthrough };
111
+ }
112
+
113
+ function withRepoAndBranch(opts) {
114
+ const { repoRoot, branch } = prModule.resolveRepoAndBranch(opts.target);
115
+ return { repoRoot, branch: opts.headBranch || branch };
116
+ }
117
+
118
+ function renderChecksLine(checks) {
119
+ if (!checks || checks.total === 0) return 'no CI checks reported';
120
+ const parts = [];
121
+ if (checks.success) parts.push(`${checks.success} ok`);
122
+ if (checks.pending) parts.push(`${checks.pending} pending`);
123
+ if (checks.failed) parts.push(`${checks.failed} failed`);
124
+ if (checks.cancelled) parts.push(`${checks.cancelled} cancelled`);
125
+ if (checks.other) parts.push(`${checks.other} other`);
126
+ return parts.length ? parts.join(', ') : `${checks.total} checks`;
127
+ }
128
+
129
+ function emitStatusText(snapshot) {
130
+ if (!snapshot) {
131
+ console.log('no open PR for this branch');
132
+ return;
133
+ }
134
+ const draftLabel = snapshot.isDraft ? ' (draft)' : '';
135
+ console.log(`PR #${snapshot.number}${draftLabel}: ${snapshot.title}`);
136
+ console.log(` url: ${snapshot.url}`);
137
+ console.log(` head: ${snapshot.head}`);
138
+ console.log(` base: ${snapshot.base}`);
139
+ console.log(` state: ${snapshot.state} / mergeable=${snapshot.mergeable}`);
140
+ console.log(` checks: ${renderChecksLine(snapshot.checks)}`);
141
+ }
142
+
143
+ function cmdStatus(opts) {
144
+ const { repoRoot, branch } = withRepoAndBranch(opts);
145
+ const snapshot = prModule.getPullRequestStatus(repoRoot, branch);
146
+ if (opts.json) {
147
+ process.stdout.write(JSON.stringify({ repoRoot, branch, pr: snapshot }, null, 2) + '\n');
148
+ return;
149
+ }
150
+ console.log(`branch: ${branch}`);
151
+ emitStatusText(snapshot);
152
+ if (!snapshot) {
153
+ console.log(`\nNothing open for this branch. Run '${SHORT_TOOL_NAME} pr open' to create one.`);
154
+ }
155
+ }
156
+
157
+ function cmdOpen(opts) {
158
+ const { repoRoot, branch } = withRepoAndBranch(opts);
159
+ const result = prModule.openPullRequest({
160
+ repoRoot,
161
+ branch,
162
+ base: opts.base,
163
+ title: opts.title,
164
+ body: opts.body,
165
+ draft: opts.draft,
166
+ push: opts.push,
167
+ });
168
+ if (result.created) {
169
+ logOk(`Created PR #${result.pr.number} (${result.pr.url})`);
170
+ } else {
171
+ logInfo(`PR already exists: #${result.pr.number} (${result.pr.url})`);
172
+ }
173
+
174
+ if (opts.ready && result.pr.isDraft) {
175
+ const ready = prModule.markPullRequestReady(repoRoot, result.pr.number);
176
+ if (ready.ok) logOk('Marked PR ready for review.');
177
+ else logWarn(`gh pr ready failed: ${ready.output}`);
178
+ }
179
+
180
+ if (opts.autoMerge) {
181
+ const am = prModule.enableAutoMerge(repoRoot, result.pr.number, {
182
+ strategy: opts.mergeStrategy,
183
+ });
184
+ if (am.ok) logOk(`Auto-merge enabled (${opts.mergeStrategy}).`);
185
+ else logWarn(`gh pr merge --auto failed: ${am.output}`);
186
+ }
187
+
188
+ if (opts.json) {
189
+ process.stdout.write(JSON.stringify({ repoRoot, branch, ...result }, null, 2) + '\n');
190
+ }
191
+ }
192
+
193
+ function cmdSync(opts) {
194
+ const { repoRoot, branch } = withRepoAndBranch(opts);
195
+ const push = prModule.pushBranch(repoRoot, branch);
196
+ if (!push.ok) {
197
+ logError(`git push failed:\n${push.output}`);
198
+ process.exitCode = 1;
199
+ return;
200
+ }
201
+ logOk(`Pushed ${branch} -> origin/${branch}`);
202
+
203
+ let pr = prModule.findOpenPrForBranch(repoRoot, branch);
204
+ if (!pr) {
205
+ logInfo('No open PR yet; opening one.');
206
+ const opened = prModule.openPullRequest({
207
+ repoRoot,
208
+ branch,
209
+ base: opts.base,
210
+ title: opts.title,
211
+ body: opts.body,
212
+ draft: opts.draft,
213
+ push: false, // already pushed
214
+ });
215
+ pr = opened.pr;
216
+ if (opened.created) {
217
+ logOk(`Created PR #${pr.number} (${pr.url})`);
218
+ }
219
+ } else {
220
+ logInfo(`PR #${pr.number} already open (${pr.url})`);
221
+ }
222
+
223
+ if (opts.ready && pr.isDraft) {
224
+ const ready = prModule.markPullRequestReady(repoRoot, pr.number);
225
+ if (ready.ok) logOk('Marked PR ready for review.');
226
+ else logWarn(`gh pr ready failed: ${ready.output}`);
227
+ }
228
+ if (opts.autoMerge) {
229
+ const am = prModule.enableAutoMerge(repoRoot, pr.number, {
230
+ strategy: opts.mergeStrategy,
231
+ });
232
+ if (am.ok) logOk(`Auto-merge enabled (${opts.mergeStrategy}).`);
233
+ else logWarn(`gh pr merge --auto failed: ${am.output}`);
234
+ }
235
+
236
+ if (opts.json) {
237
+ process.stdout.write(JSON.stringify({ repoRoot, branch, pr }, null, 2) + '\n');
238
+ }
239
+ }
240
+
241
+ async function cmdWatch(opts) {
242
+ const { repoRoot, branch } = withRepoAndBranch(opts);
243
+ let lastChecks = '';
244
+
245
+ const result = await prModule.watchPullRequest({
246
+ repoRoot,
247
+ branch,
248
+ intervalMs: opts.intervalMs,
249
+ timeoutMs: opts.timeoutMs,
250
+ onEvent: (event) => {
251
+ if (opts.json) return;
252
+ if (event.phase === 'polling' && event.pr) {
253
+ const checks = renderChecksLine(event.pr.checks);
254
+ if (checks !== lastChecks) {
255
+ logInfo(`PR #${event.pr.number}: ${checks} (mergeable=${event.pr.mergeable})`);
256
+ lastChecks = checks;
257
+ }
258
+ } else if (event.phase === 'merged') {
259
+ logOk(`PR #${event.pr.number} merged.`);
260
+ } else if (event.phase === 'closed') {
261
+ logWarn(`PR #${event.pr.number} closed without merge.`);
262
+ } else if (event.phase === 'no-pr') {
263
+ logWarn('No PR found for this branch.');
264
+ } else if (event.phase === 'ready') {
265
+ logOk('PR is mergeable + CI green.');
266
+ }
267
+ },
268
+ });
269
+
270
+ if (opts.json) {
271
+ process.stdout.write(JSON.stringify({ repoRoot, branch, ...result }, null, 2) + '\n');
272
+ return;
273
+ }
274
+
275
+ if (result.status === 'merged') return;
276
+ if (result.status === 'checks-failed') {
277
+ process.exitCode = 2;
278
+ logError('CI checks failed. Investigate the PR before retrying.');
279
+ return;
280
+ }
281
+ if (result.status === 'timeout') {
282
+ process.exitCode = 3;
283
+ logWarn('Timed out waiting for PR to merge.');
284
+ return;
285
+ }
286
+ if (result.status === 'closed') {
287
+ process.exitCode = 4;
288
+ return;
289
+ }
290
+ if (result.status === 'no-pr') {
291
+ process.exitCode = 5;
292
+ return;
293
+ }
294
+ }
295
+
296
+ function cmdList(opts) {
297
+ const repoRoot = prModule.resolveRepoAndBranch(opts.target).repoRoot;
298
+ // Use gh directly for the list since prModule keeps single-branch focus.
299
+ const { GH_BIN } = require('../../context');
300
+ const { run } = require('../../core/runtime');
301
+ const ghResult = run(GH_BIN, [
302
+ 'pr', 'list',
303
+ '--state', 'open',
304
+ '--limit', '50',
305
+ '--json', 'number,title,url,isDraft,headRefName,baseRefName,author',
306
+ ], { cwd: repoRoot, allowFailure: true });
307
+ if (ghResult.status !== 0) {
308
+ logError(`gh pr list failed: ${(ghResult.stderr || ghResult.stdout || '').trim()}`);
309
+ process.exitCode = 1;
310
+ return;
311
+ }
312
+ let parsed = [];
313
+ try {
314
+ parsed = JSON.parse(ghResult.stdout || '[]');
315
+ } catch (error) {
316
+ logError(`gh pr list returned unparseable JSON: ${error.message}`);
317
+ process.exitCode = 1;
318
+ return;
319
+ }
320
+ if (opts.json) {
321
+ process.stdout.write(JSON.stringify({ repoRoot, prs: parsed }, null, 2) + '\n');
322
+ return;
323
+ }
324
+ if (parsed.length === 0) {
325
+ console.log('no open pull requests');
326
+ return;
327
+ }
328
+ for (const item of parsed) {
329
+ const draft = item.isDraft ? ' [draft]' : '';
330
+ const author = item.author && item.author.login ? `@${item.author.login}` : '';
331
+ console.log(`#${item.number}${draft} ${item.title}`);
332
+ console.log(` ${item.headRefName} -> ${item.baseRefName} ${author}`);
333
+ console.log(` ${item.url}`);
334
+ }
335
+ }
336
+
337
+ function cmdReady(opts) {
338
+ const { repoRoot, branch } = withRepoAndBranch(opts);
339
+ const pr = prModule.findOpenPrForBranch(repoRoot, branch);
340
+ if (!pr) {
341
+ logError(`No open PR found for ${branch}.`);
342
+ process.exitCode = 1;
343
+ return;
344
+ }
345
+ if (!pr.isDraft) {
346
+ logInfo(`PR #${pr.number} is already non-draft.`);
347
+ return;
348
+ }
349
+ const ready = prModule.markPullRequestReady(repoRoot, pr.number);
350
+ if (ready.ok) logOk(`PR #${pr.number} marked ready for review.`);
351
+ else {
352
+ logError(`gh pr ready failed: ${ready.output}`);
353
+ process.exitCode = 1;
354
+ }
355
+ }
356
+
357
+ function printUsage() {
358
+ console.log(`Usage: ${SHORT_TOOL_NAME} pr <subcommand> [flags]
359
+
360
+ Subcommands:
361
+ status Show PR state + CI rollup for current branch (default).
362
+ open Create draft PR if none exists. Idempotent.
363
+ sync Push branch, ensure PR exists, optionally enable auto-merge.
364
+ watch Poll PR state until merged / failed / timeout.
365
+ list List open PRs in this repo.
366
+ ready Promote a draft PR to ready-for-review.
367
+ review Run AI PR review (codex/claude provider).
368
+
369
+ Flags:
370
+ --target <path> Operate in a different repo directory.
371
+ --branch / --head <name> Override head branch (default: current branch).
372
+ --base <name> Target base branch (default: detected from remote HEAD).
373
+ --title <text> PR title for open/sync.
374
+ --body <text> PR body for open/sync.
375
+ --no-draft Open the PR as ready-for-review immediately.
376
+ --no-push For open: do not push before creating PR.
377
+ --ready After open/sync, promote draft -> ready.
378
+ --auto-merge After open/sync, enable auto-merge.
379
+ --merge-strategy <s> squash (default) | merge | rebase.
380
+ --timeout <secs> For watch: max wait time. Default 600.
381
+ --interval <secs> For watch: poll interval. Default 5.
382
+ --json Emit JSON instead of human-readable output.
383
+ `);
384
+ }
385
+
386
+ async function pr(rawArgs) {
387
+ const [subRaw, ...rest] = Array.isArray(rawArgs) ? rawArgs : [];
388
+ if (subRaw === '-h' || subRaw === '--help' || subRaw === 'help') {
389
+ printUsage();
390
+ return;
391
+ }
392
+
393
+ const sub = subRaw || 'status';
394
+ const { opts } = parsePrArgs(rest);
395
+
396
+ // Friendly error before any gh-dependent subcommand runs.
397
+ if (!prModule.ghAvailable()) {
398
+ logError(
399
+ "GitHub CLI (gh) not found. Install from https://cli.github.com/, then run 'gh auth login'.",
400
+ );
401
+ process.exitCode = 127;
402
+ return;
403
+ }
404
+
405
+ try {
406
+ if (sub === 'status') return cmdStatus(opts);
407
+ if (sub === 'open') return cmdOpen(opts);
408
+ if (sub === 'sync') return cmdSync(opts);
409
+ if (sub === 'watch') return await cmdWatch(opts);
410
+ if (sub === 'list') return cmdList(opts);
411
+ if (sub === 'ready') return cmdReady(opts);
412
+ if (sub === 'review') return prReview(rest);
413
+ } catch (error) {
414
+ if (error && error.code === 'gh-missing') {
415
+ logError(error.message);
416
+ process.exitCode = 127;
417
+ return;
418
+ }
419
+ if (error && error.code === 'gh-unauthenticated') {
420
+ logError(error.message);
421
+ process.exitCode = 7;
422
+ return;
423
+ }
424
+ logError(error && error.message ? error.message : String(error));
425
+ process.exitCode = 1;
426
+ return;
427
+ }
428
+
429
+ logError(`Unknown 'pr' subcommand: ${sub}`);
430
+ printUsage();
431
+ process.exitCode = 64;
432
+ }
433
+
434
+ module.exports = {
435
+ pr,
436
+ parsePrArgs,
437
+ renderChecksLine,
438
+ printUsage,
439
+ };
@@ -0,0 +1,92 @@
1
+ // `gx prompt` (+ deprecated `copy-prompt`, `copy-commands`, `print-agents-snippet`).
2
+ const {
3
+ fs,
4
+ path,
5
+ SHORT_TOOL_NAME,
6
+ TEMPLATE_ROOT,
7
+ listAiSetupPartNames,
8
+ parseAiSetupPartNames,
9
+ renderAiSetupPrompt,
10
+ AI_SETUP_PROMPT,
11
+ AI_SETUP_COMMANDS,
12
+ } = require('../../context');
13
+
14
+ function printAgentsSnippet() {
15
+ const snippetPath = path.join(TEMPLATE_ROOT, 'AGENTS.multiagent-safety.md');
16
+ process.stdout.write(fs.readFileSync(snippetPath, 'utf8'));
17
+ }
18
+
19
+ function copyPrompt() {
20
+ process.stdout.write(AI_SETUP_PROMPT);
21
+ process.exitCode = 0;
22
+ }
23
+
24
+ function copyCommands() {
25
+ process.stdout.write(AI_SETUP_COMMANDS);
26
+ process.exitCode = 0;
27
+ }
28
+
29
+ function prompt(rawArgs) {
30
+ const args = Array.isArray(rawArgs) ? rawArgs : [];
31
+ let variant = 'prompt';
32
+ let listParts = false;
33
+ const selectedParts = [];
34
+ for (let index = 0; index < args.length; index += 1) {
35
+ const arg = args[index];
36
+ if (arg === '--exec' || arg === '--commands') variant = 'exec';
37
+ else if (arg === '--snippet' || arg === '--agents') variant = 'snippet';
38
+ else if (arg === '--prompt' || arg === '--full') variant = 'prompt';
39
+ else if (arg === '--list-parts') listParts = true;
40
+ else if (arg === '--part' || arg === '--parts') {
41
+ const rawValue = args[index + 1];
42
+ if (!rawValue || rawValue.startsWith('--')) {
43
+ throw new Error(`${arg} requires a value`);
44
+ }
45
+ selectedParts.push(...parseAiSetupPartNames(rawValue));
46
+ index += 1;
47
+ } else if (arg.startsWith('--part=')) {
48
+ selectedParts.push(...parseAiSetupPartNames(arg.slice('--part='.length)));
49
+ } else if (arg.startsWith('--parts=')) {
50
+ selectedParts.push(...parseAiSetupPartNames(arg.slice('--parts='.length)));
51
+ }
52
+ else if (arg === '-h' || arg === '--help') variant = 'help';
53
+ else throw new Error(`Unknown option: ${arg}`);
54
+ }
55
+ if (variant === 'help') {
56
+ console.log(
57
+ `${SHORT_TOOL_NAME} prompt commands:\n` +
58
+ ` ${SHORT_TOOL_NAME} prompt Print AI setup checklist\n` +
59
+ ` ${SHORT_TOOL_NAME} prompt --exec Print setup commands only (shell-ready)\n` +
60
+ ` ${SHORT_TOOL_NAME} prompt --part <name> Print only the named checklist slice(s)\n` +
61
+ ` ${SHORT_TOOL_NAME} prompt --exec --part <name> Print only the named exec-capable slice(s)\n` +
62
+ ` ${SHORT_TOOL_NAME} prompt --list-parts List prompt part names\n` +
63
+ ` ${SHORT_TOOL_NAME} prompt --exec --list-parts List exec-capable prompt part names\n` +
64
+ ` ${SHORT_TOOL_NAME} prompt --snippet Print the AGENTS.md managed-block template`,
65
+ );
66
+ process.exitCode = 0;
67
+ return;
68
+ }
69
+ if (variant === 'snippet') {
70
+ if (listParts || selectedParts.length > 0) {
71
+ throw new Error('--snippet does not support --list-parts or --part');
72
+ }
73
+ return printAgentsSnippet();
74
+ }
75
+ if (listParts) {
76
+ if (selectedParts.length > 0) {
77
+ throw new Error('--list-parts does not support --part');
78
+ }
79
+ process.stdout.write(`${listAiSetupPartNames({ execOnly: variant === 'exec' }).join('\n')}\n`);
80
+ process.exitCode = 0;
81
+ return;
82
+ }
83
+ process.stdout.write(renderAiSetupPrompt({ exec: variant === 'exec', parts: selectedParts }));
84
+ process.exitCode = 0;
85
+ }
86
+
87
+ module.exports = {
88
+ prompt,
89
+ printAgentsSnippet,
90
+ copyPrompt,
91
+ copyCommands,
92
+ };