@elhu/pit 0.1.1

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 (192) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +380 -0
  3. package/dist/adapters/claude-code.d.ts +70 -0
  4. package/dist/adapters/claude-code.d.ts.map +1 -0
  5. package/dist/adapters/claude-code.js +166 -0
  6. package/dist/adapters/claude-code.js.map +1 -0
  7. package/dist/adapters/index.d.ts +16 -0
  8. package/dist/adapters/index.d.ts.map +1 -0
  9. package/dist/adapters/index.js +49 -0
  10. package/dist/adapters/index.js.map +1 -0
  11. package/dist/adapters/opencode.d.ts +53 -0
  12. package/dist/adapters/opencode.d.ts.map +1 -0
  13. package/dist/adapters/opencode.js +120 -0
  14. package/dist/adapters/opencode.js.map +1 -0
  15. package/dist/adapters/process-utils.d.ts +29 -0
  16. package/dist/adapters/process-utils.d.ts.map +1 -0
  17. package/dist/adapters/process-utils.js +96 -0
  18. package/dist/adapters/process-utils.js.map +1 -0
  19. package/dist/adapters/types.d.ts +41 -0
  20. package/dist/adapters/types.d.ts.map +1 -0
  21. package/dist/adapters/types.js +6 -0
  22. package/dist/adapters/types.js.map +1 -0
  23. package/dist/assets.generated.d.ts +13 -0
  24. package/dist/assets.generated.d.ts.map +1 -0
  25. package/dist/assets.generated.js +162 -0
  26. package/dist/assets.generated.js.map +1 -0
  27. package/dist/beads.d.ts +85 -0
  28. package/dist/beads.d.ts.map +1 -0
  29. package/dist/beads.js +120 -0
  30. package/dist/beads.js.map +1 -0
  31. package/dist/cli.d.ts +3 -0
  32. package/dist/cli.d.ts.map +1 -0
  33. package/dist/cli.js +39 -0
  34. package/dist/cli.js.map +1 -0
  35. package/dist/commands/add.d.ts +10 -0
  36. package/dist/commands/add.d.ts.map +1 -0
  37. package/dist/commands/add.js +58 -0
  38. package/dist/commands/add.js.map +1 -0
  39. package/dist/commands/cleanup.d.ts +13 -0
  40. package/dist/commands/cleanup.d.ts.map +1 -0
  41. package/dist/commands/cleanup.js +174 -0
  42. package/dist/commands/cleanup.js.map +1 -0
  43. package/dist/commands/daemon.d.ts +3 -0
  44. package/dist/commands/daemon.d.ts.map +1 -0
  45. package/dist/commands/daemon.js +162 -0
  46. package/dist/commands/daemon.js.map +1 -0
  47. package/dist/commands/init.d.ts +20 -0
  48. package/dist/commands/init.d.ts.map +1 -0
  49. package/dist/commands/init.js +125 -0
  50. package/dist/commands/init.js.map +1 -0
  51. package/dist/commands/install-keybinding.d.ts +61 -0
  52. package/dist/commands/install-keybinding.d.ts.map +1 -0
  53. package/dist/commands/install-keybinding.js +138 -0
  54. package/dist/commands/install-keybinding.js.map +1 -0
  55. package/dist/commands/install-status.d.ts +35 -0
  56. package/dist/commands/install-status.d.ts.map +1 -0
  57. package/dist/commands/install-status.js +115 -0
  58. package/dist/commands/install-status.js.map +1 -0
  59. package/dist/commands/log.d.ts +7 -0
  60. package/dist/commands/log.d.ts.map +1 -0
  61. package/dist/commands/log.js +60 -0
  62. package/dist/commands/log.js.map +1 -0
  63. package/dist/commands/pause.d.ts +12 -0
  64. package/dist/commands/pause.d.ts.map +1 -0
  65. package/dist/commands/pause.js +47 -0
  66. package/dist/commands/pause.js.map +1 -0
  67. package/dist/commands/resume.d.ts +12 -0
  68. package/dist/commands/resume.d.ts.map +1 -0
  69. package/dist/commands/resume.js +59 -0
  70. package/dist/commands/resume.js.map +1 -0
  71. package/dist/commands/shared.d.ts +7 -0
  72. package/dist/commands/shared.d.ts.map +1 -0
  73. package/dist/commands/shared.js +56 -0
  74. package/dist/commands/shared.js.map +1 -0
  75. package/dist/commands/start.d.ts +12 -0
  76. package/dist/commands/start.d.ts.map +1 -0
  77. package/dist/commands/start.js +274 -0
  78. package/dist/commands/start.js.map +1 -0
  79. package/dist/commands/status.d.ts +24 -0
  80. package/dist/commands/status.d.ts.map +1 -0
  81. package/dist/commands/status.js +101 -0
  82. package/dist/commands/status.js.map +1 -0
  83. package/dist/commands/stop.d.ts +11 -0
  84. package/dist/commands/stop.d.ts.map +1 -0
  85. package/dist/commands/stop.js +52 -0
  86. package/dist/commands/stop.js.map +1 -0
  87. package/dist/commands/teardown.d.ts +15 -0
  88. package/dist/commands/teardown.d.ts.map +1 -0
  89. package/dist/commands/teardown.js +72 -0
  90. package/dist/commands/teardown.js.map +1 -0
  91. package/dist/config.d.ts +58 -0
  92. package/dist/config.d.ts.map +1 -0
  93. package/dist/config.js +129 -0
  94. package/dist/config.js.map +1 -0
  95. package/dist/daemon/client.d.ts +38 -0
  96. package/dist/daemon/client.d.ts.map +1 -0
  97. package/dist/daemon/client.js +254 -0
  98. package/dist/daemon/client.js.map +1 -0
  99. package/dist/daemon/context.d.ts +63 -0
  100. package/dist/daemon/context.d.ts.map +1 -0
  101. package/dist/daemon/context.js +14 -0
  102. package/dist/daemon/context.js.map +1 -0
  103. package/dist/daemon/handlers.d.ts +79 -0
  104. package/dist/daemon/handlers.d.ts.map +1 -0
  105. package/dist/daemon/handlers.js +1260 -0
  106. package/dist/daemon/handlers.js.map +1 -0
  107. package/dist/daemon/index.d.ts +6 -0
  108. package/dist/daemon/index.d.ts.map +1 -0
  109. package/dist/daemon/index.js +7 -0
  110. package/dist/daemon/index.js.map +1 -0
  111. package/dist/daemon/lifecycle.d.ts +56 -0
  112. package/dist/daemon/lifecycle.d.ts.map +1 -0
  113. package/dist/daemon/lifecycle.js +341 -0
  114. package/dist/daemon/lifecycle.js.map +1 -0
  115. package/dist/daemon/protocol.d.ts +174 -0
  116. package/dist/daemon/protocol.d.ts.map +1 -0
  117. package/dist/daemon/protocol.js +3 -0
  118. package/dist/daemon/protocol.js.map +1 -0
  119. package/dist/daemon/recovery.d.ts +37 -0
  120. package/dist/daemon/recovery.d.ts.map +1 -0
  121. package/dist/daemon/recovery.js +197 -0
  122. package/dist/daemon/recovery.js.map +1 -0
  123. package/dist/daemon/server.d.ts +31 -0
  124. package/dist/daemon/server.d.ts.map +1 -0
  125. package/dist/daemon/server.js +294 -0
  126. package/dist/daemon/server.js.map +1 -0
  127. package/dist/daemon/socket.d.ts +18 -0
  128. package/dist/daemon/socket.d.ts.map +1 -0
  129. package/dist/daemon/socket.js +36 -0
  130. package/dist/daemon/socket.js.map +1 -0
  131. package/dist/daemon/state.d.ts +60 -0
  132. package/dist/daemon/state.d.ts.map +1 -0
  133. package/dist/daemon/state.js +156 -0
  134. package/dist/daemon/state.js.map +1 -0
  135. package/dist/daemon/systemd.d.ts +19 -0
  136. package/dist/daemon/systemd.d.ts.map +1 -0
  137. package/dist/daemon/systemd.js +131 -0
  138. package/dist/daemon/systemd.js.map +1 -0
  139. package/dist/hooks/claude-code-hook.d.ts +32 -0
  140. package/dist/hooks/claude-code-hook.d.ts.map +1 -0
  141. package/dist/hooks/claude-code-hook.js +112 -0
  142. package/dist/hooks/claude-code-hook.js.map +1 -0
  143. package/dist/instructions-template.d.ts +9 -0
  144. package/dist/instructions-template.d.ts.map +1 -0
  145. package/dist/instructions-template.js +123 -0
  146. package/dist/instructions-template.js.map +1 -0
  147. package/dist/logger.d.ts +25 -0
  148. package/dist/logger.d.ts.map +1 -0
  149. package/dist/logger.js +44 -0
  150. package/dist/logger.js.map +1 -0
  151. package/dist/loop.d.ts +88 -0
  152. package/dist/loop.d.ts.map +1 -0
  153. package/dist/loop.js +161 -0
  154. package/dist/loop.js.map +1 -0
  155. package/dist/orchestrator-instructions-template.d.ts +13 -0
  156. package/dist/orchestrator-instructions-template.d.ts.map +1 -0
  157. package/dist/orchestrator-instructions-template.js +147 -0
  158. package/dist/orchestrator-instructions-template.js.map +1 -0
  159. package/dist/output.d.ts +12 -0
  160. package/dist/output.d.ts.map +1 -0
  161. package/dist/output.js +25 -0
  162. package/dist/output.js.map +1 -0
  163. package/dist/plugin/pit.js +57 -0
  164. package/dist/session.d.ts +55 -0
  165. package/dist/session.d.ts.map +1 -0
  166. package/dist/session.js +135 -0
  167. package/dist/session.js.map +1 -0
  168. package/dist/setup.d.ts +92 -0
  169. package/dist/setup.d.ts.map +1 -0
  170. package/dist/setup.js +382 -0
  171. package/dist/setup.js.map +1 -0
  172. package/dist/shell-quote.d.ts +16 -0
  173. package/dist/shell-quote.d.ts.map +1 -0
  174. package/dist/shell-quote.js +18 -0
  175. package/dist/shell-quote.js.map +1 -0
  176. package/dist/signals.d.ts +17 -0
  177. package/dist/signals.d.ts.map +1 -0
  178. package/dist/signals.js +26 -0
  179. package/dist/signals.js.map +1 -0
  180. package/dist/state-machine.d.ts +74 -0
  181. package/dist/state-machine.d.ts.map +1 -0
  182. package/dist/state-machine.js +153 -0
  183. package/dist/state-machine.js.map +1 -0
  184. package/dist/tmux.d.ts +101 -0
  185. package/dist/tmux.d.ts.map +1 -0
  186. package/dist/tmux.js +208 -0
  187. package/dist/tmux.js.map +1 -0
  188. package/dist/worktree.d.ts +33 -0
  189. package/dist/worktree.d.ts.map +1 -0
  190. package/dist/worktree.js +116 -0
  191. package/dist/worktree.js.map +1 -0
  192. package/package.json +66 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Setup orchestration for pit.
