@proletariat/cli 0.3.55 → 0.3.57

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 (246) hide show
  1. package/README.md +74 -5
  2. package/bin/validate-better-sqlite3.cjs +44 -5
  3. package/dist/commands/agent/cleanup.d.ts +1 -0
  4. package/dist/commands/agent/cleanup.js +11 -1
  5. package/dist/commands/agent/cleanup.js.map +1 -1
  6. package/dist/commands/agent/rebuild.js +1 -1
  7. package/dist/commands/agent/rebuild.js.map +1 -1
  8. package/dist/commands/asana/import.d.ts +14 -0
  9. package/dist/commands/asana/import.js +240 -0
  10. package/dist/commands/asana/import.js.map +1 -0
  11. package/dist/commands/claude-yolo.d.ts +20 -0
  12. package/dist/commands/claude-yolo.js +86 -0
  13. package/dist/commands/claude-yolo.js.map +1 -0
  14. package/dist/commands/codex/index.d.ts +23 -0
  15. package/dist/commands/codex/index.js +168 -0
  16. package/dist/commands/codex/index.js.map +1 -0
  17. package/dist/commands/codex-yolo.d.ts +20 -0
  18. package/dist/commands/codex-yolo.js +86 -0
  19. package/dist/commands/codex-yolo.js.map +1 -0
  20. package/dist/commands/config/index.js +2 -2
  21. package/dist/commands/config/index.js.map +1 -1
  22. package/dist/commands/dashboard.d.ts +38 -0
  23. package/dist/commands/dashboard.js +352 -0
  24. package/dist/commands/dashboard.js.map +1 -0
  25. package/dist/commands/docker/clean.js +1 -1
  26. package/dist/commands/docker/clean.js.map +1 -1
  27. package/dist/commands/docker/list.js +1 -1
  28. package/dist/commands/docker/list.js.map +1 -1
  29. package/dist/commands/docker/logs.js +1 -1
  30. package/dist/commands/docker/logs.js.map +1 -1
  31. package/dist/commands/docker/restart.js +1 -1
  32. package/dist/commands/docker/restart.js.map +1 -1
  33. package/dist/commands/docker/shell.js +1 -1
  34. package/dist/commands/docker/shell.js.map +1 -1
  35. package/dist/commands/docker/start.js +1 -1
  36. package/dist/commands/docker/start.js.map +1 -1
  37. package/dist/commands/docker/stop.js +1 -1
  38. package/dist/commands/docker/stop.js.map +1 -1
  39. package/dist/commands/docker/sync.js +1 -1
  40. package/dist/commands/docker/sync.js.map +1 -1
  41. package/dist/commands/execution/config.js +2 -2
  42. package/dist/commands/execution/config.js.map +1 -1
  43. package/dist/commands/execution/list.js +1 -1
  44. package/dist/commands/execution/list.js.map +1 -1
  45. package/dist/commands/execution/logs.js +10 -8
  46. package/dist/commands/execution/logs.js.map +1 -1
  47. package/dist/commands/execution/stop.js +1 -1
  48. package/dist/commands/execution/stop.js.map +1 -1
  49. package/dist/commands/execution/view.js +1 -1
  50. package/dist/commands/execution/view.js.map +1 -1
  51. package/dist/commands/init.d.ts +0 -16
  52. package/dist/commands/init.js +50 -160
  53. package/dist/commands/init.js.map +1 -1
  54. package/dist/commands/logs.d.ts +20 -0
  55. package/dist/commands/logs.js +84 -0
  56. package/dist/commands/logs.js.map +1 -0
  57. package/dist/commands/mcp-server.js +1 -1
  58. package/dist/commands/mcp-server.js.map +1 -1
  59. package/dist/commands/new.d.ts +27 -0
  60. package/dist/commands/new.js +184 -0
  61. package/dist/commands/new.js.map +1 -0
  62. package/dist/commands/orchestrator/attach.d.ts +1 -0
  63. package/dist/commands/orchestrator/attach.js +159 -26
  64. package/dist/commands/orchestrator/attach.js.map +1 -1
  65. package/dist/commands/orchestrator/start.d.ts +20 -0
  66. package/dist/commands/orchestrator/start.js +123 -14
  67. package/dist/commands/orchestrator/start.js.map +1 -1
  68. package/dist/commands/orchestrator/status.d.ts +4 -0
  69. package/dist/commands/orchestrator/status.js +70 -29
  70. package/dist/commands/orchestrator/status.js.map +1 -1
  71. package/dist/commands/orchestrator/stop.js +57 -23
  72. package/dist/commands/orchestrator/stop.js.map +1 -1
  73. package/dist/commands/peek.d.ts +20 -0
  74. package/dist/commands/peek.js +84 -0
  75. package/dist/commands/peek.js.map +1 -0
  76. package/dist/commands/poke.d.ts +20 -0
  77. package/dist/commands/poke.js +89 -0
  78. package/dist/commands/poke.js.map +1 -0
  79. package/dist/commands/pr/link.js +1 -1
  80. package/dist/commands/pr/link.js.map +1 -1
  81. package/dist/commands/pr/status.js +1 -1
  82. package/dist/commands/pr/status.js.map +1 -1
  83. package/dist/commands/ps.d.ts +18 -0
  84. package/dist/commands/ps.js +123 -0
  85. package/dist/commands/ps.js.map +1 -0
  86. package/dist/commands/qa/index.js +1 -1
  87. package/dist/commands/qa/index.js.map +1 -1
  88. package/dist/commands/repo/add.js +1 -1
  89. package/dist/commands/repo/add.js.map +1 -1
  90. package/dist/commands/repo/fix-remotes.d.ts +14 -0
  91. package/dist/commands/repo/fix-remotes.js +154 -0
  92. package/dist/commands/repo/fix-remotes.js.map +1 -0
  93. package/dist/commands/repo/list.js +1 -1
  94. package/dist/commands/repo/list.js.map +1 -1
  95. package/dist/commands/repo/remove.js +1 -1
  96. package/dist/commands/repo/remove.js.map +1 -1
  97. package/dist/commands/repo/view.js +1 -1
  98. package/dist/commands/repo/view.js.map +1 -1
  99. package/dist/commands/run/index.d.ts +25 -0
  100. package/dist/commands/run/index.js +212 -0
  101. package/dist/commands/run/index.js.map +1 -0
  102. package/dist/commands/session/index.js +4 -0
  103. package/dist/commands/session/index.js.map +1 -1
  104. package/dist/commands/session/prune.d.ts +18 -0
  105. package/dist/commands/session/prune.js +327 -0
  106. package/dist/commands/session/prune.js.map +1 -0
  107. package/dist/commands/shortcut/connect.d.ts +15 -0
  108. package/dist/commands/shortcut/connect.js +210 -0
  109. package/dist/commands/shortcut/connect.js.map +1 -0
  110. package/dist/commands/stop.d.ts +19 -0
  111. package/dist/commands/stop.js +83 -0
  112. package/dist/commands/stop.js.map +1 -0
  113. package/dist/commands/work/asana.d.ts +23 -0
  114. package/dist/commands/work/asana.js +213 -0
  115. package/dist/commands/work/asana.js.map +1 -0
  116. package/dist/commands/work/complete.js +1 -1
  117. package/dist/commands/work/complete.js.map +1 -1
  118. package/dist/commands/work/ready.js +1 -1
  119. package/dist/commands/work/ready.js.map +1 -1
  120. package/dist/commands/work/review.js +1 -1
  121. package/dist/commands/work/review.js.map +1 -1
  122. package/dist/commands/work/revise.js +1 -1
  123. package/dist/commands/work/revise.js.map +1 -1
  124. package/dist/commands/work/shortcut.d.ts +23 -0
  125. package/dist/commands/work/shortcut.js +212 -0
  126. package/dist/commands/work/shortcut.js.map +1 -0
  127. package/dist/commands/work/spawn.d.ts +3 -0
  128. package/dist/commands/work/spawn.js +175 -2
  129. package/dist/commands/work/spawn.js.map +1 -1
  130. package/dist/commands/work/start.js +54 -45
  131. package/dist/commands/work/start.js.map +1 -1
  132. package/dist/commands/work/watch.js +1 -1
  133. package/dist/commands/work/watch.js.map +1 -1
  134. package/dist/commands/workspace/add.js +1 -1
  135. package/dist/commands/workspace/add.js.map +1 -1
  136. package/dist/commands/workspace/list.js +1 -1
  137. package/dist/commands/workspace/list.js.map +1 -1
  138. package/dist/hooks/init.d.ts +1 -1
  139. package/dist/hooks/init.js +6 -6
  140. package/dist/hooks/init.js.map +1 -1
  141. package/dist/lib/agent-naming.d.ts +15 -0
  142. package/dist/lib/agent-naming.js +32 -0
  143. package/dist/lib/agent-naming.js.map +1 -0
  144. package/dist/lib/agents/commands.d.ts +2 -0
  145. package/dist/lib/agents/commands.js +56 -51
  146. package/dist/lib/agents/commands.js.map +1 -1
  147. package/dist/lib/agents/index.js +11 -7
  148. package/dist/lib/agents/index.js.map +1 -1
  149. package/dist/lib/asana/client.d.ts +8 -0
  150. package/dist/lib/asana/client.js +26 -7
  151. package/dist/lib/asana/client.js.map +1 -1
  152. package/dist/lib/asana/types.d.ts +20 -0
  153. package/dist/lib/branch/index.d.ts +36 -0
  154. package/dist/lib/branch/index.js +129 -0
  155. package/dist/lib/branch/index.js.map +1 -1
  156. package/dist/lib/database/index.js +1 -1
  157. package/dist/lib/database/index.js.map +1 -1
  158. package/dist/lib/database/native-validation.d.ts +2 -0
  159. package/dist/lib/database/native-validation.js +30 -1
  160. package/dist/lib/database/native-validation.js.map +1 -1
  161. package/dist/lib/events/emitting-runner.d.ts +30 -0
  162. package/dist/lib/events/emitting-runner.js +95 -0
  163. package/dist/lib/events/emitting-runner.js.map +1 -0
  164. package/dist/lib/events/event-bus.d.ts +54 -0
  165. package/dist/lib/events/event-bus.js +107 -0
  166. package/dist/lib/events/event-bus.js.map +1 -0
  167. package/dist/lib/events/events.d.ts +67 -0
  168. package/dist/lib/events/events.js +8 -0
  169. package/dist/lib/events/events.js.map +1 -0
  170. package/dist/lib/events/index.d.ts +7 -0
  171. package/dist/lib/events/index.js +6 -0
  172. package/dist/lib/events/index.js.map +1 -0
  173. package/dist/lib/execution/devcontainer.d.ts +27 -0
  174. package/dist/lib/execution/devcontainer.js +80 -0
  175. package/dist/lib/execution/devcontainer.js.map +1 -1
  176. package/dist/lib/execution/runners.d.ts +28 -0
  177. package/dist/lib/execution/runners.js +536 -35
  178. package/dist/lib/execution/runners.js.map +1 -1
  179. package/dist/lib/execution/spawner.js +38 -17
  180. package/dist/lib/execution/spawner.js.map +1 -1
  181. package/dist/lib/execution/types.d.ts +2 -0
  182. package/dist/lib/execution/types.js.map +1 -1
  183. package/dist/lib/external-issues/adapters.d.ts +34 -0
  184. package/dist/lib/external-issues/adapters.js +191 -0
  185. package/dist/lib/external-issues/adapters.js.map +1 -1
  186. package/dist/lib/external-issues/asana.d.ts +75 -0
  187. package/dist/lib/external-issues/asana.js +243 -0
  188. package/dist/lib/external-issues/asana.js.map +1 -0
  189. package/dist/lib/external-issues/index.d.ts +4 -2
  190. package/dist/lib/external-issues/index.js +6 -2
  191. package/dist/lib/external-issues/index.js.map +1 -1
  192. package/dist/lib/external-issues/linear.js.map +1 -1
  193. package/dist/lib/external-issues/mapping-store.js +1 -1
  194. package/dist/lib/external-issues/shortcut.d.ts +86 -0
  195. package/dist/lib/external-issues/shortcut.js +274 -0
  196. package/dist/lib/external-issues/shortcut.js.map +1 -0
  197. package/dist/lib/external-issues/types.d.ts +3 -3
  198. package/dist/lib/external-issues/types.js +1 -1
  199. package/dist/lib/external-issues/types.js.map +1 -1
  200. package/dist/lib/mcp/tools/cli-passthrough.js +1 -1
  201. package/dist/lib/mcp/tools/cli-passthrough.js.map +1 -1
  202. package/dist/lib/mcp/tools/work.js +1 -1
  203. package/dist/lib/mcp/tools/work.js.map +1 -1
  204. package/dist/lib/pmo/index.d.ts +2 -2
  205. package/dist/lib/pmo/index.js +3 -3
  206. package/dist/lib/pmo/index.js.map +1 -1
  207. package/dist/lib/pmo/sync-manager.js +1 -1
  208. package/dist/lib/pmo/sync-manager.js.map +1 -1
  209. package/dist/lib/pmo/watcher.js +1 -1
  210. package/dist/lib/pmo/watcher.js.map +1 -1
  211. package/dist/lib/repos/git.d.ts +44 -0
  212. package/dist/lib/repos/git.js +127 -0
  213. package/dist/lib/repos/git.js.map +1 -1
  214. package/dist/lib/repos/index.js +36 -3
  215. package/dist/lib/repos/index.js.map +1 -1
  216. package/dist/lib/runners/agent-runner.d.ts +92 -0
  217. package/dist/lib/runners/agent-runner.js +9 -0
  218. package/dist/lib/runners/agent-runner.js.map +1 -0
  219. package/dist/lib/runners/claude-code-runner.d.ts +53 -0
  220. package/dist/lib/runners/claude-code-runner.js +132 -0
  221. package/dist/lib/runners/claude-code-runner.js.map +1 -0
  222. package/dist/lib/runners/index.d.ts +34 -0
  223. package/dist/lib/runners/index.js +97 -0
  224. package/dist/lib/runners/index.js.map +1 -0
  225. package/dist/lib/session-store.d.ts +70 -0
  226. package/dist/lib/session-store.js +167 -0
  227. package/dist/lib/session-store.js.map +1 -0
  228. package/dist/lib/shortcut/config.d.ts +44 -0
  229. package/dist/lib/shortcut/config.js +98 -0
  230. package/dist/lib/shortcut/config.js.map +1 -0
  231. package/dist/lib/shortcut/index.d.ts +7 -0
  232. package/dist/lib/shortcut/index.js +7 -0
  233. package/dist/lib/shortcut/index.js.map +1 -0
  234. package/dist/lib/work-source/client.d.ts +10 -0
  235. package/dist/lib/work-source/client.js +74 -0
  236. package/dist/lib/work-source/client.js.map +1 -0
  237. package/dist/lib/work-source/config.d.ts +1 -1
  238. package/dist/lib/work-source/config.js +17 -1
  239. package/dist/lib/work-source/config.js.map +1 -1
  240. package/dist/lib/work-source/index.d.ts +1 -0
  241. package/dist/lib/work-source/index.js +1 -0
  242. package/dist/lib/work-source/index.js.map +1 -1
  243. package/dist/lib/workspace.js +2 -2
  244. package/dist/lib/workspace.js.map +1 -1
  245. package/oclif.manifest.json +8135 -6979
  246. package/package.json +1 -1
