@proletariat/cli 0.3.55 → 0.3.56

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 (233) hide show
  1. package/README.md +5 -4
  2. package/dist/commands/agent/cleanup.d.ts +1 -0
  3. package/dist/commands/agent/cleanup.js +11 -1
  4. package/dist/commands/agent/cleanup.js.map +1 -1
  5. package/dist/commands/agent/rebuild.js +1 -1
  6. package/dist/commands/agent/rebuild.js.map +1 -1
  7. package/dist/commands/asana/import.d.ts +14 -0
  8. package/dist/commands/asana/import.js +240 -0
  9. package/dist/commands/asana/import.js.map +1 -0
  10. package/dist/commands/claude-yolo.d.ts +20 -0
  11. package/dist/commands/claude-yolo.js +86 -0
  12. package/dist/commands/claude-yolo.js.map +1 -0
  13. package/dist/commands/codex/index.d.ts +23 -0
  14. package/dist/commands/codex/index.js +168 -0
  15. package/dist/commands/codex/index.js.map +1 -0
  16. package/dist/commands/codex-yolo.d.ts +20 -0
  17. package/dist/commands/codex-yolo.js +86 -0
  18. package/dist/commands/codex-yolo.js.map +1 -0
  19. package/dist/commands/config/index.js +2 -2
  20. package/dist/commands/config/index.js.map +1 -1
  21. package/dist/commands/docker/clean.js +1 -1
  22. package/dist/commands/docker/clean.js.map +1 -1
  23. package/dist/commands/docker/list.js +1 -1
  24. package/dist/commands/docker/list.js.map +1 -1
  25. package/dist/commands/docker/logs.js +1 -1
  26. package/dist/commands/docker/logs.js.map +1 -1
  27. package/dist/commands/docker/restart.js +1 -1
  28. package/dist/commands/docker/restart.js.map +1 -1
  29. package/dist/commands/docker/shell.js +1 -1
  30. package/dist/commands/docker/shell.js.map +1 -1
  31. package/dist/commands/docker/start.js +1 -1
  32. package/dist/commands/docker/start.js.map +1 -1
  33. package/dist/commands/docker/stop.js +1 -1
  34. package/dist/commands/docker/stop.js.map +1 -1
  35. package/dist/commands/docker/sync.js +1 -1
  36. package/dist/commands/docker/sync.js.map +1 -1
  37. package/dist/commands/execution/config.js +2 -2
  38. package/dist/commands/execution/config.js.map +1 -1
  39. package/dist/commands/execution/list.js +1 -1
  40. package/dist/commands/execution/list.js.map +1 -1
  41. package/dist/commands/execution/logs.js +10 -8
  42. package/dist/commands/execution/logs.js.map +1 -1
  43. package/dist/commands/execution/stop.js +1 -1
  44. package/dist/commands/execution/stop.js.map +1 -1
  45. package/dist/commands/execution/view.js +1 -1
  46. package/dist/commands/execution/view.js.map +1 -1
  47. package/dist/commands/init.d.ts +0 -16
  48. package/dist/commands/init.js +50 -160
  49. package/dist/commands/init.js.map +1 -1
  50. package/dist/commands/logs.d.ts +20 -0
  51. package/dist/commands/logs.js +84 -0
  52. package/dist/commands/logs.js.map +1 -0
  53. package/dist/commands/mcp-server.js +1 -1
  54. package/dist/commands/mcp-server.js.map +1 -1
  55. package/dist/commands/new.d.ts +27 -0
  56. package/dist/commands/new.js +184 -0
  57. package/dist/commands/new.js.map +1 -0
  58. package/dist/commands/orchestrator/attach.d.ts +1 -0
  59. package/dist/commands/orchestrator/attach.js +159 -26
  60. package/dist/commands/orchestrator/attach.js.map +1 -1
  61. package/dist/commands/orchestrator/start.d.ts +20 -0
  62. package/dist/commands/orchestrator/start.js +122 -14
  63. package/dist/commands/orchestrator/start.js.map +1 -1
  64. package/dist/commands/orchestrator/status.d.ts +4 -0
  65. package/dist/commands/orchestrator/status.js +70 -29
  66. package/dist/commands/orchestrator/status.js.map +1 -1
  67. package/dist/commands/orchestrator/stop.js +57 -23
  68. package/dist/commands/orchestrator/stop.js.map +1 -1
  69. package/dist/commands/peek.d.ts +20 -0
  70. package/dist/commands/peek.js +84 -0
  71. package/dist/commands/peek.js.map +1 -0
  72. package/dist/commands/poke.d.ts +20 -0
  73. package/dist/commands/poke.js +89 -0
  74. package/dist/commands/poke.js.map +1 -0
  75. package/dist/commands/pr/link.js +1 -1
  76. package/dist/commands/pr/link.js.map +1 -1
  77. package/dist/commands/pr/status.js +1 -1
  78. package/dist/commands/pr/status.js.map +1 -1
  79. package/dist/commands/ps.d.ts +18 -0
  80. package/dist/commands/ps.js +123 -0
  81. package/dist/commands/ps.js.map +1 -0
  82. package/dist/commands/qa/index.js +1 -1
  83. package/dist/commands/qa/index.js.map +1 -1
  84. package/dist/commands/repo/add.js +1 -1
  85. package/dist/commands/repo/add.js.map +1 -1
  86. package/dist/commands/repo/list.js +1 -1
  87. package/dist/commands/repo/list.js.map +1 -1
  88. package/dist/commands/repo/remove.js +1 -1
  89. package/dist/commands/repo/remove.js.map +1 -1
  90. package/dist/commands/repo/view.js +1 -1
  91. package/dist/commands/repo/view.js.map +1 -1
  92. package/dist/commands/run/index.d.ts +25 -0
  93. package/dist/commands/run/index.js +212 -0
  94. package/dist/commands/run/index.js.map +1 -0
  95. package/dist/commands/session/index.js +4 -0
  96. package/dist/commands/session/index.js.map +1 -1
  97. package/dist/commands/session/prune.d.ts +18 -0
  98. package/dist/commands/session/prune.js +327 -0
  99. package/dist/commands/session/prune.js.map +1 -0
  100. package/dist/commands/shortcut/connect.d.ts +15 -0
  101. package/dist/commands/shortcut/connect.js +210 -0
  102. package/dist/commands/shortcut/connect.js.map +1 -0
  103. package/dist/commands/stop.d.ts +19 -0
  104. package/dist/commands/stop.js +83 -0
  105. package/dist/commands/stop.js.map +1 -0
  106. package/dist/commands/work/asana.d.ts +23 -0
  107. package/dist/commands/work/asana.js +213 -0
  108. package/dist/commands/work/asana.js.map +1 -0
  109. package/dist/commands/work/complete.js +1 -1
  110. package/dist/commands/work/complete.js.map +1 -1
  111. package/dist/commands/work/ready.js +1 -1
  112. package/dist/commands/work/ready.js.map +1 -1
  113. package/dist/commands/work/review.js +1 -1
  114. package/dist/commands/work/review.js.map +1 -1
  115. package/dist/commands/work/revise.js +1 -1
  116. package/dist/commands/work/revise.js.map +1 -1
  117. package/dist/commands/work/shortcut.d.ts +23 -0
  118. package/dist/commands/work/shortcut.js +212 -0
  119. package/dist/commands/work/shortcut.js.map +1 -0
  120. package/dist/commands/work/spawn.d.ts +3 -0
  121. package/dist/commands/work/spawn.js +175 -2
  122. package/dist/commands/work/spawn.js.map +1 -1
  123. package/dist/commands/work/start.js +22 -30
  124. package/dist/commands/work/start.js.map +1 -1
  125. package/dist/commands/work/watch.js +1 -1
  126. package/dist/commands/work/watch.js.map +1 -1
  127. package/dist/commands/workspace/add.js +1 -1
  128. package/dist/commands/workspace/add.js.map +1 -1
  129. package/dist/commands/workspace/list.js +1 -1
  130. package/dist/commands/workspace/list.js.map +1 -1
  131. package/dist/hooks/init.d.ts +1 -1
  132. package/dist/hooks/init.js +6 -6
  133. package/dist/hooks/init.js.map +1 -1
  134. package/dist/lib/agent-naming.d.ts +15 -0
  135. package/dist/lib/agent-naming.js +32 -0
  136. package/dist/lib/agent-naming.js.map +1 -0
  137. package/dist/lib/agents/commands.d.ts +2 -0
  138. package/dist/lib/agents/commands.js +51 -44
  139. package/dist/lib/agents/commands.js.map +1 -1
  140. package/dist/lib/agents/index.js +5 -0
  141. package/dist/lib/agents/index.js.map +1 -1
  142. package/dist/lib/asana/client.d.ts +8 -0
  143. package/dist/lib/asana/client.js +26 -7
  144. package/dist/lib/asana/client.js.map +1 -1
  145. package/dist/lib/asana/types.d.ts +20 -0
  146. package/dist/lib/branch/index.d.ts +36 -0
  147. package/dist/lib/branch/index.js +129 -0
  148. package/dist/lib/branch/index.js.map +1 -1
  149. package/dist/lib/database/index.js +1 -1
  150. package/dist/lib/database/index.js.map +1 -1
  151. package/dist/lib/events/emitting-runner.d.ts +30 -0
  152. package/dist/lib/events/emitting-runner.js +95 -0
  153. package/dist/lib/events/emitting-runner.js.map +1 -0
  154. package/dist/lib/events/event-bus.d.ts +54 -0
  155. package/dist/lib/events/event-bus.js +107 -0
  156. package/dist/lib/events/event-bus.js.map +1 -0
  157. package/dist/lib/events/events.d.ts +67 -0
  158. package/dist/lib/events/events.js +8 -0
  159. package/dist/lib/events/events.js.map +1 -0
  160. package/dist/lib/events/index.d.ts +7 -0
  161. package/dist/lib/events/index.js +6 -0
  162. package/dist/lib/events/index.js.map +1 -0
  163. package/dist/lib/execution/devcontainer.d.ts +27 -0
  164. package/dist/lib/execution/devcontainer.js +80 -0
  165. package/dist/lib/execution/devcontainer.js.map +1 -1
  166. package/dist/lib/execution/runners.d.ts +28 -0
  167. package/dist/lib/execution/runners.js +459 -31
  168. package/dist/lib/execution/runners.js.map +1 -1
  169. package/dist/lib/execution/spawner.js +35 -17
  170. package/dist/lib/execution/spawner.js.map +1 -1
  171. package/dist/lib/execution/types.d.ts +1 -0
  172. package/dist/lib/execution/types.js.map +1 -1
  173. package/dist/lib/external-issues/adapters.d.ts +34 -0
  174. package/dist/lib/external-issues/adapters.js +191 -0
  175. package/dist/lib/external-issues/adapters.js.map +1 -1
  176. package/dist/lib/external-issues/asana.d.ts +75 -0
  177. package/dist/lib/external-issues/asana.js +243 -0
  178. package/dist/lib/external-issues/asana.js.map +1 -0
  179. package/dist/lib/external-issues/index.d.ts +4 -2
  180. package/dist/lib/external-issues/index.js +6 -2
  181. package/dist/lib/external-issues/index.js.map +1 -1
  182. package/dist/lib/external-issues/linear.js.map +1 -1
  183. package/dist/lib/external-issues/mapping-store.js +1 -1
  184. package/dist/lib/external-issues/shortcut.d.ts +86 -0
  185. package/dist/lib/external-issues/shortcut.js +274 -0
  186. package/dist/lib/external-issues/shortcut.js.map +1 -0
  187. package/dist/lib/external-issues/types.d.ts +3 -3
  188. package/dist/lib/external-issues/types.js +1 -1
  189. package/dist/lib/external-issues/types.js.map +1 -1
  190. package/dist/lib/mcp/tools/cli-passthrough.js +1 -1
  191. package/dist/lib/mcp/tools/cli-passthrough.js.map +1 -1
  192. package/dist/lib/mcp/tools/work.js +1 -1
  193. package/dist/lib/mcp/tools/work.js.map +1 -1
  194. package/dist/lib/pmo/index.d.ts +2 -2
  195. package/dist/lib/pmo/index.js +3 -3
  196. package/dist/lib/pmo/index.js.map +1 -1
  197. package/dist/lib/pmo/sync-manager.js +1 -1
  198. package/dist/lib/pmo/sync-manager.js.map +1 -1
  199. package/dist/lib/pmo/watcher.js +1 -1
  200. package/dist/lib/pmo/watcher.js.map +1 -1
  201. package/dist/lib/repos/index.js +1 -1
  202. package/dist/lib/repos/index.js.map +1 -1
  203. package/dist/lib/runners/agent-runner.d.ts +92 -0
  204. package/dist/lib/runners/agent-runner.js +9 -0
  205. package/dist/lib/runners/agent-runner.js.map +1 -0
  206. package/dist/lib/runners/claude-code-runner.d.ts +53 -0
  207. package/dist/lib/runners/claude-code-runner.js +132 -0
  208. package/dist/lib/runners/claude-code-runner.js.map +1 -0
  209. package/dist/lib/runners/index.d.ts +34 -0
  210. package/dist/lib/runners/index.js +97 -0
  211. package/dist/lib/runners/index.js.map +1 -0
  212. package/dist/lib/session-store.d.ts +70 -0
  213. package/dist/lib/session-store.js +167 -0
  214. package/dist/lib/session-store.js.map +1 -0
  215. package/dist/lib/shortcut/config.d.ts +44 -0
  216. package/dist/lib/shortcut/config.js +98 -0
  217. package/dist/lib/shortcut/config.js.map +1 -0
  218. package/dist/lib/shortcut/index.d.ts +7 -0
  219. package/dist/lib/shortcut/index.js +7 -0
  220. package/dist/lib/shortcut/index.js.map +1 -0
  221. package/dist/lib/work-source/client.d.ts +10 -0
  222. package/dist/lib/work-source/client.js +74 -0
  223. package/dist/lib/work-source/client.js.map +1 -0
  224. package/dist/lib/work-source/config.d.ts +1 -1
  225. package/dist/lib/work-source/config.js +17 -1
  226. package/dist/lib/work-source/config.js.map +1 -1
  227. package/dist/lib/work-source/index.d.ts +1 -0
  228. package/dist/lib/work-source/index.js +1 -0
  229. package/dist/lib/work-source/index.js.map +1 -1
  230. package/dist/lib/workspace.js +2 -2
  231. package/dist/lib/workspace.js.map +1 -1
  232. package/oclif.manifest.json +4291 -3248
  233. package/package.json +1 -1
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Runner Registry
3
+ *
4
+ * Central registry for agent runners. Provides auto-detection of available
5
+ * runtimes and a simple API for retrieving runner instances.
6
+ *
7
+ * Auto-detect order: claude-code → codex → pi
8
+ */
9
+ import { execSync } from 'node:child_process';
10
+ import { ClaudeCodeRunner } from './claude-code-runner.js';
11
+ import { EventEmittingRunner } from '../events/emitting-runner.js';
12
+ export { ClaudeCodeRunner } from './claude-code-runner.js';
13
+ export { createClaudeCodeSession } from './claude-code-runner.js';
14
+ // =============================================================================
15
+ // Runner Registry
16
+ // =============================================================================
17
+ /**
18
+ * Known runner definitions.
19
+ * Maps runner name to the CLI binary that must be on PATH and a factory function.
20
+ *
21
+ * Detection order matters — first available runner is the default.
22
+ */
23
+ const RUNNER_DEFINITIONS = [
24
+ {
25
+ name: 'claude-code',
26
+ binary: 'claude',
27
+ create: () => new ClaudeCodeRunner(),
28
+ },
29
+ // Future runners — uncomment when implemented:
30
+ // {
31
+ // name: 'codex',
32
+ // binary: 'codex',
33
+ // create: () => new CodexRunner(),
34
+ // },
35
+ // {
36
+ // name: 'pi',
37
+ // binary: 'pi',
38
+ // create: () => new PiRunner(),
39
+ // },
40
+ ];
41
+ /**
42
+ * Check if a CLI binary is available on PATH.
43
+ */
44
+ function isBinaryAvailable(binary) {
45
+ try {
46
+ execSync(`command -v ${binary}`, { stdio: 'pipe' });
47
+ return true;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ /**
54
+ * Get all runners whose CLI binary is available on PATH.
55
+ *
56
+ * Returns runners in detection order (claude-code, codex, pi).
57
+ * Only runners with an installed CLI are included.
58
+ */
59
+ export function getAvailableRunners() {
60
+ return RUNNER_DEFINITIONS
61
+ .filter(def => isBinaryAvailable(def.binary))
62
+ .map(def => def.create());
63
+ }
64
+ /**
65
+ * Get a specific runner by name, or the default (first available) runner.
66
+ *
67
+ * @param name - Runner name to look up (e.g. 'claude-code', 'codex').
68
+ * If omitted, returns the first available runner.
69
+ * @returns The runner instance, or null if not found / not available.
70
+ */
71
+ export function getRunner(name) {
72
+ if (name) {
73
+ const def = RUNNER_DEFINITIONS.find(d => d.name === name);
74
+ if (!def)
75
+ return null;
76
+ if (!isBinaryAvailable(def.binary))
77
+ return null;
78
+ return def.create();
79
+ }
80
+ // Auto-detect: return first available
81
+ for (const def of RUNNER_DEFINITIONS) {
82
+ if (isBinaryAvailable(def.binary)) {
83
+ return def.create();
84
+ }
85
+ }
86
+ return null;
87
+ }
88
+ /**
89
+ * Wrap a runner with event emission.
90
+ *
91
+ * Returns an EventEmittingRunner that delegates to the given runner
92
+ * while emitting runtime events on the global EventBus.
93
+ */
94
+ export function withEvents(runner) {
95
+ return new EventEmittingRunner(runner);
96
+ }
97
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/runners/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAIlE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF;;;;;GAKG;AACH,MAAM,kBAAkB,GAInB;IACH;QACE,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,gBAAgB,EAAE;KACrC;IACD,+CAA+C;IAC/C,IAAI;IACJ,mBAAmB;IACnB,qBAAqB;IACrB,qCAAqC;IACrC,KAAK;IACL,IAAI;IACJ,gBAAgB;IAChB,kBAAkB;IAClB,kCAAkC;IAClC,KAAK;CACN,CAAA;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,MAAc;IACvC,IAAI,CAAC;QACH,QAAQ,CAAC,cAAc,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QACnD,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,kBAAkB;SACtB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;SAC5C,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;AAC7B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,IAAa;IACrC,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;QACzD,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAA;QACrB,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAA;QAC/C,OAAO,GAAG,CAAC,MAAM,EAAE,CAAA;IACrB,CAAC;IAED,sCAAsC;IACtC,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACrC,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAClC,OAAO,GAAG,CAAC,MAAM,EAAE,CAAA;QACrB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,MAAmB;IAC5C,OAAO,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAA;AACxC,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Global Session Store
3
+ *
4
+ * Tracks agent sessions across all repos on the machine.
5
+ * Works without HQ / PMO — just needs ~/.proletariat/sessions.db.
6
+ *
7
+ * Schema: id, agentName, runner, task, workdir, sessionName,
8
+ * environment, permissionMode, status, startedAt, endedAt
9
+ */
10
+ export interface SessionRecord {
11
+ id: string;
12
+ agentName: string;
13
+ runner: string;
14
+ task: string;
15
+ workdir: string;
16
+ sessionName: string;
17
+ environment: 'host' | 'docker' | 'podman';
18
+ permissionMode: 'danger' | 'safe';
19
+ status: 'running' | 'done' | 'error' | 'stopped';
20
+ startedAt: Date;
21
+ endedAt?: Date;
22
+ }
23
+ export declare class SessionStore {
24
+ private db;
25
+ constructor(dbPath?: string);
26
+ private ensureSchema;
27
+ /**
28
+ * Create a new session record.
29
+ */
30
+ create(params: {
31
+ agentName: string;
32
+ runner: string;
33
+ task: string;
34
+ workdir: string;
35
+ sessionName: string;
36
+ environment: SessionRecord['environment'];
37
+ permissionMode: SessionRecord['permissionMode'];
38
+ }): SessionRecord;
39
+ /**
40
+ * Get a session by ID or agent name.
41
+ */
42
+ get(idOrName: string): SessionRecord | null;
43
+ /**
44
+ * Get a session by tmux session name.
45
+ */
46
+ getBySessionName(sessionName: string): SessionRecord | null;
47
+ /**
48
+ * List sessions, optionally filtered by status.
49
+ */
50
+ list(status?: SessionRecord['status']): SessionRecord[];
51
+ /**
52
+ * Update session status.
53
+ */
54
+ updateStatus(id: string, status: SessionRecord['status']): void;
55
+ /**
56
+ * Reconcile session statuses with actual tmux sessions.
57
+ * Marks sessions as 'done' if their tmux session no longer exists.
58
+ */
59
+ reconcile(): void;
60
+ /**
61
+ * Resolve an identifier to a session.
62
+ * Tries: exact ID match, agent name, partial match on agent name or session name.
63
+ */
64
+ resolve(identifier: string): SessionRecord | null;
65
+ /**
66
+ * Check if a tmux session is alive.
67
+ */
68
+ private isTmuxSessionAlive;
69
+ close(): void;
70
+ }
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Global Session Store
3
+ *
4
+ * Tracks agent sessions across all repos on the machine.
5
+ * Works without HQ / PMO — just needs ~/.proletariat/sessions.db.
6
+ *
7
+ * Schema: id, agentName, runner, task, workdir, sessionName,
8
+ * environment, permissionMode, status, startedAt, endedAt
9
+ */
10
+ import * as fs from 'node:fs';
11
+ import * as path from 'node:path';
12
+ import * as os from 'node:os';
13
+ import Database from 'better-sqlite3';
14
+ import { execSync } from 'node:child_process';
15
+ // =============================================================================
16
+ // Helpers
17
+ // =============================================================================
18
+ function rowToSession(row) {
19
+ return {
20
+ id: row.id,
21
+ agentName: row.agent_name,
22
+ runner: row.runner,
23
+ task: row.task,
24
+ workdir: row.workdir,
25
+ sessionName: row.session_name,
26
+ environment: row.environment,
27
+ permissionMode: row.permission_mode,
28
+ status: row.status,
29
+ startedAt: new Date(row.started_at),
30
+ endedAt: row.ended_at ? new Date(row.ended_at) : undefined,
31
+ };
32
+ }
33
+ function getDbPath() {
34
+ const dir = path.join(os.homedir(), '.proletariat');
35
+ fs.mkdirSync(dir, { recursive: true });
36
+ return path.join(dir, 'sessions.db');
37
+ }
38
+ // =============================================================================
39
+ // Session Store
40
+ // =============================================================================
41
+ export class SessionStore {
42
+ db;
43
+ constructor(dbPath) {
44
+ this.db = new Database(dbPath ?? getDbPath());
45
+ this.ensureSchema();
46
+ }
47
+ ensureSchema() {
48
+ this.db.exec(`
49
+ CREATE TABLE IF NOT EXISTS sessions (
50
+ id TEXT PRIMARY KEY,
51
+ agent_name TEXT NOT NULL,
52
+ runner TEXT NOT NULL,
53
+ task TEXT NOT NULL,
54
+ workdir TEXT NOT NULL,
55
+ session_name TEXT NOT NULL,
56
+ environment TEXT NOT NULL DEFAULT 'host',
57
+ permission_mode TEXT NOT NULL DEFAULT 'safe',
58
+ status TEXT NOT NULL DEFAULT 'running',
59
+ started_at INTEGER NOT NULL,
60
+ ended_at INTEGER
61
+ )
62
+ `);
63
+ }
64
+ /**
65
+ * Create a new session record.
66
+ */
67
+ create(params) {
68
+ const id = `SES-${Date.now().toString(36).toUpperCase()}`;
69
+ const now = Date.now();
70
+ this.db.prepare(`
71
+ INSERT INTO sessions (id, agent_name, runner, task, workdir, session_name, environment, permission_mode, status, started_at)
72
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'running', ?)
73
+ `).run(id, params.agentName, params.runner, params.task, params.workdir, params.sessionName, params.environment, params.permissionMode, now);
74
+ return {
75
+ id,
76
+ agentName: params.agentName,
77
+ runner: params.runner,
78
+ task: params.task,
79
+ workdir: params.workdir,
80
+ sessionName: params.sessionName,
81
+ environment: params.environment,
82
+ permissionMode: params.permissionMode,
83
+ status: 'running',
84
+ startedAt: new Date(now),
85
+ };
86
+ }
87
+ /**
88
+ * Get a session by ID or agent name.
89
+ */
90
+ get(idOrName) {
91
+ const row = this.db.prepare(`SELECT * FROM sessions WHERE id = ? OR agent_name = ? ORDER BY started_at DESC LIMIT 1`).get(idOrName, idOrName);
92
+ return row ? rowToSession(row) : null;
93
+ }
94
+ /**
95
+ * Get a session by tmux session name.
96
+ */
97
+ getBySessionName(sessionName) {
98
+ const row = this.db.prepare(`SELECT * FROM sessions WHERE session_name = ? ORDER BY started_at DESC LIMIT 1`).get(sessionName);
99
+ return row ? rowToSession(row) : null;
100
+ }
101
+ /**
102
+ * List sessions, optionally filtered by status.
103
+ */
104
+ list(status) {
105
+ let rows;
106
+ if (status) {
107
+ rows = this.db.prepare(`SELECT * FROM sessions WHERE status = ? ORDER BY started_at DESC`).all(status);
108
+ }
109
+ else {
110
+ rows = this.db.prepare(`SELECT * FROM sessions ORDER BY started_at DESC`).all();
111
+ }
112
+ return rows.map(rowToSession);
113
+ }
114
+ /**
115
+ * Update session status.
116
+ */
117
+ updateStatus(id, status) {
118
+ const endedAt = (status === 'done' || status === 'error' || status === 'stopped') ? Date.now() : null;
119
+ this.db.prepare(`UPDATE sessions SET status = ?, ended_at = COALESCE(?, ended_at) WHERE id = ?`).run(status, endedAt, id);
120
+ }
121
+ /**
122
+ * Reconcile session statuses with actual tmux sessions.
123
+ * Marks sessions as 'done' if their tmux session no longer exists.
124
+ */
125
+ reconcile() {
126
+ const running = this.list('running');
127
+ for (const session of running) {
128
+ if (!this.isTmuxSessionAlive(session.sessionName)) {
129
+ this.updateStatus(session.id, 'done');
130
+ }
131
+ }
132
+ }
133
+ /**
134
+ * Resolve an identifier to a session.
135
+ * Tries: exact ID match, agent name, partial match on agent name or session name.
136
+ */
137
+ resolve(identifier) {
138
+ // Exact ID match
139
+ const byId = this.get(identifier);
140
+ if (byId)
141
+ return byId;
142
+ // Partial agent name match (prefer running sessions)
143
+ const allSessions = this.list();
144
+ const running = allSessions.filter(s => s.status === 'running');
145
+ const pool = running.length > 0 ? running : allSessions;
146
+ const match = pool.find(s => s.agentName.includes(identifier) ||
147
+ s.sessionName.includes(identifier) ||
148
+ s.id.includes(identifier.toUpperCase()));
149
+ return match ?? null;
150
+ }
151
+ /**
152
+ * Check if a tmux session is alive.
153
+ */
154
+ isTmuxSessionAlive(sessionName) {
155
+ try {
156
+ execSync(`tmux has-session -t "${sessionName}" 2>/dev/null`, { stdio: 'pipe' });
157
+ return true;
158
+ }
159
+ catch {
160
+ return false;
161
+ }
162
+ }
163
+ close() {
164
+ this.db.close();
165
+ }
166
+ }
167
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/lib/session-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Shortcut Configuration Storage
3
+ *
4
+ * Stores Shortcut credentials and preferences in the workspace_settings table.
5
+ * Mirrors the Jira config module pattern.
6
+ */
7
+ import Database from 'better-sqlite3';
8
+ export interface ShortcutConfig {
9
+ apiToken: string;
10
+ workspaceSlug?: string;
11
+ }
12
+ /**
13
+ * Check if Shortcut is configured.
14
+ * Returns true if either:
15
+ * - Database has shortcut.api_token stored, OR
16
+ * - Environment variables PRLT_SHORTCUT_API_TOKEN/SHORTCUT_API_TOKEN are set
17
+ */
18
+ export declare function isShortcutConfigured(db: Database.Database): boolean;
19
+ /**
20
+ * Load Shortcut configuration from the database + environment.
21
+ * Returns null if not configured.
22
+ */
23
+ export declare function loadShortcutConfig(db: Database.Database): ShortcutConfig | null;
24
+ /**
25
+ * Save Shortcut configuration to the database.
26
+ */
27
+ export declare function saveShortcutConfig(db: Database.Database, config: ShortcutConfig): void;
28
+ /**
29
+ * Save the Shortcut API token.
30
+ */
31
+ export declare function saveShortcutApiToken(db: Database.Database, apiToken: string): void;
32
+ /**
33
+ * Save the Shortcut workspace slug.
34
+ */
35
+ export declare function saveShortcutWorkspaceSlug(db: Database.Database, slug: string): void;
36
+ /**
37
+ * Clear all Shortcut configuration from the database.
38
+ */
39
+ export declare function clearShortcutConfig(db: Database.Database): void;
40
+ /**
41
+ * Get the stored Shortcut API token.
42
+ * Also checks PRLT_SHORTCUT_API_TOKEN and SHORTCUT_API_TOKEN environment variables.
43
+ */
44
+ export declare function getShortcutApiToken(db: Database.Database): string | null;
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Shortcut Configuration Storage
3
+ *
4
+ * Stores Shortcut credentials and preferences in the workspace_settings table.
5
+ * Mirrors the Jira config module pattern.
6
+ */
7
+ const SETTINGS_TABLE = 'workspace_settings';
8
+ const SHORTCUT_CONFIG_KEYS = {
9
+ apiToken: 'shortcut.api_token',
10
+ workspaceSlug: 'shortcut.workspace_slug',
11
+ };
12
+ function getSetting(db, key) {
13
+ const row = db
14
+ .prepare(`SELECT value FROM ${SETTINGS_TABLE} WHERE key = ?`)
15
+ .get(key);
16
+ return row?.value ?? null;
17
+ }
18
+ function setSetting(db, key, value) {
19
+ db.prepare(`
20
+ INSERT INTO ${SETTINGS_TABLE} (key, value)
21
+ VALUES (?, ?)
22
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value
23
+ `).run(key, value);
24
+ }
25
+ function deleteSetting(db, key) {
26
+ db.prepare(`DELETE FROM ${SETTINGS_TABLE} WHERE key = ?`).run(key);
27
+ }
28
+ /**
29
+ * Check if Shortcut is configured.
30
+ * Returns true if either:
31
+ * - Database has shortcut.api_token stored, OR
32
+ * - Environment variables PRLT_SHORTCUT_API_TOKEN/SHORTCUT_API_TOKEN are set
33
+ */
34
+ export function isShortcutConfigured(db) {
35
+ const hasDbConfig = getSetting(db, SHORTCUT_CONFIG_KEYS.apiToken) !== null;
36
+ if (hasDbConfig)
37
+ return true;
38
+ const hasEnvToken = !!(process.env.PRLT_SHORTCUT_API_TOKEN || process.env.SHORTCUT_API_TOKEN);
39
+ return hasEnvToken;
40
+ }
41
+ /**
42
+ * Load Shortcut configuration from the database + environment.
43
+ * Returns null if not configured.
44
+ */
45
+ export function loadShortcutConfig(db) {
46
+ const apiToken = getSetting(db, SHORTCUT_CONFIG_KEYS.apiToken)
47
+ || process.env.PRLT_SHORTCUT_API_TOKEN
48
+ || process.env.SHORTCUT_API_TOKEN;
49
+ if (!apiToken)
50
+ return null;
51
+ return {
52
+ apiToken,
53
+ workspaceSlug: getSetting(db, SHORTCUT_CONFIG_KEYS.workspaceSlug)
54
+ || process.env.PRLT_SHORTCUT_WORKSPACE
55
+ || process.env.SHORTCUT_WORKSPACE_SLUG
56
+ || undefined,
57
+ };
58
+ }
59
+ /**
60
+ * Save Shortcut configuration to the database.
61
+ */
62
+ export function saveShortcutConfig(db, config) {
63
+ setSetting(db, SHORTCUT_CONFIG_KEYS.apiToken, config.apiToken);
64
+ if (config.workspaceSlug) {
65
+ setSetting(db, SHORTCUT_CONFIG_KEYS.workspaceSlug, config.workspaceSlug);
66
+ }
67
+ }
68
+ /**
69
+ * Save the Shortcut API token.
70
+ */
71
+ export function saveShortcutApiToken(db, apiToken) {
72
+ setSetting(db, SHORTCUT_CONFIG_KEYS.apiToken, apiToken);
73
+ }
74
+ /**
75
+ * Save the Shortcut workspace slug.
76
+ */
77
+ export function saveShortcutWorkspaceSlug(db, slug) {
78
+ setSetting(db, SHORTCUT_CONFIG_KEYS.workspaceSlug, slug);
79
+ }
80
+ /**
81
+ * Clear all Shortcut configuration from the database.
82
+ */
83
+ export function clearShortcutConfig(db) {
84
+ for (const key of Object.values(SHORTCUT_CONFIG_KEYS)) {
85
+ deleteSetting(db, key);
86
+ }
87
+ }
88
+ /**
89
+ * Get the stored Shortcut API token.
90
+ * Also checks PRLT_SHORTCUT_API_TOKEN and SHORTCUT_API_TOKEN environment variables.
91
+ */
92
+ export function getShortcutApiToken(db) {
93
+ const envKey = process.env.PRLT_SHORTCUT_API_TOKEN || process.env.SHORTCUT_API_TOKEN;
94
+ if (envKey)
95
+ return envKey;
96
+ return getSetting(db, SHORTCUT_CONFIG_KEYS.apiToken);
97
+ }
98
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/lib/shortcut/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shortcut Integration Module
3
+ *
4
+ * Provides Shortcut configuration loading and validation.
5
+ */
6
+ export { isShortcutConfigured, loadShortcutConfig, saveShortcutConfig, saveShortcutApiToken, saveShortcutWorkspaceSlug, clearShortcutConfig, getShortcutApiToken, } from './config.js';
7
+ export type { ShortcutConfig } from './config.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shortcut Integration Module
3
+ *
4
+ * Provides Shortcut configuration loading and validation.
5
+ */
6
+ export { isShortcutConfigured, loadShortcutConfig, saveShortcutConfig, saveShortcutApiToken, saveShortcutWorkspaceSlug, clearShortcutConfig, getShortcutApiToken, } from './config.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/shortcut/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,aAAa,CAAA"}
@@ -0,0 +1,10 @@
1
+ import type { NormalizedIssueEnvelope } from '../external-issues/types.js';
2
+ import type { WorkSourceProvider } from './config.js';
3
+ export interface WorkSourceClient {
4
+ readonly provider: WorkSourceProvider;
5
+ fetchByKey(key: string): Promise<NormalizedIssueEnvelope | null>;
6
+ buildTicketDescription(envelope: NormalizedIssueEnvelope): string;
7
+ buildMetadata(envelope: NormalizedIssueEnvelope): Record<string, string>;
8
+ buildSpawnContextMessage(envelope: NormalizedIssueEnvelope, additionalMessage?: string): string;
9
+ }
10
+ export declare function getWorkSourceClient(provider: WorkSourceProvider): WorkSourceClient | null;
@@ -0,0 +1,74 @@
1
+ import { buildAsanaMetadata, buildAsanaSpawnContextMessage, buildAsanaTicketDescription, getAsanaTaskByGid, } from '../external-issues/asana.js';
2
+ import { buildJiraMetadata, buildJiraSpawnContextMessage, buildJiraTicketDescription, getJiraIssueByKey, } from '../external-issues/jira.js';
3
+ import { buildLinearMetadata, buildLinearSpawnContextMessage, buildLinearTicketDescription, getLinearIssueByIdentifier, } from '../external-issues/linear.js';
4
+ import { buildShortcutMetadata, buildShortcutSpawnContextMessage, buildShortcutTicketDescription, getShortcutStoryByKey, } from '../external-issues/shortcut.js';
5
+ class LinearWorkSourceClient {
6
+ provider = 'linear';
7
+ async fetchByKey(key) {
8
+ return getLinearIssueByIdentifier({}, key);
9
+ }
10
+ buildTicketDescription(envelope) {
11
+ return buildLinearTicketDescription(envelope);
12
+ }
13
+ buildMetadata(envelope) {
14
+ return buildLinearMetadata(envelope);
15
+ }
16
+ buildSpawnContextMessage(envelope, additionalMessage) {
17
+ return buildLinearSpawnContextMessage(envelope, additionalMessage);
18
+ }
19
+ }
20
+ class JiraWorkSourceClient {
21
+ provider = 'jira';
22
+ async fetchByKey(key) {
23
+ return getJiraIssueByKey({}, key);
24
+ }
25
+ buildTicketDescription(envelope) {
26
+ return buildJiraTicketDescription(envelope);
27
+ }
28
+ buildMetadata(envelope) {
29
+ return buildJiraMetadata(envelope);
30
+ }
31
+ buildSpawnContextMessage(envelope, additionalMessage) {
32
+ return buildJiraSpawnContextMessage(envelope, additionalMessage);
33
+ }
34
+ }
35
+ class AsanaWorkSourceClient {
36
+ provider = 'asana';
37
+ async fetchByKey(key) {
38
+ return getAsanaTaskByGid({}, key);
39
+ }
40
+ buildTicketDescription(envelope) {
41
+ return buildAsanaTicketDescription(envelope);
42
+ }
43
+ buildMetadata(envelope) {
44
+ return buildAsanaMetadata(envelope);
45
+ }
46
+ buildSpawnContextMessage(envelope, additionalMessage) {
47
+ return buildAsanaSpawnContextMessage(envelope, additionalMessage);
48
+ }
49
+ }
50
+ class ShortcutWorkSourceClient {
51
+ provider = 'shortcut';
52
+ async fetchByKey(key) {
53
+ return getShortcutStoryByKey({}, key);
54
+ }
55
+ buildTicketDescription(envelope) {
56
+ return buildShortcutTicketDescription(envelope);
57
+ }
58
+ buildMetadata(envelope) {
59
+ return buildShortcutMetadata(envelope);
60
+ }
61
+ buildSpawnContextMessage(envelope, additionalMessage) {
62
+ return buildShortcutSpawnContextMessage(envelope, additionalMessage);
63
+ }
64
+ }
65
+ const SOURCE_CLIENTS = {
66
+ linear: new LinearWorkSourceClient(),
67
+ jira: new JiraWorkSourceClient(),
68
+ asana: new AsanaWorkSourceClient(),
69
+ shortcut: new ShortcutWorkSourceClient(),
70
+ };
71
+ export function getWorkSourceClient(provider) {
72
+ return SOURCE_CLIENTS[provider] ?? null;
73
+ }
74
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/lib/work-source/client.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import Database from 'better-sqlite3';
2
- export declare const WORK_SOURCE_PROVIDERS: readonly ["pmo", "linear", "jira", "asana", "monday"];
2
+ export declare const WORK_SOURCE_PROVIDERS: readonly ["pmo", "linear", "jira", "shortcut", "asana", "monday"];
3
3
  export type WorkSourceProvider = typeof WORK_SOURCE_PROVIDERS[number];
4
4
  export interface WorkSourceRef {
5
5
  provider: WorkSourceProvider;
@@ -1,8 +1,10 @@
1
+ import { loadAsanaConfig } from '../asana/config.js';
1
2
  import { loadLinearConfig } from '../linear/config.js';
2
3
  import { loadJiraConfig } from '../jira/config.js';
4
+ import { loadShortcutConfig } from '../shortcut/config.js';
3
5
  const SETTINGS_TABLE = 'workspace_settings';
4
6
  const ACTIVE_SOURCE_KEY = 'work.active_source';
5
- export const WORK_SOURCE_PROVIDERS = ['pmo', 'linear', 'jira', 'asana', 'monday'];
7
+ export const WORK_SOURCE_PROVIDERS = ['pmo', 'linear', 'jira', 'shortcut', 'asana', 'monday'];
6
8
  function getSetting(db, key) {
7
9
  const row = db
8
10
  .prepare(`SELECT value FROM ${SETTINGS_TABLE} WHERE key = ?`)
@@ -74,6 +76,20 @@ export function getRegisteredWorkSources(db) {
74
76
  context: jiraConfig.projectKey ?? undefined,
75
77
  });
76
78
  }
79
+ const asanaConfig = loadAsanaConfig(db);
80
+ if (asanaConfig) {
81
+ providers.set('asana', {
82
+ provider: 'asana',
83
+ context: asanaConfig.projectName ?? asanaConfig.projectGid ?? undefined,
84
+ });
85
+ }
86
+ const shortcutConfig = loadShortcutConfig(db);
87
+ if (shortcutConfig) {
88
+ providers.set('shortcut', {
89
+ provider: 'shortcut',
90
+ context: shortcutConfig.workspaceSlug ?? undefined,
91
+ });
92
+ }
77
93
  return Array.from(providers.values());
78
94
  }
79
95
  //# sourceMappingURL=config.js.map