@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/beads.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beads (bd) CLI wrapper module.
|
|
3
|
+
*
|
|
4
|
+
* Provides a thin async layer over the `bd` CLI for ticket discovery, progress
|
|
5
|
+
* tracking, and epic management. All bd commands are invoked with `--json` for
|
|
6
|
+
* machine-readable output.
|
|
7
|
+
*
|
|
8
|
+
* ## Data Locality Finding
|
|
9
|
+
*
|
|
10
|
+
* `bd` resolves the `.beads/` database relative to the **git root**, not the
|
|
11
|
+
* working directory of the calling process. Verified by running `bd list --json`
|
|
12
|
+
* from both the main git worktree (/home/elhu/pit) and a linked worktree
|
|
13
|
+
* (/home/elhu/worktrees/pit-beads) — both returned the identical set of issues.
|
|
14
|
+
*
|
|
15
|
+
* Consequence: `execBd` can be called from any directory within the git tree
|
|
16
|
+
* and will always access the same beads database. The `cwd` option is provided
|
|
17
|
+
* for completeness and to allow callers to scope operations to a specific
|
|
18
|
+
* worktree if needed (e.g., for future bd features that are worktree-scoped),
|
|
19
|
+
* but it does NOT affect which `.beads/` database is used.
|
|
20
|
+
*/
|
|
21
|
+
export interface BeadTicket {
|
|
22
|
+
id: string;
|
|
23
|
+
title: string;
|
|
24
|
+
status: string;
|
|
25
|
+
priority: number;
|
|
26
|
+
issue_type: string;
|
|
27
|
+
owner: string;
|
|
28
|
+
created_at: string;
|
|
29
|
+
updated_at: string;
|
|
30
|
+
}
|
|
31
|
+
export interface EpicProgress {
|
|
32
|
+
done: number;
|
|
33
|
+
total: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Shell out to the `bd` CLI.
|
|
37
|
+
*
|
|
38
|
+
* Always appends `--json` to the provided args so output is machine-readable.
|
|
39
|
+
*
|
|
40
|
+
* @param args - CLI arguments to pass to bd (without --json)
|
|
41
|
+
* @param options.cwd - Working directory for the subprocess (default: process.cwd())
|
|
42
|
+
* @returns Resolved stdout string on success
|
|
43
|
+
* @throws If bd is not installed (ENOENT) or exits with a non-zero code
|
|
44
|
+
*/
|
|
45
|
+
export declare function execBd(args: string[], options?: {
|
|
46
|
+
cwd?: string;
|
|
47
|
+
}): Promise<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Return the next available (unblocked, open) ticket under an epic, or null if
|
|
50
|
+
* there is no work ready.
|
|
51
|
+
*
|
|
52
|
+
* @param epicId - The parent epic id (e.g. "pit-24s")
|
|
53
|
+
* @param options.cwd - Working directory for the subprocess
|
|
54
|
+
*/
|
|
55
|
+
export declare function ready(epicId: string, options?: {
|
|
56
|
+
cwd?: string;
|
|
57
|
+
}): Promise<BeadTicket | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Return all tickets under an epic (open, in-progress, closed, etc.).
|
|
60
|
+
*
|
|
61
|
+
* @param epicId - The parent epic id
|
|
62
|
+
* @param options.cwd - Working directory for the subprocess
|
|
63
|
+
*/
|
|
64
|
+
export declare function list(epicId: string, options?: {
|
|
65
|
+
cwd?: string;
|
|
66
|
+
}): Promise<BeadTicket[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Return a single ticket by ID, or null if not found / bd unavailable.
|
|
69
|
+
*
|
|
70
|
+
* @param ticketId - The ticket id (e.g. "pit-24s.3")
|
|
71
|
+
* @param options.cwd - Working directory for the subprocess
|
|
72
|
+
*/
|
|
73
|
+
export declare function show(ticketId: string, options?: {
|
|
74
|
+
cwd?: string;
|
|
75
|
+
}): Promise<BeadTicket | null>;
|
|
76
|
+
/**
|
|
77
|
+
* Compute completion progress for an epic.
|
|
78
|
+
*
|
|
79
|
+
* @param epicId - The parent epic id
|
|
80
|
+
* @param options.cwd - Working directory for the subprocess
|
|
81
|
+
*/
|
|
82
|
+
export declare function progress(epicId: string, options?: {
|
|
83
|
+
cwd?: string;
|
|
84
|
+
}): Promise<EpicProgress>;
|
|
85
|
+
//# sourceMappingURL=beads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beads.d.ts","sourceRoot":"","sources":["../src/beads.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAWH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAMD;;;;;;;;;GASG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BxF;AAMD;;;;;;GAMG;AACH,wBAAsB,KAAK,CACzB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAI5B;AAED;;;;;GAKG;AACH,wBAAsB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAG5F;AAED;;;;;GAKG;AACH,wBAAsB,IAAI,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAU5B;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAOhG"}
|
package/dist/beads.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beads (bd) CLI wrapper module.
|
|
3
|
+
*
|
|
4
|
+
* Provides a thin async layer over the `bd` CLI for ticket discovery, progress
|
|
5
|
+
* tracking, and epic management. All bd commands are invoked with `--json` for
|
|
6
|
+
* machine-readable output.
|
|
7
|
+
*
|
|
8
|
+
* ## Data Locality Finding
|
|
9
|
+
*
|
|
10
|
+
* `bd` resolves the `.beads/` database relative to the **git root**, not the
|
|
11
|
+
* working directory of the calling process. Verified by running `bd list --json`
|
|
12
|
+
* from both the main git worktree (/home/elhu/pit) and a linked worktree
|
|
13
|
+
* (/home/elhu/worktrees/pit-beads) — both returned the identical set of issues.
|
|
14
|
+
*
|
|
15
|
+
* Consequence: `execBd` can be called from any directory within the git tree
|
|
16
|
+
* and will always access the same beads database. The `cwd` option is provided
|
|
17
|
+
* for completeness and to allow callers to scope operations to a specific
|
|
18
|
+
* worktree if needed (e.g., for future bd features that are worktree-scoped),
|
|
19
|
+
* but it does NOT affect which `.beads/` database is used.
|
|
20
|
+
*/
|
|
21
|
+
import { execFile } from "node:child_process";
|
|
22
|
+
import { promisify } from "node:util";
|
|
23
|
+
const execFileAsync = promisify(execFile);
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Internal helper
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
/**
|
|
28
|
+
* Shell out to the `bd` CLI.
|
|
29
|
+
*
|
|
30
|
+
* Always appends `--json` to the provided args so output is machine-readable.
|
|
31
|
+
*
|
|
32
|
+
* @param args - CLI arguments to pass to bd (without --json)
|
|
33
|
+
* @param options.cwd - Working directory for the subprocess (default: process.cwd())
|
|
34
|
+
* @returns Resolved stdout string on success
|
|
35
|
+
* @throws If bd is not installed (ENOENT) or exits with a non-zero code
|
|
36
|
+
*/
|
|
37
|
+
export async function execBd(args, options) {
|
|
38
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
39
|
+
try {
|
|
40
|
+
const { stdout } = await execFileAsync("bd", [...args, "--json"], { cwd });
|
|
41
|
+
return stdout;
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
// bd is not installed or not in PATH
|
|
45
|
+
if (typeof err === "object" &&
|
|
46
|
+
err !== null &&
|
|
47
|
+
"code" in err &&
|
|
48
|
+
err.code === "ENOENT") {
|
|
49
|
+
throw new Error("bd (beads) is not installed or not in PATH", {
|
|
50
|
+
cause: err,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// Non-zero exit — surface stderr to caller
|
|
54
|
+
if (typeof err === "object" &&
|
|
55
|
+
err !== null &&
|
|
56
|
+
"stderr" in err &&
|
|
57
|
+
typeof err.stderr === "string") {
|
|
58
|
+
throw new Error(err.stderr, { cause: err });
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Public API
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
/**
|
|
67
|
+
* Return the next available (unblocked, open) ticket under an epic, or null if
|
|
68
|
+
* there is no work ready.
|
|
69
|
+
*
|
|
70
|
+
* @param epicId - The parent epic id (e.g. "pit-24s")
|
|
71
|
+
* @param options.cwd - Working directory for the subprocess
|
|
72
|
+
*/
|
|
73
|
+
export async function ready(epicId, options) {
|
|
74
|
+
const stdout = await execBd(["ready", "--parent", epicId, "--limit", "1"], options);
|
|
75
|
+
const tickets = JSON.parse(stdout);
|
|
76
|
+
return tickets.length > 0 ? tickets[0] : null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Return all tickets under an epic (open, in-progress, closed, etc.).
|
|
80
|
+
*
|
|
81
|
+
* @param epicId - The parent epic id
|
|
82
|
+
* @param options.cwd - Working directory for the subprocess
|
|
83
|
+
*/
|
|
84
|
+
export async function list(epicId, options) {
|
|
85
|
+
const stdout = await execBd(["list", "--parent", epicId, "--limit", "0", "--all"], options);
|
|
86
|
+
return JSON.parse(stdout);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Return a single ticket by ID, or null if not found / bd unavailable.
|
|
90
|
+
*
|
|
91
|
+
* @param ticketId - The ticket id (e.g. "pit-24s.3")
|
|
92
|
+
* @param options.cwd - Working directory for the subprocess
|
|
93
|
+
*/
|
|
94
|
+
export async function show(ticketId, options) {
|
|
95
|
+
try {
|
|
96
|
+
const stdout = await execBd(["show", ticketId], options);
|
|
97
|
+
const parsed = JSON.parse(stdout);
|
|
98
|
+
// bd show --json may return an array with one element or a single object
|
|
99
|
+
const ticket = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
100
|
+
return ticket ?? null;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null; // ticket not found, bd not installed, etc.
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Compute completion progress for an epic.
|
|
108
|
+
*
|
|
109
|
+
* @param epicId - The parent epic id
|
|
110
|
+
* @param options.cwd - Working directory for the subprocess
|
|
111
|
+
*/
|
|
112
|
+
export async function progress(epicId, options) {
|
|
113
|
+
const tickets = await list(epicId, options);
|
|
114
|
+
if (tickets.length === 0) {
|
|
115
|
+
return { done: 0, total: 0 };
|
|
116
|
+
}
|
|
117
|
+
const done = tickets.filter((t) => t.status === "closed").length;
|
|
118
|
+
return { done, total: tickets.length };
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=beads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beads.js","sourceRoot":"","sources":["../src/beads.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { registerStart } from "./commands/start.js";
|
|
5
|
+
import { registerStatus } from "./commands/status.js";
|
|
6
|
+
import { registerResume } from "./commands/resume.js";
|
|
7
|
+
import { registerPause } from "./commands/pause.js";
|
|
8
|
+
import { registerLog } from "./commands/log.js";
|
|
9
|
+
import { registerStop } from "./commands/stop.js";
|
|
10
|
+
import { registerTeardown } from "./commands/teardown.js";
|
|
11
|
+
import { registerAdd } from "./commands/add.js";
|
|
12
|
+
import { registerInit } from "./commands/init.js";
|
|
13
|
+
import { registerDaemon } from "./commands/daemon.js";
|
|
14
|
+
import { registerCleanup } from "./commands/cleanup.js";
|
|
15
|
+
import { registerInstallKeybinding } from "./commands/install-keybinding.js";
|
|
16
|
+
import { registerInstallStatus } from "./commands/install-status.js";
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
const pkg = require("../package.json");
|
|
19
|
+
const program = new Command();
|
|
20
|
+
program
|
|
21
|
+
.name("pit")
|
|
22
|
+
.description("tmux-based orchestrator for parallel AI coding agent sessions")
|
|
23
|
+
.version(pkg.version)
|
|
24
|
+
.option("--pretty", "Human-readable output instead of JSON");
|
|
25
|
+
registerStart(program);
|
|
26
|
+
registerStatus(program);
|
|
27
|
+
registerResume(program);
|
|
28
|
+
registerPause(program);
|
|
29
|
+
registerLog(program);
|
|
30
|
+
registerStop(program);
|
|
31
|
+
registerTeardown(program);
|
|
32
|
+
registerAdd(program);
|
|
33
|
+
registerInit(program);
|
|
34
|
+
registerDaemon(program);
|
|
35
|
+
registerCleanup(program);
|
|
36
|
+
registerInstallKeybinding(program);
|
|
37
|
+
registerInstallStatus(program);
|
|
38
|
+
program.parse();
|
|
39
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,+DAA+D,CAAC;KAC5E,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;KACpB,MAAM,CAAC,UAAU,EAAE,uCAAuC,CAAC,CAAC;AAE/D,aAAa,CAAC,OAAO,CAAC,CAAC;AACvB,cAAc,CAAC,OAAO,CAAC,CAAC;AACxB,cAAc,CAAC,OAAO,CAAC,CAAC;AACxB,aAAa,CAAC,OAAO,CAAC,CAAC;AACvB,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAC1B,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,cAAc,CAAC,OAAO,CAAC,CAAC;AACxB,eAAe,CAAC,OAAO,CAAC,CAAC;AACzB,yBAAyB,CAAC,OAAO,CAAC,CAAC;AACnC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAE/B,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
export interface AddResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
epic: string;
|
|
5
|
+
windowName: string;
|
|
6
|
+
worktreePath: string;
|
|
7
|
+
agent: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function registerAdd(program: Command): void;
|
|
10
|
+
//# sourceMappingURL=add.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4DlD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
import { getClientOrFail } from "./shared.js";
|
|
3
|
+
import { printError, printOutput } from "../output.js";
|
|
4
|
+
export function registerAdd(program) {
|
|
5
|
+
program
|
|
6
|
+
.command("add <epic>")
|
|
7
|
+
.description("Add a new epic to an existing pit session")
|
|
8
|
+
.option("--agent <type>", "Agent type: auto, opencode, or claude-code")
|
|
9
|
+
.option("--model <value>", "Model to pass to the agent CLI")
|
|
10
|
+
.action(async (epic, opts, cmd) => {
|
|
11
|
+
const pretty = (cmd.parent?.opts()).pretty ?? false;
|
|
12
|
+
const client = await getClientOrFail({ tmuxSession: "pit" });
|
|
13
|
+
try {
|
|
14
|
+
const response = await client.send({
|
|
15
|
+
id: crypto.randomUUID(),
|
|
16
|
+
method: "add",
|
|
17
|
+
params: {
|
|
18
|
+
epic,
|
|
19
|
+
...(opts.agent ? { agent: opts.agent } : {}),
|
|
20
|
+
...(opts.model ? { model: opts.model } : {}),
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
const result = response;
|
|
24
|
+
if (!result.success) {
|
|
25
|
+
printError({ error: result.error?.message || "Add command failed" }, pretty);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const daemonResult = result.result;
|
|
30
|
+
if (!daemonResult) {
|
|
31
|
+
printError({ error: "No result returned from daemon" }, pretty);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (pretty) {
|
|
36
|
+
process.stdout.write(`Added epic ${daemonResult.epic}\n`);
|
|
37
|
+
process.stdout.write(` Window: ${daemonResult.windowName}\n`);
|
|
38
|
+
process.stdout.write(` Worktree: ${daemonResult.worktreePath}\n`);
|
|
39
|
+
process.stdout.write(` Agent: ${daemonResult.agent}\n`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Transform to legacy format
|
|
43
|
+
const legacyOutput = {
|
|
44
|
+
success: true,
|
|
45
|
+
epic: daemonResult.epic,
|
|
46
|
+
windowName: daemonResult.windowName,
|
|
47
|
+
worktreePath: daemonResult.worktreePath,
|
|
48
|
+
agent: daemonResult.agent,
|
|
49
|
+
};
|
|
50
|
+
printOutput(legacyOutput, false);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
client.close();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
export interface CleanupOutput {
|
|
3
|
+
cleaned: string[];
|
|
4
|
+
skipped: string[];
|
|
5
|
+
totalCleaned: number;
|
|
6
|
+
totalSkipped: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Core cleanup logic. Exported for testability.
|
|
10
|
+
*/
|
|
11
|
+
export declare function runCleanup(dryRun: boolean): Promise<CleanupOutput>;
|
|
12
|
+
export declare function registerCleanup(program: Command): void;
|
|
13
|
+
//# sourceMappingURL=cleanup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASzC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AA6ED;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAmDxE;AAMD,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuCtD"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import * as fsp from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { cleanup as rmDir } from "../signals.js";
|
|
4
|
+
import { printOutput, printError } from "../output.js";
|
|
5
|
+
// Base directory for all pit session dirs
|
|
6
|
+
const PIT_BASE_DIR = "/tmp/pit";
|
|
7
|
+
/**
|
|
8
|
+
* Checks if a PID corresponds to a running process.
|
|
9
|
+
* Returns:
|
|
10
|
+
* "alive" — process is alive (kill(0) succeeded, or EPERM)
|
|
11
|
+
* "dead" — process does not exist (ESRCH)
|
|
12
|
+
*/
|
|
13
|
+
function isPidAlive(pid) {
|
|
14
|
+
try {
|
|
15
|
+
process.kill(pid, 0);
|
|
16
|
+
return "alive";
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
const code = err.code;
|
|
20
|
+
if (code === "ESRCH") {
|
|
21
|
+
return "dead";
|
|
22
|
+
}
|
|
23
|
+
// EPERM — process exists but we can't signal it → conservative: treat as alive
|
|
24
|
+
return "alive";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Determines whether a session directory under /tmp/pit/<sessionId> is dead.
|
|
29
|
+
*
|
|
30
|
+
* Decision tree (evaluated in order):
|
|
31
|
+
* 1. Directory is empty → DEAD
|
|
32
|
+
* 2. Has daemon.lock but no daemon.pid → ALIVE (mid-startup)
|
|
33
|
+
* 3. Has daemon.pid and PID is alive → ALIVE
|
|
34
|
+
* 4. Has daemon.pid but PID is dead → DEAD
|
|
35
|
+
* 5. No daemon.pid and no daemon.lock → DEAD
|
|
36
|
+
*/
|
|
37
|
+
async function isSessionDead(sessionPath) {
|
|
38
|
+
let entries;
|
|
39
|
+
try {
|
|
40
|
+
const dirents = await fsp.readdir(sessionPath);
|
|
41
|
+
entries = dirents;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Can't read directory → skip conservatively
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
// 1. Empty directory → DEAD
|
|
48
|
+
if (entries.length === 0) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
const hasDaemonLock = entries.includes("daemon.lock");
|
|
52
|
+
const hasDaemonPid = entries.includes("daemon.pid");
|
|
53
|
+
// 2. Has daemon.lock but no daemon.pid → mid-startup → ALIVE
|
|
54
|
+
if (hasDaemonLock && !hasDaemonPid) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
// 3 & 4. Has daemon.pid → check PID liveness
|
|
58
|
+
if (hasDaemonPid) {
|
|
59
|
+
const pidPath = path.join(sessionPath, "daemon.pid");
|
|
60
|
+
let pidStr;
|
|
61
|
+
try {
|
|
62
|
+
pidStr = await fsp.readFile(pidPath, "utf8");
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Can't read PID file → conservative: treat as alive
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const pid = parseInt(pidStr.trim(), 10);
|
|
69
|
+
if (isNaN(pid)) {
|
|
70
|
+
// Malformed PID file → conservative: treat as alive
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return isPidAlive(pid) === "dead";
|
|
74
|
+
}
|
|
75
|
+
// 5. No daemon.pid and no daemon.lock → DEAD
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Core cleanup logic. Exported for testability.
|
|
80
|
+
*/
|
|
81
|
+
export async function runCleanup(dryRun) {
|
|
82
|
+
const cleaned = [];
|
|
83
|
+
const skipped = [];
|
|
84
|
+
// If /tmp/pit/ doesn't exist, return 0 cleaned, 0 skipped
|
|
85
|
+
let entries;
|
|
86
|
+
try {
|
|
87
|
+
entries = await fsp.readdir(PIT_BASE_DIR);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
if (err.code === "ENOENT") {
|
|
91
|
+
return { cleaned: [], skipped: [], totalCleaned: 0, totalSkipped: 0 };
|
|
92
|
+
}
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
const sessionPath = path.join(PIT_BASE_DIR, entry);
|
|
97
|
+
// Verify it's a directory
|
|
98
|
+
let stat;
|
|
99
|
+
try {
|
|
100
|
+
stat = await fsp.stat(sessionPath);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Can't stat → skip
|
|
104
|
+
skipped.push(entry);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (!stat.isDirectory()) {
|
|
108
|
+
skipped.push(entry);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const dead = await isSessionDead(sessionPath);
|
|
112
|
+
if (dead) {
|
|
113
|
+
if (!dryRun) {
|
|
114
|
+
await rmDir(sessionPath);
|
|
115
|
+
}
|
|
116
|
+
cleaned.push(entry);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
skipped.push(entry);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
cleaned,
|
|
124
|
+
skipped,
|
|
125
|
+
totalCleaned: cleaned.length,
|
|
126
|
+
totalSkipped: skipped.length,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Command registration
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
export function registerCleanup(program) {
|
|
133
|
+
program
|
|
134
|
+
.command("cleanup")
|
|
135
|
+
.description("Garbage-collect stale pit session directories under /tmp/pit/")
|
|
136
|
+
.option("--dry-run", "List stale session directories without removing them")
|
|
137
|
+
.action(async (opts, cmd) => {
|
|
138
|
+
const pretty = cmd.parent?.opts().pretty;
|
|
139
|
+
const dryRun = opts.dryRun;
|
|
140
|
+
let result;
|
|
141
|
+
try {
|
|
142
|
+
result = await runCleanup(dryRun);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
printError({ error: `Cleanup failed: ${err.message}` }, pretty);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (pretty) {
|
|
150
|
+
if (result.totalCleaned === 0 && result.totalSkipped === 0) {
|
|
151
|
+
process.stdout.write("No pit session directories found.\n");
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
if (result.cleaned.length > 0) {
|
|
155
|
+
const verb = dryRun ? "Would remove" : "Removed";
|
|
156
|
+
process.stdout.write(`${verb} ${result.totalCleaned} stale session(s):\n`);
|
|
157
|
+
for (const id of result.cleaned) {
|
|
158
|
+
process.stdout.write(` - ${id}\n`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
process.stdout.write("No stale sessions found.\n");
|
|
163
|
+
}
|
|
164
|
+
if (result.skipped.length > 0) {
|
|
165
|
+
process.stdout.write(`Skipped ${result.totalSkipped} active session(s).\n`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
printOutput(result, false);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2GzC,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmFrD"}
|