@codexhost/cli-win32-arm64 0.13.3 → 0.14.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/app/codexhost-distribution.json +1 -1
- package/app/console-server.mjs +58 -5
- package/app/console-web.js +437 -68
- package/app/desktop-controller.mjs +72 -9
- package/app/host-runtime.mjs +766 -214
- package/app/plugins/antigravity/plugin.mjs +91 -13
- package/app/plugins/claude-code/plugin.mjs +407 -26
- package/app/plugins/codebuddy/plugin.mjs +117 -22
- package/app/plugins/codex-usage/plugin.mjs +176 -74
- package/app/plugins/copilot/assets/icon.png +0 -0
- package/app/plugins/copilot/manifest.json +26 -0
- package/app/plugins/copilot/plugin.mjs +34546 -0
- package/app/plugins/cursor-cli/plugin.mjs +20701 -44819
- package/app/plugins/deepseek-harness/plugin.mjs +83 -11
- package/app/plugins/enabled.json +1 -0
- package/app/plugins/grok/plugin.mjs +214 -24
- package/app/plugins/hermes/plugin.mjs +80 -9
- package/app/plugins/kimi-code/plugin.mjs +76 -7
- package/app/plugins/kiro-cli/plugin.mjs +76 -7
- package/app/plugins/omp/plugin.mjs +2155 -2000
- package/app/plugins/opencode/plugin.mjs +85 -11
- package/app/plugins/pi/plugin.mjs +2547 -2300
- package/app/plugins/qoder/plugin.mjs +83 -11
- package/app/plugins/qoder-cn/plugin.mjs +83 -11
- package/app/plugins/workbuddy/plugin.mjs +378 -46
- package/app/plugins/zcode/plugin.mjs +84 -11
- package/app/renderer-extension.js +834 -163
- package/bin/codexhost.exe +0 -0
- package/libexec/codexhost-node-repl.exe +0 -0
- package/libexec/codexhost-shim.exe +0 -0
- package/libexec/codexhost-updater.exe +0 -0
- package/package.json +1 -1
package/app/host-runtime.mjs
CHANGED
|
@@ -3716,8 +3716,10 @@ List Harnesses available in the active Runtime.`,
|
|
|
3716
3716
|
"harness inspect": `codexhost harness inspect <harness> [--cwd <path>] [--refresh true|false] [--format json|compact]
|
|
3717
3717
|
Read available Models, native defaults, Thinking options, and configuration capabilities.
|
|
3718
3718
|
Use the returned Model and Thinking IDs for explicit selections.`,
|
|
3719
|
-
"delegate start": `codexhost delegate start --harness <id> --task <text> [--cwd <path>] [--model <opaque-ref>] [--thinking <option-id>] [--parent-thread <thread>] [--request-id <id>] [--watch true|false] [--watch-timeout-ms <n>] [--format json|compact]
|
|
3719
|
+
"delegate start": `codexhost delegate start --harness <id> --task <text> [--task-name <name>] [--cwd <path>] [--model <opaque-ref>] [--thinking <option-id>] [--parent-thread <thread>] [--request-id <id>] [--watch true|false] [--watch-timeout-ms <n>] [--format json|compact]
|
|
3720
3720
|
Create an independent child Thread, submit the task, and return immediately.
|
|
3721
|
+
--task-name supplies a short subtask name (1-120 characters); otherwise the first task line is used.
|
|
3722
|
+
The child title is "subtask name · parent title", fixed at creation; renaming the parent does not rename existing children.
|
|
3721
3723
|
Omit --model and --thinking to use the Harness native defaults.
|
|
3722
3724
|
--cwd overrides the child workspace. Otherwise use the resolved parent Thread workspace, then the Host Runtime process cwd.
|
|
3723
3725
|
--parent-thread overrides caller inference. PARENT_THREAD_AMBIGUOUS requires an explicit parent.
|
|
@@ -4161,6 +4163,7 @@ async function runDelegationCli(input) {
|
|
|
4161
4163
|
rejectUnknown(parsed2, [
|
|
4162
4164
|
"--harness",
|
|
4163
4165
|
"--task",
|
|
4166
|
+
"--task-name",
|
|
4164
4167
|
"--cwd",
|
|
4165
4168
|
"--model",
|
|
4166
4169
|
"--thinking",
|
|
@@ -4195,6 +4198,7 @@ async function runDelegationCli(input) {
|
|
|
4195
4198
|
body: {
|
|
4196
4199
|
harnessId,
|
|
4197
4200
|
task,
|
|
4201
|
+
...value(parsed2, "--task-name") !== void 0 ? { taskName: value(parsed2, "--task-name") } : {},
|
|
4198
4202
|
...value(parsed2, "--cwd") ? { cwd: value(parsed2, "--cwd") } : {},
|
|
4199
4203
|
...value(parsed2, "--model") ? { model: { id: value(parsed2, "--model") } } : {},
|
|
4200
4204
|
...value(parsed2, "--thinking") ? { thinkingOptionId: value(parsed2, "--thinking") } : {},
|
|
@@ -20089,10 +20093,19 @@ var model = external_exports.string().min(1).max(512);
|
|
|
20089
20093
|
var project = external_exports.string().min(1).max(4096);
|
|
20090
20094
|
var usageStatisticsParamsSchema = external_exports.strictObject({
|
|
20091
20095
|
range: external_exports.enum(USAGE_STATISTICS_RANGES),
|
|
20096
|
+
/** Display timezone for ranges, dates and hourly buckets; omitted means the Host's local zone. */
|
|
20097
|
+
timeZone: external_exports.string().min(1).max(128).refine((value2) => {
|
|
20098
|
+
try {
|
|
20099
|
+
new Intl.DateTimeFormat("en", { timeZone: value2 });
|
|
20100
|
+
return true;
|
|
20101
|
+
} catch {
|
|
20102
|
+
return false;
|
|
20103
|
+
}
|
|
20104
|
+
}, "Unsupported usage statistics timezone").optional(),
|
|
20092
20105
|
harness: harness.optional(),
|
|
20093
20106
|
model: model.nullable().optional(),
|
|
20094
20107
|
project: project.nullable().optional(),
|
|
20095
|
-
/** One
|
|
20108
|
+
/** One date in the query timezone inside the range. */
|
|
20096
20109
|
date: localDate.optional()
|
|
20097
20110
|
});
|
|
20098
20111
|
var usageStatisticsTotalsSchema = external_exports.strictObject({
|
|
@@ -20128,7 +20141,7 @@ var usageStatisticsSessionSchema = external_exports.strictObject({
|
|
|
20128
20141
|
});
|
|
20129
20142
|
var usageStatisticsResultSchema = external_exports.strictObject({
|
|
20130
20143
|
range: external_exports.enum(USAGE_STATISTICS_RANGES),
|
|
20131
|
-
/** First
|
|
20144
|
+
/** First date in the query timezone (Host local when omitted); null for all time. */
|
|
20132
20145
|
from: localDate.nullable(),
|
|
20133
20146
|
to: localDate,
|
|
20134
20147
|
/** The filters these figures apply, echoed so a late answer to older filters is recognised. */
|
|
@@ -20168,7 +20181,7 @@ var usageStatisticsResultSchema = external_exports.strictObject({
|
|
|
20168
20181
|
totals: usageStatisticsTotalsSchema,
|
|
20169
20182
|
/** Each date and Harness of the range: every filter except the day. */
|
|
20170
20183
|
daily: external_exports.array(external_exports.strictObject({ date: localDate, harness, ...totals })).max(2e5),
|
|
20171
|
-
/**
|
|
20184
|
+
/** Weekday (0 = Sunday) and hour in the query timezone, all filters applied. */
|
|
20172
20185
|
hourly: external_exports.array(external_exports.strictObject({
|
|
20173
20186
|
weekday: external_exports.number().int().min(0).max(6),
|
|
20174
20187
|
hour: external_exports.number().int().min(0).max(23),
|
|
@@ -20231,6 +20244,8 @@ var CONSOLE_HOST_METHODS = Object.freeze([
|
|
|
20231
20244
|
"codexhost/harness/display-settings/set",
|
|
20232
20245
|
"codexhost/harness/inspect",
|
|
20233
20246
|
"codexhost/harness/installation",
|
|
20247
|
+
"codexhost/harness/installation/start",
|
|
20248
|
+
"codexhost/harness/installation/status",
|
|
20234
20249
|
"codexhost/harness/launch-settings/get",
|
|
20235
20250
|
"codexhost/harness/launch-settings/set",
|
|
20236
20251
|
"codexhost/harness/web-ui/open",
|
|
@@ -20312,7 +20327,18 @@ var threadManualCompactionStartedSchema = external_exports.strictObject({
|
|
|
20312
20327
|
var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
|
|
20313
20328
|
var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
|
|
20314
20329
|
var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
|
|
20330
|
+
var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text) => text.length <= maximum));
|
|
20331
|
+
var composerIndicatorsSchema = external_exports.array(external_exports.object({
|
|
20332
|
+
kind: external_exports.literal("countdown"),
|
|
20333
|
+
id: external_exports.string().min(1).max(64),
|
|
20334
|
+
expiresAtUnix: nonNegativeSafeIntegerSchema,
|
|
20335
|
+
label: indicatorTextSchema(256).optional(),
|
|
20336
|
+
tooltip: indicatorTextSchema(1024).optional()
|
|
20337
|
+
}).strict()).max(2).refine((entries) => new Set(entries.map(({ id: id2 }) => id2)).size === entries.length, {
|
|
20338
|
+
message: "Composer indicator IDs must be unique"
|
|
20339
|
+
});
|
|
20315
20340
|
var threadUsageSnapshotSchema = external_exports.object({
|
|
20341
|
+
composerIndicators: composerIndicatorsSchema.optional(),
|
|
20316
20342
|
inputTokens: nonNegativeSafeIntegerSchema.optional(),
|
|
20317
20343
|
cachedInputTokens: nonNegativeSafeIntegerSchema.optional(),
|
|
20318
20344
|
cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
|
|
@@ -20728,7 +20754,9 @@ var harnessSessionCapabilitiesSchema = external_exports.object({
|
|
|
20728
20754
|
}).strict().optional(),
|
|
20729
20755
|
autonomousTurns: external_exports.object({
|
|
20730
20756
|
observe: external_exports.boolean()
|
|
20731
|
-
}).strict().optional()
|
|
20757
|
+
}).strict().optional(),
|
|
20758
|
+
/** True only when `turn.steer` delivers input into the active Turn through a native primitive. */
|
|
20759
|
+
steer: external_exports.boolean().optional()
|
|
20732
20760
|
}).strict();
|
|
20733
20761
|
var harnessConfigurationStateSchema = external_exports.object({
|
|
20734
20762
|
effectiveModel: harnessModelRefSchema.optional(),
|
|
@@ -20776,7 +20804,9 @@ var harnessInspectionSchema = external_exports.union([
|
|
|
20776
20804
|
var harnessInspectParamsSchema = external_exports.object({
|
|
20777
20805
|
harnessId: harnessIdSchema,
|
|
20778
20806
|
cwd: nonBlankTextSchema2.max(16384).optional(),
|
|
20779
|
-
refresh: external_exports.boolean().optional()
|
|
20807
|
+
refresh: external_exports.boolean().optional(),
|
|
20808
|
+
/** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
|
|
20809
|
+
purpose: external_exports.literal("availability").optional()
|
|
20780
20810
|
}).strict();
|
|
20781
20811
|
var harnessWebUiOpenParamsSchema = external_exports.object({
|
|
20782
20812
|
harnessId: harnessIdSchema
|
|
@@ -20859,6 +20889,16 @@ var threadOwnershipListResultSchema = external_exports.object({
|
|
|
20859
20889
|
seen.add(thread.threadId);
|
|
20860
20890
|
}
|
|
20861
20891
|
});
|
|
20892
|
+
var threadSteeringInspectParamsSchema = external_exports.object({
|
|
20893
|
+
threadId: hostThreadIdSchema,
|
|
20894
|
+
/** The text about to be steered; a Harness command always stops and restarts. */
|
|
20895
|
+
text: external_exports.string().optional()
|
|
20896
|
+
}).strict();
|
|
20897
|
+
var THREAD_STEER_DELIVERY_PARAM = "codexhostSteerDelivery";
|
|
20898
|
+
var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
|
|
20899
|
+
var threadSteeringInspectResultSchema = external_exports.object({
|
|
20900
|
+
delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
|
|
20901
|
+
}).strict();
|
|
20862
20902
|
|
|
20863
20903
|
// packages/shared-contracts/dist/harness-plugins.js
|
|
20864
20904
|
var HARNESS_PLUGIN_API_VERSION = 1;
|
|
@@ -20979,6 +21019,8 @@ var harnessLaunchSettingsSchema = external_exports.object({
|
|
|
20979
21019
|
|
|
20980
21020
|
// packages/shared-contracts/dist/harness-installation.js
|
|
20981
21021
|
var HARNESS_INSTALLATION_METHOD = "codexhost/harness/installation";
|
|
21022
|
+
var HARNESS_INSTALLATION_START_METHOD = "codexhost/harness/installation/start";
|
|
21023
|
+
var HARNESS_INSTALLATION_STATUS_METHOD = "codexhost/harness/installation/status";
|
|
20982
21024
|
var harnessInstallationParamsSchema = external_exports.object({
|
|
20983
21025
|
harnessId: harnessIdSchema,
|
|
20984
21026
|
action: external_exports.enum(["check", "update", "install"])
|
|
@@ -20988,6 +21030,10 @@ var harnessInstallationStateSchema = external_exports.object({
|
|
|
20988
21030
|
latestVersion: external_exports.string().min(1).max(128),
|
|
20989
21031
|
updateAvailable: external_exports.boolean(),
|
|
20990
21032
|
canUpdate: external_exports.boolean(),
|
|
21033
|
+
/** Defaults to CLI; some Harnesses ship only inside a desktop application. */
|
|
21034
|
+
versionKind: external_exports.enum(["cli", "application"]).optional(),
|
|
21035
|
+
/** Official download opened by the user; does not imply an automatic installation. */
|
|
21036
|
+
manualUpdateUrl: external_exports.url().max(2048).refine((value2) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value2), "Manual updates require a credential-free HTTPS URL").optional(),
|
|
20991
21037
|
// Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
|
|
20992
21038
|
message: external_exports.string().max(2048).optional(),
|
|
20993
21039
|
messageCode: external_exports.string().min(1).max(128).optional(),
|
|
@@ -20995,6 +21041,20 @@ var harnessInstallationStateSchema = external_exports.object({
|
|
|
20995
21041
|
notice: harnessLocalizedTextSchema.optional(),
|
|
20996
21042
|
latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
|
|
20997
21043
|
}).strict();
|
|
21044
|
+
var harnessInstallationTaskParamsSchema = external_exports.object({ taskId: external_exports.string().uuid() }).strict();
|
|
21045
|
+
var harnessInstallationTaskSchema = external_exports.discriminatedUnion("status", [
|
|
21046
|
+
external_exports.object({ taskId: external_exports.string().uuid(), status: external_exports.literal("running") }).strict(),
|
|
21047
|
+
external_exports.object({
|
|
21048
|
+
taskId: external_exports.string().uuid(),
|
|
21049
|
+
status: external_exports.literal("succeeded"),
|
|
21050
|
+
result: harnessInstallationStateSchema
|
|
21051
|
+
}).strict(),
|
|
21052
|
+
external_exports.object({
|
|
21053
|
+
taskId: external_exports.string().uuid(),
|
|
21054
|
+
status: external_exports.literal("failed"),
|
|
21055
|
+
error: external_exports.object({ code: external_exports.number().int(), message: external_exports.string().min(1).max(2048) }).strict()
|
|
21056
|
+
}).strict()
|
|
21057
|
+
]);
|
|
20998
21058
|
|
|
20999
21059
|
// packages/shared-contracts/dist/codex-accounts.js
|
|
21000
21060
|
var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
|
|
@@ -22982,9 +23042,13 @@ function requestManagerFromHookState(value2, hostId2) {
|
|
|
22982
23042
|
const direct = manager(value2) ?? manager(value2.manager);
|
|
22983
23043
|
if (direct)
|
|
22984
23044
|
return direct;
|
|
22985
|
-
if (!hostId2 || typeof value2.addManager !== "function" || typeof value2.getForHostId !== "function"
|
|
23045
|
+
if (!hostId2 || typeof value2.addManager !== "function" || typeof value2.getForHostId !== "function")
|
|
22986
23046
|
return null;
|
|
22987
|
-
|
|
23047
|
+
try {
|
|
23048
|
+
return manager(value2.getForHostId(hostId2));
|
|
23049
|
+
} catch {
|
|
23050
|
+
return null;
|
|
23051
|
+
}
|
|
22988
23052
|
}
|
|
22989
23053
|
function discoverRendererHosts(root, ancestors = committedReactAncestors, managerFrom = requestManagerFromHookState) {
|
|
22990
23054
|
const editors = [
|
|
@@ -23020,7 +23084,7 @@ function discoverRendererHosts(root, ancestors = committedReactAncestors, manage
|
|
|
23020
23084
|
const manager = managerFrom(value2);
|
|
23021
23085
|
if (manager)
|
|
23022
23086
|
managers.add(manager);
|
|
23023
|
-
if (value2 && typeof value2 === "object" && "addManager" in value2 && typeof value2.addManager === "function" && "getForHostId" in value2 && typeof value2.getForHostId === "function"
|
|
23087
|
+
if (value2 && typeof value2 === "object" && "addManager" in value2 && typeof value2.addManager === "function" && "getForHostId" in value2 && typeof value2.getForHostId === "function") {
|
|
23024
23088
|
registries.add(value2);
|
|
23025
23089
|
}
|
|
23026
23090
|
hook = hook.next && typeof hook.next === "object" ? hook.next : null;
|
|
@@ -23036,7 +23100,13 @@ function discoverRendererHosts(root, ancestors = committedReactAncestors, manage
|
|
|
23036
23100
|
function resolveRendererHostManager(discovery, hostId2, managerFrom = requestManagerFromHookState) {
|
|
23037
23101
|
if (!hostId2)
|
|
23038
23102
|
return null;
|
|
23039
|
-
const candidates = discovery.registries.length ? discovery.registries.
|
|
23103
|
+
const candidates = discovery.registries.length ? discovery.registries.flatMap((registry2) => {
|
|
23104
|
+
try {
|
|
23105
|
+
return [managerFrom(registry2.getForHostId(hostId2))];
|
|
23106
|
+
} catch {
|
|
23107
|
+
return [];
|
|
23108
|
+
}
|
|
23109
|
+
}) : discovery.managers;
|
|
23040
23110
|
const matching = new Set(candidates.filter((manager) => manager && (manager.getHostId?.() ?? manager.requestClient.hostId) === hostId2 && (manager.requestClient.hostId === void 0 || manager.requestClient.hostId === hostId2)));
|
|
23041
23111
|
return matching.size === 1 ? matching.values().next().value ?? null : null;
|
|
23042
23112
|
}
|
|
@@ -24048,6 +24118,64 @@ async function handleHarnessInstallation(params, adapters) {
|
|
|
24048
24118
|
}
|
|
24049
24119
|
}
|
|
24050
24120
|
|
|
24121
|
+
// packages/host-runtime/src/harness-installation-tasks.ts
|
|
24122
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
24123
|
+
var HarnessInstallationTasks = class {
|
|
24124
|
+
#tasks = /* @__PURE__ */ new Map();
|
|
24125
|
+
#active = /* @__PURE__ */ new Map();
|
|
24126
|
+
#prune() {
|
|
24127
|
+
const cutoff = Date.now() - 15 * 6e4;
|
|
24128
|
+
for (const [id2, task] of this.#tasks) {
|
|
24129
|
+
if (task.finishedAt !== void 0 && task.finishedAt < cutoff) this.#tasks.delete(id2);
|
|
24130
|
+
}
|
|
24131
|
+
}
|
|
24132
|
+
start(params, adapters) {
|
|
24133
|
+
const parsed2 = harnessInstallationParamsSchema.safeParse(params);
|
|
24134
|
+
if (!parsed2.success)
|
|
24135
|
+
throw new HarnessInstallationError(-32602, "Invalid Harness installation request");
|
|
24136
|
+
this.#prune();
|
|
24137
|
+
const key = JSON.stringify([parsed2.data.harnessId, parsed2.data.action]);
|
|
24138
|
+
const activeId = this.#active.get(key);
|
|
24139
|
+
const active = activeId ? this.#tasks.get(activeId) : void 0;
|
|
24140
|
+
if (active) return active.state;
|
|
24141
|
+
const taskId = randomUUID3();
|
|
24142
|
+
const task = {
|
|
24143
|
+
state: { taskId, status: "running" }
|
|
24144
|
+
};
|
|
24145
|
+
this.#tasks.set(taskId, task);
|
|
24146
|
+
this.#active.set(key, taskId);
|
|
24147
|
+
void handleHarnessInstallation(parsed2.data, adapters).then(
|
|
24148
|
+
(result) => {
|
|
24149
|
+
task.state = { taskId, status: "succeeded", result };
|
|
24150
|
+
},
|
|
24151
|
+
(error51) => {
|
|
24152
|
+
task.state = {
|
|
24153
|
+
taskId,
|
|
24154
|
+
status: "failed",
|
|
24155
|
+
error: error51 instanceof HarnessInstallationError ? { code: error51.code, message: error51.message } : { code: -32077, message: "Harness version management failed" }
|
|
24156
|
+
};
|
|
24157
|
+
}
|
|
24158
|
+
).finally(() => {
|
|
24159
|
+
task.finishedAt = Date.now();
|
|
24160
|
+
this.#active.delete(key);
|
|
24161
|
+
});
|
|
24162
|
+
return task.state;
|
|
24163
|
+
}
|
|
24164
|
+
status(params) {
|
|
24165
|
+
const parsed2 = harnessInstallationTaskParamsSchema.safeParse(params);
|
|
24166
|
+
if (!parsed2.success)
|
|
24167
|
+
throw new HarnessInstallationError(-32602, "Invalid Harness installation task request");
|
|
24168
|
+
this.#prune();
|
|
24169
|
+
const task = this.#tasks.get(parsed2.data.taskId);
|
|
24170
|
+
if (!task)
|
|
24171
|
+
throw new HarnessInstallationError(
|
|
24172
|
+
-32079,
|
|
24173
|
+
"Harness installation task is unavailable on this Host"
|
|
24174
|
+
);
|
|
24175
|
+
return task.state;
|
|
24176
|
+
}
|
|
24177
|
+
};
|
|
24178
|
+
|
|
24051
24179
|
// packages/host-runtime/src/account/codex-credential-export.ts
|
|
24052
24180
|
import { createHash as createHash3 } from "node:crypto";
|
|
24053
24181
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
@@ -24140,7 +24268,7 @@ async function listOthers(adapter) {
|
|
|
24140
24268
|
}
|
|
24141
24269
|
|
|
24142
24270
|
// packages/host-runtime/src/harness-display-settings.ts
|
|
24143
|
-
import { randomUUID as
|
|
24271
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
24144
24272
|
import { link, mkdir as mkdir6, readFile as readFile9, rename as rename4, rm as rm5, writeFile as writeFile6 } from "node:fs/promises";
|
|
24145
24273
|
import os4 from "node:os";
|
|
24146
24274
|
import path13 from "node:path";
|
|
@@ -24165,7 +24293,7 @@ var HarnessDisplaySettingsStore = class {
|
|
|
24165
24293
|
async set(input) {
|
|
24166
24294
|
const entries = harnessDisplayEntriesSchema.parse(input.entries);
|
|
24167
24295
|
await mkdir6(path13.dirname(this.#file), { recursive: true, mode: 448 });
|
|
24168
|
-
const temporary = `${this.#file}.${
|
|
24296
|
+
const temporary = `${this.#file}.${randomUUID4()}.tmp`;
|
|
24169
24297
|
try {
|
|
24170
24298
|
await writeFile6(temporary, `${JSON.stringify(entries)}
|
|
24171
24299
|
`, { mode: 384, flag: "wx" });
|
|
@@ -24186,7 +24314,7 @@ var HarnessDisplaySettingsStore = class {
|
|
|
24186
24314
|
};
|
|
24187
24315
|
|
|
24188
24316
|
// packages/host-runtime/src/model-price-overrides-file.ts
|
|
24189
|
-
import { randomUUID as
|
|
24317
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
24190
24318
|
import { mkdir as mkdir8, readFile as readFile11, rename as rename6, rm as rm6, writeFile as writeFile8 } from "node:fs/promises";
|
|
24191
24319
|
import path15 from "node:path";
|
|
24192
24320
|
|
|
@@ -24761,7 +24889,7 @@ async function updateModelPriceOverridesFile(file2, change) {
|
|
|
24761
24889
|
const updated = { ...document, models: next };
|
|
24762
24890
|
parseModelPriceOverrides(updated);
|
|
24763
24891
|
await mkdir8(path15.dirname(file2), { recursive: true });
|
|
24764
|
-
const temporary = `${file2}.${
|
|
24892
|
+
const temporary = `${file2}.${randomUUID5()}.tmp`;
|
|
24765
24893
|
try {
|
|
24766
24894
|
await writeFile8(temporary, `${JSON.stringify(updated, null, 2)}
|
|
24767
24895
|
`, { flag: "wx" });
|
|
@@ -24797,11 +24925,11 @@ async function handleModelPriceOverridesRequest(catalog, method, params) {
|
|
|
24797
24925
|
}
|
|
24798
24926
|
|
|
24799
24927
|
// packages/host-runtime/src/delegation-skill.ts
|
|
24800
|
-
import { createHash as createHash4, randomUUID as
|
|
24928
|
+
import { createHash as createHash4, randomUUID as randomUUID6 } from "node:crypto";
|
|
24801
24929
|
import { mkdir as mkdir9, open as open4, readFile as readFile12, rename as rename7, rm as rm7, stat as stat5 } from "node:fs/promises";
|
|
24802
24930
|
import os6 from "node:os";
|
|
24803
24931
|
import path16 from "node:path";
|
|
24804
|
-
var SKILL_VERSION =
|
|
24932
|
+
var SKILL_VERSION = 10;
|
|
24805
24933
|
var DELEGATION_SKILL_NAME = "codexhost-delegation";
|
|
24806
24934
|
var SKILL_RELATIVE_PATH = path16.join("skills", DELEGATION_SKILL_NAME, "SKILL.md");
|
|
24807
24935
|
var PREVIOUS_MANAGED_DIGESTS = [
|
|
@@ -24815,7 +24943,9 @@ var PREVIOUS_MANAGED_DIGESTS = [
|
|
|
24815
24943
|
"fa7944cd1e72ffbaf932fca2074bdb78aad4670d8990b6711220dd83c39509a0",
|
|
24816
24944
|
"b9c1cce41d2556e73a6514aa55618d7d3f2f9ef935f5ae50b0da5a04941514b4",
|
|
24817
24945
|
// v8, which ran a bare `codexhost` from PATH.
|
|
24818
|
-
"ca06be59f0d47c9a54d05ed2d9588c9c737306cc155cb4dff3fe2a2a61891dde"
|
|
24946
|
+
"ca06be59f0d47c9a54d05ed2d9588c9c737306cc155cb4dff3fe2a2a61891dde",
|
|
24947
|
+
// v9, before the child-session name guidance.
|
|
24948
|
+
"b72a059e139bd5b93b95f7ac02ab80f428d5a721cc67b004210d5263e75baed7"
|
|
24819
24949
|
];
|
|
24820
24950
|
var CODEXHOST_DELEGATION_SKILL = `---
|
|
24821
24951
|
name: codexhost-delegation
|
|
@@ -24852,7 +24982,8 @@ Use the Harness native defaults. Inspect the target when a Model or Thinking
|
|
|
24852
24982
|
selection is needed or the default is unavailable.
|
|
24853
24983
|
|
|
24854
24984
|
For a new delegation, create an independent child session and submit the
|
|
24855
|
-
requested task.
|
|
24985
|
+
requested task. Give it a short task name that tells it apart from sibling
|
|
24986
|
+
tasks, using the help's task-name option. For an existing external session, resolve the target from the
|
|
24856
24987
|
user-provided session link, identifier, or context and operate on that Thread
|
|
24857
24988
|
directly; it need not have been created by the current assistant. If the target
|
|
24858
24989
|
is ambiguous, ask the user to identify it. Keep requests to view or summarize a
|
|
@@ -24894,7 +25025,7 @@ async function readOptional(filePath) {
|
|
|
24894
25025
|
}
|
|
24895
25026
|
async function atomicWrite(filePath, content) {
|
|
24896
25027
|
await mkdir9(path16.dirname(filePath), { recursive: true, mode: 448 });
|
|
24897
|
-
const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${
|
|
25028
|
+
const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${randomUUID6()}.tmp`);
|
|
24898
25029
|
const handle = await open4(temporaryPath, "wx", 384);
|
|
24899
25030
|
try {
|
|
24900
25031
|
await handle.writeFile(content, "utf8");
|
|
@@ -25131,6 +25262,7 @@ var usageFields = /* @__PURE__ */ new Set([
|
|
|
25131
25262
|
...safeIntegerFields,
|
|
25132
25263
|
...percentFields,
|
|
25133
25264
|
"sessionCacheUsage",
|
|
25265
|
+
"composerIndicators",
|
|
25134
25266
|
"totalCostUsd",
|
|
25135
25267
|
"totalCredits",
|
|
25136
25268
|
"contextUsagePercent",
|
|
@@ -25153,6 +25285,7 @@ function parseHostUsage(value2) {
|
|
|
25153
25285
|
throw new Error(`Harness Usage contains unknown field '${key}'`);
|
|
25154
25286
|
}
|
|
25155
25287
|
}
|
|
25288
|
+
const indicators = value2.composerIndicators === void 0 ? {} : { composerIndicators: composerIndicatorsSchema.parse(value2.composerIndicators) };
|
|
25156
25289
|
for (const field of [
|
|
25157
25290
|
"totalCredits",
|
|
25158
25291
|
"contextUsagePercent",
|
|
@@ -25223,9 +25356,9 @@ function parseHostUsage(value2) {
|
|
|
25223
25356
|
if (value2.costSource !== "publicPrice") {
|
|
25224
25357
|
throw new Error("Harness Usage 'unpricedModels' must be provided with a 'publicPrice' cost");
|
|
25225
25358
|
}
|
|
25226
|
-
return { ...value2, unpricedModels: [...models] };
|
|
25359
|
+
return { ...value2, ...indicators, unpricedModels: [...models] };
|
|
25227
25360
|
}
|
|
25228
|
-
return { ...value2 };
|
|
25361
|
+
return { ...value2, ...indicators };
|
|
25229
25362
|
}
|
|
25230
25363
|
var requestTokenFields = [
|
|
25231
25364
|
"inputTokens",
|
|
@@ -25376,7 +25509,7 @@ var packageMetadata = {
|
|
|
25376
25509
|
|
|
25377
25510
|
// packages/mapping-store/dist/mapping-store.js
|
|
25378
25511
|
import { execFileSync } from "node:child_process";
|
|
25379
|
-
import { randomUUID as
|
|
25512
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
25380
25513
|
import { constants as constants3 } from "node:fs";
|
|
25381
25514
|
import { copyFile as copyFile3, mkdir as mkdir11, open as open7, readFile as readFile15, readdir as readdir4, rename as rename10, rm as rm10, stat as stat6 } from "node:fs/promises";
|
|
25382
25515
|
import path18 from "node:path";
|
|
@@ -25436,7 +25569,7 @@ var storedThreadMetadataV1Schema = external_exports.object({
|
|
|
25436
25569
|
formatVersion: external_exports.literal(1),
|
|
25437
25570
|
hostThreadId: storedHostThreadIdSchema,
|
|
25438
25571
|
...storedThreadMetadataFieldsShape
|
|
25439
|
-
}).
|
|
25572
|
+
}).passthrough();
|
|
25440
25573
|
function refineThreadRecord(record4, context) {
|
|
25441
25574
|
if (record4.state === "ready" && !record4.nativeSessionRef) {
|
|
25442
25575
|
context.addIssue({
|
|
@@ -25495,8 +25628,8 @@ function refineThreadRecord(record4, context) {
|
|
|
25495
25628
|
}
|
|
25496
25629
|
}
|
|
25497
25630
|
}
|
|
25498
|
-
var storedThreadCoreV1Schema = external_exports.object(storedThreadCoreV1Shape).
|
|
25499
|
-
var storedThreadRecordV1Schema = external_exports.object({ ...storedThreadCoreV1Shape, ...storedThreadMetadataFieldsShape }).
|
|
25631
|
+
var storedThreadCoreV1Schema = external_exports.object(storedThreadCoreV1Shape).passthrough().superRefine(refineThreadRecord);
|
|
25632
|
+
var storedThreadRecordV1Schema = external_exports.object({ ...storedThreadCoreV1Shape, ...storedThreadMetadataFieldsShape }).passthrough().superRefine(refineThreadRecord);
|
|
25500
25633
|
var delegationStatusSchema = external_exports.enum([
|
|
25501
25634
|
"creating",
|
|
25502
25635
|
"running",
|
|
@@ -25523,7 +25656,7 @@ var storedDelegationRecordV1Schema = external_exports.object({
|
|
|
25523
25656
|
});
|
|
25524
25657
|
|
|
25525
25658
|
// packages/mapping-store/dist/section-placements.js
|
|
25526
|
-
import { randomUUID as
|
|
25659
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
25527
25660
|
import { constants } from "node:fs";
|
|
25528
25661
|
import { open as open5, readFile as readFile13, rename as rename8, rm as rm8 } from "node:fs/promises";
|
|
25529
25662
|
var threadIdSchema = external_exports.string().min(1).max(1024);
|
|
@@ -25575,7 +25708,7 @@ async function readSectionPlacementsFile(file2) {
|
|
|
25575
25708
|
}
|
|
25576
25709
|
async function writeSectionPlacementsFile(file2, placements) {
|
|
25577
25710
|
const parsed2 = parseSectionPlacements({ formatVersion: 1, placements });
|
|
25578
|
-
const temp = `${file2}.tmp-${
|
|
25711
|
+
const temp = `${file2}.tmp-${randomUUID7()}`;
|
|
25579
25712
|
let handle = null;
|
|
25580
25713
|
try {
|
|
25581
25714
|
handle = await open5(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
@@ -25594,7 +25727,7 @@ async function writeSectionPlacementsFile(file2, placements) {
|
|
|
25594
25727
|
}
|
|
25595
25728
|
|
|
25596
25729
|
// packages/mapping-store/dist/superseded-sessions.js
|
|
25597
|
-
import { randomUUID as
|
|
25730
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
25598
25731
|
import { constants as constants2 } from "node:fs";
|
|
25599
25732
|
import { mkdir as mkdir10, open as open6, readFile as readFile14, rename as rename9, rm as rm9 } from "node:fs/promises";
|
|
25600
25733
|
import path17 from "node:path";
|
|
@@ -25629,7 +25762,7 @@ async function writeSupersededSessionsFile(file2, sessions) {
|
|
|
25629
25762
|
formatVersion: 1,
|
|
25630
25763
|
sessions: sessions.slice(-SUPERSEDED_SESSIONS_MAX)
|
|
25631
25764
|
}).sessions;
|
|
25632
|
-
const temp = `${file2}.tmp-${
|
|
25765
|
+
const temp = `${file2}.tmp-${randomUUID8()}`;
|
|
25633
25766
|
let handle = null;
|
|
25634
25767
|
try {
|
|
25635
25768
|
await mkdir10(path17.dirname(file2), { recursive: true });
|
|
@@ -25874,7 +26007,7 @@ var MappingStore = class {
|
|
|
25874
26007
|
this.#sectionsDirectory = path18.join(this.#directory, "sections");
|
|
25875
26008
|
this.#metadataDirectory = path18.join(this.#directory, "thread-metadata");
|
|
25876
26009
|
this.#lockPath = path18.join(this.#directory, "store.lock");
|
|
25877
|
-
this.#instanceId = options2.instanceId ??
|
|
26010
|
+
this.#instanceId = options2.instanceId ?? randomUUID9();
|
|
25878
26011
|
this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
|
|
25879
26012
|
this.#beforeReplace = options2.beforeReplace;
|
|
25880
26013
|
}
|
|
@@ -26398,7 +26531,7 @@ var MappingStore = class {
|
|
|
26398
26531
|
this.#rebuildIndexes();
|
|
26399
26532
|
}
|
|
26400
26533
|
async #replaceFile(target, record4, preserveBackup) {
|
|
26401
|
-
const temp = `${target}.tmp-${
|
|
26534
|
+
const temp = `${target}.tmp-${randomUUID9()}`;
|
|
26402
26535
|
let handle = null;
|
|
26403
26536
|
try {
|
|
26404
26537
|
await this.#beforeReplace?.(cloneRecord(record4));
|
|
@@ -26422,18 +26555,20 @@ var MappingStore = class {
|
|
|
26422
26555
|
});
|
|
26423
26556
|
}
|
|
26424
26557
|
}
|
|
26425
|
-
/** Atomically
|
|
26558
|
+
/** Atomically patches owned metadata fields, retaining unknown fields on disk. */
|
|
26426
26559
|
async #writeMetadataFile(hostThreadId, metadata) {
|
|
26427
26560
|
const target = this.#metadataPath(hostThreadId);
|
|
26428
|
-
const temp = `${target}.tmp-${
|
|
26561
|
+
const temp = `${target}.tmp-${randomUUID9()}`;
|
|
26429
26562
|
let handle = null;
|
|
26430
26563
|
try {
|
|
26431
|
-
|
|
26564
|
+
const retained = Object.fromEntries(Object.entries(await this.#readMetadata(hostThreadId) ?? {}).filter(([name]) => !["formatVersion", "hostThreadId", ...THREAD_METADATA_FIELDS].includes(name)));
|
|
26565
|
+
if (!metadata && Object.keys(retained).length === 0) {
|
|
26432
26566
|
await rm10(target, { force: true });
|
|
26433
26567
|
return;
|
|
26434
26568
|
}
|
|
26569
|
+
const next = { ...retained, formatVersion: 1, hostThreadId, ...metadata };
|
|
26435
26570
|
handle = await open7(temp, "wx", constants3.S_IRUSR | constants3.S_IWUSR);
|
|
26436
|
-
await handle.writeFile(`${JSON.stringify(
|
|
26571
|
+
await handle.writeFile(`${JSON.stringify(next, null, 2)}
|
|
26437
26572
|
`, "utf8");
|
|
26438
26573
|
await handle.sync();
|
|
26439
26574
|
await handle.close();
|
|
@@ -26470,7 +26605,7 @@ var MappingStore = class {
|
|
|
26470
26605
|
}
|
|
26471
26606
|
async #replaceDelegationFile(record4) {
|
|
26472
26607
|
const target = this.#delegationPath(record4.delegationId);
|
|
26473
|
-
const temp = `${target}.tmp-${
|
|
26608
|
+
const temp = `${target}.tmp-${randomUUID9()}`;
|
|
26474
26609
|
let handle = null;
|
|
26475
26610
|
try {
|
|
26476
26611
|
handle = await open7(temp, "wx", constants3.S_IRUSR | constants3.S_IWUSR);
|
|
@@ -28155,8 +28290,18 @@ function collabAgentStatus(status2) {
|
|
|
28155
28290
|
return "interrupted";
|
|
28156
28291
|
}
|
|
28157
28292
|
}
|
|
28293
|
+
function projectUserMessage(item, clientId) {
|
|
28294
|
+
return {
|
|
28295
|
+
id: item.itemId,
|
|
28296
|
+
type: "userMessage",
|
|
28297
|
+
clientId,
|
|
28298
|
+
content: item.input.map(({ text }) => ({ type: "text", text, text_elements: [] }))
|
|
28299
|
+
};
|
|
28300
|
+
}
|
|
28158
28301
|
function projectItem(item, outcome, defaultCwd, includeCommandOutput = true, senderThreadId) {
|
|
28159
28302
|
switch (item.type) {
|
|
28303
|
+
case "userMessage":
|
|
28304
|
+
return projectUserMessage(item, null);
|
|
28160
28305
|
case "agentMessage":
|
|
28161
28306
|
return {
|
|
28162
28307
|
id: item.itemId,
|
|
@@ -28368,6 +28513,7 @@ var CodexTurnProjector = class {
|
|
|
28368
28513
|
#interactions = /* @__PURE__ */ new Map();
|
|
28369
28514
|
#items = /* @__PURE__ */ new Map();
|
|
28370
28515
|
#wireItemOrder = [];
|
|
28516
|
+
#userMessageClientIds = /* @__PURE__ */ new Map();
|
|
28371
28517
|
#startedAt;
|
|
28372
28518
|
#startedAtMs;
|
|
28373
28519
|
#threadId;
|
|
@@ -28409,6 +28555,10 @@ var CodexTurnProjector = class {
|
|
|
28409
28555
|
}
|
|
28410
28556
|
return items;
|
|
28411
28557
|
}
|
|
28558
|
+
/** Associate steered input with the Desktop message that submitted it, before it is published. */
|
|
28559
|
+
bindUserMessageClientId(itemId, clientId) {
|
|
28560
|
+
this.#userMessageClientIds.set(itemId, clientId);
|
|
28561
|
+
}
|
|
28412
28562
|
pendingTurn(startedAt = null) {
|
|
28413
28563
|
return {
|
|
28414
28564
|
id: this.#turnId,
|
|
@@ -28419,6 +28569,8 @@ var CodexTurnProjector = class {
|
|
|
28419
28569
|
const projected = this.#items.get(itemId);
|
|
28420
28570
|
if (!projected?.wireStarted)
|
|
28421
28571
|
return [];
|
|
28572
|
+
if (projected.item.type === "userMessage")
|
|
28573
|
+
return [this.#projectItem(projected.item)];
|
|
28422
28574
|
if (projected.item.type === "agentMessage") {
|
|
28423
28575
|
return [projectItem(projected.item, projected.outcome, this.#cwd)];
|
|
28424
28576
|
}
|
|
@@ -28746,7 +28898,7 @@ var CodexTurnProjector = class {
|
|
|
28746
28898
|
return { messages: [] };
|
|
28747
28899
|
}
|
|
28748
28900
|
const messages = [
|
|
28749
|
-
completedItem(projectItem(projected.item, projected.outcome,
|
|
28901
|
+
completedItem(this.#projectItem(projected.item, projected.outcome, !projected.streamedCommandOutput))
|
|
28750
28902
|
];
|
|
28751
28903
|
if (projected.item.type === "reasoning") {
|
|
28752
28904
|
const reasoning = projected.item;
|
|
@@ -28811,6 +28963,8 @@ var CodexTurnProjector = class {
|
|
|
28811
28963
|
projectReasoningTranscriptItem(reasoning, projected.outcome, this.#cwd, projected.durationMs ?? null)
|
|
28812
28964
|
];
|
|
28813
28965
|
}
|
|
28966
|
+
if (projected.item.type === "userMessage")
|
|
28967
|
+
return [this.#projectItem(projected.item)];
|
|
28814
28968
|
if (projected.item.type === "agentMessage") {
|
|
28815
28969
|
return [projectItem(projected.item, projected.outcome, this.#cwd)];
|
|
28816
28970
|
}
|
|
@@ -28896,10 +29050,13 @@ var CodexTurnProjector = class {
|
|
|
28896
29050
|
threadId: this.#threadId,
|
|
28897
29051
|
turnId: this.#turnId,
|
|
28898
29052
|
startedAtMs,
|
|
28899
|
-
item: projectItem(item, null
|
|
29053
|
+
item: this.#projectItem(item, null)
|
|
28900
29054
|
}
|
|
28901
29055
|
};
|
|
28902
29056
|
}
|
|
29057
|
+
#projectItem(item, outcome = null, includeCommandOutput = true) {
|
|
29058
|
+
return item.type === "userMessage" ? projectUserMessage(item, this.#userMessageClientIds.get(item.itemId) ?? null) : projectItem(item, outcome, this.#cwd, includeCommandOutput, this.#threadId);
|
|
29059
|
+
}
|
|
28903
29060
|
#startReasoningTranscript(item, startedAtMs) {
|
|
28904
29061
|
return {
|
|
28905
29062
|
method: "item/started",
|
|
@@ -30291,7 +30448,7 @@ var HarnessAccountInspectionCache = class {
|
|
|
30291
30448
|
};
|
|
30292
30449
|
|
|
30293
30450
|
// packages/host-runtime/src/app-server-host.ts
|
|
30294
|
-
import { createHash as createHash9, randomUUID as
|
|
30451
|
+
import { createHash as createHash9, randomUUID as randomUUID16 } from "node:crypto";
|
|
30295
30452
|
import os8 from "node:os";
|
|
30296
30453
|
import path25 from "node:path";
|
|
30297
30454
|
|
|
@@ -30299,12 +30456,12 @@ import path25 from "node:path";
|
|
|
30299
30456
|
import nodePath from "node:path";
|
|
30300
30457
|
|
|
30301
30458
|
// packages/host-runtime/src/external-thread-repository.ts
|
|
30302
|
-
import { randomUUID as
|
|
30459
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
30303
30460
|
import os7 from "node:os";
|
|
30304
30461
|
import path22 from "node:path";
|
|
30305
30462
|
|
|
30306
30463
|
// packages/host-runtime/src/external-subagent-threads.ts
|
|
30307
|
-
import { createHash as createHash6, randomUUID as
|
|
30464
|
+
import { createHash as createHash6, randomUUID as randomUUID10 } from "node:crypto";
|
|
30308
30465
|
function childCreateRequest(parent, nativeRef, id2) {
|
|
30309
30466
|
const key = createHash6("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
|
|
30310
30467
|
return `subagent:${key}`;
|
|
@@ -30379,7 +30536,7 @@ function subagentMaterializer(store, parent, previousParent) {
|
|
|
30379
30536
|
return rebind(existing, parent);
|
|
30380
30537
|
}
|
|
30381
30538
|
const provisional = existing ?? await store.createProvisional({
|
|
30382
|
-
hostThreadId: hostThreadIdSchema.parse(
|
|
30539
|
+
hostThreadId: hostThreadIdSchema.parse(randomUUID10()),
|
|
30383
30540
|
createRequestId,
|
|
30384
30541
|
harnessId: parent.harnessId,
|
|
30385
30542
|
cwd: parent.cwd,
|
|
@@ -30552,7 +30709,7 @@ var ExternalThreadRepository = class {
|
|
|
30552
30709
|
throw new Error("Derived Snapshot identity does not belong to its Native Session");
|
|
30553
30710
|
}
|
|
30554
30711
|
return {
|
|
30555
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
30712
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID11()),
|
|
30556
30713
|
nativeTurnRef: turn.nativeTurnRef,
|
|
30557
30714
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
30558
30715
|
};
|
|
@@ -30675,14 +30832,14 @@ var ExternalThreadRepository = class {
|
|
|
30675
30832
|
const aligned = snapshot2.turns.map((turn) => {
|
|
30676
30833
|
const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
|
|
30677
30834
|
const mapping = existing ?? {
|
|
30678
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
30835
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID11()),
|
|
30679
30836
|
nativeTurnRef: turn.nativeTurnRef,
|
|
30680
30837
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
30681
30838
|
};
|
|
30682
30839
|
return {
|
|
30683
30840
|
snapshot: turn,
|
|
30684
30841
|
mapping: {
|
|
30685
|
-
|
|
30842
|
+
hostTurnId: mapping.hostTurnId,
|
|
30686
30843
|
nativeTurnRef: turn.nativeTurnRef,
|
|
30687
30844
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
30688
30845
|
}
|
|
@@ -30702,8 +30859,8 @@ var ExternalThreadRepository = class {
|
|
|
30702
30859
|
};
|
|
30703
30860
|
function createExternalThreadRecordInput(input) {
|
|
30704
30861
|
return {
|
|
30705
|
-
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(
|
|
30706
|
-
createRequestId: input.createRequestId ??
|
|
30862
|
+
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID11()),
|
|
30863
|
+
createRequestId: input.createRequestId ?? randomUUID11(),
|
|
30707
30864
|
harnessId: input.harnessId,
|
|
30708
30865
|
cwd: input.cwd,
|
|
30709
30866
|
...input.title ? { title: input.title } : {},
|
|
@@ -30821,6 +30978,15 @@ async function executeExternalThreadFork(input) {
|
|
|
30821
30978
|
boundaryIndex = mappings.length - 1;
|
|
30822
30979
|
}
|
|
30823
30980
|
const boundary = mappings[boundaryIndex];
|
|
30981
|
+
if (boundary && source.steeredTurnIds.has(boundary.hostTurnId)) {
|
|
30982
|
+
return {
|
|
30983
|
+
ok: false,
|
|
30984
|
+
error: {
|
|
30985
|
+
code: -32080,
|
|
30986
|
+
message: "This Turn took steered input; reopen the Thread before forking from it"
|
|
30987
|
+
}
|
|
30988
|
+
};
|
|
30989
|
+
}
|
|
30824
30990
|
if (boundaryIndex < 0 || !boundary?.nativeCheckpointRef) {
|
|
30825
30991
|
return {
|
|
30826
30992
|
ok: false,
|
|
@@ -30877,6 +31043,7 @@ async function executeExternalThreadFork(input) {
|
|
|
30877
31043
|
return { ok: false, error: mapExternalThreadHarnessError(opened.error, "fork") };
|
|
30878
31044
|
}
|
|
30879
31045
|
const session = opened.value;
|
|
31046
|
+
await inheritSourceModel(source, session);
|
|
30880
31047
|
const inheritedPermissionModeId = await inheritSourcePermissionMode(source, session);
|
|
30881
31048
|
try {
|
|
30882
31049
|
const derivedNativeRef = session.initialState.nativeRef;
|
|
@@ -30894,7 +31061,7 @@ async function executeExternalThreadFork(input) {
|
|
|
30894
31061
|
source.harnessId,
|
|
30895
31062
|
provisional.transportModelId
|
|
30896
31063
|
);
|
|
30897
|
-
if (effectiveModel && selection
|
|
31064
|
+
if (effectiveModel && selection && selection.model?.id !== effectiveModel.id) {
|
|
30898
31065
|
const transportModelId = encodeExternalTransportSelection(source.harnessId, {
|
|
30899
31066
|
...selection,
|
|
30900
31067
|
model: effectiveModel
|
|
@@ -30939,6 +31106,22 @@ async function executeExternalThreadFork(input) {
|
|
|
30939
31106
|
};
|
|
30940
31107
|
}
|
|
30941
31108
|
}
|
|
31109
|
+
async function inheritSourceModel(source, session) {
|
|
31110
|
+
let persisted;
|
|
31111
|
+
try {
|
|
31112
|
+
persisted = decodeExternalTransportSelection(source.harnessId, source.transportModelId)?.model;
|
|
31113
|
+
} catch {
|
|
31114
|
+
persisted = void 0;
|
|
31115
|
+
}
|
|
31116
|
+
const sourceModel = source.stateObserver.state.effectiveModel ?? source.requestedModel ?? persisted;
|
|
31117
|
+
if (!sourceModel || !session.capabilities.configuration.selectModel || session.initialState.effectiveModel !== void 0) {
|
|
31118
|
+
return;
|
|
31119
|
+
}
|
|
31120
|
+
try {
|
|
31121
|
+
await session.execute({ type: "model.select", model: sourceModel });
|
|
31122
|
+
} catch {
|
|
31123
|
+
}
|
|
31124
|
+
}
|
|
30942
31125
|
async function inheritSourcePermissionMode(source, session) {
|
|
30943
31126
|
const sourceModeId = source.stateObserver.state.effectivePermissionModeId ?? source.requestedPermissionModeId;
|
|
30944
31127
|
if (!sourceModeId) return void 0;
|
|
@@ -31560,6 +31743,16 @@ async function executeExternalThreadRollback(input) {
|
|
|
31560
31743
|
if (derived.running) {
|
|
31561
31744
|
return { ok: false, error: { code: -32072, message: "External Thread has an active Turn" } };
|
|
31562
31745
|
}
|
|
31746
|
+
const undone = derived.record.turnMappings.slice(-rollback.numTurns);
|
|
31747
|
+
if (undone.some((mapping) => derived.steeredTurnIds.has(mapping.hostTurnId))) {
|
|
31748
|
+
return {
|
|
31749
|
+
ok: false,
|
|
31750
|
+
error: {
|
|
31751
|
+
code: -32080,
|
|
31752
|
+
message: "A Turn here took steered input; reopen the Thread before undoing Turns"
|
|
31753
|
+
}
|
|
31754
|
+
};
|
|
31755
|
+
}
|
|
31563
31756
|
const refreshError = await runtime.refresh(derived);
|
|
31564
31757
|
if (refreshError) return { ok: false, error: refreshError };
|
|
31565
31758
|
if (expectedLastTurnId !== void 0 && derived.record.turnMappings.at(-1)?.hostTurnId !== expectedLastTurnId) {
|
|
@@ -32359,6 +32552,7 @@ var ExternalThreadRuntime = class {
|
|
|
32359
32552
|
#repository;
|
|
32360
32553
|
#lifecycle = new ExternalThreadLifecycle();
|
|
32361
32554
|
#hasRunningDescendants;
|
|
32555
|
+
#steeredTurnIds = /* @__PURE__ */ new Map();
|
|
32362
32556
|
#subagentRunning;
|
|
32363
32557
|
#threads = /* @__PURE__ */ new Map();
|
|
32364
32558
|
constructor(input) {
|
|
@@ -32372,7 +32566,8 @@ var ExternalThreadRuntime = class {
|
|
|
32372
32566
|
this.idleRelease = new ExternalThreadIdleRelease({
|
|
32373
32567
|
threads: () => this.values(),
|
|
32374
32568
|
get: (id2) => this.get(id2),
|
|
32375
|
-
|
|
32569
|
+
// Idle release detaches only the Native Session. Host Thread state survives restoration.
|
|
32570
|
+
remove: (id2) => this.#detach(id2),
|
|
32376
32571
|
queue: input.idleRelease?.queue ?? new DesktopRequestQueue(),
|
|
32377
32572
|
canRelease: (thread) => !thread.sessionUnavailable && !this.#lifecycle.busy(thread.id) && (input.idleRelease?.canRelease(thread) ?? false),
|
|
32378
32573
|
...input.idleRelease?.onClosed ? { onClosed: input.idleRelease.onClosed } : {},
|
|
@@ -32382,14 +32577,21 @@ var ExternalThreadRuntime = class {
|
|
|
32382
32577
|
get(threadId2) {
|
|
32383
32578
|
return this.#threads.get(threadId2);
|
|
32384
32579
|
}
|
|
32580
|
+
#detach(threadId2) {
|
|
32581
|
+
const thread = this.#threads.get(threadId2);
|
|
32582
|
+
this.#threads.delete(threadId2);
|
|
32583
|
+
if (!thread || thread.steeredTurnIds.size === 0) this.#steeredTurnIds.delete(threadId2);
|
|
32584
|
+
}
|
|
32385
32585
|
values() {
|
|
32386
32586
|
return [...this.#threads.values()];
|
|
32387
32587
|
}
|
|
32388
32588
|
remove(threadId2) {
|
|
32389
32589
|
this.#threads.delete(threadId2);
|
|
32590
|
+
this.#steeredTurnIds.delete(threadId2);
|
|
32390
32591
|
}
|
|
32391
32592
|
clear() {
|
|
32392
32593
|
this.#threads.clear();
|
|
32594
|
+
this.#steeredTurnIds.clear();
|
|
32393
32595
|
}
|
|
32394
32596
|
drain() {
|
|
32395
32597
|
return this.#lifecycle.drain();
|
|
@@ -32446,6 +32648,11 @@ var ExternalThreadRuntime = class {
|
|
|
32446
32648
|
...effectivePermissionModeId ? { effectivePermissionModeId } : {}
|
|
32447
32649
|
};
|
|
32448
32650
|
const running = this.#subagentRunning(input.record.hostThreadId);
|
|
32651
|
+
let steeredTurnIds = this.#steeredTurnIds.get(input.record.hostThreadId);
|
|
32652
|
+
if (!steeredTurnIds) {
|
|
32653
|
+
steeredTurnIds = /* @__PURE__ */ new Set();
|
|
32654
|
+
this.#steeredTurnIds.set(input.record.hostThreadId, steeredTurnIds);
|
|
32655
|
+
}
|
|
32449
32656
|
const externalThread = {
|
|
32450
32657
|
id: input.record.hostThreadId,
|
|
32451
32658
|
cwd: input.record.cwd,
|
|
@@ -32470,11 +32677,13 @@ var ExternalThreadRuntime = class {
|
|
|
32470
32677
|
usageTurnId: null,
|
|
32471
32678
|
projectedTurns: /* @__PURE__ */ new Map(),
|
|
32472
32679
|
responseGates: /* @__PURE__ */ new Map(),
|
|
32680
|
+
pendingSteerProjections: /* @__PURE__ */ new Set(),
|
|
32473
32681
|
ephemeralTurnIds: /* @__PURE__ */ new Set(),
|
|
32474
32682
|
persistenceError: null,
|
|
32475
32683
|
projectedTerminalTurnId: null,
|
|
32476
32684
|
ignoredInteractionIds: /* @__PURE__ */ new Set(),
|
|
32477
|
-
sessionUnavailable: false
|
|
32685
|
+
sessionUnavailable: false,
|
|
32686
|
+
steeredTurnIds
|
|
32478
32687
|
};
|
|
32479
32688
|
this.idleRelease.touch(externalThread);
|
|
32480
32689
|
externalThread.outputTask = this.#consumeOutputs(externalThread);
|
|
@@ -32531,13 +32740,13 @@ var ExternalThreadRuntime = class {
|
|
|
32531
32740
|
const retire = async () => {
|
|
32532
32741
|
if (this.#threads.get(parentId) !== parent || this.#threads.get(child.id) !== child) return;
|
|
32533
32742
|
if (bestEffort) {
|
|
32534
|
-
this
|
|
32743
|
+
this.remove(child.id);
|
|
32535
32744
|
await child.session.close();
|
|
32536
32745
|
await child.outputTask;
|
|
32537
32746
|
} else {
|
|
32538
32747
|
child.sessionUnavailable = true;
|
|
32539
32748
|
await this.#lifecycle.release(child.id, child.session, child.outputTask);
|
|
32540
|
-
if (this.#threads.get(child.id) === child) this
|
|
32749
|
+
if (this.#threads.get(child.id) === child) this.remove(child.id);
|
|
32541
32750
|
}
|
|
32542
32751
|
};
|
|
32543
32752
|
if (bestEffort) await retire().catch(this.#diagnose);
|
|
@@ -32910,6 +33119,71 @@ var ExternalThreadRuntime = class {
|
|
|
32910
33119
|
};
|
|
32911
33120
|
|
|
32912
33121
|
// packages/host-runtime/src/external-turn-steering.ts
|
|
33122
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
33123
|
+
|
|
33124
|
+
// packages/host-runtime/src/external-command-routing.ts
|
|
33125
|
+
var ExternalCommandError = class extends Error {
|
|
33126
|
+
constructor(code, message2) {
|
|
33127
|
+
super(message2);
|
|
33128
|
+
this.code = code;
|
|
33129
|
+
}
|
|
33130
|
+
code;
|
|
33131
|
+
};
|
|
33132
|
+
function isExternalCommandCandidate(text) {
|
|
33133
|
+
return /^\/[^\s/]+(?:\s|$)/u.test(text.trimStart());
|
|
33134
|
+
}
|
|
33135
|
+
async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
|
|
33136
|
+
let timeout;
|
|
33137
|
+
try {
|
|
33138
|
+
const result = await Promise.race([
|
|
33139
|
+
commands.list(),
|
|
33140
|
+
new Promise((resolve) => {
|
|
33141
|
+
timeout = setTimeout(() => resolve(null), timeoutMs);
|
|
33142
|
+
})
|
|
33143
|
+
]);
|
|
33144
|
+
return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
|
|
33145
|
+
} catch {
|
|
33146
|
+
return null;
|
|
33147
|
+
} finally {
|
|
33148
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
33149
|
+
}
|
|
33150
|
+
}
|
|
33151
|
+
async function resolveExternalCommand(commands, text, options2 = {}) {
|
|
33152
|
+
const catalog = await commands.list();
|
|
33153
|
+
if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
|
|
33154
|
+
const commandText = text.trim();
|
|
33155
|
+
const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
|
|
33156
|
+
if (commandText === command.invocation) return true;
|
|
33157
|
+
return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
|
|
33158
|
+
});
|
|
33159
|
+
if (!matched) {
|
|
33160
|
+
const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
|
|
33161
|
+
if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
|
|
33162
|
+
return null;
|
|
33163
|
+
}
|
|
33164
|
+
throw new ExternalCommandError(
|
|
33165
|
+
-32078,
|
|
33166
|
+
"External Harness does not expose the requested command"
|
|
33167
|
+
);
|
|
33168
|
+
}
|
|
33169
|
+
const argumentText = commandText.slice(matched.invocation.length).trimStart();
|
|
33170
|
+
return {
|
|
33171
|
+
descriptor: matched,
|
|
33172
|
+
...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
|
|
33173
|
+
};
|
|
33174
|
+
}
|
|
33175
|
+
|
|
33176
|
+
// packages/host-runtime/src/external-turn-steering.ts
|
|
33177
|
+
function isHarnessCommand(thread, text) {
|
|
33178
|
+
return thread.session.commands !== void 0 && isExternalCommandCandidate(restoreHarnessCommandMentions(text));
|
|
33179
|
+
}
|
|
33180
|
+
function externalSteeringDelivery(thread, text) {
|
|
33181
|
+
if (text !== void 0 && isHarnessCommand(thread, text)) return "newTurn";
|
|
33182
|
+
if (thread.session.readCapabilities) {
|
|
33183
|
+
return thread.session.readCapabilities().then((capabilities) => capabilities.steer === true ? "activeTurn" : "newTurn");
|
|
33184
|
+
}
|
|
33185
|
+
return thread.session.capabilities.steer === true ? "activeTurn" : "newTurn";
|
|
33186
|
+
}
|
|
32913
33187
|
var ExternalSteerError = class extends Error {
|
|
32914
33188
|
constructor(code, message2) {
|
|
32915
33189
|
super(message2);
|
|
@@ -32917,6 +33191,11 @@ var ExternalSteerError = class extends Error {
|
|
|
32917
33191
|
}
|
|
32918
33192
|
code;
|
|
32919
33193
|
};
|
|
33194
|
+
var ExternalSteerNotTakenError = class extends ExternalSteerError {
|
|
33195
|
+
constructor(message2) {
|
|
33196
|
+
super(-32074, message2);
|
|
33197
|
+
}
|
|
33198
|
+
};
|
|
32920
33199
|
function parseInput(params) {
|
|
32921
33200
|
if (typeof params.expectedTurnId !== "string" || !params.expectedTurnId.trim()) {
|
|
32922
33201
|
throw new ExternalSteerError(-32602, "External steering requires expectedTurnId");
|
|
@@ -32933,12 +33212,47 @@ function parseInput(params) {
|
|
|
32933
33212
|
if (clientUserMessageId != null && (typeof clientUserMessageId !== "string" || !clientUserMessageId.trim())) {
|
|
32934
33213
|
throw new ExternalSteerError(-32602, "External steering message identity is invalid");
|
|
32935
33214
|
}
|
|
33215
|
+
const delivery = params[THREAD_STEER_DELIVERY_PARAM];
|
|
33216
|
+
const parsedDelivery = delivery == null ? void 0 : threadSteerDeliverySchema.safeParse(delivery);
|
|
33217
|
+
if (parsedDelivery && !parsedDelivery.success) {
|
|
33218
|
+
throw new ExternalSteerError(-32602, "External steering delivery is invalid");
|
|
33219
|
+
}
|
|
32936
33220
|
return {
|
|
32937
33221
|
expectedTurnId: params.expectedTurnId,
|
|
32938
33222
|
text,
|
|
32939
|
-
...typeof clientUserMessageId === "string" ? { clientUserMessageId } : {}
|
|
33223
|
+
...typeof clientUserMessageId === "string" ? { clientUserMessageId } : {},
|
|
33224
|
+
...parsedDelivery ? { delivery: parsedDelivery.data } : {}
|
|
32940
33225
|
};
|
|
32941
33226
|
}
|
|
33227
|
+
async function insertNativeSteer(thread, input, host) {
|
|
33228
|
+
const restored = restoreHarnessCommandMentions(input.text);
|
|
33229
|
+
const steered = [{ type: "text", text: rewriteDelegationMentionText(restored) }];
|
|
33230
|
+
const displayed = [{ type: "text", text: restored }];
|
|
33231
|
+
const projectionDone = Promise.withResolvers();
|
|
33232
|
+
thread.pendingSteerProjections.add(projectionDone.promise);
|
|
33233
|
+
try {
|
|
33234
|
+
const result = await thread.session.execute({
|
|
33235
|
+
type: "turn.steer",
|
|
33236
|
+
turnId: input.turnId,
|
|
33237
|
+
input: steered
|
|
33238
|
+
});
|
|
33239
|
+
if (!result.ok) throw new ExternalSteerNotTakenError(result.error.message);
|
|
33240
|
+
thread.steeredTurnIds.add(input.turnId);
|
|
33241
|
+
const item = {
|
|
33242
|
+
type: "userMessage",
|
|
33243
|
+
itemId: hostItemIdSchema.parse(randomUUID12()),
|
|
33244
|
+
input: displayed
|
|
33245
|
+
};
|
|
33246
|
+
try {
|
|
33247
|
+
await host.project(input.turnId, item, input.clientUserMessageId);
|
|
33248
|
+
} catch (error51) {
|
|
33249
|
+
host.diagnose(error51);
|
|
33250
|
+
}
|
|
33251
|
+
} finally {
|
|
33252
|
+
projectionDone.resolve(void 0);
|
|
33253
|
+
thread.pendingSteerProjections.delete(projectionDone.promise);
|
|
33254
|
+
}
|
|
33255
|
+
}
|
|
32942
33256
|
var ExternalTurnSteering = class {
|
|
32943
33257
|
constructor(timeoutMs = 2e4) {
|
|
32944
33258
|
this.timeoutMs = timeoutMs;
|
|
@@ -32950,7 +33264,7 @@ var ExternalTurnSteering = class {
|
|
|
32950
33264
|
hasPending(threadId2) {
|
|
32951
33265
|
return threadId2 === void 0 ? this.#pending.size > 0 : this.#pending.has(threadId2);
|
|
32952
33266
|
}
|
|
32953
|
-
run(thread, params, start) {
|
|
33267
|
+
run(thread, params, start, insert) {
|
|
32954
33268
|
try {
|
|
32955
33269
|
const input = parseInput(params);
|
|
32956
33270
|
if (this.#closed)
|
|
@@ -32972,7 +33286,7 @@ var ExternalTurnSteering = class {
|
|
|
32972
33286
|
if (!thread.running || thread.activeTurnId !== input.expectedTurnId) {
|
|
32973
33287
|
throw new ExternalSteerError(-32074, "External steering must reference the active Turn");
|
|
32974
33288
|
}
|
|
32975
|
-
const result = this.#
|
|
33289
|
+
const result = this.#deliver(thread, input, start, insert);
|
|
32976
33290
|
if (key) {
|
|
32977
33291
|
const receipt2 = { fingerprint, result, settled: false };
|
|
32978
33292
|
this.#receipts.set(key, receipt2);
|
|
@@ -32995,6 +33309,56 @@ var ExternalTurnSteering = class {
|
|
|
32995
33309
|
return Promise.reject(error51);
|
|
32996
33310
|
}
|
|
32997
33311
|
}
|
|
33312
|
+
/**
|
|
33313
|
+
* A Renderer that already presented a delivery gets exactly that one. Otherwise native delivery
|
|
33314
|
+
* is tried only when the Session can take the input now, and input the Harness did not take
|
|
33315
|
+
* falls back to stopping and restarting, so no case is worse than the stop-then-start path.
|
|
33316
|
+
*/
|
|
33317
|
+
#deliver(thread, input, start, insert) {
|
|
33318
|
+
const delivery = input.delivery === "newTurn" || isHarnessCommand(thread, input.text) ? "newTurn" : input.delivery ?? externalSteeringDelivery(thread);
|
|
33319
|
+
const deliver = (mode) => {
|
|
33320
|
+
if (this.#closed || !thread.running || thread.activeTurnId !== input.expectedTurnId) {
|
|
33321
|
+
throw new ExternalSteerError(-32074, "External steering target is no longer active");
|
|
33322
|
+
}
|
|
33323
|
+
if (this.hasPending(thread.id))
|
|
33324
|
+
throw new ExternalSteerError(-32072, "External Thread is already changing direction");
|
|
33325
|
+
if (mode === "newTurn") return this.#replace(thread, input, start);
|
|
33326
|
+
const native = insert({
|
|
33327
|
+
turnId: thread.activeTurnId,
|
|
33328
|
+
text: input.text,
|
|
33329
|
+
...input.clientUserMessageId ? { clientUserMessageId: input.clientUserMessageId } : {}
|
|
33330
|
+
}).then((admitted) => ({ ...admitted, delivery: "activeTurn" }));
|
|
33331
|
+
if (input.delivery === "activeTurn") return native;
|
|
33332
|
+
return native.catch(async (error51) => {
|
|
33333
|
+
if (!(error51 instanceof ExternalSteerNotTakenError)) throw error51;
|
|
33334
|
+
if (thread.running || thread.activeTurnId) return deliver("newTurn");
|
|
33335
|
+
const assertActive = () => {
|
|
33336
|
+
if (this.#closed)
|
|
33337
|
+
throw new ExternalSteerError(-32074, "External steering connection is closed");
|
|
33338
|
+
};
|
|
33339
|
+
return { ...await start(input.text, assertActive), delivery: "newTurn" };
|
|
33340
|
+
});
|
|
33341
|
+
};
|
|
33342
|
+
if (typeof delivery === "string") return deliver(delivery);
|
|
33343
|
+
const failure = Promise.withResolvers();
|
|
33344
|
+
let failureReason = null;
|
|
33345
|
+
const pending = {
|
|
33346
|
+
turnId: input.expectedTurnId,
|
|
33347
|
+
resolve: () => void 0,
|
|
33348
|
+
reject(error51) {
|
|
33349
|
+
failureReason ??= error51;
|
|
33350
|
+
failure.reject(error51);
|
|
33351
|
+
}
|
|
33352
|
+
};
|
|
33353
|
+
this.#pending.set(thread.id, pending);
|
|
33354
|
+
return Promise.race([delivery, failure.promise]).then((mode) => {
|
|
33355
|
+
if (failureReason) throw failureReason;
|
|
33356
|
+
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
33357
|
+
return deliver(mode);
|
|
33358
|
+
}).finally(() => {
|
|
33359
|
+
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
33360
|
+
});
|
|
33361
|
+
}
|
|
32998
33362
|
terminal(threadId2, turnId, outcome) {
|
|
32999
33363
|
const pending = this.#pending.get(threadId2);
|
|
33000
33364
|
if (pending?.turnId === turnId) pending.resolve(outcome);
|
|
@@ -33049,7 +33413,9 @@ var ExternalTurnSteering = class {
|
|
|
33049
33413
|
thread.session.execute({ type: "turn.cancel", turnId }),
|
|
33050
33414
|
failure.promise
|
|
33051
33415
|
]);
|
|
33052
|
-
if (!cancelled.ok
|
|
33416
|
+
if (!cancelled.ok && cancelled.error.code !== "invalidState") {
|
|
33417
|
+
throw new ExternalSteerError(-32074, cancelled.error.message);
|
|
33418
|
+
}
|
|
33053
33419
|
const outcome = await Promise.race([terminal3.promise, failure.promise]);
|
|
33054
33420
|
clearTimeout(timeout);
|
|
33055
33421
|
const assertActive = () => {
|
|
@@ -33067,7 +33433,7 @@ var ExternalTurnSteering = class {
|
|
|
33067
33433
|
if (thread.running || thread.activeTurnId) {
|
|
33068
33434
|
throw new ExternalSteerError(-32072, "Another External Turn started before replacement");
|
|
33069
33435
|
}
|
|
33070
|
-
return await start(input.text, assertActive);
|
|
33436
|
+
return { ...await start(input.text, assertActive), delivery: "newTurn" };
|
|
33071
33437
|
} finally {
|
|
33072
33438
|
clearTimeout(timeout);
|
|
33073
33439
|
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
@@ -33075,58 +33441,6 @@ var ExternalTurnSteering = class {
|
|
|
33075
33441
|
}
|
|
33076
33442
|
};
|
|
33077
33443
|
|
|
33078
|
-
// packages/host-runtime/src/external-command-routing.ts
|
|
33079
|
-
var ExternalCommandError = class extends Error {
|
|
33080
|
-
constructor(code, message2) {
|
|
33081
|
-
super(message2);
|
|
33082
|
-
this.code = code;
|
|
33083
|
-
}
|
|
33084
|
-
code;
|
|
33085
|
-
};
|
|
33086
|
-
function isExternalCommandCandidate(text) {
|
|
33087
|
-
return /^\/[^\s/]+(?:\s|$)/u.test(text.trimStart());
|
|
33088
|
-
}
|
|
33089
|
-
async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
|
|
33090
|
-
let timeout;
|
|
33091
|
-
try {
|
|
33092
|
-
const result = await Promise.race([
|
|
33093
|
-
commands.list(),
|
|
33094
|
-
new Promise((resolve) => {
|
|
33095
|
-
timeout = setTimeout(() => resolve(null), timeoutMs);
|
|
33096
|
-
})
|
|
33097
|
-
]);
|
|
33098
|
-
return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
|
|
33099
|
-
} catch {
|
|
33100
|
-
return null;
|
|
33101
|
-
} finally {
|
|
33102
|
-
if (timeout !== void 0) clearTimeout(timeout);
|
|
33103
|
-
}
|
|
33104
|
-
}
|
|
33105
|
-
async function resolveExternalCommand(commands, text, options2 = {}) {
|
|
33106
|
-
const catalog = await commands.list();
|
|
33107
|
-
if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
|
|
33108
|
-
const commandText = text.trim();
|
|
33109
|
-
const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
|
|
33110
|
-
if (commandText === command.invocation) return true;
|
|
33111
|
-
return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
|
|
33112
|
-
});
|
|
33113
|
-
if (!matched) {
|
|
33114
|
-
const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
|
|
33115
|
-
if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
|
|
33116
|
-
return null;
|
|
33117
|
-
}
|
|
33118
|
-
throw new ExternalCommandError(
|
|
33119
|
-
-32078,
|
|
33120
|
-
"External Harness does not expose the requested command"
|
|
33121
|
-
);
|
|
33122
|
-
}
|
|
33123
|
-
const argumentText = commandText.slice(matched.invocation.length).trimStart();
|
|
33124
|
-
return {
|
|
33125
|
-
descriptor: matched,
|
|
33126
|
-
...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
|
|
33127
|
-
};
|
|
33128
|
-
}
|
|
33129
|
-
|
|
33130
33444
|
// packages/host-runtime/src/live-command-catalog-cache.ts
|
|
33131
33445
|
import path23 from "node:path";
|
|
33132
33446
|
var MAX_ENTRIES = 64;
|
|
@@ -33158,7 +33472,7 @@ function sameWorkspace(left, right) {
|
|
|
33158
33472
|
}
|
|
33159
33473
|
|
|
33160
33474
|
// packages/host-runtime/src/harness-delegation-coordinator.ts
|
|
33161
|
-
import { createHash as createHash8, randomUUID as
|
|
33475
|
+
import { createHash as createHash8, randomUUID as randomUUID13 } from "node:crypto";
|
|
33162
33476
|
import path24 from "node:path";
|
|
33163
33477
|
|
|
33164
33478
|
// packages/host-runtime/src/delegation-snapshot.ts
|
|
@@ -33304,6 +33618,15 @@ function projectDelegationThreadSnapshot(input) {
|
|
|
33304
33618
|
// packages/host-runtime/src/harness-delegation-coordinator.ts
|
|
33305
33619
|
var IMPLICIT_DEDUPLICATION_MS = 3e4;
|
|
33306
33620
|
var NATIVE_REF_TIMEOUT_MS = 1e4;
|
|
33621
|
+
function truncateTitle(value2, length) {
|
|
33622
|
+
return value2.slice(0, length).replace(/[\uD800-\uDBFF]$/u, "");
|
|
33623
|
+
}
|
|
33624
|
+
function delegationTitle(parentTitle, input) {
|
|
33625
|
+
const taskName = (input.taskName ?? input.task.trim().split(/\r?\n/u)[0] ?? input.task).replace(/\s+/gu, " ").trim();
|
|
33626
|
+
const subtask = truncateTitle(taskName, 120);
|
|
33627
|
+
const parent = (parentTitle?.trim() || "Untitled Thread").replace(/\s+/gu, " ");
|
|
33628
|
+
return `${subtask} · ${truncateTitle(parent, 200 - subtask.length - 3)}`;
|
|
33629
|
+
}
|
|
33307
33630
|
function delay3(milliseconds) {
|
|
33308
33631
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
33309
33632
|
}
|
|
@@ -33330,6 +33653,12 @@ function statusFromThread(thread, busy) {
|
|
|
33330
33653
|
function validateStart(input) {
|
|
33331
33654
|
if (typeof input.task !== "string" || !input.task.trim())
|
|
33332
33655
|
throw new DelegationControlError("INVALID_ARGUMENT", "Task must not be empty");
|
|
33656
|
+
if (input.taskName !== void 0 && (typeof input.taskName !== "string" || !input.taskName.trim() || input.taskName.length > 120)) {
|
|
33657
|
+
throw new DelegationControlError(
|
|
33658
|
+
"INVALID_ARGUMENT",
|
|
33659
|
+
"Task name must contain 1 to 120 characters"
|
|
33660
|
+
);
|
|
33661
|
+
}
|
|
33333
33662
|
if (input.cwd !== void 0 && (typeof input.cwd !== "string" || !input.cwd.trim()))
|
|
33334
33663
|
throw new DelegationControlError("INVALID_ARGUMENT", "cwd must not be empty");
|
|
33335
33664
|
if (input.requestId !== void 0 && (typeof input.requestId !== "string" || !input.requestId.trim())) {
|
|
@@ -33350,7 +33679,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
33350
33679
|
#cancelOfficial;
|
|
33351
33680
|
#startOfficial;
|
|
33352
33681
|
#listOfficial;
|
|
33353
|
-
#
|
|
33682
|
+
#officialThreadMetadata;
|
|
33354
33683
|
#activeOfficialParents;
|
|
33355
33684
|
#externalThreadBusy;
|
|
33356
33685
|
constructor(input) {
|
|
@@ -33367,7 +33696,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
33367
33696
|
this.#cancelOfficial = input.cancelOfficial;
|
|
33368
33697
|
this.#startOfficial = input.startOfficial;
|
|
33369
33698
|
this.#listOfficial = input.listOfficial;
|
|
33370
|
-
this.#
|
|
33699
|
+
this.#officialThreadMetadata = input.officialThreadMetadata;
|
|
33371
33700
|
this.#activeOfficialParents = input.activeOfficialParents;
|
|
33372
33701
|
this.#externalThreadBusy = input.externalThreadBusy;
|
|
33373
33702
|
}
|
|
@@ -33397,8 +33726,14 @@ var HarnessDelegationCoordinator = class {
|
|
|
33397
33726
|
const parentThreadId = await this.#resolveParent(input.parentThreadId);
|
|
33398
33727
|
const parent = await this.#parentMetadata(parentThreadId);
|
|
33399
33728
|
const selectedCwd = input.cwd ?? parent.cwd ?? process.cwd();
|
|
33729
|
+
const title = delegationTitle(parent.title, input);
|
|
33400
33730
|
if (input.harnessId === "codex") {
|
|
33401
|
-
const result = await this.#startOfficial({
|
|
33731
|
+
const result = await this.#startOfficial({
|
|
33732
|
+
...input,
|
|
33733
|
+
parentThreadId,
|
|
33734
|
+
cwd: selectedCwd,
|
|
33735
|
+
title
|
|
33736
|
+
});
|
|
33402
33737
|
return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
|
|
33403
33738
|
}
|
|
33404
33739
|
const startInput = { ...input, parentThreadId, cwd: path24.resolve(selectedCwd) };
|
|
@@ -33441,17 +33776,17 @@ var HarnessDelegationCoordinator = class {
|
|
|
33441
33776
|
});
|
|
33442
33777
|
this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
|
|
33443
33778
|
}
|
|
33444
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
33445
|
-
const childThreadId = hostThreadIdSchema.parse(
|
|
33446
|
-
const turnId = hostTurnIdSchema.parse(
|
|
33447
|
-
const createRequestId = input.requestId ? `delegation:${input.requestId}` :
|
|
33779
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID13());
|
|
33780
|
+
const childThreadId = hostThreadIdSchema.parse(randomUUID13());
|
|
33781
|
+
const turnId = hostTurnIdSchema.parse(randomUUID13());
|
|
33782
|
+
const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID13();
|
|
33448
33783
|
let record4 = await this.#repository.createProvisional(
|
|
33449
33784
|
createExternalThreadRecordInput({
|
|
33450
33785
|
hostThreadId: childThreadId,
|
|
33451
33786
|
createRequestId,
|
|
33452
33787
|
harnessId: harnessIdSchema.parse(targetHarnessId),
|
|
33453
33788
|
cwd: startInput.cwd,
|
|
33454
|
-
title
|
|
33789
|
+
title,
|
|
33455
33790
|
transportModelId: input.model || input.thinkingOptionId ? encodeExternalTransportSelection(targetHarnessId, {
|
|
33456
33791
|
...input.model ? { model: input.model } : {},
|
|
33457
33792
|
...input.thinkingOptionId ? { thinkingOptionId: input.thinkingOptionId } : {}
|
|
@@ -33598,7 +33933,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
33598
33933
|
if (this.#externalThreadBusy(thread) || thread.activeTurnId) {
|
|
33599
33934
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
33600
33935
|
}
|
|
33601
|
-
const turnId = hostTurnIdSchema.parse(
|
|
33936
|
+
const turnId = hostTurnIdSchema.parse(randomUUID13());
|
|
33602
33937
|
try {
|
|
33603
33938
|
await this.#startExternalTurn(thread, input.message, turnId);
|
|
33604
33939
|
} catch (error51) {
|
|
@@ -33812,9 +34147,14 @@ var HarnessDelegationCoordinator = class {
|
|
|
33812
34147
|
}
|
|
33813
34148
|
async #parentMetadata(parentThreadId) {
|
|
33814
34149
|
const record4 = await this.#repository.find(parentThreadId);
|
|
33815
|
-
if (record4)
|
|
33816
|
-
|
|
33817
|
-
|
|
34150
|
+
if (record4)
|
|
34151
|
+
return {
|
|
34152
|
+
harnessId: record4.harnessId,
|
|
34153
|
+
cwd: record4.cwd,
|
|
34154
|
+
title: record4.title
|
|
34155
|
+
};
|
|
34156
|
+
const metadata = await this.#officialThreadMetadata(parentThreadId).catch(() => ({}));
|
|
34157
|
+
return { harnessId: "codex", ...metadata };
|
|
33818
34158
|
}
|
|
33819
34159
|
async #existingResult(delegation) {
|
|
33820
34160
|
const record4 = await this.#repository.find(delegation.childHostThreadId);
|
|
@@ -36243,10 +36583,10 @@ var SingleNativeCodexAccount = class {
|
|
|
36243
36583
|
};
|
|
36244
36584
|
|
|
36245
36585
|
// packages/host-runtime/src/codex-runtime/official-runtime-owner.ts
|
|
36246
|
-
import { randomUUID as
|
|
36586
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
36247
36587
|
|
|
36248
36588
|
// packages/host-runtime/src/official-request-broker.ts
|
|
36249
|
-
import { randomUUID as
|
|
36589
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
36250
36590
|
var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
|
|
36251
36591
|
var MAX_RETIRED_IDS = 1024;
|
|
36252
36592
|
function isRecord15(value2) {
|
|
@@ -36262,7 +36602,7 @@ var OfficialRequestBroker = class {
|
|
|
36262
36602
|
constructor(input) {
|
|
36263
36603
|
this.#send = input.send;
|
|
36264
36604
|
this.#timeoutMs = input.timeoutMs ?? 3e4;
|
|
36265
|
-
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${
|
|
36605
|
+
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID14()}`);
|
|
36266
36606
|
}
|
|
36267
36607
|
get pendingCount() {
|
|
36268
36608
|
return this.#pending.size;
|
|
@@ -36616,7 +36956,7 @@ var OfficialRuntimeOwner = class {
|
|
|
36616
36956
|
}
|
|
36617
36957
|
#attach(role, output, onBackendStopped) {
|
|
36618
36958
|
const client = {
|
|
36619
|
-
id:
|
|
36959
|
+
id: randomUUID15(),
|
|
36620
36960
|
role,
|
|
36621
36961
|
output,
|
|
36622
36962
|
...onBackendStopped ? { onBackendStopped } : {},
|
|
@@ -36774,7 +37114,7 @@ var OfficialRuntimeOwner = class {
|
|
|
36774
37114
|
if (!object4(value2)) return client.output(event);
|
|
36775
37115
|
if (typeof value2.id === "string" || typeof value2.id === "number") {
|
|
36776
37116
|
if (typeof value2.method === "string") {
|
|
36777
|
-
const id2 = `codexhost:server:${client.id}:${event.generation}:${
|
|
37117
|
+
const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID15()}`;
|
|
36778
37118
|
client.serverRequests.set(id2, value2.id);
|
|
36779
37119
|
const projected = { ...value2, id: id2 };
|
|
36780
37120
|
return client.output({
|
|
@@ -36950,16 +37290,16 @@ var OfficialRuntimeScope = class {
|
|
|
36950
37290
|
#scheduleRecovery() {
|
|
36951
37291
|
if (!this.#recovery || this.#closed || this.#recoveryTimer || this.#starting) return;
|
|
36952
37292
|
const { delaysMs } = this.#recovery;
|
|
36953
|
-
const
|
|
37293
|
+
const delay7 = delaysMs[Math.min(this.#recoveryAttempt, delaysMs.length - 1)] ?? 0;
|
|
36954
37294
|
this.#recoveryAttempt++;
|
|
36955
37295
|
this.#diagnosticOutput.write(
|
|
36956
|
-
`codexhost: official Codex is unavailable; restarting in ${String(
|
|
37296
|
+
`codexhost: official Codex is unavailable; restarting in ${String(delay7)}ms
|
|
36957
37297
|
`
|
|
36958
37298
|
);
|
|
36959
37299
|
const timer = setTimeout(() => {
|
|
36960
37300
|
this.#recoveryTimer = void 0;
|
|
36961
37301
|
this.start().catch(() => void 0);
|
|
36962
|
-
},
|
|
37302
|
+
}, delay7);
|
|
36963
37303
|
timer.unref();
|
|
36964
37304
|
this.#recoveryTimer = timer;
|
|
36965
37305
|
}
|
|
@@ -38054,6 +38394,7 @@ var AppServerHost = class {
|
|
|
38054
38394
|
#plugins;
|
|
38055
38395
|
#launchSettings;
|
|
38056
38396
|
#accountInspections = new HarnessAccountInspectionCache();
|
|
38397
|
+
#installationTasks = new HarnessInstallationTasks();
|
|
38057
38398
|
#externalRuntime;
|
|
38058
38399
|
#executionHosts = /* @__PURE__ */ new WeakMap();
|
|
38059
38400
|
#externalPrewarms = new ExternalThreadPrewarms();
|
|
@@ -38084,7 +38425,7 @@ var AppServerHost = class {
|
|
|
38084
38425
|
#sectionMoves = Promise.resolve();
|
|
38085
38426
|
#writer;
|
|
38086
38427
|
/** Console requests share Desktop handling; their replies return to the console. */
|
|
38087
|
-
#consoleRequestPrefix = `codexhost-console:${
|
|
38428
|
+
#consoleRequestPrefix = `codexhost-console:${randomUUID16()}:`;
|
|
38088
38429
|
#consoleReplies = /* @__PURE__ */ new Map();
|
|
38089
38430
|
#nextConsoleRequest = 0;
|
|
38090
38431
|
#subagentThreadStatuses = /* @__PURE__ */ new Map();
|
|
@@ -38222,7 +38563,7 @@ var AppServerHost = class {
|
|
|
38222
38563
|
cancelOfficial: (input) => this.#cancelOfficialDelegationThread(input),
|
|
38223
38564
|
startOfficial: (input) => this.#startOfficialDelegation(input),
|
|
38224
38565
|
listOfficial: (input) => this.#listDelegationThreads(input),
|
|
38225
|
-
|
|
38566
|
+
officialThreadMetadata: (threadId2) => this.#readOfficialThreadMetadata(threadId2),
|
|
38226
38567
|
activeOfficialParents: () => [...this.#activeOfficialTurns.keys()],
|
|
38227
38568
|
externalThreadBusy: (thread) => this.#externalThreadBusy(thread)
|
|
38228
38569
|
});
|
|
@@ -38868,11 +39209,11 @@ var AppServerHost = class {
|
|
|
38868
39209
|
this.#dispatchDesktopReply(request, () => this.#inspectHarness(request));
|
|
38869
39210
|
return;
|
|
38870
39211
|
}
|
|
38871
|
-
if (request.method === HARNESS_INSTALLATION_METHOD) {
|
|
39212
|
+
if (request.method === HARNESS_INSTALLATION_METHOD || request.method === HARNESS_INSTALLATION_START_METHOD || request.method === HARNESS_INSTALLATION_STATUS_METHOD) {
|
|
38872
39213
|
this.#dispatchDesktopReply(request, async () => {
|
|
38873
|
-
await this.#waitForPlugins();
|
|
38874
39214
|
try {
|
|
38875
|
-
|
|
39215
|
+
if (request.method !== HARNESS_INSTALLATION_STATUS_METHOD) await this.#waitForPlugins();
|
|
39216
|
+
const result = request.method === HARNESS_INSTALLATION_START_METHOD ? this.#installationTasks.start(request.params, this.#externalAdapters) : request.method === HARNESS_INSTALLATION_STATUS_METHOD ? this.#installationTasks.status(request.params) : await handleHarnessInstallation(request.params, this.#externalAdapters);
|
|
38876
39217
|
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
|
|
38877
39218
|
} catch (error51) {
|
|
38878
39219
|
await this.#writer.json(
|
|
@@ -38957,6 +39298,10 @@ var AppServerHost = class {
|
|
|
38957
39298
|
await this.#listThreadOwnership(request);
|
|
38958
39299
|
return;
|
|
38959
39300
|
}
|
|
39301
|
+
if (request.method === "codexhost/thread/steering/inspect") {
|
|
39302
|
+
await this.#inspectThreadSteering(request);
|
|
39303
|
+
return;
|
|
39304
|
+
}
|
|
38960
39305
|
if (request.method === "codexhost/thread/model/select") {
|
|
38961
39306
|
await this.#selectThreadModel(request);
|
|
38962
39307
|
return;
|
|
@@ -39534,12 +39879,17 @@ var AppServerHost = class {
|
|
|
39534
39879
|
]);
|
|
39535
39880
|
return thread !== null || childDelegation !== null || delegation !== null;
|
|
39536
39881
|
}
|
|
39537
|
-
async #
|
|
39538
|
-
const response = await this.#requestOfficial("thread/read", { threadId: threadId2 });
|
|
39539
|
-
if (isRecord18(response.error)) return
|
|
39882
|
+
async #readOfficialThreadMetadata(threadId2) {
|
|
39883
|
+
const response = await this.#requestOfficial("thread/read", { threadId: threadId2, includeTurns: false });
|
|
39884
|
+
if (isRecord18(response.error)) return {};
|
|
39540
39885
|
const result = isRecord18(response.result) ? response.result : null;
|
|
39541
39886
|
const thread = result && isRecord18(result.thread) ? result.thread : null;
|
|
39542
|
-
|
|
39887
|
+
if (!thread) return {};
|
|
39888
|
+
const title = typeof thread.name === "string" && thread.name.trim() ? thread.name : thread.preview;
|
|
39889
|
+
return {
|
|
39890
|
+
...typeof thread.cwd === "string" && thread.cwd.trim() ? { cwd: thread.cwd } : {},
|
|
39891
|
+
...typeof title === "string" && title.trim() ? { title } : {}
|
|
39892
|
+
};
|
|
39543
39893
|
}
|
|
39544
39894
|
async #inspectOfficialDelegationTarget(input) {
|
|
39545
39895
|
const response = await this.#requestOfficial("model/list", {});
|
|
@@ -39692,6 +40042,9 @@ var AppServerHost = class {
|
|
|
39692
40042
|
this.#pendingOfficialDelegationThreads.add(threadId2);
|
|
39693
40043
|
let turnId;
|
|
39694
40044
|
try {
|
|
40045
|
+
await this.#requestOfficial("thread/name/set", { threadId: threadId2, name: input.title }).catch(
|
|
40046
|
+
() => void 0
|
|
40047
|
+
);
|
|
39695
40048
|
const turn = await this.#requestOfficial("turn/start", {
|
|
39696
40049
|
threadId: threadId2,
|
|
39697
40050
|
input: [{ type: "text", text: input.task }],
|
|
@@ -39710,7 +40063,7 @@ var AppServerHost = class {
|
|
|
39710
40063
|
throw error51;
|
|
39711
40064
|
}
|
|
39712
40065
|
this.#activeOfficialTurns.set(threadId2, turnId);
|
|
39713
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
40066
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID16());
|
|
39714
40067
|
try {
|
|
39715
40068
|
const source = await this.#repository.find(input.parentThreadId);
|
|
39716
40069
|
const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId2);
|
|
@@ -39898,7 +40251,7 @@ var AppServerHost = class {
|
|
|
39898
40251
|
async #listDelegationThreads(input) {
|
|
39899
40252
|
const [sortKey, sortDirection2] = input.sort.split("-");
|
|
39900
40253
|
const request = {
|
|
39901
|
-
id: `codexhost:delegation-list:${
|
|
40254
|
+
id: `codexhost:delegation-list:${randomUUID16()}`,
|
|
39902
40255
|
method: "thread/list",
|
|
39903
40256
|
params: {
|
|
39904
40257
|
cwd: input.cwd ? [input.cwd] : null,
|
|
@@ -40247,7 +40600,8 @@ var AppServerHost = class {
|
|
|
40247
40600
|
try {
|
|
40248
40601
|
inspection = await adapter.inspect({
|
|
40249
40602
|
...params.data.cwd ? { cwd: params.data.cwd } : {},
|
|
40250
|
-
...params.data.refresh !== void 0 ? { refresh: params.data.refresh } : {}
|
|
40603
|
+
...params.data.refresh !== void 0 ? { refresh: params.data.refresh } : {},
|
|
40604
|
+
...params.data.purpose ? { purpose: params.data.purpose } : {}
|
|
40251
40605
|
});
|
|
40252
40606
|
} catch (error51) {
|
|
40253
40607
|
await this.#writer.json(
|
|
@@ -40440,6 +40794,28 @@ var AppServerHost = class {
|
|
|
40440
40794
|
);
|
|
40441
40795
|
}
|
|
40442
40796
|
}
|
|
40797
|
+
/** Read the same delivery decision that Desktop `turn/steer` will follow. */
|
|
40798
|
+
async #inspectThreadSteering(request) {
|
|
40799
|
+
const params = threadSteeringInspectParamsSchema.safeParse(request.params);
|
|
40800
|
+
if (!params.success) {
|
|
40801
|
+
await this.#writer.json(rpcError(request, -32602, "Invalid Thread steering params"));
|
|
40802
|
+
return;
|
|
40803
|
+
}
|
|
40804
|
+
let delivery;
|
|
40805
|
+
try {
|
|
40806
|
+
const location = await this.#locateExternalThread(params.data.threadId);
|
|
40807
|
+
if (await this.#writeResolutionError(request, location)) return;
|
|
40808
|
+
const thread = location.kind === "external" ? this.#externalRuntime.get(params.data.threadId) : void 0;
|
|
40809
|
+
delivery = location.kind !== "external" ? "official" : thread ? await externalSteeringDelivery(thread, params.data.text) : "newTurn";
|
|
40810
|
+
} catch {
|
|
40811
|
+
await this.#writer.json(
|
|
40812
|
+
rpcError(request, -32081, "Thread steering metadata could not be read")
|
|
40813
|
+
);
|
|
40814
|
+
return;
|
|
40815
|
+
}
|
|
40816
|
+
const result = threadSteeringInspectResultSchema.parse({ delivery });
|
|
40817
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
|
|
40818
|
+
}
|
|
40443
40819
|
async #inspectThreadCommands(request) {
|
|
40444
40820
|
const params = threadCommandsInspectParamsSchema.safeParse(request.params);
|
|
40445
40821
|
if (!params.success) {
|
|
@@ -40603,7 +40979,7 @@ var AppServerHost = class {
|
|
|
40603
40979
|
if (thread.running || thread.activeTurnId) {
|
|
40604
40980
|
throw new ExternalCommandError(-32072, "External Thread already has an active operation");
|
|
40605
40981
|
}
|
|
40606
|
-
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(
|
|
40982
|
+
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID16());
|
|
40607
40983
|
const projection = {
|
|
40608
40984
|
projector: new CodexTurnProjector({
|
|
40609
40985
|
threadId: thread.id,
|
|
@@ -40691,6 +41067,26 @@ var AppServerHost = class {
|
|
|
40691
41067
|
if (!projected.effectiveModel) {
|
|
40692
41068
|
throw new Error("Harness Session did not report an effective Model");
|
|
40693
41069
|
}
|
|
41070
|
+
const transportModelId = encodeExternalTransportSelection(thread.harnessId, {
|
|
41071
|
+
...decodeExternalTransportSelection(thread.harnessId, thread.transportModelId) ?? {},
|
|
41072
|
+
model: projected.effectiveModel
|
|
41073
|
+
});
|
|
41074
|
+
thread.transportModelId = transportModelId;
|
|
41075
|
+
thread.requestedModel = projected.effectiveModel;
|
|
41076
|
+
try {
|
|
41077
|
+
thread.record = await this.#repository.setTransportModelId(
|
|
41078
|
+
thread.record.hostThreadId,
|
|
41079
|
+
transportModelId
|
|
41080
|
+
);
|
|
41081
|
+
} catch (error51) {
|
|
41082
|
+
this.#diagnose(error51);
|
|
41083
|
+
}
|
|
41084
|
+
thread.thread = externalThreadValue({
|
|
41085
|
+
record: { ...thread.record, transportModelId },
|
|
41086
|
+
turns: thread.turns,
|
|
41087
|
+
sessionId: thread.sessionId,
|
|
41088
|
+
running: thread.running
|
|
41089
|
+
});
|
|
40694
41090
|
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(projected) }));
|
|
40695
41091
|
} catch (error51) {
|
|
40696
41092
|
await this.#writer.json(
|
|
@@ -41020,9 +41416,20 @@ var AppServerHost = class {
|
|
|
41020
41416
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
41021
41417
|
return true;
|
|
41022
41418
|
}
|
|
41419
|
+
/** Refresh history before Desktop acts on native Turn boundaries. */
|
|
41023
41420
|
#refreshExternalThread(thread) {
|
|
41024
41421
|
return this.#externalRuntime.refresh(thread);
|
|
41025
41422
|
}
|
|
41423
|
+
#markExternalHistoryRead(thread, turns) {
|
|
41424
|
+
if (!thread.historyHydrated) return;
|
|
41425
|
+
for (const turnId of thread.steeredTurnIds) {
|
|
41426
|
+
if (turnId !== thread.activeTurnId && turns.some(
|
|
41427
|
+
(turn) => turn.id === turnId && (turn.status === "completed" || turn.status === "failed" || turn.status === "interrupted")
|
|
41428
|
+
)) {
|
|
41429
|
+
thread.steeredTurnIds.delete(turnId);
|
|
41430
|
+
}
|
|
41431
|
+
}
|
|
41432
|
+
}
|
|
41026
41433
|
#persistTerminalIdentity(thread, event) {
|
|
41027
41434
|
return this.#externalRuntime.persistTerminalIdentity(thread, event);
|
|
41028
41435
|
}
|
|
@@ -41224,17 +41631,19 @@ var AppServerHost = class {
|
|
|
41224
41631
|
return;
|
|
41225
41632
|
}
|
|
41226
41633
|
}
|
|
41634
|
+
const readTurns = includeTurns ? [...this.#externalHistoryTurns(thread)] : [];
|
|
41227
41635
|
await this.#writer.json(
|
|
41228
41636
|
rpcEnvelope(request, {
|
|
41229
41637
|
result: {
|
|
41230
41638
|
thread: {
|
|
41231
41639
|
...thread.thread,
|
|
41232
41640
|
...await this.#externalSectionFields(thread.record.hostThreadId),
|
|
41233
|
-
turns:
|
|
41641
|
+
turns: readTurns
|
|
41234
41642
|
}
|
|
41235
41643
|
}
|
|
41236
41644
|
})
|
|
41237
41645
|
);
|
|
41646
|
+
if (includeTurns) this.#markExternalHistoryRead(thread, readTurns);
|
|
41238
41647
|
await this.#replayExternalUsage(thread);
|
|
41239
41648
|
}
|
|
41240
41649
|
async #listExternalHistory(request, thread, params, historyFresh) {
|
|
@@ -41251,6 +41660,9 @@ var AppServerHost = class {
|
|
|
41251
41660
|
const turns = this.#externalHistoryTurns(thread);
|
|
41252
41661
|
const result = request.method === "thread/turns/list" ? listExternalTurns(turns, params) : listExternalItems(turns, params);
|
|
41253
41662
|
await this.#writer.json(rpcEnvelope(request, { result }));
|
|
41663
|
+
if (request.method === "thread/turns/list") {
|
|
41664
|
+
this.#markExternalHistoryRead(thread, result.data);
|
|
41665
|
+
}
|
|
41254
41666
|
} catch (error51) {
|
|
41255
41667
|
await this.#writer.json(
|
|
41256
41668
|
rpcError(
|
|
@@ -41269,7 +41681,7 @@ var AppServerHost = class {
|
|
|
41269
41681
|
return;
|
|
41270
41682
|
}
|
|
41271
41683
|
}
|
|
41272
|
-
const turns = this.#externalHistoryTurns(thread);
|
|
41684
|
+
const turns = [...this.#externalHistoryTurns(thread)];
|
|
41273
41685
|
const responseThread = {
|
|
41274
41686
|
...await this.#withExternalSection(thread.thread),
|
|
41275
41687
|
turns: params.excludeTurns === true ? [] : turns
|
|
@@ -41301,6 +41713,8 @@ var AppServerHost = class {
|
|
|
41301
41713
|
}
|
|
41302
41714
|
})
|
|
41303
41715
|
);
|
|
41716
|
+
if (params.excludeTurns !== true) this.#markExternalHistoryRead(thread, turns);
|
|
41717
|
+
else if (initialTurnsPage) this.#markExternalHistoryRead(thread, initialTurnsPage.data);
|
|
41304
41718
|
} catch (error51) {
|
|
41305
41719
|
await this.#writer.json(
|
|
41306
41720
|
rpcError(
|
|
@@ -41443,10 +41857,15 @@ var AppServerHost = class {
|
|
|
41443
41857
|
assertActive,
|
|
41444
41858
|
typeof requestObject(request).clientUserMessageId === "string" ? requestObject(request).clientUserMessageId : void 0,
|
|
41445
41859
|
requestObject(request)[THREAD_REFERENCE_SOURCE_HOST_PARAM]
|
|
41446
|
-
)
|
|
41860
|
+
),
|
|
41861
|
+
(input) => this.#insertExternalInput(thread, input)
|
|
41447
41862
|
);
|
|
41448
41863
|
try {
|
|
41449
|
-
await this.#writer.json(
|
|
41864
|
+
await this.#writer.json(
|
|
41865
|
+
rpcEnvelope(request, {
|
|
41866
|
+
result: { turnId: started.turnId, delivery: started.delivery }
|
|
41867
|
+
})
|
|
41868
|
+
);
|
|
41450
41869
|
} finally {
|
|
41451
41870
|
started.gate.resolve();
|
|
41452
41871
|
}
|
|
@@ -41462,6 +41881,34 @@ var AppServerHost = class {
|
|
|
41462
41881
|
this.#signalActiveWorkChanged();
|
|
41463
41882
|
}
|
|
41464
41883
|
}
|
|
41884
|
+
/** Native same-Turn input; `insertNativeSteer` owns the delivery and its fallback signal. */
|
|
41885
|
+
async #insertExternalInput(thread, input) {
|
|
41886
|
+
await insertNativeSteer(thread, input, {
|
|
41887
|
+
project: async (turnId, item, clientUserMessageId) => {
|
|
41888
|
+
const projection = this.#projectedTurn(thread, turnId);
|
|
41889
|
+
if (clientUserMessageId) {
|
|
41890
|
+
projection.projector.bindUserMessageClientId(item.itemId, clientUserMessageId);
|
|
41891
|
+
}
|
|
41892
|
+
await this.#projectHarnessOutput(thread, {
|
|
41893
|
+
kind: "event",
|
|
41894
|
+
event: { type: "item.started", turnId, item }
|
|
41895
|
+
});
|
|
41896
|
+
await this.#projectHarnessOutput(thread, {
|
|
41897
|
+
kind: "event",
|
|
41898
|
+
event: {
|
|
41899
|
+
type: "item.completed",
|
|
41900
|
+
turnId,
|
|
41901
|
+
snapshot: { item, outcome: { status: "succeeded" } }
|
|
41902
|
+
}
|
|
41903
|
+
});
|
|
41904
|
+
},
|
|
41905
|
+
diagnose: (error51) => this.#diagnose(error51)
|
|
41906
|
+
});
|
|
41907
|
+
return {
|
|
41908
|
+
turnId: input.turnId,
|
|
41909
|
+
gate: { promise: Promise.resolve(), resolve: () => void 0 }
|
|
41910
|
+
};
|
|
41911
|
+
}
|
|
41465
41912
|
/** Keep command restoration and dispatch identical for start and steer submissions. */
|
|
41466
41913
|
async #beginExternalInputTurn(thread, inputText, assertActive, clientUserMessageId, sourceHostId) {
|
|
41467
41914
|
const text = restoreHarnessCommandMentions(inputText);
|
|
@@ -41519,7 +41966,7 @@ var AppServerHost = class {
|
|
|
41519
41966
|
if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
|
|
41520
41967
|
throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
|
|
41521
41968
|
}
|
|
41522
|
-
const turnId = hostTurnIdSchema.parse(
|
|
41969
|
+
const turnId = hostTurnIdSchema.parse(randomUUID16());
|
|
41523
41970
|
const startedAtMs = Date.now();
|
|
41524
41971
|
const projection = {
|
|
41525
41972
|
projector: new CodexTurnProjector({
|
|
@@ -41814,6 +42261,9 @@ var AppServerHost = class {
|
|
|
41814
42261
|
}
|
|
41815
42262
|
return;
|
|
41816
42263
|
}
|
|
42264
|
+
if (event.type === "turn.completed" && thread.pendingSteerProjections.size > 0) {
|
|
42265
|
+
await Promise.allSettled([...thread.pendingSteerProjections]);
|
|
42266
|
+
}
|
|
41817
42267
|
const projection = this.#projectedTurn(thread, event.turnId);
|
|
41818
42268
|
await this.#waitForTurnResponse(thread, event.turnId);
|
|
41819
42269
|
if (event.type === "interaction.closed" && thread.ignoredInteractionIds.delete(event.interactionId)) {
|
|
@@ -41863,6 +42313,7 @@ var AppServerHost = class {
|
|
|
41863
42313
|
thread.activeTurnId = null;
|
|
41864
42314
|
if (!projection.projector.hasOpenDetachedItems) thread.projectedTurns.delete(event.turnId);
|
|
41865
42315
|
thread.responseGates.delete(event.turnId);
|
|
42316
|
+
thread.pendingSteerProjections.clear();
|
|
41866
42317
|
this.#signalActiveWorkChanged();
|
|
41867
42318
|
const delegation = await this.#repository.getDelegationByChild(thread.record.hostThreadId);
|
|
41868
42319
|
if (delegation) {
|
|
@@ -42153,7 +42604,7 @@ var AppServerHost = class {
|
|
|
42153
42604
|
try {
|
|
42154
42605
|
result = projection.projector.projectQuestion(
|
|
42155
42606
|
interaction,
|
|
42156
|
-
hostItemIdSchema.parse(
|
|
42607
|
+
hostItemIdSchema.parse(randomUUID16())
|
|
42157
42608
|
);
|
|
42158
42609
|
} catch (error51) {
|
|
42159
42610
|
this.#diagnose(error51);
|
|
@@ -42392,7 +42843,7 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
42392
42843
|
var wrapper_default = import_websocket.default;
|
|
42393
42844
|
|
|
42394
42845
|
// packages/host-runtime/src/remote-socket-lock.ts
|
|
42395
|
-
import { randomUUID as
|
|
42846
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
42396
42847
|
import { chmod as chmod3, lstat as lstat5, mkdir as mkdir12, open as open9, readFile as readFile16, readdir as readdir5, rename as rename11, rm as rm11 } from "node:fs/promises";
|
|
42397
42848
|
import { uptime } from "node:os";
|
|
42398
42849
|
import path26 from "node:path";
|
|
@@ -42518,7 +42969,7 @@ async function preparePrivateLockDirectory(lockDirectory) {
|
|
|
42518
42969
|
await chmod3(lockDirectory, 448);
|
|
42519
42970
|
}
|
|
42520
42971
|
async function writeLockRecordAtomic(lockDirectory, entryPath, record4) {
|
|
42521
|
-
const temporary = path26.join(lockDirectory, `.tmp-${record4.ownerToken}-${
|
|
42972
|
+
const temporary = path26.join(lockDirectory, `.tmp-${record4.ownerToken}-${randomUUID17()}`);
|
|
42522
42973
|
const handle = await open9(temporary, "wx", 384);
|
|
42523
42974
|
try {
|
|
42524
42975
|
await handle.writeFile(`${JSON.stringify(record4)}
|
|
@@ -42593,7 +43044,7 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
|
|
|
42593
43044
|
const legacyPath = `${socketPath}.initializing`;
|
|
42594
43045
|
const lockDirectory = `${socketPath}.initializers`;
|
|
42595
43046
|
await preparePrivateLockDirectory(lockDirectory);
|
|
42596
|
-
const ownerToken =
|
|
43047
|
+
const ownerToken = randomUUID17();
|
|
42597
43048
|
const entryPath = path26.join(lockDirectory, lockEntryName(ownerToken));
|
|
42598
43049
|
const baseRecord = {
|
|
42599
43050
|
version: 2,
|
|
@@ -43104,12 +43555,12 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
43104
43555
|
|
|
43105
43556
|
// packages/host-runtime/src/remote-official-app-server.ts
|
|
43106
43557
|
import { spawn as spawn5 } from "node:child_process";
|
|
43107
|
-
import { randomUUID as
|
|
43558
|
+
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
43108
43559
|
import { lstat as lstat7, rm as rm13, stat as stat7 } from "node:fs/promises";
|
|
43109
43560
|
import path28 from "node:path";
|
|
43110
43561
|
var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
|
|
43111
43562
|
var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
|
|
43112
|
-
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token =
|
|
43563
|
+
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID18()) {
|
|
43113
43564
|
if (!path28.posix.isAbsolute(desktopControlSocketPath)) {
|
|
43114
43565
|
throw new Error("Desktop control socket path must be absolute");
|
|
43115
43566
|
}
|
|
@@ -44328,11 +44779,11 @@ async function readRemoteDelegationThread(environment, input) {
|
|
|
44328
44779
|
}
|
|
44329
44780
|
|
|
44330
44781
|
// packages/host-runtime/src/shared-thread-owner.ts
|
|
44331
|
-
import { randomUUID as
|
|
44782
|
+
import { randomUUID as randomUUID20 } from "node:crypto";
|
|
44332
44783
|
import { PassThrough as PassThrough3 } from "node:stream";
|
|
44333
44784
|
|
|
44334
44785
|
// packages/host-runtime/src/shared-thread-peer.ts
|
|
44335
|
-
import { randomUUID as
|
|
44786
|
+
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
44336
44787
|
function object5(value2) {
|
|
44337
44788
|
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
44338
44789
|
}
|
|
@@ -44346,7 +44797,7 @@ var StreamThreadPeer = class {
|
|
|
44346
44797
|
input;
|
|
44347
44798
|
output;
|
|
44348
44799
|
stop;
|
|
44349
|
-
#prefix = `shared:${
|
|
44800
|
+
#prefix = `shared:${randomUUID19()}:`;
|
|
44350
44801
|
#pending = /* @__PURE__ */ new Map();
|
|
44351
44802
|
#listeners = /* @__PURE__ */ new Set();
|
|
44352
44803
|
#ended = Promise.withResolvers();
|
|
@@ -44424,7 +44875,7 @@ var SharedThreadOwner = class {
|
|
|
44424
44875
|
input = new PassThrough3();
|
|
44425
44876
|
output = new PassThrough3();
|
|
44426
44877
|
#peer = new StreamThreadPeer(this.output, this.input, () => this.input.end());
|
|
44427
|
-
#prefix = `shared-interaction:${
|
|
44878
|
+
#prefix = `shared-interaction:${randomUUID20()}:`;
|
|
44428
44879
|
#interactions = /* @__PURE__ */ new Map();
|
|
44429
44880
|
#listeners = /* @__PURE__ */ new Set();
|
|
44430
44881
|
#receipts = /* @__PURE__ */ new Map();
|
|
@@ -44734,7 +45185,7 @@ var SharedThreadBridge = class {
|
|
|
44734
45185
|
};
|
|
44735
45186
|
|
|
44736
45187
|
// packages/host-runtime/src/remote-control-app-server.ts
|
|
44737
|
-
import { randomUUID as
|
|
45188
|
+
import { randomUUID as randomUUID21 } from "node:crypto";
|
|
44738
45189
|
import { mkdir as mkdir15, open as open10, rename as rename12, rm as rm14 } from "node:fs/promises";
|
|
44739
45190
|
import path33 from "node:path";
|
|
44740
45191
|
var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
|
|
@@ -44755,7 +45206,7 @@ function nodeCompatibleWindowsPath(value2) {
|
|
|
44755
45206
|
if (value2.startsWith("\\\\?\\")) return value2.slice(4);
|
|
44756
45207
|
return value2;
|
|
44757
45208
|
}
|
|
44758
|
-
function remoteControlBridgePipePath(processId = process.pid, instanceId =
|
|
45209
|
+
function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID21()) {
|
|
44759
45210
|
const safeInstance = instanceId.replaceAll(/[^a-zA-Z0-9-]/gu, "");
|
|
44760
45211
|
if (!safeInstance) throw new Error("Remote Control bridge instance ID is invalid");
|
|
44761
45212
|
return `\\\\.\\pipe\\codexhost-remote-control-${processId}-${safeInstance}`;
|
|
@@ -44770,7 +45221,7 @@ async function publishRemoteControlAppServerDescriptor(plan) {
|
|
|
44770
45221
|
await mkdir15(directory, { recursive: true, mode: 448 });
|
|
44771
45222
|
const temporaryPath = path33.join(
|
|
44772
45223
|
directory,
|
|
44773
|
-
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${
|
|
45224
|
+
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID21()}.tmp`
|
|
44774
45225
|
);
|
|
44775
45226
|
const handle = await open10(temporaryPath, "wx", 384);
|
|
44776
45227
|
try {
|
|
@@ -45292,12 +45743,19 @@ function createHostUpdateCoordinator(options2) {
|
|
|
45292
45743
|
}
|
|
45293
45744
|
|
|
45294
45745
|
// packages/host-runtime/src/usage-statistics.ts
|
|
45295
|
-
import { randomUUID as
|
|
45746
|
+
import { randomUUID as randomUUID22 } from "node:crypto";
|
|
45296
45747
|
import { mkdir as mkdir17, readFile as readFile17, readdir as readdir6, rename as rename14, rm as rm16, writeFile as writeFile10 } from "node:fs/promises";
|
|
45297
45748
|
import path36 from "node:path";
|
|
45298
45749
|
import { setImmediate as yieldToEventLoop } from "node:timers/promises";
|
|
45299
45750
|
|
|
45300
45751
|
// packages/harness-adapter/dist/usage-statistics.js
|
|
45752
|
+
var HarnessUsageSourceChangedError = class extends Error {
|
|
45753
|
+
code = "HARNESS_USAGE_SOURCE_CHANGED";
|
|
45754
|
+
/** Plugins may bundle their own copy of this contract, so instanceof is insufficient. */
|
|
45755
|
+
static is(error51) {
|
|
45756
|
+
return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "HARNESS_USAGE_SOURCE_CHANGED";
|
|
45757
|
+
}
|
|
45758
|
+
};
|
|
45301
45759
|
var MAX_SESSION_ID_LENGTH = 512;
|
|
45302
45760
|
var MAX_CWD_LENGTH = 4096;
|
|
45303
45761
|
var MAX_SESSION_TITLE_LENGTH = 200;
|
|
@@ -45309,10 +45767,13 @@ function usageSessionTitle(value2) {
|
|
|
45309
45767
|
return void 0;
|
|
45310
45768
|
if (normalized.length <= MAX_SESSION_TITLE_LENGTH)
|
|
45311
45769
|
return normalized;
|
|
45312
|
-
|
|
45313
|
-
|
|
45314
|
-
|
|
45315
|
-
|
|
45770
|
+
let title = "";
|
|
45771
|
+
for (const character of normalized) {
|
|
45772
|
+
if (title.length + character.length >= MAX_SESSION_TITLE_LENGTH)
|
|
45773
|
+
break;
|
|
45774
|
+
title += character;
|
|
45775
|
+
}
|
|
45776
|
+
return `${title.trimEnd()}…`;
|
|
45316
45777
|
}
|
|
45317
45778
|
function sessionIdOk(value2) {
|
|
45318
45779
|
return typeof value2 === "string" && value2.length > 0 && value2.length <= MAX_SESSION_ID_LENGTH;
|
|
@@ -45397,6 +45858,95 @@ function withHostSessionTitles(result, records) {
|
|
|
45397
45858
|
};
|
|
45398
45859
|
}
|
|
45399
45860
|
|
|
45861
|
+
// packages/host-runtime/src/usage-statistics-sources.ts
|
|
45862
|
+
import { setTimeout as delay6 } from "node:timers/promises";
|
|
45863
|
+
async function* readUsageStatisticsSources(capability, sources, signal) {
|
|
45864
|
+
let pending = sources;
|
|
45865
|
+
for (let attempt = 0; ; attempt++) {
|
|
45866
|
+
const changed = [];
|
|
45867
|
+
for (const source of pending) {
|
|
45868
|
+
signal.throwIfAborted();
|
|
45869
|
+
try {
|
|
45870
|
+
const entries = (await capability.readSource(source.id, signal)).map(parseHarnessUsageEntry).filter((entry) => entry !== null);
|
|
45871
|
+
yield { source, entries };
|
|
45872
|
+
} catch (error51) {
|
|
45873
|
+
signal.throwIfAborted();
|
|
45874
|
+
if (HarnessUsageSourceChangedError.is(error51) && attempt < 2) changed.push(source);
|
|
45875
|
+
else yield { source, error: error51 };
|
|
45876
|
+
}
|
|
45877
|
+
}
|
|
45878
|
+
if (!changed.length) return;
|
|
45879
|
+
await delay6(50 * (attempt + 1), void 0, { signal });
|
|
45880
|
+
let current;
|
|
45881
|
+
try {
|
|
45882
|
+
current = new Map(
|
|
45883
|
+
(await capability.listSources(signal)).map((source) => [source.id, source])
|
|
45884
|
+
);
|
|
45885
|
+
} catch (error51) {
|
|
45886
|
+
signal.throwIfAborted();
|
|
45887
|
+
for (const source of changed) yield { source, error: error51 };
|
|
45888
|
+
return;
|
|
45889
|
+
}
|
|
45890
|
+
const next = [];
|
|
45891
|
+
for (const source of changed) {
|
|
45892
|
+
const fresh = current.get(source.id);
|
|
45893
|
+
if (fresh) next.push(fresh);
|
|
45894
|
+
else yield { source, removed: true };
|
|
45895
|
+
}
|
|
45896
|
+
pending = next;
|
|
45897
|
+
}
|
|
45898
|
+
}
|
|
45899
|
+
|
|
45900
|
+
// packages/host-runtime/src/usage-statistics-calendar.ts
|
|
45901
|
+
function dateKey(year, month, day) {
|
|
45902
|
+
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
45903
|
+
}
|
|
45904
|
+
function createUsageStatisticsCalendar(timeZone) {
|
|
45905
|
+
const localZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
45906
|
+
const zone = timeZone ?? localZone;
|
|
45907
|
+
if (zone === localZone) {
|
|
45908
|
+
return {
|
|
45909
|
+
timeZone: zone,
|
|
45910
|
+
at(ms) {
|
|
45911
|
+
const date5 = new Date(ms);
|
|
45912
|
+
return {
|
|
45913
|
+
date: dateKey(date5.getFullYear(), date5.getMonth() + 1, date5.getDate()),
|
|
45914
|
+
weekday: date5.getDay(),
|
|
45915
|
+
hour: date5.getHours()
|
|
45916
|
+
};
|
|
45917
|
+
}
|
|
45918
|
+
};
|
|
45919
|
+
}
|
|
45920
|
+
const format = new Intl.DateTimeFormat("en-US", {
|
|
45921
|
+
timeZone: zone,
|
|
45922
|
+
calendar: "gregory",
|
|
45923
|
+
numberingSystem: "latn",
|
|
45924
|
+
year: "numeric",
|
|
45925
|
+
month: "2-digit",
|
|
45926
|
+
day: "2-digit",
|
|
45927
|
+
hour: "2-digit",
|
|
45928
|
+
hourCycle: "h23"
|
|
45929
|
+
});
|
|
45930
|
+
return {
|
|
45931
|
+
timeZone: zone,
|
|
45932
|
+
at(ms) {
|
|
45933
|
+
const parts = format.formatToParts(ms);
|
|
45934
|
+
const part = (type) => Number(parts.find((value2) => value2.type === type)?.value);
|
|
45935
|
+
const year = part("year"), month = part("month"), day = part("day");
|
|
45936
|
+
return {
|
|
45937
|
+
date: dateKey(year, month, day),
|
|
45938
|
+
weekday: new Date(Date.UTC(year, month - 1, day)).getUTCDay(),
|
|
45939
|
+
hour: part("hour")
|
|
45940
|
+
};
|
|
45941
|
+
}
|
|
45942
|
+
};
|
|
45943
|
+
}
|
|
45944
|
+
function shiftUsageDate(date5, days) {
|
|
45945
|
+
const value2 = /* @__PURE__ */ new Date(`${date5}T12:00:00Z`);
|
|
45946
|
+
value2.setUTCDate(value2.getUTCDate() + days);
|
|
45947
|
+
return dateKey(value2.getUTCFullYear(), value2.getUTCMonth() + 1, value2.getUTCDate());
|
|
45948
|
+
}
|
|
45949
|
+
|
|
45400
45950
|
// packages/host-runtime/src/usage-statistics.ts
|
|
45401
45951
|
var CACHE_VERSION = 7;
|
|
45402
45952
|
var STALE_AFTER_MS = 1e4;
|
|
@@ -45457,17 +46007,6 @@ function expand(value2, intern) {
|
|
|
45457
46007
|
function message(error51) {
|
|
45458
46008
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
45459
46009
|
}
|
|
45460
|
-
function localDate2(ms) {
|
|
45461
|
-
const date5 = new Date(ms);
|
|
45462
|
-
const month = String(date5.getMonth() + 1).padStart(2, "0");
|
|
45463
|
-
const day = String(date5.getDate()).padStart(2, "0");
|
|
45464
|
-
return `${date5.getFullYear()}-${month}-${day}`;
|
|
45465
|
-
}
|
|
45466
|
-
function shiftDate(date5, days) {
|
|
45467
|
-
const value2 = /* @__PURE__ */ new Date(`${date5}T12:00:00`);
|
|
45468
|
-
value2.setDate(value2.getDate() + days);
|
|
45469
|
-
return localDate2(value2.getTime());
|
|
45470
|
-
}
|
|
45471
46010
|
var SESSIONS_PER_MEASURE = 50;
|
|
45472
46011
|
var MODELS_PER_SESSION = 16;
|
|
45473
46012
|
function emptyTotals() {
|
|
@@ -45654,23 +46193,27 @@ var UsageStatistics = class {
|
|
|
45654
46193
|
}
|
|
45655
46194
|
for (const { harness: harness2, capability, ids } of listed) {
|
|
45656
46195
|
const cache = this.#cache(harness2);
|
|
45657
|
-
const present =
|
|
46196
|
+
const present = new Set(ids.map(({ id: id2 }) => id2));
|
|
45658
46197
|
let failed = null;
|
|
45659
|
-
|
|
45660
|
-
|
|
45661
|
-
|
|
45662
|
-
|
|
45663
|
-
|
|
45664
|
-
|
|
46198
|
+
const pending = ids.filter(
|
|
46199
|
+
({ id: id2, fingerprint }) => cache.sources.get(id2)?.fingerprint !== fingerprint
|
|
46200
|
+
);
|
|
46201
|
+
this.#progress.read += ids.length - pending.length;
|
|
46202
|
+
try {
|
|
46203
|
+
for await (const result of readUsageStatisticsSources(capability, pending, signal)) {
|
|
46204
|
+
const { id: id2, fingerprint } = result.source;
|
|
46205
|
+
if ("entries" in result) {
|
|
46206
|
+
cache.sources.set(id2, { fingerprint, entries: result.entries });
|
|
45665
46207
|
cache.dirty = true;
|
|
45666
46208
|
this.#generation += 1;
|
|
45667
|
-
}
|
|
45668
|
-
|
|
45669
|
-
|
|
45670
|
-
}
|
|
46209
|
+
} else if ("error" in result) failed ??= message(result.error);
|
|
46210
|
+
else present.delete(id2);
|
|
46211
|
+
this.#progress.read += 1;
|
|
45671
46212
|
await yieldToEventLoop();
|
|
45672
46213
|
}
|
|
45673
|
-
|
|
46214
|
+
} catch (error51) {
|
|
46215
|
+
if (signal.aborted) return;
|
|
46216
|
+
throw error51;
|
|
45674
46217
|
}
|
|
45675
46218
|
for (const id2 of cache.sources.keys()) {
|
|
45676
46219
|
if (!present.has(id2)) {
|
|
@@ -45735,7 +46278,7 @@ var UsageStatistics = class {
|
|
|
45735
46278
|
async #persist(harness2, cache) {
|
|
45736
46279
|
if (!cache.dirty || this.#now() - cache.persistedAtMs < PERSIST_INTERVAL_MS) return;
|
|
45737
46280
|
const file2 = this.#file(harness2);
|
|
45738
|
-
const temporary = `${file2}.${
|
|
46281
|
+
const temporary = `${file2}.${randomUUID22()}.tmp`;
|
|
45739
46282
|
try {
|
|
45740
46283
|
await mkdir17(this.#directory, { recursive: true });
|
|
45741
46284
|
const sources = [...cache.sources].map(([id2, source]) => [
|
|
@@ -45753,9 +46296,10 @@ var UsageStatistics = class {
|
|
|
45753
46296
|
await rm16(temporary, { force: true });
|
|
45754
46297
|
}
|
|
45755
46298
|
}
|
|
45756
|
-
/** Every request once, per Harness in source order,
|
|
45757
|
-
#indexed() {
|
|
45758
|
-
if (this.#index?.generation === this.#generation
|
|
46299
|
+
/** Every request once, per Harness in source order, in the requested calendar. */
|
|
46300
|
+
#indexed(calendar) {
|
|
46301
|
+
if (this.#index?.generation === this.#generation && this.#index.timeZone === calendar.timeZone)
|
|
46302
|
+
return this.#index.entries;
|
|
45759
46303
|
const entries = [];
|
|
45760
46304
|
for (const [harness2, cache] of this.#caches) {
|
|
45761
46305
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -45763,26 +46307,20 @@ var UsageStatistics = class {
|
|
|
45763
46307
|
for (const entry of parsed2) {
|
|
45764
46308
|
if (seen.has(entry.id)) continue;
|
|
45765
46309
|
seen.add(entry.id);
|
|
45766
|
-
|
|
45767
|
-
entries.push({
|
|
45768
|
-
harness: harness2,
|
|
45769
|
-
entry,
|
|
45770
|
-
date: localDate2(entry.occurredAtMs),
|
|
45771
|
-
weekday: at.getDay(),
|
|
45772
|
-
hour: at.getHours()
|
|
45773
|
-
});
|
|
46310
|
+
entries.push({ harness: harness2, entry, ...calendar.at(entry.occurredAtMs) });
|
|
45774
46311
|
}
|
|
45775
46312
|
}
|
|
45776
46313
|
}
|
|
45777
|
-
this.#index = { generation: this.#generation, entries };
|
|
46314
|
+
this.#index = { generation: this.#generation, timeZone: calendar.timeZone, entries };
|
|
45778
46315
|
return entries;
|
|
45779
46316
|
}
|
|
45780
46317
|
#aggregate(params, now, lookup) {
|
|
45781
46318
|
const { range } = params;
|
|
45782
46319
|
const days = RANGE_DAYS[range];
|
|
45783
|
-
const
|
|
46320
|
+
const calendar = createUsageStatisticsCalendar(params.timeZone);
|
|
46321
|
+
const to = calendar.at(now).date;
|
|
45784
46322
|
let from = null;
|
|
45785
|
-
if (days !== null) from =
|
|
46323
|
+
if (days !== null) from = shiftUsageDate(to, -days + 1);
|
|
45786
46324
|
const inRange = (date5) => (from === null || date5 >= from) && date5 <= to;
|
|
45787
46325
|
const day = params.date !== void 0 && inRange(params.date) ? params.date : null;
|
|
45788
46326
|
const harnessFilter = params.harness ?? null;
|
|
@@ -45823,7 +46361,7 @@ var UsageStatistics = class {
|
|
|
45823
46361
|
const harnessPriced = /* @__PURE__ */ new Map();
|
|
45824
46362
|
const byProject = /* @__PURE__ */ new Map();
|
|
45825
46363
|
const sessions = /* @__PURE__ */ new Map();
|
|
45826
|
-
for (const indexed of this.#indexed()) {
|
|
46364
|
+
for (const indexed of this.#indexed(calendar)) {
|
|
45827
46365
|
const { harness: harness2, entry, date: date5 } = indexed;
|
|
45828
46366
|
if (!inRange(date5)) continue;
|
|
45829
46367
|
const model2 = entry.model ?? null;
|
|
@@ -46351,7 +46889,7 @@ async function runHostRuntime(input) {
|
|
|
46351
46889
|
}
|
|
46352
46890
|
|
|
46353
46891
|
// packages/host-runtime/src/remote-host-install.ts
|
|
46354
|
-
import { createHash as createHash11, randomUUID as
|
|
46892
|
+
import { createHash as createHash11, randomUUID as randomUUID23 } from "node:crypto";
|
|
46355
46893
|
import { constants as fsConstants } from "node:fs";
|
|
46356
46894
|
import {
|
|
46357
46895
|
access as access3,
|
|
@@ -46450,7 +46988,7 @@ async function writeAtomic(filePath, contents, mode) {
|
|
|
46450
46988
|
await mkdir18(path38.dirname(filePath), { recursive: true, mode: 448 });
|
|
46451
46989
|
const temporary = path38.join(
|
|
46452
46990
|
path38.dirname(filePath),
|
|
46453
|
-
`.${path38.basename(filePath)}.${process.pid}.${
|
|
46991
|
+
`.${path38.basename(filePath)}.${process.pid}.${randomUUID23()}.tmp`
|
|
46454
46992
|
);
|
|
46455
46993
|
try {
|
|
46456
46994
|
if (typeof contents === "string") {
|
|
@@ -46474,7 +47012,7 @@ async function writeAtomicExecutable(filePath, sourcePath) {
|
|
|
46474
47012
|
await mkdir18(path38.dirname(filePath), { recursive: true, mode: 448 });
|
|
46475
47013
|
const temporary = path38.join(
|
|
46476
47014
|
path38.dirname(filePath),
|
|
46477
|
-
`.${path38.basename(filePath)}.${process.pid}.${
|
|
47015
|
+
`.${path38.basename(filePath)}.${process.pid}.${randomUUID23()}.tmp`
|
|
46478
47016
|
);
|
|
46479
47017
|
try {
|
|
46480
47018
|
await copyFile4(sourcePath, temporary);
|
|
@@ -47215,6 +47753,7 @@ var harnessBrokerMethodSchema = external_exports.enum([
|
|
|
47215
47753
|
"adapter.open",
|
|
47216
47754
|
"adapter.subagent.readSnapshot",
|
|
47217
47755
|
"session.readSnapshot",
|
|
47756
|
+
"session.readCapabilities",
|
|
47218
47757
|
"session.refreshUsage",
|
|
47219
47758
|
"session.execute",
|
|
47220
47759
|
"session.commands.list",
|
|
@@ -47397,6 +47936,11 @@ var turnStartSchema = external_exports.object({
|
|
|
47397
47936
|
turnId: hostTurnIdSchema,
|
|
47398
47937
|
input: external_exports.array(textInputSchema)
|
|
47399
47938
|
}).strict();
|
|
47939
|
+
var turnSteerSchema = external_exports.object({
|
|
47940
|
+
type: external_exports.literal("turn.steer"),
|
|
47941
|
+
turnId: hostTurnIdSchema,
|
|
47942
|
+
input: external_exports.array(textInputSchema)
|
|
47943
|
+
}).strict();
|
|
47400
47944
|
var turnCancelSchema = external_exports.object({ type: external_exports.literal("turn.cancel"), turnId: hostTurnIdSchema }).strict();
|
|
47401
47945
|
var interactionResponseSchema = external_exports.union([
|
|
47402
47946
|
external_exports.object({
|
|
@@ -47422,6 +47966,7 @@ var permissionSelectSchema = external_exports.object({
|
|
|
47422
47966
|
}).strict();
|
|
47423
47967
|
var brokerHostCommandSchema = external_exports.discriminatedUnion("type", [
|
|
47424
47968
|
turnStartSchema,
|
|
47969
|
+
turnSteerSchema,
|
|
47425
47970
|
turnCancelSchema,
|
|
47426
47971
|
interactionRespondSchema,
|
|
47427
47972
|
modelSelectSchema,
|
|
@@ -47556,7 +48101,7 @@ var harnessOutputSchema = external_exports.custom((value2) => {
|
|
|
47556
48101
|
});
|
|
47557
48102
|
|
|
47558
48103
|
// packages/harness-broker/dist/server.js
|
|
47559
|
-
import { randomBytes as randomBytes5, randomUUID as
|
|
48104
|
+
import { randomBytes as randomBytes5, randomUUID as randomUUID24 } from "node:crypto";
|
|
47560
48105
|
import { chmod as chmod6, lstat as lstat10, mkdir as mkdir19, open as open11, readFile as readFile19, rename as rename16, rm as rm18 } from "node:fs/promises";
|
|
47561
48106
|
import net4, {} from "node:net";
|
|
47562
48107
|
import path41 from "node:path";
|
|
@@ -47615,7 +48160,7 @@ async function assertNoLiveDescriptor(descriptorPath) {
|
|
|
47615
48160
|
}
|
|
47616
48161
|
}
|
|
47617
48162
|
async function publishDescriptor(descriptorPath, descriptor) {
|
|
47618
|
-
const temporary = `${descriptorPath}.${process.pid}.${
|
|
48163
|
+
const temporary = `${descriptorPath}.${process.pid}.${randomUUID24()}.tmp`;
|
|
47619
48164
|
const handle = await open11(temporary, "wx", 384);
|
|
47620
48165
|
try {
|
|
47621
48166
|
await handle.writeFile(`${JSON.stringify(descriptor)}
|
|
@@ -47640,6 +48185,7 @@ function sessionMetadata(record4) {
|
|
|
47640
48185
|
sessionId: record4.id,
|
|
47641
48186
|
sessionGeneration: record4.generation,
|
|
47642
48187
|
capabilities: record4.session.capabilities,
|
|
48188
|
+
readCapabilities: true,
|
|
47643
48189
|
initialState: {
|
|
47644
48190
|
...initialState,
|
|
47645
48191
|
...record4.nativeRef ? { nativeRef: record4.nativeRef } : {},
|
|
@@ -47692,7 +48238,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
47692
48238
|
await assertNoLiveDescriptor(input.descriptorPath);
|
|
47693
48239
|
if (process.platform !== "win32")
|
|
47694
48240
|
await prepareUnixSocketPath(input.socketPath);
|
|
47695
|
-
const generation = input.generation ??
|
|
48241
|
+
const generation = input.generation ?? randomUUID24();
|
|
47696
48242
|
const token = input.token ?? randomBytes5(32).toString("hex");
|
|
47697
48243
|
const descriptor = {
|
|
47698
48244
|
schemaVersion: 1,
|
|
@@ -47733,7 +48279,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
47733
48279
|
};
|
|
47734
48280
|
const server = net4.createServer((socket) => {
|
|
47735
48281
|
const state = {
|
|
47736
|
-
id:
|
|
48282
|
+
id: randomUUID24(),
|
|
47737
48283
|
socket,
|
|
47738
48284
|
authenticated: false,
|
|
47739
48285
|
inputSequence: 0,
|
|
@@ -47971,7 +48517,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
47971
48517
|
}
|
|
47972
48518
|
};
|
|
47973
48519
|
}
|
|
47974
|
-
const openReservation =
|
|
48520
|
+
const openReservation = randomUUID24();
|
|
47975
48521
|
if (sourceKey)
|
|
47976
48522
|
nativeWriters.set(sourceKey, openReservation);
|
|
47977
48523
|
const provisionalReservation = openInput.kind === "create" ? openReservation : void 0;
|
|
@@ -48115,6 +48661,8 @@ async function startHarnessBrokerServer(input) {
|
|
|
48115
48661
|
let result;
|
|
48116
48662
|
if (command.type === "turn.start")
|
|
48117
48663
|
result = await record5.session.execute(command);
|
|
48664
|
+
else if (command.type === "turn.steer")
|
|
48665
|
+
result = await record5.session.execute(command);
|
|
48118
48666
|
else if (command.type === "turn.cancel")
|
|
48119
48667
|
result = await record5.session.execute(command);
|
|
48120
48668
|
else if (command.type === "interaction.respond") {
|
|
@@ -48146,6 +48694,10 @@ async function startHarnessBrokerServer(input) {
|
|
|
48146
48694
|
}
|
|
48147
48695
|
return result;
|
|
48148
48696
|
}
|
|
48697
|
+
if (request.method === "session.readCapabilities") {
|
|
48698
|
+
const session = requireSession(request.params).session;
|
|
48699
|
+
return session.readCapabilities ? session.readCapabilities() : session.capabilities;
|
|
48700
|
+
}
|
|
48149
48701
|
if (request.method === "session.readSnapshot") {
|
|
48150
48702
|
return requireSession(request.params).session.readSnapshot();
|
|
48151
48703
|
}
|
|
@@ -48272,7 +48824,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
48272
48824
|
}
|
|
48273
48825
|
state.authenticated = true;
|
|
48274
48826
|
state.inputSequence = 1;
|
|
48275
|
-
await send({ kind: "response", id:
|
|
48827
|
+
await send({ kind: "response", id: randomUUID24(), ok: true, value: { ready: true } });
|
|
48276
48828
|
return;
|
|
48277
48829
|
}
|
|
48278
48830
|
const parsed2 = harnessBrokerRequestSchema.safeParse(raw);
|