@codexhost/cli-darwin-x64 0.9.1 → 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 +304 -197
- package/app/host-runtime.mjs +1163 -666
- package/app/plugins/antigravity/plugin.mjs +73 -3
- package/app/plugins/claude-code/plugin.mjs +446 -48
- package/app/plugins/codebuddy/plugin.mjs +159 -6
- package/app/plugins/cursor-cli/plugin.mjs +207 -53
- package/app/plugins/deepseek-harness/plugin.mjs +89 -21
- package/app/plugins/enabled.json +2 -1
- package/app/plugins/grok/plugin.mjs +449 -160
- package/app/plugins/hermes/plugin.mjs +217 -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 +312 -65
- package/app/plugins/omp/plugin.mjs +313 -67
- package/app/plugins/opencode/plugin.mjs +73 -3
- package/app/plugins/pi/plugin.mjs +3029 -1671
- package/app/plugins/qoder/plugin.mjs +334 -187
- package/app/plugins/qoder-cn/plugin.mjs +334 -187
- package/app/plugins/workbuddy/plugin.mjs +158 -6
- package/app/renderer-extension.js +5580 -3301
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +0 -0
- package/package.json +1 -1
- package/licenses/opencodex-LICENSE.txt +0 -21
package/app/host-runtime.mjs
CHANGED
|
@@ -2278,7 +2278,7 @@ var require_websocket = __commonJS({
|
|
|
2278
2278
|
var http = __require("http");
|
|
2279
2279
|
var net5 = __require("net");
|
|
2280
2280
|
var tls = __require("tls");
|
|
2281
|
-
var { randomBytes: randomBytes4, createHash:
|
|
2281
|
+
var { randomBytes: randomBytes4, createHash: createHash11 } = __require("crypto");
|
|
2282
2282
|
var { Duplex: Duplex2, Readable } = __require("stream");
|
|
2283
2283
|
var { URL: URL2 } = __require("url");
|
|
2284
2284
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -2946,7 +2946,7 @@ var require_websocket = __commonJS({
|
|
|
2946
2946
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
2947
2947
|
return;
|
|
2948
2948
|
}
|
|
2949
|
-
const digest2 =
|
|
2949
|
+
const digest2 = createHash11("sha1").update(key + GUID).digest("base64");
|
|
2950
2950
|
if (res.headers["sec-websocket-accept"] !== digest2) {
|
|
2951
2951
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
2952
2952
|
return;
|
|
@@ -3315,7 +3315,7 @@ var require_websocket_server = __commonJS({
|
|
|
3315
3315
|
var EventEmitter = __require("events");
|
|
3316
3316
|
var http = __require("http");
|
|
3317
3317
|
var { Duplex: Duplex2 } = __require("stream");
|
|
3318
|
-
var { createHash:
|
|
3318
|
+
var { createHash: createHash11 } = __require("crypto");
|
|
3319
3319
|
var extension2 = require_extension();
|
|
3320
3320
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
3321
3321
|
var subprotocol2 = require_subprotocol();
|
|
@@ -3622,7 +3622,7 @@ var require_websocket_server = __commonJS({
|
|
|
3622
3622
|
);
|
|
3623
3623
|
}
|
|
3624
3624
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
3625
|
-
const digest2 =
|
|
3625
|
+
const digest2 = createHash11("sha1").update(key + GUID).digest("base64");
|
|
3626
3626
|
const headers = [
|
|
3627
3627
|
"HTTP/1.1 101 Switching Protocols",
|
|
3628
3628
|
"Upgrade: websocket",
|
|
@@ -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
|
}
|
|
@@ -19726,6 +19726,62 @@ function date4(params) {
|
|
|
19726
19726
|
// node_modules/zod/v4/classic/external.js
|
|
19727
19727
|
config(en_default());
|
|
19728
19728
|
|
|
19729
|
+
// packages/shared-contracts/dist/credential-imports.js
|
|
19730
|
+
var credentialSourceSchema = external_exports.object({
|
|
19731
|
+
id: external_exports.string().min(1).max(256),
|
|
19732
|
+
harnessId: external_exports.string().min(1),
|
|
19733
|
+
label: external_exports.string().min(1).max(512),
|
|
19734
|
+
provider: external_exports.enum(["openai-codex", "xai"])
|
|
19735
|
+
}).strict();
|
|
19736
|
+
var credentialImportNameSchema = external_exports.string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
19737
|
+
var credentialImportRecordSchema = external_exports.object({
|
|
19738
|
+
name: credentialImportNameSchema,
|
|
19739
|
+
source: credentialSourceSchema,
|
|
19740
|
+
importedAt: external_exports.string()
|
|
19741
|
+
}).strict();
|
|
19742
|
+
var credentialImportsRequestSchema = external_exports.discriminatedUnion("action", [
|
|
19743
|
+
external_exports.object({ action: external_exports.literal("list") }).strict(),
|
|
19744
|
+
external_exports.object({
|
|
19745
|
+
action: external_exports.literal("import"),
|
|
19746
|
+
sourceId: external_exports.string().min(1).max(256),
|
|
19747
|
+
name: credentialImportNameSchema,
|
|
19748
|
+
confirmed: external_exports.literal(true)
|
|
19749
|
+
}).strict(),
|
|
19750
|
+
external_exports.object({
|
|
19751
|
+
action: external_exports.literal("reimport"),
|
|
19752
|
+
sourceId: external_exports.string().min(1).max(256),
|
|
19753
|
+
name: credentialImportNameSchema,
|
|
19754
|
+
confirmed: external_exports.literal(true)
|
|
19755
|
+
}).strict(),
|
|
19756
|
+
external_exports.object({
|
|
19757
|
+
action: external_exports.literal("remove"),
|
|
19758
|
+
name: credentialImportNameSchema,
|
|
19759
|
+
confirmed: external_exports.literal(true)
|
|
19760
|
+
}).strict()
|
|
19761
|
+
]);
|
|
19762
|
+
var credentialOtherLoginSchema = external_exports.object({
|
|
19763
|
+
provider: external_exports.string().min(1).max(128),
|
|
19764
|
+
type: external_exports.enum(["oauth", "api_key", "unknown"]),
|
|
19765
|
+
/** Best-effort account label (e.g. the email in a Codex token), derived locally when present. */
|
|
19766
|
+
label: external_exports.string().min(1).max(512).optional(),
|
|
19767
|
+
/** Recognized credential vendor, derived from the OAuth token issuer. Absent when unknown. */
|
|
19768
|
+
vendor: external_exports.enum(["openai-codex", "xai"]).optional()
|
|
19769
|
+
}).strict();
|
|
19770
|
+
var credentialImportsResultSchema = external_exports.object({
|
|
19771
|
+
sources: external_exports.array(credentialSourceSchema),
|
|
19772
|
+
targets: external_exports.array(external_exports.object({
|
|
19773
|
+
harnessId: external_exports.string(),
|
|
19774
|
+
providers: external_exports.array(external_exports.enum(["openai-codex", "xai"])),
|
|
19775
|
+
imports: external_exports.array(credentialImportRecordSchema),
|
|
19776
|
+
others: external_exports.array(credentialOtherLoginSchema).default([])
|
|
19777
|
+
}).strict())
|
|
19778
|
+
}).strict();
|
|
19779
|
+
var credentialImportsParamsSchema = external_exports.object({
|
|
19780
|
+
targetHarnessId: external_exports.string().min(1).max(128).optional(),
|
|
19781
|
+
request: credentialImportsRequestSchema
|
|
19782
|
+
}).strict();
|
|
19783
|
+
var CREDENTIAL_IMPORTS_METHOD = "codexhost/harness/credential-imports";
|
|
19784
|
+
|
|
19729
19785
|
// packages/shared-contracts/dist/version.js
|
|
19730
19786
|
var WORKSPACE_CONTRACT_VERSION = 1;
|
|
19731
19787
|
|
|
@@ -20466,10 +20522,21 @@ var harnessCommandDescriptorSchema = external_exports.object({
|
|
|
20466
20522
|
invocation: commandInvocationSchema,
|
|
20467
20523
|
label: commandLabelSchema,
|
|
20468
20524
|
description: commandDescriptionSchema.optional(),
|
|
20469
|
-
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()
|
|
20470
20531
|
}).strict();
|
|
20471
20532
|
var harnessCommandCatalogSchema = external_exports.object({
|
|
20472
|
-
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()
|
|
20473
20540
|
}).strict().superRefine((catalog, context) => {
|
|
20474
20541
|
const ids = /* @__PURE__ */ new Set();
|
|
20475
20542
|
for (const [index, command] of catalog.commands.entries()) {
|
|
@@ -20483,7 +20550,11 @@ var harnessCommandCatalogSchema = external_exports.object({
|
|
|
20483
20550
|
ids.add(command.id);
|
|
20484
20551
|
}
|
|
20485
20552
|
});
|
|
20486
|
-
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();
|
|
20487
20558
|
var threadCommandsInspectParamsSchema = external_exports.object({
|
|
20488
20559
|
threadId: hostThreadIdSchema
|
|
20489
20560
|
}).strict();
|
|
@@ -20627,9 +20698,360 @@ var updateStatusResultSchema = external_exports.strictObject({
|
|
|
20627
20698
|
status: updateStatusSchema.nullable()
|
|
20628
20699
|
});
|
|
20629
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
|
+
|
|
20630
20736
|
// packages/shared-contracts/dist/index.js
|
|
20631
20737
|
var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
|
|
20632
20738
|
|
|
20739
|
+
// packages/host-runtime/src/account/codex-credential-export.ts
|
|
20740
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
20741
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
20742
|
+
import os from "node:os";
|
|
20743
|
+
import path5 from "node:path";
|
|
20744
|
+
async function readCodexCredential(environment) {
|
|
20745
|
+
try {
|
|
20746
|
+
const home = environment.CODEX_HOME ?? path5.join(environment.HOME ?? os.homedir(), ".codex");
|
|
20747
|
+
const auth = JSON.parse(await readFile4(path5.join(home, "auth.json"), "utf8"));
|
|
20748
|
+
if (auth.OPENAI_API_KEY || auth.auth_mode && auth.auth_mode !== "chatgpt") return [];
|
|
20749
|
+
const t = auth.tokens;
|
|
20750
|
+
if (!t || ![t.access_token, t.refresh_token, t.account_id].every(
|
|
20751
|
+
(v) => typeof v === "string" && v.length
|
|
20752
|
+
))
|
|
20753
|
+
return [];
|
|
20754
|
+
const claims = JSON.parse(Buffer.from(t.access_token.split(".")[1], "base64url").toString());
|
|
20755
|
+
if (claims.client_id !== "app_EMoamEEZ73f0CkXaXp7hrann" || !Number.isFinite(claims.exp * 1e3))
|
|
20756
|
+
return [];
|
|
20757
|
+
const account = claims["https://api.openai.com/auth"]?.chatgpt_account_id;
|
|
20758
|
+
if (account !== t.account_id) return [];
|
|
20759
|
+
let email3;
|
|
20760
|
+
try {
|
|
20761
|
+
email3 = JSON.parse(Buffer.from(t.id_token.split(".")[1], "base64url").toString()).email;
|
|
20762
|
+
} catch {
|
|
20763
|
+
}
|
|
20764
|
+
const identity = `${t.account_id}:${claims.sub ?? ""}`;
|
|
20765
|
+
return [
|
|
20766
|
+
{
|
|
20767
|
+
source: {
|
|
20768
|
+
id: `codex:${createHash2("sha256").update(identity).digest("hex")}`,
|
|
20769
|
+
harnessId: "codex",
|
|
20770
|
+
provider: "openai-codex",
|
|
20771
|
+
label: typeof email3 === "string" && email3 ? email3 : "Codex"
|
|
20772
|
+
},
|
|
20773
|
+
oauth: {
|
|
20774
|
+
access: t.access_token,
|
|
20775
|
+
refresh: t.refresh_token,
|
|
20776
|
+
expires: claims.exp * 1e3,
|
|
20777
|
+
accountId: t.account_id
|
|
20778
|
+
}
|
|
20779
|
+
}
|
|
20780
|
+
];
|
|
20781
|
+
} catch {
|
|
20782
|
+
return [];
|
|
20783
|
+
}
|
|
20784
|
+
}
|
|
20785
|
+
|
|
20786
|
+
// packages/host-runtime/src/credential-imports.ts
|
|
20787
|
+
async function handleCredentialImports(params, adapters, environment) {
|
|
20788
|
+
const input = credentialImportsParamsSchema.parse(params);
|
|
20789
|
+
const installed = [...adapters];
|
|
20790
|
+
const sources = await readCodexCredential(environment);
|
|
20791
|
+
for (const adapter of installed) {
|
|
20792
|
+
if (adapter.credentialExport) sources.push(...await adapter.credentialExport.read());
|
|
20793
|
+
}
|
|
20794
|
+
const request = input.request;
|
|
20795
|
+
if (request.action !== "list") {
|
|
20796
|
+
const target = installed.find((a) => a.harnessId === input.targetHarnessId)?.credentialImports;
|
|
20797
|
+
if (!target) throw new Error("Target Harness does not support credential imports");
|
|
20798
|
+
if (request.action === "remove") await target.remove(request.name);
|
|
20799
|
+
else {
|
|
20800
|
+
const source = sources.find((s) => s.source.id === request.sourceId);
|
|
20801
|
+
if (!source || !target.providers.includes(source.source.provider))
|
|
20802
|
+
throw new Error("Source login changed or is unavailable; refresh and confirm again");
|
|
20803
|
+
if (request.action === "reimport") await target.reimport(request.name, source);
|
|
20804
|
+
else await target.add(request.name, source);
|
|
20805
|
+
}
|
|
20806
|
+
}
|
|
20807
|
+
const targets = [];
|
|
20808
|
+
for (const adapter of installed) {
|
|
20809
|
+
if (!adapter.credentialImports) continue;
|
|
20810
|
+
try {
|
|
20811
|
+
targets.push({
|
|
20812
|
+
harnessId: adapter.harnessId,
|
|
20813
|
+
providers: [...adapter.credentialImports.providers],
|
|
20814
|
+
imports: await adapter.credentialImports.list(),
|
|
20815
|
+
others: await listOthers(adapter)
|
|
20816
|
+
});
|
|
20817
|
+
} catch {
|
|
20818
|
+
}
|
|
20819
|
+
}
|
|
20820
|
+
return credentialImportsResultSchema.parse({ sources: sources.map((s) => s.source), targets });
|
|
20821
|
+
}
|
|
20822
|
+
async function listOthers(adapter) {
|
|
20823
|
+
try {
|
|
20824
|
+
return await adapter.credentialImports?.listOthers?.() ?? [];
|
|
20825
|
+
} catch {
|
|
20826
|
+
return [];
|
|
20827
|
+
}
|
|
20828
|
+
}
|
|
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
|
+
|
|
20633
21055
|
// packages/harness-adapter/dist/output-channel.js
|
|
20634
21056
|
var HarnessOutputChannel = class {
|
|
20635
21057
|
outputs;
|
|
@@ -20708,11 +21130,11 @@ var usageFields = /* @__PURE__ */ new Set([
|
|
|
20708
21130
|
"totalCredits",
|
|
20709
21131
|
"contextUsagePercent"
|
|
20710
21132
|
]);
|
|
20711
|
-
function
|
|
21133
|
+
function isRecord2(value2) {
|
|
20712
21134
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
20713
21135
|
}
|
|
20714
21136
|
function parseHostUsage(value2) {
|
|
20715
|
-
if (!
|
|
21137
|
+
if (!isRecord2(value2))
|
|
20716
21138
|
throw new Error("Harness Usage must be an object");
|
|
20717
21139
|
const keys = Object.keys(value2);
|
|
20718
21140
|
if (keys.length === 0)
|
|
@@ -20769,6 +21191,82 @@ function parseHostUsage(value2) {
|
|
|
20769
21191
|
return { ...value2 };
|
|
20770
21192
|
}
|
|
20771
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
|
+
|
|
20772
21270
|
// packages/harness-adapter/dist/index.js
|
|
20773
21271
|
var packageMetadata = {
|
|
20774
21272
|
name: "@codexhost/harness-adapter",
|
|
@@ -20777,10 +21275,10 @@ var packageMetadata = {
|
|
|
20777
21275
|
|
|
20778
21276
|
// packages/mapping-store/dist/mapping-store.js
|
|
20779
21277
|
import { execFileSync } from "node:child_process";
|
|
20780
|
-
import { randomUUID as
|
|
21278
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
20781
21279
|
import { constants } from "node:fs";
|
|
20782
|
-
import { copyFile as copyFile2, mkdir as
|
|
20783
|
-
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";
|
|
20784
21282
|
|
|
20785
21283
|
// packages/mapping-store/dist/records.js
|
|
20786
21284
|
var nonBlankTextSchema6 = external_exports.string().refine((value2) => value2.trim().length > 0, {
|
|
@@ -20931,7 +21429,7 @@ function systemErrorCode2(error51) {
|
|
|
20931
21429
|
}
|
|
20932
21430
|
async function exists(file2) {
|
|
20933
21431
|
try {
|
|
20934
|
-
await
|
|
21432
|
+
await stat2(file2);
|
|
20935
21433
|
return true;
|
|
20936
21434
|
} catch (error51) {
|
|
20937
21435
|
if (systemErrorCode2(error51) === "ENOENT")
|
|
@@ -21041,13 +21539,13 @@ var MappingStore = class {
|
|
|
21041
21539
|
#initialized = false;
|
|
21042
21540
|
#lockHandle = null;
|
|
21043
21541
|
constructor(options2) {
|
|
21044
|
-
this.#directory =
|
|
21045
|
-
this.#threadsDirectory =
|
|
21046
|
-
this.#delegationsDirectory =
|
|
21047
|
-
this.#backupsDirectory =
|
|
21048
|
-
this.#quarantineDirectory =
|
|
21049
|
-
this.#lockPath =
|
|
21050
|
-
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();
|
|
21051
21549
|
this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
|
|
21052
21550
|
this.#beforeReplace = options2.beforeReplace;
|
|
21053
21551
|
}
|
|
@@ -21055,18 +21553,18 @@ var MappingStore = class {
|
|
|
21055
21553
|
if (this.#initialized)
|
|
21056
21554
|
return;
|
|
21057
21555
|
await Promise.all([
|
|
21058
|
-
|
|
21059
|
-
|
|
21060
|
-
|
|
21061
|
-
|
|
21556
|
+
mkdir4(this.#threadsDirectory, { recursive: true }),
|
|
21557
|
+
mkdir4(this.#delegationsDirectory, { recursive: true }),
|
|
21558
|
+
mkdir4(this.#backupsDirectory, { recursive: true }),
|
|
21559
|
+
mkdir4(this.#quarantineDirectory, { recursive: true })
|
|
21062
21560
|
]);
|
|
21063
21561
|
await this.#acquireLock();
|
|
21064
21562
|
try {
|
|
21065
21563
|
await this.#cleanupResidue();
|
|
21066
21564
|
const names = (await readdir2(this.#threadsDirectory)).filter((name) => name.endsWith(".json"));
|
|
21067
21565
|
for (const name of names) {
|
|
21068
|
-
const primary =
|
|
21069
|
-
const backup =
|
|
21566
|
+
const primary = path7.join(this.#threadsDirectory, name);
|
|
21567
|
+
const backup = path7.join(this.#backupsDirectory, name);
|
|
21070
21568
|
let record3 = null;
|
|
21071
21569
|
try {
|
|
21072
21570
|
record3 = await this.#readRecord(primary, name);
|
|
@@ -21075,31 +21573,31 @@ var MappingStore = class {
|
|
|
21075
21573
|
record3 = await this.#readRecord(backup, name);
|
|
21076
21574
|
await this.#replaceFile(primary, record3, false);
|
|
21077
21575
|
} catch (backupError) {
|
|
21078
|
-
const quarantine =
|
|
21079
|
-
await
|
|
21576
|
+
const quarantine = path7.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
|
|
21577
|
+
await rename3(primary, quarantine).catch(() => void 0);
|
|
21080
21578
|
void primaryError;
|
|
21081
21579
|
void backupError;
|
|
21082
21580
|
continue;
|
|
21083
21581
|
}
|
|
21084
21582
|
}
|
|
21085
21583
|
if (record3.state === "creating" && !record3.nativeSessionRef) {
|
|
21086
|
-
await
|
|
21087
|
-
await
|
|
21584
|
+
await rm4(primary, { force: true });
|
|
21585
|
+
await rm4(backup, { force: true });
|
|
21088
21586
|
continue;
|
|
21089
21587
|
}
|
|
21090
21588
|
this.#records.set(record3.hostThreadId, record3);
|
|
21091
21589
|
}
|
|
21092
21590
|
const delegationNames = (await readdir2(this.#delegationsDirectory)).filter((name) => name.endsWith(".json"));
|
|
21093
21591
|
for (const name of delegationNames) {
|
|
21094
|
-
const file2 =
|
|
21592
|
+
const file2 = path7.join(this.#delegationsDirectory, name);
|
|
21095
21593
|
try {
|
|
21096
|
-
const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await
|
|
21594
|
+
const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await readFile6(file2, "utf8")));
|
|
21097
21595
|
if (`${parsed.delegationId}.json` !== name)
|
|
21098
21596
|
throw new Error("filename mismatch");
|
|
21099
21597
|
this.#delegations.set(parsed.delegationId, parsed);
|
|
21100
21598
|
} catch {
|
|
21101
|
-
const quarantine =
|
|
21102
|
-
await
|
|
21599
|
+
const quarantine = path7.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
|
|
21600
|
+
await rename3(file2, quarantine).catch(() => void 0);
|
|
21103
21601
|
}
|
|
21104
21602
|
}
|
|
21105
21603
|
this.#rebuildIndexes();
|
|
@@ -21197,7 +21695,7 @@ var MappingStore = class {
|
|
|
21197
21695
|
}
|
|
21198
21696
|
async removeDelegation(delegationId) {
|
|
21199
21697
|
this.#requireInitialized();
|
|
21200
|
-
await
|
|
21698
|
+
await rm4(this.#delegationPath(delegationId), { force: true });
|
|
21201
21699
|
this.#delegations.delete(delegationId);
|
|
21202
21700
|
this.#rebuildIndexes();
|
|
21203
21701
|
}
|
|
@@ -21370,8 +21868,8 @@ var MappingStore = class {
|
|
|
21370
21868
|
if (!this.#records.has(hostThreadId))
|
|
21371
21869
|
return;
|
|
21372
21870
|
await Promise.all([
|
|
21373
|
-
|
|
21374
|
-
|
|
21871
|
+
rm4(this.#recordPath(hostThreadId), { force: true }),
|
|
21872
|
+
rm4(this.#backupPath(hostThreadId), { force: true })
|
|
21375
21873
|
]);
|
|
21376
21874
|
this.#records.delete(hostThreadId);
|
|
21377
21875
|
this.#rebuildIndexes();
|
|
@@ -21384,9 +21882,9 @@ var MappingStore = class {
|
|
|
21384
21882
|
if (handle)
|
|
21385
21883
|
await handle.close().catch(() => void 0);
|
|
21386
21884
|
try {
|
|
21387
|
-
const current = JSON.parse(await
|
|
21885
|
+
const current = JSON.parse(await readFile6(this.#lockPath, "utf8"));
|
|
21388
21886
|
if (current.instanceId === this.#instanceId)
|
|
21389
|
-
await
|
|
21887
|
+
await rm4(this.#lockPath, { force: true });
|
|
21390
21888
|
} catch {
|
|
21391
21889
|
}
|
|
21392
21890
|
}
|
|
@@ -21453,11 +21951,11 @@ var MappingStore = class {
|
|
|
21453
21951
|
this.#rebuildIndexes();
|
|
21454
21952
|
}
|
|
21455
21953
|
async #replaceFile(target, record3, preserveBackup) {
|
|
21456
|
-
const temp = `${target}.tmp-${
|
|
21954
|
+
const temp = `${target}.tmp-${randomUUID3()}`;
|
|
21457
21955
|
let handle = null;
|
|
21458
21956
|
try {
|
|
21459
21957
|
await this.#beforeReplace?.(cloneRecord(record3));
|
|
21460
|
-
handle = await
|
|
21958
|
+
handle = await open4(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
21461
21959
|
await handle.writeFile(`${JSON.stringify(record3, null, 2)}
|
|
21462
21960
|
`, "utf8");
|
|
21463
21961
|
await handle.sync();
|
|
@@ -21466,10 +21964,10 @@ var MappingStore = class {
|
|
|
21466
21964
|
if (preserveBackup && await exists(target)) {
|
|
21467
21965
|
await copyFile2(target, this.#backupPath(record3.hostThreadId));
|
|
21468
21966
|
}
|
|
21469
|
-
await
|
|
21967
|
+
await rename3(temp, target);
|
|
21470
21968
|
} catch (error51) {
|
|
21471
21969
|
await handle?.close().catch(() => void 0);
|
|
21472
|
-
await
|
|
21970
|
+
await rm4(temp, { force: true }).catch(() => void 0);
|
|
21473
21971
|
if (error51 instanceof MappingStoreError)
|
|
21474
21972
|
throw error51;
|
|
21475
21973
|
throw new MappingStoreError("IO_ERROR", "Mapping Store atomic replacement failed", {
|
|
@@ -21479,19 +21977,19 @@ var MappingStore = class {
|
|
|
21479
21977
|
}
|
|
21480
21978
|
async #replaceDelegationFile(record3) {
|
|
21481
21979
|
const target = this.#delegationPath(record3.delegationId);
|
|
21482
|
-
const temp = `${target}.tmp-${
|
|
21980
|
+
const temp = `${target}.tmp-${randomUUID3()}`;
|
|
21483
21981
|
let handle = null;
|
|
21484
21982
|
try {
|
|
21485
|
-
handle = await
|
|
21983
|
+
handle = await open4(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
21486
21984
|
await handle.writeFile(`${JSON.stringify(record3, null, 2)}
|
|
21487
21985
|
`, "utf8");
|
|
21488
21986
|
await handle.sync();
|
|
21489
21987
|
await handle.close();
|
|
21490
21988
|
handle = null;
|
|
21491
|
-
await
|
|
21989
|
+
await rename3(temp, target);
|
|
21492
21990
|
} catch (error51) {
|
|
21493
21991
|
await handle?.close().catch(() => void 0);
|
|
21494
|
-
await
|
|
21992
|
+
await rm4(temp, { force: true }).catch(() => void 0);
|
|
21495
21993
|
if (error51 instanceof MappingStoreError)
|
|
21496
21994
|
throw error51;
|
|
21497
21995
|
throw new MappingStoreError("IO_ERROR", "Delegation atomic replacement failed", {
|
|
@@ -21500,7 +21998,7 @@ var MappingStore = class {
|
|
|
21500
21998
|
}
|
|
21501
21999
|
}
|
|
21502
22000
|
async #readRecord(file2, expectedName) {
|
|
21503
|
-
const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await
|
|
22001
|
+
const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await readFile6(file2, "utf8")));
|
|
21504
22002
|
if (!parsed.success) {
|
|
21505
22003
|
throw new MappingStoreError("INVALID_RECORD", "Mapping Store record is invalid", {
|
|
21506
22004
|
cause: parsed.error
|
|
@@ -21518,15 +22016,15 @@ var MappingStore = class {
|
|
|
21518
22016
|
readdir2(this.#directory)
|
|
21519
22017
|
]);
|
|
21520
22018
|
await Promise.all([
|
|
21521
|
-
...threadNames.filter((name) => name.includes(".tmp-")).map((name) =>
|
|
21522
|
-
...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 })),
|
|
21523
22021
|
// Renamed aside by #acquireLock; nothing reads them back, and they accumulate one per run.
|
|
21524
|
-
...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 }))
|
|
21525
22023
|
]);
|
|
21526
22024
|
}
|
|
21527
22025
|
async #acquireLock() {
|
|
21528
22026
|
const attempt = async () => {
|
|
21529
|
-
const handle = await
|
|
22027
|
+
const handle = await open4(this.#lockPath, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
21530
22028
|
const lock = {
|
|
21531
22029
|
pid: process.pid,
|
|
21532
22030
|
instanceId: this.#instanceId,
|
|
@@ -21548,13 +22046,13 @@ var MappingStore = class {
|
|
|
21548
22046
|
}
|
|
21549
22047
|
let existing = {};
|
|
21550
22048
|
try {
|
|
21551
|
-
existing = JSON.parse(await
|
|
22049
|
+
existing = JSON.parse(await readFile6(this.#lockPath, "utf8"));
|
|
21552
22050
|
} catch {
|
|
21553
22051
|
}
|
|
21554
22052
|
if (typeof existing.pid === "number" && lockOwnerIsLive(existing)) {
|
|
21555
22053
|
throw new MappingStoreError("STORE_LOCKED", "Another codexhost process owns Mapping Store");
|
|
21556
22054
|
}
|
|
21557
|
-
await
|
|
22055
|
+
await rename3(this.#lockPath, `${this.#lockPath}.stale-${this.#now().getTime()}`).catch(() => void 0);
|
|
21558
22056
|
try {
|
|
21559
22057
|
this.#lockHandle = await attempt();
|
|
21560
22058
|
} catch (error51) {
|
|
@@ -21622,13 +22120,13 @@ var MappingStore = class {
|
|
|
21622
22120
|
await next;
|
|
21623
22121
|
}
|
|
21624
22122
|
#recordPath(hostThreadId) {
|
|
21625
|
-
return
|
|
22123
|
+
return path7.join(this.#threadsDirectory, `${hostThreadId}.json`);
|
|
21626
22124
|
}
|
|
21627
22125
|
#delegationPath(delegationId) {
|
|
21628
|
-
return
|
|
22126
|
+
return path7.join(this.#delegationsDirectory, `${delegationId}.json`);
|
|
21629
22127
|
}
|
|
21630
22128
|
#backupPath(hostThreadId) {
|
|
21631
|
-
return
|
|
22129
|
+
return path7.join(this.#backupsDirectory, `${hostThreadId}.json`);
|
|
21632
22130
|
}
|
|
21633
22131
|
#requireInitialized() {
|
|
21634
22132
|
if (!this.#initialized) {
|
|
@@ -21648,7 +22146,7 @@ var TITLE_MAX_LENGTH = 150;
|
|
|
21648
22146
|
var DESCRIPTION_MAX_LENGTH = 500;
|
|
21649
22147
|
var SERVER_NAME_MAX_LENGTH = 80;
|
|
21650
22148
|
var ELLIPSIS = "…";
|
|
21651
|
-
function
|
|
22149
|
+
function isRecord3(value2) {
|
|
21652
22150
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
21653
22151
|
}
|
|
21654
22152
|
function boundedText(value2, field, maxLength) {
|
|
@@ -21702,7 +22200,7 @@ function responseError(message) {
|
|
|
21702
22200
|
function responsePersist(value2) {
|
|
21703
22201
|
if (value2 === void 0 || value2 === null)
|
|
21704
22202
|
return null;
|
|
21705
|
-
if (!
|
|
22203
|
+
if (!isRecord3(value2) || Object.keys(value2).length !== 1 || value2.persist !== "session" && value2.persist !== "always") {
|
|
21706
22204
|
throw responseError("contains malformed persist metadata");
|
|
21707
22205
|
}
|
|
21708
22206
|
return value2.persist;
|
|
@@ -21748,7 +22246,7 @@ function projectCodexApprovalRequest(input) {
|
|
|
21748
22246
|
},
|
|
21749
22247
|
denyResponse,
|
|
21750
22248
|
parseResponse(result) {
|
|
21751
|
-
if (!
|
|
22249
|
+
if (!isRecord3(result) || typeof result.action !== "string") {
|
|
21752
22250
|
throw responseError("missing action");
|
|
21753
22251
|
}
|
|
21754
22252
|
if (Object.keys(result).some((key) => key !== "action" && key !== "content" && key !== "_meta")) {
|
|
@@ -21756,7 +22254,7 @@ function projectCodexApprovalRequest(input) {
|
|
|
21756
22254
|
}
|
|
21757
22255
|
const selectedPersist = responsePersist(result._meta);
|
|
21758
22256
|
if (result.action === "accept") {
|
|
21759
|
-
if ("content" in result && (!
|
|
22257
|
+
if ("content" in result && (!isRecord3(result.content) || Object.keys(result.content).length !== 0)) {
|
|
21760
22258
|
throw responseError("contains non-empty accepted content");
|
|
21761
22259
|
}
|
|
21762
22260
|
if (selectedPersist === "session") {
|
|
@@ -21816,7 +22314,7 @@ function projectApprovalChoices(input) {
|
|
|
21816
22314
|
},
|
|
21817
22315
|
denyResponse,
|
|
21818
22316
|
parseResponse(result) {
|
|
21819
|
-
if (!
|
|
22317
|
+
if (!isRecord3(result) || typeof result.action !== "string")
|
|
21820
22318
|
throw responseError("missing action");
|
|
21821
22319
|
if (Object.keys(result).some((key) => !["action", "content", "_meta"].includes(key))) {
|
|
21822
22320
|
throw responseError("contains unreviewed fields");
|
|
@@ -21831,7 +22329,7 @@ function projectApprovalChoices(input) {
|
|
|
21831
22329
|
return denyResponse;
|
|
21832
22330
|
}
|
|
21833
22331
|
const content = result.content;
|
|
21834
|
-
if (result.action !== "accept" || !
|
|
22332
|
+
if (result.action !== "accept" || !isRecord3(content) || Object.keys(content).length !== 1 || !interaction.actions.some(({ id: id2 }) => id2 === content.actionId)) {
|
|
21835
22333
|
throw responseError("contains an undeclared approval choice");
|
|
21836
22334
|
}
|
|
21837
22335
|
return { type: "approval", actionId: content.actionId };
|
|
@@ -21840,7 +22338,7 @@ function projectApprovalChoices(input) {
|
|
|
21840
22338
|
}
|
|
21841
22339
|
|
|
21842
22340
|
// packages/protocol-core/dist/codex-question.js
|
|
21843
|
-
function
|
|
22341
|
+
function isRecord4(value2) {
|
|
21844
22342
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
21845
22343
|
}
|
|
21846
22344
|
function responseError2(message) {
|
|
@@ -21909,7 +22407,7 @@ function projectCodexQuestionRequest(input) {
|
|
|
21909
22407
|
}
|
|
21910
22408
|
},
|
|
21911
22409
|
parseResponse(result) {
|
|
21912
|
-
if (!
|
|
22410
|
+
if (!isRecord4(result) || !isRecord4(result.answers)) {
|
|
21913
22411
|
throw responseError2("missing answers object");
|
|
21914
22412
|
}
|
|
21915
22413
|
const rawAnswers = result.answers;
|
|
@@ -21922,7 +22420,7 @@ function projectCodexQuestionRequest(input) {
|
|
|
21922
22420
|
const question = interaction.questions.find(({ id: id2 }) => id2 === questionId);
|
|
21923
22421
|
if (!question)
|
|
21924
22422
|
throw responseError2("contains an unknown Question ID");
|
|
21925
|
-
if (!
|
|
22423
|
+
if (!isRecord4(answerValue) || !Array.isArray(answerValue.answers)) {
|
|
21926
22424
|
throw responseError2("answer entry has no answers array");
|
|
21927
22425
|
}
|
|
21928
22426
|
const values = answerValue.answers;
|
|
@@ -22004,7 +22502,7 @@ function projectCodexThreadUsage(input) {
|
|
|
22004
22502
|
}
|
|
22005
22503
|
|
|
22006
22504
|
// packages/protocol-core/dist/codex-native-usage.js
|
|
22007
|
-
function
|
|
22505
|
+
function isRecord5(value2) {
|
|
22008
22506
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
22009
22507
|
}
|
|
22010
22508
|
function nonNegativeSafeInteger(value2) {
|
|
@@ -22034,20 +22532,20 @@ function addBreakdown(target, source) {
|
|
|
22034
22532
|
}
|
|
22035
22533
|
}
|
|
22036
22534
|
function observeCodexTokenUsage(value2) {
|
|
22037
|
-
if (!
|
|
22535
|
+
if (!isRecord5(value2) || value2.method !== "thread/tokenUsage/updated")
|
|
22038
22536
|
return null;
|
|
22039
22537
|
const params = value2.params;
|
|
22040
|
-
if (!
|
|
22538
|
+
if (!isRecord5(params))
|
|
22041
22539
|
return null;
|
|
22042
22540
|
const threadId2 = hostThreadIdSchema.safeParse(params.threadId);
|
|
22043
22541
|
const turnId = hostTurnIdSchema.safeParse(params.turnId);
|
|
22044
22542
|
if (!threadId2.success || !turnId.success)
|
|
22045
22543
|
return null;
|
|
22046
22544
|
const tokenUsage = params.tokenUsage;
|
|
22047
|
-
if (!
|
|
22545
|
+
if (!isRecord5(tokenUsage))
|
|
22048
22546
|
return null;
|
|
22049
|
-
const total =
|
|
22050
|
-
const last =
|
|
22547
|
+
const total = isRecord5(tokenUsage.total) ? tokenUsage.total : void 0;
|
|
22548
|
+
const last = isRecord5(tokenUsage.last) ? tokenUsage.last : void 0;
|
|
22051
22549
|
const usage = {};
|
|
22052
22550
|
addBreakdown(usage, total);
|
|
22053
22551
|
const contextUsedTokens = nonNegativeSafeInteger(last?.totalTokens);
|
|
@@ -22072,7 +22570,7 @@ function observeCodexTokenUsage(value2) {
|
|
|
22072
22570
|
}
|
|
22073
22571
|
}
|
|
22074
22572
|
function parseRateLimitWindow(value2) {
|
|
22075
|
-
if (!
|
|
22573
|
+
if (!isRecord5(value2))
|
|
22076
22574
|
return null;
|
|
22077
22575
|
const usedPercent = finitePercent(value2.usedPercent);
|
|
22078
22576
|
const windowDurationMins = nonNegativeSafeInteger(value2.windowDurationMins);
|
|
@@ -22083,7 +22581,7 @@ function parseRateLimitWindow(value2) {
|
|
|
22083
22581
|
return { usedPercent, windowDurationMins, ...resetsAt !== void 0 ? { resetsAt } : {} };
|
|
22084
22582
|
}
|
|
22085
22583
|
function parseRateLimitCandidate(value2, options2 = {}) {
|
|
22086
|
-
if (!
|
|
22584
|
+
if (!isRecord5(value2))
|
|
22087
22585
|
return null;
|
|
22088
22586
|
if (options2.genericOnly && value2.limitId !== void 0 && value2.limitId !== null && value2.limitId !== "codex") {
|
|
22089
22587
|
return null;
|
|
@@ -22093,16 +22591,16 @@ function parseRateLimitCandidate(value2, options2 = {}) {
|
|
|
22093
22591
|
return primary || secondary ? { primary, secondary } : null;
|
|
22094
22592
|
}
|
|
22095
22593
|
function rateLimitCandidates(value2) {
|
|
22096
|
-
if (!
|
|
22594
|
+
if (!isRecord5(value2))
|
|
22097
22595
|
return [];
|
|
22098
|
-
const result =
|
|
22099
|
-
if (!
|
|
22596
|
+
const result = isRecord5(value2.result) ? value2.result : value2;
|
|
22597
|
+
if (!isRecord5(result))
|
|
22100
22598
|
return [];
|
|
22101
22599
|
const candidates = [];
|
|
22102
22600
|
const base = parseRateLimitCandidate(result.rateLimits, { genericOnly: true });
|
|
22103
22601
|
if (base)
|
|
22104
22602
|
candidates.push(base);
|
|
22105
|
-
const notificationParams =
|
|
22603
|
+
const notificationParams = isRecord5(value2.params) ? value2.params : void 0;
|
|
22106
22604
|
const notificationSnapshot = parseRateLimitCandidate(notificationParams?.rateLimits, {
|
|
22107
22605
|
genericOnly: true
|
|
22108
22606
|
});
|
|
@@ -22146,14 +22644,14 @@ function parseAvailableCount(value2) {
|
|
|
22146
22644
|
return void 0;
|
|
22147
22645
|
}
|
|
22148
22646
|
function rateLimitResetCreditsSummary(value2) {
|
|
22149
|
-
if (!
|
|
22647
|
+
if (!isRecord5(value2))
|
|
22150
22648
|
return null;
|
|
22151
|
-
const result =
|
|
22152
|
-
const fromResult =
|
|
22649
|
+
const result = isRecord5(value2.result) ? value2.result : value2;
|
|
22650
|
+
const fromResult = isRecord5(result) && isRecord5(result.rateLimitResetCredits) ? result.rateLimitResetCredits : null;
|
|
22153
22651
|
if (fromResult)
|
|
22154
22652
|
return fromResult;
|
|
22155
|
-
const params =
|
|
22156
|
-
return
|
|
22653
|
+
const params = isRecord5(value2.params) ? value2.params : void 0;
|
|
22654
|
+
return isRecord5(params?.rateLimitResetCredits) ? params.rateLimitResetCredits : null;
|
|
22157
22655
|
}
|
|
22158
22656
|
function observeCodexRateLimitResetCredits(value2) {
|
|
22159
22657
|
const summary = rateLimitResetCreditsSummary(value2);
|
|
@@ -22165,7 +22663,7 @@ function observeCodexRateLimitResetCredits(value2) {
|
|
|
22165
22663
|
const expiresAtUnix = [];
|
|
22166
22664
|
if (Array.isArray(summary.credits)) {
|
|
22167
22665
|
for (const credit of summary.credits) {
|
|
22168
|
-
if (!
|
|
22666
|
+
if (!isRecord5(credit))
|
|
22169
22667
|
continue;
|
|
22170
22668
|
if (credit.status !== void 0 && credit.status !== "available")
|
|
22171
22669
|
continue;
|
|
@@ -22316,16 +22814,16 @@ var Diff = class {
|
|
|
22316
22814
|
}
|
|
22317
22815
|
}
|
|
22318
22816
|
}
|
|
22319
|
-
addToPath(
|
|
22320
|
-
const last =
|
|
22817
|
+
addToPath(path28, added, removed, oldPosInc, options2) {
|
|
22818
|
+
const last = path28.lastComponent;
|
|
22321
22819
|
if (last && !options2.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
22322
22820
|
return {
|
|
22323
|
-
oldPos:
|
|
22821
|
+
oldPos: path28.oldPos + oldPosInc,
|
|
22324
22822
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
22325
22823
|
};
|
|
22326
22824
|
} else {
|
|
22327
22825
|
return {
|
|
22328
|
-
oldPos:
|
|
22826
|
+
oldPos: path28.oldPos + oldPosInc,
|
|
22329
22827
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
22330
22828
|
};
|
|
22331
22829
|
}
|
|
@@ -22754,10 +23252,10 @@ function splitLines(text) {
|
|
|
22754
23252
|
}
|
|
22755
23253
|
|
|
22756
23254
|
// packages/protocol-core/dist/file-change-summary.js
|
|
22757
|
-
import
|
|
23255
|
+
import path8 from "node:path";
|
|
22758
23256
|
function filePathKey(file2, cwd) {
|
|
22759
23257
|
const windows = /^[a-z]:[/\\]/i.test(cwd) || /^[a-z]:[/\\]/i.test(file2);
|
|
22760
|
-
const paths = windows ?
|
|
23258
|
+
const paths = windows ? path8.win32 : path8.posix;
|
|
22761
23259
|
const resolved = paths.resolve(cwd, file2).replaceAll("\\", "/");
|
|
22762
23260
|
return windows ? resolved.toLowerCase() : resolved;
|
|
22763
23261
|
}
|
|
@@ -22908,11 +23406,11 @@ function itemStatus(outcome) {
|
|
|
22908
23406
|
return "inProgress";
|
|
22909
23407
|
return outcome.status === "succeeded" ? "completed" : "failed";
|
|
22910
23408
|
}
|
|
22911
|
-
function
|
|
23409
|
+
function isRecord6(value2) {
|
|
22912
23410
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
22913
23411
|
}
|
|
22914
23412
|
function nestedString(value2, keys, preserveText = false) {
|
|
22915
|
-
if (!
|
|
23413
|
+
if (!isRecord6(value2))
|
|
22916
23414
|
return void 0;
|
|
22917
23415
|
for (const key of keys) {
|
|
22918
23416
|
const field = value2[key];
|
|
@@ -23026,8 +23524,8 @@ function projectFileChangeKind(kind) {
|
|
|
23026
23524
|
return { type: kind };
|
|
23027
23525
|
}
|
|
23028
23526
|
function projectFileChanges(changes) {
|
|
23029
|
-
return changes.map(({ path:
|
|
23030
|
-
path:
|
|
23527
|
+
return changes.map(({ path: path28, kind, unifiedDiff }) => ({
|
|
23528
|
+
path: path28,
|
|
23031
23529
|
kind: projectFileChangeKind(kind),
|
|
23032
23530
|
diff: unifiedDiff
|
|
23033
23531
|
}));
|
|
@@ -23067,7 +23565,7 @@ function planFromTodoValue(value2) {
|
|
|
23067
23565
|
const record3 = unwrapToolRecord(value2);
|
|
23068
23566
|
if (!record3)
|
|
23069
23567
|
return planFromChecklistText(typeof value2 === "string" ? value2 : null);
|
|
23070
|
-
if (
|
|
23568
|
+
if (isRecord6(record3.TodosUpdated)) {
|
|
23071
23569
|
const nested = planFromTodoValue(record3.TodosUpdated);
|
|
23072
23570
|
if (nested)
|
|
23073
23571
|
return nested;
|
|
@@ -23082,7 +23580,7 @@ function planFromTodoValue(value2) {
|
|
|
23082
23580
|
plan.push({ step: entry.trim(), status: "pending" });
|
|
23083
23581
|
continue;
|
|
23084
23582
|
}
|
|
23085
|
-
if (!
|
|
23583
|
+
if (!isRecord6(entry))
|
|
23086
23584
|
continue;
|
|
23087
23585
|
const step = nestedString(entry, ["content", "step", "text", "title", "description", "task"]);
|
|
23088
23586
|
if (!step)
|
|
@@ -23137,7 +23635,7 @@ function unwrapToolRecord(value2) {
|
|
|
23137
23635
|
}
|
|
23138
23636
|
if (Array.isArray(value2))
|
|
23139
23637
|
return { todos: value2 };
|
|
23140
|
-
if (!
|
|
23638
|
+
if (!isRecord6(value2))
|
|
23141
23639
|
return null;
|
|
23142
23640
|
for (const wrapper of ["input", "arguments", "params"]) {
|
|
23143
23641
|
if (value2[wrapper] === void 0)
|
|
@@ -23927,7 +24425,7 @@ var CodexTurnProjector = class {
|
|
|
23927
24425
|
};
|
|
23928
24426
|
|
|
23929
24427
|
// packages/protocol-core/dist/thread-fork.js
|
|
23930
|
-
function
|
|
24428
|
+
function isRecord7(value2) {
|
|
23931
24429
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
23932
24430
|
}
|
|
23933
24431
|
function optionalText(params, name, options2 = {}) {
|
|
@@ -23950,7 +24448,7 @@ function optionalBoolean(params, name) {
|
|
|
23950
24448
|
function decodeThreadForkRequest(request) {
|
|
23951
24449
|
if (request.method !== "thread/fork")
|
|
23952
24450
|
return null;
|
|
23953
|
-
if (!
|
|
24451
|
+
if (!isRecord7(request.params))
|
|
23954
24452
|
throw new Error("thread/fork params must be an object");
|
|
23955
24453
|
const params = request.params;
|
|
23956
24454
|
const threadId2 = optionalText(params, "threadId");
|
|
@@ -23965,13 +24463,13 @@ function decodeThreadForkRequest(request) {
|
|
|
23965
24463
|
if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
|
|
23966
24464
|
throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
|
|
23967
24465
|
}
|
|
23968
|
-
const
|
|
24466
|
+
const path28 = optionalText(params, "path", { allowEmpty: true });
|
|
23969
24467
|
const ephemeral = optionalBoolean(params, "ephemeral");
|
|
23970
24468
|
return {
|
|
23971
24469
|
threadId: threadId2,
|
|
23972
24470
|
...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
|
|
23973
24471
|
...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
|
|
23974
|
-
...
|
|
24472
|
+
...path28 ? { path: path28 } : {},
|
|
23975
24473
|
...optionalField(params, "model"),
|
|
23976
24474
|
...optionalField(params, "modelProvider"),
|
|
23977
24475
|
...optionalField(params, "cwd"),
|
|
@@ -23986,7 +24484,7 @@ function decodeThreadForkRequest(request) {
|
|
|
23986
24484
|
function decodeThreadRevertRequest(request) {
|
|
23987
24485
|
if (request.method !== "thread/revert")
|
|
23988
24486
|
return null;
|
|
23989
|
-
if (!
|
|
24487
|
+
if (!isRecord7(request.params))
|
|
23990
24488
|
throw new Error("thread/revert params must be an object");
|
|
23991
24489
|
const { threadId: threadId2, beforeTurnId } = request.params;
|
|
23992
24490
|
if (typeof threadId2 !== "string" || threadId2.length === 0) {
|
|
@@ -24000,7 +24498,7 @@ function decodeThreadRevertRequest(request) {
|
|
|
24000
24498
|
function decodeThreadRollbackRequest(request) {
|
|
24001
24499
|
if (request.method !== "thread/rollback")
|
|
24002
24500
|
return null;
|
|
24003
|
-
if (!
|
|
24501
|
+
if (!isRecord7(request.params))
|
|
24004
24502
|
throw new Error("thread/rollback params must be an object");
|
|
24005
24503
|
const { threadId: threadId2, numTurns } = request.params;
|
|
24006
24504
|
if (typeof threadId2 !== "string" || threadId2.length === 0) {
|
|
@@ -24064,7 +24562,7 @@ function threadForkResult(thread, input) {
|
|
|
24064
24562
|
}
|
|
24065
24563
|
|
|
24066
24564
|
// packages/protocol-core/dist/thread-management.js
|
|
24067
|
-
import { createHash as
|
|
24565
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
24068
24566
|
var HOST_CURSOR_PREFIX = "codexhost:thread-list:v1:";
|
|
24069
24567
|
var MAX_CURSOR_LENGTH = 65536;
|
|
24070
24568
|
var DEFAULT_PAGE_SIZE = 25;
|
|
@@ -24097,13 +24595,13 @@ var THREAD_SOURCE_KINDS = /* @__PURE__ */ new Set([
|
|
|
24097
24595
|
"subAgentOther",
|
|
24098
24596
|
"unknown"
|
|
24099
24597
|
]);
|
|
24100
|
-
function
|
|
24598
|
+
function isRecord8(value2) {
|
|
24101
24599
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
24102
24600
|
}
|
|
24103
24601
|
function paramsObject(request, method) {
|
|
24104
24602
|
if (request.params === void 0 && method === "thread/list")
|
|
24105
24603
|
return {};
|
|
24106
|
-
if (!
|
|
24604
|
+
if (!isRecord8(request.params))
|
|
24107
24605
|
throw new Error(`${method} params must be an object`);
|
|
24108
24606
|
return request.params;
|
|
24109
24607
|
}
|
|
@@ -24161,7 +24659,7 @@ function decodeSortKey(value2) {
|
|
|
24161
24659
|
return value2;
|
|
24162
24660
|
}
|
|
24163
24661
|
function queryFingerprint(value2) {
|
|
24164
|
-
return
|
|
24662
|
+
return createHash4("sha256").update(JSON.stringify(value2)).digest("hex");
|
|
24165
24663
|
}
|
|
24166
24664
|
function cursorPayload(value2) {
|
|
24167
24665
|
return {
|
|
@@ -24175,7 +24673,7 @@ function cursorPayload(value2) {
|
|
|
24175
24673
|
};
|
|
24176
24674
|
}
|
|
24177
24675
|
function parseCursorPayload(value2) {
|
|
24178
|
-
if (!
|
|
24676
|
+
if (!isRecord8(value2) || value2.formatVersion !== 1)
|
|
24179
24677
|
throw new Error("Host cursor is invalid");
|
|
24180
24678
|
const { queryFingerprint: fingerprint, sortDirection: sortDirection2, officialCursor, officialDone } = value2;
|
|
24181
24679
|
const { externalAnchor: externalAnchor2, externalDone } = value2;
|
|
@@ -24184,7 +24682,7 @@ function parseCursorPayload(value2) {
|
|
|
24184
24682
|
}
|
|
24185
24683
|
let anchor = null;
|
|
24186
24684
|
if (externalAnchor2 !== null) {
|
|
24187
|
-
if (!
|
|
24685
|
+
if (!isRecord8(externalAnchor2) || !Number.isSafeInteger(externalAnchor2.timestamp) || typeof externalAnchor2.threadId !== "string" || externalAnchor2.threadId.length === 0) {
|
|
24188
24686
|
throw new Error("Host cursor is invalid");
|
|
24189
24687
|
}
|
|
24190
24688
|
anchor = {
|
|
@@ -24307,7 +24805,7 @@ function decodeThreadMetadataUpdateRequest(request) {
|
|
|
24307
24805
|
if (params.gitInfo === null) {
|
|
24308
24806
|
gitInfo = null;
|
|
24309
24807
|
} else if (params.gitInfo !== void 0) {
|
|
24310
|
-
if (!
|
|
24808
|
+
if (!isRecord8(params.gitInfo)) {
|
|
24311
24809
|
throw new Error("thread/metadata/update params.gitInfo must be an object or null");
|
|
24312
24810
|
}
|
|
24313
24811
|
gitInfo = {};
|
|
@@ -24335,7 +24833,7 @@ function optionalCursor(value2, name) {
|
|
|
24335
24833
|
return value2;
|
|
24336
24834
|
}
|
|
24337
24835
|
function decodeOfficialThreadListPage(value2) {
|
|
24338
|
-
if (!
|
|
24836
|
+
if (!isRecord8(value2) || !Array.isArray(value2.data) || value2.data.some((row) => !isRecord8(row))) {
|
|
24339
24837
|
throw new Error("Official thread/list response is invalid");
|
|
24340
24838
|
}
|
|
24341
24839
|
return {
|
|
@@ -25147,22 +25645,22 @@ var HarnessAccountInspectionCache = class {
|
|
|
25147
25645
|
};
|
|
25148
25646
|
|
|
25149
25647
|
// packages/host-runtime/src/app-server-host.ts
|
|
25150
|
-
import { createHash as
|
|
25151
|
-
import
|
|
25152
|
-
import
|
|
25648
|
+
import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
|
|
25649
|
+
import os5 from "node:os";
|
|
25650
|
+
import path15 from "node:path";
|
|
25153
25651
|
|
|
25154
25652
|
// packages/host-runtime/src/external-thread-fork.ts
|
|
25155
25653
|
import nodePath from "node:path";
|
|
25156
25654
|
|
|
25157
25655
|
// packages/host-runtime/src/external-thread-repository.ts
|
|
25158
|
-
import { randomUUID as
|
|
25159
|
-
import
|
|
25160
|
-
import
|
|
25656
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
25657
|
+
import os3 from "node:os";
|
|
25658
|
+
import path9 from "node:path";
|
|
25161
25659
|
|
|
25162
25660
|
// packages/host-runtime/src/external-subagent-threads.ts
|
|
25163
|
-
import { createHash as
|
|
25661
|
+
import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypto";
|
|
25164
25662
|
function childCreateRequest(parent, nativeRef, id2) {
|
|
25165
|
-
const key =
|
|
25663
|
+
const key = createHash5("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
|
|
25166
25664
|
return `subagent:${key}`;
|
|
25167
25665
|
}
|
|
25168
25666
|
function subagentMaterializer(store, parent, previousParent) {
|
|
@@ -25235,7 +25733,7 @@ function subagentMaterializer(store, parent, previousParent) {
|
|
|
25235
25733
|
return rebind(existing, parent);
|
|
25236
25734
|
}
|
|
25237
25735
|
const provisional = existing ?? await store.createProvisional({
|
|
25238
|
-
hostThreadId: hostThreadIdSchema.parse(
|
|
25736
|
+
hostThreadId: hostThreadIdSchema.parse(randomUUID4()),
|
|
25239
25737
|
createRequestId,
|
|
25240
25738
|
harnessId: parent.harnessId,
|
|
25241
25739
|
cwd: parent.cwd,
|
|
@@ -25297,8 +25795,8 @@ function sameMapping(left, right) {
|
|
|
25297
25795
|
}
|
|
25298
25796
|
function defaultMappingStoreDirectory(environment) {
|
|
25299
25797
|
const dataDirectory = environment.CODEXHOST_DATA_DIR;
|
|
25300
|
-
return
|
|
25301
|
-
dataDirectory ?
|
|
25798
|
+
return path9.join(
|
|
25799
|
+
dataDirectory ? path9.resolve(dataDirectory) : path9.join(os3.homedir(), ".codexhost"),
|
|
25302
25800
|
"mapping-store"
|
|
25303
25801
|
);
|
|
25304
25802
|
}
|
|
@@ -25395,7 +25893,7 @@ var ExternalThreadRepository = class {
|
|
|
25395
25893
|
throw new Error("Derived Snapshot identity does not belong to its Native Session");
|
|
25396
25894
|
}
|
|
25397
25895
|
return {
|
|
25398
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
25896
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
|
|
25399
25897
|
nativeTurnRef: turn.nativeTurnRef,
|
|
25400
25898
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
25401
25899
|
};
|
|
@@ -25515,7 +26013,7 @@ var ExternalThreadRepository = class {
|
|
|
25515
26013
|
const aligned = snapshot.turns.map((turn) => {
|
|
25516
26014
|
const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
|
|
25517
26015
|
const mapping = existing ?? {
|
|
25518
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
26016
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
|
|
25519
26017
|
nativeTurnRef: turn.nativeTurnRef,
|
|
25520
26018
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
25521
26019
|
};
|
|
@@ -25542,8 +26040,8 @@ var ExternalThreadRepository = class {
|
|
|
25542
26040
|
};
|
|
25543
26041
|
function createExternalThreadRecordInput(input) {
|
|
25544
26042
|
return {
|
|
25545
|
-
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(
|
|
25546
|
-
createRequestId: input.createRequestId ??
|
|
26043
|
+
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID5()),
|
|
26044
|
+
createRequestId: input.createRequestId ?? randomUUID5(),
|
|
25547
26045
|
harnessId: input.harnessId,
|
|
25548
26046
|
cwd: input.cwd,
|
|
25549
26047
|
...input.title ? { title: input.title } : {},
|
|
@@ -25704,6 +26202,7 @@ async function executeExternalThreadFork(input) {
|
|
|
25704
26202
|
return { ok: false, error: mapExternalThreadHarnessError(opened.error, "fork") };
|
|
25705
26203
|
}
|
|
25706
26204
|
const session = opened.value;
|
|
26205
|
+
const inheritedPermissionModeId = await inheritSourcePermissionMode(source, session);
|
|
25707
26206
|
try {
|
|
25708
26207
|
const derivedNativeRef = session.initialState.nativeRef;
|
|
25709
26208
|
if (!derivedNativeRef || derivedNativeRef.nativeSessionId === nativeSessionRef.nativeSessionId) {
|
|
@@ -25731,7 +26230,8 @@ async function executeExternalThreadFork(input) {
|
|
|
25731
26230
|
sessionId: source.sessionId,
|
|
25732
26231
|
thread,
|
|
25733
26232
|
turns: aligned.turns,
|
|
25734
|
-
...snapshot.value.state ? { restoredState: snapshot.value.state } : {}
|
|
26233
|
+
...snapshot.value.state ? { restoredState: snapshot.value.state } : {},
|
|
26234
|
+
...inheritedPermissionModeId ? { requestedPermissionModeId: inheritedPermissionModeId } : {}
|
|
25735
26235
|
});
|
|
25736
26236
|
return {
|
|
25737
26237
|
ok: true,
|
|
@@ -25749,6 +26249,23 @@ async function executeExternalThreadFork(input) {
|
|
|
25749
26249
|
};
|
|
25750
26250
|
}
|
|
25751
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
|
+
}
|
|
25752
26269
|
|
|
25753
26270
|
// packages/host-runtime/src/harness-session-import.ts
|
|
25754
26271
|
function fixedError(code, message) {
|
|
@@ -27313,9 +27830,12 @@ var ExternalTurnSteering = class {
|
|
|
27313
27830
|
if (!cancelled.ok) throw new ExternalSteerError(-32074, cancelled.error.message);
|
|
27314
27831
|
const outcome = await Promise.race([terminal2.promise, failure.promise]);
|
|
27315
27832
|
clearTimeout(timeout);
|
|
27316
|
-
|
|
27317
|
-
|
|
27318
|
-
|
|
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();
|
|
27319
27839
|
if (outcome.status === "failed") throw new ExternalSteerError(-32074, outcome.error.message);
|
|
27320
27840
|
if (thread.persistenceError)
|
|
27321
27841
|
throw new ExternalSteerError(
|
|
@@ -27325,7 +27845,7 @@ var ExternalTurnSteering = class {
|
|
|
27325
27845
|
if (thread.running || thread.activeTurnId) {
|
|
27326
27846
|
throw new ExternalSteerError(-32072, "Another External Turn started before replacement");
|
|
27327
27847
|
}
|
|
27328
|
-
return await start(input.text);
|
|
27848
|
+
return await start(input.text, assertActive);
|
|
27329
27849
|
} finally {
|
|
27330
27850
|
clearTimeout(timeout);
|
|
27331
27851
|
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
@@ -27333,16 +27853,98 @@ var ExternalTurnSteering = class {
|
|
|
27333
27853
|
}
|
|
27334
27854
|
};
|
|
27335
27855
|
|
|
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
|
+
|
|
27336
27938
|
// packages/host-runtime/src/harness-delegation-coordinator.ts
|
|
27337
|
-
import { createHash as
|
|
27338
|
-
import
|
|
27939
|
+
import { createHash as createHash7, randomUUID as randomUUID6 } from "node:crypto";
|
|
27940
|
+
import path11 from "node:path";
|
|
27339
27941
|
|
|
27340
27942
|
// packages/host-runtime/src/delegation-snapshot.ts
|
|
27341
|
-
import { createHash as
|
|
27943
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
27342
27944
|
var CURSOR_PREFIX = "codexhost:thread-messages:v1:";
|
|
27343
27945
|
var DEFAULT_MESSAGE_LIMIT = 25;
|
|
27344
27946
|
var MAX_MESSAGE_LIMIT = 100;
|
|
27345
|
-
function
|
|
27947
|
+
function isRecord9(value2) {
|
|
27346
27948
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
27347
27949
|
}
|
|
27348
27950
|
function stringValue(value2) {
|
|
@@ -27351,12 +27953,12 @@ function stringValue(value2) {
|
|
|
27351
27953
|
function textFromUserItem(item) {
|
|
27352
27954
|
if (!Array.isArray(item.content)) return "";
|
|
27353
27955
|
return item.content.flatMap(
|
|
27354
|
-
(part) =>
|
|
27956
|
+
(part) => isRecord9(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []
|
|
27355
27957
|
).join("\n");
|
|
27356
27958
|
}
|
|
27357
27959
|
function threadStatus(value2, running) {
|
|
27358
27960
|
if (running) return "running";
|
|
27359
|
-
if (
|
|
27961
|
+
if (isRecord9(value2)) {
|
|
27360
27962
|
if (value2.type === "active") return "running";
|
|
27361
27963
|
}
|
|
27362
27964
|
return "completed";
|
|
@@ -27373,10 +27975,10 @@ function allVisibleMessages(turns) {
|
|
|
27373
27975
|
const turnId = stringValue(turn.id);
|
|
27374
27976
|
if (!turnId || !Array.isArray(turn.items)) continue;
|
|
27375
27977
|
const agentItems = turn.items.filter(
|
|
27376
|
-
(item) =>
|
|
27978
|
+
(item) => isRecord9(item) && item.type === "agentMessage"
|
|
27377
27979
|
);
|
|
27378
27980
|
for (const item of turn.items) {
|
|
27379
|
-
if (!
|
|
27981
|
+
if (!isRecord9(item)) continue;
|
|
27380
27982
|
const id2 = stringValue(item.id);
|
|
27381
27983
|
if (!id2) continue;
|
|
27382
27984
|
if (item.type === "userMessage") {
|
|
@@ -27392,7 +27994,7 @@ function allVisibleMessages(turns) {
|
|
|
27392
27994
|
return messages;
|
|
27393
27995
|
}
|
|
27394
27996
|
function cursorFingerprint(threadId2) {
|
|
27395
|
-
return
|
|
27997
|
+
return createHash6("sha256").update(threadId2).digest("hex");
|
|
27396
27998
|
}
|
|
27397
27999
|
function encodeCursor(threadId2, offset) {
|
|
27398
28000
|
const payload = JSON.stringify({ version: 1, fingerprint: cursorFingerprint(threadId2), offset });
|
|
@@ -27451,7 +28053,7 @@ function projectDelegationThreadSnapshot(input) {
|
|
|
27451
28053
|
const progress = latestTurnMessages.filter((message) => message.phase !== "final" && message.text.trim()).map(({ id: id2, turnId, text }) => ({ id: id2, turnId, text }));
|
|
27452
28054
|
const result = input.running ? { availability: "pending" } : final ? { availability: "available", text: final.text } : {
|
|
27453
28055
|
availability: "unavailable",
|
|
27454
|
-
...
|
|
28056
|
+
...isRecord9(latestTurn?.error) && typeof latestTurn.error.message === "string" ? { message: latestTurn.error.message } : {}
|
|
27455
28057
|
};
|
|
27456
28058
|
const offset = options2.view === "messages" ? decodeCursor(input.threadId, options2.cursor) : visible.length;
|
|
27457
28059
|
const page = options2.view === "messages" ? [] : void 0;
|
|
@@ -27487,10 +28089,10 @@ function terminal(status) {
|
|
|
27487
28089
|
return status === "completed" || status === "failed" || status === "interrupted";
|
|
27488
28090
|
}
|
|
27489
28091
|
function taskDigest(input) {
|
|
27490
|
-
return
|
|
28092
|
+
return createHash7("sha256").update(
|
|
27491
28093
|
JSON.stringify({
|
|
27492
28094
|
task: input.task,
|
|
27493
|
-
cwd:
|
|
28095
|
+
cwd: path11.resolve(input.cwd),
|
|
27494
28096
|
modelId: input.model?.id ?? null,
|
|
27495
28097
|
thinkingOptionId: input.thinkingOptionId ?? null
|
|
27496
28098
|
})
|
|
@@ -27561,7 +28163,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27561
28163
|
return {
|
|
27562
28164
|
harnessId: input.harnessId,
|
|
27563
28165
|
inspection: await adapter.inspect({
|
|
27564
|
-
...input.cwd ? { cwd:
|
|
28166
|
+
...input.cwd ? { cwd: path11.resolve(input.cwd) } : {},
|
|
27565
28167
|
...input.refresh !== void 0 ? { refresh: input.refresh } : {}
|
|
27566
28168
|
})
|
|
27567
28169
|
};
|
|
@@ -27575,7 +28177,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27575
28177
|
const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
|
|
27576
28178
|
return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
|
|
27577
28179
|
}
|
|
27578
|
-
const startInput = { ...input, parentThreadId, cwd:
|
|
28180
|
+
const startInput = { ...input, parentThreadId, cwd: path11.resolve(selectedCwd) };
|
|
27579
28181
|
if (!this.#adapters.has(input.harnessId)) {
|
|
27580
28182
|
throw new DelegationControlError(
|
|
27581
28183
|
"HARNESS_NOT_FOUND",
|
|
@@ -27615,10 +28217,10 @@ var HarnessDelegationCoordinator = class {
|
|
|
27615
28217
|
});
|
|
27616
28218
|
this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
|
|
27617
28219
|
}
|
|
27618
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
27619
|
-
const childThreadId = hostThreadIdSchema.parse(
|
|
27620
|
-
const turnId = hostTurnIdSchema.parse(
|
|
27621
|
-
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();
|
|
27622
28224
|
let record3 = await this.#repository.createProvisional(
|
|
27623
28225
|
createExternalThreadRecordInput({
|
|
27624
28226
|
hostThreadId: childThreadId,
|
|
@@ -27750,7 +28352,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
27750
28352
|
if (thread.running || thread.activeTurnId) {
|
|
27751
28353
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
27752
28354
|
}
|
|
27753
|
-
const turnId = hostTurnIdSchema.parse(
|
|
28355
|
+
const turnId = hostTurnIdSchema.parse(randomUUID6());
|
|
27754
28356
|
try {
|
|
27755
28357
|
await this.#startExternalTurn(thread, input.message, turnId);
|
|
27756
28358
|
} catch (error51) {
|
|
@@ -28004,7 +28606,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
28004
28606
|
|
|
28005
28607
|
// packages/host-runtime/src/harness-plugin-loader.ts
|
|
28006
28608
|
import { readdir as readdir3, realpath as realpath2 } from "node:fs/promises";
|
|
28007
|
-
import
|
|
28609
|
+
import path13 from "node:path";
|
|
28008
28610
|
import { pathToFileURL } from "node:url";
|
|
28009
28611
|
|
|
28010
28612
|
// packages/host-runtime/src/harness-plugin-registry.ts
|
|
@@ -28041,25 +28643,25 @@ var HarnessPluginRegistry = class {
|
|
|
28041
28643
|
};
|
|
28042
28644
|
|
|
28043
28645
|
// packages/host-runtime/src/plugin-files.ts
|
|
28044
|
-
import { open as
|
|
28045
|
-
import
|
|
28646
|
+
import { open as open5, realpath, stat as stat3 } from "node:fs/promises";
|
|
28647
|
+
import path12 from "node:path";
|
|
28046
28648
|
function inside(root, candidate) {
|
|
28047
|
-
const relative =
|
|
28048
|
-
return relative !== "" && !
|
|
28649
|
+
const relative = path12.relative(root, candidate);
|
|
28650
|
+
return relative !== "" && !path12.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path12.sep}`);
|
|
28049
28651
|
}
|
|
28050
28652
|
async function pluginResourcePath(root, relative) {
|
|
28051
|
-
if (
|
|
28653
|
+
if (path12.isAbsolute(relative) || !inside(root, path12.resolve(root, relative))) {
|
|
28052
28654
|
throw new Error("Plugin resource escapes its root");
|
|
28053
28655
|
}
|
|
28054
|
-
const resolved = await realpath(
|
|
28055
|
-
if (!inside(root, resolved) || !(await
|
|
28656
|
+
const resolved = await realpath(path12.resolve(root, relative));
|
|
28657
|
+
if (!inside(root, resolved) || !(await stat3(resolved)).isFile()) {
|
|
28056
28658
|
throw new Error("Plugin resource must be a regular file inside its root");
|
|
28057
28659
|
}
|
|
28058
28660
|
return resolved;
|
|
28059
28661
|
}
|
|
28060
28662
|
async function readPluginFile(file2, maximum) {
|
|
28061
|
-
if (!(await
|
|
28062
|
-
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");
|
|
28063
28665
|
try {
|
|
28064
28666
|
const info = await handle.stat();
|
|
28065
28667
|
if (!info.isFile() || info.size > maximum) throw new Error("Plugin resource exceeds its limit");
|
|
@@ -28213,7 +28815,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
28213
28815
|
const enabledIds = /* @__PURE__ */ new Set();
|
|
28214
28816
|
const roots = /* @__PURE__ */ new Set();
|
|
28215
28817
|
for (const configuredRoot of options2.roots) {
|
|
28216
|
-
if (!
|
|
28818
|
+
if (!path13.isAbsolute(configuredRoot)) {
|
|
28217
28819
|
diagnose({ code: "invalidRoot" });
|
|
28218
28820
|
continue;
|
|
28219
28821
|
}
|
|
@@ -28243,7 +28845,7 @@ async function loadHarnessPlugins(options2) {
|
|
|
28243
28845
|
for (const directory of directories) {
|
|
28244
28846
|
try {
|
|
28245
28847
|
const file2 = await pluginResourcePath(root, `${directory.name}/manifest.json`);
|
|
28246
|
-
const pluginRoot = await realpath2(
|
|
28848
|
+
const pluginRoot = await realpath2(path13.join(root, directory.name));
|
|
28247
28849
|
await pluginResourcePath(pluginRoot, "manifest.json");
|
|
28248
28850
|
const manifest = harnessPluginManifestSchema.parse(
|
|
28249
28851
|
JSON.parse(
|
|
@@ -28338,28 +28940,28 @@ async function loadHarnessPlugins(options2) {
|
|
|
28338
28940
|
}
|
|
28339
28941
|
|
|
28340
28942
|
// packages/host-runtime/src/harness-launch-settings.ts
|
|
28341
|
-
import { randomUUID as
|
|
28342
|
-
import { mkdir as
|
|
28343
|
-
import
|
|
28344
|
-
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";
|
|
28345
28947
|
var HarnessLaunchSettingsStore = class {
|
|
28346
28948
|
#directory;
|
|
28347
28949
|
#initial = /* @__PURE__ */ new Map();
|
|
28348
28950
|
constructor(environment) {
|
|
28349
|
-
this.#directory =
|
|
28350
|
-
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"),
|
|
28351
28953
|
"harness-launch-settings"
|
|
28352
28954
|
);
|
|
28353
28955
|
}
|
|
28354
28956
|
#file(id2) {
|
|
28355
|
-
return
|
|
28957
|
+
return path14.join(this.#directory, `${harnessPluginIdSchema.parse(id2)}.json`);
|
|
28356
28958
|
}
|
|
28357
28959
|
async #read(id2) {
|
|
28358
28960
|
try {
|
|
28359
28961
|
const value2 = harnessLaunchPathSchema.parse(
|
|
28360
|
-
JSON.parse(await
|
|
28962
|
+
JSON.parse(await readFile7(this.#file(id2), "utf8"))
|
|
28361
28963
|
);
|
|
28362
|
-
if (!
|
|
28964
|
+
if (!path14.isAbsolute(value2)) throw new Error("Expected an absolute entrypoint path");
|
|
28363
28965
|
return value2;
|
|
28364
28966
|
} catch (error51) {
|
|
28365
28967
|
if (error51 && typeof error51 === "object" && "code" in error51 && error51.code === "ENOENT")
|
|
@@ -28385,22 +28987,22 @@ var HarnessLaunchSettingsStore = class {
|
|
|
28385
28987
|
const initial = await this.initialCommand(id2) ?? null;
|
|
28386
28988
|
const file2 = this.#file(id2);
|
|
28387
28989
|
if (value2 === null) {
|
|
28388
|
-
await
|
|
28990
|
+
await rm5(file2, { force: true });
|
|
28389
28991
|
} else {
|
|
28390
28992
|
value2 = harnessLaunchPathSchema.parse(value2);
|
|
28391
|
-
if (!
|
|
28993
|
+
if (!path14.isAbsolute(value2))
|
|
28392
28994
|
throw new Error("Use an absolute entrypoint path without arguments");
|
|
28393
|
-
const metadata = await
|
|
28995
|
+
const metadata = await stat4(value2).catch(() => void 0);
|
|
28394
28996
|
if (!metadata?.isDirectory() && !metadata?.isFile())
|
|
28395
28997
|
throw new Error("The installation path must be an existing directory on this Host");
|
|
28396
|
-
await
|
|
28397
|
-
const temporary = `${file2}.${
|
|
28998
|
+
await mkdir5(this.#directory, { recursive: true, mode: 448 });
|
|
28999
|
+
const temporary = `${file2}.${randomUUID7()}.tmp`;
|
|
28398
29000
|
try {
|
|
28399
29001
|
await writeFile3(temporary, `${JSON.stringify(value2)}
|
|
28400
29002
|
`, { mode: 384, flag: "wx" });
|
|
28401
|
-
await
|
|
29003
|
+
await rename4(temporary, file2);
|
|
28402
29004
|
} finally {
|
|
28403
|
-
await
|
|
29005
|
+
await rm5(temporary, { force: true });
|
|
28404
29006
|
}
|
|
28405
29007
|
}
|
|
28406
29008
|
return { path: value2, restartRequired: value2 !== initial };
|
|
@@ -28563,11 +29165,11 @@ function spawnOfficialAppServerConnection(input) {
|
|
|
28563
29165
|
}
|
|
28564
29166
|
|
|
28565
29167
|
// packages/host-runtime/src/account/codex-account-control.ts
|
|
28566
|
-
function
|
|
29168
|
+
function isRecord10(value2) {
|
|
28567
29169
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
28568
29170
|
}
|
|
28569
29171
|
function currentCodexAccountFromOfficialRead(result) {
|
|
28570
|
-
if (!
|
|
29172
|
+
if (!isRecord10(result) || !isRecord10(result.account) || result.account.type !== "chatgpt") {
|
|
28571
29173
|
return null;
|
|
28572
29174
|
}
|
|
28573
29175
|
const email3 = external_exports.string().email().max(320).safeParse(result.account.email);
|
|
@@ -28597,13 +29199,13 @@ var SingleNativeCodexAccount = class {
|
|
|
28597
29199
|
};
|
|
28598
29200
|
|
|
28599
29201
|
// packages/host-runtime/src/codex-runtime/official-runtime-owner.ts
|
|
28600
|
-
import { randomUUID as
|
|
29202
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
28601
29203
|
|
|
28602
29204
|
// packages/host-runtime/src/official-request-broker.ts
|
|
28603
|
-
import { randomUUID as
|
|
29205
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28604
29206
|
var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
|
|
28605
29207
|
var MAX_RETIRED_IDS = 1024;
|
|
28606
|
-
function
|
|
29208
|
+
function isRecord11(value2) {
|
|
28607
29209
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
28608
29210
|
}
|
|
28609
29211
|
var OfficialRequestBroker = class {
|
|
@@ -28616,7 +29218,7 @@ var OfficialRequestBroker = class {
|
|
|
28616
29218
|
constructor(input) {
|
|
28617
29219
|
this.#send = input.send;
|
|
28618
29220
|
this.#timeoutMs = input.timeoutMs ?? 3e4;
|
|
28619
|
-
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${
|
|
29221
|
+
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID8()}`);
|
|
28620
29222
|
}
|
|
28621
29223
|
get pendingCount() {
|
|
28622
29224
|
return this.#pending.size;
|
|
@@ -28646,7 +29248,7 @@ var OfficialRequestBroker = class {
|
|
|
28646
29248
|
});
|
|
28647
29249
|
}
|
|
28648
29250
|
handle(value2) {
|
|
28649
|
-
if (!
|
|
29251
|
+
if (!isRecord11(value2) || typeof value2.id !== "string") return false;
|
|
28650
29252
|
const pending = this.#pending.get(value2.id);
|
|
28651
29253
|
if (!pending) return this.#retired.has(value2.id);
|
|
28652
29254
|
clearTimeout(pending.timeout);
|
|
@@ -28970,7 +29572,7 @@ var OfficialRuntimeOwner = class {
|
|
|
28970
29572
|
}
|
|
28971
29573
|
#attach(role, output, onBackendStopped) {
|
|
28972
29574
|
const client = {
|
|
28973
|
-
id:
|
|
29575
|
+
id: randomUUID9(),
|
|
28974
29576
|
role,
|
|
28975
29577
|
output,
|
|
28976
29578
|
...onBackendStopped ? { onBackendStopped } : {},
|
|
@@ -29128,7 +29730,7 @@ var OfficialRuntimeOwner = class {
|
|
|
29128
29730
|
if (!object4(value2)) return client.output(event);
|
|
29129
29731
|
if (typeof value2.id === "string" || typeof value2.id === "number") {
|
|
29130
29732
|
if (typeof value2.method === "string") {
|
|
29131
|
-
const id2 = `codexhost:server:${client.id}:${event.generation}:${
|
|
29733
|
+
const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID9()}`;
|
|
29132
29734
|
client.serverRequests.set(id2, value2.id);
|
|
29133
29735
|
const projected = { ...value2, id: id2 };
|
|
29134
29736
|
return client.output({
|
|
@@ -29366,11 +29968,11 @@ function createOwnedConnectionBackend(factory) {
|
|
|
29366
29968
|
}
|
|
29367
29969
|
|
|
29368
29970
|
// packages/host-runtime/src/route-observation.ts
|
|
29369
|
-
function
|
|
29971
|
+
function isRecord12(value2) {
|
|
29370
29972
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29371
29973
|
}
|
|
29372
29974
|
function classifyThreadPurpose(request) {
|
|
29373
|
-
return
|
|
29975
|
+
return isRecord12(request.params) && request.params.ephemeral === true ? "ephemeral" : "conversation";
|
|
29374
29976
|
}
|
|
29375
29977
|
var RequestRouteObservationTracker = class {
|
|
29376
29978
|
#nextCreateOrdinal = 0;
|
|
@@ -29395,13 +29997,13 @@ var RequestRouteObservationTracker = class {
|
|
|
29395
29997
|
this.#createByThreadId.set(threadId2, tracked);
|
|
29396
29998
|
}
|
|
29397
29999
|
bindOfficialResponse(response) {
|
|
29398
|
-
if (!
|
|
30000
|
+
if (!isRecord12(response) || !("id" in response)) return;
|
|
29399
30001
|
const tracked = this.#pendingByRequestId.get(response.id);
|
|
29400
30002
|
if (!tracked) return;
|
|
29401
30003
|
this.#pendingByRequestId.delete(response.id);
|
|
29402
30004
|
const result = response.result;
|
|
29403
|
-
const thread =
|
|
29404
|
-
if (
|
|
30005
|
+
const thread = isRecord12(result) ? result.thread : null;
|
|
30006
|
+
if (isRecord12(thread) && typeof thread.id === "string") {
|
|
29405
30007
|
this.#createByThreadId.set(thread.id, tracked);
|
|
29406
30008
|
}
|
|
29407
30009
|
}
|
|
@@ -29523,25 +30125,25 @@ function resolveExternalSessionTreeIds(records) {
|
|
|
29523
30125
|
const resolve = (start) => {
|
|
29524
30126
|
const cached2 = resolved.get(start.hostThreadId);
|
|
29525
30127
|
if (cached2) return cached2;
|
|
29526
|
-
const
|
|
30128
|
+
const path28 = [];
|
|
29527
30129
|
const visited = /* @__PURE__ */ new Set();
|
|
29528
30130
|
let current = start;
|
|
29529
30131
|
while (true) {
|
|
29530
30132
|
const known = resolved.get(current.hostThreadId);
|
|
29531
30133
|
if (known) {
|
|
29532
|
-
for (const record3 of
|
|
30134
|
+
for (const record3 of path28) resolved.set(record3.hostThreadId, known);
|
|
29533
30135
|
return known;
|
|
29534
30136
|
}
|
|
29535
30137
|
if (visited.has(current.hostThreadId)) {
|
|
29536
30138
|
throw new Error("External Thread Fork tree contains a cycle");
|
|
29537
30139
|
}
|
|
29538
30140
|
visited.add(current.hostThreadId);
|
|
29539
|
-
|
|
30141
|
+
path28.push(current);
|
|
29540
30142
|
const sourceId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
|
|
29541
30143
|
const source = sourceId ? byId.get(sourceId) : void 0;
|
|
29542
30144
|
if (!source) {
|
|
29543
30145
|
const root = current.hostThreadId;
|
|
29544
|
-
for (const record3 of
|
|
30146
|
+
for (const record3 of path28) resolved.set(record3.hostThreadId, root);
|
|
29545
30147
|
return root;
|
|
29546
30148
|
}
|
|
29547
30149
|
current = source;
|
|
@@ -29595,11 +30197,11 @@ var OfficialThreadListError = class extends Error {
|
|
|
29595
30197
|
}
|
|
29596
30198
|
rpcError;
|
|
29597
30199
|
};
|
|
29598
|
-
function
|
|
30200
|
+
function isRecord13(value2) {
|
|
29599
30201
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29600
30202
|
}
|
|
29601
30203
|
function officialThreadListPageFromResponse(response) {
|
|
29602
|
-
if (
|
|
30204
|
+
if (isRecord13(response.error)) {
|
|
29603
30205
|
if (!Number.isSafeInteger(response.error.code) || typeof response.error.message !== "string") {
|
|
29604
30206
|
throw new Error("Official thread/list error response is invalid");
|
|
29605
30207
|
}
|
|
@@ -29767,14 +30369,14 @@ var THREAD_USAGE_UPDATED_METHOD = "codexhost/thread/usage/updated";
|
|
|
29767
30369
|
function delay3(milliseconds) {
|
|
29768
30370
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
29769
30371
|
}
|
|
29770
|
-
function
|
|
30372
|
+
function isRecord14(value2) {
|
|
29771
30373
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
29772
30374
|
}
|
|
29773
30375
|
function isCreditsAdapter(adapter) {
|
|
29774
30376
|
return typeof adapter.credits === "function";
|
|
29775
30377
|
}
|
|
29776
30378
|
function projectAccountCredits(value2) {
|
|
29777
|
-
if (!
|
|
30379
|
+
if (!isRecord14(value2)) return null;
|
|
29778
30380
|
const rest = { ...value2 };
|
|
29779
30381
|
delete rest.fetchedAt;
|
|
29780
30382
|
const parsed = accountCreditsSnapshotSchema.safeParse(rest);
|
|
@@ -29897,12 +30499,12 @@ function classifyCreateRequestRoute(request, defaultAgent) {
|
|
|
29897
30499
|
};
|
|
29898
30500
|
}
|
|
29899
30501
|
function requestObject(request) {
|
|
29900
|
-
if (!
|
|
30502
|
+
if (!isRecord14(request.params)) throw new Error(`${request.method} params must be an object`);
|
|
29901
30503
|
return request.params;
|
|
29902
30504
|
}
|
|
29903
30505
|
function requestText(params) {
|
|
29904
30506
|
if (!Array.isArray(params.input)) throw new Error("turn/start input must be an array");
|
|
29905
|
-
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");
|
|
29906
30508
|
if (!text) throw new Error("turn/start must contain text input");
|
|
29907
30509
|
return text;
|
|
29908
30510
|
}
|
|
@@ -29956,6 +30558,7 @@ var AppServerHost = class {
|
|
|
29956
30558
|
#accountInspections = new HarnessAccountInspectionCache();
|
|
29957
30559
|
#externalRuntime;
|
|
29958
30560
|
#externalSteering = new ExternalTurnSteering();
|
|
30561
|
+
#liveCommandCache = new LiveCommandCatalogCache();
|
|
29959
30562
|
#repository;
|
|
29960
30563
|
#pendingDesktopApprovals = /* @__PURE__ */ new Map();
|
|
29961
30564
|
#pendingDesktopQuestions = /* @__PURE__ */ new Map();
|
|
@@ -29997,7 +30600,7 @@ var AppServerHost = class {
|
|
|
29997
30600
|
this.#launchSettings = new HarnessLaunchSettingsStore(
|
|
29998
30601
|
this.#options.pluginContext?.environment ?? environment
|
|
29999
30602
|
);
|
|
30000
|
-
const permanentHome =
|
|
30603
|
+
const permanentHome = path15.resolve(environment.CODEX_HOME ?? path15.join(os5.homedir(), ".codex"));
|
|
30001
30604
|
this.#ownsOfficialRuntimeScope = options2.officialRuntimeScope === void 0;
|
|
30002
30605
|
this.#officialRuntimeScope = options2.officialRuntimeScope ?? new OfficialRuntimeScope({
|
|
30003
30606
|
diagnosticOutput: this.#options.diagnosticOutput,
|
|
@@ -30010,7 +30613,8 @@ var AppServerHost = class {
|
|
|
30010
30613
|
...officialEnvironment(environment),
|
|
30011
30614
|
CODEX_HOME: permanentHome
|
|
30012
30615
|
},
|
|
30013
|
-
...this.#options.spawnOfficial ? { spawnOfficial: this.#options.spawnOfficial } : {}
|
|
30616
|
+
...this.#options.spawnOfficial ? { spawnOfficial: this.#options.spawnOfficial } : {},
|
|
30617
|
+
...this.#options.officialCloseTimeoutMs === void 0 ? {} : { closeTimeoutMs: this.#options.officialCloseTimeoutMs }
|
|
30014
30618
|
})
|
|
30015
30619
|
)
|
|
30016
30620
|
});
|
|
@@ -30258,12 +30862,12 @@ var AppServerHost = class {
|
|
|
30258
30862
|
for (const resolve of waiters) resolve();
|
|
30259
30863
|
}
|
|
30260
30864
|
#observeOfficialTurnStartResponse(value2) {
|
|
30261
|
-
if (!
|
|
30865
|
+
if (!isRecord14(value2) || !("id" in value2)) return;
|
|
30262
30866
|
const threadId2 = this.#pendingOfficialTurnStarts.get(value2.id);
|
|
30263
30867
|
if (!threadId2) return;
|
|
30264
30868
|
this.#pendingOfficialTurnStarts.delete(value2.id);
|
|
30265
|
-
const result =
|
|
30266
|
-
const turn = result &&
|
|
30869
|
+
const result = isRecord14(value2.result) ? value2.result : null;
|
|
30870
|
+
const turn = result && isRecord14(result.turn) ? result.turn : null;
|
|
30267
30871
|
if (turn && typeof turn.id === "string") {
|
|
30268
30872
|
this.#activeOfficialTurns.set(threadId2, turn.id);
|
|
30269
30873
|
}
|
|
@@ -30277,7 +30881,7 @@ var AppServerHost = class {
|
|
|
30277
30881
|
async #forwardDesktop() {
|
|
30278
30882
|
for await (const frame of readLfFrames(this.#options.desktopInput)) {
|
|
30279
30883
|
const parsed = parseJsonFrame(frame);
|
|
30280
|
-
if (
|
|
30884
|
+
if (isRecord14(parsed) && parsed.method === "initialized" && !("id" in parsed)) {
|
|
30281
30885
|
continue;
|
|
30282
30886
|
}
|
|
30283
30887
|
if (await this.#handleDesktopApprovalResponse(parsed)) continue;
|
|
@@ -30301,7 +30905,7 @@ var AppServerHost = class {
|
|
|
30301
30905
|
}
|
|
30302
30906
|
continue;
|
|
30303
30907
|
}
|
|
30304
|
-
const threadId2 =
|
|
30908
|
+
const threadId2 = isRecord14(request.params) && typeof request.params.threadId === "string" ? request.params.threadId : void 0;
|
|
30305
30909
|
this.#dispatchDesktopRequest(
|
|
30306
30910
|
() => this.#desktopRequests.run(
|
|
30307
30911
|
threadId2,
|
|
@@ -30346,6 +30950,32 @@ var AppServerHost = class {
|
|
|
30346
30950
|
this.#dispatchDesktopRequest(() => this.#handleCodexAccountRequest(request));
|
|
30347
30951
|
return;
|
|
30348
30952
|
}
|
|
30953
|
+
if (request.method === CREDENTIAL_IMPORTS_METHOD) {
|
|
30954
|
+
this.#dispatchDesktopRequest(async () => {
|
|
30955
|
+
if (!credentialImportsParamsSchema.safeParse(request.params).success) {
|
|
30956
|
+
await this.#writer.json(rpcError(request, -32602, "Invalid credential import request"));
|
|
30957
|
+
return;
|
|
30958
|
+
}
|
|
30959
|
+
await this.#waitForPlugins();
|
|
30960
|
+
try {
|
|
30961
|
+
const result = await handleCredentialImports(
|
|
30962
|
+
request.params,
|
|
30963
|
+
this.#externalAdapters.values(),
|
|
30964
|
+
this.#options.environment ?? process.env
|
|
30965
|
+
);
|
|
30966
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
|
|
30967
|
+
} catch {
|
|
30968
|
+
await this.#writer.json(
|
|
30969
|
+
rpcError(
|
|
30970
|
+
request,
|
|
30971
|
+
-32077,
|
|
30972
|
+
"Credential operation failed. Check the source login, choose an unused Provider name, and verify Pi configuration access."
|
|
30973
|
+
)
|
|
30974
|
+
);
|
|
30975
|
+
}
|
|
30976
|
+
});
|
|
30977
|
+
return;
|
|
30978
|
+
}
|
|
30349
30979
|
if (request.method === "codexhost/harness/accounts/sources") {
|
|
30350
30980
|
this.#dispatchDesktopRequest(async () => {
|
|
30351
30981
|
if (!harnessAccountSourceListParamsSchema.safeParse(request.params).success) {
|
|
@@ -30503,7 +31133,7 @@ var AppServerHost = class {
|
|
|
30503
31133
|
rpcError(request, -32602, "Invalid Harness command inspection params")
|
|
30504
31134
|
);
|
|
30505
31135
|
} else {
|
|
30506
|
-
await this.#writeHarnessCommandCatalog(request, params.data.harnessId);
|
|
31136
|
+
await this.#writeHarnessCommandCatalog(request, params.data.harnessId, params.data.cwd);
|
|
30507
31137
|
}
|
|
30508
31138
|
return;
|
|
30509
31139
|
}
|
|
@@ -30600,7 +31230,7 @@ var AppServerHost = class {
|
|
|
30600
31230
|
return;
|
|
30601
31231
|
}
|
|
30602
31232
|
if (request.method === "thread/fork") {
|
|
30603
|
-
const params =
|
|
31233
|
+
const params = isRecord14(request.params) ? request.params : {};
|
|
30604
31234
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
30605
31235
|
if (resolution.kind === "error") {
|
|
30606
31236
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -30621,7 +31251,7 @@ var AppServerHost = class {
|
|
|
30621
31251
|
}
|
|
30622
31252
|
}
|
|
30623
31253
|
if (request.method === "thread/revert") {
|
|
30624
|
-
const params =
|
|
31254
|
+
const params = isRecord14(request.params) ? request.params : {};
|
|
30625
31255
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
30626
31256
|
if (resolution.kind === "error") {
|
|
30627
31257
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -30642,7 +31272,7 @@ var AppServerHost = class {
|
|
|
30642
31272
|
}
|
|
30643
31273
|
}
|
|
30644
31274
|
if (request.method === "thread/rollback") {
|
|
30645
|
-
const params =
|
|
31275
|
+
const params = isRecord14(request.params) ? request.params : {};
|
|
30646
31276
|
const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
|
|
30647
31277
|
if (resolution.kind === "error") {
|
|
30648
31278
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
@@ -30798,7 +31428,7 @@ var AppServerHost = class {
|
|
|
30798
31428
|
return;
|
|
30799
31429
|
}
|
|
30800
31430
|
}
|
|
30801
|
-
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") {
|
|
30802
31432
|
const location = await this.#locateExternalThread(request.params.threadId);
|
|
30803
31433
|
if (await this.#writeResolutionError(request, location)) return;
|
|
30804
31434
|
if (location.kind === "external") {
|
|
@@ -30808,10 +31438,30 @@ var AppServerHost = class {
|
|
|
30808
31438
|
return;
|
|
30809
31439
|
}
|
|
30810
31440
|
}
|
|
30811
|
-
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
|
+
});
|
|
30812
31462
|
}
|
|
30813
31463
|
async #forwardOfficialNonRequest(value2, frame) {
|
|
30814
|
-
const response =
|
|
31464
|
+
const response = isRecord14(value2) ? value2 : null;
|
|
30815
31465
|
const request = response && (typeof response.id === "string" || typeof response.id === "number") ? this.#officialServerRequests.get(response.id) : null;
|
|
30816
31466
|
if (request !== void 0 && response) {
|
|
30817
31467
|
this.#officialServerRequests.delete(response.id);
|
|
@@ -30840,7 +31490,7 @@ var AppServerHost = class {
|
|
|
30840
31490
|
const parsed = input.value;
|
|
30841
31491
|
this.#observeOfficialTurnStartResponse(parsed);
|
|
30842
31492
|
let forwarded = parsed;
|
|
30843
|
-
if (
|
|
31493
|
+
if (isRecord14(parsed) && typeof parsed.method === "string" && "id" in parsed) {
|
|
30844
31494
|
const originalId = parsed.id;
|
|
30845
31495
|
if (typeof originalId === "string" || typeof originalId === "number") {
|
|
30846
31496
|
const forwardedId = `codexhost:official:${++this.#nextOfficialServerRequestId}`;
|
|
@@ -30848,7 +31498,7 @@ var AppServerHost = class {
|
|
|
30848
31498
|
forwarded = { ...parsed, id: forwardedId };
|
|
30849
31499
|
}
|
|
30850
31500
|
}
|
|
30851
|
-
const accountScopedNotification =
|
|
31501
|
+
const accountScopedNotification = isRecord14(parsed) && typeof parsed.method === "string" && (parsed.method === "account/updated" || parsed.method.startsWith("account/rateLimits/"));
|
|
30852
31502
|
if (accountScopedNotification) {
|
|
30853
31503
|
if (parsed.method === "account/updated") this.#officialRateLimits.reset(input.accountId);
|
|
30854
31504
|
}
|
|
@@ -30917,10 +31567,10 @@ var AppServerHost = class {
|
|
|
30917
31567
|
}
|
|
30918
31568
|
}
|
|
30919
31569
|
async #observeOfficialTurnLifecycle(value2) {
|
|
30920
|
-
if (!
|
|
31570
|
+
if (!isRecord14(value2) || !isRecord14(value2.params)) return;
|
|
30921
31571
|
const params = value2.params;
|
|
30922
31572
|
if (value2.method === "turn/started" && typeof params.threadId === "string") {
|
|
30923
|
-
const turn =
|
|
31573
|
+
const turn = isRecord14(params.turn) ? params.turn : null;
|
|
30924
31574
|
if (turn && typeof turn.id === "string") {
|
|
30925
31575
|
this.#forgetPendingOfficialTurnStarts(params.threadId);
|
|
30926
31576
|
this.#activeOfficialTurns.set(params.threadId, turn.id);
|
|
@@ -30933,7 +31583,7 @@ var AppServerHost = class {
|
|
|
30933
31583
|
const delegation = await this.#repository.getDelegationByChild(
|
|
30934
31584
|
hostThreadIdSchema.parse(params.threadId)
|
|
30935
31585
|
);
|
|
30936
|
-
const turn =
|
|
31586
|
+
const turn = isRecord14(params.turn) ? params.turn : null;
|
|
30937
31587
|
const status = turn?.status === "failed" ? "failed" : turn?.status === "interrupted" || turn?.status === "cancelled" ? "interrupted" : "completed";
|
|
30938
31588
|
if (this.#pendingOfficialDelegationThreads.has(params.threadId)) {
|
|
30939
31589
|
this.#pendingOfficialTerminalStatuses.set(params.threadId, status);
|
|
@@ -30963,28 +31613,28 @@ var AppServerHost = class {
|
|
|
30963
31613
|
}
|
|
30964
31614
|
async #readOfficialThreadCwd(threadId2) {
|
|
30965
31615
|
const response = await this.#requestOfficial("thread/read", { threadId: threadId2 });
|
|
30966
|
-
if (
|
|
30967
|
-
const result =
|
|
30968
|
-
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;
|
|
30969
31619
|
return thread && typeof thread.cwd === "string" && thread.cwd.trim() ? thread.cwd : void 0;
|
|
30970
31620
|
}
|
|
30971
31621
|
async #inspectOfficialDelegationTarget(input) {
|
|
30972
31622
|
const response = await this.#requestOfficial("model/list", {});
|
|
30973
|
-
if (
|
|
31623
|
+
if (isRecord14(response.error)) {
|
|
30974
31624
|
throw new DelegationControlError(
|
|
30975
31625
|
"DELEGATION_FAILED",
|
|
30976
31626
|
typeof response.error.message === "string" ? response.error.message : "Official Model catalog could not be read"
|
|
30977
31627
|
);
|
|
30978
31628
|
}
|
|
30979
|
-
const result =
|
|
31629
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
30980
31630
|
const data = result && Array.isArray(result.data) ? result.data : [];
|
|
30981
31631
|
const thinkingById = /* @__PURE__ */ new Map();
|
|
30982
31632
|
const models = data.flatMap((candidate) => {
|
|
30983
|
-
if (!
|
|
31633
|
+
if (!isRecord14(candidate) || typeof candidate.model !== "string" || !candidate.model.trim()) {
|
|
30984
31634
|
return [];
|
|
30985
31635
|
}
|
|
30986
31636
|
const supportedThinkingOptionIds = Array.isArray(candidate.supportedReasoningEfforts) ? candidate.supportedReasoningEfforts.flatMap((option) => {
|
|
30987
|
-
if (!
|
|
31637
|
+
if (!isRecord14(option) || typeof option.reasoningEffort !== "string" || !option.reasoningEffort.trim()) {
|
|
30988
31638
|
return [];
|
|
30989
31639
|
}
|
|
30990
31640
|
const id2 = harnessThinkingOptionIdSchema.safeParse(option.reasoningEffort);
|
|
@@ -31004,9 +31654,9 @@ var AppServerHost = class {
|
|
|
31004
31654
|
];
|
|
31005
31655
|
});
|
|
31006
31656
|
const defaultEntry = data.find(
|
|
31007
|
-
(candidate) =>
|
|
31657
|
+
(candidate) => isRecord14(candidate) && candidate.isDefault === true
|
|
31008
31658
|
);
|
|
31009
|
-
const defaultModel =
|
|
31659
|
+
const defaultModel = isRecord14(defaultEntry) && typeof defaultEntry.model === "string" ? encodeOfficialCodexModelRef(defaultEntry.model) : void 0;
|
|
31010
31660
|
return {
|
|
31011
31661
|
harnessId: input.harnessId,
|
|
31012
31662
|
inspection: {
|
|
@@ -31036,7 +31686,7 @@ var AppServerHost = class {
|
|
|
31036
31686
|
throw new DelegationControlError("INVALID_ARGUMENT", "Official Model Ref is invalid");
|
|
31037
31687
|
}
|
|
31038
31688
|
const nativeModelId = requestedModel ? decodeOfficialCodexModelRef(requestedModel) : void 0;
|
|
31039
|
-
const digest2 =
|
|
31689
|
+
const digest2 = createHash8("sha256").update(
|
|
31040
31690
|
JSON.stringify({
|
|
31041
31691
|
task: input.task,
|
|
31042
31692
|
cwd: input.cwd,
|
|
@@ -31112,8 +31762,8 @@ var AppServerHost = class {
|
|
|
31112
31762
|
ephemeral: false,
|
|
31113
31763
|
historyMode: "paginated"
|
|
31114
31764
|
});
|
|
31115
|
-
const startedResult =
|
|
31116
|
-
const thread = startedResult &&
|
|
31765
|
+
const startedResult = isRecord14(started.result) ? started.result : null;
|
|
31766
|
+
const thread = startedResult && isRecord14(startedResult.thread) ? startedResult.thread : null;
|
|
31117
31767
|
const threadId2 = thread && typeof thread.id === "string" ? thread.id : null;
|
|
31118
31768
|
if (!threadId2) throw new Error("Official thread/start returned no Thread identity");
|
|
31119
31769
|
this.#pendingOfficialDelegationThreads.add(threadId2);
|
|
@@ -31125,8 +31775,8 @@ var AppServerHost = class {
|
|
|
31125
31775
|
...nativeModelId ? { model: nativeModelId } : {},
|
|
31126
31776
|
...input.thinkingOptionId ? { effort: input.thinkingOptionId } : {}
|
|
31127
31777
|
});
|
|
31128
|
-
const turnResult =
|
|
31129
|
-
const turnValue = turnResult &&
|
|
31778
|
+
const turnResult = isRecord14(turn.result) ? turn.result : null;
|
|
31779
|
+
const turnValue = turnResult && isRecord14(turnResult.turn) ? turnResult.turn : null;
|
|
31130
31780
|
const parsedTurnId = turnValue && typeof turnValue.id === "string" ? turnValue.id : null;
|
|
31131
31781
|
if (!parsedTurnId) throw new Error("Official turn/start returned no Turn identity");
|
|
31132
31782
|
turnId = parsedTurnId;
|
|
@@ -31137,7 +31787,7 @@ var AppServerHost = class {
|
|
|
31137
31787
|
throw error51;
|
|
31138
31788
|
}
|
|
31139
31789
|
this.#activeOfficialTurns.set(threadId2, turnId);
|
|
31140
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
31790
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID10());
|
|
31141
31791
|
try {
|
|
31142
31792
|
const source = await this.#repository.find(input.parentThreadId);
|
|
31143
31793
|
const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId2);
|
|
@@ -31196,27 +31846,27 @@ var AppServerHost = class {
|
|
|
31196
31846
|
threadId: input.threadId,
|
|
31197
31847
|
includeTurns: true
|
|
31198
31848
|
});
|
|
31199
|
-
if (
|
|
31849
|
+
if (isRecord14(current.error) || !isRecord14(current.result)) {
|
|
31200
31850
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31201
31851
|
}
|
|
31202
|
-
const currentThread =
|
|
31852
|
+
const currentThread = isRecord14(current.result.thread) ? current.result.thread : null;
|
|
31203
31853
|
const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
|
|
31204
31854
|
const latestTurn = currentTurns.at(-1);
|
|
31205
|
-
if (currentThread &&
|
|
31855
|
+
if (currentThread && isRecord14(currentThread.status) && currentThread.status.type === "active" || isRecord14(latestTurn) && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
|
|
31206
31856
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
31207
31857
|
}
|
|
31208
31858
|
const response = await this.#requestOfficial("turn/start", {
|
|
31209
31859
|
threadId: input.threadId,
|
|
31210
31860
|
input: [{ type: "text", text: input.message }]
|
|
31211
31861
|
});
|
|
31212
|
-
if (
|
|
31862
|
+
if (isRecord14(response.error)) {
|
|
31213
31863
|
throw new DelegationControlError(
|
|
31214
31864
|
"DELEGATION_FAILED",
|
|
31215
31865
|
typeof response.error.message === "string" ? response.error.message : "Turn start failed"
|
|
31216
31866
|
);
|
|
31217
31867
|
}
|
|
31218
|
-
const result =
|
|
31219
|
-
const turn = result &&
|
|
31868
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31869
|
+
const turn = result && isRecord14(result.turn) ? result.turn : null;
|
|
31220
31870
|
const turnId = turn && typeof turn.id === "string" ? turn.id : null;
|
|
31221
31871
|
if (!turnId) throw new Error("Official turn/start returned no Turn identity");
|
|
31222
31872
|
this.#activeOfficialTurns.set(input.threadId, turnId);
|
|
@@ -31238,13 +31888,13 @@ var AppServerHost = class {
|
|
|
31238
31888
|
threadId: input.threadId,
|
|
31239
31889
|
includeTurns: true
|
|
31240
31890
|
});
|
|
31241
|
-
if (
|
|
31891
|
+
if (isRecord14(current.error) || !isRecord14(current.result)) {
|
|
31242
31892
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31243
31893
|
}
|
|
31244
|
-
const currentThread =
|
|
31894
|
+
const currentThread = isRecord14(current.result.thread) ? current.result.thread : null;
|
|
31245
31895
|
const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
|
|
31246
31896
|
const latestTurn = currentTurns.at(-1);
|
|
31247
|
-
if (
|
|
31897
|
+
if (isRecord14(latestTurn) && typeof latestTurn.id === "string" && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
|
|
31248
31898
|
turnId = latestTurn.id;
|
|
31249
31899
|
this.#activeOfficialTurns.set(input.threadId, turnId);
|
|
31250
31900
|
} else {
|
|
@@ -31255,7 +31905,7 @@ var AppServerHost = class {
|
|
|
31255
31905
|
threadId: input.threadId,
|
|
31256
31906
|
turnId
|
|
31257
31907
|
});
|
|
31258
|
-
if (
|
|
31908
|
+
if (isRecord14(response.error)) {
|
|
31259
31909
|
throw new DelegationControlError(
|
|
31260
31910
|
"DELEGATION_FAILED",
|
|
31261
31911
|
typeof response.error.message === "string" ? response.error.message : "Turn cancel failed"
|
|
@@ -31268,18 +31918,18 @@ var AppServerHost = class {
|
|
|
31268
31918
|
threadId: input.threadId,
|
|
31269
31919
|
includeTurns: true
|
|
31270
31920
|
});
|
|
31271
|
-
if (
|
|
31921
|
+
if (isRecord14(response.error)) {
|
|
31272
31922
|
throw new DelegationControlError(
|
|
31273
31923
|
"THREAD_NOT_FOUND",
|
|
31274
31924
|
typeof response.error.message === "string" ? response.error.message : "Official Thread was not found"
|
|
31275
31925
|
);
|
|
31276
31926
|
}
|
|
31277
|
-
const result =
|
|
31278
|
-
const thread = result &&
|
|
31927
|
+
const result = isRecord14(response.result) ? response.result : null;
|
|
31928
|
+
const thread = result && isRecord14(result.thread) ? result.thread : null;
|
|
31279
31929
|
if (!thread)
|
|
31280
31930
|
throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
|
|
31281
|
-
const turns = Array.isArray(thread.turns) ? thread.turns.filter((turn) =>
|
|
31282
|
-
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";
|
|
31283
31933
|
const snapshot = projectDelegationThreadSnapshot({
|
|
31284
31934
|
threadId: input.threadId,
|
|
31285
31935
|
harnessId: "codex",
|
|
@@ -31301,7 +31951,7 @@ var AppServerHost = class {
|
|
|
31301
31951
|
async #listDelegationThreads(input) {
|
|
31302
31952
|
const [sortKey, sortDirection2] = input.sort.split("-");
|
|
31303
31953
|
const request = {
|
|
31304
|
-
id: `codexhost:delegation-list:${
|
|
31954
|
+
id: `codexhost:delegation-list:${randomUUID10()}`,
|
|
31305
31955
|
method: "thread/list",
|
|
31306
31956
|
params: {
|
|
31307
31957
|
cwd: input.cwd ? [input.cwd] : null,
|
|
@@ -31329,7 +31979,7 @@ var AppServerHost = class {
|
|
|
31329
31979
|
threads: result.data.flatMap((entry) => {
|
|
31330
31980
|
if (typeof entry.id !== "string") return [];
|
|
31331
31981
|
const record3 = records.find((candidate) => candidate.hostThreadId === entry.id);
|
|
31332
|
-
const status =
|
|
31982
|
+
const status = isRecord14(entry.status) && entry.status.type === "active" ? "running" : "completed";
|
|
31333
31983
|
return [
|
|
31334
31984
|
{
|
|
31335
31985
|
threadId: entry.id,
|
|
@@ -31649,21 +32299,67 @@ var AppServerHost = class {
|
|
|
31649
32299
|
await this.#writer.json(rpcEnvelope(request, { result: { commands: [] } }));
|
|
31650
32300
|
return;
|
|
31651
32301
|
}
|
|
31652
|
-
|
|
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
|
+
);
|
|
31653
32316
|
}
|
|
31654
|
-
|
|
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) {
|
|
31655
32332
|
await this.#waitForPlugins();
|
|
31656
32333
|
const adapter = this.#externalAdapters.get(harnessId);
|
|
31657
32334
|
if (!adapter) {
|
|
31658
32335
|
await this.#writer.json(rpcError(request, -32077, `Harness '${harnessId}' is unavailable`));
|
|
31659
32336
|
return;
|
|
31660
32337
|
}
|
|
32338
|
+
let catalog;
|
|
31661
32339
|
try {
|
|
31662
|
-
|
|
31663
|
-
|
|
32340
|
+
catalog = harnessCommandCatalogSchema.parse({
|
|
32341
|
+
...adapter.commandCatalog ?? { commands: [] },
|
|
32342
|
+
...adapter.liveCommandCatalog ? { source: "static" } : {}
|
|
32343
|
+
});
|
|
31664
32344
|
} catch {
|
|
31665
32345
|
await this.#writer.json(rpcError(request, -32078, "Harness command catalog is invalid"));
|
|
32346
|
+
return;
|
|
31666
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) }));
|
|
31667
32363
|
}
|
|
31668
32364
|
async #executeThreadCommand(request) {
|
|
31669
32365
|
const params = threadCommandExecuteParamsSchema.safeParse(request.params);
|
|
@@ -31715,39 +32411,43 @@ var AppServerHost = class {
|
|
|
31715
32411
|
return;
|
|
31716
32412
|
}
|
|
31717
32413
|
try {
|
|
31718
|
-
await this.#
|
|
31719
|
-
request,
|
|
32414
|
+
const started = await this.#beginExternalCommand(
|
|
31720
32415
|
thread,
|
|
31721
32416
|
params.commandId,
|
|
31722
32417
|
params.arguments,
|
|
31723
|
-
params.turnId
|
|
31724
|
-
"command"
|
|
32418
|
+
params.turnId
|
|
31725
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
|
+
}
|
|
31726
32429
|
} catch (error51) {
|
|
31727
32430
|
this.#diagnose(error51);
|
|
31728
32431
|
await this.#writer.json(
|
|
31729
|
-
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)}`)
|
|
31730
32433
|
);
|
|
31731
32434
|
}
|
|
31732
32435
|
} finally {
|
|
31733
32436
|
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
31734
32437
|
}
|
|
31735
32438
|
}
|
|
31736
|
-
async #
|
|
32439
|
+
async #beginExternalCommand(thread, commandId, arguments_2, requestedTurnId) {
|
|
31737
32440
|
const commands = thread.session.commands;
|
|
31738
32441
|
if (!commands) {
|
|
31739
|
-
|
|
31740
|
-
rpcError(request, -32078, "External Harness does not expose commands")
|
|
31741
|
-
);
|
|
31742
|
-
return;
|
|
32442
|
+
throw new ExternalCommandError(-32078, "External Harness does not expose commands");
|
|
31743
32443
|
}
|
|
31744
|
-
if (
|
|
31745
|
-
|
|
31746
|
-
|
|
31747
|
-
|
|
31748
|
-
|
|
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");
|
|
31749
32449
|
}
|
|
31750
|
-
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(
|
|
32450
|
+
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID10());
|
|
31751
32451
|
const projection = {
|
|
31752
32452
|
projector: new CodexTurnProjector({
|
|
31753
32453
|
threadId: thread.id,
|
|
@@ -31762,13 +32462,14 @@ var AppServerHost = class {
|
|
|
31762
32462
|
thread.projectedTurns.set(turnId, projection);
|
|
31763
32463
|
thread.responseGates.set(turnId, gate);
|
|
31764
32464
|
thread.ephemeralTurnIds.add(turnId);
|
|
31765
|
-
let result;
|
|
31766
32465
|
try {
|
|
31767
|
-
result = await commands.execute({
|
|
32466
|
+
const result = await commands.execute({
|
|
31768
32467
|
turnId,
|
|
31769
32468
|
commandId,
|
|
31770
32469
|
...arguments_2 ? { arguments: arguments_2 } : {}
|
|
31771
32470
|
});
|
|
32471
|
+
if (!result.ok) throw new ExternalCommandError(-32073, result.error.message);
|
|
32472
|
+
return { turnId: result.value.turnId, turn: projection.projector.pendingTurn(), gate };
|
|
31772
32473
|
} catch (error51) {
|
|
31773
32474
|
thread.running = false;
|
|
31774
32475
|
thread.activeTurnId = null;
|
|
@@ -31779,28 +32480,6 @@ var AppServerHost = class {
|
|
|
31779
32480
|
this.#signalActiveWorkChanged();
|
|
31780
32481
|
throw error51;
|
|
31781
32482
|
}
|
|
31782
|
-
if (!result.ok) {
|
|
31783
|
-
thread.running = false;
|
|
31784
|
-
thread.activeTurnId = null;
|
|
31785
|
-
thread.projectedTurns.delete(turnId);
|
|
31786
|
-
thread.responseGates.delete(turnId);
|
|
31787
|
-
thread.ephemeralTurnIds.delete(turnId);
|
|
31788
|
-
gate.resolve();
|
|
31789
|
-
this.#signalActiveWorkChanged();
|
|
31790
|
-
await this.#writer.json(rpcError(request, -32073, result.error.message));
|
|
31791
|
-
return;
|
|
31792
|
-
}
|
|
31793
|
-
try {
|
|
31794
|
-
const response = responseKind === "command" ? jsonValueSchema.parse(
|
|
31795
|
-
threadCommandExecuteResultSchema.parse({
|
|
31796
|
-
accepted: true,
|
|
31797
|
-
turnId: result.value.turnId
|
|
31798
|
-
})
|
|
31799
|
-
) : { turn: projection.projector.pendingTurn() };
|
|
31800
|
-
await this.#writer.json(rpcEnvelope(request, { result: response }));
|
|
31801
|
-
} finally {
|
|
31802
|
-
gate.resolve();
|
|
31803
|
-
}
|
|
31804
32483
|
}
|
|
31805
32484
|
async #selectThreadModel(request) {
|
|
31806
32485
|
const params = threadModelSelectParamsSchema.safeParse(request.params);
|
|
@@ -32423,10 +33102,10 @@ var AppServerHost = class {
|
|
|
32423
33102
|
...typeof params.serviceTier === "string" ? { serviceTier: params.serviceTier } : {}
|
|
32424
33103
|
});
|
|
32425
33104
|
try {
|
|
32426
|
-
if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !
|
|
33105
|
+
if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !isRecord14(params.initialTurnsPage)) {
|
|
32427
33106
|
throw new ExternalHistoryRequestError("initialTurnsPage must be an object");
|
|
32428
33107
|
}
|
|
32429
|
-
const initialPageParams =
|
|
33108
|
+
const initialPageParams = isRecord14(params.initialTurnsPage) ? params.initialTurnsPage : null;
|
|
32430
33109
|
const initialTurnsPage = initialPageParams ? listExternalTurns(turns, initialPageParams) : null;
|
|
32431
33110
|
const paginated = thread.record.historyMode === "paginated";
|
|
32432
33111
|
const turnsBackwardsCursor = paginated ? listExternalTurns(turns, { limit: 1, itemsView: "notLoaded" }).backwardsCursor : null;
|
|
@@ -32521,53 +33200,8 @@ var AppServerHost = class {
|
|
|
32521
33200
|
await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
|
|
32522
33201
|
return;
|
|
32523
33202
|
}
|
|
32524
|
-
const commandCandidate = text.trimStart();
|
|
32525
|
-
if (thread.session.commands && /^\/[^\s/]+(?:\s|$)/u.test(commandCandidate)) {
|
|
32526
|
-
const commandText = commandCandidate.trimEnd();
|
|
32527
|
-
this.#pendingExternalCommandRequests.add(thread.id);
|
|
32528
|
-
try {
|
|
32529
|
-
const catalog = await thread.session.commands.list();
|
|
32530
|
-
if (!catalog.ok) {
|
|
32531
|
-
await this.#writer.json(rpcError(request, -32073, catalog.error.message));
|
|
32532
|
-
return;
|
|
32533
|
-
}
|
|
32534
|
-
const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
|
|
32535
|
-
if (commandText === command.invocation) return true;
|
|
32536
|
-
return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
|
|
32537
|
-
});
|
|
32538
|
-
if (matched) {
|
|
32539
|
-
const argumentText = commandText.slice(matched.invocation.length).trimStart();
|
|
32540
|
-
try {
|
|
32541
|
-
await this.#startExternalCommand(
|
|
32542
|
-
request,
|
|
32543
|
-
thread,
|
|
32544
|
-
matched.id,
|
|
32545
|
-
argumentText.length > 0 ? { text: argumentText } : void 0,
|
|
32546
|
-
void 0,
|
|
32547
|
-
"turn"
|
|
32548
|
-
);
|
|
32549
|
-
} catch (error51) {
|
|
32550
|
-
this.#diagnose(error51);
|
|
32551
|
-
await this.#writer.json(
|
|
32552
|
-
rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
|
|
32553
|
-
);
|
|
32554
|
-
}
|
|
32555
|
-
return;
|
|
32556
|
-
}
|
|
32557
|
-
await this.#writer.json(
|
|
32558
|
-
rpcError(request, -32078, "External Harness does not expose the requested command")
|
|
32559
|
-
);
|
|
32560
|
-
return;
|
|
32561
|
-
} finally {
|
|
32562
|
-
this.#pendingExternalCommandRequests.delete(thread.id);
|
|
32563
|
-
}
|
|
32564
|
-
}
|
|
32565
|
-
if (this.#externalSteering.hasPending(thread.id)) {
|
|
32566
|
-
await this.#writer.json(rpcError(request, -32072, "External Thread is changing direction"));
|
|
32567
|
-
return;
|
|
32568
|
-
}
|
|
32569
33203
|
try {
|
|
32570
|
-
const started = await this.#
|
|
33204
|
+
const started = await this.#beginExternalInputTurn(thread, text);
|
|
32571
33205
|
try {
|
|
32572
33206
|
await this.#writer.json(rpcEnvelope(request, { result: { turn: started.turn } }));
|
|
32573
33207
|
} finally {
|
|
@@ -32577,7 +33211,7 @@ var AppServerHost = class {
|
|
|
32577
33211
|
await this.#writer.json(
|
|
32578
33212
|
rpcError(
|
|
32579
33213
|
request,
|
|
32580
|
-
error51 instanceof ExternalSteerError ? error51.code : -32073,
|
|
33214
|
+
error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32073,
|
|
32581
33215
|
errorMessage3(error51)
|
|
32582
33216
|
)
|
|
32583
33217
|
);
|
|
@@ -32588,7 +33222,7 @@ var AppServerHost = class {
|
|
|
32588
33222
|
const started = await this.#externalSteering.run(
|
|
32589
33223
|
thread,
|
|
32590
33224
|
requestObject(request),
|
|
32591
|
-
(text) => this.#
|
|
33225
|
+
(text, assertActive) => this.#beginExternalInputTurn(thread, text, assertActive)
|
|
32592
33226
|
);
|
|
32593
33227
|
try {
|
|
32594
33228
|
await this.#writer.json(rpcEnvelope(request, { result: { turnId: started.turnId } }));
|
|
@@ -32599,7 +33233,7 @@ var AppServerHost = class {
|
|
|
32599
33233
|
await this.#writer.json(
|
|
32600
33234
|
rpcError(
|
|
32601
33235
|
request,
|
|
32602
|
-
error51 instanceof ExternalSteerError ? error51.code : -32074,
|
|
33236
|
+
error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32074,
|
|
32603
33237
|
errorMessage3(error51)
|
|
32604
33238
|
)
|
|
32605
33239
|
);
|
|
@@ -32607,6 +33241,37 @@ var AppServerHost = class {
|
|
|
32607
33241
|
this.#signalActiveWorkChanged();
|
|
32608
33242
|
}
|
|
32609
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
|
+
}
|
|
32610
33275
|
async #beginExternalTurn(thread, text) {
|
|
32611
33276
|
if (this.#closeRequested || this.#externalRuntime.get(thread.id) !== thread) {
|
|
32612
33277
|
throw new ExternalSteerError(-32073, "External Thread is no longer available");
|
|
@@ -32614,7 +33279,7 @@ var AppServerHost = class {
|
|
|
32614
33279
|
if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
|
|
32615
33280
|
throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
|
|
32616
33281
|
}
|
|
32617
|
-
const turnId = hostTurnIdSchema.parse(
|
|
33282
|
+
const turnId = hostTurnIdSchema.parse(randomUUID10());
|
|
32618
33283
|
const startedAtMs = Date.now();
|
|
32619
33284
|
const projection = {
|
|
32620
33285
|
projector: new CodexTurnProjector({
|
|
@@ -32633,7 +33298,7 @@ var AppServerHost = class {
|
|
|
32633
33298
|
const result = await thread.session.execute({
|
|
32634
33299
|
type: "turn.start",
|
|
32635
33300
|
turnId,
|
|
32636
|
-
input: [{ type: "text", text }]
|
|
33301
|
+
input: [{ type: "text", text: rewriteDelegationMentionText(text) }]
|
|
32637
33302
|
});
|
|
32638
33303
|
if (!result.ok) throw new ExternalSteerError(-32073, result.error.message);
|
|
32639
33304
|
return { turnId, turn: projection.projector.pendingTurn(), gate };
|
|
@@ -32935,7 +33600,7 @@ var AppServerHost = class {
|
|
|
32935
33600
|
const previousItems = new Map(
|
|
32936
33601
|
child.turns.flatMap(
|
|
32937
33602
|
(turn) => Array.isArray(turn.items) ? turn.items.flatMap(
|
|
32938
|
-
(item) =>
|
|
33603
|
+
(item) => isRecord14(item) && typeof item.id === "string" ? [[item.id, JSON.stringify(item)]] : []
|
|
32939
33604
|
) : []
|
|
32940
33605
|
)
|
|
32941
33606
|
);
|
|
@@ -32948,7 +33613,7 @@ var AppServerHost = class {
|
|
|
32948
33613
|
for (const turn of child.turns) {
|
|
32949
33614
|
if (typeof turn.id !== "string" || !Array.isArray(turn.items)) continue;
|
|
32950
33615
|
const changedItems = turn.items.filter(
|
|
32951
|
-
(item) =>
|
|
33616
|
+
(item) => isRecord14(item) && typeof item.id === "string" && previousItems.get(item.id) !== JSON.stringify(item)
|
|
32952
33617
|
);
|
|
32953
33618
|
if (changedItems.length > 0) {
|
|
32954
33619
|
await this.#writer.json({
|
|
@@ -33080,7 +33745,7 @@ var AppServerHost = class {
|
|
|
33080
33745
|
}
|
|
33081
33746
|
}
|
|
33082
33747
|
async #handleDesktopApprovalResponse(value2) {
|
|
33083
|
-
if (!
|
|
33748
|
+
if (!isRecord14(value2) || !isHostApprovalRequestId(value2.id)) return false;
|
|
33084
33749
|
const requestId = value2.id;
|
|
33085
33750
|
const pending = this.#pendingDesktopApprovals.get(requestId);
|
|
33086
33751
|
if (!pending) return true;
|
|
@@ -33162,7 +33827,7 @@ var AppServerHost = class {
|
|
|
33162
33827
|
try {
|
|
33163
33828
|
result = projection.projector.projectQuestion(
|
|
33164
33829
|
interaction,
|
|
33165
|
-
hostItemIdSchema.parse(
|
|
33830
|
+
hostItemIdSchema.parse(randomUUID10())
|
|
33166
33831
|
);
|
|
33167
33832
|
} catch (error51) {
|
|
33168
33833
|
this.#diagnose(error51);
|
|
@@ -33207,7 +33872,7 @@ var AppServerHost = class {
|
|
|
33207
33872
|
}
|
|
33208
33873
|
}
|
|
33209
33874
|
async #handleDesktopQuestionResponse(value2) {
|
|
33210
|
-
if (!
|
|
33875
|
+
if (!isRecord14(value2) || !isHostQuestionRequestId(value2.id)) return false;
|
|
33211
33876
|
const requestId = value2.id;
|
|
33212
33877
|
const pending = this.#pendingDesktopQuestions.get(requestId);
|
|
33213
33878
|
if (!pending) return true;
|
|
@@ -33328,19 +33993,19 @@ var AppServerHost = class {
|
|
|
33328
33993
|
};
|
|
33329
33994
|
|
|
33330
33995
|
// packages/host-runtime/src/native-account-host.ts
|
|
33331
|
-
import { mkdir as
|
|
33996
|
+
import { mkdir as mkdir8, realpath as realpath3 } from "node:fs/promises";
|
|
33332
33997
|
import { homedir } from "node:os";
|
|
33333
|
-
import
|
|
33998
|
+
import path19 from "node:path";
|
|
33334
33999
|
|
|
33335
34000
|
// packages/host-runtime/src/codex-runtime/owned-official-backends.ts
|
|
33336
|
-
import { createHash as
|
|
34001
|
+
import { createHash as createHash9, randomBytes } from "node:crypto";
|
|
33337
34002
|
import { Writable as Writable2 } from "node:stream";
|
|
33338
34003
|
|
|
33339
34004
|
// packages/host-runtime/src/remote-app-server.ts
|
|
33340
34005
|
import { createServer } from "node:http";
|
|
33341
34006
|
import net from "node:net";
|
|
33342
|
-
import { chmod as chmod3, lstat as lstat6, mkdir as
|
|
33343
|
-
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";
|
|
33344
34009
|
import { PassThrough } from "node:stream";
|
|
33345
34010
|
|
|
33346
34011
|
// node_modules/ws/wrapper.mjs
|
|
@@ -33355,10 +34020,10 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
33355
34020
|
var wrapper_default = import_websocket.default;
|
|
33356
34021
|
|
|
33357
34022
|
// packages/host-runtime/src/remote-socket-lock.ts
|
|
33358
|
-
import { randomUUID as
|
|
33359
|
-
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";
|
|
33360
34025
|
import { uptime } from "node:os";
|
|
33361
|
-
import
|
|
34026
|
+
import path16 from "node:path";
|
|
33362
34027
|
import { setTimeout as delay4 } from "node:timers/promises";
|
|
33363
34028
|
var LOCK_RETRY_COUNT = 200;
|
|
33364
34029
|
var LOCK_RETRY_DELAY_MS = 25;
|
|
@@ -33421,7 +34086,7 @@ async function readLockEntrySnapshot(filePath) {
|
|
|
33421
34086
|
throw error51;
|
|
33422
34087
|
});
|
|
33423
34088
|
if (metadata === null || !metadata.isFile()) return null;
|
|
33424
|
-
const source = await
|
|
34089
|
+
const source = await readFile8(filePath, "utf8").catch((error51) => {
|
|
33425
34090
|
if (error51.code === "ENOENT") return null;
|
|
33426
34091
|
throw error51;
|
|
33427
34092
|
});
|
|
@@ -33432,7 +34097,7 @@ async function readLockEntrySnapshot(filePath) {
|
|
|
33432
34097
|
source,
|
|
33433
34098
|
identity: { dev: metadata.dev, ino: metadata.ino },
|
|
33434
34099
|
mtimeMs: metadata.mtimeMs,
|
|
33435
|
-
record: record3 &&
|
|
34100
|
+
record: record3 && path16.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
|
|
33436
34101
|
};
|
|
33437
34102
|
}
|
|
33438
34103
|
function lockEntryIsAbandoned(snapshot) {
|
|
@@ -33444,7 +34109,7 @@ async function removeAbandonedLockEntry(snapshot) {
|
|
|
33444
34109
|
if (current === null || current.source !== snapshot.source || !sameUnixFileIdentity(current.identity, snapshot.identity) || !lockEntryIsAbandoned(current)) {
|
|
33445
34110
|
return false;
|
|
33446
34111
|
}
|
|
33447
|
-
await
|
|
34112
|
+
await rm6(snapshot.filePath, { force: true });
|
|
33448
34113
|
return true;
|
|
33449
34114
|
}
|
|
33450
34115
|
async function readLockEntryCatalog(lockDirectory) {
|
|
@@ -33453,7 +34118,7 @@ async function readLockEntryCatalog(lockDirectory) {
|
|
|
33453
34118
|
let unsettled = false;
|
|
33454
34119
|
for (const name of names) {
|
|
33455
34120
|
if (!name.startsWith(LOCK_ENTRY_PREFIX) || !name.endsWith(LOCK_ENTRY_SUFFIX)) continue;
|
|
33456
|
-
const snapshot = await readLockEntrySnapshot(
|
|
34121
|
+
const snapshot = await readLockEntrySnapshot(path16.join(lockDirectory, name));
|
|
33457
34122
|
if (snapshot === null) continue;
|
|
33458
34123
|
if (lockEntryIsAbandoned(snapshot)) {
|
|
33459
34124
|
if (!await removeAbandonedLockEntry(snapshot)) unsettled = true;
|
|
@@ -33468,7 +34133,7 @@ async function readLockEntryCatalog(lockDirectory) {
|
|
|
33468
34133
|
return { entries, unsettled };
|
|
33469
34134
|
}
|
|
33470
34135
|
async function preparePrivateLockDirectory(lockDirectory) {
|
|
33471
|
-
await
|
|
34136
|
+
await mkdir6(lockDirectory, { mode: 448 }).catch((error51) => {
|
|
33472
34137
|
if (error51.code !== "EEXIST") throw error51;
|
|
33473
34138
|
});
|
|
33474
34139
|
const metadata = await lstat5(lockDirectory);
|
|
@@ -33481,8 +34146,8 @@ async function preparePrivateLockDirectory(lockDirectory) {
|
|
|
33481
34146
|
await chmod2(lockDirectory, 448);
|
|
33482
34147
|
}
|
|
33483
34148
|
async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
|
|
33484
|
-
const temporary =
|
|
33485
|
-
const handle = await
|
|
34149
|
+
const temporary = path16.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID11()}`);
|
|
34150
|
+
const handle = await open6(temporary, "wx", 384);
|
|
33486
34151
|
try {
|
|
33487
34152
|
await handle.writeFile(`${JSON.stringify(record3)}
|
|
33488
34153
|
`, "utf8");
|
|
@@ -33491,15 +34156,15 @@ async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
|
|
|
33491
34156
|
await handle.close();
|
|
33492
34157
|
}
|
|
33493
34158
|
try {
|
|
33494
|
-
await
|
|
34159
|
+
await rename5(temporary, entryPath);
|
|
33495
34160
|
} finally {
|
|
33496
|
-
await
|
|
34161
|
+
await rm6(temporary, { force: true });
|
|
33497
34162
|
}
|
|
33498
34163
|
}
|
|
33499
34164
|
async function removeOwnedLockEntry(entryPath, ownerToken) {
|
|
33500
34165
|
const snapshot = await readLockEntrySnapshot(entryPath);
|
|
33501
34166
|
if (snapshot?.record?.ownerToken !== ownerToken) return;
|
|
33502
|
-
await
|
|
34167
|
+
await rm6(entryPath, { force: true });
|
|
33503
34168
|
}
|
|
33504
34169
|
async function legacyLockState(legacyPath) {
|
|
33505
34170
|
const metadata = await lstat5(legacyPath).catch((error51) => {
|
|
@@ -33508,7 +34173,7 @@ async function legacyLockState(legacyPath) {
|
|
|
33508
34173
|
});
|
|
33509
34174
|
if (metadata === null) return "absent";
|
|
33510
34175
|
if (!metadata.isFile()) return "blocking";
|
|
33511
|
-
const source = await
|
|
34176
|
+
const source = await readFile8(legacyPath, "utf8").catch((error51) => {
|
|
33512
34177
|
if (error51.code === "ENOENT") return null;
|
|
33513
34178
|
throw error51;
|
|
33514
34179
|
});
|
|
@@ -33519,7 +34184,7 @@ async function legacyLockState(legacyPath) {
|
|
|
33519
34184
|
return ownerIsAbandoned(record3, metadata.mtimeMs) ? "abandoned" : "blocking";
|
|
33520
34185
|
}
|
|
33521
34186
|
async function tryAcquireLegacyCompatibilityGuard(legacyPath, record3) {
|
|
33522
|
-
const handle = await
|
|
34187
|
+
const handle = await open6(legacyPath, "wx", 384).catch((error51) => {
|
|
33523
34188
|
if (error51.code === "EEXIST") return null;
|
|
33524
34189
|
throw error51;
|
|
33525
34190
|
});
|
|
@@ -33545,7 +34210,7 @@ async function releaseLegacyCompatibilityGuard(legacyPath, guard) {
|
|
|
33545
34210
|
throw error51;
|
|
33546
34211
|
});
|
|
33547
34212
|
if (metadata?.isFile() && sameUnixFileIdentity({ dev: metadata.dev, ino: metadata.ino }, guard.identity)) {
|
|
33548
|
-
await
|
|
34213
|
+
await rm6(legacyPath, { force: true });
|
|
33549
34214
|
}
|
|
33550
34215
|
}
|
|
33551
34216
|
}
|
|
@@ -33556,8 +34221,8 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
|
|
|
33556
34221
|
const legacyPath = `${socketPath}.initializing`;
|
|
33557
34222
|
const lockDirectory = `${socketPath}.initializers`;
|
|
33558
34223
|
await preparePrivateLockDirectory(lockDirectory);
|
|
33559
|
-
const ownerToken =
|
|
33560
|
-
const entryPath =
|
|
34224
|
+
const ownerToken = randomUUID11();
|
|
34225
|
+
const entryPath = path16.join(lockDirectory, lockEntryName(ownerToken));
|
|
33561
34226
|
const baseRecord = {
|
|
33562
34227
|
version: 2,
|
|
33563
34228
|
ownerToken,
|
|
@@ -33731,14 +34396,14 @@ function remoteAppServerSocketPath(environment, listenUrl = "unix://") {
|
|
|
33731
34396
|
throw new Error("Remote app-server listener must use a Unix URL");
|
|
33732
34397
|
}
|
|
33733
34398
|
const explicit = listenUrl.slice("unix://".length);
|
|
33734
|
-
if (explicit.length > 0) return
|
|
33735
|
-
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);
|
|
33736
34401
|
if (!codexHome)
|
|
33737
34402
|
throw new Error("CODEX_HOME or HOME is required for the remote app-server socket");
|
|
33738
|
-
return
|
|
34403
|
+
return path17.posix.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
33739
34404
|
}
|
|
33740
34405
|
function officialListenerArgumentsForRemoteListener(arguments_2, socketPath) {
|
|
33741
|
-
if (!
|
|
34406
|
+
if (!path17.posix.isAbsolute(socketPath)) {
|
|
33742
34407
|
throw new Error("Shared official app-server socket path must be absolute");
|
|
33743
34408
|
}
|
|
33744
34409
|
if (remoteUnixListenerUrl(arguments_2) === null) {
|
|
@@ -33846,10 +34511,10 @@ async function removeStaleSocket(socketPath) {
|
|
|
33846
34511
|
});
|
|
33847
34512
|
});
|
|
33848
34513
|
if (active) throw new Error(`Remote app-server socket is already in use at ${socketPath}`);
|
|
33849
|
-
await
|
|
34514
|
+
await rm7(socketPath, { force: true });
|
|
33850
34515
|
}
|
|
33851
34516
|
async function prepareRemoteAppServerSocketDirectory(socketPath) {
|
|
33852
|
-
const socketDirectory =
|
|
34517
|
+
const socketDirectory = path17.dirname(socketPath);
|
|
33853
34518
|
const existing = await lstat6(socketDirectory).catch((error51) => {
|
|
33854
34519
|
if (error51.code === "ENOENT") return null;
|
|
33855
34520
|
throw error51;
|
|
@@ -33863,7 +34528,7 @@ async function prepareRemoteAppServerSocketDirectory(socketPath) {
|
|
|
33863
34528
|
);
|
|
33864
34529
|
}
|
|
33865
34530
|
}
|
|
33866
|
-
await
|
|
34531
|
+
await mkdir7(socketDirectory, { recursive: true, mode: 448 });
|
|
33867
34532
|
await chmod3(socketDirectory, 448);
|
|
33868
34533
|
}
|
|
33869
34534
|
function sendOutputFrames(socket, output) {
|
|
@@ -34036,7 +34701,7 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
34036
34701
|
if (ownedSocketIdentity) {
|
|
34037
34702
|
const current = await unixSocketIdentity(input.socketPath);
|
|
34038
34703
|
if (current && sameUnixFileIdentity2(current, ownedSocketIdentity)) {
|
|
34039
|
-
await
|
|
34704
|
+
await rm7(input.socketPath, { force: true });
|
|
34040
34705
|
}
|
|
34041
34706
|
ownedSocketIdentity = null;
|
|
34042
34707
|
}
|
|
@@ -34054,20 +34719,20 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
34054
34719
|
|
|
34055
34720
|
// packages/host-runtime/src/remote-official-app-server.ts
|
|
34056
34721
|
import { spawn as spawn3 } from "node:child_process";
|
|
34057
|
-
import { randomUUID as
|
|
34058
|
-
import { lstat as lstat7, rm as
|
|
34059
|
-
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";
|
|
34060
34725
|
var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
|
|
34061
34726
|
var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
|
|
34062
|
-
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token =
|
|
34063
|
-
if (!
|
|
34727
|
+
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID12()) {
|
|
34728
|
+
if (!path18.posix.isAbsolute(desktopControlSocketPath)) {
|
|
34064
34729
|
throw new Error("Desktop control socket path must be absolute");
|
|
34065
34730
|
}
|
|
34066
34731
|
if (!/^[A-Za-z0-9-]+$/u.test(token) || !/[A-Za-z0-9]/u.test(token)) {
|
|
34067
34732
|
throw new Error("Shared official app-server socket token is invalid");
|
|
34068
34733
|
}
|
|
34069
34734
|
const compactToken = token.replaceAll("-", "").slice(0, 15);
|
|
34070
|
-
return
|
|
34735
|
+
return path18.posix.join(path18.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
|
|
34071
34736
|
}
|
|
34072
34737
|
function errorMessage4(error51) {
|
|
34073
34738
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
@@ -34139,7 +34804,7 @@ function createRemoteOfficialAppServerListener(input) {
|
|
|
34139
34804
|
if (ownedSocketIdentity === null) return;
|
|
34140
34805
|
const current = await socketIdentity(input.socketPath).catch(() => null);
|
|
34141
34806
|
if (current && sameUnixFileIdentity3(current, ownedSocketIdentity)) {
|
|
34142
|
-
await
|
|
34807
|
+
await rm8(input.socketPath, { force: true });
|
|
34143
34808
|
}
|
|
34144
34809
|
ownedSocketIdentity = null;
|
|
34145
34810
|
};
|
|
@@ -34500,7 +35165,7 @@ function createOwnedLoopbackBackend(input) {
|
|
|
34500
35165
|
"--ws-auth",
|
|
34501
35166
|
"capability-token",
|
|
34502
35167
|
"--ws-token-sha256",
|
|
34503
|
-
|
|
35168
|
+
createHash9("sha256").update(capabilityToken).digest("hex")
|
|
34504
35169
|
],
|
|
34505
35170
|
// Managed stderr may carry credential-bearing errors. Never forward raw bytes.
|
|
34506
35171
|
diagnosticOutput: new Writable2({
|
|
@@ -34553,21 +35218,21 @@ function createOwnedUnixBackend(input) {
|
|
|
34553
35218
|
|
|
34554
35219
|
// packages/host-runtime/src/native-account-host.ts
|
|
34555
35220
|
async function canonicalCodexHome(home) {
|
|
34556
|
-
const absolute =
|
|
35221
|
+
const absolute = path19.resolve(home);
|
|
34557
35222
|
try {
|
|
34558
35223
|
return await realpath3(absolute);
|
|
34559
35224
|
} catch (error51) {
|
|
34560
35225
|
if (!(error51 instanceof Error && "code" in error51 && error51.code === "ENOENT")) throw error51;
|
|
34561
|
-
const parent =
|
|
35226
|
+
const parent = path19.dirname(absolute);
|
|
34562
35227
|
if (parent === absolute) throw error51;
|
|
34563
|
-
return
|
|
35228
|
+
return path19.join(await canonicalCodexHome(parent), path19.basename(absolute));
|
|
34564
35229
|
}
|
|
34565
35230
|
}
|
|
34566
35231
|
async function prepareLocalCodex(input) {
|
|
34567
35232
|
const home = await canonicalCodexHome(
|
|
34568
|
-
input.environment.CODEX_HOME ??
|
|
35233
|
+
input.environment.CODEX_HOME ?? path19.join(homedir(), ".codex")
|
|
34569
35234
|
);
|
|
34570
|
-
await
|
|
35235
|
+
await mkdir8(home, { recursive: true });
|
|
34571
35236
|
const scope = new OfficialRuntimeScope({
|
|
34572
35237
|
permanentHome: home,
|
|
34573
35238
|
diagnosticOutput: input.diagnosticOutput,
|
|
@@ -34731,18 +35396,18 @@ var DelegationControlRegistry = class {
|
|
|
34731
35396
|
};
|
|
34732
35397
|
|
|
34733
35398
|
// packages/host-runtime/src/installed-harness-plugins.ts
|
|
34734
|
-
import
|
|
34735
|
-
import
|
|
35399
|
+
import os6 from "node:os";
|
|
35400
|
+
import path21 from "node:path";
|
|
34736
35401
|
import { fileURLToPath } from "node:url";
|
|
34737
35402
|
|
|
34738
35403
|
// packages/host-runtime/src/launcher-url-opener.ts
|
|
34739
35404
|
import { spawn as spawn4 } from "node:child_process";
|
|
34740
|
-
import
|
|
35405
|
+
import path20 from "node:path";
|
|
34741
35406
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
|
|
34742
35407
|
var OPEN_TIMEOUT_MS = 1e4;
|
|
34743
35408
|
function createLauncherUrlOpener(environment, spawnLauncher = (command, arguments_2, options2) => spawn4(command, arguments_2, options2)) {
|
|
34744
35409
|
const launcher = environment.CODEXHOST_LAUNCHER_EXECUTABLE;
|
|
34745
|
-
if (!launcher || !
|
|
35410
|
+
if (!launcher || !path20.isAbsolute(launcher)) return void 0;
|
|
34746
35411
|
const launcherEnvironment = Object.fromEntries(
|
|
34747
35412
|
Object.entries(environment).filter(([name]) => {
|
|
34748
35413
|
const normalized = name.toUpperCase();
|
|
@@ -34800,9 +35465,9 @@ function installedHarnessPluginOptions(environment, managedRemoteHost = false, h
|
|
|
34800
35465
|
const opener = managedRemoteHost ? void 0 : createLauncherUrlOpener(environment);
|
|
34801
35466
|
return {
|
|
34802
35467
|
pluginRoots: [
|
|
34803
|
-
|
|
34804
|
-
environment[HARNESS_PLUGIN_DIRECTORY_ENV] ??
|
|
34805
|
-
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"),
|
|
34806
35471
|
"plugins"
|
|
34807
35472
|
)
|
|
34808
35473
|
],
|
|
@@ -34926,171 +35591,10 @@ async function startDelegationControlServer(input) {
|
|
|
34926
35591
|
};
|
|
34927
35592
|
}
|
|
34928
35593
|
|
|
34929
|
-
// packages/host-runtime/src/delegation-skill.ts
|
|
34930
|
-
import { createHash as createHash8, randomUUID as randomUUID12 } from "node:crypto";
|
|
34931
|
-
import { mkdir as mkdir8, open as open6, readFile as readFile7, rename as rename5, rm as rm8, stat as stat4 } from "node:fs/promises";
|
|
34932
|
-
import os5 from "node:os";
|
|
34933
|
-
import path19 from "node:path";
|
|
34934
|
-
var SKILL_VERSION = 7;
|
|
34935
|
-
var SKILL_RELATIVE_PATH = path19.join("skills", "codexhost-delegation", "SKILL.md");
|
|
34936
|
-
var PREVIOUS_MANAGED_DIGESTS = [
|
|
34937
|
-
"9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
|
|
34938
|
-
"2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
|
|
34939
|
-
"aff258622dc8ff321f32b15620d081e578cb9c9ed1134d6a57f35ca8e7762c0a",
|
|
34940
|
-
"ba509f57e5448e796b3dfdd5031dcb08672eded50b61c0a54de84cfa02c49dd3",
|
|
34941
|
-
"d3ddf6db9bc5c5df825479c885bbbf0ca08da66f7057a12e02e1fdf57525149e",
|
|
34942
|
-
"15eb63519ff867e1536c97188a0c43738d7a49d38d4d6adeb7a1036726e7246d"
|
|
34943
|
-
];
|
|
34944
|
-
var CODEXHOST_DELEGATION_SKILL = `---
|
|
34945
|
-
name: codexhost-delegation
|
|
34946
|
-
version: ${SKILL_VERSION}
|
|
34947
|
-
description: >
|
|
34948
|
-
Delegate tasks to other coding agents, or read and follow up on existing
|
|
34949
|
-
external agent sessions. Use when the user asks another agent (including
|
|
34950
|
-
@agent) to independently perform a task, or asks to view a specified external
|
|
34951
|
-
session's content, progress, or results, send follow-up messages, wait, or
|
|
34952
|
-
cancel a task. Not for recapping the current conversation, discussing or
|
|
34953
|
-
configuring agents, or role-playing.
|
|
34954
|
-
---
|
|
34955
|
-
|
|
34956
|
-
# Execute the task
|
|
34957
|
-
|
|
34958
|
-
Before acting, run:
|
|
34959
|
-
|
|
34960
|
-
\`codexhost delegate --help\`
|
|
34961
|
-
|
|
34962
|
-
Use CLI help as the authoritative source for commands and behavior. Consult
|
|
34963
|
-
command-specific help for options and the Harness listing command when the
|
|
34964
|
-
target is unknown. Prefer compact output when supported, and use its task links
|
|
34965
|
-
directly for subsequent commands.
|
|
34966
|
-
|
|
34967
|
-
Use the Harness native defaults. Inspect the target when a Model or Thinking
|
|
34968
|
-
selection is needed or the default is unavailable.
|
|
34969
|
-
|
|
34970
|
-
For a new delegation, create an independent child session and submit the
|
|
34971
|
-
requested task. For an existing external session, resolve the target from the
|
|
34972
|
-
user-provided session link, identifier, or context and operate on that Thread
|
|
34973
|
-
directly; it need not have been created by the current assistant. If the target
|
|
34974
|
-
is ambiguous, ask the user to identify it. Keep requests to view or summarize a
|
|
34975
|
-
session read-only.
|
|
34976
|
-
|
|
34977
|
-
For a new or existing task, choose the appropriate next action based on the
|
|
34978
|
-
user’s request and the task:
|
|
34979
|
-
|
|
34980
|
-
- send a follow-up message to the same Thread;
|
|
34981
|
-
- cancel its current Turn;
|
|
34982
|
-
- read its current state immediately;
|
|
34983
|
-
- wait for a bounded period;
|
|
34984
|
-
- check it again later;
|
|
34985
|
-
- leave it running in the background.
|
|
34986
|
-
|
|
34987
|
-
Report the result returned by read or a completed wait, together with the target
|
|
34988
|
-
agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
|
|
34989
|
-
`;
|
|
34990
|
-
var CURRENT_DIGEST = createHash8("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
|
|
34991
|
-
function digest(value2) {
|
|
34992
|
-
return createHash8("sha256").update(value2).digest("hex");
|
|
34993
|
-
}
|
|
34994
|
-
function managedVersion(value2) {
|
|
34995
|
-
const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
|
|
34996
|
-
return match ? Number(match[1]) : null;
|
|
34997
|
-
}
|
|
34998
|
-
async function readOptional(filePath) {
|
|
34999
|
-
try {
|
|
35000
|
-
return await readFile7(filePath, "utf8");
|
|
35001
|
-
} catch (error51) {
|
|
35002
|
-
if (error51.code === "ENOENT") return null;
|
|
35003
|
-
throw error51;
|
|
35004
|
-
}
|
|
35005
|
-
}
|
|
35006
|
-
async function atomicWrite(filePath, content) {
|
|
35007
|
-
await mkdir8(path19.dirname(filePath), { recursive: true, mode: 448 });
|
|
35008
|
-
const temporaryPath = path19.join(path19.dirname(filePath), `.SKILL.md.${randomUUID12()}.tmp`);
|
|
35009
|
-
const handle = await open6(temporaryPath, "wx", 384);
|
|
35010
|
-
try {
|
|
35011
|
-
await handle.writeFile(content, "utf8");
|
|
35012
|
-
await handle.sync();
|
|
35013
|
-
} finally {
|
|
35014
|
-
await handle.close();
|
|
35015
|
-
}
|
|
35016
|
-
try {
|
|
35017
|
-
await rename5(temporaryPath, filePath);
|
|
35018
|
-
} finally {
|
|
35019
|
-
await rm8(temporaryPath, { force: true });
|
|
35020
|
-
}
|
|
35021
|
-
}
|
|
35022
|
-
async function installDelegationSkills(input = {}) {
|
|
35023
|
-
const home = input.homeDirectory ?? os5.homedir();
|
|
35024
|
-
const destinations = [
|
|
35025
|
-
path19.join(home, ".agents", SKILL_RELATIVE_PATH),
|
|
35026
|
-
path19.join(home, ".claude", SKILL_RELATIVE_PATH)
|
|
35027
|
-
];
|
|
35028
|
-
const knownDigests = /* @__PURE__ */ new Set([
|
|
35029
|
-
CURRENT_DIGEST,
|
|
35030
|
-
...PREVIOUS_MANAGED_DIGESTS,
|
|
35031
|
-
...input.previousManagedDigests ?? []
|
|
35032
|
-
]);
|
|
35033
|
-
const results = [];
|
|
35034
|
-
for (const destination of destinations) {
|
|
35035
|
-
const current = await readOptional(destination);
|
|
35036
|
-
if (current === CODEXHOST_DELEGATION_SKILL) {
|
|
35037
|
-
results.push({
|
|
35038
|
-
path: destination,
|
|
35039
|
-
status: "current",
|
|
35040
|
-
version: SKILL_VERSION,
|
|
35041
|
-
digest: CURRENT_DIGEST
|
|
35042
|
-
});
|
|
35043
|
-
continue;
|
|
35044
|
-
}
|
|
35045
|
-
if (current !== null) {
|
|
35046
|
-
const currentDigest = digest(current);
|
|
35047
|
-
const version2 = managedVersion(current);
|
|
35048
|
-
if (!knownDigests.has(currentDigest)) {
|
|
35049
|
-
results.push({ path: destination, status: "conflict", version: version2, digest: currentDigest });
|
|
35050
|
-
continue;
|
|
35051
|
-
}
|
|
35052
|
-
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
35053
|
-
results.push({
|
|
35054
|
-
path: destination,
|
|
35055
|
-
status: "updated",
|
|
35056
|
-
version: SKILL_VERSION,
|
|
35057
|
-
digest: CURRENT_DIGEST
|
|
35058
|
-
});
|
|
35059
|
-
continue;
|
|
35060
|
-
}
|
|
35061
|
-
await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
|
|
35062
|
-
results.push({
|
|
35063
|
-
path: destination,
|
|
35064
|
-
status: "installed",
|
|
35065
|
-
version: SKILL_VERSION,
|
|
35066
|
-
digest: CURRENT_DIGEST
|
|
35067
|
-
});
|
|
35068
|
-
}
|
|
35069
|
-
for (const result of results) {
|
|
35070
|
-
if (result.status === "conflict") continue;
|
|
35071
|
-
const source = await readFile7(result.path, "utf8");
|
|
35072
|
-
const metadata = await stat4(result.path);
|
|
35073
|
-
if (!metadata.isFile() || source !== CODEXHOST_DELEGATION_SKILL) {
|
|
35074
|
-
throw new Error(`Delegation Skill verification failed: ${result.path}`);
|
|
35075
|
-
}
|
|
35076
|
-
}
|
|
35077
|
-
const managed = results.filter((result) => result.status !== "conflict");
|
|
35078
|
-
if (managed.some((result) => result.digest !== CURRENT_DIGEST)) {
|
|
35079
|
-
throw new Error("Delegation Skill copies are inconsistent");
|
|
35080
|
-
}
|
|
35081
|
-
if (results.every((result) => result.status !== "conflict")) {
|
|
35082
|
-
const copies = await Promise.all(results.map((result) => readFile7(result.path, "utf8")));
|
|
35083
|
-
if (copies.some((copy) => copy !== copies[0])) {
|
|
35084
|
-
throw new Error("Delegation Skill copies are inconsistent");
|
|
35085
|
-
}
|
|
35086
|
-
}
|
|
35087
|
-
return results;
|
|
35088
|
-
}
|
|
35089
|
-
|
|
35090
35594
|
// packages/host-runtime/src/remote-control-app-server.ts
|
|
35091
35595
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
35092
35596
|
import { mkdir as mkdir9, open as open7, rename as rename6, rm as rm9 } from "node:fs/promises";
|
|
35093
|
-
import
|
|
35597
|
+
import path22 from "node:path";
|
|
35094
35598
|
var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
|
|
35095
35599
|
var REMOTE_CONTROL_BRIDGE_NODE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_NODE_PATH";
|
|
35096
35600
|
var REMOTE_CONTROL_BRIDGE_RUNTIME_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_RUNTIME_PATH";
|
|
@@ -35101,8 +35605,8 @@ var BRIDGE_READY_METHOD = "codexhost/remote-control-bridge/ready";
|
|
|
35101
35605
|
function absoluteEnvironmentPath2(environment, name, fallback, platform = process.platform) {
|
|
35102
35606
|
const value2 = environment[name] ?? fallback;
|
|
35103
35607
|
if (!value2) return null;
|
|
35104
|
-
if (
|
|
35105
|
-
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;
|
|
35106
35610
|
}
|
|
35107
35611
|
function nodeCompatibleWindowsPath(value2) {
|
|
35108
35612
|
if (value2.startsWith("\\\\?\\UNC\\")) return `\\\\${value2.slice(8)}`;
|
|
@@ -35116,13 +35620,13 @@ function remoteControlBridgePipePath(processId = process.pid, instanceId = rando
|
|
|
35116
35620
|
}
|
|
35117
35621
|
function remoteControlBridgeDescriptorPath(environment) {
|
|
35118
35622
|
const root = environment.LOCALAPPDATA;
|
|
35119
|
-
if (!root || !
|
|
35120
|
-
return
|
|
35623
|
+
if (!root || !path22.isAbsolute(root)) return null;
|
|
35624
|
+
return path22.join(path22.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
|
|
35121
35625
|
}
|
|
35122
35626
|
async function publishRemoteControlAppServerDescriptor(plan) {
|
|
35123
|
-
const directory =
|
|
35627
|
+
const directory = path22.dirname(plan.descriptorPath);
|
|
35124
35628
|
await mkdir9(directory, { recursive: true, mode: 448 });
|
|
35125
|
-
const temporaryPath =
|
|
35629
|
+
const temporaryPath = path22.join(
|
|
35126
35630
|
directory,
|
|
35127
35631
|
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID13()}.tmp`
|
|
35128
35632
|
);
|
|
@@ -35423,9 +35927,9 @@ function hasLauncherManagedUpdateRuntime(environment, hostRuntimePath) {
|
|
|
35423
35927
|
if (!environment[UPDATE_RUNTIME_ENV.launcherPid]) return false;
|
|
35424
35928
|
const npmPackageRoot = environment[UPDATE_RUNTIME_ENV.npmPackageRoot];
|
|
35425
35929
|
if (!npmPackageRoot || !hostRuntimePath) return true;
|
|
35426
|
-
if (!
|
|
35427
|
-
const runtimePackageRoot =
|
|
35428
|
-
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) === "";
|
|
35429
35933
|
}
|
|
35430
35934
|
function requiredRuntimeConfiguration(environment) {
|
|
35431
35935
|
const stockCodexPath = environment[STOCK_CODEX_PATH_ENV];
|
|
@@ -35571,8 +36075,8 @@ async function runHostRuntime(input) {
|
|
|
35571
36075
|
const socketPath = remoteAppServerSocketPath(delegationEnvironment, listenUrl);
|
|
35572
36076
|
const officialPlan = createRemoteOfficialAppServerPlan(input.arguments, socketPath);
|
|
35573
36077
|
const officialRuntimeScope = new OfficialRuntimeScope({
|
|
35574
|
-
permanentHome:
|
|
35575
|
-
delegationEnvironment.CODEX_HOME ??
|
|
36078
|
+
permanentHome: path23.resolve(
|
|
36079
|
+
delegationEnvironment.CODEX_HOME ?? path23.join(homedir2(), ".codex")
|
|
35576
36080
|
),
|
|
35577
36081
|
diagnosticOutput: process.stderr,
|
|
35578
36082
|
createBackend: () => createOwnedUnixBackend({
|
|
@@ -35653,7 +36157,7 @@ async function runHostRuntime(input) {
|
|
|
35653
36157
|
}
|
|
35654
36158
|
|
|
35655
36159
|
// packages/host-runtime/src/remote-host-install.ts
|
|
35656
|
-
import { createHash as
|
|
36160
|
+
import { createHash as createHash10, randomUUID as randomUUID14 } from "node:crypto";
|
|
35657
36161
|
import { constants as fsConstants } from "node:fs";
|
|
35658
36162
|
import {
|
|
35659
36163
|
access,
|
|
@@ -35661,14 +36165,14 @@ import {
|
|
|
35661
36165
|
copyFile as copyFile3,
|
|
35662
36166
|
lstat as lstat8,
|
|
35663
36167
|
mkdir as mkdir10,
|
|
35664
|
-
readFile as
|
|
36168
|
+
readFile as readFile9,
|
|
35665
36169
|
rename as rename7,
|
|
35666
36170
|
rm as rm10,
|
|
35667
36171
|
rmdir,
|
|
35668
36172
|
stat as stat5,
|
|
35669
36173
|
writeFile as writeFile4
|
|
35670
36174
|
} from "node:fs/promises";
|
|
35671
|
-
import
|
|
36175
|
+
import path24 from "node:path";
|
|
35672
36176
|
var MANIFEST_FORMAT = 1;
|
|
35673
36177
|
var WRAPPER_MARKER = "# codexhost remote SSH wrapper v1";
|
|
35674
36178
|
var PROFILE_START = "# >>> codexhost remote SSH >>>";
|
|
@@ -35679,25 +36183,25 @@ function resolvePaths(options2) {
|
|
|
35679
36183
|
if (!configuredHome) {
|
|
35680
36184
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
35681
36185
|
}
|
|
35682
|
-
const home =
|
|
35683
|
-
if (!home || home ===
|
|
36186
|
+
const home = path24.resolve(configuredHome);
|
|
36187
|
+
if (!home || home === path24.parse(home).root) {
|
|
35684
36188
|
throw new Error("A non-root HOME is required for remote Host installation");
|
|
35685
36189
|
}
|
|
35686
|
-
const installRoot =
|
|
35687
|
-
const profilePath =
|
|
35688
|
-
options2.profilePath ??
|
|
36190
|
+
const installRoot = path24.resolve(options2.installRoot ?? path24.join(home, ".codexhost", "remote"));
|
|
36191
|
+
const profilePath = path24.resolve(
|
|
36192
|
+
options2.profilePath ?? path24.join(
|
|
35689
36193
|
home,
|
|
35690
|
-
|
|
36194
|
+
path24.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path24.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
|
|
35691
36195
|
)
|
|
35692
36196
|
);
|
|
35693
|
-
const binDirectory =
|
|
36197
|
+
const binDirectory = path24.join(installRoot, "bin");
|
|
35694
36198
|
return {
|
|
35695
36199
|
home,
|
|
35696
36200
|
installRoot,
|
|
35697
36201
|
binDirectory,
|
|
35698
|
-
wrapperPath:
|
|
35699
|
-
manifestPath:
|
|
35700
|
-
dataDirectory:
|
|
36202
|
+
wrapperPath: path24.join(binDirectory, "codex"),
|
|
36203
|
+
manifestPath: path24.join(installRoot, "manifest.json"),
|
|
36204
|
+
dataDirectory: path24.join(installRoot, "data"),
|
|
35701
36205
|
profilePath
|
|
35702
36206
|
};
|
|
35703
36207
|
}
|
|
@@ -35706,17 +36210,17 @@ function shellQuote(value2) {
|
|
|
35706
36210
|
}
|
|
35707
36211
|
async function existingText(filePath) {
|
|
35708
36212
|
try {
|
|
35709
|
-
return await
|
|
36213
|
+
return await readFile9(filePath, "utf8");
|
|
35710
36214
|
} catch (error51) {
|
|
35711
36215
|
if (error51.code === "ENOENT") return null;
|
|
35712
36216
|
throw error51;
|
|
35713
36217
|
}
|
|
35714
36218
|
}
|
|
35715
36219
|
async function fileSha256(filePath) {
|
|
35716
|
-
return
|
|
36220
|
+
return createHash10("sha256").update(await readFile9(filePath)).digest("hex");
|
|
35717
36221
|
}
|
|
35718
36222
|
async function executable(filePath, label) {
|
|
35719
|
-
const absolute =
|
|
36223
|
+
const absolute = path24.resolve(filePath);
|
|
35720
36224
|
try {
|
|
35721
36225
|
if (!(await stat5(absolute)).isFile()) throw new Error("not a regular file");
|
|
35722
36226
|
await access(absolute, fsConstants.X_OK);
|
|
@@ -35726,7 +36230,7 @@ async function executable(filePath, label) {
|
|
|
35726
36230
|
return absolute;
|
|
35727
36231
|
}
|
|
35728
36232
|
async function existingFile(filePath, label) {
|
|
35729
|
-
const absolute =
|
|
36233
|
+
const absolute = path24.resolve(filePath);
|
|
35730
36234
|
try {
|
|
35731
36235
|
const metadata = await stat5(absolute);
|
|
35732
36236
|
if (!metadata.isFile()) throw new Error("not a regular file");
|
|
@@ -35736,9 +36240,9 @@ async function existingFile(filePath, label) {
|
|
|
35736
36240
|
return absolute;
|
|
35737
36241
|
}
|
|
35738
36242
|
async function discoverExecutable(name, environment) {
|
|
35739
|
-
for (const directory of (environment.PATH ?? "").split(
|
|
36243
|
+
for (const directory of (environment.PATH ?? "").split(path24.delimiter)) {
|
|
35740
36244
|
if (!directory) continue;
|
|
35741
|
-
const candidate =
|
|
36245
|
+
const candidate = path24.resolve(directory, name);
|
|
35742
36246
|
try {
|
|
35743
36247
|
await access(candidate, fsConstants.X_OK);
|
|
35744
36248
|
return candidate;
|
|
@@ -35749,10 +36253,10 @@ async function discoverExecutable(name, environment) {
|
|
|
35749
36253
|
return null;
|
|
35750
36254
|
}
|
|
35751
36255
|
async function writeAtomic(filePath, contents, mode) {
|
|
35752
|
-
await mkdir10(
|
|
35753
|
-
const temporary =
|
|
35754
|
-
|
|
35755
|
-
`.${
|
|
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`
|
|
35756
36260
|
);
|
|
35757
36261
|
try {
|
|
35758
36262
|
if (typeof contents === "string") {
|
|
@@ -35773,10 +36277,10 @@ async function writeAtomic(filePath, contents, mode) {
|
|
|
35773
36277
|
}
|
|
35774
36278
|
}
|
|
35775
36279
|
async function writeAtomicExecutable(filePath, sourcePath) {
|
|
35776
|
-
await mkdir10(
|
|
35777
|
-
const temporary =
|
|
35778
|
-
|
|
35779
|
-
`.${
|
|
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`
|
|
35780
36284
|
);
|
|
35781
36285
|
try {
|
|
35782
36286
|
await copyFile3(sourcePath, temporary);
|
|
@@ -35817,15 +36321,14 @@ function removeManagedProfileBlock(contents) {
|
|
|
35817
36321
|
function installManagedProfileBlock(contents, manifest) {
|
|
35818
36322
|
const base = removeManagedProfileBlock(contents);
|
|
35819
36323
|
const environment = [
|
|
35820
|
-
`export CODEX_INSTALL_DIR=${shellQuote(
|
|
35821
|
-
`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}"`,
|
|
35822
36326
|
`export CODEXHOST_STOCK_CODEX_PATH=${shellQuote(manifest.stockCodexPath)}`,
|
|
35823
36327
|
`export CODEXHOST_HOST_NODE_PATH=${shellQuote(manifest.nodePath)}`,
|
|
35824
36328
|
`export CODEXHOST_HOST_RUNTIME_PATH=${shellQuote(manifest.hostRuntimePath)}`,
|
|
35825
36329
|
`export CODEXHOST_DATA_DIR=${shellQuote(manifest.dataDirectory)}`,
|
|
35826
36330
|
"export CODEXHOST_DEFAULT_AGENT='codex'",
|
|
35827
|
-
"export CODEXHOST_REMOTE_SSH_MANAGED='1'"
|
|
35828
|
-
...manifest.claudeCommand ? [`export CODEXHOST_CLAUDE_COMMAND=${shellQuote(manifest.claudeCommand)}`] : []
|
|
36331
|
+
"export CODEXHOST_REMOTE_SSH_MANAGED='1'"
|
|
35829
36332
|
];
|
|
35830
36333
|
const block = [
|
|
35831
36334
|
PROFILE_START,
|
|
@@ -35835,7 +36338,7 @@ function installManagedProfileBlock(contents, manifest) {
|
|
|
35835
36338
|
PROFILE_END,
|
|
35836
36339
|
""
|
|
35837
36340
|
].join("\n");
|
|
35838
|
-
if (
|
|
36341
|
+
if (path24.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
|
|
35839
36342
|
const separator = base.length > 0 && !base.endsWith("\n") ? "\n" : "";
|
|
35840
36343
|
return `${base}${separator}${block}`;
|
|
35841
36344
|
}
|
|
@@ -35847,16 +36350,16 @@ async function managedEntrypointState(manifest) {
|
|
|
35847
36350
|
if (metadata === null) return "missing";
|
|
35848
36351
|
if (!metadata.isFile()) return "modified";
|
|
35849
36352
|
if (process.platform !== "win32" && (metadata.mode & 73) === 0) return "modified";
|
|
35850
|
-
const entrypoint = await
|
|
36353
|
+
const entrypoint = await readFile9(manifest.wrapperPath);
|
|
35851
36354
|
if (entrypoint.subarray(0, 256).toString("utf8").startsWith(`#!/usr/bin/env sh
|
|
35852
36355
|
${WRAPPER_MARKER}
|
|
35853
36356
|
`)) {
|
|
35854
36357
|
return "legacy-wrapper";
|
|
35855
36358
|
}
|
|
35856
36359
|
if (manifest.entrypointSha256 !== void 0) {
|
|
35857
|
-
return
|
|
36360
|
+
return createHash10("sha256").update(entrypoint).digest("hex") === manifest.entrypointSha256 ? "native" : "modified";
|
|
35858
36361
|
}
|
|
35859
|
-
const shim = await
|
|
36362
|
+
const shim = await readFile9(manifest.shimPath).catch((error51) => {
|
|
35860
36363
|
if (error51.code === "ENOENT") return null;
|
|
35861
36364
|
throw error51;
|
|
35862
36365
|
});
|
|
@@ -35887,6 +36390,7 @@ async function readManifest(filePath) {
|
|
|
35887
36390
|
"dataDirectory",
|
|
35888
36391
|
"entrypointSha256",
|
|
35889
36392
|
"claudeCommand",
|
|
36393
|
+
// Inert metadata accepted from older format-1 manifests.
|
|
35890
36394
|
"profileBackupPath"
|
|
35891
36395
|
]);
|
|
35892
36396
|
const requiredPaths = [
|
|
@@ -35900,9 +36404,9 @@ async function readManifest(filePath) {
|
|
|
35900
36404
|
];
|
|
35901
36405
|
const optionalPaths = ["claudeCommand", "profileBackupPath"];
|
|
35902
36406
|
if (manifest.format !== MANIFEST_FORMAT || Object.keys(manifest).some((key) => !allowed.has(key)) || requiredPaths.some(
|
|
35903
|
-
(key) => typeof manifest[key] !== "string" || !
|
|
36407
|
+
(key) => typeof manifest[key] !== "string" || !path24.isAbsolute(manifest[key])
|
|
35904
36408
|
) || optionalPaths.some(
|
|
35905
|
-
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !
|
|
36409
|
+
(key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path24.isAbsolute(manifest[key]))
|
|
35906
36410
|
) || manifest.entrypointSha256 !== void 0 && (typeof manifest.entrypointSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(manifest.entrypointSha256))) {
|
|
35907
36411
|
throw new Error("Remote Host manifest has an unsupported format");
|
|
35908
36412
|
}
|
|
@@ -35924,7 +36428,7 @@ async function installRemoteHost(options2) {
|
|
|
35924
36428
|
const paths = resolvePaths(options2);
|
|
35925
36429
|
const previousManifest = await readManifest(paths.manifestPath);
|
|
35926
36430
|
const previousManifestFile = previousManifest ? {
|
|
35927
|
-
contents: await
|
|
36431
|
+
contents: await readFile9(paths.manifestPath),
|
|
35928
36432
|
mode: (await stat5(paths.manifestPath)).mode & 511
|
|
35929
36433
|
} : null;
|
|
35930
36434
|
const existingEntrypoint = await lstat8(paths.wrapperPath).catch(
|
|
@@ -35949,7 +36453,7 @@ async function installRemoteHost(options2) {
|
|
|
35949
36453
|
}
|
|
35950
36454
|
const profilePath = previousManifest?.profilePath ?? paths.profilePath;
|
|
35951
36455
|
const previousEntrypoint = existingEntrypoint?.isFile() ? {
|
|
35952
|
-
contents: await
|
|
36456
|
+
contents: await readFile9(paths.wrapperPath),
|
|
35953
36457
|
mode: existingEntrypoint.mode & 511
|
|
35954
36458
|
} : null;
|
|
35955
36459
|
const discoveredStock = options2.stockCodexPath ?? previousManifest?.stockCodexPath ?? await discoverExecutable("codex", environment);
|
|
@@ -35966,8 +36470,6 @@ async function installRemoteHost(options2) {
|
|
|
35966
36470
|
const nodePath2 = await executable(options2.nodePath, "Node runtime");
|
|
35967
36471
|
const shimPath = await executable(options2.shimPath, "codexhost Shim");
|
|
35968
36472
|
const hostRuntimePath = await existingFile(options2.hostRuntimePath, "codexhost Host Runtime");
|
|
35969
|
-
const discoveredClaude = options2.claudeCommand ?? previousManifest?.claudeCommand ?? await discoverExecutable("claude", environment);
|
|
35970
|
-
const claudeCommand = discoveredClaude ? await executable(discoveredClaude, "Claude Code command") : void 0;
|
|
35971
36473
|
let manifest = {
|
|
35972
36474
|
format: MANIFEST_FORMAT,
|
|
35973
36475
|
wrapperPath: paths.wrapperPath,
|
|
@@ -35977,7 +36479,6 @@ async function installRemoteHost(options2) {
|
|
|
35977
36479
|
shimPath,
|
|
35978
36480
|
hostRuntimePath,
|
|
35979
36481
|
dataDirectory: paths.dataDirectory,
|
|
35980
|
-
...claudeCommand ? { claudeCommand } : {},
|
|
35981
36482
|
...previousManifest?.profileBackupPath ? { profileBackupPath: previousManifest.profileBackupPath } : {}
|
|
35982
36483
|
};
|
|
35983
36484
|
const existingProfileSource = await existingText(profilePath);
|
|
@@ -36131,7 +36632,7 @@ async function uninstallRemoteHost(options2) {
|
|
|
36131
36632
|
import { spawn as spawn5 } from "node:child_process";
|
|
36132
36633
|
import { stat as stat6 } from "node:fs/promises";
|
|
36133
36634
|
import net3 from "node:net";
|
|
36134
|
-
import
|
|
36635
|
+
import path25 from "node:path";
|
|
36135
36636
|
import { Duplex } from "node:stream";
|
|
36136
36637
|
var CODEXHOST_STATUS_METHOD = "codexhost/update/status";
|
|
36137
36638
|
var DIRECT_PROBE_TIMEOUT_MS = 5e3;
|
|
@@ -36150,9 +36651,9 @@ function classifyRemoteHostProbeResponse(response, socketPath) {
|
|
|
36150
36651
|
}
|
|
36151
36652
|
var lifecycleDependencyOverrides = {};
|
|
36152
36653
|
function socketPathFor(environment) {
|
|
36153
|
-
const codexHome = environment.CODEX_HOME ?? (environment.HOME ?
|
|
36654
|
+
const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path25.join(environment.HOME, ".codex") : void 0);
|
|
36154
36655
|
if (!codexHome) throw new Error("CODEX_HOME or HOME is required for remote Host lifecycle");
|
|
36155
|
-
return
|
|
36656
|
+
return path25.join(codexHome, "app-server-control", "app-server-control.sock");
|
|
36156
36657
|
}
|
|
36157
36658
|
async function defaultSocketExists(socketPath) {
|
|
36158
36659
|
const metadata = await stat6(socketPath).catch((error51) => {
|
|
@@ -36279,15 +36780,14 @@ function installedManifest(status) {
|
|
|
36279
36780
|
function managedEnvironment(manifest, environment) {
|
|
36280
36781
|
return {
|
|
36281
36782
|
...environment,
|
|
36282
|
-
CODEX_INSTALL_DIR:
|
|
36783
|
+
CODEX_INSTALL_DIR: path25.dirname(manifest.wrapperPath),
|
|
36283
36784
|
CODEXHOST_STOCK_CODEX_PATH: manifest.stockCodexPath,
|
|
36284
36785
|
CODEXHOST_HOST_NODE_PATH: manifest.nodePath,
|
|
36285
36786
|
CODEXHOST_HOST_RUNTIME_PATH: manifest.hostRuntimePath,
|
|
36286
36787
|
CODEXHOST_DATA_DIR: manifest.dataDirectory,
|
|
36287
36788
|
CODEXHOST_DEFAULT_AGENT: "codex",
|
|
36288
36789
|
CODEXHOST_REMOTE_SSH_MANAGED: "1",
|
|
36289
|
-
|
|
36290
|
-
PATH: `${path23.dirname(manifest.wrapperPath)}${path23.delimiter}${path23.dirname(manifest.stockCodexPath)}${path23.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
|
|
36790
|
+
PATH: `${path25.dirname(manifest.wrapperPath)}${path25.delimiter}${path25.dirname(manifest.stockCodexPath)}${path25.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
|
|
36291
36791
|
};
|
|
36292
36792
|
}
|
|
36293
36793
|
async function defaultRunTerminator(manifest, socketPath, role, environment) {
|
|
@@ -36435,9 +36935,6 @@ function parseRemoteCliArguments(arguments_2) {
|
|
|
36435
36935
|
case "--stock-codex":
|
|
36436
36936
|
options2.stockCodexPath = value2;
|
|
36437
36937
|
break;
|
|
36438
|
-
case "--claude-command":
|
|
36439
|
-
options2.claudeCommand = value2;
|
|
36440
|
-
break;
|
|
36441
36938
|
case "--node":
|
|
36442
36939
|
resources.nodePath = value2;
|
|
36443
36940
|
break;
|
|
@@ -36464,7 +36961,7 @@ async function runRemoteHostCli(input) {
|
|
|
36464
36961
|
output.write(
|
|
36465
36962
|
[
|
|
36466
36963
|
"usage:",
|
|
36467
|
-
" codexhost remote install [--stock-codex PATH]
|
|
36964
|
+
" codexhost remote install [--stock-codex PATH]",
|
|
36468
36965
|
" codexhost remote start",
|
|
36469
36966
|
" codexhost remote stop",
|
|
36470
36967
|
" codexhost remote status",
|
|
@@ -36625,26 +37122,26 @@ function consumeBrokerFrames(socket, onFrame, onError) {
|
|
|
36625
37122
|
}
|
|
36626
37123
|
|
|
36627
37124
|
// packages/harness-broker/dist/paths.js
|
|
36628
|
-
import
|
|
36629
|
-
import
|
|
37125
|
+
import os7 from "node:os";
|
|
37126
|
+
import path26 from "node:path";
|
|
36630
37127
|
var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
|
|
36631
37128
|
var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
|
|
36632
37129
|
var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
|
|
36633
37130
|
function defaultHarnessBrokerDirectory(environment = process.env) {
|
|
36634
|
-
const home = environment.HOME ||
|
|
36635
|
-
return
|
|
37131
|
+
const home = environment.HOME || os7.homedir();
|
|
37132
|
+
return path26.join(home, ".codexhost", "harness-broker");
|
|
36636
37133
|
}
|
|
36637
37134
|
function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
|
|
36638
37135
|
harnessPluginIdSchema.parse(harnessId);
|
|
36639
37136
|
if (harnessId !== "claude-code")
|
|
36640
|
-
return
|
|
36641
|
-
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);
|
|
36642
37139
|
}
|
|
36643
37140
|
function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
|
|
36644
37141
|
harnessPluginIdSchema.parse(harnessId);
|
|
36645
37142
|
if (harnessId !== "claude-code")
|
|
36646
|
-
return
|
|
36647
|
-
return
|
|
37143
|
+
return path26.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
|
|
37144
|
+
return path26.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
|
|
36648
37145
|
}
|
|
36649
37146
|
|
|
36650
37147
|
// packages/harness-broker/dist/validation.js
|
|
@@ -36858,9 +37355,9 @@ var harnessOutputSchema = external_exports.custom((value2) => {
|
|
|
36858
37355
|
|
|
36859
37356
|
// packages/harness-broker/dist/server.js
|
|
36860
37357
|
import { randomBytes as randomBytes3, randomUUID as randomUUID15 } from "node:crypto";
|
|
36861
|
-
import { chmod as chmod5, lstat as lstat9, mkdir as mkdir11, open as open8, readFile as
|
|
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";
|
|
36862
37359
|
import net4, {} from "node:net";
|
|
36863
|
-
import
|
|
37360
|
+
import path27 from "node:path";
|
|
36864
37361
|
function harnessError(message, retryable = true) {
|
|
36865
37362
|
return { code: "unavailable", message, retryable, stage: "harnessBroker" };
|
|
36866
37363
|
}
|
|
@@ -36906,7 +37403,7 @@ async function assertNoLiveDescriptor(descriptorPath) {
|
|
|
36906
37403
|
throw new Error("Harness broker descriptor is not owner-only");
|
|
36907
37404
|
}
|
|
36908
37405
|
}
|
|
36909
|
-
const descriptor = harnessBrokerDescriptorSchema.parse(JSON.parse(await
|
|
37406
|
+
const descriptor = harnessBrokerDescriptorSchema.parse(JSON.parse(await readFile10(descriptorPath, "utf8")));
|
|
36910
37407
|
if (processIsAlive2(descriptor.ownerPid)) {
|
|
36911
37408
|
throw new Error("Harness broker descriptor already has a live owner");
|
|
36912
37409
|
}
|
|
@@ -36983,13 +37480,13 @@ async function prepareUnixSocketPath(socketPath) {
|
|
|
36983
37480
|
}
|
|
36984
37481
|
async function startHarnessBrokerServer(input) {
|
|
36985
37482
|
harnessPluginIdSchema.parse(input.adapter.harnessId);
|
|
36986
|
-
if (process.platform !== "win32" &&
|
|
37483
|
+
if (process.platform !== "win32" && path27.dirname(input.descriptorPath) !== path27.dirname(input.socketPath)) {
|
|
36987
37484
|
throw new Error("Harness broker descriptor and socket must share one private directory");
|
|
36988
37485
|
}
|
|
36989
37486
|
if (process.platform === "darwin" && Buffer.byteLength(input.socketPath) > 103) {
|
|
36990
37487
|
throw new Error("Harness broker Unix socket path is too long for macOS");
|
|
36991
37488
|
}
|
|
36992
|
-
await privateDirectory(
|
|
37489
|
+
await privateDirectory(path27.dirname(input.descriptorPath));
|
|
36993
37490
|
await assertNoLiveDescriptor(input.descriptorPath);
|
|
36994
37491
|
if (process.platform !== "win32")
|
|
36995
37492
|
await prepareUnixSocketPath(input.socketPath);
|