@rallycry/conveyor-agent 10.13.14 → 10.13.16
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/boot-NMXFM4GK.js +1268 -0
- package/dist/boot-NMXFM4GK.js.map +1 -0
- package/dist/{server-TVIXWCAI.js → chunk-5UYMDSAE.js} +8 -3
- package/dist/chunk-5UYMDSAE.js.map +1 -0
- package/dist/chunk-6GS5ADIY.js +11 -0
- package/dist/chunk-6GS5ADIY.js.map +1 -0
- package/dist/{chunk-RSIW2UCR.js → chunk-JG54UJ6V.js} +2 -2
- package/dist/{chunk-VKZ5W2VO.js → chunk-JIGG755T.js} +1 -1
- package/dist/chunk-JIGG755T.js.map +1 -0
- package/dist/{chunk-J4UH5TOO.js → chunk-OW2TIDWZ.js} +71 -114
- package/dist/chunk-OW2TIDWZ.js.map +1 -0
- package/dist/{chunk-LZM5OKAC.js → chunk-UDSRAHKP.js} +19 -2
- package/dist/chunk-UDSRAHKP.js.map +1 -0
- package/dist/chunk-UZTJJD7Y.js +254 -0
- package/dist/chunk-UZTJJD7Y.js.map +1 -0
- package/dist/cli.js +30 -47
- package/dist/cli.js.map +1 -1
- package/dist/{client-VQIBGPE6.js → client-BU4XA7CV.js} +3 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/{protocol-IHRTO5C4.js → protocol-QLVS5W6O.js} +2 -2
- package/dist/server-CO5O7G4U.js +9 -0
- package/dist/server-CO5O7G4U.js.map +1 -0
- package/package.json +1 -1
- package/runtime/entrypoint.sh +8 -975
- package/dist/chunk-J4UH5TOO.js.map +0 -1
- package/dist/chunk-LZM5OKAC.js.map +0 -1
- package/dist/chunk-VKZ5W2VO.js.map +0 -1
- package/dist/server-TVIXWCAI.js.map +0 -1
- /package/dist/{chunk-RSIW2UCR.js.map → chunk-JG54UJ6V.js.map} +0 -0
- /package/dist/{client-VQIBGPE6.js.map → client-BU4XA7CV.js.map} +0 -0
- /package/dist/{protocol-IHRTO5C4.js.map → protocol-QLVS5W6O.js.map} +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
DEFAULT_WORKBENCH_PORT,
|
|
7
7
|
FrameReader,
|
|
8
8
|
writeFrame
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-JIGG755T.js";
|
|
10
10
|
|
|
11
11
|
// src/workbench/client.ts
|
|
12
12
|
import { connect } from "net";
|
|
@@ -89,6 +89,23 @@ var WorkbenchClient = class {
|
|
|
89
89
|
);
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
+
/** One-shot poll of the workbench's git-prep state. A daemon without a
|
|
93
|
+
* provider answers `ready` (non-pod servers must not wedge callers). */
|
|
94
|
+
gitStatus() {
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
let status = null;
|
|
97
|
+
this.open(
|
|
98
|
+
{ op: "gitStatus" },
|
|
99
|
+
(frame) => {
|
|
100
|
+
if (frame.t === "gitStatus") status = frame;
|
|
101
|
+
},
|
|
102
|
+
(error) => {
|
|
103
|
+
if (status) resolve(status);
|
|
104
|
+
else reject(error ?? new WorkbenchError("connection closed before gitStatus"));
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
92
109
|
/** Mirrors setup/commands.ts runSetupCommand (shell form, streamed output,
|
|
93
110
|
* abort → graceful term-group kill, non-zero exit rejects). */
|
|
94
111
|
runSetupCommand(cmd, cwd, onOutput, signal) {
|
|
@@ -344,4 +361,4 @@ export {
|
|
|
344
361
|
getWorkbenchClient,
|
|
345
362
|
resetWorkbenchClient
|
|
346
363
|
};
|
|
347
|
-
//# sourceMappingURL=chunk-
|
|
364
|
+
//# sourceMappingURL=chunk-UDSRAHKP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/workbench/client.ts","../src/workbench/errors.ts","../src/workbench/remote-process.ts"],"sourcesContent":["/**\n * Client half of the workbench launcher protocol. Runs in the protected agent\n * container; every method opens one loopback connection, sends the request\n * frame, and adapts the stream back to the local signature it replaces\n * (runSetupCommand, runStartCommand, execFile, PtySpawn, workspace file\n * reads). See server.ts / protocol.ts.\n */\n\nimport { connect, type Socket } from \"node:net\";\nimport type { PtyProcess, PtySpawnOptions } from \"../harness/pty/pty-support.js\";\nimport { WorkbenchError } from \"./errors.js\";\nimport { RemoteProcessHandle } from \"./remote-process.js\";\n\nexport { WorkbenchError } from \"./errors.js\";\nexport { RemoteProcessHandle } from \"./remote-process.js\";\nimport { workbenchPort, workbenchToken } from \"./mode.js\";\nimport {\n DEFAULT_WORKBENCH_PORT,\n FrameReader,\n writeFrame,\n type GitStatusFrame,\n type WorkbenchFrame,\n type WorkbenchRequest,\n} from \"./protocol.js\";\n\nexport interface WorkbenchClientOptions {\n port?: number;\n token?: string;\n host?: string;\n}\n\n/** Omit that distributes over a discriminated union (plain Omit collapses\n * the union to its common properties). */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\nfunction frameError(frame: Extract<WorkbenchFrame, { t: \"error\" }>): WorkbenchError {\n return new WorkbenchError(frame.message, frame.code);\n}\n\nexport class WorkbenchClient {\n private readonly port: number;\n private readonly host: string;\n private readonly token: string;\n\n constructor(options: WorkbenchClientOptions = {}) {\n this.port = options.port ?? workbenchPort() ?? DEFAULT_WORKBENCH_PORT;\n this.host = options.host ?? \"127.0.0.1\";\n this.token = options.token ?? workbenchToken();\n }\n\n /** Open a connection, send the request, route response frames. */\n private open(\n request: DistributiveOmit<WorkbenchRequest, \"token\">,\n onFrame: (frame: WorkbenchFrame, socket: Socket) => void,\n onClose: (error?: Error) => void,\n ): Socket {\n const socket = connect(this.port, this.host);\n let sawError: Error | undefined;\n const reader = new FrameReader((raw) => {\n const frame = raw as unknown as WorkbenchFrame;\n if (frame.t === \"error\") {\n sawError = frameError(frame as Extract<WorkbenchFrame, { t: \"error\" }>);\n }\n onFrame(frame, socket);\n });\n socket.on(\"connect\", () => {\n writeFrame(socket, { ...request, token: this.token } as WorkbenchRequest);\n });\n socket.on(\"data\", (chunk) => reader.push(chunk));\n socket.on(\"error\", (err) => {\n sawError ??= err;\n });\n socket.on(\"close\", () => onClose(sawError));\n return socket;\n }\n\n ping(): Promise<string> {\n return new Promise((resolve, reject) => {\n let version: string | null = null;\n this.open(\n { op: \"ping\" },\n (frame) => {\n if (frame.t === \"pong\") version = frame.version;\n },\n (error) => {\n if (version === null) {\n reject(error ?? new WorkbenchError(\"connection closed before pong\"));\n } else {\n resolve(version);\n }\n },\n );\n });\n }\n\n /** One-shot poll of the workbench's git-prep state. A daemon without a\n * provider answers `ready` (non-pod servers must not wedge callers). */\n gitStatus(): Promise<GitStatusFrame> {\n return new Promise((resolve, reject) => {\n let status: GitStatusFrame | null = null;\n this.open(\n { op: \"gitStatus\" },\n (frame) => {\n if (frame.t === \"gitStatus\") status = frame;\n },\n (error) => {\n if (status) resolve(status);\n else reject(error ?? new WorkbenchError(\"connection closed before gitStatus\"));\n },\n );\n });\n }\n\n /** Mirrors setup/commands.ts runSetupCommand (shell form, streamed output,\n * abort → graceful term-group kill, non-zero exit rejects). */\n runSetupCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n signal?: AbortSignal,\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n const error = new Error(\"Operation aborted\");\n error.name = \"AbortError\";\n reject(error);\n return;\n }\n let exitCode: number | null = null;\n let exited = false;\n let aborting = false;\n const socket = this.open(\n { op: \"exec\", command: cmd, cwd },\n (frame) => {\n if (frame.t === \"out\" && !aborting) {\n onOutput(frame.s, Buffer.from(frame.d, \"base64\").toString(\"utf8\"));\n } else if (frame.t === \"exit\") {\n exited = true;\n exitCode = frame.code;\n }\n },\n (error) => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (aborting) {\n const abortError = new Error(\"Operation aborted\");\n abortError.name = \"AbortError\";\n reject(abortError);\n } else if (!exited) {\n reject(error ?? new WorkbenchError(\"connection closed before exit\"));\n } else if (exitCode === 0) {\n resolve();\n } else {\n reject(new Error(`Setup command exited with code ${exitCode}`));\n }\n },\n );\n const onAbort = (): void => {\n if (exited || aborting) return;\n aborting = true;\n writeFrame(socket, { t: \"signal\", mode: \"term-group\" });\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n }\n\n /** Mirrors setup/commands.ts runStartCommand: returns a live handle that\n * emits exit/error and whose kill() runs the graceful term-group stop. */\n runStartCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n ): RemoteProcessHandle {\n let socket: Socket | undefined;\n const handle = new RemoteProcessHandle(() => {\n if (socket) writeFrame(socket, { t: \"signal\", mode: \"term-group\" });\n });\n let exited = false;\n socket = this.open(\n { op: \"exec\", command: cmd, cwd },\n (frame) => {\n if (frame.t === \"out\") {\n onOutput(frame.s, Buffer.from(frame.d, \"base64\").toString(\"utf8\"));\n } else if (frame.t === \"exit\") {\n exited = true;\n handle.exitCode = frame.code ?? (frame.signal ? null : 0);\n handle.emit(\"exit\", frame.code, frame.signal);\n }\n },\n (error) => {\n if (!exited) {\n // Connection died without an exit frame (launcher restart, network\n // teardown): surface as an error + synthetic exit so the supervisor\n // observes the process ending rather than hanging on it forever.\n exited = true;\n handle.exitCode = handle.exitCode ?? 1;\n handle.emit(\n \"error\",\n error ?? new WorkbenchError(\"workbench connection lost\", \"workbench_gone\"),\n );\n handle.emit(\"exit\", handle.exitCode, null);\n }\n },\n );\n return handle;\n }\n\n /** Mirrors promisified execFile (argv form, no shell): resolves stdout,\n * rejects with stderr-bearing error on non-zero exit. */\n execFile(\n file: string,\n args: string[],\n opts: { cwd?: string; timeout?: number; maxBuffer?: number } = {},\n ): Promise<{ stdout: string; stderr: string }> {\n return new Promise((resolve, reject) => {\n const stdout: Buffer[] = [];\n const stderr: Buffer[] = [];\n let exitCode: number | null = null;\n let exitSignal: string | null = null;\n let exited = false;\n let timedOut = false;\n const socket = this.open(\n { op: \"exec\", argv: [file, ...args], cwd: opts.cwd ?? process.cwd() },\n (frame) => {\n if (frame.t === \"out\") {\n (frame.s === \"stdout\" ? stdout : stderr).push(Buffer.from(frame.d, \"base64\"));\n } else if (frame.t === \"exit\") {\n exited = true;\n exitCode = frame.code;\n exitSignal = frame.signal;\n }\n },\n (error) => {\n if (timer) clearTimeout(timer);\n const out = Buffer.concat(stdout).toString(\"utf8\");\n const errText = Buffer.concat(stderr).toString(\"utf8\");\n if (!exited) {\n reject(error ?? new WorkbenchError(\"connection closed before exit\"));\n } else if (exitCode === 0) {\n resolve({ stdout: out, stderr: errText });\n } else {\n const failure = new Error(\n timedOut\n ? `Command timed out: ${file}`\n : `Command failed: ${file} ${args.join(\" \")}\\n${errText}`,\n ) as Error & {\n code?: number | null;\n signal?: string | null;\n stdout: string;\n stderr: string;\n };\n failure.code = exitCode;\n failure.signal = exitSignal;\n failure.stdout = out;\n failure.stderr = errText;\n reject(failure);\n }\n },\n );\n const timer = opts.timeout\n ? setTimeout(() => {\n timedOut = true;\n writeFrame(socket, { t: \"signal\", mode: \"term-group\" });\n }, opts.timeout)\n : null;\n timer?.unref();\n });\n }\n\n /**\n * Synchronous PtySpawn adapter: returns a PtyProcess immediately; writes\n * and resizes are queued until the connection opens. Exit surfaces through\n * onExit exactly as node-pty's would (a lost connection = exit code 1 —\n * the session's finalizeOnExit path treats it as a crashed CLI).\n */\n spawnPty(file: string, args: string[], options: PtySpawnOptions): PtyProcess {\n const dataListeners: Array<(data: string) => void> = [];\n const exitListeners: Array<(event: { exitCode: number }) => void> = [];\n let connected = false;\n let exited = false;\n const preConnectQueue: WorkbenchFrame[] = [];\n\n const socket = this.open(\n {\n op: \"pty\",\n file,\n args,\n cwd: options.cwd,\n env: options.env,\n cols: options.cols,\n rows: options.rows,\n },\n (frame) => {\n if (frame.t === \"data\") {\n const text = Buffer.from(frame.d, \"base64\").toString(\"utf8\");\n for (const listener of dataListeners) listener(text);\n } else if (frame.t === \"exit\") {\n exited = true;\n for (const listener of exitListeners) listener({ exitCode: frame.code ?? 1 });\n }\n },\n () => {\n if (!exited) {\n exited = true;\n for (const listener of exitListeners) listener({ exitCode: 1 });\n }\n },\n );\n socket.on(\"connect\", () => {\n connected = true;\n for (const frame of preConnectQueue.splice(0)) writeFrame(socket, frame);\n });\n\n const send = (frame: WorkbenchFrame): void => {\n if (exited) return;\n if (connected) writeFrame(socket, frame);\n else preConnectQueue.push(frame);\n };\n\n return {\n onData: (listener) => dataListeners.push(listener),\n onExit: (listener) => exitListeners.push(listener),\n write: (data) => send({ t: \"input\", d: Buffer.from(data, \"utf8\").toString(\"base64\") }),\n resize: (cols, rows) => send({ t: \"resize\", cols, rows }),\n kill: (sig) => send({ t: \"kill\", ...(sig ? { sig } : {}) }),\n };\n }\n\n readFile(path: string): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let ended = false;\n this.open(\n { op: \"readFile\", path },\n (frame) => {\n if (frame.t === \"data\") chunks.push(Buffer.from(frame.d, \"base64\"));\n else if (frame.t === \"end\") ended = true;\n },\n (error) => {\n if (ended) resolve(Buffer.concat(chunks));\n else reject(error ?? new WorkbenchError(\"connection closed before end\"));\n },\n );\n });\n }\n\n stat(path: string): Promise<{\n exists: boolean;\n isFile: boolean;\n isDirectory: boolean;\n size: number;\n mtimeMs: number;\n }> {\n return new Promise((resolve, reject) => {\n let stat: {\n exists: boolean;\n isFile: boolean;\n isDirectory: boolean;\n size: number;\n mtimeMs: number;\n } | null = null;\n this.open(\n { op: \"stat\", path },\n (frame) => {\n if (frame.t === \"stat\") {\n stat = {\n exists: frame.exists,\n isFile: frame.isFile,\n isDirectory: frame.isDirectory,\n size: frame.size,\n mtimeMs: frame.mtimeMs,\n };\n }\n },\n (error) => {\n if (stat) resolve(stat);\n else reject(error ?? new WorkbenchError(\"connection closed before stat\"));\n },\n );\n });\n }\n\n readdir(path: string): Promise<string[]> {\n return new Promise((resolve, reject) => {\n let entries: string[] | null = null;\n this.open(\n { op: \"readdir\", path },\n (frame) => {\n if (frame.t === \"entries\") entries = frame.names;\n },\n (error) => {\n if (entries) resolve(entries);\n else reject(error ?? new WorkbenchError(\"connection closed before entries\"));\n },\n );\n });\n }\n}\n\nlet singleton: WorkbenchClient | null = null;\n\n/** Lazy env-configured client (split-mode pods). */\nexport function getWorkbenchClient(): WorkbenchClient {\n singleton ??= new WorkbenchClient();\n return singleton;\n}\n\n/** Test seam. */\nexport function resetWorkbenchClient(): void {\n singleton = null;\n}\n","/** Error surfaced by the workbench client for launcher-side failures; `code`\n * carries the remote error code (e.g. \"ENOENT\", \"unauthorized\") so callers'\n * existing errno handling keeps working across the container boundary. */\nexport class WorkbenchError extends Error {\n code?: string;\n constructor(message: string, code?: string) {\n super(message);\n this.name = \"WorkbenchError\";\n if (code) this.code = code;\n }\n}\n","import { EventEmitter } from \"node:events\";\n\n/**\n * Structural stand-in for the ChildProcess surface the workspace-command\n * supervisor actually uses (pid/exitCode/kill + exit/error events) — see\n * ManagedChildProcess in setup/commands.ts. kill() requests the launcher's\n * graceful term-group sequence regardless of the signal argument.\n */\nexport class RemoteProcessHandle extends EventEmitter {\n pid: number | undefined = undefined;\n exitCode: number | null = null;\n\n constructor(private readonly sendSignal: () => void) {\n super();\n }\n\n kill(_signal?: NodeJS.Signals | number): boolean {\n this.sendSignal();\n return true;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// src/runner/session-runner-helpers.ts
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
function mapChatHistory(messages) {
|
|
6
|
+
if (!messages) return [];
|
|
7
|
+
return messages.map((m) => ({
|
|
8
|
+
id: m.id,
|
|
9
|
+
role: m.role ?? "user",
|
|
10
|
+
content: m.content ?? "",
|
|
11
|
+
userId: m.userId,
|
|
12
|
+
userName: m.user?.name ?? void 0,
|
|
13
|
+
createdAt: m.createdAt,
|
|
14
|
+
...m.files && m.files.length > 0 ? {
|
|
15
|
+
files: m.files.map((f) => ({
|
|
16
|
+
fileId: f.id,
|
|
17
|
+
fileName: f.fileName,
|
|
18
|
+
mimeType: f.mimeType,
|
|
19
|
+
fileSize: f.fileSize,
|
|
20
|
+
downloadUrl: f.downloadUrl ?? "",
|
|
21
|
+
content: f.content,
|
|
22
|
+
contentEncoding: f.contentEncoding
|
|
23
|
+
}))
|
|
24
|
+
} : {}
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
function readAgentVersion() {
|
|
28
|
+
try {
|
|
29
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
for (const rel of ["../package.json", "../../package.json"]) {
|
|
31
|
+
try {
|
|
32
|
+
const pkg = JSON.parse(readFileSync(join(here, rel), "utf-8"));
|
|
33
|
+
if (pkg.version) return pkg.version;
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/boot/git-prep.ts
|
|
43
|
+
import { execFile } from "child_process";
|
|
44
|
+
import { existsSync, mkdirSync } from "fs";
|
|
45
|
+
import { join as join2 } from "path";
|
|
46
|
+
import { promisify } from "util";
|
|
47
|
+
var QUICK_GIT_TIMEOUT_MS = 6e4;
|
|
48
|
+
var FETCH_TIMEOUT_MS = 3e5;
|
|
49
|
+
var CLONE_TIMEOUT_MS = 6e5;
|
|
50
|
+
var execFileAsync = promisify(execFile);
|
|
51
|
+
function ensureDir(dir) {
|
|
52
|
+
mkdirSync(dir, { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
function defaultGit(args, opts = {}) {
|
|
55
|
+
return execFileAsync("git", args, {
|
|
56
|
+
cwd: opts.cwd,
|
|
57
|
+
timeout: opts.timeoutMs ?? QUICK_GIT_TIMEOUT_MS,
|
|
58
|
+
maxBuffer: 10 * 1024 * 1024
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function redactToken(text) {
|
|
62
|
+
return text.replace(/x-access-token:[^@]*@/g, "x-access-token:***@");
|
|
63
|
+
}
|
|
64
|
+
function errText(err) {
|
|
65
|
+
return redactToken(err instanceof Error ? err.message : String(err));
|
|
66
|
+
}
|
|
67
|
+
async function syncTaskBranchToRepo(deps, paths) {
|
|
68
|
+
const { git, log } = deps;
|
|
69
|
+
const { branch, baseBranch } = deps.bundle.gitPlan;
|
|
70
|
+
try {
|
|
71
|
+
await git(["remote", "set-url", "origin", paths.remoteUrl], {
|
|
72
|
+
cwd: paths.repoDir,
|
|
73
|
+
timeoutMs: QUICK_GIT_TIMEOUT_MS
|
|
74
|
+
});
|
|
75
|
+
} catch (err) {
|
|
76
|
+
log.error(`[boot] ERROR: remote set-url failed: ${errText(err)}`);
|
|
77
|
+
return { state: "failed", reason: "remote set-url failed" };
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
await git(["fetch", "origin", `+refs/heads/${baseBranch}:refs/remotes/origin/${baseBranch}`], {
|
|
81
|
+
cwd: paths.repoDir,
|
|
82
|
+
timeoutMs: FETCH_TIMEOUT_MS
|
|
83
|
+
});
|
|
84
|
+
} catch (err) {
|
|
85
|
+
log.warn(`[boot] WARN: fetch origin/${baseBranch} failed: ${errText(err)}`);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
await git(["reset", "--hard", "HEAD"], { cwd: paths.repoDir, timeoutMs: QUICK_GIT_TIMEOUT_MS });
|
|
89
|
+
} catch (err) {
|
|
90
|
+
log.error(
|
|
91
|
+
`[boot] ERROR: failed to clean tracked repo changes before checkout: ${errText(err)}`
|
|
92
|
+
);
|
|
93
|
+
return { state: "failed", reason: "pre-checkout reset failed" };
|
|
94
|
+
}
|
|
95
|
+
log.info(`[boot] Repo remote ready; agent will checkout ${branch}`);
|
|
96
|
+
return { state: "ready" };
|
|
97
|
+
}
|
|
98
|
+
async function clonePostAssignment(deps, paths) {
|
|
99
|
+
const { git, log } = deps;
|
|
100
|
+
const { branch, baseBranch, checkoutRef } = deps.bundle.gitPlan;
|
|
101
|
+
log.info("[boot] Cloning repo post-assignment (pre-clone was missing)...");
|
|
102
|
+
if (checkoutRef) {
|
|
103
|
+
try {
|
|
104
|
+
await git(
|
|
105
|
+
[
|
|
106
|
+
"clone",
|
|
107
|
+
"--depth",
|
|
108
|
+
"1",
|
|
109
|
+
"--single-branch",
|
|
110
|
+
"--branch",
|
|
111
|
+
baseBranch,
|
|
112
|
+
paths.remoteUrl,
|
|
113
|
+
"repo"
|
|
114
|
+
],
|
|
115
|
+
{ cwd: paths.workspacesDir, timeoutMs: CLONE_TIMEOUT_MS }
|
|
116
|
+
);
|
|
117
|
+
} catch (err) {
|
|
118
|
+
log.error(`[boot] ERROR: post-assignment clone failed: ${errText(err)}`);
|
|
119
|
+
return { state: "failed", reason: "post-assignment clone failed" };
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
await git(["fetch", "origin", `+${checkoutRef}:refs/remotes/origin/pr-checkout`], {
|
|
123
|
+
cwd: paths.repoDir,
|
|
124
|
+
timeoutMs: FETCH_TIMEOUT_MS
|
|
125
|
+
});
|
|
126
|
+
} catch (err) {
|
|
127
|
+
log.error(`[boot] ERROR: post-assignment fetch of ${checkoutRef} failed: ${errText(err)}`);
|
|
128
|
+
return { state: "failed", reason: `post-assignment fetch of ${checkoutRef} failed` };
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
await git(["checkout", "-f", "-B", branch, "refs/remotes/origin/pr-checkout"], {
|
|
132
|
+
cwd: paths.repoDir,
|
|
133
|
+
timeoutMs: QUICK_GIT_TIMEOUT_MS
|
|
134
|
+
});
|
|
135
|
+
} catch (err) {
|
|
136
|
+
log.error(`[boot] ERROR: post-assignment checkout of ${checkoutRef} failed: ${errText(err)}`);
|
|
137
|
+
return { state: "failed", reason: `post-assignment checkout of ${checkoutRef} failed` };
|
|
138
|
+
}
|
|
139
|
+
return { state: "ready" };
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
await git(["clone", "--single-branch", "--branch", baseBranch, paths.remoteUrl, "repo"], {
|
|
143
|
+
cwd: paths.workspacesDir,
|
|
144
|
+
timeoutMs: CLONE_TIMEOUT_MS
|
|
145
|
+
});
|
|
146
|
+
} catch (err) {
|
|
147
|
+
log.error(
|
|
148
|
+
`[boot] ERROR: post-assignment clone of base '${baseBranch}' failed: ${errText(err)}`
|
|
149
|
+
);
|
|
150
|
+
return { state: "failed", reason: "post-assignment clone failed" };
|
|
151
|
+
}
|
|
152
|
+
return syncTaskBranchToRepo(deps, paths);
|
|
153
|
+
}
|
|
154
|
+
async function prepareWorkspaceGit(deps) {
|
|
155
|
+
const { bundle, log } = deps;
|
|
156
|
+
const workspacesDir = deps.workspacesDir ?? "/workspaces";
|
|
157
|
+
const repoDir = join2(workspacesDir, "repo");
|
|
158
|
+
const { repoOwner, repoName, branch } = bundle.gitPlan;
|
|
159
|
+
const token = bundle.githubToken;
|
|
160
|
+
const paths = {
|
|
161
|
+
workspacesDir,
|
|
162
|
+
repoDir,
|
|
163
|
+
remoteUrl: `https://x-access-token:${token}@github.com/${repoOwner}/${repoName}.git`
|
|
164
|
+
};
|
|
165
|
+
try {
|
|
166
|
+
if (existsSync(join2(repoDir, ".git")) && token) {
|
|
167
|
+
log.info(
|
|
168
|
+
deps.podImage ? `[boot] Pod image \u2014 updating repo to latest (branch=${branch})...` : `[boot] Repo present (non-pod-image) \u2014 updating repo to latest (branch=${branch})...`
|
|
169
|
+
);
|
|
170
|
+
return await syncTaskBranchToRepo(deps, paths);
|
|
171
|
+
}
|
|
172
|
+
if (token && repoOwner && repoName && branch) {
|
|
173
|
+
try {
|
|
174
|
+
mkdirSync(workspacesDir, { recursive: true });
|
|
175
|
+
} catch {
|
|
176
|
+
}
|
|
177
|
+
return await clonePostAssignment(deps, paths);
|
|
178
|
+
}
|
|
179
|
+
log.info("[boot] No git plan to prepare \u2014 marking git ready.");
|
|
180
|
+
return { state: "ready" };
|
|
181
|
+
} catch (err) {
|
|
182
|
+
log.error(`[boot] ERROR: git prep failed unexpectedly: ${errText(err)}`);
|
|
183
|
+
return { state: "failed", reason: "git prep failed unexpectedly" };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
var GIT_PREP_MAX_RETRIES = 3;
|
|
187
|
+
var DEFAULT_RETRY_DELAY_MS = 1e4;
|
|
188
|
+
var GitPrepJob = class {
|
|
189
|
+
constructor(deps, extras) {
|
|
190
|
+
this.deps = deps;
|
|
191
|
+
this.extras = extras;
|
|
192
|
+
}
|
|
193
|
+
deps;
|
|
194
|
+
extras;
|
|
195
|
+
current = { state: "pending" };
|
|
196
|
+
started = false;
|
|
197
|
+
get status() {
|
|
198
|
+
return this.current;
|
|
199
|
+
}
|
|
200
|
+
/** Kick off the background attempts. Idempotent. */
|
|
201
|
+
start() {
|
|
202
|
+
if (this.started) return;
|
|
203
|
+
this.started = true;
|
|
204
|
+
void this.run();
|
|
205
|
+
}
|
|
206
|
+
async run() {
|
|
207
|
+
const { log } = this.deps;
|
|
208
|
+
const retryDelayMs = this.extras.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
|
|
209
|
+
for (let attempt = 1; attempt <= GIT_PREP_MAX_RETRIES; attempt++) {
|
|
210
|
+
const result = await prepareWorkspaceGit(this.deps);
|
|
211
|
+
if (result.state === "ready") {
|
|
212
|
+
try {
|
|
213
|
+
await this.extras.onReady();
|
|
214
|
+
} catch (err) {
|
|
215
|
+
log.warn(`[boot] WARN: pre-ready binds failed: ${errText(err)}`);
|
|
216
|
+
}
|
|
217
|
+
this.current = { state: "ready" };
|
|
218
|
+
try {
|
|
219
|
+
await this.extras.afterReady();
|
|
220
|
+
} catch (err) {
|
|
221
|
+
log.warn(`[boot] WARN: post-ready work failed: ${errText(err)}`);
|
|
222
|
+
}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (attempt >= GIT_PREP_MAX_RETRIES) {
|
|
226
|
+
log.error(
|
|
227
|
+
`[boot] workbench git prep failed ${GIT_PREP_MAX_RETRIES} times \u2014 giving up (agent surfaces the failure).`
|
|
228
|
+
);
|
|
229
|
+
this.current = result;
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
log.warn(
|
|
233
|
+
`[boot] workbench git prep failed \u2014 retrying (attempt ${attempt}/${GIT_PREP_MAX_RETRIES})...`
|
|
234
|
+
);
|
|
235
|
+
await new Promise((resolve) => {
|
|
236
|
+
setTimeout(resolve, retryDelayMs);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
export {
|
|
243
|
+
mapChatHistory,
|
|
244
|
+
readAgentVersion,
|
|
245
|
+
FETCH_TIMEOUT_MS,
|
|
246
|
+
CLONE_TIMEOUT_MS,
|
|
247
|
+
ensureDir,
|
|
248
|
+
defaultGit,
|
|
249
|
+
redactToken,
|
|
250
|
+
GIT_PREP_MAX_RETRIES,
|
|
251
|
+
DEFAULT_RETRY_DELAY_MS,
|
|
252
|
+
GitPrepJob
|
|
253
|
+
};
|
|
254
|
+
//# sourceMappingURL=chunk-UZTJJD7Y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runner/session-runner-helpers.ts","../src/boot/git-prep.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ChatMessage, TaskContextDTO } from \"@project/shared\";\n\nexport function mapChatHistory(\n messages: TaskContextDTO[\"chatHistory\"] | undefined | null,\n): ChatMessage[] {\n if (!messages) return [];\n return messages.map((m) => ({\n id: m.id,\n role: (m.role ?? \"user\") as \"user\" | \"assistant\" | \"system\",\n content: m.content ?? \"\",\n userId: m.userId,\n userName: m.user?.name ?? undefined,\n createdAt: m.createdAt,\n ...(m.files && m.files.length > 0\n ? {\n files: m.files.map((f) => ({\n fileId: f.id,\n fileName: f.fileName,\n mimeType: f.mimeType,\n fileSize: f.fileSize,\n downloadUrl: f.downloadUrl ?? \"\",\n content: f.content,\n contentEncoding: f.contentEncoding,\n })),\n }\n : {}),\n }));\n}\n\n/** Read this agent's version from its bundled package.json. */\nexport function readAgentVersion(): string | null {\n try {\n const here = dirname(fileURLToPath(import.meta.url));\n // Walk up: dist/runner/session-runner.js → dist/ → package.json\n for (const rel of [\"../package.json\", \"../../package.json\"]) {\n try {\n const pkg = JSON.parse(readFileSync(join(here, rel), \"utf-8\")) as { version?: string };\n if (pkg.version) return pkg.version;\n } catch {\n /* try next candidate */\n }\n }\n } catch {\n /* ignore */\n }\n return null;\n}\n","import { execFile } from \"node:child_process\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport type { BootstrapBundle } from \"../setup/bootstrap-bundle-types.js\";\nimport type { BootLogger } from \"./types.js\";\n\n/**\n * Ports `prepare_workspace_git` + `sync_task_branch_to_repo` +\n * `reset_tracked_repo_changes_before_assignment_checkout`\n * (entrypoint.sh:623-829) and the workbench bounded retry loop\n * (entrypoint.sh:877-893). The bash signalled via marker files on the shared\n * emptyDir; vnext replaces the markers with daemon-owned state — `GitPrepJob`\n * holds it and the workbench daemon serves it over the `gitStatus` op.\n *\n * Contract carried from the old entrypoint-git-prep.test.ts (verbatim — the\n * agent side depends on it):\n * - `syncTaskBranchToRepo` NEVER touches BRANCH/CHECKOUT_REF and does NO\n * merge. It refreshes the origin remote with the fresh installation token,\n * warms `origin/<base>` (warn-only on failure — the ref may already be\n * present from the bake), and resets tracked changes. The agent's\n * `ensureOnTaskBranch` owns the authoritative checkout.\n * - Clone paths: with checkoutRef → depth-1 base clone, fetch the ref to\n * refs/remotes/origin/pr-checkout, `checkout -f -B <branch>` onto it.\n * Without → clone the BASE branch at FULL depth (a naive `--branch <task>`\n * dies when the task branch was never pushed; `--depth 1` caused the\n * \"refusing to merge unrelated histories\" incident), then sync.\n * - No git plan (empty token/owner/name/branch) → immediate ready.\n *\n * Every fallible git call is guarded — `prepareWorkspaceGit` NEVER throws\n * (the bash equivalent: every error path wrote the failed marker instead of\n * exiting the backgrounded subshell). Reasons stay the short bash marker\n * strings; redacted detail goes to the log.\n */\n\nexport type GitPrepState =\n | { state: \"pending\" }\n | { state: \"ready\" }\n | { state: \"failed\"; reason: string };\n\n/** Async git runner — always `execFile` with a timeout, never execSync (a\n * sync child freezes the event loop; see runner/git-utils.ts history). */\nexport type GitFn = (\n args: string[],\n opts?: { cwd?: string; timeoutMs?: number },\n) => Promise<{ stdout: string }>;\n\nexport interface GitPrepDeps {\n git: GitFn;\n bundle: BootstrapBundle;\n /** env CONVEYOR_POD_IMAGE === \"1\" — log-line fidelity only; behavior matches. */\n podImage: boolean;\n /** default \"/workspaces\" */\n workspacesDir?: string;\n log: BootLogger;\n}\n\nconst QUICK_GIT_TIMEOUT_MS = 60_000;\n// FETCH/CLONE timeouts are exported so setup/git-ready.ts can DERIVE its gate\n// deadline from the daemon's actual retry envelope instead of hand-picking a\n// number that silently drifts when these change.\nexport const FETCH_TIMEOUT_MS = 300_000;\nexport const CLONE_TIMEOUT_MS = 600_000;\n\nconst execFileAsync = promisify(execFile);\n\n/** `mkdir -p`. Shared with the workbench boot's `ensureWorkspaceDir` default so\n * its deps aggregator reuses this module rather than pulling in node:fs. */\nexport function ensureDir(dir: string): void {\n mkdirSync(dir, { recursive: true });\n}\n\n/** Production GitFn. */\nexport function defaultGit(\n args: string[],\n opts: { cwd?: string; timeoutMs?: number } = {},\n): Promise<{ stdout: string }> {\n return execFileAsync(\"git\", args, {\n cwd: opts.cwd,\n timeout: opts.timeoutMs ?? QUICK_GIT_TIMEOUT_MS,\n maxBuffer: 10 * 1024 * 1024,\n });\n}\n\n/** Remote URLs embed the installation token; execFile error messages embed\n * the command line. Redact before ANY log/reason sink. */\nexport function redactToken(text: string): string {\n return text.replace(/x-access-token:[^@]*@/g, \"x-access-token:***@\");\n}\n\nfunction errText(err: unknown): string {\n return redactToken(err instanceof Error ? err.message : String(err));\n}\n\ninterface PrepPaths {\n workspacesDir: string;\n repoDir: string;\n remoteUrl: string;\n}\n\n/** Refresh the remote token + warm origin/<base> + reset tracked changes.\n * Deliberately no BRANCH/CHECKOUT_REF handling — see module doc. */\nasync function syncTaskBranchToRepo(deps: GitPrepDeps, paths: PrepPaths): Promise<GitPrepState> {\n const { git, log } = deps;\n const { branch, baseBranch } = deps.bundle.gitPlan;\n try {\n await git([\"remote\", \"set-url\", \"origin\", paths.remoteUrl], {\n cwd: paths.repoDir,\n timeoutMs: QUICK_GIT_TIMEOUT_MS,\n });\n } catch (err) {\n log.error(`[boot] ERROR: remote set-url failed: ${errText(err)}`);\n return { state: \"failed\", reason: \"remote set-url failed\" };\n }\n // Warm origin/<base> so the agent's checkout/fetch is a fast-forward.\n // Warn-only: a stale-but-present origin/<base> from the bake still works.\n try {\n await git([\"fetch\", \"origin\", `+refs/heads/${baseBranch}:refs/remotes/origin/${baseBranch}`], {\n cwd: paths.repoDir,\n timeoutMs: FETCH_TIMEOUT_MS,\n });\n } catch (err) {\n log.warn(`[boot] WARN: fetch origin/${baseBranch} failed: ${errText(err)}`);\n }\n // The baked/pooled repo is not user-owned until this gate succeeds: reset\n // stale tracked image dirt so the agent's checkout isn't blocked. No\n // `git clean` — untracked prebake artifacts may be intentional.\n try {\n await git([\"reset\", \"--hard\", \"HEAD\"], { cwd: paths.repoDir, timeoutMs: QUICK_GIT_TIMEOUT_MS });\n } catch (err) {\n log.error(\n `[boot] ERROR: failed to clean tracked repo changes before checkout: ${errText(err)}`,\n );\n return { state: \"failed\", reason: \"pre-checkout reset failed\" };\n }\n log.info(`[boot] Repo remote ready; agent will checkout ${branch}`);\n return { state: \"ready\" };\n}\n\nasync function clonePostAssignment(deps: GitPrepDeps, paths: PrepPaths): Promise<GitPrepState> {\n const { git, log } = deps;\n const { branch, baseBranch, checkoutRef } = deps.bundle.gitPlan;\n log.info(\"[boot] Cloning repo post-assignment (pre-clone was missing)...\");\n if (checkoutRef) {\n try {\n await git(\n [\n \"clone\",\n \"--depth\",\n \"1\",\n \"--single-branch\",\n \"--branch\",\n baseBranch,\n paths.remoteUrl,\n \"repo\",\n ],\n { cwd: paths.workspacesDir, timeoutMs: CLONE_TIMEOUT_MS },\n );\n } catch (err) {\n log.error(`[boot] ERROR: post-assignment clone failed: ${errText(err)}`);\n return { state: \"failed\", reason: \"post-assignment clone failed\" };\n }\n try {\n await git([\"fetch\", \"origin\", `+${checkoutRef}:refs/remotes/origin/pr-checkout`], {\n cwd: paths.repoDir,\n timeoutMs: FETCH_TIMEOUT_MS,\n });\n } catch (err) {\n log.error(`[boot] ERROR: post-assignment fetch of ${checkoutRef} failed: ${errText(err)}`);\n return { state: \"failed\", reason: `post-assignment fetch of ${checkoutRef} failed` };\n }\n // -f: an untracked bake artifact can collide with a path the target ref\n // tracks; the repo is not user-owned yet, so forcing is safe.\n try {\n await git([\"checkout\", \"-f\", \"-B\", branch, \"refs/remotes/origin/pr-checkout\"], {\n cwd: paths.repoDir,\n timeoutMs: QUICK_GIT_TIMEOUT_MS,\n });\n } catch (err) {\n log.error(`[boot] ERROR: post-assignment checkout of ${checkoutRef} failed: ${errText(err)}`);\n return { state: \"failed\", reason: `post-assignment checkout of ${checkoutRef} failed` };\n }\n return { state: \"ready\" };\n }\n // FULL depth base-branch clone — see module doc for both incidents.\n try {\n await git([\"clone\", \"--single-branch\", \"--branch\", baseBranch, paths.remoteUrl, \"repo\"], {\n cwd: paths.workspacesDir,\n timeoutMs: CLONE_TIMEOUT_MS,\n });\n } catch (err) {\n log.error(\n `[boot] ERROR: post-assignment clone of base '${baseBranch}' failed: ${errText(err)}`,\n );\n return { state: \"failed\", reason: \"post-assignment clone failed\" };\n }\n return syncTaskBranchToRepo(deps, paths);\n}\n\n/** ONE preparation attempt. Never throws. */\nexport async function prepareWorkspaceGit(deps: GitPrepDeps): Promise<GitPrepState> {\n const { bundle, log } = deps;\n const workspacesDir = deps.workspacesDir ?? \"/workspaces\";\n const repoDir = join(workspacesDir, \"repo\");\n const { repoOwner, repoName, branch } = bundle.gitPlan;\n const token = bundle.githubToken;\n const paths: PrepPaths = {\n workspacesDir,\n repoDir,\n remoteUrl: `https://x-access-token:${token}@github.com/${repoOwner}/${repoName}.git`,\n };\n try {\n if (existsSync(join(repoDir, \".git\")) && token) {\n // Do NOT silently fall through to the image snapshot on failure — a\n // stale image repo has bitten us before (old scripts, wrong deps) and is\n // brutal to diagnose from pod logs. Fail loud via the returned state.\n log.info(\n deps.podImage\n ? `[boot] Pod image — updating repo to latest (branch=${branch})...`\n : `[boot] Repo present (non-pod-image) — updating repo to latest (branch=${branch})...`,\n );\n return await syncTaskBranchToRepo(deps, paths);\n }\n if (token && repoOwner && repoName && branch) {\n try {\n mkdirSync(workspacesDir, { recursive: true });\n } catch {\n /* clone below surfaces the real failure */\n }\n return await clonePostAssignment(deps, paths);\n }\n // No git plan (task-less pod, or no token/repo) — nothing to prepare;\n // signal ready so the agent doesn't wait out its gate timeout.\n log.info(\"[boot] No git plan to prepare — marking git ready.\");\n return { state: \"ready\" };\n } catch (err) {\n // Belt-and-braces: nothing above should throw, but this function's\n // contract is \"never throws\" (the bash never `exit`ed the subshell).\n log.error(`[boot] ERROR: git prep failed unexpectedly: ${errText(err)}`);\n return { state: \"failed\", reason: \"git prep failed unexpectedly\" };\n }\n}\n\n// Brief-mandated attempt count: 3 total. Not a literal match for the bash\n// workbench retry loop (entrypoint.sh:883) — bash did 1 initial attempt + 3\n// retries = 4 attempts total; the TS port intentionally caps at 3.\nexport const GIT_PREP_MAX_RETRIES = 3;\n/** Exported for setup/git-ready.ts's derived gate deadline (see above). */\nexport const DEFAULT_RETRY_DELAY_MS = 10_000;\n\nexport interface GitPrepJobExtras {\n /** Awaited BEFORE status flips ready — graphify bind + grimoire submodule +\n * skill links. Claude must not spawn before skills exist. */\n onReady: () => Promise<void>;\n /** Runs AFTER ready — reference-repo clones must never block Claude. */\n afterReady: () => Promise<void>;\n /** default 10s (the bash loop's poll cadence); tests shrink it. */\n retryDelayMs?: number;\n}\n\n/**\n * Daemon-owned replacement for the marker files + workbench retry loop: up to\n * `GIT_PREP_MAX_RETRIES` `prepareWorkspaceGit` attempts, then give up leaving\n * `status` failed (the agent surfaces it). While a retry is still possible the\n * status stays `pending`, never transiently `failed` — the agent's gitStatus\n * gate treats `failed` as fatal, and the bash marker dance had exactly this\n * race (agent glimpses the failed marker before the retry loop clears it).\n */\nexport class GitPrepJob {\n private current: GitPrepState = { state: \"pending\" };\n private started = false;\n\n constructor(\n private readonly deps: GitPrepDeps,\n private readonly extras: GitPrepJobExtras,\n ) {}\n\n get status(): GitPrepState {\n return this.current;\n }\n\n /** Kick off the background attempts. Idempotent. */\n start(): void {\n if (this.started) return;\n this.started = true;\n void this.run();\n }\n\n private async run(): Promise<void> {\n const { log } = this.deps;\n const retryDelayMs = this.extras.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;\n for (let attempt = 1; attempt <= GIT_PREP_MAX_RETRIES; attempt++) {\n const result = await prepareWorkspaceGit(this.deps);\n if (result.state === \"ready\") {\n // Binds gate readiness but are best-effort — a graphify/grimoire\n // failure must never fail the git gate itself.\n try {\n await this.extras.onReady();\n } catch (err) {\n log.warn(`[boot] WARN: pre-ready binds failed: ${errText(err)}`);\n }\n this.current = { state: \"ready\" };\n try {\n await this.extras.afterReady();\n } catch (err) {\n log.warn(`[boot] WARN: post-ready work failed: ${errText(err)}`);\n }\n return;\n }\n if (attempt >= GIT_PREP_MAX_RETRIES) {\n log.error(\n `[boot] workbench git prep failed ${GIT_PREP_MAX_RETRIES} times — giving up (agent surfaces the failure).`,\n );\n this.current = result;\n return;\n }\n log.warn(\n `[boot] workbench git prep failed — retrying (attempt ${attempt}/${GIT_PREP_MAX_RETRIES})...`,\n );\n await new Promise<void>((resolve) => {\n setTimeout(resolve, retryDelayMs);\n });\n }\n }\n}\n"],"mappings":"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","names":["join"]}
|
package/dist/cli.js
CHANGED
|
@@ -28,11 +28,16 @@ import {
|
|
|
28
28
|
runUsageProbe,
|
|
29
29
|
sampleKeyUsage,
|
|
30
30
|
textResult
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-OW2TIDWZ.js";
|
|
32
32
|
import "./chunk-7TQO4ZF4.js";
|
|
33
33
|
import {
|
|
34
34
|
getWorkbenchClient
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-UDSRAHKP.js";
|
|
36
|
+
import {
|
|
37
|
+
TOMBSTONE_MESSAGE,
|
|
38
|
+
isLegacyEntrypointLaunch
|
|
39
|
+
} from "./chunk-6GS5ADIY.js";
|
|
40
|
+
import "./chunk-UZTJJD7Y.js";
|
|
36
41
|
import {
|
|
37
42
|
workbenchEnabled
|
|
38
43
|
} from "./chunk-4VUQ2NPF.js";
|
|
@@ -42,18 +47,16 @@ import {
|
|
|
42
47
|
loadPtySpawn,
|
|
43
48
|
runStartCommand,
|
|
44
49
|
terminateProcessGroup
|
|
45
|
-
} from "./chunk-
|
|
46
|
-
import "./chunk-
|
|
50
|
+
} from "./chunk-JG54UJ6V.js";
|
|
51
|
+
import "./chunk-JIGG755T.js";
|
|
47
52
|
|
|
48
53
|
// src/cli.ts
|
|
49
54
|
import { readFileSync } from "fs";
|
|
50
|
-
import { join as join3, dirname as
|
|
55
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
51
56
|
import { fileURLToPath } from "url";
|
|
52
57
|
|
|
53
58
|
// src/setup/sidecars.ts
|
|
54
59
|
import net from "net";
|
|
55
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
56
|
-
import { dirname } from "path";
|
|
57
60
|
var POSTGRES_TIMEOUT_MS = 12e4;
|
|
58
61
|
var FIREBASE_TIMEOUT_MS = 6e4;
|
|
59
62
|
var FALLBACK_TIMEOUT_MS = 3e4;
|
|
@@ -61,22 +64,6 @@ var DEFAULT_SIDECAR_POLL_INTERVAL_MS = 1e3;
|
|
|
61
64
|
var DEFAULT_PROBE_TIMEOUT_MS = 2e3;
|
|
62
65
|
var POSTGRES_DEFAULT_PORT = 5432;
|
|
63
66
|
var FIREBASE_DEFAULT_PORT = 9099;
|
|
64
|
-
async function startLazySidecars(env, onLog, signal) {
|
|
65
|
-
throwIfAborted(signal);
|
|
66
|
-
const markerPath = env.CONVEYOR_SIDECAR_START_FILE;
|
|
67
|
-
if (!markerPath) return;
|
|
68
|
-
try {
|
|
69
|
-
await mkdir(dirname(markerPath), { recursive: true });
|
|
70
|
-
throwIfAborted(signal);
|
|
71
|
-
await writeFile(markerPath, "start\n", "utf8");
|
|
72
|
-
throwIfAborted(signal);
|
|
73
|
-
onLog("Started lazy sidecars");
|
|
74
|
-
} catch (err) {
|
|
75
|
-
if (signal?.aborted) throw abortError();
|
|
76
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
77
|
-
onLog(`WARNING: failed to start lazy sidecars: ${message}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
67
|
function parseHostPort(value, defaultPort) {
|
|
81
68
|
const trimmed = value.trim().replace(/^[a-z]+:\/\//i, "");
|
|
82
69
|
if (!trimmed) return null;
|
|
@@ -203,12 +190,8 @@ async function waitForSidecars(opts = {}) {
|
|
|
203
190
|
timeoutMs,
|
|
204
191
|
pollIntervalMs = DEFAULT_SIDECAR_POLL_INTERVAL_MS,
|
|
205
192
|
probe = defaultProbe,
|
|
206
|
-
startLazy = true,
|
|
207
193
|
signal
|
|
208
194
|
} = opts;
|
|
209
|
-
if (startLazy) {
|
|
210
|
-
await startLazySidecars(env, onLog, signal);
|
|
211
|
-
}
|
|
212
195
|
throwIfAborted(signal);
|
|
213
196
|
const targets = resolveSidecarTargets(env);
|
|
214
197
|
if (targets.length === 0) return;
|
|
@@ -278,7 +261,6 @@ var WorkspaceCommandSupervisor = class {
|
|
|
278
261
|
connection;
|
|
279
262
|
env;
|
|
280
263
|
awaitGitReadyFn;
|
|
281
|
-
startLazySidecarsFn;
|
|
282
264
|
waitForSidecarsFn;
|
|
283
265
|
runStartCommandFn;
|
|
284
266
|
loadForwardPortsFn;
|
|
@@ -313,8 +295,7 @@ var WorkspaceCommandSupervisor = class {
|
|
|
313
295
|
onLog: opts.onLog,
|
|
314
296
|
signal: opts.signal
|
|
315
297
|
}));
|
|
316
|
-
this.
|
|
317
|
-
this.waitForSidecarsFn = options.waitForSidecars ?? ((opts) => waitForSidecars({ onLog: opts.onLog, startLazy: opts.startLazy, signal: opts.signal }));
|
|
298
|
+
this.waitForSidecarsFn = options.waitForSidecars ?? ((opts) => waitForSidecars({ onLog: opts.onLog, signal: opts.signal }));
|
|
318
299
|
const executors = defaultCommandExecutors();
|
|
319
300
|
this.runStartCommandFn = options.runStartCommand ?? executors.runStartCommand;
|
|
320
301
|
this.loadForwardPortsFn = options.loadForwardPorts ?? loadForwardPorts;
|
|
@@ -328,14 +309,6 @@ var WorkspaceCommandSupervisor = class {
|
|
|
328
309
|
if (this.started || this.stopped) return;
|
|
329
310
|
this.started = true;
|
|
330
311
|
this.connection.onRunStartCommand(() => this.restartStartCommand());
|
|
331
|
-
this.trackBackgroundTask(
|
|
332
|
-
this.startLazySidecarsFn(
|
|
333
|
-
this.env,
|
|
334
|
-
(message) => this.forwardSetupOutput("stdout", `[sidecars] ${message}
|
|
335
|
-
`),
|
|
336
|
-
this.abortController.signal
|
|
337
|
-
).catch((error) => this.reportUnexpectedError(error))
|
|
338
|
-
);
|
|
339
312
|
if (this.config) {
|
|
340
313
|
this.trackBackgroundTask(
|
|
341
314
|
this.runSetupAndStart().catch((error) => this.reportUnexpectedError(error))
|
|
@@ -380,7 +353,6 @@ var WorkspaceCommandSupervisor = class {
|
|
|
380
353
|
await this.waitForSidecarsFn({
|
|
381
354
|
onLog: (message) => this.forwardSetupOutput("stdout", `[sidecars] ${message}
|
|
382
355
|
`),
|
|
383
|
-
startLazy: false,
|
|
384
356
|
signal: this.abortController.signal
|
|
385
357
|
});
|
|
386
358
|
if (this.stopped) return;
|
|
@@ -720,7 +692,7 @@ var ProjectSessionRunner = class {
|
|
|
720
692
|
};
|
|
721
693
|
|
|
722
694
|
// src/usage/multi-key-probe.ts
|
|
723
|
-
import { mkdtemp, writeFile
|
|
695
|
+
import { mkdtemp, writeFile, copyFile, rm } from "fs/promises";
|
|
724
696
|
import { tmpdir } from "os";
|
|
725
697
|
import { join } from "path";
|
|
726
698
|
var logger = createServiceLogger("multi-key-probe");
|
|
@@ -751,7 +723,7 @@ async function isolatedProbe(token, now) {
|
|
|
751
723
|
let dir = null;
|
|
752
724
|
try {
|
|
753
725
|
dir = await mkdtemp(join(tmpdir(), "conveyor-usage-"));
|
|
754
|
-
await
|
|
726
|
+
await writeFile(join(dir, ".credentials.json"), buildSynthesizedCredentials(token, now), {
|
|
755
727
|
encoding: "utf8",
|
|
756
728
|
mode: 384
|
|
757
729
|
});
|
|
@@ -792,7 +764,7 @@ async function probeKeysUsage(keys, deps = {}) {
|
|
|
792
764
|
|
|
793
765
|
// src/harness/pty/adapters/opencode-auth.ts
|
|
794
766
|
import { promises as fs } from "fs";
|
|
795
|
-
import { dirname
|
|
767
|
+
import { dirname, join as join2 } from "path";
|
|
796
768
|
import { homedir } from "os";
|
|
797
769
|
var logger2 = createServiceLogger("opencode-auth");
|
|
798
770
|
var OPENCODE_CODEX_PLUGIN = "opencode-openai-codex-auth@4.4.0";
|
|
@@ -833,7 +805,7 @@ async function readJsonFile(path) {
|
|
|
833
805
|
}
|
|
834
806
|
}
|
|
835
807
|
async function writeJsonFile(path, value) {
|
|
836
|
-
await fs.mkdir(
|
|
808
|
+
await fs.mkdir(dirname(path), { recursive: true });
|
|
837
809
|
await fs.writeFile(path, `${JSON.stringify(value, null, 2)}
|
|
838
810
|
`, { mode: 384 });
|
|
839
811
|
}
|
|
@@ -1492,6 +1464,8 @@ function buildReviewChildEnv(baseEnv, data) {
|
|
|
1492
1464
|
delete env.CONVEYOR_BOOTSTRAP_TOKEN;
|
|
1493
1465
|
delete env.CONVEYOR_SETUP_COMMAND;
|
|
1494
1466
|
delete env.CONVEYOR_START_COMMAND;
|
|
1467
|
+
delete env.CONVEYOR_GIT_READY;
|
|
1468
|
+
delete env.CONVEYOR_GIT_READY_MARKER;
|
|
1495
1469
|
delete env.CONVEYOR_AGENT_MODE;
|
|
1496
1470
|
delete env.CONVEYOR_IS_AUTO;
|
|
1497
1471
|
return env;
|
|
@@ -1922,8 +1896,17 @@ function createSpawnedChildRunner(inputs) {
|
|
|
1922
1896
|
}
|
|
1923
1897
|
|
|
1924
1898
|
// src/cli.ts
|
|
1899
|
+
if (process.argv[2] === "boot") {
|
|
1900
|
+
const { runBoot } = await import("./boot-NMXFM4GK.js");
|
|
1901
|
+
process.exit(await runBoot(process.argv.slice(3)));
|
|
1902
|
+
}
|
|
1903
|
+
if (isLegacyEntrypointLaunch(process.env)) {
|
|
1904
|
+
process.stderr.write(`${TOMBSTONE_MESSAGE}
|
|
1905
|
+
`);
|
|
1906
|
+
process.exit(1);
|
|
1907
|
+
}
|
|
1925
1908
|
if (process.argv.includes("--version")) {
|
|
1926
|
-
const __dirname =
|
|
1909
|
+
const __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
1927
1910
|
const pkgPath = join3(__dirname, "..", "package.json");
|
|
1928
1911
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
1929
1912
|
process.stdout.write(pkg.version + "\n");
|
|
@@ -2005,15 +1988,15 @@ process.on("unhandledRejection", (reason) => {
|
|
|
2005
1988
|
process.exit(1);
|
|
2006
1989
|
});
|
|
2007
1990
|
if (process.env.CONVEYOR_MODE === "workbench") {
|
|
2008
|
-
const { startWorkbenchServer } = await import("./server-
|
|
2009
|
-
const { DEFAULT_WORKBENCH_PORT } = await import("./protocol-
|
|
1991
|
+
const { startWorkbenchServer } = await import("./server-CO5O7G4U.js");
|
|
1992
|
+
const { DEFAULT_WORKBENCH_PORT } = await import("./protocol-QLVS5W6O.js");
|
|
2010
1993
|
const port = Number(process.env.CONVEYOR_WORKBENCH_PORT) || DEFAULT_WORKBENCH_PORT;
|
|
2011
1994
|
const token = process.env.CONVEYOR_WORKBENCH_TOKEN ?? process.env.POD_BOOTSTRAP_TOKEN ?? "";
|
|
2012
1995
|
if (!token) {
|
|
2013
1996
|
logger6.error("workbench mode requires POD_BOOTSTRAP_TOKEN (or CONVEYOR_WORKBENCH_TOKEN)");
|
|
2014
1997
|
process.exit(1);
|
|
2015
1998
|
}
|
|
2016
|
-
const pkgDir =
|
|
1999
|
+
const pkgDir = dirname2(fileURLToPath(import.meta.url));
|
|
2017
2000
|
const pkg = JSON.parse(readFileSync(join3(pkgDir, "..", "package.json"), "utf-8"));
|
|
2018
2001
|
const handle = await startWorkbenchServer({
|
|
2019
2002
|
port,
|