@proletariat/cli 0.3.24 → 0.3.26

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 (134) hide show
  1. package/dist/commands/action/create.js +3 -3
  2. package/dist/commands/action/index.js +2 -2
  3. package/dist/commands/action/update.js +3 -3
  4. package/dist/commands/agent/auth.js +1 -1
  5. package/dist/commands/agent/cleanup.js +6 -6
  6. package/dist/commands/agent/discover.js +1 -1
  7. package/dist/commands/agent/remove.js +4 -4
  8. package/dist/commands/autocomplete/setup.d.ts +2 -2
  9. package/dist/commands/autocomplete/setup.js +5 -5
  10. package/dist/commands/branch/create.js +31 -30
  11. package/dist/commands/category/create.js +4 -5
  12. package/dist/commands/category/delete.js +2 -3
  13. package/dist/commands/category/rename.js +2 -3
  14. package/dist/commands/claude.d.ts +2 -8
  15. package/dist/commands/claude.js +26 -26
  16. package/dist/commands/commit.d.ts +2 -8
  17. package/dist/commands/commit.js +4 -26
  18. package/dist/commands/config/index.d.ts +2 -10
  19. package/dist/commands/config/index.js +8 -34
  20. package/dist/commands/docker/index.d.ts +2 -2
  21. package/dist/commands/docker/index.js +8 -8
  22. package/dist/commands/epic/activate.js +9 -17
  23. package/dist/commands/epic/archive.js +13 -24
  24. package/dist/commands/epic/create.js +7 -6
  25. package/dist/commands/epic/delete.js +4 -5
  26. package/dist/commands/epic/move.js +28 -47
  27. package/dist/commands/epic/progress.js +10 -14
  28. package/dist/commands/epic/project.js +42 -59
  29. package/dist/commands/epic/reorder.js +25 -30
  30. package/dist/commands/epic/spec.d.ts +1 -0
  31. package/dist/commands/epic/spec.js +39 -40
  32. package/dist/commands/epic/ticket.d.ts +2 -0
  33. package/dist/commands/epic/ticket.js +63 -37
  34. package/dist/commands/feedback/index.d.ts +10 -0
  35. package/dist/commands/feedback/index.js +60 -0
  36. package/dist/commands/feedback/list.d.ts +12 -0
  37. package/dist/commands/feedback/list.js +126 -0
  38. package/dist/commands/feedback/submit.d.ts +16 -0
  39. package/dist/commands/feedback/submit.js +220 -0
  40. package/dist/commands/feedback/view.d.ts +15 -0
  41. package/dist/commands/feedback/view.js +109 -0
  42. package/dist/commands/gh/index.js +4 -0
  43. package/dist/commands/link/index.js +2 -2
  44. package/dist/commands/pmo/init.d.ts +2 -2
  45. package/dist/commands/pmo/init.js +7 -7
  46. package/dist/commands/project/spec.js +6 -6
  47. package/dist/commands/repo/create.d.ts +38 -0
  48. package/dist/commands/repo/create.js +283 -0
  49. package/dist/commands/repo/index.js +7 -0
  50. package/dist/commands/roadmap/add-project.js +9 -22
  51. package/dist/commands/roadmap/create.d.ts +0 -1
  52. package/dist/commands/roadmap/create.js +46 -40
  53. package/dist/commands/roadmap/delete.js +10 -24
  54. package/dist/commands/roadmap/generate.d.ts +1 -0
  55. package/dist/commands/roadmap/generate.js +21 -22
  56. package/dist/commands/roadmap/remove-project.js +14 -34
  57. package/dist/commands/roadmap/reorder.js +19 -26
  58. package/dist/commands/roadmap/update.js +27 -26
  59. package/dist/commands/roadmap/view.js +5 -12
  60. package/dist/commands/session/attach.d.ts +1 -8
  61. package/dist/commands/session/attach.js +93 -59
  62. package/dist/commands/session/health.d.ts +29 -0
  63. package/dist/commands/session/health.js +495 -0
  64. package/dist/commands/session/index.js +4 -0
  65. package/dist/commands/session/list.d.ts +0 -8
  66. package/dist/commands/session/list.js +130 -81
  67. package/dist/commands/spec/create.js +1 -1
  68. package/dist/commands/spec/edit.js +64 -35
  69. package/dist/commands/staff/add.d.ts +2 -2
  70. package/dist/commands/staff/add.js +15 -14
  71. package/dist/commands/staff/index.js +2 -2
  72. package/dist/commands/staff/remove.js +4 -4
  73. package/dist/commands/status/index.js +6 -7
  74. package/dist/commands/support/book.d.ts +10 -0
  75. package/dist/commands/support/book.js +54 -0
  76. package/dist/commands/support/discord.d.ts +10 -0
  77. package/dist/commands/support/discord.js +54 -0
  78. package/dist/commands/support/docs.d.ts +10 -0
  79. package/dist/commands/support/docs.js +54 -0
  80. package/dist/commands/support/index.d.ts +19 -0
  81. package/dist/commands/support/index.js +81 -0
  82. package/dist/commands/support/issues.d.ts +11 -0
  83. package/dist/commands/support/issues.js +77 -0
  84. package/dist/commands/support/logs.d.ts +18 -0
  85. package/dist/commands/support/logs.js +247 -0
  86. package/dist/commands/template/apply.js +10 -11
  87. package/dist/commands/template/create.js +18 -17
  88. package/dist/commands/template/index.d.ts +2 -2
  89. package/dist/commands/template/index.js +6 -6
  90. package/dist/commands/template/save.js +8 -7
  91. package/dist/commands/template/update.js +6 -7
  92. package/dist/commands/terminal/title.d.ts +2 -26
  93. package/dist/commands/terminal/title.js +4 -33
  94. package/dist/commands/theme/index.d.ts +2 -2
  95. package/dist/commands/theme/index.js +19 -18
  96. package/dist/commands/theme/set.d.ts +2 -2
  97. package/dist/commands/theme/set.js +5 -5
  98. package/dist/commands/ticket/create.js +52 -26
  99. package/dist/commands/ticket/delete.js +15 -13
  100. package/dist/commands/ticket/edit.js +59 -20
  101. package/dist/commands/ticket/epic.js +12 -10
  102. package/dist/commands/ticket/move.d.ts +7 -0
  103. package/dist/commands/ticket/move.js +132 -0
  104. package/dist/commands/ticket/project.js +11 -9
  105. package/dist/commands/ticket/reassign.js +23 -19
  106. package/dist/commands/ticket/spec.js +7 -5
  107. package/dist/commands/ticket/update.js +55 -53
  108. package/dist/commands/whoami.js +1 -0
  109. package/dist/commands/work/ready.js +7 -7
  110. package/dist/commands/work/revise.js +13 -11
  111. package/dist/commands/work/spawn.d.ts +1 -0
  112. package/dist/commands/work/spawn.js +225 -64
  113. package/dist/commands/work/start.d.ts +1 -0
  114. package/dist/commands/work/start.js +301 -173
  115. package/dist/hooks/init.js +4 -0
  116. package/dist/lib/execution/runners.js +21 -17
  117. package/dist/lib/execution/session-utils.d.ts +60 -0
  118. package/dist/lib/execution/session-utils.js +162 -0
  119. package/dist/lib/execution/spawner.d.ts +2 -0
  120. package/dist/lib/execution/spawner.js +42 -0
  121. package/dist/lib/flags/resolver.d.ts +2 -2
  122. package/dist/lib/flags/resolver.js +15 -0
  123. package/dist/lib/init/index.js +18 -0
  124. package/dist/lib/multiline-input.d.ts +63 -0
  125. package/dist/lib/multiline-input.js +360 -0
  126. package/dist/lib/pr/index.d.ts +4 -0
  127. package/dist/lib/pr/index.js +32 -14
  128. package/dist/lib/prompt-command.d.ts +3 -0
  129. package/dist/lib/prompt-json.d.ts +77 -6
  130. package/dist/lib/prompt-json.js +46 -0
  131. package/dist/lib/repos/git.d.ts +7 -0
  132. package/dist/lib/repos/git.js +20 -0
  133. package/oclif.manifest.json +2913 -2246
  134. package/package.json +1 -1
