@codexhost/cli-darwin-x64 0.6.1 → 0.7.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/README.md +1 -1
- package/THIRD_PARTY_NOTICES.txt +4 -0
- package/app/codexhost-distribution.json +1 -1
- package/app/desktop-controller.mjs +3 -1
- package/app/host-runtime.mjs +1000 -472
- package/app/plugins/antigravity/plugin.mjs +54 -205
- package/app/plugins/claude-code/plugin.mjs +223 -49
- package/app/plugins/codebuddy/assets/icon.svg +1 -0
- package/app/plugins/codebuddy/manifest.json +13 -0
- package/app/plugins/codebuddy/plugin.mjs +23045 -0
- package/app/plugins/cursor-cli/assets/icon.svg +1 -0
- package/app/plugins/cursor-cli/manifest.json +13 -0
- package/app/plugins/cursor-cli/plugin.mjs +22579 -0
- package/app/plugins/deepseek-harness/plugin.mjs +7695 -10516
- package/app/plugins/enabled.json +3 -1
- package/app/plugins/grok/plugin.mjs +921 -74
- package/app/plugins/kiro-cli/plugin.mjs +29 -6
- package/app/plugins/pi/plugin.mjs +0 -12
- package/app/renderer-extension.js +746 -344
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +0 -0
- package/licenses/Agent-Client-Protocol-SDK-LICENSE.txt +191 -0
- package/package.json +1 -1
package/app/host-runtime.mjs
CHANGED
|
@@ -2278,7 +2278,7 @@ var require_websocket = __commonJS({
|
|
|
2278
2278
|
var http = __require("http");
|
|
2279
2279
|
var net5 = __require("net");
|
|
2280
2280
|
var tls = __require("tls");
|
|
2281
|
-
var { randomBytes: randomBytes3, createHash:
|
|
2281
|
+
var { randomBytes: randomBytes3, createHash: createHash9 } = __require("crypto");
|
|
2282
2282
|
var { Duplex: Duplex2, Readable } = __require("stream");
|
|
2283
2283
|
var { URL: URL2 } = __require("url");
|
|
2284
2284
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -2946,7 +2946,7 @@ var require_websocket = __commonJS({
|
|
|
2946
2946
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
2947
2947
|
return;
|
|
2948
2948
|
}
|
|
2949
|
-
const digest2 =
|
|
2949
|
+
const digest2 = createHash9("sha1").update(key + GUID).digest("base64");
|
|
2950
2950
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
2951
2951
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
2952
2952
|
return;
|
|
@@ -3315,7 +3315,7 @@ var require_websocket_server = __commonJS({
|
|
|
3315
3315
|
var EventEmitter = __require("events");
|
|
3316
3316
|
var http = __require("http");
|
|
3317
3317
|
var { Duplex: Duplex2 } = __require("stream");
|
|
3318
|
-
var { createHash:
|
|
3318
|
+
var { createHash: createHash9 } = __require("crypto");
|
|
3319
3319
|
var extension2 = require_extension();
|
|
3320
3320
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
3321
3321
|
var subprotocol2 = require_subprotocol();
|
|
@@ -3622,7 +3622,7 @@ var require_websocket_server = __commonJS({
|
|
|
3622
3622
|
);
|
|
3623
3623
|
}
|
|
3624
3624
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
3625
|
-
const digest2 =
|
|
3625
|
+
const digest2 = createHash9("sha1").update(key + GUID).digest("base64");
|
|
3626
3626
|
const headers = [
|
|
3627
3627
|
"HTTP/1.1 101 Switching Protocols",
|
|
3628
3628
|
"Upgrade: websocket",
|
|
@@ -3709,6 +3709,92 @@ var require_websocket_server = __commonJS({
|
|
|
3709
3709
|
}
|
|
3710
3710
|
});
|
|
3711
3711
|
|
|
3712
|
+
// packages/host-runtime/src/delegation-cli-help.ts
|
|
3713
|
+
var COMMAND_HELP = {
|
|
3714
|
+
"harness list": `codexhost harness list [--format json|compact]
|
|
3715
|
+
List Harnesses available in the active Runtime.`,
|
|
3716
|
+
"harness inspect": `codexhost harness inspect <harness> [--cwd <path>] [--refresh true|false] [--format json|compact]
|
|
3717
|
+
Read available Models, native defaults, Thinking options, and configuration capabilities.
|
|
3718
|
+
Use the returned Model and Thinking IDs for explicit selections.`,
|
|
3719
|
+
"delegate start": `codexhost delegate start --harness <id> --task <text> [--cwd <path>] [--model <opaque-ref>] [--thinking <option-id>] [--parent-thread <thread>] [--request-id <id>] [--format json|compact]
|
|
3720
|
+
Create an independent child Thread, submit the task, and return immediately.
|
|
3721
|
+
Omit --model and --thinking to use the Harness native defaults.
|
|
3722
|
+
--cwd overrides the child workspace. Otherwise use the resolved parent Thread workspace, then the Host Runtime process cwd.
|
|
3723
|
+
--parent-thread overrides caller inference. PARENT_THREAD_AMBIGUOUS requires an explicit parent.
|
|
3724
|
+
Reuse --request-id for an idempotent retry. Identical recent parent/target/task/configuration requests are also deduplicated briefly.
|
|
3725
|
+
The response confirms cwd and parent. Use its Thread reference with thread read, wait, send, or cancel.`,
|
|
3726
|
+
"thread send": `codexhost thread send <thread> --message <text> [--format json|compact]
|
|
3727
|
+
Start a new Turn in an idle writable Thread and return immediately.
|
|
3728
|
+
THREAD_BUSY means the current Turn is still active: wait or cancel before sending. Messages are not queued.`,
|
|
3729
|
+
"thread cancel": `codexhost thread cancel <thread> [--format json|compact]
|
|
3730
|
+
Request cancellation of the active Turn while preserving the Thread and history.
|
|
3731
|
+
cancelled=true (compact: cancelRequested=true) means the cancellation request was accepted. Read or wait to confirm the terminal state. An idle Thread returns false.`,
|
|
3732
|
+
"thread read": `codexhost thread read <thread> [--view result|messages] [--cursor <cursor>] [--limit <n>] [--format json|compact]
|
|
3733
|
+
Read immediately without starting a Turn. The default result view reports the latest Turn's status and result.
|
|
3734
|
+
The messages view pages visible user/Agent messages, oldest first. Default limit 25, maximum 100; --cursor and --limit require --view messages.
|
|
3735
|
+
hasMore describes remaining messages now. Save nextCursor for later incremental reads even when hasMore=false.
|
|
3736
|
+
Compact messages output contains only the message page and status; compact result output includes the latest nonempty progress while running.
|
|
3737
|
+
Full JSON retains the complete snapshot. Tool calls/output, file activity, and reasoning are not included in either format.`,
|
|
3738
|
+
"thread wait": `codexhost thread wait <thread> [--timeout-ms <n>] [--view result|messages] [--cursor <cursor>] [--limit <n>] [--format json|compact]
|
|
3739
|
+
Wait until the Thread is terminal or the timeout expires (default 30000 ms), then return the same snapshot as thread read plus timedOut.
|
|
3740
|
+
timedOut=true is a running checkpoint: the child keeps running. The response already includes the result when available; another read is unnecessary unless more information is needed.
|
|
3741
|
+
Message pagination uses --view messages, default limit 25, maximum 100. hasMore is for current pages; nextCursor also supports future incremental reads.`,
|
|
3742
|
+
"thread list": `codexhost thread list [--cwd <path>] [--parent <thread>] [--limit <n>] [--cursor <cursor>] [--sort created-asc|created-desc|updated-asc|updated-desc|recency-asc|recency-desc] [--format json|compact]
|
|
3743
|
+
Find existing Threads by workspace, or use --parent to list a Thread's delegated children.
|
|
3744
|
+
Workspace listing defaults to the caller process cwd. Default limit 25 (maximum 100), sorted created-desc.
|
|
3745
|
+
--parent uses Delegation relationships. A null nextCursor ends the list.
|
|
3746
|
+
Compact output keeps task links, Harness, status, title, and workspace.`
|
|
3747
|
+
};
|
|
3748
|
+
var COMMON_HELP = `Thread references accept a bare ID or codex://threads/<id>.
|
|
3749
|
+
--format json is the compatible full JSON output (default); --format compact returns concise JSON using task links instead of internal IDs.
|
|
3750
|
+
Success is written to stdout; errors {"error":{"code":"...","message":"...","details":{...}}} go to stderr with exit code 1. Exit code 0 means the command succeeded, not that the delegated task succeeded.
|
|
3751
|
+
read/wait are non-consuming. Native Codex callers need local Runtime access; RUNTIME_UNREACHABLE requires the Host-provided environment and a sandbox that permits that connection.`;
|
|
3752
|
+
var DELEGATION_HELP = `usage:
|
|
3753
|
+
codexhost harness list
|
|
3754
|
+
codexhost harness inspect <harness>
|
|
3755
|
+
codexhost delegate start --harness <id> --task <text>
|
|
3756
|
+
codexhost thread send <thread> --message <text>
|
|
3757
|
+
codexhost thread cancel <thread>
|
|
3758
|
+
codexhost thread read <thread>
|
|
3759
|
+
codexhost thread wait <thread>
|
|
3760
|
+
codexhost thread list
|
|
3761
|
+
|
|
3762
|
+
Use <command> --help for its options. Use harness list to discover targets.
|
|
3763
|
+
${COMMON_HELP}
|
|
3764
|
+
`;
|
|
3765
|
+
function hasHelpOption(arguments_2) {
|
|
3766
|
+
for (let index = 0; index < arguments_2.length; index += 1) {
|
|
3767
|
+
const argument = arguments_2[index];
|
|
3768
|
+
if (argument === "--help" || argument === "-h") return true;
|
|
3769
|
+
if (argument?.startsWith("--")) index += 1;
|
|
3770
|
+
}
|
|
3771
|
+
return false;
|
|
3772
|
+
}
|
|
3773
|
+
function delegationCliHelp(arguments_2) {
|
|
3774
|
+
const [group, command, ...rest] = arguments_2;
|
|
3775
|
+
if (!group || group === "--help" || group === "-h") return DELEGATION_HELP;
|
|
3776
|
+
if (!command || command === "--help" || command === "-h" || command === "help") {
|
|
3777
|
+
if (group === "delegate") return DELEGATION_HELP;
|
|
3778
|
+
if (group === "harness" || group === "thread") {
|
|
3779
|
+
const usages = Object.entries(COMMAND_HELP).filter(([name]) => name.startsWith(`${group} `)).map(([, help]) => help.split("\n")[0]);
|
|
3780
|
+
return `${usages.join("\n")}
|
|
3781
|
+
|
|
3782
|
+
${COMMON_HELP}
|
|
3783
|
+
`;
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
if (hasHelpOption(rest)) {
|
|
3787
|
+
const name = `${group} ${command}`;
|
|
3788
|
+
if (Object.hasOwn(COMMAND_HELP, name)) {
|
|
3789
|
+
return `${COMMAND_HELP[name]}
|
|
3790
|
+
|
|
3791
|
+
${COMMON_HELP}
|
|
3792
|
+
`;
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
return void 0;
|
|
3796
|
+
}
|
|
3797
|
+
|
|
3712
3798
|
// packages/host-runtime/src/delegation-types.ts
|
|
3713
3799
|
var DELEGATION_RUNTIME_ENDPOINT_ENV = "CODEXHOST_RUNTIME_ENDPOINT";
|
|
3714
3800
|
var DELEGATION_RUNTIME_TOKEN_ENV = "CODEXHOST_RUNTIME_TOKEN";
|
|
@@ -3725,6 +3811,114 @@ var DelegationControlError = class extends Error {
|
|
|
3725
3811
|
details;
|
|
3726
3812
|
};
|
|
3727
3813
|
|
|
3814
|
+
// packages/host-runtime/src/delegation-cli-output.ts
|
|
3815
|
+
function threadLink(threadId3) {
|
|
3816
|
+
return `codex://threads/${threadId3}`;
|
|
3817
|
+
}
|
|
3818
|
+
function inspectOutput({ harnessId, inspection }) {
|
|
3819
|
+
if (inspection.status !== "ready") return { harnessId, ...inspection };
|
|
3820
|
+
const { catalog } = inspection;
|
|
3821
|
+
return {
|
|
3822
|
+
harnessId,
|
|
3823
|
+
status: inspection.status,
|
|
3824
|
+
models: catalog.models.map(({ ref, label, supportedThinkingOptionIds }) => ({
|
|
3825
|
+
id: ref.id,
|
|
3826
|
+
label,
|
|
3827
|
+
...supportedThinkingOptionIds ? { thinking: supportedThinkingOptionIds } : {}
|
|
3828
|
+
})),
|
|
3829
|
+
...catalog.defaultModel ? { defaultModel: catalog.defaultModel.id } : {},
|
|
3830
|
+
thinkingOptions: catalog.thinkingOptions,
|
|
3831
|
+
...catalog.defaultThinkingOptionId ? { defaultThinkingOptionId: catalog.defaultThinkingOptionId } : {},
|
|
3832
|
+
capabilities: inspection.capabilities
|
|
3833
|
+
};
|
|
3834
|
+
}
|
|
3835
|
+
function snapshotOutput(snapshot, view) {
|
|
3836
|
+
const common = {
|
|
3837
|
+
thread: threadLink(snapshot.threadId),
|
|
3838
|
+
harnessId: snapshot.harnessId,
|
|
3839
|
+
status: snapshot.status,
|
|
3840
|
+
...snapshot.timedOut !== void 0 ? { timedOut: snapshot.timedOut } : {}
|
|
3841
|
+
};
|
|
3842
|
+
if (view === "messages") {
|
|
3843
|
+
if (typeof snapshot.hasMore !== "boolean") {
|
|
3844
|
+
throw new DelegationControlError(
|
|
3845
|
+
"INTERNAL_ERROR",
|
|
3846
|
+
"Compact message pagination requires an updated Host Runtime; use --format json with this Runtime."
|
|
3847
|
+
);
|
|
3848
|
+
}
|
|
3849
|
+
return {
|
|
3850
|
+
...common,
|
|
3851
|
+
messages: (snapshot.messages ?? []).map(({ role, phase, text }) => ({
|
|
3852
|
+
role,
|
|
3853
|
+
...phase ? { phase } : {},
|
|
3854
|
+
text
|
|
3855
|
+
})),
|
|
3856
|
+
hasMore: snapshot.hasMore,
|
|
3857
|
+
nextCursor: snapshot.nextCursor,
|
|
3858
|
+
...snapshot.result.message ? { error: snapshot.result.message } : {}
|
|
3859
|
+
};
|
|
3860
|
+
}
|
|
3861
|
+
const progress = snapshot.progress.filter(({ text }) => text.trim()).at(-1)?.text;
|
|
3862
|
+
return {
|
|
3863
|
+
...common,
|
|
3864
|
+
result: snapshot.result,
|
|
3865
|
+
...snapshot.status === "running" && progress ? { progress } : {}
|
|
3866
|
+
};
|
|
3867
|
+
}
|
|
3868
|
+
function compactDelegationOutput(command, body, view = "result") {
|
|
3869
|
+
switch (command) {
|
|
3870
|
+
case "harness list":
|
|
3871
|
+
return body;
|
|
3872
|
+
case "harness inspect":
|
|
3873
|
+
return inspectOutput(body);
|
|
3874
|
+
case "delegate start": {
|
|
3875
|
+
const result = body;
|
|
3876
|
+
const effective = result.configuration?.effective;
|
|
3877
|
+
return {
|
|
3878
|
+
thread: result.deepLink,
|
|
3879
|
+
harnessId: result.harnessId,
|
|
3880
|
+
status: result.status,
|
|
3881
|
+
...result.cwd ? { cwd: result.cwd } : {},
|
|
3882
|
+
...result.parentThreadId ? { parent: threadLink(result.parentThreadId) } : {},
|
|
3883
|
+
...effective?.resolvedModelLabel ? { model: effective.resolvedModelLabel } : {},
|
|
3884
|
+
...effective?.effectiveThinkingOptionId ? { thinking: effective.effectiveThinkingOptionId } : {}
|
|
3885
|
+
};
|
|
3886
|
+
}
|
|
3887
|
+
case "thread send": {
|
|
3888
|
+
const result = body;
|
|
3889
|
+
return {
|
|
3890
|
+
thread: threadLink(result.threadId),
|
|
3891
|
+
harnessId: result.harnessId,
|
|
3892
|
+
status: result.status
|
|
3893
|
+
};
|
|
3894
|
+
}
|
|
3895
|
+
case "thread cancel": {
|
|
3896
|
+
const result = body;
|
|
3897
|
+
return {
|
|
3898
|
+
thread: threadLink(result.threadId),
|
|
3899
|
+
harnessId: result.harnessId,
|
|
3900
|
+
cancelRequested: result.cancelled
|
|
3901
|
+
};
|
|
3902
|
+
}
|
|
3903
|
+
case "thread read":
|
|
3904
|
+
case "thread wait":
|
|
3905
|
+
return snapshotOutput(body, view);
|
|
3906
|
+
case "thread list": {
|
|
3907
|
+
const result = body;
|
|
3908
|
+
return {
|
|
3909
|
+
threads: result.threads.map(({ deepLink, harnessId, status, title, cwd }) => ({
|
|
3910
|
+
thread: deepLink,
|
|
3911
|
+
harnessId,
|
|
3912
|
+
status,
|
|
3913
|
+
...title ? { title } : {},
|
|
3914
|
+
...cwd ? { cwd } : {}
|
|
3915
|
+
})),
|
|
3916
|
+
nextCursor: result.nextCursor
|
|
3917
|
+
};
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
|
|
3728
3922
|
// packages/host-runtime/src/delegation-cli.ts
|
|
3729
3923
|
var DEFAULT_WAIT_TIMEOUT_MS = 3e4;
|
|
3730
3924
|
var DEFAULT_LIMIT = 25;
|
|
@@ -3771,44 +3965,12 @@ function value(parsed, name) {
|
|
|
3771
3965
|
return parsed.options.get(name);
|
|
3772
3966
|
}
|
|
3773
3967
|
function rejectUnknown(parsed, allowed) {
|
|
3774
|
-
const known = new Set(allowed);
|
|
3968
|
+
const known = /* @__PURE__ */ new Set([...allowed, "--format"]);
|
|
3775
3969
|
for (const name of parsed.options.keys()) {
|
|
3776
3970
|
if (!known.has(name))
|
|
3777
3971
|
throw new DelegationControlError("INVALID_ARGUMENT", `Unknown option '${name}'`);
|
|
3778
3972
|
}
|
|
3779
3973
|
}
|
|
3780
|
-
var DELEGATION_HELP = `usage:
|
|
3781
|
-
codexhost harness inspect <harness> [--cwd <path>] [--refresh true|false]
|
|
3782
|
-
codexhost delegate start --harness <id> --task <text> [--model <opaque-ref>] [--thinking <option-id>] [--parent-thread <thread>] [--request-id <id>]
|
|
3783
|
-
codexhost thread send <thread> --message <text>
|
|
3784
|
-
codexhost thread cancel <thread>
|
|
3785
|
-
codexhost thread read <thread> [--view result|messages] [--cursor <cursor>] [--limit <n>]
|
|
3786
|
-
codexhost thread wait <thread> [--timeout-ms <n>] [--view result|messages] [--cursor <cursor>] [--limit <n>]
|
|
3787
|
-
codexhost thread list [--cwd <path>] [--parent <thread>] [--limit <n>] [--cursor <cursor>] [--sort created-asc|created-desc|updated-asc|updated-desc|recency-asc|recency-desc]
|
|
3788
|
-
|
|
3789
|
-
Thread identifiers accept a bare ID or codex://threads/<id>. Output is JSON by default.
|
|
3790
|
-
harness inspect returns the target Model catalog, default Model, Thinking options, and configuration capabilities without creating a Thread. Use opaque IDs exactly as returned.
|
|
3791
|
-
delegate start requires --harness and --task, creates and submits the child Thread, then returns immediately. --model and --thinking select values returned by harness inspect. Omit either option to preserve that target's current default behavior. --parent-thread overrides caller inference. Reuse --request-id for idempotent retries; without it, identical recent parent/target/task/configuration requests are deduplicated briefly.
|
|
3792
|
-
Successful start fields: delegationId, threadId, turnId, harnessId, deepLink, status, next.read, next.wait.
|
|
3793
|
-
thread send starts a new Turn in an idle writable Thread and returns immediately. It fails with THREAD_BUSY instead of queueing or starting a concurrent Turn.
|
|
3794
|
-
thread cancel requests cancellation of the current Turn while preserving the Thread. An idle Thread returns cancelled=false.
|
|
3795
|
-
thread read is non-blocking. Its default result view returns threadId, harnessId, status, latest turn, visible progress, result.availability/result.text, and nextCursor.
|
|
3796
|
-
thread read --view messages additionally returns paginated user/Agent-visible messages. The default page is 25 and --limit is capped at 100; --cursor and --limit require the messages view. Tool calls, tool output, file activity, reasoning summaries, hidden reasoning, and private Harness transcripts are never returned.
|
|
3797
|
-
thread wait defaults to 30000 ms and waits only until the Thread reaches a terminal state or the bounded timeout expires. A timeout is a successful running checkpoint with timedOut=true; the child keeps running.
|
|
3798
|
-
thread list defaults to the caller cwd, limit 25, created-desc; limit is capped at 100. --parent uses Delegation lineage, not Codex Subagent relationships.
|
|
3799
|
-
read and wait are non-consuming: they do not start a Turn, send input, wake an Agent, mark messages read, or inject a result into the parent Session.
|
|
3800
|
-
Native Codex as caller requires a session sandbox that permits local Runtime connections; otherwise RUNTIME_UNREACHABLE is returned. Native Codex as a target uses brokered official requests and is unaffected.
|
|
3801
|
-
|
|
3802
|
-
Errors are JSON: {"error":{"code":"...","message":"...","details":{...}}}.
|
|
3803
|
-
INVALID_ARGUMENT: fix the named argument or incompatible option combination.
|
|
3804
|
-
HARNESS_NOT_FOUND: choose a Harness ID listed in error.details.validHarnessIds.
|
|
3805
|
-
THREAD_NOT_FOUND: verify the bare ID or codex:// deep link.
|
|
3806
|
-
THREAD_BUSY: wait for or cancel the active Turn before sending another message.
|
|
3807
|
-
PARENT_THREAD_AMBIGUOUS: pass --parent-thread explicitly.
|
|
3808
|
-
RUNTIME_UNREACHABLE: run inside the Host-provided environment and, for native Codex, allow local Runtime connections; codexhost never falls back to PATH or another Runtime.
|
|
3809
|
-
DELEGATION_FAILED: the target Session or initial task delivery failed and no successful child was published.
|
|
3810
|
-
INTERNAL_ERROR: retry after checking the Host Runtime diagnostics.
|
|
3811
|
-
`;
|
|
3812
3974
|
async function requestRuntime(input) {
|
|
3813
3975
|
const endpoint = input.environment[DELEGATION_RUNTIME_ENDPOINT_ENV];
|
|
3814
3976
|
const token = input.environment[DELEGATION_RUNTIME_TOKEN_ENV];
|
|
@@ -3854,12 +4016,37 @@ async function runDelegationCli(input) {
|
|
|
3854
4016
|
const environment = input.environment ?? process.env;
|
|
3855
4017
|
try {
|
|
3856
4018
|
const [group, command, ...rest] = input.arguments;
|
|
3857
|
-
|
|
3858
|
-
|
|
4019
|
+
const help = delegationCliHelp(input.arguments);
|
|
4020
|
+
if (help !== void 0) {
|
|
4021
|
+
output.write(help);
|
|
4022
|
+
return 0;
|
|
4023
|
+
}
|
|
4024
|
+
const parsed = options(rest);
|
|
4025
|
+
const format = value(parsed, "--format") ?? "json";
|
|
4026
|
+
if (format !== "json" && format !== "compact") {
|
|
4027
|
+
throw new DelegationControlError("INVALID_ARGUMENT", "--format must be json or compact");
|
|
4028
|
+
}
|
|
4029
|
+
const writeResult = (name, body, view = "result") => writeJson(output, format === "json" ? body : compactDelegationOutput(name, body, view));
|
|
4030
|
+
if (group === "harness" && command === "list") {
|
|
4031
|
+
rejectUnknown(parsed, []);
|
|
4032
|
+
if (parsed.positionals.length > 0) {
|
|
4033
|
+
throw new DelegationControlError(
|
|
4034
|
+
"INVALID_ARGUMENT",
|
|
4035
|
+
"harness list accepts no positional arguments"
|
|
4036
|
+
);
|
|
4037
|
+
}
|
|
4038
|
+
writeResult(
|
|
4039
|
+
"harness list",
|
|
4040
|
+
await requestRuntime({
|
|
4041
|
+
environment,
|
|
4042
|
+
path: "/v1/harness/list",
|
|
4043
|
+
body: {},
|
|
4044
|
+
...input.fetchImpl ? { fetchImpl: input.fetchImpl } : {}
|
|
4045
|
+
})
|
|
4046
|
+
);
|
|
3859
4047
|
return 0;
|
|
3860
4048
|
}
|
|
3861
4049
|
if (group === "harness" && command === "inspect") {
|
|
3862
|
-
const parsed = options(rest);
|
|
3863
4050
|
rejectUnknown(parsed, ["--cwd", "--refresh"]);
|
|
3864
4051
|
if (parsed.positionals.length !== 1) {
|
|
3865
4052
|
throw new DelegationControlError(
|
|
@@ -3875,8 +4062,8 @@ async function runDelegationCli(input) {
|
|
|
3875
4062
|
if (refresh !== void 0 && refresh !== "true" && refresh !== "false") {
|
|
3876
4063
|
throw new DelegationControlError("INVALID_ARGUMENT", "--refresh must be true or false");
|
|
3877
4064
|
}
|
|
3878
|
-
|
|
3879
|
-
|
|
4065
|
+
writeResult(
|
|
4066
|
+
"harness inspect",
|
|
3880
4067
|
await requestRuntime({
|
|
3881
4068
|
environment,
|
|
3882
4069
|
path: "/v1/harness/inspect",
|
|
@@ -3891,10 +4078,10 @@ async function runDelegationCli(input) {
|
|
|
3891
4078
|
return 0;
|
|
3892
4079
|
}
|
|
3893
4080
|
if (group === "delegate" && command === "start") {
|
|
3894
|
-
const parsed = options(rest);
|
|
3895
4081
|
rejectUnknown(parsed, [
|
|
3896
4082
|
"--harness",
|
|
3897
4083
|
"--task",
|
|
4084
|
+
"--cwd",
|
|
3898
4085
|
"--model",
|
|
3899
4086
|
"--thinking",
|
|
3900
4087
|
"--parent-thread",
|
|
@@ -3910,15 +4097,15 @@ async function runDelegationCli(input) {
|
|
|
3910
4097
|
if (!harnessId || !task)
|
|
3911
4098
|
throw new DelegationControlError("INVALID_ARGUMENT", "--harness and --task are required");
|
|
3912
4099
|
const parentThread = value(parsed, "--parent-thread") ?? environment[DELEGATION_THREAD_ID_ENV];
|
|
3913
|
-
|
|
3914
|
-
|
|
4100
|
+
writeResult(
|
|
4101
|
+
"delegate start",
|
|
3915
4102
|
await requestRuntime({
|
|
3916
4103
|
environment,
|
|
3917
4104
|
path: "/v1/delegate/start",
|
|
3918
4105
|
body: {
|
|
3919
4106
|
harnessId,
|
|
3920
4107
|
task,
|
|
3921
|
-
cwd:
|
|
4108
|
+
...value(parsed, "--cwd") ? { cwd: value(parsed, "--cwd") } : {},
|
|
3922
4109
|
...value(parsed, "--model") ? { model: { id: value(parsed, "--model") } } : {},
|
|
3923
4110
|
...value(parsed, "--thinking") ? { thinkingOptionId: value(parsed, "--thinking") } : {},
|
|
3924
4111
|
...parentThread ? { parentThreadId: normalizeThreadId(parentThread) } : {},
|
|
@@ -3930,7 +4117,6 @@ async function runDelegationCli(input) {
|
|
|
3930
4117
|
return 0;
|
|
3931
4118
|
}
|
|
3932
4119
|
if (group === "thread" && command === "send") {
|
|
3933
|
-
const parsed = options(rest);
|
|
3934
4120
|
rejectUnknown(parsed, ["--message"]);
|
|
3935
4121
|
if (parsed.positionals.length !== 1) {
|
|
3936
4122
|
throw new DelegationControlError(
|
|
@@ -3946,8 +4132,8 @@ async function runDelegationCli(input) {
|
|
|
3946
4132
|
"Thread identifier and --message are required"
|
|
3947
4133
|
);
|
|
3948
4134
|
}
|
|
3949
|
-
|
|
3950
|
-
|
|
4135
|
+
writeResult(
|
|
4136
|
+
"thread send",
|
|
3951
4137
|
await requestRuntime({
|
|
3952
4138
|
environment,
|
|
3953
4139
|
path: "/v1/thread/send",
|
|
@@ -3958,7 +4144,6 @@ async function runDelegationCli(input) {
|
|
|
3958
4144
|
return 0;
|
|
3959
4145
|
}
|
|
3960
4146
|
if (group === "thread" && command === "cancel") {
|
|
3961
|
-
const parsed = options(rest);
|
|
3962
4147
|
rejectUnknown(parsed, []);
|
|
3963
4148
|
if (parsed.positionals.length !== 1) {
|
|
3964
4149
|
throw new DelegationControlError(
|
|
@@ -3970,8 +4155,8 @@ async function runDelegationCli(input) {
|
|
|
3970
4155
|
if (!threadId3) {
|
|
3971
4156
|
throw new DelegationControlError("INVALID_ARGUMENT", "Thread identifier is required");
|
|
3972
4157
|
}
|
|
3973
|
-
|
|
3974
|
-
|
|
4158
|
+
writeResult(
|
|
4159
|
+
"thread cancel",
|
|
3975
4160
|
await requestRuntime({
|
|
3976
4161
|
environment,
|
|
3977
4162
|
path: "/v1/thread/cancel",
|
|
@@ -3982,7 +4167,6 @@ async function runDelegationCli(input) {
|
|
|
3982
4167
|
return 0;
|
|
3983
4168
|
}
|
|
3984
4169
|
if (group === "thread" && (command === "read" || command === "wait")) {
|
|
3985
|
-
const parsed = options(rest);
|
|
3986
4170
|
rejectUnknown(parsed, ["--view", "--cursor", "--limit", "--timeout-ms"]);
|
|
3987
4171
|
if (parsed.positionals.length !== 1)
|
|
3988
4172
|
throw new DelegationControlError(
|
|
@@ -4014,19 +4198,19 @@ async function runDelegationCli(input) {
|
|
|
4014
4198
|
timeoutMs: value(parsed, "--timeout-ms") ? positiveInteger(value(parsed, "--timeout-ms"), "--timeout-ms") : DEFAULT_WAIT_TIMEOUT_MS
|
|
4015
4199
|
} : {}
|
|
4016
4200
|
};
|
|
4017
|
-
|
|
4018
|
-
|
|
4201
|
+
writeResult(
|
|
4202
|
+
command === "read" ? "thread read" : "thread wait",
|
|
4019
4203
|
await requestRuntime({
|
|
4020
4204
|
environment,
|
|
4021
4205
|
path: command === "read" ? "/v1/thread/read" : "/v1/thread/wait",
|
|
4022
4206
|
body,
|
|
4023
4207
|
...input.fetchImpl ? { fetchImpl: input.fetchImpl } : {}
|
|
4024
|
-
})
|
|
4208
|
+
}),
|
|
4209
|
+
view
|
|
4025
4210
|
);
|
|
4026
4211
|
return 0;
|
|
4027
4212
|
}
|
|
4028
4213
|
if (group === "thread" && command === "list") {
|
|
4029
|
-
const parsed = options(rest);
|
|
4030
4214
|
rejectUnknown(parsed, ["--cwd", "--parent", "--limit", "--cursor", "--sort"]);
|
|
4031
4215
|
if (parsed.positionals.length > 0)
|
|
4032
4216
|
throw new DelegationControlError(
|
|
@@ -4044,8 +4228,8 @@ async function runDelegationCli(input) {
|
|
|
4044
4228
|
])).has(sort))
|
|
4045
4229
|
throw new DelegationControlError("INVALID_ARGUMENT", "--sort is invalid");
|
|
4046
4230
|
const parentThread = value(parsed, "--parent");
|
|
4047
|
-
|
|
4048
|
-
|
|
4231
|
+
writeResult(
|
|
4232
|
+
"thread list",
|
|
4049
4233
|
await requestRuntime({
|
|
4050
4234
|
environment,
|
|
4051
4235
|
path: "/v1/thread/list",
|
|
@@ -4083,7 +4267,7 @@ async function runDelegationCli(input) {
|
|
|
4083
4267
|
|
|
4084
4268
|
// packages/host-runtime/src/run-host-runtime.ts
|
|
4085
4269
|
import { randomBytes } from "node:crypto";
|
|
4086
|
-
import
|
|
4270
|
+
import path21 from "node:path";
|
|
4087
4271
|
import { homedir } from "node:os";
|
|
4088
4272
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
4089
4273
|
|
|
@@ -4429,9 +4613,85 @@ function selectInstallerReleaseArtifact(release, target) {
|
|
|
4429
4613
|
});
|
|
4430
4614
|
}
|
|
4431
4615
|
|
|
4616
|
+
// packages/update-manager/dist/github-cli-release.js
|
|
4617
|
+
import { execFile } from "node:child_process";
|
|
4618
|
+
import path2 from "node:path";
|
|
4619
|
+
var GITHUB_LATEST_RELEASE_ENDPOINT = "repos/BytePioneer-AI/codex-host/releases/latest";
|
|
4620
|
+
var MAX_RELEASE_RESPONSE_BYTES = 1024 * 1024;
|
|
4621
|
+
var GITHUB_CLI_TIMEOUT_MS = 5e3;
|
|
4622
|
+
function defaultExecutableCandidates(environment, platform) {
|
|
4623
|
+
if (environment.CODEXHOST_GH_COMMAND)
|
|
4624
|
+
return [environment.CODEXHOST_GH_COMMAND];
|
|
4625
|
+
const candidates = ["gh"];
|
|
4626
|
+
if (platform === "darwin") {
|
|
4627
|
+
candidates.push("/opt/homebrew/bin/gh", "/usr/local/bin/gh");
|
|
4628
|
+
} else if (platform === "win32") {
|
|
4629
|
+
const programFiles = environment.ProgramFiles ?? environment.PROGRAMFILES;
|
|
4630
|
+
const localAppData = environment.LOCALAPPDATA;
|
|
4631
|
+
if (programFiles)
|
|
4632
|
+
candidates.push(path2.win32.join(programFiles, "GitHub CLI", "gh.exe"));
|
|
4633
|
+
if (localAppData) {
|
|
4634
|
+
candidates.push(path2.win32.join(localAppData, "Programs", "GitHub CLI", "gh.exe"));
|
|
4635
|
+
}
|
|
4636
|
+
} else {
|
|
4637
|
+
candidates.push("/usr/local/bin/gh", "/usr/bin/gh", "/snap/bin/gh");
|
|
4638
|
+
}
|
|
4639
|
+
return [...new Set(candidates.filter((candidate) => Boolean(candidate)))];
|
|
4640
|
+
}
|
|
4641
|
+
function runGitHubCli(executable2, arguments_2, options2) {
|
|
4642
|
+
return new Promise((resolve, reject) => {
|
|
4643
|
+
execFile(executable2, [...arguments_2], {
|
|
4644
|
+
encoding: "utf8",
|
|
4645
|
+
env: options2.environment,
|
|
4646
|
+
maxBuffer: MAX_RELEASE_RESPONSE_BYTES,
|
|
4647
|
+
timeout: GITHUB_CLI_TIMEOUT_MS,
|
|
4648
|
+
windowsHide: true,
|
|
4649
|
+
...options2.signal ? { signal: options2.signal } : {}
|
|
4650
|
+
}, (error51, stdout) => {
|
|
4651
|
+
if (error51)
|
|
4652
|
+
reject(error51);
|
|
4653
|
+
else
|
|
4654
|
+
resolve(stdout);
|
|
4655
|
+
});
|
|
4656
|
+
});
|
|
4657
|
+
}
|
|
4658
|
+
async function fetchLatestGitHubReleaseWithGitHubCli(options2 = {}) {
|
|
4659
|
+
const environment = options2.environment ?? process.env;
|
|
4660
|
+
const platform = options2.platform ?? process.platform;
|
|
4661
|
+
const candidates = options2.executableCandidates ?? defaultExecutableCandidates(environment, platform);
|
|
4662
|
+
const run = options2.run ?? runGitHubCli;
|
|
4663
|
+
const arguments_2 = [
|
|
4664
|
+
"api",
|
|
4665
|
+
"--hostname",
|
|
4666
|
+
"github.com",
|
|
4667
|
+
"--method",
|
|
4668
|
+
"GET",
|
|
4669
|
+
"--header",
|
|
4670
|
+
"Accept: application/vnd.github+json",
|
|
4671
|
+
"--header",
|
|
4672
|
+
"X-GitHub-Api-Version: 2022-11-28",
|
|
4673
|
+
GITHUB_LATEST_RELEASE_ENDPOINT
|
|
4674
|
+
];
|
|
4675
|
+
for (const executable2 of candidates) {
|
|
4676
|
+
options2.signal?.throwIfAborted();
|
|
4677
|
+
try {
|
|
4678
|
+
return parseLatestGitHubRelease(JSON.parse(await run(executable2, arguments_2, {
|
|
4679
|
+
environment,
|
|
4680
|
+
...options2.signal ? { signal: options2.signal } : {}
|
|
4681
|
+
})));
|
|
4682
|
+
} catch (error51) {
|
|
4683
|
+
options2.signal?.throwIfAborted();
|
|
4684
|
+
const code = error51?.code;
|
|
4685
|
+
if (code !== "ENOENT" && code !== "EACCES")
|
|
4686
|
+
return null;
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
return null;
|
|
4690
|
+
}
|
|
4691
|
+
|
|
4432
4692
|
// packages/update-manager/dist/operation-state.js
|
|
4433
4693
|
import { lstat as lstat2, mkdir, open, readFile as readFile2, readdir, rm, writeFile } from "node:fs/promises";
|
|
4434
|
-
import
|
|
4694
|
+
import path3 from "node:path";
|
|
4435
4695
|
var LOCK_FILE = "active-update-v1.lock";
|
|
4436
4696
|
var STATUS_FILE = "status-v1.json";
|
|
4437
4697
|
var TERMINAL_PHASES = /* @__PURE__ */ new Set(["succeeded", "failed"]);
|
|
@@ -4446,12 +4706,12 @@ async function regularFile(filePath) {
|
|
|
4446
4706
|
}
|
|
4447
4707
|
}
|
|
4448
4708
|
async function isUpdateOperationActive(stateDirectory) {
|
|
4449
|
-
if (!
|
|
4709
|
+
if (!path3.isAbsolute(stateDirectory))
|
|
4450
4710
|
throw new Error("update state directory must be absolute");
|
|
4451
|
-
return regularFile(
|
|
4711
|
+
return regularFile(path3.join(stateDirectory, LOCK_FILE));
|
|
4452
4712
|
}
|
|
4453
4713
|
async function discoverLatestUpdateStatus(stateDirectory) {
|
|
4454
|
-
if (!
|
|
4714
|
+
if (!path3.isAbsolute(stateDirectory))
|
|
4455
4715
|
throw new Error("update state directory must be absolute");
|
|
4456
4716
|
let entries;
|
|
4457
4717
|
try {
|
|
@@ -4465,7 +4725,7 @@ async function discoverLatestUpdateStatus(stateDirectory) {
|
|
|
4465
4725
|
for (const entry of entries) {
|
|
4466
4726
|
if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
|
|
4467
4727
|
continue;
|
|
4468
|
-
const statusPath =
|
|
4728
|
+
const statusPath = path3.join(stateDirectory, entry.name, STATUS_FILE);
|
|
4469
4729
|
if (!await regularFile(statusPath))
|
|
4470
4730
|
continue;
|
|
4471
4731
|
try {
|
|
@@ -4493,8 +4753,8 @@ async function cleanupTerminalUpdateState(stateDirectory, options2 = {}) {
|
|
|
4493
4753
|
for (const entry of entries) {
|
|
4494
4754
|
if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
|
|
4495
4755
|
continue;
|
|
4496
|
-
const directory =
|
|
4497
|
-
const statusPath =
|
|
4756
|
+
const directory = path3.join(stateDirectory, entry.name);
|
|
4757
|
+
const statusPath = path3.join(directory, STATUS_FILE);
|
|
4498
4758
|
try {
|
|
4499
4759
|
const status = parseUpdateStatus(JSON.parse(await readFile2(statusPath, "utf8")));
|
|
4500
4760
|
if (TERMINAL_PHASES.has(status.phase) && now - status.updatedAt > retentionSeconds) {
|
|
@@ -4505,10 +4765,10 @@ async function cleanupTerminalUpdateState(stateDirectory, options2 = {}) {
|
|
|
4505
4765
|
}
|
|
4506
4766
|
}
|
|
4507
4767
|
async function acquireUpdateOperationLock(stateDirectory) {
|
|
4508
|
-
if (!
|
|
4768
|
+
if (!path3.isAbsolute(stateDirectory))
|
|
4509
4769
|
throw new Error("update state directory must be absolute");
|
|
4510
4770
|
await mkdir(stateDirectory, { recursive: true, mode: 448 });
|
|
4511
|
-
const lockPath =
|
|
4771
|
+
const lockPath = path3.join(stateDirectory, LOCK_FILE);
|
|
4512
4772
|
let handle;
|
|
4513
4773
|
try {
|
|
4514
4774
|
handle = await open(lockPath, "wx", 384);
|
|
@@ -4527,9 +4787,9 @@ async function acquireUpdateOperationLock(stateDirectory) {
|
|
|
4527
4787
|
async setStatusPath(statusPath) {
|
|
4528
4788
|
if (released)
|
|
4529
4789
|
throw new Error("update operation lock is released");
|
|
4530
|
-
if (!
|
|
4790
|
+
if (!path3.isAbsolute(statusPath))
|
|
4531
4791
|
throw new Error("update status path must be absolute");
|
|
4532
|
-
await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath:
|
|
4792
|
+
await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath: path3.normalize(statusPath) })}
|
|
4533
4793
|
`, { encoding: "utf8", mode: 384 });
|
|
4534
4794
|
},
|
|
4535
4795
|
async release() {
|
|
@@ -4551,7 +4811,7 @@ function processIsAlive(processId) {
|
|
|
4551
4811
|
}
|
|
4552
4812
|
}
|
|
4553
4813
|
async function recoverUpdateOperationLock(stateDirectory) {
|
|
4554
|
-
const lockPath =
|
|
4814
|
+
const lockPath = path3.join(stateDirectory, LOCK_FILE);
|
|
4555
4815
|
if (!await regularFile(lockPath))
|
|
4556
4816
|
return;
|
|
4557
4817
|
let ownerPid;
|
|
@@ -4563,7 +4823,7 @@ async function recoverUpdateOperationLock(stateDirectory) {
|
|
|
4563
4823
|
} catch {
|
|
4564
4824
|
return;
|
|
4565
4825
|
}
|
|
4566
|
-
if (typeof statusPath !== "string" || !
|
|
4826
|
+
if (typeof statusPath !== "string" || !path3.isAbsolute(statusPath))
|
|
4567
4827
|
return;
|
|
4568
4828
|
try {
|
|
4569
4829
|
const status = parseUpdateStatus(JSON.parse(await readFile2(statusPath, "utf8")));
|
|
@@ -4578,7 +4838,7 @@ async function recoverUpdateOperationLock(stateDirectory) {
|
|
|
4578
4838
|
import { spawn } from "node:child_process";
|
|
4579
4839
|
import { randomUUID } from "node:crypto";
|
|
4580
4840
|
import { chmod, copyFile, lstat as lstat4, mkdir as mkdir2, readFile as readFile3, rename, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
|
|
4581
|
-
import
|
|
4841
|
+
import path4 from "node:path";
|
|
4582
4842
|
|
|
4583
4843
|
// packages/update-manager/dist/artifact.js
|
|
4584
4844
|
import { createHash } from "node:crypto";
|
|
@@ -4699,9 +4959,9 @@ async function replaceStatusFile(temporaryPath, statusPath) {
|
|
|
4699
4959
|
}
|
|
4700
4960
|
}
|
|
4701
4961
|
function requireAbsolutePath(value2, label) {
|
|
4702
|
-
if (!
|
|
4962
|
+
if (!path4.isAbsolute(value2))
|
|
4703
4963
|
throw new Error(`${label} must be an absolute path`);
|
|
4704
|
-
return
|
|
4964
|
+
return path4.normalize(value2);
|
|
4705
4965
|
}
|
|
4706
4966
|
async function requireRegularFile(value2, label) {
|
|
4707
4967
|
const filePath = requireAbsolutePath(value2, label);
|
|
@@ -4744,7 +5004,7 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
|
|
|
4744
5004
|
const now = dependencies2.now ?? Date.now;
|
|
4745
5005
|
const preparedRequests = /* @__PURE__ */ new Set();
|
|
4746
5006
|
async function writeStatusSnapshot(statusPath, status) {
|
|
4747
|
-
const temporaryPath =
|
|
5007
|
+
const temporaryPath = path4.join(path4.dirname(statusPath), `.update-status-${randomId()}.tmp`);
|
|
4748
5008
|
try {
|
|
4749
5009
|
await writeFile2(temporaryPath, `${JSON.stringify(status)}
|
|
4750
5010
|
`, {
|
|
@@ -4804,15 +5064,15 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
|
|
|
4804
5064
|
const updaterExecutable = await requireRegularFile(options2.updaterExecutable, "Updater executable");
|
|
4805
5065
|
const stateDirectory = requireAbsolutePath(options2.stateDirectory, "update state directory");
|
|
4806
5066
|
await mkdir2(stateDirectory, { recursive: true, mode: 448 });
|
|
4807
|
-
const workDirectory =
|
|
5067
|
+
const workDirectory = path4.join(stateDirectory, `update-${version2}-${randomId()}`);
|
|
4808
5068
|
await mkdir2(workDirectory, { recursive: false, mode: 448 });
|
|
4809
5069
|
const executableSuffix = platform === "win32" ? ".exe" : "";
|
|
4810
|
-
const helperPath =
|
|
5070
|
+
const helperPath = path4.join(workDirectory, `codexhost-updater${executableSuffix}`);
|
|
4811
5071
|
await copyFile(updaterExecutable, helperPath);
|
|
4812
5072
|
if (platform !== "win32")
|
|
4813
5073
|
await chmod(helperPath, 448);
|
|
4814
|
-
const requestPath =
|
|
4815
|
-
const statusPath =
|
|
5074
|
+
const requestPath = path4.join(workDirectory, "request-v1.json");
|
|
5075
|
+
const statusPath = path4.join(workDirectory, "status-v1.json");
|
|
4816
5076
|
await writePrivateJson(statusPath, preparedStatus(version2, installation, now()));
|
|
4817
5077
|
await options2.onPrepared?.({ version: version2, installation, statusPath });
|
|
4818
5078
|
return {
|
|
@@ -4828,8 +5088,8 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
|
|
|
4828
5088
|
}
|
|
4829
5089
|
async function prepareArtifact(common, installation, sourceValue, fileName) {
|
|
4830
5090
|
const source = validateArtifact(sourceValue);
|
|
4831
|
-
const temporaryPath =
|
|
4832
|
-
const artifactPath =
|
|
5091
|
+
const temporaryPath = path4.join(common.workDirectory, `.${fileName}.download`);
|
|
5092
|
+
const artifactPath = path4.join(common.workDirectory, fileName);
|
|
4833
5093
|
const progress = progressReporter(common.statusPath, common.version, installation, source.size);
|
|
4834
5094
|
try {
|
|
4835
5095
|
const result = await download(source, temporaryPath, progress.update);
|
|
@@ -4903,7 +5163,7 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
|
|
|
4903
5163
|
throw new Error("macOS DMG updates require macOS");
|
|
4904
5164
|
const common = await prepareCommon(options2, "macos-dmg");
|
|
4905
5165
|
const appPath = requireAbsolutePath(options2.appPath, "macOS application path");
|
|
4906
|
-
if (
|
|
5166
|
+
if (path4.extname(appPath) !== ".app") {
|
|
4907
5167
|
throw new Error("macOS application path must end in .app");
|
|
4908
5168
|
}
|
|
4909
5169
|
const artifact = await prepareArtifact(common, "macos-dmg", options2.artifact, "update.dmg");
|
|
@@ -5702,10 +5962,10 @@ function mergeDefs(...defs) {
|
|
|
5702
5962
|
function cloneDef(schema) {
|
|
5703
5963
|
return mergeDefs(schema._zod.def);
|
|
5704
5964
|
}
|
|
5705
|
-
function getElementAtPath(obj,
|
|
5706
|
-
if (!
|
|
5965
|
+
function getElementAtPath(obj, path26) {
|
|
5966
|
+
if (!path26)
|
|
5707
5967
|
return obj;
|
|
5708
|
-
return
|
|
5968
|
+
return path26.reduce((acc, key) => acc?.[key], obj);
|
|
5709
5969
|
}
|
|
5710
5970
|
function promiseAllObject(promisesObj) {
|
|
5711
5971
|
const keys = Object.keys(promisesObj);
|
|
@@ -6114,11 +6374,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
6114
6374
|
}
|
|
6115
6375
|
return false;
|
|
6116
6376
|
}
|
|
6117
|
-
function prefixIssues(
|
|
6377
|
+
function prefixIssues(path26, issues) {
|
|
6118
6378
|
return issues.map((iss) => {
|
|
6119
6379
|
var _a3;
|
|
6120
6380
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
6121
|
-
iss.path.unshift(
|
|
6381
|
+
iss.path.unshift(path26);
|
|
6122
6382
|
return iss;
|
|
6123
6383
|
});
|
|
6124
6384
|
}
|
|
@@ -6265,16 +6525,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
6265
6525
|
}
|
|
6266
6526
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
6267
6527
|
const fieldErrors = { _errors: [] };
|
|
6268
|
-
const processError = (error52,
|
|
6528
|
+
const processError = (error52, path26 = []) => {
|
|
6269
6529
|
for (const issue2 of error52.issues) {
|
|
6270
6530
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
6271
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
6531
|
+
issue2.errors.map((issues) => processError({ issues }, [...path26, ...issue2.path]));
|
|
6272
6532
|
} else if (issue2.code === "invalid_key") {
|
|
6273
|
-
processError({ issues: issue2.issues }, [...
|
|
6533
|
+
processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
|
|
6274
6534
|
} else if (issue2.code === "invalid_element") {
|
|
6275
|
-
processError({ issues: issue2.issues }, [...
|
|
6535
|
+
processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
|
|
6276
6536
|
} else {
|
|
6277
|
-
const fullpath = [...
|
|
6537
|
+
const fullpath = [...path26, ...issue2.path];
|
|
6278
6538
|
if (fullpath.length === 0) {
|
|
6279
6539
|
fieldErrors._errors.push(mapper(issue2));
|
|
6280
6540
|
} else {
|
|
@@ -6301,17 +6561,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
6301
6561
|
}
|
|
6302
6562
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
6303
6563
|
const result = { errors: [] };
|
|
6304
|
-
const processError = (error52,
|
|
6564
|
+
const processError = (error52, path26 = []) => {
|
|
6305
6565
|
var _a3, _b;
|
|
6306
6566
|
for (const issue2 of error52.issues) {
|
|
6307
6567
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
6308
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
6568
|
+
issue2.errors.map((issues) => processError({ issues }, [...path26, ...issue2.path]));
|
|
6309
6569
|
} else if (issue2.code === "invalid_key") {
|
|
6310
|
-
processError({ issues: issue2.issues }, [...
|
|
6570
|
+
processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
|
|
6311
6571
|
} else if (issue2.code === "invalid_element") {
|
|
6312
|
-
processError({ issues: issue2.issues }, [...
|
|
6572
|
+
processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
|
|
6313
6573
|
} else {
|
|
6314
|
-
const fullpath = [...
|
|
6574
|
+
const fullpath = [...path26, ...issue2.path];
|
|
6315
6575
|
if (fullpath.length === 0) {
|
|
6316
6576
|
result.errors.push(mapper(issue2));
|
|
6317
6577
|
continue;
|
|
@@ -6343,8 +6603,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
6343
6603
|
}
|
|
6344
6604
|
function toDotPath(_path) {
|
|
6345
6605
|
const segs = [];
|
|
6346
|
-
const
|
|
6347
|
-
for (const seg of
|
|
6606
|
+
const path26 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
6607
|
+
for (const seg of path26) {
|
|
6348
6608
|
if (typeof seg === "number")
|
|
6349
6609
|
segs.push(`[${seg}]`);
|
|
6350
6610
|
else if (typeof seg === "symbol")
|
|
@@ -19036,13 +19296,13 @@ function resolveRef(ref, ctx) {
|
|
|
19036
19296
|
if (!ref.startsWith("#")) {
|
|
19037
19297
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
19038
19298
|
}
|
|
19039
|
-
const
|
|
19040
|
-
if (
|
|
19299
|
+
const path26 = ref.slice(1).split("/").filter(Boolean);
|
|
19300
|
+
if (path26.length === 0) {
|
|
19041
19301
|
return ctx.rootSchema;
|
|
19042
19302
|
}
|
|
19043
19303
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
19044
|
-
if (
|
|
19045
|
-
const key =
|
|
19304
|
+
if (path26[0] === defsKey) {
|
|
19305
|
+
const key = path26[1];
|
|
19046
19306
|
if (!key || !ctx.defs[key]) {
|
|
19047
19307
|
throw new Error(`Reference not found: ${ref}`);
|
|
19048
19308
|
}
|
|
@@ -20465,7 +20725,7 @@ import { execFileSync } from "node:child_process";
|
|
|
20465
20725
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
20466
20726
|
import { constants } from "node:fs";
|
|
20467
20727
|
import { copyFile as copyFile2, mkdir as mkdir3, open as open3, readFile as readFile4, readdir as readdir2, rename as rename2, rm as rm3, stat } from "node:fs/promises";
|
|
20468
|
-
import
|
|
20728
|
+
import path5 from "node:path";
|
|
20469
20729
|
|
|
20470
20730
|
// packages/mapping-store/dist/records.js
|
|
20471
20731
|
var nonBlankTextSchema6 = external_exports.string().refine((value2) => value2.trim().length > 0, {
|
|
@@ -20716,12 +20976,12 @@ var MappingStore = class {
|
|
|
20716
20976
|
#initialized = false;
|
|
20717
20977
|
#lockHandle = null;
|
|
20718
20978
|
constructor(options2) {
|
|
20719
|
-
this.#directory =
|
|
20720
|
-
this.#threadsDirectory =
|
|
20721
|
-
this.#delegationsDirectory =
|
|
20722
|
-
this.#backupsDirectory =
|
|
20723
|
-
this.#quarantineDirectory =
|
|
20724
|
-
this.#lockPath =
|
|
20979
|
+
this.#directory = path5.resolve(options2.directory);
|
|
20980
|
+
this.#threadsDirectory = path5.join(this.#directory, "threads");
|
|
20981
|
+
this.#delegationsDirectory = path5.join(this.#directory, "delegations");
|
|
20982
|
+
this.#backupsDirectory = path5.join(this.#directory, "backups");
|
|
20983
|
+
this.#quarantineDirectory = path5.join(this.#directory, "quarantine");
|
|
20984
|
+
this.#lockPath = path5.join(this.#directory, "store.lock");
|
|
20725
20985
|
this.#instanceId = options2.instanceId ?? randomUUID2();
|
|
20726
20986
|
this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
|
|
20727
20987
|
this.#beforeReplace = options2.beforeReplace;
|
|
@@ -20740,8 +21000,8 @@ var MappingStore = class {
|
|
|
20740
21000
|
await this.#cleanupResidue();
|
|
20741
21001
|
const names = (await readdir2(this.#threadsDirectory)).filter((name) => name.endsWith(".json"));
|
|
20742
21002
|
for (const name of names) {
|
|
20743
|
-
const primary =
|
|
20744
|
-
const backup =
|
|
21003
|
+
const primary = path5.join(this.#threadsDirectory, name);
|
|
21004
|
+
const backup = path5.join(this.#backupsDirectory, name);
|
|
20745
21005
|
let record3 = null;
|
|
20746
21006
|
try {
|
|
20747
21007
|
record3 = await this.#readRecord(primary, name);
|
|
@@ -20750,7 +21010,7 @@ var MappingStore = class {
|
|
|
20750
21010
|
record3 = await this.#readRecord(backup, name);
|
|
20751
21011
|
await this.#replaceFile(primary, record3, false);
|
|
20752
21012
|
} catch (backupError) {
|
|
20753
|
-
const quarantine =
|
|
21013
|
+
const quarantine = path5.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
|
|
20754
21014
|
await rename2(primary, quarantine).catch(() => void 0);
|
|
20755
21015
|
void primaryError;
|
|
20756
21016
|
void backupError;
|
|
@@ -20766,14 +21026,14 @@ var MappingStore = class {
|
|
|
20766
21026
|
}
|
|
20767
21027
|
const delegationNames = (await readdir2(this.#delegationsDirectory)).filter((name) => name.endsWith(".json"));
|
|
20768
21028
|
for (const name of delegationNames) {
|
|
20769
|
-
const file2 =
|
|
21029
|
+
const file2 = path5.join(this.#delegationsDirectory, name);
|
|
20770
21030
|
try {
|
|
20771
21031
|
const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await readFile4(file2, "utf8")));
|
|
20772
21032
|
if (`${parsed.delegationId}.json` !== name)
|
|
20773
21033
|
throw new Error("filename mismatch");
|
|
20774
21034
|
this.#delegations.set(parsed.delegationId, parsed);
|
|
20775
21035
|
} catch {
|
|
20776
|
-
const quarantine =
|
|
21036
|
+
const quarantine = path5.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
|
|
20777
21037
|
await rename2(file2, quarantine).catch(() => void 0);
|
|
20778
21038
|
}
|
|
20779
21039
|
}
|
|
@@ -20931,10 +21191,35 @@ var MappingStore = class {
|
|
|
20931
21191
|
turnMappings: this.#mergeMappings(current.turnMappings, input.turnMappings ?? [])
|
|
20932
21192
|
}));
|
|
20933
21193
|
}
|
|
21194
|
+
// Keep native ref, Turn mappings and the indexed create request in one serialized
|
|
21195
|
+
// record mutation; separate setters could leave a child pointing at mixed Sessions.
|
|
21196
|
+
async rebindSubagentSession(input) {
|
|
21197
|
+
return this.#update(input.hostThreadId, (current) => {
|
|
21198
|
+
const parent = this.#records.get(input.parentHostThreadId);
|
|
21199
|
+
if (current.state !== "ready" || !current.nativeSessionRef || current.subagent?.parentHostThreadId !== input.parentHostThreadId || parent?.state !== "ready" || parent.harnessId !== current.harnessId || input.previousNativeSessionRef.harnessId !== current.harnessId || input.nativeSessionRef.harnessId !== current.harnessId || !sameJson(parent.nativeSessionRef, input.nativeSessionRef))
|
|
21200
|
+
throw new MappingStoreError("MAPPING_CONFLICT", "Subagent replacement must belong to its current parent Session");
|
|
21201
|
+
if (sameJson(current.nativeSessionRef, input.nativeSessionRef) && current.createRequestId === input.createRequestId)
|
|
21202
|
+
return null;
|
|
21203
|
+
if (!sameJson(current.nativeSessionRef, input.previousNativeSessionRef)) {
|
|
21204
|
+
throw new MappingStoreError("MAPPING_CONFLICT", "Subagent replacement source Session is stale");
|
|
21205
|
+
}
|
|
21206
|
+
const nativeSessionId = input.nativeSessionRef.nativeSessionId;
|
|
21207
|
+
return {
|
|
21208
|
+
...current,
|
|
21209
|
+
createRequestId: input.createRequestId,
|
|
21210
|
+
nativeSessionRef: input.nativeSessionRef,
|
|
21211
|
+
turnMappings: current.turnMappings.map((mapping) => ({
|
|
21212
|
+
...mapping,
|
|
21213
|
+
nativeTurnRef: { ...mapping.nativeTurnRef, nativeSessionId },
|
|
21214
|
+
...mapping.nativeCheckpointRef ? { nativeCheckpointRef: { ...mapping.nativeCheckpointRef, nativeSessionId } } : {}
|
|
21215
|
+
}))
|
|
21216
|
+
};
|
|
21217
|
+
});
|
|
21218
|
+
}
|
|
20934
21219
|
async replaceReadySession(input) {
|
|
20935
21220
|
return this.#update(input.hostThreadId, (current) => {
|
|
20936
|
-
if (current.state !== "ready" || !current.nativeSessionRef || !current.forkSource || current.forkSource.hostThreadId !== input.forkSource.hostThreadId || current.nativeSessionRef.nativeSessionId === input.nativeSessionRef.nativeSessionId || input.turnMappings.length < 1 || input.turnMappings.length >= current.turnMappings.length || input.turnMappings.some(({ hostTurnId }, index) => hostTurnId !== current.turnMappings[index]?.hostTurnId)) {
|
|
20937
|
-
throw new MappingStoreError("MAPPING_CONFLICT", "Ready Session replacement must retain an exact shorter derived prefix");
|
|
21221
|
+
if (current.state !== "ready" || !current.nativeSessionRef || current.revision !== input.expectedRevision || !sameJson(current.nativeSessionRef, input.expectedNativeSessionRef) || !current.forkSource || current.forkSource.hostThreadId !== input.forkSource.hostThreadId || current.nativeSessionRef.nativeSessionId === input.nativeSessionRef.nativeSessionId || input.turnMappings.length < 1 || input.turnMappings.length >= current.turnMappings.length || input.turnMappings.some(({ hostTurnId }, index) => hostTurnId !== current.turnMappings[index]?.hostTurnId)) {
|
|
21222
|
+
throw new MappingStoreError("MAPPING_CONFLICT", "Ready Session replacement must match the expected record and retain an exact shorter derived prefix");
|
|
20938
21223
|
}
|
|
20939
21224
|
return {
|
|
20940
21225
|
...current,
|
|
@@ -20946,8 +21231,8 @@ var MappingStore = class {
|
|
|
20946
21231
|
}
|
|
20947
21232
|
async replaceReadySessionAfterLastTurn(input) {
|
|
20948
21233
|
return this.#update(input.hostThreadId, (current) => {
|
|
20949
|
-
if (current.state !== "ready" || !current.nativeSessionRef || input.turnMappings.length !== current.turnMappings.length - 1 || input.turnMappings.some(({ hostTurnId }, index) => hostTurnId !== current.turnMappings[index]?.hostTurnId)) {
|
|
20950
|
-
throw new MappingStoreError("MAPPING_CONFLICT", "Last-Turn Session replacement must retain the exact shorter Host Turn prefix");
|
|
21234
|
+
if (current.state !== "ready" || !current.nativeSessionRef || current.revision !== input.expectedRevision || !sameJson(current.nativeSessionRef, input.expectedNativeSessionRef) || input.turnMappings.length !== current.turnMappings.length - 1 || input.turnMappings.some(({ hostTurnId }, index) => hostTurnId !== current.turnMappings[index]?.hostTurnId)) {
|
|
21235
|
+
throw new MappingStoreError("MAPPING_CONFLICT", "Last-Turn Session replacement must match the expected record and retain the exact shorter Host Turn prefix");
|
|
20951
21236
|
}
|
|
20952
21237
|
return {
|
|
20953
21238
|
...current,
|
|
@@ -21168,10 +21453,10 @@ var MappingStore = class {
|
|
|
21168
21453
|
readdir2(this.#directory)
|
|
21169
21454
|
]);
|
|
21170
21455
|
await Promise.all([
|
|
21171
|
-
...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(
|
|
21172
|
-
...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(
|
|
21456
|
+
...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path5.join(this.#threadsDirectory, name), { force: true })),
|
|
21457
|
+
...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path5.join(this.#delegationsDirectory, name), { force: true })),
|
|
21173
21458
|
// Renamed aside by #acquireLock; nothing reads them back, and they accumulate one per run.
|
|
21174
|
-
...rootNames.filter((name) => name.startsWith(`${
|
|
21459
|
+
...rootNames.filter((name) => name.startsWith(`${path5.basename(this.#lockPath)}.stale-`)).map((name) => rm3(path5.join(this.#directory, name), { force: true }))
|
|
21175
21460
|
]);
|
|
21176
21461
|
}
|
|
21177
21462
|
async #acquireLock() {
|
|
@@ -21272,13 +21557,13 @@ var MappingStore = class {
|
|
|
21272
21557
|
await next;
|
|
21273
21558
|
}
|
|
21274
21559
|
#recordPath(hostThreadId) {
|
|
21275
|
-
return
|
|
21560
|
+
return path5.join(this.#threadsDirectory, `${hostThreadId}.json`);
|
|
21276
21561
|
}
|
|
21277
21562
|
#delegationPath(delegationId) {
|
|
21278
|
-
return
|
|
21563
|
+
return path5.join(this.#delegationsDirectory, `${delegationId}.json`);
|
|
21279
21564
|
}
|
|
21280
21565
|
#backupPath(hostThreadId) {
|
|
21281
|
-
return
|
|
21566
|
+
return path5.join(this.#backupsDirectory, `${hostThreadId}.json`);
|
|
21282
21567
|
}
|
|
21283
21568
|
#requireInitialized() {
|
|
21284
21569
|
if (!this.#initialized) {
|
|
@@ -22031,8 +22316,8 @@ function projectFileChangeKind(kind) {
|
|
|
22031
22316
|
return { type: kind };
|
|
22032
22317
|
}
|
|
22033
22318
|
function projectFileChanges(changes) {
|
|
22034
|
-
return changes.map(({ path:
|
|
22035
|
-
path:
|
|
22319
|
+
return changes.map(({ path: path26, kind, unifiedDiff }) => ({
|
|
22320
|
+
path: path26,
|
|
22036
22321
|
kind: projectFileChangeKind(kind),
|
|
22037
22322
|
diff: unifiedDiff
|
|
22038
22323
|
}));
|
|
@@ -22253,7 +22538,9 @@ function projectItem(item, outcome, defaultCwd, includeCommandOutput = true, sen
|
|
|
22253
22538
|
changes: projectFileChanges(item.changes),
|
|
22254
22539
|
status: itemStatus(outcome)
|
|
22255
22540
|
};
|
|
22256
|
-
case "subagentDelegation":
|
|
22541
|
+
case "subagentDelegation": {
|
|
22542
|
+
const primary = item.subagents[0];
|
|
22543
|
+
const sameConfiguration = item.subagents.every((subagent) => subagent.model === primary?.model && subagent.reasoningEffort === primary?.reasoningEffort);
|
|
22257
22544
|
return {
|
|
22258
22545
|
id: item.itemId,
|
|
22259
22546
|
type: "collabAgentToolCall",
|
|
@@ -22262,13 +22549,14 @@ function projectItem(item, outcome, defaultCwd, includeCommandOutput = true, sen
|
|
|
22262
22549
|
senderThreadId: senderThreadId ?? "",
|
|
22263
22550
|
receiverThreadIds: item.subagents.map(({ subagentId }) => subagentId),
|
|
22264
22551
|
prompt: item.prompt ?? null,
|
|
22265
|
-
model: null,
|
|
22266
|
-
reasoningEffort: null,
|
|
22552
|
+
model: sameConfiguration ? primary?.model ?? null : null,
|
|
22553
|
+
reasoningEffort: sameConfiguration ? primary?.reasoningEffort ?? null : null,
|
|
22267
22554
|
agentsStates: Object.fromEntries(item.subagents.map(({ subagentId, status, resultSummary }) => [
|
|
22268
22555
|
subagentId,
|
|
22269
22556
|
{ status: collabAgentStatus(status), message: resultSummary ?? null }
|
|
22270
22557
|
]))
|
|
22271
22558
|
};
|
|
22559
|
+
}
|
|
22272
22560
|
}
|
|
22273
22561
|
}
|
|
22274
22562
|
function reasoningPreviewItemId(itemId) {
|
|
@@ -22344,9 +22632,9 @@ function projectHistoricalTurn(input) {
|
|
|
22344
22632
|
return [];
|
|
22345
22633
|
}
|
|
22346
22634
|
return item.type === "reasoning" ? [
|
|
22347
|
-
projectItem(item, outcome, cwd, true, ""),
|
|
22635
|
+
projectItem(item, outcome, cwd, true, input.threadId ?? ""),
|
|
22348
22636
|
projectReasoningTranscriptItem(item, outcome, cwd)
|
|
22349
|
-
] : [projectItem(item, outcome, cwd, true, "")];
|
|
22637
|
+
] : [projectItem(item, outcome, cwd, true, input.threadId ?? "")];
|
|
22350
22638
|
})
|
|
22351
22639
|
],
|
|
22352
22640
|
error: error51,
|
|
@@ -22978,13 +23266,13 @@ function decodeThreadForkRequest(request) {
|
|
|
22978
23266
|
if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
|
|
22979
23267
|
throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
|
|
22980
23268
|
}
|
|
22981
|
-
const
|
|
23269
|
+
const path26 = optionalText(params, "path", { allowEmpty: true });
|
|
22982
23270
|
const ephemeral = optionalBoolean(params, "ephemeral");
|
|
22983
23271
|
return {
|
|
22984
23272
|
threadId: threadId3,
|
|
22985
23273
|
...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
|
|
22986
23274
|
...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
|
|
22987
|
-
...
|
|
23275
|
+
...path26 ? { path: path26 } : {},
|
|
22988
23276
|
...optionalField(params, "model"),
|
|
22989
23277
|
...optionalField(params, "modelProvider"),
|
|
22990
23278
|
...optionalField(params, "cwd"),
|
|
@@ -23995,18 +24283,149 @@ async function inspectHarnessAccounts(adapters, descriptors, timeoutMs = 12e3) {
|
|
|
23995
24283
|
}
|
|
23996
24284
|
|
|
23997
24285
|
// packages/host-runtime/src/app-server-host.ts
|
|
23998
|
-
import { createHash as
|
|
24286
|
+
import { createHash as createHash6, randomUUID as randomUUID9 } from "node:crypto";
|
|
23999
24287
|
import { rm as rm4 } from "node:fs/promises";
|
|
24000
24288
|
import os2 from "node:os";
|
|
24001
|
-
import
|
|
24289
|
+
import path12 from "node:path";
|
|
24002
24290
|
|
|
24003
24291
|
// packages/host-runtime/src/external-thread-fork.ts
|
|
24004
24292
|
import nodePath from "node:path";
|
|
24005
24293
|
|
|
24006
24294
|
// packages/host-runtime/src/external-thread-repository.ts
|
|
24007
|
-
import { randomUUID as
|
|
24295
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
24008
24296
|
import os from "node:os";
|
|
24009
|
-
import
|
|
24297
|
+
import path6 from "node:path";
|
|
24298
|
+
|
|
24299
|
+
// packages/host-runtime/src/external-subagent-threads.ts
|
|
24300
|
+
import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
|
|
24301
|
+
function childCreateRequest(parent, nativeRef, id2) {
|
|
24302
|
+
const key = createHash3("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
|
|
24303
|
+
return `subagent:${key}`;
|
|
24304
|
+
}
|
|
24305
|
+
function subagentMaterializer(store, parent, previousParent) {
|
|
24306
|
+
if (previousParent && (previousParent.hostThreadId !== parent.hostThreadId || previousParent.harnessId !== parent.harnessId)) {
|
|
24307
|
+
throw new Error("Subagent Session replacement must stay in the same Host Thread");
|
|
24308
|
+
}
|
|
24309
|
+
const previousRef = previousParent?.nativeSessionRef;
|
|
24310
|
+
let legacy;
|
|
24311
|
+
const legacyRecords = () => legacy ??= store.listThreads().then((records) => {
|
|
24312
|
+
const byRequest = /* @__PURE__ */ new Map();
|
|
24313
|
+
const children = /* @__PURE__ */ new Map();
|
|
24314
|
+
for (const record3 of records) {
|
|
24315
|
+
if (!record3.subagent || record3.harnessId !== parent.harnessId || !record3.nativeSessionRef)
|
|
24316
|
+
continue;
|
|
24317
|
+
const owner = {
|
|
24318
|
+
hostThreadId: record3.subagent.parentHostThreadId,
|
|
24319
|
+
harnessId: record3.harnessId
|
|
24320
|
+
};
|
|
24321
|
+
const key = childCreateRequest(
|
|
24322
|
+
owner,
|
|
24323
|
+
record3.nativeSessionRef,
|
|
24324
|
+
record3.subagent.nativeSubagentId
|
|
24325
|
+
);
|
|
24326
|
+
if (!byRequest.has(key) || record3.state === "ready") byRequest.set(key, record3);
|
|
24327
|
+
const siblings = children.get(owner.hostThreadId) ?? [];
|
|
24328
|
+
siblings.push(record3);
|
|
24329
|
+
children.set(owner.hostThreadId, siblings);
|
|
24330
|
+
}
|
|
24331
|
+
return { byRequest, children };
|
|
24332
|
+
});
|
|
24333
|
+
const rebind = async (existing, owner, visited = /* @__PURE__ */ new Set()) => {
|
|
24334
|
+
if (!previousRef || !owner.nativeSessionRef || !existing.subagent || visited.has(existing.hostThreadId)) {
|
|
24335
|
+
throw new Error("Invalid retained Subagent Session tree");
|
|
24336
|
+
}
|
|
24337
|
+
visited.add(existing.hostThreadId);
|
|
24338
|
+
const rebound = await store.rebindSubagentSession({
|
|
24339
|
+
hostThreadId: existing.hostThreadId,
|
|
24340
|
+
parentHostThreadId: owner.hostThreadId,
|
|
24341
|
+
previousNativeSessionRef: previousRef,
|
|
24342
|
+
nativeSessionRef: owner.nativeSessionRef,
|
|
24343
|
+
createRequestId: childCreateRequest(
|
|
24344
|
+
owner,
|
|
24345
|
+
owner.nativeSessionRef,
|
|
24346
|
+
existing.subagent.nativeSubagentId
|
|
24347
|
+
)
|
|
24348
|
+
});
|
|
24349
|
+
for (const descendant of (await legacyRecords()).children.get(existing.hostThreadId) ?? []) {
|
|
24350
|
+
if (descendant.state === "ready" && descendant.nativeSessionRef?.nativeSessionId === previousRef.nativeSessionId) {
|
|
24351
|
+
await rebind(descendant, rebound, visited);
|
|
24352
|
+
}
|
|
24353
|
+
}
|
|
24354
|
+
return rebound;
|
|
24355
|
+
};
|
|
24356
|
+
return async (child) => {
|
|
24357
|
+
if (!child.nativeSubagentId || !parent.nativeSessionRef || parent.state !== "ready")
|
|
24358
|
+
return null;
|
|
24359
|
+
const nativeRef = parent.nativeSessionRef;
|
|
24360
|
+
const createRequestId = childCreateRequest(parent, nativeRef, child.nativeSubagentId);
|
|
24361
|
+
const previousRequest = previousRef && previousRef.nativeSessionId !== nativeRef.nativeSessionId ? childCreateRequest(parent, previousRef, child.nativeSubagentId) : void 0;
|
|
24362
|
+
let existing = await store.getThreadByCreateRequest(createRequestId);
|
|
24363
|
+
if (!existing && previousRequest)
|
|
24364
|
+
existing = await store.getThreadByCreateRequest(previousRequest);
|
|
24365
|
+
if (!existing) {
|
|
24366
|
+
const { byRequest } = await legacyRecords();
|
|
24367
|
+
existing = byRequest.get(createRequestId) ?? (previousRequest ? byRequest.get(previousRequest) : void 0) ?? null;
|
|
24368
|
+
}
|
|
24369
|
+
if (existing?.state === "ready") {
|
|
24370
|
+
if (existing.nativeSessionRef?.nativeSessionId === nativeRef.nativeSessionId) return existing;
|
|
24371
|
+
if (!previousRef) throw new Error("Subagent belongs to a different Native Session");
|
|
24372
|
+
return rebind(existing, parent);
|
|
24373
|
+
}
|
|
24374
|
+
const provisional = existing ?? await store.createProvisional({
|
|
24375
|
+
hostThreadId: hostThreadIdSchema.parse(randomUUID3()),
|
|
24376
|
+
createRequestId,
|
|
24377
|
+
harnessId: parent.harnessId,
|
|
24378
|
+
cwd: parent.cwd,
|
|
24379
|
+
title: child.description,
|
|
24380
|
+
transportModelId: parent.transportModelId,
|
|
24381
|
+
ephemeral: parent.ephemeral,
|
|
24382
|
+
historyMode: "paginated",
|
|
24383
|
+
subagent: {
|
|
24384
|
+
parentHostThreadId: parent.hostThreadId,
|
|
24385
|
+
nativeSubagentId: child.nativeSubagentId,
|
|
24386
|
+
...child.role ? { role: child.role } : {}
|
|
24387
|
+
}
|
|
24388
|
+
});
|
|
24389
|
+
return provisional.state === "ready" ? provisional : store.commitReady({
|
|
24390
|
+
hostThreadId: provisional.hostThreadId,
|
|
24391
|
+
nativeSessionRef: nativeRef
|
|
24392
|
+
});
|
|
24393
|
+
};
|
|
24394
|
+
}
|
|
24395
|
+
async function materializeExternalSubagent(store, parent, child) {
|
|
24396
|
+
return subagentMaterializer(store, parent)(child);
|
|
24397
|
+
}
|
|
24398
|
+
async function projectExternalSnapshot(store, record3, snapshot, previousParent) {
|
|
24399
|
+
const materialize = subagentMaterializer(store, record3, previousParent);
|
|
24400
|
+
const turns = [];
|
|
24401
|
+
for (const [index, turn] of snapshot.turns.entries()) {
|
|
24402
|
+
const mapping = record3.turnMappings[index];
|
|
24403
|
+
if (!mapping) throw new Error("External Snapshot mapping is incomplete");
|
|
24404
|
+
const items = await Promise.all(
|
|
24405
|
+
turn.items.map(async (entry) => {
|
|
24406
|
+
if (entry.item.type !== "subagentDelegation") return entry;
|
|
24407
|
+
const subagents = await Promise.all(
|
|
24408
|
+
entry.item.subagents.map(async (child) => {
|
|
24409
|
+
const stored = await materialize(child);
|
|
24410
|
+
return stored ? { ...child, subagentId: stored.hostThreadId } : child;
|
|
24411
|
+
})
|
|
24412
|
+
);
|
|
24413
|
+
return { ...entry, item: { ...entry.item, subagents } };
|
|
24414
|
+
})
|
|
24415
|
+
);
|
|
24416
|
+
turns.push(
|
|
24417
|
+
projectHistoricalTurn({
|
|
24418
|
+
threadId: record3.hostThreadId,
|
|
24419
|
+
turnId: mapping.hostTurnId,
|
|
24420
|
+
cwd: record3.cwd,
|
|
24421
|
+
snapshot: { ...turn, items }
|
|
24422
|
+
})
|
|
24423
|
+
);
|
|
24424
|
+
}
|
|
24425
|
+
return turns;
|
|
24426
|
+
}
|
|
24427
|
+
|
|
24428
|
+
// packages/host-runtime/src/external-thread-repository.ts
|
|
24010
24429
|
function nativeTurnKey2(ref) {
|
|
24011
24430
|
return `${ref.harnessId}\0${ref.nativeSessionId}\0${ref.nativeTurnKey}\0${ref.formatVersion}`;
|
|
24012
24431
|
}
|
|
@@ -24015,8 +24434,8 @@ function sameMapping(left, right) {
|
|
|
24015
24434
|
}
|
|
24016
24435
|
function defaultMappingStoreDirectory(environment) {
|
|
24017
24436
|
const dataDirectory = environment.CODEXHOST_DATA_DIR;
|
|
24018
|
-
return
|
|
24019
|
-
dataDirectory ?
|
|
24437
|
+
return path6.join(
|
|
24438
|
+
dataDirectory ? path6.resolve(dataDirectory) : path6.join(os.homedir(), ".codexhost"),
|
|
24020
24439
|
"mapping-store"
|
|
24021
24440
|
);
|
|
24022
24441
|
}
|
|
@@ -24041,6 +24460,9 @@ var ExternalThreadRepository = class {
|
|
|
24041
24460
|
list() {
|
|
24042
24461
|
return this.store.listThreads();
|
|
24043
24462
|
}
|
|
24463
|
+
materializeSubagent(parent, child) {
|
|
24464
|
+
return materializeExternalSubagent(this.store, parent, child);
|
|
24465
|
+
}
|
|
24044
24466
|
findByCreateRequest(createRequestId) {
|
|
24045
24467
|
return this.store.getThreadByCreateRequest(createRequestId);
|
|
24046
24468
|
}
|
|
@@ -24110,7 +24532,7 @@ var ExternalThreadRepository = class {
|
|
|
24110
24532
|
throw new Error("Derived Snapshot identity does not belong to its Native Session");
|
|
24111
24533
|
}
|
|
24112
24534
|
return {
|
|
24113
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
24535
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID4()),
|
|
24114
24536
|
nativeTurnRef: turn.nativeTurnRef,
|
|
24115
24537
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
24116
24538
|
};
|
|
@@ -24122,15 +24544,7 @@ var ExternalThreadRepository = class {
|
|
|
24122
24544
|
});
|
|
24123
24545
|
return {
|
|
24124
24546
|
record: nextRecord,
|
|
24125
|
-
turns:
|
|
24126
|
-
const mapping = mappings[index];
|
|
24127
|
-
if (!mapping) throw new Error("Derived Snapshot mapping is incomplete");
|
|
24128
|
-
return projectHistoricalTurn({
|
|
24129
|
-
turnId: mapping.hostTurnId,
|
|
24130
|
-
cwd: record3.cwd,
|
|
24131
|
-
snapshot: turn
|
|
24132
|
-
});
|
|
24133
|
-
})
|
|
24547
|
+
turns: await projectExternalSnapshot(this.store, nextRecord, snapshot)
|
|
24134
24548
|
};
|
|
24135
24549
|
}
|
|
24136
24550
|
async commitForkRollback(derived, source, nativeSessionRef, snapshot) {
|
|
@@ -24164,6 +24578,8 @@ var ExternalThreadRepository = class {
|
|
|
24164
24578
|
});
|
|
24165
24579
|
const nextRecord = await this.store.replaceReadySession({
|
|
24166
24580
|
hostThreadId: derived.hostThreadId,
|
|
24581
|
+
expectedRevision: derived.revision,
|
|
24582
|
+
expectedNativeSessionRef: derived.nativeSessionRef,
|
|
24167
24583
|
nativeSessionRef,
|
|
24168
24584
|
turnMappings: mappings,
|
|
24169
24585
|
forkSource: {
|
|
@@ -24173,15 +24589,7 @@ var ExternalThreadRepository = class {
|
|
|
24173
24589
|
});
|
|
24174
24590
|
return {
|
|
24175
24591
|
record: nextRecord,
|
|
24176
|
-
turns:
|
|
24177
|
-
const mapping = mappings[index];
|
|
24178
|
-
if (!mapping) throw new Error("External rollback Snapshot mapping is incomplete");
|
|
24179
|
-
return projectHistoricalTurn({
|
|
24180
|
-
turnId: mapping.hostTurnId,
|
|
24181
|
-
cwd: derived.cwd,
|
|
24182
|
-
snapshot: turn
|
|
24183
|
-
});
|
|
24184
|
-
})
|
|
24592
|
+
turns: await projectExternalSnapshot(this.store, nextRecord, snapshot, derived)
|
|
24185
24593
|
};
|
|
24186
24594
|
}
|
|
24187
24595
|
async commitLastTurnRollback(current, nativeSessionRef, snapshot) {
|
|
@@ -24201,30 +24609,26 @@ var ExternalThreadRepository = class {
|
|
|
24201
24609
|
});
|
|
24202
24610
|
const nextRecord = await this.store.replaceReadySessionAfterLastTurn({
|
|
24203
24611
|
hostThreadId: current.hostThreadId,
|
|
24612
|
+
expectedRevision: current.revision,
|
|
24613
|
+
expectedNativeSessionRef: current.nativeSessionRef,
|
|
24204
24614
|
nativeSessionRef,
|
|
24205
24615
|
turnMappings: mappings
|
|
24206
24616
|
});
|
|
24207
24617
|
return {
|
|
24208
24618
|
record: nextRecord,
|
|
24209
|
-
turns:
|
|
24210
|
-
const mapping = mappings[index];
|
|
24211
|
-
if (!mapping) throw new Error("Last-Turn rollback Snapshot mapping is incomplete");
|
|
24212
|
-
return projectHistoricalTurn({
|
|
24213
|
-
turnId: mapping.hostTurnId,
|
|
24214
|
-
cwd: current.cwd,
|
|
24215
|
-
snapshot: turn
|
|
24216
|
-
});
|
|
24217
|
-
})
|
|
24619
|
+
turns: await projectExternalSnapshot(this.store, nextRecord, snapshot, current)
|
|
24218
24620
|
};
|
|
24219
24621
|
}
|
|
24220
24622
|
async sessionTreeId(record3) {
|
|
24221
24623
|
let current = record3;
|
|
24222
24624
|
const visited = /* @__PURE__ */ new Set();
|
|
24223
|
-
while (current.forkSource) {
|
|
24625
|
+
while (current.subagent || current.forkSource) {
|
|
24224
24626
|
if (visited.has(current.hostThreadId))
|
|
24225
24627
|
throw new Error("External Thread Fork tree contains a cycle");
|
|
24226
24628
|
visited.add(current.hostThreadId);
|
|
24227
|
-
const
|
|
24629
|
+
const parentId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
|
|
24630
|
+
if (!parentId) break;
|
|
24631
|
+
const source = await this.find(parentId);
|
|
24228
24632
|
if (!source) break;
|
|
24229
24633
|
current = source;
|
|
24230
24634
|
}
|
|
@@ -24248,7 +24652,7 @@ var ExternalThreadRepository = class {
|
|
|
24248
24652
|
const aligned = snapshot.turns.map((turn) => {
|
|
24249
24653
|
const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
|
|
24250
24654
|
const mapping = existing ?? {
|
|
24251
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
24655
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID4()),
|
|
24252
24656
|
nativeTurnRef: turn.nativeTurnRef,
|
|
24253
24657
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
24254
24658
|
};
|
|
@@ -24269,16 +24673,14 @@ var ExternalThreadRepository = class {
|
|
|
24269
24673
|
const nextRecord = mappingsChanged ? await this.store.reconcileTurnMappings(record3.hostThreadId, orderedMappings) : record3;
|
|
24270
24674
|
return {
|
|
24271
24675
|
record: nextRecord,
|
|
24272
|
-
turns:
|
|
24273
|
-
({ mapping, snapshot: turn }) => projectHistoricalTurn({ turnId: mapping.hostTurnId, cwd: record3.cwd, snapshot: turn })
|
|
24274
|
-
)
|
|
24676
|
+
turns: await projectExternalSnapshot(this.store, nextRecord, snapshot)
|
|
24275
24677
|
};
|
|
24276
24678
|
}
|
|
24277
24679
|
};
|
|
24278
24680
|
function createExternalThreadRecordInput(input) {
|
|
24279
24681
|
return {
|
|
24280
|
-
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(
|
|
24281
|
-
createRequestId: input.createRequestId ??
|
|
24682
|
+
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID4()),
|
|
24683
|
+
createRequestId: input.createRequestId ?? randomUUID4(),
|
|
24282
24684
|
harnessId: input.harnessId,
|
|
24283
24685
|
cwd: input.cwd,
|
|
24284
24686
|
...input.title ? { title: input.title } : {},
|
|
@@ -24925,13 +25327,14 @@ async function restoreCurrentConfiguration(session, configuration) {
|
|
|
24925
25327
|
}
|
|
24926
25328
|
async function executeCurrentLastTurnRollback(input) {
|
|
24927
25329
|
const { current, adapters, repository, runtime } = input;
|
|
24928
|
-
|
|
25330
|
+
const currentRecord = current.record;
|
|
25331
|
+
if (currentRecord.turnMappings.length === 0) {
|
|
24929
25332
|
return {
|
|
24930
25333
|
ok: false,
|
|
24931
25334
|
error: { code: -32076, message: "External Thread has no Turn to roll back" }
|
|
24932
25335
|
};
|
|
24933
25336
|
}
|
|
24934
|
-
const currentNativeRef =
|
|
25337
|
+
const currentNativeRef = currentRecord.nativeSessionRef;
|
|
24935
25338
|
const adapter = adapters.get(current.harnessId);
|
|
24936
25339
|
if (!currentNativeRef || !adapter) {
|
|
24937
25340
|
return {
|
|
@@ -24979,7 +25382,7 @@ async function executeCurrentLastTurnRollback(input) {
|
|
|
24979
25382
|
await session.close().catch(() => void 0);
|
|
24980
25383
|
return { ok: false, error: mapExternalThreadHarnessError(snapshot.error, "read") };
|
|
24981
25384
|
}
|
|
24982
|
-
if (snapshot.value.turns.length !==
|
|
25385
|
+
if (snapshot.value.turns.length !== currentRecord.turnMappings.length - 1) {
|
|
24983
25386
|
await session.close().catch(() => void 0);
|
|
24984
25387
|
return {
|
|
24985
25388
|
ok: false,
|
|
@@ -24997,7 +25400,7 @@ async function executeCurrentLastTurnRollback(input) {
|
|
|
24997
25400
|
let aligned;
|
|
24998
25401
|
try {
|
|
24999
25402
|
aligned = await repository.commitLastTurnRollback(
|
|
25000
|
-
|
|
25403
|
+
currentRecord,
|
|
25001
25404
|
finalNativeRef,
|
|
25002
25405
|
snapshot.value
|
|
25003
25406
|
);
|
|
@@ -25045,7 +25448,8 @@ async function executeExternalThreadRollback(input) {
|
|
|
25045
25448
|
...input.environment ? { environment: input.environment } : {}
|
|
25046
25449
|
});
|
|
25047
25450
|
}
|
|
25048
|
-
const
|
|
25451
|
+
const derivedRecord = derived.record;
|
|
25452
|
+
const forkSource = derivedRecord.forkSource;
|
|
25049
25453
|
if (!forkSource) {
|
|
25050
25454
|
return {
|
|
25051
25455
|
ok: false,
|
|
@@ -25076,10 +25480,11 @@ async function executeExternalThreadRollback(input) {
|
|
|
25076
25480
|
const sourceRefreshError = await runtime.refresh(source);
|
|
25077
25481
|
if (sourceRefreshError) return { ok: false, error: sourceRefreshError };
|
|
25078
25482
|
}
|
|
25079
|
-
const
|
|
25483
|
+
const sourceRecord = source.record;
|
|
25484
|
+
const sourceBoundaryIndex = sourceRecord.turnMappings.findIndex(
|
|
25080
25485
|
({ hostTurnId }) => hostTurnId === forkSource.hostTurnId
|
|
25081
25486
|
);
|
|
25082
|
-
if (sourceBoundaryIndex < 0 ||
|
|
25487
|
+
if (sourceBoundaryIndex < 0 || derivedRecord.turnMappings.length !== sourceBoundaryIndex + 1) {
|
|
25083
25488
|
return {
|
|
25084
25489
|
ok: false,
|
|
25085
25490
|
error: {
|
|
@@ -25088,19 +25493,19 @@ async function executeExternalThreadRollback(input) {
|
|
|
25088
25493
|
}
|
|
25089
25494
|
};
|
|
25090
25495
|
}
|
|
25091
|
-
const excludedActiveTurnCount = source.running ||
|
|
25092
|
-
const retainedCount =
|
|
25093
|
-
if (retainedCount ===
|
|
25496
|
+
const excludedActiveTurnCount = source.running || sourceRecord.turnMappings.length > derivedRecord.turnMappings.length ? 1 : 0;
|
|
25497
|
+
const retainedCount = derivedRecord.turnMappings.length - rollback.numTurns + excludedActiveTurnCount;
|
|
25498
|
+
if (retainedCount === derivedRecord.turnMappings.length) {
|
|
25094
25499
|
return { ok: true, thread: derived.thread };
|
|
25095
25500
|
}
|
|
25096
|
-
const boundary =
|
|
25501
|
+
const boundary = sourceRecord.turnMappings[retainedCount - 1];
|
|
25097
25502
|
if (retainedCount < 1 || !boundary?.nativeCheckpointRef) {
|
|
25098
25503
|
return {
|
|
25099
25504
|
ok: false,
|
|
25100
25505
|
error: { code: -32080, message: "External Fork Checkpoint is unavailable" }
|
|
25101
25506
|
};
|
|
25102
25507
|
}
|
|
25103
|
-
const sourceNativeRef =
|
|
25508
|
+
const sourceNativeRef = sourceRecord.nativeSessionRef;
|
|
25104
25509
|
const adapter = adapters.get(source.harnessId);
|
|
25105
25510
|
if (!sourceNativeRef || !adapter) {
|
|
25106
25511
|
return {
|
|
@@ -25128,7 +25533,7 @@ async function executeExternalThreadRollback(input) {
|
|
|
25128
25533
|
}
|
|
25129
25534
|
const session = opened.value;
|
|
25130
25535
|
const finalNativeRef = session.initialState.nativeRef;
|
|
25131
|
-
if (!finalNativeRef || finalNativeRef.nativeSessionId === sourceNativeRef.nativeSessionId || finalNativeRef.nativeSessionId ===
|
|
25536
|
+
if (!finalNativeRef || finalNativeRef.nativeSessionId === sourceNativeRef.nativeSessionId || finalNativeRef.nativeSessionId === derivedRecord.nativeSessionRef?.nativeSessionId) {
|
|
25132
25537
|
await session.close().catch(() => void 0);
|
|
25133
25538
|
return {
|
|
25134
25539
|
ok: false,
|
|
@@ -25150,8 +25555,8 @@ async function executeExternalThreadRollback(input) {
|
|
|
25150
25555
|
let aligned;
|
|
25151
25556
|
try {
|
|
25152
25557
|
aligned = await repository.commitForkRollback(
|
|
25153
|
-
|
|
25154
|
-
|
|
25558
|
+
derivedRecord,
|
|
25559
|
+
sourceRecord,
|
|
25155
25560
|
finalNativeRef,
|
|
25156
25561
|
snapshot.value
|
|
25157
25562
|
);
|
|
@@ -25396,9 +25801,43 @@ var ExternalThreadRuntime = class {
|
|
|
25396
25801
|
} catch (error51) {
|
|
25397
25802
|
this.#diagnose(error51);
|
|
25398
25803
|
}
|
|
25804
|
+
await this.#retireSubagents(current.id);
|
|
25399
25805
|
this.#threads.delete(current.id);
|
|
25400
25806
|
return this.register(input);
|
|
25401
25807
|
}
|
|
25808
|
+
async #retireSubagents(parentId) {
|
|
25809
|
+
const ancestors = /* @__PURE__ */ new Map();
|
|
25810
|
+
const descendant = async (record3) => {
|
|
25811
|
+
const visited = /* @__PURE__ */ new Set();
|
|
25812
|
+
let ownerId = record3?.subagent?.parentHostThreadId;
|
|
25813
|
+
while (ownerId && !visited.has(ownerId)) {
|
|
25814
|
+
if (ownerId === parentId) return true;
|
|
25815
|
+
visited.add(ownerId);
|
|
25816
|
+
let ancestor = ancestors.get(ownerId);
|
|
25817
|
+
if (!ancestor) {
|
|
25818
|
+
ancestor = this.#repository.find(ownerId);
|
|
25819
|
+
ancestors.set(ownerId, ancestor);
|
|
25820
|
+
}
|
|
25821
|
+
ownerId = (await ancestor)?.subagent?.parentHostThreadId;
|
|
25822
|
+
}
|
|
25823
|
+
return false;
|
|
25824
|
+
};
|
|
25825
|
+
for (const [id2, restoring] of [...this.#restores]) {
|
|
25826
|
+
if (await descendant(await this.#repository.find(id2))) {
|
|
25827
|
+
await restoring.catch(this.#diagnose);
|
|
25828
|
+
}
|
|
25829
|
+
}
|
|
25830
|
+
for (const child of this.#threads.values()) {
|
|
25831
|
+
if (!await descendant(child.record)) continue;
|
|
25832
|
+
this.#threads.delete(child.id);
|
|
25833
|
+
try {
|
|
25834
|
+
await child.session.close();
|
|
25835
|
+
await child.outputTask;
|
|
25836
|
+
} catch (error51) {
|
|
25837
|
+
this.#diagnose(error51);
|
|
25838
|
+
}
|
|
25839
|
+
}
|
|
25840
|
+
}
|
|
25402
25841
|
async locate(threadId3) {
|
|
25403
25842
|
const loaded = this.#threads.get(threadId3);
|
|
25404
25843
|
if (loaded) return { kind: "external", record: loaded.record, thread: loaded };
|
|
@@ -25509,6 +25948,10 @@ var ExternalThreadRuntime = class {
|
|
|
25509
25948
|
nativeSubagentId: subagent.nativeSubagentId,
|
|
25510
25949
|
cwd: record3.cwd
|
|
25511
25950
|
});
|
|
25951
|
+
const latest = await this.#repository.find(record3.hostThreadId);
|
|
25952
|
+
if (latest?.state === "ready" && latest.nativeSessionRef && JSON.stringify(latest.nativeSessionRef) !== JSON.stringify(parent)) {
|
|
25953
|
+
return this.#restore(latest);
|
|
25954
|
+
}
|
|
25512
25955
|
if (!snapshot.ok) {
|
|
25513
25956
|
throw new ExternalThreadOpenError(mapExternalThreadHarnessError(snapshot.error, "read"));
|
|
25514
25957
|
}
|
|
@@ -25785,11 +26228,11 @@ var ExternalTurnSteering = class {
|
|
|
25785
26228
|
};
|
|
25786
26229
|
|
|
25787
26230
|
// packages/host-runtime/src/harness-delegation-coordinator.ts
|
|
25788
|
-
import { createHash as
|
|
25789
|
-
import
|
|
26231
|
+
import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
|
|
26232
|
+
import path7 from "node:path";
|
|
25790
26233
|
|
|
25791
26234
|
// packages/host-runtime/src/delegation-snapshot.ts
|
|
25792
|
-
import { createHash as
|
|
26235
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
25793
26236
|
var CURSOR_PREFIX = "codexhost:thread-messages:v1:";
|
|
25794
26237
|
var DEFAULT_MESSAGE_LIMIT = 25;
|
|
25795
26238
|
var MAX_MESSAGE_LIMIT = 100;
|
|
@@ -25843,7 +26286,7 @@ function allVisibleMessages(turns) {
|
|
|
25843
26286
|
return messages;
|
|
25844
26287
|
}
|
|
25845
26288
|
function cursorFingerprint(threadId3) {
|
|
25846
|
-
return
|
|
26289
|
+
return createHash4("sha256").update(threadId3).digest("hex");
|
|
25847
26290
|
}
|
|
25848
26291
|
function encodeCursor(threadId3, offset) {
|
|
25849
26292
|
const payload = JSON.stringify({ version: 1, fingerprint: cursorFingerprint(threadId3), offset });
|
|
@@ -25898,15 +26341,21 @@ function projectDelegationThreadSnapshot(input) {
|
|
|
25898
26341
|
const latestTurnStatus = latestTurn ? turnStatus2(latestTurn.status) : null;
|
|
25899
26342
|
const status = input.running ? "running" : latestTurnStatus === "failed" || latestTurnStatus === "interrupted" ? latestTurnStatus : threadStatus(input.thread.status, input.running);
|
|
25900
26343
|
const latestTurnMessages = latestTurnId ? visible.filter((message) => message.turnId === latestTurnId && message.role === "agent") : [];
|
|
25901
|
-
const final = latestTurnMessages.filter((message) => message.phase === "final").at(-1);
|
|
25902
|
-
const progress = latestTurnMessages.filter((message) => message.phase !== "final").map(({ id: id2, turnId, text }) => ({ id: id2, turnId, text }));
|
|
26344
|
+
const final = latestTurnMessages.filter((message) => message.phase === "final" && message.text.trim()).at(-1);
|
|
26345
|
+
const progress = latestTurnMessages.filter((message) => message.phase !== "final" && message.text.trim()).map(({ id: id2, turnId, text }) => ({ id: id2, turnId, text }));
|
|
25903
26346
|
const result = input.running ? { availability: "pending" } : final ? { availability: "available", text: final.text } : {
|
|
25904
26347
|
availability: "unavailable",
|
|
25905
26348
|
...isRecord8(latestTurn?.error) && typeof latestTurn.error.message === "string" ? { message: latestTurn.error.message } : {}
|
|
25906
26349
|
};
|
|
25907
26350
|
const offset = options2.view === "messages" ? decodeCursor(input.threadId, options2.cursor) : visible.length;
|
|
25908
|
-
const page = options2.view === "messages" ?
|
|
25909
|
-
|
|
26351
|
+
const page = options2.view === "messages" ? [] : void 0;
|
|
26352
|
+
let nextOffset = offset;
|
|
26353
|
+
if (page) {
|
|
26354
|
+
while (nextOffset < visible.length && page.length < options2.limit) {
|
|
26355
|
+
const message = visible[nextOffset++];
|
|
26356
|
+
if (message?.text.trim()) page.push(message);
|
|
26357
|
+
}
|
|
26358
|
+
}
|
|
25910
26359
|
return {
|
|
25911
26360
|
threadId: input.threadId,
|
|
25912
26361
|
harnessId: input.harnessId,
|
|
@@ -25914,7 +26363,10 @@ function projectDelegationThreadSnapshot(input) {
|
|
|
25914
26363
|
turn: latestTurnId && latestTurnStatus ? { turnId: latestTurnId, status: latestTurnStatus } : null,
|
|
25915
26364
|
progress,
|
|
25916
26365
|
result,
|
|
25917
|
-
...page ? {
|
|
26366
|
+
...page ? {
|
|
26367
|
+
messages: page,
|
|
26368
|
+
hasMore: visible.slice(nextOffset).some((message) => message.text.trim())
|
|
26369
|
+
} : {},
|
|
25918
26370
|
nextCursor: encodeCursor(input.threadId, nextOffset)
|
|
25919
26371
|
};
|
|
25920
26372
|
}
|
|
@@ -25929,10 +26381,10 @@ function terminal(status) {
|
|
|
25929
26381
|
return status === "completed" || status === "failed" || status === "interrupted";
|
|
25930
26382
|
}
|
|
25931
26383
|
function taskDigest(input) {
|
|
25932
|
-
return
|
|
26384
|
+
return createHash5("sha256").update(
|
|
25933
26385
|
JSON.stringify({
|
|
25934
26386
|
task: input.task,
|
|
25935
|
-
cwd:
|
|
26387
|
+
cwd: path7.resolve(input.cwd),
|
|
25936
26388
|
modelId: input.model?.id ?? null,
|
|
25937
26389
|
thinkingOptionId: input.thinkingOptionId ?? null
|
|
25938
26390
|
})
|
|
@@ -25946,11 +26398,11 @@ function statusFromThread(thread) {
|
|
|
25946
26398
|
return last ? "completed" : "creating";
|
|
25947
26399
|
}
|
|
25948
26400
|
function validateStart(input) {
|
|
25949
|
-
if (!input.task
|
|
26401
|
+
if (typeof input.task !== "string" || !input.task.trim())
|
|
25950
26402
|
throw new DelegationControlError("INVALID_ARGUMENT", "Task must not be empty");
|
|
25951
|
-
if (!input.cwd
|
|
26403
|
+
if (input.cwd !== void 0 && (typeof input.cwd !== "string" || !input.cwd.trim()))
|
|
25952
26404
|
throw new DelegationControlError("INVALID_ARGUMENT", "cwd must not be empty");
|
|
25953
|
-
if (input.requestId !== void 0 && !input.requestId.trim()) {
|
|
26405
|
+
if (input.requestId !== void 0 && (typeof input.requestId !== "string" || !input.requestId.trim())) {
|
|
25954
26406
|
throw new DelegationControlError("INVALID_ARGUMENT", "Request ID must not be empty");
|
|
25955
26407
|
}
|
|
25956
26408
|
}
|
|
@@ -25968,6 +26420,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
25968
26420
|
#cancelOfficial;
|
|
25969
26421
|
#startOfficial;
|
|
25970
26422
|
#listOfficial;
|
|
26423
|
+
#officialThreadCwd;
|
|
25971
26424
|
#activeOfficialParents;
|
|
25972
26425
|
constructor(input) {
|
|
25973
26426
|
this.#adapters = input.adapters;
|
|
@@ -25983,8 +26436,12 @@ var HarnessDelegationCoordinator = class {
|
|
|
25983
26436
|
this.#cancelOfficial = input.cancelOfficial;
|
|
25984
26437
|
this.#startOfficial = input.startOfficial;
|
|
25985
26438
|
this.#listOfficial = input.listOfficial;
|
|
26439
|
+
this.#officialThreadCwd = input.officialThreadCwd;
|
|
25986
26440
|
this.#activeOfficialParents = input.activeOfficialParents;
|
|
25987
26441
|
}
|
|
26442
|
+
async listHarnesses() {
|
|
26443
|
+
return { harnesses: ["codex", ...this.#adapters.keys()] };
|
|
26444
|
+
}
|
|
25988
26445
|
async inspect(input) {
|
|
25989
26446
|
if (input.harnessId === "codex") return this.#inspectOfficial(input);
|
|
25990
26447
|
const adapter = this.#adapters.get(input.harnessId);
|
|
@@ -25998,7 +26455,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
25998
26455
|
return {
|
|
25999
26456
|
harnessId: input.harnessId,
|
|
26000
26457
|
inspection: await adapter.inspect({
|
|
26001
|
-
...input.cwd ? { cwd:
|
|
26458
|
+
...input.cwd ? { cwd: path7.resolve(input.cwd) } : {},
|
|
26002
26459
|
...input.refresh !== void 0 ? { refresh: input.refresh } : {}
|
|
26003
26460
|
})
|
|
26004
26461
|
};
|
|
@@ -26006,7 +26463,13 @@ var HarnessDelegationCoordinator = class {
|
|
|
26006
26463
|
async start(input) {
|
|
26007
26464
|
validateStart(input);
|
|
26008
26465
|
const parentThreadId = await this.#resolveParent(input.parentThreadId);
|
|
26009
|
-
|
|
26466
|
+
const parent = await this.#parentMetadata(parentThreadId);
|
|
26467
|
+
const selectedCwd = input.cwd ?? parent.cwd ?? process.cwd();
|
|
26468
|
+
if (input.harnessId === "codex") {
|
|
26469
|
+
const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
|
|
26470
|
+
return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
|
|
26471
|
+
}
|
|
26472
|
+
const startInput = { ...input, parentThreadId, cwd: path7.resolve(selectedCwd) };
|
|
26010
26473
|
if (!this.#adapters.has(input.harnessId)) {
|
|
26011
26474
|
throw new DelegationControlError(
|
|
26012
26475
|
"HARNESS_NOT_FOUND",
|
|
@@ -26015,7 +26478,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
26015
26478
|
);
|
|
26016
26479
|
}
|
|
26017
26480
|
const targetHarnessId = input.harnessId;
|
|
26018
|
-
const digest2 = taskDigest(
|
|
26481
|
+
const digest2 = taskDigest(startInput);
|
|
26019
26482
|
const duplicate = input.requestId ? await this.#repository.findDelegationByRequest(input.requestId) : await this.#repository.findRecentDelegation({
|
|
26020
26483
|
parentHostThreadId: hostThreadIdSchema.parse(parentThreadId),
|
|
26021
26484
|
targetHarnessId: harnessIdSchema.parse(targetHarnessId),
|
|
@@ -26042,21 +26505,20 @@ var HarnessDelegationCoordinator = class {
|
|
|
26042
26505
|
if (input.model || input.thinkingOptionId) {
|
|
26043
26506
|
const inspected = await this.inspect({
|
|
26044
26507
|
harnessId: targetHarnessId,
|
|
26045
|
-
cwd:
|
|
26508
|
+
cwd: startInput.cwd
|
|
26046
26509
|
});
|
|
26047
26510
|
this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
|
|
26048
26511
|
}
|
|
26049
|
-
const
|
|
26050
|
-
const
|
|
26051
|
-
const
|
|
26052
|
-
const
|
|
26053
|
-
const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID4();
|
|
26512
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID5());
|
|
26513
|
+
const childThreadId = hostThreadIdSchema.parse(randomUUID5());
|
|
26514
|
+
const turnId = hostTurnIdSchema.parse(randomUUID5());
|
|
26515
|
+
const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID5();
|
|
26054
26516
|
let record3 = await this.#repository.createProvisional(
|
|
26055
26517
|
createExternalThreadRecordInput({
|
|
26056
26518
|
hostThreadId: childThreadId,
|
|
26057
26519
|
createRequestId,
|
|
26058
26520
|
harnessId: harnessIdSchema.parse(targetHarnessId),
|
|
26059
|
-
cwd:
|
|
26521
|
+
cwd: startInput.cwd,
|
|
26060
26522
|
title: input.task.trim().slice(0, 120),
|
|
26061
26523
|
transportModelId: input.model || input.thinkingOptionId ? encodeExternalTransportSelection(targetHarnessId, {
|
|
26062
26524
|
...input.model ? { model: input.model } : {},
|
|
@@ -26127,17 +26589,21 @@ var HarnessDelegationCoordinator = class {
|
|
|
26127
26589
|
}
|
|
26128
26590
|
await this.#repository.setDelegationStatus(delegationId, "running");
|
|
26129
26591
|
await this.#notifyThreadStarted(thread.thread);
|
|
26130
|
-
return
|
|
26131
|
-
|
|
26132
|
-
|
|
26133
|
-
|
|
26134
|
-
|
|
26135
|
-
|
|
26136
|
-
|
|
26137
|
-
|
|
26138
|
-
|
|
26139
|
-
|
|
26140
|
-
|
|
26592
|
+
return {
|
|
26593
|
+
...this.#result(delegationId, childThreadId, turnId, targetHarnessId, "running", {
|
|
26594
|
+
requested: {
|
|
26595
|
+
...input.model ? { model: input.model } : {},
|
|
26596
|
+
...input.thinkingOptionId ? { thinkingOptionId: input.thinkingOptionId } : {}
|
|
26597
|
+
},
|
|
26598
|
+
effective: {
|
|
26599
|
+
...thread.stateObserver.state.effectiveModel ? { effectiveModel: thread.stateObserver.state.effectiveModel } : {},
|
|
26600
|
+
...thread.stateObserver.state.resolvedModelLabel ? { resolvedModelLabel: thread.stateObserver.state.resolvedModelLabel } : {},
|
|
26601
|
+
...thread.stateObserver.state.effectiveThinkingOptionId ? { effectiveThinkingOptionId: thread.stateObserver.state.effectiveThinkingOptionId } : {}
|
|
26602
|
+
}
|
|
26603
|
+
}),
|
|
26604
|
+
cwd: record3.cwd,
|
|
26605
|
+
parentThreadId
|
|
26606
|
+
};
|
|
26141
26607
|
} catch (error51) {
|
|
26142
26608
|
if (session) await session.close().catch(() => void 0);
|
|
26143
26609
|
this.#externalRuntime.remove(childThreadId);
|
|
@@ -26171,7 +26637,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
26171
26637
|
if (thread.running || thread.activeTurnId) {
|
|
26172
26638
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
26173
26639
|
}
|
|
26174
|
-
const turnId = hostTurnIdSchema.parse(
|
|
26640
|
+
const turnId = hostTurnIdSchema.parse(randomUUID5());
|
|
26175
26641
|
try {
|
|
26176
26642
|
await this.#startExternalTurn(thread, input.message, turnId);
|
|
26177
26643
|
} catch (error51) {
|
|
@@ -26366,18 +26832,24 @@ var HarnessDelegationCoordinator = class {
|
|
|
26366
26832
|
}
|
|
26367
26833
|
async #parentMetadata(parentThreadId) {
|
|
26368
26834
|
const record3 = await this.#repository.find(parentThreadId);
|
|
26369
|
-
return { harnessId: record3
|
|
26835
|
+
if (record3) return { harnessId: record3.harnessId, cwd: record3.cwd };
|
|
26836
|
+
const cwd = await this.#officialThreadCwd(parentThreadId).catch(() => void 0);
|
|
26837
|
+
return { harnessId: "codex", ...cwd ? { cwd } : {} };
|
|
26370
26838
|
}
|
|
26371
26839
|
async #existingResult(delegation) {
|
|
26372
26840
|
const record3 = await this.#repository.find(delegation.childHostThreadId);
|
|
26373
26841
|
const turnId = record3?.turnMappings.at(-1)?.hostTurnId ?? "pending";
|
|
26374
|
-
return
|
|
26375
|
-
|
|
26376
|
-
|
|
26377
|
-
|
|
26378
|
-
|
|
26379
|
-
|
|
26380
|
-
|
|
26842
|
+
return {
|
|
26843
|
+
...this.#result(
|
|
26844
|
+
delegation.delegationId,
|
|
26845
|
+
delegation.childHostThreadId,
|
|
26846
|
+
turnId,
|
|
26847
|
+
delegation.targetHarnessId,
|
|
26848
|
+
delegation.status
|
|
26849
|
+
),
|
|
26850
|
+
...record3 ? { cwd: record3.cwd } : {},
|
|
26851
|
+
parentThreadId: delegation.parentHostThreadId
|
|
26852
|
+
};
|
|
26381
26853
|
}
|
|
26382
26854
|
#turnResult(threadId3, turnId, harnessId) {
|
|
26383
26855
|
return {
|
|
@@ -26410,7 +26882,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
26410
26882
|
|
|
26411
26883
|
// packages/host-runtime/src/harness-plugin-loader.ts
|
|
26412
26884
|
import { readdir as readdir3, realpath as realpath2 } from "node:fs/promises";
|
|
26413
|
-
import
|
|
26885
|
+
import path9 from "node:path";
|
|
26414
26886
|
import { pathToFileURL } from "node:url";
|
|
26415
26887
|
|
|
26416
26888
|
// packages/host-runtime/src/harness-plugin-registry.ts
|
|
@@ -26448,16 +26920,16 @@ var HarnessPluginRegistry = class {
|
|
|
26448
26920
|
|
|
26449
26921
|
// packages/host-runtime/src/plugin-files.ts
|
|
26450
26922
|
import { open as open4, realpath, stat as stat2 } from "node:fs/promises";
|
|
26451
|
-
import
|
|
26923
|
+
import path8 from "node:path";
|
|
26452
26924
|
function inside(root, candidate) {
|
|
26453
|
-
const relative =
|
|
26454
|
-
return relative !== "" && !
|
|
26925
|
+
const relative = path8.relative(root, candidate);
|
|
26926
|
+
return relative !== "" && !path8.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path8.sep}`);
|
|
26455
26927
|
}
|
|
26456
26928
|
async function pluginResourcePath(root, relative) {
|
|
26457
|
-
if (
|
|
26929
|
+
if (path8.isAbsolute(relative) || !inside(root, path8.resolve(root, relative))) {
|
|
26458
26930
|
throw new Error("Plugin resource escapes its root");
|
|
26459
26931
|
}
|
|
26460
|
-
const resolved = await realpath(
|
|
26932
|
+
const resolved = await realpath(path8.resolve(root, relative));
|
|
26461
26933
|
if (!inside(root, resolved) || !(await stat2(resolved)).isFile()) {
|
|
26462
26934
|
throw new Error("Plugin resource must be a regular file inside its root");
|
|
26463
26935
|
}
|
|
@@ -26602,7 +27074,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
26602
27074
|
const enabledIds = /* @__PURE__ */ new Set();
|
|
26603
27075
|
const roots = /* @__PURE__ */ new Set();
|
|
26604
27076
|
for (const configuredRoot of options2.roots) {
|
|
26605
|
-
if (!
|
|
27077
|
+
if (!path9.isAbsolute(configuredRoot)) {
|
|
26606
27078
|
diagnose({ code: "invalidRoot" });
|
|
26607
27079
|
continue;
|
|
26608
27080
|
}
|
|
@@ -26632,7 +27104,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
26632
27104
|
for (const directory of directories) {
|
|
26633
27105
|
try {
|
|
26634
27106
|
const file2 = await pluginResourcePath(root, `${directory.name}/manifest.json`);
|
|
26635
|
-
const pluginRoot = await realpath2(
|
|
27107
|
+
const pluginRoot = await realpath2(path9.join(root, directory.name));
|
|
26636
27108
|
await pluginResourcePath(pluginRoot, "manifest.json");
|
|
26637
27109
|
const manifest = harnessPluginManifestSchema.parse(
|
|
26638
27110
|
JSON.parse(
|
|
@@ -26779,8 +27251,8 @@ function spawnOfficialAppServerConnection(input) {
|
|
|
26779
27251
|
|
|
26780
27252
|
// packages/host-runtime/src/account/account-repository.ts
|
|
26781
27253
|
import { mkdir as mkdir4, readFile as readFile5, rename as rename3, writeFile as writeFile3 } from "node:fs/promises";
|
|
26782
|
-
import
|
|
26783
|
-
import { randomUUID as
|
|
27254
|
+
import path10 from "node:path";
|
|
27255
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
26784
27256
|
function validateAccountId(accountId) {
|
|
26785
27257
|
if (!/^[A-Za-z0-9._~-]+$/u.test(accountId)) {
|
|
26786
27258
|
throw new Error("Codex Account ID must be non-empty and filename-safe");
|
|
@@ -26798,19 +27270,19 @@ var AccountRepository = class {
|
|
|
26798
27270
|
#mutationTail = Promise.resolve();
|
|
26799
27271
|
#writeTail = Promise.resolve();
|
|
26800
27272
|
constructor(input) {
|
|
26801
|
-
this.#file =
|
|
27273
|
+
this.#file = path10.join(path10.resolve(input.directory), "accounts.json");
|
|
26802
27274
|
this.#defaultAccount = {
|
|
26803
27275
|
...input.defaultAccount,
|
|
26804
27276
|
label: input.defaultAccount.label ?? input.defaultAccount.accountId
|
|
26805
27277
|
};
|
|
26806
27278
|
validateAccountId(this.#defaultAccount.accountId);
|
|
26807
|
-
if (!
|
|
27279
|
+
if (!path10.isAbsolute(this.#defaultAccount.codexHome)) {
|
|
26808
27280
|
throw new Error("Codex Account CODEX_HOME must be absolute");
|
|
26809
27281
|
}
|
|
26810
27282
|
}
|
|
26811
27283
|
async initialize() {
|
|
26812
27284
|
if (this.#initialized) return;
|
|
26813
|
-
await mkdir4(
|
|
27285
|
+
await mkdir4(path10.dirname(this.#file), { recursive: true });
|
|
26814
27286
|
let stored = null;
|
|
26815
27287
|
try {
|
|
26816
27288
|
stored = JSON.parse(await readFile5(this.#file, "utf8"));
|
|
@@ -26878,7 +27350,7 @@ var AccountRepository = class {
|
|
|
26878
27350
|
async upsert(input) {
|
|
26879
27351
|
this.#requireInitialized();
|
|
26880
27352
|
validateAccountId(input.accountId);
|
|
26881
|
-
if (!
|
|
27353
|
+
if (!path10.isAbsolute(input.codexHome))
|
|
26882
27354
|
throw new Error("Codex Account CODEX_HOME must be absolute");
|
|
26883
27355
|
return this.#mutate(async () => {
|
|
26884
27356
|
const previous = this.#accounts.get(input.accountId);
|
|
@@ -26887,7 +27359,7 @@ var AccountRepository = class {
|
|
|
26887
27359
|
const planType = input.planType === null ? void 0 : input.planType ?? previous?.planType;
|
|
26888
27360
|
const account = {
|
|
26889
27361
|
accountId: input.accountId,
|
|
26890
|
-
codexHome:
|
|
27362
|
+
codexHome: path10.normalize(input.codexHome),
|
|
26891
27363
|
...email3 ? { email: email3 } : {},
|
|
26892
27364
|
...planType ? { planType } : {},
|
|
26893
27365
|
label: input.label ?? previous?.label ?? input.accountId,
|
|
@@ -26901,7 +27373,7 @@ var AccountRepository = class {
|
|
|
26901
27373
|
}
|
|
26902
27374
|
#validateAccount(account) {
|
|
26903
27375
|
validateAccountId(account.accountId);
|
|
26904
|
-
if (!
|
|
27376
|
+
if (!path10.isAbsolute(account.codexHome)) throw new Error("Stored CODEX_HOME must be absolute");
|
|
26905
27377
|
if (account.email && (!account.email.includes("@") || account.email.length > 320)) {
|
|
26906
27378
|
throw new Error("Stored Codex Account email is invalid");
|
|
26907
27379
|
}
|
|
@@ -26922,7 +27394,7 @@ var AccountRepository = class {
|
|
|
26922
27394
|
accounts: [...this.#accounts.values()]
|
|
26923
27395
|
};
|
|
26924
27396
|
const operation = this.#writeTail.then(async () => {
|
|
26925
|
-
const temporary = `${this.#file}.${process.pid}.${
|
|
27397
|
+
const temporary = `${this.#file}.${process.pid}.${randomUUID6()}.tmp`;
|
|
26926
27398
|
await writeFile3(temporary, `${JSON.stringify(value2, null, 2)}
|
|
26927
27399
|
`, { mode: 384 });
|
|
26928
27400
|
await rename3(temporary, this.#file);
|
|
@@ -26945,19 +27417,19 @@ function isMissingFile(error51) {
|
|
|
26945
27417
|
|
|
26946
27418
|
// packages/host-runtime/src/account/thread-account-store.ts
|
|
26947
27419
|
import { mkdir as mkdir5, readFile as readFile6, rename as rename4, writeFile as writeFile4 } from "node:fs/promises";
|
|
26948
|
-
import { randomUUID as
|
|
26949
|
-
import
|
|
27420
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
27421
|
+
import path11 from "node:path";
|
|
26950
27422
|
var ThreadAccountStore = class {
|
|
26951
27423
|
#file;
|
|
26952
27424
|
#bindings = /* @__PURE__ */ new Map();
|
|
26953
27425
|
#initialized = false;
|
|
26954
27426
|
#writeTail = Promise.resolve();
|
|
26955
27427
|
constructor(input) {
|
|
26956
|
-
this.#file =
|
|
27428
|
+
this.#file = path11.join(path11.resolve(input.directory), "thread-accounts.json");
|
|
26957
27429
|
}
|
|
26958
27430
|
async initialize() {
|
|
26959
27431
|
if (this.#initialized) return;
|
|
26960
|
-
await mkdir5(
|
|
27432
|
+
await mkdir5(path11.dirname(this.#file), { recursive: true });
|
|
26961
27433
|
try {
|
|
26962
27434
|
const stored = JSON.parse(await readFile6(this.#file, "utf8"));
|
|
26963
27435
|
if (stored.formatVersion !== 1 || !stored.bindings || typeof stored.bindings !== "object") {
|
|
@@ -27016,7 +27488,7 @@ var ThreadAccountStore = class {
|
|
|
27016
27488
|
bindings: Object.fromEntries(this.#bindings)
|
|
27017
27489
|
};
|
|
27018
27490
|
const operation = this.#writeTail.then(async () => {
|
|
27019
|
-
const temporary = `${this.#file}.${process.pid}.${
|
|
27491
|
+
const temporary = `${this.#file}.${process.pid}.${randomUUID7()}.tmp`;
|
|
27020
27492
|
await writeFile4(temporary, `${JSON.stringify(value2, null, 2)}
|
|
27021
27493
|
`, { mode: 384 });
|
|
27022
27494
|
await rename4(temporary, this.#file);
|
|
@@ -27033,7 +27505,7 @@ function isMissingFile2(error51) {
|
|
|
27033
27505
|
import { mkdir as mkdir6 } from "node:fs/promises";
|
|
27034
27506
|
|
|
27035
27507
|
// packages/host-runtime/src/official-request-broker.ts
|
|
27036
|
-
import { randomUUID as
|
|
27508
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
27037
27509
|
var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
|
|
27038
27510
|
var MAX_RETIRED_IDS = 1024;
|
|
27039
27511
|
function isRecord9(value2) {
|
|
@@ -27049,7 +27521,7 @@ var OfficialRequestBroker = class {
|
|
|
27049
27521
|
constructor(input) {
|
|
27050
27522
|
this.#send = input.send;
|
|
27051
27523
|
this.#timeoutMs = input.timeoutMs ?? 3e4;
|
|
27052
|
-
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${
|
|
27524
|
+
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID8()}`);
|
|
27053
27525
|
}
|
|
27054
27526
|
get pendingCount() {
|
|
27055
27527
|
return this.#pending.size;
|
|
@@ -27413,21 +27885,45 @@ function externalAnchor(entry) {
|
|
|
27413
27885
|
if (entry.source !== "external") throw new Error("Expected an External Thread list entry");
|
|
27414
27886
|
return { timestamp: entry.timestamp, threadId: threadId(entry.thread) };
|
|
27415
27887
|
}
|
|
27416
|
-
function includesExternalRecord(record3, query) {
|
|
27888
|
+
function includesExternalRecord(record3, query, byId) {
|
|
27417
27889
|
if (record3.state !== "ready" || !record3.nativeSessionRef) return false;
|
|
27418
|
-
|
|
27890
|
+
let current = record3;
|
|
27891
|
+
const owners = /* @__PURE__ */ new Set();
|
|
27892
|
+
while (current.subagent) {
|
|
27893
|
+
if (owners.has(current.hostThreadId)) return false;
|
|
27894
|
+
owners.add(current.hostThreadId);
|
|
27895
|
+
const parent = byId.get(current.subagent.parentHostThreadId);
|
|
27896
|
+
if (!parent || parent.state !== "ready" || parent.harnessId !== current.harnessId || parent.nativeSessionRef?.nativeSessionId !== current.nativeSessionRef?.nativeSessionId)
|
|
27897
|
+
return false;
|
|
27898
|
+
current = parent;
|
|
27899
|
+
}
|
|
27900
|
+
const sourceKind = record3.subagent ? "subAgentThreadSpawn" : "vscode";
|
|
27901
|
+
const scoped = query.parentThreadId !== null || query.ancestorThreadId !== null;
|
|
27902
|
+
if (record3.subagent && !scoped && !query.sourceKinds?.some((kind) => kind === "subAgent" || kind === "subAgentThreadSpawn"))
|
|
27903
|
+
return false;
|
|
27904
|
+
if (query.parentThreadId !== null && record3.subagent?.parentHostThreadId !== query.parentThreadId)
|
|
27905
|
+
return false;
|
|
27906
|
+
if (query.ancestorThreadId !== null) {
|
|
27907
|
+
let parentId = record3.subagent?.parentHostThreadId;
|
|
27908
|
+
const visited = /* @__PURE__ */ new Set([record3.hostThreadId]);
|
|
27909
|
+
while (parentId && parentId !== query.ancestorThreadId && !visited.has(parentId)) {
|
|
27910
|
+
visited.add(parentId);
|
|
27911
|
+
parentId = byId.get(parentId)?.subagent?.parentHostThreadId;
|
|
27912
|
+
}
|
|
27913
|
+
if (record3.hostThreadId === query.ancestorThreadId || parentId !== query.ancestorThreadId)
|
|
27914
|
+
return false;
|
|
27915
|
+
}
|
|
27419
27916
|
if (record3.archived !== query.archived) return false;
|
|
27420
27917
|
if (query.cwd !== null && !query.cwd.includes(record3.cwd)) return false;
|
|
27421
27918
|
if (query.modelProviders !== null && query.modelProviders.length > 0 && !query.modelProviders.includes("codexhost")) {
|
|
27422
27919
|
return false;
|
|
27423
27920
|
}
|
|
27424
|
-
if (query.sourceKinds !== null && query.sourceKinds.length > 0 && !query.sourceKinds.includes("
|
|
27921
|
+
if (query.sourceKinds !== null && query.sourceKinds.length > 0 && !query.sourceKinds.includes(sourceKind) && !(record3.subagent && query.sourceKinds.includes("subAgent"))) {
|
|
27425
27922
|
return false;
|
|
27426
27923
|
}
|
|
27427
27924
|
if (query.searchTerm !== null && !record3.title.toLowerCase().includes(query.searchTerm.toLowerCase())) {
|
|
27428
27925
|
return false;
|
|
27429
27926
|
}
|
|
27430
|
-
if (query.parentThreadId !== null || query.ancestorThreadId !== null) return false;
|
|
27431
27927
|
if (query.isPinned === true) return false;
|
|
27432
27928
|
return true;
|
|
27433
27929
|
}
|
|
@@ -27437,25 +27933,25 @@ function resolveExternalSessionTreeIds(records) {
|
|
|
27437
27933
|
const resolve = (start) => {
|
|
27438
27934
|
const cached2 = resolved.get(start.hostThreadId);
|
|
27439
27935
|
if (cached2) return cached2;
|
|
27440
|
-
const
|
|
27936
|
+
const path26 = [];
|
|
27441
27937
|
const visited = /* @__PURE__ */ new Set();
|
|
27442
27938
|
let current = start;
|
|
27443
27939
|
while (true) {
|
|
27444
27940
|
const known = resolved.get(current.hostThreadId);
|
|
27445
27941
|
if (known) {
|
|
27446
|
-
for (const record3 of
|
|
27942
|
+
for (const record3 of path26) resolved.set(record3.hostThreadId, known);
|
|
27447
27943
|
return known;
|
|
27448
27944
|
}
|
|
27449
27945
|
if (visited.has(current.hostThreadId)) {
|
|
27450
27946
|
throw new Error("External Thread Fork tree contains a cycle");
|
|
27451
27947
|
}
|
|
27452
27948
|
visited.add(current.hostThreadId);
|
|
27453
|
-
|
|
27454
|
-
const sourceId = current.forkSource?.hostThreadId;
|
|
27949
|
+
path26.push(current);
|
|
27950
|
+
const sourceId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
|
|
27455
27951
|
const source = sourceId ? byId.get(sourceId) : void 0;
|
|
27456
27952
|
if (!source) {
|
|
27457
27953
|
const root = current.hostThreadId;
|
|
27458
|
-
for (const record3 of
|
|
27954
|
+
for (const record3 of path26) resolved.set(record3.hostThreadId, root);
|
|
27459
27955
|
return root;
|
|
27460
27956
|
}
|
|
27461
27957
|
current = source;
|
|
@@ -27467,7 +27963,8 @@ function resolveExternalSessionTreeIds(records) {
|
|
|
27467
27963
|
function listExternalThreadMetadata(input) {
|
|
27468
27964
|
if (!input.query.supportsExternal) return { data: [], hasMore: false };
|
|
27469
27965
|
const sessionIds = resolveExternalSessionTreeIds(input.records);
|
|
27470
|
-
const
|
|
27966
|
+
const byId = new Map(input.records.map((record3) => [record3.hostThreadId, record3]));
|
|
27967
|
+
const entries = input.records.filter((record3) => includesExternalRecord(record3, input.query, byId)).map((record3) => {
|
|
27471
27968
|
const runtime = input.runtimeFor(record3.hostThreadId);
|
|
27472
27969
|
const sessionId = sessionIds.get(record3.hostThreadId);
|
|
27473
27970
|
if (!sessionId) throw new Error("External Thread Session tree could not be resolved");
|
|
@@ -27549,6 +28046,7 @@ function threadId2(entry) {
|
|
|
27549
28046
|
return entry.thread.id;
|
|
27550
28047
|
}
|
|
27551
28048
|
async function aggregateOfficialAccountThreadListPage(input) {
|
|
28049
|
+
const pageLimit = typeof input.params.limit === "number" ? input.params.limit : input.query.limit;
|
|
27552
28050
|
const cursorValue2 = typeof input.params.cursor === "string" ? input.params.cursor : null;
|
|
27553
28051
|
const cursor = cursorValue2 ? decodeCursor2(cursorValue2) : { accounts: initialAccounts(input.accountIds) };
|
|
27554
28052
|
const sources = Object.entries(cursor.accounts).map(([accountId, state]) => ({
|
|
@@ -27585,7 +28083,7 @@ async function aggregateOfficialAccountThreadListPage(input) {
|
|
|
27585
28083
|
if (source.done) return null;
|
|
27586
28084
|
}
|
|
27587
28085
|
source.batchStart = source.cursor;
|
|
27588
|
-
const page = await request(source, source.cursor, Math.max(1,
|
|
28086
|
+
const page = await request(source, source.cursor, Math.max(1, pageLimit));
|
|
27589
28087
|
if (!source.requestedThisPage) {
|
|
27590
28088
|
source.backwardsCursor = page.backwardsCursor;
|
|
27591
28089
|
source.requestedThisPage = true;
|
|
@@ -27607,7 +28105,7 @@ async function aggregateOfficialAccountThreadListPage(input) {
|
|
|
27607
28105
|
};
|
|
27608
28106
|
const output = [];
|
|
27609
28107
|
const emitted = /* @__PURE__ */ new Set();
|
|
27610
|
-
while (output.length <
|
|
28108
|
+
while (output.length < pageLimit) {
|
|
27611
28109
|
const candidates = await Promise.all(
|
|
27612
28110
|
sources.map(async (source) => ({ source, entry: await ensure(source) }))
|
|
27613
28111
|
);
|
|
@@ -28141,18 +28639,18 @@ var AppServerHost = class {
|
|
|
28141
28639
|
};
|
|
28142
28640
|
this.#writer = new OrderedWriter(this.#options.desktopOutput);
|
|
28143
28641
|
const environment = this.#options.environment ?? process.env;
|
|
28144
|
-
const dataDirectory =
|
|
28145
|
-
environment.CODEXHOST_DATA_DIR ??
|
|
28642
|
+
const dataDirectory = path12.resolve(
|
|
28643
|
+
environment.CODEXHOST_DATA_DIR ?? path12.join(os2.homedir(), ".codexhost")
|
|
28146
28644
|
);
|
|
28147
28645
|
const accountRepository = options2.accountRepository ?? new AccountRepository({
|
|
28148
|
-
directory:
|
|
28646
|
+
directory: path12.join(dataDirectory, "codex-accounts"),
|
|
28149
28647
|
defaultAccount: {
|
|
28150
28648
|
accountId: "default",
|
|
28151
|
-
codexHome:
|
|
28649
|
+
codexHome: path12.resolve(environment.CODEX_HOME ?? path12.join(os2.homedir(), ".codex")),
|
|
28152
28650
|
label: "Default Codex Account"
|
|
28153
28651
|
}
|
|
28154
28652
|
});
|
|
28155
|
-
const threadAccountStore = options2.threadAccountStore ?? new ThreadAccountStore({ directory:
|
|
28653
|
+
const threadAccountStore = options2.threadAccountStore ?? new ThreadAccountStore({ directory: path12.join(dataDirectory, "codex-accounts") });
|
|
28156
28654
|
this.#accountRepository = accountRepository;
|
|
28157
28655
|
this.#threadAccountStore = threadAccountStore;
|
|
28158
28656
|
this.#accountDataDirectory = dataDirectory;
|
|
@@ -28199,9 +28697,11 @@ var AppServerHost = class {
|
|
|
28199
28697
|
cancelOfficial: (input) => this.#cancelOfficialDelegationThread(input),
|
|
28200
28698
|
startOfficial: (input) => this.#startOfficialDelegation(input),
|
|
28201
28699
|
listOfficial: (input) => this.#listDelegationThreads(input),
|
|
28700
|
+
officialThreadCwd: (threadId3) => this.#readOfficialThreadCwd(threadId3),
|
|
28202
28701
|
activeOfficialParents: () => [...this.#activeOfficialTurns.keys()]
|
|
28203
28702
|
});
|
|
28204
28703
|
const unregisterDelegationApi = options2.onDelegationApi?.({
|
|
28704
|
+
listHarnesses: () => this.#delegationCoordinator.listHarnesses(),
|
|
28205
28705
|
inspect: (input) => this.#delegationCoordinator.inspect(input),
|
|
28206
28706
|
start: (input) => this.#delegationCoordinator.start(input),
|
|
28207
28707
|
send: (input) => this.#delegationCoordinator.send(input),
|
|
@@ -28965,7 +29465,7 @@ var AppServerHost = class {
|
|
|
28965
29465
|
throw new Error("Unknown Codex Account");
|
|
28966
29466
|
const runtime = await this.#codexRuntimePool.get(params2.accountId);
|
|
28967
29467
|
const response2 = await runtime.request("account/rateLimitResetCredit/consume", {
|
|
28968
|
-
idempotencyKey: params2.idempotencyKey ??
|
|
29468
|
+
idempotencyKey: params2.idempotencyKey ?? randomUUID9()
|
|
28969
29469
|
});
|
|
28970
29470
|
if (isRecord12(response2.error)) {
|
|
28971
29471
|
await this.#writer.json(rpcEnvelope(request, { error: response2.error }));
|
|
@@ -29012,10 +29512,10 @@ var AppServerHost = class {
|
|
|
29012
29512
|
}
|
|
29013
29513
|
if (request.method === "codexhost/account/create") {
|
|
29014
29514
|
const params2 = codexAccountCreateParamsSchema.parse(requestObject(request));
|
|
29015
|
-
const accountId =
|
|
29515
|
+
const accountId = randomUUID9();
|
|
29016
29516
|
const account = await this.#accountRepository.upsert({
|
|
29017
29517
|
accountId,
|
|
29018
|
-
codexHome:
|
|
29518
|
+
codexHome: path12.join(this.#accountDataDirectory, "codex-homes", accountId),
|
|
29019
29519
|
label: params2.label ?? `Codex Account ${accountId.slice(0, 8)}`
|
|
29020
29520
|
});
|
|
29021
29521
|
const activeAccountId = await this.#accountRepository.getActiveAccountId();
|
|
@@ -29071,12 +29571,12 @@ var AppServerHost = class {
|
|
|
29071
29571
|
for (const [key, session2] of this.#officialLoginSessions) {
|
|
29072
29572
|
if (session2.accountId === params2.accountId) this.#officialLoginSessions.delete(key);
|
|
29073
29573
|
}
|
|
29074
|
-
const managedCodexHome =
|
|
29574
|
+
const managedCodexHome = path12.join(
|
|
29075
29575
|
this.#accountDataDirectory,
|
|
29076
29576
|
"codex-homes",
|
|
29077
29577
|
params2.accountId
|
|
29078
29578
|
);
|
|
29079
|
-
if (
|
|
29579
|
+
if (path12.resolve(account.codexHome) === path12.resolve(managedCodexHome)) {
|
|
29080
29580
|
try {
|
|
29081
29581
|
await rm4(managedCodexHome, { recursive: true, force: true });
|
|
29082
29582
|
} catch (error51) {
|
|
@@ -29225,6 +29725,13 @@ var AppServerHost = class {
|
|
|
29225
29725
|
]);
|
|
29226
29726
|
return thread !== null || childDelegation !== null || delegation !== null;
|
|
29227
29727
|
}
|
|
29728
|
+
async #readOfficialThreadCwd(threadId3) {
|
|
29729
|
+
const response = await this.#requestOfficial("thread/read", { threadId: threadId3 });
|
|
29730
|
+
if (isRecord12(response.error)) return void 0;
|
|
29731
|
+
const result = isRecord12(response.result) ? response.result : null;
|
|
29732
|
+
const thread = result && isRecord12(result.thread) ? result.thread : null;
|
|
29733
|
+
return thread && typeof thread.cwd === "string" && thread.cwd.trim() ? thread.cwd : void 0;
|
|
29734
|
+
}
|
|
29228
29735
|
async #inspectOfficialDelegationTarget(input) {
|
|
29229
29736
|
const response = await this.#requestOfficial("model/list", {});
|
|
29230
29737
|
if (isRecord12(response.error)) {
|
|
@@ -29293,7 +29800,7 @@ var AppServerHost = class {
|
|
|
29293
29800
|
throw new DelegationControlError("INVALID_ARGUMENT", "Official Model Ref is invalid");
|
|
29294
29801
|
}
|
|
29295
29802
|
const nativeModelId = requestedModel ? decodeOfficialCodexModelRef(requestedModel) : void 0;
|
|
29296
|
-
const digest2 =
|
|
29803
|
+
const digest2 = createHash6("sha256").update(
|
|
29297
29804
|
JSON.stringify({
|
|
29298
29805
|
task: input.task,
|
|
29299
29806
|
cwd: input.cwd,
|
|
@@ -29396,7 +29903,7 @@ var AppServerHost = class {
|
|
|
29396
29903
|
throw error51;
|
|
29397
29904
|
}
|
|
29398
29905
|
this.#activeOfficialTurns.set(threadId3, turnId);
|
|
29399
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
29906
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID9());
|
|
29400
29907
|
try {
|
|
29401
29908
|
const source = await this.#repository.find(input.parentThreadId);
|
|
29402
29909
|
const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId3);
|
|
@@ -29417,6 +29924,7 @@ var AppServerHost = class {
|
|
|
29417
29924
|
harnessId: "codex",
|
|
29418
29925
|
deepLink: `codex://threads/${threadId3}`,
|
|
29419
29926
|
status: pendingTerminal ?? "running",
|
|
29927
|
+
cwd: thread && typeof thread.cwd === "string" ? thread.cwd : input.cwd,
|
|
29420
29928
|
...requestedModel || input.thinkingOptionId ? {
|
|
29421
29929
|
configuration: {
|
|
29422
29930
|
requested: {
|
|
@@ -29559,7 +30067,7 @@ var AppServerHost = class {
|
|
|
29559
30067
|
async #listDelegationThreads(input) {
|
|
29560
30068
|
const [sortKey, sortDirection2] = input.sort.split("-");
|
|
29561
30069
|
const request = {
|
|
29562
|
-
id: `codexhost:delegation-list:${
|
|
30070
|
+
id: `codexhost:delegation-list:${randomUUID9()}`,
|
|
29563
30071
|
method: "thread/list",
|
|
29564
30072
|
params: {
|
|
29565
30073
|
cwd: input.cwd ? [input.cwd] : null,
|
|
@@ -29622,6 +30130,8 @@ var AppServerHost = class {
|
|
|
29622
30130
|
records,
|
|
29623
30131
|
runtimeFor: (threadId3) => {
|
|
29624
30132
|
const thread = this.#externalRuntime.get(threadId3);
|
|
30133
|
+
const subagentStatus = this.#subagentThreadStatuses.get(threadId3);
|
|
30134
|
+
if (subagentStatus) return { running: subagentStatus === "active" };
|
|
29625
30135
|
return thread ? { running: thread.running } : null;
|
|
29626
30136
|
},
|
|
29627
30137
|
requestOfficialPage: (params) => aggregateOfficialAccountThreadListPage({
|
|
@@ -30035,7 +30545,7 @@ var AppServerHost = class {
|
|
|
30035
30545
|
);
|
|
30036
30546
|
return;
|
|
30037
30547
|
}
|
|
30038
|
-
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(
|
|
30548
|
+
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID9());
|
|
30039
30549
|
const projection = {
|
|
30040
30550
|
projector: new CodexTurnProjector({
|
|
30041
30551
|
threadId: thread.id,
|
|
@@ -30894,7 +31404,7 @@ var AppServerHost = class {
|
|
|
30894
31404
|
if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
|
|
30895
31405
|
throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
|
|
30896
31406
|
}
|
|
30897
|
-
const turnId = hostTurnIdSchema.parse(
|
|
31407
|
+
const turnId = hostTurnIdSchema.parse(randomUUID9());
|
|
30898
31408
|
const startedAtMs = Date.now();
|
|
30899
31409
|
const projection = {
|
|
30900
31410
|
projector: new CodexTurnProjector({
|
|
@@ -31070,7 +31580,7 @@ var AppServerHost = class {
|
|
|
31070
31580
|
if (event.type === "subagent.transcript.changed") {
|
|
31071
31581
|
const nativeSubagentId = event.nativeSubagentId;
|
|
31072
31582
|
const record3 = (await this.#repository.list()).find(
|
|
31073
|
-
(candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId
|
|
31583
|
+
(candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId && candidate.nativeSessionRef?.nativeSessionId === thread.record.nativeSessionRef?.nativeSessionId
|
|
31074
31584
|
);
|
|
31075
31585
|
if (record3) await this.#refreshOpenSubagentThread(record3.hostThreadId, false);
|
|
31076
31586
|
return;
|
|
@@ -31078,7 +31588,7 @@ var AppServerHost = class {
|
|
|
31078
31588
|
if (event.type === "subagent.state.changed") {
|
|
31079
31589
|
const nativeSubagentId = event.nativeSubagentId;
|
|
31080
31590
|
const record3 = (await this.#repository.list()).find(
|
|
31081
|
-
(candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId
|
|
31591
|
+
(candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId && candidate.nativeSessionRef?.nativeSessionId === thread.record.nativeSessionRef?.nativeSessionId
|
|
31082
31592
|
);
|
|
31083
31593
|
if (!record3) return;
|
|
31084
31594
|
const status = event.status === "pending" || event.status === "running" ? "active" : "idle";
|
|
@@ -31182,33 +31692,13 @@ var AppServerHost = class {
|
|
|
31182
31692
|
async #materializeSubagent(parent, subagent) {
|
|
31183
31693
|
if (!subagent.nativeSubagentId || !parent.record.nativeSessionRef) return subagent;
|
|
31184
31694
|
const status = subagent.status === "pending" || subagent.status === "running" ? "active" : "idle";
|
|
31185
|
-
const
|
|
31186
|
-
|
|
31187
|
-
|
|
31188
|
-
|
|
31189
|
-
|
|
31190
|
-
|
|
31191
|
-
await this.#setSubagentThreadStatus(existing.hostThreadId, status);
|
|
31192
|
-
return { ...subagent, subagentId: existing.hostThreadId };
|
|
31695
|
+
const record3 = await this.#repository.materializeSubagent(parent.record, subagent);
|
|
31696
|
+
if (!record3) return subagent;
|
|
31697
|
+
if (this.#subagentThreadStatuses.has(record3.hostThreadId)) {
|
|
31698
|
+
this.#trackRunningSubagent(parent.id, record3.hostThreadId, status);
|
|
31699
|
+
await this.#setSubagentThreadStatus(record3.hostThreadId, status);
|
|
31700
|
+
return { ...subagent, subagentId: record3.hostThreadId };
|
|
31193
31701
|
}
|
|
31194
|
-
const recordInput = createExternalThreadRecordInput({
|
|
31195
|
-
harnessId: parent.record.harnessId,
|
|
31196
|
-
cwd: parent.cwd,
|
|
31197
|
-
title: subagent.description,
|
|
31198
|
-
transportModelId: parent.transportModelId,
|
|
31199
|
-
ephemeral: false,
|
|
31200
|
-
historyMode: "paginated",
|
|
31201
|
-
subagent: {
|
|
31202
|
-
parentHostThreadId: parent.id,
|
|
31203
|
-
nativeSubagentId: subagent.nativeSubagentId,
|
|
31204
|
-
...subagent.role ? { role: subagent.role } : {}
|
|
31205
|
-
}
|
|
31206
|
-
});
|
|
31207
|
-
let record3 = await this.#repository.createProvisional(recordInput);
|
|
31208
|
-
record3 = await this.#repository.commitNative(
|
|
31209
|
-
record3.hostThreadId,
|
|
31210
|
-
parent.record.nativeSessionRef
|
|
31211
|
-
);
|
|
31212
31702
|
const thread = externalThreadValue({
|
|
31213
31703
|
record: record3,
|
|
31214
31704
|
turns: [],
|
|
@@ -31452,7 +31942,7 @@ var AppServerHost = class {
|
|
|
31452
31942
|
try {
|
|
31453
31943
|
result = projection.projector.projectQuestion(
|
|
31454
31944
|
interaction,
|
|
31455
|
-
hostItemIdSchema.parse(
|
|
31945
|
+
hostItemIdSchema.parse(randomUUID9())
|
|
31456
31946
|
);
|
|
31457
31947
|
} catch (error51) {
|
|
31458
31948
|
this.#diagnose(error51);
|
|
@@ -31608,7 +32098,7 @@ var AppServerHost = class {
|
|
|
31608
32098
|
};
|
|
31609
32099
|
|
|
31610
32100
|
// packages/host-runtime/src/codex-runtime/account-official-listeners.ts
|
|
31611
|
-
import
|
|
32101
|
+
import path13 from "node:path";
|
|
31612
32102
|
var AccountOfficialListeners = class {
|
|
31613
32103
|
constructor(createListener) {
|
|
31614
32104
|
this.createListener = createListener;
|
|
@@ -31619,7 +32109,7 @@ var AccountOfficialListeners = class {
|
|
|
31619
32109
|
#closed = false;
|
|
31620
32110
|
async endpoint(account) {
|
|
31621
32111
|
if (this.#closed) throw new Error("Account official listeners are closed");
|
|
31622
|
-
const key =
|
|
32112
|
+
const key = path13.resolve(account.codexHome);
|
|
31623
32113
|
const existing = this.#starting.get(key);
|
|
31624
32114
|
if (existing) return existing;
|
|
31625
32115
|
const listener = this.createListener(account);
|
|
@@ -31667,6 +32157,12 @@ var DelegationControlRegistry = class {
|
|
|
31667
32157
|
"Harness inspection requires exactly one active Host Runtime session"
|
|
31668
32158
|
).inspect(input);
|
|
31669
32159
|
}
|
|
32160
|
+
async listHarnesses() {
|
|
32161
|
+
return only(
|
|
32162
|
+
[...this.#registrations],
|
|
32163
|
+
"Harness discovery requires exactly one active Host Runtime session"
|
|
32164
|
+
).listHarnesses();
|
|
32165
|
+
}
|
|
31670
32166
|
async start(input) {
|
|
31671
32167
|
return (await this.#registrationForStart(input)).start(input);
|
|
31672
32168
|
}
|
|
@@ -31749,17 +32245,17 @@ var DelegationControlRegistry = class {
|
|
|
31749
32245
|
|
|
31750
32246
|
// packages/host-runtime/src/installed-harness-plugins.ts
|
|
31751
32247
|
import os3 from "node:os";
|
|
31752
|
-
import
|
|
32248
|
+
import path15 from "node:path";
|
|
31753
32249
|
import { fileURLToPath } from "node:url";
|
|
31754
32250
|
|
|
31755
32251
|
// packages/host-runtime/src/launcher-url-opener.ts
|
|
31756
32252
|
import { spawn as spawn3 } from "node:child_process";
|
|
31757
|
-
import
|
|
32253
|
+
import path14 from "node:path";
|
|
31758
32254
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
|
|
31759
32255
|
var OPEN_TIMEOUT_MS = 1e4;
|
|
31760
32256
|
function createLauncherUrlOpener(environment, spawnLauncher = (command, arguments_2, options2) => spawn3(command, arguments_2, options2)) {
|
|
31761
32257
|
const launcher = environment.CODEXHOST_LAUNCHER_EXECUTABLE;
|
|
31762
|
-
if (!launcher || !
|
|
32258
|
+
if (!launcher || !path14.isAbsolute(launcher)) return void 0;
|
|
31763
32259
|
const launcherEnvironment = Object.fromEntries(
|
|
31764
32260
|
Object.entries(environment).filter(([name]) => {
|
|
31765
32261
|
const normalized = name.toUpperCase();
|
|
@@ -31817,9 +32313,9 @@ function installedHarnessPluginOptions(environment, managedRemoteHost = false, h
|
|
|
31817
32313
|
const opener = managedRemoteHost ? void 0 : createLauncherUrlOpener(environment);
|
|
31818
32314
|
return {
|
|
31819
32315
|
pluginRoots: [
|
|
31820
|
-
|
|
31821
|
-
environment[HARNESS_PLUGIN_DIRECTORY_ENV] ??
|
|
31822
|
-
environment.CODEXHOST_DATA_DIR ?
|
|
32316
|
+
path15.join(path15.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
|
|
32317
|
+
environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path15.join(
|
|
32318
|
+
environment.CODEXHOST_DATA_DIR ? path15.resolve(environment.CODEXHOST_DATA_DIR) : path15.join(os3.homedir(), ".codexhost"),
|
|
31823
32319
|
"plugins"
|
|
31824
32320
|
)
|
|
31825
32321
|
],
|
|
@@ -31898,6 +32394,9 @@ async function startDelegationControlServer(input) {
|
|
|
31898
32394
|
}
|
|
31899
32395
|
const body = await jsonBody(request);
|
|
31900
32396
|
switch (request.url) {
|
|
32397
|
+
case "/v1/harness/list":
|
|
32398
|
+
writeJson2(response, 200, await input.api.listHarnesses());
|
|
32399
|
+
return;
|
|
31901
32400
|
case "/v1/harness/inspect":
|
|
31902
32401
|
writeJson2(response, 200, await input.api.inspect(body));
|
|
31903
32402
|
return;
|
|
@@ -31941,13 +32440,15 @@ async function startDelegationControlServer(input) {
|
|
|
31941
32440
|
}
|
|
31942
32441
|
|
|
31943
32442
|
// packages/host-runtime/src/delegation-skill.ts
|
|
31944
|
-
import { createHash as
|
|
32443
|
+
import { createHash as createHash7, randomUUID as randomUUID10 } from "node:crypto";
|
|
31945
32444
|
import { mkdir as mkdir7, open as open5, readFile as readFile7, rename as rename5, rm as rm5, stat as stat3 } from "node:fs/promises";
|
|
31946
32445
|
import os4 from "node:os";
|
|
31947
|
-
import
|
|
31948
|
-
var SKILL_VERSION =
|
|
31949
|
-
var SKILL_RELATIVE_PATH =
|
|
32446
|
+
import path16 from "node:path";
|
|
32447
|
+
var SKILL_VERSION = 7;
|
|
32448
|
+
var SKILL_RELATIVE_PATH = path16.join("skills", "codexhost-delegation", "SKILL.md");
|
|
31950
32449
|
var PREVIOUS_MANAGED_DIGESTS = [
|
|
32450
|
+
"9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
|
|
32451
|
+
"2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
|
|
31951
32452
|
"aff258622dc8ff321f32b15620d081e578cb9c9ed1134d6a57f35ca8e7762c0a",
|
|
31952
32453
|
"ba509f57e5448e796b3dfdd5031dcb08672eded50b61c0a54de84cfa02c49dd3",
|
|
31953
32454
|
"d3ddf6db9bc5c5df825479c885bbbf0ca08da66f7057a12e02e1fdf57525149e",
|
|
@@ -31971,21 +32472,13 @@ Before acting, run:
|
|
|
31971
32472
|
|
|
31972
32473
|
\`codexhost delegate --help\`
|
|
31973
32474
|
|
|
31974
|
-
|
|
31975
|
-
|
|
31976
|
-
|
|
31977
|
-
|
|
31978
|
-
- available target Harness IDs;
|
|
31979
|
-
- Thread identifier formats;
|
|
31980
|
-
- waiting and reading behavior;
|
|
31981
|
-
- response fields;
|
|
31982
|
-
- errors and recovery guidance.
|
|
31983
|
-
|
|
31984
|
-
Do not construct commands, parameters, or Harness IDs from memory.
|
|
32475
|
+
Use CLI help as the authoritative source for commands and behavior. Consult
|
|
32476
|
+
command-specific help for options and the Harness listing command when the
|
|
32477
|
+
target is unknown. Prefer compact output when supported, and use its task links
|
|
32478
|
+
directly for subsequent commands.
|
|
31985
32479
|
|
|
31986
|
-
|
|
31987
|
-
|
|
31988
|
-
When they do not specify either setting, omit it so the target keeps its default.
|
|
32480
|
+
Use the Harness native defaults. Inspect the target when a Model or Thinking
|
|
32481
|
+
selection is needed or the default is unavailable.
|
|
31989
32482
|
|
|
31990
32483
|
For a new delegation, create an independent child session and submit the
|
|
31991
32484
|
requested task. For an existing external session, resolve the target from the
|
|
@@ -32004,22 +32497,12 @@ user’s request and the task:
|
|
|
32004
32497
|
- check it again later;
|
|
32005
32498
|
- leave it running in the background.
|
|
32006
32499
|
|
|
32007
|
-
|
|
32008
|
-
|
|
32009
|
-
|
|
32010
|
-
Provide the user with the necessary tracking information available from the
|
|
32011
|
-
CLI; omit unavailable fields rather than inventing them:
|
|
32012
|
-
|
|
32013
|
-
- target agent;
|
|
32014
|
-
- \`delegationId\`;
|
|
32015
|
-
- \`threadId\`;
|
|
32016
|
-
- \`turnId\`;
|
|
32017
|
-
- \`deepLink\`;
|
|
32018
|
-
- current or final status.
|
|
32500
|
+
Report the result returned by read or a completed wait, together with the target
|
|
32501
|
+
agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
|
|
32019
32502
|
`;
|
|
32020
|
-
var CURRENT_DIGEST =
|
|
32503
|
+
var CURRENT_DIGEST = createHash7("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
|
|
32021
32504
|
function digest(value2) {
|
|
32022
|
-
return
|
|
32505
|
+
return createHash7("sha256").update(value2).digest("hex");
|
|
32023
32506
|
}
|
|
32024
32507
|
function managedVersion(value2) {
|
|
32025
32508
|
const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
|
|
@@ -32034,8 +32517,8 @@ async function readOptional(filePath) {
|
|
|
32034
32517
|
}
|
|
32035
32518
|
}
|
|
32036
32519
|
async function atomicWrite(filePath, content) {
|
|
32037
|
-
await mkdir7(
|
|
32038
|
-
const temporaryPath =
|
|
32520
|
+
await mkdir7(path16.dirname(filePath), { recursive: true, mode: 448 });
|
|
32521
|
+
const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${randomUUID10()}.tmp`);
|
|
32039
32522
|
const handle = await open5(temporaryPath, "wx", 384);
|
|
32040
32523
|
try {
|
|
32041
32524
|
await handle.writeFile(content, "utf8");
|
|
@@ -32052,8 +32535,8 @@ async function atomicWrite(filePath, content) {
|
|
|
32052
32535
|
async function installDelegationSkills(input = {}) {
|
|
32053
32536
|
const home = input.homeDirectory ?? os4.homedir();
|
|
32054
32537
|
const destinations = [
|
|
32055
|
-
|
|
32056
|
-
|
|
32538
|
+
path16.join(home, ".agents", SKILL_RELATIVE_PATH),
|
|
32539
|
+
path16.join(home, ".claude", SKILL_RELATIVE_PATH)
|
|
32057
32540
|
];
|
|
32058
32541
|
const knownDigests = /* @__PURE__ */ new Set([
|
|
32059
32542
|
CURRENT_DIGEST,
|
|
@@ -32118,9 +32601,9 @@ async function installDelegationSkills(input = {}) {
|
|
|
32118
32601
|
}
|
|
32119
32602
|
|
|
32120
32603
|
// packages/host-runtime/src/remote-control-app-server.ts
|
|
32121
|
-
import { randomUUID as
|
|
32604
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
32122
32605
|
import { mkdir as mkdir8, open as open6, rename as rename6, rm as rm6 } from "node:fs/promises";
|
|
32123
|
-
import
|
|
32606
|
+
import path17 from "node:path";
|
|
32124
32607
|
|
|
32125
32608
|
// packages/host-runtime/src/remote-official-connection.ts
|
|
32126
32609
|
import net from "node:net";
|
|
@@ -32310,30 +32793,30 @@ var BRIDGE_READY_METHOD = "codexhost/remote-control-bridge/ready";
|
|
|
32310
32793
|
function absoluteEnvironmentPath2(environment, name, fallback, platform = process.platform) {
|
|
32311
32794
|
const value2 = environment[name] ?? fallback;
|
|
32312
32795
|
if (!value2) return null;
|
|
32313
|
-
if (
|
|
32314
|
-
return platform === "win32" &&
|
|
32796
|
+
if (path17.isAbsolute(value2)) return path17.normalize(value2);
|
|
32797
|
+
return platform === "win32" && path17.win32.isAbsolute(value2) ? path17.win32.normalize(value2) : null;
|
|
32315
32798
|
}
|
|
32316
32799
|
function nodeCompatibleWindowsPath(value2) {
|
|
32317
32800
|
if (value2.startsWith("\\\\?\\UNC\\")) return `\\\\${value2.slice(8)}`;
|
|
32318
32801
|
if (value2.startsWith("\\\\?\\")) return value2.slice(4);
|
|
32319
32802
|
return value2;
|
|
32320
32803
|
}
|
|
32321
|
-
function remoteControlBridgePipePath(processId = process.pid, instanceId =
|
|
32804
|
+
function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID11()) {
|
|
32322
32805
|
const safeInstance = instanceId.replaceAll(/[^a-zA-Z0-9-]/gu, "");
|
|
32323
32806
|
if (!safeInstance) throw new Error("Remote Control bridge instance ID is invalid");
|
|
32324
32807
|
return `\\\\.\\pipe\\codexhost-remote-control-${processId}-${safeInstance}`;
|
|
32325
32808
|
}
|
|
32326
32809
|
function remoteControlBridgeDescriptorPath(environment) {
|
|
32327
32810
|
const root = environment.LOCALAPPDATA;
|
|
32328
|
-
if (!root || !
|
|
32329
|
-
return
|
|
32811
|
+
if (!root || !path17.isAbsolute(root)) return null;
|
|
32812
|
+
return path17.join(path17.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
|
|
32330
32813
|
}
|
|
32331
32814
|
async function publishRemoteControlAppServerDescriptor(plan) {
|
|
32332
|
-
const directory =
|
|
32815
|
+
const directory = path17.dirname(plan.descriptorPath);
|
|
32333
32816
|
await mkdir8(directory, { recursive: true, mode: 448 });
|
|
32334
|
-
const temporaryPath =
|
|
32817
|
+
const temporaryPath = path17.join(
|
|
32335
32818
|
directory,
|
|
32336
|
-
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${
|
|
32819
|
+
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID11()}.tmp`
|
|
32337
32820
|
);
|
|
32338
32821
|
const handle = await open6(temporaryPath, "wx", 384);
|
|
32339
32822
|
try {
|
|
@@ -32424,14 +32907,14 @@ async function runRemoteControlAppServerBridge(input = {}) {
|
|
|
32424
32907
|
import { createServer as createServer2 } from "node:http";
|
|
32425
32908
|
import net2 from "node:net";
|
|
32426
32909
|
import { chmod as chmod3, lstat as lstat6, mkdir as mkdir10, rm as rm8 } from "node:fs/promises";
|
|
32427
|
-
import
|
|
32910
|
+
import path19 from "node:path";
|
|
32428
32911
|
import { PassThrough as PassThrough2 } from "node:stream";
|
|
32429
32912
|
|
|
32430
32913
|
// packages/host-runtime/src/remote-socket-lock.ts
|
|
32431
|
-
import { randomUUID as
|
|
32914
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
32432
32915
|
import { chmod as chmod2, lstat as lstat5, mkdir as mkdir9, open as open7, readFile as readFile8, readdir as readdir4, rename as rename7, rm as rm7 } from "node:fs/promises";
|
|
32433
32916
|
import { uptime } from "node:os";
|
|
32434
|
-
import
|
|
32917
|
+
import path18 from "node:path";
|
|
32435
32918
|
import { setTimeout as delay4 } from "node:timers/promises";
|
|
32436
32919
|
var LOCK_RETRY_COUNT = 200;
|
|
32437
32920
|
var LOCK_RETRY_DELAY_MS = 25;
|
|
@@ -32505,7 +32988,7 @@ async function readLockEntrySnapshot(filePath) {
|
|
|
32505
32988
|
source,
|
|
32506
32989
|
identity: { dev: metadata.dev, ino: metadata.ino },
|
|
32507
32990
|
mtimeMs: metadata.mtimeMs,
|
|
32508
|
-
record: record3 &&
|
|
32991
|
+
record: record3 && path18.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
|
|
32509
32992
|
};
|
|
32510
32993
|
}
|
|
32511
32994
|
function lockEntryIsAbandoned(snapshot) {
|
|
@@ -32526,7 +33009,7 @@ async function readLockEntryCatalog(lockDirectory) {
|
|
|
32526
33009
|
let unsettled = false;
|
|
32527
33010
|
for (const name of names) {
|
|
32528
33011
|
if (!name.startsWith(LOCK_ENTRY_PREFIX) || !name.endsWith(LOCK_ENTRY_SUFFIX)) continue;
|
|
32529
|
-
const snapshot = await readLockEntrySnapshot(
|
|
33012
|
+
const snapshot = await readLockEntrySnapshot(path18.join(lockDirectory, name));
|
|
32530
33013
|
if (snapshot === null) continue;
|
|
32531
33014
|
if (lockEntryIsAbandoned(snapshot)) {
|
|
32532
33015
|
if (!await removeAbandonedLockEntry(snapshot)) unsettled = true;
|
|
@@ -32554,7 +33037,7 @@ async function preparePrivateLockDirectory(lockDirectory) {
|
|
|
32554
33037
|
await chmod2(lockDirectory, 448);
|
|
32555
33038
|
}
|
|
32556
33039
|
async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
|
|
32557
|
-
const temporary =
|
|
33040
|
+
const temporary = path18.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID12()}`);
|
|
32558
33041
|
const handle = await open7(temporary, "wx", 384);
|
|
32559
33042
|
try {
|
|
32560
33043
|
await handle.writeFile(`${JSON.stringify(record3)}
|
|
@@ -32629,8 +33112,8 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
|
|
|
32629
33112
|
const legacyPath = `${socketPath}.initializing`;
|
|
32630
33113
|
const lockDirectory = `${socketPath}.initializers`;
|
|
32631
33114
|
await preparePrivateLockDirectory(lockDirectory);
|
|
32632
|
-
const ownerToken =
|
|
32633
|
-
const entryPath =
|
|
33115
|
+
const ownerToken = randomUUID12();
|
|
33116
|
+
const entryPath = path18.join(lockDirectory, lockEntryName(ownerToken));
|
|
32634
33117
|
const baseRecord = {
|
|
32635
33118
|
version: 2,
|
|
32636
33119
|
ownerToken,
|
|
@@ -32804,14 +33287,14 @@ function remoteAppServerSocketPath(environment, listenUrl = "unix://") {
|
|
|
32804
33287
|
throw new Error("Remote app-server listener must use a Unix URL");
|
|
32805
33288
|
}
|
|
32806
33289
|
const explicit = listenUrl.slice("unix://".length);
|
|
32807
|
-
if (explicit.length > 0) return
|
|
32808
|
-
const codexHome = environment.CODEX_HOME ?? (environment.HOME ?
|
|
33290
|
+
if (explicit.length > 0) return path19.posix.resolve(decodeURIComponent(explicit));
|
|
33291
|
+
const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path19.posix.join(environment.HOME, ".codex") : void 0);
|
|
32809
33292
|
if (!codexHome)
|
|
32810
33293
|
throw new Error("CODEX_HOME or HOME is required for the remote app-server socket");
|
|
32811
|
-
return
|
|
33294
|
+
return path19.posix.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
32812
33295
|
}
|
|
32813
33296
|
function officialListenerArgumentsForRemoteListener(arguments_2, socketPath) {
|
|
32814
|
-
if (!
|
|
33297
|
+
if (!path19.posix.isAbsolute(socketPath)) {
|
|
32815
33298
|
throw new Error("Shared official app-server socket path must be absolute");
|
|
32816
33299
|
}
|
|
32817
33300
|
if (remoteUnixListenerUrl(arguments_2) === null) {
|
|
@@ -32922,7 +33405,7 @@ async function removeStaleSocket(socketPath) {
|
|
|
32922
33405
|
await rm8(socketPath, { force: true });
|
|
32923
33406
|
}
|
|
32924
33407
|
async function prepareRemoteAppServerSocketDirectory(socketPath) {
|
|
32925
|
-
const socketDirectory =
|
|
33408
|
+
const socketDirectory = path19.dirname(socketPath);
|
|
32926
33409
|
const existing = await lstat6(socketDirectory).catch((error51) => {
|
|
32927
33410
|
if (error51.code === "ENOENT") return null;
|
|
32928
33411
|
throw error51;
|
|
@@ -33127,20 +33610,20 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
33127
33610
|
|
|
33128
33611
|
// packages/host-runtime/src/remote-official-app-server.ts
|
|
33129
33612
|
import { spawn as spawn4 } from "node:child_process";
|
|
33130
|
-
import { randomUUID as
|
|
33613
|
+
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
33131
33614
|
import { lstat as lstat7, rm as rm9 } from "node:fs/promises";
|
|
33132
|
-
import
|
|
33615
|
+
import path20 from "node:path";
|
|
33133
33616
|
var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
|
|
33134
33617
|
var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
|
|
33135
|
-
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token =
|
|
33136
|
-
if (!
|
|
33618
|
+
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID13()) {
|
|
33619
|
+
if (!path20.posix.isAbsolute(desktopControlSocketPath)) {
|
|
33137
33620
|
throw new Error("Desktop control socket path must be absolute");
|
|
33138
33621
|
}
|
|
33139
33622
|
if (!/^[A-Za-z0-9-]+$/u.test(token) || !/[A-Za-z0-9]/u.test(token)) {
|
|
33140
33623
|
throw new Error("Shared official app-server socket token is invalid");
|
|
33141
33624
|
}
|
|
33142
33625
|
const compactToken = token.replaceAll("-", "").slice(0, 15);
|
|
33143
|
-
return
|
|
33626
|
+
return path20.posix.join(path20.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
|
|
33144
33627
|
}
|
|
33145
33628
|
function errorMessage5(error51) {
|
|
33146
33629
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
@@ -33431,7 +33914,16 @@ function createHostUpdateCoordinator(options2) {
|
|
|
33431
33914
|
});
|
|
33432
33915
|
return contextPromise;
|
|
33433
33916
|
};
|
|
33434
|
-
const fetchLatest = options2.fetchLatest ?? ((signal) =>
|
|
33917
|
+
const fetchLatest = options2.fetchLatest ?? (async (signal) => {
|
|
33918
|
+
const timeoutSignal = AbortSignal.timeout(15e3);
|
|
33919
|
+
const requestSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
33920
|
+
const authenticated = await fetchLatestGitHubReleaseWithGitHubCli({
|
|
33921
|
+
...options2.environment ? { environment: options2.environment } : {},
|
|
33922
|
+
platform,
|
|
33923
|
+
signal: requestSignal
|
|
33924
|
+
});
|
|
33925
|
+
return authenticated ?? fetchLatestGitHubRelease({ signal: requestSignal });
|
|
33926
|
+
});
|
|
33435
33927
|
let candidate = null;
|
|
33436
33928
|
async function latestStatus(context) {
|
|
33437
33929
|
const discovered = await discoverLatestUpdateStatus(context.common.stateDirectory);
|
|
@@ -33607,9 +34099,9 @@ function hasLauncherManagedUpdateRuntime(environment, hostRuntimePath) {
|
|
|
33607
34099
|
if (!environment[UPDATE_RUNTIME_ENV.launcherPid]) return false;
|
|
33608
34100
|
const npmPackageRoot = environment[UPDATE_RUNTIME_ENV.npmPackageRoot];
|
|
33609
34101
|
if (!npmPackageRoot || !hostRuntimePath) return true;
|
|
33610
|
-
if (!
|
|
33611
|
-
const runtimePackageRoot =
|
|
33612
|
-
return
|
|
34102
|
+
if (!path21.isAbsolute(npmPackageRoot) || !path21.isAbsolute(hostRuntimePath)) return false;
|
|
34103
|
+
const runtimePackageRoot = path21.dirname(path21.dirname(path21.normalize(hostRuntimePath)));
|
|
34104
|
+
return path21.relative(path21.normalize(npmPackageRoot), runtimePackageRoot) === "";
|
|
33613
34105
|
}
|
|
33614
34106
|
function requiredRuntimeConfiguration(environment) {
|
|
33615
34107
|
const stockCodexPath = environment[STOCK_CODEX_PATH_ENV];
|
|
@@ -33736,8 +34228,8 @@ async function runHostRuntime(input) {
|
|
|
33736
34228
|
});
|
|
33737
34229
|
try {
|
|
33738
34230
|
await officialListeners.endpoint({
|
|
33739
|
-
codexHome:
|
|
33740
|
-
delegationEnvironment.CODEX_HOME ??
|
|
34231
|
+
codexHome: path21.resolve(
|
|
34232
|
+
delegationEnvironment.CODEX_HOME ?? path21.join(homedir(), ".codex")
|
|
33741
34233
|
)
|
|
33742
34234
|
});
|
|
33743
34235
|
await listener.listen();
|
|
@@ -33838,7 +34330,7 @@ async function runHostRuntime(input) {
|
|
|
33838
34330
|
}
|
|
33839
34331
|
|
|
33840
34332
|
// packages/host-runtime/src/remote-host-install.ts
|
|
33841
|
-
import { createHash as
|
|
34333
|
+
import { createHash as createHash8, randomUUID as randomUUID14 } from "node:crypto";
|
|
33842
34334
|
import { constants as fsConstants } from "node:fs";
|
|
33843
34335
|
import {
|
|
33844
34336
|
access,
|
|
@@ -33853,7 +34345,7 @@ import {
|
|
|
33853
34345
|
stat as stat4,
|
|
33854
34346
|
writeFile as writeFile5
|
|
33855
34347
|
} from "node:fs/promises";
|
|
33856
|
-
import
|
|
34348
|
+
import path22 from "node:path";
|
|
33857
34349
|
var MANIFEST_FORMAT = 1;
|
|
33858
34350
|
var WRAPPER_MARKER = "# codexhost remote SSH wrapper v1";
|
|
33859
34351
|
var PROFILE_START = "# >>> codexhost remote SSH >>>";
|
|
@@ -33864,25 +34356,25 @@ function resolvePaths(options2) {
|
|
|
33864
34356
|
if (!configuredHome) {
|
|
33865
34357
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
33866
34358
|
}
|
|
33867
|
-
const home =
|
|
33868
|
-
if (!home || home ===
|
|
34359
|
+
const home = path22.resolve(configuredHome);
|
|
34360
|
+
if (!home || home === path22.parse(home).root) {
|
|
33869
34361
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
33870
34362
|
}
|
|
33871
|
-
const installRoot =
|
|
33872
|
-
const profilePath =
|
|
33873
|
-
options2.profilePath ??
|
|
34363
|
+
const installRoot = path22.resolve(options2.installRoot ?? path22.join(home, ".codexhost", "remote"));
|
|
34364
|
+
const profilePath = path22.resolve(
|
|
34365
|
+
options2.profilePath ?? path22.join(
|
|
33874
34366
|
home,
|
|
33875
|
-
|
|
34367
|
+
path22.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path22.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
|
|
33876
34368
|
)
|
|
33877
34369
|
);
|
|
33878
|
-
const binDirectory =
|
|
34370
|
+
const binDirectory = path22.join(installRoot, "bin");
|
|
33879
34371
|
return {
|
|
33880
34372
|
home,
|
|
33881
34373
|
installRoot,
|
|
33882
34374
|
binDirectory,
|
|
33883
|
-
wrapperPath:
|
|
33884
|
-
manifestPath:
|
|
33885
|
-
dataDirectory:
|
|
34375
|
+
wrapperPath: path22.join(binDirectory, "codex"),
|
|
34376
|
+
manifestPath: path22.join(installRoot, "manifest.json"),
|
|
34377
|
+
dataDirectory: path22.join(installRoot, "data"),
|
|
33886
34378
|
profilePath
|
|
33887
34379
|
};
|
|
33888
34380
|
}
|
|
@@ -33898,10 +34390,10 @@ async function existingText(filePath) {
|
|
|
33898
34390
|
}
|
|
33899
34391
|
}
|
|
33900
34392
|
async function fileSha256(filePath) {
|
|
33901
|
-
return
|
|
34393
|
+
return createHash8("sha256").update(await readFile9(filePath)).digest("hex");
|
|
33902
34394
|
}
|
|
33903
34395
|
async function executable(filePath, label) {
|
|
33904
|
-
const absolute =
|
|
34396
|
+
const absolute = path22.resolve(filePath);
|
|
33905
34397
|
try {
|
|
33906
34398
|
if (!(await stat4(absolute)).isFile()) throw new Error("not a regular file");
|
|
33907
34399
|
await access(absolute, fsConstants.X_OK);
|
|
@@ -33911,7 +34403,7 @@ async function executable(filePath, label) {
|
|
|
33911
34403
|
return absolute;
|
|
33912
34404
|
}
|
|
33913
34405
|
async function existingFile(filePath, label) {
|
|
33914
|
-
const absolute =
|
|
34406
|
+
const absolute = path22.resolve(filePath);
|
|
33915
34407
|
try {
|
|
33916
34408
|
const metadata = await stat4(absolute);
|
|
33917
34409
|
if (!metadata.isFile()) throw new Error("not a regular file");
|
|
@@ -33921,9 +34413,9 @@ async function existingFile(filePath, label) {
|
|
|
33921
34413
|
return absolute;
|
|
33922
34414
|
}
|
|
33923
34415
|
async function discoverExecutable(name, environment) {
|
|
33924
|
-
for (const directory of (environment.PATH ?? "").split(
|
|
34416
|
+
for (const directory of (environment.PATH ?? "").split(path22.delimiter)) {
|
|
33925
34417
|
if (!directory) continue;
|
|
33926
|
-
const candidate =
|
|
34418
|
+
const candidate = path22.resolve(directory, name);
|
|
33927
34419
|
try {
|
|
33928
34420
|
await access(candidate, fsConstants.X_OK);
|
|
33929
34421
|
return candidate;
|
|
@@ -33934,10 +34426,10 @@ async function discoverExecutable(name, environment) {
|
|
|
33934
34426
|
return null;
|
|
33935
34427
|
}
|
|
33936
34428
|
async function writeAtomic(filePath, contents, mode) {
|
|
33937
|
-
await mkdir11(
|
|
33938
|
-
const temporary =
|
|
33939
|
-
|
|
33940
|
-
`.${
|
|
34429
|
+
await mkdir11(path22.dirname(filePath), { recursive: true, mode: 448 });
|
|
34430
|
+
const temporary = path22.join(
|
|
34431
|
+
path22.dirname(filePath),
|
|
34432
|
+
`.${path22.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
|
|
33941
34433
|
);
|
|
33942
34434
|
try {
|
|
33943
34435
|
if (typeof contents === "string") {
|
|
@@ -33958,10 +34450,10 @@ async function writeAtomic(filePath, contents, mode) {
|
|
|
33958
34450
|
}
|
|
33959
34451
|
}
|
|
33960
34452
|
async function writeAtomicExecutable(filePath, sourcePath) {
|
|
33961
|
-
await mkdir11(
|
|
33962
|
-
const temporary =
|
|
33963
|
-
|
|
33964
|
-
`.${
|
|
34453
|
+
await mkdir11(path22.dirname(filePath), { recursive: true, mode: 448 });
|
|
34454
|
+
const temporary = path22.join(
|
|
34455
|
+
path22.dirname(filePath),
|
|
34456
|
+
`.${path22.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
|
|
33965
34457
|
);
|
|
33966
34458
|
try {
|
|
33967
34459
|
await copyFile3(sourcePath, temporary);
|
|
@@ -34002,8 +34494,8 @@ function removeManagedProfileBlock(contents) {
|
|
|
34002
34494
|
function installManagedProfileBlock(contents, manifest) {
|
|
34003
34495
|
const base = removeManagedProfileBlock(contents);
|
|
34004
34496
|
const environment = [
|
|
34005
|
-
`export CODEX_INSTALL_DIR=${shellQuote(
|
|
34006
|
-
`export PATH=${shellQuote(
|
|
34497
|
+
`export CODEX_INSTALL_DIR=${shellQuote(path22.dirname(manifest.wrapperPath))}`,
|
|
34498
|
+
`export PATH=${shellQuote(path22.dirname(manifest.wrapperPath))}:${shellQuote(path22.dirname(manifest.nodePath))}:${shellQuote(path22.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
|
|
34007
34499
|
`export CODEXHOST_STOCK_CODEX_PATH=${shellQuote(manifest.stockCodexPath)}`,
|
|
34008
34500
|
`export CODEXHOST_HOST_NODE_PATH=${shellQuote(manifest.nodePath)}`,
|
|
34009
34501
|
`export CODEXHOST_HOST_RUNTIME_PATH=${shellQuote(manifest.hostRuntimePath)}`,
|
|
@@ -34020,7 +34512,7 @@ function installManagedProfileBlock(contents, manifest) {
|
|
|
34020
34512
|
PROFILE_END,
|
|
34021
34513
|
""
|
|
34022
34514
|
].join("\n");
|
|
34023
|
-
if (
|
|
34515
|
+
if (path22.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
|
|
34024
34516
|
const separator = base.length > 0 && !base.endsWith("\n") ? "\n" : "";
|
|
34025
34517
|
return `${base}${separator}${block}`;
|
|
34026
34518
|
}
|
|
@@ -34039,7 +34531,7 @@ ${WRAPPER_MARKER}
|
|
|
34039
34531
|
return "legacy-wrapper";
|
|
34040
34532
|
}
|
|
34041
34533
|
if (manifest.entrypointSha256 !== void 0) {
|
|
34042
|
-
return
|
|
34534
|
+
return createHash8("sha256").update(entrypoint).digest("hex") === manifest.entrypointSha256 ? "native" : "modified";
|
|
34043
34535
|
}
|
|
34044
34536
|
const shim = await readFile9(manifest.shimPath).catch((error51) => {
|
|
34045
34537
|
if (error51.code === "ENOENT") return null;
|
|
@@ -34085,9 +34577,9 @@ async function readManifest(filePath) {
|
|
|
34085
34577
|
];
|
|
34086
34578
|
const optionalPaths = ["claudeCommand", "profileBackupPath"];
|
|
34087
34579
|
if (manifest.format !== MANIFEST_FORMAT || Object.keys(manifest).some((key) => !allowed.has(key)) || requiredPaths.some(
|
|
34088
|
-
(key) => typeof manifest[key] !== "string" || !
|
|
34580
|
+
(key) => typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key])
|
|
34089
34581
|
) || optionalPaths.some(
|
|
34090
|
-
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !
|
|
34582
|
+
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key]))
|
|
34091
34583
|
) || manifest.entrypointSha256 !== void 0 && (typeof manifest.entrypointSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(manifest.entrypointSha256))) {
|
|
34092
34584
|
throw new Error("Remote Host manifest has an unsupported format");
|
|
34093
34585
|
}
|
|
@@ -34316,7 +34808,7 @@ async function uninstallRemoteHost(options2) {
|
|
|
34316
34808
|
import { spawn as spawn5 } from "node:child_process";
|
|
34317
34809
|
import { stat as stat5 } from "node:fs/promises";
|
|
34318
34810
|
import net3 from "node:net";
|
|
34319
|
-
import
|
|
34811
|
+
import path23 from "node:path";
|
|
34320
34812
|
import { Duplex } from "node:stream";
|
|
34321
34813
|
var CODEXHOST_STATUS_METHOD = "codexhost/update/status";
|
|
34322
34814
|
var DIRECT_PROBE_TIMEOUT_MS = 5e3;
|
|
@@ -34335,9 +34827,9 @@ function classifyRemoteHostProbeResponse(response, socketPath) {
|
|
|
34335
34827
|
}
|
|
34336
34828
|
var lifecycleDependencyOverrides = {};
|
|
34337
34829
|
function socketPathFor(environment) {
|
|
34338
|
-
const codexHome = environment.CODEX_HOME ?? (environment.HOME ?
|
|
34830
|
+
const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path23.join(environment.HOME, ".codex") : void 0);
|
|
34339
34831
|
if (!codexHome) throw new Error("CODEX_HOME or HOME is required for remote Host lifecycle");
|
|
34340
|
-
return
|
|
34832
|
+
return path23.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
34341
34833
|
}
|
|
34342
34834
|
async function defaultSocketExists(socketPath) {
|
|
34343
34835
|
const metadata = await stat5(socketPath).catch((error51) => {
|
|
@@ -34464,7 +34956,7 @@ function installedManifest(status) {
|
|
|
34464
34956
|
function managedEnvironment(manifest, environment) {
|
|
34465
34957
|
return {
|
|
34466
34958
|
...environment,
|
|
34467
|
-
CODEX_INSTALL_DIR:
|
|
34959
|
+
CODEX_INSTALL_DIR: path23.dirname(manifest.wrapperPath),
|
|
34468
34960
|
CODEXHOST_STOCK_CODEX_PATH: manifest.stockCodexPath,
|
|
34469
34961
|
CODEXHOST_HOST_NODE_PATH: manifest.nodePath,
|
|
34470
34962
|
CODEXHOST_HOST_RUNTIME_PATH: manifest.hostRuntimePath,
|
|
@@ -34472,7 +34964,7 @@ function managedEnvironment(manifest, environment) {
|
|
|
34472
34964
|
CODEXHOST_DEFAULT_AGENT: "codex",
|
|
34473
34965
|
CODEXHOST_REMOTE_SSH_MANAGED: "1",
|
|
34474
34966
|
...manifest.claudeCommand ? { CODEXHOST_CLAUDE_COMMAND: manifest.claudeCommand } : {},
|
|
34475
|
-
PATH: `${
|
|
34967
|
+
PATH: `${path23.dirname(manifest.wrapperPath)}${path23.delimiter}${path23.dirname(manifest.stockCodexPath)}${path23.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
|
|
34476
34968
|
};
|
|
34477
34969
|
}
|
|
34478
34970
|
async function defaultRunTerminator(manifest, socketPath, role, environment) {
|
|
@@ -34760,7 +35252,7 @@ var harnessBrokerServerFrameSchema = external_exports.union([
|
|
|
34760
35252
|
var harnessBrokerDescriptorSchema = external_exports.object({
|
|
34761
35253
|
schemaVersion: external_exports.literal(1),
|
|
34762
35254
|
protocolVersion: external_exports.literal(HARNESS_BROKER_PROTOCOL_VERSION),
|
|
34763
|
-
harnessId:
|
|
35255
|
+
harnessId: harnessPluginIdSchema,
|
|
34764
35256
|
generation: external_exports.string().uuid(),
|
|
34765
35257
|
ownerPid: external_exports.number().int().positive(),
|
|
34766
35258
|
socketPath: external_exports.string().min(1).max(512),
|
|
@@ -34811,33 +35303,48 @@ function consumeBrokerFrames(socket, onFrame, onError) {
|
|
|
34811
35303
|
|
|
34812
35304
|
// packages/harness-broker/dist/paths.js
|
|
34813
35305
|
import os5 from "node:os";
|
|
34814
|
-
import
|
|
35306
|
+
import path24 from "node:path";
|
|
34815
35307
|
var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
|
|
34816
35308
|
var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
|
|
34817
35309
|
var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
|
|
34818
35310
|
function defaultHarnessBrokerDirectory(environment = process.env) {
|
|
34819
35311
|
const home = environment.HOME || os5.homedir();
|
|
34820
|
-
return
|
|
35312
|
+
return path24.join(home, ".codexhost", "harness-broker");
|
|
34821
35313
|
}
|
|
34822
|
-
function defaultHarnessBrokerDescriptorPath(environment = process.env) {
|
|
34823
|
-
|
|
35314
|
+
function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
|
|
35315
|
+
harnessPluginIdSchema.parse(harnessId);
|
|
35316
|
+
if (harnessId !== "claude-code")
|
|
35317
|
+
return path24.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
|
|
35318
|
+
return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
|
|
34824
35319
|
}
|
|
34825
|
-
function defaultHarnessBrokerSocketPath(environment = process.env) {
|
|
34826
|
-
|
|
35320
|
+
function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
|
|
35321
|
+
harnessPluginIdSchema.parse(harnessId);
|
|
35322
|
+
if (harnessId !== "claude-code")
|
|
35323
|
+
return path24.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
|
|
35324
|
+
return path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
|
|
34827
35325
|
}
|
|
34828
35326
|
|
|
34829
35327
|
// packages/harness-broker/dist/validation.js
|
|
34830
35328
|
var cwdSchema = external_exports.string().min(1).max(16384);
|
|
35329
|
+
var brokerEnvironmentSchema = external_exports.object({
|
|
35330
|
+
CODEXHOST_CLI_PATH: external_exports.string().max(16384).optional(),
|
|
35331
|
+
CODEXHOST_RUNTIME_ENDPOINT: external_exports.string().max(16384).optional(),
|
|
35332
|
+
CODEXHOST_RUNTIME_TOKEN: external_exports.string().max(16384).optional(),
|
|
35333
|
+
CODEXHOST_THREAD_ID: external_exports.string().max(256).optional()
|
|
35334
|
+
}).strict();
|
|
34831
35335
|
var createSchema = external_exports.object({
|
|
34832
35336
|
kind: external_exports.literal("create"),
|
|
34833
35337
|
cwd: cwdSchema,
|
|
34834
35338
|
executionPolicy: external_exports.enum(["default", "unattended-full-access"]).optional(),
|
|
35339
|
+
environment: brokerEnvironmentSchema.optional(),
|
|
34835
35340
|
model: harnessModelRefSchema.optional(),
|
|
34836
35341
|
thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
|
|
34837
35342
|
permissionModeId: harnessPermissionModeIdSchema.optional()
|
|
34838
35343
|
}).strict();
|
|
34839
35344
|
var resumeSchema = external_exports.object({
|
|
34840
35345
|
kind: external_exports.literal("resume"),
|
|
35346
|
+
environment: brokerEnvironmentSchema.optional(),
|
|
35347
|
+
permissionModeId: harnessPermissionModeIdSchema.optional(),
|
|
34841
35348
|
model: harnessModelRefSchema.optional(),
|
|
34842
35349
|
thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
|
|
34843
35350
|
nativeRef: nativeSessionRefSchema,
|
|
@@ -34846,12 +35353,14 @@ var resumeSchema = external_exports.object({
|
|
|
34846
35353
|
}).strict();
|
|
34847
35354
|
var forkSchema = external_exports.object({
|
|
34848
35355
|
kind: external_exports.literal("fork"),
|
|
35356
|
+
environment: brokerEnvironmentSchema.optional(),
|
|
34849
35357
|
sourceRef: nativeSessionRefSchema,
|
|
34850
35358
|
checkpoint: nativeCheckpointRefSchema,
|
|
34851
35359
|
cwd: cwdSchema
|
|
34852
35360
|
}).strict();
|
|
34853
35361
|
var rollbackSchema = external_exports.object({
|
|
34854
35362
|
kind: external_exports.literal("rollbackLastTurn"),
|
|
35363
|
+
environment: brokerEnvironmentSchema.optional(),
|
|
34855
35364
|
model: harnessModelRefSchema.optional(),
|
|
34856
35365
|
thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
|
|
34857
35366
|
permissionModeId: harnessPermissionModeIdSchema.optional(),
|
|
@@ -35025,10 +35534,10 @@ var harnessOutputSchema = external_exports.custom((value2) => {
|
|
|
35025
35534
|
});
|
|
35026
35535
|
|
|
35027
35536
|
// packages/harness-broker/dist/server.js
|
|
35028
|
-
import { randomBytes as randomBytes2, randomUUID as
|
|
35537
|
+
import { randomBytes as randomBytes2, randomUUID as randomUUID15 } from "node:crypto";
|
|
35029
35538
|
import { chmod as chmod5, lstat as lstat9, mkdir as mkdir12, open as open8, readFile as readFile10, rename as rename9, rm as rm11 } from "node:fs/promises";
|
|
35030
35539
|
import net4, {} from "node:net";
|
|
35031
|
-
import
|
|
35540
|
+
import path25 from "node:path";
|
|
35032
35541
|
function harnessError(message, retryable = true) {
|
|
35033
35542
|
return { code: "unavailable", message, retryable, stage: "harnessBroker" };
|
|
35034
35543
|
}
|
|
@@ -35084,7 +35593,7 @@ async function assertNoLiveDescriptor(descriptorPath) {
|
|
|
35084
35593
|
}
|
|
35085
35594
|
}
|
|
35086
35595
|
async function publishDescriptor(descriptorPath, descriptor) {
|
|
35087
|
-
const temporary = `${descriptorPath}.${process.pid}.${
|
|
35596
|
+
const temporary = `${descriptorPath}.${process.pid}.${randomUUID15()}.tmp`;
|
|
35088
35597
|
const handle = await open8(temporary, "wx", 384);
|
|
35089
35598
|
try {
|
|
35090
35599
|
await handle.writeFile(`${JSON.stringify(descriptor)}
|
|
@@ -35150,25 +35659,23 @@ async function prepareUnixSocketPath(socketPath) {
|
|
|
35150
35659
|
}
|
|
35151
35660
|
}
|
|
35152
35661
|
async function startHarnessBrokerServer(input) {
|
|
35153
|
-
|
|
35154
|
-
|
|
35155
|
-
}
|
|
35156
|
-
if (process.platform !== "win32" && path24.dirname(input.descriptorPath) !== path24.dirname(input.socketPath)) {
|
|
35662
|
+
harnessPluginIdSchema.parse(input.adapter.harnessId);
|
|
35663
|
+
if (process.platform !== "win32" && path25.dirname(input.descriptorPath) !== path25.dirname(input.socketPath)) {
|
|
35157
35664
|
throw new Error("Harness broker descriptor and socket must share one private directory");
|
|
35158
35665
|
}
|
|
35159
35666
|
if (process.platform === "darwin" && Buffer.byteLength(input.socketPath) > 103) {
|
|
35160
35667
|
throw new Error("Harness broker Unix socket path is too long for macOS");
|
|
35161
35668
|
}
|
|
35162
|
-
await privateDirectory(
|
|
35669
|
+
await privateDirectory(path25.dirname(input.descriptorPath));
|
|
35163
35670
|
await assertNoLiveDescriptor(input.descriptorPath);
|
|
35164
35671
|
if (process.platform !== "win32")
|
|
35165
35672
|
await prepareUnixSocketPath(input.socketPath);
|
|
35166
|
-
const generation = input.generation ??
|
|
35673
|
+
const generation = input.generation ?? randomUUID15();
|
|
35167
35674
|
const token = input.token ?? randomBytes2(32).toString("hex");
|
|
35168
35675
|
const descriptor = {
|
|
35169
35676
|
schemaVersion: 1,
|
|
35170
35677
|
protocolVersion: HARNESS_BROKER_PROTOCOL_VERSION,
|
|
35171
|
-
harnessId:
|
|
35678
|
+
harnessId: input.adapter.harnessId,
|
|
35172
35679
|
generation,
|
|
35173
35680
|
ownerPid: process.pid,
|
|
35174
35681
|
socketPath: input.socketPath,
|
|
@@ -35181,7 +35688,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35181
35688
|
let closed = false;
|
|
35182
35689
|
const server = net4.createServer((socket) => {
|
|
35183
35690
|
const state = {
|
|
35184
|
-
id:
|
|
35691
|
+
id: randomUUID15(),
|
|
35185
35692
|
socket,
|
|
35186
35693
|
authenticated: false,
|
|
35187
35694
|
inputSequence: 0,
|
|
@@ -35224,8 +35731,9 @@ async function startHarnessBrokerServer(input) {
|
|
|
35224
35731
|
if (output.kind === "event" && output.event.type === "session.state.changed") {
|
|
35225
35732
|
const state2 = output.event.state;
|
|
35226
35733
|
const observedNativeId = state2.nativeRef?.nativeSessionId;
|
|
35227
|
-
if (state2.nativeRef && record3.nativeRef && (record3.nativeRef.harnessId !== state2.nativeRef.harnessId || record3.nativeRef.nativeSessionId !== state2.nativeRef.nativeSessionId || record3.nativeRef.formatVersion !== state2.nativeRef.formatVersion)) {
|
|
35734
|
+
if (state2.nativeRef && (state2.nativeRef.harnessId !== input.adapter.harnessId || record3.nativeRef && (record3.nativeRef.harnessId !== state2.nativeRef.harnessId || record3.nativeRef.nativeSessionId !== state2.nativeRef.nativeSessionId || record3.nativeRef.formatVersion !== state2.nativeRef.formatVersion))) {
|
|
35228
35735
|
record3.faulted = true;
|
|
35736
|
+
releaseProvisionalWriter(record3);
|
|
35229
35737
|
await send({
|
|
35230
35738
|
kind: "output",
|
|
35231
35739
|
sessionId: record3.id,
|
|
@@ -35236,7 +35744,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35236
35744
|
type: "session.faulted",
|
|
35237
35745
|
error: {
|
|
35238
35746
|
code: "protocolError",
|
|
35239
|
-
message: "Native
|
|
35747
|
+
message: "Native Harness Session identity changed after open",
|
|
35240
35748
|
retryable: false,
|
|
35241
35749
|
stage: "harnessBroker.identity"
|
|
35242
35750
|
}
|
|
@@ -35262,7 +35770,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35262
35770
|
type: "session.faulted",
|
|
35263
35771
|
error: {
|
|
35264
35772
|
code: "sessionBusy",
|
|
35265
|
-
message: "Native
|
|
35773
|
+
message: "Native Harness Session already has an active writer",
|
|
35266
35774
|
retryable: true,
|
|
35267
35775
|
stage: "harnessBroker.identity"
|
|
35268
35776
|
}
|
|
@@ -35360,20 +35868,25 @@ async function startHarnessBrokerServer(input) {
|
|
|
35360
35868
|
if (request.method === "adapter.subagent.readSnapshot") {
|
|
35361
35869
|
const subagents = input.adapter.subagents;
|
|
35362
35870
|
if (!subagents)
|
|
35363
|
-
return { ok: false, error: harnessError("
|
|
35364
|
-
|
|
35871
|
+
return { ok: false, error: harnessError("Harness subagents are unavailable", false) };
|
|
35872
|
+
const params = subagentReadSnapshotSchema.parse(request.params);
|
|
35873
|
+
if (params.parent.harnessId !== input.adapter.harnessId)
|
|
35874
|
+
return { ok: false, error: protocolError("Subagent parent belongs to another Harness") };
|
|
35875
|
+
return subagents.readSnapshot(params);
|
|
35365
35876
|
}
|
|
35366
35877
|
if (request.method === "adapter.open") {
|
|
35367
35878
|
const openInput = brokerOpenInputSchema.parse(request.params);
|
|
35368
35879
|
const sourceRef = openInput.kind === "create" ? void 0 : openInput.kind === "resume" ? openInput.nativeRef : openInput.sourceRef;
|
|
35369
35880
|
const sourceNativeId = sourceRef?.nativeSessionId;
|
|
35881
|
+
if (sourceRef && sourceRef.harnessId !== input.adapter.harnessId)
|
|
35882
|
+
return { ok: false, error: protocolError("Native Session belongs to another Harness") };
|
|
35370
35883
|
const sourceKey = sourceNativeId ? nativeWriterKey(sourceNativeId) : void 0;
|
|
35371
35884
|
if (sourceKey && nativeWriters.has(sourceKey)) {
|
|
35372
35885
|
return {
|
|
35373
35886
|
ok: false,
|
|
35374
35887
|
error: {
|
|
35375
35888
|
code: "sessionBusy",
|
|
35376
|
-
message: "Native
|
|
35889
|
+
message: "Native Harness Session already has an active writer",
|
|
35377
35890
|
retryable: true,
|
|
35378
35891
|
stage: "harnessBroker.open"
|
|
35379
35892
|
}
|
|
@@ -35384,13 +35897,13 @@ async function startHarnessBrokerServer(input) {
|
|
|
35384
35897
|
ok: false,
|
|
35385
35898
|
error: {
|
|
35386
35899
|
code: "sessionBusy",
|
|
35387
|
-
message: "Native
|
|
35900
|
+
message: "Native Harness Session identity claim is already pending",
|
|
35388
35901
|
retryable: true,
|
|
35389
35902
|
stage: "harnessBroker.open"
|
|
35390
35903
|
}
|
|
35391
35904
|
};
|
|
35392
35905
|
}
|
|
35393
|
-
const openReservation =
|
|
35906
|
+
const openReservation = randomUUID15();
|
|
35394
35907
|
if (sourceKey)
|
|
35395
35908
|
nativeWriters.set(sourceKey, openReservation);
|
|
35396
35909
|
const provisionalReservation = openInput.kind === "create" ? openReservation : void 0;
|
|
@@ -35418,6 +35931,14 @@ async function startHarnessBrokerServer(input) {
|
|
|
35418
35931
|
return { ok: false, error: harnessError("Harness broker connection closed") };
|
|
35419
35932
|
}
|
|
35420
35933
|
const openedRef = opened.value.initialState.nativeRef;
|
|
35934
|
+
if (openedRef && openedRef.harnessId !== input.adapter.harnessId) {
|
|
35935
|
+
releaseOpenReservations();
|
|
35936
|
+
await opened.value.close().catch(() => void 0);
|
|
35937
|
+
return {
|
|
35938
|
+
ok: false,
|
|
35939
|
+
error: protocolError("Adapter opened a Session for another Harness")
|
|
35940
|
+
};
|
|
35941
|
+
}
|
|
35421
35942
|
if (sourceRef && (!openedRef || openedRef.harnessId !== sourceRef.harnessId || openedRef.formatVersion !== sourceRef.formatVersion || openInput.kind === "resume" && openedRef.nativeSessionId !== sourceRef.nativeSessionId)) {
|
|
35422
35943
|
releaseOpenReservations();
|
|
35423
35944
|
await opened.value.close().catch(() => void 0);
|
|
@@ -35425,7 +35946,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35425
35946
|
ok: false,
|
|
35426
35947
|
error: {
|
|
35427
35948
|
code: "protocolError",
|
|
35428
|
-
message: "Native
|
|
35949
|
+
message: "Native Harness Session identity did not match the requested open",
|
|
35429
35950
|
retryable: false,
|
|
35430
35951
|
stage: "harnessBroker.open"
|
|
35431
35952
|
}
|
|
@@ -35441,7 +35962,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35441
35962
|
ok: false,
|
|
35442
35963
|
error: {
|
|
35443
35964
|
code: "sessionBusy",
|
|
35444
|
-
message: "Native
|
|
35965
|
+
message: "Native Harness Session already has an active writer",
|
|
35445
35966
|
retryable: true,
|
|
35446
35967
|
stage: "harnessBroker.open"
|
|
35447
35968
|
}
|
|
@@ -35453,6 +35974,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35453
35974
|
generation: 1,
|
|
35454
35975
|
owner: state.id,
|
|
35455
35976
|
cwd: openInput.cwd,
|
|
35977
|
+
...openInput.environment ? { environment: openInput.environment } : {},
|
|
35456
35978
|
...nativeId ? { nativeId } : {},
|
|
35457
35979
|
...opened.value.initialState.nativeRef ? { nativeRef: opened.value.initialState.nativeRef } : {},
|
|
35458
35980
|
...nativeKey ? { writerKey: nativeKey } : {},
|
|
@@ -35493,7 +36015,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35493
36015
|
ok: false,
|
|
35494
36016
|
error: {
|
|
35495
36017
|
code: "sessionBusy",
|
|
35496
|
-
message: "Native
|
|
36018
|
+
message: "Native Harness Session identity has not been claimed yet",
|
|
35497
36019
|
retryable: true,
|
|
35498
36020
|
stage: "harnessBroker.identity"
|
|
35499
36021
|
}
|
|
@@ -35570,7 +36092,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35570
36092
|
ok: false,
|
|
35571
36093
|
error: {
|
|
35572
36094
|
code: "sessionBusy",
|
|
35573
|
-
message: "Faulted
|
|
36095
|
+
message: "Faulted Harness Session has no authoritative native identity",
|
|
35574
36096
|
retryable: false,
|
|
35575
36097
|
stage: "harnessBroker.reopen"
|
|
35576
36098
|
}
|
|
@@ -35582,7 +36104,12 @@ async function startHarnessBrokerServer(input) {
|
|
|
35582
36104
|
record4.forwarderEpoch += 1;
|
|
35583
36105
|
await oldSession.close().catch(() => void 0);
|
|
35584
36106
|
await oldOutputTask.catch(() => void 0);
|
|
35585
|
-
const reopened = await input.adapter.open({
|
|
36107
|
+
const reopened = await input.adapter.open({
|
|
36108
|
+
kind: "resume",
|
|
36109
|
+
cwd: record4.cwd,
|
|
36110
|
+
nativeRef,
|
|
36111
|
+
...record4.environment ? { environment: record4.environment } : {}
|
|
36112
|
+
});
|
|
35586
36113
|
if (!reopened.ok)
|
|
35587
36114
|
return reopened;
|
|
35588
36115
|
const reopenedRef = reopened.value.initialState.nativeRef;
|
|
@@ -35592,7 +36119,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35592
36119
|
ok: false,
|
|
35593
36120
|
error: {
|
|
35594
36121
|
code: "protocolError",
|
|
35595
|
-
message: "
|
|
36122
|
+
message: "Aqua Harness broker reopen changed the native Session identity",
|
|
35596
36123
|
retryable: false,
|
|
35597
36124
|
stage: "harnessBroker.reopen"
|
|
35598
36125
|
}
|
|
@@ -35656,7 +36183,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
35656
36183
|
}
|
|
35657
36184
|
state.authenticated = true;
|
|
35658
36185
|
state.inputSequence = 1;
|
|
35659
|
-
await send({ kind: "response", id:
|
|
36186
|
+
await send({ kind: "response", id: randomUUID15(), ok: true, value: { ready: true } });
|
|
35660
36187
|
return;
|
|
35661
36188
|
}
|
|
35662
36189
|
const parsed = harnessBrokerRequestSchema.safeParse(raw);
|
|
@@ -35729,15 +36256,16 @@ async function startHarnessBrokerServer(input) {
|
|
|
35729
36256
|
}
|
|
35730
36257
|
|
|
35731
36258
|
// packages/host-runtime/src/aqua-harness-broker.ts
|
|
35732
|
-
async function runClaudeAquaHarnessBroker(environment = process.env) {
|
|
36259
|
+
async function runClaudeAquaHarnessBroker(environment = process.env, requestedHarnessId = "claude-code") {
|
|
36260
|
+
const harnessId = harnessPluginIdSchema.parse(requestedHarnessId);
|
|
35733
36261
|
if (process.platform !== "darwin") {
|
|
35734
|
-
throw new Error("
|
|
36262
|
+
throw new Error("Aqua Harness broker is available only on macOS");
|
|
35735
36263
|
}
|
|
35736
36264
|
const { pluginRoots, pluginContext } = installedHarnessPluginOptions(environment);
|
|
35737
36265
|
const plugins = await loadHarnessPlugins({
|
|
35738
36266
|
roots: pluginRoots,
|
|
35739
36267
|
context: pluginContext,
|
|
35740
|
-
onlyIds: /* @__PURE__ */ new Set([
|
|
36268
|
+
onlyIds: /* @__PURE__ */ new Set([harnessId]),
|
|
35741
36269
|
warmup: false,
|
|
35742
36270
|
diagnose: (diagnostic) => process.stderr.write(`Harness plugin: ${JSON.stringify(diagnostic)}
|
|
35743
36271
|
`)
|
|
@@ -35750,19 +36278,19 @@ async function runClaudeAquaHarnessBroker(environment = process.env) {
|
|
|
35750
36278
|
let server;
|
|
35751
36279
|
try {
|
|
35752
36280
|
server = await startHarnessBrokerServer({
|
|
35753
|
-
descriptorPath: defaultHarnessBrokerDescriptorPath(environment),
|
|
35754
|
-
socketPath: defaultHarnessBrokerSocketPath(environment),
|
|
36281
|
+
descriptorPath: defaultHarnessBrokerDescriptorPath(environment, harnessId),
|
|
36282
|
+
socketPath: defaultHarnessBrokerSocketPath(environment, harnessId),
|
|
35755
36283
|
adapter
|
|
35756
36284
|
});
|
|
35757
36285
|
} catch (error51) {
|
|
35758
36286
|
await adapter.close().catch(() => void 0);
|
|
35759
36287
|
throw error51;
|
|
35760
36288
|
}
|
|
35761
|
-
process.title =
|
|
36289
|
+
process.title = `codexhost ${harnessId} Aqua harness broker`;
|
|
35762
36290
|
process.stdout.write(
|
|
35763
36291
|
`${JSON.stringify({
|
|
35764
36292
|
method: "codexhost/harness-broker/ready",
|
|
35765
|
-
params: { protocolVersion: 1, harnessId
|
|
36293
|
+
params: { protocolVersion: 1, harnessId }
|
|
35766
36294
|
})}
|
|
35767
36295
|
`
|
|
35768
36296
|
);
|
|
@@ -35785,7 +36313,7 @@ async function runClaudeAquaHarnessBroker(environment = process.env) {
|
|
|
35785
36313
|
|
|
35786
36314
|
// packages/host-runtime/src/release-main.ts
|
|
35787
36315
|
var arguments_ = process.argv.slice(2);
|
|
35788
|
-
process.exitCode = arguments_[0] === "--codexhost-delegation-cli" ? await runDelegationCli({ arguments: arguments_.slice(1), environment: process.env }) : arguments_[0] === "--codexhost-harness-broker" ? await runClaudeAquaHarnessBroker(process.env) : arguments_[0] === "--codexhost-remote" ? await runRemoteHostCli({ arguments: arguments_.slice(1), environment: process.env }) : arguments_[0] === "--codexhost-remote-control-bridge" ? await runRemoteControlAppServerBridge() : await runHostRuntime({
|
|
36316
|
+
process.exitCode = arguments_[0] === "--codexhost-delegation-cli" ? await runDelegationCli({ arguments: arguments_.slice(1), environment: process.env }) : arguments_[0] === "--codexhost-harness-broker" ? await runClaudeAquaHarnessBroker(process.env, arguments_[1] ?? "claude-code") : arguments_[0] === "--codexhost-remote" ? await runRemoteHostCli({ arguments: arguments_.slice(1), environment: process.env }) : arguments_[0] === "--codexhost-remote-control-bridge" ? await runRemoteControlAppServerBridge() : await runHostRuntime({
|
|
35789
36317
|
arguments: arguments_,
|
|
35790
36318
|
environment: process.env,
|
|
35791
36319
|
hostRuntimeUrl: import.meta.url
|