@proletariat/cli 0.3.34 → 0.3.36

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 (198) hide show
  1. package/dist/commands/agent/auth.d.ts +15 -3
  2. package/dist/commands/agent/auth.js +136 -15
  3. package/dist/commands/agent/index.js +11 -2
  4. package/dist/commands/agent/list.js +16 -7
  5. package/dist/commands/agent/staff/add.d.ts +1 -0
  6. package/dist/commands/agent/staff/add.js +1 -0
  7. package/dist/commands/agent/staff/index.d.ts +15 -0
  8. package/dist/commands/agent/staff/index.js +83 -0
  9. package/dist/commands/agent/staff/list.d.ts +1 -0
  10. package/dist/commands/agent/staff/list.js +1 -0
  11. package/dist/commands/agent/staff/remove.d.ts +1 -0
  12. package/dist/commands/agent/staff/remove.js +1 -0
  13. package/dist/commands/agent/status.js +32 -4
  14. package/dist/commands/agent/themes/add-names.d.ts +1 -0
  15. package/dist/commands/agent/themes/add-names.js +1 -0
  16. package/dist/commands/agent/themes/create.d.ts +1 -0
  17. package/dist/commands/agent/themes/create.js +1 -0
  18. package/dist/commands/agent/themes/index.d.ts +10 -0
  19. package/dist/commands/agent/themes/index.js +144 -0
  20. package/dist/commands/agent/themes/list.d.ts +1 -0
  21. package/dist/commands/agent/themes/list.js +1 -0
  22. package/dist/commands/agent/themes/set.d.ts +1 -0
  23. package/dist/commands/agent/themes/set.js +1 -0
  24. package/dist/commands/agents/themes/add-names.d.ts +1 -0
  25. package/dist/commands/agents/themes/add-names.js +1 -0
  26. package/dist/commands/agents/themes/create.d.ts +1 -0
  27. package/dist/commands/agents/themes/create.js +1 -0
  28. package/dist/commands/agents/themes/list.d.ts +1 -0
  29. package/dist/commands/agents/themes/list.js +1 -0
  30. package/dist/commands/board/watch.js +6 -0
  31. package/dist/commands/branch/list.d.ts +1 -0
  32. package/dist/commands/branch/list.js +43 -12
  33. package/dist/commands/branch/where.js +3 -2
  34. package/dist/commands/category/list.d.ts +2 -1
  35. package/dist/commands/category/list.js +38 -13
  36. package/dist/commands/{claude.d.ts → claude/index.d.ts} +1 -1
  37. package/dist/commands/{claude.js → claude/index.js} +12 -12
  38. package/dist/commands/claude/open.d.ts +13 -0
  39. package/dist/commands/claude/open.js +175 -0
  40. package/dist/commands/diet.js +18 -2
  41. package/dist/commands/docker/logs.js +7 -3
  42. package/dist/commands/docker/shell.js +6 -0
  43. package/dist/commands/docker/start.js +20 -4
  44. package/dist/commands/docker/sync.d.ts +4 -0
  45. package/dist/commands/docker/sync.js +30 -2
  46. package/dist/commands/epic/show.d.ts +13 -0
  47. package/dist/commands/epic/show.js +16 -0
  48. package/dist/commands/epic/view.js +27 -0
  49. package/dist/commands/execution/config.d.ts +0 -4
  50. package/dist/commands/execution/config.js +10 -32
  51. package/dist/commands/execution/index.js +2 -1
  52. package/dist/commands/execution/logs.js +1 -1
  53. package/dist/commands/execution/stop.js +2 -1
  54. package/dist/commands/execution/view.js +22 -26
  55. package/dist/commands/init.js +2 -19
  56. package/dist/commands/label/create.d.ts +20 -0
  57. package/dist/commands/label/create.js +57 -0
  58. package/dist/commands/label/delete.d.ts +17 -0
  59. package/dist/commands/label/delete.js +32 -0
  60. package/dist/commands/label/group/create.d.ts +20 -0
  61. package/dist/commands/label/group/create.js +55 -0
  62. package/dist/commands/label/group/list.d.ts +14 -0
  63. package/dist/commands/label/group/list.js +52 -0
  64. package/dist/commands/label/index.d.ts +15 -0
  65. package/dist/commands/label/index.js +58 -0
  66. package/dist/commands/label/list.d.ts +16 -0
  67. package/dist/commands/label/list.js +83 -0
  68. package/dist/commands/link/list.js +3 -2
  69. package/dist/commands/mcp-server.js +27 -1
  70. package/dist/commands/phase/template/apply.d.ts +26 -0
  71. package/dist/commands/phase/template/apply.js +14 -0
  72. package/dist/commands/phase/template/create.d.ts +23 -0
  73. package/dist/commands/phase/template/create.js +14 -0
  74. package/dist/commands/phase/template/delete.d.ts +18 -0
  75. package/dist/commands/phase/template/delete.js +61 -0
  76. package/dist/commands/phase/template/list.d.ts +17 -0
  77. package/dist/commands/phase/template/list.js +89 -0
  78. package/dist/commands/phase/template/update.d.ts +1 -0
  79. package/dist/commands/phase/template/update.js +1 -0
  80. package/dist/commands/priority/add.js +1 -1
  81. package/dist/commands/project/create.js +3 -4
  82. package/dist/commands/project/update.js +5 -8
  83. package/dist/commands/pull.js +24 -0
  84. package/dist/commands/roadmap/generate.js +1 -2
  85. package/dist/commands/session/create.d.ts +19 -0
  86. package/dist/commands/session/create.js +102 -0
  87. package/dist/commands/session/health.js +2 -21
  88. package/dist/commands/session/index.js +14 -1
  89. package/dist/commands/session/list.js +26 -7
  90. package/dist/commands/session/peek.d.ts +38 -0
  91. package/dist/commands/session/peek.js +316 -0
  92. package/dist/commands/session/poke.d.ts +27 -0
  93. package/dist/commands/session/poke.js +219 -0
  94. package/dist/commands/spec/link/depends.d.ts +18 -0
  95. package/dist/commands/spec/link/depends.js +86 -0
  96. package/dist/commands/spec/link/index.d.ts +17 -0
  97. package/dist/commands/spec/link/index.js +92 -0
  98. package/dist/commands/spec/link/remove.d.ts +18 -0
  99. package/dist/commands/spec/link/remove.js +90 -0
  100. package/dist/commands/spec/view.js +29 -0
  101. package/dist/commands/support/logs.js +2 -2
  102. package/dist/commands/template/apply.js +5 -4
  103. package/dist/commands/template/create.js +1 -1
  104. package/dist/commands/template/list.js +2 -1
  105. package/dist/commands/theme/add-names.d.ts +4 -0
  106. package/dist/commands/theme/add-names.js +11 -1
  107. package/dist/commands/theme/create.d.ts +2 -0
  108. package/dist/commands/theme/create.js +8 -0
  109. package/dist/commands/ticket/bulk.js +2 -2
  110. package/dist/commands/ticket/complete.js +2 -2
  111. package/dist/commands/ticket/create.js +21 -0
  112. package/dist/commands/ticket/delete.js +8 -0
  113. package/dist/commands/ticket/edit.js +25 -0
  114. package/dist/commands/ticket/index.js +2 -2
  115. package/dist/commands/ticket/link/block.d.ts +15 -0
  116. package/dist/commands/ticket/link/block.js +95 -0
  117. package/dist/commands/ticket/link/index.d.ts +14 -0
  118. package/dist/commands/ticket/link/index.js +96 -0
  119. package/dist/commands/ticket/list.d.ts +1 -0
  120. package/dist/commands/ticket/list.js +6 -0
  121. package/dist/commands/ticket/move.js +25 -2
  122. package/dist/commands/ticket/resolve.js +4 -5
  123. package/dist/commands/ticket/show.d.ts +13 -0
  124. package/dist/commands/ticket/show.js +16 -0
  125. package/dist/commands/ticket/template/apply.d.ts +26 -0
  126. package/dist/commands/ticket/template/apply.js +14 -0
  127. package/dist/commands/ticket/template/delete.d.ts +18 -0
  128. package/dist/commands/ticket/template/delete.js +61 -0
  129. package/dist/commands/ticket/template/list.d.ts +17 -0
  130. package/dist/commands/ticket/template/list.js +78 -0
  131. package/dist/commands/ticket/template/save.d.ts +17 -0
  132. package/dist/commands/ticket/template/save.js +97 -0
  133. package/dist/commands/ticket/view.js +30 -0
  134. package/dist/commands/work/index.js +4 -0
  135. package/dist/commands/work/ready.js +17 -0
  136. package/dist/commands/work/resolve.js +1 -1
  137. package/dist/commands/work/spawn.js +4 -4
  138. package/dist/commands/work/start.d.ts +1 -0
  139. package/dist/commands/work/start.js +203 -93
  140. package/dist/commands/work/status.d.ts +14 -0
  141. package/dist/commands/work/status.js +60 -0
  142. package/dist/commands/workflow/index.js +2 -1
  143. package/dist/commands/workflow/show.d.ts +13 -0
  144. package/dist/commands/workflow/show.js +16 -0
  145. package/dist/commands/workspace/add.js +15 -0
  146. package/dist/commands/workspace/list.js +2 -1
  147. package/dist/commands/workspace/prune.js +5 -5
  148. package/dist/lib/branch/index.d.ts +1 -0
  149. package/dist/lib/database/index.d.ts +1 -1
  150. package/dist/lib/database/index.js +20 -0
  151. package/dist/lib/execution/config.d.ts +15 -1
  152. package/dist/lib/execution/config.js +28 -0
  153. package/dist/lib/execution/devcontainer.js +3 -1
  154. package/dist/lib/execution/runners.d.ts +18 -2
  155. package/dist/lib/execution/runners.js +71 -29
  156. package/dist/lib/execution/session-utils.d.ts +11 -1
  157. package/dist/lib/execution/session-utils.js +26 -1
  158. package/dist/lib/execution/storage.d.ts +5 -0
  159. package/dist/lib/execution/storage.js +18 -3
  160. package/dist/lib/execution/types.d.ts +3 -0
  161. package/dist/lib/flags/resolver.js +1 -0
  162. package/dist/lib/mcp/helpers.d.ts +1 -2
  163. package/dist/lib/mcp/tools/board.js +4 -6
  164. package/dist/lib/mcp/tools/cli-passthrough.js +25 -6
  165. package/dist/lib/mcp/tools/diet.js +1 -0
  166. package/dist/lib/mcp/tools/epic.js +8 -3
  167. package/dist/lib/mcp/tools/index.d.ts +1 -0
  168. package/dist/lib/mcp/tools/index.js +1 -0
  169. package/dist/lib/mcp/tools/label.d.ts +6 -0
  170. package/dist/lib/mcp/tools/label.js +338 -0
  171. package/dist/lib/mcp/tools/spec.js +1 -1
  172. package/dist/lib/mcp/tools/ticket.js +57 -19
  173. package/dist/lib/mcp/tools/work.js +96 -6
  174. package/dist/lib/mcp/types.d.ts +10 -0
  175. package/dist/lib/multiline-input.js +8 -19
  176. package/dist/lib/pmo/base-command.d.ts +0 -1
  177. package/dist/lib/pmo/base-command.js +4 -5
  178. package/dist/lib/pmo/schema.d.ts +6 -0
  179. package/dist/lib/pmo/schema.js +44 -0
  180. package/dist/lib/pmo/storage/actions.js +1 -1
  181. package/dist/lib/pmo/storage/base.d.ts +6 -0
  182. package/dist/lib/pmo/storage/base.js +311 -52
  183. package/dist/lib/pmo/storage/index.d.ts +23 -1
  184. package/dist/lib/pmo/storage/index.js +59 -1
  185. package/dist/lib/pmo/storage/labels.d.ts +55 -0
  186. package/dist/lib/pmo/storage/labels.js +346 -0
  187. package/dist/lib/pmo/storage/tickets.js +17 -0
  188. package/dist/lib/pmo/storage/types.d.ts +25 -0
  189. package/dist/lib/pmo/types.d.ts +44 -0
  190. package/dist/lib/pmo/utils.js +1 -1
  191. package/dist/lib/prompt-command.d.ts +20 -0
  192. package/dist/lib/prompt-command.js +38 -2
  193. package/dist/lib/prompt-json.d.ts +36 -4
  194. package/dist/lib/prompt-json.js +129 -7
  195. package/dist/lib/styles.d.ts +37 -0
  196. package/dist/lib/styles.js +73 -0
  197. package/oclif.manifest.json +6399 -3799
  198. package/package.json +1 -1