3
+ *
4
+ * Provides verifyDependencies (checks that all required tools are available)
5
+ * and setupEpic (creates a worktree, installs agent bridge, creates a tmux
6
+ * window, and starts the agent for a single epic).
7
+ *
8
+ * startSession orchestrates multi-epic setup: resolves project root, checks
9
+ * lock, resolves adapter, verifies deps, creates session, sets up each epic
10
+ * sequentially, writes lock, updates status bar.
11
+ */
12
+ import type { AgentAdapter } from "./adapters/types.js";
13
+ import type { LoopHandle } from "./loop.js";
14
+ import type { Logger } from "./logger.js";
15
+ import { type LockData } from "./session.js";
16
+ export interface SetupOptions {
17
+ agent: string;
18
+ epics: string[];
19
+ worktreeDir: string;
20
+ baseBranch: string;
21
+ tmuxSession: string;
22
+ promptTemplate?: string;
23
+ instructionsTemplate?: string;
24
+ inlinePromptTemplate?: string;
25
+ clearDelay?: number;
26
+ initDelay?: number;
27
+ model?: string;
28
+ }
29
+ export interface EpicSetupResult {
30
+ epic: string;
31
+ status: "ok" | "error";
32
+ error?: string;
33
+ worktreePath?: string;
34
+ /** The actual tmux window name used (may differ if window was renamed or recreated). */
35
+ windowName?: string;
36
+ /** True if an already-running agent was detected and reused (no re-start or re-prompt). */
37
+ reused?: boolean;
38
+ }
39
+ export interface StartResult {
40
+ sessionId: string;
41
+ tmuxSession: string;
42
+ epics: EpicSetupResult[];
43
+ /** Loop handles for each successfully started epic, keyed by epic ID */
44
+ loops: Map<string, LoopHandle>;
45
+ }
46
+ /**
47
+ * Formats a concise status bar string from epic setup results.
48
+ * Example: "[auth: ok] [payments: error]"
49
+ */
50
+ export declare function formatSetupStatusBar(results: EpicSetupResult[]): string;
51
+ /**
52
+ * Cleans up a stale session: removes tmux session, worktrees, signal dirs, and lock file.
53
+ */
54
+ export declare function cleanupStaleSession(staleData: LockData, projectRoot: string, options: SetupOptions, logger: Logger): Promise<void>;
55
+ /**
56
+ * Orchestrate a full pit session: resolve project root, check lock, resolve
57
+ * adapter, verify dependencies, create session dir, create tmux session if
58
+ * needed, write lock, set up each epic sequentially, update status bar.
59
+ *
60
+ * Throws if:
61
+ * - lock is alive (another pit is running)
62
+ * - adapter/dependency verification fails
63
+ * - ALL epics fail (partial failure is allowed)
64
+ */
65
+ export declare function startSession(options: SetupOptions, logger: Logger): Promise<StartResult>;
66
+ /**
67
+ * Resolves template content from a three-tier cascade:
68
+ * 1. File path (if provided, reads file — throws if missing)
69
+ * 2. Inline content (if provided, uses directly)
70
+ * 3. Built-in default
71
+ *
72
+ * Callers should resolve relative paths to absolute before passing filePath.
73
+ */
74
+ export declare function resolveTemplateContent(filePath: string | undefined, inlineContent: string | undefined, builtinDefault: string): string;
75
+ export declare const DEFAULT_PROMPT = "Find the next ready ticket in epic {{EPIC_ID}} and work on it.";
76
+ export declare function renderPrompt(epicId: string, customTemplate?: string): string;
77
+ /**
78
+ * Check that all required tools are installed and available on PATH.
79
+ * Throws with a clear message on the first missing dependency.
80
+ */
81
+ export declare function verifyDependencies(adapter: AgentAdapter): Promise<void>;
82
+ /**
83
+ * Set up a single epic: create a worktree, install the agent event bridge,
84
+ * write instructions, ensure the signal directory, set the initial status,
85
+ * create a tmux window (if it doesn't already exist), start the agent, and
86
+ * send the initial prompt.
87
+ *
88
+ * Each step is wrapped in a try/catch: on failure, logs the error and returns
89
+ * an error result. This prevents one epic's failure from crashing the others.
90
+ */
91
+ export declare function setupEpic(adapter: AgentAdapter, epic: string, sessionId: string, tmuxSession: string, options: SetupOptions, logger: Logger): Promise<EpicSetupResult>;
92
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,WAAW,CAAC;AAE3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAML,KAAK,QAAQ,EACd,MAAM,cAAc,CAAC;AAmBtB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,wEAAwE;IACxE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAChC;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,MAAM,CAEvE;AA8BD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,QAAQ,EACnB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAsCf;AAwBD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAmG9F;AAMD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,cAAc,EAAE,MAAM,GACrB,MAAM,CAWR;AAMD,eAAO,MAAM,cAAc,mEAAmE,CAAC;AAE/F,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAG5E;AAMD;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B7E;AAMD;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC,CAgH1B"}
package/dist/setup.js ADDED
@@ -0,0 +1,382 @@
1
+ /**
2
+ * Setup orchestration for pit.
3
+ *
4
+ * Provides verifyDependencies (checks that all required tools are available)
5
+ * and setupEpic (creates a worktree, installs agent bridge, creates a tmux
6
+ * window, and starts the agent for a single epic).
7
+ *
8
+ * startSession orchestrates multi-epic setup: resolves project root, checks
9
+ * lock, resolves adapter, verifies deps, creates session, sets up each epic
10
+ * sequentially, writes lock, updates status bar.
11
+ */
12
+ import * as fs from "node:fs";
13
+ import * as path from "node:path";
14
+ import { execFile } from "node:child_process";
15
+ import { promisify } from "node:util";
16
+ import * as readline from "node:readline";
17
+ import { resolveAdapter } from "./adapters/index.js";
18
+ import { INSTRUCTIONS_TEMPLATE, renderInstructions } from "./instructions-template.js";
19
+ import { startLoop, updateStatusBar } from "./loop.js";
20
+ import { createLogger } from "./logger.js";
21
+ import { checkLock, generateSessionId, removeLock, sessionDir, writeLock, } from "./session.js";
22
+ import { ensureDir } from "./signals.js";
23
+ import { createSession, createWindow, sendKeys, sendPrompt, sessionExists, windowExists, killSession, } from "./tmux.js";
24
+ import { createWorktree, removeWorktree } from "./worktree.js";
25
+ const execFileAsync = promisify(execFile);
26
+ // ---------------------------------------------------------------------------
27
+ // Status bar formatting
28
+ // ---------------------------------------------------------------------------
29
+ /**
30
+ * Formats a concise status bar string from epic setup results.
31
+ * Example: "[auth: ok] [payments: error]"
32
+ */
33
+ export function formatSetupStatusBar(results) {
34
+ return results.map((r) => `[${r.epic}: ${r.status}]`).join(" ");
35
+ }
36
+ // ---------------------------------------------------------------------------
37
+ // Stale session handling
38
+ // ---------------------------------------------------------------------------
39
+ /**
40
+ * Prompts user for confirmation to clean up stale session.
41
+ * Returns true if user confirms cleanup, false if they want to abort.
42
+ */
43
+ async function promptCleanup(staleData) {
44
+ const rl = readline.createInterface({
45
+ input: process.stdin,
46
+ output: process.stdout,
47
+ });
48
+ return new Promise((resolve) => {
49
+ const staleInfo = `Stale session detected:
50
+ PID: ${staleData.pid} (dead)
51
+ Session: ${staleData.tmuxSession}
52
+ Epics: ${staleData.epics.join(", ")}
53
+ Created: ${staleData.createdAt}`;
54
+ rl.question(`${staleInfo}\n\nClean up stale session? (y/n) `, (answer) => {
55
+ rl.close();
56
+ resolve(answer.toLowerCase().trim() === "y");
57
+ });
58
+ });
59
+ }
60
+ /**
61
+ * Cleans up a stale session: removes tmux session, worktrees, signal dirs, and lock file.
62
+ */
63
+ export async function cleanupStaleSession(staleData, projectRoot, options, logger) {
64
+ logger.info("cleaning up stale session", { sessionId: staleData.sessionId });
65
+ // 1. Kill tmux session if it exists
66
+ try {
67
+ const tmuxExists = await sessionExists(staleData.tmuxSession);
68
+ if (tmuxExists) {
69
+ await killSession(staleData.tmuxSession);
70
+ logger.info(`removed tmux session: ${staleData.tmuxSession}`);
71
+ }
72
+ }
73
+ catch (err) {
74
+ logger.warn(`failed to remove tmux session: ${err}`);
75
+ }
76
+ // 2. Remove worktrees for each epic
77
+ for (const epic of staleData.epics) {
78
+ try {
79
+ await removeWorktree(options.worktreeDir, epic);
80
+ logger.info(`removed worktree for epic: ${epic}`);
81
+ }
82
+ catch (err) {
83
+ logger.warn(`failed to remove worktree for ${epic}: ${err}`);
84
+ }
85
+ }
86
+ // 3. Remove session signal directory
87
+ try {
88
+ const sessionSignalDir = sessionDir(staleData.sessionId);
89
+ if (fs.existsSync(sessionSignalDir)) {
90
+ await fs.promises.rm(sessionSignalDir, { recursive: true, force: true });
91
+ logger.info(`removed session directory: ${sessionSignalDir}`);
92
+ }
93
+ }
94
+ catch (err) {
95
+ logger.warn(`failed to remove session directory: ${err}`);
96
+ }
97
+ // 4. Remove lock file
98
+ await removeLock(projectRoot);
99
+ logger.info("removed stale lock file");
100
+ }
101
+ /**
102
+ * Handles stale session detection with user prompt for cleanup.
103
+ */
104
+ async function handleStaleSession(staleData, projectRoot, options, logger) {
105
+ const shouldCleanup = await promptCleanup(staleData);
106
+ if (!shouldCleanup) {
107
+ throw new Error("Aborted: stale session cleanup declined");
108
+ }
109
+ await cleanupStaleSession(staleData, projectRoot, options, logger);
110
+ logger.info("stale session cleaned up successfully");
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // startSession
114
+ // ---------------------------------------------------------------------------
115
+ /**
116
+ * Orchestrate a full pit session: resolve project root, check lock, resolve
117
+ * adapter, verify dependencies, create session dir, create tmux session if
118
+ * needed, write lock, set up each epic sequentially, update status bar.
119
+ *
120
+ * Throws if:
121
+ * - lock is alive (another pit is running)
122
+ * - adapter/dependency verification fails
123
+ * - ALL epics fail (partial failure is allowed)
124
+ */
125
+ export async function startSession(options, logger) {
126
+ // 1. Resolve project root
127
+ const { stdout: gitRoot } = await execFileAsync("git", ["rev-parse", "--show-toplevel"]);
128
+ const projectRoot = gitRoot.trim();
129
+ // 2. Check lock and handle stale sessions
130
+ const lockStatus = await checkLock(projectRoot);
131
+ if (lockStatus.status === "alive") {
132
+ throw new Error(`pit is already running (PID ${lockStatus.data.pid})`);
133
+ }
134
+ if (lockStatus.status === "stale") {
135
+ await handleStaleSession(lockStatus.data, projectRoot, options, logger);
136
+ }
137
+ // 3. Resolve adapter
138
+ const adapter = await resolveAdapter(options.agent);
139
+ // 4. Verify dependencies
140
+ await verifyDependencies(adapter);
141
+ // 5. Generate session ID
142
+ const sessionId = generateSessionId(projectRoot, options.tmuxSession);
143
+ // 6. Ensure session dir exists
144
+ await ensureDir(sessionDir(sessionId));
145
+ // 7. Init log stream and logger for the session
146
+ const logStream = fs.createWriteStream(path.join(sessionDir(sessionId), "pit.log"), {
147
+ flags: "a",
148
+ });
149
+ const sessionLogger = createLogger({ stream: logStream });
150
+ // 8. Create tmux session if it doesn't exist
151
+ const sessionAlreadyExists = await sessionExists(options.tmuxSession);
152
+ if (!sessionAlreadyExists) {
153
+ await createSession(options.tmuxSession);
154
+ }
155
+ // 9. Write lock
156
+ await writeLock(projectRoot, {
157
+ sessionId,
158
+ pid: process.pid,
159
+ tmuxSession: options.tmuxSession,
160
+ epics: options.epics,
161
+ createdAt: new Date().toISOString(),
162
+ createdSession: !sessionAlreadyExists,
163
+ });
164
+ // 10. Set up each epic sequentially
165
+ const results = [];
166
+ for (const epic of options.epics) {
167
+ const result = await setupEpic(adapter, epic, sessionId, options.tmuxSession, options, sessionLogger);
168
+ results.push(result);
169
+ }
170
+ // 11. If ALL epics failed, remove lock and throw
171
+ const allFailed = results.every((r) => r.status === "error");
172
+ if (allFailed) {
173
+ await removeLock(projectRoot);
174
+ throw new Error(`All epics failed to start: ${results.map((r) => `${r.epic}: ${r.error ?? "unknown"}`).join(", ")}`);
175
+ }
176
+ // 12. Start the autonomous loop for each successfully set up epic
177
+ const loops = new Map();
178
+ for (const result of results) {
179
+ if (result.status !== "ok")
180
+ continue;
181
+ const epic = result.epic;
182
+ const windowName = `epic-${epic}`;
183
+ const handle = startLoop({
184
+ epic,
185
+ tmuxSession: options.tmuxSession,
186
+ windowName,
187
+ adapter,
188
+ logger: sessionLogger,
189
+ });
190
+ loops.set(epic, handle);
191
+ sessionLogger.info(`[${epic}] loop started`, { epic });
192
+ }
193
+ // 13. Update status bar with initial loop states
194
+ const epicStates = new Map(Array.from(loops.entries()).map(([epic, handle]) => [
195
+ epic,
196
+ { state: handle.machine.state, progress: null, pauseReason: null },
197
+ ]));
198
+ await updateStatusBar(options.tmuxSession, epicStates);
199
+ // 14. Return result
200
+ return { sessionId, tmuxSession: options.tmuxSession, epics: results, loops };
201
+ }
202
+ // ---------------------------------------------------------------------------
203
+ // Template resolution
204
+ // ---------------------------------------------------------------------------
205
+ /**
206
+ * Resolves template content from a three-tier cascade:
207
+ * 1. File path (if provided, reads file — throws if missing)
208
+ * 2. Inline content (if provided, uses directly)
209
+ * 3. Built-in default
210
+ *
211
+ * Callers should resolve relative paths to absolute before passing filePath.
212
+ */
213
+ export function resolveTemplateContent(filePath, inlineContent, builtinDefault) {
214
+ if (filePath !== undefined) {
215
+ if (!fs.existsSync(filePath)) {
216
+ throw new Error(`Template file not found: ${filePath}`);
217
+ }
218
+ return fs.readFileSync(filePath, "utf8");
219
+ }
220
+ if (inlineContent !== undefined) {
221
+ return inlineContent;
222
+ }
223
+ return builtinDefault;
224
+ }
225
+ // ---------------------------------------------------------------------------
226
+ // Prompt template
227
+ // ---------------------------------------------------------------------------
228
+ export const DEFAULT_PROMPT = "Find the next ready ticket in epic {{EPIC_ID}} and work on it.";
229
+ export function renderPrompt(epicId, customTemplate) {
230
+ const template = customTemplate ?? DEFAULT_PROMPT;
231
+ return template.replaceAll("{{EPIC_ID}}", epicId).replaceAll("{{EPIC_NAME}}", epicId);
232
+ }
233
+ // ---------------------------------------------------------------------------
234
+ // verifyDependencies
235
+ // ---------------------------------------------------------------------------
236
+ /**
237
+ * Check that all required tools are installed and available on PATH.
238
+ * Throws with a clear message on the first missing dependency.
239
+ */
240
+ export async function verifyDependencies(adapter) {
241
+ // Check tmux
242
+ try {
243
+ await execFileAsync("which", ["tmux"]);
244
+ }
245
+ catch {
246
+ throw new Error("tmux is not installed");
247
+ }
248
+ // Check git
249
+ try {
250
+ await execFileAsync("which", ["git"]);
251
+ }
252
+ catch {
253
+ throw new Error("git is not installed");
254
+ }
255
+ // Check bd (beads)
256
+ try {
257
+ await execFileAsync("which", ["bd"]);
258
+ }
259
+ catch {
260
+ throw new Error("bd (beads) is not installed");
261
+ }
262
+ // Check agent
263
+ const agentInstalled = await adapter.checkInstalled();
264
+ if (!agentInstalled) {
265
+ throw new Error(`Agent ${adapter.name} is not installed`);
266
+ }
267
+ }
268
+ // ---------------------------------------------------------------------------
269
+ // setupEpic
270
+ // ---------------------------------------------------------------------------
271
+ /**
272
+ * Set up a single epic: create a worktree, install the agent event bridge,
273
+ * write instructions, ensure the signal directory, set the initial status,
274
+ * create a tmux window (if it doesn't already exist), start the agent, and
275
+ * send the initial prompt.
276
+ *
277
+ * Each step is wrapped in a try/catch: on failure, logs the error and returns
278
+ * an error result. This prevents one epic's failure from crashing the others.
279
+ */
280
+ export async function setupEpic(adapter, epic, sessionId, tmuxSession, options, logger) {
281
+ // Step 1: Create worktree
282
+ let worktreePath;
283
+ try {
284
+ const result = await createWorktree(options.worktreeDir, epic, options.baseBranch);
285
+ worktreePath = result.path;
286
+ }
287
+ catch (err) {
288
+ logger.error("setupEpic: createWorktree failed", { epic, err: String(err) });
289
+ return { epic, status: "error", error: err.message };
290
+ }
291
+ // Step 2: Install event bridge
292
+ try {
293
+ await adapter.installEventBridge(worktreePath, epic);
294
+ }
295
+ catch (err) {
296
+ logger.error("setupEpic: installEventBridge failed", { epic, err: String(err) });
297
+ return { epic, status: "error", error: err.message };
298
+ }
299
+ // Step 3: Write agent instructions
300
+ try {
301
+ const resolvedInstructionsPath = options.instructionsTemplate
302
+ ? path.resolve(options.instructionsTemplate)
303
+ : undefined;
304
+ const instructionsContent = resolveTemplateContent(resolvedInstructionsPath, undefined, INSTRUCTIONS_TEMPLATE);
305
+ await adapter.writeInstructions(worktreePath, renderInstructions(epic, instructionsContent));
306
+ }
307
+ catch (err) {
308
+ logger.error("setupEpic: writeInstructions failed", { epic, err: String(err) });
309
+ return { epic, status: "error", error: err.message };
310
+ }
311
+ // Step 4: Create tmux window (skip if already exists) and detect running agent
312
+ const windowName = `epic-${epic}`;
313
+ const socketPath = `/tmp/pit/${sessionId}/daemon.sock`;
314
+ const env = {
315
+ PIT_EPIC: epic,
316
+ PIT_SOCKET_PATH: socketPath,
317
+ };
318
+ let windowAlreadyExisted;
319
+ try {
320
+ const exists = await windowExists(tmuxSession, windowName);
321
+ windowAlreadyExisted = exists;
322
+ if (!exists) {
323
+ await createWindow(tmuxSession, windowName, worktreePath, env);
324
+ }
325
+ }
326
+ catch (err) {
327
+ logger.error("setupEpic: createWindow failed", { epic, err: String(err) });
328
+ return { epic, status: "error", error: err.message };
329
+ }
330
+ // Step 5: If window already existed, check whether the agent process is still running
331
+ if (windowAlreadyExisted) {
332
+ let agentRunning = false;
333
+ try {
334
+ agentRunning = await adapter.verifyRunning(tmuxSession, windowName);
335
+ }
336
+ catch (err) {
337
+ // verifyRunning failure → treat as not running, proceed with restart
338
+ logger.warn("setupEpic: verifyRunning threw, treating agent as not running", {
339
+ epic,
340
+ err: String(err),
341
+ });
342
+ }
343
+ if (agentRunning) {
344
+ // Agent is alive — reuse the existing session, skip start/wait/prompt
345
+ logger.info("setupEpic: existing agent detected, reusing session", { epic });
346
+ return { epic, status: "ok", worktreePath, windowName, reused: true };
347
+ }
348
+ // Agent is dead — restart it in the existing window
349
+ logger.info("setupEpic: agent not running in existing window, restarting", { epic });
350
+ }
351
+ // Step 8: Start the agent
352
+ try {
353
+ await sendKeys(tmuxSession, windowName, adapter.startCommand(worktreePath, env, options.model));
354
+ }
355
+ catch (err) {
356
+ logger.error("setupEpic: sendKeys (startCommand) failed", { epic, err: String(err) });
357
+ return { epic, status: "error", error: err.message };
358
+ }
359
+ // Step 9: Wait for agent to be ready
360
+ try {
361
+ await adapter.waitForReady({ timeoutMs: options.initDelay ?? 5000 });
362
+ }
363
+ catch (err) {
364
+ logger.error("setupEpic: waitForReady failed", { epic, err: String(err) });
365
+ return { epic, status: "error", error: err.message };
366
+ }
367
+ // Step 10: Send initial prompt
368
+ try {
369
+ const resolvedPromptPath = options.promptTemplate
370
+ ? path.resolve(options.promptTemplate)
371
+ : undefined;
372
+ const promptContent = resolveTemplateContent(resolvedPromptPath, options.inlinePromptTemplate, DEFAULT_PROMPT);
373
+ await sendPrompt(tmuxSession, windowName, renderPrompt(epic, promptContent));
374
+ }
375
+ catch (err) {
376
+ logger.error("setupEpic: sendPrompt (renderPrompt) failed", { epic, err: String(err) });
377
+ return { epic, status: "error", error: err.message };
378
+ }
379
+ // Step 11: Return success
380
+ return { epic, status: "ok", worktreePath, windowName, reused: false };
381
+ }
382
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Shell-quoting utility for safely embedding values in shell commands.
3
+ *
4
+ * Used by agent adapters to pass the --model flag through tmux send-keys,
5
+ * which requires shell-safe quoting of arbitrary user-supplied strings.
6
+ */
7
+ /**
8
+ * Wrap a string in single quotes, escaping any embedded single quotes.
9
+ *
10
+ * Examples:
11
+ * shellQuote('claude-sonnet-4-20250514') → "'claude-sonnet-4-20250514'"
12
+ * shellQuote('model with spaces') → "'model with spaces'"
13
+ * shellQuote("it's") → "'it'\\''s'"
14
+ */
15
+ export declare function shellQuote(s: string): string;
16
+ //# sourceMappingURL=shell-quote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-quote.d.ts","sourceRoot":"","sources":["../src/shell-quote.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Shell-quoting utility for safely embedding values in shell commands.
3
+ *
4
+ * Used by agent adapters to pass the --model flag through tmux send-keys,
5
+ * which requires shell-safe quoting of arbitrary user-supplied strings.
6
+ */
7
+ /**
8
+ * Wrap a string in single quotes, escaping any embedded single quotes.
9
+ *
10
+ * Examples:
11
+ * shellQuote('claude-sonnet-4-20250514') → "'claude-sonnet-4-20250514'"
12
+ * shellQuote('model with spaces') → "'model with spaces'"
13
+ * shellQuote("it's") → "'it'\\''s'"
14
+ */
15
+ export function shellQuote(s) {
16
+ return "'" + s.replace(/'/g, "'\\''") + "'";
17
+ }
18
+ //# sourceMappingURL=shell-quote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-quote.js","sourceRoot":"","sources":["../src/shell-quote.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,OAAO,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Ensures a directory exists, creating it (and any parents) if needed.
3
+ * Idempotent — safe to call multiple times.
4
+ */
5
+ export declare function ensureDir(dir: string): Promise<void>;
6
+ /**
7
+ * Removes a directory tree recursively.
8
+ * Idempotent — does not throw if the directory does not exist.
9
+ */
10
+ export declare function cleanup(dir: string): Promise<void>;
11
+ /**
12
+ * Atomically writes `content` to `filePath`.
13
+ * Writes to a `.tmp` sibling file first, then renames into place so readers
14
+ * never observe a partial write.
15
+ */
16
+ export declare function atomicWrite(filePath: string, content: string): Promise<void>;
17
+ //# sourceMappingURL=signals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAExD;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIlF"}
@@ -0,0 +1,26 @@
1
+ import * as fsp from "node:fs/promises";
2
+ /**
3
+ * Ensures a directory exists, creating it (and any parents) if needed.
4
+ * Idempotent — safe to call multiple times.
5
+ */
6
+ export async function ensureDir(dir) {
7
+ await fsp.mkdir(dir, { recursive: true });
8
+ }
9
+ /**
10
+ * Removes a directory tree recursively.
11
+ * Idempotent — does not throw if the directory does not exist.
12
+ */
13
+ export async function cleanup(dir) {
14
+ await fsp.rm(dir, { recursive: true, force: true });
15
+ }
16
+ /**
17
+ * Atomically writes `content` to `filePath`.
18
+ * Writes to a `.tmp` sibling file first, then renames into place so readers
19
+ * never observe a partial write.
20
+ */
21
+ export async function atomicWrite(filePath, content) {
22
+ const tmpPath = `${filePath}.tmp`;
23
+ await fsp.writeFile(tmpPath, content, "utf8");
24
+ await fsp.rename(tmpPath, filePath);
25
+ }
26
+ //# sourceMappingURL=signals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signals.js","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAExC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAW;IACvC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB,EAAE,OAAe;IACjE,MAAM,OAAO,GAAG,GAAG,QAAQ,MAAM,CAAC;IAClC,MAAM,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC"}