@rallycry/conveyor-agent 10.2.4 → 10.2.5
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/{chunk-DEMRCBJN.js → chunk-CFELRV35.js} +383 -292
- package/dist/chunk-CFELRV35.js.map +1 -0
- package/dist/cli.js +123 -6
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/runtime/entrypoint.sh +93 -4
- package/dist/chunk-DEMRCBJN.js.map +0 -1
|
@@ -1909,6 +1909,7 @@ async function restoreOnBoot(bundle, cwd) {
|
|
|
1909
1909
|
import { z } from "zod";
|
|
1910
1910
|
import { z as z2 } from "zod";
|
|
1911
1911
|
var DEFAULT_SONNET_MODEL = "claude-sonnet-5";
|
|
1912
|
+
var TUI_KINDS = ["claude-code", "opencode"];
|
|
1912
1913
|
var MAX_FILE_SIZE_BYTES = 25 * 1024 * 1024;
|
|
1913
1914
|
var EMBED_THRESHOLD_IMAGES = 5 * 1024 * 1024;
|
|
1914
1915
|
var EMBED_THRESHOLD_TEXT = 2 * 1024 * 1024;
|
|
@@ -2444,9 +2445,14 @@ var ListMyLiveSessionsRequestSchema = z2.object({
|
|
|
2444
2445
|
/** Admin-only: list another member's sessions instead of the caller's. */
|
|
2445
2446
|
targetUserId: z2.string().optional()
|
|
2446
2447
|
});
|
|
2448
|
+
var GetProjectAvailableTuisRequestSchema = z2.object({
|
|
2449
|
+
projectId: z2.string()
|
|
2450
|
+
});
|
|
2447
2451
|
var StartAdhocSessionRequestSchema = z2.object({
|
|
2448
2452
|
projectId: z2.string(),
|
|
2449
2453
|
label: z2.string().max(200).optional(),
|
|
2454
|
+
/** Coding-agent key to launch under — validated pick-time (ownership + TUI availability) in the handler. */
|
|
2455
|
+
codingAgentKeyId: z2.string().optional(),
|
|
2450
2456
|
/**
|
|
2451
2457
|
* Session role. Constrained: other task-less modes fall through to the pm
|
|
2452
2458
|
* runner in the pod entrypoint, and "review" would crash without a task.
|
|
@@ -2977,9 +2983,9 @@ var ClaudeCodeHarness = class {
|
|
|
2977
2983
|
};
|
|
2978
2984
|
|
|
2979
2985
|
// src/harness/pty/session.ts
|
|
2980
|
-
import { mkdtemp as mkdtemp2, mkdir as
|
|
2986
|
+
import { mkdtemp as mkdtemp2, mkdir as mkdir3, rm as rm5 } from "fs/promises";
|
|
2981
2987
|
import { tmpdir as tmpdir3 } from "os";
|
|
2982
|
-
import { join as
|
|
2988
|
+
import { join as join4, dirname } from "path";
|
|
2983
2989
|
|
|
2984
2990
|
// src/harness/pty/event-queue.ts
|
|
2985
2991
|
var AsyncEventQueue = class {
|
|
@@ -3442,76 +3448,6 @@ function mapChatRecords(raw) {
|
|
|
3442
3448
|
}
|
|
3443
3449
|
}
|
|
3444
3450
|
|
|
3445
|
-
// src/harness/pty/spawn-args.ts
|
|
3446
|
-
function resolveClaudeBinary() {
|
|
3447
|
-
return process.env.CONVEYOR_CLAUDE_BIN ?? "claude";
|
|
3448
|
-
}
|
|
3449
|
-
function buildSpawnArgs(input) {
|
|
3450
|
-
const args = [];
|
|
3451
|
-
if (input.resume) {
|
|
3452
|
-
args.push("--resume", input.resume);
|
|
3453
|
-
} else if (input.sessionId) {
|
|
3454
|
-
args.push("--session-id", input.sessionId);
|
|
3455
|
-
}
|
|
3456
|
-
args.push("--model", input.model);
|
|
3457
|
-
if (input.permissionMode === "bypassPermissions") {
|
|
3458
|
-
args.push("--dangerously-skip-permissions");
|
|
3459
|
-
} else {
|
|
3460
|
-
args.push("--permission-mode", "plan");
|
|
3461
|
-
}
|
|
3462
|
-
args.push("--settings", input.settingsPath);
|
|
3463
|
-
if (input.appendSystemPrompt) {
|
|
3464
|
-
args.push("--append-system-prompt", input.appendSystemPrompt);
|
|
3465
|
-
}
|
|
3466
|
-
if (input.mcpConfigPath) {
|
|
3467
|
-
args.push("--mcp-config", input.mcpConfigPath);
|
|
3468
|
-
if (input.strictMcpConfig) {
|
|
3469
|
-
args.push("--strict-mcp-config");
|
|
3470
|
-
}
|
|
3471
|
-
}
|
|
3472
|
-
return args;
|
|
3473
|
-
}
|
|
3474
|
-
function spawnOptionsFingerprint(input) {
|
|
3475
|
-
return JSON.stringify([
|
|
3476
|
-
input.model,
|
|
3477
|
-
input.permissionMode,
|
|
3478
|
-
input.appendSystemPrompt ?? "",
|
|
3479
|
-
input.cwd
|
|
3480
|
-
]);
|
|
3481
|
-
}
|
|
3482
|
-
var ANSI_CSI = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`, "g");
|
|
3483
|
-
function cleanTerminalOutput(raw, maxChars = 1200) {
|
|
3484
|
-
const noAnsi = raw.replace(ANSI_CSI, "");
|
|
3485
|
-
let out = "";
|
|
3486
|
-
for (const ch of noAnsi) {
|
|
3487
|
-
const code = ch.charCodeAt(0);
|
|
3488
|
-
if (ch === "\r" || ch === "\n") out += "\n";
|
|
3489
|
-
else if (ch === " ") out += ch;
|
|
3490
|
-
else if (code < 32 || code === 127) continue;
|
|
3491
|
-
else out += ch;
|
|
3492
|
-
}
|
|
3493
|
-
const lines = out.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim().length > 0);
|
|
3494
|
-
const text = lines.join("\n").trim();
|
|
3495
|
-
return text.length > maxChars ? `\u2026${text.slice(-maxChars)}` : text;
|
|
3496
|
-
}
|
|
3497
|
-
function isMissingBinaryFailure(tail) {
|
|
3498
|
-
return /execvp\(\d+\) failed|no such file or directory|command not found/i.test(tail);
|
|
3499
|
-
}
|
|
3500
|
-
function buildExitErrors(exitCode, rawOutput, binary) {
|
|
3501
|
-
const errors = [`claude exited (code ${exitCode}) without a result`];
|
|
3502
|
-
const tail = cleanTerminalOutput(rawOutput);
|
|
3503
|
-
if (isMissingBinaryFailure(tail)) {
|
|
3504
|
-
errors.push(
|
|
3505
|
-
`The \`${binary}\` CLI could not be started \u2014 it is not installed or not on PATH. Install the Claude Code CLI in this environment (npm i -g @anthropic-ai/claude-code) or set CONVEYOR_CLAUDE_BIN to its absolute path.`
|
|
3506
|
-
);
|
|
3507
|
-
}
|
|
3508
|
-
if (tail) {
|
|
3509
|
-
errors.push(`Last terminal output before exit:
|
|
3510
|
-
${tail}`);
|
|
3511
|
-
}
|
|
3512
|
-
return errors;
|
|
3513
|
-
}
|
|
3514
|
-
|
|
3515
3451
|
// src/harness/pty/settings.ts
|
|
3516
3452
|
import { mkdir, writeFile as writeFile2, chmod } from "fs/promises";
|
|
3517
3453
|
import { homedir } from "os";
|
|
@@ -3982,6 +3918,238 @@ async function startToolServers(mcpServers, tempDir) {
|
|
|
3982
3918
|
return { servers, mcpConfigPath };
|
|
3983
3919
|
}
|
|
3984
3920
|
|
|
3921
|
+
// src/harness/pty/spawn-args.ts
|
|
3922
|
+
function buildSpawnArgs(input) {
|
|
3923
|
+
const args = [];
|
|
3924
|
+
if (input.resume) {
|
|
3925
|
+
args.push("--resume", input.resume);
|
|
3926
|
+
} else if (input.sessionId) {
|
|
3927
|
+
args.push("--session-id", input.sessionId);
|
|
3928
|
+
}
|
|
3929
|
+
args.push("--model", input.model);
|
|
3930
|
+
if (input.permissionMode === "bypassPermissions") {
|
|
3931
|
+
args.push("--dangerously-skip-permissions");
|
|
3932
|
+
} else {
|
|
3933
|
+
args.push("--permission-mode", "plan");
|
|
3934
|
+
}
|
|
3935
|
+
args.push("--settings", input.settingsPath);
|
|
3936
|
+
if (input.appendSystemPrompt) {
|
|
3937
|
+
args.push("--append-system-prompt", input.appendSystemPrompt);
|
|
3938
|
+
}
|
|
3939
|
+
if (input.mcpConfigPath) {
|
|
3940
|
+
args.push("--mcp-config", input.mcpConfigPath);
|
|
3941
|
+
if (input.strictMcpConfig) {
|
|
3942
|
+
args.push("--strict-mcp-config");
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3945
|
+
return args;
|
|
3946
|
+
}
|
|
3947
|
+
function spawnOptionsFingerprint(input) {
|
|
3948
|
+
return JSON.stringify([
|
|
3949
|
+
input.model,
|
|
3950
|
+
input.permissionMode,
|
|
3951
|
+
input.appendSystemPrompt ?? "",
|
|
3952
|
+
input.cwd
|
|
3953
|
+
]);
|
|
3954
|
+
}
|
|
3955
|
+
var ANSI_CSI = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`, "g");
|
|
3956
|
+
function cleanTerminalOutput(raw, maxChars = 1200) {
|
|
3957
|
+
const noAnsi = raw.replace(ANSI_CSI, "");
|
|
3958
|
+
let out = "";
|
|
3959
|
+
for (const ch of noAnsi) {
|
|
3960
|
+
const code = ch.charCodeAt(0);
|
|
3961
|
+
if (ch === "\r" || ch === "\n") out += "\n";
|
|
3962
|
+
else if (ch === " ") out += ch;
|
|
3963
|
+
else if (code < 32 || code === 127) continue;
|
|
3964
|
+
else out += ch;
|
|
3965
|
+
}
|
|
3966
|
+
const lines = out.split("\n").map((line) => line.trimEnd()).filter((line) => line.trim().length > 0);
|
|
3967
|
+
const text = lines.join("\n").trim();
|
|
3968
|
+
return text.length > maxChars ? `\u2026${text.slice(-maxChars)}` : text;
|
|
3969
|
+
}
|
|
3970
|
+
function isMissingBinaryFailure(tail) {
|
|
3971
|
+
return /execvp\(\d+\) failed|no such file or directory|command not found/i.test(tail);
|
|
3972
|
+
}
|
|
3973
|
+
function buildExitErrors(exitCode, rawOutput, binary) {
|
|
3974
|
+
const errors = [`claude exited (code ${exitCode}) without a result`];
|
|
3975
|
+
const tail = cleanTerminalOutput(rawOutput);
|
|
3976
|
+
if (isMissingBinaryFailure(tail)) {
|
|
3977
|
+
errors.push(
|
|
3978
|
+
`The \`${binary}\` CLI could not be started \u2014 it is not installed or not on PATH. Install the Claude Code CLI in this environment (npm i -g @anthropic-ai/claude-code) or set CONVEYOR_CLAUDE_BIN to its absolute path.`
|
|
3979
|
+
);
|
|
3980
|
+
}
|
|
3981
|
+
if (tail) {
|
|
3982
|
+
errors.push(`Last terminal output before exit:
|
|
3983
|
+
${tail}`);
|
|
3984
|
+
}
|
|
3985
|
+
return errors;
|
|
3986
|
+
}
|
|
3987
|
+
|
|
3988
|
+
// src/harness/pty/credentials.ts
|
|
3989
|
+
import { chmod as chmod2, mkdir as mkdir2, readFile, rm as rm4, writeFile as writeFile4 } from "fs/promises";
|
|
3990
|
+
import { homedir as homedir2 } from "os";
|
|
3991
|
+
import { join as join3 } from "path";
|
|
3992
|
+
var SYNTH_TOKEN_TTL_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
3993
|
+
var REFRESH_SKEW_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
3994
|
+
function claudeCredentialsPath() {
|
|
3995
|
+
return join3(claudeConfigHome(), ".credentials.json");
|
|
3996
|
+
}
|
|
3997
|
+
function isConveyorCloudEnv(env = process.env) {
|
|
3998
|
+
return Boolean(env.CLAUDESPACE_NAME || env.CODESPACE_NAME || env.CODESPACES);
|
|
3999
|
+
}
|
|
4000
|
+
function parseClaudeAiOauth(raw) {
|
|
4001
|
+
if (!raw || raw.trim() === "") return null;
|
|
4002
|
+
try {
|
|
4003
|
+
const parsed = JSON.parse(raw);
|
|
4004
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
4005
|
+
const oauth = parsed.claudeAiOauth;
|
|
4006
|
+
if (typeof oauth !== "object" || oauth === null) return null;
|
|
4007
|
+
const record = oauth;
|
|
4008
|
+
return {
|
|
4009
|
+
accessToken: record.accessToken,
|
|
4010
|
+
refreshToken: record.refreshToken,
|
|
4011
|
+
expiresAt: record.expiresAt
|
|
4012
|
+
};
|
|
4013
|
+
} catch {
|
|
4014
|
+
return null;
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
function buildSynthesizedCredentials(token, now) {
|
|
4018
|
+
return JSON.stringify({
|
|
4019
|
+
claudeAiOauth: {
|
|
4020
|
+
accessToken: token,
|
|
4021
|
+
expiresAt: now + SYNTH_TOKEN_TTL_MS,
|
|
4022
|
+
scopes: ["user:inference", "user:profile"],
|
|
4023
|
+
subscriptionType: "max"
|
|
4024
|
+
}
|
|
4025
|
+
});
|
|
4026
|
+
}
|
|
4027
|
+
function planCredentialsWrite(input) {
|
|
4028
|
+
if (!input.isCloud) return { action: "skip", reason: "not-cloud" };
|
|
4029
|
+
if (!input.token) return { action: "skip", reason: "no-token" };
|
|
4030
|
+
const contents = buildSynthesizedCredentials(input.token, input.now);
|
|
4031
|
+
const existing = parseClaudeAiOauth(input.existingRaw);
|
|
4032
|
+
if (!existing) return { action: "write", contents };
|
|
4033
|
+
if (typeof existing.refreshToken === "string" && existing.refreshToken.length > 0) {
|
|
4034
|
+
return { action: "skip", reason: "foreign-credentials" };
|
|
4035
|
+
}
|
|
4036
|
+
const fresh = existing.accessToken === input.token && typeof existing.expiresAt === "number" && existing.expiresAt > input.now + REFRESH_SKEW_MS;
|
|
4037
|
+
if (fresh) return { action: "skip", reason: "current" };
|
|
4038
|
+
return { action: "write", contents };
|
|
4039
|
+
}
|
|
4040
|
+
async function readRaw(path4) {
|
|
4041
|
+
try {
|
|
4042
|
+
return await readFile(path4, "utf8");
|
|
4043
|
+
} catch {
|
|
4044
|
+
return null;
|
|
4045
|
+
}
|
|
4046
|
+
}
|
|
4047
|
+
async function ensureClaudeCredentials(env = process.env) {
|
|
4048
|
+
try {
|
|
4049
|
+
const path4 = claudeCredentialsPath();
|
|
4050
|
+
const plan = planCredentialsWrite({
|
|
4051
|
+
isCloud: isConveyorCloudEnv(env),
|
|
4052
|
+
token: env.CLAUDE_CODE_OAUTH_TOKEN,
|
|
4053
|
+
existingRaw: await readRaw(path4),
|
|
4054
|
+
now: Date.now()
|
|
4055
|
+
});
|
|
4056
|
+
if (plan.action === "skip") return;
|
|
4057
|
+
await mkdir2(claudeConfigHome(), { recursive: true });
|
|
4058
|
+
await writeFile4(path4, plan.contents, { encoding: "utf8", mode: 384 });
|
|
4059
|
+
await chmod2(path4, 384).catch(() => {
|
|
4060
|
+
});
|
|
4061
|
+
} catch (err) {
|
|
4062
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4063
|
+
process.stderr.write(`[conveyor-agent] claude credentials sync failed: ${message}
|
|
4064
|
+
`);
|
|
4065
|
+
}
|
|
4066
|
+
}
|
|
4067
|
+
function claudeJsonPath() {
|
|
4068
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
4069
|
+
return configDir ? join3(configDir, ".claude.json") : join3(homedir2(), ".claude.json");
|
|
4070
|
+
}
|
|
4071
|
+
function asRecord(value) {
|
|
4072
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
4073
|
+
}
|
|
4074
|
+
function parseClaudeJson(existingRaw) {
|
|
4075
|
+
if (!existingRaw || existingRaw.trim() === "") return {};
|
|
4076
|
+
try {
|
|
4077
|
+
return asRecord(JSON.parse(existingRaw));
|
|
4078
|
+
} catch {
|
|
4079
|
+
return {};
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
function seedWorkspaceTrust(config, trustCwd) {
|
|
4083
|
+
const projects = asRecord(config.projects);
|
|
4084
|
+
const entry = asRecord(projects[trustCwd]);
|
|
4085
|
+
if (entry.hasTrustDialogAccepted === true) return false;
|
|
4086
|
+
entry.hasTrustDialogAccepted = true;
|
|
4087
|
+
projects[trustCwd] = entry;
|
|
4088
|
+
config.projects = projects;
|
|
4089
|
+
return true;
|
|
4090
|
+
}
|
|
4091
|
+
function planClaudeJsonSeed(existingRaw, trustCwd) {
|
|
4092
|
+
const config = parseClaudeJson(existingRaw);
|
|
4093
|
+
const isFresh = Object.keys(config).length === 0;
|
|
4094
|
+
let changed = false;
|
|
4095
|
+
if (config.hasCompletedOnboarding !== true) {
|
|
4096
|
+
config.hasCompletedOnboarding = true;
|
|
4097
|
+
changed = true;
|
|
4098
|
+
}
|
|
4099
|
+
if (config.bypassPermissionsModeAccepted !== true) {
|
|
4100
|
+
config.bypassPermissionsModeAccepted = true;
|
|
4101
|
+
changed = true;
|
|
4102
|
+
}
|
|
4103
|
+
if (isFresh && typeof config.theme !== "string") {
|
|
4104
|
+
config.theme = "dark";
|
|
4105
|
+
changed = true;
|
|
4106
|
+
}
|
|
4107
|
+
if (trustCwd && seedWorkspaceTrust(config, trustCwd)) {
|
|
4108
|
+
changed = true;
|
|
4109
|
+
}
|
|
4110
|
+
return changed ? JSON.stringify(config) : null;
|
|
4111
|
+
}
|
|
4112
|
+
async function ensureClaudeOnboarding(env = process.env, trustCwd) {
|
|
4113
|
+
try {
|
|
4114
|
+
if (!isConveyorCloudEnv(env)) return;
|
|
4115
|
+
const path4 = claudeJsonPath();
|
|
4116
|
+
const contents = planClaudeJsonSeed(await readRaw(path4), trustCwd);
|
|
4117
|
+
if (contents === null) return;
|
|
4118
|
+
await writeFile4(path4, contents, "utf8");
|
|
4119
|
+
const verify = await readRaw(path4);
|
|
4120
|
+
if (verify === contents) {
|
|
4121
|
+
process.stderr.write(
|
|
4122
|
+
`[conveyor-agent] claude onboarding seeded${trustCwd ? ` (trust: ${trustCwd})` : ""}
|
|
4123
|
+
`
|
|
4124
|
+
);
|
|
4125
|
+
} else {
|
|
4126
|
+
process.stderr.write(
|
|
4127
|
+
`[conveyor-agent] claude onboarding seed read-back MISMATCH at ${path4}: wrote ${contents.length}B, read ${verify?.length ?? 0}B \u2014 CLI may see stale config and park at a startup dialog
|
|
4128
|
+
`
|
|
4129
|
+
);
|
|
4130
|
+
}
|
|
4131
|
+
} catch (err) {
|
|
4132
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4133
|
+
process.stderr.write(`[conveyor-agent] claude onboarding seed failed: ${message}
|
|
4134
|
+
`);
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
async function removeConveyorCredentials(env = process.env) {
|
|
4138
|
+
try {
|
|
4139
|
+
if (!isConveyorCloudEnv(env)) return;
|
|
4140
|
+
const path4 = claudeCredentialsPath();
|
|
4141
|
+
const existing = parseClaudeAiOauth(await readRaw(path4));
|
|
4142
|
+
if (existing && typeof existing.refreshToken === "string" && existing.refreshToken.length > 0) {
|
|
4143
|
+
return;
|
|
4144
|
+
}
|
|
4145
|
+
await rm4(path4, { force: true });
|
|
4146
|
+
} catch (err) {
|
|
4147
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4148
|
+
process.stderr.write(`[conveyor-agent] claude credentials removal failed: ${message}
|
|
4149
|
+
`);
|
|
4150
|
+
}
|
|
4151
|
+
}
|
|
4152
|
+
|
|
3985
4153
|
// src/harness/pty/pty-support.ts
|
|
3986
4154
|
import { stat as stat3 } from "fs/promises";
|
|
3987
4155
|
var MAX_DIAGNOSTIC_OUTPUT = 4e3;
|
|
@@ -4037,7 +4205,9 @@ function inheritedEnv(socketPath) {
|
|
|
4037
4205
|
for (const [key, value] of Object.entries(process.env)) {
|
|
4038
4206
|
if (typeof value === "string") env[key] = value;
|
|
4039
4207
|
}
|
|
4040
|
-
|
|
4208
|
+
if (socketPath) {
|
|
4209
|
+
env.CONVEYOR_HOOK_SOCKET = socketPath;
|
|
4210
|
+
}
|
|
4041
4211
|
env.MCP_TIMEOUT ??= "60000";
|
|
4042
4212
|
env.MCP_TOOL_TIMEOUT ??= "180000";
|
|
4043
4213
|
return env;
|
|
@@ -4087,18 +4257,65 @@ function parseUserQuestions(input) {
|
|
|
4087
4257
|
return questions;
|
|
4088
4258
|
}
|
|
4089
4259
|
|
|
4260
|
+
// src/harness/pty/adapters/claude.ts
|
|
4261
|
+
var ClaudeTuiAdapter = class {
|
|
4262
|
+
id = "claude-code";
|
|
4263
|
+
capabilities = {
|
|
4264
|
+
resume: true,
|
|
4265
|
+
structuredEvents: true,
|
|
4266
|
+
prefill: true,
|
|
4267
|
+
passiveTurns: true
|
|
4268
|
+
};
|
|
4269
|
+
resolveBinary(env = process.env) {
|
|
4270
|
+
return env.CONVEYOR_CLAUDE_BIN ?? "claude";
|
|
4271
|
+
}
|
|
4272
|
+
buildSpawn(input) {
|
|
4273
|
+
const { options, resume } = input;
|
|
4274
|
+
const args = buildSpawnArgs({
|
|
4275
|
+
...resume ? { resume } : {},
|
|
4276
|
+
...options.sessionId ? { sessionId: options.sessionId } : {},
|
|
4277
|
+
model: options.model,
|
|
4278
|
+
permissionMode: options.permissionMode,
|
|
4279
|
+
settingsPath: input.settingsPath ?? "",
|
|
4280
|
+
...options.appendSystemPrompt ? { appendSystemPrompt: options.appendSystemPrompt } : {},
|
|
4281
|
+
...input.mcpConfigPath ? { mcpConfigPath: input.mcpConfigPath, strictMcpConfig: true } : {}
|
|
4282
|
+
});
|
|
4283
|
+
return {
|
|
4284
|
+
file: this.resolveBinary(),
|
|
4285
|
+
args,
|
|
4286
|
+
env: inheritedEnv(input.hookSocketPath)
|
|
4287
|
+
};
|
|
4288
|
+
}
|
|
4289
|
+
async prepareEnvironment(opts) {
|
|
4290
|
+
const env = opts.env ?? process.env;
|
|
4291
|
+
await ensureClaudeCredentials(env);
|
|
4292
|
+
await ensureClaudeOnboarding(env, opts.cwd);
|
|
4293
|
+
}
|
|
4294
|
+
spawnFingerprint(input) {
|
|
4295
|
+
return spawnOptionsFingerprint(input);
|
|
4296
|
+
}
|
|
4297
|
+
encodePromptBytes(text) {
|
|
4298
|
+
return buildPromptBytes(text);
|
|
4299
|
+
}
|
|
4300
|
+
buildExitErrors(exitCode, rawOutput) {
|
|
4301
|
+
return buildExitErrors(exitCode, rawOutput, this.resolveBinary());
|
|
4302
|
+
}
|
|
4303
|
+
};
|
|
4304
|
+
|
|
4090
4305
|
// src/harness/pty/session.ts
|
|
4091
4306
|
var PtySession = class {
|
|
4092
|
-
constructor(prompt, options, resume, bridge) {
|
|
4307
|
+
constructor(prompt, options, resume, bridge, adapter = new ClaudeTuiAdapter()) {
|
|
4093
4308
|
this.options = options;
|
|
4094
4309
|
this.resume = resume;
|
|
4095
4310
|
this.bridge = bridge;
|
|
4311
|
+
this.adapter = adapter;
|
|
4096
4312
|
this.turnPrompt = prompt;
|
|
4097
4313
|
this.turn = turnOptionsFrom(options);
|
|
4098
4314
|
}
|
|
4099
4315
|
options;
|
|
4100
4316
|
resume;
|
|
4101
4317
|
bridge;
|
|
4318
|
+
adapter;
|
|
4102
4319
|
// The current turn's event stream. Null between turns (process parked) — the
|
|
4103
4320
|
// process outlives any single turn, so the queue is per-turn, not per-process.
|
|
4104
4321
|
activeQueue = null;
|
|
@@ -4184,7 +4401,7 @@ var PtySession = class {
|
|
|
4184
4401
|
}
|
|
4185
4402
|
/** Fingerprint of the spawn-time options a reused process cannot change. */
|
|
4186
4403
|
get spawnFingerprint() {
|
|
4187
|
-
return
|
|
4404
|
+
return this.adapter.spawnFingerprint({
|
|
4188
4405
|
model: this.options.model,
|
|
4189
4406
|
permissionMode: this.options.permissionMode,
|
|
4190
4407
|
...this.options.appendSystemPrompt ? { appendSystemPrompt: this.options.appendSystemPrompt } : {},
|
|
@@ -4321,29 +4538,19 @@ var PtySession = class {
|
|
|
4321
4538
|
return;
|
|
4322
4539
|
}
|
|
4323
4540
|
try {
|
|
4324
|
-
this.
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
const sendChat = this.bridge?.sendChatEvent?.bind(this.bridge);
|
|
4338
|
-
this.tailer = new JsonlTailer(
|
|
4339
|
-
transcriptPath,
|
|
4340
|
-
(event) => this.handleTranscriptEvent(event),
|
|
4341
|
-
sendChat ? (raw) => {
|
|
4342
|
-
for (const chatEvent of mapChatRecords(raw)) sendChat(chatEvent);
|
|
4343
|
-
} : void 0
|
|
4344
|
-
);
|
|
4345
|
-
this.tailer.start(startOffset);
|
|
4346
|
-
await this.spawn(settingsPath, socketPath);
|
|
4541
|
+
if (this.adapter.capabilities.structuredEvents) {
|
|
4542
|
+
const { settingsPath, socketPath } = await this.startStructuredEventSources(sessionId);
|
|
4543
|
+
await this.spawn(settingsPath, socketPath);
|
|
4544
|
+
} else {
|
|
4545
|
+
this.tempDir = await mkdtemp2(join4(tmpdir3(), "conveyor-pty-"));
|
|
4546
|
+
await this.spawn();
|
|
4547
|
+
this.pushEvent({
|
|
4548
|
+
type: "system",
|
|
4549
|
+
subtype: "init",
|
|
4550
|
+
session_id: sessionId,
|
|
4551
|
+
model: this.options.model
|
|
4552
|
+
});
|
|
4553
|
+
}
|
|
4347
4554
|
if (signal) {
|
|
4348
4555
|
this.abortHandler = () => {
|
|
4349
4556
|
void this.teardown();
|
|
@@ -4364,6 +4571,38 @@ var PtySession = class {
|
|
|
4364
4571
|
throw err;
|
|
4365
4572
|
}
|
|
4366
4573
|
}
|
|
4574
|
+
/**
|
|
4575
|
+
* Allocate the Claude-style structured-event sources: the PostToolUse hook
|
|
4576
|
+
* socket, the per-run settings file, the in-process tool servers, and the
|
|
4577
|
+
* transcript tailer. Only structured-events adapters call this — raw-terminal
|
|
4578
|
+
* adapters have no trusted event source and skip it entirely. Returns the
|
|
4579
|
+
* paths spawn() must wire into the child's argv/env.
|
|
4580
|
+
*/
|
|
4581
|
+
async startStructuredEventSources(sessionId) {
|
|
4582
|
+
this.tempDir = await mkdtemp2(join4(tmpdir3(), "conveyor-pty-"));
|
|
4583
|
+
const socketPath = join4(this.tempDir, "hook.sock");
|
|
4584
|
+
this.socket = new HookSocketServer(
|
|
4585
|
+
socketPath,
|
|
4586
|
+
(progress) => this.handleProgress(progress),
|
|
4587
|
+
(request) => this.handlePreToolUse(request)
|
|
4588
|
+
);
|
|
4589
|
+
await this.socket.listen();
|
|
4590
|
+
const { settingsPath } = await writeHookSettings(this.tempDir);
|
|
4591
|
+
await this.setupToolServers();
|
|
4592
|
+
const transcriptPath = sessionTranscriptPath(this.options.cwd, sessionId);
|
|
4593
|
+
await mkdir3(dirname(transcriptPath), { recursive: true });
|
|
4594
|
+
const startOffset = this.resume ? await transcriptSize(transcriptPath) : 0;
|
|
4595
|
+
const sendChat = this.bridge?.sendChatEvent?.bind(this.bridge);
|
|
4596
|
+
this.tailer = new JsonlTailer(
|
|
4597
|
+
transcriptPath,
|
|
4598
|
+
(event) => this.handleTranscriptEvent(event),
|
|
4599
|
+
sendChat ? (raw) => {
|
|
4600
|
+
for (const chatEvent of mapChatRecords(raw)) sendChat(chatEvent);
|
|
4601
|
+
} : void 0
|
|
4602
|
+
);
|
|
4603
|
+
this.tailer.start(startOffset);
|
|
4604
|
+
return { settingsPath, socketPath };
|
|
4605
|
+
}
|
|
4367
4606
|
writeStdin(text) {
|
|
4368
4607
|
this.pty?.write(text);
|
|
4369
4608
|
}
|
|
@@ -4429,7 +4668,7 @@ var PtySession = class {
|
|
|
4429
4668
|
this.activeQueue?.close();
|
|
4430
4669
|
this.activeQueue = null;
|
|
4431
4670
|
if (this.tempDir) {
|
|
4432
|
-
await
|
|
4671
|
+
await rm5(this.tempDir, { recursive: true, force: true });
|
|
4433
4672
|
this.tempDir = "";
|
|
4434
4673
|
}
|
|
4435
4674
|
}
|
|
@@ -4448,25 +4687,23 @@ var PtySession = class {
|
|
|
4448
4687
|
this.mcpConfigPath = mcpConfigPath;
|
|
4449
4688
|
}
|
|
4450
4689
|
async spawn(settingsPath, socketPath) {
|
|
4451
|
-
const
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
settingsPath,
|
|
4457
|
-
...this.options.appendSystemPrompt ? { appendSystemPrompt: this.options.appendSystemPrompt } : {},
|
|
4690
|
+
const spec = this.adapter.buildSpawn({
|
|
4691
|
+
options: this.options,
|
|
4692
|
+
...this.resume ? { resume: this.resume } : {},
|
|
4693
|
+
...settingsPath ? { settingsPath } : {},
|
|
4694
|
+
...socketPath ? { hookSocketPath: socketPath } : {},
|
|
4458
4695
|
// Only this config: ignore the user's ~/.claude.json / project .mcp.json
|
|
4459
4696
|
// so the agent's tool set is deterministic (and a stale personal conveyor
|
|
4460
4697
|
// server doesn't load).
|
|
4461
|
-
...this.mcpConfigPath ? { mcpConfigPath: this.mcpConfigPath
|
|
4698
|
+
...this.mcpConfigPath ? { mcpConfigPath: this.mcpConfigPath } : {}
|
|
4462
4699
|
});
|
|
4463
4700
|
const spawn2 = await loadPtySpawn();
|
|
4464
|
-
const pty = spawn2(
|
|
4701
|
+
const pty = spawn2(spec.file, spec.args, {
|
|
4465
4702
|
name: "xterm-color",
|
|
4466
4703
|
cols: this.cols,
|
|
4467
4704
|
rows: this.rows,
|
|
4468
4705
|
cwd: this.options.cwd,
|
|
4469
|
-
env:
|
|
4706
|
+
env: spec.env
|
|
4470
4707
|
});
|
|
4471
4708
|
const bridge = this.bridge;
|
|
4472
4709
|
if (bridge) {
|
|
@@ -4487,12 +4724,13 @@ var PtySession = class {
|
|
|
4487
4724
|
this.pty = pty;
|
|
4488
4725
|
}
|
|
4489
4726
|
async deliverPrompt(text) {
|
|
4490
|
-
this.
|
|
4727
|
+
if (text === "" && !this.adapter.capabilities.prefill) return;
|
|
4728
|
+
this.writeStdin(this.adapter.encodePromptBytes(text));
|
|
4491
4729
|
if (this.turn.promptDelivery === "prefill") return;
|
|
4492
4730
|
await sleep3(SUBMIT_SETTLE_MS);
|
|
4493
4731
|
if (this._toreDown) return;
|
|
4494
4732
|
this.writeStdin("\r");
|
|
4495
|
-
this.armSubmitNudge();
|
|
4733
|
+
if (this.adapter.capabilities.structuredEvents) this.armSubmitNudge();
|
|
4496
4734
|
}
|
|
4497
4735
|
async feedPrompt() {
|
|
4498
4736
|
if (typeof this.turnPrompt === "string") {
|
|
@@ -4649,11 +4887,22 @@ var PtySession = class {
|
|
|
4649
4887
|
this.tailer.close();
|
|
4650
4888
|
await this.tailer.flush();
|
|
4651
4889
|
}
|
|
4652
|
-
if (!this.
|
|
4890
|
+
if (!this.adapter.capabilities.structuredEvents) {
|
|
4891
|
+
if (exitCode === 0) {
|
|
4892
|
+
this.pushEvent({ type: "result", subtype: "success", result: "", total_cost_usd: 0 });
|
|
4893
|
+
} else {
|
|
4894
|
+
this.pushEvent({
|
|
4895
|
+
type: "result",
|
|
4896
|
+
subtype: "error",
|
|
4897
|
+
errors: this.adapter.buildExitErrors(exitCode, this.recentOutput)
|
|
4898
|
+
});
|
|
4899
|
+
}
|
|
4900
|
+
this.endTurn(exitCode === 0);
|
|
4901
|
+
} else if (!this.sawResult && this.activeQueue) {
|
|
4653
4902
|
this.activeQueue.push({
|
|
4654
4903
|
type: "result",
|
|
4655
4904
|
subtype: "error",
|
|
4656
|
-
errors: buildExitErrors(exitCode, this.recentOutput
|
|
4905
|
+
errors: this.adapter.buildExitErrors(exitCode, this.recentOutput)
|
|
4657
4906
|
});
|
|
4658
4907
|
}
|
|
4659
4908
|
for (const listener of this.exitListeners) listener(exitCode);
|
|
@@ -4662,191 +4911,29 @@ var PtySession = class {
|
|
|
4662
4911
|
}
|
|
4663
4912
|
};
|
|
4664
4913
|
|
|
4665
|
-
// src/harness/pty/credentials.ts
|
|
4666
|
-
import { chmod as chmod2, mkdir as mkdir3, readFile, rm as rm5, writeFile as writeFile4 } from "fs/promises";
|
|
4667
|
-
import { homedir as homedir2 } from "os";
|
|
4668
|
-
import { join as join4 } from "path";
|
|
4669
|
-
var SYNTH_TOKEN_TTL_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
4670
|
-
var REFRESH_SKEW_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
4671
|
-
function claudeCredentialsPath() {
|
|
4672
|
-
return join4(claudeConfigHome(), ".credentials.json");
|
|
4673
|
-
}
|
|
4674
|
-
function isConveyorCloudEnv(env = process.env) {
|
|
4675
|
-
return Boolean(env.CLAUDESPACE_NAME || env.CODESPACE_NAME || env.CODESPACES);
|
|
4676
|
-
}
|
|
4677
|
-
function parseClaudeAiOauth(raw) {
|
|
4678
|
-
if (!raw || raw.trim() === "") return null;
|
|
4679
|
-
try {
|
|
4680
|
-
const parsed = JSON.parse(raw);
|
|
4681
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
4682
|
-
const oauth = parsed.claudeAiOauth;
|
|
4683
|
-
if (typeof oauth !== "object" || oauth === null) return null;
|
|
4684
|
-
const record = oauth;
|
|
4685
|
-
return {
|
|
4686
|
-
accessToken: record.accessToken,
|
|
4687
|
-
refreshToken: record.refreshToken,
|
|
4688
|
-
expiresAt: record.expiresAt
|
|
4689
|
-
};
|
|
4690
|
-
} catch {
|
|
4691
|
-
return null;
|
|
4692
|
-
}
|
|
4693
|
-
}
|
|
4694
|
-
function buildSynthesizedCredentials(token, now) {
|
|
4695
|
-
return JSON.stringify({
|
|
4696
|
-
claudeAiOauth: {
|
|
4697
|
-
accessToken: token,
|
|
4698
|
-
expiresAt: now + SYNTH_TOKEN_TTL_MS,
|
|
4699
|
-
scopes: ["user:inference", "user:profile"],
|
|
4700
|
-
subscriptionType: "max"
|
|
4701
|
-
}
|
|
4702
|
-
});
|
|
4703
|
-
}
|
|
4704
|
-
function planCredentialsWrite(input) {
|
|
4705
|
-
if (!input.isCloud) return { action: "skip", reason: "not-cloud" };
|
|
4706
|
-
if (!input.token) return { action: "skip", reason: "no-token" };
|
|
4707
|
-
const contents = buildSynthesizedCredentials(input.token, input.now);
|
|
4708
|
-
const existing = parseClaudeAiOauth(input.existingRaw);
|
|
4709
|
-
if (!existing) return { action: "write", contents };
|
|
4710
|
-
if (typeof existing.refreshToken === "string" && existing.refreshToken.length > 0) {
|
|
4711
|
-
return { action: "skip", reason: "foreign-credentials" };
|
|
4712
|
-
}
|
|
4713
|
-
const fresh = existing.accessToken === input.token && typeof existing.expiresAt === "number" && existing.expiresAt > input.now + REFRESH_SKEW_MS;
|
|
4714
|
-
if (fresh) return { action: "skip", reason: "current" };
|
|
4715
|
-
return { action: "write", contents };
|
|
4716
|
-
}
|
|
4717
|
-
async function readRaw(path4) {
|
|
4718
|
-
try {
|
|
4719
|
-
return await readFile(path4, "utf8");
|
|
4720
|
-
} catch {
|
|
4721
|
-
return null;
|
|
4722
|
-
}
|
|
4723
|
-
}
|
|
4724
|
-
async function ensureClaudeCredentials(env = process.env) {
|
|
4725
|
-
try {
|
|
4726
|
-
const path4 = claudeCredentialsPath();
|
|
4727
|
-
const plan = planCredentialsWrite({
|
|
4728
|
-
isCloud: isConveyorCloudEnv(env),
|
|
4729
|
-
token: env.CLAUDE_CODE_OAUTH_TOKEN,
|
|
4730
|
-
existingRaw: await readRaw(path4),
|
|
4731
|
-
now: Date.now()
|
|
4732
|
-
});
|
|
4733
|
-
if (plan.action === "skip") return;
|
|
4734
|
-
await mkdir3(claudeConfigHome(), { recursive: true });
|
|
4735
|
-
await writeFile4(path4, plan.contents, { encoding: "utf8", mode: 384 });
|
|
4736
|
-
await chmod2(path4, 384).catch(() => {
|
|
4737
|
-
});
|
|
4738
|
-
} catch (err) {
|
|
4739
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
4740
|
-
process.stderr.write(`[conveyor-agent] claude credentials sync failed: ${message}
|
|
4741
|
-
`);
|
|
4742
|
-
}
|
|
4743
|
-
}
|
|
4744
|
-
function claudeJsonPath() {
|
|
4745
|
-
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
4746
|
-
return configDir ? join4(configDir, ".claude.json") : join4(homedir2(), ".claude.json");
|
|
4747
|
-
}
|
|
4748
|
-
function asRecord(value) {
|
|
4749
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
4750
|
-
}
|
|
4751
|
-
function parseClaudeJson(existingRaw) {
|
|
4752
|
-
if (!existingRaw || existingRaw.trim() === "") return {};
|
|
4753
|
-
try {
|
|
4754
|
-
return asRecord(JSON.parse(existingRaw));
|
|
4755
|
-
} catch {
|
|
4756
|
-
return {};
|
|
4757
|
-
}
|
|
4758
|
-
}
|
|
4759
|
-
function seedWorkspaceTrust(config, trustCwd) {
|
|
4760
|
-
const projects = asRecord(config.projects);
|
|
4761
|
-
const entry = asRecord(projects[trustCwd]);
|
|
4762
|
-
if (entry.hasTrustDialogAccepted === true) return false;
|
|
4763
|
-
entry.hasTrustDialogAccepted = true;
|
|
4764
|
-
projects[trustCwd] = entry;
|
|
4765
|
-
config.projects = projects;
|
|
4766
|
-
return true;
|
|
4767
|
-
}
|
|
4768
|
-
function planClaudeJsonSeed(existingRaw, trustCwd) {
|
|
4769
|
-
const config = parseClaudeJson(existingRaw);
|
|
4770
|
-
const isFresh = Object.keys(config).length === 0;
|
|
4771
|
-
let changed = false;
|
|
4772
|
-
if (config.hasCompletedOnboarding !== true) {
|
|
4773
|
-
config.hasCompletedOnboarding = true;
|
|
4774
|
-
changed = true;
|
|
4775
|
-
}
|
|
4776
|
-
if (config.bypassPermissionsModeAccepted !== true) {
|
|
4777
|
-
config.bypassPermissionsModeAccepted = true;
|
|
4778
|
-
changed = true;
|
|
4779
|
-
}
|
|
4780
|
-
if (isFresh && typeof config.theme !== "string") {
|
|
4781
|
-
config.theme = "dark";
|
|
4782
|
-
changed = true;
|
|
4783
|
-
}
|
|
4784
|
-
if (trustCwd && seedWorkspaceTrust(config, trustCwd)) {
|
|
4785
|
-
changed = true;
|
|
4786
|
-
}
|
|
4787
|
-
return changed ? JSON.stringify(config) : null;
|
|
4788
|
-
}
|
|
4789
|
-
async function ensureClaudeOnboarding(env = process.env, trustCwd) {
|
|
4790
|
-
try {
|
|
4791
|
-
if (!isConveyorCloudEnv(env)) return;
|
|
4792
|
-
const path4 = claudeJsonPath();
|
|
4793
|
-
const contents = planClaudeJsonSeed(await readRaw(path4), trustCwd);
|
|
4794
|
-
if (contents === null) return;
|
|
4795
|
-
await writeFile4(path4, contents, "utf8");
|
|
4796
|
-
const verify = await readRaw(path4);
|
|
4797
|
-
if (verify === contents) {
|
|
4798
|
-
process.stderr.write(
|
|
4799
|
-
`[conveyor-agent] claude onboarding seeded${trustCwd ? ` (trust: ${trustCwd})` : ""}
|
|
4800
|
-
`
|
|
4801
|
-
);
|
|
4802
|
-
} else {
|
|
4803
|
-
process.stderr.write(
|
|
4804
|
-
`[conveyor-agent] claude onboarding seed read-back MISMATCH at ${path4}: wrote ${contents.length}B, read ${verify?.length ?? 0}B \u2014 CLI may see stale config and park at a startup dialog
|
|
4805
|
-
`
|
|
4806
|
-
);
|
|
4807
|
-
}
|
|
4808
|
-
} catch (err) {
|
|
4809
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
4810
|
-
process.stderr.write(`[conveyor-agent] claude onboarding seed failed: ${message}
|
|
4811
|
-
`);
|
|
4812
|
-
}
|
|
4813
|
-
}
|
|
4814
|
-
async function removeConveyorCredentials(env = process.env) {
|
|
4815
|
-
try {
|
|
4816
|
-
if (!isConveyorCloudEnv(env)) return;
|
|
4817
|
-
const path4 = claudeCredentialsPath();
|
|
4818
|
-
const existing = parseClaudeAiOauth(await readRaw(path4));
|
|
4819
|
-
if (existing && typeof existing.refreshToken === "string" && existing.refreshToken.length > 0) {
|
|
4820
|
-
return;
|
|
4821
|
-
}
|
|
4822
|
-
await rm5(path4, { force: true });
|
|
4823
|
-
} catch (err) {
|
|
4824
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
4825
|
-
process.stderr.write(`[conveyor-agent] claude credentials removal failed: ${message}
|
|
4826
|
-
`);
|
|
4827
|
-
}
|
|
4828
|
-
}
|
|
4829
|
-
|
|
4830
4914
|
// src/harness/pty/index.ts
|
|
4831
4915
|
var ENDED_GRACE_MS = 4e3;
|
|
4832
|
-
function fingerprintOf(options) {
|
|
4833
|
-
return spawnOptionsFingerprint({
|
|
4834
|
-
model: options.model,
|
|
4835
|
-
permissionMode: options.permissionMode,
|
|
4836
|
-
...options.appendSystemPrompt ? { appendSystemPrompt: options.appendSystemPrompt } : {},
|
|
4837
|
-
cwd: options.cwd
|
|
4838
|
-
});
|
|
4839
|
-
}
|
|
4840
4916
|
var PtyHarness = class {
|
|
4841
4917
|
/**
|
|
4842
4918
|
* `bridge` relays raw terminal I/O to/from the S2 server (and on to the S5
|
|
4843
4919
|
* terminal). It is undefined for SDK-only callers and PTY runs that never
|
|
4844
4920
|
* attach a relay; the session simply discards stdout in that case.
|
|
4845
4921
|
*/
|
|
4846
|
-
constructor(bridge) {
|
|
4922
|
+
constructor(bridge, adapter = new ClaudeTuiAdapter()) {
|
|
4847
4923
|
this.bridge = bridge;
|
|
4924
|
+
this.adapter = adapter;
|
|
4848
4925
|
}
|
|
4849
4926
|
bridge;
|
|
4927
|
+
adapter;
|
|
4928
|
+
/** Fingerprint of the spawn-time options a reused process cannot change. */
|
|
4929
|
+
fingerprintOf(options) {
|
|
4930
|
+
return this.adapter.spawnFingerprint({
|
|
4931
|
+
model: options.model,
|
|
4932
|
+
permissionMode: options.permissionMode,
|
|
4933
|
+
...options.appendSystemPrompt ? { appendSystemPrompt: options.appendSystemPrompt } : {},
|
|
4934
|
+
cwd: options.cwd
|
|
4935
|
+
});
|
|
4936
|
+
}
|
|
4850
4937
|
/** The session currently streaming events, if any — repaint target. */
|
|
4851
4938
|
activeSession = null;
|
|
4852
4939
|
/** A completed-but-alive session kept for the next turn (keep-alive). */
|
|
@@ -4865,7 +4952,7 @@ var PtyHarness = class {
|
|
|
4865
4952
|
}
|
|
4866
4953
|
async *executeQuery(opts) {
|
|
4867
4954
|
const want = opts.resume ?? opts.options.resume;
|
|
4868
|
-
const fingerprint = fingerprintOf(opts.options);
|
|
4955
|
+
const fingerprint = this.fingerprintOf(opts.options);
|
|
4869
4956
|
let session;
|
|
4870
4957
|
if (this.parked?.canReuse(want, fingerprint)) {
|
|
4871
4958
|
session = this.parked;
|
|
@@ -4879,9 +4966,8 @@ var PtyHarness = class {
|
|
|
4879
4966
|
this.cancelEndedTimer();
|
|
4880
4967
|
await stale.teardown();
|
|
4881
4968
|
}
|
|
4882
|
-
session = new PtySession(opts.prompt, opts.options, want, this.bridge);
|
|
4883
|
-
await
|
|
4884
|
-
await ensureClaudeOnboarding(process.env, opts.options.cwd);
|
|
4969
|
+
session = new PtySession(opts.prompt, opts.options, want, this.bridge, this.adapter);
|
|
4970
|
+
await this.adapter.prepareEnvironment({ cwd: opts.options.cwd });
|
|
4885
4971
|
session.onExit(() => this.handleSessionExit(session));
|
|
4886
4972
|
await session.start();
|
|
4887
4973
|
}
|
|
@@ -10758,8 +10844,13 @@ export {
|
|
|
10758
10844
|
applyBootstrapToEnv,
|
|
10759
10845
|
AgentConnection,
|
|
10760
10846
|
DEFAULT_SONNET_MODEL,
|
|
10847
|
+
TUI_KINDS,
|
|
10761
10848
|
DEFAULT_LIFECYCLE_CONFIG,
|
|
10762
10849
|
Lifecycle,
|
|
10850
|
+
cleanTerminalOutput,
|
|
10851
|
+
inheritedEnv,
|
|
10852
|
+
buildPromptBytes,
|
|
10853
|
+
ClaudeTuiAdapter,
|
|
10763
10854
|
PtyHarness,
|
|
10764
10855
|
createServiceLogger,
|
|
10765
10856
|
hasUncommittedChanges,
|
|
@@ -10787,4 +10878,4 @@ export {
|
|
|
10787
10878
|
runStartCommand,
|
|
10788
10879
|
unshallowRepo
|
|
10789
10880
|
};
|
|
10790
|
-
//# sourceMappingURL=chunk-
|
|
10881
|
+
//# sourceMappingURL=chunk-CFELRV35.js.map
|