@@ -0,0 +1,26 @@
1
+ import TemplateApply from '../../template/apply.js';
2
+ export default class PhaseTemplateApply extends TemplateApply {
3
+ static description: string;
4
+ static args: {
5
+ template: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ type: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ title: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ column: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ priority: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ category: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ assignee: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ owner: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ epic: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ 'no-subtasks': import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ interactive: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
21
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
22
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
23
+ };
24
+ static examples: string[];
25
+ run(): Promise<void>;
26
+ }
@@ -0,0 +1,14 @@
1
+ import TemplateApply from '../../template/apply.js';
2
+ export default class PhaseTemplateApply extends TemplateApply {
3
+ static description = 'Apply a phase template to the workspace';
4
+ static args = TemplateApply.args;
5
+ static flags = TemplateApply.flags;
6
+ static examples = TemplateApply.examples;
7
+ async run() {
8
+ const argv = this.argv;
9
+ if (!argv.includes('--type') && !argv.includes('-t')) {
10
+ argv.push('--type', 'phase');
11
+ }
12
+ return super.run();
13
+ }
14
+ }
@@ -0,0 +1,23 @@
1
+ import TemplateCreate from '../../template/create.js';
2
+ export default class PhaseTemplateCreate extends TemplateCreate {
3
+ static description: string;
4
+ static args: {
5
+ name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ type: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ 'title-pattern': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ 'description-template': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ priority: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ category: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ subtask: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ ac: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ label: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
20
+ };
21
+ static examples: string[];
22
+ run(): Promise<void>;
23
+ }
@@ -0,0 +1,14 @@
1
+ import TemplateCreate from '../../template/create.js';
2
+ export default class PhaseTemplateCreate extends TemplateCreate {
3
+ static description = 'Create a phase template from current workspace phases';
4
+ static args = TemplateCreate.args;
5
+ static flags = TemplateCreate.flags;
6
+ static examples = TemplateCreate.examples;
7
+ async run() {
8
+ const argv = this.argv;
9
+ if (!argv.includes('--type') && !argv.includes('-t')) {
10
+ argv.push('--type', 'phase');
11
+ }
12
+ return super.run();
13
+ }
14
+ }
@@ -0,0 +1,18 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class PhaseTemplateDelete extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ };
14
+ protected getPMOOptions(): {
15
+ promptIfMultiple: boolean;
16
+ };
17
+ execute(): Promise<void>;
18
+ }
@@ -0,0 +1,61 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { styles } from '../../../lib/styles.js';
4
+ import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../../lib/prompt-json.js';
5
+ export default class PhaseTemplateDelete extends PMOCommand {
6
+ static description = 'Delete a phase template';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %> my-template --force',
9
+ ];
10
+ static args = {
11
+ id: Args.string({
12
+ description: 'Template ID to delete',
13
+ required: true,
14
+ }),
15
+ };
16
+ static flags = {
17
+ ...pmoBaseFlags,
18
+ force: Flags.boolean({
19
+ char: 'f',
20
+ description: 'Skip confirmation',
21
+ default: false,
22
+ }),
23
+ };
24
+ getPMOOptions() {
25
+ return { promptIfMultiple: false };
26
+ }
27
+ async execute() {
28
+ const { args, flags } = await this.parse(PhaseTemplateDelete);
29
+ const jsonMode = shouldOutputJson(flags);
30
+ const handleError = (code, message) => {
31
+ if (jsonMode) {
32
+ outputErrorAsJson(code, message, createMetadata('phase template delete', flags));
33
+ }
34
+ this.error(message);
35
+ };
36
+ const template = await this.storage.getPhaseTemplate(args.id);
37
+ if (!template) {
38
+ return handleError('NOT_FOUND', `Phase template not found: ${args.id}`);
39
+ }
40
+ if (template.isBuiltin) {
41
+ return handleError('BUILTIN', `Cannot delete built-in template "${template.name}".`);
42
+ }
43
+ if (!flags.force) {
44
+ const { confirm } = await this.prompt([{
45
+ type: 'list',
46
+ name: 'confirm',
47
+ message: `Delete phase template "${template.name}"?`,
48
+ choices: [
49
+ { name: 'No', value: false },
50
+ { name: 'Yes', value: true },
51
+ ],
52
+ }], jsonMode ? { flags, commandName: 'phase template delete' } : null);
53
+ if (!confirm) {
54
+ this.log(styles.muted('Cancelled.'));
55
+ return;
56
+ }
57
+ }
58
+ await this.storage.deletePhaseTemplate(args.id);
59
+ this.log(styles.success(`\nDeleted phase template "${template.name}"`));
60
+ }
61
+ }
@@ -0,0 +1,17 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class PhaseTemplateList extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ builtin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ custom: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
12
+ protected getPMOOptions(): {
13
+ promptIfMultiple: boolean;
14
+ };
15
+ execute(): Promise<void>;
16
+ private printTemplate;
17
+ }
@@ -0,0 +1,89 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { shouldOutputJson } from '../../../lib/prompt-json.js';
4
+ import { styles } from '../../../lib/styles.js';
5
+ export default class PhaseTemplateList extends PMOCommand {
6
+ static description = 'List phase templates';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %>',
9
+ '<%= config.bin %> <%= command.id %> --builtin',
10
+ '<%= config.bin %> <%= command.id %> --json',
11
+ ];
12
+ static flags = {
13
+ ...pmoBaseFlags,
14
+ builtin: Flags.boolean({
15
+ description: 'Show only built-in templates',
16
+ exclusive: ['custom'],
17
+ }),
18
+ custom: Flags.boolean({
19
+ description: 'Show only custom templates',
20
+ exclusive: ['builtin'],
21
+ }),
22
+ };
23
+ getPMOOptions() {
24
+ return { promptIfMultiple: false };
25
+ }
26
+ async execute() {
27
+ const { flags } = await this.parse(PhaseTemplateList);
28
+ let builtinFilter;
29
+ if (flags.builtin)
30
+ builtinFilter = { isBuiltin: true };
31
+ if (flags.custom)
32
+ builtinFilter = { isBuiltin: false };
33
+ const templates = await this.storage.listPhaseTemplates(builtinFilter);
34
+ if (shouldOutputJson(flags)) {
35
+ this.log(JSON.stringify(templates, null, 2));
36
+ return;
37
+ }
38
+ if (templates.length === 0) {
39
+ this.log(styles.muted('\nNo phase templates found.'));
40
+ return;
41
+ }
42
+ this.log(`\n${styles.emphasis('Phase Templates')}`);
43
+ this.log('═'.repeat(60));
44
+ const builtinTemplates = templates.filter(t => t.isBuiltin);
45
+ const customTemplates = templates.filter(t => !t.isBuiltin);
46
+ if (builtinTemplates.length > 0 && !flags.custom) {
47
+ this.log(`\n${styles.emphasis('Built-in Templates')}`);
48
+ this.log('─'.repeat(40));
49
+ for (const template of builtinTemplates) {
50
+ this.printTemplate(template);
51
+ }
52
+ }
53
+ if (customTemplates.length > 0 && !flags.builtin) {
54
+ this.log(`\n${styles.emphasis('Custom Templates')}`);
55
+ this.log('─'.repeat(40));
56
+ for (const template of customTemplates) {
57
+ this.printTemplate(template);
58
+ }
59
+ }
60
+ this.log('');
61
+ }
62
+ printTemplate(template) {
63
+ const categoryEmoji = {
64
+ triage: '📬',
65
+ backlog: '📥',
66
+ unstarted: '📋',
67
+ started: '🚀',
68
+ completed: '✅',
69
+ canceled: '🚫',
70
+ };
71
+ this.log(` ${styles.emphasis(template.name)} ${styles.muted(`(${template.id})`)}`);
72
+ if (template.description) {
73
+ this.log(` ${styles.muted(template.description)}`);
74
+ }
75
+ if (template.phases && template.phases.length > 0) {
76
+ const phasesByCategory = new Map();
77
+ for (const phase of template.phases) {
78
+ const existing = phasesByCategory.get(phase.category) || [];
79
+ existing.push(phase.name);
80
+ phasesByCategory.set(phase.category, existing);
81
+ }
82
+ const phaseParts = [];
83
+ for (const [category, names] of phasesByCategory) {
84
+ phaseParts.push(`${categoryEmoji[category]} ${names.join(', ')}`);
85
+ }
86
+ this.log(` ${styles.muted(phaseParts.join(' → '))}`);
87
+ }
88
+ }
89
+ }
@@ -0,0 +1 @@
1
+ export { default } from '../../template/update.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../template/update.js';
@@ -46,7 +46,7 @@ export default class PriorityAdd extends PMOCommand {
46
46
  }
