@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,18 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class SpecLinkDepends extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ spec: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ target: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
8
+ };
9
+ static flags: {
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,86 @@
1
+ import { Args } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { styles } from '../../../lib/styles.js';
4
+ import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
5
+ export default class SpecLinkDepends extends PMOCommand {
6
+ static description = 'Add a dependency between specs';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %> SPEC-001 SPEC-002',
9
+ '<%= config.bin %> <%= command.id %> SPEC-001 --machine',
10
+ ];
11
+ static args = {
12
+ spec: Args.string({
13
+ description: 'Source spec ID (the one that depends on another)',
14
+ required: true,
15
+ }),
16
+ target: Args.string({
17
+ description: 'Target spec ID (the one depended upon)',
18
+ required: false,
19
+ }),
20
+ };
21
+ static flags = {
22
+ ...pmoBaseFlags,
23
+ };
24
+ getPMOOptions() {
25
+ return { promptIfMultiple: false };
26
+ }
27
+ async execute() {
28
+ const { args, flags } = await this.parse(SpecLinkDepends);
29
+ const jsonMode = shouldOutputJson(flags);
30
+ const handleError = (code, message) => {
31
+ if (jsonMode) {
32
+ outputErrorAsJson(code, message, createMetadata('spec link depends', flags));
33
+ this.exit(1);
34
+ }
35
+ this.error(message);
36
+ };
37
+ // Verify source spec exists
38
+ const sourceSpec = await this.storage.getSpec(args.spec);
39
+ if (!sourceSpec) {
40
+ return handleError('SPEC_NOT_FOUND', `Spec not found: ${args.spec}`);
41
+ }
42
+ // If target not provided, prompt for selection
43
+ if (!args.target) {
44
+ const specs = await this.storage.listSpecs();
45
+ const otherSpecs = specs.filter(s => s.id !== args.spec);
46
+ if (otherSpecs.length === 0) {
47
+ return handleError('NO_SPECS', 'No other specs to select as dependency.');
48
+ }
49
+ const choices = otherSpecs.map(s => ({
50
+ name: `${s.id} - ${s.title}`,
51
+ value: s.id,
52
+ command: `prlt spec link depends ${args.spec} ${s.id} --json`,
53
+ }));
54
+ const message = `Select spec that ${args.spec} depends on:`;
55
+ if (jsonMode) {
56
+ outputPromptAsJson(buildPromptConfig('list', 'target', message, choices), createMetadata('spec link depends', flags));
57
+ return;
58
+ }
59
+ const { selected } = await this.prompt([{
60
+ type: 'list',
61
+ name: 'selected',
62
+ message,
63
+ choices,
64
+ }], null);
65
+ args.target = selected;
66
+ }
67
+ // Verify target spec exists
68
+ const targetSpec = await this.storage.getSpec(args.target);
69
+ if (!targetSpec) {
70
+ return handleError('TARGET_NOT_FOUND', `Spec not found: ${args.target}`);
71
+ }
72
+ // Create the dependency
73
+ try {
74
+ await this.storage.createSpecDependency(args.spec, args.target, 'depends_on');
75
+ this.log(styles.success(`\n${args.spec} now depends on ${args.target}`));
76
+ this.log(styles.muted(` ${sourceSpec.title}`));
77
+ this.log(styles.muted(` depends on: ${targetSpec.title}`));
78
+ }
79
+ catch (error) {
80
+ if (error instanceof Error && error.message.includes('already exists')) {
81
+ return handleError('ALREADY_EXISTS', 'Dependency already exists.');
82
+ }
83
+ throw error;
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,17 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class SpecLink extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ spec: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ };
13
+ protected getPMOOptions(): {
14
+ promptIfMultiple: boolean;
15
+ };
16
+ execute(): Promise<void>;
17
+ }
@@ -0,0 +1,92 @@
1
+ import { Args } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { styles } from '../../../lib/styles.js';
4
+ import { shouldOutputJson, outputPromptAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
5
+ export default class SpecLink extends PMOCommand {
6
+ static description = 'Manage links (dependencies) for a spec';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %>',
9
+ '<%= config.bin %> <%= command.id %> SPEC-001',
10
+ '<%= config.bin %> <%= command.id %> --machine',
11
+ ];
12
+ static args = {
13
+ spec: Args.string({
14
+ description: 'Spec ID',
15
+ required: false,
16
+ }),
17
+ };
18
+ static flags = {
19
+ ...pmoBaseFlags,
20
+ };
21
+ getPMOOptions() {
22
+ return { promptIfMultiple: false };
23
+ }
24
+ async execute() {
25
+ const { args, flags } = await this.parse(SpecLink);
26
+ const jsonMode = shouldOutputJson(flags);
27
+ // If no spec ID provided, prompt for selection
28
+ if (!args.spec) {
29
+ const specs = await this.storage.listSpecs();
30
+ if (specs.length === 0) {
31
+ this.log(styles.muted('No specs found.'));
32
+ return;
33
+ }
34
+ const choices = specs.map(s => ({
35
+ name: `${s.id} - ${s.title}`,
36
+ value: s.id,
37
+ command: `prlt spec link ${s.id} --machine`,
38
+ }));
39
+ const message = 'Select a spec to manage links:';
40
+ if (jsonMode) {
41
+ outputPromptAsJson(buildPromptConfig('list', 'id', message, choices), createMetadata('spec link', flags));
42
+ return;
43
+ }
44
+ const { selected } = await this.prompt([{
45
+ type: 'list',
46
+ name: 'selected',
47
+ message,
48
+ choices,
49
+ }], null);
50
+ args.spec = selected;
51
+ }
52
+ const spec = await this.storage.getSpec(args.spec);
53
+ if (!spec) {
54
+ this.error(`Spec not found: ${args.spec}`);
55
+ }
56
+ // Show link actions submenu
57
+ const menuChoices = [
58
+ { name: 'Add dependency', value: 'depends', command: `prlt spec link depends ${args.spec} --machine` },
59
+ { name: 'Remove dependency', value: 'remove', command: `prlt spec link remove ${args.spec} --machine` },
60
+ { name: 'Cancel', value: 'cancel', command: '' },
61
+ ];
62
+ const message = `Manage links for ${args.spec}: ${spec.title}`;
63
+ if (jsonMode) {
64
+ outputPromptAsJson(buildPromptConfig('list', 'action', message, menuChoices), createMetadata('spec link', flags));
65
+ return;
66
+ }
67
+ const { action } = await this.prompt([{
68
+ type: 'list',
69
+ name: 'action',
70
+ message,
71
+ choices: menuChoices,
72
+ }], null);
73
+ if (action === 'cancel') {
74
+ this.log(styles.muted('Cancelled.'));
75
+ return;
76
+ }
77
+ switch (action) {
78
+ case 'depends': {
79
+ const { default: DependsCommand } = await import('./depends.js');
80
+ const cmd = new DependsCommand([args.spec], this.config);
81
+ await cmd.run();
82
+ break;
83
+ }
84
+ case 'remove': {
85
+ const { default: RemoveCommand } = await import('./remove.js');
86
+ const cmd = new RemoveCommand([args.spec], this.config);
87
+ await cmd.run();
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,18 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class SpecLinkRemove extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ spec: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ target: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
8
+ };
9
+ static flags: {
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,90 @@
1
+ import { Args } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { styles } from '../../../lib/styles.js';
4
+ import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
5
+ export default class SpecLinkRemove extends PMOCommand {
6
+ static description = 'Remove a dependency between specs';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %> SPEC-001 SPEC-002',
9
+ '<%= config.bin %> <%= command.id %> SPEC-001 --machine',
10
+ ];
11
+ static args = {
12
+ spec: Args.string({
13
+ description: 'Source spec ID',
14
+ required: true,
15
+ }),
16
+ target: Args.string({
17
+ description: 'Target spec ID to remove dependency from',
18
+ required: false,
19
+ }),
20
+ };
21
+ static flags = {
22
+ ...pmoBaseFlags,
23
+ };
24
+ getPMOOptions() {
25
+ return { promptIfMultiple: false };
26
+ }
27
+ async execute() {
28
+ const { args, flags } = await this.parse(SpecLinkRemove);
29
+ const jsonMode = shouldOutputJson(flags);
30
+ const handleError = (code, message) => {
31
+ if (jsonMode) {
32
+ outputErrorAsJson(code, message, createMetadata('spec link remove', flags));
33
+ this.exit(1);
34
+ }
35
+ this.error(message);
36
+ };
37
+ // Verify source spec exists
38
+ const sourceSpec = await this.storage.getSpec(args.spec);
39
+ if (!sourceSpec) {
40
+ return handleError('SPEC_NOT_FOUND', `Spec not found: ${args.spec}`);
41
+ }
42
+ // If target not provided, show existing dependencies for selection
43
+ if (!args.target) {
44
+ const dependencies = await this.storage.listSpecDependencies(args.spec);
45
+ if (dependencies.length === 0) {
46
+ if (jsonMode) {
47
+ outputErrorAsJson('NO_DEPENDENCIES', `No dependencies found for ${args.spec}.`, createMetadata('spec link remove', flags));
48
+ return;
49
+ }
50
+ this.log(styles.muted(`No dependencies found for ${args.spec}.`));
51
+ return;
52
+ }
53
+ // Get spec details for dependency targets
54
+ const choices = [];
55
+ for (const dep of dependencies) {
56
+ // eslint-disable-next-line no-await-in-loop
57
+ const targetSpec = await this.storage.getSpec(dep.dependsOnSpecId);
58
+ const name = targetSpec ? `${dep.dependsOnSpecId} - ${targetSpec.title} (${dep.dependencyType})` : `${dep.dependsOnSpecId} (${dep.dependencyType})`;
59
+ choices.push({
60
+ name,
61
+ value: dep.dependsOnSpecId,
62
+ command: `prlt spec link remove ${args.spec} ${dep.dependsOnSpecId} --json`,
63
+ });
64
+ }
65
+ const message = `Select dependency to remove from ${args.spec}:`;
66
+ if (jsonMode) {
67
+ outputPromptAsJson(buildPromptConfig('list', 'target', message, choices), createMetadata('spec link remove', flags));
68
+ return;
69
+ }
70
+ const { selected } = await this.prompt([{
71
+ type: 'list',
72
+ name: 'selected',
73
+ message,
74
+ choices,
75
+ }], null);
76
+ args.target = selected;
77
+ }
78
+ // Remove the dependency
79
+ try {
80
+ await this.storage.deleteSpecDependency(args.spec, args.target);
81
+ this.log(styles.success(`\nRemoved dependency: ${args.spec} no longer depends on ${args.target}`));
82
+ }
83
+ catch (error) {
84
+ if (error instanceof Error && error.message.includes('not found')) {
85
+ return handleError('NOT_FOUND', `Dependency not found between ${args.spec} and ${args.target}`);
86
+ }
87
+ throw error;
88
+ }
89
+ }
90
+ }
@@ -83,6 +83,35 @@ export default class SpecView extends PMOCommand {
83
83
  // Get dependencies
84
84
  const dependencies = await this.storage.getSpecDependencies(spec.id);
85
85
  const dependents = await this.storage.getSpecDependents(spec.id);
86
+ // JSON output mode
87
+ if (jsonMode) {
88
+ this.log(JSON.stringify({
89
+ success: true,
90
+ spec: {
91
+ id: spec.id,
92
+ title: spec.title,
93
+ status: spec.status,
94
+ type: spec.type,
95
+ problem: spec.problem,
96
+ solution: spec.solution,
97
+ decisions: spec.decisions,
98
+ notNow: spec.notNow,
99
+ uiUx: spec.uiUx,
100
+ acceptanceCriteria: spec.acceptanceCriteria,
101
+ openQuestions: spec.openQuestions,
102
+ requirementsFunctional: spec.requirementsFunctional,
103
+ requirementsTechnical: spec.requirementsTechnical,
104
+ context: spec.context,
105
+ tags: spec.tags,
106
+ createdAt: spec.createdAt.toISOString(),
107
+ updatedAt: spec.updatedAt.toISOString(),
108
+ dependencies: dependencies.map(d => ({ id: d.id, title: d.title, status: d.status })),
109
+ dependents: dependents.map(d => ({ id: d.id, title: d.title, status: d.status })),
110
+ tickets: tickets.map(t => ({ id: t.id, title: t.title, status: t.status })),
111
+ },
112
+ }, null, 2));
113
+ return;
114
+ }
86
115
  // Display spec info
87
116
  this.log(styles.title(`\n📄 ${spec.title}`));
88
117
  this.log(styles.muted('═'.repeat(60)));
@@ -210,8 +210,8 @@ export default class SupportLogs extends PMOCommand {
210
210
  copyToClipboard(text) {
211
211
  const platform = process.platform;
212
212
  // Strip ANSI codes for clipboard
213
- // biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ANSI escape code stripping
214
- const plainText = text.replace(/\x1b\[[0-9;]*m/g, '');
213
+ // eslint-disable-next-line no-control-regex -- intentional ANSI escape code stripping
214
+ const plainText = text.replace(/\u001B\[[0-9;]*m/g, '');
215
215
  try {
216
216
  if (platform === 'darwin') {
217
217
  execSync('pbcopy', { input: plainText, encoding: 'utf-8' });
@@ -135,10 +135,10 @@ export default class TemplateApply extends PMOCommand {
135
135
  let title = flags.title || template.titlePattern || '';
136
136
  let column = flags.column || columns[0];
137
137
  let priority = flags.priority || template.defaultPriority;
138
- let category = flags.category || template.defaultCategory;
139
- let assignee = flags.assignee || template.defaultAssignee;
140
- let owner = flags.owner || template.defaultOwner;
141
- let description = flags.description || template.descriptionTemplate;
138
+ const category = flags.category || template.defaultCategory;
139
+ const assignee = flags.assignee || template.defaultAssignee;
140
+ const owner = flags.owner || template.defaultOwner;
141
+ const description = flags.description || template.descriptionTemplate;
142
142
  const labels = template.defaultLabels;
143
143
  // Interactive mode
144
144
  if (flags.interactive || !title) {
@@ -182,6 +182,7 @@ export default class TemplateApply extends PMOCommand {
182
182
  // Add subtasks
183
183
  if (!flags['no-subtasks'] && template.suggestedSubtasks.length > 0) {
184
184
  for (const subtask of template.suggestedSubtasks) {
185
+ // eslint-disable-next-line no-await-in-loop
185
186
  await this.storage.addSubtask(ticket.id, subtask.title);
186
187
  }
187
188
  }
@@ -135,7 +135,7 @@ export default class TemplateCreate extends PMOCommand {
135
135
  }
136
136
  // Get optional values
137
137
  let description = flags.description;
138
- let titlePattern = flags['title-pattern'];
138
+ const titlePattern = flags['title-pattern'];
139
139
  let priority = flags.priority;
140
140
  let category = flags.category;
141
141
  const subtasks = flags.subtask || [];
@@ -1,5 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
3
+ import { shouldOutputJson } from '../../lib/prompt-json.js';
3
4
  import { styles } from '../../lib/styles.js';
4
5
  export default class TemplateList extends PMOCommand {
5
6
  static description = 'List all templates (ticket and phase)';
@@ -44,7 +45,7 @@ export default class TemplateList extends PMOCommand {
44
45
  showTicket ? this.storage.listTicketTemplates(builtinFilter) : Promise.resolve([]),
45
46
  showPhase ? this.storage.listPhaseTemplates(builtinFilter) : Promise.resolve([]),
46
47
  ]);
47
- if (flags.json || flags.machine) {
48
+ if (shouldOutputJson(flags)) {
48
49
  const result = {};
49
50
  if (showTicket)
50
51
  result.ticket = ticketTemplates;
@@ -2,6 +2,10 @@ import { Command } from '@oclif/core';
2
2
  export default class ThemeAddNames extends Command {
3
3
  static description: string;
4
4
  static examples: string[];
5
+ static flags: {
6
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ };
5
9
  static args: {
6
10
  theme: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
11
  names: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
@@ -3,12 +3,17 @@ import chalk from 'chalk';
3
3
  import { getWorkspaceInfo } from '../../lib/agents/commands.js';
4
4
  import { isValidAgentName, normalizeAgentName } from '../../lib/themes.js';
5
5
  import { getTheme, addThemeNames, getThemeNames } from '../../lib/database/index.js';
6
+ import { machineOutputFlags } from '../../lib/pmo/index.js';
7
+ import { shouldOutputJson } from '../../lib/prompt-json.js';
6
8
  export default class ThemeAddNames extends Command {
7
9
  static description = 'Add names to a theme';
8
10
  static examples = [
9
11
  '<%= config.bin %> <%= command.id %> greek-gods zeus athena poseidon',
10
12
  '<%= config.bin %> <%= command.id %> my-theme agent-a agent-b',
11
13
  ];
14
+ static flags = {
15
+ ...machineOutputFlags,
16
+ };
12
17
  static args = {
13
18
  theme: Args.string({
14
19
  description: 'Theme ID',
@@ -21,7 +26,8 @@ export default class ThemeAddNames extends Command {
21
26
  };
22
27
  static strict = false; // Allow multiple name arguments
23
28
  async run() {
24
- const { args, argv } = await this.parse(ThemeAddNames);
29
+ const { args, argv, flags } = await this.parse(ThemeAddNames);
30
+ const jsonMode = shouldOutputJson(flags);
25
31
  try {
26
32
  const workspaceInfo = getWorkspaceInfo();
27
33
  // Validate theme exists
@@ -60,6 +66,10 @@ export default class ThemeAddNames extends Command {
60
66
  addThemeNames(workspaceInfo.path, theme.id, validNames);
61
67
  // Get updated count
62
68
  const allNames = getThemeNames(workspaceInfo.path, theme.id);
69
+ if (jsonMode) {
70
+ this.log(JSON.stringify({ type: 'success', result: { theme: args.theme, added: validNames, totalNames: allNames.length } }, null, 2));
71
+ return;
72
+ }
63
73
  this.log(chalk.green(`\n Added ${validNames.length} name(s) to ${theme.display_name}:`));
64
74
  this.log(chalk.gray(` ${validNames.join(', ')}`));
65
75
  this.log(chalk.gray(`\n Theme now has ${allNames.length} names total.`));
@@ -8,6 +8,8 @@ export default class ThemeCreate extends Command {
8
8
  static flags: {
9
9
  description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
10
  'display-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
13
  };
12
14
  run(): Promise<void>;
13
15
  }
@@ -2,6 +2,8 @@ import { Command, Args, Flags } from '@oclif/core';
2
2
  import chalk from 'chalk';
3
3
  import { getWorkspaceInfo } from '../../lib/agents/commands.js';
4
4
  import { createTheme, getTheme } from '../../lib/database/index.js';
5
+ import { machineOutputFlags } from '../../lib/pmo/index.js';
6
+ import { shouldOutputJson } from '../../lib/prompt-json.js';
5
7
  export default class ThemeCreate extends Command {
6
8
  static description = 'Create a custom agent theme';
7
9
  static examples = [
@@ -16,6 +18,7 @@ export default class ThemeCreate extends Command {
16
18
  }),
17
19
  };
18
20
  static flags = {
21
+ ...machineOutputFlags,
19
22
  description: Flags.string({
20
23
  char: 'd',
21
24
  description: 'Theme description',
@@ -26,6 +29,7 @@ export default class ThemeCreate extends Command {
26
29
  };
27
30
  async run() {
28
31
  const { args, flags } = await this.parse(ThemeCreate);
32
+ const jsonMode = shouldOutputJson(flags);
29
33
  try {
30
34
  const workspaceInfo = getWorkspaceInfo();
31
35
  // Validate theme name format
@@ -51,6 +55,10 @@ export default class ThemeCreate extends Command {
51
55
  description: flags.description,
52
56
  builtin: false,
53
57
  });
58
+ if (jsonMode) {
59
+ this.log(JSON.stringify({ type: 'success', result: { id: theme.id, displayName: theme.display_name, description: theme.description } }, null, 2));
60
+ return;
61
+ }
54
62
  this.log(chalk.green(`\n Created theme: ${theme.display_name}`));
55
63
  this.log(chalk.gray(` ID: ${theme.id}`));
56
64
  if (theme.description) {
@@ -45,7 +45,7 @@ export default class TicketBulk extends PMOCommand {
45
45
  const choice = menuChoices.find(c => c.value === value);
46
46
  return { name: choice.emoji ? `${choice.emoji} ${choice.name}` : choice.name, value: choice.value };
47
47
  };
48
- const { action } = await inquirer.prompt([{
48
+ const { action } = await this.prompt([{
49
49
  type: 'list',
50
50
  name: 'action',
51
51
  message: 'What would you like to do?',
@@ -64,7 +64,7 @@ export default class TicketBulk extends PMOCommand {
64
64
  new inquirer.Separator(),
65
65
  withEmoji('cancel'),
66
66
  ]
67
- }]);
67
+ }], null);
68
68
  if (action === 'cancel') {
69
69
  this.log(styles.muted('Operation cancelled.'));
70
70
  return;
@@ -98,11 +98,11 @@ export default class TicketComplete extends PMOCommand {
98
98
  }
99
99
  async executeBulk(incompleteTickets, doneColumnName, flags) {
100
100
  // Only show header in interactive mode
101
- if (!(flags.json || flags.machine)) {
101
+ if (!shouldOutputJson(flags)) {
102
102
  this.log(styles.emphasis('✅ Complete Multiple Tickets\n'));
103
103
  }
104
104
  // Agent mode config for prompts
105
- const jsonModeConfig = (flags.json || flags.machine) ? { flags, commandName: 'ticket complete --bulk' } : null;
105
+ const jsonModeConfig = shouldOutputJson(flags) ? { flags, commandName: 'ticket complete --bulk' } : null;
106
106
  // Select tickets to complete (now agent-compatible!)
107
107
  const { selectedTickets } = await this.prompt([{
108
108
  type: 'checkbox',
@@ -284,6 +284,27 @@ export default class TicketCreate extends PMOCommand {
284
284
  updateEpicTicketsSection(this.pmoPath, ticketData.epicId, epic.status, ticketInfos, projectId);
285
285
  }
286
286
  }
287
+ // JSON output mode - match MCP tool response shape
288
+ if (jsonMode) {
289
+ this.log(JSON.stringify({
290
+ success: true,
291
+ ticket: {
292
+ id: ticket.id,
293
+ title: ticket.title,
294
+ priority: ticket.priority,
295
+ category: ticket.category,
296
+ statusName: ticket.statusName,
297
+ statusCategory: ticket.statusCategory,
298
+ projectId: ticket.projectId,
299
+ assignee: ticket.assignee,
300
+ owner: ticket.owner,
301
+ branch: ticket.branch,
302
+ epicId: ticket.epicId,
303
+ position: ticket.position,
304
+ },
305
+ }, null, 2));
306
+ return;
307
+ }
287
308
  this.log(styles.success(`\n✅ Created ticket ${styles.emphasis(ticket.id)} in project ${styles.emphasis(projectName)}`));
288
309
  if (template) {
289
310
  this.log(styles.muted(` Template: ${template.name}`));
@@ -103,6 +103,14 @@ export default class TicketDelete extends PMOCommand {
103
103
  await this.storage.deleteTicket(ticketId);
104
104
  // Auto-export to board.md after write
105
105
  await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
106
+ // JSON output mode - match MCP tool response shape
107
+ if (jsonMode) {
108
+ this.log(JSON.stringify({
109
+ success: true,
110
+ message: `Deleted ${ticketId}`,
111
+ }, null, 2));
112
+ return;
113
+ }
106
114
  this.log(styles.success(`\n✅ Ticket ${styles.emphasis(ticketId)} deleted`));
107
115
  this.log(styles.muted(' Removed from database and board'));
108
116
  }
@@ -227,6 +227,31 @@ export default class TicketEdit extends PMOCommand {
227
227
  const updatedTicket = await this.storage.updateTicket(ticketId, updates);
228
228
  // Auto-export to board.md
229
229
  await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
230
+ // JSON output mode - match MCP tool response shape
231
+ if (jsonMode) {
232
+ // Re-fetch to get latest state including subtasks/AC changes
233
+ const finalTicket = (subtasksChanged || acChanged)
234
+ ? await this.storage.getTicket(ticketId) ?? updatedTicket
235
+ : updatedTicket;
236
+ this.log(JSON.stringify({
237
+ success: true,
238
+ ticket: {
239
+ id: finalTicket.id,
240
+ title: finalTicket.title,
241
+ priority: finalTicket.priority,
242
+ category: finalTicket.category,
243
+ statusName: finalTicket.statusName,
244
+ statusCategory: finalTicket.statusCategory,
245
+ projectId: finalTicket.projectId,
246
+ assignee: finalTicket.assignee,
247
+ owner: finalTicket.owner,
248
+ branch: finalTicket.branch,
249
+ epicId: finalTicket.epicId,
250
+ position: finalTicket.position,
251
+ },
252
+ }, null, 2));
253
+ return;
254
+ }
230
255
  // Display updated ticket
231
256
  this.log(styles.success(`\n✅ Updated ticket ${styles.emphasis(updatedTicket.id)}`));
232
257
  const changedFields = [];
@@ -41,7 +41,7 @@ export default class Ticket extends PMOCommand {
41
41
  return;
42
42
  }
43
43
  // Show interactive menu
44
- const { action } = await inquirer.prompt([{
44
+ const { action } = await this.prompt([{
45
45
  type: 'list',
46
46
  name: 'action',
47
47
  message: '🎫 ' + message,
@@ -52,7 +52,7 @@ export default class Ticket extends PMOCommand {
52
52
  menuChoices[12],
53
53
  menuChoices[13],
54
54
  ],
55
- }]);
55
+ }], null);
56
56
  if (action === 'cancel') {
57
57
  return;
58
58
  }