@@ -0,0 +1,23 @@
1
+ import { PMOCommand } from '../../lib/pmo/index.js';
2
+ export default class WorkShortcut extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ issue: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
8
+ executor: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ display: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ action: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ message: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ 'run-on-host': import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ 'skip-permissions': import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ 'create-pr': import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
17
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
+ };
20
+ private findLinkedTicket;
21
+ private createOrUpdateLinkedTicket;
22
+ execute(): Promise<void>;
23
+ }
@@ -0,0 +1,212 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags, autoExportToBoard, } from '../../lib/pmo/index.js';
3
+ import { shouldOutputJson, } from '../../lib/prompt-json.js';
4
+ import { ExternalIssueAdapterError, } from '../../lib/external-issues/types.js';
5
+ import { listShortcutStories, getShortcutStoryByKey, buildShortcutStoryChoiceCommand, buildShortcutTicketDescription, buildShortcutMetadata, buildShortcutSpawnContextMessage, } from '../../lib/external-issues/shortcut.js';
6
+ import { getShortcutApiToken, loadShortcutConfig } from '../../lib/shortcut/index.js';
7
+ function buildWorkStartArgs(options) {
8
+ const args = [options.ticketId, '--project', options.projectId, '--ephemeral'];
9
+ if (options.executor)
10
+ args.push('--executor', options.executor);
11
+ if (options.display)
12
+ args.push('--display', options.display);
13
+ if (options.runOnHost)
14
+ args.push('--run-on-host');
15
+ if (options.skipPermissions)
16
+ args.push('--skip-permissions');
17
+ if (options.createPr)
18
+ args.push('--create-pr');
19
+ if (options.action)
20
+ args.push('--action', options.action);
21
+ if (options.message)
22
+ args.push('--message', options.message);
23
+ if (options.json)
24
+ args.push('--json');
25
+ if (options.machine)
26
+ args.push('--machine');
27
+ if (options.yes)
28
+ args.push('--yes');
29
+ return args;
30
+ }
31
+ export default class WorkShortcut extends PMOCommand {
32
+ static description = 'List/select Shortcut stories and spawn work using the existing work-start flow';
33
+ static examples = [
34
+ '<%= config.bin %> <%= command.id %>',
35
+ '<%= config.bin %> <%= command.id %> --issue sc-123',
36
+ '<%= config.bin %> <%= command.id %> --issue sc-123 --yes --skip-permissions --display terminal',
37
+ ];
38
+ static flags = {
39
+ ...pmoBaseFlags,
40
+ issue: Flags.string({
41
+ description: 'Shortcut story key (for example: sc-123 or 123)',
42
+ }),
43
+ limit: Flags.integer({
44
+ char: 'l',
45
+ description: 'Maximum number of Shortcut stories to fetch',
46
+ default: 20,
47
+ min: 1,
48
+ max: 100,
49
+ }),
50
+ executor: Flags.string({
51
+ char: 'e',
52
+ description: 'Override executor',
53
+ options: ['claude-code', 'codex', 'custom'],
54
+ }),
55
+ display: Flags.string({
56
+ char: 'd',
57
+ description: 'Display mode',
58
+ options: ['terminal', 'background', 'foreground'],
59
+ }),
60
+ action: Flags.string({
61
+ char: 'A',
62
+ description: 'Action to run in work start (default: implement)',
63
+ default: 'implement',
64
+ }),
65
+ message: Flags.string({
66
+ description: 'Additional instructions appended to spawn context',
67
+ }),
68
+ 'run-on-host': Flags.boolean({
69
+ description: 'Run on host even if devcontainer exists',
70
+ default: false,
71
+ }),
72
+ 'skip-permissions': Flags.boolean({
73
+ description: 'Skip permission prompts (danger mode)',
74
+ default: false,
75
+ }),
76
+ 'create-pr': Flags.boolean({
77
+ description: 'Create PR when work is ready',
78
+ default: false,
79
+ }),
80
+ yes: Flags.boolean({
81
+ char: 'y',
82
+ description: 'Skip confirmation prompts in downstream work start',
83
+ default: false,
84
+ }),
85
+ };
86
+ async findLinkedTicket(projectId, envelope) {
87
+ const tickets = await this.storage.listTickets(projectId);
88
+ return tickets.find((ticket) => {
89
+ const source = ticket.metadata?.external_source;
90
+ const key = ticket.metadata?.external_key;
91
+ const id = ticket.metadata?.external_id;
92
+ return source === 'shortcut'
93
+ && (key === envelope.source.externalKey || id === envelope.source.externalId);
94
+ });
95
+ }
96
+ async createOrUpdateLinkedTicket(projectId, envelope) {
97
+ const existing = await this.findLinkedTicket(projectId, envelope);
98
+ const description = buildShortcutTicketDescription(envelope);
99
+ const metadata = buildShortcutMetadata(envelope);
100
+ if (existing) {
101
+ const updated = await this.storage.updateTicket(existing.id, {
102
+ title: envelope.title,
103
+ description,
104
+ priority: envelope.priority ?? undefined,
105
+ category: envelope.category ?? undefined,
106
+ labels: envelope.labels,
107
+ metadata: {
108
+ ...existing.metadata,
109
+ ...metadata,
110
+ },
111
+ });
112
+ return updated;
113
+ }
114
+ return this.storage.createTicket(projectId, {
115
+ title: envelope.title,
116
+ description,
117
+ priority: envelope.priority ?? undefined,
118
+ category: envelope.category ?? undefined,
119
+ labels: envelope.labels,
120
+ metadata,
121
+ });
122
+ }
123
+ async execute() {
124
+ const { flags } = await this.parse(WorkShortcut);
125
+ const jsonMode = shouldOutputJson(flags);
126
+ const db = this.storage.getDatabase();
127
+ const shortcutConfig = loadShortcutConfig(db);
128
+ const projectId = await this.requireProject({
129
+ jsonMode: {
130
+ flags,
131
+ commandName: 'work shortcut',
132
+ baseCommand: 'prlt work shortcut',
133
+ },
134
+ });
135
+ const apiToken = getShortcutApiToken(db) || undefined;
136
+ let issues;
137
+ try {
138
+ issues = await listShortcutStories({
139
+ apiToken,
140
+ workspaceSlug: shortcutConfig?.workspaceSlug,
141
+ }, { limit: flags.limit });
142
+ }
143
+ catch (error) {
144
+ if (error instanceof ExternalIssueAdapterError) {
145
+ return this.handleError(error.code, error.message, { jsonMode, commandName: 'work shortcut', flags });
146
+ }
147
+ const msg = error instanceof Error ? error.message : 'Failed to fetch Shortcut stories.';
148
+ return this.handleError('SHORTCUT_REQUEST_FAILED', msg, { jsonMode, commandName: 'work shortcut', flags });
149
+ }
150
+ if (issues.length === 0) {
151
+ return this.handleError('NO_SHORTCUT_STORIES', 'No active Shortcut stories found.', { jsonMode, commandName: 'work shortcut', flags });
152
+ }
153
+ let selectedIssue = issues.find(issue => issue.source.externalKey === flags.issue);
154
+ if (!selectedIssue && flags.issue) {
155
+ try {
156
+ selectedIssue = await getShortcutStoryByKey({
157
+ apiToken,
158
+ workspaceSlug: shortcutConfig?.workspaceSlug,
159
+ }, flags.issue) ?? undefined;
160
+ }
161
+ catch (error) {
162
+ if (error instanceof ExternalIssueAdapterError) {
163
+ return this.handleError(error.code, error.message, { jsonMode, commandName: 'work shortcut', flags });
164
+ }
165
+ const msg = error instanceof Error ? error.message : 'Failed to fetch Shortcut story.';
166
+ return this.handleError('SHORTCUT_REQUEST_FAILED', msg, { jsonMode, commandName: 'work shortcut', flags });
167
+ }
168
+ if (!selectedIssue) {
169
+ return this.handleError('SHORTCUT_STORY_NOT_FOUND', `Shortcut story "${flags.issue}" was not found.`, { jsonMode, commandName: 'work shortcut', flags });
170
+ }
171
+ }
172
+ if (!selectedIssue) {
173
+ const selectedKey = await this.selectFromList({
174
+ message: 'Select Shortcut story to spawn:',
175
+ items: issues,
176
+ getName: (issue) => {
177
+ const priority = issue.priority || 'None';
178
+ return `[${priority}] ${issue.source.externalKey} - ${issue.title}`;
179
+ },
180
+ getValue: issue => issue.source.externalKey,
181
+ getCommand: issue => buildShortcutStoryChoiceCommand(issue.source.externalKey, projectId),
182
+ jsonMode: jsonMode ? { flags, commandName: 'work shortcut' } : null,
183
+ });
184
+ if (!selectedKey) {
185
+ return;
186
+ }
187
+ selectedIssue = issues.find(issue => issue.source.externalKey === selectedKey);
188
+ if (!selectedIssue) {
189
+ return this.handleError('SHORTCUT_STORY_NOT_FOUND', `Shortcut story "${selectedKey}" was not found.`, { jsonMode, commandName: 'work shortcut', flags });
190
+ }
191
+ }
192
+ const ticket = await this.createOrUpdateLinkedTicket(projectId, selectedIssue);
193
+ await autoExportToBoard(this.pmoPath, this.storage);
194
+ const contextMessage = buildShortcutSpawnContextMessage(selectedIssue, flags.message);
195
+ const args = buildWorkStartArgs({
196
+ ticketId: ticket.id,
197
+ projectId,
198
+ executor: flags.executor,
199
+ display: flags.display,
200
+ runOnHost: flags['run-on-host'],
201
+ skipPermissions: flags['skip-permissions'],
202
+ createPr: flags['create-pr'],
203
+ action: flags.action,
204
+ message: contextMessage,
205
+ json: flags.json,
206
+ machine: flags.machine,
207
+ yes: flags.yes,
208
+ });
209
+ await this.config.runCommand('work:start', args);
210
+ }
211
+ }
212
+ //# sourceMappingURL=shortcut.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shortcut.js","sourceRoot":"","sources":["../../../src/commands/work/shortcut.ts"],"names":[],"mappings":"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"}
@@ -40,12 +40,15 @@ export default class WorkSpawn extends PMOCommand {
40
40
  'jira-project': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
41
41
  'jira-jql': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
42
42
  'jira-limit': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
43
+ 'shortcut-limit': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
43
44
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
44
45
  machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
45
46
  project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
46
47
  };