47
47
  else if (flags.after) {
48
48
  const afterIndex = priorities.indexOf(flags.after);
49
- if (afterIndex < 0) {
49
+ if (afterIndex === -1) {
50
50
  if (jsonMode) {
51
51
  outputErrorAsJson('PRIORITY_NOT_FOUND', `Priority "${flags.after}" not found`, createMetadata('priority add', flags));
52
52
  this.exit(1);
@@ -1,7 +1,6 @@
1
1
  import { Flags, Args } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
- import inquirer from 'inquirer';
5
4
  import { createBoardContent, createSpecFolders, PMOCommand, pmoBaseFlags, BUILTIN_TEMPLATES } from '../../lib/pmo/index.js';
6
5
  import { styles } from '../../lib/styles.js';
7
6
  import { slugify } from '../../lib/pmo/utils.js';
@@ -164,16 +163,16 @@ export default class ProjectCreate extends PMOCommand {
164
163
  }
165
164
  async promptProjectData(fields) {
166
165
  // Build inquirer prompts from fields, adding validators and dynamic defaults
167
- const answers = await inquirer.prompt(fields.map(field => ({
166
+ const answers = await this.prompt(fields.map(field => ({
168
167
  ...field,
169
168
  validate: field.name === 'name'
170
- ? ((input) => input.length > 0 || 'Name is required')
169
+ ? ((input) => String(input).length > 0 || 'Name is required')
171
170
  : undefined,
172
171
  // Dynamic default for id based on name
173
172
  default: field.name === 'id'
174
173
  ? ((answers) => slugify(answers.name))
175
174
  : field.default,
176
- })));
175
+ })), null);
177
176
  return {
178
177
  name: answers.name,
179
178
  id: answers.id || undefined,
@@ -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, outputErrorAsJson, outputSuccessAsJson, createMetadata, buildFormPromptConfig, } from '../../lib/prompt-json.js';
@@ -43,8 +42,6 @@ export default class ProjectUpdate extends PMOCommand {
43
42
  }
44
43
  this.error(message);
45
44
  };
46
- // Agent mode config for prompts
47
- const agentConfig = jsonMode ? { flags, commandName: 'project update' } : null;
48
45
  // Get project ID - from args or prompt
49
46
  let projectId = args.id;
50
47
  if (!projectId) {
@@ -68,12 +65,12 @@ export default class ProjectUpdate extends PMOCommand {
68
65
  }, createMetadata('project update', flags));
69
66
  return;
70
67
  }
71
- const { selectedProjectId } = await inquirer.prompt([{
68
+ const { selectedProjectId } = await this.prompt([{
72
69
  type: 'list',
73
70
  name: 'selectedProjectId',
74
71
  message: 'Select project to update:',
75
72
  choices: projectChoices,
76
- }]);
73
+ }], null);
77
74
  projectId = selectedProjectId;
78
75
  }
79
76
  // Get the project
@@ -105,12 +102,12 @@ export default class ProjectUpdate extends PMOCommand {
105
102
  outputPromptAsJson(buildFormPromptConfig(fields), createMetadata('project update', flags));
106
103
  return;
107
104
  }
108
- const answers = await inquirer.prompt(fields.map(field => ({
105
+ const answers = await this.prompt(fields.map(field => ({
109
106
  ...field,
110
107
  validate: field.name === 'name'
111
- ? ((input) => input.length > 0 || 'Name is required')
108
+ ? ((input) => String(input).length > 0 || 'Name is required')
112
109
  : undefined,
113
- })));
110
+ })), null);
114
111
  newName = answers.name;
115
112
  newDescription = answers.description;
116
113
  }
@@ -1,5 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import { PMOCommand, pmoBaseFlags } from '../lib/pmo/base-command.js';
3
+ import { shouldOutputJson } from '../lib/prompt-json.js';
3
4
  import { styles, divider } from '../lib/styles.js';
4
5
  import { loadDietConfig, formatDietConfig, } from '../lib/pmo/diet.js';
5
6
  export default class Pull extends PMOCommand {
@@ -26,6 +27,7 @@ export default class Pull extends PMOCommand {
26
27
  };
27
28
  async execute() {
28
29
  const { flags } = await this.parse(Pull);
30
+ const jsonMode = shouldOutputJson(flags);
29
31
  const projectId = await this.requireProject();
30
32
  const count = flags.count;
31
33
  const dryRun = flags['dry-run'];
@@ -60,6 +62,28 @@ export default class Pull extends PMOCommand {
60
62
  const existingReadyTickets = await this.storage.listTickets(projectId, { statusCategory: 'unstarted' });
61
63
  // Run the pull algorithm
62
64
  const result = await this.runPullAlgorithm(allBacklogTickets, existingReadyTickets, dietConfig, count);
65
+ // JSON output path
66
+ if (jsonMode) {
67
+ this.log(JSON.stringify({
68
+ type: 'success',
69
+ result: {
70
+ dryRun,
71
+ pulled: result.pulled,
72
+ skippedBlocked: result.skippedBlocked,
73
+ skippedCeiling: result.skippedCeiling,
74
+ totalCandidates: result.totalCandidates,
75
+ targetStatus: targetStatus.name,
76
+ }
77
+ }, null, 2));
78
+ // Still move tickets if not dry-run
79
+ if (!dryRun && result.pulled.length > 0) {
80
+ for (const ticket of result.pulled) {
81
+ // eslint-disable-next-line no-await-in-loop -- Sequential moves to maintain ordering
82
+ await this.storage.moveTicket(projectId, ticket.id, targetStatus.name);
83
+ }
84
+ }
85
+ return;
86
+ }
63
87
  // Display results
64
88
  this.displayPullResults(result, dietConfig, targetStatus, dryRun);
65
89
  // Move tickets if not dry-run
@@ -3,9 +3,8 @@ import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
5
5
  import { styles } from '../../lib/styles.js';
6
- import { slugify } from '../../lib/pmo/utils.js';
6
+ import { slugify, getWorkspacePriorities } from '../../lib/pmo/utils.js';
7
7
  import { normalizePriority } from '../../lib/pmo/types.js';
8
- import { getWorkspacePriorities } from '../../lib/pmo/utils.js';
9
8
  import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
10
9
  export default class RoadmapGenerate extends PMOCommand {
11
10
  static description = 'Generate roadmap markdown file';
@@ -0,0 +1,19 @@
1
+ import { PMOCommand } from '../../lib/pmo/index.js';
2
+ export default class SessionCreate extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ command: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ detach: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ };
15
+ protected getPMOOptions(): {
16
+ promptIfMultiple: boolean;
17
+ };
18
+ execute(): Promise<void>;
19
+ }
@@ -0,0 +1,102 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { execSync } from 'node:child_process';
3
+ import { styles } from '../../lib/styles.js';
4
+ import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
5
+ import { shouldOutputJson, outputSuccessAsJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
6
+ export default class SessionCreate extends PMOCommand {
7
+ static description = 'Create a new tmux session';
8
+ static examples = [
9
+ '<%= config.bin %> <%= command.id %> my-session',
10
+ '<%= config.bin %> <%= command.id %> my-session --command "npm run dev"',
11
+ '<%= config.bin %> <%= command.id %> my-session --detach',
12
+ ];
13
+ static args = {
14
+ name: Args.string({
15
+ description: 'Name for the new tmux session',
16
+ required: true,
17
+ }),
18
+ };
19
+ static flags = {
20
+ ...pmoBaseFlags,
21
+ command: Flags.string({
22
+ char: 'c',
23
+ description: 'Initial command to run in the session',
24
+ }),
25
+ detach: Flags.boolean({
26
+ char: 'd',
27
+ description: 'Create session in detached mode (do not attach)',
28
+ default: false,
29
+ }),
30
+ };
31
+ getPMOOptions() {
32
+ return { promptIfMultiple: false };
33
+ }
34
+ async execute() {
35
+ const { args, flags } = await this.parse(SessionCreate);
36
+ const jsonMode = shouldOutputJson(flags);
37
+ const sessionName = args.name;
38
+ // Check if tmux is available
39
+ try {
40
+ execSync('which tmux', { stdio: 'pipe' });
41
+ }
42
+ catch {
43
+ if (jsonMode) {
44
+ outputErrorAsJson('TMUX_NOT_FOUND', 'tmux is not installed or not in PATH.', createMetadata('session create', flags));
45
+ }
46
+ this.error('tmux is not installed or not in PATH.');
47
+ }
48
+ // Check if a session with this name already exists
49
+ try {
50
+ execSync(`tmux has-session -t "${sessionName}" 2>/dev/null`, { stdio: 'pipe' });
51
+ // If we get here, session exists
52
+ if (jsonMode) {
53
+ outputErrorAsJson('SESSION_EXISTS', `A tmux session named "${sessionName}" already exists.`, createMetadata('session create', flags));
54
+ }
55
+ this.error(`A tmux session named "${sessionName}" already exists.`);
56
+ }
57
+ catch {
58
+ // Session doesn't exist, good to proceed
59
+ }
60
+ // Build the tmux new-session command
61
+ const tmuxArgs = ['tmux', 'new-session'];
62
+ // Always use detached mode for creation, then attach if needed
63
+ tmuxArgs.push('-d');
64
+ tmuxArgs.push('-s', `"${sessionName}"`);
65
+ if (flags.command) {
66
+ tmuxArgs.push(`"${flags.command}"`);
67
+ }
68
+ try {
69
+ execSync(tmuxArgs.join(' '), { stdio: 'pipe' });
70
+ }
71
+ catch (error) {
72
+ const message = `Failed to create tmux session "${sessionName}": ${error instanceof Error ? error.message : error}`;
73
+ if (jsonMode) {
74
+ outputErrorAsJson('CREATE_FAILED', message, createMetadata('session create', flags));
75
+ }
76
+ this.error(message);
77
+ }
78
+ if (jsonMode) {
79
+ outputSuccessAsJson({
80
+ sessionName,
81
+ detached: flags.detach,
82
+ command: flags.command || null,
83
+ }, createMetadata('session create', flags));
84
+ }
85
+ this.log('');
86
+ this.log(styles.success(`Created tmux session: ${sessionName}`));
87
+ if (!flags.detach) {
88
+ this.log(styles.info(`Attaching to session: ${sessionName}`));
89
+ try {
90
+ execSync(`tmux attach -t "${sessionName}"`, { stdio: 'inherit' });
91
+ }
92
+ catch {
93
+ this.log(styles.muted(`Session "${sessionName}" is running in detached mode.`));
94
+ this.log(styles.muted(`Attach with: tmux attach -t "${sessionName}"`));
95
+ }
96
+ }
97
+ else {
98
+ this.log(styles.muted(`Attach with: prlt session attach ${sessionName}`));
99
+ }
100
+ this.log('');
101
+ }
102
+ }
@@ -5,32 +5,13 @@ import Database from 'better-sqlite3';
5
5
  import { styles } from '../../lib/styles.js';
6
6
  import { getWorkspaceInfo } from '../../lib/agents/commands.js';
7
7
  import { ExecutionStorage } from '../../lib/execution/index.js';
8
- import { parseSessionName, getHostTmuxSessionNames, getContainerTmuxSessionMap, flattenContainerSessions, findSessionForExecution, } from '../../lib/execution/session-utils.js';
8
+ import { parseSessionName, getHostTmuxSessionNames, getContainerTmuxSessionMap, flattenContainerSessions, findSessionForExecution, captureTmuxPane, } from '../../lib/execution/session-utils.js';
9
9
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
10
10
  import { visualPadEnd } from '../../lib/string-utils.js';
11
11
  import { shouldOutputJson, outputSuccessAsJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
12
12
  // =============================================================================
13
13
  // Detection Logic
14
14
  // =============================================================================
15
- /**
16
- * Capture the last N lines from a tmux pane.
17
- */
18
- function captureTmuxPane(sessionId, lines, containerId) {
19
- try {
20
- const captureCmd = `tmux capture-pane -t "${sessionId}" -p -S -${lines}`;
21
- if (containerId) {
22
- return execSync(`docker exec ${containerId} bash -c '${captureCmd}'`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 10000 }).trim();
23
- }
24
- return execSync(captureCmd, {
25
- encoding: 'utf-8',
26
- stdio: ['pipe', 'pipe', 'pipe'],
27
- timeout: 5000,
28
- }).trim();
29
- }
30
- catch {
31
- return null;
32
- }
33
- }
34
15
  /**
35
16
  * Detect agent health state from tmux pane content.
36
17
  *
@@ -60,7 +41,7 @@ function detectState(paneContent) {
60
41
  }
61
42
  // IDLE: shell prompt visible (agent has finished or is waiting)
62
43
  // Match common prompt patterns at end of last non-empty line
63
- const lastNonEmpty = lines.filter(l => l.trim().length > 0).pop() || '';
44
+ const lastNonEmpty = [...lines].reverse().find((l) => l.trim().length > 0) || '';
64
45
  if (/[$❯#>]\s*$/.test(lastNonEmpty) || /^\s*\$\s*$/.test(lastNonEmpty)) {
65
46
  return 'IDLE';
66
47
  }
@@ -1,11 +1,12 @@
1
1
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
2
2
  import { shouldOutputJson } from '../../lib/prompt-json.js';
3
3
  export default class Session extends PMOCommand {
4
- static description = 'Manage agent tmux sessions (list, attach, detach)';
4
+ static description = 'Manage agent tmux sessions (list, attach, create, detach)';
5
5
  static examples = [
6
6
  '<%= config.bin %> <%= command.id %>',
7
7
  '<%= config.bin %> <%= command.id %> list',
8
8
  '<%= config.bin %> <%= command.id %> attach TKT-347-implement',
9
+ '<%= config.bin %> <%= command.id %> create my-session',
9
10
  ];
10
11
  static flags = {
11
12
  ...pmoBaseFlags,
@@ -22,8 +23,11 @@ export default class Session extends PMOCommand {
22
23
  message: 'Session Management - What would you like to do?',
23
24
  choices: [
24
25
  { name: 'List active sessions', value: 'list', command: 'prlt session list --json' },
26
+ { name: 'Create a new session', value: 'create', command: 'prlt session create --json' },
25
27
  { name: 'Attach to a session', value: 'attach', command: 'prlt session attach --json' },
28
+ { name: 'Peek at agent output', value: 'peek', command: 'prlt session peek --json' },
26
29
  { name: 'Check agent health', value: 'health', command: 'prlt session health --json' },
30
+ { name: 'Poke a running agent', value: 'poke', command: 'prlt session poke --json' },
27
31
  { name: 'Cancel', value: 'cancel' },
28
32
  ],
29
33
  }], jsonModeConfig);
@@ -35,12 +39,21 @@ export default class Session extends PMOCommand {
35
39
  case 'list':
36
40
  await this.config.runCommand('session:list', []);
37
41
  break;
42
+ case 'create':
43
+ await this.config.runCommand('session:create', []);
44
+ break;
38
45
  case 'attach':
39
46
  await this.config.runCommand('session:attach', []);
40
47
  break;
48
+ case 'peek':
49
+ await this.config.runCommand('session:peek', []);
50
+ break;
41
51
  case 'health':
42
52
  await this.config.runCommand('session:health', []);
43
53
  break;
54
+ case 'poke':
55
+ await this.config.runCommand('session:poke', []);
56
+ break;
44
57
  }
45
58
  }
46
59
  }