@@ -85,11 +85,11 @@ export default class ActionCreate extends PMOCommand {
85
85
  requiredFields: ['name (as first argument)', '--prompt'],
86
86
  },
87
87
  });
88
- // Prompt input (editor type in interactive, but input for JSON mode context)
88
+ // Prompt input (multiline for inline text input)
89
89
  resolver.addPrompt({
90
90
  flagName: 'prompt',
91
- type: 'editor',
92
- message: 'Prompt (opens editor):',
91
+ type: 'multiline',
92
+ message: 'Prompt (agent instructions):',
93
93
  default: prompt || 'Enter the prompt that will be sent to the agent...',
94
94
  when: (ctx) => !ctx.flags.prompt && ctx.flags.name !== undefined,
95
95
  validate: (value) => value.trim() ? true : 'Prompt is required',
@@ -84,7 +84,7 @@ export default class Action extends PMOCommand {
84
84
  this.log('No actions found.');
85
85
  return null;
86
86
  }
87
- const { selected } = await inquirer.prompt([{
87
+ const { selected } = await this.prompt([{
88
88
  type: 'list',
89
89
  name: 'selected',
90
90
  message,
@@ -96,7 +96,7 @@ export default class Action extends PMOCommand {
96
96
  new inquirer.Separator(),
97
97
  { name: 'Cancel', value: null },
98
98
  ],
99
- }]);
99
+ }], null);
100
100
  return selected;
101
101
  }
102
102
  }
