@abitat_reece/host-daemon 0.1.0
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/dist/cli/conversation-runtime.d.ts +23 -0
- package/dist/cli/conversation-runtime.d.ts.map +1 -0
- package/dist/cli/conversation-runtime.js +73 -0
- package/dist/cli/conversation-runtime.js.map +1 -0
- package/dist/cli/daemon-connection.d.ts +14 -0
- package/dist/cli/daemon-connection.d.ts.map +1 -0
- package/dist/cli/daemon-connection.js +17 -0
- package/dist/cli/daemon-connection.js.map +1 -0
- package/dist/cli/heartbeat-loop.d.ts +2 -0
- package/dist/cli/heartbeat-loop.d.ts.map +1 -0
- package/dist/cli/heartbeat-loop.js +10 -0
- package/dist/cli/heartbeat-loop.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +371 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/retryable-task.d.ts +5 -0
- package/dist/cli/retryable-task.d.ts.map +1 -0
- package/dist/cli/retryable-task.js +16 -0
- package/dist/cli/retryable-task.js.map +1 -0
- package/dist/cli/start-options.d.ts +5 -0
- package/dist/cli/start-options.d.ts.map +1 -0
- package/dist/cli/start-options.js +6 -0
- package/dist/cli/start-options.js.map +1 -0
- package/dist/config/host-config.d.ts +10 -0
- package/dist/config/host-config.d.ts.map +1 -0
- package/dist/config/host-config.js +15 -0
- package/dist/config/host-config.js.map +1 -0
- package/dist/git/changeset.d.ts +9 -0
- package/dist/git/changeset.d.ts.map +1 -0
- package/dist/git/changeset.js +78 -0
- package/dist/git/changeset.js.map +1 -0
- package/dist/git/paths.d.ts +12 -0
- package/dist/git/paths.d.ts.map +1 -0
- package/dist/git/paths.js +72 -0
- package/dist/git/paths.js.map +1 -0
- package/dist/git/publish.d.ts +24 -0
- package/dist/git/publish.d.ts.map +1 -0
- package/dist/git/publish.js +23 -0
- package/dist/git/publish.js.map +1 -0
- package/dist/git/repo.d.ts +21 -0
- package/dist/git/repo.d.ts.map +1 -0
- package/dist/git/repo.js +113 -0
- package/dist/git/repo.js.map +1 -0
- package/dist/git/worktree.d.ts +25 -0
- package/dist/git/worktree.d.ts.map +1 -0
- package/dist/git/worktree.js +33 -0
- package/dist/git/worktree.js.map +1 -0
- package/dist/remote-control/manager.d.ts +46 -0
- package/dist/remote-control/manager.d.ts.map +1 -0
- package/dist/remote-control/manager.js +86 -0
- package/dist/remote-control/manager.js.map +1 -0
- package/dist/runtime/adapter.d.ts +27 -0
- package/dist/runtime/adapter.d.ts.map +1 -0
- package/dist/runtime/adapter.js +2 -0
- package/dist/runtime/adapter.js.map +1 -0
- package/dist/runtime/cli.d.ts +41 -0
- package/dist/runtime/cli.d.ts.map +1 -0
- package/dist/runtime/cli.js +540 -0
- package/dist/runtime/cli.js.map +1 -0
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +39 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/mock.d.ts +3 -0
- package/dist/runtime/mock.d.ts.map +1 -0
- package/dist/runtime/mock.js +34 -0
- package/dist/runtime/mock.js.map +1 -0
- package/dist/runtime/pty.d.ts +32 -0
- package/dist/runtime/pty.d.ts.map +1 -0
- package/dist/runtime/pty.js +197 -0
- package/dist/runtime/pty.js.map +1 -0
- package/dist/tools/scanner.d.ts +14 -0
- package/dist/tools/scanner.d.ts.map +1 -0
- package/dist/tools/scanner.js +53 -0
- package/dist/tools/scanner.js.map +1 -0
- package/dist/transport/api-client.d.ts +153 -0
- package/dist/transport/api-client.d.ts.map +1 -0
- package/dist/transport/api-client.js +93 -0
- package/dist/transport/api-client.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/remote-control/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { RunEventType, Runtime } from "@abitat_reece/shared";
|
|
2
|
+
export interface RuntimeEvent {
|
|
3
|
+
type: Extract<RunEventType, "error" | "status" | "stdout" | "stderr" | "summary">;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
export interface RuntimeRunInput {
|
|
7
|
+
worktreePath: string;
|
|
8
|
+
prompt: string;
|
|
9
|
+
model?: string;
|
|
10
|
+
instructions: string;
|
|
11
|
+
conversationId?: string;
|
|
12
|
+
allowedTools?: string[];
|
|
13
|
+
resumeSessionId?: string;
|
|
14
|
+
skipGitRepoCheck?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface RuntimeAvailability {
|
|
17
|
+
installed: boolean;
|
|
18
|
+
version?: string;
|
|
19
|
+
path?: string;
|
|
20
|
+
reason?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface RuntimeAdapter {
|
|
23
|
+
name: Runtime;
|
|
24
|
+
isAvailable(): Promise<RuntimeAvailability>;
|
|
25
|
+
run(input: RuntimeRunInput, emit: (event: RuntimeEvent) => Promise<void>): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/runtime/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAElE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC;IAClF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC5C,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/runtime/adapter.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { RuntimeAdapter, RuntimeAvailability } from "./adapter.js";
|
|
2
|
+
export declare const terminalShellPidMarker = "__ABITAT_SHELL_PID__";
|
|
3
|
+
type CliRuntimeName = "codex" | "claude";
|
|
4
|
+
type CliOutput = {
|
|
5
|
+
type: "stdout" | "stderr" | "summary";
|
|
6
|
+
content: string;
|
|
7
|
+
};
|
|
8
|
+
interface CliRunOptions {
|
|
9
|
+
cwd: string;
|
|
10
|
+
stdin: string;
|
|
11
|
+
}
|
|
12
|
+
export interface TerminalLaunchInput {
|
|
13
|
+
scriptPath: string;
|
|
14
|
+
logPath: string;
|
|
15
|
+
exitMarker: string;
|
|
16
|
+
}
|
|
17
|
+
interface TerminalCliRuntimeRunnerInput {
|
|
18
|
+
check?: (command: string) => Promise<RuntimeAvailability>;
|
|
19
|
+
launch?: (input: TerminalLaunchInput) => Promise<void>;
|
|
20
|
+
isProcessAlive?: (pid: number) => Promise<boolean>;
|
|
21
|
+
startupTimeoutMs?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface CliRuntimeRunner {
|
|
24
|
+
interactive: boolean;
|
|
25
|
+
check(command: string): Promise<RuntimeAvailability>;
|
|
26
|
+
run(command: string, args: string[], options: CliRunOptions, emit: (event: CliOutput) => Promise<void>): Promise<number>;
|
|
27
|
+
}
|
|
28
|
+
interface CliRuntimeAdapterInput {
|
|
29
|
+
name: CliRuntimeName;
|
|
30
|
+
command: string;
|
|
31
|
+
runner?: CliRuntimeRunner;
|
|
32
|
+
}
|
|
33
|
+
export declare function createCodexRuntimeAdapter(): RuntimeAdapter;
|
|
34
|
+
export declare function createClaudeRuntimeAdapter(): RuntimeAdapter;
|
|
35
|
+
export declare function createCliRuntimeAdapter(input: CliRuntimeAdapterInput): RuntimeAdapter;
|
|
36
|
+
export declare const defaultCliRuntimeRunner: CliRuntimeRunner;
|
|
37
|
+
export declare function createTerminalCliRuntimeRunner(input?: TerminalCliRuntimeRunnerInput): CliRuntimeRunner;
|
|
38
|
+
type ExecFileAsync = (file: string, args: string[]) => Promise<unknown>;
|
|
39
|
+
export declare function launchITerm2Script(input: TerminalLaunchInput, execFileAsyncImpl?: ExecFileAsync): Promise<void>;
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/runtime/cli.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAmB,MAAM,cAAc,CAAC;AAczF,eAAO,MAAM,sBAAsB,yBAAyB,CAAC;AAE7D,KAAK,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;AACzC,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,6BAA6B;IACrC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC1D,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACrD,GAAG,CACD,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,GACxC,OAAO,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,UAAU,sBAAsB;IAC9B,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,wBAAgB,yBAAyB,mBAMxC;AAED,wBAAgB,0BAA0B,mBAMzC;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,sBAAsB,GAAG,cAAc,CAyCrF;AAED,eAAO,MAAM,uBAAuB,EAAE,gBAiDrC,CAAC;AAEF,wBAAgB,8BAA8B,CAC5C,KAAK,GAAE,6BAAkC,GACxC,gBAAgB,CA4DlB;AAwBD,KAAK,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAExE,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,mBAAmB,EAC1B,iBAAiB,GAAE,aAA6B,iBAoBjD"}
|
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import { execFile, spawn } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { chmod, mkdtemp, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
4
|
+
import { homedir, tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
const ESCAPE_CHARACTER = String.fromCharCode(27);
|
|
9
|
+
const BELL_CHARACTER = String.fromCharCode(7);
|
|
10
|
+
const CONTROL_CHARACTER_PATTERN = new RegExp(`[${String.fromCharCode(0)}-${String.fromCharCode(8)}${String.fromCharCode(11)}${String.fromCharCode(12)}${String.fromCharCode(14)}-${String.fromCharCode(31)}${String.fromCharCode(127)}]`, "g");
|
|
11
|
+
const ANSI_CSI_PATTERN = new RegExp(`${ESCAPE_CHARACTER}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
12
|
+
const ANSI_OSC_PATTERN = new RegExp(`${ESCAPE_CHARACTER}\\][^${BELL_CHARACTER}]*(?:${BELL_CHARACTER}|${ESCAPE_CHARACTER}\\\\)`, "g");
|
|
13
|
+
export const terminalShellPidMarker = "__ABITAT_SHELL_PID__";
|
|
14
|
+
export function createCodexRuntimeAdapter() {
|
|
15
|
+
return createCliRuntimeAdapter({
|
|
16
|
+
name: "codex",
|
|
17
|
+
command: "codex",
|
|
18
|
+
runner: defaultRunnerForAgentCli()
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export function createClaudeRuntimeAdapter() {
|
|
22
|
+
return createCliRuntimeAdapter({
|
|
23
|
+
name: "claude",
|
|
24
|
+
command: "claude",
|
|
25
|
+
runner: defaultRunnerForAgentCli()
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export function createCliRuntimeAdapter(input) {
|
|
29
|
+
const runner = input.runner ?? defaultCliRuntimeRunner;
|
|
30
|
+
return {
|
|
31
|
+
name: input.name,
|
|
32
|
+
isAvailable() {
|
|
33
|
+
return runner.check(input.command);
|
|
34
|
+
},
|
|
35
|
+
async run(runInput, emit) {
|
|
36
|
+
const availability = await runner.check(input.command);
|
|
37
|
+
let lastOutput = "";
|
|
38
|
+
if (!availability.installed) {
|
|
39
|
+
throw new Error(availability.reason ?? `${input.name} CLI is unavailable`);
|
|
40
|
+
}
|
|
41
|
+
await emit({ type: "status", content: `${input.name} runtime starting` });
|
|
42
|
+
const exitCode = await runner.run(input.command, runtimeArgs(input.name, runInput, runner.interactive), {
|
|
43
|
+
cwd: runInput.worktreePath,
|
|
44
|
+
stdin: runtimePrompt(runInput)
|
|
45
|
+
}, async (event) => {
|
|
46
|
+
if (event.content.trim().length > 0) {
|
|
47
|
+
lastOutput = event.content.trim();
|
|
48
|
+
}
|
|
49
|
+
await emit(event);
|
|
50
|
+
});
|
|
51
|
+
if (exitCode !== 0) {
|
|
52
|
+
const details = lastOutput ? `: ${lastOutput}` : "";
|
|
53
|
+
throw new Error(`${input.name} exited with code ${exitCode}${details}`);
|
|
54
|
+
}
|
|
55
|
+
await emit({ type: "status", content: `${input.name} runtime completed` });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export const defaultCliRuntimeRunner = {
|
|
60
|
+
interactive: false,
|
|
61
|
+
async check(command) {
|
|
62
|
+
try {
|
|
63
|
+
const { stdout: path } = await execFileAsync("which", [command]);
|
|
64
|
+
const version = await readVersion(command);
|
|
65
|
+
return {
|
|
66
|
+
installed: true,
|
|
67
|
+
path: path.trim(),
|
|
68
|
+
...(version ? { version } : {})
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return {
|
|
73
|
+
installed: false,
|
|
74
|
+
reason: `${command} CLI is unavailable on the host.`
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
run(command, args, options, emit) {
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const child = spawn(command, args, {
|
|
81
|
+
cwd: options.cwd,
|
|
82
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
83
|
+
});
|
|
84
|
+
const flushStdout = createLineEmitter("stdout", emit);
|
|
85
|
+
const flushStderr = createLineEmitter("stderr", emit);
|
|
86
|
+
const queue = createAsyncQueue();
|
|
87
|
+
child.stdout.on("data", (chunk) => {
|
|
88
|
+
queue.add(() => flushStdout.write(chunk.toString("utf8")));
|
|
89
|
+
});
|
|
90
|
+
child.stderr.on("data", (chunk) => {
|
|
91
|
+
queue.add(() => flushStderr.write(chunk.toString("utf8")));
|
|
92
|
+
});
|
|
93
|
+
child.on("error", reject);
|
|
94
|
+
child.on("close", (code) => {
|
|
95
|
+
queue
|
|
96
|
+
.add(async () => {
|
|
97
|
+
await flushStdout.close();
|
|
98
|
+
await flushStderr.close();
|
|
99
|
+
})
|
|
100
|
+
.then(() => resolve(code ?? 1))
|
|
101
|
+
.catch(reject);
|
|
102
|
+
});
|
|
103
|
+
child.stdin.end(options.stdin);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
export function createTerminalCliRuntimeRunner(input = {}) {
|
|
108
|
+
const check = input.check ?? defaultCliRuntimeRunner.check;
|
|
109
|
+
const launch = input.launch ?? launchITerm2Script;
|
|
110
|
+
const isProcessAlive = input.isProcessAlive ?? defaultIsProcessAlive;
|
|
111
|
+
const startupTimeoutMs = input.startupTimeoutMs ?? 15_000;
|
|
112
|
+
return {
|
|
113
|
+
interactive: true,
|
|
114
|
+
check,
|
|
115
|
+
async run(command, args, options, emit) {
|
|
116
|
+
const availability = await check(command);
|
|
117
|
+
const startedAt = Date.now();
|
|
118
|
+
if (!availability.installed) {
|
|
119
|
+
return 127;
|
|
120
|
+
}
|
|
121
|
+
const runDir = await mkdtemp(join(tmpdir(), "abitat-terminal-runtime-"));
|
|
122
|
+
const logPath = join(runDir, "runtime.log");
|
|
123
|
+
const promptPath = join(runDir, "prompt.txt");
|
|
124
|
+
const scriptPath = join(runDir, `${command}.command`);
|
|
125
|
+
const exitMarker = `__ABITAT_EXIT_${randomUUID()}__`;
|
|
126
|
+
const commandPath = availability.path ?? command;
|
|
127
|
+
await writeFile(promptPath, options.stdin, "utf8");
|
|
128
|
+
await writeFile(logPath, "", "utf8");
|
|
129
|
+
await writeFile(scriptPath, terminalScript({
|
|
130
|
+
args,
|
|
131
|
+
commandName: command,
|
|
132
|
+
commandPath,
|
|
133
|
+
cwd: options.cwd,
|
|
134
|
+
exitMarker,
|
|
135
|
+
logPath,
|
|
136
|
+
promptPath
|
|
137
|
+
}), "utf8");
|
|
138
|
+
await chmod(scriptPath, 0o700);
|
|
139
|
+
const watch = watchTerminalLog(logPath, exitMarker, emit, {
|
|
140
|
+
isProcessAlive,
|
|
141
|
+
startupTimeoutMs
|
|
142
|
+
});
|
|
143
|
+
await launch({ scriptPath, logPath, exitMarker });
|
|
144
|
+
const { exitCode, sawSessionId } = await watch;
|
|
145
|
+
const sessionId = command === "codex" && isInteractiveCodexArgs(args)
|
|
146
|
+
? await findLatestCodexSessionId(options.cwd, startedAt)
|
|
147
|
+
: null;
|
|
148
|
+
if (sessionId && !sawSessionId) {
|
|
149
|
+
await emit({ type: "stdout", content: `session id: ${sessionId}` });
|
|
150
|
+
}
|
|
151
|
+
return exitCode;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function defaultRunnerForAgentCli() {
|
|
156
|
+
if (process.env.ABITAT_CLI_RUNTIME_MODE === "inline" || process.platform !== "darwin") {
|
|
157
|
+
console.log("runtime runner: inline (hidden)");
|
|
158
|
+
return defaultCliRuntimeRunner;
|
|
159
|
+
}
|
|
160
|
+
console.log("runtime runner: terminal (visible window)");
|
|
161
|
+
return createTerminalCliRuntimeRunner();
|
|
162
|
+
}
|
|
163
|
+
function createAsyncQueue() {
|
|
164
|
+
let current = Promise.resolve();
|
|
165
|
+
return {
|
|
166
|
+
add(task) {
|
|
167
|
+
const next = current.then(task, task);
|
|
168
|
+
current = next.catch(() => undefined);
|
|
169
|
+
return next;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
export async function launchITerm2Script(input, execFileAsyncImpl = execFileAsync) {
|
|
174
|
+
const command = shellQuote(input.scriptPath);
|
|
175
|
+
const script = [
|
|
176
|
+
'tell application "iTerm2"',
|
|
177
|
+
"activate",
|
|
178
|
+
"if (count of windows) = 0 then",
|
|
179
|
+
"set newWindow to create window with default profile",
|
|
180
|
+
"set targetSession to current session of newWindow",
|
|
181
|
+
"else",
|
|
182
|
+
"tell current window",
|
|
183
|
+
"set newTab to create tab with default profile",
|
|
184
|
+
"set targetSession to current session of newTab",
|
|
185
|
+
"end tell",
|
|
186
|
+
"end if",
|
|
187
|
+
`tell targetSession to write text ${appleScriptString(command)}`,
|
|
188
|
+
"end tell"
|
|
189
|
+
].join("\n");
|
|
190
|
+
await execFileAsyncImpl("osascript", ["-e", script]);
|
|
191
|
+
}
|
|
192
|
+
function terminalScript(input) {
|
|
193
|
+
const usesPrompt = usesPromptFile(input.commandName, input.args);
|
|
194
|
+
const command = terminalCommand(input.commandName, input.commandPath, input.args, input.promptPath);
|
|
195
|
+
const holdOpen = process.env.ABITAT_TERMINAL_HOLD_OPEN !== "0";
|
|
196
|
+
const capturesOutput = capturesTerminalOutput(input.commandName, input.args);
|
|
197
|
+
const lines = [
|
|
198
|
+
"#!/bin/bash",
|
|
199
|
+
"set +e",
|
|
200
|
+
`cd ${shellQuote(input.cwd)}`,
|
|
201
|
+
`echo "${terminalShellPidMarker}:$$" >> ${shellQuote(input.logPath)}`,
|
|
202
|
+
terminalLogLine("Abitat Workspace terminal runtime", input.logPath, capturesOutput),
|
|
203
|
+
terminalLogLine(`cwd: ${input.cwd}`, input.logPath, capturesOutput),
|
|
204
|
+
terminalLogLine(`command: ${command}`, input.logPath, capturesOutput),
|
|
205
|
+
capturesOutput ? `echo ""` : "clear",
|
|
206
|
+
...(usesPrompt
|
|
207
|
+
? [`echo "--- Task ---"`, `cat ${shellQuote(input.promptPath)}`, `echo ""`]
|
|
208
|
+
: []),
|
|
209
|
+
...(capturesOutput ? [`echo "--- Starting Codex CLI ---"`, `echo ""`] : []),
|
|
210
|
+
capturesOutput
|
|
211
|
+
? // Use `script` to give noninteractive CLI runs a real pseudo-terminal
|
|
212
|
+
// while capturing output for the daemon to stream to the web UI.
|
|
213
|
+
`script -q -a ${shellQuote(input.logPath)} /bin/bash -lc ${shellQuote(command)}`
|
|
214
|
+
: command,
|
|
215
|
+
"status=$?",
|
|
216
|
+
`echo "${input.exitMarker}:$status" >> ${shellQuote(input.logPath)}`,
|
|
217
|
+
'echo ""',
|
|
218
|
+
'echo "--- Agent finished (exit $status) ---"',
|
|
219
|
+
...(holdOpen ? ['read -p "Press enter to close this window..."'] : []),
|
|
220
|
+
"exit $status",
|
|
221
|
+
""
|
|
222
|
+
];
|
|
223
|
+
return lines.join("\n");
|
|
224
|
+
}
|
|
225
|
+
function terminalLogLine(line, logPath, echoToTerminal) {
|
|
226
|
+
const escaped = escapeDoubleQuoted(line);
|
|
227
|
+
const log = shellQuote(logPath);
|
|
228
|
+
return echoToTerminal ? `echo "${escaped}" | tee -a ${log}` : `echo "${escaped}" >> ${log}`;
|
|
229
|
+
}
|
|
230
|
+
function terminalCommand(commandName, commandPath, args, promptPath) {
|
|
231
|
+
if (commandName === "codex" && args[0] === "exec") {
|
|
232
|
+
const promptArgs = args.at(-1) === "-" ? args.slice(0, -1) : args;
|
|
233
|
+
return [
|
|
234
|
+
shellQuote(commandPath),
|
|
235
|
+
...promptArgs.map(shellQuote),
|
|
236
|
+
`"$(cat ${shellQuote(promptPath)})"`
|
|
237
|
+
].join(" ");
|
|
238
|
+
}
|
|
239
|
+
if (commandName === "codex") {
|
|
240
|
+
return [commandPath, ...args].map(shellQuote).join(" ");
|
|
241
|
+
}
|
|
242
|
+
return `${[commandPath, ...args].map(shellQuote).join(" ")} < ${shellQuote(promptPath)}`;
|
|
243
|
+
}
|
|
244
|
+
function usesPromptFile(commandName, args) {
|
|
245
|
+
return commandName !== "codex" || args[0] === "exec";
|
|
246
|
+
}
|
|
247
|
+
function capturesTerminalOutput(commandName, args) {
|
|
248
|
+
return commandName !== "codex" || args[0] === "exec";
|
|
249
|
+
}
|
|
250
|
+
async function watchTerminalLog(logPath, exitMarker, emit, options) {
|
|
251
|
+
let offset = 0;
|
|
252
|
+
let buffered = "";
|
|
253
|
+
let shellPid = null;
|
|
254
|
+
let sawSessionId = false;
|
|
255
|
+
const startedAt = Date.now();
|
|
256
|
+
const emittedLines = [];
|
|
257
|
+
while (true) {
|
|
258
|
+
const text = await readFile(logPath, "utf8").catch(() => "");
|
|
259
|
+
const chunk = text.slice(offset);
|
|
260
|
+
offset = text.length;
|
|
261
|
+
if (chunk) {
|
|
262
|
+
buffered += chunk;
|
|
263
|
+
const lines = buffered.split(/\r?\n/);
|
|
264
|
+
buffered = lines.pop() ?? "";
|
|
265
|
+
for (const line of lines) {
|
|
266
|
+
if (line.startsWith(`${terminalShellPidMarker}:`)) {
|
|
267
|
+
shellPid = Number(line.slice(terminalShellPidMarker.length + 1)) || null;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (line.startsWith(`${exitMarker}:`)) {
|
|
271
|
+
const summary = summarizeTerminalLines(emittedLines);
|
|
272
|
+
if (summary) {
|
|
273
|
+
await emit({ type: "summary", content: summary });
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
exitCode: Number(line.slice(exitMarker.length + 1)) || 0,
|
|
277
|
+
sawSessionId
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
if (line.length > 0) {
|
|
281
|
+
emittedLines.push(line);
|
|
282
|
+
await emit({ type: "stdout", content: line });
|
|
283
|
+
const sessionId = parseTerminalSessionId(line);
|
|
284
|
+
if (sessionId) {
|
|
285
|
+
sawSessionId = true;
|
|
286
|
+
if (!/^session id:/i.test(cleanTerminalLine(line))) {
|
|
287
|
+
await emit({ type: "stdout", content: `session id: ${sessionId}` });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (shellPid !== null && !(await options.isProcessAlive(shellPid))) {
|
|
294
|
+
const summary = summarizeTerminalLines(emittedLines);
|
|
295
|
+
if (summary) {
|
|
296
|
+
await emit({ type: "summary", content: summary });
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
exitCode: 130,
|
|
300
|
+
sawSessionId
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
if (shellPid === null && Date.now() - startedAt > options.startupTimeoutMs) {
|
|
304
|
+
const summary = summarizeTerminalLines(emittedLines);
|
|
305
|
+
if (summary) {
|
|
306
|
+
await emit({ type: "summary", content: summary });
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
exitCode: 124,
|
|
310
|
+
sawSessionId
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async function readVersion(command) {
|
|
317
|
+
try {
|
|
318
|
+
const { stdout } = await execFileAsync(command, ["--version"]);
|
|
319
|
+
return stdout.trim().split("\n")[0] || undefined;
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function isInteractiveCodexArgs(args) {
|
|
326
|
+
return args[0] !== "exec";
|
|
327
|
+
}
|
|
328
|
+
async function findLatestCodexSessionId(cwd, startedAt) {
|
|
329
|
+
const sessionsRoot = join(process.env.CODEX_HOME ?? join(homedir(), ".codex"), "sessions");
|
|
330
|
+
const files = await listFiles(sessionsRoot).catch(() => []);
|
|
331
|
+
let latest = null;
|
|
332
|
+
for (const file of files) {
|
|
333
|
+
if (!file.endsWith(".jsonl")) {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
const details = await stat(file).catch(() => null);
|
|
337
|
+
if (!details || details.mtimeMs < startedAt - 60_000) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
const firstLine = (await readFile(file, "utf8").catch(() => "")).split(/\r?\n/)[0];
|
|
341
|
+
const session = parseCodexSessionMeta(firstLine, cwd);
|
|
342
|
+
if (session && (!latest || details.mtimeMs > latest.mtimeMs)) {
|
|
343
|
+
latest = {
|
|
344
|
+
id: session,
|
|
345
|
+
mtimeMs: details.mtimeMs
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return latest?.id ?? null;
|
|
350
|
+
}
|
|
351
|
+
async function listFiles(root) {
|
|
352
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
353
|
+
const files = await Promise.all(entries.map(async (entry) => {
|
|
354
|
+
const path = join(root, entry.name);
|
|
355
|
+
if (entry.isDirectory()) {
|
|
356
|
+
return listFiles(path);
|
|
357
|
+
}
|
|
358
|
+
return entry.isFile() ? [path] : [];
|
|
359
|
+
}));
|
|
360
|
+
return files.flat();
|
|
361
|
+
}
|
|
362
|
+
function parseCodexSessionMeta(line, cwd) {
|
|
363
|
+
try {
|
|
364
|
+
const parsed = JSON.parse(line);
|
|
365
|
+
if (parsed.type !== "session_meta") {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
if (parsed.payload?.cwd !== cwd || typeof parsed.payload.id !== "string") {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
return parsed.payload.id;
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function summarizeTerminalLines(lines) {
|
|
378
|
+
const recent = lines.map(cleanTerminalLine).map(cleanSummaryLine).filter(isSummaryLine).slice(-6);
|
|
379
|
+
if (recent.length === 0) {
|
|
380
|
+
return "Codex terminal session ended.";
|
|
381
|
+
}
|
|
382
|
+
return [
|
|
383
|
+
"Codex terminal session ended.",
|
|
384
|
+
"",
|
|
385
|
+
"Recent activity:",
|
|
386
|
+
...recent.map((line) => `- ${line}`)
|
|
387
|
+
].join("\n");
|
|
388
|
+
}
|
|
389
|
+
function cleanTerminalLine(line) {
|
|
390
|
+
return line
|
|
391
|
+
.replace(ANSI_CSI_PATTERN, "")
|
|
392
|
+
.replace(ANSI_OSC_PATTERN, "")
|
|
393
|
+
.replace(CONTROL_CHARACTER_PATTERN, "")
|
|
394
|
+
.replace(/\s+/g, " ")
|
|
395
|
+
.trim();
|
|
396
|
+
}
|
|
397
|
+
function parseTerminalSessionId(line) {
|
|
398
|
+
const cleaned = cleanTerminalLine(line);
|
|
399
|
+
const direct = /^session id:\s*(\S+)/i.exec(cleaned);
|
|
400
|
+
if (direct) {
|
|
401
|
+
return direct[1];
|
|
402
|
+
}
|
|
403
|
+
const resume = /\bcodex\s+resume\s+(\S+)/i.exec(cleaned);
|
|
404
|
+
return resume?.[1]?.replace(/[.,;:]+$/u, "");
|
|
405
|
+
}
|
|
406
|
+
function cleanSummaryLine(line) {
|
|
407
|
+
let cleaned = line
|
|
408
|
+
.replace(/^[\u2022\-\s]+/u, "")
|
|
409
|
+
.replace(/^[\u2713\u2714]\s*/u, "")
|
|
410
|
+
.trim();
|
|
411
|
+
for (const marker of [" › ", " Token usage:"]) {
|
|
412
|
+
const markerIndex = cleaned.indexOf(marker);
|
|
413
|
+
if (markerIndex > 0) {
|
|
414
|
+
cleaned = cleaned.slice(0, markerIndex).trim();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return cleaned;
|
|
418
|
+
}
|
|
419
|
+
function isSummaryLine(line) {
|
|
420
|
+
if (!line) {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
if (/^session id:/i.test(line)) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
if (/to continue this session/i.test(line)) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
if (["Abitat Workspace terminal runtime", "--- Starting Codex CLI ---", "--- Task ---"].some((prefix) => line.startsWith(prefix)) ||
|
|
430
|
+
line.startsWith("cwd:") ||
|
|
431
|
+
line.startsWith("command:")) {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
if (/^[\u256d\u2570\u2502\u2500\s]+$/u.test(line) || /^\d+\s+[+-]?/u.test(line)) {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
return /^(?:added|changed|completed|created|deleted|edited|fixed|generated|implemented|modified|updated|wrote)\b/iu.test(line);
|
|
438
|
+
}
|
|
439
|
+
function shellQuote(value) {
|
|
440
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
441
|
+
}
|
|
442
|
+
function appleScriptString(value) {
|
|
443
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
444
|
+
}
|
|
445
|
+
function escapeDoubleQuoted(value) {
|
|
446
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\$/g, "\\$");
|
|
447
|
+
}
|
|
448
|
+
async function defaultIsProcessAlive(pid) {
|
|
449
|
+
try {
|
|
450
|
+
process.kill(pid, 0);
|
|
451
|
+
return true;
|
|
452
|
+
}
|
|
453
|
+
catch (error) {
|
|
454
|
+
return !(typeof error === "object" &&
|
|
455
|
+
error !== null &&
|
|
456
|
+
"code" in error &&
|
|
457
|
+
error.code === "ESRCH");
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
function runtimeArgs(name, input, interactive) {
|
|
461
|
+
if (name === "codex") {
|
|
462
|
+
const localFolderArgs = input.skipGitRepoCheck ? ["--skip-git-repo-check"] : [];
|
|
463
|
+
const vpnStableArgs = ["--disable", "plugins", "--disable", "general_analytics"];
|
|
464
|
+
if (interactive) {
|
|
465
|
+
const interactiveArgs = [...vpnStableArgs, ...codexModelArgs(input.model), "--full-auto"];
|
|
466
|
+
if (input.resumeSessionId) {
|
|
467
|
+
return [...interactiveArgs, "resume", input.resumeSessionId];
|
|
468
|
+
}
|
|
469
|
+
return interactiveArgs;
|
|
470
|
+
}
|
|
471
|
+
if (input.resumeSessionId) {
|
|
472
|
+
return [
|
|
473
|
+
"exec",
|
|
474
|
+
"resume",
|
|
475
|
+
...localFolderArgs,
|
|
476
|
+
...vpnStableArgs,
|
|
477
|
+
...codexModelArgs(input.model),
|
|
478
|
+
"--full-auto",
|
|
479
|
+
input.resumeSessionId,
|
|
480
|
+
"-"
|
|
481
|
+
];
|
|
482
|
+
}
|
|
483
|
+
return [
|
|
484
|
+
"exec",
|
|
485
|
+
...localFolderArgs,
|
|
486
|
+
...vpnStableArgs,
|
|
487
|
+
...codexModelArgs(input.model),
|
|
488
|
+
"--full-auto"
|
|
489
|
+
];
|
|
490
|
+
}
|
|
491
|
+
if (interactive) {
|
|
492
|
+
return [];
|
|
493
|
+
}
|
|
494
|
+
return [...plainModelArgs(input.model), "--print"];
|
|
495
|
+
}
|
|
496
|
+
function codexModelArgs(model) {
|
|
497
|
+
const trimmed = model?.trim();
|
|
498
|
+
return trimmed ? ["--model", resolveCodexModel(trimmed)] : [];
|
|
499
|
+
}
|
|
500
|
+
function plainModelArgs(model) {
|
|
501
|
+
const trimmed = model?.trim();
|
|
502
|
+
return trimmed ? ["--model", trimmed] : [];
|
|
503
|
+
}
|
|
504
|
+
function resolveCodexModel(model) {
|
|
505
|
+
return /^\d+(?:\.\d+)+$/.test(model) ? `gpt-${model}` : model;
|
|
506
|
+
}
|
|
507
|
+
function runtimePrompt(input) {
|
|
508
|
+
return [
|
|
509
|
+
"# Instructions",
|
|
510
|
+
input.instructions,
|
|
511
|
+
"",
|
|
512
|
+
"# Task",
|
|
513
|
+
input.prompt,
|
|
514
|
+
"",
|
|
515
|
+
"# Allowed Tools",
|
|
516
|
+
(input.allowedTools ?? []).join(", ")
|
|
517
|
+
].join("\n");
|
|
518
|
+
}
|
|
519
|
+
function createLineEmitter(type, emit) {
|
|
520
|
+
let buffered = "";
|
|
521
|
+
return {
|
|
522
|
+
async write(text) {
|
|
523
|
+
buffered += text;
|
|
524
|
+
const lines = buffered.split(/\r?\n/);
|
|
525
|
+
buffered = lines.pop() ?? "";
|
|
526
|
+
for (const line of lines) {
|
|
527
|
+
if (line.length > 0) {
|
|
528
|
+
await emit({ type, content: line });
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
async close() {
|
|
533
|
+
if (buffered.length > 0) {
|
|
534
|
+
await emit({ type, content: buffered });
|
|
535
|
+
buffered = "";
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
//# sourceMappingURL=cli.js.map
|