@liberseek/boft-cli-win32-arm64 0.7.1 → 0.7.3
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/app/codexhost-distribution.json +1 -1
- package/app/desktop-controller.mjs +49 -18
- package/app/host-runtime.mjs +1025 -671
- package/app/plugins/antigravity/plugin.mjs +18 -3
- package/app/plugins/claude-code/plugin.mjs +214 -7
- package/app/plugins/codebuddy/plugin.mjs +103 -5
- package/app/plugins/cursor-cli/plugin.mjs +152 -53
- package/app/plugins/deepseek-harness/plugin.mjs +34 -21
- package/app/plugins/enabled.json +2 -1
- package/app/plugins/grok/plugin.mjs +281 -88
- package/app/plugins/hermes/plugin.mjs +162 -63
- package/app/plugins/kimi-code/manifest.json +11 -0
- package/app/plugins/kimi-code/plugin.mjs +24259 -0
- package/app/plugins/kiro-cli/plugin.mjs +257 -65
- package/app/plugins/muse/plugin.mjs +18 -3
- package/app/plugins/omp/plugin.mjs +258 -67
- package/app/plugins/opencode/plugin.mjs +18 -3
- package/app/plugins/pi/plugin.mjs +211 -4
- package/app/plugins/qoder/plugin.mjs +285 -193
- package/app/plugins/qoder-cn/plugin.mjs +285 -193
- package/app/plugins/workbuddy/plugin.mjs +102 -5
- package/app/renderer-extension.js +1304 -468
- package/bin/boft.exe +0 -0
- package/libexec/boft-node-repl.exe +0 -0
- package/libexec/boft-shim.exe +0 -0
- package/libexec/boft-updater.exe +0 -0
- package/package.json +1 -1
package/app/host-runtime.mjs
CHANGED
|
@@ -4283,7 +4283,7 @@ async function runDelegationCli(input) {
|
|
|
4283
4283
|
|
|
4284
4284
|
// packages/host-runtime/src/run-host-runtime.ts
|
|
4285
4285
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
4286
|
-
import
|
|
4286
|
+
import path24 from "node:path";
|
|
4287
4287
|
import { homedir as homedir2 } from "node:os";
|
|
4288
4288
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
4289
4289
|
|
|
@@ -5978,10 +5978,10 @@ function mergeDefs(...defs) {
|
|
|
5978
5978
|
function cloneDef(schema) {
|
|
5979
5979
|
return mergeDefs(schema._zod.def);
|
|
5980
5980
|
}
|
|
5981
|
-
function getElementAtPath(obj,
|
|
5982
|
-
if (!
|
|
5981
|
+
function getElementAtPath(obj, path29) {
|
|
5982
|
+
if (!path29)
|
|
5983
5983
|
return obj;
|
|
5984
|
-
return
|
|
5984
|
+
return path29.reduce((acc, key) => acc?.[key], obj);
|
|
5985
5985
|
}
|
|
5986
5986
|
function promiseAllObject(promisesObj) {
|
|
5987
5987
|
const keys = Object.keys(promisesObj);
|
|
@@ -6390,11 +6390,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
6390
6390
|
}
|
|
6391
6391
|
return false;
|
|
6392
6392
|
}
|
|
6393
|
-
function prefixIssues(
|
|
6393
|
+
function prefixIssues(path29, issues) {
|
|
6394
6394
|
return issues.map((iss) => {
|
|
6395
6395
|
var _a3;
|
|
6396
6396
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
6397
|
-
iss.path.unshift(
|
|
6397
|
+
iss.path.unshift(path29);
|
|
6398
6398
|
return iss;
|
|
6399
6399
|
});
|
|
6400
6400
|
}
|
|
@@ -6541,16 +6541,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
6541
6541
|
}
|
|
6542
6542
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
6543
6543
|
const fieldErrors = { _errors: [] };
|
|
6544
|
-
const processError = (error52,
|
|
6544
|
+
const processError = (error52, path29 = []) => {
|
|
6545
6545
|
for (const issue2 of error52.issues) {
|
|
6546
6546
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
6547
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
6547
|
+
issue2.errors.map((issues) => processError({ issues }, [...path29, ...issue2.path]));
|
|
6548
6548
|
} else if (issue2.code === "invalid_key") {
|
|
6549
|
-
processError({ issues: issue2.issues }, [...
|
|
6549
|
+
processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
|
|
6550
6550
|
} else if (issue2.code === "invalid_element") {
|
|
6551
|
-
processError({ issues: issue2.issues }, [...
|
|
6551
|
+
processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
|
|
6552
6552
|
} else {
|
|
6553
|
-
const fullpath = [...
|
|
6553
|
+
const fullpath = [...path29, ...issue2.path];
|
|
6554
6554
|
if (fullpath.length === 0) {
|
|
6555
6555
|
fieldErrors._errors.push(mapper(issue2));
|
|
6556
6556
|
} else {
|
|
@@ -6577,17 +6577,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
6577
6577
|
}
|
|
6578
6578
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
6579
6579
|
const result = { errors: [] };
|
|
6580
|
-
const processError = (error52,
|
|
6580
|
+
const processError = (error52, path29 = []) => {
|
|
6581
6581
|
var _a3, _b;
|
|
6582
6582
|
for (const issue2 of error52.issues) {
|
|
6583
6583
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
6584
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
6584
|
+
issue2.errors.map((issues) => processError({ issues }, [...path29, ...issue2.path]));
|
|
6585
6585
|
} else if (issue2.code === "invalid_key") {
|
|
6586
|
-
processError({ issues: issue2.issues }, [...
|
|
6586
|
+
processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
|
|
6587
6587
|
} else if (issue2.code === "invalid_element") {
|
|
6588
|
-
processError({ issues: issue2.issues }, [...
|
|
6588
|
+
processError({ issues: issue2.issues }, [...path29, ...issue2.path]);
|
|
6589
6589
|
} else {
|
|
6590
|
-
const fullpath = [...
|
|
6590
|
+
const fullpath = [...path29, ...issue2.path];
|
|
6591
6591
|
if (fullpath.length === 0) {
|
|
6592
6592
|
result.errors.push(mapper(issue2));
|
|
6593
6593
|
continue;
|
|
@@ -6619,8 +6619,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
6619
6619
|
}
|
|
6620
6620
|
function toDotPath(_path) {
|
|
6621
6621
|
const segs = [];
|
|
6622
|
-
const
|
|
6623
|
-
for (const seg of
|
|
6622
|
+
const path29 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
6623
|
+
for (const seg of path29) {
|
|
6624
6624
|
if (typeof seg === "number")
|
|
6625
6625
|
segs.push(`[${seg}]`);
|
|
6626
6626
|
else if (typeof seg === "symbol")
|
|
@@ -19312,13 +19312,13 @@ function resolveRef(ref, ctx) {
|
|
|
19312
19312
|
if (!ref.startsWith("#")) {
|
|
19313
19313
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
19314
19314
|
}
|
|
19315
|
-
const
|
|
19316
|
-
if (
|
|
19315
|
+
const path29 = ref.slice(1).split("/").filter(Boolean);
|
|
19316
|
+
if (path29.length === 0) {
|
|
19317
19317
|
return ctx.rootSchema;
|
|
19318
19318
|
}
|
|
19319
19319
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
19320
|
-
if (
|
|
19321
|
-
const key =
|
|
19320
|
+
if (path29[0] === defsKey) {
|
|
19321
|
+
const key = path29[1];
|
|
19322
19322
|
if (!key || !ctx.defs[key]) {
|
|
19323
19323
|
throw new Error(`Reference not found: ${ref}`);
|
|
19324
19324
|
}
|
|
@@ -20546,10 +20546,21 @@ var harnessCommandDescriptorSchema = external_exports.object({
|
|
|
20546
20546
|
invocation: commandInvocationSchema,
|
|
20547
20547
|
label: commandLabelSchema,
|
|
20548
20548
|
description: commandDescriptionSchema.optional(),
|
|
20549
|
-
argumentMode: external_exports.enum(["none", "text"])
|
|
20549
|
+
argumentMode: external_exports.enum(["none", "text"]),
|
|
20550
|
+
/**
|
|
20551
|
+
* Native distinction reported by the Harness. Omitted when the Harness does
|
|
20552
|
+
* not tell skills and commands apart; consumers treat that as "command".
|
|
20553
|
+
*/
|
|
20554
|
+
kind: external_exports.enum(["command", "skill"]).optional()
|
|
20550
20555
|
}).strict();
|
|
20551
20556
|
var harnessCommandCatalogSchema = external_exports.object({
|
|
20552
|
-
commands: external_exports.array(harnessCommandDescriptorSchema)
|
|
20557
|
+
commands: external_exports.array(harnessCommandDescriptorSchema),
|
|
20558
|
+
/**
|
|
20559
|
+
* `live` when the catalog includes what a native Session reports for its
|
|
20560
|
+
* workspace (custom commands, skills); `static` for Adapter built-ins only.
|
|
20561
|
+
* Omitted by Adapters; set by the Host on inspection results.
|
|
20562
|
+
*/
|
|
20563
|
+
source: external_exports.enum(["live", "static"]).optional()
|
|
20553
20564
|
}).strict().superRefine((catalog, context) => {
|
|
20554
20565
|
const ids = /* @__PURE__ */ new Set();
|
|
20555
20566
|
for (const [index, command] of catalog.commands.entries()) {
|
|
@@ -20563,7 +20574,11 @@ var harnessCommandCatalogSchema = external_exports.object({
|
|
|
20563
20574
|
ids.add(command.id);
|
|
20564
20575
|
}
|
|
20565
20576
|
});
|
|
20566
|
-
var harnessCommandsInspectParamsSchema = external_exports.object({
|
|
20577
|
+
var harnessCommandsInspectParamsSchema = external_exports.object({
|
|
20578
|
+
harnessId: harnessIdSchema,
|
|
20579
|
+
/** Workspace of a draft without a Thread, for its live catalog when known. */
|
|
20580
|
+
cwd: external_exports.string().min(1).optional()
|
|
20581
|
+
}).strict();
|
|
20567
20582
|
var threadCommandsInspectParamsSchema = external_exports.object({
|
|
20568
20583
|
threadId: hostThreadIdSchema
|
|
20569
20584
|
}).strict();
|
|
@@ -20707,6 +20722,41 @@ var updateStatusResultSchema = external_exports.strictObject({
|
|
|
20707
20722
|
status: updateStatusSchema.nullable()
|
|
20708
20723
|
});
|
|
20709
20724
|
|
|
20725
|
+
// packages/shared-contracts/dist/delegation-mention.js
|
|
20726
|
+
var DELEGATION_MENTION_PATH_PREFIX = "subagent://codexhost.";
|
|
20727
|
+
var MENTION_LINK_PATTERN = /\[@([^\]\n]+)\]\(<?subagent:\/\/codexhost\.([a-z0-9][a-z0-9-]*)>?\)/gu;
|
|
20728
|
+
function stripDelegationMentions(text2) {
|
|
20729
|
+
const mentions = [];
|
|
20730
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20731
|
+
const rewritten = text2.replace(MENTION_LINK_PATTERN, (_match, label, harnessId) => {
|
|
20732
|
+
const trimmed = label.trim();
|
|
20733
|
+
if (!seen.has(harnessId)) {
|
|
20734
|
+
seen.add(harnessId);
|
|
20735
|
+
mentions.push({ harnessId, label: trimmed });
|
|
20736
|
+
}
|
|
20737
|
+
return `@${trimmed}`;
|
|
20738
|
+
});
|
|
20739
|
+
return { text: rewritten, mentions };
|
|
20740
|
+
}
|
|
20741
|
+
var COMMAND_LINK_PATTERN = /([ \t]*)\[@([^\]\n]+)\]\(<?subagent:\/\/codexhost-command\.([^)\s>]+)>?\)([ \t]*)/gu;
|
|
20742
|
+
function restoreHarnessCommandMentions(text2) {
|
|
20743
|
+
let invocation = null;
|
|
20744
|
+
const rest = text2.replace(COMMAND_LINK_PATTERN, (match, before, _label, encoded, after) => {
|
|
20745
|
+
if (invocation === null) {
|
|
20746
|
+
try {
|
|
20747
|
+
invocation = `/${decodeURIComponent(encoded)}`;
|
|
20748
|
+
} catch {
|
|
20749
|
+
return match;
|
|
20750
|
+
}
|
|
20751
|
+
}
|
|
20752
|
+
return before || after ? " " : "";
|
|
20753
|
+
});
|
|
20754
|
+
if (invocation === null)
|
|
20755
|
+
return text2;
|
|
20756
|
+
const argumentsText = rest.trim();
|
|
20757
|
+
return argumentsText ? `${invocation} ${argumentsText}` : invocation;
|
|
20758
|
+
}
|
|
20759
|
+
|
|
20710
20760
|
// packages/shared-contracts/dist/index.js
|
|
20711
20761
|
var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
|
|
20712
20762
|
|
|
@@ -20801,6 +20851,232 @@ async function listOthers(adapter) {
|
|
|
20801
20851
|
}
|
|
20802
20852
|
}
|
|
20803
20853
|
|
|
20854
|
+
// packages/host-runtime/src/delegation-skill.ts
|
|
20855
|
+
import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
|
|
20856
|
+
import { mkdir as mkdir3, open as open3, readFile as readFile5, rename as rename2, rm as rm3, stat } from "node:fs/promises";
|
|
20857
|
+
import os2 from "node:os";
|
|
20858
|
+
import path6 from "node:path";
|
|
20859
|
+
var SKILL_VERSION = 7;
|
|
20860
|
+
var DELEGATION_SKILL_NAME = "codexhost-delegation";
|
|
20861
|
+
var SKILL_RELATIVE_PATH = path6.join("skills", DELEGATION_SKILL_NAME, "SKILL.md");
|
|
20862
|
+
var PREVIOUS_MANAGED_DIGESTS = [
|
|
20863
|
+
"9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
|
|
20864
|
+
"2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
|
|
20865
|
+
"aff258622dc8ff321f32b15620d081e578cb9c9ed1134d6a57f35ca8e7762c0a",
|
|
20866
|
+
"ba509f57e5448e796b3dfdd5031dcb08672eded50b61c0a54de84cfa02c49dd3",
|
|
20867
|
+
"d3ddf6db9bc5c5df825479c885bbbf0ca08da66f7057a12e02e1fdf57525149e",
|
|
20868
|
+
"15eb63519ff867e1536c97188a0c43738d7a49d38d4d6adeb7a1036726e7246d",
|
|
20869
|
+
"09acc3cc0a598e546ce35fccb9d856d9fe06c01ab055dfce1914dab92479c9a2"
|
|
20870
|
+
];
|
|
20871
|
+
var CODEXHOST_DELEGATION_SKILL = `---
|
|
20872
|
+
name: codexhost-delegation
|
|
20873
|
+
version: ${SKILL_VERSION}
|
|
20874
|
+
description: >
|
|
20875
|
+
Delegate tasks to other coding agents, or read and follow up on existing
|
|
20876
|
+
external agent sessions. Use when the user asks another agent (including
|
|
20877
|
+
@agent) to independently perform a task, or asks to view a specified external
|
|
20878
|
+
session's content, progress, or results, send follow-up messages, wait, or
|
|
20879
|
+
cancel a task. Not for recapping the current conversation, discussing or
|
|
20880
|
+
configuring agents, or role-playing.
|
|
20881
|
+
---
|
|
20882
|
+
|
|
20883
|
+
# Execute the task
|
|
20884
|
+
|
|
20885
|
+
Before acting, run:
|
|
20886
|
+
|
|
20887
|
+
\`boft delegate --help\`
|
|
20888
|
+
|
|
20889
|
+
Use CLI help as the authoritative source for commands and behavior. Consult
|
|
20890
|
+
command-specific help for options and the Harness listing command when the
|
|
20891
|
+
target is unknown. Prefer compact output when supported, and use its task links
|
|
20892
|
+
directly for subsequent commands.
|
|
20893
|
+
|
|
20894
|
+
Use the Harness native defaults. Inspect the target when a Model or Thinking
|
|
20895
|
+
selection is needed or the default is unavailable.
|
|
20896
|
+
|
|
20897
|
+
For a new delegation, create an independent child session and submit the
|
|
20898
|
+
requested task. For an existing external session, resolve the target from the
|
|
20899
|
+
user-provided session link, identifier, or context and operate on that Thread
|
|
20900
|
+
directly; it need not have been created by the current assistant. If the target
|
|
20901
|
+
is ambiguous, ask the user to identify it. Keep requests to view or summarize a
|
|
20902
|
+
session read-only.
|
|
20903
|
+
|
|
20904
|
+
For a new or existing task, choose the appropriate next action based on the
|
|
20905
|
+
user’s request and the task:
|
|
20906
|
+
|
|
20907
|
+
- send a follow-up message to the same Thread;
|
|
20908
|
+
- cancel its current Turn;
|
|
20909
|
+
- read its current state immediately;
|
|
20910
|
+
- wait for a bounded period;
|
|
20911
|
+
- check it again later;
|
|
20912
|
+
- leave it running in the background.
|
|
20913
|
+
|
|
20914
|
+
Report the result returned by read or a completed wait, together with the target
|
|
20915
|
+
agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
|
|
20916
|
+
`;
|
|
20917
|
+
var CURRENT_DIGEST = createHash3("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
|
|
20918
|
+
function digest(value2) {
|
|
20919
|
+
return createHash3("sha256").update(value2).digest("hex");
|
|
20920
|
+
}
|
|
20921
|
+
function managedVersion(value2) {
|
|
20922
|
+
const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
|
|
20923
|
+
return match ? Number(match[1]) : null;
|
|
20924
|
+
}
|
|
20925
|
+
async function readOptional(filePath) {
|
|
20926
|
+
try {
|
|
20927
|
+
return await readFile5(filePath, "utf8");
|
|
20928
|
+
} catch (error51) {
|
|
20929
|
+
if (error51.code === "ENOENT") return null;
|
|
20930
|
+
throw error51;
|
|
20931
|
+
}
|
|
20932
|
+
}
|
|
20933
|
+
async function atomicWrite(filePath, content) {
|
|
20934
|
+
await mkdir3(path6.dirname(filePath), { recursive: true, mode: 448 });
|
|
20935
|
+
const temporaryPath = path6.join(path6.dirname(filePath), `.SKILL.md.${randomUUID2()}.tmp`);
|
|
20936
|
+
const handle = await open3(temporaryPath, "wx", 384);
|
|
20937
|
+
try {
|
|
20938
|
+
await handle.writeFile(content, "utf8");
|
|
20939
|
+
await handle.sync();
|
|
20940
|
+
} finally {
|
|
20941
|
+
await handle.close();
|
|
20942
|
+
}
|
|
20943
|
+
try {
|
|
20944
|
+
await rename2(temporaryPath, filePath);
|
|
20945
|
+
} finally {
|
|
20946
|
+
await rm3(temporaryPath, { force: true });
|
|
20947
|
+
}
|
|
20948
|
+
}
|
|
20949
|
+
async function installDelegationSkills(input = {}) {
|
|
20950
|
+
const home = input.homeDirectory ?? os2.homedir();
|
|
20951
|
+
const destinations = [
|
|
20952
|
+
path6.join(home, ".agents", SKILL_RELATIVE_PATH),
|
|
20953
|
+
path6.join(home, ".claude", SKILL_RELATIVE_PATH)
|
|
20954
|
+
];
|
|
20955
|
+
const knownDigests = /* @__PURE__ */ new Set([
|
|
20956
|
+
CURRENT_DIGEST,
|
|
20957
|
+
...PREVIOUS_MANAGED_DIGESTS,
|
|
20958
|
+
...input.previousManagedDigests ?? []
|
|
20959
|
+
]);
|
|
20960
|
+
const results = [];
|
|
20961
|
+
for (const destination of destinations) {
|
|
20962
|
+
const current = await readOptional(destination);
|
|
20963
|
+
if (current === CODEXHOST_DELEGATION_SKILL) {
|
|
20964
|
+
results.push({
|
|
20965
|
+
path: destination,
|
|
20966
|
+
status: "current",
|
|
20967
|
+
version: SKILL_VERSION,
|
|
20968
|
+
digest: CURRENT_DIGEST
|
|
20969
|
+
});
|
|
20970
|
+
continue;
|
|
20971
|
+
}
|
|
20972
|
+
if (current !== null) {
|
|
20973
|
+
const currentDigest = digest(current);
|
|
20974
|
+
const version2 = managedVersion(current);
|
|
20975
|
+
if (!knownDigests.has(currentDigest)) {
|
|
20976
|
+
results.push({ path: destination, status: "conflict", version: version2, digest: currentDigest });
|
|
20977
|
+
continue;
|
|
20978
|
+
}
|
|
20979
|
+
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
20980
|
+
results.push({
|
|
20981
|
+
path: destination,
|
|
20982
|
+
status: "updated",
|
|
20983
|
+
version: SKILL_VERSION,
|
|
20984
|
+
digest: CURRENT_DIGEST
|
|
20985
|
+
});
|
|
20986
|
+
continue;
|
|
20987
|
+
}
|
|
20988
|
+
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
20989
|
+
results.push({
|
|
20990
|
+
path: destination,
|
|
20991
|
+
status: "installed",
|
|
20992
|
+
version: SKILL_VERSION,
|
|
20993
|
+
digest: CURRENT_DIGEST
|
|
20994
|
+
});
|
|
20995
|
+
}
|
|
20996
|
+
for (const result of results) {
|
|
20997
|
+
if (result.status === "conflict") continue;
|
|
20998
|
+
const source = await readFile5(result.path, "utf8");
|
|
20999
|
+
const metadata = await stat(result.path);
|
|
21000
|
+
if (!metadata.isFile() || source !== CODEXHOST_DELEGATION_SKILL) {
|
|
21001
|
+
throw new Error(`Delegation Skill verification failed: ${result.path}`);
|
|
21002
|
+
}
|
|
21003
|
+
}
|
|
21004
|
+
const managed = results.filter((result) => result.status !== "conflict");
|
|
21005
|
+
if (managed.some((result) => result.digest !== CURRENT_DIGEST)) {
|
|
21006
|
+
throw new Error("Delegation Skill copies are inconsistent");
|
|
21007
|
+
}
|
|
21008
|
+
if (results.every((result) => result.status !== "conflict")) {
|
|
21009
|
+
const copies = await Promise.all(results.map((result) => readFile5(result.path, "utf8")));
|
|
21010
|
+
if (copies.some((copy) => copy !== copies[0])) {
|
|
21011
|
+
throw new Error("Delegation Skill copies are inconsistent");
|
|
21012
|
+
}
|
|
21013
|
+
}
|
|
21014
|
+
return results;
|
|
21015
|
+
}
|
|
21016
|
+
async function managedDelegationSkillReference(input = {}) {
|
|
21017
|
+
const filePath = path6.join(input.homeDirectory ?? os2.homedir(), ".agents", SKILL_RELATIVE_PATH);
|
|
21018
|
+
try {
|
|
21019
|
+
return await readOptional(filePath) === CODEXHOST_DELEGATION_SKILL ? { name: DELEGATION_SKILL_NAME, path: filePath } : null;
|
|
21020
|
+
} catch {
|
|
21021
|
+
return null;
|
|
21022
|
+
}
|
|
21023
|
+
}
|
|
21024
|
+
|
|
21025
|
+
// packages/host-runtime/src/delegation-mention-rewrite.ts
|
|
21026
|
+
function describeTargets(mentions) {
|
|
21027
|
+
return mentions.map(({ harnessId, label }) => `@${label} (Harness \`${harnessId}\`)`).join(", ");
|
|
21028
|
+
}
|
|
21029
|
+
function delegationMentionInstruction(mentions) {
|
|
21030
|
+
const plural = mentions.length > 1;
|
|
21031
|
+
return [
|
|
21032
|
+
`[codexhost delegation] The user mentioned ${describeTargets(mentions)}.`,
|
|
21033
|
+
`Use the ${DELEGATION_SKILL_NAME} skill to delegate this request to ${plural ? "each mentioned Harness" : "that Harness"}`,
|
|
21034
|
+
"with `codexhost delegate start --harness <id>`, instead of doing the task yourself."
|
|
21035
|
+
].join(" ");
|
|
21036
|
+
}
|
|
21037
|
+
function appendInstruction(text2, mentions) {
|
|
21038
|
+
const instruction = delegationMentionInstruction(mentions);
|
|
21039
|
+
return text2.trim().length === 0 ? instruction : `${text2}
|
|
21040
|
+
|
|
21041
|
+
${instruction}`;
|
|
21042
|
+
}
|
|
21043
|
+
function rewriteDelegationMentionText(text2) {
|
|
21044
|
+
const { text: stripped, mentions } = stripDelegationMentions(text2);
|
|
21045
|
+
return mentions.length === 0 ? text2 : appendInstruction(stripped, mentions);
|
|
21046
|
+
}
|
|
21047
|
+
function isRecord(value2) {
|
|
21048
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
21049
|
+
}
|
|
21050
|
+
function rewriteDelegationMentionInput(input, skill) {
|
|
21051
|
+
const mentions = [];
|
|
21052
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21053
|
+
let lastTextIndex = -1;
|
|
21054
|
+
const rewritten = input.map((item, index) => {
|
|
21055
|
+
if (!isRecord(item) || item.type !== "text" || typeof item.text !== "string") return item;
|
|
21056
|
+
lastTextIndex = index;
|
|
21057
|
+
const result = stripDelegationMentions(item.text);
|
|
21058
|
+
for (const mention of result.mentions) {
|
|
21059
|
+
if (seen.has(mention.harnessId)) continue;
|
|
21060
|
+
seen.add(mention.harnessId);
|
|
21061
|
+
mentions.push(mention);
|
|
21062
|
+
}
|
|
21063
|
+
return result.mentions.length === 0 ? item : { ...item, text: result.text };
|
|
21064
|
+
});
|
|
21065
|
+
if (mentions.length === 0) return null;
|
|
21066
|
+
const target = rewritten[lastTextIndex];
|
|
21067
|
+
if (isRecord(target) && typeof target.text === "string") {
|
|
21068
|
+
rewritten[lastTextIndex] = {
|
|
21069
|
+
...target,
|
|
21070
|
+
text: appendInstruction(target.text, mentions)
|
|
21071
|
+
};
|
|
21072
|
+
}
|
|
21073
|
+
const hasSkill = rewritten.some(
|
|
21074
|
+
(item) => isRecord(item) && item.type === "skill" && item.name === skill?.name
|
|
21075
|
+
);
|
|
21076
|
+
if (skill && !hasSkill) rewritten.push({ type: "skill", name: skill.name, path: skill.path });
|
|
21077
|
+
return rewritten;
|
|
21078
|
+
}
|
|
21079
|
+
|
|
20804
21080
|
// packages/harness-adapter/dist/output-channel.js
|
|
20805
21081
|
var HarnessOutputChannel = class {
|
|
20806
21082
|
outputs;
|
|
@@ -20879,11 +21155,11 @@ var usageFields = /* @__PURE__ */ new Set([
|
|
|
20879
21155
|
"totalCredits",
|
|
20880
21156
|
"contextUsagePercent"
|
|
20881
21157
|
]);
|
|
20882
|
-
function
|
|
21158
|
+
function isRecord2(value2) {
|
|
20883
21159
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
20884
21160
|
}
|
|
20885
21161
|
function parseHostUsage(value2) {
|
|
20886
|
-
if (!
|
|
21162
|
+
if (!isRecord2(value2))
|
|
20887
21163
|
throw new Error("Harness Usage must be an object");
|
|
20888
21164
|
const keys = Object.keys(value2);
|
|
20889
21165
|
if (keys.length === 0)
|
|
@@ -20946,6 +21222,82 @@ function parseHostUsage(value2) {
|
|
|
20946
21222
|
return { ...value2 };
|
|
20947
21223
|
}
|
|
20948
21224
|
|
|
21225
|
+
// packages/harness-adapter/dist/live-command-catalog.js
|
|
21226
|
+
var COMMON_EXCLUDED_LIVE_COMMANDS = /* @__PURE__ */ new Set([
|
|
21227
|
+
// Session lifecycle
|
|
21228
|
+
"branch",
|
|
21229
|
+
"clear",
|
|
21230
|
+
"exit",
|
|
21231
|
+
"fork",
|
|
21232
|
+
"fresh",
|
|
21233
|
+
"new",
|
|
21234
|
+
"quit",
|
|
21235
|
+
"rename",
|
|
21236
|
+
"rename-chat",
|
|
21237
|
+
"reset",
|
|
21238
|
+
"resume",
|
|
21239
|
+
"rewind",
|
|
21240
|
+
"session",
|
|
21241
|
+
"sessions",
|
|
21242
|
+
// Desktop-owned configuration
|
|
21243
|
+
"autocompact",
|
|
21244
|
+
"color",
|
|
21245
|
+
"config",
|
|
21246
|
+
"effort",
|
|
21247
|
+
"fast",
|
|
21248
|
+
"keybindings",
|
|
21249
|
+
"model",
|
|
21250
|
+
"models",
|
|
21251
|
+
"output-style",
|
|
21252
|
+
"permissions",
|
|
21253
|
+
"settings",
|
|
21254
|
+
"statusline",
|
|
21255
|
+
"terminal-setup",
|
|
21256
|
+
"theme",
|
|
21257
|
+
"vim",
|
|
21258
|
+
// Trust and approval policy
|
|
21259
|
+
"always-approve",
|
|
21260
|
+
"auto-mode-setup",
|
|
21261
|
+
// Native login
|
|
21262
|
+
"login",
|
|
21263
|
+
"logout",
|
|
21264
|
+
// Work outliving the Turn
|
|
21265
|
+
"autopilot",
|
|
21266
|
+
"background",
|
|
21267
|
+
"bg",
|
|
21268
|
+
"goal",
|
|
21269
|
+
"jobs",
|
|
21270
|
+
"loop",
|
|
21271
|
+
"multitask",
|
|
21272
|
+
"queue",
|
|
21273
|
+
"remote-control",
|
|
21274
|
+
"schedule",
|
|
21275
|
+
"steer",
|
|
21276
|
+
// Native terminal UI
|
|
21277
|
+
"copy",
|
|
21278
|
+
"debug",
|
|
21279
|
+
"feedback",
|
|
21280
|
+
"heapdump",
|
|
21281
|
+
"share",
|
|
21282
|
+
"shell",
|
|
21283
|
+
// Plugin and MCP management
|
|
21284
|
+
"marketplace",
|
|
21285
|
+
"mcp",
|
|
21286
|
+
"plugins",
|
|
21287
|
+
"reload-plugins"
|
|
21288
|
+
]);
|
|
21289
|
+
var COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES = ["__", "hooks-"];
|
|
21290
|
+
function isExcludedLiveCommand(name, kind, extra = {}) {
|
|
21291
|
+
const normalized = name.trim().replace(/^\//u, "");
|
|
21292
|
+
if (new Set(extra.names ?? []).has(normalized))
|
|
21293
|
+
return true;
|
|
21294
|
+
if (extra.prefixes?.some((prefix) => normalized.startsWith(prefix)))
|
|
21295
|
+
return true;
|
|
21296
|
+
if (kind === "skill")
|
|
21297
|
+
return false;
|
|
21298
|
+
return COMMON_EXCLUDED_LIVE_COMMANDS.has(normalized) || COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
21299
|
+
}
|
|
21300
|
+
|
|
20949
21301
|
// packages/harness-adapter/dist/index.js
|
|
20950
21302
|
var packageMetadata = {
|
|
20951
21303
|
name: "@codexhost/harness-adapter",
|
|
@@ -20954,10 +21306,10 @@ var packageMetadata = {
|
|
|
20954
21306
|
|
|
20955
21307
|
// packages/mapping-store/dist/mapping-store.js
|
|
20956
21308
|
import { execFileSync } from "node:child_process";
|
|
20957
|
-
import { randomUUID as
|
|
21309
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
20958
21310
|
import { constants } from "node:fs";
|
|
20959
|
-
import { copyFile as copyFile2, mkdir as
|
|
20960
|
-
import
|
|
21311
|
+
import { copyFile as copyFile2, mkdir as mkdir4, open as open4, readFile as readFile6, readdir as readdir2, rename as rename3, rm as rm4, stat as stat2 } from "node:fs/promises";
|
|
21312
|
+
import path7 from "node:path";
|
|
20961
21313
|
|
|
20962
21314
|
// packages/mapping-store/dist/records.js
|
|
20963
21315
|
var nonBlankTextSchema6 = external_exports.string().refine((value2) => value2.trim().length > 0, {
|
|
@@ -21110,7 +21462,7 @@ function systemErrorCode2(error51) {
|
|
|
21110
21462
|
}
|
|
21111
21463
|
async function exists(file2) {
|
|
21112
21464
|
try {
|
|
21113
|
-
await
|
|
21465
|
+
await stat2(file2);
|
|
21114
21466
|
return true;
|
|
21115
21467
|
} catch (error51) {
|
|
21116
21468
|
if (systemErrorCode2(error51) === "ENOENT")
|
|
@@ -21220,13 +21572,13 @@ var MappingStore = class {
|
|
|
21220
21572
|
#initialized = false;
|
|
21221
21573
|
#lockHandle = null;
|
|
21222
21574
|
constructor(options2) {
|
|
21223
|
-
this.#directory =
|
|
21224
|
-
this.#threadsDirectory =
|
|
21225
|
-
this.#delegationsDirectory =
|
|
21226
|
-
this.#backupsDirectory =
|
|
21227
|
-
this.#quarantineDirectory =
|
|
21228
|
-
this.#lockPath =
|
|
21229
|
-
this.#instanceId = options2.instanceId ??
|
|
21575
|
+
this.#directory = path7.resolve(options2.directory);
|
|
21576
|
+
this.#threadsDirectory = path7.join(this.#directory, "threads");
|
|
21577
|
+
this.#delegationsDirectory = path7.join(this.#directory, "delegations");
|
|
21578
|
+
this.#backupsDirectory = path7.join(this.#directory, "backups");
|
|
21579
|
+
this.#quarantineDirectory = path7.join(this.#directory, "quarantine");
|
|
21580
|
+
this.#lockPath = path7.join(this.#directory, "store.lock");
|
|
21581
|
+
this.#instanceId = options2.instanceId ?? randomUUID3();
|
|
21230
21582
|
this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
|
|
21231
21583
|
this.#beforeReplace = options2.beforeReplace;
|
|
21232
21584
|
}
|
|
@@ -21234,18 +21586,18 @@ var MappingStore = class {
|
|
|
21234
21586
|
if (this.#initialized)
|
|
21235
21587
|
return;
|
|
21236
21588
|
await Promise.all([
|
|
21237
|
-
|
|
21238
|
-
|
|
21239
|
-
|
|
21240
|
-
|
|
21589
|
+
mkdir4(this.#threadsDirectory, { recursive: true }),
|
|
21590
|
+
mkdir4(this.#delegationsDirectory, { recursive: true }),
|
|
21591
|
+
mkdir4(this.#backupsDirectory, { recursive: true }),
|
|
21592
|
+
mkdir4(this.#quarantineDirectory, { recursive: true })
|
|
21241
21593
|
]);
|
|
21242
21594
|
await this.#acquireLock();
|
|
21243
21595
|
try {
|
|
21244
21596
|
await this.#cleanupResidue();
|
|
21245
21597
|
const names = (await readdir2(this.#threadsDirectory)).filter((name) => name.endsWith(".json"));
|
|
21246
21598
|
for (const name of names) {
|
|
21247
|
-
const primary =
|
|
21248
|
-
const backup =
|
|
21599
|
+
const primary = path7.join(this.#threadsDirectory, name);
|
|
21600
|
+
const backup = path7.join(this.#backupsDirectory, name);
|
|
21249
21601
|
let record3 = null;
|
|
21250
21602
|
try {
|
|
21251
21603
|
record3 = await this.#readRecord(primary, name);
|
|
@@ -21254,31 +21606,31 @@ var MappingStore = class {
|
|
|
21254
21606
|
record3 = await this.#readRecord(backup, name);
|
|
21255
21607
|
await this.#replaceFile(primary, record3, false);
|
|
21256
21608
|
} catch (backupError) {
|
|
21257
|
-
const quarantine =
|
|
21258
|
-
await
|
|
21609
|
+
const quarantine = path7.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
|
|
21610
|
+
await rename3(primary, quarantine).catch(() => void 0);
|
|
21259
21611
|
void primaryError;
|
|
21260
21612
|
void backupError;
|
|
21261
21613
|
continue;
|
|
21262
21614
|
}
|
|
21263
21615
|
}
|
|
21264
21616
|
if (record3.state === "creating" && !record3.nativeSessionRef) {
|
|
21265
|
-
await
|
|
21266
|
-
await
|
|
21617
|
+
await rm4(primary, { force: true });
|
|
21618
|
+
await rm4(backup, { force: true });
|
|
21267
21619
|
continue;
|
|
21268
21620
|
}
|
|
21269
21621
|
this.#records.set(record3.hostThreadId, record3);
|
|
21270
21622
|
}
|
|
21271
21623
|
const delegationNames = (await readdir2(this.#delegationsDirectory)).filter((name) => name.endsWith(".json"));
|
|
21272
21624
|
for (const name of delegationNames) {
|
|
21273
|
-
const file2 =
|
|
21625
|
+
const file2 = path7.join(this.#delegationsDirectory, name);
|
|
21274
21626
|
try {
|
|
21275
|
-
const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await
|
|
21627
|
+
const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await readFile6(file2, "utf8")));
|
|
21276
21628
|
if (`${parsed.delegationId}.json` !== name)
|
|
21277
21629
|
throw new Error("filename mismatch");
|
|
21278
21630
|
this.#delegations.set(parsed.delegationId, parsed);
|
|
21279
21631
|
} catch {
|
|
21280
|
-
const quarantine =
|
|
21281
|
-
await
|
|
21632
|
+
const quarantine = path7.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
|
|
21633
|
+
await rename3(file2, quarantine).catch(() => void 0);
|
|
21282
21634
|
}
|
|
21283
21635
|
}
|
|
21284
21636
|
this.#rebuildIndexes();
|
|
@@ -21376,7 +21728,7 @@ var MappingStore = class {
|
|
|
21376
21728
|
}
|
|
21377
21729
|
async removeDelegation(delegationId) {
|
|
21378
21730
|
this.#requireInitialized();
|
|
21379
|
-
await
|
|
21731
|
+
await rm4(this.#delegationPath(delegationId), { force: true });
|
|
21380
21732
|
this.#delegations.delete(delegationId);
|
|
21381
21733
|
this.#rebuildIndexes();
|
|
21382
21734
|
}
|
|
@@ -21557,8 +21909,8 @@ var MappingStore = class {
|
|
|
21557
21909
|
if (!this.#records.has(hostThreadId))
|
|
21558
21910
|
return;
|
|
21559
21911
|
await Promise.all([
|
|
21560
|
-
|
|
21561
|
-
|
|
21912
|
+
rm4(this.#recordPath(hostThreadId), { force: true }),
|
|
21913
|
+
rm4(this.#backupPath(hostThreadId), { force: true })
|
|
21562
21914
|
]);
|
|
21563
21915
|
this.#records.delete(hostThreadId);
|
|
21564
21916
|
this.#rebuildIndexes();
|
|
@@ -21571,9 +21923,9 @@ var MappingStore = class {
|
|
|
21571
21923
|
if (handle)
|
|
21572
21924
|
await handle.close().catch(() => void 0);
|
|
21573
21925
|
try {
|
|
21574
|
-
const current = JSON.parse(await
|
|
21926
|
+
const current = JSON.parse(await readFile6(this.#lockPath, "utf8"));
|
|
21575
21927
|
if (current.instanceId === this.#instanceId)
|
|
21576
|
-
await
|
|
21928
|
+
await rm4(this.#lockPath, { force: true });
|
|
21577
21929
|
} catch {
|
|
21578
21930
|
}
|
|
21579
21931
|
}
|
|
@@ -21640,11 +21992,11 @@ var MappingStore = class {
|
|
|
21640
21992
|
this.#rebuildIndexes();
|
|
21641
21993
|
}
|
|
21642
21994
|
async #replaceFile(target, record3, preserveBackup) {
|
|
21643
|
-
const temp = `${target}.tmp-${
|
|
21995
|
+
const temp = `${target}.tmp-${randomUUID3()}`;
|
|
21644
21996
|
let handle = null;
|
|
21645
21997
|
try {
|
|
21646
21998
|
await this.#beforeReplace?.(cloneRecord(record3));
|
|
21647
|
-
handle = await
|
|
21999
|
+
handle = await open4(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
21648
22000
|
await handle.writeFile(`${JSON.stringify(record3, null, 2)}
|
|
21649
22001
|
`, "utf8");
|
|
21650
22002
|
await handle.sync();
|
|
@@ -21653,10 +22005,10 @@ var MappingStore = class {
|
|
|
21653
22005
|
if (preserveBackup && await exists(target)) {
|
|
21654
22006
|
await copyFile2(target, this.#backupPath(record3.hostThreadId));
|
|
21655
22007
|
}
|
|
21656
|
-
await
|
|
22008
|
+
await rename3(temp, target);
|
|
21657
22009
|
} catch (error51) {
|
|
21658
22010
|
await handle?.close().catch(() => void 0);
|
|
21659
|
-
await
|
|
22011
|
+
await rm4(temp, { force: true }).catch(() => void 0);
|
|
21660
22012
|
if (error51 instanceof MappingStoreError)
|
|
21661
22013
|
throw error51;
|
|
21662
22014
|
throw new MappingStoreError("IO_ERROR", "Mapping Store atomic replacement failed", {
|
|
@@ -21666,19 +22018,19 @@ var MappingStore = class {
|
|
|
21666
22018
|
}
|
|
21667
22019
|
async #replaceDelegationFile(record3) {
|
|
21668
22020
|
const target = this.#delegationPath(record3.delegationId);
|
|
21669
|
-
const temp = `${target}.tmp-${
|
|
22021
|
+
const temp = `${target}.tmp-${randomUUID3()}`;
|
|
21670
22022
|
let handle = null;
|
|
21671
22023
|
try {
|
|
21672
|
-
handle = await
|
|
22024
|
+
handle = await open4(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
21673
22025
|
await handle.writeFile(`${JSON.stringify(record3, null, 2)}
|
|
21674
22026
|
`, "utf8");
|
|
21675
22027
|
await handle.sync();
|
|
21676
22028
|
await handle.close();
|
|
21677
22029
|
handle = null;
|
|
21678
|
-
await
|
|
22030
|
+
await rename3(temp, target);
|
|
21679
22031
|
} catch (error51) {
|
|
21680
22032
|
await handle?.close().catch(() => void 0);
|
|
21681
|
-
await
|
|
22033
|
+
await rm4(temp, { force: true }).catch(() => void 0);
|
|
21682
22034
|
if (error51 instanceof MappingStoreError)
|
|
21683
22035
|
throw error51;
|
|
21684
22036
|
throw new MappingStoreError("IO_ERROR", "Delegation atomic replacement failed", {
|
|
@@ -21687,7 +22039,7 @@ var MappingStore = class {
|
|
|
21687
22039
|
}
|
|
21688
22040
|
}
|
|
21689
22041
|
async #readRecord(file2, expectedName) {
|
|
21690
|
-
const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await
|
|
22042
|
+
const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await readFile6(file2, "utf8")));
|
|
21691
22043
|
if (!parsed.success) {
|
|
21692
22044
|
throw new MappingStoreError("INVALID_RECORD", "Mapping Store record is invalid", {
|
|
21693
22045
|
cause: parsed.error
|
|
@@ -21705,15 +22057,15 @@ var MappingStore = class {
|
|
|
21705
22057
|
readdir2(this.#directory)
|
|
21706
22058
|
]);
|
|
21707
22059
|
await Promise.all([
|
|
21708
|
-
...threadNames.filter((name) => name.includes(".tmp-")).map((name) =>
|
|
21709
|
-
...delegationNames.filter((name) => name.includes(".tmp-")).map((name) =>
|
|
22060
|
+
...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm4(path7.join(this.#threadsDirectory, name), { force: true })),
|
|
22061
|
+
...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm4(path7.join(this.#delegationsDirectory, name), { force: true })),
|
|
21710
22062
|
// Renamed aside by #acquireLock; nothing reads them back, and they accumulate one per run.
|
|
21711
|
-
...rootNames.filter((name) => name.startsWith(`${
|
|
22063
|
+
...rootNames.filter((name) => name.startsWith(`${path7.basename(this.#lockPath)}.stale-`)).map((name) => rm4(path7.join(this.#directory, name), { force: true }))
|
|
21712
22064
|
]);
|
|
21713
22065
|
}
|
|
21714
22066
|
async #acquireLock() {
|
|
21715
22067
|
const attempt = async () => {
|
|
21716
|
-
const handle = await
|
|
22068
|
+
const handle = await open4(this.#lockPath, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
21717
22069
|
const lock = {
|
|
21718
22070
|
pid: process.pid,
|
|
21719
22071
|
instanceId: this.#instanceId,
|
|
@@ -21735,13 +22087,13 @@ var MappingStore = class {
|
|
|
21735
22087
|
}
|
|
21736
22088
|
let existing = {};
|
|
21737
22089
|
try {
|
|
21738
|
-
existing = JSON.parse(await
|
|
22090
|
+
existing = JSON.parse(await readFile6(this.#lockPath, "utf8"));
|
|
21739
22091
|
} catch {
|
|
21740
22092
|
}
|
|
21741
22093
|
if (typeof existing.pid === "number" && lockOwnerIsLive(existing)) {
|
|
21742
22094
|
throw new MappingStoreError("STORE_LOCKED", "Another BOFT CLI process owns Mapping Store");
|
|
21743
22095
|
}
|
|
21744
|
-
await
|
|
22096
|
+
await rename3(this.#lockPath, `${this.#lockPath}.stale-${this.#now().getTime()}`).catch(() => void 0);
|
|
21745
22097
|
try {
|
|
21746
22098
|
this.#lockHandle = await attempt();
|
|
21747
22099
|
} catch (error51) {
|
|
@@ -21809,13 +22161,13 @@ var MappingStore = class {
|
|
|
21809
22161
|
await next;
|
|
21810
22162
|
}
|
|
21811
22163
|
#recordPath(hostThreadId) {
|
|
21812
|
-
return
|
|
22164
|
+
return path7.join(this.#threadsDirectory, `${hostThreadId}.json`);
|
|
21813
22165
|
}
|
|
21814
22166
|
#delegationPath(delegationId) {
|
|
21815
|
-
return
|
|
22167
|
+
return path7.join(this.#delegationsDirectory, `${delegationId}.json`);
|
|
21816
22168
|
}
|
|
21817
22169
|
#backupPath(hostThreadId) {
|
|
21818
|
-
return
|
|
22170
|
+
return path7.join(this.#backupsDirectory, `${hostThreadId}.json`);
|
|
21819
22171
|
}
|
|
21820
22172
|
#requireInitialized() {
|
|
21821
22173
|
if (!this.#initialized) {
|
|
@@ -21835,7 +22187,7 @@ var TITLE_MAX_LENGTH = 150;
|
|
|
21835
22187
|
var DESCRIPTION_MAX_LENGTH = 500;
|
|
21836
22188
|
var SERVER_NAME_MAX_LENGTH = 80;
|
|
21837
22189
|
var ELLIPSIS = "…";
|
|
21838
|
-
function
|
|
22190
|
+
function isRecord3(value2) {
|
|
21839
22191
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
21840
22192
|
}
|
|
21841
22193
|
function boundedText(value2, field, maxLength) {
|
|
@@ -21889,7 +22241,7 @@ function responseError(message) {
|
|
|
21889
22241
|
function responsePersist(value2) {
|
|
21890
22242
|
if (value2 === void 0 || value2 === null)
|
|
21891
22243
|
return null;
|
|
21892
|
-
if (!
|
|
22244
|
+
if (!isRecord3(value2) || Object.keys(value2).length !== 1 || value2.persist !== "session" && value2.persist !== "always") {
|
|
21893
22245
|
throw responseError("contains malformed persist metadata");
|
|
21894
22246
|
}
|
|
21895
22247
|
return value2.persist;
|
|
@@ -21939,7 +22291,7 @@ function projectCodexApprovalRequest(input) {
|
|
|
21939
22291
|
},
|
|
21940
22292
|
denyResponse,
|
|
21941
22293
|
parseResponse(result) {
|
|
21942
|
-
if (!
|
|
22294
|
+
if (!isRecord3(result) || typeof result.action !== "string") {
|
|
21943
22295
|
throw responseError("missing action");
|
|
21944
22296
|
}
|
|
21945
22297
|
if (Object.keys(result).some((key) => key !== "action" && key !== "content" && key !== "_meta")) {
|
|
@@ -21947,7 +22299,7 @@ function projectCodexApprovalRequest(input) {
|
|
|
21947
22299
|
}
|
|
21948
22300
|
const selectedPersist = responsePersist(result._meta);
|
|
21949
22301
|
if (result.action === "accept") {
|
|
21950
|
-
if ("content" in result && (!
|
|
22302
|
+
if ("content" in result && (!isRecord3(result.content) || Object.keys(result.content).length !== 0)) {
|
|
21951
22303
|
throw responseError("contains non-empty accepted content");
|
|
21952
22304
|
}
|
|
21953
22305
|
if (selectedPersist === "session") {
|
|
@@ -22007,7 +22359,7 @@ function projectApprovalChoices(input) {
|
|
|
22007
22359
|
},
|
|
22008
22360
|
denyResponse,
|
|
22009
22361
|
parseResponse(result) {
|
|
22010
|
-
if (!
|
|
22362
|
+
if (!isRecord3(result) || typeof result.action !== "string")
|
|
22011
22363
|
throw responseError("missing action");
|
|
22012
22364
|
if (Object.keys(result).some((key) => !["action", "content", "_meta"].includes(key))) {
|
|
22013
22365
|
throw responseError("contains unreviewed fields");
|
|
@@ -22022,7 +22374,7 @@ function projectApprovalChoices(input) {
|
|
|
22022
22374
|
return denyResponse;
|
|
22023
22375
|
}
|
|
22024
22376
|
const content = result.content;
|
|
22025
|
-
if (result.action !== "accept" || !
|
|
22377
|
+
if (result.action !== "accept" || !isRecord3(content) || Object.keys(content).length !== 1 || !interaction.actions.some(({ id: id2 }) => id2 === content.actionId)) {
|
|
22026
22378
|
throw responseError("contains an undeclared approval choice");
|
|
22027
22379
|
}
|
|
22028
22380
|
return { type: "approval", actionId: content.actionId };
|
|
@@ -22031,7 +22383,7 @@ function projectApprovalChoices(input) {
|
|
|
22031
22383
|
}
|
|
22032
22384
|
|
|
22033
22385
|
// packages/protocol-core/dist/codex-question.js
|
|
22034
|
-
function
|
|
22386
|
+
function isRecord4(value2) {
|
|
22035
22387
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
22036
22388
|
}
|
|
22037
22389
|
function responseError2(message) {
|
|
@@ -22100,7 +22452,7 @@ function projectCodexQuestionRequest(input) {
|
|
|
22100
22452
|
}
|
|
22101
22453
|
},
|
|
22102
22454
|
parseResponse(result) {
|
|
22103
|
-
if (!
|
|
22455
|
+
if (!isRecord4(result) || !isRecord4(result.answers)) {
|
|
22104
22456
|
throw responseError2("missing answers object");
|
|
22105
22457
|
}
|
|
22106
22458
|
const rawAnswers = result.answers;
|
|
@@ -22113,7 +22465,7 @@ function projectCodexQuestionRequest(input) {
|
|
|
22113
22465
|
const question = interaction.questions.find(({ id: id2 }) => id2 === questionId);
|
|
22114
22466
|
if (!question)
|
|
22115
22467
|
throw responseError2("contains an unknown Question ID");
|
|
22116
|
-
if (!
|
|
22468
|
+
if (!isRecord4(answerValue) || !Array.isArray(answerValue.answers)) {
|
|
22117
22469
|
throw responseError2("answer entry has no answers array");
|
|
22118
22470
|
}
|
|
22119
22471
|
const values = answerValue.answers;
|
|
@@ -22200,7 +22552,7 @@ function projectCodexThreadUsage(input) {
|
|
|
22200
22552
|
}
|
|
22201
22553
|
|
|
22202
22554
|
// packages/protocol-core/dist/codex-native-usage.js
|
|
22203
|
-
function
|
|
22555
|
+
function isRecord5(value2) {
|
|
22204
22556
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
22205
22557
|
}
|
|
22206
22558
|
function nonNegativeSafeInteger(value2) {
|
|
@@ -22230,20 +22582,20 @@ function addBreakdown(target, source) {
|
|
|
22230
22582
|
}
|
|
22231
22583
|
}
|
|
22232
22584
|
function observeCodexTokenUsage(value2) {
|
|
22233
|
-
if (!
|
|
22585
|
+
if (!isRecord5(value2) || value2.method !== "thread/tokenUsage/updated")
|
|
22234
22586
|
return null;
|
|
22235
22587
|
const params = value2.params;
|
|
22236
|
-
if (!
|
|
22588
|
+
if (!isRecord5(params))
|
|
22237
22589
|
return null;
|
|
22238
22590
|
const threadId2 = hostThreadIdSchema.safeParse(params.threadId);
|
|
22239
22591
|
const turnId = hostTurnIdSchema.safeParse(params.turnId);
|
|
22240
22592
|
if (!threadId2.success || !turnId.success)
|
|
22241
22593
|
return null;
|
|
22242
22594
|
const tokenUsage = params.tokenUsage;
|
|
22243
|
-
if (!
|
|
22595
|
+
if (!isRecord5(tokenUsage))
|
|
22244
22596
|
return null;
|
|
22245
|
-
const total =
|
|
22246
|
-
const last =
|
|
22597
|
+
const total = isRecord5(tokenUsage.total) ? tokenUsage.total : void 0;
|
|
22598
|
+
const last = isRecord5(tokenUsage.last) ? tokenUsage.last : void 0;
|
|
22247
22599
|
const usage = {};
|
|
22248
22600
|
addBreakdown(usage, total);
|
|
22249
22601
|
const contextUsedTokens = nonNegativeSafeInteger(last?.totalTokens);
|
|
@@ -22268,7 +22620,7 @@ function observeCodexTokenUsage(value2) {
|
|
|
22268
22620
|
}
|
|
22269
22621
|
}
|
|
22270
22622
|
function parseRateLimitWindow(value2) {
|
|
22271
|
-
if (!
|
|
22623
|
+
if (!isRecord5(value2))
|
|
22272
22624
|
return null;
|
|
22273
22625
|
const usedPercent = finitePercent(value2.usedPercent);
|
|
22274
22626
|
const windowDurationMins = nonNegativeSafeInteger(value2.windowDurationMins);
|
|
@@ -22279,7 +22631,7 @@ function parseRateLimitWindow(value2) {
|
|
|
22279
22631
|
return { usedPercent, windowDurationMins, ...resetsAt !== void 0 ? { resetsAt } : {} };
|
|
22280
22632
|
}
|
|
22281
22633
|
function parseRateLimitCandidate(value2, options2 = {}) {
|
|
22282
|
-
if (!
|
|
22634
|
+
if (!isRecord5(value2))
|
|
22283
22635
|
return null;
|
|
22284
22636
|
if (options2.genericOnly && value2.limitId !== void 0 && value2.limitId !== null && value2.limitId !== "codex") {
|
|
22285
22637
|
return null;
|
|
@@ -22289,16 +22641,16 @@ function parseRateLimitCandidate(value2, options2 = {}) {
|
|
|
22289
22641
|
return primary || secondary ? { primary, secondary } : null;
|
|
22290
22642
|
}
|
|
22291
22643
|
function rateLimitCandidates(value2) {
|
|
22292
|
-
if (!
|
|
22644
|
+
if (!isRecord5(value2))
|
|
22293
22645
|
return [];
|
|
22294
|
-
const result =
|
|
22295
|
-
if (!
|
|
22646
|
+
const result = isRecord5(value2.result) ? value2.result : value2;
|
|
22647
|
+
if (!isRecord5(result))
|
|
22296
22648
|
return [];
|
|
22297
22649
|
const candidates = [];
|
|
22298
22650
|
const base = parseRateLimitCandidate(result.rateLimits, { genericOnly: true });
|
|
22299
22651
|
if (base)
|
|
22300
22652
|
candidates.push(base);
|
|
22301
|
-
const notificationParams =
|
|
22653
|
+
const notificationParams = isRecord5(value2.params) ? value2.params : void 0;
|
|
22302
22654
|
const notificationSnapshot = parseRateLimitCandidate(notificationParams?.rateLimits, {
|
|
22303
22655
|
genericOnly: true
|
|
22304
22656
|
});
|
|
@@ -22342,14 +22694,14 @@ function parseAvailableCount(value2) {
|
|
|
22342
22694
|
return void 0;
|
|
22343
22695
|
}
|
|
22344
22696
|
function rateLimitResetCreditsSummary(value2) {
|
|
22345
|
-
if (!
|
|
22697
|
+
if (!isRecord5(value2))
|
|
22346
22698
|
return null;
|
|
22347
|
-
const result =
|
|
22348
|
-
const fromResult =
|
|
22699
|
+
const result = isRecord5(value2.result) ? value2.result : value2;
|
|
22700
|
+
const fromResult = isRecord5(result) && isRecord5(result.rateLimitResetCredits) ? result.rateLimitResetCredits : null;
|
|
22349
22701
|
if (fromResult)
|
|
22350
22702
|
return fromResult;
|
|
22351
|
-
const params =
|
|
22352
|
-
return
|
|
22703
|
+
const params = isRecord5(value2.params) ? value2.params : void 0;
|
|
22704
|
+
return isRecord5(params?.rateLimitResetCredits) ? params.rateLimitResetCredits : null;
|
|
22353
22705
|
}
|
|
22354
22706
|
function observeCodexRateLimitResetCredits(value2) {
|
|
22355
22707
|
const summary = rateLimitResetCreditsSummary(value2);
|
|
@@ -22361,7 +22713,7 @@ function observeCodexRateLimitResetCredits(value2) {
|
|
|
22361
22713
|
const expiresAtUnix = [];
|
|
22362
22714
|
if (Array.isArray(summary.credits)) {
|
|
22363
22715
|
for (const credit of summary.credits) {
|
|
22364
|
-
if (!
|
|
22716
|
+
if (!isRecord5(credit))
|
|
22365
22717
|
continue;
|
|
22366
22718
|
if (credit.status !== void 0 && credit.status !== "available")
|
|
22367
22719
|
continue;
|
|
@@ -22512,16 +22864,16 @@ var Diff = class {
|
|
|
22512
22864
|
}
|
|
22513
22865
|
}
|
|
22514
22866
|
}
|
|
22515
|
-
addToPath(
|
|
22516
|
-
const last =
|
|
22867
|
+
addToPath(path29, added, removed, oldPosInc, options2) {
|
|
22868
|
+
const last = path29.lastComponent;
|
|
22517
22869
|
if (last && !options2.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
22518
22870
|
return {
|
|
22519
|
-
oldPos:
|
|
22871
|
+
oldPos: path29.oldPos + oldPosInc,
|
|
22520
22872
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
22521
22873
|
};
|
|
22522
22874
|
} else {
|
|
22523
22875
|
return {
|
|
22524
|
-
oldPos:
|
|
22876
|
+
oldPos: path29.oldPos + oldPosInc,
|
|
22525
22877
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
22526
22878
|
};
|
|
22527
22879
|
}
|
|
@@ -22950,10 +23302,10 @@ function splitLines(text2) {
|
|
|
22950
23302
|
}
|
|
22951
23303
|
|
|
22952
23304
|
// packages/protocol-core/dist/file-change-summary.js
|
|
22953
|
-
import
|
|
23305
|
+
import path8 from "node:path";
|
|
22954
23306
|
function filePathKey(file2, cwd) {
|
|
22955
23307
|
const windows = /^[a-z]:[/\\]/i.test(cwd) || /^[a-z]:[/\\]/i.test(file2);
|
|
22956
|
-
const paths = windows ?
|
|
23308
|
+
const paths = windows ? path8.win32 : path8.posix;
|
|
22957
23309
|
const resolved = paths.resolve(cwd, file2).replaceAll("\\", "/");
|
|
22958
23310
|
return windows ? resolved.toLowerCase() : resolved;
|
|
22959
23311
|
}
|
|
@@ -23105,11 +23457,11 @@ function itemStatus(outcome) {
|
|
|
23105
23457
|
return "inProgress";
|
|
23106
23458
|
return outcome.status === "succeeded" ? "completed" : "failed";
|
|
23107
23459
|
}
|
|
23108
|
-
function
|
|
23460
|
+
function isRecord6(value2) {
|
|
23109
23461
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
23110
23462
|
}
|
|
23111
23463
|
function nestedString(value2, keys, preserveText = false) {
|
|
23112
|
-
if (!
|
|
23464
|
+
if (!isRecord6(value2))
|
|
23113
23465
|
return void 0;
|
|
23114
23466
|
for (const key of keys) {
|
|
23115
23467
|
const field = value2[key];
|
|
@@ -23223,8 +23575,8 @@ function projectFileChangeKind(kind) {
|
|
|
23223
23575
|
return { type: kind };
|
|
23224
23576
|
}
|
|
23225
23577
|
function projectFileChanges(changes) {
|
|
23226
|
-
return changes.map(({ path:
|
|
23227
|
-
path:
|
|
23578
|
+
return changes.map(({ path: path29, kind, unifiedDiff }) => ({
|
|
23579
|
+
path: path29,
|
|
23228
23580
|
kind: projectFileChangeKind(kind),
|
|
23229
23581
|
diff: unifiedDiff
|
|
23230
23582
|
}));
|
|
@@ -23264,7 +23616,7 @@ function planFromTodoValue(value2) {
|
|
|
23264
23616
|
const record3 = unwrapToolRecord(value2);
|
|
23265
23617
|
if (!record3)
|
|
23266
23618
|
return planFromChecklistText(typeof value2 === "string" ? value2 : null);
|
|
23267
|
-
if (
|
|
23619
|
+
if (isRecord6(record3.TodosUpdated)) {
|
|
23268
23620
|
const nested = planFromTodoValue(record3.TodosUpdated);
|
|
23269
23621
|
if (nested)
|
|
23270
23622
|
return nested;
|
|
@@ -23279,7 +23631,7 @@ function planFromTodoValue(value2) {
|
|
|
23279
23631
|
plan.push({ step: entry.trim(), status: "pending" });
|
|
23280
23632
|
continue;
|
|
23281
23633
|
}
|
|
23282
|
-
if (!
|
|
23634
|
+
if (!isRecord6(entry))
|
|
23283
23635
|
continue;
|
|
23284
23636
|
const step = nestedString(entry, ["content", "step", "text", "title", "description", "task"]);
|
|
23285
23637
|
if (!step)
|
|
@@ -23334,7 +23686,7 @@ function unwrapToolRecord(value2) {
|
|
|
23334
23686
|
}
|
|
23335
23687
|
if (Array.isArray(value2))
|
|
23336
23688
|
return { todos: value2 };
|
|
23337
|
-
if (!
|
|
23689
|
+
if (!isRecord6(value2))
|
|
23338
23690
|
return null;
|
|
23339
23691
|
for (const wrapper of ["input", "arguments", "params"]) {
|
|
23340
23692
|
if (value2[wrapper] === void 0)
|
|
@@ -24133,7 +24485,7 @@ var CodexTurnProjector = class {
|
|
|
24133
24485
|
};
|
|
24134
24486
|
|
|
24135
24487
|
// packages/protocol-core/dist/thread-fork.js
|
|
24136
|
-
function
|
|
24488
|
+
function isRecord7(value2) {
|
|
24137
24489
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
24138
24490
|
}
|
|
24139
24491
|
function optionalText(params, name, options2 = {}) {
|
|
@@ -24156,7 +24508,7 @@ function optionalBoolean(params, name) {
|
|
|
24156
24508
|
function decodeThreadForkRequest(request) {
|
|
24157
24509
|
if (request.method !== "thread/fork")
|
|
24158
24510
|
return null;
|
|
24159
|
-
if (!
|
|
24511
|
+
if (!isRecord7(request.params))
|
|
24160
24512
|
throw new Error("thread/fork params must be an object");
|
|
24161
24513
|
const params = request.params;
|
|
24162
24514
|
const threadId2 = optionalText(params, "threadId");
|
|
@@ -24171,13 +24523,13 @@ function decodeThreadForkRequest(request) {
|
|
|
24171
24523
|
if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
|
|
24172
24524
|
throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
|
|
24173
24525
|
}
|
|
24174
|
-
const
|
|
24526
|
+
const path29 = optionalText(params, "path", { allowEmpty: true });
|
|
24175
24527
|
const ephemeral = optionalBoolean(params, "ephemeral");
|
|
24176
24528
|
return {
|
|
24177
24529
|
threadId: threadId2,
|
|
24178
24530
|
...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
|
|
24179
24531
|
...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
|
|
24180
|
-
...
|
|
24532
|
+
...path29 ? { path: path29 } : {},
|
|
24181
24533
|
...optionalField(params, "model"),
|
|
24182
24534
|
...optionalField(params, "modelProvider"),
|
|
24183
24535
|
...optionalField(params, "cwd"),
|
|
@@ -24192,7 +24544,7 @@ function decodeThreadForkRequest(request) {
|
|
|
24192
24544
|
function decodeThreadRevertRequest(request) {
|
|
24193
24545
|
if (request.method !== "thread/revert")
|
|
24194
24546
|
return null;
|
|
24195
|
-
if (!
|
|
24547
|
+
if (!isRecord7(request.params))
|
|
24196
24548
|
throw new Error("thread/revert params must be an object");
|
|
24197
24549
|
const { threadId: threadId2, beforeTurnId } = request.params;
|
|
24198
24550
|
if (typeof threadId2 !== "string" || threadId2.length === 0) {
|
|
@@ -24206,7 +24558,7 @@ function decodeThreadRevertRequest(request) {
|
|
|
24206
24558
|
function decodeThreadRollbackRequest(request) {
|
|
24207
24559
|
if (request.method !== "thread/rollback")
|
|
24208
24560
|
return null;
|
|
24209
|
-
if (!
|
|
24561
|
+
if (!isRecord7(request.params))
|
|
24210
24562
|
throw new Error("thread/rollback params must be an object");
|
|
24211
24563
|
const { threadId: threadId2, numTurns } = request.params;
|
|
24212
24564
|
if (typeof threadId2 !== "string" || threadId2.length === 0) {
|
|
@@ -24270,7 +24622,7 @@ function threadForkResult(thread, input) {
|
|
|
24270
24622
|
}
|
|
24271
24623
|
|
|
24272
24624
|
// packages/protocol-core/dist/thread-management.js
|
|
24273
|
-
import { createHash as
|
|
24625
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
24274
24626
|
var HOST_CURSOR_PREFIX = "codexhost:thread-list:v1:";
|
|
24275
24627
|
var MAX_CURSOR_LENGTH = 65536;
|
|
24276
24628
|
var DEFAULT_PAGE_SIZE = 25;
|
|
@@ -24303,13 +24655,13 @@ var THREAD_SOURCE_KINDS = /* @__PURE__ */ new Set([
|
|
|
24303
24655
|
"subAgentOther",
|
|
24304
24656
|
"unknown"
|
|
24305
24657
|
]);
|
|
24306
|
-
function
|
|
24658
|
+
function isRecord8(value2) {
|
|
24307
24659
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
24308
24660
|
}
|
|
24309
24661
|
function paramsObject(request, method) {
|
|
24310
24662
|
if (request.params === void 0 && method === "thread/list")
|
|
24311
24663
|
return {};
|
|
24312
|
-
if (!
|
|
24664
|
+
if (!isRecord8(request.params))
|
|
24313
24665
|
throw new Error(`${method} params must be an object`);
|
|
24314
24666
|
return request.params;
|
|
24315
24667
|
}
|
|
@@ -24367,7 +24719,7 @@ function decodeSortKey(value2) {
|
|
|
24367
24719
|
return value2;
|
|
24368
24720
|
}
|
|
24369
24721
|
function queryFingerprint(value2) {
|
|
24370
|
-
return
|
|
24722
|
+
return createHash4("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
24371
24723
|
}
|
|
24372
24724
|
function cursorPayload(value2) {
|
|
24373
24725
|
return {
|
|
@@ -24381,7 +24733,7 @@ function cursorPayload(value2) {
|
|
|
24381
24733
|
};
|
|
24382
24734
|
}
|
|
24383
24735
|
function parseCursorPayload(value2) {
|
|
24384
|
-
if (!
|
|
24736
|
+
if (!isRecord8(value2) || value2.formatVersion !== 1)
|
|
24385
24737
|
throw new Error("Host cursor is invalid");
|
|
24386
24738
|
const { queryFingerprint: fingerprint, sortDirection: sortDirection2, officialCursor, officialDone } = value2;
|
|
24387
24739
|
const { externalAnchor: externalAnchor2, externalDone } = value2;
|
|
@@ -24390,7 +24742,7 @@ function parseCursorPayload(value2) {
|
|
|
24390
24742
|
}
|
|
24391
24743
|
let anchor = null;
|
|
24392
24744
|
if (externalAnchor2 !== null) {
|
|
24393
|
-
if (!
|
|
24745
|
+
if (!isRecord8(externalAnchor2) || !Number.isSafeInteger(externalAnchor2.timestamp) || typeof externalAnchor2.threadId !== "string" || externalAnchor2.threadId.length === 0) {
|
|
24394
24746
|
throw new Error("Host cursor is invalid");
|
|
24395
24747
|
}
|
|
24396
24748
|
anchor = {
|
|
@@ -24513,7 +24865,7 @@ function decodeThreadMetadataUpdateRequest(request) {
|
|
|
24513
24865
|
if (params.gitInfo === null) {
|
|
24514
24866
|
gitInfo = null;
|
|
24515
24867
|
} else if (params.gitInfo !== void 0) {
|
|
24516
|
-
if (!
|
|
24868
|
+
if (!isRecord8(params.gitInfo)) {
|
|
24517
24869
|
throw new Error("thread/metadata/update params.gitInfo must be an object or null");
|
|
24518
24870
|
}
|
|
24519
24871
|
gitInfo = {};
|
|
@@ -24541,7 +24893,7 @@ function optionalCursor(value2, name) {
|
|
|
24541
24893
|
return value2;
|
|
24542
24894
|
}
|
|
24543
24895
|
function decodeOfficialThreadListPage(value2) {
|
|
24544
|
-
if (!
|
|
24896
|
+
if (!isRecord8(value2) || !Array.isArray(value2.data) || value2.data.some((row) => !isRecord8(row))) {
|
|
24545
24897
|
throw new Error("Official thread/list response is invalid");
|
|
24546
24898
|
}
|
|
24547
24899
|
return {
|
|
@@ -25353,22 +25705,22 @@ var HarnessAccountInspectionCache = class {
|
|
|
25353
25705
|
};
|
|
25354
25706
|
|
|
25355
25707
|
// packages/host-runtime/src/app-server-host.ts
|
|
25356
|
-
import { createHash as
|
|
25357
|
-
import
|
|
25358
|
-
import
|
|
25708
|
+
import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
|
|
25709
|
+
import os5 from "node:os";
|
|
25710
|
+
import path16 from "node:path";
|
|
25359
25711
|
|
|
25360
25712
|
// packages/host-runtime/src/external-thread-fork.ts
|
|
25361
25713
|
import nodePath from "node:path";
|
|
25362
25714
|
|
|
25363
25715
|
// packages/host-runtime/src/external-thread-repository.ts
|
|
25364
|
-
import { randomUUID as
|
|
25365
|
-
import
|
|
25366
|
-
import
|
|
25716
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
25717
|
+
import os3 from "node:os";
|
|
25718
|
+
import path9 from "node:path";
|
|
25367
25719
|
|
|
25368
25720
|
// packages/host-runtime/src/external-subagent-threads.ts
|
|
25369
|
-
import { createHash as
|
|
25721
|
+
import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypto";
|
|
25370
25722
|
function childCreateRequest(parent, nativeRef, id2) {
|
|
25371
|
-
const key =
|
|
25723
|
+
const key = createHash5("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
|
|
25372
25724
|
return `subagent:${key}`;
|
|
25373
25725
|
}
|
|
25374
25726
|
function subagentMaterializer(store, parent, previousParent) {
|
|
@@ -25441,7 +25793,7 @@ function subagentMaterializer(store, parent, previousParent) {
|
|
|
25441
25793
|
return rebind(existing, parent);
|
|
25442
25794
|
}
|
|
25443
25795
|
const provisional = existing ?? await store.createProvisional({
|
|
25444
|
-
hostThreadId: hostThreadIdSchema.parse(
|
|
25796
|
+
hostThreadId: hostThreadIdSchema.parse(randomUUID4()),
|
|
25445
25797
|
createRequestId,
|
|
25446
25798
|
harnessId: parent.harnessId,
|
|
25447
25799
|
cwd: parent.cwd,
|
|
@@ -25503,8 +25855,8 @@ function sameMapping(left, right) {
|
|
|
25503
25855
|
}
|
|
25504
25856
|
function defaultMappingStoreDirectory(environment) {
|
|
25505
25857
|
const dataDirectory = environment.CODEXHOST_DATA_DIR;
|
|
25506
|
-
return
|
|
25507
|
-
dataDirectory ?
|
|
25858
|
+
return path9.join(
|
|
25859
|
+
dataDirectory ? path9.resolve(dataDirectory) : path9.join(os3.homedir(), ".codexhost"),
|
|
25508
25860
|
"mapping-store"
|
|
25509
25861
|
);
|
|
25510
25862
|
}
|
|
@@ -25608,7 +25960,7 @@ var ExternalThreadRepository = class {
|
|
|
25608
25960
|
throw new Error("Derived Snapshot identity does not belong to its Native Session");
|
|
25609
25961
|
}
|
|
25610
25962
|
return {
|
|
25611
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
25963
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
|
|
25612
25964
|
nativeTurnRef: turn.nativeTurnRef,
|
|
25613
25965
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
25614
25966
|
};
|
|
@@ -25728,7 +26080,7 @@ var ExternalThreadRepository = class {
|
|
|
25728
26080
|
const aligned = snapshot.turns.map((turn) => {
|
|
25729
26081
|
const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
|
|
25730
26082
|
const mapping = existing ?? {
|
|
25731
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
26083
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
|
|
25732
26084
|
nativeTurnRef: turn.nativeTurnRef,
|
|
25733
26085
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
25734
26086
|
};
|
|
@@ -25755,8 +26107,8 @@ var ExternalThreadRepository = class {
|
|
|
25755
26107
|
};
|
|
25756
26108
|
function createExternalThreadRecordInput(input) {
|
|
25757
26109
|
return {
|
|
25758
|
-
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(
|
|
25759
|
-
createRequestId: input.createRequestId ??
|
|
26110
|
+
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID5()),
|
|
26111
|
+
createRequestId: input.createRequestId ?? randomUUID5(),
|
|
25760
26112
|
harnessId: input.harnessId,
|
|
25761
26113
|
cwd: input.cwd,
|
|
25762
26114
|
...input.title ? { title: input.title } : {},
|
|
@@ -25931,6 +26283,7 @@ async function executeExternalThreadFork(input) {
|
|
|
25931
26283
|
return { ok: false, error: mapExternalThreadHarnessError(opened.error, "fork") };
|
|
25932
26284
|
}
|
|
25933
26285
|
const session = opened.value;
|
|
26286
|
+
const inheritedPermissionModeId = await inheritSourcePermissionMode(source, session);
|
|
25934
26287
|
try {
|
|
25935
26288
|
const derivedNativeRef = session.initialState.nativeRef;
|
|
25936
26289
|
if (!derivedNativeRef || derivedNativeRef.nativeSessionId === nativeSessionRef.nativeSessionId) {
|
|
@@ -25958,7 +26311,8 @@ async function executeExternalThreadFork(input) {
|
|
|
25958
26311
|
sessionId: source.sessionId,
|
|
25959
26312
|
thread,
|
|
25960
26313
|
turns: aligned.turns,
|
|
25961
|
-
...snapshot.value.state ? { restoredState: snapshot.value.state } : {}
|
|
26314
|
+
...snapshot.value.state ? { restoredState: snapshot.value.state } : {},
|
|
26315
|
+
...inheritedPermissionModeId ? { requestedPermissionModeId: inheritedPermissionModeId } : {}
|
|
25962
26316
|
});
|
|
25963
26317
|
return {
|
|
25964
26318
|
ok: true,
|
|
@@ -25976,6 +26330,23 @@ async function executeExternalThreadFork(input) {
|
|
|
25976
26330
|
};
|
|
25977
26331
|
}
|
|
25978
26332
|
}
|
|
26333
|
+
async function inheritSourcePermissionMode(source, session) {
|
|
26334
|
+
const sourceModeId = source.stateObserver.state.effectivePermissionModeId ?? source.requestedPermissionModeId;
|
|
26335
|
+
if (!sourceModeId) return void 0;
|
|
26336
|
+
const configuration = session.capabilities.configuration;
|
|
26337
|
+
if (!configuration.selectPermissionMode || permissionModeFixedAtCreate(configuration)) {
|
|
26338
|
+
return void 0;
|
|
26339
|
+
}
|
|
26340
|
+
try {
|
|
26341
|
+
const selected = await session.execute({
|
|
26342
|
+
type: "permissionMode.select",
|
|
26343
|
+
permissionModeId: sourceModeId
|
|
26344
|
+
});
|
|
26345
|
+
return selected.ok ? sourceModeId : void 0;
|
|
26346
|
+
} catch {
|
|
26347
|
+
return void 0;
|
|
26348
|
+
}
|
|
26349
|
+
}
|
|
25979
26350
|
|
|
25980
26351
|
// packages/host-runtime/src/harness-session-import.ts
|
|
25981
26352
|
function fixedError(code, message) {
|
|
@@ -27557,9 +27928,12 @@ var ExternalTurnSteering = class {
|
|
|
27557
27928
|
if (!cancelled.ok) throw new ExternalSteerError(-32074, cancelled.error.message);
|
|
27558
27929
|
const outcome = await Promise.race([terminal2.promise, failure.promise]);
|
|
27559
27930
|
clearTimeout(timeout);
|
|
27560
|
-
|
|
27561
|
-
|
|
27562
|
-
|
|
27931
|
+
const assertActive = () => {
|
|
27932
|
+
if (failureReason) throw failureReason;
|
|
27933
|
+
if (this.#closed)
|
|
27934
|
+
throw new ExternalSteerError(-32074, "External steering connection is closed");
|
|
27935
|
+
};
|
|
27936
|
+
assertActive();
|
|
27563
27937
|
if (outcome.status === "failed") throw new ExternalSteerError(-32074, outcome.error.message);
|
|
27564
27938
|
if (thread.persistenceError)
|
|
27565
27939
|
throw new ExternalSteerError(
|
|
@@ -27569,7 +27943,7 @@ var ExternalTurnSteering = class {
|
|
|
27569
27943
|
if (thread.running || thread.activeTurnId) {
|
|
27570
27944
|
throw new ExternalSteerError(-32072, "Another External Turn started before replacement");
|
|
27571
27945
|
}
|
|
27572
|
-
return await start(input.text);
|
|
27946
|
+
return await start(input.text, assertActive);
|
|
27573
27947
|
} finally {
|
|
27574
27948
|
clearTimeout(timeout);
|
|
27575
27949
|
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
@@ -27577,16 +27951,98 @@ var ExternalTurnSteering = class {
|
|
|
27577
27951
|
}
|
|
27578
27952
|
};
|
|
27579
27953
|
|
|
27954
|
+
// packages/host-runtime/src/external-command-routing.ts
|
|
27955
|
+
var ExternalCommandError = class extends Error {
|
|
27956
|
+
constructor(code, message) {
|
|
27957
|
+
super(message);
|
|
27958
|
+
this.code = code;
|
|
27959
|
+
}
|
|
27960
|
+
code;
|
|
27961
|
+
};
|
|
27962
|
+
function isExternalCommandCandidate(text2) {
|
|
27963
|
+
return /^\/[^\s/]+(?:\s|$)/u.test(text2.trimStart());
|
|
27964
|
+
}
|
|
27965
|
+
async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
|
|
27966
|
+
let timeout;
|
|
27967
|
+
try {
|
|
27968
|
+
const result = await Promise.race([
|
|
27969
|
+
commands.list(),
|
|
27970
|
+
new Promise((resolve) => {
|
|
27971
|
+
timeout = setTimeout(() => resolve(null), timeoutMs);
|
|
27972
|
+
})
|
|
27973
|
+
]);
|
|
27974
|
+
return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
|
|
27975
|
+
} catch {
|
|
27976
|
+
return null;
|
|
27977
|
+
} finally {
|
|
27978
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
27979
|
+
}
|
|
27980
|
+
}
|
|
27981
|
+
async function resolveExternalCommand(commands, text2, options2 = {}) {
|
|
27982
|
+
const catalog = await commands.list();
|
|
27983
|
+
if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
|
|
27984
|
+
const commandText = text2.trim();
|
|
27985
|
+
const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
|
|
27986
|
+
if (commandText === command.invocation) return true;
|
|
27987
|
+
return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
|
|
27988
|
+
});
|
|
27989
|
+
if (!matched) {
|
|
27990
|
+
const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
|
|
27991
|
+
if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
|
|
27992
|
+
return null;
|
|
27993
|
+
}
|
|
27994
|
+
throw new ExternalCommandError(
|
|
27995
|
+
-32078,
|
|
27996
|
+
"External Harness does not expose the requested command"
|
|
27997
|
+
);
|
|
27998
|
+
}
|
|
27999
|
+
const argumentText = commandText.slice(matched.invocation.length).trimStart();
|
|
28000
|
+
return {
|
|
28001
|
+
commandId: matched.id,
|
|
28002
|
+
...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
|
|
28003
|
+
};
|
|
28004
|
+
}
|
|
28005
|
+
|
|
28006
|
+
// packages/host-runtime/src/live-command-catalog-cache.ts
|
|
28007
|
+
import path10 from "node:path";
|
|
28008
|
+
var MAX_ENTRIES = 64;
|
|
28009
|
+
function isLiveCommandCatalog(catalog, staticCatalog) {
|
|
28010
|
+
const staticIds = new Set(staticCatalog.commands.map(({ id: id2 }) => id2));
|
|
28011
|
+
return catalog.commands.some(({ id: id2 }) => !staticIds.has(id2));
|
|
28012
|
+
}
|
|
28013
|
+
var LiveCommandCatalogCache = class {
|
|
28014
|
+
#entries = /* @__PURE__ */ new Map();
|
|
28015
|
+
#key(harnessId, cwd) {
|
|
28016
|
+
return `${harnessId}\0${path10.resolve(cwd)}`;
|
|
28017
|
+
}
|
|
28018
|
+
remember(harnessId, cwd, catalog) {
|
|
28019
|
+
const key = this.#key(harnessId, cwd);
|
|
28020
|
+
this.#entries.delete(key);
|
|
28021
|
+
this.#entries.set(key, catalog);
|
|
28022
|
+
while (this.#entries.size > MAX_ENTRIES) {
|
|
28023
|
+
const oldest = this.#entries.keys().next().value;
|
|
28024
|
+
if (oldest === void 0) break;
|
|
28025
|
+
this.#entries.delete(oldest);
|
|
28026
|
+
}
|
|
28027
|
+
}
|
|
28028
|
+
lookup(harnessId, cwd) {
|
|
28029
|
+
return this.#entries.get(this.#key(harnessId, cwd));
|
|
28030
|
+
}
|
|
28031
|
+
};
|
|
28032
|
+
function sameWorkspace(left, right) {
|
|
28033
|
+
return path10.resolve(left) === path10.resolve(right);
|
|
28034
|
+
}
|
|
28035
|
+
|
|
27580
28036
|
// packages/host-runtime/src/harness-delegation-coordinator.ts
|
|
27581
|
-
import { createHash as
|
|
27582
|
-
import
|
|
28037
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "node:crypto";
|
|
28038
|
+
import path11 from "node:path";
|
|
27583
28039
|
|
|
27584
28040
|
// packages/host-runtime/src/delegation-snapshot.ts
|
|
27585
|
-
import { createHash as
|
|
28041
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
27586
28042
|
var CURSOR_PREFIX = "codexhost:thread-messages:v1:";
|
|
27587
28043
|
var DEFAULT_MESSAGE_LIMIT = 25;
|
|
27588
28044
|
var MAX_MESSAGE_LIMIT = 100;
|
|
27589
|
-
function
|
|
28045
|
+
function isRecord9(value2) {
|
|
27590
28046
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
27591
28047
|
}
|
|
27592
28048
|
function stringValue(value2) {
|
|
@@ -27595,12 +28051,12 @@ function stringValue(value2) {
|
|
|
27595
28051
|
function textFromUserItem(item) {
|
|
27596
28052
|
if (!Array.isArray(item.content)) return "";
|
|
27597
28053
|
return item.content.flatMap(
|
|
27598
|
-
(part) =>
|
|
28054
|
+
(part) => isRecord9(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []
|
|
27599
28055
|
).join("\n");
|
|
27600
28056
|
}
|
|
27601
28057
|
function threadStatus(value2, running) {
|
|
27602
28058
|
if (running) return "running";
|
|
27603
|
-
if (
|
|
28059
|
+
if (isRecord9(value2)) {
|
|
27604
28060
|
if (value2.type === "active") return "running";
|
|
27605
28061
|
}
|
|
27606
28062
|
return "completed";
|
|
@@ -27617,10 +28073,10 @@ function allVisibleMessages(turns) {
|
|
|
27617
28073
|
const turnId = stringValue(turn.id);
|
|
27618
28074
|
if (!turnId || !Array.isArray(turn.items)) continue;
|
|
27619
28075
|
const agentItems = turn.items.filter(
|
|
27620
|
-
(item) =>
|
|
28076
|
+
(item) => isRecord9(item) && item.type === "agentMessage"
|
|
27621
28077
|
);
|
|
27622
28078
|
for (const item of turn.items) {
|
|
27623
|
-
if (!
|
|
28079
|
+
if (!isRecord9(item)) continue;
|
|
27624
28080
|
const id2 = stringValue(item.id);
|
|
27625
28081
|
if (!id2) continue;
|
|
27626
28082
|
if (item.type === "userMessage") {
|
|
@@ -27636,7 +28092,7 @@ function allVisibleMessages(turns) {
|
|
|
27636
28092
|
return messages;
|
|
27637
28093
|
}
|
|
27638
28094
|
function cursorFingerprint(threadId2) {
|
|
27639
|
-
return
|
|
28095
|
+
return createHash6("sha256").update(threadId2).digest("hex");
|
|
27640
28096
|
}
|
|
27641
28097
|
function encodeCursor(threadId2, offset) {
|
|
27642
28098
|
const payload = JSON.stringify({ version: 1, fingerprint: cursorFingerprint(threadId2), offset });
|
|
@@ -27695,7 +28151,7 @@ function projectDelegationThreadSnapshot(input) {
|
|
|
27695
28151
|
const progress = latestTurnMessages.filter((message) => message.phase !== "final" && message.text.trim()).map(({ id: id2, turnId, text: text2 }) => ({ id: id2, turnId, text: text2 }));
|
|
27696
28152
|
const result = input.running ? { availability: "pending" } : final ? { availability: "available", text: final.text } : {
|
|
27697
28153
|
availability: "unavailable",
|
|
27698
|
-
...
|
|
28154
|
+
...isRecord9(latestTurn?.error) && typeof latestTurn.error.message === "string" ? { message: latestTurn.error.message } : {}
|
|
27699
28155
|
};
|
|
27700
28156
|
const offset = options2.view === "messages" ? decodeCursor(input.threadId, options2.cursor) : visible.length;
|
|
27701
28157
|
const page = options2.view === "messages" ? [] : void 0;
|
|
@@ -27747,10 +28203,10 @@ function terminal(status) {
|
|
|
27747
28203
|
return status === "completed" || status === "failed" || status === "interrupted";
|
|
27748
28204
|
}
|
|
27749
28205
|
function taskDigest(input) {
|
|
27750
|
-
return
|
|
28206
|
+
return createHash7("sha256").update(
|
|
27751
28207
|
JSON.stringify({
|
|
27752
28208
|
task: input.task,
|
|
27753
|
-
cwd:
|
|
28209
|
+
cwd: path11.resolve(input.cwd),
|
|
27754
28210
|
modelId: input.model?.id ?? null,
|
|
27755
28211
|
thinkingOptionId: input.thinkingOptionId ?? null
|
|
27756
28212
|
})
|
|
@@ -27821,7 +28277,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27821
28277
|
return {
|
|
27822
28278
|
harnessId: input.harnessId,
|
|
27823
28279
|
inspection: await adapter.inspect({
|
|
27824
|
-
...input.cwd ? { cwd:
|
|
28280
|
+
...input.cwd ? { cwd: path11.resolve(input.cwd) } : {},
|
|
27825
28281
|
...input.refresh !== void 0 ? { refresh: input.refresh } : {}
|
|
27826
28282
|
})
|
|
27827
28283
|
};
|
|
@@ -27835,7 +28291,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27835
28291
|
const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
|
|
27836
28292
|
return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
|
|
27837
28293
|
}
|
|
27838
|
-
const startInput = { ...input, parentThreadId, cwd:
|
|
28294
|
+
const startInput = { ...input, parentThreadId, cwd: path11.resolve(selectedCwd) };
|
|
27839
28295
|
if (!this.#adapters.has(input.harnessId)) {
|
|
27840
28296
|
throw new DelegationControlError(
|
|
27841
28297
|
"HARNESS_NOT_FOUND",
|
|
@@ -27875,10 +28331,10 @@ var HarnessDelegationCoordinator = class {
|
|
|
27875
28331
|
});
|
|
27876
28332
|
this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
|
|
27877
28333
|
}
|
|
27878
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
27879
|
-
const childThreadId = hostThreadIdSchema.parse(
|
|
27880
|
-
const turnId = hostTurnIdSchema.parse(
|
|
27881
|
-
const createRequestId = input.requestId ? `delegation:${input.requestId}` :
|
|
28334
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID6());
|
|
28335
|
+
const childThreadId = hostThreadIdSchema.parse(randomUUID6());
|
|
28336
|
+
const turnId = hostTurnIdSchema.parse(randomUUID6());
|
|
28337
|
+
const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID6();
|
|
27882
28338
|
let record3 = await this.#repository.createProvisional(
|
|
27883
28339
|
createExternalThreadRecordInput({
|
|
27884
28340
|
hostThreadId: childThreadId,
|
|
@@ -28010,7 +28466,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
28010
28466
|
if (thread.running || thread.activeTurnId) {
|
|
28011
28467
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
28012
28468
|
}
|
|
28013
|
-
const turnId = hostTurnIdSchema.parse(
|
|
28469
|
+
const turnId = hostTurnIdSchema.parse(randomUUID6());
|
|
28014
28470
|
try {
|
|
28015
28471
|
await this.#startExternalTurn(thread, input.message, turnId);
|
|
28016
28472
|
} catch (error51) {
|
|
@@ -28264,7 +28720,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
28264
28720
|
|
|
28265
28721
|
// packages/host-runtime/src/harness-plugin-loader.ts
|
|
28266
28722
|
import { readdir as readdir3, realpath as realpath2 } from "node:fs/promises";
|
|
28267
|
-
import
|
|
28723
|
+
import path13 from "node:path";
|
|
28268
28724
|
import { pathToFileURL } from "node:url";
|
|
28269
28725
|
|
|
28270
28726
|
// packages/host-runtime/src/harness-plugin-registry.ts
|
|
@@ -28301,25 +28757,25 @@ var HarnessPluginRegistry = class {
|
|
|
28301
28757
|
};
|
|
28302
28758
|
|
|
28303
28759
|
// packages/host-runtime/src/plugin-files.ts
|
|
28304
|
-
import { open as
|
|
28305
|
-
import
|
|
28760
|
+
import { open as open5, realpath, stat as stat3 } from "node:fs/promises";
|
|
28761
|
+
import path12 from "node:path";
|
|
28306
28762
|
function inside(root, candidate) {
|
|
28307
|
-
const relative =
|
|
28308
|
-
return relative !== "" && !
|
|
28763
|
+
const relative = path12.relative(root, candidate);
|
|
28764
|
+
return relative !== "" && !path12.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path12.sep}`);
|
|
28309
28765
|
}
|
|
28310
28766
|
async function pluginResourcePath(root, relative) {
|
|
28311
|
-
if (
|
|
28767
|
+
if (path12.isAbsolute(relative) || !inside(root, path12.resolve(root, relative))) {
|
|
28312
28768
|
throw new Error("Plugin resource escapes its root");
|
|
28313
28769
|
}
|
|
28314
|
-
const resolved = await realpath(
|
|
28315
|
-
if (!inside(root, resolved) || !(await
|
|
28770
|
+
const resolved = await realpath(path12.resolve(root, relative));
|
|
28771
|
+
if (!inside(root, resolved) || !(await stat3(resolved)).isFile()) {
|
|
28316
28772
|
throw new Error("Plugin resource must be a regular file inside its root");
|
|
28317
28773
|
}
|
|
28318
28774
|
return resolved;
|
|
28319
28775
|
}
|
|
28320
28776
|
async function readPluginFile(file2, maximum) {
|
|
28321
|
-
if (!(await
|
|
28322
|
-
const handle = await
|
|
28777
|
+
if (!(await stat3(file2)).isFile()) throw new Error("Plugin resource is not a regular file");
|
|
28778
|
+
const handle = await open5(file2, "r");
|
|
28323
28779
|
try {
|
|
28324
28780
|
const info = await handle.stat();
|
|
28325
28781
|
if (!info.isFile() || info.size > maximum) throw new Error("Plugin resource exceeds its limit");
|
|
@@ -28473,7 +28929,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
28473
28929
|
const enabledIds = /* @__PURE__ */ new Set();
|
|
28474
28930
|
const roots = /* @__PURE__ */ new Set();
|
|
28475
28931
|
for (const configuredRoot of options2.roots) {
|
|
28476
|
-
if (!
|
|
28932
|
+
if (!path13.isAbsolute(configuredRoot)) {
|
|
28477
28933
|
diagnose({ code: "invalidRoot" });
|
|
28478
28934
|
continue;
|
|
28479
28935
|
}
|
|
@@ -28503,7 +28959,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
28503
28959
|
for (const directory of directories) {
|
|
28504
28960
|
try {
|
|
28505
28961
|
const file2 = await pluginResourcePath(root, `${directory.name}/manifest.json`);
|
|
28506
|
-
const pluginRoot = await realpath2(
|
|
28962
|
+
const pluginRoot = await realpath2(path13.join(root, directory.name));
|
|
28507
28963
|
await pluginResourcePath(pluginRoot, "manifest.json");
|
|
28508
28964
|
const manifest = harnessPluginManifestSchema.parse(
|
|
28509
28965
|
JSON.parse(
|
|
@@ -28598,28 +29054,28 @@ async function loadHarnessPlugins(options2) {
|
|
|
28598
29054
|
}
|
|
28599
29055
|
|
|
28600
29056
|
// packages/host-runtime/src/harness-launch-settings.ts
|
|
28601
|
-
import { randomUUID as
|
|
28602
|
-
import { mkdir as
|
|
28603
|
-
import
|
|
28604
|
-
import
|
|
29057
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
29058
|
+
import { mkdir as mkdir5, readFile as readFile7, rename as rename4, rm as rm5, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
|
|
29059
|
+
import os4 from "node:os";
|
|
29060
|
+
import path14 from "node:path";
|
|
28605
29061
|
var HarnessLaunchSettingsStore = class {
|
|
28606
29062
|
#directory;
|
|
28607
29063
|
#initial = /* @__PURE__ */ new Map();
|
|
28608
29064
|
constructor(environment) {
|
|
28609
|
-
this.#directory =
|
|
28610
|
-
environment.CODEXHOST_DATA_DIR ?
|
|
29065
|
+
this.#directory = path14.join(
|
|
29066
|
+
environment.CODEXHOST_DATA_DIR ? path14.resolve(environment.CODEXHOST_DATA_DIR) : path14.join(os4.homedir(), ".codexhost"),
|
|
28611
29067
|
"harness-launch-settings"
|
|
28612
29068
|
);
|
|
28613
29069
|
}
|
|
28614
29070
|
#file(id2) {
|
|
28615
|
-
return
|
|
29071
|
+
return path14.join(this.#directory, `${harnessPluginIdSchema.parse(id2)}.json`);
|
|
28616
29072
|
}
|
|
28617
29073
|
async #read(id2) {
|
|
28618
29074
|
try {
|
|
28619
29075
|
const value2 = harnessLaunchPathSchema.parse(
|
|
28620
|
-
JSON.parse(await
|
|
29076
|
+
JSON.parse(await readFile7(this.#file(id2), "utf8"))
|
|
28621
29077
|
);
|
|
28622
|
-
if (!
|
|
29078
|
+
if (!path14.isAbsolute(value2)) throw new Error("Expected an absolute entrypoint path");
|
|
28623
29079
|
return value2;
|
|
28624
29080
|
} catch (error51) {
|
|
28625
29081
|
if (error51 && typeof error51 === "object" && "code" in error51 && error51.code === "ENOENT")
|
|
@@ -28645,22 +29101,22 @@ var HarnessLaunchSettingsStore = class {
|
|
|
28645
29101
|
const initial = await this.initialCommand(id2) ?? null;
|
|
28646
29102
|
const file2 = this.#file(id2);
|
|
28647
29103
|
if (value2 === null) {
|
|
28648
|
-
await
|
|
29104
|
+
await rm5(file2, { force: true });
|
|
28649
29105
|
} else {
|
|
28650
29106
|
value2 = harnessLaunchPathSchema.parse(value2);
|
|
28651
|
-
if (!
|
|
29107
|
+
if (!path14.isAbsolute(value2))
|
|
28652
29108
|
throw new Error("Use an absolute entrypoint path without arguments");
|
|
28653
|
-
const metadata = await
|
|
29109
|
+
const metadata = await stat4(value2).catch(() => void 0);
|
|
28654
29110
|
if (!metadata?.isDirectory() && !metadata?.isFile())
|
|
28655
29111
|
throw new Error("The installation path must be an existing directory on this Host");
|
|
28656
|
-
await
|
|
28657
|
-
const temporary = `${file2}.${
|
|
29112
|
+
await mkdir5(this.#directory, { recursive: true, mode: 448 });
|
|
29113
|
+
const temporary = `${file2}.${randomUUID7()}.tmp`;
|
|
28658
29114
|
try {
|
|
28659
29115
|
await writeFile3(temporary, `${JSON.stringify(value2)}
|
|
28660
29116
|
`, { mode: 384, flag: "wx" });
|
|
28661
|
-
await
|
|
29117
|
+
await rename4(temporary, file2);
|
|
28662
29118
|
} finally {
|
|
28663
|
-
await
|
|
29119
|
+
await rm5(temporary, { force: true });
|
|
28664
29120
|
}
|
|
28665
29121
|
}
|
|
28666
29122
|
return { path: value2, restartRequired: value2 !== initial };
|
|
@@ -28823,11 +29279,11 @@ function spawnOfficialAppServerConnection(input) {
|
|
|
28823
29279
|
}
|
|
28824
29280
|
|
|
28825
29281
|
// packages/host-runtime/src/account/codex-account-control.ts
|
|
28826
|
-
function
|
|
29282
|
+
function isRecord10(value2) {
|
|
28827
29283
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
28828
29284
|
}
|
|
28829
29285
|
function currentCodexAccountFromOfficialRead(result) {
|
|
28830
|
-
if (!
|
|
29286
|
+
if (!isRecord10(result) || !isRecord10(result.account) || result.account.type !== "chatgpt") {
|
|
28831
29287
|
return null;
|
|
28832
29288
|
}
|
|
28833
29289
|
const email3 = external_exports.string().email().max(320).safeParse(result.account.email);
|
|
@@ -28857,8 +29313,8 @@ var SingleNativeCodexAccount = class {
|
|
|
28857
29313
|
};
|
|
28858
29314
|
|
|
28859
29315
|
// packages/host-runtime/src/account/codex-home-auth.ts
|
|
28860
|
-
import { readFile as
|
|
28861
|
-
import
|
|
29316
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
29317
|
+
import path15 from "node:path";
|
|
28862
29318
|
var CODEX_API_AUTH_IDENTITY_FALLBACK = "BANK OF TOKEN";
|
|
28863
29319
|
function tomlUnquote(value2) {
|
|
28864
29320
|
const trimmed = value2.trim();
|
|
@@ -28979,7 +29435,7 @@ function inspectCodexAuthDocuments(input) {
|
|
|
28979
29435
|
}
|
|
28980
29436
|
async function readOptionalUtf8(file2) {
|
|
28981
29437
|
try {
|
|
28982
|
-
return await
|
|
29438
|
+
return await readFile8(file2, "utf8");
|
|
28983
29439
|
} catch (error51) {
|
|
28984
29440
|
if (error51.code === "ENOENT") return void 0;
|
|
28985
29441
|
throw error51;
|
|
@@ -29004,10 +29460,10 @@ function inspectCodexApiUsageSource(input) {
|
|
|
29004
29460
|
return { baseUrl, apiKey };
|
|
29005
29461
|
}
|
|
29006
29462
|
async function inspectCodexHomeAuth(codexHome) {
|
|
29007
|
-
const root =
|
|
29463
|
+
const root = path15.resolve(codexHome);
|
|
29008
29464
|
const [configToml, authJson] = await Promise.all([
|
|
29009
|
-
readOptionalUtf8(
|
|
29010
|
-
readOptionalUtf8(
|
|
29465
|
+
readOptionalUtf8(path15.join(root, "config.toml")),
|
|
29466
|
+
readOptionalUtf8(path15.join(root, "auth.json"))
|
|
29011
29467
|
]);
|
|
29012
29468
|
return inspectCodexAuthDocuments({
|
|
29013
29469
|
...configToml ? { configToml } : {},
|
|
@@ -29015,10 +29471,10 @@ async function inspectCodexHomeAuth(codexHome) {
|
|
|
29015
29471
|
});
|
|
29016
29472
|
}
|
|
29017
29473
|
async function inspectCodexHomeApiUsageSource(codexHome, env = process.env) {
|
|
29018
|
-
const root =
|
|
29474
|
+
const root = path15.resolve(codexHome);
|
|
29019
29475
|
const [configToml, authJson] = await Promise.all([
|
|
29020
|
-
readOptionalUtf8(
|
|
29021
|
-
readOptionalUtf8(
|
|
29476
|
+
readOptionalUtf8(path15.join(root, "config.toml")),
|
|
29477
|
+
readOptionalUtf8(path15.join(root, "auth.json"))
|
|
29022
29478
|
]);
|
|
29023
29479
|
return inspectCodexApiUsageSource({
|
|
29024
29480
|
...configToml ? { configToml } : {},
|
|
@@ -29029,7 +29485,7 @@ async function inspectCodexHomeApiUsageSource(codexHome, env = process.env) {
|
|
|
29029
29485
|
|
|
29030
29486
|
// packages/host-runtime/src/account/codex-api-usage.ts
|
|
29031
29487
|
var REQUEST_TIMEOUT_MS = 15e3;
|
|
29032
|
-
function
|
|
29488
|
+
function isRecord11(value2) {
|
|
29033
29489
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29034
29490
|
}
|
|
29035
29491
|
function finiteNumber(value2) {
|
|
@@ -29057,8 +29513,8 @@ function codexApiUsageUrl(baseUrl) {
|
|
|
29057
29513
|
return parsed.toString();
|
|
29058
29514
|
}
|
|
29059
29515
|
function extractCodexApiUsage(response) {
|
|
29060
|
-
if (!
|
|
29061
|
-
const quota =
|
|
29516
|
+
if (!isRecord11(response)) return null;
|
|
29517
|
+
const quota = isRecord11(response.quota) ? response.quota : void 0;
|
|
29062
29518
|
const remaining = finiteNumber(response.remaining) ?? finiteNumber(quota?.remaining) ?? finiteNumber(response.balance);
|
|
29063
29519
|
if (remaining === void 0) return null;
|
|
29064
29520
|
const isValid = boolean4(response.is_active) ?? boolean4(response.isValid) ?? true;
|
|
@@ -29134,13 +29590,13 @@ function projectCodexAccountAuth(snapshot, homeAuth) {
|
|
|
29134
29590
|
}
|
|
29135
29591
|
|
|
29136
29592
|
// packages/host-runtime/src/codex-runtime/official-runtime-owner.ts
|
|
29137
|
-
import { randomUUID as
|
|
29593
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
29138
29594
|
|
|
29139
29595
|
// packages/host-runtime/src/official-request-broker.ts
|
|
29140
|
-
import { randomUUID as
|
|
29596
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
29141
29597
|
var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
|
|
29142
29598
|
var MAX_RETIRED_IDS = 1024;
|
|
29143
|
-
function
|
|
29599
|
+
function isRecord12(value2) {
|
|
29144
29600
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29145
29601
|
}
|
|
29146
29602
|
var OfficialRequestBroker = class {
|
|
@@ -29153,7 +29609,7 @@ var OfficialRequestBroker = class {
|
|
|
29153
29609
|
constructor(input) {
|
|
29154
29610
|
this.#send = input.send;
|
|
29155
29611
|
this.#timeoutMs = input.timeoutMs ?? 3e4;
|
|
29156
|
-
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${
|
|
29612
|
+
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID8()}`);
|
|
29157
29613
|
}
|
|
29158
29614
|
get pendingCount() {
|
|
29159
29615
|
return this.#pending.size;
|
|
@@ -29183,7 +29639,7 @@ var OfficialRequestBroker = class {
|
|
|
29183
29639
|
});
|
|
29184
29640
|
}
|
|
29185
29641
|
handle(value2) {
|
|
29186
|
-
if (!
|
|
29642
|
+
if (!isRecord12(value2) || typeof value2.id !== "string") return false;
|
|
29187
29643
|
const pending = this.#pending.get(value2.id);
|
|
29188
29644
|
if (!pending) return this.#retired.has(value2.id);
|
|
29189
29645
|
clearTimeout(pending.timeout);
|
|
@@ -29507,7 +29963,7 @@ var OfficialRuntimeOwner = class {
|
|
|
29507
29963
|
}
|
|
29508
29964
|
#attach(role, output, onBackendStopped) {
|
|
29509
29965
|
const client = {
|
|
29510
|
-
id:
|
|
29966
|
+
id: randomUUID9(),
|
|
29511
29967
|
role,
|
|
29512
29968
|
output,
|
|
29513
29969
|
...onBackendStopped ? { onBackendStopped } : {},
|
|
@@ -29665,7 +30121,7 @@ var OfficialRuntimeOwner = class {
|
|
|
29665
30121
|
if (!object4(value2)) return client.output(event);
|
|
29666
30122
|
if (typeof value2.id === "string" || typeof value2.id === "number") {
|
|
29667
30123
|
if (typeof value2.method === "string") {
|
|
29668
|
-
const id2 = `codexhost:server:${client.id}:${event.generation}:${
|
|
30124
|
+
const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID9()}`;
|
|
29669
30125
|
client.serverRequests.set(id2, value2.id);
|
|
29670
30126
|
const projected = { ...value2, id: id2 };
|
|
29671
30127
|
return client.output({
|
|
@@ -29903,11 +30359,11 @@ function createOwnedConnectionBackend(factory) {
|
|
|
29903
30359
|
}
|
|
29904
30360
|
|
|
29905
30361
|
// packages/host-runtime/src/route-observation.ts
|
|
29906
|
-
function
|
|
30362
|
+
function isRecord13(value2) {
|
|
29907
30363
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29908
30364
|
}
|
|
29909
30365
|
function classifyThreadPurpose(request) {
|
|
29910
|
-
return
|
|
30366
|
+
return isRecord13(request.params) && request.params.ephemeral === true ? "ephemeral" : "conversation";
|
|
29911
30367
|
}
|
|
29912
30368
|
var RequestRouteObservationTracker = class {
|
|
29913
30369
|
#nextCreateOrdinal = 0;
|
|
@@ -29932,13 +30388,13 @@ var RequestRouteObservationTracker = class {
|
|
|
29932
30388
|
this.#createByThreadId.set(threadId2, tracked);
|
|
29933
30389
|
}
|
|
29934
30390
|
bindOfficialResponse(response) {
|
|
29935
|
-
if (!
|
|
30391
|
+
if (!isRecord13(response) || !("id" in response)) return;
|
|
29936
30392
|
const tracked = this.#pendingByRequestId.get(response.id);
|
|
29937
30393
|
if (!tracked) return;
|
|
29938
30394
|
this.#pendingByRequestId.delete(response.id);
|
|
29939
30395
|
const result = response.result;
|
|
29940
|
-
const thread =
|
|
29941
|
-
if (
|
|
30396
|
+
const thread = isRecord13(result) ? result.thread : null;
|
|
30397
|
+
if (isRecord13(thread) && typeof thread.id === "string") {
|
|
29942
30398
|
this.#createByThreadId.set(thread.id, tracked);
|
|
29943
30399
|
}
|
|
29944
30400
|
}
|
|
@@ -30060,25 +30516,25 @@ function resolveExternalSessionTreeIds(records) {
|
|
|
30060
30516
|
const resolve = (start) => {
|
|
30061
30517
|
const cached2 = resolved.get(start.hostThreadId);
|
|
30062
30518
|
if (cached2) return cached2;
|
|
30063
|
-
const
|
|
30519
|
+
const path29 = [];
|
|
30064
30520
|
const visited = /* @__PURE__ */ new Set();
|
|
30065
30521
|
let current = start;
|
|
30066
30522
|
while (true) {
|
|
30067
30523
|
const known = resolved.get(current.hostThreadId);
|
|
30068
30524
|
if (known) {
|
|
30069
|
-
for (const record3 of
|
|
30525
|
+
for (const record3 of path29) resolved.set(record3.hostThreadId, known);
|
|
30070
30526
|
return known;
|
|
30071
30527
|
}
|
|
30072
30528
|
if (visited.has(current.hostThreadId)) {
|
|
30073
30529
|
throw new Error("External Thread Fork tree contains a cycle");
|
|
30074
30530
|
}
|
|
30075
30531
|
visited.add(current.hostThreadId);
|
|
30076
|
-
|
|
30532
|
+
path29.push(current);
|
|
30077
30533
|
const sourceId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
|
|
30078
30534
|
const source = sourceId ? byId.get(sourceId) : void 0;
|
|
30079
30535
|
if (!source) {
|
|
30080
30536
|
const root = current.hostThreadId;
|
|
30081
|
-
for (const record3 of
|
|
30537
|
+
for (const record3 of path29) resolved.set(record3.hostThreadId, root);
|
|
30082
30538
|
return root;
|
|
30083
30539
|
}
|
|
30084
30540
|
current = source;
|
|
@@ -30132,11 +30588,11 @@ var OfficialThreadListError = class extends Error {
|
|
|
30132
30588
|
}
|
|
30133
30589
|
rpcError;
|
|
30134
30590
|
};
|
|
30135
|
-
function
|
|
30591
|
+
function isRecord14(value2) {
|
|
30136
30592
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
30137
30593
|
}
|
|
30138
30594
|
function officialThreadListPageFromResponse(response) {
|
|
30139
|
-
if (
|
|
30595
|
+
if (isRecord14(response.error)) {
|
|
30140
30596
|
if (!Number.isSafeInteger(response.error.code) || typeof response.error.message !== "string") {
|
|
30141
30597
|
throw new Error("Official thread/list error response is invalid");
|
|
30142
30598
|
}
|
|
@@ -30308,14 +30764,14 @@ var THREAD_USAGE_UPDATED_METHOD = "codexhost/thread/usage/updated";
|
|
|
30308
30764
|
function delay3(milliseconds) {
|
|
30309
30765
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
30310
30766
|
}
|
|
30311
|
-
function
|
|
30767
|
+
function isRecord15(value2) {
|
|
30312
30768
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
30313
30769
|
}
|
|
30314
30770
|
function isCreditsAdapter(adapter) {
|
|
30315
30771
|
return typeof adapter.credits === "function";
|
|
30316
30772
|
}
|
|
30317
30773
|
function projectAccountCredits(value2) {
|
|
30318
|
-
if (!
|
|
30774
|
+
if (!isRecord15(value2)) return null;
|
|
30319
30775
|
const rest = { ...value2 };
|
|
30320
30776
|
delete rest.fetchedAt;
|
|
30321
30777
|
const parsed = accountCreditsSnapshotSchema.safeParse(rest);
|
|
@@ -30441,12 +30897,12 @@ function classifyCreateRequestRoute(request, defaultAgent) {
|
|
|
30441
30897
|
};
|
|
30442
30898
|
}
|
|
30443
30899
|
function requestObject(request) {
|
|
30444
|
-
if (!
|
|
30900
|
+
if (!isRecord15(request.params)) throw new Error(`${request.method} params must be an object`);
|
|
30445
30901
|
return request.params;
|
|
30446
30902
|
}
|
|
30447
30903
|
function requestText(params) {
|
|
30448
30904
|
if (!Array.isArray(params.input)) throw new Error("turn/start input must be an array");
|
|
30449
|
-
const text2 = params.input.filter((item) =>
|
|
30905
|
+
const text2 = params.input.filter((item) => isRecord15(item) && item.type === "text").map((item) => item.text).filter((value2) => typeof value2 === "string").join("\n");
|
|
30450
30906
|
if (!text2) throw new Error("turn/start must contain text input");
|
|
30451
30907
|
return text2;
|
|
30452
30908
|
}
|
|
@@ -30501,6 +30957,7 @@ var AppServerHost = class {
|
|
|
30501
30957
|
#accountInspections = new HarnessAccountInspectionCache();
|
|
30502
30958
|
#externalRuntime;
|
|
30503
30959
|
#externalSteering = new ExternalTurnSteering();
|
|
30960
|
+
#liveCommandCache = new LiveCommandCatalogCache();
|
|
30504
30961
|
#repository;
|
|
30505
30962
|
#pendingDesktopApprovals = /* @__PURE__ */ new Map();
|
|
30506
30963
|
#pendingDesktopQuestions = /* @__PURE__ */ new Map();
|
|
@@ -30542,7 +30999,7 @@ var AppServerHost = class {
|
|
|
30542
30999
|
this.#launchSettings = new HarnessLaunchSettingsStore(
|
|
30543
31000
|
this.#options.pluginContext?.environment ?? environment
|
|
30544
31001
|
);
|
|
30545
|
-
const permanentHome =
|
|
31002
|
+
const permanentHome = path16.resolve(environment.CODEX_HOME ?? path16.join(os5.homedir(), ".codex"));
|
|
30546
31003
|
this.#ownsOfficialRuntimeScope = options2.officialRuntimeScope === void 0;
|
|
30547
31004
|
this.#officialRuntimeScope = options2.officialRuntimeScope ?? new OfficialRuntimeScope({
|
|
30548
31005
|
diagnosticOutput: this.#options.diagnosticOutput,
|
|
@@ -30810,12 +31267,12 @@ var AppServerHost = class {
|
|
|
30810
31267
|
for (const resolve of waiters) resolve();
|
|
30811
31268
|
}
|
|
30812
31269
|
#observeOfficialTurnStartResponse(value2) {
|
|
30813
|
-
if (!
|
|
31270
|
+
if (!isRecord15(value2) || !("id" in value2)) return;
|
|
30814
31271
|
const threadId2 = this.#pendingOfficialTurnStarts.get(value2.id);
|
|
30815
31272
|
if (!threadId2) return;
|
|
30816
31273
|
this.#pendingOfficialTurnStarts.delete(value2.id);
|
|
30817
|
-
const result =
|
|
30818
|
-
const turn = result &&
|
|
31274
|
+
const result = isRecord15(value2.result) ? value2.result : null;
|
|
31275
|
+
const turn = result && isRecord15(result.turn) ? result.turn : null;
|
|
30819
31276
|
if (turn && typeof turn.id === "string") {
|
|
30820
31277
|
this.#activeOfficialTurns.set(threadId2, turn.id);
|
|
30821
31278
|
}
|
|
@@ -30829,7 +31286,7 @@ var AppServerHost = class {
|
|
|
30829
31286
|
async #forwardDesktop() {
|
|
30830
31287
|
for await (const frame of readLfFrames(this.#options.desktopInput)) {
|
|
30831
31288
|
const parsed = parseJsonFrame(frame);
|
|
30832
|
-
if (
|
|
31289
|
+
if (isRecord15(parsed) && parsed.method === "initialized" && !("id" in parsed)) {
|
|
30833
31290
|
continue;
|
|
30834
31291
|
}
|
|
30835
31292
|
if (await this.#handleDesktopApprovalResponse(parsed)) continue;
|
|
@@ -30853,7 +31310,7 @@ var AppServerHost = class {
|
|
|
30853
31310
|
}
|
|
30854
31311
|
continue;
|
|
30855
31312
|
}
|
|
30856
|
-
const threadId2 =
|
|
31313
|
+
const threadId2 = isRecord15(request.params) && typeof request.params.threadId === "string" ? request.params.threadId : void 0;
|
|
30857
31314
|
this.#dispatchDesktopRequest(
|
|
30858
31315
|
() => this.#desktopRequests.run(
|
|
30859
31316
|
threadId2,
|
|
@@ -31081,7 +31538,7 @@ var AppServerHost = class {
|
|
|
31081
31538
|
rpcError(request, -32602, "Invalid Harness command inspection params")
|
|
31082
31539
|
);
|
|
31083
31540
|
} else {
|
|
31084
|
-
await this.#writeHarnessCommandCatalog(request, params.data.harnessId);
|
|
31541
|
+
await this.#writeHarnessCommandCatalog(request, params.data.harnessId, params.data.cwd);
|
|
31085
31542
|
}
|
|
31086
31543
|
return;
|
|
31087
31544
|
}
|
|
@@ -31185,7 +31642,7 @@ var AppServerHost = class {
|
|
|
31185
31642
|
return;
|
|
31186
31643
|
}
|
|
31187
31644
|
if (request.method === "thread/fork") {
|
|
31188
|
-
const params =
|
|
31645
|
+
const params = isRecord15(request.params) ? request.params : {};
|
|
31189
31646
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
31190
31647
|
if (resolution.kind === "error") {
|
|
31191
31648
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -31206,7 +31663,7 @@ var AppServerHost = class {
|
|
|
31206
31663
|
}
|
|
31207
31664
|
}
|
|
31208
31665
|
if (request.method === "thread/revert") {
|
|
31209
|
-
const params =
|
|
31666
|
+
const params = isRecord15(request.params) ? request.params : {};
|
|
31210
31667
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
31211
31668
|
if (resolution.kind === "error") {
|
|
31212
31669
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -31227,7 +31684,7 @@ var AppServerHost = class {
|
|
|
31227
31684
|
}
|
|
31228
31685
|
}
|
|
31229
31686
|
if (request.method === "thread/rollback") {
|
|
31230
|
-
const params =
|
|
31687
|
+
const params = isRecord15(request.params) ? request.params : {};
|
|
31231
31688
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
31232
31689
|
if (resolution.kind === "error") {
|
|
31233
31690
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -31383,7 +31840,7 @@ var AppServerHost = class {
|
|
|
31383
31840
|
return;
|
|
31384
31841
|
}
|
|
31385
31842
|
}
|
|
31386
|
-
if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) &&
|
|
31843
|
+
if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) && isRecord15(request.params) && typeof request.params.threadId === "string") {
|
|
31387
31844
|
const location = await this.#locateExternalThread(request.params.threadId);
|
|
31388
31845
|
if (await this.#writeResolutionError(request, location)) return;
|
|
31389
31846
|
if (location.kind === "external") {
|
|
@@ -31393,10 +31850,30 @@ var AppServerHost = class {
|
|
|
31393
31850
|
return;
|
|
31394
31851
|
}
|
|
31395
31852
|
}
|
|
31396
|
-
await this.#forwardOfficialRequest(
|
|
31853
|
+
await this.#forwardOfficialRequest(
|
|
31854
|
+
request,
|
|
31855
|
+
await this.#rewriteOfficialDelegationMentions(request, frame)
|
|
31856
|
+
);
|
|
31857
|
+
}
|
|
31858
|
+
/** Native Codex Turns: turn `#` delegation chips into an explicit Skill-backed request. */
|
|
31859
|
+
async #rewriteOfficialDelegationMentions(request, frame) {
|
|
31860
|
+
if (request.method !== "turn/start" && request.method !== "turn/steer") return frame;
|
|
31861
|
+
if (!isRecord15(request.params) || !Array.isArray(request.params.input)) return frame;
|
|
31862
|
+
const input = request.params.input;
|
|
31863
|
+
if (!input.some(
|
|
31864
|
+
(item) => isRecord15(item) && typeof item.text === "string" && item.text.includes(DELEGATION_MENTION_PATH_PREFIX)
|
|
31865
|
+
)) {
|
|
31866
|
+
return frame;
|
|
31867
|
+
}
|
|
31868
|
+
const rewritten = rewriteDelegationMentionInput(input, await managedDelegationSkillReference());
|
|
31869
|
+
if (!rewritten) return frame;
|
|
31870
|
+
return encodeJsonFrame({
|
|
31871
|
+
...request,
|
|
31872
|
+
params: { ...request.params, input: rewritten }
|
|
31873
|
+
});
|
|
31397
31874
|
}
|
|
31398
31875
|
async #forwardOfficialNonRequest(value2, frame) {
|
|
31399
|
-
const response =
|
|
31876
|
+
const response = isRecord15(value2) ? value2 : null;
|
|
31400
31877
|
const request = response && (typeof response.id === "string" || typeof response.id === "number") ? this.#officialServerRequests.get(response.id) : null;
|
|
31401
31878
|
if (request !== void 0 && response) {
|
|
31402
31879
|
this.#officialServerRequests.delete(response.id);
|
|
@@ -31425,7 +31902,7 @@ var AppServerHost = class {
|
|
|
31425
31902
|
const parsed = input.value;
|
|
31426
31903
|
this.#observeOfficialTurnStartResponse(parsed);
|
|
31427
31904
|
let forwarded = parsed;
|
|
31428
|
-
if (
|
|
31905
|
+
if (isRecord15(parsed) && typeof parsed.method === "string" && "id" in parsed) {
|
|
31429
31906
|
const originalId = parsed.id;
|
|
31430
31907
|
if (typeof originalId === "string" || typeof originalId === "number") {
|
|
31431
31908
|
const forwardedId = `codexhost:official:${++this.#nextOfficialServerRequestId}`;
|
|
@@ -31433,7 +31910,7 @@ var AppServerHost = class {
|
|
|
31433
31910
|
forwarded = { ...parsed, id: forwardedId };
|
|
31434
31911
|
}
|
|
31435
31912
|
}
|
|
31436
|
-
const accountScopedNotification =
|
|
31913
|
+
const accountScopedNotification = isRecord15(parsed) && typeof parsed.method === "string" && (parsed.method === "account/updated" || parsed.method.startsWith("account/rateLimits/"));
|
|
31437
31914
|
if (accountScopedNotification) {
|
|
31438
31915
|
if (parsed.method === "account/updated") this.#officialRateLimits.reset(input.accountId);
|
|
31439
31916
|
}
|
|
@@ -31534,10 +32011,10 @@ var AppServerHost = class {
|
|
|
31534
32011
|
}
|
|
31535
32012
|
}
|
|
31536
32013
|
async #observeOfficialTurnLifecycle(value2) {
|
|
31537
|
-
if (!
|
|
32014
|
+
if (!isRecord15(value2) || !isRecord15(value2.params)) return;
|
|
31538
32015
|
const params = value2.params;
|
|
31539
32016
|
if (value2.method === "turn/started" && typeof params.threadId === "string") {
|
|
31540
|
-
const turn =
|
|
32017
|
+
const turn = isRecord15(params.turn) ? params.turn : null;
|
|
31541
32018
|
if (turn && typeof turn.id === "string") {
|
|
31542
32019
|
this.#forgetPendingOfficialTurnStarts(params.threadId);
|
|
31543
32020
|
this.#activeOfficialTurns.set(params.threadId, turn.id);
|
|
@@ -31550,7 +32027,7 @@ var AppServerHost = class {
|
|
|
31550
32027
|
const delegation = await this.#repository.getDelegationByChild(
|
|
31551
32028
|
hostThreadIdSchema.parse(params.threadId)
|
|
31552
32029
|
);
|
|
31553
|
-
const turn =
|
|
32030
|
+
const turn = isRecord15(params.turn) ? params.turn : null;
|
|
31554
32031
|
const status = turn?.status === "failed" ? "failed" : turn?.status === "interrupted" || turn?.status === "cancelled" ? "interrupted" : "completed";
|
|
31555
32032
|
if (this.#pendingOfficialDelegationThreads.has(params.threadId)) {
|
|
31556
32033
|
this.#pendingOfficialTerminalStatuses.set(params.threadId, status);
|
|
@@ -31580,28 +32057,28 @@ var AppServerHost = class {
|
|
|
31580
32057
|
}
|
|
31581
32058
|
async #readOfficialThreadCwd(threadId2) {
|
|
31582
32059
|
const response = await this.#requestOfficial("thread/read", { threadId: threadId2 });
|
|
31583
|
-
if (
|
|
31584
|
-
const result =
|
|
31585
|
-
const thread = result &&
|
|
32060
|
+
if (isRecord15(response.error)) return void 0;
|
|
32061
|
+
const result = isRecord15(response.result) ? response.result : null;
|
|
32062
|
+
const thread = result && isRecord15(result.thread) ? result.thread : null;
|
|
31586
32063
|
return thread && typeof thread.cwd === "string" && thread.cwd.trim() ? thread.cwd : void 0;
|
|
31587
32064
|
}
|
|
31588
32065
|
async #inspectOfficialDelegationTarget(input) {
|
|
31589
32066
|
const response = await this.#requestOfficial("model/list", {});
|
|
31590
|
-
if (
|
|
32067
|
+
if (isRecord15(response.error)) {
|
|
31591
32068
|
throw new DelegationControlError(
|
|
31592
32069
|
"DELEGATION_FAILED",
|
|
31593
32070
|
typeof response.error.message === "string" ? response.error.message : "Official Model catalog could not be read"
|
|
31594
32071
|
);
|
|
31595
32072
|
}
|
|
31596
|
-
const result =
|
|
32073
|
+
const result = isRecord15(response.result) ? response.result : null;
|
|
31597
32074
|
const data = result && Array.isArray(result.data) ? result.data : [];
|
|
31598
32075
|
const thinkingById = /* @__PURE__ */ new Map();
|
|
31599
32076
|
const models = data.flatMap((candidate) => {
|
|
31600
|
-
if (!
|
|
32077
|
+
if (!isRecord15(candidate) || typeof candidate.model !== "string" || !candidate.model.trim()) {
|
|
31601
32078
|
return [];
|
|
31602
32079
|
}
|
|
31603
32080
|
const supportedThinkingOptionIds = Array.isArray(candidate.supportedReasoningEfforts) ? candidate.supportedReasoningEfforts.flatMap((option) => {
|
|
31604
|
-
if (!
|
|
32081
|
+
if (!isRecord15(option) || typeof option.reasoningEffort !== "string" || !option.reasoningEffort.trim()) {
|
|
31605
32082
|
return [];
|
|
31606
32083
|
}
|
|
31607
32084
|
const id2 = harnessThinkingOptionIdSchema.safeParse(option.reasoningEffort);
|
|
@@ -31621,9 +32098,9 @@ var AppServerHost = class {
|
|
|
31621
32098
|
];
|
|
31622
32099
|
});
|
|
31623
32100
|
const defaultEntry = data.find(
|
|
31624
|
-
(candidate) =>
|
|
32101
|
+
(candidate) => isRecord15(candidate) && candidate.isDefault === true
|
|
31625
32102
|
);
|
|
31626
|
-
const defaultModel =
|
|
32103
|
+
const defaultModel = isRecord15(defaultEntry) && typeof defaultEntry.model === "string" ? encodeOfficialCodexModelRef(defaultEntry.model) : void 0;
|
|
31627
32104
|
return {
|
|
31628
32105
|
harnessId: input.harnessId,
|
|
31629
32106
|
inspection: {
|
|
@@ -31653,7 +32130,7 @@ var AppServerHost = class {
|
|
|
31653
32130
|
throw new DelegationControlError("INVALID_ARGUMENT", "Official Model Ref is invalid");
|
|
31654
32131
|
}
|
|
31655
32132
|
const nativeModelId = requestedModel ? decodeOfficialCodexModelRef(requestedModel) : void 0;
|
|
31656
|
-
const digest2 =
|
|
32133
|
+
const digest2 = createHash8("sha256").update(
|
|
31657
32134
|
JSON.stringify({
|
|
31658
32135
|
task: input.task,
|
|
31659
32136
|
cwd: input.cwd,
|
|
@@ -31729,8 +32206,8 @@ var AppServerHost = class {
|
|
|
31729
32206
|
ephemeral: false,
|
|
31730
32207
|
historyMode: "paginated"
|
|
31731
32208
|
});
|
|
31732
|
-
const startedResult =
|
|
31733
|
-
const thread = startedResult &&
|
|
32209
|
+
const startedResult = isRecord15(started.result) ? started.result : null;
|
|
32210
|
+
const thread = startedResult && isRecord15(startedResult.thread) ? startedResult.thread : null;
|
|
31734
32211
|
const threadId2 = thread && typeof thread.id === "string" ? thread.id : null;
|
|
31735
32212
|
if (!threadId2) throw new Error("Official thread/start returned no Thread identity");
|
|
31736
32213
|
this.#pendingOfficialDelegationThreads.add(threadId2);
|
|
@@ -31742,8 +32219,8 @@ var AppServerHost = class {
|
|
|
31742
32219
|
...nativeModelId ? { model: nativeModelId } : {},
|
|
31743
32220
|
...input.thinkingOptionId ? { effort: input.thinkingOptionId } : {}
|
|
31744
32221
|
});
|
|
31745
|
-
const turnResult =
|
|
31746
|
-
const turnValue = turnResult &&
|
|
32222
|
+
const turnResult = isRecord15(turn.result) ? turn.result : null;
|
|
32223
|
+
const turnValue = turnResult && isRecord15(turnResult.turn) ? turnResult.turn : null;
|
|
31747
32224
|
const parsedTurnId = turnValue && typeof turnValue.id === "string" ? turnValue.id : null;
|
|
31748
32225
|
if (!parsedTurnId) throw new Error("Official turn/start returned no Turn identity");
|
|
31749
32226
|
turnId = parsedTurnId;
|
|
@@ -31754,7 +32231,7 @@ var AppServerHost = class {
|
|
|
31754
32231
|
throw error51;
|
|
31755
32232
|
}
|
|
31756
32233
|
this.#activeOfficialTurns.set(threadId2, turnId);
|
|
31757
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
32234
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID10());
|
|
31758
32235
|
try {
|
|
31759
32236
|
const source = await this.#repository.find(input.parentThreadId);
|
|
31760
32237
|
const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId2);
|
|
@@ -31813,27 +32290,27 @@ var AppServerHost = class {
|
|
|
31813
32290
|
threadId: input.threadId,
|
|
31814
32291
|
includeTurns: true
|
|
31815
32292
|
});
|
|
31816
|
-
if (
|
|
32293
|
+
if (isRecord15(current.error) || !isRecord15(current.result)) {
|
|
31817
32294
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31818
32295
|
}
|
|
31819
|
-
const currentThread =
|
|
32296
|
+
const currentThread = isRecord15(current.result.thread) ? current.result.thread : null;
|
|
31820
32297
|
const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
|
|
31821
32298
|
const latestTurn = currentTurns.at(-1);
|
|
31822
|
-
if (currentThread &&
|
|
32299
|
+
if (currentThread && isRecord15(currentThread.status) && currentThread.status.type === "active" || isRecord15(latestTurn) && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
|
|
31823
32300
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
31824
32301
|
}
|
|
31825
32302
|
const response = await this.#requestOfficial("turn/start", {
|
|
31826
32303
|
threadId: input.threadId,
|
|
31827
32304
|
input: [{ type: "text", text: input.message }]
|
|
31828
32305
|
});
|
|
31829
|
-
if (
|
|
32306
|
+
if (isRecord15(response.error)) {
|
|
31830
32307
|
throw new DelegationControlError(
|
|
31831
32308
|
"DELEGATION_FAILED",
|
|
31832
32309
|
typeof response.error.message === "string" ? response.error.message : "Turn start failed"
|
|
31833
32310
|
);
|
|
31834
32311
|
}
|
|
31835
|
-
const result =
|
|
31836
|
-
const turn = result &&
|
|
32312
|
+
const result = isRecord15(response.result) ? response.result : null;
|
|
32313
|
+
const turn = result && isRecord15(result.turn) ? result.turn : null;
|
|
31837
32314
|
const turnId = turn && typeof turn.id === "string" ? turn.id : null;
|
|
31838
32315
|
if (!turnId) throw new Error("Official turn/start returned no Turn identity");
|
|
31839
32316
|
this.#activeOfficialTurns.set(input.threadId, turnId);
|
|
@@ -31855,13 +32332,13 @@ var AppServerHost = class {
|
|
|
31855
32332
|
threadId: input.threadId,
|
|
31856
32333
|
includeTurns: true
|
|
31857
32334
|
});
|
|
31858
|
-
if (
|
|
32335
|
+
if (isRecord15(current.error) || !isRecord15(current.result)) {
|
|
31859
32336
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31860
32337
|
}
|
|
31861
|
-
const currentThread =
|
|
32338
|
+
const currentThread = isRecord15(current.result.thread) ? current.result.thread : null;
|
|
31862
32339
|
const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
|
|
31863
32340
|
const latestTurn = currentTurns.at(-1);
|
|
31864
|
-
if (
|
|
32341
|
+
if (isRecord15(latestTurn) && typeof latestTurn.id === "string" && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
|
|
31865
32342
|
turnId = latestTurn.id;
|
|
31866
32343
|
this.#activeOfficialTurns.set(input.threadId, turnId);
|
|
31867
32344
|
} else {
|
|
@@ -31872,7 +32349,7 @@ var AppServerHost = class {
|
|
|
31872
32349
|
threadId: input.threadId,
|
|
31873
32350
|
turnId
|
|
31874
32351
|
});
|
|
31875
|
-
if (
|
|
32352
|
+
if (isRecord15(response.error)) {
|
|
31876
32353
|
throw new DelegationControlError(
|
|
31877
32354
|
"DELEGATION_FAILED",
|
|
31878
32355
|
typeof response.error.message === "string" ? response.error.message : "Turn cancel failed"
|
|
@@ -31885,18 +32362,18 @@ var AppServerHost = class {
|
|
|
31885
32362
|
threadId: input.threadId,
|
|
31886
32363
|
includeTurns: true
|
|
31887
32364
|
});
|
|
31888
|
-
if (
|
|
32365
|
+
if (isRecord15(response.error)) {
|
|
31889
32366
|
throw new DelegationControlError(
|
|
31890
32367
|
"THREAD_NOT_FOUND",
|
|
31891
32368
|
typeof response.error.message === "string" ? response.error.message : "Official Thread was not found"
|
|
31892
32369
|
);
|
|
31893
32370
|
}
|
|
31894
|
-
const result =
|
|
31895
|
-
const thread = result &&
|
|
32371
|
+
const result = isRecord15(response.result) ? response.result : null;
|
|
32372
|
+
const thread = result && isRecord15(result.thread) ? result.thread : null;
|
|
31896
32373
|
if (!thread)
|
|
31897
32374
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31898
|
-
const turns = Array.isArray(thread.turns) ? thread.turns.filter((turn) =>
|
|
31899
|
-
const running = this.#activeOfficialTurns.has(input.threadId) ||
|
|
32375
|
+
const turns = Array.isArray(thread.turns) ? thread.turns.filter((turn) => isRecord15(turn)) : [];
|
|
32376
|
+
const running = this.#activeOfficialTurns.has(input.threadId) || isRecord15(thread.status) && thread.status.type === "active";
|
|
31900
32377
|
const snapshot = projectDelegationThreadSnapshot({
|
|
31901
32378
|
threadId: input.threadId,
|
|
31902
32379
|
harnessId: "codex",
|
|
@@ -31918,7 +32395,7 @@ var AppServerHost = class {
|
|
|
31918
32395
|
async #listDelegationThreads(input) {
|
|
31919
32396
|
const [sortKey, sortDirection2] = input.sort.split("-");
|
|
31920
32397
|
const request = {
|
|
31921
|
-
id: `codexhost:delegation-list:${
|
|
32398
|
+
id: `codexhost:delegation-list:${randomUUID10()}`,
|
|
31922
32399
|
method: "thread/list",
|
|
31923
32400
|
params: {
|
|
31924
32401
|
cwd: input.cwd ? [input.cwd] : null,
|
|
@@ -31946,7 +32423,7 @@ var AppServerHost = class {
|
|
|
31946
32423
|
threads: result.data.flatMap((entry) => {
|
|
31947
32424
|
if (typeof entry.id !== "string") return [];
|
|
31948
32425
|
const record3 = records.find((candidate) => candidate.hostThreadId === entry.id);
|
|
31949
|
-
const status =
|
|
32426
|
+
const status = isRecord15(entry.status) && entry.status.type === "active" ? "running" : "completed";
|
|
31950
32427
|
return [
|
|
31951
32428
|
{
|
|
31952
32429
|
threadId: entry.id,
|
|
@@ -32304,21 +32781,67 @@ var AppServerHost = class {
|
|
|
32304
32781
|
await this.#writer.json(rpcEnvelope(request, { result: { commands: [] } }));
|
|
32305
32782
|
return;
|
|
32306
32783
|
}
|
|
32307
|
-
|
|
32784
|
+
const loaded = this.#externalRuntime.get(params.data.threadId);
|
|
32785
|
+
if (loaded) {
|
|
32786
|
+
const catalog = await this.#inspectLoadedCommands(loaded);
|
|
32787
|
+
if (catalog) {
|
|
32788
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(catalog) }));
|
|
32789
|
+
return;
|
|
32790
|
+
}
|
|
32791
|
+
}
|
|
32792
|
+
await this.#writeHarnessCommandCatalog(
|
|
32793
|
+
request,
|
|
32794
|
+
location.record.harnessId,
|
|
32795
|
+
loaded?.cwd ?? location.record.cwd,
|
|
32796
|
+
params.data.threadId
|
|
32797
|
+
);
|
|
32308
32798
|
}
|
|
32309
|
-
|
|
32799
|
+
/**
|
|
32800
|
+
* Catalog of a loaded Session, marked live or static. A live catalog is
|
|
32801
|
+
* remembered for its Harness and workspace so later drafts there can show it.
|
|
32802
|
+
*/
|
|
32803
|
+
async #inspectLoadedCommands(thread) {
|
|
32804
|
+
if (!thread.session.commands) return null;
|
|
32805
|
+
const catalog = await inspectLiveCommandCatalog(thread.session.commands);
|
|
32806
|
+
if (!catalog) return null;
|
|
32807
|
+
const staticCatalog = this.#externalAdapters.get(thread.harnessId)?.commandCatalog;
|
|
32808
|
+
if (staticCatalog && !isLiveCommandCatalog(catalog, staticCatalog)) return null;
|
|
32809
|
+
const live = { ...catalog, source: "live" };
|
|
32810
|
+
this.#liveCommandCache.remember(thread.harnessId, thread.cwd, live);
|
|
32811
|
+
return live;
|
|
32812
|
+
}
|
|
32813
|
+
async #writeHarnessCommandCatalog(request, harnessId, cwd, inspectedThreadId) {
|
|
32310
32814
|
await this.#waitForPlugins();
|
|
32311
32815
|
const adapter = this.#externalAdapters.get(harnessId);
|
|
32312
32816
|
if (!adapter) {
|
|
32313
32817
|
await this.#writer.json(rpcError(request, -32077, `Harness '${harnessId}' is unavailable`));
|
|
32314
32818
|
return;
|
|
32315
32819
|
}
|
|
32820
|
+
let catalog;
|
|
32316
32821
|
try {
|
|
32317
|
-
|
|
32318
|
-
|
|
32822
|
+
catalog = harnessCommandCatalogSchema.parse({
|
|
32823
|
+
...adapter.commandCatalog ?? { commands: [] },
|
|
32824
|
+
...adapter.liveCommandCatalog ? { source: "static" } : {}
|
|
32825
|
+
});
|
|
32319
32826
|
} catch {
|
|
32320
32827
|
await this.#writer.json(rpcError(request, -32078, "Harness command catalog is invalid"));
|
|
32828
|
+
return;
|
|
32321
32829
|
}
|
|
32830
|
+
if (cwd && adapter.liveCommandCatalog) {
|
|
32831
|
+
for (const thread of this.#externalRuntime.values()) {
|
|
32832
|
+
if (thread.id === inspectedThreadId) continue;
|
|
32833
|
+
if (thread.harnessId !== harnessId || !sameWorkspace(thread.cwd, cwd)) continue;
|
|
32834
|
+
const live = await this.#inspectLoadedCommands(thread);
|
|
32835
|
+
if (live) {
|
|
32836
|
+
catalog = live;
|
|
32837
|
+
break;
|
|
32838
|
+
}
|
|
32839
|
+
}
|
|
32840
|
+
if (catalog.source === "static") {
|
|
32841
|
+
catalog = this.#liveCommandCache.lookup(harnessId, cwd) ?? catalog;
|
|
32842
|
+
}
|
|
32843
|
+
}
|
|
32844
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(catalog) }));
|
|
32322
32845
|
}
|
|
32323
32846
|
async #executeThreadCommand(request) {
|
|
32324
32847
|
const params = threadCommandExecuteParamsSchema.safeParse(request.params);
|
|
@@ -32370,39 +32893,43 @@ var AppServerHost = class {
|
|
|
32370
32893
|
return;
|
|
32371
32894
|
}
|
|
32372
32895
|
try {
|
|
32373
|
-
await this.#
|
|
32374
|
-
request,
|
|
32896
|
+
const started = await this.#beginExternalCommand(
|
|
32375
32897
|
thread,
|
|
32376
32898
|
params.commandId,
|
|
32377
32899
|
params.arguments,
|
|
32378
|
-
params.turnId
|
|
32379
|
-
"command"
|
|
32900
|
+
params.turnId
|
|
32380
32901
|
);
|
|
32902
|
+
try {
|
|
32903
|
+
const result = threadCommandExecuteResultSchema.parse({
|
|
32904
|
+
accepted: true,
|
|
32905
|
+
turnId: started.turnId
|
|
32906
|
+
});
|
|
32907
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
|
|
32908
|
+
} finally {
|
|
32909
|
+
started.gate.resolve();
|
|
32910
|
+
}
|
|
32381
32911
|
} catch (error51) {
|
|
32382
32912
|
this.#diagnose(error51);
|
|
32383
32913
|
await this.#writer.json(
|
|
32384
|
-
rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
|
|
32914
|
+
error51 instanceof ExternalCommandError ? rpcError(request, error51.code, error51.message) : rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
|
|
32385
32915
|
);
|
|
32386
32916
|
}
|
|
32387
32917
|
} finally {
|
|
32388
32918
|
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
32389
32919
|
}
|
|
32390
32920
|
}
|
|
32391
|
-
async #
|
|
32921
|
+
async #beginExternalCommand(thread, commandId, arguments_2, requestedTurnId) {
|
|
32392
32922
|
const commands = thread.session.commands;
|
|
32393
32923
|
if (!commands) {
|
|
32394
|
-
|
|
32395
|
-
rpcError(request, -32078, "External Harness does not expose commands")
|
|
32396
|
-
);
|
|
32397
|
-
return;
|
|
32924
|
+
throw new ExternalCommandError(-32078, "External Harness does not expose commands");
|
|
32398
32925
|
}
|
|
32399
|
-
if (
|
|
32400
|
-
|
|
32401
|
-
|
|
32402
|
-
|
|
32403
|
-
|
|
32926
|
+
if (this.#closeRequested || this.#externalRuntime.get(thread.id) !== thread) {
|
|
32927
|
+
throw new ExternalCommandError(-32073, "External Thread is no longer available");
|
|
32928
|
+
}
|
|
32929
|
+
if (thread.running || thread.activeTurnId) {
|
|
32930
|
+
throw new ExternalCommandError(-32072, "External Thread already has an active operation");
|
|
32404
32931
|
}
|
|
32405
|
-
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(
|
|
32932
|
+
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID10());
|
|
32406
32933
|
const projection = {
|
|
32407
32934
|
projector: new CodexTurnProjector({
|
|
32408
32935
|
threadId: thread.id,
|
|
@@ -32417,13 +32944,14 @@ var AppServerHost = class {
|
|
|
32417
32944
|
thread.projectedTurns.set(turnId, projection);
|
|
32418
32945
|
thread.responseGates.set(turnId, gate);
|
|
32419
32946
|
thread.ephemeralTurnIds.add(turnId);
|
|
32420
|
-
let result;
|
|
32421
32947
|
try {
|
|
32422
|
-
result = await commands.execute({
|
|
32948
|
+
const result = await commands.execute({
|
|
32423
32949
|
turnId,
|
|
32424
32950
|
commandId,
|
|
32425
32951
|
...arguments_2 ? { arguments: arguments_2 } : {}
|
|
32426
32952
|
});
|
|
32953
|
+
if (!result.ok) throw new ExternalCommandError(-32073, result.error.message);
|
|
32954
|
+
return { turnId: result.value.turnId, turn: projection.projector.pendingTurn(), gate };
|
|
32427
32955
|
} catch (error51) {
|
|
32428
32956
|
thread.running = false;
|
|
32429
32957
|
thread.activeTurnId = null;
|
|
@@ -32434,28 +32962,6 @@ var AppServerHost = class {
|
|
|
32434
32962
|
this.#signalActiveWorkChanged();
|
|
32435
32963
|
throw error51;
|
|
32436
32964
|
}
|
|
32437
|
-
if (!result.ok) {
|
|
32438
|
-
thread.running = false;
|
|
32439
|
-
thread.activeTurnId = null;
|
|
32440
|
-
thread.projectedTurns.delete(turnId);
|
|
32441
|
-
thread.responseGates.delete(turnId);
|
|
32442
|
-
thread.ephemeralTurnIds.delete(turnId);
|
|
32443
|
-
gate.resolve();
|
|
32444
|
-
this.#signalActiveWorkChanged();
|
|
32445
|
-
await this.#writer.json(rpcError(request, -32073, result.error.message));
|
|
32446
|
-
return;
|
|
32447
|
-
}
|
|
32448
|
-
try {
|
|
32449
|
-
const response = responseKind === "command" ? jsonValueSchema.parse(
|
|
32450
|
-
threadCommandExecuteResultSchema.parse({
|
|
32451
|
-
accepted: true,
|
|
32452
|
-
turnId: result.value.turnId
|
|
32453
|
-
})
|
|
32454
|
-
) : { turn: projection.projector.pendingTurn() };
|
|
32455
|
-
await this.#writer.json(rpcEnvelope(request, { result: response }));
|
|
32456
|
-
} finally {
|
|
32457
|
-
gate.resolve();
|
|
32458
|
-
}
|
|
32459
32965
|
}
|
|
32460
32966
|
async #selectThreadModel(request) {
|
|
32461
32967
|
const params = threadModelSelectParamsSchema.safeParse(request.params);
|
|
@@ -33078,10 +33584,10 @@ var AppServerHost = class {
|
|
|
33078
33584
|
...typeof params.serviceTier === "string" ? { serviceTier: params.serviceTier } : {}
|
|
33079
33585
|
});
|
|
33080
33586
|
try {
|
|
33081
|
-
if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !
|
|
33587
|
+
if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !isRecord15(params.initialTurnsPage)) {
|
|
33082
33588
|
throw new ExternalHistoryRequestError("initialTurnsPage must be an object");
|
|
33083
33589
|
}
|
|
33084
|
-
const initialPageParams =
|
|
33590
|
+
const initialPageParams = isRecord15(params.initialTurnsPage) ? params.initialTurnsPage : null;
|
|
33085
33591
|
const initialTurnsPage = initialPageParams ? listExternalTurns(turns, initialPageParams) : null;
|
|
33086
33592
|
const paginated = thread.record.historyMode === "paginated";
|
|
33087
33593
|
const turnsBackwardsCursor = paginated ? listExternalTurns(turns, { limit: 1, itemsView: "notLoaded" }).backwardsCursor : null;
|
|
@@ -33176,53 +33682,8 @@ var AppServerHost = class {
|
|
|
33176
33682
|
await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
|
|
33177
33683
|
return;
|
|
33178
33684
|
}
|
|
33179
|
-
const commandCandidate = text2.trimStart();
|
|
33180
|
-
if (thread.session.commands && /^\/[^\s/]+(?:\s|$)/u.test(commandCandidate)) {
|
|
33181
|
-
const commandText = commandCandidate.trimEnd();
|
|
33182
|
-
this.#pendingExternalCommandRequests.add(thread.id);
|
|
33183
|
-
try {
|
|
33184
|
-
const catalog = await thread.session.commands.list();
|
|
33185
|
-
if (!catalog.ok) {
|
|
33186
|
-
await this.#writer.json(rpcError(request, -32073, catalog.error.message));
|
|
33187
|
-
return;
|
|
33188
|
-
}
|
|
33189
|
-
const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
|
|
33190
|
-
if (commandText === command.invocation) return true;
|
|
33191
|
-
return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
|
|
33192
|
-
});
|
|
33193
|
-
if (matched) {
|
|
33194
|
-
const argumentText = commandText.slice(matched.invocation.length).trimStart();
|
|
33195
|
-
try {
|
|
33196
|
-
await this.#startExternalCommand(
|
|
33197
|
-
request,
|
|
33198
|
-
thread,
|
|
33199
|
-
matched.id,
|
|
33200
|
-
argumentText.length > 0 ? { text: argumentText } : void 0,
|
|
33201
|
-
void 0,
|
|
33202
|
-
"turn"
|
|
33203
|
-
);
|
|
33204
|
-
} catch (error51) {
|
|
33205
|
-
this.#diagnose(error51);
|
|
33206
|
-
await this.#writer.json(
|
|
33207
|
-
rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
|
|
33208
|
-
);
|
|
33209
|
-
}
|
|
33210
|
-
return;
|
|
33211
|
-
}
|
|
33212
|
-
await this.#writer.json(
|
|
33213
|
-
rpcError(request, -32078, "External Harness does not expose the requested command")
|
|
33214
|
-
);
|
|
33215
|
-
return;
|
|
33216
|
-
} finally {
|
|
33217
|
-
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
33218
|
-
}
|
|
33219
|
-
}
|
|
33220
|
-
if (this.#externalSteering.hasPending(thread.id)) {
|
|
33221
|
-
await this.#writer.json(rpcError(request, -32072, "External Thread is changing direction"));
|
|
33222
|
-
return;
|
|
33223
|
-
}
|
|
33224
33685
|
try {
|
|
33225
|
-
const started = await this.#
|
|
33686
|
+
const started = await this.#beginExternalInputTurn(thread, text2);
|
|
33226
33687
|
try {
|
|
33227
33688
|
await this.#writer.json(rpcEnvelope(request, { result: { turn: started.turn } }));
|
|
33228
33689
|
} finally {
|
|
@@ -33232,7 +33693,7 @@ var AppServerHost = class {
|
|
|
33232
33693
|
await this.#writer.json(
|
|
33233
33694
|
rpcError(
|
|
33234
33695
|
request,
|
|
33235
|
-
error51 instanceof ExternalSteerError ? error51.code : -32073,
|
|
33696
|
+
error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32073,
|
|
33236
33697
|
errorMessage3(error51)
|
|
33237
33698
|
)
|
|
33238
33699
|
);
|
|
@@ -33243,7 +33704,7 @@ var AppServerHost = class {
|
|
|
33243
33704
|
const started = await this.#externalSteering.run(
|
|
33244
33705
|
thread,
|
|
33245
33706
|
requestObject(request),
|
|
33246
|
-
(text2) => this.#
|
|
33707
|
+
(text2, assertActive) => this.#beginExternalInputTurn(thread, text2, assertActive)
|
|
33247
33708
|
);
|
|
33248
33709
|
try {
|
|
33249
33710
|
await this.#writer.json(rpcEnvelope(request, { result: { turnId: started.turnId } }));
|
|
@@ -33254,7 +33715,7 @@ var AppServerHost = class {
|
|
|
33254
33715
|
await this.#writer.json(
|
|
33255
33716
|
rpcError(
|
|
33256
33717
|
request,
|
|
33257
|
-
error51 instanceof ExternalSteerError ? error51.code : -32074,
|
|
33718
|
+
error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32074,
|
|
33258
33719
|
errorMessage3(error51)
|
|
33259
33720
|
)
|
|
33260
33721
|
);
|
|
@@ -33262,6 +33723,37 @@ var AppServerHost = class {
|
|
|
33262
33723
|
this.#signalActiveWorkChanged();
|
|
33263
33724
|
}
|
|
33264
33725
|
}
|
|
33726
|
+
/** Keep command restoration and dispatch identical for start and steer submissions. */
|
|
33727
|
+
async #beginExternalInputTurn(thread, inputText, assertActive) {
|
|
33728
|
+
const text2 = restoreHarnessCommandMentions(inputText);
|
|
33729
|
+
const commands = thread.session.commands;
|
|
33730
|
+
if (!commands || !isExternalCommandCandidate(text2)) {
|
|
33731
|
+
assertActive?.();
|
|
33732
|
+
return this.#beginExternalTurn(thread, text2);
|
|
33733
|
+
}
|
|
33734
|
+
this.#pendingExternalCommandRequests.add(thread.id);
|
|
33735
|
+
try {
|
|
33736
|
+
const adapter = this.#externalAdapters.get(thread.harnessId);
|
|
33737
|
+
const command = await resolveExternalCommand(commands, text2, {
|
|
33738
|
+
liveCatalogPending: (catalog) => adapter?.liveCommandCatalog === true && !isLiveCommandCatalog(catalog, adapter.commandCatalog ?? { commands: [] })
|
|
33739
|
+
});
|
|
33740
|
+
assertActive?.();
|
|
33741
|
+
if (!command) {
|
|
33742
|
+
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
33743
|
+
return await this.#beginExternalTurn(thread, text2);
|
|
33744
|
+
}
|
|
33745
|
+
return await this.#beginExternalCommand(thread, command.commandId, command.arguments);
|
|
33746
|
+
} catch (error51) {
|
|
33747
|
+
if (error51 instanceof ExternalCommandError || error51 instanceof ExternalSteerError) throw error51;
|
|
33748
|
+
this.#diagnose(error51);
|
|
33749
|
+
throw new ExternalCommandError(
|
|
33750
|
+
-32073,
|
|
33751
|
+
`External Harness command failed: ${errorMessage3(error51)}`
|
|
33752
|
+
);
|
|
33753
|
+
} finally {
|
|
33754
|
+
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
33755
|
+
}
|
|
33756
|
+
}
|
|
33265
33757
|
async #beginExternalTurn(thread, text2) {
|
|
33266
33758
|
if (this.#closeRequested || this.#externalRuntime.get(thread.id) !== thread) {
|
|
33267
33759
|
throw new ExternalSteerError(-32073, "External Thread is no longer available");
|
|
@@ -33269,7 +33761,7 @@ var AppServerHost = class {
|
|
|
33269
33761
|
if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
|
|
33270
33762
|
throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
|
|
33271
33763
|
}
|
|
33272
|
-
const turnId = hostTurnIdSchema.parse(
|
|
33764
|
+
const turnId = hostTurnIdSchema.parse(randomUUID10());
|
|
33273
33765
|
const startedAtMs = Date.now();
|
|
33274
33766
|
const projection = {
|
|
33275
33767
|
projector: new CodexTurnProjector({
|
|
@@ -33288,7 +33780,7 @@ var AppServerHost = class {
|
|
|
33288
33780
|
const result = await thread.session.execute({
|
|
33289
33781
|
type: "turn.start",
|
|
33290
33782
|
turnId,
|
|
33291
|
-
input: [{ type: "text", text: text2 }]
|
|
33783
|
+
input: [{ type: "text", text: rewriteDelegationMentionText(text2) }]
|
|
33292
33784
|
});
|
|
33293
33785
|
if (!result.ok) throw new ExternalSteerError(-32073, result.error.message);
|
|
33294
33786
|
return { turnId, turn: projection.projector.pendingTurn(), gate };
|
|
@@ -33670,7 +34162,7 @@ var AppServerHost = class {
|
|
|
33670
34162
|
const previousItems = new Map(
|
|
33671
34163
|
child.turns.flatMap(
|
|
33672
34164
|
(turn) => Array.isArray(turn.items) ? turn.items.flatMap(
|
|
33673
|
-
(item) =>
|
|
34165
|
+
(item) => isRecord15(item) && typeof item.id === "string" ? [[item.id, JSON.stringify(item)]] : []
|
|
33674
34166
|
) : []
|
|
33675
34167
|
)
|
|
33676
34168
|
);
|
|
@@ -33683,7 +34175,7 @@ var AppServerHost = class {
|
|
|
33683
34175
|
for (const turn of child.turns) {
|
|
33684
34176
|
if (typeof turn.id !== "string" || !Array.isArray(turn.items)) continue;
|
|
33685
34177
|
const changedItems = turn.items.filter(
|
|
33686
|
-
(item) =>
|
|
34178
|
+
(item) => isRecord15(item) && typeof item.id === "string" && previousItems.get(item.id) !== JSON.stringify(item)
|
|
33687
34179
|
);
|
|
33688
34180
|
if (changedItems.length > 0) {
|
|
33689
34181
|
await this.#writer.json({
|
|
@@ -33815,7 +34307,7 @@ var AppServerHost = class {
|
|
|
33815
34307
|
}
|
|
33816
34308
|
}
|
|
33817
34309
|
async #handleDesktopApprovalResponse(value2) {
|
|
33818
|
-
if (!
|
|
34310
|
+
if (!isRecord15(value2) || !isHostApprovalRequestId(value2.id)) return false;
|
|
33819
34311
|
const requestId = value2.id;
|
|
33820
34312
|
const pending = this.#pendingDesktopApprovals.get(requestId);
|
|
33821
34313
|
if (!pending) return true;
|
|
@@ -33897,7 +34389,7 @@ var AppServerHost = class {
|
|
|
33897
34389
|
try {
|
|
33898
34390
|
result = projection.projector.projectQuestion(
|
|
33899
34391
|
interaction,
|
|
33900
|
-
hostItemIdSchema.parse(
|
|
34392
|
+
hostItemIdSchema.parse(randomUUID10())
|
|
33901
34393
|
);
|
|
33902
34394
|
} catch (error51) {
|
|
33903
34395
|
this.#diagnose(error51);
|
|
@@ -33942,7 +34434,7 @@ var AppServerHost = class {
|
|
|
33942
34434
|
}
|
|
33943
34435
|
}
|
|
33944
34436
|
async #handleDesktopQuestionResponse(value2) {
|
|
33945
|
-
if (!
|
|
34437
|
+
if (!isRecord15(value2) || !isHostQuestionRequestId(value2.id)) return false;
|
|
33946
34438
|
const requestId = value2.id;
|
|
33947
34439
|
const pending = this.#pendingDesktopQuestions.get(requestId);
|
|
33948
34440
|
if (!pending) return true;
|
|
@@ -34063,19 +34555,19 @@ var AppServerHost = class {
|
|
|
34063
34555
|
};
|
|
34064
34556
|
|
|
34065
34557
|
// packages/host-runtime/src/native-account-host.ts
|
|
34066
|
-
import { mkdir as
|
|
34558
|
+
import { mkdir as mkdir8, realpath as realpath3 } from "node:fs/promises";
|
|
34067
34559
|
import { homedir } from "node:os";
|
|
34068
|
-
import
|
|
34560
|
+
import path20 from "node:path";
|
|
34069
34561
|
|
|
34070
34562
|
// packages/host-runtime/src/codex-runtime/owned-official-backends.ts
|
|
34071
|
-
import { createHash as
|
|
34563
|
+
import { createHash as createHash9, randomBytes } from "node:crypto";
|
|
34072
34564
|
import { Writable as Writable2 } from "node:stream";
|
|
34073
34565
|
|
|
34074
34566
|
// packages/host-runtime/src/remote-app-server.ts
|
|
34075
34567
|
import { createServer } from "node:http";
|
|
34076
34568
|
import net from "node:net";
|
|
34077
|
-
import { chmod as chmod3, lstat as lstat6, mkdir as
|
|
34078
|
-
import
|
|
34569
|
+
import { chmod as chmod3, lstat as lstat6, mkdir as mkdir7, rm as rm7 } from "node:fs/promises";
|
|
34570
|
+
import path18 from "node:path";
|
|
34079
34571
|
import { PassThrough } from "node:stream";
|
|
34080
34572
|
|
|
34081
34573
|
// node_modules/ws/wrapper.mjs
|
|
@@ -34090,10 +34582,10 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
34090
34582
|
var wrapper_default = import_websocket.default;
|
|
34091
34583
|
|
|
34092
34584
|
// packages/host-runtime/src/remote-socket-lock.ts
|
|
34093
|
-
import { randomUUID as
|
|
34094
|
-
import { chmod as chmod2, lstat as lstat5, mkdir as
|
|
34585
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
34586
|
+
import { chmod as chmod2, lstat as lstat5, mkdir as mkdir6, open as open6, readFile as readFile9, readdir as readdir4, rename as rename5, rm as rm6 } from "node:fs/promises";
|
|
34095
34587
|
import { uptime } from "node:os";
|
|
34096
|
-
import
|
|
34588
|
+
import path17 from "node:path";
|
|
34097
34589
|
import { setTimeout as delay4 } from "node:timers/promises";
|
|
34098
34590
|
var LOCK_RETRY_COUNT = 200;
|
|
34099
34591
|
var LOCK_RETRY_DELAY_MS = 25;
|
|
@@ -34156,7 +34648,7 @@ async function readLockEntrySnapshot(filePath) {
|
|
|
34156
34648
|
throw error51;
|
|
34157
34649
|
});
|
|
34158
34650
|
if (metadata === null || !metadata.isFile()) return null;
|
|
34159
|
-
const source = await
|
|
34651
|
+
const source = await readFile9(filePath, "utf8").catch((error51) => {
|
|
34160
34652
|
if (error51.code === "ENOENT") return null;
|
|
34161
34653
|
throw error51;
|
|
34162
34654
|
});
|
|
@@ -34167,7 +34659,7 @@ async function readLockEntrySnapshot(filePath) {
|
|
|
34167
34659
|
source,
|
|
34168
34660
|
identity: { dev: metadata.dev, ino: metadata.ino },
|
|
34169
34661
|
mtimeMs: metadata.mtimeMs,
|
|
34170
|
-
record: record3 &&
|
|
34662
|
+
record: record3 && path17.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
|
|
34171
34663
|
};
|
|
34172
34664
|
}
|
|
34173
34665
|
function lockEntryIsAbandoned(snapshot) {
|
|
@@ -34179,7 +34671,7 @@ async function removeAbandonedLockEntry(snapshot) {
|
|
|
34179
34671
|
if (current === null || current.source !== snapshot.source || !sameUnixFileIdentity(current.identity, snapshot.identity) || !lockEntryIsAbandoned(current)) {
|
|
34180
34672
|
return false;
|
|
34181
34673
|
}
|
|
34182
|
-
await
|
|
34674
|
+
await rm6(snapshot.filePath, { force: true });
|
|
34183
34675
|
return true;
|
|
34184
34676
|
}
|
|
34185
34677
|
async function readLockEntryCatalog(lockDirectory) {
|
|
@@ -34188,7 +34680,7 @@ async function readLockEntryCatalog(lockDirectory) {
|
|
|
34188
34680
|
let unsettled = false;
|
|
34189
34681
|
for (const name of names) {
|
|
34190
34682
|
if (!name.startsWith(LOCK_ENTRY_PREFIX) || !name.endsWith(LOCK_ENTRY_SUFFIX)) continue;
|
|
34191
|
-
const snapshot = await readLockEntrySnapshot(
|
|
34683
|
+
const snapshot = await readLockEntrySnapshot(path17.join(lockDirectory, name));
|
|
34192
34684
|
if (snapshot === null) continue;
|
|
34193
34685
|
if (lockEntryIsAbandoned(snapshot)) {
|
|
34194
34686
|
if (!await removeAbandonedLockEntry(snapshot)) unsettled = true;
|
|
@@ -34203,7 +34695,7 @@ async function readLockEntryCatalog(lockDirectory) {
|
|
|
34203
34695
|
return { entries, unsettled };
|
|
34204
34696
|
}
|
|
34205
34697
|
async function preparePrivateLockDirectory(lockDirectory) {
|
|
34206
|
-
await
|
|
34698
|
+
await mkdir6(lockDirectory, { mode: 448 }).catch((error51) => {
|
|
34207
34699
|
if (error51.code !== "EEXIST") throw error51;
|
|
34208
34700
|
});
|
|
34209
34701
|
const metadata = await lstat5(lockDirectory);
|
|
@@ -34216,8 +34708,8 @@ async function preparePrivateLockDirectory(lockDirectory) {
|
|
|
34216
34708
|
await chmod2(lockDirectory, 448);
|
|
34217
34709
|
}
|
|
34218
34710
|
async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
|
|
34219
|
-
const temporary =
|
|
34220
|
-
const handle = await
|
|
34711
|
+
const temporary = path17.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID11()}`);
|
|
34712
|
+
const handle = await open6(temporary, "wx", 384);
|
|
34221
34713
|
try {
|
|
34222
34714
|
await handle.writeFile(`${JSON.stringify(record3)}
|
|
34223
34715
|
`, "utf8");
|
|
@@ -34226,15 +34718,15 @@ async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
|
|
|
34226
34718
|
await handle.close();
|
|
34227
34719
|
}
|
|
34228
34720
|
try {
|
|
34229
|
-
await
|
|
34721
|
+
await rename5(temporary, entryPath);
|
|
34230
34722
|
} finally {
|
|
34231
|
-
await
|
|
34723
|
+
await rm6(temporary, { force: true });
|
|
34232
34724
|
}
|
|
34233
34725
|
}
|
|
34234
34726
|
async function removeOwnedLockEntry(entryPath, ownerToken) {
|
|
34235
34727
|
const snapshot = await readLockEntrySnapshot(entryPath);
|
|
34236
34728
|
if (snapshot?.record?.ownerToken !== ownerToken) return;
|
|
34237
|
-
await
|
|
34729
|
+
await rm6(entryPath, { force: true });
|
|
34238
34730
|
}
|
|
34239
34731
|
async function legacyLockState(legacyPath) {
|
|
34240
34732
|
const metadata = await lstat5(legacyPath).catch((error51) => {
|
|
@@ -34243,7 +34735,7 @@ async function legacyLockState(legacyPath) {
|
|
|
34243
34735
|
});
|
|
34244
34736
|
if (metadata === null) return "absent";
|
|
34245
34737
|
if (!metadata.isFile()) return "blocking";
|
|
34246
|
-
const source = await
|
|
34738
|
+
const source = await readFile9(legacyPath, "utf8").catch((error51) => {
|
|
34247
34739
|
if (error51.code === "ENOENT") return null;
|
|
34248
34740
|
throw error51;
|
|
34249
34741
|
});
|
|
@@ -34254,7 +34746,7 @@ async function legacyLockState(legacyPath) {
|
|
|
34254
34746
|
return ownerIsAbandoned(record3, metadata.mtimeMs) ? "abandoned" : "blocking";
|
|
34255
34747
|
}
|
|
34256
34748
|
async function tryAcquireLegacyCompatibilityGuard(legacyPath, record3) {
|
|
34257
|
-
const handle = await
|
|
34749
|
+
const handle = await open6(legacyPath, "wx", 384).catch((error51) => {
|
|
34258
34750
|
if (error51.code === "EEXIST") return null;
|
|
34259
34751
|
throw error51;
|
|
34260
34752
|
});
|
|
@@ -34280,7 +34772,7 @@ async function releaseLegacyCompatibilityGuard(legacyPath, guard) {
|
|
|
34280
34772
|
throw error51;
|
|
34281
34773
|
});
|
|
34282
34774
|
if (metadata?.isFile() && sameUnixFileIdentity({ dev: metadata.dev, ino: metadata.ino }, guard.identity)) {
|
|
34283
|
-
await
|
|
34775
|
+
await rm6(legacyPath, { force: true });
|
|
34284
34776
|
}
|
|
34285
34777
|
}
|
|
34286
34778
|
}
|
|
@@ -34291,8 +34783,8 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
|
|
|
34291
34783
|
const legacyPath = `${socketPath}.initializing`;
|
|
34292
34784
|
const lockDirectory = `${socketPath}.initializers`;
|
|
34293
34785
|
await preparePrivateLockDirectory(lockDirectory);
|
|
34294
|
-
const ownerToken =
|
|
34295
|
-
const entryPath =
|
|
34786
|
+
const ownerToken = randomUUID11();
|
|
34787
|
+
const entryPath = path17.join(lockDirectory, lockEntryName(ownerToken));
|
|
34296
34788
|
const baseRecord = {
|
|
34297
34789
|
version: 2,
|
|
34298
34790
|
ownerToken,
|
|
@@ -34466,14 +34958,14 @@ function remoteAppServerSocketPath(environment, listenUrl = "unix://") {
|
|
|
34466
34958
|
throw new Error("Remote app-server listener must use a Unix URL");
|
|
34467
34959
|
}
|
|
34468
34960
|
const explicit = listenUrl.slice("unix://".length);
|
|
34469
|
-
if (explicit.length > 0) return
|
|
34470
|
-
const codexHome = environment.CODEX_HOME ?? (environment.HOME ?
|
|
34961
|
+
if (explicit.length > 0) return path18.posix.resolve(decodeURIComponent(explicit));
|
|
34962
|
+
const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path18.posix.join(environment.HOME, ".codex") : void 0);
|
|
34471
34963
|
if (!codexHome)
|
|
34472
34964
|
throw new Error("CODEX_HOME or HOME is required for the remote app-server socket");
|
|
34473
|
-
return
|
|
34965
|
+
return path18.posix.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
34474
34966
|
}
|
|
34475
34967
|
function officialListenerArgumentsForRemoteListener(arguments_2, socketPath) {
|
|
34476
|
-
if (!
|
|
34968
|
+
if (!path18.posix.isAbsolute(socketPath)) {
|
|
34477
34969
|
throw new Error("Shared official app-server socket path must be absolute");
|
|
34478
34970
|
}
|
|
34479
34971
|
if (remoteUnixListenerUrl(arguments_2) === null) {
|
|
@@ -34581,10 +35073,10 @@ async function removeStaleSocket(socketPath) {
|
|
|
34581
35073
|
});
|
|
34582
35074
|
});
|
|
34583
35075
|
if (active) throw new Error(`Remote app-server socket is already in use at ${socketPath}`);
|
|
34584
|
-
await
|
|
35076
|
+
await rm7(socketPath, { force: true });
|
|
34585
35077
|
}
|
|
34586
35078
|
async function prepareRemoteAppServerSocketDirectory(socketPath) {
|
|
34587
|
-
const socketDirectory =
|
|
35079
|
+
const socketDirectory = path18.dirname(socketPath);
|
|
34588
35080
|
const existing = await lstat6(socketDirectory).catch((error51) => {
|
|
34589
35081
|
if (error51.code === "ENOENT") return null;
|
|
34590
35082
|
throw error51;
|
|
@@ -34598,7 +35090,7 @@ async function prepareRemoteAppServerSocketDirectory(socketPath) {
|
|
|
34598
35090
|
);
|
|
34599
35091
|
}
|
|
34600
35092
|
}
|
|
34601
|
-
await
|
|
35093
|
+
await mkdir7(socketDirectory, { recursive: true, mode: 448 });
|
|
34602
35094
|
await chmod3(socketDirectory, 448);
|
|
34603
35095
|
}
|
|
34604
35096
|
function sendOutputFrames(socket, output) {
|
|
@@ -34771,7 +35263,7 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
34771
35263
|
if (ownedSocketIdentity) {
|
|
34772
35264
|
const current = await unixSocketIdentity(input.socketPath);
|
|
34773
35265
|
if (current && sameUnixFileIdentity2(current, ownedSocketIdentity)) {
|
|
34774
|
-
await
|
|
35266
|
+
await rm7(input.socketPath, { force: true });
|
|
34775
35267
|
}
|
|
34776
35268
|
ownedSocketIdentity = null;
|
|
34777
35269
|
}
|
|
@@ -34789,39 +35281,57 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
34789
35281
|
|
|
34790
35282
|
// packages/host-runtime/src/remote-official-app-server.ts
|
|
34791
35283
|
import { spawn as spawn3 } from "node:child_process";
|
|
34792
|
-
import { randomUUID as
|
|
34793
|
-
import { lstat as lstat7, rm as
|
|
34794
|
-
import
|
|
35284
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
35285
|
+
import { lstat as lstat7, rm as rm8, stat as stat5 } from "node:fs/promises";
|
|
35286
|
+
import path19 from "node:path";
|
|
34795
35287
|
var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
|
|
34796
35288
|
var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
|
|
34797
|
-
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token =
|
|
34798
|
-
if (!
|
|
35289
|
+
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID12()) {
|
|
35290
|
+
if (!path19.posix.isAbsolute(desktopControlSocketPath)) {
|
|
34799
35291
|
throw new Error("Desktop control socket path must be absolute");
|
|
34800
35292
|
}
|
|
34801
35293
|
if (!/^[A-Za-z0-9-]+$/u.test(token) || !/[A-Za-z0-9]/u.test(token)) {
|
|
34802
35294
|
throw new Error("Shared official app-server socket token is invalid");
|
|
34803
35295
|
}
|
|
34804
35296
|
const compactToken = token.replaceAll("-", "").slice(0, 15);
|
|
34805
|
-
return
|
|
35297
|
+
return path19.posix.join(path19.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
|
|
34806
35298
|
}
|
|
34807
35299
|
function errorMessage4(error51) {
|
|
34808
35300
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
34809
35301
|
}
|
|
34810
|
-
async function
|
|
35302
|
+
async function inspectSocket(socketPath) {
|
|
34811
35303
|
const metadata = await lstat7(socketPath).catch((error51) => {
|
|
34812
35304
|
if (error51.code === "ENOENT") return null;
|
|
34813
35305
|
throw error51;
|
|
34814
35306
|
});
|
|
34815
35307
|
if (metadata === null) return null;
|
|
34816
|
-
|
|
35308
|
+
const identity = { dev: metadata.dev, ino: metadata.ino };
|
|
35309
|
+
if (metadata.isSymbolicLink()) {
|
|
35310
|
+
const uid = process.getuid?.();
|
|
35311
|
+
if (uid === void 0 || metadata.uid !== uid) {
|
|
35312
|
+
throw new Error(
|
|
35313
|
+
`Shared official app-server link must belong to the current user: ${socketPath}`
|
|
35314
|
+
);
|
|
35315
|
+
}
|
|
35316
|
+
const target = await stat5(socketPath).catch((error51) => {
|
|
35317
|
+
if (error51.code === "ENOENT") return null;
|
|
35318
|
+
throw error51;
|
|
35319
|
+
});
|
|
35320
|
+
if (target === null) return { identity, ready: false };
|
|
35321
|
+
if (target.uid !== uid || !target.isSocket() || (target.mode & 63) !== 0) {
|
|
35322
|
+
throw new Error(
|
|
35323
|
+
`Shared official app-server link must target a current-user private socket: ${socketPath}`
|
|
35324
|
+
);
|
|
35325
|
+
}
|
|
35326
|
+
} else if (!metadata.isSocket()) {
|
|
34817
35327
|
throw new Error(`Shared official app-server path is not a socket: ${socketPath}`);
|
|
34818
35328
|
}
|
|
34819
|
-
return {
|
|
35329
|
+
return { identity, ready: true };
|
|
34820
35330
|
}
|
|
34821
35331
|
function sameUnixFileIdentity3(left, right) {
|
|
34822
35332
|
return left.dev === right.dev && left.ino === right.ino;
|
|
34823
35333
|
}
|
|
34824
|
-
async function waitForOfficialSocket(socketPath, closed) {
|
|
35334
|
+
async function waitForOfficialSocket(socketPath, closed, onIdentity) {
|
|
34825
35335
|
const deadline = Date.now() + 1e4;
|
|
34826
35336
|
const state = { exit: null };
|
|
34827
35337
|
void closed.then((value2) => {
|
|
@@ -34834,14 +35344,20 @@ async function waitForOfficialSocket(socketPath, closed) {
|
|
|
34834
35344
|
exit.error ? `Shared official app-server failed: ${exit.error.message}` : `Shared official app-server exited before its socket was ready (code=${String(exit.code)}, signal=${String(exit.signal)})`
|
|
34835
35345
|
);
|
|
34836
35346
|
}
|
|
34837
|
-
|
|
35347
|
+
const socket = await inspectSocket(socketPath);
|
|
35348
|
+
if (socket !== null) {
|
|
35349
|
+
onIdentity(socket.identity);
|
|
35350
|
+
if (socket.ready) return;
|
|
35351
|
+
}
|
|
34838
35352
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
34839
35353
|
}
|
|
34840
35354
|
throw new Error(`Shared official app-server socket was not ready after 10000ms: ${socketPath}`);
|
|
34841
35355
|
}
|
|
34842
35356
|
function createRemoteOfficialAppServerListener(input) {
|
|
34843
35357
|
const spawnOfficial = input.spawnOfficial ?? spawn3;
|
|
34844
|
-
const waitUntilReady = input.waitUntilReady ?? waitForOfficialSocket
|
|
35358
|
+
const waitUntilReady = input.waitUntilReady ?? ((socketPath, closed2) => waitForOfficialSocket(socketPath, closed2, (identity) => {
|
|
35359
|
+
ownedSocketIdentity ??= identity;
|
|
35360
|
+
}));
|
|
34845
35361
|
const closeTimeoutMs = input.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS;
|
|
34846
35362
|
const closed = Promise.withResolvers();
|
|
34847
35363
|
let child = null;
|
|
@@ -34872,9 +35388,9 @@ function createRemoteOfficialAppServerListener(input) {
|
|
|
34872
35388
|
};
|
|
34873
35389
|
const removeOwnedSocket = async () => {
|
|
34874
35390
|
if (ownedSocketIdentity === null) return;
|
|
34875
|
-
const current = await
|
|
35391
|
+
const current = await lstat7(input.socketPath).catch(() => null);
|
|
34876
35392
|
if (current && sameUnixFileIdentity3(current, ownedSocketIdentity)) {
|
|
34877
|
-
await
|
|
35393
|
+
await rm8(input.socketPath, { force: true });
|
|
34878
35394
|
}
|
|
34879
35395
|
ownedSocketIdentity = null;
|
|
34880
35396
|
};
|
|
@@ -34898,7 +35414,7 @@ function createRemoteOfficialAppServerListener(input) {
|
|
|
34898
35414
|
spawned.stderr?.pipe(input.diagnosticOutput, { end: false });
|
|
34899
35415
|
try {
|
|
34900
35416
|
await waitUntilReady(input.socketPath, closed.promise);
|
|
34901
|
-
ownedSocketIdentity
|
|
35417
|
+
ownedSocketIdentity ??= (await inspectSocket(input.socketPath).catch(() => null))?.identity ?? null;
|
|
34902
35418
|
} catch (error51) {
|
|
34903
35419
|
let stopFailed = false;
|
|
34904
35420
|
try {
|
|
@@ -34906,7 +35422,7 @@ function createRemoteOfficialAppServerListener(input) {
|
|
|
34906
35422
|
} catch {
|
|
34907
35423
|
stopFailed = true;
|
|
34908
35424
|
}
|
|
34909
|
-
ownedSocketIdentity ??= await
|
|
35425
|
+
ownedSocketIdentity ??= (await inspectSocket(input.socketPath).catch(() => null))?.identity ?? null;
|
|
34910
35426
|
if (!stopFailed) await removeOwnedSocket();
|
|
34911
35427
|
throw new Error(`Shared official app-server startup failed: ${errorMessage4(error51)}`);
|
|
34912
35428
|
}
|
|
@@ -35235,7 +35751,7 @@ function createOwnedLoopbackBackend(input) {
|
|
|
35235
35751
|
"--ws-auth",
|
|
35236
35752
|
"capability-token",
|
|
35237
35753
|
"--ws-token-sha256",
|
|
35238
|
-
|
|
35754
|
+
createHash9("sha256").update(capabilityToken).digest("hex")
|
|
35239
35755
|
],
|
|
35240
35756
|
// Managed stderr may carry credential-bearing errors. Never forward raw bytes.
|
|
35241
35757
|
diagnosticOutput: new Writable2({
|
|
@@ -35288,21 +35804,21 @@ function createOwnedUnixBackend(input) {
|
|
|
35288
35804
|
|
|
35289
35805
|
// packages/host-runtime/src/native-account-host.ts
|
|
35290
35806
|
async function canonicalCodexHome(home) {
|
|
35291
|
-
const absolute =
|
|
35807
|
+
const absolute = path20.resolve(home);
|
|
35292
35808
|
try {
|
|
35293
35809
|
return await realpath3(absolute);
|
|
35294
35810
|
} catch (error51) {
|
|
35295
35811
|
if (!(error51 instanceof Error && "code" in error51 && error51.code === "ENOENT")) throw error51;
|
|
35296
|
-
const parent =
|
|
35812
|
+
const parent = path20.dirname(absolute);
|
|
35297
35813
|
if (parent === absolute) throw error51;
|
|
35298
|
-
return
|
|
35814
|
+
return path20.join(await canonicalCodexHome(parent), path20.basename(absolute));
|
|
35299
35815
|
}
|
|
35300
35816
|
}
|
|
35301
35817
|
async function prepareLocalCodex(input) {
|
|
35302
35818
|
const home = await canonicalCodexHome(
|
|
35303
|
-
input.environment.CODEX_HOME ??
|
|
35819
|
+
input.environment.CODEX_HOME ?? path20.join(homedir(), ".codex")
|
|
35304
35820
|
);
|
|
35305
|
-
await
|
|
35821
|
+
await mkdir8(home, { recursive: true });
|
|
35306
35822
|
const scope = new OfficialRuntimeScope({
|
|
35307
35823
|
permanentHome: home,
|
|
35308
35824
|
diagnosticOutput: input.diagnosticOutput,
|
|
@@ -35466,18 +35982,18 @@ var DelegationControlRegistry = class {
|
|
|
35466
35982
|
};
|
|
35467
35983
|
|
|
35468
35984
|
// packages/host-runtime/src/installed-harness-plugins.ts
|
|
35469
|
-
import
|
|
35470
|
-
import
|
|
35985
|
+
import os6 from "node:os";
|
|
35986
|
+
import path22 from "node:path";
|
|
35471
35987
|
import { fileURLToPath } from "node:url";
|
|
35472
35988
|
|
|
35473
35989
|
// packages/host-runtime/src/launcher-url-opener.ts
|
|
35474
35990
|
import { spawn as spawn4 } from "node:child_process";
|
|
35475
|
-
import
|
|
35991
|
+
import path21 from "node:path";
|
|
35476
35992
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
|
|
35477
35993
|
var OPEN_TIMEOUT_MS = 1e4;
|
|
35478
35994
|
function createLauncherUrlOpener(environment, spawnLauncher = (command, arguments_2, options2) => spawn4(command, arguments_2, options2)) {
|
|
35479
35995
|
const launcher = environment.CODEXHOST_LAUNCHER_EXECUTABLE;
|
|
35480
|
-
if (!launcher || !
|
|
35996
|
+
if (!launcher || !path21.isAbsolute(launcher)) return void 0;
|
|
35481
35997
|
const launcherEnvironment = Object.fromEntries(
|
|
35482
35998
|
Object.entries(environment).filter(([name]) => {
|
|
35483
35999
|
const normalized = name.toUpperCase();
|
|
@@ -35535,9 +36051,9 @@ function installedHarnessPluginOptions(environment, managedRemoteHost = false, h
|
|
|
35535
36051
|
const opener = managedRemoteHost ? void 0 : createLauncherUrlOpener(environment);
|
|
35536
36052
|
return {
|
|
35537
36053
|
pluginRoots: [
|
|
35538
|
-
|
|
35539
|
-
environment[HARNESS_PLUGIN_DIRECTORY_ENV] ??
|
|
35540
|
-
environment.CODEXHOST_DATA_DIR ?
|
|
36054
|
+
path22.join(path22.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
|
|
36055
|
+
environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path22.join(
|
|
36056
|
+
environment.CODEXHOST_DATA_DIR ? path22.resolve(environment.CODEXHOST_DATA_DIR) : path22.join(os6.homedir(), ".codexhost"),
|
|
35541
36057
|
"plugins"
|
|
35542
36058
|
)
|
|
35543
36059
|
],
|
|
@@ -35661,172 +36177,10 @@ async function startDelegationControlServer(input) {
|
|
|
35661
36177
|
};
|
|
35662
36178
|
}
|
|
35663
36179
|
|
|
35664
|
-
// packages/host-runtime/src/delegation-skill.ts
|
|
35665
|
-
import { createHash as createHash9, randomUUID as randomUUID12 } from "node:crypto";
|
|
35666
|
-
import { mkdir as mkdir8, open as open6, readFile as readFile9, rename as rename5, rm as rm8, stat as stat4 } from "node:fs/promises";
|
|
35667
|
-
import os6 from "node:os";
|
|
35668
|
-
import path21 from "node:path";
|
|
35669
|
-
var SKILL_VERSION = 7;
|
|
35670
|
-
var SKILL_RELATIVE_PATH = path21.join("skills", "codexhost-delegation", "SKILL.md");
|
|
35671
|
-
var PREVIOUS_MANAGED_DIGESTS = [
|
|
35672
|
-
"9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
|
|
35673
|
-
"2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
|
|
35674
|
-
"aff258622dc8ff321f32b15620d081e578cb9c9ed1134d6a57f35ca8e7762c0a",
|
|
35675
|
-
"ba509f57e5448e796b3dfdd5031dcb08672eded50b61c0a54de84cfa02c49dd3",
|
|
35676
|
-
"d3ddf6db9bc5c5df825479c885bbbf0ca08da66f7057a12e02e1fdf57525149e",
|
|
35677
|
-
"15eb63519ff867e1536c97188a0c43738d7a49d38d4d6adeb7a1036726e7246d",
|
|
35678
|
-
"09acc3cc0a598e546ce35fccb9d856d9fe06c01ab055dfce1914dab92479c9a2"
|
|
35679
|
-
];
|
|
35680
|
-
var CODEXHOST_DELEGATION_SKILL = `---
|
|
35681
|
-
name: codexhost-delegation
|
|
35682
|
-
version: ${SKILL_VERSION}
|
|
35683
|
-
description: >
|
|
35684
|
-
Delegate tasks to other coding agents, or read and follow up on existing
|
|
35685
|
-
external agent sessions. Use when the user asks another agent (including
|
|
35686
|
-
@agent) to independently perform a task, or asks to view a specified external
|
|
35687
|
-
session's content, progress, or results, send follow-up messages, wait, or
|
|
35688
|
-
cancel a task. Not for recapping the current conversation, discussing or
|
|
35689
|
-
configuring agents, or role-playing.
|
|
35690
|
-
---
|
|
35691
|
-
|
|
35692
|
-
# Execute the task
|
|
35693
|
-
|
|
35694
|
-
Before acting, run:
|
|
35695
|
-
|
|
35696
|
-
\`boft delegate --help\`
|
|
35697
|
-
|
|
35698
|
-
Use CLI help as the authoritative source for commands and behavior. Consult
|
|
35699
|
-
command-specific help for options and the Harness listing command when the
|
|
35700
|
-
target is unknown. Prefer compact output when supported, and use its task links
|
|
35701
|
-
directly for subsequent commands.
|
|
35702
|
-
|
|
35703
|
-
Use the Harness native defaults. Inspect the target when a Model or Thinking
|
|
35704
|
-
selection is needed or the default is unavailable.
|
|
35705
|
-
|
|
35706
|
-
For a new delegation, create an independent child session and submit the
|
|
35707
|
-
requested task. For an existing external session, resolve the target from the
|
|
35708
|
-
user-provided session link, identifier, or context and operate on that Thread
|
|
35709
|
-
directly; it need not have been created by the current assistant. If the target
|
|
35710
|
-
is ambiguous, ask the user to identify it. Keep requests to view or summarize a
|
|
35711
|
-
session read-only.
|
|
35712
|
-
|
|
35713
|
-
For a new or existing task, choose the appropriate next action based on the
|
|
35714
|
-
user’s request and the task:
|
|
35715
|
-
|
|
35716
|
-
- send a follow-up message to the same Thread;
|
|
35717
|
-
- cancel its current Turn;
|
|
35718
|
-
- read its current state immediately;
|
|
35719
|
-
- wait for a bounded period;
|
|
35720
|
-
- check it again later;
|
|
35721
|
-
- leave it running in the background.
|
|
35722
|
-
|
|
35723
|
-
Report the result returned by read or a completed wait, together with the target
|
|
35724
|
-
agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
|
|
35725
|
-
`;
|
|
35726
|
-
var CURRENT_DIGEST = createHash9("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
|
|
35727
|
-
function digest(value2) {
|
|
35728
|
-
return createHash9("sha256").update(value2).digest("hex");
|
|
35729
|
-
}
|
|
35730
|
-
function managedVersion(value2) {
|
|
35731
|
-
const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
|
|
35732
|
-
return match ? Number(match[1]) : null;
|
|
35733
|
-
}
|
|
35734
|
-
async function readOptional(filePath) {
|
|
35735
|
-
try {
|
|
35736
|
-
return await readFile9(filePath, "utf8");
|
|
35737
|
-
} catch (error51) {
|
|
35738
|
-
if (error51.code === "ENOENT") return null;
|
|
35739
|
-
throw error51;
|
|
35740
|
-
}
|
|
35741
|
-
}
|
|
35742
|
-
async function atomicWrite(filePath, content) {
|
|
35743
|
-
await mkdir8(path21.dirname(filePath), { recursive: true, mode: 448 });
|
|
35744
|
-
const temporaryPath = path21.join(path21.dirname(filePath), `.SKILL.md.${randomUUID12()}.tmp`);
|
|
35745
|
-
const handle = await open6(temporaryPath, "wx", 384);
|
|
35746
|
-
try {
|
|
35747
|
-
await handle.writeFile(content, "utf8");
|
|
35748
|
-
await handle.sync();
|
|
35749
|
-
} finally {
|
|
35750
|
-
await handle.close();
|
|
35751
|
-
}
|
|
35752
|
-
try {
|
|
35753
|
-
await rename5(temporaryPath, filePath);
|
|
35754
|
-
} finally {
|
|
35755
|
-
await rm8(temporaryPath, { force: true });
|
|
35756
|
-
}
|
|
35757
|
-
}
|
|
35758
|
-
async function installDelegationSkills(input = {}) {
|
|
35759
|
-
const home = input.homeDirectory ?? os6.homedir();
|
|
35760
|
-
const destinations = [
|
|
35761
|
-
path21.join(home, ".agents", SKILL_RELATIVE_PATH),
|
|
35762
|
-
path21.join(home, ".claude", SKILL_RELATIVE_PATH)
|
|
35763
|
-
];
|
|
35764
|
-
const knownDigests = /* @__PURE__ */ new Set([
|
|
35765
|
-
CURRENT_DIGEST,
|
|
35766
|
-
...PREVIOUS_MANAGED_DIGESTS,
|
|
35767
|
-
...input.previousManagedDigests ?? []
|
|
35768
|
-
]);
|
|
35769
|
-
const results = [];
|
|
35770
|
-
for (const destination of destinations) {
|
|
35771
|
-
const current = await readOptional(destination);
|
|
35772
|
-
if (current === CODEXHOST_DELEGATION_SKILL) {
|
|
35773
|
-
results.push({
|
|
35774
|
-
path: destination,
|
|
35775
|
-
status: "current",
|
|
35776
|
-
version: SKILL_VERSION,
|
|
35777
|
-
digest: CURRENT_DIGEST
|
|
35778
|
-
});
|
|
35779
|
-
continue;
|
|
35780
|
-
}
|
|
35781
|
-
if (current !== null) {
|
|
35782
|
-
const currentDigest = digest(current);
|
|
35783
|
-
const version2 = managedVersion(current);
|
|
35784
|
-
if (!knownDigests.has(currentDigest)) {
|
|
35785
|
-
results.push({ path: destination, status: "conflict", version: version2, digest: currentDigest });
|
|
35786
|
-
continue;
|
|
35787
|
-
}
|
|
35788
|
-
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
35789
|
-
results.push({
|
|
35790
|
-
path: destination,
|
|
35791
|
-
status: "updated",
|
|
35792
|
-
version: SKILL_VERSION,
|
|
35793
|
-
digest: CURRENT_DIGEST
|
|
35794
|
-
});
|
|
35795
|
-
continue;
|
|
35796
|
-
}
|
|
35797
|
-
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
35798
|
-
results.push({
|
|
35799
|
-
path: destination,
|
|
35800
|
-
status: "installed",
|
|
35801
|
-
version: SKILL_VERSION,
|
|
35802
|
-
digest: CURRENT_DIGEST
|
|
35803
|
-
});
|
|
35804
|
-
}
|
|
35805
|
-
for (const result of results) {
|
|
35806
|
-
if (result.status === "conflict") continue;
|
|
35807
|
-
const source = await readFile9(result.path, "utf8");
|
|
35808
|
-
const metadata = await stat4(result.path);
|
|
35809
|
-
if (!metadata.isFile() || source !== CODEXHOST_DELEGATION_SKILL) {
|
|
35810
|
-
throw new Error(`Delegation Skill verification failed: ${result.path}`);
|
|
35811
|
-
}
|
|
35812
|
-
}
|
|
35813
|
-
const managed = results.filter((result) => result.status !== "conflict");
|
|
35814
|
-
if (managed.some((result) => result.digest !== CURRENT_DIGEST)) {
|
|
35815
|
-
throw new Error("Delegation Skill copies are inconsistent");
|
|
35816
|
-
}
|
|
35817
|
-
if (results.every((result) => result.status !== "conflict")) {
|
|
35818
|
-
const copies = await Promise.all(results.map((result) => readFile9(result.path, "utf8")));
|
|
35819
|
-
if (copies.some((copy) => copy !== copies[0])) {
|
|
35820
|
-
throw new Error("Delegation Skill copies are inconsistent");
|
|
35821
|
-
}
|
|
35822
|
-
}
|
|
35823
|
-
return results;
|
|
35824
|
-
}
|
|
35825
|
-
|
|
35826
36180
|
// packages/host-runtime/src/remote-control-app-server.ts
|
|
35827
36181
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
35828
36182
|
import { mkdir as mkdir9, open as open7, rename as rename6, rm as rm9 } from "node:fs/promises";
|
|
35829
|
-
import
|
|
36183
|
+
import path23 from "node:path";
|
|
35830
36184
|
var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
|
|
35831
36185
|
var REMOTE_CONTROL_BRIDGE_NODE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_NODE_PATH";
|
|
35832
36186
|
var REMOTE_CONTROL_BRIDGE_RUNTIME_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_RUNTIME_PATH";
|
|
@@ -35837,8 +36191,8 @@ var BRIDGE_READY_METHOD = "codexhost/remote-control-bridge/ready";
|
|
|
35837
36191
|
function absoluteEnvironmentPath2(environment, name, fallback, platform = process.platform) {
|
|
35838
36192
|
const value2 = environment[name] ?? fallback;
|
|
35839
36193
|
if (!value2) return null;
|
|
35840
|
-
if (
|
|
35841
|
-
return platform === "win32" &&
|
|
36194
|
+
if (path23.isAbsolute(value2)) return path23.normalize(value2);
|
|
36195
|
+
return platform === "win32" && path23.win32.isAbsolute(value2) ? path23.win32.normalize(value2) : null;
|
|
35842
36196
|
}
|
|
35843
36197
|
function nodeCompatibleWindowsPath(value2) {
|
|
35844
36198
|
if (value2.startsWith("\\\\?\\UNC\\")) return `\\\\${value2.slice(8)}`;
|
|
@@ -35852,13 +36206,13 @@ function remoteControlBridgePipePath(processId = process.pid, instanceId = rando
|
|
|
35852
36206
|
}
|
|
35853
36207
|
function remoteControlBridgeDescriptorPath(environment) {
|
|
35854
36208
|
const root = environment.LOCALAPPDATA;
|
|
35855
|
-
if (!root || !
|
|
35856
|
-
return
|
|
36209
|
+
if (!root || !path23.isAbsolute(root)) return null;
|
|
36210
|
+
return path23.join(path23.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
|
|
35857
36211
|
}
|
|
35858
36212
|
async function publishRemoteControlAppServerDescriptor(plan) {
|
|
35859
|
-
const directory =
|
|
36213
|
+
const directory = path23.dirname(plan.descriptorPath);
|
|
35860
36214
|
await mkdir9(directory, { recursive: true, mode: 448 });
|
|
35861
|
-
const temporaryPath =
|
|
36215
|
+
const temporaryPath = path23.join(
|
|
35862
36216
|
directory,
|
|
35863
36217
|
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID13()}.tmp`
|
|
35864
36218
|
);
|
|
@@ -36159,9 +36513,9 @@ function hasLauncherManagedUpdateRuntime(environment, hostRuntimePath) {
|
|
|
36159
36513
|
if (!environment[UPDATE_RUNTIME_ENV.launcherPid]) return false;
|
|
36160
36514
|
const npmPackageRoot = environment[UPDATE_RUNTIME_ENV.npmPackageRoot];
|
|
36161
36515
|
if (!npmPackageRoot || !hostRuntimePath) return true;
|
|
36162
|
-
if (!
|
|
36163
|
-
const runtimePackageRoot =
|
|
36164
|
-
return
|
|
36516
|
+
if (!path24.isAbsolute(npmPackageRoot) || !path24.isAbsolute(hostRuntimePath)) return false;
|
|
36517
|
+
const runtimePackageRoot = path24.dirname(path24.dirname(path24.normalize(hostRuntimePath)));
|
|
36518
|
+
return path24.relative(path24.normalize(npmPackageRoot), runtimePackageRoot) === "";
|
|
36165
36519
|
}
|
|
36166
36520
|
function requiredRuntimeConfiguration(environment) {
|
|
36167
36521
|
const stockCodexPath = environment[STOCK_CODEX_PATH_ENV];
|
|
@@ -36307,8 +36661,8 @@ async function runHostRuntime(input) {
|
|
|
36307
36661
|
const socketPath = remoteAppServerSocketPath(delegationEnvironment, listenUrl);
|
|
36308
36662
|
const officialPlan = createRemoteOfficialAppServerPlan(input.arguments, socketPath);
|
|
36309
36663
|
const officialRuntimeScope = new OfficialRuntimeScope({
|
|
36310
|
-
permanentHome:
|
|
36311
|
-
delegationEnvironment.CODEX_HOME ??
|
|
36664
|
+
permanentHome: path24.resolve(
|
|
36665
|
+
delegationEnvironment.CODEX_HOME ?? path24.join(homedir2(), ".codex")
|
|
36312
36666
|
),
|
|
36313
36667
|
diagnosticOutput: process.stderr,
|
|
36314
36668
|
createBackend: () => createOwnedUnixBackend({
|
|
@@ -36401,10 +36755,10 @@ import {
|
|
|
36401
36755
|
rename as rename7,
|
|
36402
36756
|
rm as rm10,
|
|
36403
36757
|
rmdir,
|
|
36404
|
-
stat as
|
|
36758
|
+
stat as stat6,
|
|
36405
36759
|
writeFile as writeFile4
|
|
36406
36760
|
} from "node:fs/promises";
|
|
36407
|
-
import
|
|
36761
|
+
import path25 from "node:path";
|
|
36408
36762
|
var MANIFEST_FORMAT = 1;
|
|
36409
36763
|
var WRAPPER_MARKER = "# codexhost remote SSH wrapper v1";
|
|
36410
36764
|
var PROFILE_START = "# >>> codexhost remote SSH >>>";
|
|
@@ -36415,25 +36769,25 @@ function resolvePaths(options2) {
|
|
|
36415
36769
|
if (!configuredHome) {
|
|
36416
36770
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
36417
36771
|
}
|
|
36418
|
-
const home =
|
|
36419
|
-
if (!home || home ===
|
|
36772
|
+
const home = path25.resolve(configuredHome);
|
|
36773
|
+
if (!home || home === path25.parse(home).root) {
|
|
36420
36774
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
36421
36775
|
}
|
|
36422
|
-
const installRoot =
|
|
36423
|
-
const profilePath =
|
|
36424
|
-
options2.profilePath ??
|
|
36776
|
+
const installRoot = path25.resolve(options2.installRoot ?? path25.join(home, ".codexhost", "remote"));
|
|
36777
|
+
const profilePath = path25.resolve(
|
|
36778
|
+
options2.profilePath ?? path25.join(
|
|
36425
36779
|
home,
|
|
36426
|
-
|
|
36780
|
+
path25.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path25.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
|
|
36427
36781
|
)
|
|
36428
36782
|
);
|
|
36429
|
-
const binDirectory =
|
|
36783
|
+
const binDirectory = path25.join(installRoot, "bin");
|
|
36430
36784
|
return {
|
|
36431
36785
|
home,
|
|
36432
36786
|
installRoot,
|
|
36433
36787
|
binDirectory,
|
|
36434
|
-
wrapperPath:
|
|
36435
|
-
manifestPath:
|
|
36436
|
-
dataDirectory:
|
|
36788
|
+
wrapperPath: path25.join(binDirectory, "codex"),
|
|
36789
|
+
manifestPath: path25.join(installRoot, "manifest.json"),
|
|
36790
|
+
dataDirectory: path25.join(installRoot, "data"),
|
|
36437
36791
|
profilePath
|
|
36438
36792
|
};
|
|
36439
36793
|
}
|
|
@@ -36452,9 +36806,9 @@ async function fileSha256(filePath) {
|
|
|
36452
36806
|
return createHash10("sha256").update(await readFile10(filePath)).digest("hex");
|
|
36453
36807
|
}
|
|
36454
36808
|
async function executable(filePath, label) {
|
|
36455
|
-
const absolute =
|
|
36809
|
+
const absolute = path25.resolve(filePath);
|
|
36456
36810
|
try {
|
|
36457
|
-
if (!(await
|
|
36811
|
+
if (!(await stat6(absolute)).isFile()) throw new Error("not a regular file");
|
|
36458
36812
|
await access(absolute, fsConstants.X_OK);
|
|
36459
36813
|
} catch {
|
|
36460
36814
|
throw new Error(`${label} is not an executable file: ${absolute}`);
|
|
@@ -36462,9 +36816,9 @@ async function executable(filePath, label) {
|
|
|
36462
36816
|
return absolute;
|
|
36463
36817
|
}
|
|
36464
36818
|
async function existingFile(filePath, label) {
|
|
36465
|
-
const absolute =
|
|
36819
|
+
const absolute = path25.resolve(filePath);
|
|
36466
36820
|
try {
|
|
36467
|
-
const metadata = await
|
|
36821
|
+
const metadata = await stat6(absolute);
|
|
36468
36822
|
if (!metadata.isFile()) throw new Error("not a regular file");
|
|
36469
36823
|
} catch {
|
|
36470
36824
|
throw new Error(`${label} is not a regular file: ${absolute}`);
|
|
@@ -36472,9 +36826,9 @@ async function existingFile(filePath, label) {
|
|
|
36472
36826
|
return absolute;
|
|
36473
36827
|
}
|
|
36474
36828
|
async function discoverExecutable(name, environment) {
|
|
36475
|
-
for (const directory of (environment.PATH ?? "").split(
|
|
36829
|
+
for (const directory of (environment.PATH ?? "").split(path25.delimiter)) {
|
|
36476
36830
|
if (!directory) continue;
|
|
36477
|
-
const candidate =
|
|
36831
|
+
const candidate = path25.resolve(directory, name);
|
|
36478
36832
|
try {
|
|
36479
36833
|
await access(candidate, fsConstants.X_OK);
|
|
36480
36834
|
return candidate;
|
|
@@ -36485,10 +36839,10 @@ async function discoverExecutable(name, environment) {
|
|
|
36485
36839
|
return null;
|
|
36486
36840
|
}
|
|
36487
36841
|
async function writeAtomic(filePath, contents, mode) {
|
|
36488
|
-
await mkdir10(
|
|
36489
|
-
const temporary =
|
|
36490
|
-
|
|
36491
|
-
`.${
|
|
36842
|
+
await mkdir10(path25.dirname(filePath), { recursive: true, mode: 448 });
|
|
36843
|
+
const temporary = path25.join(
|
|
36844
|
+
path25.dirname(filePath),
|
|
36845
|
+
`.${path25.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
|
|
36492
36846
|
);
|
|
36493
36847
|
try {
|
|
36494
36848
|
if (typeof contents === "string") {
|
|
@@ -36509,10 +36863,10 @@ async function writeAtomic(filePath, contents, mode) {
|
|
|
36509
36863
|
}
|
|
36510
36864
|
}
|
|
36511
36865
|
async function writeAtomicExecutable(filePath, sourcePath) {
|
|
36512
|
-
await mkdir10(
|
|
36513
|
-
const temporary =
|
|
36514
|
-
|
|
36515
|
-
`.${
|
|
36866
|
+
await mkdir10(path25.dirname(filePath), { recursive: true, mode: 448 });
|
|
36867
|
+
const temporary = path25.join(
|
|
36868
|
+
path25.dirname(filePath),
|
|
36869
|
+
`.${path25.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
|
|
36516
36870
|
);
|
|
36517
36871
|
try {
|
|
36518
36872
|
await copyFile3(sourcePath, temporary);
|
|
@@ -36553,8 +36907,8 @@ function removeManagedProfileBlock(contents) {
|
|
|
36553
36907
|
function installManagedProfileBlock(contents, manifest) {
|
|
36554
36908
|
const base = removeManagedProfileBlock(contents);
|
|
36555
36909
|
const environment = [
|
|
36556
|
-
`export CODEX_INSTALL_DIR=${shellQuote(
|
|
36557
|
-
`export PATH=${shellQuote(
|
|
36910
|
+
`export CODEX_INSTALL_DIR=${shellQuote(path25.dirname(manifest.wrapperPath))}`,
|
|
36911
|
+
`export PATH=${shellQuote(path25.dirname(manifest.wrapperPath))}:${shellQuote(path25.dirname(manifest.nodePath))}:${shellQuote(path25.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
|
|
36558
36912
|
`export CODEXHOST_STOCK_CODEX_PATH=${shellQuote(manifest.stockCodexPath)}`,
|
|
36559
36913
|
`export CODEXHOST_HOST_NODE_PATH=${shellQuote(manifest.nodePath)}`,
|
|
36560
36914
|
`export CODEXHOST_HOST_RUNTIME_PATH=${shellQuote(manifest.hostRuntimePath)}`,
|
|
@@ -36570,7 +36924,7 @@ function installManagedProfileBlock(contents, manifest) {
|
|
|
36570
36924
|
PROFILE_END,
|
|
36571
36925
|
""
|
|
36572
36926
|
].join("\n");
|
|
36573
|
-
if (
|
|
36927
|
+
if (path25.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
|
|
36574
36928
|
const separator = base.length > 0 && !base.endsWith("\n") ? "\n" : "";
|
|
36575
36929
|
return `${base}${separator}${block}`;
|
|
36576
36930
|
}
|
|
@@ -36636,9 +36990,9 @@ async function readManifest(filePath) {
|
|
|
36636
36990
|
];
|
|
36637
36991
|
const optionalPaths = ["claudeCommand", "profileBackupPath"];
|
|
36638
36992
|
if (manifest.format !== MANIFEST_FORMAT || Object.keys(manifest).some((key) => !allowed.has(key)) || requiredPaths.some(
|
|
36639
|
-
(key) => typeof manifest[key] !== "string" || !
|
|
36993
|
+
(key) => typeof manifest[key] !== "string" || !path25.isAbsolute(manifest[key])
|
|
36640
36994
|
) || optionalPaths.some(
|
|
36641
|
-
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !
|
|
36995
|
+
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path25.isAbsolute(manifest[key]))
|
|
36642
36996
|
) || manifest.entrypointSha256 !== void 0 && (typeof manifest.entrypointSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(manifest.entrypointSha256))) {
|
|
36643
36997
|
throw new Error("Remote Host manifest has an unsupported format");
|
|
36644
36998
|
}
|
|
@@ -36647,7 +37001,7 @@ async function readManifest(filePath) {
|
|
|
36647
37001
|
async function backupProfile(profilePath, contents, action) {
|
|
36648
37002
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replaceAll(/[-:.TZ]/gu, "");
|
|
36649
37003
|
const backupPath = `${profilePath}.codexhost-${action}-${timestamp}.bak`;
|
|
36650
|
-
const metadata = await
|
|
37004
|
+
const metadata = await stat6(profilePath).catch(() => null);
|
|
36651
37005
|
await writeAtomic(backupPath, contents, metadata?.mode ?? 384);
|
|
36652
37006
|
return backupPath;
|
|
36653
37007
|
}
|
|
@@ -36661,7 +37015,7 @@ async function installRemoteHost(options2) {
|
|
|
36661
37015
|
const previousManifest = await readManifest(paths.manifestPath);
|
|
36662
37016
|
const previousManifestFile = previousManifest ? {
|
|
36663
37017
|
contents: await readFile10(paths.manifestPath),
|
|
36664
|
-
mode: (await
|
|
37018
|
+
mode: (await stat6(paths.manifestPath)).mode & 511
|
|
36665
37019
|
} : null;
|
|
36666
37020
|
const existingEntrypoint = await lstat8(paths.wrapperPath).catch(
|
|
36667
37021
|
(error51) => {
|
|
@@ -36717,7 +37071,7 @@ async function installRemoteHost(options2) {
|
|
|
36717
37071
|
const existingProfile = existingProfileSource ?? "";
|
|
36718
37072
|
const nextProfile = installManagedProfileBlock(existingProfile, manifest);
|
|
36719
37073
|
const profileChanged = nextProfile !== existingProfile;
|
|
36720
|
-
const profileMetadata = await
|
|
37074
|
+
const profileMetadata = await stat6(profilePath).catch(() => null);
|
|
36721
37075
|
try {
|
|
36722
37076
|
if (profileChanged) {
|
|
36723
37077
|
const profileBackupPath = await backupProfile(profilePath, existingProfile, "install");
|
|
@@ -36808,7 +37162,7 @@ async function inspectRemoteHostInstallation(options2) {
|
|
|
36808
37162
|
if (!profileMatches && profileIssue === null)
|
|
36809
37163
|
profileIssue = "shell profile does not configure the managed native entrypoint";
|
|
36810
37164
|
if (profileIssue !== null) issues.push(profileIssue);
|
|
36811
|
-
const dataDirectory = await
|
|
37165
|
+
const dataDirectory = await stat6(manifest.dataDirectory).catch(() => null);
|
|
36812
37166
|
if (!dataDirectory?.isDirectory()) issues.push("remote Host data directory is unavailable");
|
|
36813
37167
|
for (const [label, filePath, requiresExecutable] of [
|
|
36814
37168
|
["stock Codex", manifest.stockCodexPath, true],
|
|
@@ -36818,7 +37172,7 @@ async function inspectRemoteHostInstallation(options2) {
|
|
|
36818
37172
|
]) {
|
|
36819
37173
|
try {
|
|
36820
37174
|
if (requiresExecutable) await executable(filePath, label);
|
|
36821
|
-
else if (!(await
|
|
37175
|
+
else if (!(await stat6(filePath)).isFile()) throw new Error("not a regular file");
|
|
36822
37176
|
} catch {
|
|
36823
37177
|
issues.push(`${label} is unavailable`);
|
|
36824
37178
|
}
|
|
@@ -36847,7 +37201,7 @@ async function uninstallRemoteHost(options2) {
|
|
|
36847
37201
|
const nextProfile = removeManagedProfileBlock(profile);
|
|
36848
37202
|
if (nextProfile !== profile) {
|
|
36849
37203
|
await backupProfile(manifest.profilePath, profile, "uninstall");
|
|
36850
|
-
const metadata = await
|
|
37204
|
+
const metadata = await stat6(manifest.profilePath).catch(() => null);
|
|
36851
37205
|
await writeAtomic(manifest.profilePath, nextProfile, metadata?.mode ?? 384);
|
|
36852
37206
|
}
|
|
36853
37207
|
await rm10(manifest.wrapperPath, { force: true });
|
|
@@ -36862,9 +37216,9 @@ async function uninstallRemoteHost(options2) {
|
|
|
36862
37216
|
|
|
36863
37217
|
// packages/host-runtime/src/remote-host-lifecycle.ts
|
|
36864
37218
|
import { spawn as spawn5 } from "node:child_process";
|
|
36865
|
-
import { stat as
|
|
37219
|
+
import { stat as stat7 } from "node:fs/promises";
|
|
36866
37220
|
import net3 from "node:net";
|
|
36867
|
-
import
|
|
37221
|
+
import path26 from "node:path";
|
|
36868
37222
|
import { Duplex } from "node:stream";
|
|
36869
37223
|
|
|
36870
37224
|
// packages/host-runtime/src/app-server-websocket-options.ts
|
|
@@ -36891,12 +37245,12 @@ function classifyRemoteHostProbeResponse(response, socketPath) {
|
|
|
36891
37245
|
}
|
|
36892
37246
|
var lifecycleDependencyOverrides = {};
|
|
36893
37247
|
function socketPathFor(environment) {
|
|
36894
|
-
const codexHome = environment.CODEX_HOME ?? (environment.HOME ?
|
|
37248
|
+
const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path26.join(environment.HOME, ".codex") : void 0);
|
|
36895
37249
|
if (!codexHome) throw new Error("CODEX_HOME or HOME is required for remote Host lifecycle");
|
|
36896
|
-
return
|
|
37250
|
+
return path26.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
36897
37251
|
}
|
|
36898
37252
|
async function defaultSocketExists(socketPath) {
|
|
36899
|
-
const metadata = await
|
|
37253
|
+
const metadata = await stat7(socketPath).catch((error51) => {
|
|
36900
37254
|
if (error51.code === "ENOENT") return null;
|
|
36901
37255
|
throw error51;
|
|
36902
37256
|
});
|
|
@@ -37023,14 +37377,14 @@ function installedManifest(status) {
|
|
|
37023
37377
|
function managedEnvironment(manifest, environment) {
|
|
37024
37378
|
return {
|
|
37025
37379
|
...environment,
|
|
37026
|
-
CODEX_INSTALL_DIR:
|
|
37380
|
+
CODEX_INSTALL_DIR: path26.dirname(manifest.wrapperPath),
|
|
37027
37381
|
CODEXHOST_STOCK_CODEX_PATH: manifest.stockCodexPath,
|
|
37028
37382
|
CODEXHOST_HOST_NODE_PATH: manifest.nodePath,
|
|
37029
37383
|
CODEXHOST_HOST_RUNTIME_PATH: manifest.hostRuntimePath,
|
|
37030
37384
|
CODEXHOST_DATA_DIR: manifest.dataDirectory,
|
|
37031
37385
|
CODEXHOST_DEFAULT_AGENT: "codex",
|
|
37032
37386
|
CODEXHOST_REMOTE_SSH_MANAGED: "1",
|
|
37033
|
-
PATH: `${
|
|
37387
|
+
PATH: `${path26.dirname(manifest.wrapperPath)}${path26.delimiter}${path26.dirname(manifest.stockCodexPath)}${path26.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
|
|
37034
37388
|
};
|
|
37035
37389
|
}
|
|
37036
37390
|
async function defaultRunTerminator(manifest, socketPath, role, environment) {
|
|
@@ -37369,25 +37723,25 @@ function consumeBrokerFrames(socket, onFrame, onError) {
|
|
|
37369
37723
|
|
|
37370
37724
|
// packages/harness-broker/dist/paths.js
|
|
37371
37725
|
import os7 from "node:os";
|
|
37372
|
-
import
|
|
37726
|
+
import path27 from "node:path";
|
|
37373
37727
|
var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
|
|
37374
37728
|
var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
|
|
37375
37729
|
var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
|
|
37376
37730
|
function defaultHarnessBrokerDirectory(environment = process.env) {
|
|
37377
37731
|
const home = environment.HOME || os7.homedir();
|
|
37378
|
-
return
|
|
37732
|
+
return path27.join(home, ".codexhost", "harness-broker");
|
|
37379
37733
|
}
|
|
37380
37734
|
function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
|
|
37381
37735
|
harnessPluginIdSchema.parse(harnessId);
|
|
37382
37736
|
if (harnessId !== "claude-code")
|
|
37383
|
-
return
|
|
37384
|
-
return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ??
|
|
37737
|
+
return path27.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
|
|
37738
|
+
return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path27.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
|
|
37385
37739
|
}
|
|
37386
37740
|
function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
|
|
37387
37741
|
harnessPluginIdSchema.parse(harnessId);
|
|
37388
37742
|
if (harnessId !== "claude-code")
|
|
37389
|
-
return
|
|
37390
|
-
return
|
|
37743
|
+
return path27.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
|
|
37744
|
+
return path27.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
|
|
37391
37745
|
}
|
|
37392
37746
|
|
|
37393
37747
|
// packages/harness-broker/dist/validation.js
|
|
@@ -37624,7 +37978,7 @@ var harnessOutputSchema = external_exports.custom((value2) => {
|
|
|
37624
37978
|
import { randomBytes as randomBytes3, randomUUID as randomUUID15 } from "node:crypto";
|
|
37625
37979
|
import { chmod as chmod5, lstat as lstat9, mkdir as mkdir11, open as open8, readFile as readFile11, rename as rename8, rm as rm11 } from "node:fs/promises";
|
|
37626
37980
|
import net4, {} from "node:net";
|
|
37627
|
-
import
|
|
37981
|
+
import path28 from "node:path";
|
|
37628
37982
|
function harnessError(message, retryable = true) {
|
|
37629
37983
|
return { code: "unavailable", message, retryable, stage: "harnessBroker" };
|
|
37630
37984
|
}
|
|
@@ -37747,13 +38101,13 @@ async function prepareUnixSocketPath(socketPath) {
|
|
|
37747
38101
|
}
|
|
37748
38102
|
async function startHarnessBrokerServer(input) {
|
|
37749
38103
|
harnessPluginIdSchema.parse(input.adapter.harnessId);
|
|
37750
|
-
if (process.platform !== "win32" &&
|
|
38104
|
+
if (process.platform !== "win32" && path28.dirname(input.descriptorPath) !== path28.dirname(input.socketPath)) {
|
|
37751
38105
|
throw new Error("Harness broker descriptor and socket must share one private directory");
|
|
37752
38106
|
}
|
|
37753
38107
|
if (process.platform === "darwin" && Buffer.byteLength(input.socketPath) > 103) {
|
|
37754
38108
|
throw new Error("Harness broker Unix socket path is too long for macOS");
|
|
37755
38109
|
}
|
|
37756
|
-
await privateDirectory(
|
|
38110
|
+
await privateDirectory(path28.dirname(input.descriptorPath));
|
|
37757
38111
|
await assertNoLiveDescriptor(input.descriptorPath);
|
|
37758
38112
|
if (process.platform !== "win32")
|
|
37759
38113
|
await prepareUnixSocketPath(input.socketPath);
|