@codexhost/cli-win32-arm64 0.9.2 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/THIRD_PARTY_NOTICES.txt +0 -4
- package/app/codexhost-distribution.json +1 -1
- package/app/desktop-controller.mjs +49 -18
- package/app/host-runtime.mjs +1050 -673
- 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 +622 -109
- package/app/plugins/enabled.json +2 -1
- package/app/plugins/grok/plugin.mjs +272 -79
- package/app/plugins/hermes/plugin.mjs +162 -63
- package/app/plugins/kimi-code/manifest.json +11 -0
- package/app/plugins/kimi-code/plugin.mjs +24226 -0
- package/app/plugins/kiro-cli/plugin.mjs +257 -65
- package/app/plugins/omp/plugin.mjs +407 -156
- package/app/plugins/opencode/plugin.mjs +18 -3
- package/app/plugins/pi/plugin.mjs +215 -5
- package/app/plugins/qoder/plugin.mjs +279 -187
- package/app/plugins/qoder-cn/plugin.mjs +279 -187
- package/app/plugins/workbuddy/plugin.mjs +102 -5
- package/app/renderer-extension.js +1445 -497
- package/bin/codexhost.exe +0 -0
- package/libexec/codexhost-node-repl.exe +0 -0
- package/libexec/codexhost-shim.exe +0 -0
- package/libexec/codexhost-updater.exe +0 -0
- package/package.json +1 -1
- package/licenses/opencodex-LICENSE.txt +0 -21
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
|
}
|
|
@@ -20522,10 +20522,21 @@ var harnessCommandDescriptorSchema = external_exports.object({
|
|
|
20522
20522
|
invocation: commandInvocationSchema,
|
|
20523
20523
|
label: commandLabelSchema,
|
|
20524
20524
|
description: commandDescriptionSchema.optional(),
|
|
20525
|
-
argumentMode: external_exports.enum(["none", "text"])
|
|
20525
|
+
argumentMode: external_exports.enum(["none", "text"]),
|
|
20526
|
+
/**
|
|
20527
|
+
* Native distinction reported by the Harness. Omitted when the Harness does
|
|
20528
|
+
* not tell skills and commands apart; consumers treat that as "command".
|
|
20529
|
+
*/
|
|
20530
|
+
kind: external_exports.enum(["command", "skill"]).optional()
|
|
20526
20531
|
}).strict();
|
|
20527
20532
|
var harnessCommandCatalogSchema = external_exports.object({
|
|
20528
|
-
commands: external_exports.array(harnessCommandDescriptorSchema)
|
|
20533
|
+
commands: external_exports.array(harnessCommandDescriptorSchema),
|
|
20534
|
+
/**
|
|
20535
|
+
* `live` when the catalog includes what a native Session reports for its
|
|
20536
|
+
* workspace (custom commands, skills); `static` for Adapter built-ins only.
|
|
20537
|
+
* Omitted by Adapters; set by the Host on inspection results.
|
|
20538
|
+
*/
|
|
20539
|
+
source: external_exports.enum(["live", "static"]).optional()
|
|
20529
20540
|
}).strict().superRefine((catalog, context) => {
|
|
20530
20541
|
const ids = /* @__PURE__ */ new Set();
|
|
20531
20542
|
for (const [index, command] of catalog.commands.entries()) {
|
|
@@ -20539,7 +20550,11 @@ var harnessCommandCatalogSchema = external_exports.object({
|
|
|
20539
20550
|
ids.add(command.id);
|
|
20540
20551
|
}
|
|
20541
20552
|
});
|
|
20542
|
-
var harnessCommandsInspectParamsSchema = external_exports.object({
|
|
20553
|
+
var harnessCommandsInspectParamsSchema = external_exports.object({
|
|
20554
|
+
harnessId: harnessIdSchema,
|
|
20555
|
+
/** Workspace of a draft without a Thread, for its live catalog when known. */
|
|
20556
|
+
cwd: external_exports.string().min(1).optional()
|
|
20557
|
+
}).strict();
|
|
20543
20558
|
var threadCommandsInspectParamsSchema = external_exports.object({
|
|
20544
20559
|
threadId: hostThreadIdSchema
|
|
20545
20560
|
}).strict();
|
|
@@ -20683,6 +20698,41 @@ var updateStatusResultSchema = external_exports.strictObject({
|
|
|
20683
20698
|
status: updateStatusSchema.nullable()
|
|
20684
20699
|
});
|
|
20685
20700
|
|
|
20701
|
+
// packages/shared-contracts/dist/delegation-mention.js
|
|
20702
|
+
var DELEGATION_MENTION_PATH_PREFIX = "subagent://codexhost.";
|
|
20703
|
+
var MENTION_LINK_PATTERN = /\[@([^\]\n]+)\]\(<?subagent:\/\/codexhost\.([a-z0-9][a-z0-9-]*)>?\)/gu;
|
|
20704
|
+
function stripDelegationMentions(text) {
|
|
20705
|
+
const mentions = [];
|
|
20706
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20707
|
+
const rewritten = text.replace(MENTION_LINK_PATTERN, (_match, label, harnessId) => {
|
|
20708
|
+
const trimmed = label.trim();
|
|
20709
|
+
if (!seen.has(harnessId)) {
|
|
20710
|
+
seen.add(harnessId);
|
|
20711
|
+
mentions.push({ harnessId, label: trimmed });
|
|
20712
|
+
}
|
|
20713
|
+
return `@${trimmed}`;
|
|
20714
|
+
});
|
|
20715
|
+
return { text: rewritten, mentions };
|
|
20716
|
+
}
|
|
20717
|
+
var COMMAND_LINK_PATTERN = /([ \t]*)\[@([^\]\n]+)\]\(<?subagent:\/\/codexhost-command\.([^)\s>]+)>?\)([ \t]*)/gu;
|
|
20718
|
+
function restoreHarnessCommandMentions(text) {
|
|
20719
|
+
let invocation = null;
|
|
20720
|
+
const rest = text.replace(COMMAND_LINK_PATTERN, (match, before, _label, encoded, after) => {
|
|
20721
|
+
if (invocation === null) {
|
|
20722
|
+
try {
|
|
20723
|
+
invocation = `/${decodeURIComponent(encoded)}`;
|
|
20724
|
+
} catch {
|
|
20725
|
+
return match;
|
|
20726
|
+
}
|
|
20727
|
+
}
|
|
20728
|
+
return before || after ? " " : "";
|
|
20729
|
+
});
|
|
20730
|
+
if (invocation === null)
|
|
20731
|
+
return text;
|
|
20732
|
+
const argumentsText = rest.trim();
|
|
20733
|
+
return argumentsText ? `${invocation} ${argumentsText}` : invocation;
|
|
20734
|
+
}
|
|
20735
|
+
|
|
20686
20736
|
// packages/shared-contracts/dist/index.js
|
|
20687
20737
|
var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
|
|
20688
20738
|
|
|
@@ -20777,6 +20827,231 @@ async function listOthers(adapter) {
|
|
|
20777
20827
|
}
|
|
20778
20828
|
}
|
|
20779
20829
|
|
|
20830
|
+
// packages/host-runtime/src/delegation-skill.ts
|
|
20831
|
+
import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
|
|
20832
|
+
import { mkdir as mkdir3, open as open3, readFile as readFile5, rename as rename2, rm as rm3, stat } from "node:fs/promises";
|
|
20833
|
+
import os2 from "node:os";
|
|
20834
|
+
import path6 from "node:path";
|
|
20835
|
+
var SKILL_VERSION = 7;
|
|
20836
|
+
var DELEGATION_SKILL_NAME = "codexhost-delegation";
|
|
20837
|
+
var SKILL_RELATIVE_PATH = path6.join("skills", DELEGATION_SKILL_NAME, "SKILL.md");
|
|
20838
|
+
var PREVIOUS_MANAGED_DIGESTS = [
|
|
20839
|
+
"9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
|
|
20840
|
+
"2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
|
|
20841
|
+
"aff258622dc8ff321f32b15620d081e578cb9c9ed1134d6a57f35ca8e7762c0a",
|
|
20842
|
+
"ba509f57e5448e796b3dfdd5031dcb08672eded50b61c0a54de84cfa02c49dd3",
|
|
20843
|
+
"d3ddf6db9bc5c5df825479c885bbbf0ca08da66f7057a12e02e1fdf57525149e",
|
|
20844
|
+
"15eb63519ff867e1536c97188a0c43738d7a49d38d4d6adeb7a1036726e7246d"
|
|
20845
|
+
];
|
|
20846
|
+
var CODEXHOST_DELEGATION_SKILL = `---
|
|
20847
|
+
name: codexhost-delegation
|
|
20848
|
+
version: ${SKILL_VERSION}
|
|
20849
|
+
description: >
|
|
20850
|
+
Delegate tasks to other coding agents, or read and follow up on existing
|
|
20851
|
+
external agent sessions. Use when the user asks another agent (including
|
|
20852
|
+
@agent) to independently perform a task, or asks to view a specified external
|
|
20853
|
+
session's content, progress, or results, send follow-up messages, wait, or
|
|
20854
|
+
cancel a task. Not for recapping the current conversation, discussing or
|
|
20855
|
+
configuring agents, or role-playing.
|
|
20856
|
+
---
|
|
20857
|
+
|
|
20858
|
+
# Execute the task
|
|
20859
|
+
|
|
20860
|
+
Before acting, run:
|
|
20861
|
+
|
|
20862
|
+
\`codexhost delegate --help\`
|
|
20863
|
+
|
|
20864
|
+
Use CLI help as the authoritative source for commands and behavior. Consult
|
|
20865
|
+
command-specific help for options and the Harness listing command when the
|
|
20866
|
+
target is unknown. Prefer compact output when supported, and use its task links
|
|
20867
|
+
directly for subsequent commands.
|
|
20868
|
+
|
|
20869
|
+
Use the Harness native defaults. Inspect the target when a Model or Thinking
|
|
20870
|
+
selection is needed or the default is unavailable.
|
|
20871
|
+
|
|
20872
|
+
For a new delegation, create an independent child session and submit the
|
|
20873
|
+
requested task. For an existing external session, resolve the target from the
|
|
20874
|
+
user-provided session link, identifier, or context and operate on that Thread
|
|
20875
|
+
directly; it need not have been created by the current assistant. If the target
|
|
20876
|
+
is ambiguous, ask the user to identify it. Keep requests to view or summarize a
|
|
20877
|
+
session read-only.
|
|
20878
|
+
|
|
20879
|
+
For a new or existing task, choose the appropriate next action based on the
|
|
20880
|
+
user’s request and the task:
|
|
20881
|
+
|
|
20882
|
+
- send a follow-up message to the same Thread;
|
|
20883
|
+
- cancel its current Turn;
|
|
20884
|
+
- read its current state immediately;
|
|
20885
|
+
- wait for a bounded period;
|
|
20886
|
+
- check it again later;
|
|
20887
|
+
- leave it running in the background.
|
|
20888
|
+
|
|
20889
|
+
Report the result returned by read or a completed wait, together with the target
|
|
20890
|
+
agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
|
|
20891
|
+
`;
|
|
20892
|
+
var CURRENT_DIGEST = createHash3("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
|
|
20893
|
+
function digest(value2) {
|
|
20894
|
+
return createHash3("sha256").update(value2).digest("hex");
|
|
20895
|
+
}
|
|
20896
|
+
function managedVersion(value2) {
|
|
20897
|
+
const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
|
|
20898
|
+
return match ? Number(match[1]) : null;
|
|
20899
|
+
}
|
|
20900
|
+
async function readOptional(filePath) {
|
|
20901
|
+
try {
|
|
20902
|
+
return await readFile5(filePath, "utf8");
|
|
20903
|
+
} catch (error51) {
|
|
20904
|
+
if (error51.code === "ENOENT") return null;
|
|
20905
|
+
throw error51;
|
|
20906
|
+
}
|
|
20907
|
+
}
|
|
20908
|
+
async function atomicWrite(filePath, content) {
|
|
20909
|
+
await mkdir3(path6.dirname(filePath), { recursive: true, mode: 448 });
|
|
20910
|
+
const temporaryPath = path6.join(path6.dirname(filePath), `.SKILL.md.${randomUUID2()}.tmp`);
|
|
20911
|
+
const handle = await open3(temporaryPath, "wx", 384);
|
|
20912
|
+
try {
|
|
20913
|
+
await handle.writeFile(content, "utf8");
|
|
20914
|
+
await handle.sync();
|
|
20915
|
+
} finally {
|
|
20916
|
+
await handle.close();
|
|
20917
|
+
}
|
|
20918
|
+
try {
|
|
20919
|
+
await rename2(temporaryPath, filePath);
|
|
20920
|
+
} finally {
|
|
20921
|
+
await rm3(temporaryPath, { force: true });
|
|
20922
|
+
}
|
|
20923
|
+
}
|
|
20924
|
+
async function installDelegationSkills(input = {}) {
|
|
20925
|
+
const home = input.homeDirectory ?? os2.homedir();
|
|
20926
|
+
const destinations = [
|
|
20927
|
+
path6.join(home, ".agents", SKILL_RELATIVE_PATH),
|
|
20928
|
+
path6.join(home, ".claude", SKILL_RELATIVE_PATH)
|
|
20929
|
+
];
|
|
20930
|
+
const knownDigests = /* @__PURE__ */ new Set([
|
|
20931
|
+
CURRENT_DIGEST,
|
|
20932
|
+
...PREVIOUS_MANAGED_DIGESTS,
|
|
20933
|
+
...input.previousManagedDigests ?? []
|
|
20934
|
+
]);
|
|
20935
|
+
const results = [];
|
|
20936
|
+
for (const destination of destinations) {
|
|
20937
|
+
const current = await readOptional(destination);
|
|
20938
|
+
if (current === CODEXHOST_DELEGATION_SKILL) {
|
|
20939
|
+
results.push({
|
|
20940
|
+
path: destination,
|
|
20941
|
+
status: "current",
|
|
20942
|
+
version: SKILL_VERSION,
|
|
20943
|
+
digest: CURRENT_DIGEST
|
|
20944
|
+
});
|
|
20945
|
+
continue;
|
|
20946
|
+
}
|
|
20947
|
+
if (current !== null) {
|
|
20948
|
+
const currentDigest = digest(current);
|
|
20949
|
+
const version2 = managedVersion(current);
|
|
20950
|
+
if (!knownDigests.has(currentDigest)) {
|
|
20951
|
+
results.push({ path: destination, status: "conflict", version: version2, digest: currentDigest });
|
|
20952
|
+
continue;
|
|
20953
|
+
}
|
|
20954
|
+
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
20955
|
+
results.push({
|
|
20956
|
+
path: destination,
|
|
20957
|
+
status: "updated",
|
|
20958
|
+
version: SKILL_VERSION,
|
|
20959
|
+
digest: CURRENT_DIGEST
|
|
20960
|
+
});
|
|
20961
|
+
continue;
|
|
20962
|
+
}
|
|
20963
|
+
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
20964
|
+
results.push({
|
|
20965
|
+
path: destination,
|
|
20966
|
+
status: "installed",
|
|
20967
|
+
version: SKILL_VERSION,
|
|
20968
|
+
digest: CURRENT_DIGEST
|
|
20969
|
+
});
|
|
20970
|
+
}
|
|
20971
|
+
for (const result of results) {
|
|
20972
|
+
if (result.status === "conflict") continue;
|
|
20973
|
+
const source = await readFile5(result.path, "utf8");
|
|
20974
|
+
const metadata = await stat(result.path);
|
|
20975
|
+
if (!metadata.isFile() || source !== CODEXHOST_DELEGATION_SKILL) {
|
|
20976
|
+
throw new Error(`Delegation Skill verification failed: ${result.path}`);
|
|
20977
|
+
}
|
|
20978
|
+
}
|
|
20979
|
+
const managed = results.filter((result) => result.status !== "conflict");
|
|
20980
|
+
if (managed.some((result) => result.digest !== CURRENT_DIGEST)) {
|
|
20981
|
+
throw new Error("Delegation Skill copies are inconsistent");
|
|
20982
|
+
}
|
|
20983
|
+
if (results.every((result) => result.status !== "conflict")) {
|
|
20984
|
+
const copies = await Promise.all(results.map((result) => readFile5(result.path, "utf8")));
|
|
20985
|
+
if (copies.some((copy) => copy !== copies[0])) {
|
|
20986
|
+
throw new Error("Delegation Skill copies are inconsistent");
|
|
20987
|
+
}
|
|
20988
|
+
}
|
|
20989
|
+
return results;
|
|
20990
|
+
}
|
|
20991
|
+
async function managedDelegationSkillReference(input = {}) {
|
|
20992
|
+
const filePath = path6.join(input.homeDirectory ?? os2.homedir(), ".agents", SKILL_RELATIVE_PATH);
|
|
20993
|
+
try {
|
|
20994
|
+
return await readOptional(filePath) === CODEXHOST_DELEGATION_SKILL ? { name: DELEGATION_SKILL_NAME, path: filePath } : null;
|
|
20995
|
+
} catch {
|
|
20996
|
+
return null;
|
|
20997
|
+
}
|
|
20998
|
+
}
|
|
20999
|
+
|
|
21000
|
+
// packages/host-runtime/src/delegation-mention-rewrite.ts
|
|
21001
|
+
function describeTargets(mentions) {
|
|
21002
|
+
return mentions.map(({ harnessId, label }) => `@${label} (Harness \`${harnessId}\`)`).join(", ");
|
|
21003
|
+
}
|
|
21004
|
+
function delegationMentionInstruction(mentions) {
|
|
21005
|
+
const plural = mentions.length > 1;
|
|
21006
|
+
return [
|
|
21007
|
+
`[codexhost delegation] The user mentioned ${describeTargets(mentions)}.`,
|
|
21008
|
+
`Use the ${DELEGATION_SKILL_NAME} skill to delegate this request to ${plural ? "each mentioned Harness" : "that Harness"}`,
|
|
21009
|
+
"with `codexhost delegate start --harness <id>`, instead of doing the task yourself."
|
|
21010
|
+
].join(" ");
|
|
21011
|
+
}
|
|
21012
|
+
function appendInstruction(text, mentions) {
|
|
21013
|
+
const instruction = delegationMentionInstruction(mentions);
|
|
21014
|
+
return text.trim().length === 0 ? instruction : `${text}
|
|
21015
|
+
|
|
21016
|
+
${instruction}`;
|
|
21017
|
+
}
|
|
21018
|
+
function rewriteDelegationMentionText(text) {
|
|
21019
|
+
const { text: stripped, mentions } = stripDelegationMentions(text);
|
|
21020
|
+
return mentions.length === 0 ? text : appendInstruction(stripped, mentions);
|
|
21021
|
+
}
|
|
21022
|
+
function isRecord(value2) {
|
|
21023
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
21024
|
+
}
|
|
21025
|
+
function rewriteDelegationMentionInput(input, skill) {
|
|
21026
|
+
const mentions = [];
|
|
21027
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21028
|
+
let lastTextIndex = -1;
|
|
21029
|
+
const rewritten = input.map((item, index) => {
|
|
21030
|
+
if (!isRecord(item) || item.type !== "text" || typeof item.text !== "string") return item;
|
|
21031
|
+
lastTextIndex = index;
|
|
21032
|
+
const result = stripDelegationMentions(item.text);
|
|
21033
|
+
for (const mention of result.mentions) {
|
|
21034
|
+
if (seen.has(mention.harnessId)) continue;
|
|
21035
|
+
seen.add(mention.harnessId);
|
|
21036
|
+
mentions.push(mention);
|
|
21037
|
+
}
|
|
21038
|
+
return result.mentions.length === 0 ? item : { ...item, text: result.text };
|
|
21039
|
+
});
|
|
21040
|
+
if (mentions.length === 0) return null;
|
|
21041
|
+
const target = rewritten[lastTextIndex];
|
|
21042
|
+
if (isRecord(target) && typeof target.text === "string") {
|
|
21043
|
+
rewritten[lastTextIndex] = {
|
|
21044
|
+
...target,
|
|
21045
|
+
text: appendInstruction(target.text, mentions)
|
|
21046
|
+
};
|
|
21047
|
+
}
|
|
21048
|
+
const hasSkill = rewritten.some(
|
|
21049
|
+
(item) => isRecord(item) && item.type === "skill" && item.name === skill?.name
|
|
21050
|
+
);
|
|
21051
|
+
if (skill && !hasSkill) rewritten.push({ type: "skill", name: skill.name, path: skill.path });
|
|
21052
|
+
return rewritten;
|
|
21053
|
+
}
|
|
21054
|
+
|
|
20780
21055
|
// packages/harness-adapter/dist/output-channel.js
|
|
20781
21056
|
var HarnessOutputChannel = class {
|
|
20782
21057
|
outputs;
|
|
@@ -20855,11 +21130,11 @@ var usageFields = /* @__PURE__ */ new Set([
|
|
|
20855
21130
|
"totalCredits",
|
|
20856
21131
|
"contextUsagePercent"
|
|
20857
21132
|
]);
|
|
20858
|
-
function
|
|
21133
|
+
function isRecord2(value2) {
|
|
20859
21134
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
20860
21135
|
}
|
|
20861
21136
|
function parseHostUsage(value2) {
|
|
20862
|
-
if (!
|
|
21137
|
+
if (!isRecord2(value2))
|
|
20863
21138
|
throw new Error("Harness Usage must be an object");
|
|
20864
21139
|
const keys = Object.keys(value2);
|
|
20865
21140
|
if (keys.length === 0)
|
|
@@ -20916,6 +21191,82 @@ function parseHostUsage(value2) {
|
|
|
20916
21191
|
return { ...value2 };
|
|
20917
21192
|
}
|
|
20918
21193
|
|
|
21194
|
+
// packages/harness-adapter/dist/live-command-catalog.js
|
|
21195
|
+
var COMMON_EXCLUDED_LIVE_COMMANDS = /* @__PURE__ */ new Set([
|
|
21196
|
+
// Session lifecycle
|
|
21197
|
+
"branch",
|
|
21198
|
+
"clear",
|
|
21199
|
+
"exit",
|
|
21200
|
+
"fork",
|
|
21201
|
+
"fresh",
|
|
21202
|
+
"new",
|
|
21203
|
+
"quit",
|
|
21204
|
+
"rename",
|
|
21205
|
+
"rename-chat",
|
|
21206
|
+
"reset",
|
|
21207
|
+
"resume",
|
|
21208
|
+
"rewind",
|
|
21209
|
+
"session",
|
|
21210
|
+
"sessions",
|
|
21211
|
+
// Desktop-owned configuration
|
|
21212
|
+
"autocompact",
|
|
21213
|
+
"color",
|
|
21214
|
+
"config",
|
|
21215
|
+
"effort",
|
|
21216
|
+
"fast",
|
|
21217
|
+
"keybindings",
|
|
21218
|
+
"model",
|
|
21219
|
+
"models",
|
|
21220
|
+
"output-style",
|
|
21221
|
+
"permissions",
|
|
21222
|
+
"settings",
|
|
21223
|
+
"statusline",
|
|
21224
|
+
"terminal-setup",
|
|
21225
|
+
"theme",
|
|
21226
|
+
"vim",
|
|
21227
|
+
// Trust and approval policy
|
|
21228
|
+
"always-approve",
|
|
21229
|
+
"auto-mode-setup",
|
|
21230
|
+
// Native login
|
|
21231
|
+
"login",
|
|
21232
|
+
"logout",
|
|
21233
|
+
// Work outliving the Turn
|
|
21234
|
+
"autopilot",
|
|
21235
|
+
"background",
|
|
21236
|
+
"bg",
|
|
21237
|
+
"goal",
|
|
21238
|
+
"jobs",
|
|
21239
|
+
"loop",
|
|
21240
|
+
"multitask",
|
|
21241
|
+
"queue",
|
|
21242
|
+
"remote-control",
|
|
21243
|
+
"schedule",
|
|
21244
|
+
"steer",
|
|
21245
|
+
// Native terminal UI
|
|
21246
|
+
"copy",
|
|
21247
|
+
"debug",
|
|
21248
|
+
"feedback",
|
|
21249
|
+
"heapdump",
|
|
21250
|
+
"share",
|
|
21251
|
+
"shell",
|
|
21252
|
+
// Plugin and MCP management
|
|
21253
|
+
"marketplace",
|
|
21254
|
+
"mcp",
|
|
21255
|
+
"plugins",
|
|
21256
|
+
"reload-plugins"
|
|
21257
|
+
]);
|
|
21258
|
+
var COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES = ["__", "hooks-"];
|
|
21259
|
+
function isExcludedLiveCommand(name, kind, extra = {}) {
|
|
21260
|
+
const normalized = name.trim().replace(/^\//u, "");
|
|
21261
|
+
if (new Set(extra.names ?? []).has(normalized))
|
|
21262
|
+
return true;
|
|
21263
|
+
if (extra.prefixes?.some((prefix) => normalized.startsWith(prefix)))
|
|
21264
|
+
return true;
|
|
21265
|
+
if (kind === "skill")
|
|
21266
|
+
return false;
|
|
21267
|
+
return COMMON_EXCLUDED_LIVE_COMMANDS.has(normalized) || COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
21268
|
+
}
|
|
21269
|
+
|
|
20919
21270
|
// packages/harness-adapter/dist/index.js
|
|
20920
21271
|
var packageMetadata = {
|
|
20921
21272
|
name: "@codexhost/harness-adapter",
|
|
@@ -20924,10 +21275,10 @@ var packageMetadata = {
|
|
|
20924
21275
|
|
|
20925
21276
|
// packages/mapping-store/dist/mapping-store.js
|
|
20926
21277
|
import { execFileSync } from "node:child_process";
|
|
20927
|
-
import { randomUUID as
|
|
21278
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
20928
21279
|
import { constants } from "node:fs";
|
|
20929
|
-
import { copyFile as copyFile2, mkdir as
|
|
20930
|
-
import
|
|
21280
|
+
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";
|
|
21281
|
+
import path7 from "node:path";
|
|
20931
21282
|
|
|
20932
21283
|
// packages/mapping-store/dist/records.js
|
|
20933
21284
|
var nonBlankTextSchema6 = external_exports.string().refine((value2) => value2.trim().length > 0, {
|
|
@@ -21078,7 +21429,7 @@ function systemErrorCode2(error51) {
|
|
|
21078
21429
|
}
|
|
21079
21430
|
async function exists(file2) {
|
|
21080
21431
|
try {
|
|
21081
|
-
await
|
|
21432
|
+
await stat2(file2);
|
|
21082
21433
|
return true;
|
|
21083
21434
|
} catch (error51) {
|
|
21084
21435
|
if (systemErrorCode2(error51) === "ENOENT")
|
|
@@ -21188,13 +21539,13 @@ var MappingStore = class {
|
|
|
21188
21539
|
#initialized = false;
|
|
21189
21540
|
#lockHandle = null;
|
|
21190
21541
|
constructor(options2) {
|
|
21191
|
-
this.#directory =
|
|
21192
|
-
this.#threadsDirectory =
|
|
21193
|
-
this.#delegationsDirectory =
|
|
21194
|
-
this.#backupsDirectory =
|
|
21195
|
-
this.#quarantineDirectory =
|
|
21196
|
-
this.#lockPath =
|
|
21197
|
-
this.#instanceId = options2.instanceId ??
|
|
21542
|
+
this.#directory = path7.resolve(options2.directory);
|
|
21543
|
+
this.#threadsDirectory = path7.join(this.#directory, "threads");
|
|
21544
|
+
this.#delegationsDirectory = path7.join(this.#directory, "delegations");
|
|
21545
|
+
this.#backupsDirectory = path7.join(this.#directory, "backups");
|
|
21546
|
+
this.#quarantineDirectory = path7.join(this.#directory, "quarantine");
|
|
21547
|
+
this.#lockPath = path7.join(this.#directory, "store.lock");
|
|
21548
|
+
this.#instanceId = options2.instanceId ?? randomUUID3();
|
|
21198
21549
|
this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
|
|
21199
21550
|
this.#beforeReplace = options2.beforeReplace;
|
|
21200
21551
|
}
|
|
@@ -21202,18 +21553,18 @@ var MappingStore = class {
|
|
|
21202
21553
|
if (this.#initialized)
|
|
21203
21554
|
return;
|
|
21204
21555
|
await Promise.all([
|
|
21205
|
-
|
|
21206
|
-
|
|
21207
|
-
|
|
21208
|
-
|
|
21556
|
+
mkdir4(this.#threadsDirectory, { recursive: true }),
|
|
21557
|
+
mkdir4(this.#delegationsDirectory, { recursive: true }),
|
|
21558
|
+
mkdir4(this.#backupsDirectory, { recursive: true }),
|
|
21559
|
+
mkdir4(this.#quarantineDirectory, { recursive: true })
|
|
21209
21560
|
]);
|
|
21210
21561
|
await this.#acquireLock();
|
|
21211
21562
|
try {
|
|
21212
21563
|
await this.#cleanupResidue();
|
|
21213
21564
|
const names = (await readdir2(this.#threadsDirectory)).filter((name) => name.endsWith(".json"));
|
|
21214
21565
|
for (const name of names) {
|
|
21215
|
-
const primary =
|
|
21216
|
-
const backup =
|
|
21566
|
+
const primary = path7.join(this.#threadsDirectory, name);
|
|
21567
|
+
const backup = path7.join(this.#backupsDirectory, name);
|
|
21217
21568
|
let record3 = null;
|
|
21218
21569
|
try {
|
|
21219
21570
|
record3 = await this.#readRecord(primary, name);
|
|
@@ -21222,31 +21573,31 @@ var MappingStore = class {
|
|
|
21222
21573
|
record3 = await this.#readRecord(backup, name);
|
|
21223
21574
|
await this.#replaceFile(primary, record3, false);
|
|
21224
21575
|
} catch (backupError) {
|
|
21225
|
-
const quarantine =
|
|
21226
|
-
await
|
|
21576
|
+
const quarantine = path7.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
|
|
21577
|
+
await rename3(primary, quarantine).catch(() => void 0);
|
|
21227
21578
|
void primaryError;
|
|
21228
21579
|
void backupError;
|
|
21229
21580
|
continue;
|
|
21230
21581
|
}
|
|
21231
21582
|
}
|
|
21232
21583
|
if (record3.state === "creating" && !record3.nativeSessionRef) {
|
|
21233
|
-
await
|
|
21234
|
-
await
|
|
21584
|
+
await rm4(primary, { force: true });
|
|
21585
|
+
await rm4(backup, { force: true });
|
|
21235
21586
|
continue;
|
|
21236
21587
|
}
|
|
21237
21588
|
this.#records.set(record3.hostThreadId, record3);
|
|
21238
21589
|
}
|
|
21239
21590
|
const delegationNames = (await readdir2(this.#delegationsDirectory)).filter((name) => name.endsWith(".json"));
|
|
21240
21591
|
for (const name of delegationNames) {
|
|
21241
|
-
const file2 =
|
|
21592
|
+
const file2 = path7.join(this.#delegationsDirectory, name);
|
|
21242
21593
|
try {
|
|
21243
|
-
const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await
|
|
21594
|
+
const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await readFile6(file2, "utf8")));
|
|
21244
21595
|
if (`${parsed.delegationId}.json` !== name)
|
|
21245
21596
|
throw new Error("filename mismatch");
|
|
21246
21597
|
this.#delegations.set(parsed.delegationId, parsed);
|
|
21247
21598
|
} catch {
|
|
21248
|
-
const quarantine =
|
|
21249
|
-
await
|
|
21599
|
+
const quarantine = path7.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
|
|
21600
|
+
await rename3(file2, quarantine).catch(() => void 0);
|
|
21250
21601
|
}
|
|
21251
21602
|
}
|
|
21252
21603
|
this.#rebuildIndexes();
|
|
@@ -21344,7 +21695,7 @@ var MappingStore = class {
|
|
|
21344
21695
|
}
|
|
21345
21696
|
async removeDelegation(delegationId) {
|
|
21346
21697
|
this.#requireInitialized();
|
|
21347
|
-
await
|
|
21698
|
+
await rm4(this.#delegationPath(delegationId), { force: true });
|
|
21348
21699
|
this.#delegations.delete(delegationId);
|
|
21349
21700
|
this.#rebuildIndexes();
|
|
21350
21701
|
}
|
|
@@ -21517,8 +21868,8 @@ var MappingStore = class {
|
|
|
21517
21868
|
if (!this.#records.has(hostThreadId))
|
|
21518
21869
|
return;
|
|
21519
21870
|
await Promise.all([
|
|
21520
|
-
|
|
21521
|
-
|
|
21871
|
+
rm4(this.#recordPath(hostThreadId), { force: true }),
|
|
21872
|
+
rm4(this.#backupPath(hostThreadId), { force: true })
|
|
21522
21873
|
]);
|
|
21523
21874
|
this.#records.delete(hostThreadId);
|
|
21524
21875
|
this.#rebuildIndexes();
|
|
@@ -21531,9 +21882,9 @@ var MappingStore = class {
|
|
|
21531
21882
|
if (handle)
|
|
21532
21883
|
await handle.close().catch(() => void 0);
|
|
21533
21884
|
try {
|
|
21534
|
-
const current = JSON.parse(await
|
|
21885
|
+
const current = JSON.parse(await readFile6(this.#lockPath, "utf8"));
|
|
21535
21886
|
if (current.instanceId === this.#instanceId)
|
|
21536
|
-
await
|
|
21887
|
+
await rm4(this.#lockPath, { force: true });
|
|
21537
21888
|
} catch {
|
|
21538
21889
|
}
|
|
21539
21890
|
}
|
|
@@ -21600,11 +21951,11 @@ var MappingStore = class {
|
|
|
21600
21951
|
this.#rebuildIndexes();
|
|
21601
21952
|
}
|
|
21602
21953
|
async #replaceFile(target, record3, preserveBackup) {
|
|
21603
|
-
const temp = `${target}.tmp-${
|
|
21954
|
+
const temp = `${target}.tmp-${randomUUID3()}`;
|
|
21604
21955
|
let handle = null;
|
|
21605
21956
|
try {
|
|
21606
21957
|
await this.#beforeReplace?.(cloneRecord(record3));
|
|
21607
|
-
handle = await
|
|
21958
|
+
handle = await open4(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
21608
21959
|
await handle.writeFile(`${JSON.stringify(record3, null, 2)}
|
|
21609
21960
|
`, "utf8");
|
|
21610
21961
|
await handle.sync();
|
|
@@ -21613,10 +21964,10 @@ var MappingStore = class {
|
|
|
21613
21964
|
if (preserveBackup && await exists(target)) {
|
|
21614
21965
|
await copyFile2(target, this.#backupPath(record3.hostThreadId));
|
|
21615
21966
|
}
|
|
21616
|
-
await
|
|
21967
|
+
await rename3(temp, target);
|
|
21617
21968
|
} catch (error51) {
|
|
21618
21969
|
await handle?.close().catch(() => void 0);
|
|
21619
|
-
await
|
|
21970
|
+
await rm4(temp, { force: true }).catch(() => void 0);
|
|
21620
21971
|
if (error51 instanceof MappingStoreError)
|
|
21621
21972
|
throw error51;
|
|
21622
21973
|
throw new MappingStoreError("IO_ERROR", "Mapping Store atomic replacement failed", {
|
|
@@ -21626,19 +21977,19 @@ var MappingStore = class {
|
|
|
21626
21977
|
}
|
|
21627
21978
|
async #replaceDelegationFile(record3) {
|
|
21628
21979
|
const target = this.#delegationPath(record3.delegationId);
|
|
21629
|
-
const temp = `${target}.tmp-${
|
|
21980
|
+
const temp = `${target}.tmp-${randomUUID3()}`;
|
|
21630
21981
|
let handle = null;
|
|
21631
21982
|
try {
|
|
21632
|
-
handle = await
|
|
21983
|
+
handle = await open4(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
21633
21984
|
await handle.writeFile(`${JSON.stringify(record3, null, 2)}
|
|
21634
21985
|
`, "utf8");
|
|
21635
21986
|
await handle.sync();
|
|
21636
21987
|
await handle.close();
|
|
21637
21988
|
handle = null;
|
|
21638
|
-
await
|
|
21989
|
+
await rename3(temp, target);
|
|
21639
21990
|
} catch (error51) {
|
|
21640
21991
|
await handle?.close().catch(() => void 0);
|
|
21641
|
-
await
|
|
21992
|
+
await rm4(temp, { force: true }).catch(() => void 0);
|
|
21642
21993
|
if (error51 instanceof MappingStoreError)
|
|
21643
21994
|
throw error51;
|
|
21644
21995
|
throw new MappingStoreError("IO_ERROR", "Delegation atomic replacement failed", {
|
|
@@ -21647,7 +21998,7 @@ var MappingStore = class {
|
|
|
21647
21998
|
}
|
|
21648
21999
|
}
|
|
21649
22000
|
async #readRecord(file2, expectedName) {
|
|
21650
|
-
const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await
|
|
22001
|
+
const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await readFile6(file2, "utf8")));
|
|
21651
22002
|
if (!parsed.success) {
|
|
21652
22003
|
throw new MappingStoreError("INVALID_RECORD", "Mapping Store record is invalid", {
|
|
21653
22004
|
cause: parsed.error
|
|
@@ -21665,15 +22016,15 @@ var MappingStore = class {
|
|
|
21665
22016
|
readdir2(this.#directory)
|
|
21666
22017
|
]);
|
|
21667
22018
|
await Promise.all([
|
|
21668
|
-
...threadNames.filter((name) => name.includes(".tmp-")).map((name) =>
|
|
21669
|
-
...delegationNames.filter((name) => name.includes(".tmp-")).map((name) =>
|
|
22019
|
+
...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm4(path7.join(this.#threadsDirectory, name), { force: true })),
|
|
22020
|
+
...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm4(path7.join(this.#delegationsDirectory, name), { force: true })),
|
|
21670
22021
|
// Renamed aside by #acquireLock; nothing reads them back, and they accumulate one per run.
|
|
21671
|
-
...rootNames.filter((name) => name.startsWith(`${
|
|
22022
|
+
...rootNames.filter((name) => name.startsWith(`${path7.basename(this.#lockPath)}.stale-`)).map((name) => rm4(path7.join(this.#directory, name), { force: true }))
|
|
21672
22023
|
]);
|
|
21673
22024
|
}
|
|
21674
22025
|
async #acquireLock() {
|
|
21675
22026
|
const attempt = async () => {
|
|
21676
|
-
const handle = await
|
|
22027
|
+
const handle = await open4(this.#lockPath, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
21677
22028
|
const lock = {
|
|
21678
22029
|
pid: process.pid,
|
|
21679
22030
|
instanceId: this.#instanceId,
|
|
@@ -21695,13 +22046,13 @@ var MappingStore = class {
|
|
|
21695
22046
|
}
|
|
21696
22047
|
let existing = {};
|
|
21697
22048
|
try {
|
|
21698
|
-
existing = JSON.parse(await
|
|
22049
|
+
existing = JSON.parse(await readFile6(this.#lockPath, "utf8"));
|
|
21699
22050
|
} catch {
|
|
21700
22051
|
}
|
|
21701
22052
|
if (typeof existing.pid === "number" && lockOwnerIsLive(existing)) {
|
|
21702
22053
|
throw new MappingStoreError("STORE_LOCKED", "Another codexhost process owns Mapping Store");
|
|
21703
22054
|
}
|
|
21704
|
-
await
|
|
22055
|
+
await rename3(this.#lockPath, `${this.#lockPath}.stale-${this.#now().getTime()}`).catch(() => void 0);
|
|
21705
22056
|
try {
|
|
21706
22057
|
this.#lockHandle = await attempt();
|
|
21707
22058
|
} catch (error51) {
|
|
@@ -21769,13 +22120,13 @@ var MappingStore = class {
|
|
|
21769
22120
|
await next;
|
|
21770
22121
|
}
|
|
21771
22122
|
#recordPath(hostThreadId) {
|
|
21772
|
-
return
|
|
22123
|
+
return path7.join(this.#threadsDirectory, `${hostThreadId}.json`);
|
|
21773
22124
|
}
|
|
21774
22125
|
#delegationPath(delegationId) {
|
|
21775
|
-
return
|
|
22126
|
+
return path7.join(this.#delegationsDirectory, `${delegationId}.json`);
|
|
21776
22127
|
}
|
|
21777
22128
|
#backupPath(hostThreadId) {
|
|
21778
|
-
return
|
|
22129
|
+
return path7.join(this.#backupsDirectory, `${hostThreadId}.json`);
|
|
21779
22130
|
}
|
|
21780
22131
|
#requireInitialized() {
|
|
21781
22132
|
if (!this.#initialized) {
|
|
@@ -21795,7 +22146,7 @@ var TITLE_MAX_LENGTH = 150;
|
|
|
21795
22146
|
var DESCRIPTION_MAX_LENGTH = 500;
|
|
21796
22147
|
var SERVER_NAME_MAX_LENGTH = 80;
|
|
21797
22148
|
var ELLIPSIS = "…";
|
|
21798
|
-
function
|
|
22149
|
+
function isRecord3(value2) {
|
|
21799
22150
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
21800
22151
|
}
|
|
21801
22152
|
function boundedText(value2, field, maxLength) {
|
|
@@ -21849,7 +22200,7 @@ function responseError(message) {
|
|
|
21849
22200
|
function responsePersist(value2) {
|
|
21850
22201
|
if (value2 === void 0 || value2 === null)
|
|
21851
22202
|
return null;
|
|
21852
|
-
if (!
|
|
22203
|
+
if (!isRecord3(value2) || Object.keys(value2).length !== 1 || value2.persist !== "session" && value2.persist !== "always") {
|
|
21853
22204
|
throw responseError("contains malformed persist metadata");
|
|
21854
22205
|
}
|
|
21855
22206
|
return value2.persist;
|
|
@@ -21895,7 +22246,7 @@ function projectCodexApprovalRequest(input) {
|
|
|
21895
22246
|
},
|
|
21896
22247
|
denyResponse,
|
|
21897
22248
|
parseResponse(result) {
|
|
21898
|
-
if (!
|
|
22249
|
+
if (!isRecord3(result) || typeof result.action !== "string") {
|
|
21899
22250
|
throw responseError("missing action");
|
|
21900
22251
|
}
|
|
21901
22252
|
if (Object.keys(result).some((key) => key !== "action" && key !== "content" && key !== "_meta")) {
|
|
@@ -21903,7 +22254,7 @@ function projectCodexApprovalRequest(input) {
|
|
|
21903
22254
|
}
|
|
21904
22255
|
const selectedPersist = responsePersist(result._meta);
|
|
21905
22256
|
if (result.action === "accept") {
|
|
21906
|
-
if ("content" in result && (!
|
|
22257
|
+
if ("content" in result && (!isRecord3(result.content) || Object.keys(result.content).length !== 0)) {
|
|
21907
22258
|
throw responseError("contains non-empty accepted content");
|
|
21908
22259
|
}
|
|
21909
22260
|
if (selectedPersist === "session") {
|
|
@@ -21963,7 +22314,7 @@ function projectApprovalChoices(input) {
|
|
|
21963
22314
|
},
|
|
21964
22315
|
denyResponse,
|
|
21965
22316
|
parseResponse(result) {
|
|
21966
|
-
if (!
|
|
22317
|
+
if (!isRecord3(result) || typeof result.action !== "string")
|
|
21967
22318
|
throw responseError("missing action");
|
|
21968
22319
|
if (Object.keys(result).some((key) => !["action", "content", "_meta"].includes(key))) {
|
|
21969
22320
|
throw responseError("contains unreviewed fields");
|
|
@@ -21978,7 +22329,7 @@ function projectApprovalChoices(input) {
|
|
|
21978
22329
|
return denyResponse;
|
|
21979
22330
|
}
|
|
21980
22331
|
const content = result.content;
|
|
21981
|
-
if (result.action !== "accept" || !
|
|
22332
|
+
if (result.action !== "accept" || !isRecord3(content) || Object.keys(content).length !== 1 || !interaction.actions.some(({ id: id2 }) => id2 === content.actionId)) {
|
|
21982
22333
|
throw responseError("contains an undeclared approval choice");
|
|
21983
22334
|
}
|
|
21984
22335
|
return { type: "approval", actionId: content.actionId };
|
|
@@ -21987,7 +22338,7 @@ function projectApprovalChoices(input) {
|
|
|
21987
22338
|
}
|
|
21988
22339
|
|
|
21989
22340
|
// packages/protocol-core/dist/codex-question.js
|
|
21990
|
-
function
|
|
22341
|
+
function isRecord4(value2) {
|
|
21991
22342
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
21992
22343
|
}
|
|
21993
22344
|
function responseError2(message) {
|
|
@@ -22056,7 +22407,7 @@ function projectCodexQuestionRequest(input) {
|
|
|
22056
22407
|
}
|
|
22057
22408
|
},
|
|
22058
22409
|
parseResponse(result) {
|
|
22059
|
-
if (!
|
|
22410
|
+
if (!isRecord4(result) || !isRecord4(result.answers)) {
|
|
22060
22411
|
throw responseError2("missing answers object");
|
|
22061
22412
|
}
|
|
22062
22413
|
const rawAnswers = result.answers;
|
|
@@ -22069,7 +22420,7 @@ function projectCodexQuestionRequest(input) {
|
|
|
22069
22420
|
const question = interaction.questions.find(({ id: id2 }) => id2 === questionId);
|
|
22070
22421
|
if (!question)
|
|
22071
22422
|
throw responseError2("contains an unknown Question ID");
|
|
22072
|
-
if (!
|
|
22423
|
+
if (!isRecord4(answerValue) || !Array.isArray(answerValue.answers)) {
|
|
22073
22424
|
throw responseError2("answer entry has no answers array");
|
|
22074
22425
|
}
|
|
22075
22426
|
const values = answerValue.answers;
|
|
@@ -22151,7 +22502,7 @@ function projectCodexThreadUsage(input) {
|
|
|
22151
22502
|
}
|
|
22152
22503
|
|
|
22153
22504
|
// packages/protocol-core/dist/codex-native-usage.js
|
|
22154
|
-
function
|
|
22505
|
+
function isRecord5(value2) {
|
|
22155
22506
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
22156
22507
|
}
|
|
22157
22508
|
function nonNegativeSafeInteger(value2) {
|
|
@@ -22181,20 +22532,20 @@ function addBreakdown(target, source) {
|
|
|
22181
22532
|
}
|
|
22182
22533
|
}
|
|
22183
22534
|
function observeCodexTokenUsage(value2) {
|
|
22184
|
-
if (!
|
|
22535
|
+
if (!isRecord5(value2) || value2.method !== "thread/tokenUsage/updated")
|
|
22185
22536
|
return null;
|
|
22186
22537
|
const params = value2.params;
|
|
22187
|
-
if (!
|
|
22538
|
+
if (!isRecord5(params))
|
|
22188
22539
|
return null;
|
|
22189
22540
|
const threadId2 = hostThreadIdSchema.safeParse(params.threadId);
|
|
22190
22541
|
const turnId = hostTurnIdSchema.safeParse(params.turnId);
|
|
22191
22542
|
if (!threadId2.success || !turnId.success)
|
|
22192
22543
|
return null;
|
|
22193
22544
|
const tokenUsage = params.tokenUsage;
|
|
22194
|
-
if (!
|
|
22545
|
+
if (!isRecord5(tokenUsage))
|
|
22195
22546
|
return null;
|
|
22196
|
-
const total =
|
|
22197
|
-
const last =
|
|
22547
|
+
const total = isRecord5(tokenUsage.total) ? tokenUsage.total : void 0;
|
|
22548
|
+
const last = isRecord5(tokenUsage.last) ? tokenUsage.last : void 0;
|
|
22198
22549
|
const usage = {};
|
|
22199
22550
|
addBreakdown(usage, total);
|
|
22200
22551
|
const contextUsedTokens = nonNegativeSafeInteger(last?.totalTokens);
|
|
@@ -22219,7 +22570,7 @@ function observeCodexTokenUsage(value2) {
|
|
|
22219
22570
|
}
|
|
22220
22571
|
}
|
|
22221
22572
|
function parseRateLimitWindow(value2) {
|
|
22222
|
-
if (!
|
|
22573
|
+
if (!isRecord5(value2))
|
|
22223
22574
|
return null;
|
|
22224
22575
|
const usedPercent = finitePercent(value2.usedPercent);
|
|
22225
22576
|
const windowDurationMins = nonNegativeSafeInteger(value2.windowDurationMins);
|
|
@@ -22230,7 +22581,7 @@ function parseRateLimitWindow(value2) {
|
|
|
22230
22581
|
return { usedPercent, windowDurationMins, ...resetsAt !== void 0 ? { resetsAt } : {} };
|
|
22231
22582
|
}
|
|
22232
22583
|
function parseRateLimitCandidate(value2, options2 = {}) {
|
|
22233
|
-
if (!
|
|
22584
|
+
if (!isRecord5(value2))
|
|
22234
22585
|
return null;
|
|
22235
22586
|
if (options2.genericOnly && value2.limitId !== void 0 && value2.limitId !== null && value2.limitId !== "codex") {
|
|
22236
22587
|
return null;
|
|
@@ -22240,16 +22591,16 @@ function parseRateLimitCandidate(value2, options2 = {}) {
|
|
|
22240
22591
|
return primary || secondary ? { primary, secondary } : null;
|
|
22241
22592
|
}
|
|
22242
22593
|
function rateLimitCandidates(value2) {
|
|
22243
|
-
if (!
|
|
22594
|
+
if (!isRecord5(value2))
|
|
22244
22595
|
return [];
|
|
22245
|
-
const result =
|
|
22246
|
-
if (!
|
|
22596
|
+
const result = isRecord5(value2.result) ? value2.result : value2;
|
|
22597
|
+
if (!isRecord5(result))
|
|
22247
22598
|
return [];
|
|
22248
22599
|
const candidates = [];
|
|
22249
22600
|
const base = parseRateLimitCandidate(result.rateLimits, { genericOnly: true });
|
|
22250
22601
|
if (base)
|
|
22251
22602
|
candidates.push(base);
|
|
22252
|
-
const notificationParams =
|
|
22603
|
+
const notificationParams = isRecord5(value2.params) ? value2.params : void 0;
|
|
22253
22604
|
const notificationSnapshot = parseRateLimitCandidate(notificationParams?.rateLimits, {
|
|
22254
22605
|
genericOnly: true
|
|
22255
22606
|
});
|
|
@@ -22293,14 +22644,14 @@ function parseAvailableCount(value2) {
|
|
|
22293
22644
|
return void 0;
|
|
22294
22645
|
}
|
|
22295
22646
|
function rateLimitResetCreditsSummary(value2) {
|
|
22296
|
-
if (!
|
|
22647
|
+
if (!isRecord5(value2))
|
|
22297
22648
|
return null;
|
|
22298
|
-
const result =
|
|
22299
|
-
const fromResult =
|
|
22649
|
+
const result = isRecord5(value2.result) ? value2.result : value2;
|
|
22650
|
+
const fromResult = isRecord5(result) && isRecord5(result.rateLimitResetCredits) ? result.rateLimitResetCredits : null;
|
|
22300
22651
|
if (fromResult)
|
|
22301
22652
|
return fromResult;
|
|
22302
|
-
const params =
|
|
22303
|
-
return
|
|
22653
|
+
const params = isRecord5(value2.params) ? value2.params : void 0;
|
|
22654
|
+
return isRecord5(params?.rateLimitResetCredits) ? params.rateLimitResetCredits : null;
|
|
22304
22655
|
}
|
|
22305
22656
|
function observeCodexRateLimitResetCredits(value2) {
|
|
22306
22657
|
const summary = rateLimitResetCreditsSummary(value2);
|
|
@@ -22312,7 +22663,7 @@ function observeCodexRateLimitResetCredits(value2) {
|
|
|
22312
22663
|
const expiresAtUnix = [];
|
|
22313
22664
|
if (Array.isArray(summary.credits)) {
|
|
22314
22665
|
for (const credit of summary.credits) {
|
|
22315
|
-
if (!
|
|
22666
|
+
if (!isRecord5(credit))
|
|
22316
22667
|
continue;
|
|
22317
22668
|
if (credit.status !== void 0 && credit.status !== "available")
|
|
22318
22669
|
continue;
|
|
@@ -22463,16 +22814,16 @@ var Diff = class {
|
|
|
22463
22814
|
}
|
|
22464
22815
|
}
|
|
22465
22816
|
}
|
|
22466
|
-
addToPath(
|
|
22467
|
-
const last =
|
|
22817
|
+
addToPath(path29, added, removed, oldPosInc, options2) {
|
|
22818
|
+
const last = path29.lastComponent;
|
|
22468
22819
|
if (last && !options2.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
22469
22820
|
return {
|
|
22470
|
-
oldPos:
|
|
22821
|
+
oldPos: path29.oldPos + oldPosInc,
|
|
22471
22822
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
22472
22823
|
};
|
|
22473
22824
|
} else {
|
|
22474
22825
|
return {
|
|
22475
|
-
oldPos:
|
|
22826
|
+
oldPos: path29.oldPos + oldPosInc,
|
|
22476
22827
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
22477
22828
|
};
|
|
22478
22829
|
}
|
|
@@ -22900,11 +23251,14 @@ function splitLines(text) {
|
|
|
22900
23251
|
return result;
|
|
22901
23252
|
}
|
|
22902
23253
|
|
|
23254
|
+
// packages/protocol-core/dist/codex-ui-projector.js
|
|
23255
|
+
import path9 from "node:path";
|
|
23256
|
+
|
|
22903
23257
|
// packages/protocol-core/dist/file-change-summary.js
|
|
22904
|
-
import
|
|
23258
|
+
import path8 from "node:path";
|
|
22905
23259
|
function filePathKey(file2, cwd) {
|
|
22906
23260
|
const windows = /^[a-z]:[/\\]/i.test(cwd) || /^[a-z]:[/\\]/i.test(file2);
|
|
22907
|
-
const paths = windows ?
|
|
23261
|
+
const paths = windows ? path8.win32 : path8.posix;
|
|
22908
23262
|
const resolved = paths.resolve(cwd, file2).replaceAll("\\", "/");
|
|
22909
23263
|
return windows ? resolved.toLowerCase() : resolved;
|
|
22910
23264
|
}
|
|
@@ -23055,11 +23409,11 @@ function itemStatus(outcome) {
|
|
|
23055
23409
|
return "inProgress";
|
|
23056
23410
|
return outcome.status === "succeeded" ? "completed" : "failed";
|
|
23057
23411
|
}
|
|
23058
|
-
function
|
|
23412
|
+
function isRecord6(value2) {
|
|
23059
23413
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
23060
23414
|
}
|
|
23061
23415
|
function nestedString(value2, keys, preserveText = false) {
|
|
23062
|
-
if (!
|
|
23416
|
+
if (!isRecord6(value2))
|
|
23063
23417
|
return void 0;
|
|
23064
23418
|
for (const key of keys) {
|
|
23065
23419
|
const field = value2[key];
|
|
@@ -23073,6 +23427,14 @@ function nestedString(value2, keys, preserveText = false) {
|
|
|
23073
23427
|
}
|
|
23074
23428
|
return void 0;
|
|
23075
23429
|
}
|
|
23430
|
+
function toolWorkingDirectory(args, defaultCwd) {
|
|
23431
|
+
const workdir = nestedString(args, ["workdir"]);
|
|
23432
|
+
if (workdir === void 0)
|
|
23433
|
+
return defaultCwd;
|
|
23434
|
+
const windows = /^(?:[a-z]:[/\\]|\\\\)/iu;
|
|
23435
|
+
const paths = windows.test(defaultCwd) || windows.test(workdir) ? path9.win32 : path9.posix;
|
|
23436
|
+
return paths.resolve(defaultCwd, workdir);
|
|
23437
|
+
}
|
|
23076
23438
|
function toolOutputText(item) {
|
|
23077
23439
|
if (!item.output)
|
|
23078
23440
|
return null;
|
|
@@ -23082,7 +23444,7 @@ function toolOutputText(item) {
|
|
|
23082
23444
|
function toolCommandLine(toolName, args) {
|
|
23083
23445
|
const lower = toolName.toLowerCase().replaceAll(/[_-]/g, "");
|
|
23084
23446
|
const command = nestedString(args, ["command", "cmd", "script", "commandLine", "command_line"]);
|
|
23085
|
-
if (command && ["bash", "exec", "terminal", "run", "shell", "powershell", "command"].includes(lower)) {
|
|
23447
|
+
if (command && ["bash", "exec", "terminal", "run", "shell", "powershell", "pwsh", "command"].includes(lower)) {
|
|
23086
23448
|
return command;
|
|
23087
23449
|
}
|
|
23088
23450
|
const filePath = nestedString(args, [
|
|
@@ -23173,8 +23535,8 @@ function projectFileChangeKind(kind) {
|
|
|
23173
23535
|
return { type: kind };
|
|
23174
23536
|
}
|
|
23175
23537
|
function projectFileChanges(changes) {
|
|
23176
|
-
return changes.map(({ path:
|
|
23177
|
-
path:
|
|
23538
|
+
return changes.map(({ path: path29, kind, unifiedDiff }) => ({
|
|
23539
|
+
path: path29,
|
|
23178
23540
|
kind: projectFileChangeKind(kind),
|
|
23179
23541
|
diff: unifiedDiff
|
|
23180
23542
|
}));
|
|
@@ -23214,7 +23576,7 @@ function planFromTodoValue(value2) {
|
|
|
23214
23576
|
const record3 = unwrapToolRecord(value2);
|
|
23215
23577
|
if (!record3)
|
|
23216
23578
|
return planFromChecklistText(typeof value2 === "string" ? value2 : null);
|
|
23217
|
-
if (
|
|
23579
|
+
if (isRecord6(record3.TodosUpdated)) {
|
|
23218
23580
|
const nested = planFromTodoValue(record3.TodosUpdated);
|
|
23219
23581
|
if (nested)
|
|
23220
23582
|
return nested;
|
|
@@ -23229,7 +23591,7 @@ function planFromTodoValue(value2) {
|
|
|
23229
23591
|
plan.push({ step: entry.trim(), status: "pending" });
|
|
23230
23592
|
continue;
|
|
23231
23593
|
}
|
|
23232
|
-
if (!
|
|
23594
|
+
if (!isRecord6(entry))
|
|
23233
23595
|
continue;
|
|
23234
23596
|
const step = nestedString(entry, ["content", "step", "text", "title", "description", "task"]);
|
|
23235
23597
|
if (!step)
|
|
@@ -23284,7 +23646,7 @@ function unwrapToolRecord(value2) {
|
|
|
23284
23646
|
}
|
|
23285
23647
|
if (Array.isArray(value2))
|
|
23286
23648
|
return { todos: value2 };
|
|
23287
|
-
if (!
|
|
23649
|
+
if (!isRecord6(value2))
|
|
23288
23650
|
return null;
|
|
23289
23651
|
for (const wrapper of ["input", "arguments", "params"]) {
|
|
23290
23652
|
if (value2[wrapper] === void 0)
|
|
@@ -23339,13 +23701,15 @@ function projectItem(item, outcome, defaultCwd, includeCommandOutput = true, sen
|
|
|
23339
23701
|
phase: item.phase ?? null,
|
|
23340
23702
|
memoryCitation: null
|
|
23341
23703
|
};
|
|
23342
|
-
case "reasoning":
|
|
23704
|
+
case "reasoning": {
|
|
23705
|
+
const text = reasoningDisplayText(item.text);
|
|
23343
23706
|
return {
|
|
23344
23707
|
id: reasoningPreviewItemId(item.itemId),
|
|
23345
23708
|
type: "reasoning",
|
|
23346
|
-
summary:
|
|
23709
|
+
summary: text ? [text] : [],
|
|
23347
23710
|
content: []
|
|
23348
23711
|
};
|
|
23712
|
+
}
|
|
23349
23713
|
case "contextCompaction":
|
|
23350
23714
|
return { id: item.itemId, type: "contextCompaction" };
|
|
23351
23715
|
case "commandExecution":
|
|
@@ -23369,13 +23733,13 @@ function projectItem(item, outcome, defaultCwd, includeCommandOutput = true, sen
|
|
|
23369
23733
|
id: item.itemId,
|
|
23370
23734
|
type: "commandExecution",
|
|
23371
23735
|
command,
|
|
23372
|
-
cwd: defaultCwd,
|
|
23736
|
+
cwd: toolWorkingDirectory(item.arguments, defaultCwd),
|
|
23373
23737
|
processId: null,
|
|
23374
23738
|
source: "agent",
|
|
23375
23739
|
status: itemStatus(outcome),
|
|
23376
23740
|
commandActions: [],
|
|
23377
23741
|
aggregatedOutput: includeCommandOutput ? toolOutputText(item) : null,
|
|
23378
|
-
exitCode:
|
|
23742
|
+
exitCode: null,
|
|
23379
23743
|
durationMs: item.durationMs ?? null
|
|
23380
23744
|
};
|
|
23381
23745
|
}
|
|
@@ -23423,6 +23787,9 @@ function projectItem(item, outcome, defaultCwd, includeCommandOutput = true, sen
|
|
|
23423
23787
|
function reasoningPreviewItemId(itemId) {
|
|
23424
23788
|
return `${itemId}-summary`;
|
|
23425
23789
|
}
|
|
23790
|
+
function reasoningDisplayText(text) {
|
|
23791
|
+
return text.replace(/[\r\n]+$/u, "");
|
|
23792
|
+
}
|
|
23426
23793
|
function projectReasoningTranscriptItem(item, outcome, defaultCwd, durationMs = null) {
|
|
23427
23794
|
return {
|
|
23428
23795
|
id: item.itemId,
|
|
@@ -23433,7 +23800,7 @@ function projectReasoningTranscriptItem(item, outcome, defaultCwd, durationMs =
|
|
|
23433
23800
|
source: "agent",
|
|
23434
23801
|
status: itemStatus(outcome),
|
|
23435
23802
|
commandActions: [],
|
|
23436
|
-
aggregatedOutput: item.text
|
|
23803
|
+
aggregatedOutput: reasoningDisplayText(item.text) || null,
|
|
23437
23804
|
exitCode: outcome ? 0 : null,
|
|
23438
23805
|
durationMs
|
|
23439
23806
|
};
|
|
@@ -23490,6 +23857,8 @@ function projectHistoricalTurn(input) {
|
|
|
23490
23857
|
if (isFileMutatingTool(item.toolName))
|
|
23491
23858
|
return [];
|
|
23492
23859
|
}
|
|
23860
|
+
if (item.type === "reasoning" && !reasoningDisplayText(item.text))
|
|
23861
|
+
return [];
|
|
23493
23862
|
return item.type === "reasoning" ? [
|
|
23494
23863
|
projectItem(item, outcome, cwd, true, input.threadId ?? ""),
|
|
23495
23864
|
projectReasoningTranscriptItem(item, outcome, cwd)
|
|
@@ -23679,7 +24048,7 @@ var CodexTurnProjector = class {
|
|
|
23679
24048
|
startedAtMs
|
|
23680
24049
|
};
|
|
23681
24050
|
this.#items.set(event.item.itemId, projected);
|
|
23682
|
-
if ((event.item.type === "agentMessage" || event.item.type === "reasoning") && event.item.text.length === 0) {
|
|
24051
|
+
if ((event.item.type === "agentMessage" || event.item.type === "reasoning") && (event.item.type === "reasoning" ? reasoningDisplayText(event.item.text).length === 0 : event.item.text.length === 0)) {
|
|
23683
24052
|
return { messages: [] };
|
|
23684
24053
|
}
|
|
23685
24054
|
if (event.item.type === "toolExecution") {
|
|
@@ -23699,7 +24068,8 @@ var CodexTurnProjector = class {
|
|
|
23699
24068
|
const startedItem = event.item.type === "reasoning" ? { ...event.item, text: "" } : event.item;
|
|
23700
24069
|
const messages = [this.#startWireItem(projected, startedItem, startedAtMs)];
|
|
23701
24070
|
if (event.item.type === "reasoning") {
|
|
23702
|
-
|
|
24071
|
+
const text = reasoningDisplayText(event.item.text);
|
|
24072
|
+
messages.push(this.#startReasoningTranscript(event.item, startedAtMs), this.#reasoningOutputDelta(event.item.itemId, text, startedAtMs), ...this.#reasoningDelta(projected, text, startedAtMs));
|
|
23703
24073
|
}
|
|
23704
24074
|
return { messages };
|
|
23705
24075
|
}
|
|
@@ -23727,10 +24097,14 @@ var CodexTurnProjector = class {
|
|
|
23727
24097
|
}
|
|
23728
24098
|
});
|
|
23729
24099
|
} else if (next.type === "reasoning") {
|
|
24100
|
+
const previousText = previous.type === "reasoning" ? reasoningDisplayText(previous.text) : "";
|
|
24101
|
+
const delta = reasoningDisplayText(next.text).slice(previousText.length);
|
|
24102
|
+
if (!delta)
|
|
24103
|
+
return { messages };
|
|
23730
24104
|
if (!projected.wireStarted) {
|
|
23731
24105
|
messages.push(this.#startWireItem(projected, { ...next, text: "" }, emittedAtMs), this.#startReasoningTranscript({ ...next, text: "" }, emittedAtMs));
|
|
23732
24106
|
}
|
|
23733
|
-
messages.push(this.#reasoningOutputDelta(event.itemId,
|
|
24107
|
+
messages.push(this.#reasoningOutputDelta(event.itemId, delta, emittedAtMs), ...this.#reasoningDelta(projected, delta, emittedAtMs));
|
|
23734
24108
|
}
|
|
23735
24109
|
} else if (event.update.type === "output.append") {
|
|
23736
24110
|
projected.streamedCommandOutput = true;
|
|
@@ -24074,7 +24448,7 @@ var CodexTurnProjector = class {
|
|
|
24074
24448
|
};
|
|
24075
24449
|
|
|
24076
24450
|
// packages/protocol-core/dist/thread-fork.js
|
|
24077
|
-
function
|
|
24451
|
+
function isRecord7(value2) {
|
|
24078
24452
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
24079
24453
|
}
|
|
24080
24454
|
function optionalText(params, name, options2 = {}) {
|
|
@@ -24097,7 +24471,7 @@ function optionalBoolean(params, name) {
|
|
|
24097
24471
|
function decodeThreadForkRequest(request) {
|
|
24098
24472
|
if (request.method !== "thread/fork")
|
|
24099
24473
|
return null;
|
|
24100
|
-
if (!
|
|
24474
|
+
if (!isRecord7(request.params))
|
|
24101
24475
|
throw new Error("thread/fork params must be an object");
|
|
24102
24476
|
const params = request.params;
|
|
24103
24477
|
const threadId2 = optionalText(params, "threadId");
|
|
@@ -24112,13 +24486,13 @@ function decodeThreadForkRequest(request) {
|
|
|
24112
24486
|
if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
|
|
24113
24487
|
throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
|
|
24114
24488
|
}
|
|
24115
|
-
const
|
|
24489
|
+
const path29 = optionalText(params, "path", { allowEmpty: true });
|
|
24116
24490
|
const ephemeral = optionalBoolean(params, "ephemeral");
|
|
24117
24491
|
return {
|
|
24118
24492
|
threadId: threadId2,
|
|
24119
24493
|
...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
|
|
24120
24494
|
...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
|
|
24121
|
-
...
|
|
24495
|
+
...path29 ? { path: path29 } : {},
|
|
24122
24496
|
...optionalField(params, "model"),
|
|
24123
24497
|
...optionalField(params, "modelProvider"),
|
|
24124
24498
|
...optionalField(params, "cwd"),
|
|
@@ -24133,7 +24507,7 @@ function decodeThreadForkRequest(request) {
|
|
|
24133
24507
|
function decodeThreadRevertRequest(request) {
|
|
24134
24508
|
if (request.method !== "thread/revert")
|
|
24135
24509
|
return null;
|
|
24136
|
-
if (!
|
|
24510
|
+
if (!isRecord7(request.params))
|
|
24137
24511
|
throw new Error("thread/revert params must be an object");
|
|
24138
24512
|
const { threadId: threadId2, beforeTurnId } = request.params;
|
|
24139
24513
|
if (typeof threadId2 !== "string" || threadId2.length === 0) {
|
|
@@ -24147,7 +24521,7 @@ function decodeThreadRevertRequest(request) {
|
|
|
24147
24521
|
function decodeThreadRollbackRequest(request) {
|
|
24148
24522
|
if (request.method !== "thread/rollback")
|
|
24149
24523
|
return null;
|
|
24150
|
-
if (!
|
|
24524
|
+
if (!isRecord7(request.params))
|
|
24151
24525
|
throw new Error("thread/rollback params must be an object");
|
|
24152
24526
|
const { threadId: threadId2, numTurns } = request.params;
|
|
24153
24527
|
if (typeof threadId2 !== "string" || threadId2.length === 0) {
|
|
@@ -24211,7 +24585,7 @@ function threadForkResult(thread, input) {
|
|
|
24211
24585
|
}
|
|
24212
24586
|
|
|
24213
24587
|
// packages/protocol-core/dist/thread-management.js
|
|
24214
|
-
import { createHash as
|
|
24588
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
24215
24589
|
var HOST_CURSOR_PREFIX = "codexhost:thread-list:v1:";
|
|
24216
24590
|
var MAX_CURSOR_LENGTH = 65536;
|
|
24217
24591
|
var DEFAULT_PAGE_SIZE = 25;
|
|
@@ -24244,13 +24618,13 @@ var THREAD_SOURCE_KINDS = /* @__PURE__ */ new Set([
|
|
|
24244
24618
|
"subAgentOther",
|
|
24245
24619
|
"unknown"
|
|
24246
24620
|
]);
|
|
24247
|
-
function
|
|
24621
|
+
function isRecord8(value2) {
|
|
24248
24622
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
24249
24623
|
}
|
|
24250
24624
|
function paramsObject(request, method) {
|
|
24251
24625
|
if (request.params === void 0 && method === "thread/list")
|
|
24252
24626
|
return {};
|
|
24253
|
-
if (!
|
|
24627
|
+
if (!isRecord8(request.params))
|
|
24254
24628
|
throw new Error(`${method} params must be an object`);
|
|
24255
24629
|
return request.params;
|
|
24256
24630
|
}
|
|
@@ -24308,7 +24682,7 @@ function decodeSortKey(value2) {
|
|
|
24308
24682
|
return value2;
|
|
24309
24683
|
}
|
|
24310
24684
|
function queryFingerprint(value2) {
|
|
24311
|
-
return
|
|
24685
|
+
return createHash4("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
24312
24686
|
}
|
|
24313
24687
|
function cursorPayload(value2) {
|
|
24314
24688
|
return {
|
|
@@ -24322,7 +24696,7 @@ function cursorPayload(value2) {
|
|
|
24322
24696
|
};
|
|
24323
24697
|
}
|
|
24324
24698
|
function parseCursorPayload(value2) {
|
|
24325
|
-
if (!
|
|
24699
|
+
if (!isRecord8(value2) || value2.formatVersion !== 1)
|
|
24326
24700
|
throw new Error("Host cursor is invalid");
|
|
24327
24701
|
const { queryFingerprint: fingerprint, sortDirection: sortDirection2, officialCursor, officialDone } = value2;
|
|
24328
24702
|
const { externalAnchor: externalAnchor2, externalDone } = value2;
|
|
@@ -24331,7 +24705,7 @@ function parseCursorPayload(value2) {
|
|
|
24331
24705
|
}
|
|
24332
24706
|
let anchor = null;
|
|
24333
24707
|
if (externalAnchor2 !== null) {
|
|
24334
|
-
if (!
|
|
24708
|
+
if (!isRecord8(externalAnchor2) || !Number.isSafeInteger(externalAnchor2.timestamp) || typeof externalAnchor2.threadId !== "string" || externalAnchor2.threadId.length === 0) {
|
|
24335
24709
|
throw new Error("Host cursor is invalid");
|
|
24336
24710
|
}
|
|
24337
24711
|
anchor = {
|
|
@@ -24454,7 +24828,7 @@ function decodeThreadMetadataUpdateRequest(request) {
|
|
|
24454
24828
|
if (params.gitInfo === null) {
|
|
24455
24829
|
gitInfo = null;
|
|
24456
24830
|
} else if (params.gitInfo !== void 0) {
|
|
24457
|
-
if (!
|
|
24831
|
+
if (!isRecord8(params.gitInfo)) {
|
|
24458
24832
|
throw new Error("thread/metadata/update params.gitInfo must be an object or null");
|
|
24459
24833
|
}
|
|
24460
24834
|
gitInfo = {};
|
|
@@ -24482,7 +24856,7 @@ function optionalCursor(value2, name) {
|
|
|
24482
24856
|
return value2;
|
|
24483
24857
|
}
|
|
24484
24858
|
function decodeOfficialThreadListPage(value2) {
|
|
24485
|
-
if (!
|
|
24859
|
+
if (!isRecord8(value2) || !Array.isArray(value2.data) || value2.data.some((row) => !isRecord8(row))) {
|
|
24486
24860
|
throw new Error("Official thread/list response is invalid");
|
|
24487
24861
|
}
|
|
24488
24862
|
return {
|
|
@@ -25294,22 +25668,22 @@ var HarnessAccountInspectionCache = class {
|
|
|
25294
25668
|
};
|
|
25295
25669
|
|
|
25296
25670
|
// packages/host-runtime/src/app-server-host.ts
|
|
25297
|
-
import { createHash as
|
|
25298
|
-
import
|
|
25299
|
-
import
|
|
25671
|
+
import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
|
|
25672
|
+
import os5 from "node:os";
|
|
25673
|
+
import path16 from "node:path";
|
|
25300
25674
|
|
|
25301
25675
|
// packages/host-runtime/src/external-thread-fork.ts
|
|
25302
25676
|
import nodePath from "node:path";
|
|
25303
25677
|
|
|
25304
25678
|
// packages/host-runtime/src/external-thread-repository.ts
|
|
25305
|
-
import { randomUUID as
|
|
25306
|
-
import
|
|
25307
|
-
import
|
|
25679
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
25680
|
+
import os3 from "node:os";
|
|
25681
|
+
import path10 from "node:path";
|
|
25308
25682
|
|
|
25309
25683
|
// packages/host-runtime/src/external-subagent-threads.ts
|
|
25310
|
-
import { createHash as
|
|
25684
|
+
import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypto";
|
|
25311
25685
|
function childCreateRequest(parent, nativeRef, id2) {
|
|
25312
|
-
const key =
|
|
25686
|
+
const key = createHash5("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
|
|
25313
25687
|
return `subagent:${key}`;
|
|
25314
25688
|
}
|
|
25315
25689
|
function subagentMaterializer(store, parent, previousParent) {
|
|
@@ -25382,7 +25756,7 @@ function subagentMaterializer(store, parent, previousParent) {
|
|
|
25382
25756
|
return rebind(existing, parent);
|
|
25383
25757
|
}
|
|
25384
25758
|
const provisional = existing ?? await store.createProvisional({
|
|
25385
|
-
hostThreadId: hostThreadIdSchema.parse(
|
|
25759
|
+
hostThreadId: hostThreadIdSchema.parse(randomUUID4()),
|
|
25386
25760
|
createRequestId,
|
|
25387
25761
|
harnessId: parent.harnessId,
|
|
25388
25762
|
cwd: parent.cwd,
|
|
@@ -25444,8 +25818,8 @@ function sameMapping(left, right) {
|
|
|
25444
25818
|
}
|
|
25445
25819
|
function defaultMappingStoreDirectory(environment) {
|
|
25446
25820
|
const dataDirectory = environment.CODEXHOST_DATA_DIR;
|
|
25447
|
-
return
|
|
25448
|
-
dataDirectory ?
|
|
25821
|
+
return path10.join(
|
|
25822
|
+
dataDirectory ? path10.resolve(dataDirectory) : path10.join(os3.homedir(), ".codexhost"),
|
|
25449
25823
|
"mapping-store"
|
|
25450
25824
|
);
|
|
25451
25825
|
}
|
|
@@ -25542,7 +25916,7 @@ var ExternalThreadRepository = class {
|
|
|
25542
25916
|
throw new Error("Derived Snapshot identity does not belong to its Native Session");
|
|
25543
25917
|
}
|
|
25544
25918
|
return {
|
|
25545
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
25919
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
|
|
25546
25920
|
nativeTurnRef: turn.nativeTurnRef,
|
|
25547
25921
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
25548
25922
|
};
|
|
@@ -25662,7 +26036,7 @@ var ExternalThreadRepository = class {
|
|
|
25662
26036
|
const aligned = snapshot.turns.map((turn) => {
|
|
25663
26037
|
const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
|
|
25664
26038
|
const mapping = existing ?? {
|
|
25665
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
26039
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
|
|
25666
26040
|
nativeTurnRef: turn.nativeTurnRef,
|
|
25667
26041
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
25668
26042
|
};
|
|
@@ -25689,8 +26063,8 @@ var ExternalThreadRepository = class {
|
|
|
25689
26063
|
};
|
|
25690
26064
|
function createExternalThreadRecordInput(input) {
|
|
25691
26065
|
return {
|
|
25692
|
-
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(
|
|
25693
|
-
createRequestId: input.createRequestId ??
|
|
26066
|
+
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID5()),
|
|
26067
|
+
createRequestId: input.createRequestId ?? randomUUID5(),
|
|
25694
26068
|
harnessId: input.harnessId,
|
|
25695
26069
|
cwd: input.cwd,
|
|
25696
26070
|
...input.title ? { title: input.title } : {},
|
|
@@ -25851,6 +26225,7 @@ async function executeExternalThreadFork(input) {
|
|
|
25851
26225
|
return { ok: false, error: mapExternalThreadHarnessError(opened.error, "fork") };
|
|
25852
26226
|
}
|
|
25853
26227
|
const session = opened.value;
|
|
26228
|
+
const inheritedPermissionModeId = await inheritSourcePermissionMode(source, session);
|
|
25854
26229
|
try {
|
|
25855
26230
|
const derivedNativeRef = session.initialState.nativeRef;
|
|
25856
26231
|
if (!derivedNativeRef || derivedNativeRef.nativeSessionId === nativeSessionRef.nativeSessionId) {
|
|
@@ -25878,7 +26253,8 @@ async function executeExternalThreadFork(input) {
|
|
|
25878
26253
|
sessionId: source.sessionId,
|
|
25879
26254
|
thread,
|
|
25880
26255
|
turns: aligned.turns,
|
|
25881
|
-
...snapshot.value.state ? { restoredState: snapshot.value.state } : {}
|
|
26256
|
+
...snapshot.value.state ? { restoredState: snapshot.value.state } : {},
|
|
26257
|
+
...inheritedPermissionModeId ? { requestedPermissionModeId: inheritedPermissionModeId } : {}
|
|
25882
26258
|
});
|
|
25883
26259
|
return {
|
|
25884
26260
|
ok: true,
|
|
@@ -25896,6 +26272,23 @@ async function executeExternalThreadFork(input) {
|
|
|
25896
26272
|
};
|
|
25897
26273
|
}
|
|
25898
26274
|
}
|
|
26275
|
+
async function inheritSourcePermissionMode(source, session) {
|
|
26276
|
+
const sourceModeId = source.stateObserver.state.effectivePermissionModeId ?? source.requestedPermissionModeId;
|
|
26277
|
+
if (!sourceModeId) return void 0;
|
|
26278
|
+
const configuration = session.capabilities.configuration;
|
|
26279
|
+
if (!configuration.selectPermissionMode || permissionModeFixedAtCreate(configuration)) {
|
|
26280
|
+
return void 0;
|
|
26281
|
+
}
|
|
26282
|
+
try {
|
|
26283
|
+
const selected = await session.execute({
|
|
26284
|
+
type: "permissionMode.select",
|
|
26285
|
+
permissionModeId: sourceModeId
|
|
26286
|
+
});
|
|
26287
|
+
return selected.ok ? sourceModeId : void 0;
|
|
26288
|
+
} catch {
|
|
26289
|
+
return void 0;
|
|
26290
|
+
}
|
|
26291
|
+
}
|
|
25899
26292
|
|
|
25900
26293
|
// packages/host-runtime/src/harness-session-import.ts
|
|
25901
26294
|
function fixedError(code, message) {
|
|
@@ -27460,9 +27853,12 @@ var ExternalTurnSteering = class {
|
|
|
27460
27853
|
if (!cancelled.ok) throw new ExternalSteerError(-32074, cancelled.error.message);
|
|
27461
27854
|
const outcome = await Promise.race([terminal2.promise, failure.promise]);
|
|
27462
27855
|
clearTimeout(timeout);
|
|
27463
|
-
|
|
27464
|
-
|
|
27465
|
-
|
|
27856
|
+
const assertActive = () => {
|
|
27857
|
+
if (failureReason) throw failureReason;
|
|
27858
|
+
if (this.#closed)
|
|
27859
|
+
throw new ExternalSteerError(-32074, "External steering connection is closed");
|
|
27860
|
+
};
|
|
27861
|
+
assertActive();
|
|
27466
27862
|
if (outcome.status === "failed") throw new ExternalSteerError(-32074, outcome.error.message);
|
|
27467
27863
|
if (thread.persistenceError)
|
|
27468
27864
|
throw new ExternalSteerError(
|
|
@@ -27472,7 +27868,7 @@ var ExternalTurnSteering = class {
|
|
|
27472
27868
|
if (thread.running || thread.activeTurnId) {
|
|
27473
27869
|
throw new ExternalSteerError(-32072, "Another External Turn started before replacement");
|
|
27474
27870
|
}
|
|
27475
|
-
return await start(input.text);
|
|
27871
|
+
return await start(input.text, assertActive);
|
|
27476
27872
|
} finally {
|
|
27477
27873
|
clearTimeout(timeout);
|
|
27478
27874
|
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
@@ -27480,16 +27876,98 @@ var ExternalTurnSteering = class {
|
|
|
27480
27876
|
}
|
|
27481
27877
|
};
|
|
27482
27878
|
|
|
27483
|
-
// packages/host-runtime/src/
|
|
27484
|
-
|
|
27485
|
-
|
|
27486
|
-
|
|
27487
|
-
|
|
27488
|
-
|
|
27489
|
-
|
|
27490
|
-
|
|
27491
|
-
|
|
27492
|
-
|
|
27879
|
+
// packages/host-runtime/src/external-command-routing.ts
|
|
27880
|
+
var ExternalCommandError = class extends Error {
|
|
27881
|
+
constructor(code, message) {
|
|
27882
|
+
super(message);
|
|
27883
|
+
this.code = code;
|
|
27884
|
+
}
|
|
27885
|
+
code;
|
|
27886
|
+
};
|
|
27887
|
+
function isExternalCommandCandidate(text) {
|
|
27888
|
+
return /^\/[^\s/]+(?:\s|$)/u.test(text.trimStart());
|
|
27889
|
+
}
|
|
27890
|
+
async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
|
|
27891
|
+
let timeout;
|
|
27892
|
+
try {
|
|
27893
|
+
const result = await Promise.race([
|
|
27894
|
+
commands.list(),
|
|
27895
|
+
new Promise((resolve) => {
|
|
27896
|
+
timeout = setTimeout(() => resolve(null), timeoutMs);
|
|
27897
|
+
})
|
|
27898
|
+
]);
|
|
27899
|
+
return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
|
|
27900
|
+
} catch {
|
|
27901
|
+
return null;
|
|
27902
|
+
} finally {
|
|
27903
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
27904
|
+
}
|
|
27905
|
+
}
|
|
27906
|
+
async function resolveExternalCommand(commands, text, options2 = {}) {
|
|
27907
|
+
const catalog = await commands.list();
|
|
27908
|
+
if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
|
|
27909
|
+
const commandText = text.trim();
|
|
27910
|
+
const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
|
|
27911
|
+
if (commandText === command.invocation) return true;
|
|
27912
|
+
return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
|
|
27913
|
+
});
|
|
27914
|
+
if (!matched) {
|
|
27915
|
+
const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
|
|
27916
|
+
if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
|
|
27917
|
+
return null;
|
|
27918
|
+
}
|
|
27919
|
+
throw new ExternalCommandError(
|
|
27920
|
+
-32078,
|
|
27921
|
+
"External Harness does not expose the requested command"
|
|
27922
|
+
);
|
|
27923
|
+
}
|
|
27924
|
+
const argumentText = commandText.slice(matched.invocation.length).trimStart();
|
|
27925
|
+
return {
|
|
27926
|
+
commandId: matched.id,
|
|
27927
|
+
...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
|
|
27928
|
+
};
|
|
27929
|
+
}
|
|
27930
|
+
|
|
27931
|
+
// packages/host-runtime/src/live-command-catalog-cache.ts
|
|
27932
|
+
import path11 from "node:path";
|
|
27933
|
+
var MAX_ENTRIES = 64;
|
|
27934
|
+
function isLiveCommandCatalog(catalog, staticCatalog) {
|
|
27935
|
+
const staticIds = new Set(staticCatalog.commands.map(({ id: id2 }) => id2));
|
|
27936
|
+
return catalog.commands.some(({ id: id2 }) => !staticIds.has(id2));
|
|
27937
|
+
}
|
|
27938
|
+
var LiveCommandCatalogCache = class {
|
|
27939
|
+
#entries = /* @__PURE__ */ new Map();
|
|
27940
|
+
#key(harnessId, cwd) {
|
|
27941
|
+
return `${harnessId}\0${path11.resolve(cwd)}`;
|
|
27942
|
+
}
|
|
27943
|
+
remember(harnessId, cwd, catalog) {
|
|
27944
|
+
const key = this.#key(harnessId, cwd);
|
|
27945
|
+
this.#entries.delete(key);
|
|
27946
|
+
this.#entries.set(key, catalog);
|
|
27947
|
+
while (this.#entries.size > MAX_ENTRIES) {
|
|
27948
|
+
const oldest = this.#entries.keys().next().value;
|
|
27949
|
+
if (oldest === void 0) break;
|
|
27950
|
+
this.#entries.delete(oldest);
|
|
27951
|
+
}
|
|
27952
|
+
}
|
|
27953
|
+
lookup(harnessId, cwd) {
|
|
27954
|
+
return this.#entries.get(this.#key(harnessId, cwd));
|
|
27955
|
+
}
|
|
27956
|
+
};
|
|
27957
|
+
function sameWorkspace(left, right) {
|
|
27958
|
+
return path11.resolve(left) === path11.resolve(right);
|
|
27959
|
+
}
|
|
27960
|
+
|
|
27961
|
+
// packages/host-runtime/src/harness-delegation-coordinator.ts
|
|
27962
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "node:crypto";
|
|
27963
|
+
import path12 from "node:path";
|
|
27964
|
+
|
|
27965
|
+
// packages/host-runtime/src/delegation-snapshot.ts
|
|
27966
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
27967
|
+
var CURSOR_PREFIX = "codexhost:thread-messages:v1:";
|
|
27968
|
+
var DEFAULT_MESSAGE_LIMIT = 25;
|
|
27969
|
+
var MAX_MESSAGE_LIMIT = 100;
|
|
27970
|
+
function isRecord9(value2) {
|
|
27493
27971
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
27494
27972
|
}
|
|
27495
27973
|
function stringValue(value2) {
|
|
@@ -27498,12 +27976,12 @@ function stringValue(value2) {
|
|
|
27498
27976
|
function textFromUserItem(item) {
|
|
27499
27977
|
if (!Array.isArray(item.content)) return "";
|
|
27500
27978
|
return item.content.flatMap(
|
|
27501
|
-
(part) =>
|
|
27979
|
+
(part) => isRecord9(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []
|
|
27502
27980
|
).join("\n");
|
|
27503
27981
|
}
|
|
27504
27982
|
function threadStatus(value2, running) {
|
|
27505
27983
|
if (running) return "running";
|
|
27506
|
-
if (
|
|
27984
|
+
if (isRecord9(value2)) {
|
|
27507
27985
|
if (value2.type === "active") return "running";
|
|
27508
27986
|
}
|
|
27509
27987
|
return "completed";
|
|
@@ -27520,10 +27998,10 @@ function allVisibleMessages(turns) {
|
|
|
27520
27998
|
const turnId = stringValue(turn.id);
|
|
27521
27999
|
if (!turnId || !Array.isArray(turn.items)) continue;
|
|
27522
28000
|
const agentItems = turn.items.filter(
|
|
27523
|
-
(item) =>
|
|
28001
|
+
(item) => isRecord9(item) && item.type === "agentMessage"
|
|
27524
28002
|
);
|
|
27525
28003
|
for (const item of turn.items) {
|
|
27526
|
-
if (!
|
|
28004
|
+
if (!isRecord9(item)) continue;
|
|
27527
28005
|
const id2 = stringValue(item.id);
|
|
27528
28006
|
if (!id2) continue;
|
|
27529
28007
|
if (item.type === "userMessage") {
|
|
@@ -27539,7 +28017,7 @@ function allVisibleMessages(turns) {
|
|
|
27539
28017
|
return messages;
|
|
27540
28018
|
}
|
|
27541
28019
|
function cursorFingerprint(threadId2) {
|
|
27542
|
-
return
|
|
28020
|
+
return createHash6("sha256").update(threadId2).digest("hex");
|
|
27543
28021
|
}
|
|
27544
28022
|
function encodeCursor(threadId2, offset) {
|
|
27545
28023
|
const payload = JSON.stringify({ version: 1, fingerprint: cursorFingerprint(threadId2), offset });
|
|
@@ -27598,7 +28076,7 @@ function projectDelegationThreadSnapshot(input) {
|
|
|
27598
28076
|
const progress = latestTurnMessages.filter((message) => message.phase !== "final" && message.text.trim()).map(({ id: id2, turnId, text }) => ({ id: id2, turnId, text }));
|
|
27599
28077
|
const result = input.running ? { availability: "pending" } : final ? { availability: "available", text: final.text } : {
|
|
27600
28078
|
availability: "unavailable",
|
|
27601
|
-
...
|
|
28079
|
+
...isRecord9(latestTurn?.error) && typeof latestTurn.error.message === "string" ? { message: latestTurn.error.message } : {}
|
|
27602
28080
|
};
|
|
27603
28081
|
const offset = options2.view === "messages" ? decodeCursor(input.threadId, options2.cursor) : visible.length;
|
|
27604
28082
|
const page = options2.view === "messages" ? [] : void 0;
|
|
@@ -27634,10 +28112,10 @@ function terminal(status) {
|
|
|
27634
28112
|
return status === "completed" || status === "failed" || status === "interrupted";
|
|
27635
28113
|
}
|
|
27636
28114
|
function taskDigest(input) {
|
|
27637
|
-
return
|
|
28115
|
+
return createHash7("sha256").update(
|
|
27638
28116
|
JSON.stringify({
|
|
27639
28117
|
task: input.task,
|
|
27640
|
-
cwd:
|
|
28118
|
+
cwd: path12.resolve(input.cwd),
|
|
27641
28119
|
modelId: input.model?.id ?? null,
|
|
27642
28120
|
thinkingOptionId: input.thinkingOptionId ?? null
|
|
27643
28121
|
})
|
|
@@ -27708,7 +28186,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27708
28186
|
return {
|
|
27709
28187
|
harnessId: input.harnessId,
|
|
27710
28188
|
inspection: await adapter.inspect({
|
|
27711
|
-
...input.cwd ? { cwd:
|
|
28189
|
+
...input.cwd ? { cwd: path12.resolve(input.cwd) } : {},
|
|
27712
28190
|
...input.refresh !== void 0 ? { refresh: input.refresh } : {}
|
|
27713
28191
|
})
|
|
27714
28192
|
};
|
|
@@ -27722,7 +28200,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27722
28200
|
const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
|
|
27723
28201
|
return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
|
|
27724
28202
|
}
|
|
27725
|
-
const startInput = { ...input, parentThreadId, cwd:
|
|
28203
|
+
const startInput = { ...input, parentThreadId, cwd: path12.resolve(selectedCwd) };
|
|
27726
28204
|
if (!this.#adapters.has(input.harnessId)) {
|
|
27727
28205
|
throw new DelegationControlError(
|
|
27728
28206
|
"HARNESS_NOT_FOUND",
|
|
@@ -27762,10 +28240,10 @@ var HarnessDelegationCoordinator = class {
|
|
|
27762
28240
|
});
|
|
27763
28241
|
this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
|
|
27764
28242
|
}
|
|
27765
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
27766
|
-
const childThreadId = hostThreadIdSchema.parse(
|
|
27767
|
-
const turnId = hostTurnIdSchema.parse(
|
|
27768
|
-
const createRequestId = input.requestId ? `delegation:${input.requestId}` :
|
|
28243
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID6());
|
|
28244
|
+
const childThreadId = hostThreadIdSchema.parse(randomUUID6());
|
|
28245
|
+
const turnId = hostTurnIdSchema.parse(randomUUID6());
|
|
28246
|
+
const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID6();
|
|
27769
28247
|
let record3 = await this.#repository.createProvisional(
|
|
27770
28248
|
createExternalThreadRecordInput({
|
|
27771
28249
|
hostThreadId: childThreadId,
|
|
@@ -27897,7 +28375,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27897
28375
|
if (thread.running || thread.activeTurnId) {
|
|
27898
28376
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
27899
28377
|
}
|
|
27900
|
-
const turnId = hostTurnIdSchema.parse(
|
|
28378
|
+
const turnId = hostTurnIdSchema.parse(randomUUID6());
|
|
27901
28379
|
try {
|
|
27902
28380
|
await this.#startExternalTurn(thread, input.message, turnId);
|
|
27903
28381
|
} catch (error51) {
|
|
@@ -28151,7 +28629,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
28151
28629
|
|
|
28152
28630
|
// packages/host-runtime/src/harness-plugin-loader.ts
|
|
28153
28631
|
import { readdir as readdir3, realpath as realpath2 } from "node:fs/promises";
|
|
28154
|
-
import
|
|
28632
|
+
import path14 from "node:path";
|
|
28155
28633
|
import { pathToFileURL } from "node:url";
|
|
28156
28634
|
|
|
28157
28635
|
// packages/host-runtime/src/harness-plugin-registry.ts
|
|
@@ -28188,25 +28666,25 @@ var HarnessPluginRegistry = class {
|
|
|
28188
28666
|
};
|
|
28189
28667
|
|
|
28190
28668
|
// packages/host-runtime/src/plugin-files.ts
|
|
28191
|
-
import { open as
|
|
28192
|
-
import
|
|
28669
|
+
import { open as open5, realpath, stat as stat3 } from "node:fs/promises";
|
|
28670
|
+
import path13 from "node:path";
|
|
28193
28671
|
function inside(root, candidate) {
|
|
28194
|
-
const relative =
|
|
28195
|
-
return relative !== "" && !
|
|
28672
|
+
const relative = path13.relative(root, candidate);
|
|
28673
|
+
return relative !== "" && !path13.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path13.sep}`);
|
|
28196
28674
|
}
|
|
28197
28675
|
async function pluginResourcePath(root, relative) {
|
|
28198
|
-
if (
|
|
28676
|
+
if (path13.isAbsolute(relative) || !inside(root, path13.resolve(root, relative))) {
|
|
28199
28677
|
throw new Error("Plugin resource escapes its root");
|
|
28200
28678
|
}
|
|
28201
|
-
const resolved = await realpath(
|
|
28202
|
-
if (!inside(root, resolved) || !(await
|
|
28679
|
+
const resolved = await realpath(path13.resolve(root, relative));
|
|
28680
|
+
if (!inside(root, resolved) || !(await stat3(resolved)).isFile()) {
|
|
28203
28681
|
throw new Error("Plugin resource must be a regular file inside its root");
|
|
28204
28682
|
}
|
|
28205
28683
|
return resolved;
|
|
28206
28684
|
}
|
|
28207
28685
|
async function readPluginFile(file2, maximum) {
|
|
28208
|
-
if (!(await
|
|
28209
|
-
const handle = await
|
|
28686
|
+
if (!(await stat3(file2)).isFile()) throw new Error("Plugin resource is not a regular file");
|
|
28687
|
+
const handle = await open5(file2, "r");
|
|
28210
28688
|
try {
|
|
28211
28689
|
const info = await handle.stat();
|
|
28212
28690
|
if (!info.isFile() || info.size > maximum) throw new Error("Plugin resource exceeds its limit");
|
|
@@ -28360,7 +28838,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
28360
28838
|
const enabledIds = /* @__PURE__ */ new Set();
|
|
28361
28839
|
const roots = /* @__PURE__ */ new Set();
|
|
28362
28840
|
for (const configuredRoot of options2.roots) {
|
|
28363
|
-
if (!
|
|
28841
|
+
if (!path14.isAbsolute(configuredRoot)) {
|
|
28364
28842
|
diagnose({ code: "invalidRoot" });
|
|
28365
28843
|
continue;
|
|
28366
28844
|
}
|
|
@@ -28390,7 +28868,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
28390
28868
|
for (const directory of directories) {
|
|
28391
28869
|
try {
|
|
28392
28870
|
const file2 = await pluginResourcePath(root, `${directory.name}/manifest.json`);
|
|
28393
|
-
const pluginRoot = await realpath2(
|
|
28871
|
+
const pluginRoot = await realpath2(path14.join(root, directory.name));
|
|
28394
28872
|
await pluginResourcePath(pluginRoot, "manifest.json");
|
|
28395
28873
|
const manifest = harnessPluginManifestSchema.parse(
|
|
28396
28874
|
JSON.parse(
|
|
@@ -28485,28 +28963,28 @@ async function loadHarnessPlugins(options2) {
|
|
|
28485
28963
|
}
|
|
28486
28964
|
|
|
28487
28965
|
// packages/host-runtime/src/harness-launch-settings.ts
|
|
28488
|
-
import { randomUUID as
|
|
28489
|
-
import { mkdir as
|
|
28490
|
-
import
|
|
28491
|
-
import
|
|
28966
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
28967
|
+
import { mkdir as mkdir5, readFile as readFile7, rename as rename4, rm as rm5, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
|
|
28968
|
+
import os4 from "node:os";
|
|
28969
|
+
import path15 from "node:path";
|
|
28492
28970
|
var HarnessLaunchSettingsStore = class {
|
|
28493
28971
|
#directory;
|
|
28494
28972
|
#initial = /* @__PURE__ */ new Map();
|
|
28495
28973
|
constructor(environment) {
|
|
28496
|
-
this.#directory =
|
|
28497
|
-
environment.CODEXHOST_DATA_DIR ?
|
|
28974
|
+
this.#directory = path15.join(
|
|
28975
|
+
environment.CODEXHOST_DATA_DIR ? path15.resolve(environment.CODEXHOST_DATA_DIR) : path15.join(os4.homedir(), ".codexhost"),
|
|
28498
28976
|
"harness-launch-settings"
|
|
28499
28977
|
);
|
|
28500
28978
|
}
|
|
28501
28979
|
#file(id2) {
|
|
28502
|
-
return
|
|
28980
|
+
return path15.join(this.#directory, `${harnessPluginIdSchema.parse(id2)}.json`);
|
|
28503
28981
|
}
|
|
28504
28982
|
async #read(id2) {
|
|
28505
28983
|
try {
|
|
28506
28984
|
const value2 = harnessLaunchPathSchema.parse(
|
|
28507
|
-
JSON.parse(await
|
|
28985
|
+
JSON.parse(await readFile7(this.#file(id2), "utf8"))
|
|
28508
28986
|
);
|
|
28509
|
-
if (!
|
|
28987
|
+
if (!path15.isAbsolute(value2)) throw new Error("Expected an absolute entrypoint path");
|
|
28510
28988
|
return value2;
|
|
28511
28989
|
} catch (error51) {
|
|
28512
28990
|
if (error51 && typeof error51 === "object" && "code" in error51 && error51.code === "ENOENT")
|
|
@@ -28532,22 +29010,22 @@ var HarnessLaunchSettingsStore = class {
|
|
|
28532
29010
|
const initial = await this.initialCommand(id2) ?? null;
|
|
28533
29011
|
const file2 = this.#file(id2);
|
|
28534
29012
|
if (value2 === null) {
|
|
28535
|
-
await
|
|
29013
|
+
await rm5(file2, { force: true });
|
|
28536
29014
|
} else {
|
|
28537
29015
|
value2 = harnessLaunchPathSchema.parse(value2);
|
|
28538
|
-
if (!
|
|
29016
|
+
if (!path15.isAbsolute(value2))
|
|
28539
29017
|
throw new Error("Use an absolute entrypoint path without arguments");
|
|
28540
|
-
const metadata = await
|
|
29018
|
+
const metadata = await stat4(value2).catch(() => void 0);
|
|
28541
29019
|
if (!metadata?.isDirectory() && !metadata?.isFile())
|
|
28542
29020
|
throw new Error("The installation path must be an existing directory on this Host");
|
|
28543
|
-
await
|
|
28544
|
-
const temporary = `${file2}.${
|
|
29021
|
+
await mkdir5(this.#directory, { recursive: true, mode: 448 });
|
|
29022
|
+
const temporary = `${file2}.${randomUUID7()}.tmp`;
|
|
28545
29023
|
try {
|
|
28546
29024
|
await writeFile3(temporary, `${JSON.stringify(value2)}
|
|
28547
29025
|
`, { mode: 384, flag: "wx" });
|
|
28548
|
-
await
|
|
29026
|
+
await rename4(temporary, file2);
|
|
28549
29027
|
} finally {
|
|
28550
|
-
await
|
|
29028
|
+
await rm5(temporary, { force: true });
|
|
28551
29029
|
}
|
|
28552
29030
|
}
|
|
28553
29031
|
return { path: value2, restartRequired: value2 !== initial };
|
|
@@ -28710,11 +29188,11 @@ function spawnOfficialAppServerConnection(input) {
|
|
|
28710
29188
|
}
|
|
28711
29189
|
|
|
28712
29190
|
// packages/host-runtime/src/account/codex-account-control.ts
|
|
28713
|
-
function
|
|
29191
|
+
function isRecord10(value2) {
|
|
28714
29192
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
28715
29193
|
}
|
|
28716
29194
|
function currentCodexAccountFromOfficialRead(result) {
|
|
28717
|
-
if (!
|
|
29195
|
+
if (!isRecord10(result) || !isRecord10(result.account) || result.account.type !== "chatgpt") {
|
|
28718
29196
|
return null;
|
|
28719
29197
|
}
|
|
28720
29198
|
const email3 = external_exports.string().email().max(320).safeParse(result.account.email);
|
|
@@ -28744,13 +29222,13 @@ var SingleNativeCodexAccount = class {
|
|
|
28744
29222
|
};
|
|
28745
29223
|
|
|
28746
29224
|
// packages/host-runtime/src/codex-runtime/official-runtime-owner.ts
|
|
28747
|
-
import { randomUUID as
|
|
29225
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
28748
29226
|
|
|
28749
29227
|
// packages/host-runtime/src/official-request-broker.ts
|
|
28750
|
-
import { randomUUID as
|
|
29228
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28751
29229
|
var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
|
|
28752
29230
|
var MAX_RETIRED_IDS = 1024;
|
|
28753
|
-
function
|
|
29231
|
+
function isRecord11(value2) {
|
|
28754
29232
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
28755
29233
|
}
|
|
28756
29234
|
var OfficialRequestBroker = class {
|
|
@@ -28763,7 +29241,7 @@ var OfficialRequestBroker = class {
|
|
|
28763
29241
|
constructor(input) {
|
|
28764
29242
|
this.#send = input.send;
|
|
28765
29243
|
this.#timeoutMs = input.timeoutMs ?? 3e4;
|
|
28766
|
-
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${
|
|
29244
|
+
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID8()}`);
|
|
28767
29245
|
}
|
|
28768
29246
|
get pendingCount() {
|
|
28769
29247
|
return this.#pending.size;
|
|
@@ -28793,7 +29271,7 @@ var OfficialRequestBroker = class {
|
|
|
28793
29271
|
});
|
|
28794
29272
|
}
|
|
28795
29273
|
handle(value2) {
|
|
28796
|
-
if (!
|
|
29274
|
+
if (!isRecord11(value2) || typeof value2.id !== "string") return false;
|
|
28797
29275
|
const pending = this.#pending.get(value2.id);
|
|
28798
29276
|
if (!pending) return this.#retired.has(value2.id);
|
|
28799
29277
|
clearTimeout(pending.timeout);
|
|
@@ -29117,7 +29595,7 @@ var OfficialRuntimeOwner = class {
|
|
|
29117
29595
|
}
|
|
29118
29596
|
#attach(role, output, onBackendStopped) {
|
|
29119
29597
|
const client = {
|
|
29120
|
-
id:
|
|
29598
|
+
id: randomUUID9(),
|
|
29121
29599
|
role,
|
|
29122
29600
|
output,
|
|
29123
29601
|
...onBackendStopped ? { onBackendStopped } : {},
|
|
@@ -29275,7 +29753,7 @@ var OfficialRuntimeOwner = class {
|
|
|
29275
29753
|
if (!object4(value2)) return client.output(event);
|
|
29276
29754
|
if (typeof value2.id === "string" || typeof value2.id === "number") {
|
|
29277
29755
|
if (typeof value2.method === "string") {
|
|
29278
|
-
const id2 = `codexhost:server:${client.id}:${event.generation}:${
|
|
29756
|
+
const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID9()}`;
|
|
29279
29757
|
client.serverRequests.set(id2, value2.id);
|
|
29280
29758
|
const projected = { ...value2, id: id2 };
|
|
29281
29759
|
return client.output({
|
|
@@ -29513,11 +29991,11 @@ function createOwnedConnectionBackend(factory) {
|
|
|
29513
29991
|
}
|
|
29514
29992
|
|
|
29515
29993
|
// packages/host-runtime/src/route-observation.ts
|
|
29516
|
-
function
|
|
29994
|
+
function isRecord12(value2) {
|
|
29517
29995
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29518
29996
|
}
|
|
29519
29997
|
function classifyThreadPurpose(request) {
|
|
29520
|
-
return
|
|
29998
|
+
return isRecord12(request.params) && request.params.ephemeral === true ? "ephemeral" : "conversation";
|
|
29521
29999
|
}
|
|
29522
30000
|
var RequestRouteObservationTracker = class {
|
|
29523
30001
|
#nextCreateOrdinal = 0;
|
|
@@ -29542,13 +30020,13 @@ var RequestRouteObservationTracker = class {
|
|
|
29542
30020
|
this.#createByThreadId.set(threadId2, tracked);
|
|
29543
30021
|
}
|
|
29544
30022
|
bindOfficialResponse(response) {
|
|
29545
|
-
if (!
|
|
30023
|
+
if (!isRecord12(response) || !("id" in response)) return;
|
|
29546
30024
|
const tracked = this.#pendingByRequestId.get(response.id);
|
|
29547
30025
|
if (!tracked) return;
|
|
29548
30026
|
this.#pendingByRequestId.delete(response.id);
|
|
29549
30027
|
const result = response.result;
|
|
29550
|
-
const thread =
|
|
29551
|
-
if (
|
|
30028
|
+
const thread = isRecord12(result) ? result.thread : null;
|
|
30029
|
+
if (isRecord12(thread) && typeof thread.id === "string") {
|
|
29552
30030
|
this.#createByThreadId.set(thread.id, tracked);
|
|
29553
30031
|
}
|
|
29554
30032
|
}
|
|
@@ -29670,25 +30148,25 @@ function resolveExternalSessionTreeIds(records) {
|
|
|
29670
30148
|
const resolve = (start) => {
|
|
29671
30149
|
const cached2 = resolved.get(start.hostThreadId);
|
|
29672
30150
|
if (cached2) return cached2;
|
|
29673
|
-
const
|
|
30151
|
+
const path29 = [];
|
|
29674
30152
|
const visited = /* @__PURE__ */ new Set();
|
|
29675
30153
|
let current = start;
|
|
29676
30154
|
while (true) {
|
|
29677
30155
|
const known = resolved.get(current.hostThreadId);
|
|
29678
30156
|
if (known) {
|
|
29679
|
-
for (const record3 of
|
|
30157
|
+
for (const record3 of path29) resolved.set(record3.hostThreadId, known);
|
|
29680
30158
|
return known;
|
|
29681
30159
|
}
|
|
29682
30160
|
if (visited.has(current.hostThreadId)) {
|
|
29683
30161
|
throw new Error("External Thread Fork tree contains a cycle");
|
|
29684
30162
|
}
|
|
29685
30163
|
visited.add(current.hostThreadId);
|
|
29686
|
-
|
|
30164
|
+
path29.push(current);
|
|
29687
30165
|
const sourceId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
|
|
29688
30166
|
const source = sourceId ? byId.get(sourceId) : void 0;
|
|
29689
30167
|
if (!source) {
|
|
29690
30168
|
const root = current.hostThreadId;
|
|
29691
|
-
for (const record3 of
|
|
30169
|
+
for (const record3 of path29) resolved.set(record3.hostThreadId, root);
|
|
29692
30170
|
return root;
|
|
29693
30171
|
}
|
|
29694
30172
|
current = source;
|
|
@@ -29742,11 +30220,11 @@ var OfficialThreadListError = class extends Error {
|
|
|
29742
30220
|
}
|
|
29743
30221
|
rpcError;
|
|
29744
30222
|
};
|
|
29745
|
-
function
|
|
30223
|
+
function isRecord13(value2) {
|
|
29746
30224
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29747
30225
|
}
|
|
29748
30226
|
function officialThreadListPageFromResponse(response) {
|
|
29749
|
-
if (
|
|
30227
|
+
if (isRecord13(response.error)) {
|
|
29750
30228
|
if (!Number.isSafeInteger(response.error.code) || typeof response.error.message !== "string") {
|
|
29751
30229
|
throw new Error("Official thread/list error response is invalid");
|
|
29752
30230
|
}
|
|
@@ -29914,14 +30392,14 @@ var THREAD_USAGE_UPDATED_METHOD = "codexhost/thread/usage/updated";
|
|
|
29914
30392
|
function delay3(milliseconds) {
|
|
29915
30393
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
29916
30394
|
}
|
|
29917
|
-
function
|
|
30395
|
+
function isRecord14(value2) {
|
|
29918
30396
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29919
30397
|
}
|
|
29920
30398
|
function isCreditsAdapter(adapter) {
|
|
29921
30399
|
return typeof adapter.credits === "function";
|
|
29922
30400
|
}
|
|
29923
30401
|
function projectAccountCredits(value2) {
|
|
29924
|
-
if (!
|
|
30402
|
+
if (!isRecord14(value2)) return null;
|
|
29925
30403
|
const rest = { ...value2 };
|
|
29926
30404
|
delete rest.fetchedAt;
|
|
29927
30405
|
const parsed = accountCreditsSnapshotSchema.safeParse(rest);
|
|
@@ -30044,12 +30522,12 @@ function classifyCreateRequestRoute(request, defaultAgent) {
|
|
|
30044
30522
|
};
|
|
30045
30523
|
}
|
|
30046
30524
|
function requestObject(request) {
|
|
30047
|
-
if (!
|
|
30525
|
+
if (!isRecord14(request.params)) throw new Error(`${request.method} params must be an object`);
|
|
30048
30526
|
return request.params;
|
|
30049
30527
|
}
|
|
30050
30528
|
function requestText(params) {
|
|
30051
30529
|
if (!Array.isArray(params.input)) throw new Error("turn/start input must be an array");
|
|
30052
|
-
const text = params.input.filter((item) =>
|
|
30530
|
+
const text = params.input.filter((item) => isRecord14(item) && item.type === "text").map((item) => item.text).filter((value2) => typeof value2 === "string").join("\n");
|
|
30053
30531
|
if (!text) throw new Error("turn/start must contain text input");
|
|
30054
30532
|
return text;
|
|
30055
30533
|
}
|
|
@@ -30103,6 +30581,7 @@ var AppServerHost = class {
|
|
|
30103
30581
|
#accountInspections = new HarnessAccountInspectionCache();
|
|
30104
30582
|
#externalRuntime;
|
|
30105
30583
|
#externalSteering = new ExternalTurnSteering();
|
|
30584
|
+
#liveCommandCache = new LiveCommandCatalogCache();
|
|
30106
30585
|
#repository;
|
|
30107
30586
|
#pendingDesktopApprovals = /* @__PURE__ */ new Map();
|
|
30108
30587
|
#pendingDesktopQuestions = /* @__PURE__ */ new Map();
|
|
@@ -30144,7 +30623,7 @@ var AppServerHost = class {
|
|
|
30144
30623
|
this.#launchSettings = new HarnessLaunchSettingsStore(
|
|
30145
30624
|
this.#options.pluginContext?.environment ?? environment
|
|
30146
30625
|
);
|
|
30147
|
-
const permanentHome =
|
|
30626
|
+
const permanentHome = path16.resolve(environment.CODEX_HOME ?? path16.join(os5.homedir(), ".codex"));
|
|
30148
30627
|
this.#ownsOfficialRuntimeScope = options2.officialRuntimeScope === void 0;
|
|
30149
30628
|
this.#officialRuntimeScope = options2.officialRuntimeScope ?? new OfficialRuntimeScope({
|
|
30150
30629
|
diagnosticOutput: this.#options.diagnosticOutput,
|
|
@@ -30406,12 +30885,12 @@ var AppServerHost = class {
|
|
|
30406
30885
|
for (const resolve of waiters) resolve();
|
|
30407
30886
|
}
|
|
30408
30887
|
#observeOfficialTurnStartResponse(value2) {
|
|
30409
|
-
if (!
|
|
30888
|
+
if (!isRecord14(value2) || !("id" in value2)) return;
|
|
30410
30889
|
const threadId2 = this.#pendingOfficialTurnStarts.get(value2.id);
|
|
30411
30890
|
if (!threadId2) return;
|
|
30412
30891
|
this.#pendingOfficialTurnStarts.delete(value2.id);
|
|
30413
|
-
const result =
|
|
30414
|
-
const turn = result &&
|
|
30892
|
+
const result = isRecord14(value2.result) ? value2.result : null;
|
|
30893
|
+
const turn = result && isRecord14(result.turn) ? result.turn : null;
|
|
30415
30894
|
if (turn && typeof turn.id === "string") {
|
|
30416
30895
|
this.#activeOfficialTurns.set(threadId2, turn.id);
|
|
30417
30896
|
}
|
|
@@ -30425,7 +30904,7 @@ var AppServerHost = class {
|
|
|
30425
30904
|
async #forwardDesktop() {
|
|
30426
30905
|
for await (const frame of readLfFrames(this.#options.desktopInput)) {
|
|
30427
30906
|
const parsed = parseJsonFrame(frame);
|
|
30428
|
-
if (
|
|
30907
|
+
if (isRecord14(parsed) && parsed.method === "initialized" && !("id" in parsed)) {
|
|
30429
30908
|
continue;
|
|
30430
30909
|
}
|
|
30431
30910
|
if (await this.#handleDesktopApprovalResponse(parsed)) continue;
|
|
@@ -30449,7 +30928,7 @@ var AppServerHost = class {
|
|
|
30449
30928
|
}
|
|
30450
30929
|
continue;
|
|
30451
30930
|
}
|
|
30452
|
-
const threadId2 =
|
|
30931
|
+
const threadId2 = isRecord14(request.params) && typeof request.params.threadId === "string" ? request.params.threadId : void 0;
|
|
30453
30932
|
this.#dispatchDesktopRequest(
|
|
30454
30933
|
() => this.#desktopRequests.run(
|
|
30455
30934
|
threadId2,
|
|
@@ -30677,7 +31156,7 @@ var AppServerHost = class {
|
|
|
30677
31156
|
rpcError(request, -32602, "Invalid Harness command inspection params")
|
|
30678
31157
|
);
|
|
30679
31158
|
} else {
|
|
30680
|
-
await this.#writeHarnessCommandCatalog(request, params.data.harnessId);
|
|
31159
|
+
await this.#writeHarnessCommandCatalog(request, params.data.harnessId, params.data.cwd);
|
|
30681
31160
|
}
|
|
30682
31161
|
return;
|
|
30683
31162
|
}
|
|
@@ -30774,7 +31253,7 @@ var AppServerHost = class {
|
|
|
30774
31253
|
return;
|
|
30775
31254
|
}
|
|
30776
31255
|
if (request.method === "thread/fork") {
|
|
30777
|
-
const params =
|
|
31256
|
+
const params = isRecord14(request.params) ? request.params : {};
|
|
30778
31257
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
30779
31258
|
if (resolution.kind === "error") {
|
|
30780
31259
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -30795,7 +31274,7 @@ var AppServerHost = class {
|
|
|
30795
31274
|
}
|
|
30796
31275
|
}
|
|
30797
31276
|
if (request.method === "thread/revert") {
|
|
30798
|
-
const params =
|
|
31277
|
+
const params = isRecord14(request.params) ? request.params : {};
|
|
30799
31278
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
30800
31279
|
if (resolution.kind === "error") {
|
|
30801
31280
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -30816,7 +31295,7 @@ var AppServerHost = class {
|
|
|
30816
31295
|
}
|
|
30817
31296
|
}
|
|
30818
31297
|
if (request.method === "thread/rollback") {
|
|
30819
|
-
const params =
|
|
31298
|
+
const params = isRecord14(request.params) ? request.params : {};
|
|
30820
31299
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
30821
31300
|
if (resolution.kind === "error") {
|
|
30822
31301
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -30972,7 +31451,7 @@ var AppServerHost = class {
|
|
|
30972
31451
|
return;
|
|
30973
31452
|
}
|
|
30974
31453
|
}
|
|
30975
|
-
if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) &&
|
|
31454
|
+
if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) && isRecord14(request.params) && typeof request.params.threadId === "string") {
|
|
30976
31455
|
const location = await this.#locateExternalThread(request.params.threadId);
|
|
30977
31456
|
if (await this.#writeResolutionError(request, location)) return;
|
|
30978
31457
|
if (location.kind === "external") {
|
|
@@ -30982,10 +31461,30 @@ var AppServerHost = class {
|
|
|
30982
31461
|
return;
|
|
30983
31462
|
}
|
|
30984
31463
|
}
|
|
30985
|
-
await this.#forwardOfficialRequest(
|
|
31464
|
+
await this.#forwardOfficialRequest(
|
|
31465
|
+
request,
|
|
31466
|
+
await this.#rewriteOfficialDelegationMentions(request, frame)
|
|
31467
|
+
);
|
|
31468
|
+
}
|
|
31469
|
+
/** Native Codex Turns: turn `#` delegation chips into an explicit Skill-backed request. */
|
|
31470
|
+
async #rewriteOfficialDelegationMentions(request, frame) {
|
|
31471
|
+
if (request.method !== "turn/start" && request.method !== "turn/steer") return frame;
|
|
31472
|
+
if (!isRecord14(request.params) || !Array.isArray(request.params.input)) return frame;
|
|
31473
|
+
const input = request.params.input;
|
|
31474
|
+
if (!input.some(
|
|
31475
|
+
(item) => isRecord14(item) && typeof item.text === "string" && item.text.includes(DELEGATION_MENTION_PATH_PREFIX)
|
|
31476
|
+
)) {
|
|
31477
|
+
return frame;
|
|
31478
|
+
}
|
|
31479
|
+
const rewritten = rewriteDelegationMentionInput(input, await managedDelegationSkillReference());
|
|
31480
|
+
if (!rewritten) return frame;
|
|
31481
|
+
return encodeJsonFrame({
|
|
31482
|
+
...request,
|
|
31483
|
+
params: { ...request.params, input: rewritten }
|
|
31484
|
+
});
|
|
30986
31485
|
}
|
|
30987
31486
|
async #forwardOfficialNonRequest(value2, frame) {
|
|
30988
|
-
const response =
|
|
31487
|
+
const response = isRecord14(value2) ? value2 : null;
|
|
30989
31488
|
const request = response && (typeof response.id === "string" || typeof response.id === "number") ? this.#officialServerRequests.get(response.id) : null;
|
|
30990
31489
|
if (request !== void 0 && response) {
|
|
30991
31490
|
this.#officialServerRequests.delete(response.id);
|
|
@@ -31014,7 +31513,7 @@ var AppServerHost = class {
|
|
|
31014
31513
|
const parsed = input.value;
|
|
31015
31514
|
this.#observeOfficialTurnStartResponse(parsed);
|
|
31016
31515
|
let forwarded = parsed;
|
|
31017
|
-
if (
|
|
31516
|
+
if (isRecord14(parsed) && typeof parsed.method === "string" && "id" in parsed) {
|
|
31018
31517
|
const originalId = parsed.id;
|
|
31019
31518
|
if (typeof originalId === "string" || typeof originalId === "number") {
|
|
31020
31519
|
const forwardedId = `codexhost:official:${++this.#nextOfficialServerRequestId}`;
|
|
@@ -31022,7 +31521,7 @@ var AppServerHost = class {
|
|
|
31022
31521
|
forwarded = { ...parsed, id: forwardedId };
|
|
31023
31522
|
}
|
|
31024
31523
|
}
|
|
31025
|
-
const accountScopedNotification =
|
|
31524
|
+
const accountScopedNotification = isRecord14(parsed) && typeof parsed.method === "string" && (parsed.method === "account/updated" || parsed.method.startsWith("account/rateLimits/"));
|
|
31026
31525
|
if (accountScopedNotification) {
|
|
31027
31526
|
if (parsed.method === "account/updated") this.#officialRateLimits.reset(input.accountId);
|
|
31028
31527
|
}
|
|
@@ -31091,10 +31590,10 @@ var AppServerHost = class {
|
|
|
31091
31590
|
}
|
|
31092
31591
|
}
|
|
31093
31592
|
async #observeOfficialTurnLifecycle(value2) {
|
|
31094
|
-
if (!
|
|
31593
|
+
if (!isRecord14(value2) || !isRecord14(value2.params)) return;
|
|
31095
31594
|
const params = value2.params;
|
|
31096
31595
|
if (value2.method === "turn/started" && typeof params.threadId === "string") {
|
|
31097
|
-
const turn =
|
|
31596
|
+
const turn = isRecord14(params.turn) ? params.turn : null;
|
|
31098
31597
|
if (turn && typeof turn.id === "string") {
|
|
31099
31598
|
this.#forgetPendingOfficialTurnStarts(params.threadId);
|
|
31100
31599
|
this.#activeOfficialTurns.set(params.threadId, turn.id);
|
|
@@ -31107,7 +31606,7 @@ var AppServerHost = class {
|
|
|
31107
31606
|
const delegation = await this.#repository.getDelegationByChild(
|
|
31108
31607
|
hostThreadIdSchema.parse(params.threadId)
|
|
31109
31608
|
);
|
|
31110
|
-
const turn =
|
|
31609
|
+
const turn = isRecord14(params.turn) ? params.turn : null;
|
|
31111
31610
|
const status = turn?.status === "failed" ? "failed" : turn?.status === "interrupted" || turn?.status === "cancelled" ? "interrupted" : "completed";
|
|
31112
31611
|
if (this.#pendingOfficialDelegationThreads.has(params.threadId)) {
|
|
31113
31612
|
this.#pendingOfficialTerminalStatuses.set(params.threadId, status);
|
|
@@ -31137,28 +31636,28 @@ var AppServerHost = class {
|
|
|
31137
31636
|
}
|
|
31138
31637
|
async #readOfficialThreadCwd(threadId2) {
|
|
31139
31638
|
const response = await this.#requestOfficial("thread/read", { threadId: threadId2 });
|
|
31140
|
-
if (
|
|
31141
|
-
const result =
|
|
31142
|
-
const thread = result &&
|
|
31639
|
+
if (isRecord14(response.error)) return void 0;
|
|
31640
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31641
|
+
const thread = result && isRecord14(result.thread) ? result.thread : null;
|
|
31143
31642
|
return thread && typeof thread.cwd === "string" && thread.cwd.trim() ? thread.cwd : void 0;
|
|
31144
31643
|
}
|
|
31145
31644
|
async #inspectOfficialDelegationTarget(input) {
|
|
31146
31645
|
const response = await this.#requestOfficial("model/list", {});
|
|
31147
|
-
if (
|
|
31646
|
+
if (isRecord14(response.error)) {
|
|
31148
31647
|
throw new DelegationControlError(
|
|
31149
31648
|
"DELEGATION_FAILED",
|
|
31150
31649
|
typeof response.error.message === "string" ? response.error.message : "Official Model catalog could not be read"
|
|
31151
31650
|
);
|
|
31152
31651
|
}
|
|
31153
|
-
const result =
|
|
31652
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31154
31653
|
const data = result && Array.isArray(result.data) ? result.data : [];
|
|
31155
31654
|
const thinkingById = /* @__PURE__ */ new Map();
|
|
31156
31655
|
const models = data.flatMap((candidate) => {
|
|
31157
|
-
if (!
|
|
31656
|
+
if (!isRecord14(candidate) || typeof candidate.model !== "string" || !candidate.model.trim()) {
|
|
31158
31657
|
return [];
|
|
31159
31658
|
}
|
|
31160
31659
|
const supportedThinkingOptionIds = Array.isArray(candidate.supportedReasoningEfforts) ? candidate.supportedReasoningEfforts.flatMap((option) => {
|
|
31161
|
-
if (!
|
|
31660
|
+
if (!isRecord14(option) || typeof option.reasoningEffort !== "string" || !option.reasoningEffort.trim()) {
|
|
31162
31661
|
return [];
|
|
31163
31662
|
}
|
|
31164
31663
|
const id2 = harnessThinkingOptionIdSchema.safeParse(option.reasoningEffort);
|
|
@@ -31178,9 +31677,9 @@ var AppServerHost = class {
|
|
|
31178
31677
|
];
|
|
31179
31678
|
});
|
|
31180
31679
|
const defaultEntry = data.find(
|
|
31181
|
-
(candidate) =>
|
|
31680
|
+
(candidate) => isRecord14(candidate) && candidate.isDefault === true
|
|
31182
31681
|
);
|
|
31183
|
-
const defaultModel =
|
|
31682
|
+
const defaultModel = isRecord14(defaultEntry) && typeof defaultEntry.model === "string" ? encodeOfficialCodexModelRef(defaultEntry.model) : void 0;
|
|
31184
31683
|
return {
|
|
31185
31684
|
harnessId: input.harnessId,
|
|
31186
31685
|
inspection: {
|
|
@@ -31210,7 +31709,7 @@ var AppServerHost = class {
|
|
|
31210
31709
|
throw new DelegationControlError("INVALID_ARGUMENT", "Official Model Ref is invalid");
|
|
31211
31710
|
}
|
|
31212
31711
|
const nativeModelId = requestedModel ? decodeOfficialCodexModelRef(requestedModel) : void 0;
|
|
31213
|
-
const digest2 =
|
|
31712
|
+
const digest2 = createHash8("sha256").update(
|
|
31214
31713
|
JSON.stringify({
|
|
31215
31714
|
task: input.task,
|
|
31216
31715
|
cwd: input.cwd,
|
|
@@ -31286,8 +31785,8 @@ var AppServerHost = class {
|
|
|
31286
31785
|
ephemeral: false,
|
|
31287
31786
|
historyMode: "paginated"
|
|
31288
31787
|
});
|
|
31289
|
-
const startedResult =
|
|
31290
|
-
const thread = startedResult &&
|
|
31788
|
+
const startedResult = isRecord14(started.result) ? started.result : null;
|
|
31789
|
+
const thread = startedResult && isRecord14(startedResult.thread) ? startedResult.thread : null;
|
|
31291
31790
|
const threadId2 = thread && typeof thread.id === "string" ? thread.id : null;
|
|
31292
31791
|
if (!threadId2) throw new Error("Official thread/start returned no Thread identity");
|
|
31293
31792
|
this.#pendingOfficialDelegationThreads.add(threadId2);
|
|
@@ -31299,8 +31798,8 @@ var AppServerHost = class {
|
|
|
31299
31798
|
...nativeModelId ? { model: nativeModelId } : {},
|
|
31300
31799
|
...input.thinkingOptionId ? { effort: input.thinkingOptionId } : {}
|
|
31301
31800
|
});
|
|
31302
|
-
const turnResult =
|
|
31303
|
-
const turnValue = turnResult &&
|
|
31801
|
+
const turnResult = isRecord14(turn.result) ? turn.result : null;
|
|
31802
|
+
const turnValue = turnResult && isRecord14(turnResult.turn) ? turnResult.turn : null;
|
|
31304
31803
|
const parsedTurnId = turnValue && typeof turnValue.id === "string" ? turnValue.id : null;
|
|
31305
31804
|
if (!parsedTurnId) throw new Error("Official turn/start returned no Turn identity");
|
|
31306
31805
|
turnId = parsedTurnId;
|
|
@@ -31311,7 +31810,7 @@ var AppServerHost = class {
|
|
|
31311
31810
|
throw error51;
|
|
31312
31811
|
}
|
|
31313
31812
|
this.#activeOfficialTurns.set(threadId2, turnId);
|
|
31314
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
31813
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID10());
|
|
31315
31814
|
try {
|
|
31316
31815
|
const source = await this.#repository.find(input.parentThreadId);
|
|
31317
31816
|
const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId2);
|
|
@@ -31370,27 +31869,27 @@ var AppServerHost = class {
|
|
|
31370
31869
|
threadId: input.threadId,
|
|
31371
31870
|
includeTurns: true
|
|
31372
31871
|
});
|
|
31373
|
-
if (
|
|
31872
|
+
if (isRecord14(current.error) || !isRecord14(current.result)) {
|
|
31374
31873
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31375
31874
|
}
|
|
31376
|
-
const currentThread =
|
|
31875
|
+
const currentThread = isRecord14(current.result.thread) ? current.result.thread : null;
|
|
31377
31876
|
const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
|
|
31378
31877
|
const latestTurn = currentTurns.at(-1);
|
|
31379
|
-
if (currentThread &&
|
|
31878
|
+
if (currentThread && isRecord14(currentThread.status) && currentThread.status.type === "active" || isRecord14(latestTurn) && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
|
|
31380
31879
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
31381
31880
|
}
|
|
31382
31881
|
const response = await this.#requestOfficial("turn/start", {
|
|
31383
31882
|
threadId: input.threadId,
|
|
31384
31883
|
input: [{ type: "text", text: input.message }]
|
|
31385
31884
|
});
|
|
31386
|
-
if (
|
|
31885
|
+
if (isRecord14(response.error)) {
|
|
31387
31886
|
throw new DelegationControlError(
|
|
31388
31887
|
"DELEGATION_FAILED",
|
|
31389
31888
|
typeof response.error.message === "string" ? response.error.message : "Turn start failed"
|
|
31390
31889
|
);
|
|
31391
31890
|
}
|
|
31392
|
-
const result =
|
|
31393
|
-
const turn = result &&
|
|
31891
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31892
|
+
const turn = result && isRecord14(result.turn) ? result.turn : null;
|
|
31394
31893
|
const turnId = turn && typeof turn.id === "string" ? turn.id : null;
|
|
31395
31894
|
if (!turnId) throw new Error("Official turn/start returned no Turn identity");
|
|
31396
31895
|
this.#activeOfficialTurns.set(input.threadId, turnId);
|
|
@@ -31412,13 +31911,13 @@ var AppServerHost = class {
|
|
|
31412
31911
|
threadId: input.threadId,
|
|
31413
31912
|
includeTurns: true
|
|
31414
31913
|
});
|
|
31415
|
-
if (
|
|
31914
|
+
if (isRecord14(current.error) || !isRecord14(current.result)) {
|
|
31416
31915
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31417
31916
|
}
|
|
31418
|
-
const currentThread =
|
|
31917
|
+
const currentThread = isRecord14(current.result.thread) ? current.result.thread : null;
|
|
31419
31918
|
const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
|
|
31420
31919
|
const latestTurn = currentTurns.at(-1);
|
|
31421
|
-
if (
|
|
31920
|
+
if (isRecord14(latestTurn) && typeof latestTurn.id === "string" && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
|
|
31422
31921
|
turnId = latestTurn.id;
|
|
31423
31922
|
this.#activeOfficialTurns.set(input.threadId, turnId);
|
|
31424
31923
|
} else {
|
|
@@ -31429,7 +31928,7 @@ var AppServerHost = class {
|
|
|
31429
31928
|
threadId: input.threadId,
|
|
31430
31929
|
turnId
|
|
31431
31930
|
});
|
|
31432
|
-
if (
|
|
31931
|
+
if (isRecord14(response.error)) {
|
|
31433
31932
|
throw new DelegationControlError(
|
|
31434
31933
|
"DELEGATION_FAILED",
|
|
31435
31934
|
typeof response.error.message === "string" ? response.error.message : "Turn cancel failed"
|
|
@@ -31442,18 +31941,18 @@ var AppServerHost = class {
|
|
|
31442
31941
|
threadId: input.threadId,
|
|
31443
31942
|
includeTurns: true
|
|
31444
31943
|
});
|
|
31445
|
-
if (
|
|
31944
|
+
if (isRecord14(response.error)) {
|
|
31446
31945
|
throw new DelegationControlError(
|
|
31447
31946
|
"THREAD_NOT_FOUND",
|
|
31448
31947
|
typeof response.error.message === "string" ? response.error.message : "Official Thread was not found"
|
|
31449
31948
|
);
|
|
31450
31949
|
}
|
|
31451
|
-
const result =
|
|
31452
|
-
const thread = result &&
|
|
31950
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31951
|
+
const thread = result && isRecord14(result.thread) ? result.thread : null;
|
|
31453
31952
|
if (!thread)
|
|
31454
31953
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31455
|
-
const turns = Array.isArray(thread.turns) ? thread.turns.filter((turn) =>
|
|
31456
|
-
const running = this.#activeOfficialTurns.has(input.threadId) ||
|
|
31954
|
+
const turns = Array.isArray(thread.turns) ? thread.turns.filter((turn) => isRecord14(turn)) : [];
|
|
31955
|
+
const running = this.#activeOfficialTurns.has(input.threadId) || isRecord14(thread.status) && thread.status.type === "active";
|
|
31457
31956
|
const snapshot = projectDelegationThreadSnapshot({
|
|
31458
31957
|
threadId: input.threadId,
|
|
31459
31958
|
harnessId: "codex",
|
|
@@ -31475,7 +31974,7 @@ var AppServerHost = class {
|
|
|
31475
31974
|
async #listDelegationThreads(input) {
|
|
31476
31975
|
const [sortKey, sortDirection2] = input.sort.split("-");
|
|
31477
31976
|
const request = {
|
|
31478
|
-
id: `codexhost:delegation-list:${
|
|
31977
|
+
id: `codexhost:delegation-list:${randomUUID10()}`,
|
|
31479
31978
|
method: "thread/list",
|
|
31480
31979
|
params: {
|
|
31481
31980
|
cwd: input.cwd ? [input.cwd] : null,
|
|
@@ -31503,7 +32002,7 @@ var AppServerHost = class {
|
|
|
31503
32002
|
threads: result.data.flatMap((entry) => {
|
|
31504
32003
|
if (typeof entry.id !== "string") return [];
|
|
31505
32004
|
const record3 = records.find((candidate) => candidate.hostThreadId === entry.id);
|
|
31506
|
-
const status =
|
|
32005
|
+
const status = isRecord14(entry.status) && entry.status.type === "active" ? "running" : "completed";
|
|
31507
32006
|
return [
|
|
31508
32007
|
{
|
|
31509
32008
|
threadId: entry.id,
|
|
@@ -31823,21 +32322,67 @@ var AppServerHost = class {
|
|
|
31823
32322
|
await this.#writer.json(rpcEnvelope(request, { result: { commands: [] } }));
|
|
31824
32323
|
return;
|
|
31825
32324
|
}
|
|
31826
|
-
|
|
32325
|
+
const loaded = this.#externalRuntime.get(params.data.threadId);
|
|
32326
|
+
if (loaded) {
|
|
32327
|
+
const catalog = await this.#inspectLoadedCommands(loaded);
|
|
32328
|
+
if (catalog) {
|
|
32329
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(catalog) }));
|
|
32330
|
+
return;
|
|
32331
|
+
}
|
|
32332
|
+
}
|
|
32333
|
+
await this.#writeHarnessCommandCatalog(
|
|
32334
|
+
request,
|
|
32335
|
+
location.record.harnessId,
|
|
32336
|
+
loaded?.cwd ?? location.record.cwd,
|
|
32337
|
+
params.data.threadId
|
|
32338
|
+
);
|
|
31827
32339
|
}
|
|
31828
|
-
|
|
32340
|
+
/**
|
|
32341
|
+
* Catalog of a loaded Session, marked live or static. A live catalog is
|
|
32342
|
+
* remembered for its Harness and workspace so later drafts there can show it.
|
|
32343
|
+
*/
|
|
32344
|
+
async #inspectLoadedCommands(thread) {
|
|
32345
|
+
if (!thread.session.commands) return null;
|
|
32346
|
+
const catalog = await inspectLiveCommandCatalog(thread.session.commands);
|
|
32347
|
+
if (!catalog) return null;
|
|
32348
|
+
const staticCatalog = this.#externalAdapters.get(thread.harnessId)?.commandCatalog;
|
|
32349
|
+
if (staticCatalog && !isLiveCommandCatalog(catalog, staticCatalog)) return null;
|
|
32350
|
+
const live = { ...catalog, source: "live" };
|
|
32351
|
+
this.#liveCommandCache.remember(thread.harnessId, thread.cwd, live);
|
|
32352
|
+
return live;
|
|
32353
|
+
}
|
|
32354
|
+
async #writeHarnessCommandCatalog(request, harnessId, cwd, inspectedThreadId) {
|
|
31829
32355
|
await this.#waitForPlugins();
|
|
31830
32356
|
const adapter = this.#externalAdapters.get(harnessId);
|
|
31831
32357
|
if (!adapter) {
|
|
31832
32358
|
await this.#writer.json(rpcError(request, -32077, `Harness '${harnessId}' is unavailable`));
|
|
31833
32359
|
return;
|
|
31834
32360
|
}
|
|
32361
|
+
let catalog;
|
|
31835
32362
|
try {
|
|
31836
|
-
|
|
31837
|
-
|
|
32363
|
+
catalog = harnessCommandCatalogSchema.parse({
|
|
32364
|
+
...adapter.commandCatalog ?? { commands: [] },
|
|
32365
|
+
...adapter.liveCommandCatalog ? { source: "static" } : {}
|
|
32366
|
+
});
|
|
31838
32367
|
} catch {
|
|
31839
32368
|
await this.#writer.json(rpcError(request, -32078, "Harness command catalog is invalid"));
|
|
32369
|
+
return;
|
|
32370
|
+
}
|
|
32371
|
+
if (cwd && adapter.liveCommandCatalog) {
|
|
32372
|
+
for (const thread of this.#externalRuntime.values()) {
|
|
32373
|
+
if (thread.id === inspectedThreadId) continue;
|
|
32374
|
+
if (thread.harnessId !== harnessId || !sameWorkspace(thread.cwd, cwd)) continue;
|
|
32375
|
+
const live = await this.#inspectLoadedCommands(thread);
|
|
32376
|
+
if (live) {
|
|
32377
|
+
catalog = live;
|
|
32378
|
+
break;
|
|
32379
|
+
}
|
|
32380
|
+
}
|
|
32381
|
+
if (catalog.source === "static") {
|
|
32382
|
+
catalog = this.#liveCommandCache.lookup(harnessId, cwd) ?? catalog;
|
|
32383
|
+
}
|
|
31840
32384
|
}
|
|
32385
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(catalog) }));
|
|
31841
32386
|
}
|
|
31842
32387
|
async #executeThreadCommand(request) {
|
|
31843
32388
|
const params = threadCommandExecuteParamsSchema.safeParse(request.params);
|
|
@@ -31889,39 +32434,43 @@ var AppServerHost = class {
|
|
|
31889
32434
|
return;
|
|
31890
32435
|
}
|
|
31891
32436
|
try {
|
|
31892
|
-
await this.#
|
|
31893
|
-
request,
|
|
32437
|
+
const started = await this.#beginExternalCommand(
|
|
31894
32438
|
thread,
|
|
31895
32439
|
params.commandId,
|
|
31896
32440
|
params.arguments,
|
|
31897
|
-
params.turnId
|
|
31898
|
-
"command"
|
|
32441
|
+
params.turnId
|
|
31899
32442
|
);
|
|
32443
|
+
try {
|
|
32444
|
+
const result = threadCommandExecuteResultSchema.parse({
|
|
32445
|
+
accepted: true,
|
|
32446
|
+
turnId: started.turnId
|
|
32447
|
+
});
|
|
32448
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
|
|
32449
|
+
} finally {
|
|
32450
|
+
started.gate.resolve();
|
|
32451
|
+
}
|
|
31900
32452
|
} catch (error51) {
|
|
31901
32453
|
this.#diagnose(error51);
|
|
31902
32454
|
await this.#writer.json(
|
|
31903
|
-
rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
|
|
32455
|
+
error51 instanceof ExternalCommandError ? rpcError(request, error51.code, error51.message) : rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
|
|
31904
32456
|
);
|
|
31905
32457
|
}
|
|
31906
32458
|
} finally {
|
|
31907
32459
|
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
31908
32460
|
}
|
|
31909
32461
|
}
|
|
31910
|
-
async #
|
|
32462
|
+
async #beginExternalCommand(thread, commandId, arguments_2, requestedTurnId) {
|
|
31911
32463
|
const commands = thread.session.commands;
|
|
31912
32464
|
if (!commands) {
|
|
31913
|
-
|
|
31914
|
-
rpcError(request, -32078, "External Harness does not expose commands")
|
|
31915
|
-
);
|
|
31916
|
-
return;
|
|
32465
|
+
throw new ExternalCommandError(-32078, "External Harness does not expose commands");
|
|
31917
32466
|
}
|
|
31918
|
-
if (
|
|
31919
|
-
|
|
31920
|
-
|
|
31921
|
-
|
|
31922
|
-
|
|
32467
|
+
if (this.#closeRequested || this.#externalRuntime.get(thread.id) !== thread) {
|
|
32468
|
+
throw new ExternalCommandError(-32073, "External Thread is no longer available");
|
|
32469
|
+
}
|
|
32470
|
+
if (thread.running || thread.activeTurnId) {
|
|
32471
|
+
throw new ExternalCommandError(-32072, "External Thread already has an active operation");
|
|
31923
32472
|
}
|
|
31924
|
-
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(
|
|
32473
|
+
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID10());
|
|
31925
32474
|
const projection = {
|
|
31926
32475
|
projector: new CodexTurnProjector({
|
|
31927
32476
|
threadId: thread.id,
|
|
@@ -31936,13 +32485,14 @@ var AppServerHost = class {
|
|
|
31936
32485
|
thread.projectedTurns.set(turnId, projection);
|
|
31937
32486
|
thread.responseGates.set(turnId, gate);
|
|
31938
32487
|
thread.ephemeralTurnIds.add(turnId);
|
|
31939
|
-
let result;
|
|
31940
32488
|
try {
|
|
31941
|
-
result = await commands.execute({
|
|
32489
|
+
const result = await commands.execute({
|
|
31942
32490
|
turnId,
|
|
31943
32491
|
commandId,
|
|
31944
32492
|
...arguments_2 ? { arguments: arguments_2 } : {}
|
|
31945
32493
|
});
|
|
32494
|
+
if (!result.ok) throw new ExternalCommandError(-32073, result.error.message);
|
|
32495
|
+
return { turnId: result.value.turnId, turn: projection.projector.pendingTurn(), gate };
|
|
31946
32496
|
} catch (error51) {
|
|
31947
32497
|
thread.running = false;
|
|
31948
32498
|
thread.activeTurnId = null;
|
|
@@ -31953,28 +32503,6 @@ var AppServerHost = class {
|
|
|
31953
32503
|
this.#signalActiveWorkChanged();
|
|
31954
32504
|
throw error51;
|
|
31955
32505
|
}
|
|
31956
|
-
if (!result.ok) {
|
|
31957
|
-
thread.running = false;
|
|
31958
|
-
thread.activeTurnId = null;
|
|
31959
|
-
thread.projectedTurns.delete(turnId);
|
|
31960
|
-
thread.responseGates.delete(turnId);
|
|
31961
|
-
thread.ephemeralTurnIds.delete(turnId);
|
|
31962
|
-
gate.resolve();
|
|
31963
|
-
this.#signalActiveWorkChanged();
|
|
31964
|
-
await this.#writer.json(rpcError(request, -32073, result.error.message));
|
|
31965
|
-
return;
|
|
31966
|
-
}
|
|
31967
|
-
try {
|
|
31968
|
-
const response = responseKind === "command" ? jsonValueSchema.parse(
|
|
31969
|
-
threadCommandExecuteResultSchema.parse({
|
|
31970
|
-
accepted: true,
|
|
31971
|
-
turnId: result.value.turnId
|
|
31972
|
-
})
|
|
31973
|
-
) : { turn: projection.projector.pendingTurn() };
|
|
31974
|
-
await this.#writer.json(rpcEnvelope(request, { result: response }));
|
|
31975
|
-
} finally {
|
|
31976
|
-
gate.resolve();
|
|
31977
|
-
}
|
|
31978
32506
|
}
|
|
31979
32507
|
async #selectThreadModel(request) {
|
|
31980
32508
|
const params = threadModelSelectParamsSchema.safeParse(request.params);
|
|
@@ -32597,10 +33125,10 @@ var AppServerHost = class {
|
|
|
32597
33125
|
...typeof params.serviceTier === "string" ? { serviceTier: params.serviceTier } : {}
|
|
32598
33126
|
});
|
|
32599
33127
|
try {
|
|
32600
|
-
if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !
|
|
33128
|
+
if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !isRecord14(params.initialTurnsPage)) {
|
|
32601
33129
|
throw new ExternalHistoryRequestError("initialTurnsPage must be an object");
|
|
32602
33130
|
}
|
|
32603
|
-
const initialPageParams =
|
|
33131
|
+
const initialPageParams = isRecord14(params.initialTurnsPage) ? params.initialTurnsPage : null;
|
|
32604
33132
|
const initialTurnsPage = initialPageParams ? listExternalTurns(turns, initialPageParams) : null;
|
|
32605
33133
|
const paginated = thread.record.historyMode === "paginated";
|
|
32606
33134
|
const turnsBackwardsCursor = paginated ? listExternalTurns(turns, { limit: 1, itemsView: "notLoaded" }).backwardsCursor : null;
|
|
@@ -32695,53 +33223,8 @@ var AppServerHost = class {
|
|
|
32695
33223
|
await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
|
|
32696
33224
|
return;
|
|
32697
33225
|
}
|
|
32698
|
-
const commandCandidate = text.trimStart();
|
|
32699
|
-
if (thread.session.commands && /^\/[^\s/]+(?:\s|$)/u.test(commandCandidate)) {
|
|
32700
|
-
const commandText = commandCandidate.trimEnd();
|
|
32701
|
-
this.#pendingExternalCommandRequests.add(thread.id);
|
|
32702
|
-
try {
|
|
32703
|
-
const catalog = await thread.session.commands.list();
|
|
32704
|
-
if (!catalog.ok) {
|
|
32705
|
-
await this.#writer.json(rpcError(request, -32073, catalog.error.message));
|
|
32706
|
-
return;
|
|
32707
|
-
}
|
|
32708
|
-
const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
|
|
32709
|
-
if (commandText === command.invocation) return true;
|
|
32710
|
-
return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
|
|
32711
|
-
});
|
|
32712
|
-
if (matched) {
|
|
32713
|
-
const argumentText = commandText.slice(matched.invocation.length).trimStart();
|
|
32714
|
-
try {
|
|
32715
|
-
await this.#startExternalCommand(
|
|
32716
|
-
request,
|
|
32717
|
-
thread,
|
|
32718
|
-
matched.id,
|
|
32719
|
-
argumentText.length > 0 ? { text: argumentText } : void 0,
|
|
32720
|
-
void 0,
|
|
32721
|
-
"turn"
|
|
32722
|
-
);
|
|
32723
|
-
} catch (error51) {
|
|
32724
|
-
this.#diagnose(error51);
|
|
32725
|
-
await this.#writer.json(
|
|
32726
|
-
rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
|
|
32727
|
-
);
|
|
32728
|
-
}
|
|
32729
|
-
return;
|
|
32730
|
-
}
|
|
32731
|
-
await this.#writer.json(
|
|
32732
|
-
rpcError(request, -32078, "External Harness does not expose the requested command")
|
|
32733
|
-
);
|
|
32734
|
-
return;
|
|
32735
|
-
} finally {
|
|
32736
|
-
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
32737
|
-
}
|
|
32738
|
-
}
|
|
32739
|
-
if (this.#externalSteering.hasPending(thread.id)) {
|
|
32740
|
-
await this.#writer.json(rpcError(request, -32072, "External Thread is changing direction"));
|
|
32741
|
-
return;
|
|
32742
|
-
}
|
|
32743
33226
|
try {
|
|
32744
|
-
const started = await this.#
|
|
33227
|
+
const started = await this.#beginExternalInputTurn(thread, text);
|
|
32745
33228
|
try {
|
|
32746
33229
|
await this.#writer.json(rpcEnvelope(request, { result: { turn: started.turn } }));
|
|
32747
33230
|
} finally {
|
|
@@ -32751,7 +33234,7 @@ var AppServerHost = class {
|
|
|
32751
33234
|
await this.#writer.json(
|
|
32752
33235
|
rpcError(
|
|
32753
33236
|
request,
|
|
32754
|
-
error51 instanceof ExternalSteerError ? error51.code : -32073,
|
|
33237
|
+
error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32073,
|
|
32755
33238
|
errorMessage3(error51)
|
|
32756
33239
|
)
|
|
32757
33240
|
);
|
|
@@ -32762,7 +33245,7 @@ var AppServerHost = class {
|
|
|
32762
33245
|
const started = await this.#externalSteering.run(
|
|
32763
33246
|
thread,
|
|
32764
33247
|
requestObject(request),
|
|
32765
|
-
(text) => this.#
|
|
33248
|
+
(text, assertActive) => this.#beginExternalInputTurn(thread, text, assertActive)
|
|
32766
33249
|
);
|
|
32767
33250
|
try {
|
|
32768
33251
|
await this.#writer.json(rpcEnvelope(request, { result: { turnId: started.turnId } }));
|
|
@@ -32773,7 +33256,7 @@ var AppServerHost = class {
|
|
|
32773
33256
|
await this.#writer.json(
|
|
32774
33257
|
rpcError(
|
|
32775
33258
|
request,
|
|
32776
|
-
error51 instanceof ExternalSteerError ? error51.code : -32074,
|
|
33259
|
+
error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32074,
|
|
32777
33260
|
errorMessage3(error51)
|
|
32778
33261
|
)
|
|
32779
33262
|
);
|
|
@@ -32781,6 +33264,37 @@ var AppServerHost = class {
|
|
|
32781
33264
|
this.#signalActiveWorkChanged();
|
|
32782
33265
|
}
|
|
32783
33266
|
}
|
|
33267
|
+
/** Keep command restoration and dispatch identical for start and steer submissions. */
|
|
33268
|
+
async #beginExternalInputTurn(thread, inputText, assertActive) {
|
|
33269
|
+
const text = restoreHarnessCommandMentions(inputText);
|
|
33270
|
+
const commands = thread.session.commands;
|
|
33271
|
+
if (!commands || !isExternalCommandCandidate(text)) {
|
|
33272
|
+
assertActive?.();
|
|
33273
|
+
return this.#beginExternalTurn(thread, text);
|
|
33274
|
+
}
|
|
33275
|
+
this.#pendingExternalCommandRequests.add(thread.id);
|
|
33276
|
+
try {
|
|
33277
|
+
const adapter = this.#externalAdapters.get(thread.harnessId);
|
|
33278
|
+
const command = await resolveExternalCommand(commands, text, {
|
|
33279
|
+
liveCatalogPending: (catalog) => adapter?.liveCommandCatalog === true && !isLiveCommandCatalog(catalog, adapter.commandCatalog ?? { commands: [] })
|
|
33280
|
+
});
|
|
33281
|
+
assertActive?.();
|
|
33282
|
+
if (!command) {
|
|
33283
|
+
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
33284
|
+
return await this.#beginExternalTurn(thread, text);
|
|
33285
|
+
}
|
|
33286
|
+
return await this.#beginExternalCommand(thread, command.commandId, command.arguments);
|
|
33287
|
+
} catch (error51) {
|
|
33288
|
+
if (error51 instanceof ExternalCommandError || error51 instanceof ExternalSteerError) throw error51;
|
|
33289
|
+
this.#diagnose(error51);
|
|
33290
|
+
throw new ExternalCommandError(
|
|
33291
|
+
-32073,
|
|
33292
|
+
`External Harness command failed: ${errorMessage3(error51)}`
|
|
33293
|
+
);
|
|
33294
|
+
} finally {
|
|
33295
|
+
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
33296
|
+
}
|
|
33297
|
+
}
|
|
32784
33298
|
async #beginExternalTurn(thread, text) {
|
|
32785
33299
|
if (this.#closeRequested || this.#externalRuntime.get(thread.id) !== thread) {
|
|
32786
33300
|
throw new ExternalSteerError(-32073, "External Thread is no longer available");
|
|
@@ -32788,7 +33302,7 @@ var AppServerHost = class {
|
|
|
32788
33302
|
if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
|
|
32789
33303
|
throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
|
|
32790
33304
|
}
|
|
32791
|
-
const turnId = hostTurnIdSchema.parse(
|
|
33305
|
+
const turnId = hostTurnIdSchema.parse(randomUUID10());
|
|
32792
33306
|
const startedAtMs = Date.now();
|
|
32793
33307
|
const projection = {
|
|
32794
33308
|
projector: new CodexTurnProjector({
|
|
@@ -32807,7 +33321,7 @@ var AppServerHost = class {
|
|
|
32807
33321
|
const result = await thread.session.execute({
|
|
32808
33322
|
type: "turn.start",
|
|
32809
33323
|
turnId,
|
|
32810
|
-
input: [{ type: "text", text }]
|
|
33324
|
+
input: [{ type: "text", text: rewriteDelegationMentionText(text) }]
|
|
32811
33325
|
});
|
|
32812
33326
|
if (!result.ok) throw new ExternalSteerError(-32073, result.error.message);
|
|
32813
33327
|
return { turnId, turn: projection.projector.pendingTurn(), gate };
|
|
@@ -33109,7 +33623,7 @@ var AppServerHost = class {
|
|
|
33109
33623
|
const previousItems = new Map(
|
|
33110
33624
|
child.turns.flatMap(
|
|
33111
33625
|
(turn) => Array.isArray(turn.items) ? turn.items.flatMap(
|
|
33112
|
-
(item) =>
|
|
33626
|
+
(item) => isRecord14(item) && typeof item.id === "string" ? [[item.id, JSON.stringify(item)]] : []
|
|
33113
33627
|
) : []
|
|
33114
33628
|
)
|
|
33115
33629
|
);
|
|
@@ -33122,7 +33636,7 @@ var AppServerHost = class {
|
|
|
33122
33636
|
for (const turn of child.turns) {
|
|
33123
33637
|
if (typeof turn.id !== "string" || !Array.isArray(turn.items)) continue;
|
|
33124
33638
|
const changedItems = turn.items.filter(
|
|
33125
|
-
(item) =>
|
|
33639
|
+
(item) => isRecord14(item) && typeof item.id === "string" && previousItems.get(item.id) !== JSON.stringify(item)
|
|
33126
33640
|
);
|
|
33127
33641
|
if (changedItems.length > 0) {
|
|
33128
33642
|
await this.#writer.json({
|
|
@@ -33254,7 +33768,7 @@ var AppServerHost = class {
|
|
|
33254
33768
|
}
|
|
33255
33769
|
}
|
|
33256
33770
|
async #handleDesktopApprovalResponse(value2) {
|
|
33257
|
-
if (!
|
|
33771
|
+
if (!isRecord14(value2) || !isHostApprovalRequestId(value2.id)) return false;
|
|
33258
33772
|
const requestId = value2.id;
|
|
33259
33773
|
const pending = this.#pendingDesktopApprovals.get(requestId);
|
|
33260
33774
|
if (!pending) return true;
|
|
@@ -33336,7 +33850,7 @@ var AppServerHost = class {
|
|
|
33336
33850
|
try {
|
|
33337
33851
|
result = projection.projector.projectQuestion(
|
|
33338
33852
|
interaction,
|
|
33339
|
-
hostItemIdSchema.parse(
|
|
33853
|
+
hostItemIdSchema.parse(randomUUID10())
|
|
33340
33854
|
);
|
|
33341
33855
|
} catch (error51) {
|
|
33342
33856
|
this.#diagnose(error51);
|
|
@@ -33381,7 +33895,7 @@ var AppServerHost = class {
|
|
|
33381
33895
|
}
|
|
33382
33896
|
}
|
|
33383
33897
|
async #handleDesktopQuestionResponse(value2) {
|
|
33384
|
-
if (!
|
|
33898
|
+
if (!isRecord14(value2) || !isHostQuestionRequestId(value2.id)) return false;
|
|
33385
33899
|
const requestId = value2.id;
|
|
33386
33900
|
const pending = this.#pendingDesktopQuestions.get(requestId);
|
|
33387
33901
|
if (!pending) return true;
|
|
@@ -33502,19 +34016,19 @@ var AppServerHost = class {
|
|
|
33502
34016
|
};
|
|
33503
34017
|
|
|
33504
34018
|
// packages/host-runtime/src/native-account-host.ts
|
|
33505
|
-
import { mkdir as
|
|
34019
|
+
import { mkdir as mkdir8, realpath as realpath3 } from "node:fs/promises";
|
|
33506
34020
|
import { homedir } from "node:os";
|
|
33507
|
-
import
|
|
34021
|
+
import path20 from "node:path";
|
|
33508
34022
|
|
|
33509
34023
|
// packages/host-runtime/src/codex-runtime/owned-official-backends.ts
|
|
33510
|
-
import { createHash as
|
|
34024
|
+
import { createHash as createHash9, randomBytes } from "node:crypto";
|
|
33511
34025
|
import { Writable as Writable2 } from "node:stream";
|
|
33512
34026
|
|
|
33513
34027
|
// packages/host-runtime/src/remote-app-server.ts
|
|
33514
34028
|
import { createServer } from "node:http";
|
|
33515
34029
|
import net from "node:net";
|
|
33516
|
-
import { chmod as chmod3, lstat as lstat6, mkdir as
|
|
33517
|
-
import
|
|
34030
|
+
import { chmod as chmod3, lstat as lstat6, mkdir as mkdir7, rm as rm7 } from "node:fs/promises";
|
|
34031
|
+
import path18 from "node:path";
|
|
33518
34032
|
import { PassThrough } from "node:stream";
|
|
33519
34033
|
|
|
33520
34034
|
// node_modules/ws/wrapper.mjs
|
|
@@ -33529,10 +34043,10 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
33529
34043
|
var wrapper_default = import_websocket.default;
|
|
33530
34044
|
|
|
33531
34045
|
// packages/host-runtime/src/remote-socket-lock.ts
|
|
33532
|
-
import { randomUUID as
|
|
33533
|
-
import { chmod as chmod2, lstat as lstat5, mkdir as
|
|
34046
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
34047
|
+
import { chmod as chmod2, lstat as lstat5, mkdir as mkdir6, open as open6, readFile as readFile8, readdir as readdir4, rename as rename5, rm as rm6 } from "node:fs/promises";
|
|
33534
34048
|
import { uptime } from "node:os";
|
|
33535
|
-
import
|
|
34049
|
+
import path17 from "node:path";
|
|
33536
34050
|
import { setTimeout as delay4 } from "node:timers/promises";
|
|
33537
34051
|
var LOCK_RETRY_COUNT = 200;
|
|
33538
34052
|
var LOCK_RETRY_DELAY_MS = 25;
|
|
@@ -33595,7 +34109,7 @@ async function readLockEntrySnapshot(filePath) {
|
|
|
33595
34109
|
throw error51;
|
|
33596
34110
|
});
|
|
33597
34111
|
if (metadata === null || !metadata.isFile()) return null;
|
|
33598
|
-
const source = await
|
|
34112
|
+
const source = await readFile8(filePath, "utf8").catch((error51) => {
|
|
33599
34113
|
if (error51.code === "ENOENT") return null;
|
|
33600
34114
|
throw error51;
|
|
33601
34115
|
});
|
|
@@ -33606,7 +34120,7 @@ async function readLockEntrySnapshot(filePath) {
|
|
|
33606
34120
|
source,
|
|
33607
34121
|
identity: { dev: metadata.dev, ino: metadata.ino },
|
|
33608
34122
|
mtimeMs: metadata.mtimeMs,
|
|
33609
|
-
record: record3 &&
|
|
34123
|
+
record: record3 && path17.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
|
|
33610
34124
|
};
|
|
33611
34125
|
}
|
|
33612
34126
|
function lockEntryIsAbandoned(snapshot) {
|
|
@@ -33618,7 +34132,7 @@ async function removeAbandonedLockEntry(snapshot) {
|
|
|
33618
34132
|
if (current === null || current.source !== snapshot.source || !sameUnixFileIdentity(current.identity, snapshot.identity) || !lockEntryIsAbandoned(current)) {
|
|
33619
34133
|
return false;
|
|
33620
34134
|
}
|
|
33621
|
-
await
|
|
34135
|
+
await rm6(snapshot.filePath, { force: true });
|
|
33622
34136
|
return true;
|
|
33623
34137
|
}
|
|
33624
34138
|
async function readLockEntryCatalog(lockDirectory) {
|
|
@@ -33627,7 +34141,7 @@ async function readLockEntryCatalog(lockDirectory) {
|
|
|
33627
34141
|
let unsettled = false;
|
|
33628
34142
|
for (const name of names) {
|
|
33629
34143
|
if (!name.startsWith(LOCK_ENTRY_PREFIX) || !name.endsWith(LOCK_ENTRY_SUFFIX)) continue;
|
|
33630
|
-
const snapshot = await readLockEntrySnapshot(
|
|
34144
|
+
const snapshot = await readLockEntrySnapshot(path17.join(lockDirectory, name));
|
|
33631
34145
|
if (snapshot === null) continue;
|
|
33632
34146
|
if (lockEntryIsAbandoned(snapshot)) {
|
|
33633
34147
|
if (!await removeAbandonedLockEntry(snapshot)) unsettled = true;
|
|
@@ -33642,7 +34156,7 @@ async function readLockEntryCatalog(lockDirectory) {
|
|
|
33642
34156
|
return { entries, unsettled };
|
|
33643
34157
|
}
|
|
33644
34158
|
async function preparePrivateLockDirectory(lockDirectory) {
|
|
33645
|
-
await
|
|
34159
|
+
await mkdir6(lockDirectory, { mode: 448 }).catch((error51) => {
|
|
33646
34160
|
if (error51.code !== "EEXIST") throw error51;
|
|
33647
34161
|
});
|
|
33648
34162
|
const metadata = await lstat5(lockDirectory);
|
|
@@ -33655,8 +34169,8 @@ async function preparePrivateLockDirectory(lockDirectory) {
|
|
|
33655
34169
|
await chmod2(lockDirectory, 448);
|
|
33656
34170
|
}
|
|
33657
34171
|
async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
|
|
33658
|
-
const temporary =
|
|
33659
|
-
const handle = await
|
|
34172
|
+
const temporary = path17.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID11()}`);
|
|
34173
|
+
const handle = await open6(temporary, "wx", 384);
|
|
33660
34174
|
try {
|
|
33661
34175
|
await handle.writeFile(`${JSON.stringify(record3)}
|
|
33662
34176
|
`, "utf8");
|
|
@@ -33665,15 +34179,15 @@ async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
|
|
|
33665
34179
|
await handle.close();
|
|
33666
34180
|
}
|
|
33667
34181
|
try {
|
|
33668
|
-
await
|
|
34182
|
+
await rename5(temporary, entryPath);
|
|
33669
34183
|
} finally {
|
|
33670
|
-
await
|
|
34184
|
+
await rm6(temporary, { force: true });
|
|
33671
34185
|
}
|
|
33672
34186
|
}
|
|
33673
34187
|
async function removeOwnedLockEntry(entryPath, ownerToken) {
|
|
33674
34188
|
const snapshot = await readLockEntrySnapshot(entryPath);
|
|
33675
34189
|
if (snapshot?.record?.ownerToken !== ownerToken) return;
|
|
33676
|
-
await
|
|
34190
|
+
await rm6(entryPath, { force: true });
|
|
33677
34191
|
}
|
|
33678
34192
|
async function legacyLockState(legacyPath) {
|
|
33679
34193
|
const metadata = await lstat5(legacyPath).catch((error51) => {
|
|
@@ -33682,7 +34196,7 @@ async function legacyLockState(legacyPath) {
|
|
|
33682
34196
|
});
|
|
33683
34197
|
if (metadata === null) return "absent";
|
|
33684
34198
|
if (!metadata.isFile()) return "blocking";
|
|
33685
|
-
const source = await
|
|
34199
|
+
const source = await readFile8(legacyPath, "utf8").catch((error51) => {
|
|
33686
34200
|
if (error51.code === "ENOENT") return null;
|
|
33687
34201
|
throw error51;
|
|
33688
34202
|
});
|
|
@@ -33693,7 +34207,7 @@ async function legacyLockState(legacyPath) {
|
|
|
33693
34207
|
return ownerIsAbandoned(record3, metadata.mtimeMs) ? "abandoned" : "blocking";
|
|
33694
34208
|
}
|
|
33695
34209
|
async function tryAcquireLegacyCompatibilityGuard(legacyPath, record3) {
|
|
33696
|
-
const handle = await
|
|
34210
|
+
const handle = await open6(legacyPath, "wx", 384).catch((error51) => {
|
|
33697
34211
|
if (error51.code === "EEXIST") return null;
|
|
33698
34212
|
throw error51;
|
|
33699
34213
|
});
|
|
@@ -33719,7 +34233,7 @@ async function releaseLegacyCompatibilityGuard(legacyPath, guard) {
|
|
|
33719
34233
|
throw error51;
|
|
33720
34234
|
});
|
|
33721
34235
|
if (metadata?.isFile() && sameUnixFileIdentity({ dev: metadata.dev, ino: metadata.ino }, guard.identity)) {
|
|
33722
|
-
await
|
|
34236
|
+
await rm6(legacyPath, { force: true });
|
|
33723
34237
|
}
|
|
33724
34238
|
}
|
|
33725
34239
|
}
|
|
@@ -33730,8 +34244,8 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
|
|
|
33730
34244
|
const legacyPath = `${socketPath}.initializing`;
|
|
33731
34245
|
const lockDirectory = `${socketPath}.initializers`;
|
|
33732
34246
|
await preparePrivateLockDirectory(lockDirectory);
|
|
33733
|
-
const ownerToken =
|
|
33734
|
-
const entryPath =
|
|
34247
|
+
const ownerToken = randomUUID11();
|
|
34248
|
+
const entryPath = path17.join(lockDirectory, lockEntryName(ownerToken));
|
|
33735
34249
|
const baseRecord = {
|
|
33736
34250
|
version: 2,
|
|
33737
34251
|
ownerToken,
|
|
@@ -33905,14 +34419,14 @@ function remoteAppServerSocketPath(environment, listenUrl = "unix://") {
|
|
|
33905
34419
|
throw new Error("Remote app-server listener must use a Unix URL");
|
|
33906
34420
|
}
|
|
33907
34421
|
const explicit = listenUrl.slice("unix://".length);
|
|
33908
|
-
if (explicit.length > 0) return
|
|
33909
|
-
const codexHome = environment.CODEX_HOME ?? (environment.HOME ?
|
|
34422
|
+
if (explicit.length > 0) return path18.posix.resolve(decodeURIComponent(explicit));
|
|
34423
|
+
const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path18.posix.join(environment.HOME, ".codex") : void 0);
|
|
33910
34424
|
if (!codexHome)
|
|
33911
34425
|
throw new Error("CODEX_HOME or HOME is required for the remote app-server socket");
|
|
33912
|
-
return
|
|
34426
|
+
return path18.posix.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
33913
34427
|
}
|
|
33914
34428
|
function officialListenerArgumentsForRemoteListener(arguments_2, socketPath) {
|
|
33915
|
-
if (!
|
|
34429
|
+
if (!path18.posix.isAbsolute(socketPath)) {
|
|
33916
34430
|
throw new Error("Shared official app-server socket path must be absolute");
|
|
33917
34431
|
}
|
|
33918
34432
|
if (remoteUnixListenerUrl(arguments_2) === null) {
|
|
@@ -34020,10 +34534,10 @@ async function removeStaleSocket(socketPath) {
|
|
|
34020
34534
|
});
|
|
34021
34535
|
});
|
|
34022
34536
|
if (active) throw new Error(`Remote app-server socket is already in use at ${socketPath}`);
|
|
34023
|
-
await
|
|
34537
|
+
await rm7(socketPath, { force: true });
|
|
34024
34538
|
}
|
|
34025
34539
|
async function prepareRemoteAppServerSocketDirectory(socketPath) {
|
|
34026
|
-
const socketDirectory =
|
|
34540
|
+
const socketDirectory = path18.dirname(socketPath);
|
|
34027
34541
|
const existing = await lstat6(socketDirectory).catch((error51) => {
|
|
34028
34542
|
if (error51.code === "ENOENT") return null;
|
|
34029
34543
|
throw error51;
|
|
@@ -34037,7 +34551,7 @@ async function prepareRemoteAppServerSocketDirectory(socketPath) {
|
|
|
34037
34551
|
);
|
|
34038
34552
|
}
|
|
34039
34553
|
}
|
|
34040
|
-
await
|
|
34554
|
+
await mkdir7(socketDirectory, { recursive: true, mode: 448 });
|
|
34041
34555
|
await chmod3(socketDirectory, 448);
|
|
34042
34556
|
}
|
|
34043
34557
|
function sendOutputFrames(socket, output) {
|
|
@@ -34210,7 +34724,7 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
34210
34724
|
if (ownedSocketIdentity) {
|
|
34211
34725
|
const current = await unixSocketIdentity(input.socketPath);
|
|
34212
34726
|
if (current && sameUnixFileIdentity2(current, ownedSocketIdentity)) {
|
|
34213
|
-
await
|
|
34727
|
+
await rm7(input.socketPath, { force: true });
|
|
34214
34728
|
}
|
|
34215
34729
|
ownedSocketIdentity = null;
|
|
34216
34730
|
}
|
|
@@ -34228,39 +34742,57 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
34228
34742
|
|
|
34229
34743
|
// packages/host-runtime/src/remote-official-app-server.ts
|
|
34230
34744
|
import { spawn as spawn3 } from "node:child_process";
|
|
34231
|
-
import { randomUUID as
|
|
34232
|
-
import { lstat as lstat7, rm as
|
|
34233
|
-
import
|
|
34745
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
34746
|
+
import { lstat as lstat7, rm as rm8, stat as stat5 } from "node:fs/promises";
|
|
34747
|
+
import path19 from "node:path";
|
|
34234
34748
|
var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
|
|
34235
34749
|
var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
|
|
34236
|
-
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token =
|
|
34237
|
-
if (!
|
|
34750
|
+
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID12()) {
|
|
34751
|
+
if (!path19.posix.isAbsolute(desktopControlSocketPath)) {
|
|
34238
34752
|
throw new Error("Desktop control socket path must be absolute");
|
|
34239
34753
|
}
|
|
34240
34754
|
if (!/^[A-Za-z0-9-]+$/u.test(token) || !/[A-Za-z0-9]/u.test(token)) {
|
|
34241
34755
|
throw new Error("Shared official app-server socket token is invalid");
|
|
34242
34756
|
}
|
|
34243
34757
|
const compactToken = token.replaceAll("-", "").slice(0, 15);
|
|
34244
|
-
return
|
|
34758
|
+
return path19.posix.join(path19.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
|
|
34245
34759
|
}
|
|
34246
34760
|
function errorMessage4(error51) {
|
|
34247
34761
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
34248
34762
|
}
|
|
34249
|
-
async function
|
|
34763
|
+
async function inspectSocket(socketPath) {
|
|
34250
34764
|
const metadata = await lstat7(socketPath).catch((error51) => {
|
|
34251
34765
|
if (error51.code === "ENOENT") return null;
|
|
34252
34766
|
throw error51;
|
|
34253
34767
|
});
|
|
34254
34768
|
if (metadata === null) return null;
|
|
34255
|
-
|
|
34769
|
+
const identity = { dev: metadata.dev, ino: metadata.ino };
|
|
34770
|
+
if (metadata.isSymbolicLink()) {
|
|
34771
|
+
const uid = process.getuid?.();
|
|
34772
|
+
if (uid === void 0 || metadata.uid !== uid) {
|
|
34773
|
+
throw new Error(
|
|
34774
|
+
`Shared official app-server link must belong to the current user: ${socketPath}`
|
|
34775
|
+
);
|
|
34776
|
+
}
|
|
34777
|
+
const target = await stat5(socketPath).catch((error51) => {
|
|
34778
|
+
if (error51.code === "ENOENT") return null;
|
|
34779
|
+
throw error51;
|
|
34780
|
+
});
|
|
34781
|
+
if (target === null) return { identity, ready: false };
|
|
34782
|
+
if (target.uid !== uid || !target.isSocket() || (target.mode & 63) !== 0) {
|
|
34783
|
+
throw new Error(
|
|
34784
|
+
`Shared official app-server link must target a current-user private socket: ${socketPath}`
|
|
34785
|
+
);
|
|
34786
|
+
}
|
|
34787
|
+
} else if (!metadata.isSocket()) {
|
|
34256
34788
|
throw new Error(`Shared official app-server path is not a socket: ${socketPath}`);
|
|
34257
34789
|
}
|
|
34258
|
-
return {
|
|
34790
|
+
return { identity, ready: true };
|
|
34259
34791
|
}
|
|
34260
34792
|
function sameUnixFileIdentity3(left, right) {
|
|
34261
34793
|
return left.dev === right.dev && left.ino === right.ino;
|
|
34262
34794
|
}
|
|
34263
|
-
async function waitForOfficialSocket(socketPath, closed) {
|
|
34795
|
+
async function waitForOfficialSocket(socketPath, closed, onIdentity) {
|
|
34264
34796
|
const deadline = Date.now() + 1e4;
|
|
34265
34797
|
const state = { exit: null };
|
|
34266
34798
|
void closed.then((value2) => {
|
|
@@ -34273,14 +34805,20 @@ async function waitForOfficialSocket(socketPath, closed) {
|
|
|
34273
34805
|
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)})`
|
|
34274
34806
|
);
|
|
34275
34807
|
}
|
|
34276
|
-
|
|
34808
|
+
const socket = await inspectSocket(socketPath);
|
|
34809
|
+
if (socket !== null) {
|
|
34810
|
+
onIdentity(socket.identity);
|
|
34811
|
+
if (socket.ready) return;
|
|
34812
|
+
}
|
|
34277
34813
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
34278
34814
|
}
|
|
34279
34815
|
throw new Error(`Shared official app-server socket was not ready after 10000ms: ${socketPath}`);
|
|
34280
34816
|
}
|
|
34281
34817
|
function createRemoteOfficialAppServerListener(input) {
|
|
34282
34818
|
const spawnOfficial = input.spawnOfficial ?? spawn3;
|
|
34283
|
-
const waitUntilReady = input.waitUntilReady ?? waitForOfficialSocket
|
|
34819
|
+
const waitUntilReady = input.waitUntilReady ?? ((socketPath, closed2) => waitForOfficialSocket(socketPath, closed2, (identity) => {
|
|
34820
|
+
ownedSocketIdentity ??= identity;
|
|
34821
|
+
}));
|
|
34284
34822
|
const closeTimeoutMs = input.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS;
|
|
34285
34823
|
const closed = Promise.withResolvers();
|
|
34286
34824
|
let child = null;
|
|
@@ -34311,9 +34849,9 @@ function createRemoteOfficialAppServerListener(input) {
|
|
|
34311
34849
|
};
|
|
34312
34850
|
const removeOwnedSocket = async () => {
|
|
34313
34851
|
if (ownedSocketIdentity === null) return;
|
|
34314
|
-
const current = await
|
|
34852
|
+
const current = await lstat7(input.socketPath).catch(() => null);
|
|
34315
34853
|
if (current && sameUnixFileIdentity3(current, ownedSocketIdentity)) {
|
|
34316
|
-
await
|
|
34854
|
+
await rm8(input.socketPath, { force: true });
|
|
34317
34855
|
}
|
|
34318
34856
|
ownedSocketIdentity = null;
|
|
34319
34857
|
};
|
|
@@ -34337,7 +34875,7 @@ function createRemoteOfficialAppServerListener(input) {
|
|
|
34337
34875
|
spawned.stderr?.pipe(input.diagnosticOutput, { end: false });
|
|
34338
34876
|
try {
|
|
34339
34877
|
await waitUntilReady(input.socketPath, closed.promise);
|
|
34340
|
-
ownedSocketIdentity
|
|
34878
|
+
ownedSocketIdentity ??= (await inspectSocket(input.socketPath).catch(() => null))?.identity ?? null;
|
|
34341
34879
|
} catch (error51) {
|
|
34342
34880
|
let stopFailed = false;
|
|
34343
34881
|
try {
|
|
@@ -34345,7 +34883,7 @@ function createRemoteOfficialAppServerListener(input) {
|
|
|
34345
34883
|
} catch {
|
|
34346
34884
|
stopFailed = true;
|
|
34347
34885
|
}
|
|
34348
|
-
ownedSocketIdentity ??= await
|
|
34886
|
+
ownedSocketIdentity ??= (await inspectSocket(input.socketPath).catch(() => null))?.identity ?? null;
|
|
34349
34887
|
if (!stopFailed) await removeOwnedSocket();
|
|
34350
34888
|
throw new Error(`Shared official app-server startup failed: ${errorMessage4(error51)}`);
|
|
34351
34889
|
}
|
|
@@ -34674,7 +35212,7 @@ function createOwnedLoopbackBackend(input) {
|
|
|
34674
35212
|
"--ws-auth",
|
|
34675
35213
|
"capability-token",
|
|
34676
35214
|
"--ws-token-sha256",
|
|
34677
|
-
|
|
35215
|
+
createHash9("sha256").update(capabilityToken).digest("hex")
|
|
34678
35216
|
],
|
|
34679
35217
|
// Managed stderr may carry credential-bearing errors. Never forward raw bytes.
|
|
34680
35218
|
diagnosticOutput: new Writable2({
|
|
@@ -34727,21 +35265,21 @@ function createOwnedUnixBackend(input) {
|
|
|
34727
35265
|
|
|
34728
35266
|
// packages/host-runtime/src/native-account-host.ts
|
|
34729
35267
|
async function canonicalCodexHome(home) {
|
|
34730
|
-
const absolute =
|
|
35268
|
+
const absolute = path20.resolve(home);
|
|
34731
35269
|
try {
|
|
34732
35270
|
return await realpath3(absolute);
|
|
34733
35271
|
} catch (error51) {
|
|
34734
35272
|
if (!(error51 instanceof Error && "code" in error51 && error51.code === "ENOENT")) throw error51;
|
|
34735
|
-
const parent =
|
|
35273
|
+
const parent = path20.dirname(absolute);
|
|
34736
35274
|
if (parent === absolute) throw error51;
|
|
34737
|
-
return
|
|
35275
|
+
return path20.join(await canonicalCodexHome(parent), path20.basename(absolute));
|
|
34738
35276
|
}
|
|
34739
35277
|
}
|
|
34740
35278
|
async function prepareLocalCodex(input) {
|
|
34741
35279
|
const home = await canonicalCodexHome(
|
|
34742
|
-
input.environment.CODEX_HOME ??
|
|
35280
|
+
input.environment.CODEX_HOME ?? path20.join(homedir(), ".codex")
|
|
34743
35281
|
);
|
|
34744
|
-
await
|
|
35282
|
+
await mkdir8(home, { recursive: true });
|
|
34745
35283
|
const scope = new OfficialRuntimeScope({
|
|
34746
35284
|
permanentHome: home,
|
|
34747
35285
|
diagnosticOutput: input.diagnosticOutput,
|
|
@@ -34905,18 +35443,18 @@ var DelegationControlRegistry = class {
|
|
|
34905
35443
|
};
|
|
34906
35444
|
|
|
34907
35445
|
// packages/host-runtime/src/installed-harness-plugins.ts
|
|
34908
|
-
import
|
|
34909
|
-
import
|
|
35446
|
+
import os6 from "node:os";
|
|
35447
|
+
import path22 from "node:path";
|
|
34910
35448
|
import { fileURLToPath } from "node:url";
|
|
34911
35449
|
|
|
34912
35450
|
// packages/host-runtime/src/launcher-url-opener.ts
|
|
34913
35451
|
import { spawn as spawn4 } from "node:child_process";
|
|
34914
|
-
import
|
|
35452
|
+
import path21 from "node:path";
|
|
34915
35453
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
|
|
34916
35454
|
var OPEN_TIMEOUT_MS = 1e4;
|
|
34917
35455
|
function createLauncherUrlOpener(environment, spawnLauncher = (command, arguments_2, options2) => spawn4(command, arguments_2, options2)) {
|
|
34918
35456
|
const launcher = environment.CODEXHOST_LAUNCHER_EXECUTABLE;
|
|
34919
|
-
if (!launcher || !
|
|
35457
|
+
if (!launcher || !path21.isAbsolute(launcher)) return void 0;
|
|
34920
35458
|
const launcherEnvironment = Object.fromEntries(
|
|
34921
35459
|
Object.entries(environment).filter(([name]) => {
|
|
34922
35460
|
const normalized = name.toUpperCase();
|
|
@@ -34974,9 +35512,9 @@ function installedHarnessPluginOptions(environment, managedRemoteHost = false, h
|
|
|
34974
35512
|
const opener = managedRemoteHost ? void 0 : createLauncherUrlOpener(environment);
|
|
34975
35513
|
return {
|
|
34976
35514
|
pluginRoots: [
|
|
34977
|
-
|
|
34978
|
-
environment[HARNESS_PLUGIN_DIRECTORY_ENV] ??
|
|
34979
|
-
environment.CODEXHOST_DATA_DIR ?
|
|
35515
|
+
path22.join(path22.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
|
|
35516
|
+
environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path22.join(
|
|
35517
|
+
environment.CODEXHOST_DATA_DIR ? path22.resolve(environment.CODEXHOST_DATA_DIR) : path22.join(os6.homedir(), ".codexhost"),
|
|
34980
35518
|
"plugins"
|
|
34981
35519
|
)
|
|
34982
35520
|
],
|
|
@@ -35100,171 +35638,10 @@ async function startDelegationControlServer(input) {
|
|
|
35100
35638
|
};
|
|
35101
35639
|
}
|
|
35102
35640
|
|
|
35103
|
-
// packages/host-runtime/src/delegation-skill.ts
|
|
35104
|
-
import { createHash as createHash9, randomUUID as randomUUID12 } from "node:crypto";
|
|
35105
|
-
import { mkdir as mkdir8, open as open6, readFile as readFile8, rename as rename5, rm as rm8, stat as stat4 } from "node:fs/promises";
|
|
35106
|
-
import os6 from "node:os";
|
|
35107
|
-
import path20 from "node:path";
|
|
35108
|
-
var SKILL_VERSION = 7;
|
|
35109
|
-
var SKILL_RELATIVE_PATH = path20.join("skills", "codexhost-delegation", "SKILL.md");
|
|
35110
|
-
var PREVIOUS_MANAGED_DIGESTS = [
|
|
35111
|
-
"9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
|
|
35112
|
-
"2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
|
|
35113
|
-
"aff258622dc8ff321f32b15620d081e578cb9c9ed1134d6a57f35ca8e7762c0a",
|
|
35114
|
-
"ba509f57e5448e796b3dfdd5031dcb08672eded50b61c0a54de84cfa02c49dd3",
|
|
35115
|
-
"d3ddf6db9bc5c5df825479c885bbbf0ca08da66f7057a12e02e1fdf57525149e",
|
|
35116
|
-
"15eb63519ff867e1536c97188a0c43738d7a49d38d4d6adeb7a1036726e7246d"
|
|
35117
|
-
];
|
|
35118
|
-
var CODEXHOST_DELEGATION_SKILL = `---
|
|
35119
|
-
name: codexhost-delegation
|
|
35120
|
-
version: ${SKILL_VERSION}
|
|
35121
|
-
description: >
|
|
35122
|
-
Delegate tasks to other coding agents, or read and follow up on existing
|
|
35123
|
-
external agent sessions. Use when the user asks another agent (including
|
|
35124
|
-
@agent) to independently perform a task, or asks to view a specified external
|
|
35125
|
-
session's content, progress, or results, send follow-up messages, wait, or
|
|
35126
|
-
cancel a task. Not for recapping the current conversation, discussing or
|
|
35127
|
-
configuring agents, or role-playing.
|
|
35128
|
-
---
|
|
35129
|
-
|
|
35130
|
-
# Execute the task
|
|
35131
|
-
|
|
35132
|
-
Before acting, run:
|
|
35133
|
-
|
|
35134
|
-
\`codexhost delegate --help\`
|
|
35135
|
-
|
|
35136
|
-
Use CLI help as the authoritative source for commands and behavior. Consult
|
|
35137
|
-
command-specific help for options and the Harness listing command when the
|
|
35138
|
-
target is unknown. Prefer compact output when supported, and use its task links
|
|
35139
|
-
directly for subsequent commands.
|
|
35140
|
-
|
|
35141
|
-
Use the Harness native defaults. Inspect the target when a Model or Thinking
|
|
35142
|
-
selection is needed or the default is unavailable.
|
|
35143
|
-
|
|
35144
|
-
For a new delegation, create an independent child session and submit the
|
|
35145
|
-
requested task. For an existing external session, resolve the target from the
|
|
35146
|
-
user-provided session link, identifier, or context and operate on that Thread
|
|
35147
|
-
directly; it need not have been created by the current assistant. If the target
|
|
35148
|
-
is ambiguous, ask the user to identify it. Keep requests to view or summarize a
|
|
35149
|
-
session read-only.
|
|
35150
|
-
|
|
35151
|
-
For a new or existing task, choose the appropriate next action based on the
|
|
35152
|
-
user’s request and the task:
|
|
35153
|
-
|
|
35154
|
-
- send a follow-up message to the same Thread;
|
|
35155
|
-
- cancel its current Turn;
|
|
35156
|
-
- read its current state immediately;
|
|
35157
|
-
- wait for a bounded period;
|
|
35158
|
-
- check it again later;
|
|
35159
|
-
- leave it running in the background.
|
|
35160
|
-
|
|
35161
|
-
Report the result returned by read or a completed wait, together with the target
|
|
35162
|
-
agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
|
|
35163
|
-
`;
|
|
35164
|
-
var CURRENT_DIGEST = createHash9("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
|
|
35165
|
-
function digest(value2) {
|
|
35166
|
-
return createHash9("sha256").update(value2).digest("hex");
|
|
35167
|
-
}
|
|
35168
|
-
function managedVersion(value2) {
|
|
35169
|
-
const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
|
|
35170
|
-
return match ? Number(match[1]) : null;
|
|
35171
|
-
}
|
|
35172
|
-
async function readOptional(filePath) {
|
|
35173
|
-
try {
|
|
35174
|
-
return await readFile8(filePath, "utf8");
|
|
35175
|
-
} catch (error51) {
|
|
35176
|
-
if (error51.code === "ENOENT") return null;
|
|
35177
|
-
throw error51;
|
|
35178
|
-
}
|
|
35179
|
-
}
|
|
35180
|
-
async function atomicWrite(filePath, content) {
|
|
35181
|
-
await mkdir8(path20.dirname(filePath), { recursive: true, mode: 448 });
|
|
35182
|
-
const temporaryPath = path20.join(path20.dirname(filePath), `.SKILL.md.${randomUUID12()}.tmp`);
|
|
35183
|
-
const handle = await open6(temporaryPath, "wx", 384);
|
|
35184
|
-
try {
|
|
35185
|
-
await handle.writeFile(content, "utf8");
|
|
35186
|
-
await handle.sync();
|
|
35187
|
-
} finally {
|
|
35188
|
-
await handle.close();
|
|
35189
|
-
}
|
|
35190
|
-
try {
|
|
35191
|
-
await rename5(temporaryPath, filePath);
|
|
35192
|
-
} finally {
|
|
35193
|
-
await rm8(temporaryPath, { force: true });
|
|
35194
|
-
}
|
|
35195
|
-
}
|
|
35196
|
-
async function installDelegationSkills(input = {}) {
|
|
35197
|
-
const home = input.homeDirectory ?? os6.homedir();
|
|
35198
|
-
const destinations = [
|
|
35199
|
-
path20.join(home, ".agents", SKILL_RELATIVE_PATH),
|
|
35200
|
-
path20.join(home, ".claude", SKILL_RELATIVE_PATH)
|
|
35201
|
-
];
|
|
35202
|
-
const knownDigests = /* @__PURE__ */ new Set([
|
|
35203
|
-
CURRENT_DIGEST,
|
|
35204
|
-
...PREVIOUS_MANAGED_DIGESTS,
|
|
35205
|
-
...input.previousManagedDigests ?? []
|
|
35206
|
-
]);
|
|
35207
|
-
const results = [];
|
|
35208
|
-
for (const destination of destinations) {
|
|
35209
|
-
const current = await readOptional(destination);
|
|
35210
|
-
if (current === CODEXHOST_DELEGATION_SKILL) {
|
|
35211
|
-
results.push({
|
|
35212
|
-
path: destination,
|
|
35213
|
-
status: "current",
|
|
35214
|
-
version: SKILL_VERSION,
|
|
35215
|
-
digest: CURRENT_DIGEST
|
|
35216
|
-
});
|
|
35217
|
-
continue;
|
|
35218
|
-
}
|
|
35219
|
-
if (current !== null) {
|
|
35220
|
-
const currentDigest = digest(current);
|
|
35221
|
-
const version2 = managedVersion(current);
|
|
35222
|
-
if (!knownDigests.has(currentDigest)) {
|
|
35223
|
-
results.push({ path: destination, status: "conflict", version: version2, digest: currentDigest });
|
|
35224
|
-
continue;
|
|
35225
|
-
}
|
|
35226
|
-
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
35227
|
-
results.push({
|
|
35228
|
-
path: destination,
|
|
35229
|
-
status: "updated",
|
|
35230
|
-
version: SKILL_VERSION,
|
|
35231
|
-
digest: CURRENT_DIGEST
|
|
35232
|
-
});
|
|
35233
|
-
continue;
|
|
35234
|
-
}
|
|
35235
|
-
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
35236
|
-
results.push({
|
|
35237
|
-
path: destination,
|
|
35238
|
-
status: "installed",
|
|
35239
|
-
version: SKILL_VERSION,
|
|
35240
|
-
digest: CURRENT_DIGEST
|
|
35241
|
-
});
|
|
35242
|
-
}
|
|
35243
|
-
for (const result of results) {
|
|
35244
|
-
if (result.status === "conflict") continue;
|
|
35245
|
-
const source = await readFile8(result.path, "utf8");
|
|
35246
|
-
const metadata = await stat4(result.path);
|
|
35247
|
-
if (!metadata.isFile() || source !== CODEXHOST_DELEGATION_SKILL) {
|
|
35248
|
-
throw new Error(`Delegation Skill verification failed: ${result.path}`);
|
|
35249
|
-
}
|
|
35250
|
-
}
|
|
35251
|
-
const managed = results.filter((result) => result.status !== "conflict");
|
|
35252
|
-
if (managed.some((result) => result.digest !== CURRENT_DIGEST)) {
|
|
35253
|
-
throw new Error("Delegation Skill copies are inconsistent");
|
|
35254
|
-
}
|
|
35255
|
-
if (results.every((result) => result.status !== "conflict")) {
|
|
35256
|
-
const copies = await Promise.all(results.map((result) => readFile8(result.path, "utf8")));
|
|
35257
|
-
if (copies.some((copy) => copy !== copies[0])) {
|
|
35258
|
-
throw new Error("Delegation Skill copies are inconsistent");
|
|
35259
|
-
}
|
|
35260
|
-
}
|
|
35261
|
-
return results;
|
|
35262
|
-
}
|
|
35263
|
-
|
|
35264
35641
|
// packages/host-runtime/src/remote-control-app-server.ts
|
|
35265
35642
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
35266
35643
|
import { mkdir as mkdir9, open as open7, rename as rename6, rm as rm9 } from "node:fs/promises";
|
|
35267
|
-
import
|
|
35644
|
+
import path23 from "node:path";
|
|
35268
35645
|
var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
|
|
35269
35646
|
var REMOTE_CONTROL_BRIDGE_NODE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_NODE_PATH";
|
|
35270
35647
|
var REMOTE_CONTROL_BRIDGE_RUNTIME_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_RUNTIME_PATH";
|
|
@@ -35275,8 +35652,8 @@ var BRIDGE_READY_METHOD = "codexhost/remote-control-bridge/ready";
|
|
|
35275
35652
|
function absoluteEnvironmentPath2(environment, name, fallback, platform = process.platform) {
|
|
35276
35653
|
const value2 = environment[name] ?? fallback;
|
|
35277
35654
|
if (!value2) return null;
|
|
35278
|
-
if (
|
|
35279
|
-
return platform === "win32" &&
|
|
35655
|
+
if (path23.isAbsolute(value2)) return path23.normalize(value2);
|
|
35656
|
+
return platform === "win32" && path23.win32.isAbsolute(value2) ? path23.win32.normalize(value2) : null;
|
|
35280
35657
|
}
|
|
35281
35658
|
function nodeCompatibleWindowsPath(value2) {
|
|
35282
35659
|
if (value2.startsWith("\\\\?\\UNC\\")) return `\\\\${value2.slice(8)}`;
|
|
@@ -35290,13 +35667,13 @@ function remoteControlBridgePipePath(processId = process.pid, instanceId = rando
|
|
|
35290
35667
|
}
|
|
35291
35668
|
function remoteControlBridgeDescriptorPath(environment) {
|
|
35292
35669
|
const root = environment.LOCALAPPDATA;
|
|
35293
|
-
if (!root || !
|
|
35294
|
-
return
|
|
35670
|
+
if (!root || !path23.isAbsolute(root)) return null;
|
|
35671
|
+
return path23.join(path23.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
|
|
35295
35672
|
}
|
|
35296
35673
|
async function publishRemoteControlAppServerDescriptor(plan) {
|
|
35297
|
-
const directory =
|
|
35674
|
+
const directory = path23.dirname(plan.descriptorPath);
|
|
35298
35675
|
await mkdir9(directory, { recursive: true, mode: 448 });
|
|
35299
|
-
const temporaryPath =
|
|
35676
|
+
const temporaryPath = path23.join(
|
|
35300
35677
|
directory,
|
|
35301
35678
|
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID13()}.tmp`
|
|
35302
35679
|
);
|
|
@@ -35597,9 +35974,9 @@ function hasLauncherManagedUpdateRuntime(environment, hostRuntimePath) {
|
|
|
35597
35974
|
if (!environment[UPDATE_RUNTIME_ENV.launcherPid]) return false;
|
|
35598
35975
|
const npmPackageRoot = environment[UPDATE_RUNTIME_ENV.npmPackageRoot];
|
|
35599
35976
|
if (!npmPackageRoot || !hostRuntimePath) return true;
|
|
35600
|
-
if (!
|
|
35601
|
-
const runtimePackageRoot =
|
|
35602
|
-
return
|
|
35977
|
+
if (!path24.isAbsolute(npmPackageRoot) || !path24.isAbsolute(hostRuntimePath)) return false;
|
|
35978
|
+
const runtimePackageRoot = path24.dirname(path24.dirname(path24.normalize(hostRuntimePath)));
|
|
35979
|
+
return path24.relative(path24.normalize(npmPackageRoot), runtimePackageRoot) === "";
|
|
35603
35980
|
}
|
|
35604
35981
|
function requiredRuntimeConfiguration(environment) {
|
|
35605
35982
|
const stockCodexPath = environment[STOCK_CODEX_PATH_ENV];
|
|
@@ -35745,8 +36122,8 @@ async function runHostRuntime(input) {
|
|
|
35745
36122
|
const socketPath = remoteAppServerSocketPath(delegationEnvironment, listenUrl);
|
|
35746
36123
|
const officialPlan = createRemoteOfficialAppServerPlan(input.arguments, socketPath);
|
|
35747
36124
|
const officialRuntimeScope = new OfficialRuntimeScope({
|
|
35748
|
-
permanentHome:
|
|
35749
|
-
delegationEnvironment.CODEX_HOME ??
|
|
36125
|
+
permanentHome: path24.resolve(
|
|
36126
|
+
delegationEnvironment.CODEX_HOME ?? path24.join(homedir2(), ".codex")
|
|
35750
36127
|
),
|
|
35751
36128
|
diagnosticOutput: process.stderr,
|
|
35752
36129
|
createBackend: () => createOwnedUnixBackend({
|
|
@@ -35839,10 +36216,10 @@ import {
|
|
|
35839
36216
|
rename as rename7,
|
|
35840
36217
|
rm as rm10,
|
|
35841
36218
|
rmdir,
|
|
35842
|
-
stat as
|
|
36219
|
+
stat as stat6,
|
|
35843
36220
|
writeFile as writeFile4
|
|
35844
36221
|
} from "node:fs/promises";
|
|
35845
|
-
import
|
|
36222
|
+
import path25 from "node:path";
|
|
35846
36223
|
var MANIFEST_FORMAT = 1;
|
|
35847
36224
|
var WRAPPER_MARKER = "# codexhost remote SSH wrapper v1";
|
|
35848
36225
|
var PROFILE_START = "# >>> codexhost remote SSH >>>";
|
|
@@ -35853,25 +36230,25 @@ function resolvePaths(options2) {
|
|
|
35853
36230
|
if (!configuredHome) {
|
|
35854
36231
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
35855
36232
|
}
|
|
35856
|
-
const home =
|
|
35857
|
-
if (!home || home ===
|
|
36233
|
+
const home = path25.resolve(configuredHome);
|
|
36234
|
+
if (!home || home === path25.parse(home).root) {
|
|
35858
36235
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
35859
36236
|
}
|
|
35860
|
-
const installRoot =
|
|
35861
|
-
const profilePath =
|
|
35862
|
-
options2.profilePath ??
|
|
36237
|
+
const installRoot = path25.resolve(options2.installRoot ?? path25.join(home, ".codexhost", "remote"));
|
|
36238
|
+
const profilePath = path25.resolve(
|
|
36239
|
+
options2.profilePath ?? path25.join(
|
|
35863
36240
|
home,
|
|
35864
|
-
|
|
36241
|
+
path25.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path25.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
|
|
35865
36242
|
)
|
|
35866
36243
|
);
|
|
35867
|
-
const binDirectory =
|
|
36244
|
+
const binDirectory = path25.join(installRoot, "bin");
|
|
35868
36245
|
return {
|
|
35869
36246
|
home,
|
|
35870
36247
|
installRoot,
|
|
35871
36248
|
binDirectory,
|
|
35872
|
-
wrapperPath:
|
|
35873
|
-
manifestPath:
|
|
35874
|
-
dataDirectory:
|
|
36249
|
+
wrapperPath: path25.join(binDirectory, "codex"),
|
|
36250
|
+
manifestPath: path25.join(installRoot, "manifest.json"),
|
|
36251
|
+
dataDirectory: path25.join(installRoot, "data"),
|
|
35875
36252
|
profilePath
|
|
35876
36253
|
};
|
|
35877
36254
|
}
|
|
@@ -35890,9 +36267,9 @@ async function fileSha256(filePath) {
|
|
|
35890
36267
|
return createHash10("sha256").update(await readFile9(filePath)).digest("hex");
|
|
35891
36268
|
}
|
|
35892
36269
|
async function executable(filePath, label) {
|
|
35893
|
-
const absolute =
|
|
36270
|
+
const absolute = path25.resolve(filePath);
|
|
35894
36271
|
try {
|
|
35895
|
-
if (!(await
|
|
36272
|
+
if (!(await stat6(absolute)).isFile()) throw new Error("not a regular file");
|
|
35896
36273
|
await access(absolute, fsConstants.X_OK);
|
|
35897
36274
|
} catch {
|
|
35898
36275
|
throw new Error(`${label} is not an executable file: ${absolute}`);
|
|
@@ -35900,9 +36277,9 @@ async function executable(filePath, label) {
|
|
|
35900
36277
|
return absolute;
|
|
35901
36278
|
}
|
|
35902
36279
|
async function existingFile(filePath, label) {
|
|
35903
|
-
const absolute =
|
|
36280
|
+
const absolute = path25.resolve(filePath);
|
|
35904
36281
|
try {
|
|
35905
|
-
const metadata = await
|
|
36282
|
+
const metadata = await stat6(absolute);
|
|
35906
36283
|
if (!metadata.isFile()) throw new Error("not a regular file");
|
|
35907
36284
|
} catch {
|
|
35908
36285
|
throw new Error(`${label} is not a regular file: ${absolute}`);
|
|
@@ -35910,9 +36287,9 @@ async function existingFile(filePath, label) {
|
|
|
35910
36287
|
return absolute;
|
|
35911
36288
|
}
|
|
35912
36289
|
async function discoverExecutable(name, environment) {
|
|
35913
|
-
for (const directory of (environment.PATH ?? "").split(
|
|
36290
|
+
for (const directory of (environment.PATH ?? "").split(path25.delimiter)) {
|
|
35914
36291
|
if (!directory) continue;
|
|
35915
|
-
const candidate =
|
|
36292
|
+
const candidate = path25.resolve(directory, name);
|
|
35916
36293
|
try {
|
|
35917
36294
|
await access(candidate, fsConstants.X_OK);
|
|
35918
36295
|
return candidate;
|
|
@@ -35923,10 +36300,10 @@ async function discoverExecutable(name, environment) {
|
|
|
35923
36300
|
return null;
|
|
35924
36301
|
}
|
|
35925
36302
|
async function writeAtomic(filePath, contents, mode) {
|
|
35926
|
-
await mkdir10(
|
|
35927
|
-
const temporary =
|
|
35928
|
-
|
|
35929
|
-
`.${
|
|
36303
|
+
await mkdir10(path25.dirname(filePath), { recursive: true, mode: 448 });
|
|
36304
|
+
const temporary = path25.join(
|
|
36305
|
+
path25.dirname(filePath),
|
|
36306
|
+
`.${path25.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
|
|
35930
36307
|
);
|
|
35931
36308
|
try {
|
|
35932
36309
|
if (typeof contents === "string") {
|
|
@@ -35947,10 +36324,10 @@ async function writeAtomic(filePath, contents, mode) {
|
|
|
35947
36324
|
}
|
|
35948
36325
|
}
|
|
35949
36326
|
async function writeAtomicExecutable(filePath, sourcePath) {
|
|
35950
|
-
await mkdir10(
|
|
35951
|
-
const temporary =
|
|
35952
|
-
|
|
35953
|
-
`.${
|
|
36327
|
+
await mkdir10(path25.dirname(filePath), { recursive: true, mode: 448 });
|
|
36328
|
+
const temporary = path25.join(
|
|
36329
|
+
path25.dirname(filePath),
|
|
36330
|
+
`.${path25.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
|
|
35954
36331
|
);
|
|
35955
36332
|
try {
|
|
35956
36333
|
await copyFile3(sourcePath, temporary);
|
|
@@ -35991,8 +36368,8 @@ function removeManagedProfileBlock(contents) {
|
|
|
35991
36368
|
function installManagedProfileBlock(contents, manifest) {
|
|
35992
36369
|
const base = removeManagedProfileBlock(contents);
|
|
35993
36370
|
const environment = [
|
|
35994
|
-
`export CODEX_INSTALL_DIR=${shellQuote(
|
|
35995
|
-
`export PATH=${shellQuote(
|
|
36371
|
+
`export CODEX_INSTALL_DIR=${shellQuote(path25.dirname(manifest.wrapperPath))}`,
|
|
36372
|
+
`export PATH=${shellQuote(path25.dirname(manifest.wrapperPath))}:${shellQuote(path25.dirname(manifest.nodePath))}:${shellQuote(path25.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
|
|
35996
36373
|
`export CODEXHOST_STOCK_CODEX_PATH=${shellQuote(manifest.stockCodexPath)}`,
|
|
35997
36374
|
`export CODEXHOST_HOST_NODE_PATH=${shellQuote(manifest.nodePath)}`,
|
|
35998
36375
|
`export CODEXHOST_HOST_RUNTIME_PATH=${shellQuote(manifest.hostRuntimePath)}`,
|
|
@@ -36008,7 +36385,7 @@ function installManagedProfileBlock(contents, manifest) {
|
|
|
36008
36385
|
PROFILE_END,
|
|
36009
36386
|
""
|
|
36010
36387
|
].join("\n");
|
|
36011
|
-
if (
|
|
36388
|
+
if (path25.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
|
|
36012
36389
|
const separator = base.length > 0 && !base.endsWith("\n") ? "\n" : "";
|
|
36013
36390
|
return `${base}${separator}${block}`;
|
|
36014
36391
|
}
|
|
@@ -36074,9 +36451,9 @@ async function readManifest(filePath) {
|
|
|
36074
36451
|
];
|
|
36075
36452
|
const optionalPaths = ["claudeCommand", "profileBackupPath"];
|
|
36076
36453
|
if (manifest.format !== MANIFEST_FORMAT || Object.keys(manifest).some((key) => !allowed.has(key)) || requiredPaths.some(
|
|
36077
|
-
(key) => typeof manifest[key] !== "string" || !
|
|
36454
|
+
(key) => typeof manifest[key] !== "string" || !path25.isAbsolute(manifest[key])
|
|
36078
36455
|
) || optionalPaths.some(
|
|
36079
|
-
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !
|
|
36456
|
+
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path25.isAbsolute(manifest[key]))
|
|
36080
36457
|
) || manifest.entrypointSha256 !== void 0 && (typeof manifest.entrypointSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(manifest.entrypointSha256))) {
|
|
36081
36458
|
throw new Error("Remote Host manifest has an unsupported format");
|
|
36082
36459
|
}
|
|
@@ -36085,7 +36462,7 @@ async function readManifest(filePath) {
|
|
|
36085
36462
|
async function backupProfile(profilePath, contents, action) {
|
|
36086
36463
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replaceAll(/[-:.TZ]/gu, "");
|
|
36087
36464
|
const backupPath = `${profilePath}.codexhost-${action}-${timestamp}.bak`;
|
|
36088
|
-
const metadata = await
|
|
36465
|
+
const metadata = await stat6(profilePath).catch(() => null);
|
|
36089
36466
|
await writeAtomic(backupPath, contents, metadata?.mode ?? 384);
|
|
36090
36467
|
return backupPath;
|
|
36091
36468
|
}
|
|
@@ -36099,7 +36476,7 @@ async function installRemoteHost(options2) {
|
|
|
36099
36476
|
const previousManifest = await readManifest(paths.manifestPath);
|
|
36100
36477
|
const previousManifestFile = previousManifest ? {
|
|
36101
36478
|
contents: await readFile9(paths.manifestPath),
|
|
36102
|
-
mode: (await
|
|
36479
|
+
mode: (await stat6(paths.manifestPath)).mode & 511
|
|
36103
36480
|
} : null;
|
|
36104
36481
|
const existingEntrypoint = await lstat8(paths.wrapperPath).catch(
|
|
36105
36482
|
(error51) => {
|
|
@@ -36155,7 +36532,7 @@ async function installRemoteHost(options2) {
|
|
|
36155
36532
|
const existingProfile = existingProfileSource ?? "";
|
|
36156
36533
|
const nextProfile = installManagedProfileBlock(existingProfile, manifest);
|
|
36157
36534
|
const profileChanged = nextProfile !== existingProfile;
|
|
36158
|
-
const profileMetadata = await
|
|
36535
|
+
const profileMetadata = await stat6(profilePath).catch(() => null);
|
|
36159
36536
|
try {
|
|
36160
36537
|
if (profileChanged) {
|
|
36161
36538
|
const profileBackupPath = await backupProfile(profilePath, existingProfile, "install");
|
|
@@ -36246,7 +36623,7 @@ async function inspectRemoteHostInstallation(options2) {
|
|
|
36246
36623
|
if (!profileMatches && profileIssue === null)
|
|
36247
36624
|
profileIssue = "shell profile does not configure the managed native entrypoint";
|
|
36248
36625
|
if (profileIssue !== null) issues.push(profileIssue);
|
|
36249
|
-
const dataDirectory = await
|
|
36626
|
+
const dataDirectory = await stat6(manifest.dataDirectory).catch(() => null);
|
|
36250
36627
|
if (!dataDirectory?.isDirectory()) issues.push("remote Host data directory is unavailable");
|
|
36251
36628
|
for (const [label, filePath, requiresExecutable] of [
|
|
36252
36629
|
["stock Codex", manifest.stockCodexPath, true],
|
|
@@ -36256,7 +36633,7 @@ async function inspectRemoteHostInstallation(options2) {
|
|
|
36256
36633
|
]) {
|
|
36257
36634
|
try {
|
|
36258
36635
|
if (requiresExecutable) await executable(filePath, label);
|
|
36259
|
-
else if (!(await
|
|
36636
|
+
else if (!(await stat6(filePath)).isFile()) throw new Error("not a regular file");
|
|
36260
36637
|
} catch {
|
|
36261
36638
|
issues.push(`${label} is unavailable`);
|
|
36262
36639
|
}
|
|
@@ -36285,7 +36662,7 @@ async function uninstallRemoteHost(options2) {
|
|
|
36285
36662
|
const nextProfile = removeManagedProfileBlock(profile);
|
|
36286
36663
|
if (nextProfile !== profile) {
|
|
36287
36664
|
await backupProfile(manifest.profilePath, profile, "uninstall");
|
|
36288
|
-
const metadata = await
|
|
36665
|
+
const metadata = await stat6(manifest.profilePath).catch(() => null);
|
|
36289
36666
|
await writeAtomic(manifest.profilePath, nextProfile, metadata?.mode ?? 384);
|
|
36290
36667
|
}
|
|
36291
36668
|
await rm10(manifest.wrapperPath, { force: true });
|
|
@@ -36300,9 +36677,9 @@ async function uninstallRemoteHost(options2) {
|
|
|
36300
36677
|
|
|
36301
36678
|
// packages/host-runtime/src/remote-host-lifecycle.ts
|
|
36302
36679
|
import { spawn as spawn5 } from "node:child_process";
|
|
36303
|
-
import { stat as
|
|
36680
|
+
import { stat as stat7 } from "node:fs/promises";
|
|
36304
36681
|
import net3 from "node:net";
|
|
36305
|
-
import
|
|
36682
|
+
import path26 from "node:path";
|
|
36306
36683
|
import { Duplex } from "node:stream";
|
|
36307
36684
|
var CODEXHOST_STATUS_METHOD = "codexhost/update/status";
|
|
36308
36685
|
var DIRECT_PROBE_TIMEOUT_MS = 5e3;
|
|
@@ -36321,12 +36698,12 @@ function classifyRemoteHostProbeResponse(response, socketPath) {
|
|
|
36321
36698
|
}
|
|
36322
36699
|
var lifecycleDependencyOverrides = {};
|
|
36323
36700
|
function socketPathFor(environment) {
|
|
36324
|
-
const codexHome = environment.CODEX_HOME ?? (environment.HOME ?
|
|
36701
|
+
const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path26.join(environment.HOME, ".codex") : void 0);
|
|
36325
36702
|
if (!codexHome) throw new Error("CODEX_HOME or HOME is required for remote Host lifecycle");
|
|
36326
|
-
return
|
|
36703
|
+
return path26.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
36327
36704
|
}
|
|
36328
36705
|
async function defaultSocketExists(socketPath) {
|
|
36329
|
-
const metadata = await
|
|
36706
|
+
const metadata = await stat7(socketPath).catch((error51) => {
|
|
36330
36707
|
if (error51.code === "ENOENT") return null;
|
|
36331
36708
|
throw error51;
|
|
36332
36709
|
});
|
|
@@ -36450,14 +36827,14 @@ function installedManifest(status) {
|
|
|
36450
36827
|
function managedEnvironment(manifest, environment) {
|
|
36451
36828
|
return {
|
|
36452
36829
|
...environment,
|
|
36453
|
-
CODEX_INSTALL_DIR:
|
|
36830
|
+
CODEX_INSTALL_DIR: path26.dirname(manifest.wrapperPath),
|
|
36454
36831
|
CODEXHOST_STOCK_CODEX_PATH: manifest.stockCodexPath,
|
|
36455
36832
|
CODEXHOST_HOST_NODE_PATH: manifest.nodePath,
|
|
36456
36833
|
CODEXHOST_HOST_RUNTIME_PATH: manifest.hostRuntimePath,
|
|
36457
36834
|
CODEXHOST_DATA_DIR: manifest.dataDirectory,
|
|
36458
36835
|
CODEXHOST_DEFAULT_AGENT: "codex",
|
|
36459
36836
|
CODEXHOST_REMOTE_SSH_MANAGED: "1",
|
|
36460
|
-
PATH: `${
|
|
36837
|
+
PATH: `${path26.dirname(manifest.wrapperPath)}${path26.delimiter}${path26.dirname(manifest.stockCodexPath)}${path26.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
|
|
36461
36838
|
};
|
|
36462
36839
|
}
|
|
36463
36840
|
async function defaultRunTerminator(manifest, socketPath, role, environment) {
|
|
@@ -36793,25 +37170,25 @@ function consumeBrokerFrames(socket, onFrame, onError) {
|
|
|
36793
37170
|
|
|
36794
37171
|
// packages/harness-broker/dist/paths.js
|
|
36795
37172
|
import os7 from "node:os";
|
|
36796
|
-
import
|
|
37173
|
+
import path27 from "node:path";
|
|
36797
37174
|
var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
|
|
36798
37175
|
var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
|
|
36799
37176
|
var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
|
|
36800
37177
|
function defaultHarnessBrokerDirectory(environment = process.env) {
|
|
36801
37178
|
const home = environment.HOME || os7.homedir();
|
|
36802
|
-
return
|
|
37179
|
+
return path27.join(home, ".codexhost", "harness-broker");
|
|
36803
37180
|
}
|
|
36804
37181
|
function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
|
|
36805
37182
|
harnessPluginIdSchema.parse(harnessId);
|
|
36806
37183
|
if (harnessId !== "claude-code")
|
|
36807
|
-
return
|
|
36808
|
-
return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ??
|
|
37184
|
+
return path27.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
|
|
37185
|
+
return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path27.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
|
|
36809
37186
|
}
|
|
36810
37187
|
function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
|
|
36811
37188
|
harnessPluginIdSchema.parse(harnessId);
|
|
36812
37189
|
if (harnessId !== "claude-code")
|
|
36813
|
-
return
|
|
36814
|
-
return
|
|
37190
|
+
return path27.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
|
|
37191
|
+
return path27.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
|
|
36815
37192
|
}
|
|
36816
37193
|
|
|
36817
37194
|
// packages/harness-broker/dist/validation.js
|
|
@@ -37027,7 +37404,7 @@ var harnessOutputSchema = external_exports.custom((value2) => {
|
|
|
37027
37404
|
import { randomBytes as randomBytes3, randomUUID as randomUUID15 } from "node:crypto";
|
|
37028
37405
|
import { chmod as chmod5, lstat as lstat9, mkdir as mkdir11, open as open8, readFile as readFile10, rename as rename8, rm as rm11 } from "node:fs/promises";
|
|
37029
37406
|
import net4, {} from "node:net";
|
|
37030
|
-
import
|
|
37407
|
+
import path28 from "node:path";
|
|
37031
37408
|
function harnessError(message, retryable = true) {
|
|
37032
37409
|
return { code: "unavailable", message, retryable, stage: "harnessBroker" };
|
|
37033
37410
|
}
|
|
@@ -37150,13 +37527,13 @@ async function prepareUnixSocketPath(socketPath) {
|
|
|
37150
37527
|
}
|
|
37151
37528
|
async function startHarnessBrokerServer(input) {
|
|
37152
37529
|
harnessPluginIdSchema.parse(input.adapter.harnessId);
|
|
37153
|
-
if (process.platform !== "win32" &&
|
|
37530
|
+
if (process.platform !== "win32" && path28.dirname(input.descriptorPath) !== path28.dirname(input.socketPath)) {
|
|
37154
37531
|
throw new Error("Harness broker descriptor and socket must share one private directory");
|
|
37155
37532
|
}
|
|
37156
37533
|
if (process.platform === "darwin" && Buffer.byteLength(input.socketPath) > 103) {
|
|
37157
37534
|
throw new Error("Harness broker Unix socket path is too long for macOS");
|
|
37158
37535
|
}
|
|
37159
|
-
await privateDirectory(
|
|
37536
|
+
await privateDirectory(path28.dirname(input.descriptorPath));
|
|
37160
37537
|
await assertNoLiveDescriptor(input.descriptorPath);
|
|
37161
37538
|
if (process.platform !== "win32")
|
|
37162
37539
|
await prepareUnixSocketPath(input.socketPath);
|