@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.
- package/README.md +74 -5
- package/bin/validate-better-sqlite3.cjs +44 -5
- package/dist/commands/agent/cleanup.d.ts +1 -0
- package/dist/commands/agent/cleanup.js +11 -1
- package/dist/commands/agent/cleanup.js.map +1 -1
- package/dist/commands/agent/rebuild.js +1 -1
- package/dist/commands/agent/rebuild.js.map +1 -1
- package/dist/commands/asana/import.d.ts +14 -0
- package/dist/commands/asana/import.js +240 -0
- package/dist/commands/asana/import.js.map +1 -0
- package/dist/commands/claude-yolo.d.ts +20 -0
- package/dist/commands/claude-yolo.js +86 -0
- package/dist/commands/claude-yolo.js.map +1 -0
- package/dist/commands/codex/index.d.ts +23 -0
- package/dist/commands/codex/index.js +168 -0
- package/dist/commands/codex/index.js.map +1 -0
- package/dist/commands/codex-yolo.d.ts +20 -0
- package/dist/commands/codex-yolo.js +86 -0
- package/dist/commands/codex-yolo.js.map +1 -0
- package/dist/commands/config/index.js +2 -2
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/dashboard.d.ts +38 -0
- package/dist/commands/dashboard.js +352 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/docker/clean.js +1 -1
- package/dist/commands/docker/clean.js.map +1 -1
- package/dist/commands/docker/list.js +1 -1
- package/dist/commands/docker/list.js.map +1 -1
- package/dist/commands/docker/logs.js +1 -1
- package/dist/commands/docker/logs.js.map +1 -1
- package/dist/commands/docker/restart.js +1 -1
- package/dist/commands/docker/restart.js.map +1 -1
- package/dist/commands/docker/shell.js +1 -1
- package/dist/commands/docker/shell.js.map +1 -1
- package/dist/commands/docker/start.js +1 -1
- package/dist/commands/docker/start.js.map +1 -1
- package/dist/commands/docker/stop.js +1 -1
- package/dist/commands/docker/stop.js.map +1 -1
- package/dist/commands/docker/sync.js +1 -1
- package/dist/commands/docker/sync.js.map +1 -1
- package/dist/commands/execution/config.js +2 -2
- package/dist/commands/execution/config.js.map +1 -1
- package/dist/commands/execution/list.js +1 -1
- package/dist/commands/execution/list.js.map +1 -1
- package/dist/commands/execution/logs.js +10 -8
- package/dist/commands/execution/logs.js.map +1 -1
- package/dist/commands/execution/stop.js +1 -1
- package/dist/commands/execution/stop.js.map +1 -1
- package/dist/commands/execution/view.js +1 -1
- package/dist/commands/execution/view.js.map +1 -1
- package/dist/commands/init.d.ts +0 -16
- package/dist/commands/init.js +50 -160
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/logs.d.ts +20 -0
- package/dist/commands/logs.js +84 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/mcp-server.js +1 -1
- package/dist/commands/mcp-server.js.map +1 -1
- package/dist/commands/new.d.ts +27 -0
- package/dist/commands/new.js +184 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/orchestrator/attach.d.ts +1 -0
- package/dist/commands/orchestrator/attach.js +159 -26
- package/dist/commands/orchestrator/attach.js.map +1 -1
- package/dist/commands/orchestrator/start.d.ts +20 -0
- package/dist/commands/orchestrator/start.js +123 -14
- package/dist/commands/orchestrator/start.js.map +1 -1
- package/dist/commands/orchestrator/status.d.ts +4 -0
- package/dist/commands/orchestrator/status.js +70 -29
- package/dist/commands/orchestrator/status.js.map +1 -1
- package/dist/commands/orchestrator/stop.js +57 -23
- package/dist/commands/orchestrator/stop.js.map +1 -1
- package/dist/commands/peek.d.ts +20 -0
- package/dist/commands/peek.js +84 -0
- package/dist/commands/peek.js.map +1 -0
- package/dist/commands/poke.d.ts +20 -0
- package/dist/commands/poke.js +89 -0
- package/dist/commands/poke.js.map +1 -0
- package/dist/commands/pr/link.js +1 -1
- package/dist/commands/pr/link.js.map +1 -1
- package/dist/commands/pr/status.js +1 -1
- package/dist/commands/pr/status.js.map +1 -1
- package/dist/commands/ps.d.ts +18 -0
- package/dist/commands/ps.js +123 -0
- package/dist/commands/ps.js.map +1 -0
- package/dist/commands/qa/index.js +1 -1
- package/dist/commands/qa/index.js.map +1 -1
- package/dist/commands/repo/add.js +1 -1
- package/dist/commands/repo/add.js.map +1 -1
- package/dist/commands/repo/fix-remotes.d.ts +14 -0
- package/dist/commands/repo/fix-remotes.js +154 -0
- package/dist/commands/repo/fix-remotes.js.map +1 -0
- package/dist/commands/repo/list.js +1 -1
- package/dist/commands/repo/list.js.map +1 -1
- package/dist/commands/repo/remove.js +1 -1
- package/dist/commands/repo/remove.js.map +1 -1
- package/dist/commands/repo/view.js +1 -1
- package/dist/commands/repo/view.js.map +1 -1
- package/dist/commands/run/index.d.ts +25 -0
- package/dist/commands/run/index.js +212 -0
- package/dist/commands/run/index.js.map +1 -0
- package/dist/commands/session/index.js +4 -0
- package/dist/commands/session/index.js.map +1 -1
- package/dist/commands/session/prune.d.ts +18 -0
- package/dist/commands/session/prune.js +327 -0
- package/dist/commands/session/prune.js.map +1 -0
- package/dist/commands/shortcut/connect.d.ts +15 -0
- package/dist/commands/shortcut/connect.js +210 -0
- package/dist/commands/shortcut/connect.js.map +1 -0
- package/dist/commands/stop.d.ts +19 -0
- package/dist/commands/stop.js +83 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/work/asana.d.ts +23 -0
- package/dist/commands/work/asana.js +213 -0
- package/dist/commands/work/asana.js.map +1 -0
- package/dist/commands/work/complete.js +1 -1
- package/dist/commands/work/complete.js.map +1 -1
- package/dist/commands/work/ready.js +1 -1
- package/dist/commands/work/ready.js.map +1 -1
- package/dist/commands/work/review.js +1 -1
- package/dist/commands/work/review.js.map +1 -1
- package/dist/commands/work/revise.js +1 -1
- package/dist/commands/work/revise.js.map +1 -1
- package/dist/commands/work/shortcut.d.ts +23 -0
- package/dist/commands/work/shortcut.js +212 -0
- package/dist/commands/work/shortcut.js.map +1 -0
- package/dist/commands/work/spawn.d.ts +3 -0
- package/dist/commands/work/spawn.js +175 -2
- package/dist/commands/work/spawn.js.map +1 -1
- package/dist/commands/work/start.js +54 -45
- package/dist/commands/work/start.js.map +1 -1
- package/dist/commands/work/watch.js +1 -1
- package/dist/commands/work/watch.js.map +1 -1
- package/dist/commands/workspace/add.js +1 -1
- package/dist/commands/workspace/add.js.map +1 -1
- package/dist/commands/workspace/list.js +1 -1
- package/dist/commands/workspace/list.js.map +1 -1
- package/dist/hooks/init.d.ts +1 -1
- package/dist/hooks/init.js +6 -6
- package/dist/hooks/init.js.map +1 -1
- package/dist/lib/agent-naming.d.ts +15 -0
- package/dist/lib/agent-naming.js +32 -0
- package/dist/lib/agent-naming.js.map +1 -0
- package/dist/lib/agents/commands.d.ts +2 -0
- package/dist/lib/agents/commands.js +56 -51
- package/dist/lib/agents/commands.js.map +1 -1
- package/dist/lib/agents/index.js +11 -7
- package/dist/lib/agents/index.js.map +1 -1
- package/dist/lib/asana/client.d.ts +8 -0
- package/dist/lib/asana/client.js +26 -7
- package/dist/lib/asana/client.js.map +1 -1
- package/dist/lib/asana/types.d.ts +20 -0
- package/dist/lib/branch/index.d.ts +36 -0
- package/dist/lib/branch/index.js +129 -0
- package/dist/lib/branch/index.js.map +1 -1
- package/dist/lib/database/index.js +1 -1
- package/dist/lib/database/index.js.map +1 -1
- package/dist/lib/database/native-validation.d.ts +2 -0
- package/dist/lib/database/native-validation.js +30 -1
- package/dist/lib/database/native-validation.js.map +1 -1
- package/dist/lib/events/emitting-runner.d.ts +30 -0
- package/dist/lib/events/emitting-runner.js +95 -0
- package/dist/lib/events/emitting-runner.js.map +1 -0
- package/dist/lib/events/event-bus.d.ts +54 -0
- package/dist/lib/events/event-bus.js +107 -0
- package/dist/lib/events/event-bus.js.map +1 -0
- package/dist/lib/events/events.d.ts +67 -0
- package/dist/lib/events/events.js +8 -0
- package/dist/lib/events/events.js.map +1 -0
- package/dist/lib/events/index.d.ts +7 -0
- package/dist/lib/events/index.js +6 -0
- package/dist/lib/events/index.js.map +1 -0
- package/dist/lib/execution/devcontainer.d.ts +27 -0
- package/dist/lib/execution/devcontainer.js +80 -0
- package/dist/lib/execution/devcontainer.js.map +1 -1
- package/dist/lib/execution/runners.d.ts +28 -0
- package/dist/lib/execution/runners.js +536 -35
- package/dist/lib/execution/runners.js.map +1 -1
- package/dist/lib/execution/spawner.js +38 -17
- package/dist/lib/execution/spawner.js.map +1 -1
- package/dist/lib/execution/types.d.ts +2 -0
- package/dist/lib/execution/types.js.map +1 -1
- package/dist/lib/external-issues/adapters.d.ts +34 -0
- package/dist/lib/external-issues/adapters.js +191 -0
- package/dist/lib/external-issues/adapters.js.map +1 -1
- package/dist/lib/external-issues/asana.d.ts +75 -0
- package/dist/lib/external-issues/asana.js +243 -0
- package/dist/lib/external-issues/asana.js.map +1 -0
- package/dist/lib/external-issues/index.d.ts +4 -2
- package/dist/lib/external-issues/index.js +6 -2
- package/dist/lib/external-issues/index.js.map +1 -1
- package/dist/lib/external-issues/linear.js.map +1 -1
- package/dist/lib/external-issues/mapping-store.js +1 -1
- package/dist/lib/external-issues/shortcut.d.ts +86 -0
- package/dist/lib/external-issues/shortcut.js +274 -0
- package/dist/lib/external-issues/shortcut.js.map +1 -0
- package/dist/lib/external-issues/types.d.ts +3 -3
- package/dist/lib/external-issues/types.js +1 -1
- package/dist/lib/external-issues/types.js.map +1 -1
- package/dist/lib/mcp/tools/cli-passthrough.js +1 -1
- package/dist/lib/mcp/tools/cli-passthrough.js.map +1 -1
- package/dist/lib/mcp/tools/work.js +1 -1
- package/dist/lib/mcp/tools/work.js.map +1 -1
- package/dist/lib/pmo/index.d.ts +2 -2
- package/dist/lib/pmo/index.js +3 -3
- package/dist/lib/pmo/index.js.map +1 -1
- package/dist/lib/pmo/sync-manager.js +1 -1
- package/dist/lib/pmo/sync-manager.js.map +1 -1
- package/dist/lib/pmo/watcher.js +1 -1
- package/dist/lib/pmo/watcher.js.map +1 -1
- package/dist/lib/repos/git.d.ts +44 -0
- package/dist/lib/repos/git.js +127 -0
- package/dist/lib/repos/git.js.map +1 -1
- package/dist/lib/repos/index.js +36 -3
- package/dist/lib/repos/index.js.map +1 -1
- package/dist/lib/runners/agent-runner.d.ts +92 -0
- package/dist/lib/runners/agent-runner.js +9 -0
- package/dist/lib/runners/agent-runner.js.map +1 -0
- package/dist/lib/runners/claude-code-runner.d.ts +53 -0
- package/dist/lib/runners/claude-code-runner.js +132 -0
- package/dist/lib/runners/claude-code-runner.js.map +1 -0
- package/dist/lib/runners/index.d.ts +34 -0
- package/dist/lib/runners/index.js +97 -0
- package/dist/lib/runners/index.js.map +1 -0
- package/dist/lib/session-store.d.ts +70 -0
- package/dist/lib/session-store.js +167 -0
- package/dist/lib/session-store.js.map +1 -0
- package/dist/lib/shortcut/config.d.ts +44 -0
- package/dist/lib/shortcut/config.js +98 -0
- package/dist/lib/shortcut/config.js.map +1 -0
- package/dist/lib/shortcut/index.d.ts +7 -0
- package/dist/lib/shortcut/index.js +7 -0
- package/dist/lib/shortcut/index.js.map +1 -0
- package/dist/lib/work-source/client.d.ts +10 -0
- package/dist/lib/work-source/client.js +74 -0
- package/dist/lib/work-source/client.js.map +1 -0
- package/dist/lib/work-source/config.d.ts +1 -1
- package/dist/lib/work-source/config.js +17 -1
- package/dist/lib/work-source/config.js.map +1 -1
- package/dist/lib/work-source/index.d.ts +1 -0
- package/dist/lib/work-source/index.js +1 -0
- package/dist/lib/work-source/index.js.map +1 -1
- package/dist/lib/workspace.js +2 -2
- package/dist/lib/workspace.js.map +1 -1
- package/oclif.manifest.json +8135 -6979
- 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],
|
|
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
|
|
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');
|