@codexhost/cli-win32-arm64 0.9.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/THIRD_PARTY_NOTICES.txt +0 -4
- package/app/codexhost-distribution.json +1 -1
- package/app/desktop-controller.mjs +49 -18
- package/app/host-runtime.mjs +980 -650
- package/app/plugins/antigravity/plugin.mjs +18 -3
- package/app/plugins/claude-code/plugin.mjs +214 -7
- package/app/plugins/codebuddy/plugin.mjs +103 -5
- package/app/plugins/cursor-cli/plugin.mjs +152 -53
- package/app/plugins/deepseek-harness/plugin.mjs +34 -21
- package/app/plugins/enabled.json +2 -1
- package/app/plugins/grok/plugin.mjs +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 +258 -67
- package/app/plugins/opencode/plugin.mjs +18 -3
- package/app/plugins/pi/plugin.mjs +211 -4
- 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 +1394 -520
- 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 path23 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, path28) {
|
|
5982
|
+
if (!path28)
|
|
5983
5983
|
return obj;
|
|
5984
|
-
return
|
|
5984
|
+
return path28.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(path28, 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(path28);
|
|
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, path28 = []) => {
|
|
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 }, [...path28, ...issue2.path]));
|
|
6548
6548
|
} else if (issue2.code === "invalid_key") {
|
|
6549
|
-
processError({ issues: issue2.issues }, [...
|
|
6549
|
+
processError({ issues: issue2.issues }, [...path28, ...issue2.path]);
|
|
6550
6550
|
} else if (issue2.code === "invalid_element") {
|
|
6551
|
-
processError({ issues: issue2.issues }, [...
|
|
6551
|
+
processError({ issues: issue2.issues }, [...path28, ...issue2.path]);
|
|
6552
6552
|
} else {
|
|
6553
|
-
const fullpath = [...
|
|
6553
|
+
const fullpath = [...path28, ...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, path28 = []) => {
|
|
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 }, [...path28, ...issue2.path]));
|
|
6585
6585
|
} else if (issue2.code === "invalid_key") {
|
|
6586
|
-
processError({ issues: issue2.issues }, [...
|
|
6586
|
+
processError({ issues: issue2.issues }, [...path28, ...issue2.path]);
|
|
6587
6587
|
} else if (issue2.code === "invalid_element") {
|
|
6588
|
-
processError({ issues: issue2.issues }, [...
|
|
6588
|
+
processError({ issues: issue2.issues }, [...path28, ...issue2.path]);
|
|
6589
6589
|
} else {
|
|
6590
|
-
const fullpath = [...
|
|
6590
|
+
const fullpath = [...path28, ...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 path28 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
6623
|
+
for (const seg of path28) {
|
|
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 path28 = ref.slice(1).split("/").filter(Boolean);
|
|
19316
|
+
if (path28.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 (path28[0] === defsKey) {
|
|
19321
|
+
const key = path28[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(path28, added, removed, oldPosInc, options2) {
|
|
22818
|
+
const last = path28.lastComponent;
|
|
22468
22819
|
if (last && !options2.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
22469
22820
|
return {
|
|
22470
|
-
oldPos:
|
|
22821
|
+
oldPos: path28.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: path28.oldPos + oldPosInc,
|
|
22476
22827
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
22477
22828
|
};
|
|
22478
22829
|
}
|
|
@@ -22901,10 +23252,10 @@ function splitLines(text) {
|
|
|
22901
23252
|
}
|
|
22902
23253
|
|
|
22903
23254
|
// packages/protocol-core/dist/file-change-summary.js
|
|
22904
|
-
import
|
|
23255
|
+
import path8 from "node:path";
|
|
22905
23256
|
function filePathKey(file2, cwd) {
|
|
22906
23257
|
const windows = /^[a-z]:[/\\]/i.test(cwd) || /^[a-z]:[/\\]/i.test(file2);
|
|
22907
|
-
const paths = windows ?
|
|
23258
|
+
const paths = windows ? path8.win32 : path8.posix;
|
|
22908
23259
|
const resolved = paths.resolve(cwd, file2).replaceAll("\\", "/");
|
|
22909
23260
|
return windows ? resolved.toLowerCase() : resolved;
|
|
22910
23261
|
}
|
|
@@ -23055,11 +23406,11 @@ function itemStatus(outcome) {
|
|
|
23055
23406
|
return "inProgress";
|
|
23056
23407
|
return outcome.status === "succeeded" ? "completed" : "failed";
|
|
23057
23408
|
}
|
|
23058
|
-
function
|
|
23409
|
+
function isRecord6(value2) {
|
|
23059
23410
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
23060
23411
|
}
|
|
23061
23412
|
function nestedString(value2, keys, preserveText = false) {
|
|
23062
|
-
if (!
|
|
23413
|
+
if (!isRecord6(value2))
|
|
23063
23414
|
return void 0;
|
|
23064
23415
|
for (const key of keys) {
|
|
23065
23416
|
const field = value2[key];
|
|
@@ -23173,8 +23524,8 @@ function projectFileChangeKind(kind) {
|
|
|
23173
23524
|
return { type: kind };
|
|
23174
23525
|
}
|
|
23175
23526
|
function projectFileChanges(changes) {
|
|
23176
|
-
return changes.map(({ path:
|
|
23177
|
-
path:
|
|
23527
|
+
return changes.map(({ path: path28, kind, unifiedDiff }) => ({
|
|
23528
|
+
path: path28,
|
|
23178
23529
|
kind: projectFileChangeKind(kind),
|
|
23179
23530
|
diff: unifiedDiff
|
|
23180
23531
|
}));
|
|
@@ -23214,7 +23565,7 @@ function planFromTodoValue(value2) {
|
|
|
23214
23565
|
const record3 = unwrapToolRecord(value2);
|
|
23215
23566
|
if (!record3)
|
|
23216
23567
|
return planFromChecklistText(typeof value2 === "string" ? value2 : null);
|
|
23217
|
-
if (
|
|
23568
|
+
if (isRecord6(record3.TodosUpdated)) {
|
|
23218
23569
|
const nested = planFromTodoValue(record3.TodosUpdated);
|
|
23219
23570
|
if (nested)
|
|
23220
23571
|
return nested;
|
|
@@ -23229,7 +23580,7 @@ function planFromTodoValue(value2) {
|
|
|
23229
23580
|
plan.push({ step: entry.trim(), status: "pending" });
|
|
23230
23581
|
continue;
|
|
23231
23582
|
}
|
|
23232
|
-
if (!
|
|
23583
|
+
if (!isRecord6(entry))
|
|
23233
23584
|
continue;
|
|
23234
23585
|
const step = nestedString(entry, ["content", "step", "text", "title", "description", "task"]);
|
|
23235
23586
|
if (!step)
|
|
@@ -23284,7 +23635,7 @@ function unwrapToolRecord(value2) {
|
|
|
23284
23635
|
}
|
|
23285
23636
|
if (Array.isArray(value2))
|
|
23286
23637
|
return { todos: value2 };
|
|
23287
|
-
if (!
|
|
23638
|
+
if (!isRecord6(value2))
|
|
23288
23639
|
return null;
|
|
23289
23640
|
for (const wrapper of ["input", "arguments", "params"]) {
|
|
23290
23641
|
if (value2[wrapper] === void 0)
|
|
@@ -24074,7 +24425,7 @@ var CodexTurnProjector = class {
|
|
|
24074
24425
|
};
|
|
24075
24426
|
|
|
24076
24427
|
// packages/protocol-core/dist/thread-fork.js
|
|
24077
|
-
function
|
|
24428
|
+
function isRecord7(value2) {
|
|
24078
24429
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
24079
24430
|
}
|
|
24080
24431
|
function optionalText(params, name, options2 = {}) {
|
|
@@ -24097,7 +24448,7 @@ function optionalBoolean(params, name) {
|
|
|
24097
24448
|
function decodeThreadForkRequest(request) {
|
|
24098
24449
|
if (request.method !== "thread/fork")
|
|
24099
24450
|
return null;
|
|
24100
|
-
if (!
|
|
24451
|
+
if (!isRecord7(request.params))
|
|
24101
24452
|
throw new Error("thread/fork params must be an object");
|
|
24102
24453
|
const params = request.params;
|
|
24103
24454
|
const threadId2 = optionalText(params, "threadId");
|
|
@@ -24112,13 +24463,13 @@ function decodeThreadForkRequest(request) {
|
|
|
24112
24463
|
if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
|
|
24113
24464
|
throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
|
|
24114
24465
|
}
|
|
24115
|
-
const
|
|
24466
|
+
const path28 = optionalText(params, "path", { allowEmpty: true });
|
|
24116
24467
|
const ephemeral = optionalBoolean(params, "ephemeral");
|
|
24117
24468
|
return {
|
|
24118
24469
|
threadId: threadId2,
|
|
24119
24470
|
...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
|
|
24120
24471
|
...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
|
|
24121
|
-
...
|
|
24472
|
+
...path28 ? { path: path28 } : {},
|
|
24122
24473
|
...optionalField(params, "model"),
|
|
24123
24474
|
...optionalField(params, "modelProvider"),
|
|
24124
24475
|
...optionalField(params, "cwd"),
|
|
@@ -24133,7 +24484,7 @@ function decodeThreadForkRequest(request) {
|
|
|
24133
24484
|
function decodeThreadRevertRequest(request) {
|
|
24134
24485
|
if (request.method !== "thread/revert")
|
|
24135
24486
|
return null;
|
|
24136
|
-
if (!
|
|
24487
|
+
if (!isRecord7(request.params))
|
|
24137
24488
|
throw new Error("thread/revert params must be an object");
|
|
24138
24489
|
const { threadId: threadId2, beforeTurnId } = request.params;
|
|
24139
24490
|
if (typeof threadId2 !== "string" || threadId2.length === 0) {
|
|
@@ -24147,7 +24498,7 @@ function decodeThreadRevertRequest(request) {
|
|
|
24147
24498
|
function decodeThreadRollbackRequest(request) {
|
|
24148
24499
|
if (request.method !== "thread/rollback")
|
|
24149
24500
|
return null;
|
|
24150
|
-
if (!
|
|
24501
|
+
if (!isRecord7(request.params))
|
|
24151
24502
|
throw new Error("thread/rollback params must be an object");
|
|
24152
24503
|
const { threadId: threadId2, numTurns } = request.params;
|
|
24153
24504
|
if (typeof threadId2 !== "string" || threadId2.length === 0) {
|
|
@@ -24211,7 +24562,7 @@ function threadForkResult(thread, input) {
|
|
|
24211
24562
|
}
|
|
24212
24563
|
|
|
24213
24564
|
// packages/protocol-core/dist/thread-management.js
|
|
24214
|
-
import { createHash as
|
|
24565
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
24215
24566
|
var HOST_CURSOR_PREFIX = "codexhost:thread-list:v1:";
|
|
24216
24567
|
var MAX_CURSOR_LENGTH = 65536;
|
|
24217
24568
|
var DEFAULT_PAGE_SIZE = 25;
|
|
@@ -24244,13 +24595,13 @@ var THREAD_SOURCE_KINDS = /* @__PURE__ */ new Set([
|
|
|
24244
24595
|
"subAgentOther",
|
|
24245
24596
|
"unknown"
|
|
24246
24597
|
]);
|
|
24247
|
-
function
|
|
24598
|
+
function isRecord8(value2) {
|
|
24248
24599
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
24249
24600
|
}
|
|
24250
24601
|
function paramsObject(request, method) {
|
|
24251
24602
|
if (request.params === void 0 && method === "thread/list")
|
|
24252
24603
|
return {};
|
|
24253
|
-
if (!
|
|
24604
|
+
if (!isRecord8(request.params))
|
|
24254
24605
|
throw new Error(`${method} params must be an object`);
|
|
24255
24606
|
return request.params;
|
|
24256
24607
|
}
|
|
@@ -24308,7 +24659,7 @@ function decodeSortKey(value2) {
|
|
|
24308
24659
|
return value2;
|
|
24309
24660
|
}
|
|
24310
24661
|
function queryFingerprint(value2) {
|
|
24311
|
-
return
|
|
24662
|
+
return createHash4("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
24312
24663
|
}
|
|
24313
24664
|
function cursorPayload(value2) {
|
|
24314
24665
|
return {
|
|
@@ -24322,7 +24673,7 @@ function cursorPayload(value2) {
|
|
|
24322
24673
|
};
|
|
24323
24674
|
}
|
|
24324
24675
|
function parseCursorPayload(value2) {
|
|
24325
|
-
if (!
|
|
24676
|
+
if (!isRecord8(value2) || value2.formatVersion !== 1)
|
|
24326
24677
|
throw new Error("Host cursor is invalid");
|
|
24327
24678
|
const { queryFingerprint: fingerprint, sortDirection: sortDirection2, officialCursor, officialDone } = value2;
|
|
24328
24679
|
const { externalAnchor: externalAnchor2, externalDone } = value2;
|
|
@@ -24331,7 +24682,7 @@ function parseCursorPayload(value2) {
|
|
|
24331
24682
|
}
|
|
24332
24683
|
let anchor = null;
|
|
24333
24684
|
if (externalAnchor2 !== null) {
|
|
24334
|
-
if (!
|
|
24685
|
+
if (!isRecord8(externalAnchor2) || !Number.isSafeInteger(externalAnchor2.timestamp) || typeof externalAnchor2.threadId !== "string" || externalAnchor2.threadId.length === 0) {
|
|
24335
24686
|
throw new Error("Host cursor is invalid");
|
|
24336
24687
|
}
|
|
24337
24688
|
anchor = {
|
|
@@ -24454,7 +24805,7 @@ function decodeThreadMetadataUpdateRequest(request) {
|
|
|
24454
24805
|
if (params.gitInfo === null) {
|
|
24455
24806
|
gitInfo = null;
|
|
24456
24807
|
} else if (params.gitInfo !== void 0) {
|
|
24457
|
-
if (!
|
|
24808
|
+
if (!isRecord8(params.gitInfo)) {
|
|
24458
24809
|
throw new Error("thread/metadata/update params.gitInfo must be an object or null");
|
|
24459
24810
|
}
|
|
24460
24811
|
gitInfo = {};
|
|
@@ -24482,7 +24833,7 @@ function optionalCursor(value2, name) {
|
|
|
24482
24833
|
return value2;
|
|
24483
24834
|
}
|
|
24484
24835
|
function decodeOfficialThreadListPage(value2) {
|
|
24485
|
-
if (!
|
|
24836
|
+
if (!isRecord8(value2) || !Array.isArray(value2.data) || value2.data.some((row) => !isRecord8(row))) {
|
|
24486
24837
|
throw new Error("Official thread/list response is invalid");
|
|
24487
24838
|
}
|
|
24488
24839
|
return {
|
|
@@ -25294,22 +25645,22 @@ var HarnessAccountInspectionCache = class {
|
|
|
25294
25645
|
};
|
|
25295
25646
|
|
|
25296
25647
|
// packages/host-runtime/src/app-server-host.ts
|
|
25297
|
-
import { createHash as
|
|
25298
|
-
import
|
|
25299
|
-
import
|
|
25648
|
+
import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
|
|
25649
|
+
import os5 from "node:os";
|
|
25650
|
+
import path15 from "node:path";
|
|
25300
25651
|
|
|
25301
25652
|
// packages/host-runtime/src/external-thread-fork.ts
|
|
25302
25653
|
import nodePath from "node:path";
|
|
25303
25654
|
|
|
25304
25655
|
// packages/host-runtime/src/external-thread-repository.ts
|
|
25305
|
-
import { randomUUID as
|
|
25306
|
-
import
|
|
25307
|
-
import
|
|
25656
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
25657
|
+
import os3 from "node:os";
|
|
25658
|
+
import path9 from "node:path";
|
|
25308
25659
|
|
|
25309
25660
|
// packages/host-runtime/src/external-subagent-threads.ts
|
|
25310
|
-
import { createHash as
|
|
25661
|
+
import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypto";
|
|
25311
25662
|
function childCreateRequest(parent, nativeRef, id2) {
|
|
25312
|
-
const key =
|
|
25663
|
+
const key = createHash5("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
|
|
25313
25664
|
return `subagent:${key}`;
|
|
25314
25665
|
}
|
|
25315
25666
|
function subagentMaterializer(store, parent, previousParent) {
|
|
@@ -25382,7 +25733,7 @@ function subagentMaterializer(store, parent, previousParent) {
|
|
|
25382
25733
|
return rebind(existing, parent);
|
|
25383
25734
|
}
|
|
25384
25735
|
const provisional = existing ?? await store.createProvisional({
|
|
25385
|
-
hostThreadId: hostThreadIdSchema.parse(
|
|
25736
|
+
hostThreadId: hostThreadIdSchema.parse(randomUUID4()),
|
|
25386
25737
|
createRequestId,
|
|
25387
25738
|
harnessId: parent.harnessId,
|
|
25388
25739
|
cwd: parent.cwd,
|
|
@@ -25444,8 +25795,8 @@ function sameMapping(left, right) {
|
|
|
25444
25795
|
}
|
|
25445
25796
|
function defaultMappingStoreDirectory(environment) {
|
|
25446
25797
|
const dataDirectory = environment.CODEXHOST_DATA_DIR;
|
|
25447
|
-
return
|
|
25448
|
-
dataDirectory ?
|
|
25798
|
+
return path9.join(
|
|
25799
|
+
dataDirectory ? path9.resolve(dataDirectory) : path9.join(os3.homedir(), ".codexhost"),
|
|
25449
25800
|
"mapping-store"
|
|
25450
25801
|
);
|
|
25451
25802
|
}
|
|
@@ -25542,7 +25893,7 @@ var ExternalThreadRepository = class {
|
|
|
25542
25893
|
throw new Error("Derived Snapshot identity does not belong to its Native Session");
|
|
25543
25894
|
}
|
|
25544
25895
|
return {
|
|
25545
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
25896
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
|
|
25546
25897
|
nativeTurnRef: turn.nativeTurnRef,
|
|
25547
25898
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
25548
25899
|
};
|
|
@@ -25662,7 +26013,7 @@ var ExternalThreadRepository = class {
|
|
|
25662
26013
|
const aligned = snapshot.turns.map((turn) => {
|
|
25663
26014
|
const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
|
|
25664
26015
|
const mapping = existing ?? {
|
|
25665
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
26016
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
|
|
25666
26017
|
nativeTurnRef: turn.nativeTurnRef,
|
|
25667
26018
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
25668
26019
|
};
|
|
@@ -25689,8 +26040,8 @@ var ExternalThreadRepository = class {
|
|
|
25689
26040
|
};
|
|
25690
26041
|
function createExternalThreadRecordInput(input) {
|
|
25691
26042
|
return {
|
|
25692
|
-
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(
|
|
25693
|
-
createRequestId: input.createRequestId ??
|
|
26043
|
+
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID5()),
|
|
26044
|
+
createRequestId: input.createRequestId ?? randomUUID5(),
|
|
25694
26045
|
harnessId: input.harnessId,
|
|
25695
26046
|
cwd: input.cwd,
|
|
25696
26047
|
...input.title ? { title: input.title } : {},
|
|
@@ -25851,6 +26202,7 @@ async function executeExternalThreadFork(input) {
|
|
|
25851
26202
|
return { ok: false, error: mapExternalThreadHarnessError(opened.error, "fork") };
|
|
25852
26203
|
}
|
|
25853
26204
|
const session = opened.value;
|
|
26205
|
+
const inheritedPermissionModeId = await inheritSourcePermissionMode(source, session);
|
|
25854
26206
|
try {
|
|
25855
26207
|
const derivedNativeRef = session.initialState.nativeRef;
|
|
25856
26208
|
if (!derivedNativeRef || derivedNativeRef.nativeSessionId === nativeSessionRef.nativeSessionId) {
|
|
@@ -25878,7 +26230,8 @@ async function executeExternalThreadFork(input) {
|
|
|
25878
26230
|
sessionId: source.sessionId,
|
|
25879
26231
|
thread,
|
|
25880
26232
|
turns: aligned.turns,
|
|
25881
|
-
...snapshot.value.state ? { restoredState: snapshot.value.state } : {}
|
|
26233
|
+
...snapshot.value.state ? { restoredState: snapshot.value.state } : {},
|
|
26234
|
+
...inheritedPermissionModeId ? { requestedPermissionModeId: inheritedPermissionModeId } : {}
|
|
25882
26235
|
});
|
|
25883
26236
|
return {
|
|
25884
26237
|
ok: true,
|
|
@@ -25896,6 +26249,23 @@ async function executeExternalThreadFork(input) {
|
|
|
25896
26249
|
};
|
|
25897
26250
|
}
|
|
25898
26251
|
}
|
|
26252
|
+
async function inheritSourcePermissionMode(source, session) {
|
|
26253
|
+
const sourceModeId = source.stateObserver.state.effectivePermissionModeId ?? source.requestedPermissionModeId;
|
|
26254
|
+
if (!sourceModeId) return void 0;
|
|
26255
|
+
const configuration = session.capabilities.configuration;
|
|
26256
|
+
if (!configuration.selectPermissionMode || permissionModeFixedAtCreate(configuration)) {
|
|
26257
|
+
return void 0;
|
|
26258
|
+
}
|
|
26259
|
+
try {
|
|
26260
|
+
const selected = await session.execute({
|
|
26261
|
+
type: "permissionMode.select",
|
|
26262
|
+
permissionModeId: sourceModeId
|
|
26263
|
+
});
|
|
26264
|
+
return selected.ok ? sourceModeId : void 0;
|
|
26265
|
+
} catch {
|
|
26266
|
+
return void 0;
|
|
26267
|
+
}
|
|
26268
|
+
}
|
|
25899
26269
|
|
|
25900
26270
|
// packages/host-runtime/src/harness-session-import.ts
|
|
25901
26271
|
function fixedError(code, message) {
|
|
@@ -27460,9 +27830,12 @@ var ExternalTurnSteering = class {
|
|
|
27460
27830
|
if (!cancelled.ok) throw new ExternalSteerError(-32074, cancelled.error.message);
|
|
27461
27831
|
const outcome = await Promise.race([terminal2.promise, failure.promise]);
|
|
27462
27832
|
clearTimeout(timeout);
|
|
27463
|
-
|
|
27464
|
-
|
|
27465
|
-
|
|
27833
|
+
const assertActive = () => {
|
|
27834
|
+
if (failureReason) throw failureReason;
|
|
27835
|
+
if (this.#closed)
|
|
27836
|
+
throw new ExternalSteerError(-32074, "External steering connection is closed");
|
|
27837
|
+
};
|
|
27838
|
+
assertActive();
|
|
27466
27839
|
if (outcome.status === "failed") throw new ExternalSteerError(-32074, outcome.error.message);
|
|
27467
27840
|
if (thread.persistenceError)
|
|
27468
27841
|
throw new ExternalSteerError(
|
|
@@ -27472,7 +27845,7 @@ var ExternalTurnSteering = class {
|
|
|
27472
27845
|
if (thread.running || thread.activeTurnId) {
|
|
27473
27846
|
throw new ExternalSteerError(-32072, "Another External Turn started before replacement");
|
|
27474
27847
|
}
|
|
27475
|
-
return await start(input.text);
|
|
27848
|
+
return await start(input.text, assertActive);
|
|
27476
27849
|
} finally {
|
|
27477
27850
|
clearTimeout(timeout);
|
|
27478
27851
|
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
@@ -27480,30 +27853,112 @@ var ExternalTurnSteering = class {
|
|
|
27480
27853
|
}
|
|
27481
27854
|
};
|
|
27482
27855
|
|
|
27483
|
-
// packages/host-runtime/src/
|
|
27484
|
-
|
|
27485
|
-
|
|
27486
|
-
|
|
27487
|
-
|
|
27488
|
-
|
|
27489
|
-
|
|
27490
|
-
|
|
27491
|
-
|
|
27492
|
-
|
|
27493
|
-
|
|
27494
|
-
|
|
27495
|
-
|
|
27496
|
-
|
|
27497
|
-
|
|
27498
|
-
|
|
27856
|
+
// packages/host-runtime/src/external-command-routing.ts
|
|
27857
|
+
var ExternalCommandError = class extends Error {
|
|
27858
|
+
constructor(code, message) {
|
|
27859
|
+
super(message);
|
|
27860
|
+
this.code = code;
|
|
27861
|
+
}
|
|
27862
|
+
code;
|
|
27863
|
+
};
|
|
27864
|
+
function isExternalCommandCandidate(text) {
|
|
27865
|
+
return /^\/[^\s/]+(?:\s|$)/u.test(text.trimStart());
|
|
27866
|
+
}
|
|
27867
|
+
async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
|
|
27868
|
+
let timeout;
|
|
27869
|
+
try {
|
|
27870
|
+
const result = await Promise.race([
|
|
27871
|
+
commands.list(),
|
|
27872
|
+
new Promise((resolve) => {
|
|
27873
|
+
timeout = setTimeout(() => resolve(null), timeoutMs);
|
|
27874
|
+
})
|
|
27875
|
+
]);
|
|
27876
|
+
return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
|
|
27877
|
+
} catch {
|
|
27878
|
+
return null;
|
|
27879
|
+
} finally {
|
|
27880
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
27881
|
+
}
|
|
27882
|
+
}
|
|
27883
|
+
async function resolveExternalCommand(commands, text, options2 = {}) {
|
|
27884
|
+
const catalog = await commands.list();
|
|
27885
|
+
if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
|
|
27886
|
+
const commandText = text.trim();
|
|
27887
|
+
const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
|
|
27888
|
+
if (commandText === command.invocation) return true;
|
|
27889
|
+
return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
|
|
27890
|
+
});
|
|
27891
|
+
if (!matched) {
|
|
27892
|
+
const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
|
|
27893
|
+
if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
|
|
27894
|
+
return null;
|
|
27895
|
+
}
|
|
27896
|
+
throw new ExternalCommandError(
|
|
27897
|
+
-32078,
|
|
27898
|
+
"External Harness does not expose the requested command"
|
|
27899
|
+
);
|
|
27900
|
+
}
|
|
27901
|
+
const argumentText = commandText.slice(matched.invocation.length).trimStart();
|
|
27902
|
+
return {
|
|
27903
|
+
commandId: matched.id,
|
|
27904
|
+
...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
|
|
27905
|
+
};
|
|
27906
|
+
}
|
|
27907
|
+
|
|
27908
|
+
// packages/host-runtime/src/live-command-catalog-cache.ts
|
|
27909
|
+
import path10 from "node:path";
|
|
27910
|
+
var MAX_ENTRIES = 64;
|
|
27911
|
+
function isLiveCommandCatalog(catalog, staticCatalog) {
|
|
27912
|
+
const staticIds = new Set(staticCatalog.commands.map(({ id: id2 }) => id2));
|
|
27913
|
+
return catalog.commands.some(({ id: id2 }) => !staticIds.has(id2));
|
|
27914
|
+
}
|
|
27915
|
+
var LiveCommandCatalogCache = class {
|
|
27916
|
+
#entries = /* @__PURE__ */ new Map();
|
|
27917
|
+
#key(harnessId, cwd) {
|
|
27918
|
+
return `${harnessId}\0${path10.resolve(cwd)}`;
|
|
27919
|
+
}
|
|
27920
|
+
remember(harnessId, cwd, catalog) {
|
|
27921
|
+
const key = this.#key(harnessId, cwd);
|
|
27922
|
+
this.#entries.delete(key);
|
|
27923
|
+
this.#entries.set(key, catalog);
|
|
27924
|
+
while (this.#entries.size > MAX_ENTRIES) {
|
|
27925
|
+
const oldest = this.#entries.keys().next().value;
|
|
27926
|
+
if (oldest === void 0) break;
|
|
27927
|
+
this.#entries.delete(oldest);
|
|
27928
|
+
}
|
|
27929
|
+
}
|
|
27930
|
+
lookup(harnessId, cwd) {
|
|
27931
|
+
return this.#entries.get(this.#key(harnessId, cwd));
|
|
27932
|
+
}
|
|
27933
|
+
};
|
|
27934
|
+
function sameWorkspace(left, right) {
|
|
27935
|
+
return path10.resolve(left) === path10.resolve(right);
|
|
27936
|
+
}
|
|
27937
|
+
|
|
27938
|
+
// packages/host-runtime/src/harness-delegation-coordinator.ts
|
|
27939
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "node:crypto";
|
|
27940
|
+
import path11 from "node:path";
|
|
27941
|
+
|
|
27942
|
+
// packages/host-runtime/src/delegation-snapshot.ts
|
|
27943
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
27944
|
+
var CURSOR_PREFIX = "codexhost:thread-messages:v1:";
|
|
27945
|
+
var DEFAULT_MESSAGE_LIMIT = 25;
|
|
27946
|
+
var MAX_MESSAGE_LIMIT = 100;
|
|
27947
|
+
function isRecord9(value2) {
|
|
27948
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
27949
|
+
}
|
|
27950
|
+
function stringValue(value2) {
|
|
27951
|
+
return typeof value2 === "string" && value2.length > 0 ? value2 : null;
|
|
27952
|
+
}
|
|
27953
|
+
function textFromUserItem(item) {
|
|
27499
27954
|
if (!Array.isArray(item.content)) return "";
|
|
27500
27955
|
return item.content.flatMap(
|
|
27501
|
-
(part) =>
|
|
27956
|
+
(part) => isRecord9(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []
|
|
27502
27957
|
).join("\n");
|
|
27503
27958
|
}
|
|
27504
27959
|
function threadStatus(value2, running) {
|
|
27505
27960
|
if (running) return "running";
|
|
27506
|
-
if (
|
|
27961
|
+
if (isRecord9(value2)) {
|
|
27507
27962
|
if (value2.type === "active") return "running";
|
|
27508
27963
|
}
|
|
27509
27964
|
return "completed";
|
|
@@ -27520,10 +27975,10 @@ function allVisibleMessages(turns) {
|
|
|
27520
27975
|
const turnId = stringValue(turn.id);
|
|
27521
27976
|
if (!turnId || !Array.isArray(turn.items)) continue;
|
|
27522
27977
|
const agentItems = turn.items.filter(
|
|
27523
|
-
(item) =>
|
|
27978
|
+
(item) => isRecord9(item) && item.type === "agentMessage"
|
|
27524
27979
|
);
|
|
27525
27980
|
for (const item of turn.items) {
|
|
27526
|
-
if (!
|
|
27981
|
+
if (!isRecord9(item)) continue;
|
|
27527
27982
|
const id2 = stringValue(item.id);
|
|
27528
27983
|
if (!id2) continue;
|
|
27529
27984
|
if (item.type === "userMessage") {
|
|
@@ -27539,7 +27994,7 @@ function allVisibleMessages(turns) {
|
|
|
27539
27994
|
return messages;
|
|
27540
27995
|
}
|
|
27541
27996
|
function cursorFingerprint(threadId2) {
|
|
27542
|
-
return
|
|
27997
|
+
return createHash6("sha256").update(threadId2).digest("hex");
|
|
27543
27998
|
}
|
|
27544
27999
|
function encodeCursor(threadId2, offset) {
|
|
27545
28000
|
const payload = JSON.stringify({ version: 1, fingerprint: cursorFingerprint(threadId2), offset });
|
|
@@ -27598,7 +28053,7 @@ function projectDelegationThreadSnapshot(input) {
|
|
|
27598
28053
|
const progress = latestTurnMessages.filter((message) => message.phase !== "final" && message.text.trim()).map(({ id: id2, turnId, text }) => ({ id: id2, turnId, text }));
|
|
27599
28054
|
const result = input.running ? { availability: "pending" } : final ? { availability: "available", text: final.text } : {
|
|
27600
28055
|
availability: "unavailable",
|
|
27601
|
-
...
|
|
28056
|
+
...isRecord9(latestTurn?.error) && typeof latestTurn.error.message === "string" ? { message: latestTurn.error.message } : {}
|
|
27602
28057
|
};
|
|
27603
28058
|
const offset = options2.view === "messages" ? decodeCursor(input.threadId, options2.cursor) : visible.length;
|
|
27604
28059
|
const page = options2.view === "messages" ? [] : void 0;
|
|
@@ -27634,10 +28089,10 @@ function terminal(status) {
|
|
|
27634
28089
|
return status === "completed" || status === "failed" || status === "interrupted";
|
|
27635
28090
|
}
|
|
27636
28091
|
function taskDigest(input) {
|
|
27637
|
-
return
|
|
28092
|
+
return createHash7("sha256").update(
|
|
27638
28093
|
JSON.stringify({
|
|
27639
28094
|
task: input.task,
|
|
27640
|
-
cwd:
|
|
28095
|
+
cwd: path11.resolve(input.cwd),
|
|
27641
28096
|
modelId: input.model?.id ?? null,
|
|
27642
28097
|
thinkingOptionId: input.thinkingOptionId ?? null
|
|
27643
28098
|
})
|
|
@@ -27708,7 +28163,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27708
28163
|
return {
|
|
27709
28164
|
harnessId: input.harnessId,
|
|
27710
28165
|
inspection: await adapter.inspect({
|
|
27711
|
-
...input.cwd ? { cwd:
|
|
28166
|
+
...input.cwd ? { cwd: path11.resolve(input.cwd) } : {},
|
|
27712
28167
|
...input.refresh !== void 0 ? { refresh: input.refresh } : {}
|
|
27713
28168
|
})
|
|
27714
28169
|
};
|
|
@@ -27722,7 +28177,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27722
28177
|
const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
|
|
27723
28178
|
return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
|
|
27724
28179
|
}
|
|
27725
|
-
const startInput = { ...input, parentThreadId, cwd:
|
|
28180
|
+
const startInput = { ...input, parentThreadId, cwd: path11.resolve(selectedCwd) };
|
|
27726
28181
|
if (!this.#adapters.has(input.harnessId)) {
|
|
27727
28182
|
throw new DelegationControlError(
|
|
27728
28183
|
"HARNESS_NOT_FOUND",
|
|
@@ -27762,10 +28217,10 @@ var HarnessDelegationCoordinator = class {
|
|
|
27762
28217
|
});
|
|
27763
28218
|
this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
|
|
27764
28219
|
}
|
|
27765
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
27766
|
-
const childThreadId = hostThreadIdSchema.parse(
|
|
27767
|
-
const turnId = hostTurnIdSchema.parse(
|
|
27768
|
-
const createRequestId = input.requestId ? `delegation:${input.requestId}` :
|
|
28220
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID6());
|
|
28221
|
+
const childThreadId = hostThreadIdSchema.parse(randomUUID6());
|
|
28222
|
+
const turnId = hostTurnIdSchema.parse(randomUUID6());
|
|
28223
|
+
const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID6();
|
|
27769
28224
|
let record3 = await this.#repository.createProvisional(
|
|
27770
28225
|
createExternalThreadRecordInput({
|
|
27771
28226
|
hostThreadId: childThreadId,
|
|
@@ -27897,7 +28352,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27897
28352
|
if (thread.running || thread.activeTurnId) {
|
|
27898
28353
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
27899
28354
|
}
|
|
27900
|
-
const turnId = hostTurnIdSchema.parse(
|
|
28355
|
+
const turnId = hostTurnIdSchema.parse(randomUUID6());
|
|
27901
28356
|
try {
|
|
27902
28357
|
await this.#startExternalTurn(thread, input.message, turnId);
|
|
27903
28358
|
} catch (error51) {
|
|
@@ -28151,7 +28606,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
28151
28606
|
|
|
28152
28607
|
// packages/host-runtime/src/harness-plugin-loader.ts
|
|
28153
28608
|
import { readdir as readdir3, realpath as realpath2 } from "node:fs/promises";
|
|
28154
|
-
import
|
|
28609
|
+
import path13 from "node:path";
|
|
28155
28610
|
import { pathToFileURL } from "node:url";
|
|
28156
28611
|
|
|
28157
28612
|
// packages/host-runtime/src/harness-plugin-registry.ts
|
|
@@ -28188,25 +28643,25 @@ var HarnessPluginRegistry = class {
|
|
|
28188
28643
|
};
|
|
28189
28644
|
|
|
28190
28645
|
// packages/host-runtime/src/plugin-files.ts
|
|
28191
|
-
import { open as
|
|
28192
|
-
import
|
|
28646
|
+
import { open as open5, realpath, stat as stat3 } from "node:fs/promises";
|
|
28647
|
+
import path12 from "node:path";
|
|
28193
28648
|
function inside(root, candidate) {
|
|
28194
|
-
const relative =
|
|
28195
|
-
return relative !== "" && !
|
|
28649
|
+
const relative = path12.relative(root, candidate);
|
|
28650
|
+
return relative !== "" && !path12.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path12.sep}`);
|
|
28196
28651
|
}
|
|
28197
28652
|
async function pluginResourcePath(root, relative) {
|
|
28198
|
-
if (
|
|
28653
|
+
if (path12.isAbsolute(relative) || !inside(root, path12.resolve(root, relative))) {
|
|
28199
28654
|
throw new Error("Plugin resource escapes its root");
|
|
28200
28655
|
}
|
|
28201
|
-
const resolved = await realpath(
|
|
28202
|
-
if (!inside(root, resolved) || !(await
|
|
28656
|
+
const resolved = await realpath(path12.resolve(root, relative));
|
|
28657
|
+
if (!inside(root, resolved) || !(await stat3(resolved)).isFile()) {
|
|
28203
28658
|
throw new Error("Plugin resource must be a regular file inside its root");
|
|
28204
28659
|
}
|
|
28205
28660
|
return resolved;
|
|
28206
28661
|
}
|
|
28207
28662
|
async function readPluginFile(file2, maximum) {
|
|
28208
|
-
if (!(await
|
|
28209
|
-
const handle = await
|
|
28663
|
+
if (!(await stat3(file2)).isFile()) throw new Error("Plugin resource is not a regular file");
|
|
28664
|
+
const handle = await open5(file2, "r");
|
|
28210
28665
|
try {
|
|
28211
28666
|
const info = await handle.stat();
|
|
28212
28667
|
if (!info.isFile() || info.size > maximum) throw new Error("Plugin resource exceeds its limit");
|
|
@@ -28360,7 +28815,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
28360
28815
|
const enabledIds = /* @__PURE__ */ new Set();
|
|
28361
28816
|
const roots = /* @__PURE__ */ new Set();
|
|
28362
28817
|
for (const configuredRoot of options2.roots) {
|
|
28363
|
-
if (!
|
|
28818
|
+
if (!path13.isAbsolute(configuredRoot)) {
|
|
28364
28819
|
diagnose({ code: "invalidRoot" });
|
|
28365
28820
|
continue;
|
|
28366
28821
|
}
|
|
@@ -28390,7 +28845,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
28390
28845
|
for (const directory of directories) {
|
|
28391
28846
|
try {
|
|
28392
28847
|
const file2 = await pluginResourcePath(root, `${directory.name}/manifest.json`);
|
|
28393
|
-
const pluginRoot = await realpath2(
|
|
28848
|
+
const pluginRoot = await realpath2(path13.join(root, directory.name));
|
|
28394
28849
|
await pluginResourcePath(pluginRoot, "manifest.json");
|
|
28395
28850
|
const manifest = harnessPluginManifestSchema.parse(
|
|
28396
28851
|
JSON.parse(
|
|
@@ -28485,28 +28940,28 @@ async function loadHarnessPlugins(options2) {
|
|
|
28485
28940
|
}
|
|
28486
28941
|
|
|
28487
28942
|
// packages/host-runtime/src/harness-launch-settings.ts
|
|
28488
|
-
import { randomUUID as
|
|
28489
|
-
import { mkdir as
|
|
28490
|
-
import
|
|
28491
|
-
import
|
|
28943
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
28944
|
+
import { mkdir as mkdir5, readFile as readFile7, rename as rename4, rm as rm5, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
|
|
28945
|
+
import os4 from "node:os";
|
|
28946
|
+
import path14 from "node:path";
|
|
28492
28947
|
var HarnessLaunchSettingsStore = class {
|
|
28493
28948
|
#directory;
|
|
28494
28949
|
#initial = /* @__PURE__ */ new Map();
|
|
28495
28950
|
constructor(environment) {
|
|
28496
|
-
this.#directory =
|
|
28497
|
-
environment.CODEXHOST_DATA_DIR ?
|
|
28951
|
+
this.#directory = path14.join(
|
|
28952
|
+
environment.CODEXHOST_DATA_DIR ? path14.resolve(environment.CODEXHOST_DATA_DIR) : path14.join(os4.homedir(), ".codexhost"),
|
|
28498
28953
|
"harness-launch-settings"
|
|
28499
28954
|
);
|
|
28500
28955
|
}
|
|
28501
28956
|
#file(id2) {
|
|
28502
|
-
return
|
|
28957
|
+
return path14.join(this.#directory, `${harnessPluginIdSchema.parse(id2)}.json`);
|
|
28503
28958
|
}
|
|
28504
28959
|
async #read(id2) {
|
|
28505
28960
|
try {
|
|
28506
28961
|
const value2 = harnessLaunchPathSchema.parse(
|
|
28507
|
-
JSON.parse(await
|
|
28962
|
+
JSON.parse(await readFile7(this.#file(id2), "utf8"))
|
|
28508
28963
|
);
|
|
28509
|
-
if (!
|
|
28964
|
+
if (!path14.isAbsolute(value2)) throw new Error("Expected an absolute entrypoint path");
|
|
28510
28965
|
return value2;
|
|
28511
28966
|
} catch (error51) {
|
|
28512
28967
|
if (error51 && typeof error51 === "object" && "code" in error51 && error51.code === "ENOENT")
|
|
@@ -28532,22 +28987,22 @@ var HarnessLaunchSettingsStore = class {
|
|
|
28532
28987
|
const initial = await this.initialCommand(id2) ?? null;
|
|
28533
28988
|
const file2 = this.#file(id2);
|
|
28534
28989
|
if (value2 === null) {
|
|
28535
|
-
await
|
|
28990
|
+
await rm5(file2, { force: true });
|
|
28536
28991
|
} else {
|
|
28537
28992
|
value2 = harnessLaunchPathSchema.parse(value2);
|
|
28538
|
-
if (!
|
|
28993
|
+
if (!path14.isAbsolute(value2))
|
|
28539
28994
|
throw new Error("Use an absolute entrypoint path without arguments");
|
|
28540
|
-
const metadata = await
|
|
28995
|
+
const metadata = await stat4(value2).catch(() => void 0);
|
|
28541
28996
|
if (!metadata?.isDirectory() && !metadata?.isFile())
|
|
28542
28997
|
throw new Error("The installation path must be an existing directory on this Host");
|
|
28543
|
-
await
|
|
28544
|
-
const temporary = `${file2}.${
|
|
28998
|
+
await mkdir5(this.#directory, { recursive: true, mode: 448 });
|
|
28999
|
+
const temporary = `${file2}.${randomUUID7()}.tmp`;
|
|
28545
29000
|
try {
|
|
28546
29001
|
await writeFile3(temporary, `${JSON.stringify(value2)}
|
|
28547
29002
|
`, { mode: 384, flag: "wx" });
|
|
28548
|
-
await
|
|
29003
|
+
await rename4(temporary, file2);
|
|
28549
29004
|
} finally {
|
|
28550
|
-
await
|
|
29005
|
+
await rm5(temporary, { force: true });
|
|
28551
29006
|
}
|
|
28552
29007
|
}
|
|
28553
29008
|
return { path: value2, restartRequired: value2 !== initial };
|
|
@@ -28710,11 +29165,11 @@ function spawnOfficialAppServerConnection(input) {
|
|
|
28710
29165
|
}
|
|
28711
29166
|
|
|
28712
29167
|
// packages/host-runtime/src/account/codex-account-control.ts
|
|
28713
|
-
function
|
|
29168
|
+
function isRecord10(value2) {
|
|
28714
29169
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
28715
29170
|
}
|
|
28716
29171
|
function currentCodexAccountFromOfficialRead(result) {
|
|
28717
|
-
if (!
|
|
29172
|
+
if (!isRecord10(result) || !isRecord10(result.account) || result.account.type !== "chatgpt") {
|
|
28718
29173
|
return null;
|
|
28719
29174
|
}
|
|
28720
29175
|
const email3 = external_exports.string().email().max(320).safeParse(result.account.email);
|
|
@@ -28744,13 +29199,13 @@ var SingleNativeCodexAccount = class {
|
|
|
28744
29199
|
};
|
|
28745
29200
|
|
|
28746
29201
|
// packages/host-runtime/src/codex-runtime/official-runtime-owner.ts
|
|
28747
|
-
import { randomUUID as
|
|
29202
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
28748
29203
|
|
|
28749
29204
|
// packages/host-runtime/src/official-request-broker.ts
|
|
28750
|
-
import { randomUUID as
|
|
29205
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28751
29206
|
var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
|
|
28752
29207
|
var MAX_RETIRED_IDS = 1024;
|
|
28753
|
-
function
|
|
29208
|
+
function isRecord11(value2) {
|
|
28754
29209
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
28755
29210
|
}
|
|
28756
29211
|
var OfficialRequestBroker = class {
|
|
@@ -28763,7 +29218,7 @@ var OfficialRequestBroker = class {
|
|
|
28763
29218
|
constructor(input) {
|
|
28764
29219
|
this.#send = input.send;
|
|
28765
29220
|
this.#timeoutMs = input.timeoutMs ?? 3e4;
|
|
28766
|
-
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${
|
|
29221
|
+
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID8()}`);
|
|
28767
29222
|
}
|
|
28768
29223
|
get pendingCount() {
|
|
28769
29224
|
return this.#pending.size;
|
|
@@ -28793,7 +29248,7 @@ var OfficialRequestBroker = class {
|
|
|
28793
29248
|
});
|
|
28794
29249
|
}
|
|
28795
29250
|
handle(value2) {
|
|
28796
|
-
if (!
|
|
29251
|
+
if (!isRecord11(value2) || typeof value2.id !== "string") return false;
|
|
28797
29252
|
const pending = this.#pending.get(value2.id);
|
|
28798
29253
|
if (!pending) return this.#retired.has(value2.id);
|
|
28799
29254
|
clearTimeout(pending.timeout);
|
|
@@ -29117,7 +29572,7 @@ var OfficialRuntimeOwner = class {
|
|
|
29117
29572
|
}
|
|
29118
29573
|
#attach(role, output, onBackendStopped) {
|
|
29119
29574
|
const client = {
|
|
29120
|
-
id:
|
|
29575
|
+
id: randomUUID9(),
|
|
29121
29576
|
role,
|
|
29122
29577
|
output,
|
|
29123
29578
|
...onBackendStopped ? { onBackendStopped } : {},
|
|
@@ -29275,7 +29730,7 @@ var OfficialRuntimeOwner = class {
|
|
|
29275
29730
|
if (!object4(value2)) return client.output(event);
|
|
29276
29731
|
if (typeof value2.id === "string" || typeof value2.id === "number") {
|
|
29277
29732
|
if (typeof value2.method === "string") {
|
|
29278
|
-
const id2 = `codexhost:server:${client.id}:${event.generation}:${
|
|
29733
|
+
const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID9()}`;
|
|
29279
29734
|
client.serverRequests.set(id2, value2.id);
|
|
29280
29735
|
const projected = { ...value2, id: id2 };
|
|
29281
29736
|
return client.output({
|
|
@@ -29513,11 +29968,11 @@ function createOwnedConnectionBackend(factory) {
|
|
|
29513
29968
|
}
|
|
29514
29969
|
|
|
29515
29970
|
// packages/host-runtime/src/route-observation.ts
|
|
29516
|
-
function
|
|
29971
|
+
function isRecord12(value2) {
|
|
29517
29972
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29518
29973
|
}
|
|
29519
29974
|
function classifyThreadPurpose(request) {
|
|
29520
|
-
return
|
|
29975
|
+
return isRecord12(request.params) && request.params.ephemeral === true ? "ephemeral" : "conversation";
|
|
29521
29976
|
}
|
|
29522
29977
|
var RequestRouteObservationTracker = class {
|
|
29523
29978
|
#nextCreateOrdinal = 0;
|
|
@@ -29542,13 +29997,13 @@ var RequestRouteObservationTracker = class {
|
|
|
29542
29997
|
this.#createByThreadId.set(threadId2, tracked);
|
|
29543
29998
|
}
|
|
29544
29999
|
bindOfficialResponse(response) {
|
|
29545
|
-
if (!
|
|
30000
|
+
if (!isRecord12(response) || !("id" in response)) return;
|
|
29546
30001
|
const tracked = this.#pendingByRequestId.get(response.id);
|
|
29547
30002
|
if (!tracked) return;
|
|
29548
30003
|
this.#pendingByRequestId.delete(response.id);
|
|
29549
30004
|
const result = response.result;
|
|
29550
|
-
const thread =
|
|
29551
|
-
if (
|
|
30005
|
+
const thread = isRecord12(result) ? result.thread : null;
|
|
30006
|
+
if (isRecord12(thread) && typeof thread.id === "string") {
|
|
29552
30007
|
this.#createByThreadId.set(thread.id, tracked);
|
|
29553
30008
|
}
|
|
29554
30009
|
}
|
|
@@ -29670,25 +30125,25 @@ function resolveExternalSessionTreeIds(records) {
|
|
|
29670
30125
|
const resolve = (start) => {
|
|
29671
30126
|
const cached2 = resolved.get(start.hostThreadId);
|
|
29672
30127
|
if (cached2) return cached2;
|
|
29673
|
-
const
|
|
30128
|
+
const path28 = [];
|
|
29674
30129
|
const visited = /* @__PURE__ */ new Set();
|
|
29675
30130
|
let current = start;
|
|
29676
30131
|
while (true) {
|
|
29677
30132
|
const known = resolved.get(current.hostThreadId);
|
|
29678
30133
|
if (known) {
|
|
29679
|
-
for (const record3 of
|
|
30134
|
+
for (const record3 of path28) resolved.set(record3.hostThreadId, known);
|
|
29680
30135
|
return known;
|
|
29681
30136
|
}
|
|
29682
30137
|
if (visited.has(current.hostThreadId)) {
|
|
29683
30138
|
throw new Error("External Thread Fork tree contains a cycle");
|
|
29684
30139
|
}
|
|
29685
30140
|
visited.add(current.hostThreadId);
|
|
29686
|
-
|
|
30141
|
+
path28.push(current);
|
|
29687
30142
|
const sourceId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
|
|
29688
30143
|
const source = sourceId ? byId.get(sourceId) : void 0;
|
|
29689
30144
|
if (!source) {
|
|
29690
30145
|
const root = current.hostThreadId;
|
|
29691
|
-
for (const record3 of
|
|
30146
|
+
for (const record3 of path28) resolved.set(record3.hostThreadId, root);
|
|
29692
30147
|
return root;
|
|
29693
30148
|
}
|
|
29694
30149
|
current = source;
|
|
@@ -29742,11 +30197,11 @@ var OfficialThreadListError = class extends Error {
|
|
|
29742
30197
|
}
|
|
29743
30198
|
rpcError;
|
|
29744
30199
|
};
|
|
29745
|
-
function
|
|
30200
|
+
function isRecord13(value2) {
|
|
29746
30201
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29747
30202
|
}
|
|
29748
30203
|
function officialThreadListPageFromResponse(response) {
|
|
29749
|
-
if (
|
|
30204
|
+
if (isRecord13(response.error)) {
|
|
29750
30205
|
if (!Number.isSafeInteger(response.error.code) || typeof response.error.message !== "string") {
|
|
29751
30206
|
throw new Error("Official thread/list error response is invalid");
|
|
29752
30207
|
}
|
|
@@ -29914,14 +30369,14 @@ var THREAD_USAGE_UPDATED_METHOD = "codexhost/thread/usage/updated";
|
|
|
29914
30369
|
function delay3(milliseconds) {
|
|
29915
30370
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
29916
30371
|
}
|
|
29917
|
-
function
|
|
30372
|
+
function isRecord14(value2) {
|
|
29918
30373
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29919
30374
|
}
|
|
29920
30375
|
function isCreditsAdapter(adapter) {
|
|
29921
30376
|
return typeof adapter.credits === "function";
|
|
29922
30377
|
}
|
|
29923
30378
|
function projectAccountCredits(value2) {
|
|
29924
|
-
if (!
|
|
30379
|
+
if (!isRecord14(value2)) return null;
|
|
29925
30380
|
const rest = { ...value2 };
|
|
29926
30381
|
delete rest.fetchedAt;
|
|
29927
30382
|
const parsed = accountCreditsSnapshotSchema.safeParse(rest);
|
|
@@ -30044,12 +30499,12 @@ function classifyCreateRequestRoute(request, defaultAgent) {
|
|
|
30044
30499
|
};
|
|
30045
30500
|
}
|
|
30046
30501
|
function requestObject(request) {
|
|
30047
|
-
if (!
|
|
30502
|
+
if (!isRecord14(request.params)) throw new Error(`${request.method} params must be an object`);
|
|
30048
30503
|
return request.params;
|
|
30049
30504
|
}
|
|
30050
30505
|
function requestText(params) {
|
|
30051
30506
|
if (!Array.isArray(params.input)) throw new Error("turn/start input must be an array");
|
|
30052
|
-
const text = params.input.filter((item) =>
|
|
30507
|
+
const text = params.input.filter((item) => isRecord14(item) && item.type === "text").map((item) => item.text).filter((value2) => typeof value2 === "string").join("\n");
|
|
30053
30508
|
if (!text) throw new Error("turn/start must contain text input");
|
|
30054
30509
|
return text;
|
|
30055
30510
|
}
|
|
@@ -30103,6 +30558,7 @@ var AppServerHost = class {
|
|
|
30103
30558
|
#accountInspections = new HarnessAccountInspectionCache();
|
|
30104
30559
|
#externalRuntime;
|
|
30105
30560
|
#externalSteering = new ExternalTurnSteering();
|
|
30561
|
+
#liveCommandCache = new LiveCommandCatalogCache();
|
|
30106
30562
|
#repository;
|
|
30107
30563
|
#pendingDesktopApprovals = /* @__PURE__ */ new Map();
|
|
30108
30564
|
#pendingDesktopQuestions = /* @__PURE__ */ new Map();
|
|
@@ -30144,7 +30600,7 @@ var AppServerHost = class {
|
|
|
30144
30600
|
this.#launchSettings = new HarnessLaunchSettingsStore(
|
|
30145
30601
|
this.#options.pluginContext?.environment ?? environment
|
|
30146
30602
|
);
|
|
30147
|
-
const permanentHome =
|
|
30603
|
+
const permanentHome = path15.resolve(environment.CODEX_HOME ?? path15.join(os5.homedir(), ".codex"));
|
|
30148
30604
|
this.#ownsOfficialRuntimeScope = options2.officialRuntimeScope === void 0;
|
|
30149
30605
|
this.#officialRuntimeScope = options2.officialRuntimeScope ?? new OfficialRuntimeScope({
|
|
30150
30606
|
diagnosticOutput: this.#options.diagnosticOutput,
|
|
@@ -30406,12 +30862,12 @@ var AppServerHost = class {
|
|
|
30406
30862
|
for (const resolve of waiters) resolve();
|
|
30407
30863
|
}
|
|
30408
30864
|
#observeOfficialTurnStartResponse(value2) {
|
|
30409
|
-
if (!
|
|
30865
|
+
if (!isRecord14(value2) || !("id" in value2)) return;
|
|
30410
30866
|
const threadId2 = this.#pendingOfficialTurnStarts.get(value2.id);
|
|
30411
30867
|
if (!threadId2) return;
|
|
30412
30868
|
this.#pendingOfficialTurnStarts.delete(value2.id);
|
|
30413
|
-
const result =
|
|
30414
|
-
const turn = result &&
|
|
30869
|
+
const result = isRecord14(value2.result) ? value2.result : null;
|
|
30870
|
+
const turn = result && isRecord14(result.turn) ? result.turn : null;
|
|
30415
30871
|
if (turn && typeof turn.id === "string") {
|
|
30416
30872
|
this.#activeOfficialTurns.set(threadId2, turn.id);
|
|
30417
30873
|
}
|
|
@@ -30425,7 +30881,7 @@ var AppServerHost = class {
|
|
|
30425
30881
|
async #forwardDesktop() {
|
|
30426
30882
|
for await (const frame of readLfFrames(this.#options.desktopInput)) {
|
|
30427
30883
|
const parsed = parseJsonFrame(frame);
|
|
30428
|
-
if (
|
|
30884
|
+
if (isRecord14(parsed) && parsed.method === "initialized" && !("id" in parsed)) {
|
|
30429
30885
|
continue;
|
|
30430
30886
|
}
|
|
30431
30887
|
if (await this.#handleDesktopApprovalResponse(parsed)) continue;
|
|
@@ -30449,7 +30905,7 @@ var AppServerHost = class {
|
|
|
30449
30905
|
}
|
|
30450
30906
|
continue;
|
|
30451
30907
|
}
|
|
30452
|
-
const threadId2 =
|
|
30908
|
+
const threadId2 = isRecord14(request.params) && typeof request.params.threadId === "string" ? request.params.threadId : void 0;
|
|
30453
30909
|
this.#dispatchDesktopRequest(
|
|
30454
30910
|
() => this.#desktopRequests.run(
|
|
30455
30911
|
threadId2,
|
|
@@ -30677,7 +31133,7 @@ var AppServerHost = class {
|
|
|
30677
31133
|
rpcError(request, -32602, "Invalid Harness command inspection params")
|
|
30678
31134
|
);
|
|
30679
31135
|
} else {
|
|
30680
|
-
await this.#writeHarnessCommandCatalog(request, params.data.harnessId);
|
|
31136
|
+
await this.#writeHarnessCommandCatalog(request, params.data.harnessId, params.data.cwd);
|
|
30681
31137
|
}
|
|
30682
31138
|
return;
|
|
30683
31139
|
}
|
|
@@ -30774,7 +31230,7 @@ var AppServerHost = class {
|
|
|
30774
31230
|
return;
|
|
30775
31231
|
}
|
|
30776
31232
|
if (request.method === "thread/fork") {
|
|
30777
|
-
const params =
|
|
31233
|
+
const params = isRecord14(request.params) ? request.params : {};
|
|
30778
31234
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
30779
31235
|
if (resolution.kind === "error") {
|
|
30780
31236
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -30795,7 +31251,7 @@ var AppServerHost = class {
|
|
|
30795
31251
|
}
|
|
30796
31252
|
}
|
|
30797
31253
|
if (request.method === "thread/revert") {
|
|
30798
|
-
const params =
|
|
31254
|
+
const params = isRecord14(request.params) ? request.params : {};
|
|
30799
31255
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
30800
31256
|
if (resolution.kind === "error") {
|
|
30801
31257
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -30816,7 +31272,7 @@ var AppServerHost = class {
|
|
|
30816
31272
|
}
|
|
30817
31273
|
}
|
|
30818
31274
|
if (request.method === "thread/rollback") {
|
|
30819
|
-
const params =
|
|
31275
|
+
const params = isRecord14(request.params) ? request.params : {};
|
|
30820
31276
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
30821
31277
|
if (resolution.kind === "error") {
|
|
30822
31278
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -30972,7 +31428,7 @@ var AppServerHost = class {
|
|
|
30972
31428
|
return;
|
|
30973
31429
|
}
|
|
30974
31430
|
}
|
|
30975
|
-
if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) &&
|
|
31431
|
+
if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) && isRecord14(request.params) && typeof request.params.threadId === "string") {
|
|
30976
31432
|
const location = await this.#locateExternalThread(request.params.threadId);
|
|
30977
31433
|
if (await this.#writeResolutionError(request, location)) return;
|
|
30978
31434
|
if (location.kind === "external") {
|
|
@@ -30982,10 +31438,30 @@ var AppServerHost = class {
|
|
|
30982
31438
|
return;
|
|
30983
31439
|
}
|
|
30984
31440
|
}
|
|
30985
|
-
await this.#forwardOfficialRequest(
|
|
31441
|
+
await this.#forwardOfficialRequest(
|
|
31442
|
+
request,
|
|
31443
|
+
await this.#rewriteOfficialDelegationMentions(request, frame)
|
|
31444
|
+
);
|
|
31445
|
+
}
|
|
31446
|
+
/** Native Codex Turns: turn `#` delegation chips into an explicit Skill-backed request. */
|
|
31447
|
+
async #rewriteOfficialDelegationMentions(request, frame) {
|
|
31448
|
+
if (request.method !== "turn/start" && request.method !== "turn/steer") return frame;
|
|
31449
|
+
if (!isRecord14(request.params) || !Array.isArray(request.params.input)) return frame;
|
|
31450
|
+
const input = request.params.input;
|
|
31451
|
+
if (!input.some(
|
|
31452
|
+
(item) => isRecord14(item) && typeof item.text === "string" && item.text.includes(DELEGATION_MENTION_PATH_PREFIX)
|
|
31453
|
+
)) {
|
|
31454
|
+
return frame;
|
|
31455
|
+
}
|
|
31456
|
+
const rewritten = rewriteDelegationMentionInput(input, await managedDelegationSkillReference());
|
|
31457
|
+
if (!rewritten) return frame;
|
|
31458
|
+
return encodeJsonFrame({
|
|
31459
|
+
...request,
|
|
31460
|
+
params: { ...request.params, input: rewritten }
|
|
31461
|
+
});
|
|
30986
31462
|
}
|
|
30987
31463
|
async #forwardOfficialNonRequest(value2, frame) {
|
|
30988
|
-
const response =
|
|
31464
|
+
const response = isRecord14(value2) ? value2 : null;
|
|
30989
31465
|
const request = response && (typeof response.id === "string" || typeof response.id === "number") ? this.#officialServerRequests.get(response.id) : null;
|
|
30990
31466
|
if (request !== void 0 && response) {
|
|
30991
31467
|
this.#officialServerRequests.delete(response.id);
|
|
@@ -31014,7 +31490,7 @@ var AppServerHost = class {
|
|
|
31014
31490
|
const parsed = input.value;
|
|
31015
31491
|
this.#observeOfficialTurnStartResponse(parsed);
|
|
31016
31492
|
let forwarded = parsed;
|
|
31017
|
-
if (
|
|
31493
|
+
if (isRecord14(parsed) && typeof parsed.method === "string" && "id" in parsed) {
|
|
31018
31494
|
const originalId = parsed.id;
|
|
31019
31495
|
if (typeof originalId === "string" || typeof originalId === "number") {
|
|
31020
31496
|
const forwardedId = `codexhost:official:${++this.#nextOfficialServerRequestId}`;
|
|
@@ -31022,7 +31498,7 @@ var AppServerHost = class {
|
|
|
31022
31498
|
forwarded = { ...parsed, id: forwardedId };
|
|
31023
31499
|
}
|
|
31024
31500
|
}
|
|
31025
|
-
const accountScopedNotification =
|
|
31501
|
+
const accountScopedNotification = isRecord14(parsed) && typeof parsed.method === "string" && (parsed.method === "account/updated" || parsed.method.startsWith("account/rateLimits/"));
|
|
31026
31502
|
if (accountScopedNotification) {
|
|
31027
31503
|
if (parsed.method === "account/updated") this.#officialRateLimits.reset(input.accountId);
|
|
31028
31504
|
}
|
|
@@ -31091,10 +31567,10 @@ var AppServerHost = class {
|
|
|
31091
31567
|
}
|
|
31092
31568
|
}
|
|
31093
31569
|
async #observeOfficialTurnLifecycle(value2) {
|
|
31094
|
-
if (!
|
|
31570
|
+
if (!isRecord14(value2) || !isRecord14(value2.params)) return;
|
|
31095
31571
|
const params = value2.params;
|
|
31096
31572
|
if (value2.method === "turn/started" && typeof params.threadId === "string") {
|
|
31097
|
-
const turn =
|
|
31573
|
+
const turn = isRecord14(params.turn) ? params.turn : null;
|
|
31098
31574
|
if (turn && typeof turn.id === "string") {
|
|
31099
31575
|
this.#forgetPendingOfficialTurnStarts(params.threadId);
|
|
31100
31576
|
this.#activeOfficialTurns.set(params.threadId, turn.id);
|
|
@@ -31107,7 +31583,7 @@ var AppServerHost = class {
|
|
|
31107
31583
|
const delegation = await this.#repository.getDelegationByChild(
|
|
31108
31584
|
hostThreadIdSchema.parse(params.threadId)
|
|
31109
31585
|
);
|
|
31110
|
-
const turn =
|
|
31586
|
+
const turn = isRecord14(params.turn) ? params.turn : null;
|
|
31111
31587
|
const status = turn?.status === "failed" ? "failed" : turn?.status === "interrupted" || turn?.status === "cancelled" ? "interrupted" : "completed";
|
|
31112
31588
|
if (this.#pendingOfficialDelegationThreads.has(params.threadId)) {
|
|
31113
31589
|
this.#pendingOfficialTerminalStatuses.set(params.threadId, status);
|
|
@@ -31137,28 +31613,28 @@ var AppServerHost = class {
|
|
|
31137
31613
|
}
|
|
31138
31614
|
async #readOfficialThreadCwd(threadId2) {
|
|
31139
31615
|
const response = await this.#requestOfficial("thread/read", { threadId: threadId2 });
|
|
31140
|
-
if (
|
|
31141
|
-
const result =
|
|
31142
|
-
const thread = result &&
|
|
31616
|
+
if (isRecord14(response.error)) return void 0;
|
|
31617
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31618
|
+
const thread = result && isRecord14(result.thread) ? result.thread : null;
|
|
31143
31619
|
return thread && typeof thread.cwd === "string" && thread.cwd.trim() ? thread.cwd : void 0;
|
|
31144
31620
|
}
|
|
31145
31621
|
async #inspectOfficialDelegationTarget(input) {
|
|
31146
31622
|
const response = await this.#requestOfficial("model/list", {});
|
|
31147
|
-
if (
|
|
31623
|
+
if (isRecord14(response.error)) {
|
|
31148
31624
|
throw new DelegationControlError(
|
|
31149
31625
|
"DELEGATION_FAILED",
|
|
31150
31626
|
typeof response.error.message === "string" ? response.error.message : "Official Model catalog could not be read"
|
|
31151
31627
|
);
|
|
31152
31628
|
}
|
|
31153
|
-
const result =
|
|
31629
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31154
31630
|
const data = result && Array.isArray(result.data) ? result.data : [];
|
|
31155
31631
|
const thinkingById = /* @__PURE__ */ new Map();
|
|
31156
31632
|
const models = data.flatMap((candidate) => {
|
|
31157
|
-
if (!
|
|
31633
|
+
if (!isRecord14(candidate) || typeof candidate.model !== "string" || !candidate.model.trim()) {
|
|
31158
31634
|
return [];
|
|
31159
31635
|
}
|
|
31160
31636
|
const supportedThinkingOptionIds = Array.isArray(candidate.supportedReasoningEfforts) ? candidate.supportedReasoningEfforts.flatMap((option) => {
|
|
31161
|
-
if (!
|
|
31637
|
+
if (!isRecord14(option) || typeof option.reasoningEffort !== "string" || !option.reasoningEffort.trim()) {
|
|
31162
31638
|
return [];
|
|
31163
31639
|
}
|
|
31164
31640
|
const id2 = harnessThinkingOptionIdSchema.safeParse(option.reasoningEffort);
|
|
@@ -31178,9 +31654,9 @@ var AppServerHost = class {
|
|
|
31178
31654
|
];
|
|
31179
31655
|
});
|
|
31180
31656
|
const defaultEntry = data.find(
|
|
31181
|
-
(candidate) =>
|
|
31657
|
+
(candidate) => isRecord14(candidate) && candidate.isDefault === true
|
|
31182
31658
|
);
|
|
31183
|
-
const defaultModel =
|
|
31659
|
+
const defaultModel = isRecord14(defaultEntry) && typeof defaultEntry.model === "string" ? encodeOfficialCodexModelRef(defaultEntry.model) : void 0;
|
|
31184
31660
|
return {
|
|
31185
31661
|
harnessId: input.harnessId,
|
|
31186
31662
|
inspection: {
|
|
@@ -31210,7 +31686,7 @@ var AppServerHost = class {
|
|
|
31210
31686
|
throw new DelegationControlError("INVALID_ARGUMENT", "Official Model Ref is invalid");
|
|
31211
31687
|
}
|
|
31212
31688
|
const nativeModelId = requestedModel ? decodeOfficialCodexModelRef(requestedModel) : void 0;
|
|
31213
|
-
const digest2 =
|
|
31689
|
+
const digest2 = createHash8("sha256").update(
|
|
31214
31690
|
JSON.stringify({
|
|
31215
31691
|
task: input.task,
|
|
31216
31692
|
cwd: input.cwd,
|
|
@@ -31286,8 +31762,8 @@ var AppServerHost = class {
|
|
|
31286
31762
|
ephemeral: false,
|
|
31287
31763
|
historyMode: "paginated"
|
|
31288
31764
|
});
|
|
31289
|
-
const startedResult =
|
|
31290
|
-
const thread = startedResult &&
|
|
31765
|
+
const startedResult = isRecord14(started.result) ? started.result : null;
|
|
31766
|
+
const thread = startedResult && isRecord14(startedResult.thread) ? startedResult.thread : null;
|
|
31291
31767
|
const threadId2 = thread && typeof thread.id === "string" ? thread.id : null;
|
|
31292
31768
|
if (!threadId2) throw new Error("Official thread/start returned no Thread identity");
|
|
31293
31769
|
this.#pendingOfficialDelegationThreads.add(threadId2);
|
|
@@ -31299,8 +31775,8 @@ var AppServerHost = class {
|
|
|
31299
31775
|
...nativeModelId ? { model: nativeModelId } : {},
|
|
31300
31776
|
...input.thinkingOptionId ? { effort: input.thinkingOptionId } : {}
|
|
31301
31777
|
});
|
|
31302
|
-
const turnResult =
|
|
31303
|
-
const turnValue = turnResult &&
|
|
31778
|
+
const turnResult = isRecord14(turn.result) ? turn.result : null;
|
|
31779
|
+
const turnValue = turnResult && isRecord14(turnResult.turn) ? turnResult.turn : null;
|
|
31304
31780
|
const parsedTurnId = turnValue && typeof turnValue.id === "string" ? turnValue.id : null;
|
|
31305
31781
|
if (!parsedTurnId) throw new Error("Official turn/start returned no Turn identity");
|
|
31306
31782
|
turnId = parsedTurnId;
|
|
@@ -31311,7 +31787,7 @@ var AppServerHost = class {
|
|
|
31311
31787
|
throw error51;
|
|
31312
31788
|
}
|
|
31313
31789
|
this.#activeOfficialTurns.set(threadId2, turnId);
|
|
31314
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
31790
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID10());
|
|
31315
31791
|
try {
|
|
31316
31792
|
const source = await this.#repository.find(input.parentThreadId);
|
|
31317
31793
|
const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId2);
|
|
@@ -31370,27 +31846,27 @@ var AppServerHost = class {
|
|
|
31370
31846
|
threadId: input.threadId,
|
|
31371
31847
|
includeTurns: true
|
|
31372
31848
|
});
|
|
31373
|
-
if (
|
|
31849
|
+
if (isRecord14(current.error) || !isRecord14(current.result)) {
|
|
31374
31850
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31375
31851
|
}
|
|
31376
|
-
const currentThread =
|
|
31852
|
+
const currentThread = isRecord14(current.result.thread) ? current.result.thread : null;
|
|
31377
31853
|
const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
|
|
31378
31854
|
const latestTurn = currentTurns.at(-1);
|
|
31379
|
-
if (currentThread &&
|
|
31855
|
+
if (currentThread && isRecord14(currentThread.status) && currentThread.status.type === "active" || isRecord14(latestTurn) && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
|
|
31380
31856
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
31381
31857
|
}
|
|
31382
31858
|
const response = await this.#requestOfficial("turn/start", {
|
|
31383
31859
|
threadId: input.threadId,
|
|
31384
31860
|
input: [{ type: "text", text: input.message }]
|
|
31385
31861
|
});
|
|
31386
|
-
if (
|
|
31862
|
+
if (isRecord14(response.error)) {
|
|
31387
31863
|
throw new DelegationControlError(
|
|
31388
31864
|
"DELEGATION_FAILED",
|
|
31389
31865
|
typeof response.error.message === "string" ? response.error.message : "Turn start failed"
|
|
31390
31866
|
);
|
|
31391
31867
|
}
|
|
31392
|
-
const result =
|
|
31393
|
-
const turn = result &&
|
|
31868
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31869
|
+
const turn = result && isRecord14(result.turn) ? result.turn : null;
|
|
31394
31870
|
const turnId = turn && typeof turn.id === "string" ? turn.id : null;
|
|
31395
31871
|
if (!turnId) throw new Error("Official turn/start returned no Turn identity");
|
|
31396
31872
|
this.#activeOfficialTurns.set(input.threadId, turnId);
|
|
@@ -31412,13 +31888,13 @@ var AppServerHost = class {
|
|
|
31412
31888
|
threadId: input.threadId,
|
|
31413
31889
|
includeTurns: true
|
|
31414
31890
|
});
|
|
31415
|
-
if (
|
|
31891
|
+
if (isRecord14(current.error) || !isRecord14(current.result)) {
|
|
31416
31892
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31417
31893
|
}
|
|
31418
|
-
const currentThread =
|
|
31894
|
+
const currentThread = isRecord14(current.result.thread) ? current.result.thread : null;
|
|
31419
31895
|
const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
|
|
31420
31896
|
const latestTurn = currentTurns.at(-1);
|
|
31421
|
-
if (
|
|
31897
|
+
if (isRecord14(latestTurn) && typeof latestTurn.id === "string" && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
|
|
31422
31898
|
turnId = latestTurn.id;
|
|
31423
31899
|
this.#activeOfficialTurns.set(input.threadId, turnId);
|
|
31424
31900
|
} else {
|
|
@@ -31429,7 +31905,7 @@ var AppServerHost = class {
|
|
|
31429
31905
|
threadId: input.threadId,
|
|
31430
31906
|
turnId
|
|
31431
31907
|
});
|
|
31432
|
-
if (
|
|
31908
|
+
if (isRecord14(response.error)) {
|
|
31433
31909
|
throw new DelegationControlError(
|
|
31434
31910
|
"DELEGATION_FAILED",
|
|
31435
31911
|
typeof response.error.message === "string" ? response.error.message : "Turn cancel failed"
|
|
@@ -31442,18 +31918,18 @@ var AppServerHost = class {
|
|
|
31442
31918
|
threadId: input.threadId,
|
|
31443
31919
|
includeTurns: true
|
|
31444
31920
|
});
|
|
31445
|
-
if (
|
|
31921
|
+
if (isRecord14(response.error)) {
|
|
31446
31922
|
throw new DelegationControlError(
|
|
31447
31923
|
"THREAD_NOT_FOUND",
|
|
31448
31924
|
typeof response.error.message === "string" ? response.error.message : "Official Thread was not found"
|
|
31449
31925
|
);
|
|
31450
31926
|
}
|
|
31451
|
-
const result =
|
|
31452
|
-
const thread = result &&
|
|
31927
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31928
|
+
const thread = result && isRecord14(result.thread) ? result.thread : null;
|
|
31453
31929
|
if (!thread)
|
|
31454
31930
|
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) ||
|
|
31931
|
+
const turns = Array.isArray(thread.turns) ? thread.turns.filter((turn) => isRecord14(turn)) : [];
|
|
31932
|
+
const running = this.#activeOfficialTurns.has(input.threadId) || isRecord14(thread.status) && thread.status.type === "active";
|
|
31457
31933
|
const snapshot = projectDelegationThreadSnapshot({
|
|
31458
31934
|
threadId: input.threadId,
|
|
31459
31935
|
harnessId: "codex",
|
|
@@ -31475,7 +31951,7 @@ var AppServerHost = class {
|
|
|
31475
31951
|
async #listDelegationThreads(input) {
|
|
31476
31952
|
const [sortKey, sortDirection2] = input.sort.split("-");
|
|
31477
31953
|
const request = {
|
|
31478
|
-
id: `codexhost:delegation-list:${
|
|
31954
|
+
id: `codexhost:delegation-list:${randomUUID10()}`,
|
|
31479
31955
|
method: "thread/list",
|
|
31480
31956
|
params: {
|
|
31481
31957
|
cwd: input.cwd ? [input.cwd] : null,
|
|
@@ -31503,7 +31979,7 @@ var AppServerHost = class {
|
|
|
31503
31979
|
threads: result.data.flatMap((entry) => {
|
|
31504
31980
|
if (typeof entry.id !== "string") return [];
|
|
31505
31981
|
const record3 = records.find((candidate) => candidate.hostThreadId === entry.id);
|
|
31506
|
-
const status =
|
|
31982
|
+
const status = isRecord14(entry.status) && entry.status.type === "active" ? "running" : "completed";
|
|
31507
31983
|
return [
|
|
31508
31984
|
{
|
|
31509
31985
|
threadId: entry.id,
|
|
@@ -31823,21 +32299,67 @@ var AppServerHost = class {
|
|
|
31823
32299
|
await this.#writer.json(rpcEnvelope(request, { result: { commands: [] } }));
|
|
31824
32300
|
return;
|
|
31825
32301
|
}
|
|
31826
|
-
|
|
32302
|
+
const loaded = this.#externalRuntime.get(params.data.threadId);
|
|
32303
|
+
if (loaded) {
|
|
32304
|
+
const catalog = await this.#inspectLoadedCommands(loaded);
|
|
32305
|
+
if (catalog) {
|
|
32306
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(catalog) }));
|
|
32307
|
+
return;
|
|
32308
|
+
}
|
|
32309
|
+
}
|
|
32310
|
+
await this.#writeHarnessCommandCatalog(
|
|
32311
|
+
request,
|
|
32312
|
+
location.record.harnessId,
|
|
32313
|
+
loaded?.cwd ?? location.record.cwd,
|
|
32314
|
+
params.data.threadId
|
|
32315
|
+
);
|
|
31827
32316
|
}
|
|
31828
|
-
|
|
32317
|
+
/**
|
|
32318
|
+
* Catalog of a loaded Session, marked live or static. A live catalog is
|
|
32319
|
+
* remembered for its Harness and workspace so later drafts there can show it.
|
|
32320
|
+
*/
|
|
32321
|
+
async #inspectLoadedCommands(thread) {
|
|
32322
|
+
if (!thread.session.commands) return null;
|
|
32323
|
+
const catalog = await inspectLiveCommandCatalog(thread.session.commands);
|
|
32324
|
+
if (!catalog) return null;
|
|
32325
|
+
const staticCatalog = this.#externalAdapters.get(thread.harnessId)?.commandCatalog;
|
|
32326
|
+
if (staticCatalog && !isLiveCommandCatalog(catalog, staticCatalog)) return null;
|
|
32327
|
+
const live = { ...catalog, source: "live" };
|
|
32328
|
+
this.#liveCommandCache.remember(thread.harnessId, thread.cwd, live);
|
|
32329
|
+
return live;
|
|
32330
|
+
}
|
|
32331
|
+
async #writeHarnessCommandCatalog(request, harnessId, cwd, inspectedThreadId) {
|
|
31829
32332
|
await this.#waitForPlugins();
|
|
31830
32333
|
const adapter = this.#externalAdapters.get(harnessId);
|
|
31831
32334
|
if (!adapter) {
|
|
31832
32335
|
await this.#writer.json(rpcError(request, -32077, `Harness '${harnessId}' is unavailable`));
|
|
31833
32336
|
return;
|
|
31834
32337
|
}
|
|
32338
|
+
let catalog;
|
|
31835
32339
|
try {
|
|
31836
|
-
|
|
31837
|
-
|
|
32340
|
+
catalog = harnessCommandCatalogSchema.parse({
|
|
32341
|
+
...adapter.commandCatalog ?? { commands: [] },
|
|
32342
|
+
...adapter.liveCommandCatalog ? { source: "static" } : {}
|
|
32343
|
+
});
|
|
31838
32344
|
} catch {
|
|
31839
32345
|
await this.#writer.json(rpcError(request, -32078, "Harness command catalog is invalid"));
|
|
32346
|
+
return;
|
|
31840
32347
|
}
|
|
32348
|
+
if (cwd && adapter.liveCommandCatalog) {
|
|
32349
|
+
for (const thread of this.#externalRuntime.values()) {
|
|
32350
|
+
if (thread.id === inspectedThreadId) continue;
|
|
32351
|
+
if (thread.harnessId !== harnessId || !sameWorkspace(thread.cwd, cwd)) continue;
|
|
32352
|
+
const live = await this.#inspectLoadedCommands(thread);
|
|
32353
|
+
if (live) {
|
|
32354
|
+
catalog = live;
|
|
32355
|
+
break;
|
|
32356
|
+
}
|
|
32357
|
+
}
|
|
32358
|
+
if (catalog.source === "static") {
|
|
32359
|
+
catalog = this.#liveCommandCache.lookup(harnessId, cwd) ?? catalog;
|
|
32360
|
+
}
|
|
32361
|
+
}
|
|
32362
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(catalog) }));
|
|
31841
32363
|
}
|
|
31842
32364
|
async #executeThreadCommand(request) {
|
|
31843
32365
|
const params = threadCommandExecuteParamsSchema.safeParse(request.params);
|
|
@@ -31889,39 +32411,43 @@ var AppServerHost = class {
|
|
|
31889
32411
|
return;
|
|
31890
32412
|
}
|
|
31891
32413
|
try {
|
|
31892
|
-
await this.#
|
|
31893
|
-
request,
|
|
32414
|
+
const started = await this.#beginExternalCommand(
|
|
31894
32415
|
thread,
|
|
31895
32416
|
params.commandId,
|
|
31896
32417
|
params.arguments,
|
|
31897
|
-
params.turnId
|
|
31898
|
-
"command"
|
|
32418
|
+
params.turnId
|
|
31899
32419
|
);
|
|
32420
|
+
try {
|
|
32421
|
+
const result = threadCommandExecuteResultSchema.parse({
|
|
32422
|
+
accepted: true,
|
|
32423
|
+
turnId: started.turnId
|
|
32424
|
+
});
|
|
32425
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
|
|
32426
|
+
} finally {
|
|
32427
|
+
started.gate.resolve();
|
|
32428
|
+
}
|
|
31900
32429
|
} catch (error51) {
|
|
31901
32430
|
this.#diagnose(error51);
|
|
31902
32431
|
await this.#writer.json(
|
|
31903
|
-
rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
|
|
32432
|
+
error51 instanceof ExternalCommandError ? rpcError(request, error51.code, error51.message) : rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
|
|
31904
32433
|
);
|
|
31905
32434
|
}
|
|
31906
32435
|
} finally {
|
|
31907
32436
|
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
31908
32437
|
}
|
|
31909
32438
|
}
|
|
31910
|
-
async #
|
|
32439
|
+
async #beginExternalCommand(thread, commandId, arguments_2, requestedTurnId) {
|
|
31911
32440
|
const commands = thread.session.commands;
|
|
31912
32441
|
if (!commands) {
|
|
31913
|
-
|
|
31914
|
-
rpcError(request, -32078, "External Harness does not expose commands")
|
|
31915
|
-
);
|
|
31916
|
-
return;
|
|
32442
|
+
throw new ExternalCommandError(-32078, "External Harness does not expose commands");
|
|
31917
32443
|
}
|
|
31918
|
-
if (
|
|
31919
|
-
|
|
31920
|
-
|
|
31921
|
-
|
|
31922
|
-
|
|
32444
|
+
if (this.#closeRequested || this.#externalRuntime.get(thread.id) !== thread) {
|
|
32445
|
+
throw new ExternalCommandError(-32073, "External Thread is no longer available");
|
|
32446
|
+
}
|
|
32447
|
+
if (thread.running || thread.activeTurnId) {
|
|
32448
|
+
throw new ExternalCommandError(-32072, "External Thread already has an active operation");
|
|
31923
32449
|
}
|
|
31924
|
-
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(
|
|
32450
|
+
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID10());
|
|
31925
32451
|
const projection = {
|
|
31926
32452
|
projector: new CodexTurnProjector({
|
|
31927
32453
|
threadId: thread.id,
|
|
@@ -31936,13 +32462,14 @@ var AppServerHost = class {
|
|
|
31936
32462
|
thread.projectedTurns.set(turnId, projection);
|
|
31937
32463
|
thread.responseGates.set(turnId, gate);
|
|
31938
32464
|
thread.ephemeralTurnIds.add(turnId);
|
|
31939
|
-
let result;
|
|
31940
32465
|
try {
|
|
31941
|
-
result = await commands.execute({
|
|
32466
|
+
const result = await commands.execute({
|
|
31942
32467
|
turnId,
|
|
31943
32468
|
commandId,
|
|
31944
32469
|
...arguments_2 ? { arguments: arguments_2 } : {}
|
|
31945
32470
|
});
|
|
32471
|
+
if (!result.ok) throw new ExternalCommandError(-32073, result.error.message);
|
|
32472
|
+
return { turnId: result.value.turnId, turn: projection.projector.pendingTurn(), gate };
|
|
31946
32473
|
} catch (error51) {
|
|
31947
32474
|
thread.running = false;
|
|
31948
32475
|
thread.activeTurnId = null;
|
|
@@ -31953,28 +32480,6 @@ var AppServerHost = class {
|
|
|
31953
32480
|
this.#signalActiveWorkChanged();
|
|
31954
32481
|
throw error51;
|
|
31955
32482
|
}
|
|
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
32483
|
}
|
|
31979
32484
|
async #selectThreadModel(request) {
|
|
31980
32485
|
const params = threadModelSelectParamsSchema.safeParse(request.params);
|
|
@@ -32597,10 +33102,10 @@ var AppServerHost = class {
|
|
|
32597
33102
|
...typeof params.serviceTier === "string" ? { serviceTier: params.serviceTier } : {}
|
|
32598
33103
|
});
|
|
32599
33104
|
try {
|
|
32600
|
-
if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !
|
|
33105
|
+
if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !isRecord14(params.initialTurnsPage)) {
|
|
32601
33106
|
throw new ExternalHistoryRequestError("initialTurnsPage must be an object");
|
|
32602
33107
|
}
|
|
32603
|
-
const initialPageParams =
|
|
33108
|
+
const initialPageParams = isRecord14(params.initialTurnsPage) ? params.initialTurnsPage : null;
|
|
32604
33109
|
const initialTurnsPage = initialPageParams ? listExternalTurns(turns, initialPageParams) : null;
|
|
32605
33110
|
const paginated = thread.record.historyMode === "paginated";
|
|
32606
33111
|
const turnsBackwardsCursor = paginated ? listExternalTurns(turns, { limit: 1, itemsView: "notLoaded" }).backwardsCursor : null;
|
|
@@ -32695,53 +33200,8 @@ var AppServerHost = class {
|
|
|
32695
33200
|
await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
|
|
32696
33201
|
return;
|
|
32697
33202
|
}
|
|
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
33203
|
try {
|
|
32744
|
-
const started = await this.#
|
|
33204
|
+
const started = await this.#beginExternalInputTurn(thread, text);
|
|
32745
33205
|
try {
|
|
32746
33206
|
await this.#writer.json(rpcEnvelope(request, { result: { turn: started.turn } }));
|
|
32747
33207
|
} finally {
|
|
@@ -32751,7 +33211,7 @@ var AppServerHost = class {
|
|
|
32751
33211
|
await this.#writer.json(
|
|
32752
33212
|
rpcError(
|
|
32753
33213
|
request,
|
|
32754
|
-
error51 instanceof ExternalSteerError ? error51.code : -32073,
|
|
33214
|
+
error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32073,
|
|
32755
33215
|
errorMessage3(error51)
|
|
32756
33216
|
)
|
|
32757
33217
|
);
|
|
@@ -32762,7 +33222,7 @@ var AppServerHost = class {
|
|
|
32762
33222
|
const started = await this.#externalSteering.run(
|
|
32763
33223
|
thread,
|
|
32764
33224
|
requestObject(request),
|
|
32765
|
-
(text) => this.#
|
|
33225
|
+
(text, assertActive) => this.#beginExternalInputTurn(thread, text, assertActive)
|
|
32766
33226
|
);
|
|
32767
33227
|
try {
|
|
32768
33228
|
await this.#writer.json(rpcEnvelope(request, { result: { turnId: started.turnId } }));
|
|
@@ -32773,7 +33233,7 @@ var AppServerHost = class {
|
|
|
32773
33233
|
await this.#writer.json(
|
|
32774
33234
|
rpcError(
|
|
32775
33235
|
request,
|
|
32776
|
-
error51 instanceof ExternalSteerError ? error51.code : -32074,
|
|
33236
|
+
error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32074,
|
|
32777
33237
|
errorMessage3(error51)
|
|
32778
33238
|
)
|
|
32779
33239
|
);
|
|
@@ -32781,6 +33241,37 @@ var AppServerHost = class {
|
|
|
32781
33241
|
this.#signalActiveWorkChanged();
|
|
32782
33242
|
}
|
|
32783
33243
|
}
|
|
33244
|
+
/** Keep command restoration and dispatch identical for start and steer submissions. */
|
|
33245
|
+
async #beginExternalInputTurn(thread, inputText, assertActive) {
|
|
33246
|
+
const text = restoreHarnessCommandMentions(inputText);
|
|
33247
|
+
const commands = thread.session.commands;
|
|
33248
|
+
if (!commands || !isExternalCommandCandidate(text)) {
|
|
33249
|
+
assertActive?.();
|
|
33250
|
+
return this.#beginExternalTurn(thread, text);
|
|
33251
|
+
}
|
|
33252
|
+
this.#pendingExternalCommandRequests.add(thread.id);
|
|
33253
|
+
try {
|
|
33254
|
+
const adapter = this.#externalAdapters.get(thread.harnessId);
|
|
33255
|
+
const command = await resolveExternalCommand(commands, text, {
|
|
33256
|
+
liveCatalogPending: (catalog) => adapter?.liveCommandCatalog === true && !isLiveCommandCatalog(catalog, adapter.commandCatalog ?? { commands: [] })
|
|
33257
|
+
});
|
|
33258
|
+
assertActive?.();
|
|
33259
|
+
if (!command) {
|
|
33260
|
+
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
33261
|
+
return await this.#beginExternalTurn(thread, text);
|
|
33262
|
+
}
|
|
33263
|
+
return await this.#beginExternalCommand(thread, command.commandId, command.arguments);
|
|
33264
|
+
} catch (error51) {
|
|
33265
|
+
if (error51 instanceof ExternalCommandError || error51 instanceof ExternalSteerError) throw error51;
|
|
33266
|
+
this.#diagnose(error51);
|
|
33267
|
+
throw new ExternalCommandError(
|
|
33268
|
+
-32073,
|
|
33269
|
+
`External Harness command failed: ${errorMessage3(error51)}`
|
|
33270
|
+
);
|
|
33271
|
+
} finally {
|
|
33272
|
+
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
33273
|
+
}
|
|
33274
|
+
}
|
|
32784
33275
|
async #beginExternalTurn(thread, text) {
|
|
32785
33276
|
if (this.#closeRequested || this.#externalRuntime.get(thread.id) !== thread) {
|
|
32786
33277
|
throw new ExternalSteerError(-32073, "External Thread is no longer available");
|
|
@@ -32788,7 +33279,7 @@ var AppServerHost = class {
|
|
|
32788
33279
|
if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
|
|
32789
33280
|
throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
|
|
32790
33281
|
}
|
|
32791
|
-
const turnId = hostTurnIdSchema.parse(
|
|
33282
|
+
const turnId = hostTurnIdSchema.parse(randomUUID10());
|
|
32792
33283
|
const startedAtMs = Date.now();
|
|
32793
33284
|
const projection = {
|
|
32794
33285
|
projector: new CodexTurnProjector({
|
|
@@ -32807,7 +33298,7 @@ var AppServerHost = class {
|
|
|
32807
33298
|
const result = await thread.session.execute({
|
|
32808
33299
|
type: "turn.start",
|
|
32809
33300
|
turnId,
|
|
32810
|
-
input: [{ type: "text", text }]
|
|
33301
|
+
input: [{ type: "text", text: rewriteDelegationMentionText(text) }]
|
|
32811
33302
|
});
|
|
32812
33303
|
if (!result.ok) throw new ExternalSteerError(-32073, result.error.message);
|
|
32813
33304
|
return { turnId, turn: projection.projector.pendingTurn(), gate };
|
|
@@ -33109,7 +33600,7 @@ var AppServerHost = class {
|
|
|
33109
33600
|
const previousItems = new Map(
|
|
33110
33601
|
child.turns.flatMap(
|
|
33111
33602
|
(turn) => Array.isArray(turn.items) ? turn.items.flatMap(
|
|
33112
|
-
(item) =>
|
|
33603
|
+
(item) => isRecord14(item) && typeof item.id === "string" ? [[item.id, JSON.stringify(item)]] : []
|
|
33113
33604
|
) : []
|
|
33114
33605
|
)
|
|
33115
33606
|
);
|
|
@@ -33122,7 +33613,7 @@ var AppServerHost = class {
|
|
|
33122
33613
|
for (const turn of child.turns) {
|
|
33123
33614
|
if (typeof turn.id !== "string" || !Array.isArray(turn.items)) continue;
|
|
33124
33615
|
const changedItems = turn.items.filter(
|
|
33125
|
-
(item) =>
|
|
33616
|
+
(item) => isRecord14(item) && typeof item.id === "string" && previousItems.get(item.id) !== JSON.stringify(item)
|
|
33126
33617
|
);
|
|
33127
33618
|
if (changedItems.length > 0) {
|
|
33128
33619
|
await this.#writer.json({
|
|
@@ -33254,7 +33745,7 @@ var AppServerHost = class {
|
|
|
33254
33745
|
}
|
|
33255
33746
|
}
|
|
33256
33747
|
async #handleDesktopApprovalResponse(value2) {
|
|
33257
|
-
if (!
|
|
33748
|
+
if (!isRecord14(value2) || !isHostApprovalRequestId(value2.id)) return false;
|
|
33258
33749
|
const requestId = value2.id;
|
|
33259
33750
|
const pending = this.#pendingDesktopApprovals.get(requestId);
|
|
33260
33751
|
if (!pending) return true;
|
|
@@ -33336,7 +33827,7 @@ var AppServerHost = class {
|
|
|
33336
33827
|
try {
|
|
33337
33828
|
result = projection.projector.projectQuestion(
|
|
33338
33829
|
interaction,
|
|
33339
|
-
hostItemIdSchema.parse(
|
|
33830
|
+
hostItemIdSchema.parse(randomUUID10())
|
|
33340
33831
|
);
|
|
33341
33832
|
} catch (error51) {
|
|
33342
33833
|
this.#diagnose(error51);
|
|
@@ -33381,7 +33872,7 @@ var AppServerHost = class {
|
|
|
33381
33872
|
}
|
|
33382
33873
|
}
|
|
33383
33874
|
async #handleDesktopQuestionResponse(value2) {
|
|
33384
|
-
if (!
|
|
33875
|
+
if (!isRecord14(value2) || !isHostQuestionRequestId(value2.id)) return false;
|
|
33385
33876
|
const requestId = value2.id;
|
|
33386
33877
|
const pending = this.#pendingDesktopQuestions.get(requestId);
|
|
33387
33878
|
if (!pending) return true;
|
|
@@ -33502,19 +33993,19 @@ var AppServerHost = class {
|
|
|
33502
33993
|
};
|
|
33503
33994
|
|
|
33504
33995
|
// packages/host-runtime/src/native-account-host.ts
|
|
33505
|
-
import { mkdir as
|
|
33996
|
+
import { mkdir as mkdir8, realpath as realpath3 } from "node:fs/promises";
|
|
33506
33997
|
import { homedir } from "node:os";
|
|
33507
|
-
import
|
|
33998
|
+
import path19 from "node:path";
|
|
33508
33999
|
|
|
33509
34000
|
// packages/host-runtime/src/codex-runtime/owned-official-backends.ts
|
|
33510
|
-
import { createHash as
|
|
34001
|
+
import { createHash as createHash9, randomBytes } from "node:crypto";
|
|
33511
34002
|
import { Writable as Writable2 } from "node:stream";
|
|
33512
34003
|
|
|
33513
34004
|
// packages/host-runtime/src/remote-app-server.ts
|
|
33514
34005
|
import { createServer } from "node:http";
|
|
33515
34006
|
import net from "node:net";
|
|
33516
|
-
import { chmod as chmod3, lstat as lstat6, mkdir as
|
|
33517
|
-
import
|
|
34007
|
+
import { chmod as chmod3, lstat as lstat6, mkdir as mkdir7, rm as rm7 } from "node:fs/promises";
|
|
34008
|
+
import path17 from "node:path";
|
|
33518
34009
|
import { PassThrough } from "node:stream";
|
|
33519
34010
|
|
|
33520
34011
|
// node_modules/ws/wrapper.mjs
|
|
@@ -33529,10 +34020,10 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
33529
34020
|
var wrapper_default = import_websocket.default;
|
|
33530
34021
|
|
|
33531
34022
|
// packages/host-runtime/src/remote-socket-lock.ts
|
|
33532
|
-
import { randomUUID as
|
|
33533
|
-
import { chmod as chmod2, lstat as lstat5, mkdir as
|
|
34023
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
34024
|
+
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
34025
|
import { uptime } from "node:os";
|
|
33535
|
-
import
|
|
34026
|
+
import path16 from "node:path";
|
|
33536
34027
|
import { setTimeout as delay4 } from "node:timers/promises";
|
|
33537
34028
|
var LOCK_RETRY_COUNT = 200;
|
|
33538
34029
|
var LOCK_RETRY_DELAY_MS = 25;
|
|
@@ -33595,7 +34086,7 @@ async function readLockEntrySnapshot(filePath) {
|
|
|
33595
34086
|
throw error51;
|
|
33596
34087
|
});
|
|
33597
34088
|
if (metadata === null || !metadata.isFile()) return null;
|
|
33598
|
-
const source = await
|
|
34089
|
+
const source = await readFile8(filePath, "utf8").catch((error51) => {
|
|
33599
34090
|
if (error51.code === "ENOENT") return null;
|
|
33600
34091
|
throw error51;
|
|
33601
34092
|
});
|
|
@@ -33606,7 +34097,7 @@ async function readLockEntrySnapshot(filePath) {
|
|
|
33606
34097
|
source,
|
|
33607
34098
|
identity: { dev: metadata.dev, ino: metadata.ino },
|
|
33608
34099
|
mtimeMs: metadata.mtimeMs,
|
|
33609
|
-
record: record3 &&
|
|
34100
|
+
record: record3 && path16.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
|
|
33610
34101
|
};
|
|
33611
34102
|
}
|
|
33612
34103
|
function lockEntryIsAbandoned(snapshot) {
|
|
@@ -33618,7 +34109,7 @@ async function removeAbandonedLockEntry(snapshot) {
|
|
|
33618
34109
|
if (current === null || current.source !== snapshot.source || !sameUnixFileIdentity(current.identity, snapshot.identity) || !lockEntryIsAbandoned(current)) {
|
|
33619
34110
|
return false;
|
|
33620
34111
|
}
|
|
33621
|
-
await
|
|
34112
|
+
await rm6(snapshot.filePath, { force: true });
|
|
33622
34113
|
return true;
|
|
33623
34114
|
}
|
|
33624
34115
|
async function readLockEntryCatalog(lockDirectory) {
|
|
@@ -33627,7 +34118,7 @@ async function readLockEntryCatalog(lockDirectory) {
|
|
|
33627
34118
|
let unsettled = false;
|
|
33628
34119
|
for (const name of names) {
|
|
33629
34120
|
if (!name.startsWith(LOCK_ENTRY_PREFIX) || !name.endsWith(LOCK_ENTRY_SUFFIX)) continue;
|
|
33630
|
-
const snapshot = await readLockEntrySnapshot(
|
|
34121
|
+
const snapshot = await readLockEntrySnapshot(path16.join(lockDirectory, name));
|
|
33631
34122
|
if (snapshot === null) continue;
|
|
33632
34123
|
if (lockEntryIsAbandoned(snapshot)) {
|
|
33633
34124
|
if (!await removeAbandonedLockEntry(snapshot)) unsettled = true;
|
|
@@ -33642,7 +34133,7 @@ async function readLockEntryCatalog(lockDirectory) {
|
|
|
33642
34133
|
return { entries, unsettled };
|
|
33643
34134
|
}
|
|
33644
34135
|
async function preparePrivateLockDirectory(lockDirectory) {
|
|
33645
|
-
await
|
|
34136
|
+
await mkdir6(lockDirectory, { mode: 448 }).catch((error51) => {
|
|
33646
34137
|
if (error51.code !== "EEXIST") throw error51;
|
|
33647
34138
|
});
|
|
33648
34139
|
const metadata = await lstat5(lockDirectory);
|
|
@@ -33655,8 +34146,8 @@ async function preparePrivateLockDirectory(lockDirectory) {
|
|
|
33655
34146
|
await chmod2(lockDirectory, 448);
|
|
33656
34147
|
}
|
|
33657
34148
|
async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
|
|
33658
|
-
const temporary =
|
|
33659
|
-
const handle = await
|
|
34149
|
+
const temporary = path16.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID11()}`);
|
|
34150
|
+
const handle = await open6(temporary, "wx", 384);
|
|
33660
34151
|
try {
|
|
33661
34152
|
await handle.writeFile(`${JSON.stringify(record3)}
|
|
33662
34153
|
`, "utf8");
|
|
@@ -33665,15 +34156,15 @@ async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
|
|
|
33665
34156
|
await handle.close();
|
|
33666
34157
|
}
|
|
33667
34158
|
try {
|
|
33668
|
-
await
|
|
34159
|
+
await rename5(temporary, entryPath);
|
|
33669
34160
|
} finally {
|
|
33670
|
-
await
|
|
34161
|
+
await rm6(temporary, { force: true });
|
|
33671
34162
|
}
|
|
33672
34163
|
}
|
|
33673
34164
|
async function removeOwnedLockEntry(entryPath, ownerToken) {
|
|
33674
34165
|
const snapshot = await readLockEntrySnapshot(entryPath);
|
|
33675
34166
|
if (snapshot?.record?.ownerToken !== ownerToken) return;
|
|
33676
|
-
await
|
|
34167
|
+
await rm6(entryPath, { force: true });
|
|
33677
34168
|
}
|
|
33678
34169
|
async function legacyLockState(legacyPath) {
|
|
33679
34170
|
const metadata = await lstat5(legacyPath).catch((error51) => {
|
|
@@ -33682,7 +34173,7 @@ async function legacyLockState(legacyPath) {
|
|
|
33682
34173
|
});
|
|
33683
34174
|
if (metadata === null) return "absent";
|
|
33684
34175
|
if (!metadata.isFile()) return "blocking";
|
|
33685
|
-
const source = await
|
|
34176
|
+
const source = await readFile8(legacyPath, "utf8").catch((error51) => {
|
|
33686
34177
|
if (error51.code === "ENOENT") return null;
|
|
33687
34178
|
throw error51;
|
|
33688
34179
|
});
|
|
@@ -33693,7 +34184,7 @@ async function legacyLockState(legacyPath) {
|
|
|
33693
34184
|
return ownerIsAbandoned(record3, metadata.mtimeMs) ? "abandoned" : "blocking";
|
|
33694
34185
|
}
|
|
33695
34186
|
async function tryAcquireLegacyCompatibilityGuard(legacyPath, record3) {
|
|
33696
|
-
const handle = await
|
|
34187
|
+
const handle = await open6(legacyPath, "wx", 384).catch((error51) => {
|
|
33697
34188
|
if (error51.code === "EEXIST") return null;
|
|
33698
34189
|
throw error51;
|
|
33699
34190
|
});
|
|
@@ -33719,7 +34210,7 @@ async function releaseLegacyCompatibilityGuard(legacyPath, guard) {
|
|
|
33719
34210
|
throw error51;
|
|
33720
34211
|
});
|
|
33721
34212
|
if (metadata?.isFile() && sameUnixFileIdentity({ dev: metadata.dev, ino: metadata.ino }, guard.identity)) {
|
|
33722
|
-
await
|
|
34213
|
+
await rm6(legacyPath, { force: true });
|
|
33723
34214
|
}
|
|
33724
34215
|
}
|
|
33725
34216
|
}
|
|
@@ -33730,8 +34221,8 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
|
|
|
33730
34221
|
const legacyPath = `${socketPath}.initializing`;
|
|
33731
34222
|
const lockDirectory = `${socketPath}.initializers`;
|
|
33732
34223
|
await preparePrivateLockDirectory(lockDirectory);
|
|
33733
|
-
const ownerToken =
|
|
33734
|
-
const entryPath =
|
|
34224
|
+
const ownerToken = randomUUID11();
|
|
34225
|
+
const entryPath = path16.join(lockDirectory, lockEntryName(ownerToken));
|
|
33735
34226
|
const baseRecord = {
|
|
33736
34227
|
version: 2,
|
|
33737
34228
|
ownerToken,
|
|
@@ -33905,14 +34396,14 @@ function remoteAppServerSocketPath(environment, listenUrl = "unix://") {
|
|
|
33905
34396
|
throw new Error("Remote app-server listener must use a Unix URL");
|
|
33906
34397
|
}
|
|
33907
34398
|
const explicit = listenUrl.slice("unix://".length);
|
|
33908
|
-
if (explicit.length > 0) return
|
|
33909
|
-
const codexHome = environment.CODEX_HOME ?? (environment.HOME ?
|
|
34399
|
+
if (explicit.length > 0) return path17.posix.resolve(decodeURIComponent(explicit));
|
|
34400
|
+
const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path17.posix.join(environment.HOME, ".codex") : void 0);
|
|
33910
34401
|
if (!codexHome)
|
|
33911
34402
|
throw new Error("CODEX_HOME or HOME is required for the remote app-server socket");
|
|
33912
|
-
return
|
|
34403
|
+
return path17.posix.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
33913
34404
|
}
|
|
33914
34405
|
function officialListenerArgumentsForRemoteListener(arguments_2, socketPath) {
|
|
33915
|
-
if (!
|
|
34406
|
+
if (!path17.posix.isAbsolute(socketPath)) {
|
|
33916
34407
|
throw new Error("Shared official app-server socket path must be absolute");
|
|
33917
34408
|
}
|
|
33918
34409
|
if (remoteUnixListenerUrl(arguments_2) === null) {
|
|
@@ -34020,10 +34511,10 @@ async function removeStaleSocket(socketPath) {
|
|
|
34020
34511
|
});
|
|
34021
34512
|
});
|
|
34022
34513
|
if (active) throw new Error(`Remote app-server socket is already in use at ${socketPath}`);
|
|
34023
|
-
await
|
|
34514
|
+
await rm7(socketPath, { force: true });
|
|
34024
34515
|
}
|
|
34025
34516
|
async function prepareRemoteAppServerSocketDirectory(socketPath) {
|
|
34026
|
-
const socketDirectory =
|
|
34517
|
+
const socketDirectory = path17.dirname(socketPath);
|
|
34027
34518
|
const existing = await lstat6(socketDirectory).catch((error51) => {
|
|
34028
34519
|
if (error51.code === "ENOENT") return null;
|
|
34029
34520
|
throw error51;
|
|
@@ -34037,7 +34528,7 @@ async function prepareRemoteAppServerSocketDirectory(socketPath) {
|
|
|
34037
34528
|
);
|
|
34038
34529
|
}
|
|
34039
34530
|
}
|
|
34040
|
-
await
|
|
34531
|
+
await mkdir7(socketDirectory, { recursive: true, mode: 448 });
|
|
34041
34532
|
await chmod3(socketDirectory, 448);
|
|
34042
34533
|
}
|
|
34043
34534
|
function sendOutputFrames(socket, output) {
|
|
@@ -34210,7 +34701,7 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
34210
34701
|
if (ownedSocketIdentity) {
|
|
34211
34702
|
const current = await unixSocketIdentity(input.socketPath);
|
|
34212
34703
|
if (current && sameUnixFileIdentity2(current, ownedSocketIdentity)) {
|
|
34213
|
-
await
|
|
34704
|
+
await rm7(input.socketPath, { force: true });
|
|
34214
34705
|
}
|
|
34215
34706
|
ownedSocketIdentity = null;
|
|
34216
34707
|
}
|
|
@@ -34228,20 +34719,20 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
34228
34719
|
|
|
34229
34720
|
// packages/host-runtime/src/remote-official-app-server.ts
|
|
34230
34721
|
import { spawn as spawn3 } from "node:child_process";
|
|
34231
|
-
import { randomUUID as
|
|
34232
|
-
import { lstat as lstat7, rm as
|
|
34233
|
-
import
|
|
34722
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
34723
|
+
import { lstat as lstat7, rm as rm8 } from "node:fs/promises";
|
|
34724
|
+
import path18 from "node:path";
|
|
34234
34725
|
var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
|
|
34235
34726
|
var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
|
|
34236
|
-
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token =
|
|
34237
|
-
if (!
|
|
34727
|
+
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID12()) {
|
|
34728
|
+
if (!path18.posix.isAbsolute(desktopControlSocketPath)) {
|
|
34238
34729
|
throw new Error("Desktop control socket path must be absolute");
|
|
34239
34730
|
}
|
|
34240
34731
|
if (!/^[A-Za-z0-9-]+$/u.test(token) || !/[A-Za-z0-9]/u.test(token)) {
|
|
34241
34732
|
throw new Error("Shared official app-server socket token is invalid");
|
|
34242
34733
|
}
|
|
34243
34734
|
const compactToken = token.replaceAll("-", "").slice(0, 15);
|
|
34244
|
-
return
|
|
34735
|
+
return path18.posix.join(path18.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
|
|
34245
34736
|
}
|
|
34246
34737
|
function errorMessage4(error51) {
|
|
34247
34738
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
@@ -34313,7 +34804,7 @@ function createRemoteOfficialAppServerListener(input) {
|
|
|
34313
34804
|
if (ownedSocketIdentity === null) return;
|
|
34314
34805
|
const current = await socketIdentity(input.socketPath).catch(() => null);
|
|
34315
34806
|
if (current && sameUnixFileIdentity3(current, ownedSocketIdentity)) {
|
|
34316
|
-
await
|
|
34807
|
+
await rm8(input.socketPath, { force: true });
|
|
34317
34808
|
}
|
|
34318
34809
|
ownedSocketIdentity = null;
|
|
34319
34810
|
};
|
|
@@ -34674,7 +35165,7 @@ function createOwnedLoopbackBackend(input) {
|
|
|
34674
35165
|
"--ws-auth",
|
|
34675
35166
|
"capability-token",
|
|
34676
35167
|
"--ws-token-sha256",
|
|
34677
|
-
|
|
35168
|
+
createHash9("sha256").update(capabilityToken).digest("hex")
|
|
34678
35169
|
],
|
|
34679
35170
|
// Managed stderr may carry credential-bearing errors. Never forward raw bytes.
|
|
34680
35171
|
diagnosticOutput: new Writable2({
|
|
@@ -34727,21 +35218,21 @@ function createOwnedUnixBackend(input) {
|
|
|
34727
35218
|
|
|
34728
35219
|
// packages/host-runtime/src/native-account-host.ts
|
|
34729
35220
|
async function canonicalCodexHome(home) {
|
|
34730
|
-
const absolute =
|
|
35221
|
+
const absolute = path19.resolve(home);
|
|
34731
35222
|
try {
|
|
34732
35223
|
return await realpath3(absolute);
|
|
34733
35224
|
} catch (error51) {
|
|
34734
35225
|
if (!(error51 instanceof Error && "code" in error51 && error51.code === "ENOENT")) throw error51;
|
|
34735
|
-
const parent =
|
|
35226
|
+
const parent = path19.dirname(absolute);
|
|
34736
35227
|
if (parent === absolute) throw error51;
|
|
34737
|
-
return
|
|
35228
|
+
return path19.join(await canonicalCodexHome(parent), path19.basename(absolute));
|
|
34738
35229
|
}
|
|
34739
35230
|
}
|
|
34740
35231
|
async function prepareLocalCodex(input) {
|
|
34741
35232
|
const home = await canonicalCodexHome(
|
|
34742
|
-
input.environment.CODEX_HOME ??
|
|
35233
|
+
input.environment.CODEX_HOME ?? path19.join(homedir(), ".codex")
|
|
34743
35234
|
);
|
|
34744
|
-
await
|
|
35235
|
+
await mkdir8(home, { recursive: true });
|
|
34745
35236
|
const scope = new OfficialRuntimeScope({
|
|
34746
35237
|
permanentHome: home,
|
|
34747
35238
|
diagnosticOutput: input.diagnosticOutput,
|
|
@@ -34905,18 +35396,18 @@ var DelegationControlRegistry = class {
|
|
|
34905
35396
|
};
|
|
34906
35397
|
|
|
34907
35398
|
// packages/host-runtime/src/installed-harness-plugins.ts
|
|
34908
|
-
import
|
|
34909
|
-
import
|
|
35399
|
+
import os6 from "node:os";
|
|
35400
|
+
import path21 from "node:path";
|
|
34910
35401
|
import { fileURLToPath } from "node:url";
|
|
34911
35402
|
|
|
34912
35403
|
// packages/host-runtime/src/launcher-url-opener.ts
|
|
34913
35404
|
import { spawn as spawn4 } from "node:child_process";
|
|
34914
|
-
import
|
|
35405
|
+
import path20 from "node:path";
|
|
34915
35406
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
|
|
34916
35407
|
var OPEN_TIMEOUT_MS = 1e4;
|
|
34917
35408
|
function createLauncherUrlOpener(environment, spawnLauncher = (command, arguments_2, options2) => spawn4(command, arguments_2, options2)) {
|
|
34918
35409
|
const launcher = environment.CODEXHOST_LAUNCHER_EXECUTABLE;
|
|
34919
|
-
if (!launcher || !
|
|
35410
|
+
if (!launcher || !path20.isAbsolute(launcher)) return void 0;
|
|
34920
35411
|
const launcherEnvironment = Object.fromEntries(
|
|
34921
35412
|
Object.entries(environment).filter(([name]) => {
|
|
34922
35413
|
const normalized = name.toUpperCase();
|
|
@@ -34974,9 +35465,9 @@ function installedHarnessPluginOptions(environment, managedRemoteHost = false, h
|
|
|
34974
35465
|
const opener = managedRemoteHost ? void 0 : createLauncherUrlOpener(environment);
|
|
34975
35466
|
return {
|
|
34976
35467
|
pluginRoots: [
|
|
34977
|
-
|
|
34978
|
-
environment[HARNESS_PLUGIN_DIRECTORY_ENV] ??
|
|
34979
|
-
environment.CODEXHOST_DATA_DIR ?
|
|
35468
|
+
path21.join(path21.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
|
|
35469
|
+
environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path21.join(
|
|
35470
|
+
environment.CODEXHOST_DATA_DIR ? path21.resolve(environment.CODEXHOST_DATA_DIR) : path21.join(os6.homedir(), ".codexhost"),
|
|
34980
35471
|
"plugins"
|
|
34981
35472
|
)
|
|
34982
35473
|
],
|
|
@@ -35100,171 +35591,10 @@ async function startDelegationControlServer(input) {
|
|
|
35100
35591
|
};
|
|
35101
35592
|
}
|
|
35102
35593
|
|
|
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
35594
|
// packages/host-runtime/src/remote-control-app-server.ts
|
|
35265
35595
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
35266
35596
|
import { mkdir as mkdir9, open as open7, rename as rename6, rm as rm9 } from "node:fs/promises";
|
|
35267
|
-
import
|
|
35597
|
+
import path22 from "node:path";
|
|
35268
35598
|
var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
|
|
35269
35599
|
var REMOTE_CONTROL_BRIDGE_NODE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_NODE_PATH";
|
|
35270
35600
|
var REMOTE_CONTROL_BRIDGE_RUNTIME_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_RUNTIME_PATH";
|
|
@@ -35275,8 +35605,8 @@ var BRIDGE_READY_METHOD = "codexhost/remote-control-bridge/ready";
|
|
|
35275
35605
|
function absoluteEnvironmentPath2(environment, name, fallback, platform = process.platform) {
|
|
35276
35606
|
const value2 = environment[name] ?? fallback;
|
|
35277
35607
|
if (!value2) return null;
|
|
35278
|
-
if (
|
|
35279
|
-
return platform === "win32" &&
|
|
35608
|
+
if (path22.isAbsolute(value2)) return path22.normalize(value2);
|
|
35609
|
+
return platform === "win32" && path22.win32.isAbsolute(value2) ? path22.win32.normalize(value2) : null;
|
|
35280
35610
|
}
|
|
35281
35611
|
function nodeCompatibleWindowsPath(value2) {
|
|
35282
35612
|
if (value2.startsWith("\\\\?\\UNC\\")) return `\\\\${value2.slice(8)}`;
|
|
@@ -35290,13 +35620,13 @@ function remoteControlBridgePipePath(processId = process.pid, instanceId = rando
|
|
|
35290
35620
|
}
|
|
35291
35621
|
function remoteControlBridgeDescriptorPath(environment) {
|
|
35292
35622
|
const root = environment.LOCALAPPDATA;
|
|
35293
|
-
if (!root || !
|
|
35294
|
-
return
|
|
35623
|
+
if (!root || !path22.isAbsolute(root)) return null;
|
|
35624
|
+
return path22.join(path22.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
|
|
35295
35625
|
}
|
|
35296
35626
|
async function publishRemoteControlAppServerDescriptor(plan) {
|
|
35297
|
-
const directory =
|
|
35627
|
+
const directory = path22.dirname(plan.descriptorPath);
|
|
35298
35628
|
await mkdir9(directory, { recursive: true, mode: 448 });
|
|
35299
|
-
const temporaryPath =
|
|
35629
|
+
const temporaryPath = path22.join(
|
|
35300
35630
|
directory,
|
|
35301
35631
|
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID13()}.tmp`
|
|
35302
35632
|
);
|
|
@@ -35597,9 +35927,9 @@ function hasLauncherManagedUpdateRuntime(environment, hostRuntimePath) {
|
|
|
35597
35927
|
if (!environment[UPDATE_RUNTIME_ENV.launcherPid]) return false;
|
|
35598
35928
|
const npmPackageRoot = environment[UPDATE_RUNTIME_ENV.npmPackageRoot];
|
|
35599
35929
|
if (!npmPackageRoot || !hostRuntimePath) return true;
|
|
35600
|
-
if (!
|
|
35601
|
-
const runtimePackageRoot =
|
|
35602
|
-
return
|
|
35930
|
+
if (!path23.isAbsolute(npmPackageRoot) || !path23.isAbsolute(hostRuntimePath)) return false;
|
|
35931
|
+
const runtimePackageRoot = path23.dirname(path23.dirname(path23.normalize(hostRuntimePath)));
|
|
35932
|
+
return path23.relative(path23.normalize(npmPackageRoot), runtimePackageRoot) === "";
|
|
35603
35933
|
}
|
|
35604
35934
|
function requiredRuntimeConfiguration(environment) {
|
|
35605
35935
|
const stockCodexPath = environment[STOCK_CODEX_PATH_ENV];
|
|
@@ -35745,8 +36075,8 @@ async function runHostRuntime(input) {
|
|
|
35745
36075
|
const socketPath = remoteAppServerSocketPath(delegationEnvironment, listenUrl);
|
|
35746
36076
|
const officialPlan = createRemoteOfficialAppServerPlan(input.arguments, socketPath);
|
|
35747
36077
|
const officialRuntimeScope = new OfficialRuntimeScope({
|
|
35748
|
-
permanentHome:
|
|
35749
|
-
delegationEnvironment.CODEX_HOME ??
|
|
36078
|
+
permanentHome: path23.resolve(
|
|
36079
|
+
delegationEnvironment.CODEX_HOME ?? path23.join(homedir2(), ".codex")
|
|
35750
36080
|
),
|
|
35751
36081
|
diagnosticOutput: process.stderr,
|
|
35752
36082
|
createBackend: () => createOwnedUnixBackend({
|
|
@@ -35842,7 +36172,7 @@ import {
|
|
|
35842
36172
|
stat as stat5,
|
|
35843
36173
|
writeFile as writeFile4
|
|
35844
36174
|
} from "node:fs/promises";
|
|
35845
|
-
import
|
|
36175
|
+
import path24 from "node:path";
|
|
35846
36176
|
var MANIFEST_FORMAT = 1;
|
|
35847
36177
|
var WRAPPER_MARKER = "# codexhost remote SSH wrapper v1";
|
|
35848
36178
|
var PROFILE_START = "# >>> codexhost remote SSH >>>";
|
|
@@ -35853,25 +36183,25 @@ function resolvePaths(options2) {
|
|
|
35853
36183
|
if (!configuredHome) {
|
|
35854
36184
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
35855
36185
|
}
|
|
35856
|
-
const home =
|
|
35857
|
-
if (!home || home ===
|
|
36186
|
+
const home = path24.resolve(configuredHome);
|
|
36187
|
+
if (!home || home === path24.parse(home).root) {
|
|
35858
36188
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
35859
36189
|
}
|
|
35860
|
-
const installRoot =
|
|
35861
|
-
const profilePath =
|
|
35862
|
-
options2.profilePath ??
|
|
36190
|
+
const installRoot = path24.resolve(options2.installRoot ?? path24.join(home, ".codexhost", "remote"));
|
|
36191
|
+
const profilePath = path24.resolve(
|
|
36192
|
+
options2.profilePath ?? path24.join(
|
|
35863
36193
|
home,
|
|
35864
|
-
|
|
36194
|
+
path24.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path24.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
|
|
35865
36195
|
)
|
|
35866
36196
|
);
|
|
35867
|
-
const binDirectory =
|
|
36197
|
+
const binDirectory = path24.join(installRoot, "bin");
|
|
35868
36198
|
return {
|
|
35869
36199
|
home,
|
|
35870
36200
|
installRoot,
|
|
35871
36201
|
binDirectory,
|
|
35872
|
-
wrapperPath:
|
|
35873
|
-
manifestPath:
|
|
35874
|
-
dataDirectory:
|
|
36202
|
+
wrapperPath: path24.join(binDirectory, "codex"),
|
|
36203
|
+
manifestPath: path24.join(installRoot, "manifest.json"),
|
|
36204
|
+
dataDirectory: path24.join(installRoot, "data"),
|
|
35875
36205
|
profilePath
|
|
35876
36206
|
};
|
|
35877
36207
|
}
|
|
@@ -35890,7 +36220,7 @@ async function fileSha256(filePath) {
|
|
|
35890
36220
|
return createHash10("sha256").update(await readFile9(filePath)).digest("hex");
|
|
35891
36221
|
}
|
|
35892
36222
|
async function executable(filePath, label) {
|
|
35893
|
-
const absolute =
|
|
36223
|
+
const absolute = path24.resolve(filePath);
|
|
35894
36224
|
try {
|
|
35895
36225
|
if (!(await stat5(absolute)).isFile()) throw new Error("not a regular file");
|
|
35896
36226
|
await access(absolute, fsConstants.X_OK);
|
|
@@ -35900,7 +36230,7 @@ async function executable(filePath, label) {
|
|
|
35900
36230
|
return absolute;
|
|
35901
36231
|
}
|
|
35902
36232
|
async function existingFile(filePath, label) {
|
|
35903
|
-
const absolute =
|
|
36233
|
+
const absolute = path24.resolve(filePath);
|
|
35904
36234
|
try {
|
|
35905
36235
|
const metadata = await stat5(absolute);
|
|
35906
36236
|
if (!metadata.isFile()) throw new Error("not a regular file");
|
|
@@ -35910,9 +36240,9 @@ async function existingFile(filePath, label) {
|
|
|
35910
36240
|
return absolute;
|
|
35911
36241
|
}
|
|
35912
36242
|
async function discoverExecutable(name, environment) {
|
|
35913
|
-
for (const directory of (environment.PATH ?? "").split(
|
|
36243
|
+
for (const directory of (environment.PATH ?? "").split(path24.delimiter)) {
|
|
35914
36244
|
if (!directory) continue;
|
|
35915
|
-
const candidate =
|
|
36245
|
+
const candidate = path24.resolve(directory, name);
|
|
35916
36246
|
try {
|
|
35917
36247
|
await access(candidate, fsConstants.X_OK);
|
|
35918
36248
|
return candidate;
|
|
@@ -35923,10 +36253,10 @@ async function discoverExecutable(name, environment) {
|
|
|
35923
36253
|
return null;
|
|
35924
36254
|
}
|
|
35925
36255
|
async function writeAtomic(filePath, contents, mode) {
|
|
35926
|
-
await mkdir10(
|
|
35927
|
-
const temporary =
|
|
35928
|
-
|
|
35929
|
-
`.${
|
|
36256
|
+
await mkdir10(path24.dirname(filePath), { recursive: true, mode: 448 });
|
|
36257
|
+
const temporary = path24.join(
|
|
36258
|
+
path24.dirname(filePath),
|
|
36259
|
+
`.${path24.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
|
|
35930
36260
|
);
|
|
35931
36261
|
try {
|
|
35932
36262
|
if (typeof contents === "string") {
|
|
@@ -35947,10 +36277,10 @@ async function writeAtomic(filePath, contents, mode) {
|
|
|
35947
36277
|
}
|
|
35948
36278
|
}
|
|
35949
36279
|
async function writeAtomicExecutable(filePath, sourcePath) {
|
|
35950
|
-
await mkdir10(
|
|
35951
|
-
const temporary =
|
|
35952
|
-
|
|
35953
|
-
`.${
|
|
36280
|
+
await mkdir10(path24.dirname(filePath), { recursive: true, mode: 448 });
|
|
36281
|
+
const temporary = path24.join(
|
|
36282
|
+
path24.dirname(filePath),
|
|
36283
|
+
`.${path24.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
|
|
35954
36284
|
);
|
|
35955
36285
|
try {
|
|
35956
36286
|
await copyFile3(sourcePath, temporary);
|
|
@@ -35991,8 +36321,8 @@ function removeManagedProfileBlock(contents) {
|
|
|
35991
36321
|
function installManagedProfileBlock(contents, manifest) {
|
|
35992
36322
|
const base = removeManagedProfileBlock(contents);
|
|
35993
36323
|
const environment = [
|
|
35994
|
-
`export CODEX_INSTALL_DIR=${shellQuote(
|
|
35995
|
-
`export PATH=${shellQuote(
|
|
36324
|
+
`export CODEX_INSTALL_DIR=${shellQuote(path24.dirname(manifest.wrapperPath))}`,
|
|
36325
|
+
`export PATH=${shellQuote(path24.dirname(manifest.wrapperPath))}:${shellQuote(path24.dirname(manifest.nodePath))}:${shellQuote(path24.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
|
|
35996
36326
|
`export CODEXHOST_STOCK_CODEX_PATH=${shellQuote(manifest.stockCodexPath)}`,
|
|
35997
36327
|
`export CODEXHOST_HOST_NODE_PATH=${shellQuote(manifest.nodePath)}`,
|
|
35998
36328
|
`export CODEXHOST_HOST_RUNTIME_PATH=${shellQuote(manifest.hostRuntimePath)}`,
|
|
@@ -36008,7 +36338,7 @@ function installManagedProfileBlock(contents, manifest) {
|
|
|
36008
36338
|
PROFILE_END,
|
|
36009
36339
|
""
|
|
36010
36340
|
].join("\n");
|
|
36011
|
-
if (
|
|
36341
|
+
if (path24.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
|
|
36012
36342
|
const separator = base.length > 0 && !base.endsWith("\n") ? "\n" : "";
|
|
36013
36343
|
return `${base}${separator}${block}`;
|
|
36014
36344
|
}
|
|
@@ -36074,9 +36404,9 @@ async function readManifest(filePath) {
|
|
|
36074
36404
|
];
|
|
36075
36405
|
const optionalPaths = ["claudeCommand", "profileBackupPath"];
|
|
36076
36406
|
if (manifest.format !== MANIFEST_FORMAT || Object.keys(manifest).some((key) => !allowed.has(key)) || requiredPaths.some(
|
|
36077
|
-
(key) => typeof manifest[key] !== "string" || !
|
|
36407
|
+
(key) => typeof manifest[key] !== "string" || !path24.isAbsolute(manifest[key])
|
|
36078
36408
|
) || optionalPaths.some(
|
|
36079
|
-
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !
|
|
36409
|
+
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path24.isAbsolute(manifest[key]))
|
|
36080
36410
|
) || manifest.entrypointSha256 !== void 0 && (typeof manifest.entrypointSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(manifest.entrypointSha256))) {
|
|
36081
36411
|
throw new Error("Remote Host manifest has an unsupported format");
|
|
36082
36412
|
}
|
|
@@ -36302,7 +36632,7 @@ async function uninstallRemoteHost(options2) {
|
|
|
36302
36632
|
import { spawn as spawn5 } from "node:child_process";
|
|
36303
36633
|
import { stat as stat6 } from "node:fs/promises";
|
|
36304
36634
|
import net3 from "node:net";
|
|
36305
|
-
import
|
|
36635
|
+
import path25 from "node:path";
|
|
36306
36636
|
import { Duplex } from "node:stream";
|
|
36307
36637
|
var CODEXHOST_STATUS_METHOD = "codexhost/update/status";
|
|
36308
36638
|
var DIRECT_PROBE_TIMEOUT_MS = 5e3;
|
|
@@ -36321,9 +36651,9 @@ function classifyRemoteHostProbeResponse(response, socketPath) {
|
|
|
36321
36651
|
}
|
|
36322
36652
|
var lifecycleDependencyOverrides = {};
|
|
36323
36653
|
function socketPathFor(environment) {
|
|
36324
|
-
const codexHome = environment.CODEX_HOME ?? (environment.HOME ?
|
|
36654
|
+
const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path25.join(environment.HOME, ".codex") : void 0);
|
|
36325
36655
|
if (!codexHome) throw new Error("CODEX_HOME or HOME is required for remote Host lifecycle");
|
|
36326
|
-
return
|
|
36656
|
+
return path25.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
36327
36657
|
}
|
|
36328
36658
|
async function defaultSocketExists(socketPath) {
|
|
36329
36659
|
const metadata = await stat6(socketPath).catch((error51) => {
|
|
@@ -36450,14 +36780,14 @@ function installedManifest(status) {
|
|
|
36450
36780
|
function managedEnvironment(manifest, environment) {
|
|
36451
36781
|
return {
|
|
36452
36782
|
...environment,
|
|
36453
|
-
CODEX_INSTALL_DIR:
|
|
36783
|
+
CODEX_INSTALL_DIR: path25.dirname(manifest.wrapperPath),
|
|
36454
36784
|
CODEXHOST_STOCK_CODEX_PATH: manifest.stockCodexPath,
|
|
36455
36785
|
CODEXHOST_HOST_NODE_PATH: manifest.nodePath,
|
|
36456
36786
|
CODEXHOST_HOST_RUNTIME_PATH: manifest.hostRuntimePath,
|
|
36457
36787
|
CODEXHOST_DATA_DIR: manifest.dataDirectory,
|
|
36458
36788
|
CODEXHOST_DEFAULT_AGENT: "codex",
|
|
36459
36789
|
CODEXHOST_REMOTE_SSH_MANAGED: "1",
|
|
36460
|
-
PATH: `${
|
|
36790
|
+
PATH: `${path25.dirname(manifest.wrapperPath)}${path25.delimiter}${path25.dirname(manifest.stockCodexPath)}${path25.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
|
|
36461
36791
|
};
|
|
36462
36792
|
}
|
|
36463
36793
|
async function defaultRunTerminator(manifest, socketPath, role, environment) {
|
|
@@ -36793,25 +37123,25 @@ function consumeBrokerFrames(socket, onFrame, onError) {
|
|
|
36793
37123
|
|
|
36794
37124
|
// packages/harness-broker/dist/paths.js
|
|
36795
37125
|
import os7 from "node:os";
|
|
36796
|
-
import
|
|
37126
|
+
import path26 from "node:path";
|
|
36797
37127
|
var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
|
|
36798
37128
|
var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
|
|
36799
37129
|
var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
|
|
36800
37130
|
function defaultHarnessBrokerDirectory(environment = process.env) {
|
|
36801
37131
|
const home = environment.HOME || os7.homedir();
|
|
36802
|
-
return
|
|
37132
|
+
return path26.join(home, ".codexhost", "harness-broker");
|
|
36803
37133
|
}
|
|
36804
37134
|
function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
|
|
36805
37135
|
harnessPluginIdSchema.parse(harnessId);
|
|
36806
37136
|
if (harnessId !== "claude-code")
|
|
36807
|
-
return
|
|
36808
|
-
return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ??
|
|
37137
|
+
return path26.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
|
|
37138
|
+
return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path26.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
|
|
36809
37139
|
}
|
|
36810
37140
|
function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
|
|
36811
37141
|
harnessPluginIdSchema.parse(harnessId);
|
|
36812
37142
|
if (harnessId !== "claude-code")
|
|
36813
|
-
return
|
|
36814
|
-
return
|
|
37143
|
+
return path26.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
|
|
37144
|
+
return path26.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
|
|
36815
37145
|
}
|
|
36816
37146
|
|
|
36817
37147
|
// packages/harness-broker/dist/validation.js
|
|
@@ -37027,7 +37357,7 @@ var harnessOutputSchema = external_exports.custom((value2) => {
|
|
|
37027
37357
|
import { randomBytes as randomBytes3, randomUUID as randomUUID15 } from "node:crypto";
|
|
37028
37358
|
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
37359
|
import net4, {} from "node:net";
|
|
37030
|
-
import
|
|
37360
|
+
import path27 from "node:path";
|
|
37031
37361
|
function harnessError(message, retryable = true) {
|
|
37032
37362
|
return { code: "unavailable", message, retryable, stage: "harnessBroker" };
|
|
37033
37363
|
}
|
|
@@ -37150,13 +37480,13 @@ async function prepareUnixSocketPath(socketPath) {
|
|
|
37150
37480
|
}
|
|
37151
37481
|
async function startHarnessBrokerServer(input) {
|
|
37152
37482
|
harnessPluginIdSchema.parse(input.adapter.harnessId);
|
|
37153
|
-
if (process.platform !== "win32" &&
|
|
37483
|
+
if (process.platform !== "win32" && path27.dirname(input.descriptorPath) !== path27.dirname(input.socketPath)) {
|
|
37154
37484
|
throw new Error("Harness broker descriptor and socket must share one private directory");
|
|
37155
37485
|
}
|
|
37156
37486
|
if (process.platform === "darwin" && Buffer.byteLength(input.socketPath) > 103) {
|
|
37157
37487
|
throw new Error("Harness broker Unix socket path is too long for macOS");
|
|
37158
37488
|
}
|
|
37159
|
-
await privateDirectory(
|
|
37489
|
+
await privateDirectory(path27.dirname(input.descriptorPath));
|
|
37160
37490
|
await assertNoLiveDescriptor(input.descriptorPath);
|
|
37161
37491
|
if (process.platform !== "win32")
|
|
37162
37492
|
await prepareUnixSocketPath(input.socketPath);
|