47
48
  private findLinkedJiraTicket;
48
49
  private findOrCreateJiraTicket;
50
+ private findLinkedShortcutTicket;
51
+ private findOrCreateShortcutTicket;
49
52
  execute(): Promise<void>;
50
53
  /**
51
54
  * Select tickets using diet-balanced category weighting.
@@ -12,7 +12,9 @@ import { loadDietConfig, formatDietConfig, } from '../../lib/pmo/diet.js';
12
12
  import { LinearClient, LinearMapper, isLinearConfigured, loadLinearConfig, } from '../../lib/linear/index.js';
13
13
  import { parseWorkSourceRef, formatWorkSourceRef, loadActiveWorkSource, saveActiveWorkSource, getRegisteredWorkSources, } from '../../lib/work-source/index.js';
14
14
  import { isJiraConfigured, loadJiraConfig, } from '../../lib/jira/index.js';
15
+ import { isShortcutConfigured, loadShortcutConfig, } from '../../lib/shortcut/index.js';
15
16
  import { listJiraIssues, getJiraIssueByKey, buildJiraTicketDescription, buildJiraMetadata, } from '../../lib/external-issues/jira.js';
17
+ import { listShortcutStories, getShortcutStoryByKey, buildShortcutTicketDescription, buildShortcutMetadata, } from '../../lib/external-issues/shortcut.js';
16
18
  import { ExternalIssueAdapterError, } from '../../lib/external-issues/types.js';
17
19
  export default class WorkSpawn extends PMOCommand {
18
20
  static description = 'Spawn work for multiple tickets by column (batch mode)';
@@ -42,6 +44,9 @@ export default class WorkSpawn extends PMOCommand {
42
44
  '<%= config.bin %> <%= command.id %> --from jira:PROJ PROJ-123 PROJ-456 # Pull specific Jira issues',
43
45
  '<%= config.bin %> <%= command.id %> --from jira --jira-project PROJ # Jira with explicit project key',
44
46
  '<%= config.bin %> work source set jira:PROJ # Persist Jira as default source',
47
+ '<%= config.bin %> <%= command.id %> --from shortcut # Pull Shortcut stories → PMO → spawn',
48
+ '<%= config.bin %> <%= command.id %> --from shortcut sc-123 sc-456 # Pull specific Shortcut stories',
49
+ '<%= config.bin %> work source set shortcut # Persist Shortcut as default source',
45
50
  ];
46
51
  static flags = {
47
52
  ...pmoBaseFlags,
@@ -189,6 +194,11 @@ export default class WorkSpawn extends PMOCommand {
189
194
  description: 'Maximum number of Jira issues to pull',
190
195
  default: 20,
191
196
  }),
197
+ // Shortcut integration flags
198
+ 'shortcut-limit': Flags.integer({
199
+ description: 'Maximum number of Shortcut stories to pull',
200
+ default: 20,
201
+ }),
192
202
  };
193
203
  async findLinkedJiraTicket(projectId, envelope) {
194
204
  const tickets = await this.storage.listTickets(projectId);
@@ -226,6 +236,42 @@ export default class WorkSpawn extends PMOCommand {
226
236
  metadata,
227
237
  });
228
238
  }
239
+ async findLinkedShortcutTicket(projectId, envelope) {
240
+ const tickets = await this.storage.listTickets(projectId);
241
+ return tickets.find((ticket) => {
242
+ const source = ticket.metadata?.external_source;
243
+ const key = ticket.metadata?.external_key;
244
+ const id = ticket.metadata?.external_id;
245
+ return source === 'shortcut'
246
+ && (key === envelope.source.externalKey || id === envelope.source.externalId);
247
+ });
248
+ }
249
+ async findOrCreateShortcutTicket(projectId, envelope) {
250
+ const existing = await this.findLinkedShortcutTicket(projectId, envelope);
251
+ const description = buildShortcutTicketDescription(envelope);
252
+ const metadata = buildShortcutMetadata(envelope);
253
+ if (existing) {
254
+ return this.storage.updateTicket(existing.id, {
255
+ title: envelope.title,
256
+ description,
257
+ priority: envelope.priority ?? undefined,
258
+ category: envelope.category ?? undefined,
259
+ labels: envelope.labels,
260
+ metadata: {
261
+ ...existing.metadata,
262
+ ...metadata,
263
+ },
264
+ });
265
+ }
266
+ return this.storage.createTicket(projectId, {
267
+ title: envelope.title,
268
+ description,
269
+ priority: envelope.priority ?? undefined,
270
+ category: envelope.category ?? undefined,
271
+ labels: envelope.labels,
272
+ metadata,
273
+ });
274
+ }
229
275
  async execute() {
230
276
  const { flags, argv } = await this.parse(WorkSpawn);
231
277
  // Check if JSON output mode is active
@@ -603,8 +649,135 @@ export default class WorkSpawn extends PMOCommand {
603
649
  // Sync board
604
650
  await autoExportToBoard(this.pmoPath, this.storage);
605
651
  }
652
+ else if (resolvedSource?.provider === 'shortcut') {
653
+ // =========================================================================
654
+ // Shortcut source: Pull Shortcut stories → mirror into PMO → spawn from PMO
655
+ // =========================================================================
656
+ const db = this.storage.getDatabase();
657
+ if (!isShortcutConfigured(db)) {
658
+ return handleError('SHORTCUT_NOT_CONFIGURED', 'Shortcut is not configured. Set PRLT_SHORTCUT_API_TOKEN or SHORTCUT_API_TOKEN environment variables, or use "prlt shortcut connect".');
659
+ }
660
+ const shortcutConfig = loadShortcutConfig(db);
661
+ // Determine project first (needed for ticket creation)
662
+ const shortcutProjectId = await this.requireProject({
663
+ jsonMode: jsonMode ? {
664
+ flags,
665
+ commandName: 'work spawn',
666
+ baseCommand: `prlt work spawn --from ${formatWorkSourceRef(resolvedSource)}`,
667
+ } : undefined,
668
+ });
669
+ // Get project workflow statuses for mapping
670
+ const workflow = await this.storage.getProjectWorkflow(shortcutProjectId);
671
+ if (!workflow) {
672
+ return handleError('NO_WORKFLOW', 'Project has no workflow configured.');
673
+ }
674
+ // Check if args are Shortcut identifiers (e.g., sc-123 or plain numbers)
675
+ const shortcutIdentifiers = ticketIdArgs.filter((id) => /^(sc-)?\d+$/i.test(id));
676
+ const pmoTicketIds = [];
677
+ const shortcutAdapterConfig = {
678
+ apiToken: shortcutConfig.apiToken,
679
+ workspaceSlug: shortcutConfig.workspaceSlug,
680
+ };
681
+ if (shortcutIdentifiers.length > 0) {
682
+ // Fetch and import specific Shortcut stories
683
+ if (!jsonMode) {
684
+ this.log(styles.muted(`Pulling ${shortcutIdentifiers.length} story(ies) from Shortcut...`));
685
+ }
686
+ for (const identifier of shortcutIdentifiers) {
687
+ try {
688
+ // eslint-disable-next-line no-await-in-loop
689
+ const envelope = await getShortcutStoryByKey(shortcutAdapterConfig, identifier);
690
+ if (!envelope) {
691
+ if (!jsonMode)
692
+ this.warn(`Shortcut story not found: ${identifier}`);
693
+ continue;
694
+ }
695
+ // eslint-disable-next-line no-await-in-loop
696
+ const ticket = await this.findOrCreateShortcutTicket(shortcutProjectId, envelope);
697
+ pmoTicketIds.push(ticket.id);
698
+ if (!jsonMode) {
699
+ this.log(styles.muted(` Imported: ${identifier} → ${ticket.id}`));
700
+ }
701
+ }
702
+ catch (error) {
703
+ if (error instanceof ExternalIssueAdapterError) {
704
+ return handleError(`SHORTCUT_${error.code}`, error.message);
705
+ }
706
+ throw error;
707
+ }
708
+ }
709
+ }
710
+ else {
711
+ // Fetch stories using filters
712
+ if (!jsonMode) {
713
+ this.log(styles.muted('Pulling stories from Shortcut...'));
714
+ }
715
+ let issues;
716
+ try {
717
+ issues = await listShortcutStories(shortcutAdapterConfig, {
718
+ limit: flags['shortcut-limit'],
719
+ });
720
+ }
721
+ catch (error) {
722
+ if (error instanceof ExternalIssueAdapterError) {
723
+ return handleError(`SHORTCUT_${error.code}`, error.message);
724
+ }
725
+ const msg = error instanceof Error ? error.message : 'Failed to fetch Shortcut stories.';
726
+ return handleError('SHORTCUT_REQUEST_FAILED', msg);
727
+ }
728
+ if (issues.length === 0) {
729
+ if (jsonMode) {
730
+ outputSuccessAsJson({
731
+ imported: 0,
732
+ spawned: 0,
733
+ message: 'No matching Shortcut stories found.',
734
+ }, createMetadata('work spawn', flags));
735
+ return;
736
+ }
737
+ this.log(styles.muted('No matching Shortcut stories found.'));
738
+ return;
739
+ }
740
+ if (!jsonMode) {
741
+ this.log(styles.muted(`Found ${issues.length} story(ies). Importing into PMO...`));
742
+ }
743
+ let imported = 0;
744
+ let skipped = 0;
745
+ for (const envelope of issues) {
746
+ // eslint-disable-next-line no-await-in-loop
747
+ const existing = await this.findLinkedShortcutTicket(shortcutProjectId, envelope);
748
+ if (existing) {
749
+ pmoTicketIds.push(existing.id);
750
+ skipped++;
751
+ }
752
+ else {
753
+ // eslint-disable-next-line no-await-in-loop
754
+ const ticket = await this.findOrCreateShortcutTicket(shortcutProjectId, envelope);
755
+ pmoTicketIds.push(ticket.id);
756
+ imported++;
757
+ }
758
+ }
759
+ if (!jsonMode) {
760
+ if (imported > 0)
761
+ this.log(styles.success(` Imported: ${imported}`));
762
+ if (skipped > 0)
763
+ this.log(styles.muted(` Already imported: ${skipped}`));
764
+ }
765
+ }
766
+ if (pmoTicketIds.length === 0) {
767
+ return handleError('NO_SHORTCUT_STORIES', 'No Shortcut stories were imported. Nothing to spawn.');
768
+ }
769
+ if (!jsonMode) {
770
+ this.log('');
771
+ this.log(styles.header(`Spawning agents for ${pmoTicketIds.length} imported ticket(s)...`));
772
+ this.log('');
773
+ }
774
+ // Replace ticket args with the imported PMO ticket IDs
775
+ ticketIdArgs = pmoTicketIds;
776
+ // Sync board
777
+ await autoExportToBoard(this.pmoPath, this.storage);
778
+ }
606
779
  else if (resolvedSource && resolvedSource.provider !== 'pmo') {
607
- return handleError('SOURCE_NOT_SUPPORTED', `Source "${resolvedSource.provider}" is configured but not supported by work spawn yet. Use --from pmo, --from linear[:team], or --from jira[:project].`);
780
+ return handleError('SOURCE_NOT_SUPPORTED', `Source "${resolvedSource.provider}" is configured but not supported by work spawn yet. Use --from pmo, --from linear[:team], --from jira[:project], or --from shortcut.`);
608
781
  }
609
782
  // Try to infer project from ticket IDs if provided
610
783
  let projectId;
@@ -646,7 +819,7 @@ export default class WorkSpawn extends PMOCommand {
646
819
  workspaceInfo = getWorkspaceInfo();
647
820
  }
648
821
  catch {
649
- return handleError('NOT_IN_WORKSPACE', 'Not in a workspace. Run "prlt init" first.');
822
+ return handleError('NOT_IN_WORKSPACE', 'Not in a workspace. Run "prlt new" first.');
650
823
  }
651
824
  // Open database
652
825
  const dbPath = path.join(workspaceInfo.path, '.proletariat', 'workspace.db');