@@ -113,11 +113,11 @@ export default class ActionUpdate extends PMOCommand {
113
113
  currentValue: existingAction.description || '',
114
114
  },
115
115
  });
116
- // Prompt input (editor)
116
+ // Prompt input (multiline)
117
117
  resolver.addPrompt({
118
118
  flagName: 'prompt',
119
- type: 'editor',
120
- message: 'Prompt (opens editor):',
119
+ type: 'multiline',
120
+ message: 'Prompt (agent instructions):',
121
121
  default: existingAction.prompt,
122
122
  when: (ctx) => ctx.flags.name !== undefined && ctx.flags.description !== undefined,
123
123
  context: {
@@ -23,7 +23,7 @@ export default class Auth extends Command {
23
23
  json: Flags.boolean({
24
24
  char: 'm',
25
25
  aliases: ['machine'],
26
- description: 'Output as JSON for AI agents/scripts',
26
+ description: 'Output status as JSON',
27
27
  default: false,
28
28
  }),
29
29
  };
@@ -178,14 +178,14 @@ export default class Cleanup extends PMOCommand {
178
178
  outputPromptAsJson(buildPromptConfig('checkbox', 'agents', selectMessage, choices), createMetadata('agent cleanup', flags));
179
179
  return;
180
180
  }
181
- const { selected } = await inquirer.prompt([
181
+ const { selected } = await this.prompt([
182
182
  {
183
183
  type: 'checkbox',
184
184
  name: 'selected',
185
185
  message: selectMessage,
186
186
  choices,
187
187
  },
188
- ]);
188
+ ], null);
189
189
  if (selected.length === 0 || selected.includes('__cancel__')) {
190
190
  this.log(colors.textMuted('Operation cancelled.'));
191
191
  return;
@@ -235,7 +235,7 @@ export default class Cleanup extends PMOCommand {
235
235
  this.log(` - ${name} ${typeLabel}`);
236
236
  }
237
237
  this.log('');
238
- const { confirm } = await inquirer.prompt([
238
+ const { confirm } = await this.prompt([
239
239
  {
240
240
  type: 'list',
241
241
  name: 'confirm',
@@ -246,7 +246,7 @@ export default class Cleanup extends PMOCommand {
246
246
  ],
247
247
  default: 0,
248
248
  },
249
- ]);
249
+ ], null);
250
250
  if (!confirm) {
251
251
  this.log(colors.textMuted('Operation cancelled.'));
252
252
  return;
@@ -311,14 +311,14 @@ export default class Cleanup extends PMOCommand {
311
311
  choices.push({ name: '⏭️ Skip this agent', value: 'skip' });
312
312
  // In interactive mode, prompt for action
313
313
  // eslint-disable-next-line no-await-in-loop -- User interaction per agent
314
- const { action } = await inquirer.prompt([
314
+ const { action } = await this.prompt([
315
315
  {
316
316
  type: 'list',
317
317
  name: 'action',
318
318
  message: `What would you like to do with ${agentName}?`,
319
319
  choices,
320
320
  },
321
- ]);
321
+ ], null);
322
322
  if (action === 'skip') {
323
323
  this.log(colors.textMuted(` Skipping ${agentName}`));
324
324
  results.push(result);
@@ -17,7 +17,7 @@ export default class Discover extends Command {
17
17
  json: Flags.boolean({
18
18
  char: 'm',
19
19
  aliases: ['machine'],
20
- description: 'Output as JSON for AI agents/scripts',
20
+ description: 'Output discovery results as JSON',
21
21
  default: false,
22
22
  }),
23
23
  };
@@ -76,7 +76,7 @@ export default class Remove extends PMOCommand {
76
76
  outputPromptAsJson(buildPromptConfig('list', 'name', selectMessage, agentChoices), createMetadata('agent remove', flags));
77
77
  return;
78
78
  }
79
- const { selected } = await inquirer.prompt([
79
+ const { selected } = await this.prompt([
80
80
  {
81
81
  type: 'list',
82
82
  name: 'selected',
@@ -87,7 +87,7 @@ export default class Remove extends PMOCommand {
87
87
  { name: '❌ ' + agentChoices[agentChoices.length - 1].name, value: agentChoices[agentChoices.length - 1].value }
88
88
  ]
89
89
  }
90
- ]);
90
+ ], null);
91
91
  if (selected === 'cancel') {
92
92
  this.log(colors.textMuted('Operation cancelled.'));
93
93
  return;
@@ -114,7 +114,7 @@ export default class Remove extends PMOCommand {
114
114
  outputPromptAsJson(buildPromptConfig('list', 'confirmed', confirmMessage, confirmChoices), createMetadata('agent remove', flags));
115
115
  return;
116
116
  }
117
- const { confirm } = await inquirer.prompt([
117
+ const { confirm } = await this.prompt([
118
118
  {
119
119
  type: 'list',
120
120
  name: 'confirm',
@@ -125,7 +125,7 @@ export default class Remove extends PMOCommand {
125
125
  ],
126
126
  default: 0 // Default to "No, cancel"
127
127
  }
128
- ]);
128
+ ], null);
129
129
  if (!confirm) {
130
130
  this.log(colors.textMuted('Removal cancelled.'));
131
131
  return;
@@ -1,5 +1,5 @@
1
- import { Command } from '@oclif/core';
2
- export default class AutocompleteSetup extends Command {
1
+ import { PromptCommand } from '../../lib/prompt-command.js';
2
+ export default class AutocompleteSetup extends PromptCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
@@ -1,13 +1,13 @@
1
- import { Command, Flags } from '@oclif/core';
1
+ import { Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import * as os from 'node:os';
5
5
  import chalk from 'chalk';
6
- import inquirer from 'inquirer';
6
+ import { PromptCommand } from '../../lib/prompt-command.js';
7
7
  import { machineOutputFlags } from '../../lib/pmo/base-command.js';
8
8
  import { isAgentMode, outputPromptAsJson, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
9
9
  const SUPPORTED_SHELLS = ['zsh', 'bash', 'powershell'];
10
- export default class AutocompleteSetup extends Command {
10
+ export default class AutocompleteSetup extends PromptCommand {
11
11
  static description = 'Auto-detect shell and set up autocomplete';
12
12
  static examples = [
13
13
  '<%= config.bin %> <%= command.id %>',
@@ -72,12 +72,12 @@ export default class AutocompleteSetup extends Command {
72
72
  // Interactive mode without --shell
73
73
  if (detectedShell === 'unknown') {
74
74
  // Shell not detected: prompt user to select
75
- const { selectedShell } = await inquirer.prompt([{
75
+ const { selectedShell } = await this.prompt([{
76
76
  type: 'list',
77
77
  name: 'selectedShell',
78
78
  message: 'Could not detect shell. Select your shell:',
79
79
  choices: SUPPORTED_SHELLS.map(s => ({ name: s, value: s })),
80
- }]);
80
+ }], null);
81
81
  this.log('');
82
82
  const shell = selectedShell;
83
83
  const { configFile, snippet } = this.getShellConfig(shell);
@@ -205,7 +205,7 @@ export default class BranchCreate extends PMOCommand {
205
205
  let createCommit = flags['empty-commit'] || autoCommit;
206
206
  if (!createCommit && !args.name && !jsonMode) {
207
207
  // Only prompt in interactive mode (non-quick, not JSON mode)
208
- const { wantCommit } = await inquirer.prompt([
208
+ const { wantCommit } = await this.prompt([
209
209
  {
210
210
  type: 'list',
211
211
  name: 'wantCommit',
@@ -216,7 +216,7 @@ export default class BranchCreate extends PMOCommand {
216
216
  ],
217
217
  default: true,
218
218
  },
219
- ]);
219
+ ], null);
220
220
  createCommit = wantCommit;
221
221
  }
222
222
  if (createCommit) {
@@ -228,14 +228,14 @@ export default class BranchCreate extends PMOCommand {
228
228
  // In autoCommit mode or JSON mode, skip the prompt
229
229
  let commitMessage = defaultCommitMessage;
230
230
  if (!autoCommit && !jsonMode) {
231
- const result = await inquirer.prompt([
231
+ const result = await this.prompt([
232
232
  {
233
233
  type: 'input',
234
234
  name: 'commitMessage',
235
235
  message: 'Enter commit message:',
236
236
  default: defaultCommitMessage,
237
237
  },
238
- ]);
238
+ ], null);
239
239
  commitMessage = result.commitMessage;
240
240
  }
241
241
  createEmptyCommit(commitMessage);
@@ -390,7 +390,7 @@ export default class BranchCreate extends PMOCommand {
390
390
  : `${t.id} - ${t.title.substring(0, 50)}${t.title.length > 50 ? '...' : ''} ${styles.muted(`[${t.status || 'todo'}]`)}`,
391
391
  value: t,
392
392
  }));
393
- const { ticket } = await inquirer.prompt([
393
+ const { ticket } = await this.prompt([
394
394
  {
395
395
  type: 'list',
396
396
  name: 'ticket',
@@ -398,7 +398,7 @@ export default class BranchCreate extends PMOCommand {
398
398
  choices: ticketChoices,
399
399
  pageSize: 15,
400
400
  },
401
- ]);
401
+ ], null);
402
402
  // Auto-generate branch name with defaults
403
403
  const type = getBranchType(ticket.category);
404
404
  const slug = toKebabCase(ticket.title).substring(0, 20).replace(/-+$/, '');
@@ -423,7 +423,7 @@ export default class BranchCreate extends PMOCommand {
423
423
  : `${t.id} - ${t.title.substring(0, 50)}${t.title.length > 50 ? '...' : ''} ${styles.muted(`[${t.status || 'todo'}]`)}`,
424
424
  value: t,
425
425
  }));
426
- const { ticket } = await inquirer.prompt([
426
+ const { ticket } = await this.prompt([
427
427
  {
428
428
  type: 'list',
429
429
  name: 'ticket',
@@ -431,9 +431,9 @@ export default class BranchCreate extends PMOCommand {
431
431
  choices: ticketChoices,
432
432
  pageSize: 15,
433
433
  },
434
- ]);
434
+ ], null);
435
435
  // Get owner (defaults to GitHub username)
436
- const { owner } = await inquirer.prompt([
436
+ const { owner } = await this.prompt([
437
437
  {
438
438
  type: 'input',
439
439
  name: 'owner',
@@ -448,7 +448,7 @@ export default class BranchCreate extends PMOCommand {
448
448
  return true;
449
449
  },
450
450
  },
451
- ]);
451
+ ], null);
452
452
  // Auto-generate branch name from ticket
453
453
  const type = getBranchType(ticket.category);
454
454
  const slug = toKebabCase(ticket.title).substring(0, 20).replace(/-+$/, '');
@@ -461,7 +461,7 @@ export default class BranchCreate extends PMOCommand {
461
461
  this.log('');
462
462
  this.log(styles.muted(` Generated: ${branchName}`));
463
463
  // Confirm or allow edit
464
- const { confirmed } = await inquirer.prompt([
464
+ const { confirmed } = await this.prompt([
465
465
  {
466
466
  type: 'list',
467
467
  name: 'confirmed',
@@ -471,9 +471,9 @@ export default class BranchCreate extends PMOCommand {
471
471
  { name: 'No, let me edit', value: false },
472
472
  ],
473
473
  },
474
- ]);
474
+ ], null);
475
475
  // Ask where to branch from
476
- const { branchFrom } = await inquirer.prompt([
476
+ const { branchFrom } = await this.prompt([
477
477
  {
478
478
  type: 'list',
479
479
  name: 'branchFrom',
@@ -485,7 +485,7 @@ export default class BranchCreate extends PMOCommand {
485
485
  ],
486
486
  default: 0,
487
487
  },
488
- ]);
488
+ ], null);
489
489
  const fromOrigin = branchFrom === 'origin-main';
490
490
  let customStartPoint;
491
491
  if (branchFrom === 'other') {
@@ -493,14 +493,14 @@ export default class BranchCreate extends PMOCommand {
493
493
  }
494
494
  if (!confirmed) {
495
495
  // Allow manual edit
496
- const { customName } = await inquirer.prompt([
496
+ const { customName } = await this.prompt([
497
497
  {
498
498
  type: 'input',
499
499
  name: 'customName',
500
500
  message: 'Enter branch name:',
501
501
  default: branchName,
502
502
  },
503
- ]);
503
+ ], null);
504
504
  // Still return ticket info for commit message even with custom branch name
505
505
  return { branchName: customName, ticket: { id: ticket.id, title: ticket.title }, fromOrigin, customStartPoint };
506
506
  }
@@ -523,16 +523,16 @@ export default class BranchCreate extends PMOCommand {
523
523
  value: t,
524
524
  })),
525
525
  ];
526
- const { type } = await inquirer.prompt([
526
+ const { type } = await this.prompt([
527
527
  {
528
528
  type: 'list',
529
529
  name: 'type',
530
530
  message: 'Select branch type:',
531
531
  choices: typeChoices,
532
532
  },
533
- ]);
533
+ ], null);
534
534
  // Enter owner (defaults to GitHub username)
535
- const { owner } = await inquirer.prompt([
535
+ const { owner } = await this.prompt([
536
536
  {
537
537
  type: 'input',
538
538
  name: 'owner',
@@ -547,35 +547,36 @@ export default class BranchCreate extends PMOCommand {
547
547
  return true;
548
548
  },
549
549
  },
550
- ]);
550
+ ], null);
551
551
  // Enter description
552
- const { description } = await inquirer.prompt([
552
+ const { description } = await this.prompt([
553
553
  {
554
554
  type: 'input',
555
555
  name: 'description',
556
556
  message: 'Description (kebab-case):',
557
557
  validate: (input) => {
558
- if (!input.trim()) {
558
+ const val = input;
559
+ if (!val.trim()) {
559
560
  return 'Description is required';
560
561
  }
561
562
  // Auto-convert to kebab case for validation preview
562
- const kebab = toKebabCase(input);
563
- if (kebab !== input && input.includes(' ')) {
563
+ const kebab = toKebabCase(val);
564
+ if (kebab !== val && val.includes(' ')) {
564
565
  return `Will be converted to: ${kebab}. Use that? (press enter) or type kebab-case directly`;
565
566
  }
566
- if (!isKebabCase(input)) {
567
+ if (!isKebabCase(val)) {
567
568
  return 'Description must be kebab-case (lowercase, hyphens only)';
568
569
  }
569
570
  return true;
570
571
  },
571
572
  filter: (input) => toKebabCase(input),
572
573
  },
573
- ]);
574
+ ], null);
574
575
  const branchName = buildBranchName(type, description, {
575
576
  owner: owner || undefined,
576
577
  });
577
578
  // Ask where to branch from
578
- const { branchFrom } = await inquirer.prompt([
579
+ const { branchFrom } = await this.prompt([
579
580
  {
580
581
  type: 'list',
581
582
  name: 'branchFrom',
@@ -587,7 +588,7 @@ export default class BranchCreate extends PMOCommand {
587
588
  ],
588
589
  default: 0,
589
590
  },
590
- ]);
591
+ ], null);
591
592
  const fromOrigin = branchFrom === 'origin-main';
592
593
  let customStartPoint;
593
594
  if (branchFrom === 'other') {
@@ -612,7 +613,7 @@ export default class BranchCreate extends PMOCommand {
612
613
  this.warn('No branches found');
613
614
  return undefined;
614
615
  }
615
- const { selectedBranch } = await inquirer.prompt([
616
+ const { selectedBranch } = await this.prompt([
616
617
  {
617
618
  type: 'list',
618
619
  name: 'selectedBranch',
@@ -620,7 +621,7 @@ export default class BranchCreate extends PMOCommand {
620
621
  choices: branches,
621
622
  pageSize: 15,
622
623
  },
623
- ]);
624
+ ], null);
624
625
  return selectedBranch;
625
626
  }
626
627
  }
@@ -1,5 +1,4 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
2
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
4
3
  import { styles } from '../../lib/styles.js';
5
4
  import { shouldOutputJson, outputPromptAsJson, buildPromptConfig, createMetadata } from '../../lib/prompt-json.js';
@@ -51,7 +50,7 @@ export default class CategoryCreate extends PMOCommand {
51
50
  outputPromptAsJson(buildPromptConfig('input', 'name', message, choices), createMetadata('category create', flags));
52
51
  return;
53
52
  }
54
- const { categoryName } = await inquirer.prompt([{
53
+ const { categoryName } = await this.prompt([{
55
54
  type: 'input',
56
55
  name: 'categoryName',
57
56
  message,
@@ -63,7 +62,7 @@ export default class CategoryCreate extends PMOCommand {
63
62
  }
64
63
  return true;
65
64
  },
66
- }]);
65
+ }], null);
67
66
  name = categoryName;
68
67
  }
69
68
  // At this point name should be defined
@@ -76,11 +75,11 @@ export default class CategoryCreate extends PMOCommand {
76
75
  }
77
76
  // Prompt for description if not provided
78
77
  if (!description && !jsonMode) {
79
- const { categoryDescription } = await inquirer.prompt([{
78
+ const { categoryDescription } = await this.prompt([{
80
79
  type: 'input',
81
80
  name: 'categoryDescription',
82
81
  message: 'Description (optional):',
83
- }]);
82
+ }], null);
84
83
  description = categoryDescription || undefined;
85
84
  }
86
85
  try {
@@ -1,5 +1,4 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
2
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
4
3
  import { styles } from '../../lib/styles.js';
5
4
  import { shouldOutputJson, outputPromptAsJson, buildPromptConfig, createMetadata } from '../../lib/prompt-json.js';
@@ -75,7 +74,7 @@ export default class CategoryDelete extends PMOCommand {
75
74
  }
76
75
  // Confirm deletion
77
76
  if (!jsonMode) {
78
- const { confirmed } = await inquirer.prompt([{
77
+ const { confirmed } = await this.prompt([{
79
78
  type: 'list',
80
79
  name: 'confirmed',
81
80
  message: `Are you sure you want to delete category "${name}"?`,
@@ -83,7 +82,7 @@ export default class CategoryDelete extends PMOCommand {
83
82
  { name: 'Yes, delete it', value: true },
84
83
  { name: 'No, cancel', value: false },
85
84
  ],
86
- }]);
85
+ }], null);
87
86
  if (!confirmed) {
88
87
  this.log(styles.muted('Deletion cancelled.'));
89
88
  return;
@@ -1,5 +1,4 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
2
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
4
3
  import { styles } from '../../lib/styles.js';
5
4
  import { shouldOutputJson, outputPromptAsJson, buildPromptConfig, createMetadata } from '../../lib/prompt-json.js';
@@ -84,7 +83,7 @@ export default class CategoryRename extends PMOCommand {
84
83
  outputPromptAsJson(buildPromptConfig('input', 'newName', message, []), createMetadata('category rename', { ...flags, oldName }));
85
84
  return;
86
85
  }
87
- const { categoryNewName } = await inquirer.prompt([{
86
+ const { categoryNewName } = await this.prompt([{
88
87
  type: 'input',
89
88
  name: 'categoryNewName',
90
89
  message,
@@ -96,7 +95,7 @@ export default class CategoryRename extends PMOCommand {
96
95
  }
97
96
  return true;
98
97
  },
99
- }]);
98
+ }], null);
100
99
  newName = categoryNewName;
101
100
  }
102
101
  // At this point newName and oldName should be defined
@@ -1,5 +1,5 @@
1
- import { Command } from '@oclif/core';
2
- export default class Claude extends Command {
1
+ import { PromptCommand } from '../lib/prompt-command.js';
2
+ export default class Claude extends PromptCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
@@ -13,12 +13,6 @@ export default class Claude extends Command {
13
13
  project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
14
  title: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
15
  };
16
- /**
17
- * Prompt wrapper - handles both JSON mode and interactive mode.
18
- * In JSON mode: outputs prompt as JSON and exits.
19
- * In interactive mode: calls inquirer.prompt normally.
20
- */
21
- private prompt;
22
16
  run(): Promise<void>;
23
17
  /**
24
18
  * Run in "yolo mode" - outside any HQ
@@ -1,13 +1,13 @@
1
- import { Command, Flags } from '@oclif/core';
1
+ import { Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import * as os from 'node:os';
5
5
  import { execSync } from 'node:child_process';
6
- import inquirer from 'inquirer';
6
+ import { PromptCommand } from '../lib/prompt-command.js';
7
7
  import Database from 'better-sqlite3';
8
8
  import { findHQRoot } from '../lib/workspace.js';
9
9
  import { getWorkspaceInfo, createEphemeralAgent, } from '../lib/agents/commands.js';
10
- import { shouldOutputJson, isAgentMode, outputPromptAsJson, outputErrorAsJson, createMetadata, normalizeChoices, } from '../lib/prompt-json.js';
10
+ import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../lib/prompt-json.js';
11
11
  import { styles } from '../lib/styles.js';
12
12
  import { DEFAULT_EXECUTION_CONFIG, } from '../lib/execution/types.js';
13
13
  import { runExecution, isDockerRunning, isGitHubTokenAvailable, isDevcontainerCliInstalled } from '../lib/execution/runners.js';
@@ -40,7 +40,7 @@ function isGitRepo(dir) {
40
40
  return false;
41
41
  }
42
42
  }
43
- export default class Claude extends Command {
43
+ export default class Claude extends PromptCommand {
44
44
  static description = 'Quick launch Claude Code for ad-hoc sessions (works anywhere)';
45
45
  static examples = [
46
46
  '<%= config.bin %> <%= command.id %>',
@@ -90,28 +90,6 @@ export default class Claude extends Command {
90
90
  description: 'Ticket title (inside HQ only)',
91
91
  }),
92
92
  };
93
- /**
94
- * Prompt wrapper - handles both JSON mode and interactive mode.
95
- * In JSON mode: outputs prompt as JSON and exits.
96
- * In interactive mode: calls inquirer.prompt normally.
97
- */
98
- async prompt(questions, jsonModeConfig) {
99
- if (jsonModeConfig && isAgentMode(jsonModeConfig.flags)) {
100
- const firstQuestion = questions[0];
101
- if (firstQuestion) {
102
- const choices = firstQuestion.choices ? normalizeChoices(firstQuestion.choices) : undefined;
103
- outputPromptAsJson({
104
- type: firstQuestion.type,
105
- name: firstQuestion.name,
106
- message: firstQuestion.message,
107
- choices,
108
- default: firstQuestion.default,
109
- }, createMetadata(jsonModeConfig.commandName, jsonModeConfig.flags));
110
- }
111
- return {};
112
- }
113
- return inquirer.prompt(questions);
114
- }
115
93
  async run() {
116
94
  const { flags } = await this.parse(Claude);
117
95
  const jsonMode = shouldOutputJson(flags);
@@ -155,6 +133,8 @@ export default class Claude extends Command {
155
133
  validate: (input) => input.trim() ? true : 'Session name required',
156
134
  },
157
135
  ], jsonModeConfig);
136
+ if (jsonMode)
137
+ return;
158
138
  slug = inputSlug.trim();
159
139
  }
160
140
  // Determine if devcontainer is available
@@ -300,6 +280,8 @@ export default class Claude extends Command {
300
280
  default: 'terminal',
301
281
  },
302
282
  ], jsonModeConfig);
283
+ if (jsonMode)
284
+ return;
303
285
  displayMode = selectedDisplay;
304
286
  }
305
287
  // Prompt for permission mode
@@ -320,6 +302,8 @@ export default class Claude extends Command {
320
302
  default: 'danger',
321
303
  },
322
304
  ], jsonModeConfig);
305
+ if (jsonMode)
306
+ return;
323
307
  sandboxed = permissionMode === 'safe';
324
308
  }
325
309
  // Warn about uncommitted changes in danger mode
@@ -528,6 +512,10 @@ export default class Claude extends Command {
528
512
  })),
529
513
  },
530
514
  ], jsonModeConfig);
515
+ if (jsonMode) {
516
+ db.close();
517
+ return;
518
+ }
531
519
  projectId = selectedProject;
532
520
  }
533
521
  }
@@ -543,6 +531,10 @@ export default class Claude extends Command {
543
531
  validate: (input) => input.trim() ? true : 'Title required',
544
532
  },
545
533
  ], jsonModeConfig);
534
+ if (jsonMode) {
535
+ db.close();
536
+ return;
537
+ }
546
538
  ticketTitle = inputTitle.trim();
547
539
  }
548
540
  // Get optional description
@@ -703,6 +695,10 @@ export default class Claude extends Command {
703
695
  default: 'terminal',
704
696
  },
705
697
  ], jsonModeConfig);
698
+ if (jsonMode) {
699
+ db.close();
700
+ return;
701
+ }
706
702
  displayMode = selectedDisplay;
707
703
  }
708
704
  // Prompt for permission mode
@@ -724,6 +720,10 @@ export default class Claude extends Command {
724
720
  default: 'danger',
725
721
  },
726
722
  ], jsonModeConfig);
723
+ if (jsonMode) {
724
+ db.close();
725
+ return;
726
+ }
727
727
  sandboxed = permissionMode === 'safe';
728
728
  }
729
729
  // Warn about uncommitted changes in danger mode