@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.
- package/LICENSE +21 -0
- package/README.md +380 -0
- package/dist/adapters/claude-code.d.ts +70 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +166 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/index.d.ts +16 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +49 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/opencode.d.ts +53 -0
- package/dist/adapters/opencode.d.ts.map +1 -0
- package/dist/adapters/opencode.js +120 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/adapters/process-utils.d.ts +29 -0
- package/dist/adapters/process-utils.d.ts.map +1 -0
- package/dist/adapters/process-utils.js +96 -0
- package/dist/adapters/process-utils.js.map +1 -0
- package/dist/adapters/types.d.ts +41 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +6 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/assets.generated.d.ts +13 -0
- package/dist/assets.generated.d.ts.map +1 -0
- package/dist/assets.generated.js +162 -0
- package/dist/assets.generated.js.map +1 -0
- package/dist/beads.d.ts +85 -0
- package/dist/beads.d.ts.map +1 -0
- package/dist/beads.js +120 -0
- package/dist/beads.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +39 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add.d.ts +10 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +58 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/cleanup.d.ts +13 -0
- package/dist/commands/cleanup.d.ts.map +1 -0
- package/dist/commands/cleanup.js +174 -0
- package/dist/commands/cleanup.js.map +1 -0
- package/dist/commands/daemon.d.ts +3 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +162 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/init.d.ts +20 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +125 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install-keybinding.d.ts +61 -0
- package/dist/commands/install-keybinding.d.ts.map +1 -0
- package/dist/commands/install-keybinding.js +138 -0
- package/dist/commands/install-keybinding.js.map +1 -0
- package/dist/commands/install-status.d.ts +35 -0
- package/dist/commands/install-status.d.ts.map +1 -0
- package/dist/commands/install-status.js +115 -0
- package/dist/commands/install-status.js.map +1 -0
- package/dist/commands/log.d.ts +7 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +60 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/pause.d.ts +12 -0
- package/dist/commands/pause.d.ts.map +1 -0
- package/dist/commands/pause.js +47 -0
- package/dist/commands/pause.js.map +1 -0
- package/dist/commands/resume.d.ts +12 -0
- package/dist/commands/resume.d.ts.map +1 -0
- package/dist/commands/resume.js +59 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/commands/shared.d.ts +7 -0
- package/dist/commands/shared.d.ts.map +1 -0
- package/dist/commands/shared.js +56 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/start.d.ts +12 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +274 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +24 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +101 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +11 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +52 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/teardown.d.ts +15 -0
- package/dist/commands/teardown.d.ts.map +1 -0
- package/dist/commands/teardown.js +72 -0
- package/dist/commands/teardown.js.map +1 -0
- package/dist/config.d.ts +58 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +129 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/client.d.ts +38 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +254 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/context.d.ts +63 -0
- package/dist/daemon/context.d.ts.map +1 -0
- package/dist/daemon/context.js +14 -0
- package/dist/daemon/context.js.map +1 -0
- package/dist/daemon/handlers.d.ts +79 -0
- package/dist/daemon/handlers.d.ts.map +1 -0
- package/dist/daemon/handlers.js +1260 -0
- package/dist/daemon/handlers.js.map +1 -0
- package/dist/daemon/index.d.ts +6 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +7 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/lifecycle.d.ts +56 -0
- package/dist/daemon/lifecycle.d.ts.map +1 -0
- package/dist/daemon/lifecycle.js +341 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/protocol.d.ts +174 -0
- package/dist/daemon/protocol.d.ts.map +1 -0
- package/dist/daemon/protocol.js +3 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/daemon/recovery.d.ts +37 -0
- package/dist/daemon/recovery.d.ts.map +1 -0
- package/dist/daemon/recovery.js +197 -0
- package/dist/daemon/recovery.js.map +1 -0
- package/dist/daemon/server.d.ts +31 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +294 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/socket.d.ts +18 -0
- package/dist/daemon/socket.d.ts.map +1 -0
- package/dist/daemon/socket.js +36 -0
- package/dist/daemon/socket.js.map +1 -0
- package/dist/daemon/state.d.ts +60 -0
- package/dist/daemon/state.d.ts.map +1 -0
- package/dist/daemon/state.js +156 -0
- package/dist/daemon/state.js.map +1 -0
- package/dist/daemon/systemd.d.ts +19 -0
- package/dist/daemon/systemd.d.ts.map +1 -0
- package/dist/daemon/systemd.js +131 -0
- package/dist/daemon/systemd.js.map +1 -0
- package/dist/hooks/claude-code-hook.d.ts +32 -0
- package/dist/hooks/claude-code-hook.d.ts.map +1 -0
- package/dist/hooks/claude-code-hook.js +112 -0
- package/dist/hooks/claude-code-hook.js.map +1 -0
- package/dist/instructions-template.d.ts +9 -0
- package/dist/instructions-template.d.ts.map +1 -0
- package/dist/instructions-template.js +123 -0
- package/dist/instructions-template.js.map +1 -0
- package/dist/logger.d.ts +25 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +44 -0
- package/dist/logger.js.map +1 -0
- package/dist/loop.d.ts +88 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +161 -0
- package/dist/loop.js.map +1 -0
- package/dist/orchestrator-instructions-template.d.ts +13 -0
- package/dist/orchestrator-instructions-template.d.ts.map +1 -0
- package/dist/orchestrator-instructions-template.js +147 -0
- package/dist/orchestrator-instructions-template.js.map +1 -0
- package/dist/output.d.ts +12 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +25 -0
- package/dist/output.js.map +1 -0
- package/dist/plugin/pit.js +57 -0
- package/dist/session.d.ts +55 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +135 -0
- package/dist/session.js.map +1 -0
- package/dist/setup.d.ts +92 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +382 -0
- package/dist/setup.js.map +1 -0
- package/dist/shell-quote.d.ts +16 -0
- package/dist/shell-quote.d.ts.map +1 -0
- package/dist/shell-quote.js +18 -0
- package/dist/shell-quote.js.map +1 -0
- package/dist/signals.d.ts +17 -0
- package/dist/signals.d.ts.map +1 -0
- package/dist/signals.js +26 -0
- package/dist/signals.js.map +1 -0
- package/dist/state-machine.d.ts +74 -0
- package/dist/state-machine.d.ts.map +1 -0
- package/dist/state-machine.js +153 -0
- package/dist/state-machine.js.map +1 -0
- package/dist/tmux.d.ts +101 -0
- package/dist/tmux.d.ts.map +1 -0
- package/dist/tmux.js +208 -0
- package/dist/tmux.js.map +1 -0
- package/dist/worktree.d.ts +33 -0
- package/dist/worktree.d.ts.map +1 -0
- package/dist/worktree.js +116 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +66 -0
package/dist/setup.d.ts
ADDED
|
@@ -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"}
|
package/dist/signals.js
ADDED
|
@@ -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"}
|