@codexhost/cli-darwin-x64 0.13.3 → 0.15.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 +109 -11
- package/app/console-web.js +649 -132
- package/app/desktop-controller.mjs +120 -12
- package/app/host-runtime.mjs +1124 -293
- package/app/plugins/antigravity/plugin.mjs +431 -66
- package/app/plugins/claude-code/plugin.mjs +761 -139
- package/app/plugins/codebuddy/plugin.mjs +322 -68
- package/app/plugins/codex-usage/plugin.mjs +249 -102
- package/app/plugins/copilot/assets/icon.png +0 -0
- package/app/plugins/copilot/manifest.json +26 -0
- package/app/plugins/copilot/plugin.mjs +34591 -0
- package/app/plugins/cursor-cli/plugin.mjs +21011 -44970
- package/app/plugins/deepseek-harness/plugin.mjs +160 -43
- package/app/plugins/enabled.json +1 -0
- package/app/plugins/grok/plugin.mjs +565 -107
- package/app/plugins/hermes/plugin.mjs +128 -12
- package/app/plugins/kimi-code/plugin.mjs +136 -22
- package/app/plugins/kiro-cli/plugin.mjs +136 -22
- package/app/plugins/omp/plugin.mjs +2236 -2036
- package/app/plugins/opencode/plugin.mjs +187 -68
- package/app/plugins/pi/plugin.mjs +2621 -2304
- package/app/plugins/qoder/plugin.mjs +153 -36
- package/app/plugins/qoder-cn/plugin.mjs +153 -36
- package/app/plugins/workbuddy/plugin.mjs +583 -92
- package/app/plugins/zcode/plugin.mjs +183 -40
- package/app/renderer-extension.js +1758 -392
- package/bin/codexhost +0 -0
- package/libexec/codexhost-shim +0 -0
- package/libexec/codexhost-updater +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") } : {},
|
|
@@ -8457,10 +8461,10 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
8457
8461
|
const shape = def.shape;
|
|
8458
8462
|
const propValues = {};
|
|
8459
8463
|
for (const key in shape) {
|
|
8460
|
-
const
|
|
8461
|
-
if (
|
|
8464
|
+
const field2 = shape[key]._zod;
|
|
8465
|
+
if (field2.values) {
|
|
8462
8466
|
propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
|
|
8463
|
-
for (const v of
|
|
8467
|
+
for (const v of field2.values)
|
|
8464
8468
|
propValues[key].add(v);
|
|
8465
8469
|
}
|
|
8466
8470
|
}
|
|
@@ -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),
|
|
@@ -20210,6 +20223,53 @@ var THREAD_PREWARM_DISCARD_METHOD = "codexhost/thread/prewarm/discard";
|
|
|
20210
20223
|
var threadPrewarmDiscardParamsSchema = external_exports.object({ threadId: hostThreadIdSchema });
|
|
20211
20224
|
var threadPrewarmDiscardResultSchema = external_exports.object({ discarded: external_exports.boolean() });
|
|
20212
20225
|
|
|
20226
|
+
// packages/shared-contracts/dist/thread-questions.js
|
|
20227
|
+
var THREAD_QUESTIONS_LIST_METHOD = "codexhost/thread/questions/list";
|
|
20228
|
+
var THREAD_QUESTION_RESPOND_METHOD = "codexhost/thread/question/respond";
|
|
20229
|
+
var field = external_exports.discriminatedUnion("type", [
|
|
20230
|
+
external_exports.object({
|
|
20231
|
+
id: external_exports.string().min(1),
|
|
20232
|
+
type: external_exports.literal("choice"),
|
|
20233
|
+
prompt: external_exports.string(),
|
|
20234
|
+
options: external_exports.array(external_exports.object({
|
|
20235
|
+
value: external_exports.string().min(1),
|
|
20236
|
+
label: external_exports.string(),
|
|
20237
|
+
description: external_exports.string().optional()
|
|
20238
|
+
})).min(1),
|
|
20239
|
+
multiple: external_exports.boolean(),
|
|
20240
|
+
allowOther: external_exports.boolean(),
|
|
20241
|
+
optional: external_exports.boolean()
|
|
20242
|
+
}),
|
|
20243
|
+
external_exports.object({
|
|
20244
|
+
id: external_exports.string().min(1),
|
|
20245
|
+
type: external_exports.literal("text"),
|
|
20246
|
+
prompt: external_exports.string(),
|
|
20247
|
+
multiline: external_exports.boolean(),
|
|
20248
|
+
secret: external_exports.literal(false),
|
|
20249
|
+
optional: external_exports.boolean(),
|
|
20250
|
+
placeholder: external_exports.string().optional(),
|
|
20251
|
+
prefill: external_exports.string().optional()
|
|
20252
|
+
})
|
|
20253
|
+
]);
|
|
20254
|
+
var threadQuestionSchema = external_exports.object({
|
|
20255
|
+
interactionId: external_exports.string().min(1),
|
|
20256
|
+
turnId: external_exports.string().min(1),
|
|
20257
|
+
title: external_exports.string().optional(),
|
|
20258
|
+
questions: external_exports.array(field).min(1)
|
|
20259
|
+
}).refine(({ questions }) => questions.some((q) => q.type === "choice" && q.multiple), {
|
|
20260
|
+
message: "Shared cards require at least one multi-select question"
|
|
20261
|
+
});
|
|
20262
|
+
var threadQuestionsListParamsSchema = external_exports.strictObject({ threadId: external_exports.string().min(1) });
|
|
20263
|
+
var threadQuestionsResultSchema = external_exports.object({ questions: external_exports.array(threadQuestionSchema) });
|
|
20264
|
+
var threadQuestionRespondParamsSchema = external_exports.strictObject({
|
|
20265
|
+
threadId: external_exports.string().min(1),
|
|
20266
|
+
turnId: external_exports.string().min(1),
|
|
20267
|
+
interactionId: external_exports.string().min(1),
|
|
20268
|
+
answers: external_exports.record(external_exports.string(), external_exports.array(external_exports.string())),
|
|
20269
|
+
cancelled: external_exports.boolean().default(false)
|
|
20270
|
+
});
|
|
20271
|
+
var threadQuestionRespondResultSchema = external_exports.object({ accepted: external_exports.literal(true) });
|
|
20272
|
+
|
|
20213
20273
|
// packages/shared-contracts/dist/console.js
|
|
20214
20274
|
var consoleAnnouncementSchema = external_exports.strictObject({
|
|
20215
20275
|
title: external_exports.string().trim().min(1).max(200),
|
|
@@ -20231,6 +20291,8 @@ var CONSOLE_HOST_METHODS = Object.freeze([
|
|
|
20231
20291
|
"codexhost/harness/display-settings/set",
|
|
20232
20292
|
"codexhost/harness/inspect",
|
|
20233
20293
|
"codexhost/harness/installation",
|
|
20294
|
+
"codexhost/harness/installation/start",
|
|
20295
|
+
"codexhost/harness/installation/status",
|
|
20234
20296
|
"codexhost/harness/launch-settings/get",
|
|
20235
20297
|
"codexhost/harness/launch-settings/set",
|
|
20236
20298
|
"codexhost/harness/web-ui/open",
|
|
@@ -20312,7 +20374,18 @@ var threadManualCompactionStartedSchema = external_exports.strictObject({
|
|
|
20312
20374
|
var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
|
|
20313
20375
|
var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
|
|
20314
20376
|
var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
|
|
20377
|
+
var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text) => text.length <= maximum));
|
|
20378
|
+
var composerIndicatorsSchema = external_exports.array(external_exports.object({
|
|
20379
|
+
kind: external_exports.literal("countdown"),
|
|
20380
|
+
id: external_exports.string().min(1).max(64),
|
|
20381
|
+
expiresAtUnix: nonNegativeSafeIntegerSchema,
|
|
20382
|
+
label: indicatorTextSchema(256).optional(),
|
|
20383
|
+
tooltip: indicatorTextSchema(1024).optional()
|
|
20384
|
+
}).strict()).max(2).refine((entries) => new Set(entries.map(({ id: id2 }) => id2)).size === entries.length, {
|
|
20385
|
+
message: "Composer indicator IDs must be unique"
|
|
20386
|
+
});
|
|
20315
20387
|
var threadUsageSnapshotSchema = external_exports.object({
|
|
20388
|
+
composerIndicators: composerIndicatorsSchema.optional(),
|
|
20316
20389
|
inputTokens: nonNegativeSafeIntegerSchema.optional(),
|
|
20317
20390
|
cachedInputTokens: nonNegativeSafeIntegerSchema.optional(),
|
|
20318
20391
|
cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
|
|
@@ -20728,7 +20801,9 @@ var harnessSessionCapabilitiesSchema = external_exports.object({
|
|
|
20728
20801
|
}).strict().optional(),
|
|
20729
20802
|
autonomousTurns: external_exports.object({
|
|
20730
20803
|
observe: external_exports.boolean()
|
|
20731
|
-
}).strict().optional()
|
|
20804
|
+
}).strict().optional(),
|
|
20805
|
+
/** True only when `turn.steer` delivers input into the active Turn through a native primitive. */
|
|
20806
|
+
steer: external_exports.boolean().optional()
|
|
20732
20807
|
}).strict();
|
|
20733
20808
|
var harnessConfigurationStateSchema = external_exports.object({
|
|
20734
20809
|
effectiveModel: harnessModelRefSchema.optional(),
|
|
@@ -20776,7 +20851,9 @@ var harnessInspectionSchema = external_exports.union([
|
|
|
20776
20851
|
var harnessInspectParamsSchema = external_exports.object({
|
|
20777
20852
|
harnessId: harnessIdSchema,
|
|
20778
20853
|
cwd: nonBlankTextSchema2.max(16384).optional(),
|
|
20779
|
-
refresh: external_exports.boolean().optional()
|
|
20854
|
+
refresh: external_exports.boolean().optional(),
|
|
20855
|
+
/** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
|
|
20856
|
+
purpose: external_exports.literal("availability").optional()
|
|
20780
20857
|
}).strict();
|
|
20781
20858
|
var harnessWebUiOpenParamsSchema = external_exports.object({
|
|
20782
20859
|
harnessId: harnessIdSchema
|
|
@@ -20859,6 +20936,16 @@ var threadOwnershipListResultSchema = external_exports.object({
|
|
|
20859
20936
|
seen.add(thread.threadId);
|
|
20860
20937
|
}
|
|
20861
20938
|
});
|
|
20939
|
+
var threadSteeringInspectParamsSchema = external_exports.object({
|
|
20940
|
+
threadId: hostThreadIdSchema,
|
|
20941
|
+
/** The text about to be steered; a Harness command always stops and restarts. */
|
|
20942
|
+
text: external_exports.string().optional()
|
|
20943
|
+
}).strict();
|
|
20944
|
+
var THREAD_STEER_DELIVERY_PARAM = "codexhostSteerDelivery";
|
|
20945
|
+
var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
|
|
20946
|
+
var threadSteeringInspectResultSchema = external_exports.object({
|
|
20947
|
+
delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
|
|
20948
|
+
}).strict();
|
|
20862
20949
|
|
|
20863
20950
|
// packages/shared-contracts/dist/harness-plugins.js
|
|
20864
20951
|
var HARNESS_PLUGIN_API_VERSION = 1;
|
|
@@ -20979,6 +21066,8 @@ var harnessLaunchSettingsSchema = external_exports.object({
|
|
|
20979
21066
|
|
|
20980
21067
|
// packages/shared-contracts/dist/harness-installation.js
|
|
20981
21068
|
var HARNESS_INSTALLATION_METHOD = "codexhost/harness/installation";
|
|
21069
|
+
var HARNESS_INSTALLATION_START_METHOD = "codexhost/harness/installation/start";
|
|
21070
|
+
var HARNESS_INSTALLATION_STATUS_METHOD = "codexhost/harness/installation/status";
|
|
20982
21071
|
var harnessInstallationParamsSchema = external_exports.object({
|
|
20983
21072
|
harnessId: harnessIdSchema,
|
|
20984
21073
|
action: external_exports.enum(["check", "update", "install"])
|
|
@@ -20988,6 +21077,10 @@ var harnessInstallationStateSchema = external_exports.object({
|
|
|
20988
21077
|
latestVersion: external_exports.string().min(1).max(128),
|
|
20989
21078
|
updateAvailable: external_exports.boolean(),
|
|
20990
21079
|
canUpdate: external_exports.boolean(),
|
|
21080
|
+
/** Defaults to CLI; some Harnesses ship only inside a desktop application. */
|
|
21081
|
+
versionKind: external_exports.enum(["cli", "application"]).optional(),
|
|
21082
|
+
/** Official download opened by the user; does not imply an automatic installation. */
|
|
21083
|
+
manualUpdateUrl: external_exports.url().max(2048).refine((value2) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value2), "Manual updates require a credential-free HTTPS URL").optional(),
|
|
20991
21084
|
// Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
|
|
20992
21085
|
message: external_exports.string().max(2048).optional(),
|
|
20993
21086
|
messageCode: external_exports.string().min(1).max(128).optional(),
|
|
@@ -20995,6 +21088,20 @@ var harnessInstallationStateSchema = external_exports.object({
|
|
|
20995
21088
|
notice: harnessLocalizedTextSchema.optional(),
|
|
20996
21089
|
latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
|
|
20997
21090
|
}).strict();
|
|
21091
|
+
var harnessInstallationTaskParamsSchema = external_exports.object({ taskId: external_exports.string().uuid() }).strict();
|
|
21092
|
+
var harnessInstallationTaskSchema = external_exports.discriminatedUnion("status", [
|
|
21093
|
+
external_exports.object({ taskId: external_exports.string().uuid(), status: external_exports.literal("running") }).strict(),
|
|
21094
|
+
external_exports.object({
|
|
21095
|
+
taskId: external_exports.string().uuid(),
|
|
21096
|
+
status: external_exports.literal("succeeded"),
|
|
21097
|
+
result: harnessInstallationStateSchema
|
|
21098
|
+
}).strict(),
|
|
21099
|
+
external_exports.object({
|
|
21100
|
+
taskId: external_exports.string().uuid(),
|
|
21101
|
+
status: external_exports.literal("failed"),
|
|
21102
|
+
error: external_exports.object({ code: external_exports.number().int(), message: external_exports.string().min(1).max(2048) }).strict()
|
|
21103
|
+
}).strict()
|
|
21104
|
+
]);
|
|
20998
21105
|
|
|
20999
21106
|
// packages/shared-contracts/dist/codex-accounts.js
|
|
21000
21107
|
var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
|
|
@@ -22982,9 +23089,13 @@ function requestManagerFromHookState(value2, hostId2) {
|
|
|
22982
23089
|
const direct = manager(value2) ?? manager(value2.manager);
|
|
22983
23090
|
if (direct)
|
|
22984
23091
|
return direct;
|
|
22985
|
-
if (!hostId2 || typeof value2.addManager !== "function" || typeof value2.getForHostId !== "function"
|
|
23092
|
+
if (!hostId2 || typeof value2.addManager !== "function" || typeof value2.getForHostId !== "function")
|
|
22986
23093
|
return null;
|
|
22987
|
-
|
|
23094
|
+
try {
|
|
23095
|
+
return manager(value2.getForHostId(hostId2));
|
|
23096
|
+
} catch {
|
|
23097
|
+
return null;
|
|
23098
|
+
}
|
|
22988
23099
|
}
|
|
22989
23100
|
function discoverRendererHosts(root, ancestors = committedReactAncestors, managerFrom = requestManagerFromHookState) {
|
|
22990
23101
|
const editors = [
|
|
@@ -23020,7 +23131,7 @@ function discoverRendererHosts(root, ancestors = committedReactAncestors, manage
|
|
|
23020
23131
|
const manager = managerFrom(value2);
|
|
23021
23132
|
if (manager)
|
|
23022
23133
|
managers.add(manager);
|
|
23023
|
-
if (value2 && typeof value2 === "object" && "addManager" in value2 && typeof value2.addManager === "function" && "getForHostId" in value2 && typeof value2.getForHostId === "function"
|
|
23134
|
+
if (value2 && typeof value2 === "object" && "addManager" in value2 && typeof value2.addManager === "function" && "getForHostId" in value2 && typeof value2.getForHostId === "function") {
|
|
23024
23135
|
registries.add(value2);
|
|
23025
23136
|
}
|
|
23026
23137
|
hook = hook.next && typeof hook.next === "object" ? hook.next : null;
|
|
@@ -23036,7 +23147,13 @@ function discoverRendererHosts(root, ancestors = committedReactAncestors, manage
|
|
|
23036
23147
|
function resolveRendererHostManager(discovery, hostId2, managerFrom = requestManagerFromHookState) {
|
|
23037
23148
|
if (!hostId2)
|
|
23038
23149
|
return null;
|
|
23039
|
-
const candidates = discovery.registries.length ? discovery.registries.
|
|
23150
|
+
const candidates = discovery.registries.length ? discovery.registries.flatMap((registry2) => {
|
|
23151
|
+
try {
|
|
23152
|
+
return [managerFrom(registry2.getForHostId(hostId2))];
|
|
23153
|
+
} catch {
|
|
23154
|
+
return [];
|
|
23155
|
+
}
|
|
23156
|
+
}) : discovery.managers;
|
|
23040
23157
|
const matching = new Set(candidates.filter((manager) => manager && (manager.getHostId?.() ?? manager.requestClient.hostId) === hostId2 && (manager.requestClient.hostId === void 0 || manager.requestClient.hostId === hostId2)));
|
|
23041
23158
|
return matching.size === 1 ? matching.values().next().value ?? null : null;
|
|
23042
23159
|
}
|
|
@@ -24048,6 +24165,64 @@ async function handleHarnessInstallation(params, adapters) {
|
|
|
24048
24165
|
}
|
|
24049
24166
|
}
|
|
24050
24167
|
|
|
24168
|
+
// packages/host-runtime/src/harness-installation-tasks.ts
|
|
24169
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
24170
|
+
var HarnessInstallationTasks = class {
|
|
24171
|
+
#tasks = /* @__PURE__ */ new Map();
|
|
24172
|
+
#active = /* @__PURE__ */ new Map();
|
|
24173
|
+
#prune() {
|
|
24174
|
+
const cutoff = Date.now() - 15 * 6e4;
|
|
24175
|
+
for (const [id2, task] of this.#tasks) {
|
|
24176
|
+
if (task.finishedAt !== void 0 && task.finishedAt < cutoff) this.#tasks.delete(id2);
|
|
24177
|
+
}
|
|
24178
|
+
}
|
|
24179
|
+
start(params, adapters) {
|
|
24180
|
+
const parsed2 = harnessInstallationParamsSchema.safeParse(params);
|
|
24181
|
+
if (!parsed2.success)
|
|
24182
|
+
throw new HarnessInstallationError(-32602, "Invalid Harness installation request");
|
|
24183
|
+
this.#prune();
|
|
24184
|
+
const key = JSON.stringify([parsed2.data.harnessId, parsed2.data.action]);
|
|
24185
|
+
const activeId = this.#active.get(key);
|
|
24186
|
+
const active = activeId ? this.#tasks.get(activeId) : void 0;
|
|
24187
|
+
if (active) return active.state;
|
|
24188
|
+
const taskId = randomUUID3();
|
|
24189
|
+
const task = {
|
|
24190
|
+
state: { taskId, status: "running" }
|
|
24191
|
+
};
|
|
24192
|
+
this.#tasks.set(taskId, task);
|
|
24193
|
+
this.#active.set(key, taskId);
|
|
24194
|
+
void handleHarnessInstallation(parsed2.data, adapters).then(
|
|
24195
|
+
(result) => {
|
|
24196
|
+
task.state = { taskId, status: "succeeded", result };
|
|
24197
|
+
},
|
|
24198
|
+
(error51) => {
|
|
24199
|
+
task.state = {
|
|
24200
|
+
taskId,
|
|
24201
|
+
status: "failed",
|
|
24202
|
+
error: error51 instanceof HarnessInstallationError ? { code: error51.code, message: error51.message } : { code: -32077, message: "Harness version management failed" }
|
|
24203
|
+
};
|
|
24204
|
+
}
|
|
24205
|
+
).finally(() => {
|
|
24206
|
+
task.finishedAt = Date.now();
|
|
24207
|
+
this.#active.delete(key);
|
|
24208
|
+
});
|
|
24209
|
+
return task.state;
|
|
24210
|
+
}
|
|
24211
|
+
status(params) {
|
|
24212
|
+
const parsed2 = harnessInstallationTaskParamsSchema.safeParse(params);
|
|
24213
|
+
if (!parsed2.success)
|
|
24214
|
+
throw new HarnessInstallationError(-32602, "Invalid Harness installation task request");
|
|
24215
|
+
this.#prune();
|
|
24216
|
+
const task = this.#tasks.get(parsed2.data.taskId);
|
|
24217
|
+
if (!task)
|
|
24218
|
+
throw new HarnessInstallationError(
|
|
24219
|
+
-32079,
|
|
24220
|
+
"Harness installation task is unavailable on this Host"
|
|
24221
|
+
);
|
|
24222
|
+
return task.state;
|
|
24223
|
+
}
|
|
24224
|
+
};
|
|
24225
|
+
|
|
24051
24226
|
// packages/host-runtime/src/account/codex-credential-export.ts
|
|
24052
24227
|
import { createHash as createHash3 } from "node:crypto";
|
|
24053
24228
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
@@ -24140,7 +24315,7 @@ async function listOthers(adapter) {
|
|
|
24140
24315
|
}
|
|
24141
24316
|
|
|
24142
24317
|
// packages/host-runtime/src/harness-display-settings.ts
|
|
24143
|
-
import { randomUUID as
|
|
24318
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
24144
24319
|
import { link, mkdir as mkdir6, readFile as readFile9, rename as rename4, rm as rm5, writeFile as writeFile6 } from "node:fs/promises";
|
|
24145
24320
|
import os4 from "node:os";
|
|
24146
24321
|
import path13 from "node:path";
|
|
@@ -24165,7 +24340,7 @@ var HarnessDisplaySettingsStore = class {
|
|
|
24165
24340
|
async set(input) {
|
|
24166
24341
|
const entries = harnessDisplayEntriesSchema.parse(input.entries);
|
|
24167
24342
|
await mkdir6(path13.dirname(this.#file), { recursive: true, mode: 448 });
|
|
24168
|
-
const temporary = `${this.#file}.${
|
|
24343
|
+
const temporary = `${this.#file}.${randomUUID4()}.tmp`;
|
|
24169
24344
|
try {
|
|
24170
24345
|
await writeFile6(temporary, `${JSON.stringify(entries)}
|
|
24171
24346
|
`, { mode: 384, flag: "wx" });
|
|
@@ -24186,7 +24361,7 @@ var HarnessDisplaySettingsStore = class {
|
|
|
24186
24361
|
};
|
|
24187
24362
|
|
|
24188
24363
|
// packages/host-runtime/src/model-price-overrides-file.ts
|
|
24189
|
-
import { randomUUID as
|
|
24364
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
24190
24365
|
import { mkdir as mkdir8, readFile as readFile11, rename as rename6, rm as rm6, writeFile as writeFile8 } from "node:fs/promises";
|
|
24191
24366
|
import path15 from "node:path";
|
|
24192
24367
|
|
|
@@ -24346,9 +24521,9 @@ function parseModelPriceOverrides(value2) {
|
|
|
24346
24521
|
if (key.length === 0 || !isRecord3(entry)) {
|
|
24347
24522
|
throw new Error(`Price override '${key}' is invalid`);
|
|
24348
24523
|
}
|
|
24349
|
-
for (const
|
|
24350
|
-
if (!["input", "output", "cacheRead", "cacheWrite", "cacheWrite1h"].includes(
|
|
24351
|
-
throw new Error(`Price override '${key}' contains unknown field '${
|
|
24524
|
+
for (const field2 of Object.keys(entry)) {
|
|
24525
|
+
if (!["input", "output", "cacheRead", "cacheWrite", "cacheWrite1h"].includes(field2)) {
|
|
24526
|
+
throw new Error(`Price override '${key}' contains unknown field '${field2}'`);
|
|
24352
24527
|
}
|
|
24353
24528
|
}
|
|
24354
24529
|
const input = price(entry.input);
|
|
@@ -24357,11 +24532,11 @@ function parseModelPriceOverrides(value2) {
|
|
|
24357
24532
|
throw new Error(`Price override '${key}' needs non-negative 'input' and 'output'`);
|
|
24358
24533
|
}
|
|
24359
24534
|
const resolved = { input, output };
|
|
24360
|
-
for (const
|
|
24361
|
-
if (entry[
|
|
24362
|
-
const candidate = price(entry[
|
|
24363
|
-
if (candidate === null) throw new Error(`Price override '${key}' has invalid '${
|
|
24364
|
-
resolved[
|
|
24535
|
+
for (const field2 of ["cacheRead", "cacheWrite", "cacheWrite1h"]) {
|
|
24536
|
+
if (entry[field2] === void 0) continue;
|
|
24537
|
+
const candidate = price(entry[field2]);
|
|
24538
|
+
if (candidate === null) throw new Error(`Price override '${key}' has invalid '${field2}'`);
|
|
24539
|
+
resolved[field2] = candidate;
|
|
24365
24540
|
}
|
|
24366
24541
|
overrides.set(key, resolved);
|
|
24367
24542
|
}
|
|
@@ -24761,7 +24936,7 @@ async function updateModelPriceOverridesFile(file2, change) {
|
|
|
24761
24936
|
const updated = { ...document, models: next };
|
|
24762
24937
|
parseModelPriceOverrides(updated);
|
|
24763
24938
|
await mkdir8(path15.dirname(file2), { recursive: true });
|
|
24764
|
-
const temporary = `${file2}.${
|
|
24939
|
+
const temporary = `${file2}.${randomUUID5()}.tmp`;
|
|
24765
24940
|
try {
|
|
24766
24941
|
await writeFile8(temporary, `${JSON.stringify(updated, null, 2)}
|
|
24767
24942
|
`, { flag: "wx" });
|
|
@@ -24797,11 +24972,11 @@ async function handleModelPriceOverridesRequest(catalog, method, params) {
|
|
|
24797
24972
|
}
|
|
24798
24973
|
|
|
24799
24974
|
// packages/host-runtime/src/delegation-skill.ts
|
|
24800
|
-
import { createHash as createHash4, randomUUID as
|
|
24975
|
+
import { createHash as createHash4, randomUUID as randomUUID6 } from "node:crypto";
|
|
24801
24976
|
import { mkdir as mkdir9, open as open4, readFile as readFile12, rename as rename7, rm as rm7, stat as stat5 } from "node:fs/promises";
|
|
24802
24977
|
import os6 from "node:os";
|
|
24803
24978
|
import path16 from "node:path";
|
|
24804
|
-
var SKILL_VERSION =
|
|
24979
|
+
var SKILL_VERSION = 10;
|
|
24805
24980
|
var DELEGATION_SKILL_NAME = "codexhost-delegation";
|
|
24806
24981
|
var SKILL_RELATIVE_PATH = path16.join("skills", DELEGATION_SKILL_NAME, "SKILL.md");
|
|
24807
24982
|
var PREVIOUS_MANAGED_DIGESTS = [
|
|
@@ -24815,7 +24990,9 @@ var PREVIOUS_MANAGED_DIGESTS = [
|
|
|
24815
24990
|
"fa7944cd1e72ffbaf932fca2074bdb78aad4670d8990b6711220dd83c39509a0",
|
|
24816
24991
|
"b9c1cce41d2556e73a6514aa55618d7d3f2f9ef935f5ae50b0da5a04941514b4",
|
|
24817
24992
|
// v8, which ran a bare `codexhost` from PATH.
|
|
24818
|
-
"ca06be59f0d47c9a54d05ed2d9588c9c737306cc155cb4dff3fe2a2a61891dde"
|
|
24993
|
+
"ca06be59f0d47c9a54d05ed2d9588c9c737306cc155cb4dff3fe2a2a61891dde",
|
|
24994
|
+
// v9, before the child-session name guidance.
|
|
24995
|
+
"b72a059e139bd5b93b95f7ac02ab80f428d5a721cc67b004210d5263e75baed7"
|
|
24819
24996
|
];
|
|
24820
24997
|
var CODEXHOST_DELEGATION_SKILL = `---
|
|
24821
24998
|
name: codexhost-delegation
|
|
@@ -24852,7 +25029,8 @@ Use the Harness native defaults. Inspect the target when a Model or Thinking
|
|
|
24852
25029
|
selection is needed or the default is unavailable.
|
|
24853
25030
|
|
|
24854
25031
|
For a new delegation, create an independent child session and submit the
|
|
24855
|
-
requested task.
|
|
25032
|
+
requested task. Give it a short task name that tells it apart from sibling
|
|
25033
|
+
tasks, using the help's task-name option. For an existing external session, resolve the target from the
|
|
24856
25034
|
user-provided session link, identifier, or context and operate on that Thread
|
|
24857
25035
|
directly; it need not have been created by the current assistant. If the target
|
|
24858
25036
|
is ambiguous, ask the user to identify it. Keep requests to view or summarize a
|
|
@@ -24894,7 +25072,7 @@ async function readOptional(filePath) {
|
|
|
24894
25072
|
}
|
|
24895
25073
|
async function atomicWrite(filePath, content) {
|
|
24896
25074
|
await mkdir9(path16.dirname(filePath), { recursive: true, mode: 448 });
|
|
24897
|
-
const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${
|
|
25075
|
+
const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${randomUUID6()}.tmp`);
|
|
24898
25076
|
const handle = await open4(temporaryPath, "wx", 384);
|
|
24899
25077
|
try {
|
|
24900
25078
|
await handle.writeFile(content, "utf8");
|
|
@@ -25049,6 +25227,42 @@ function parseHarnessAccountCredits(value2) {
|
|
|
25049
25227
|
return parsed2.success ? parsed2.data : null;
|
|
25050
25228
|
}
|
|
25051
25229
|
|
|
25230
|
+
// packages/harness-adapter/dist/question.js
|
|
25231
|
+
function invalidRequest(message2) {
|
|
25232
|
+
return { code: "invalidRequest", message: message2, retryable: false };
|
|
25233
|
+
}
|
|
25234
|
+
function validateHostQuestionResponse(interaction, response) {
|
|
25235
|
+
const questionIds = new Set(interaction.questions.map(({ id: id2 }) => id2));
|
|
25236
|
+
if (response.cancelled) {
|
|
25237
|
+
return Object.keys(response.answers).length === 0 ? null : invalidRequest("Cancelled Question Response must not contain answers");
|
|
25238
|
+
}
|
|
25239
|
+
for (const answerId of Object.keys(response.answers)) {
|
|
25240
|
+
if (!questionIds.has(answerId)) {
|
|
25241
|
+
return invalidRequest("Question Response contains an unknown Question ID");
|
|
25242
|
+
}
|
|
25243
|
+
}
|
|
25244
|
+
for (const question of interaction.questions) {
|
|
25245
|
+
const answers = response.answers[question.id] ?? [];
|
|
25246
|
+
if (!question.optional && answers.length === 0) {
|
|
25247
|
+
return invalidRequest("Question Response omits a required answer");
|
|
25248
|
+
}
|
|
25249
|
+
if (question.type === "text") {
|
|
25250
|
+
if (answers.length > 1) {
|
|
25251
|
+
return invalidRequest("Text Question accepts at most one answer");
|
|
25252
|
+
}
|
|
25253
|
+
continue;
|
|
25254
|
+
}
|
|
25255
|
+
if (!question.multiple && answers.length > 1) {
|
|
25256
|
+
return invalidRequest("Single-choice Question accepts at most one answer");
|
|
25257
|
+
}
|
|
25258
|
+
const declared = new Set(question.options.map(({ value: value2 }) => value2));
|
|
25259
|
+
if (!question.allowOther && answers.some((answer) => !declared.has(answer))) {
|
|
25260
|
+
return invalidRequest("Question Response contains an undeclared choice");
|
|
25261
|
+
}
|
|
25262
|
+
}
|
|
25263
|
+
return null;
|
|
25264
|
+
}
|
|
25265
|
+
|
|
25052
25266
|
// packages/harness-adapter/dist/output-channel.js
|
|
25053
25267
|
var HarnessOutputChannel = class {
|
|
25054
25268
|
outputs;
|
|
@@ -25131,6 +25345,7 @@ var usageFields = /* @__PURE__ */ new Set([
|
|
|
25131
25345
|
...safeIntegerFields,
|
|
25132
25346
|
...percentFields,
|
|
25133
25347
|
"sessionCacheUsage",
|
|
25348
|
+
"composerIndicators",
|
|
25134
25349
|
"totalCostUsd",
|
|
25135
25350
|
"totalCredits",
|
|
25136
25351
|
"contextUsagePercent",
|
|
@@ -25153,26 +25368,27 @@ function parseHostUsage(value2) {
|
|
|
25153
25368
|
throw new Error(`Harness Usage contains unknown field '${key}'`);
|
|
25154
25369
|
}
|
|
25155
25370
|
}
|
|
25156
|
-
|
|
25371
|
+
const indicators = value2.composerIndicators === void 0 ? {} : { composerIndicators: composerIndicatorsSchema.parse(value2.composerIndicators) };
|
|
25372
|
+
for (const field2 of [
|
|
25157
25373
|
"totalCredits",
|
|
25158
25374
|
"contextUsagePercent",
|
|
25159
25375
|
"apiOutputTokensPerSecond"
|
|
25160
25376
|
]) {
|
|
25161
|
-
const candidate = value2[
|
|
25377
|
+
const candidate = value2[field2];
|
|
25162
25378
|
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
|
|
25163
|
-
throw new Error(`Harness Usage '${
|
|
25379
|
+
throw new Error(`Harness Usage '${field2}' must be a finite non-negative number`);
|
|
25164
25380
|
}
|
|
25165
25381
|
}
|
|
25166
|
-
for (const
|
|
25167
|
-
const candidate = value2[
|
|
25382
|
+
for (const field2 of tokenFields) {
|
|
25383
|
+
const candidate = value2[field2];
|
|
25168
25384
|
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
|
|
25169
|
-
throw new Error(`Harness Usage '${
|
|
25385
|
+
throw new Error(`Harness Usage '${field2}' must be a non-negative safe integer`);
|
|
25170
25386
|
}
|
|
25171
25387
|
}
|
|
25172
|
-
for (const
|
|
25173
|
-
const candidate = value2[
|
|
25388
|
+
for (const field2 of safeIntegerFields) {
|
|
25389
|
+
const candidate = value2[field2];
|
|
25174
25390
|
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
|
|
25175
|
-
throw new Error(`Harness Usage '${
|
|
25391
|
+
throw new Error(`Harness Usage '${field2}' must be a non-negative safe integer`);
|
|
25176
25392
|
}
|
|
25177
25393
|
}
|
|
25178
25394
|
if (value2.outputTokensPerSecond !== void 0 && (typeof value2.outputTokensPerSecond !== "number" || !Number.isFinite(value2.outputTokensPerSecond) || value2.outputTokensPerSecond < 0)) {
|
|
@@ -25181,10 +25397,10 @@ function parseHostUsage(value2) {
|
|
|
25181
25397
|
if (value2.totalCostUsd !== void 0 && (typeof value2.totalCostUsd !== "number" || !Number.isFinite(value2.totalCostUsd) || value2.totalCostUsd < 0)) {
|
|
25182
25398
|
throw new Error("Harness Usage 'totalCostUsd' must be a finite non-negative number");
|
|
25183
25399
|
}
|
|
25184
|
-
for (const
|
|
25185
|
-
const candidate = value2[
|
|
25400
|
+
for (const field2 of percentFields) {
|
|
25401
|
+
const candidate = value2[field2];
|
|
25186
25402
|
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0 || candidate > 100)) {
|
|
25187
|
-
throw new Error(`Harness Usage '${
|
|
25403
|
+
throw new Error(`Harness Usage '${field2}' must be between 0 and 100`);
|
|
25188
25404
|
}
|
|
25189
25405
|
}
|
|
25190
25406
|
if (value2.sessionCacheUsage !== void 0) {
|
|
@@ -25223,9 +25439,9 @@ function parseHostUsage(value2) {
|
|
|
25223
25439
|
if (value2.costSource !== "publicPrice") {
|
|
25224
25440
|
throw new Error("Harness Usage 'unpricedModels' must be provided with a 'publicPrice' cost");
|
|
25225
25441
|
}
|
|
25226
|
-
return { ...value2, unpricedModels: [...models] };
|
|
25442
|
+
return { ...value2, ...indicators, unpricedModels: [...models] };
|
|
25227
25443
|
}
|
|
25228
|
-
return { ...value2 };
|
|
25444
|
+
return { ...value2, ...indicators };
|
|
25229
25445
|
}
|
|
25230
25446
|
var requestTokenFields = [
|
|
25231
25447
|
"inputTokens",
|
|
@@ -25255,19 +25471,19 @@ function parseHostUsageRequest(value2) {
|
|
|
25255
25471
|
if (typeof value2.requestId !== "string" || value2.requestId.length === 0) {
|
|
25256
25472
|
throw new Error("Harness Usage request 'requestId' must be a non-empty string");
|
|
25257
25473
|
}
|
|
25258
|
-
for (const
|
|
25259
|
-
const candidate = value2[
|
|
25474
|
+
for (const field2 of ["model", "provider"]) {
|
|
25475
|
+
const candidate = value2[field2];
|
|
25260
25476
|
if (candidate !== void 0 && (typeof candidate !== "string" || candidate.length === 0)) {
|
|
25261
|
-
throw new Error(`Harness Usage request '${
|
|
25477
|
+
throw new Error(`Harness Usage request '${field2}' must be a non-empty string`);
|
|
25262
25478
|
}
|
|
25263
25479
|
}
|
|
25264
25480
|
if (value2.historical !== void 0 && typeof value2.historical !== "boolean") {
|
|
25265
25481
|
throw new Error("Harness Usage request 'historical' must be a boolean");
|
|
25266
25482
|
}
|
|
25267
|
-
for (const
|
|
25268
|
-
const candidate = value2[
|
|
25483
|
+
for (const field2 of requestTokenFields) {
|
|
25484
|
+
const candidate = value2[field2];
|
|
25269
25485
|
if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
|
|
25270
|
-
throw new Error(`Harness Usage request '${
|
|
25486
|
+
throw new Error(`Harness Usage request '${field2}' must be a non-negative safe integer`);
|
|
25271
25487
|
}
|
|
25272
25488
|
}
|
|
25273
25489
|
if (value2.inputTokens === void 0 || value2.outputTokens === void 0) {
|
|
@@ -25376,7 +25592,7 @@ var packageMetadata = {
|
|
|
25376
25592
|
|
|
25377
25593
|
// packages/mapping-store/dist/mapping-store.js
|
|
25378
25594
|
import { execFileSync } from "node:child_process";
|
|
25379
|
-
import { randomUUID as
|
|
25595
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
25380
25596
|
import { constants as constants3 } from "node:fs";
|
|
25381
25597
|
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
25598
|
import path18 from "node:path";
|
|
@@ -25436,7 +25652,7 @@ var storedThreadMetadataV1Schema = external_exports.object({
|
|
|
25436
25652
|
formatVersion: external_exports.literal(1),
|
|
25437
25653
|
hostThreadId: storedHostThreadIdSchema,
|
|
25438
25654
|
...storedThreadMetadataFieldsShape
|
|
25439
|
-
}).
|
|
25655
|
+
}).passthrough();
|
|
25440
25656
|
function refineThreadRecord(record4, context) {
|
|
25441
25657
|
if (record4.state === "ready" && !record4.nativeSessionRef) {
|
|
25442
25658
|
context.addIssue({
|
|
@@ -25495,8 +25711,8 @@ function refineThreadRecord(record4, context) {
|
|
|
25495
25711
|
}
|
|
25496
25712
|
}
|
|
25497
25713
|
}
|
|
25498
|
-
var storedThreadCoreV1Schema = external_exports.object(storedThreadCoreV1Shape).
|
|
25499
|
-
var storedThreadRecordV1Schema = external_exports.object({ ...storedThreadCoreV1Shape, ...storedThreadMetadataFieldsShape }).
|
|
25714
|
+
var storedThreadCoreV1Schema = external_exports.object(storedThreadCoreV1Shape).passthrough().superRefine(refineThreadRecord);
|
|
25715
|
+
var storedThreadRecordV1Schema = external_exports.object({ ...storedThreadCoreV1Shape, ...storedThreadMetadataFieldsShape }).passthrough().superRefine(refineThreadRecord);
|
|
25500
25716
|
var delegationStatusSchema = external_exports.enum([
|
|
25501
25717
|
"creating",
|
|
25502
25718
|
"running",
|
|
@@ -25523,7 +25739,7 @@ var storedDelegationRecordV1Schema = external_exports.object({
|
|
|
25523
25739
|
});
|
|
25524
25740
|
|
|
25525
25741
|
// packages/mapping-store/dist/section-placements.js
|
|
25526
|
-
import { randomUUID as
|
|
25742
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
25527
25743
|
import { constants } from "node:fs";
|
|
25528
25744
|
import { open as open5, readFile as readFile13, rename as rename8, rm as rm8 } from "node:fs/promises";
|
|
25529
25745
|
var threadIdSchema = external_exports.string().min(1).max(1024);
|
|
@@ -25575,7 +25791,7 @@ async function readSectionPlacementsFile(file2) {
|
|
|
25575
25791
|
}
|
|
25576
25792
|
async function writeSectionPlacementsFile(file2, placements) {
|
|
25577
25793
|
const parsed2 = parseSectionPlacements({ formatVersion: 1, placements });
|
|
25578
|
-
const temp = `${file2}.tmp-${
|
|
25794
|
+
const temp = `${file2}.tmp-${randomUUID7()}`;
|
|
25579
25795
|
let handle = null;
|
|
25580
25796
|
try {
|
|
25581
25797
|
handle = await open5(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
|
|
@@ -25594,7 +25810,7 @@ async function writeSectionPlacementsFile(file2, placements) {
|
|
|
25594
25810
|
}
|
|
25595
25811
|
|
|
25596
25812
|
// packages/mapping-store/dist/superseded-sessions.js
|
|
25597
|
-
import { randomUUID as
|
|
25813
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
25598
25814
|
import { constants as constants2 } from "node:fs";
|
|
25599
25815
|
import { mkdir as mkdir10, open as open6, readFile as readFile14, rename as rename9, rm as rm9 } from "node:fs/promises";
|
|
25600
25816
|
import path17 from "node:path";
|
|
@@ -25629,7 +25845,7 @@ async function writeSupersededSessionsFile(file2, sessions) {
|
|
|
25629
25845
|
formatVersion: 1,
|
|
25630
25846
|
sessions: sessions.slice(-SUPERSEDED_SESSIONS_MAX)
|
|
25631
25847
|
}).sessions;
|
|
25632
|
-
const temp = `${file2}.tmp-${
|
|
25848
|
+
const temp = `${file2}.tmp-${randomUUID8()}`;
|
|
25633
25849
|
let handle = null;
|
|
25634
25850
|
try {
|
|
25635
25851
|
await mkdir10(path17.dirname(file2), { recursive: true });
|
|
@@ -25783,10 +25999,15 @@ function processIdentity(pid) {
|
|
|
25783
25999
|
}
|
|
25784
26000
|
const query = [
|
|
25785
26001
|
"$ErrorActionPreference = 'Stop'",
|
|
25786
|
-
`$process = Get-
|
|
25787
|
-
"$process
|
|
26002
|
+
`$process = Get-CimInstance -ClassName Win32_Process -Filter 'ProcessId = ${pid}'`,
|
|
26003
|
+
"if ($null -ne $process) { [pscustomobject]@{ Path = $process.ExecutablePath; StartTime = $(if ($null -ne $process.CreationDate) { $process.CreationDate.ToUniversalTime().ToString('o', [Globalization.CultureInfo]::InvariantCulture) } else { $null }) } | ConvertTo-Json -Compress }"
|
|
25788
26004
|
].join("; ");
|
|
25789
|
-
const result = execFileSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", query], {
|
|
26005
|
+
const result = execFileSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", query], {
|
|
26006
|
+
encoding: "utf8",
|
|
26007
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
26008
|
+
windowsHide: true,
|
|
26009
|
+
timeout: 5e3
|
|
26010
|
+
}).trim();
|
|
25790
26011
|
if (!result)
|
|
25791
26012
|
return { executablePath: null, startedAt: null };
|
|
25792
26013
|
const parsed2 = JSON.parse(result);
|
|
@@ -25874,7 +26095,7 @@ var MappingStore = class {
|
|
|
25874
26095
|
this.#sectionsDirectory = path18.join(this.#directory, "sections");
|
|
25875
26096
|
this.#metadataDirectory = path18.join(this.#directory, "thread-metadata");
|
|
25876
26097
|
this.#lockPath = path18.join(this.#directory, "store.lock");
|
|
25877
|
-
this.#instanceId = options2.instanceId ??
|
|
26098
|
+
this.#instanceId = options2.instanceId ?? randomUUID9();
|
|
25878
26099
|
this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
|
|
25879
26100
|
this.#beforeReplace = options2.beforeReplace;
|
|
25880
26101
|
}
|
|
@@ -26398,7 +26619,7 @@ var MappingStore = class {
|
|
|
26398
26619
|
this.#rebuildIndexes();
|
|
26399
26620
|
}
|
|
26400
26621
|
async #replaceFile(target, record4, preserveBackup) {
|
|
26401
|
-
const temp = `${target}.tmp-${
|
|
26622
|
+
const temp = `${target}.tmp-${randomUUID9()}`;
|
|
26402
26623
|
let handle = null;
|
|
26403
26624
|
try {
|
|
26404
26625
|
await this.#beforeReplace?.(cloneRecord(record4));
|
|
@@ -26422,18 +26643,20 @@ var MappingStore = class {
|
|
|
26422
26643
|
});
|
|
26423
26644
|
}
|
|
26424
26645
|
}
|
|
26425
|
-
/** Atomically
|
|
26646
|
+
/** Atomically patches owned metadata fields, retaining unknown fields on disk. */
|
|
26426
26647
|
async #writeMetadataFile(hostThreadId, metadata) {
|
|
26427
26648
|
const target = this.#metadataPath(hostThreadId);
|
|
26428
|
-
const temp = `${target}.tmp-${
|
|
26649
|
+
const temp = `${target}.tmp-${randomUUID9()}`;
|
|
26429
26650
|
let handle = null;
|
|
26430
26651
|
try {
|
|
26431
|
-
|
|
26652
|
+
const retained = Object.fromEntries(Object.entries(await this.#readMetadata(hostThreadId) ?? {}).filter(([name]) => !["formatVersion", "hostThreadId", ...THREAD_METADATA_FIELDS].includes(name)));
|
|
26653
|
+
if (!metadata && Object.keys(retained).length === 0) {
|
|
26432
26654
|
await rm10(target, { force: true });
|
|
26433
26655
|
return;
|
|
26434
26656
|
}
|
|
26657
|
+
const next = { ...retained, formatVersion: 1, hostThreadId, ...metadata };
|
|
26435
26658
|
handle = await open7(temp, "wx", constants3.S_IRUSR | constants3.S_IWUSR);
|
|
26436
|
-
await handle.writeFile(`${JSON.stringify(
|
|
26659
|
+
await handle.writeFile(`${JSON.stringify(next, null, 2)}
|
|
26437
26660
|
`, "utf8");
|
|
26438
26661
|
await handle.sync();
|
|
26439
26662
|
await handle.close();
|
|
@@ -26470,7 +26693,7 @@ var MappingStore = class {
|
|
|
26470
26693
|
}
|
|
26471
26694
|
async #replaceDelegationFile(record4) {
|
|
26472
26695
|
const target = this.#delegationPath(record4.delegationId);
|
|
26473
|
-
const temp = `${target}.tmp-${
|
|
26696
|
+
const temp = `${target}.tmp-${randomUUID9()}`;
|
|
26474
26697
|
let handle = null;
|
|
26475
26698
|
try {
|
|
26476
26699
|
handle = await open7(temp, "wx", constants3.S_IRUSR | constants3.S_IWUSR);
|
|
@@ -26655,17 +26878,17 @@ var ELLIPSIS = "…";
|
|
|
26655
26878
|
function isRecord7(value2) {
|
|
26656
26879
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
26657
26880
|
}
|
|
26658
|
-
function boundedText(value2,
|
|
26881
|
+
function boundedText(value2, field2, maxLength) {
|
|
26659
26882
|
const text = value2.trim();
|
|
26660
26883
|
if (text.length === 0 || text.length > maxLength) {
|
|
26661
|
-
throw new Error(`Host Approval ${
|
|
26884
|
+
throw new Error(`Host Approval ${field2} must contain 1 to ${maxLength} characters`);
|
|
26662
26885
|
}
|
|
26663
26886
|
return text;
|
|
26664
26887
|
}
|
|
26665
|
-
function clampedText(value2,
|
|
26888
|
+
function clampedText(value2, field2, maxLength) {
|
|
26666
26889
|
const text = value2.trim();
|
|
26667
26890
|
if (text.length === 0) {
|
|
26668
|
-
throw new Error(`Host Approval ${
|
|
26891
|
+
throw new Error(`Host Approval ${field2} must contain at least 1 character`);
|
|
26669
26892
|
}
|
|
26670
26893
|
const characters = [...text];
|
|
26671
26894
|
if (characters.length <= maxLength)
|
|
@@ -27880,9 +28103,9 @@ function nestedString(value2, keys, preserveText = false) {
|
|
|
27880
28103
|
if (!isRecord10(value2))
|
|
27881
28104
|
return void 0;
|
|
27882
28105
|
for (const key of keys) {
|
|
27883
|
-
const
|
|
27884
|
-
if (typeof
|
|
27885
|
-
return preserveText ?
|
|
28106
|
+
const field2 = value2[key];
|
|
28107
|
+
if (typeof field2 === "string" && (preserveText || field2.trim().length > 0))
|
|
28108
|
+
return preserveText ? field2 : field2.trim();
|
|
27886
28109
|
}
|
|
27887
28110
|
for (const wrapper of ["input", "arguments", "params"]) {
|
|
27888
28111
|
const nested = nestedString(value2[wrapper], keys, preserveText);
|
|
@@ -28155,8 +28378,18 @@ function collabAgentStatus(status2) {
|
|
|
28155
28378
|
return "interrupted";
|
|
28156
28379
|
}
|
|
28157
28380
|
}
|
|
28381
|
+
function projectUserMessage(item, clientId) {
|
|
28382
|
+
return {
|
|
28383
|
+
id: item.itemId,
|
|
28384
|
+
type: "userMessage",
|
|
28385
|
+
clientId,
|
|
28386
|
+
content: item.input.map(({ text }) => ({ type: "text", text, text_elements: [] }))
|
|
28387
|
+
};
|
|
28388
|
+
}
|
|
28158
28389
|
function projectItem(item, outcome, defaultCwd, includeCommandOutput = true, senderThreadId) {
|
|
28159
28390
|
switch (item.type) {
|
|
28391
|
+
case "userMessage":
|
|
28392
|
+
return projectUserMessage(item, null);
|
|
28160
28393
|
case "agentMessage":
|
|
28161
28394
|
return {
|
|
28162
28395
|
id: item.itemId,
|
|
@@ -28368,6 +28601,7 @@ var CodexTurnProjector = class {
|
|
|
28368
28601
|
#interactions = /* @__PURE__ */ new Map();
|
|
28369
28602
|
#items = /* @__PURE__ */ new Map();
|
|
28370
28603
|
#wireItemOrder = [];
|
|
28604
|
+
#userMessageClientIds = /* @__PURE__ */ new Map();
|
|
28371
28605
|
#startedAt;
|
|
28372
28606
|
#startedAtMs;
|
|
28373
28607
|
#threadId;
|
|
@@ -28409,6 +28643,10 @@ var CodexTurnProjector = class {
|
|
|
28409
28643
|
}
|
|
28410
28644
|
return items;
|
|
28411
28645
|
}
|
|
28646
|
+
/** Associate steered input with the Desktop message that submitted it, before it is published. */
|
|
28647
|
+
bindUserMessageClientId(itemId, clientId) {
|
|
28648
|
+
this.#userMessageClientIds.set(itemId, clientId);
|
|
28649
|
+
}
|
|
28412
28650
|
pendingTurn(startedAt = null) {
|
|
28413
28651
|
return {
|
|
28414
28652
|
id: this.#turnId,
|
|
@@ -28419,6 +28657,8 @@ var CodexTurnProjector = class {
|
|
|
28419
28657
|
const projected = this.#items.get(itemId);
|
|
28420
28658
|
if (!projected?.wireStarted)
|
|
28421
28659
|
return [];
|
|
28660
|
+
if (projected.item.type === "userMessage")
|
|
28661
|
+
return [this.#projectItem(projected.item)];
|
|
28422
28662
|
if (projected.item.type === "agentMessage") {
|
|
28423
28663
|
return [projectItem(projected.item, projected.outcome, this.#cwd)];
|
|
28424
28664
|
}
|
|
@@ -28746,7 +28986,7 @@ var CodexTurnProjector = class {
|
|
|
28746
28986
|
return { messages: [] };
|
|
28747
28987
|
}
|
|
28748
28988
|
const messages = [
|
|
28749
|
-
completedItem(projectItem(projected.item, projected.outcome,
|
|
28989
|
+
completedItem(this.#projectItem(projected.item, projected.outcome, !projected.streamedCommandOutput))
|
|
28750
28990
|
];
|
|
28751
28991
|
if (projected.item.type === "reasoning") {
|
|
28752
28992
|
const reasoning = projected.item;
|
|
@@ -28811,6 +29051,8 @@ var CodexTurnProjector = class {
|
|
|
28811
29051
|
projectReasoningTranscriptItem(reasoning, projected.outcome, this.#cwd, projected.durationMs ?? null)
|
|
28812
29052
|
];
|
|
28813
29053
|
}
|
|
29054
|
+
if (projected.item.type === "userMessage")
|
|
29055
|
+
return [this.#projectItem(projected.item)];
|
|
28814
29056
|
if (projected.item.type === "agentMessage") {
|
|
28815
29057
|
return [projectItem(projected.item, projected.outcome, this.#cwd)];
|
|
28816
29058
|
}
|
|
@@ -28896,10 +29138,13 @@ var CodexTurnProjector = class {
|
|
|
28896
29138
|
threadId: this.#threadId,
|
|
28897
29139
|
turnId: this.#turnId,
|
|
28898
29140
|
startedAtMs,
|
|
28899
|
-
item: projectItem(item, null
|
|
29141
|
+
item: this.#projectItem(item, null)
|
|
28900
29142
|
}
|
|
28901
29143
|
};
|
|
28902
29144
|
}
|
|
29145
|
+
#projectItem(item, outcome = null, includeCommandOutput = true) {
|
|
29146
|
+
return item.type === "userMessage" ? projectUserMessage(item, this.#userMessageClientIds.get(item.itemId) ?? null) : projectItem(item, outcome, this.#cwd, includeCommandOutput, this.#threadId);
|
|
29147
|
+
}
|
|
28903
29148
|
#startReasoningTranscript(item, startedAtMs) {
|
|
28904
29149
|
return {
|
|
28905
29150
|
method: "item/started",
|
|
@@ -30291,7 +30536,7 @@ var HarnessAccountInspectionCache = class {
|
|
|
30291
30536
|
};
|
|
30292
30537
|
|
|
30293
30538
|
// packages/host-runtime/src/app-server-host.ts
|
|
30294
|
-
import { createHash as createHash9, randomUUID as
|
|
30539
|
+
import { createHash as createHash9, randomUUID as randomUUID16 } from "node:crypto";
|
|
30295
30540
|
import os8 from "node:os";
|
|
30296
30541
|
import path25 from "node:path";
|
|
30297
30542
|
|
|
@@ -30299,12 +30544,12 @@ import path25 from "node:path";
|
|
|
30299
30544
|
import nodePath from "node:path";
|
|
30300
30545
|
|
|
30301
30546
|
// packages/host-runtime/src/external-thread-repository.ts
|
|
30302
|
-
import { randomUUID as
|
|
30547
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
30303
30548
|
import os7 from "node:os";
|
|
30304
30549
|
import path22 from "node:path";
|
|
30305
30550
|
|
|
30306
30551
|
// packages/host-runtime/src/external-subagent-threads.ts
|
|
30307
|
-
import { createHash as createHash6, randomUUID as
|
|
30552
|
+
import { createHash as createHash6, randomUUID as randomUUID10 } from "node:crypto";
|
|
30308
30553
|
function childCreateRequest(parent, nativeRef, id2) {
|
|
30309
30554
|
const key = createHash6("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
|
|
30310
30555
|
return `subagent:${key}`;
|
|
@@ -30379,7 +30624,7 @@ function subagentMaterializer(store, parent, previousParent) {
|
|
|
30379
30624
|
return rebind(existing, parent);
|
|
30380
30625
|
}
|
|
30381
30626
|
const provisional = existing ?? await store.createProvisional({
|
|
30382
|
-
hostThreadId: hostThreadIdSchema.parse(
|
|
30627
|
+
hostThreadId: hostThreadIdSchema.parse(randomUUID10()),
|
|
30383
30628
|
createRequestId,
|
|
30384
30629
|
harnessId: parent.harnessId,
|
|
30385
30630
|
cwd: parent.cwd,
|
|
@@ -30552,7 +30797,7 @@ var ExternalThreadRepository = class {
|
|
|
30552
30797
|
throw new Error("Derived Snapshot identity does not belong to its Native Session");
|
|
30553
30798
|
}
|
|
30554
30799
|
return {
|
|
30555
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
30800
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID11()),
|
|
30556
30801
|
nativeTurnRef: turn.nativeTurnRef,
|
|
30557
30802
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
30558
30803
|
};
|
|
@@ -30675,14 +30920,14 @@ var ExternalThreadRepository = class {
|
|
|
30675
30920
|
const aligned = snapshot2.turns.map((turn) => {
|
|
30676
30921
|
const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
|
|
30677
30922
|
const mapping = existing ?? {
|
|
30678
|
-
hostTurnId: hostTurnIdSchema.parse(
|
|
30923
|
+
hostTurnId: hostTurnIdSchema.parse(randomUUID11()),
|
|
30679
30924
|
nativeTurnRef: turn.nativeTurnRef,
|
|
30680
30925
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
30681
30926
|
};
|
|
30682
30927
|
return {
|
|
30683
30928
|
snapshot: turn,
|
|
30684
30929
|
mapping: {
|
|
30685
|
-
|
|
30930
|
+
hostTurnId: mapping.hostTurnId,
|
|
30686
30931
|
nativeTurnRef: turn.nativeTurnRef,
|
|
30687
30932
|
...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
|
|
30688
30933
|
}
|
|
@@ -30702,8 +30947,8 @@ var ExternalThreadRepository = class {
|
|
|
30702
30947
|
};
|
|
30703
30948
|
function createExternalThreadRecordInput(input) {
|
|
30704
30949
|
return {
|
|
30705
|
-
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(
|
|
30706
|
-
createRequestId: input.createRequestId ??
|
|
30950
|
+
hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID11()),
|
|
30951
|
+
createRequestId: input.createRequestId ?? randomUUID11(),
|
|
30707
30952
|
harnessId: input.harnessId,
|
|
30708
30953
|
cwd: input.cwd,
|
|
30709
30954
|
...input.title ? { title: input.title } : {},
|
|
@@ -30821,6 +31066,15 @@ async function executeExternalThreadFork(input) {
|
|
|
30821
31066
|
boundaryIndex = mappings.length - 1;
|
|
30822
31067
|
}
|
|
30823
31068
|
const boundary = mappings[boundaryIndex];
|
|
31069
|
+
if (boundary && source.steeredTurnIds.has(boundary.hostTurnId)) {
|
|
31070
|
+
return {
|
|
31071
|
+
ok: false,
|
|
31072
|
+
error: {
|
|
31073
|
+
code: -32080,
|
|
31074
|
+
message: "This Turn took steered input; reopen the Thread before forking from it"
|
|
31075
|
+
}
|
|
31076
|
+
};
|
|
31077
|
+
}
|
|
30824
31078
|
if (boundaryIndex < 0 || !boundary?.nativeCheckpointRef) {
|
|
30825
31079
|
return {
|
|
30826
31080
|
ok: false,
|
|
@@ -30877,6 +31131,7 @@ async function executeExternalThreadFork(input) {
|
|
|
30877
31131
|
return { ok: false, error: mapExternalThreadHarnessError(opened.error, "fork") };
|
|
30878
31132
|
}
|
|
30879
31133
|
const session = opened.value;
|
|
31134
|
+
await inheritSourceModel(source, session);
|
|
30880
31135
|
const inheritedPermissionModeId = await inheritSourcePermissionMode(source, session);
|
|
30881
31136
|
try {
|
|
30882
31137
|
const derivedNativeRef = session.initialState.nativeRef;
|
|
@@ -30894,7 +31149,7 @@ async function executeExternalThreadFork(input) {
|
|
|
30894
31149
|
source.harnessId,
|
|
30895
31150
|
provisional.transportModelId
|
|
30896
31151
|
);
|
|
30897
|
-
if (effectiveModel && selection
|
|
31152
|
+
if (effectiveModel && selection && selection.model?.id !== effectiveModel.id) {
|
|
30898
31153
|
const transportModelId = encodeExternalTransportSelection(source.harnessId, {
|
|
30899
31154
|
...selection,
|
|
30900
31155
|
model: effectiveModel
|
|
@@ -30939,6 +31194,22 @@ async function executeExternalThreadFork(input) {
|
|
|
30939
31194
|
};
|
|
30940
31195
|
}
|
|
30941
31196
|
}
|
|
31197
|
+
async function inheritSourceModel(source, session) {
|
|
31198
|
+
let persisted;
|
|
31199
|
+
try {
|
|
31200
|
+
persisted = decodeExternalTransportSelection(source.harnessId, source.transportModelId)?.model;
|
|
31201
|
+
} catch {
|
|
31202
|
+
persisted = void 0;
|
|
31203
|
+
}
|
|
31204
|
+
const sourceModel = source.stateObserver.state.effectiveModel ?? source.requestedModel ?? persisted;
|
|
31205
|
+
if (!sourceModel || !session.capabilities.configuration.selectModel || session.initialState.effectiveModel !== void 0) {
|
|
31206
|
+
return;
|
|
31207
|
+
}
|
|
31208
|
+
try {
|
|
31209
|
+
await session.execute({ type: "model.select", model: sourceModel });
|
|
31210
|
+
} catch {
|
|
31211
|
+
}
|
|
31212
|
+
}
|
|
30942
31213
|
async function inheritSourcePermissionMode(source, session) {
|
|
30943
31214
|
const sourceModeId = source.stateObserver.state.effectivePermissionModeId ?? source.requestedPermissionModeId;
|
|
30944
31215
|
if (!sourceModeId) return void 0;
|
|
@@ -31227,6 +31498,22 @@ var SessionImportRequests = class {
|
|
|
31227
31498
|
}
|
|
31228
31499
|
};
|
|
31229
31500
|
|
|
31501
|
+
// packages/host-runtime/src/shared-question.ts
|
|
31502
|
+
function usesSharedQuestionCard(interaction) {
|
|
31503
|
+
return interaction.questions.some((question) => question.type === "choice" && question.multiple);
|
|
31504
|
+
}
|
|
31505
|
+
function sharedQuestion(interaction) {
|
|
31506
|
+
return threadQuestionSchema.parse(interaction);
|
|
31507
|
+
}
|
|
31508
|
+
function validateSharedQuestionResponse(interaction, response) {
|
|
31509
|
+
const error51 = validateHostQuestionResponse(interaction, response);
|
|
31510
|
+
if (error51) throw new Error(error51.message);
|
|
31511
|
+
for (const values of Object.values(response.answers)) {
|
|
31512
|
+
if (new Set(values).size !== values.length) throw new Error("Duplicate Question answers");
|
|
31513
|
+
if (values.some((value2) => !value2.trim())) throw new Error("Empty Question answer");
|
|
31514
|
+
}
|
|
31515
|
+
}
|
|
31516
|
+
|
|
31230
31517
|
// packages/host-runtime/src/external-thread-history.ts
|
|
31231
31518
|
var DEFAULT_PAGE_SIZE2 = 25;
|
|
31232
31519
|
var MAX_PAGE_SIZE2 = 100;
|
|
@@ -31560,6 +31847,16 @@ async function executeExternalThreadRollback(input) {
|
|
|
31560
31847
|
if (derived.running) {
|
|
31561
31848
|
return { ok: false, error: { code: -32072, message: "External Thread has an active Turn" } };
|
|
31562
31849
|
}
|
|
31850
|
+
const undone = derived.record.turnMappings.slice(-rollback.numTurns);
|
|
31851
|
+
if (undone.some((mapping) => derived.steeredTurnIds.has(mapping.hostTurnId))) {
|
|
31852
|
+
return {
|
|
31853
|
+
ok: false,
|
|
31854
|
+
error: {
|
|
31855
|
+
code: -32080,
|
|
31856
|
+
message: "A Turn here took steered input; reopen the Thread before undoing Turns"
|
|
31857
|
+
}
|
|
31858
|
+
};
|
|
31859
|
+
}
|
|
31563
31860
|
const refreshError = await runtime.refresh(derived);
|
|
31564
31861
|
if (refreshError) return { ok: false, error: refreshError };
|
|
31565
31862
|
if (expectedLastTurnId !== void 0 && derived.record.turnMappings.at(-1)?.hostTurnId !== expectedLastTurnId) {
|
|
@@ -32174,7 +32471,7 @@ var UsageMeter = class {
|
|
|
32174
32471
|
derive(native, prices) {
|
|
32175
32472
|
const usage = Object.fromEntries(
|
|
32176
32473
|
Object.entries(native ?? {}).filter(
|
|
32177
|
-
([
|
|
32474
|
+
([field2]) => !hostDerivedUsageFields.includes(field2)
|
|
32178
32475
|
)
|
|
32179
32476
|
);
|
|
32180
32477
|
const sessionCacheUsage = usage.sessionCacheUsage;
|
|
@@ -32359,6 +32656,7 @@ var ExternalThreadRuntime = class {
|
|
|
32359
32656
|
#repository;
|
|
32360
32657
|
#lifecycle = new ExternalThreadLifecycle();
|
|
32361
32658
|
#hasRunningDescendants;
|
|
32659
|
+
#steeredTurnIds = /* @__PURE__ */ new Map();
|
|
32362
32660
|
#subagentRunning;
|
|
32363
32661
|
#threads = /* @__PURE__ */ new Map();
|
|
32364
32662
|
constructor(input) {
|
|
@@ -32372,7 +32670,8 @@ var ExternalThreadRuntime = class {
|
|
|
32372
32670
|
this.idleRelease = new ExternalThreadIdleRelease({
|
|
32373
32671
|
threads: () => this.values(),
|
|
32374
32672
|
get: (id2) => this.get(id2),
|
|
32375
|
-
|
|
32673
|
+
// Idle release detaches only the Native Session. Host Thread state survives restoration.
|
|
32674
|
+
remove: (id2) => this.#detach(id2),
|
|
32376
32675
|
queue: input.idleRelease?.queue ?? new DesktopRequestQueue(),
|
|
32377
32676
|
canRelease: (thread) => !thread.sessionUnavailable && !this.#lifecycle.busy(thread.id) && (input.idleRelease?.canRelease(thread) ?? false),
|
|
32378
32677
|
...input.idleRelease?.onClosed ? { onClosed: input.idleRelease.onClosed } : {},
|
|
@@ -32382,14 +32681,21 @@ var ExternalThreadRuntime = class {
|
|
|
32382
32681
|
get(threadId2) {
|
|
32383
32682
|
return this.#threads.get(threadId2);
|
|
32384
32683
|
}
|
|
32684
|
+
#detach(threadId2) {
|
|
32685
|
+
const thread = this.#threads.get(threadId2);
|
|
32686
|
+
this.#threads.delete(threadId2);
|
|
32687
|
+
if (!thread || thread.steeredTurnIds.size === 0) this.#steeredTurnIds.delete(threadId2);
|
|
32688
|
+
}
|
|
32385
32689
|
values() {
|
|
32386
32690
|
return [...this.#threads.values()];
|
|
32387
32691
|
}
|
|
32388
32692
|
remove(threadId2) {
|
|
32389
32693
|
this.#threads.delete(threadId2);
|
|
32694
|
+
this.#steeredTurnIds.delete(threadId2);
|
|
32390
32695
|
}
|
|
32391
32696
|
clear() {
|
|
32392
32697
|
this.#threads.clear();
|
|
32698
|
+
this.#steeredTurnIds.clear();
|
|
32393
32699
|
}
|
|
32394
32700
|
drain() {
|
|
32395
32701
|
return this.#lifecycle.drain();
|
|
@@ -32446,6 +32752,11 @@ var ExternalThreadRuntime = class {
|
|
|
32446
32752
|
...effectivePermissionModeId ? { effectivePermissionModeId } : {}
|
|
32447
32753
|
};
|
|
32448
32754
|
const running = this.#subagentRunning(input.record.hostThreadId);
|
|
32755
|
+
let steeredTurnIds = this.#steeredTurnIds.get(input.record.hostThreadId);
|
|
32756
|
+
if (!steeredTurnIds) {
|
|
32757
|
+
steeredTurnIds = /* @__PURE__ */ new Set();
|
|
32758
|
+
this.#steeredTurnIds.set(input.record.hostThreadId, steeredTurnIds);
|
|
32759
|
+
}
|
|
32449
32760
|
const externalThread = {
|
|
32450
32761
|
id: input.record.hostThreadId,
|
|
32451
32762
|
cwd: input.record.cwd,
|
|
@@ -32470,11 +32781,13 @@ var ExternalThreadRuntime = class {
|
|
|
32470
32781
|
usageTurnId: null,
|
|
32471
32782
|
projectedTurns: /* @__PURE__ */ new Map(),
|
|
32472
32783
|
responseGates: /* @__PURE__ */ new Map(),
|
|
32784
|
+
pendingSteerProjections: /* @__PURE__ */ new Set(),
|
|
32473
32785
|
ephemeralTurnIds: /* @__PURE__ */ new Set(),
|
|
32474
32786
|
persistenceError: null,
|
|
32475
32787
|
projectedTerminalTurnId: null,
|
|
32476
32788
|
ignoredInteractionIds: /* @__PURE__ */ new Set(),
|
|
32477
|
-
sessionUnavailable: false
|
|
32789
|
+
sessionUnavailable: false,
|
|
32790
|
+
steeredTurnIds
|
|
32478
32791
|
};
|
|
32479
32792
|
this.idleRelease.touch(externalThread);
|
|
32480
32793
|
externalThread.outputTask = this.#consumeOutputs(externalThread);
|
|
@@ -32531,13 +32844,13 @@ var ExternalThreadRuntime = class {
|
|
|
32531
32844
|
const retire = async () => {
|
|
32532
32845
|
if (this.#threads.get(parentId) !== parent || this.#threads.get(child.id) !== child) return;
|
|
32533
32846
|
if (bestEffort) {
|
|
32534
|
-
this
|
|
32847
|
+
this.remove(child.id);
|
|
32535
32848
|
await child.session.close();
|
|
32536
32849
|
await child.outputTask;
|
|
32537
32850
|
} else {
|
|
32538
32851
|
child.sessionUnavailable = true;
|
|
32539
32852
|
await this.#lifecycle.release(child.id, child.session, child.outputTask);
|
|
32540
|
-
if (this.#threads.get(child.id) === child) this
|
|
32853
|
+
if (this.#threads.get(child.id) === child) this.remove(child.id);
|
|
32541
32854
|
}
|
|
32542
32855
|
};
|
|
32543
32856
|
if (bestEffort) await retire().catch(this.#diagnose);
|
|
@@ -32910,6 +33223,71 @@ var ExternalThreadRuntime = class {
|
|
|
32910
33223
|
};
|
|
32911
33224
|
|
|
32912
33225
|
// packages/host-runtime/src/external-turn-steering.ts
|
|
33226
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
33227
|
+
|
|
33228
|
+
// packages/host-runtime/src/external-command-routing.ts
|
|
33229
|
+
var ExternalCommandError = class extends Error {
|
|
33230
|
+
constructor(code, message2) {
|
|
33231
|
+
super(message2);
|
|
33232
|
+
this.code = code;
|
|
33233
|
+
}
|
|
33234
|
+
code;
|
|
33235
|
+
};
|
|
33236
|
+
function isExternalCommandCandidate(text) {
|
|
33237
|
+
return /^\/[^\s/]+(?:\s|$)/u.test(text.trimStart());
|
|
33238
|
+
}
|
|
33239
|
+
async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
|
|
33240
|
+
let timeout;
|
|
33241
|
+
try {
|
|
33242
|
+
const result = await Promise.race([
|
|
33243
|
+
commands.list(),
|
|
33244
|
+
new Promise((resolve) => {
|
|
33245
|
+
timeout = setTimeout(() => resolve(null), timeoutMs);
|
|
33246
|
+
})
|
|
33247
|
+
]);
|
|
33248
|
+
return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
|
|
33249
|
+
} catch {
|
|
33250
|
+
return null;
|
|
33251
|
+
} finally {
|
|
33252
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
33253
|
+
}
|
|
33254
|
+
}
|
|
33255
|
+
async function resolveExternalCommand(commands, text, options2 = {}) {
|
|
33256
|
+
const catalog = await commands.list();
|
|
33257
|
+
if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
|
|
33258
|
+
const commandText = text.trim();
|
|
33259
|
+
const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
|
|
33260
|
+
if (commandText === command.invocation) return true;
|
|
33261
|
+
return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
|
|
33262
|
+
});
|
|
33263
|
+
if (!matched) {
|
|
33264
|
+
const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
|
|
33265
|
+
if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
|
|
33266
|
+
return null;
|
|
33267
|
+
}
|
|
33268
|
+
throw new ExternalCommandError(
|
|
33269
|
+
-32078,
|
|
33270
|
+
"External Harness does not expose the requested command"
|
|
33271
|
+
);
|
|
33272
|
+
}
|
|
33273
|
+
const argumentText = commandText.slice(matched.invocation.length).trimStart();
|
|
33274
|
+
return {
|
|
33275
|
+
descriptor: matched,
|
|
33276
|
+
...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
|
|
33277
|
+
};
|
|
33278
|
+
}
|
|
33279
|
+
|
|
33280
|
+
// packages/host-runtime/src/external-turn-steering.ts
|
|
33281
|
+
function isHarnessCommand(thread, text) {
|
|
33282
|
+
return thread.session.commands !== void 0 && isExternalCommandCandidate(restoreHarnessCommandMentions(text));
|
|
33283
|
+
}
|
|
33284
|
+
function externalSteeringDelivery(thread, text) {
|
|
33285
|
+
if (text !== void 0 && isHarnessCommand(thread, text)) return "newTurn";
|
|
33286
|
+
if (thread.session.readCapabilities) {
|
|
33287
|
+
return thread.session.readCapabilities().then((capabilities) => capabilities.steer === true ? "activeTurn" : "newTurn");
|
|
33288
|
+
}
|
|
33289
|
+
return thread.session.capabilities.steer === true ? "activeTurn" : "newTurn";
|
|
33290
|
+
}
|
|
32913
33291
|
var ExternalSteerError = class extends Error {
|
|
32914
33292
|
constructor(code, message2) {
|
|
32915
33293
|
super(message2);
|
|
@@ -32917,6 +33295,11 @@ var ExternalSteerError = class extends Error {
|
|
|
32917
33295
|
}
|
|
32918
33296
|
code;
|
|
32919
33297
|
};
|
|
33298
|
+
var ExternalSteerNotTakenError = class extends ExternalSteerError {
|
|
33299
|
+
constructor(message2) {
|
|
33300
|
+
super(-32074, message2);
|
|
33301
|
+
}
|
|
33302
|
+
};
|
|
32920
33303
|
function parseInput(params) {
|
|
32921
33304
|
if (typeof params.expectedTurnId !== "string" || !params.expectedTurnId.trim()) {
|
|
32922
33305
|
throw new ExternalSteerError(-32602, "External steering requires expectedTurnId");
|
|
@@ -32933,12 +33316,47 @@ function parseInput(params) {
|
|
|
32933
33316
|
if (clientUserMessageId != null && (typeof clientUserMessageId !== "string" || !clientUserMessageId.trim())) {
|
|
32934
33317
|
throw new ExternalSteerError(-32602, "External steering message identity is invalid");
|
|
32935
33318
|
}
|
|
33319
|
+
const delivery = params[THREAD_STEER_DELIVERY_PARAM];
|
|
33320
|
+
const parsedDelivery = delivery == null ? void 0 : threadSteerDeliverySchema.safeParse(delivery);
|
|
33321
|
+
if (parsedDelivery && !parsedDelivery.success) {
|
|
33322
|
+
throw new ExternalSteerError(-32602, "External steering delivery is invalid");
|
|
33323
|
+
}
|
|
32936
33324
|
return {
|
|
32937
33325
|
expectedTurnId: params.expectedTurnId,
|
|
32938
33326
|
text,
|
|
32939
|
-
...typeof clientUserMessageId === "string" ? { clientUserMessageId } : {}
|
|
33327
|
+
...typeof clientUserMessageId === "string" ? { clientUserMessageId } : {},
|
|
33328
|
+
...parsedDelivery ? { delivery: parsedDelivery.data } : {}
|
|
32940
33329
|
};
|
|
32941
33330
|
}
|
|
33331
|
+
async function insertNativeSteer(thread, input, host) {
|
|
33332
|
+
const restored = restoreHarnessCommandMentions(input.text);
|
|
33333
|
+
const steered = [{ type: "text", text: rewriteDelegationMentionText(restored) }];
|
|
33334
|
+
const displayed = [{ type: "text", text: restored }];
|
|
33335
|
+
const projectionDone = Promise.withResolvers();
|
|
33336
|
+
thread.pendingSteerProjections.add(projectionDone.promise);
|
|
33337
|
+
try {
|
|
33338
|
+
const result = await thread.session.execute({
|
|
33339
|
+
type: "turn.steer",
|
|
33340
|
+
turnId: input.turnId,
|
|
33341
|
+
input: steered
|
|
33342
|
+
});
|
|
33343
|
+
if (!result.ok) throw new ExternalSteerNotTakenError(result.error.message);
|
|
33344
|
+
thread.steeredTurnIds.add(input.turnId);
|
|
33345
|
+
const item = {
|
|
33346
|
+
type: "userMessage",
|
|
33347
|
+
itemId: hostItemIdSchema.parse(randomUUID12()),
|
|
33348
|
+
input: displayed
|
|
33349
|
+
};
|
|
33350
|
+
try {
|
|
33351
|
+
await host.project(input.turnId, item, input.clientUserMessageId);
|
|
33352
|
+
} catch (error51) {
|
|
33353
|
+
host.diagnose(error51);
|
|
33354
|
+
}
|
|
33355
|
+
} finally {
|
|
33356
|
+
projectionDone.resolve(void 0);
|
|
33357
|
+
thread.pendingSteerProjections.delete(projectionDone.promise);
|
|
33358
|
+
}
|
|
33359
|
+
}
|
|
32942
33360
|
var ExternalTurnSteering = class {
|
|
32943
33361
|
constructor(timeoutMs = 2e4) {
|
|
32944
33362
|
this.timeoutMs = timeoutMs;
|
|
@@ -32950,7 +33368,7 @@ var ExternalTurnSteering = class {
|
|
|
32950
33368
|
hasPending(threadId2) {
|
|
32951
33369
|
return threadId2 === void 0 ? this.#pending.size > 0 : this.#pending.has(threadId2);
|
|
32952
33370
|
}
|
|
32953
|
-
run(thread, params, start) {
|
|
33371
|
+
run(thread, params, start, insert) {
|
|
32954
33372
|
try {
|
|
32955
33373
|
const input = parseInput(params);
|
|
32956
33374
|
if (this.#closed)
|
|
@@ -32972,7 +33390,7 @@ var ExternalTurnSteering = class {
|
|
|
32972
33390
|
if (!thread.running || thread.activeTurnId !== input.expectedTurnId) {
|
|
32973
33391
|
throw new ExternalSteerError(-32074, "External steering must reference the active Turn");
|
|
32974
33392
|
}
|
|
32975
|
-
const result = this.#
|
|
33393
|
+
const result = this.#deliver(thread, input, start, insert);
|
|
32976
33394
|
if (key) {
|
|
32977
33395
|
const receipt2 = { fingerprint, result, settled: false };
|
|
32978
33396
|
this.#receipts.set(key, receipt2);
|
|
@@ -32995,6 +33413,56 @@ var ExternalTurnSteering = class {
|
|
|
32995
33413
|
return Promise.reject(error51);
|
|
32996
33414
|
}
|
|
32997
33415
|
}
|
|
33416
|
+
/**
|
|
33417
|
+
* A Renderer that already presented a delivery gets exactly that one. Otherwise native delivery
|
|
33418
|
+
* is tried only when the Session can take the input now, and input the Harness did not take
|
|
33419
|
+
* falls back to stopping and restarting, so no case is worse than the stop-then-start path.
|
|
33420
|
+
*/
|
|
33421
|
+
#deliver(thread, input, start, insert) {
|
|
33422
|
+
const delivery = input.delivery === "newTurn" || isHarnessCommand(thread, input.text) ? "newTurn" : input.delivery ?? externalSteeringDelivery(thread);
|
|
33423
|
+
const deliver = (mode) => {
|
|
33424
|
+
if (this.#closed || !thread.running || thread.activeTurnId !== input.expectedTurnId) {
|
|
33425
|
+
throw new ExternalSteerError(-32074, "External steering target is no longer active");
|
|
33426
|
+
}
|
|
33427
|
+
if (this.hasPending(thread.id))
|
|
33428
|
+
throw new ExternalSteerError(-32072, "External Thread is already changing direction");
|
|
33429
|
+
if (mode === "newTurn") return this.#replace(thread, input, start);
|
|
33430
|
+
const native = insert({
|
|
33431
|
+
turnId: thread.activeTurnId,
|
|
33432
|
+
text: input.text,
|
|
33433
|
+
...input.clientUserMessageId ? { clientUserMessageId: input.clientUserMessageId } : {}
|
|
33434
|
+
}).then((admitted) => ({ ...admitted, delivery: "activeTurn" }));
|
|
33435
|
+
if (input.delivery === "activeTurn") return native;
|
|
33436
|
+
return native.catch(async (error51) => {
|
|
33437
|
+
if (!(error51 instanceof ExternalSteerNotTakenError)) throw error51;
|
|
33438
|
+
if (thread.running || thread.activeTurnId) return deliver("newTurn");
|
|
33439
|
+
const assertActive = () => {
|
|
33440
|
+
if (this.#closed)
|
|
33441
|
+
throw new ExternalSteerError(-32074, "External steering connection is closed");
|
|
33442
|
+
};
|
|
33443
|
+
return { ...await start(input.text, assertActive), delivery: "newTurn" };
|
|
33444
|
+
});
|
|
33445
|
+
};
|
|
33446
|
+
if (typeof delivery === "string") return deliver(delivery);
|
|
33447
|
+
const failure = Promise.withResolvers();
|
|
33448
|
+
let failureReason = null;
|
|
33449
|
+
const pending = {
|
|
33450
|
+
turnId: input.expectedTurnId,
|
|
33451
|
+
resolve: () => void 0,
|
|
33452
|
+
reject(error51) {
|
|
33453
|
+
failureReason ??= error51;
|
|
33454
|
+
failure.reject(error51);
|
|
33455
|
+
}
|
|
33456
|
+
};
|
|
33457
|
+
this.#pending.set(thread.id, pending);
|
|
33458
|
+
return Promise.race([delivery, failure.promise]).then((mode) => {
|
|
33459
|
+
if (failureReason) throw failureReason;
|
|
33460
|
+
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
33461
|
+
return deliver(mode);
|
|
33462
|
+
}).finally(() => {
|
|
33463
|
+
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
33464
|
+
});
|
|
33465
|
+
}
|
|
32998
33466
|
terminal(threadId2, turnId, outcome) {
|
|
32999
33467
|
const pending = this.#pending.get(threadId2);
|
|
33000
33468
|
if (pending?.turnId === turnId) pending.resolve(outcome);
|
|
@@ -33049,7 +33517,9 @@ var ExternalTurnSteering = class {
|
|
|
33049
33517
|
thread.session.execute({ type: "turn.cancel", turnId }),
|
|
33050
33518
|
failure.promise
|
|
33051
33519
|
]);
|
|
33052
|
-
if (!cancelled.ok
|
|
33520
|
+
if (!cancelled.ok && cancelled.error.code !== "invalidState") {
|
|
33521
|
+
throw new ExternalSteerError(-32074, cancelled.error.message);
|
|
33522
|
+
}
|
|
33053
33523
|
const outcome = await Promise.race([terminal3.promise, failure.promise]);
|
|
33054
33524
|
clearTimeout(timeout);
|
|
33055
33525
|
const assertActive = () => {
|
|
@@ -33067,7 +33537,7 @@ var ExternalTurnSteering = class {
|
|
|
33067
33537
|
if (thread.running || thread.activeTurnId) {
|
|
33068
33538
|
throw new ExternalSteerError(-32072, "Another External Turn started before replacement");
|
|
33069
33539
|
}
|
|
33070
|
-
return await start(input.text, assertActive);
|
|
33540
|
+
return { ...await start(input.text, assertActive), delivery: "newTurn" };
|
|
33071
33541
|
} finally {
|
|
33072
33542
|
clearTimeout(timeout);
|
|
33073
33543
|
if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
|
|
@@ -33075,58 +33545,6 @@ var ExternalTurnSteering = class {
|
|
|
33075
33545
|
}
|
|
33076
33546
|
};
|
|
33077
33547
|
|
|
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
33548
|
// packages/host-runtime/src/live-command-catalog-cache.ts
|
|
33131
33549
|
import path23 from "node:path";
|
|
33132
33550
|
var MAX_ENTRIES = 64;
|
|
@@ -33158,7 +33576,7 @@ function sameWorkspace(left, right) {
|
|
|
33158
33576
|
}
|
|
33159
33577
|
|
|
33160
33578
|
// packages/host-runtime/src/harness-delegation-coordinator.ts
|
|
33161
|
-
import { createHash as createHash8, randomUUID as
|
|
33579
|
+
import { createHash as createHash8, randomUUID as randomUUID13 } from "node:crypto";
|
|
33162
33580
|
import path24 from "node:path";
|
|
33163
33581
|
|
|
33164
33582
|
// packages/host-runtime/src/delegation-snapshot.ts
|
|
@@ -33304,6 +33722,15 @@ function projectDelegationThreadSnapshot(input) {
|
|
|
33304
33722
|
// packages/host-runtime/src/harness-delegation-coordinator.ts
|
|
33305
33723
|
var IMPLICIT_DEDUPLICATION_MS = 3e4;
|
|
33306
33724
|
var NATIVE_REF_TIMEOUT_MS = 1e4;
|
|
33725
|
+
function truncateTitle(value2, length) {
|
|
33726
|
+
return value2.slice(0, length).replace(/[\uD800-\uDBFF]$/u, "");
|
|
33727
|
+
}
|
|
33728
|
+
function delegationTitle(parentTitle, input) {
|
|
33729
|
+
const taskName = (input.taskName ?? input.task.trim().split(/\r?\n/u)[0] ?? input.task).replace(/\s+/gu, " ").trim();
|
|
33730
|
+
const subtask = truncateTitle(taskName, 120);
|
|
33731
|
+
const parent = (parentTitle?.trim() || "Untitled Thread").replace(/\s+/gu, " ");
|
|
33732
|
+
return `${subtask} · ${truncateTitle(parent, 200 - subtask.length - 3)}`;
|
|
33733
|
+
}
|
|
33307
33734
|
function delay3(milliseconds) {
|
|
33308
33735
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
33309
33736
|
}
|
|
@@ -33330,6 +33757,12 @@ function statusFromThread(thread, busy) {
|
|
|
33330
33757
|
function validateStart(input) {
|
|
33331
33758
|
if (typeof input.task !== "string" || !input.task.trim())
|
|
33332
33759
|
throw new DelegationControlError("INVALID_ARGUMENT", "Task must not be empty");
|
|
33760
|
+
if (input.taskName !== void 0 && (typeof input.taskName !== "string" || !input.taskName.trim() || input.taskName.length > 120)) {
|
|
33761
|
+
throw new DelegationControlError(
|
|
33762
|
+
"INVALID_ARGUMENT",
|
|
33763
|
+
"Task name must contain 1 to 120 characters"
|
|
33764
|
+
);
|
|
33765
|
+
}
|
|
33333
33766
|
if (input.cwd !== void 0 && (typeof input.cwd !== "string" || !input.cwd.trim()))
|
|
33334
33767
|
throw new DelegationControlError("INVALID_ARGUMENT", "cwd must not be empty");
|
|
33335
33768
|
if (input.requestId !== void 0 && (typeof input.requestId !== "string" || !input.requestId.trim())) {
|
|
@@ -33350,7 +33783,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
33350
33783
|
#cancelOfficial;
|
|
33351
33784
|
#startOfficial;
|
|
33352
33785
|
#listOfficial;
|
|
33353
|
-
#
|
|
33786
|
+
#officialThreadMetadata;
|
|
33354
33787
|
#activeOfficialParents;
|
|
33355
33788
|
#externalThreadBusy;
|
|
33356
33789
|
constructor(input) {
|
|
@@ -33367,7 +33800,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
33367
33800
|
this.#cancelOfficial = input.cancelOfficial;
|
|
33368
33801
|
this.#startOfficial = input.startOfficial;
|
|
33369
33802
|
this.#listOfficial = input.listOfficial;
|
|
33370
|
-
this.#
|
|
33803
|
+
this.#officialThreadMetadata = input.officialThreadMetadata;
|
|
33371
33804
|
this.#activeOfficialParents = input.activeOfficialParents;
|
|
33372
33805
|
this.#externalThreadBusy = input.externalThreadBusy;
|
|
33373
33806
|
}
|
|
@@ -33397,8 +33830,14 @@ var HarnessDelegationCoordinator = class {
|
|
|
33397
33830
|
const parentThreadId = await this.#resolveParent(input.parentThreadId);
|
|
33398
33831
|
const parent = await this.#parentMetadata(parentThreadId);
|
|
33399
33832
|
const selectedCwd = input.cwd ?? parent.cwd ?? process.cwd();
|
|
33833
|
+
const title = delegationTitle(parent.title, input);
|
|
33400
33834
|
if (input.harnessId === "codex") {
|
|
33401
|
-
const result = await this.#startOfficial({
|
|
33835
|
+
const result = await this.#startOfficial({
|
|
33836
|
+
...input,
|
|
33837
|
+
parentThreadId,
|
|
33838
|
+
cwd: selectedCwd,
|
|
33839
|
+
title
|
|
33840
|
+
});
|
|
33402
33841
|
return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
|
|
33403
33842
|
}
|
|
33404
33843
|
const startInput = { ...input, parentThreadId, cwd: path24.resolve(selectedCwd) };
|
|
@@ -33441,17 +33880,17 @@ var HarnessDelegationCoordinator = class {
|
|
|
33441
33880
|
});
|
|
33442
33881
|
this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
|
|
33443
33882
|
}
|
|
33444
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
33445
|
-
const childThreadId = hostThreadIdSchema.parse(
|
|
33446
|
-
const turnId = hostTurnIdSchema.parse(
|
|
33447
|
-
const createRequestId = input.requestId ? `delegation:${input.requestId}` :
|
|
33883
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID13());
|
|
33884
|
+
const childThreadId = hostThreadIdSchema.parse(randomUUID13());
|
|
33885
|
+
const turnId = hostTurnIdSchema.parse(randomUUID13());
|
|
33886
|
+
const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID13();
|
|
33448
33887
|
let record4 = await this.#repository.createProvisional(
|
|
33449
33888
|
createExternalThreadRecordInput({
|
|
33450
33889
|
hostThreadId: childThreadId,
|
|
33451
33890
|
createRequestId,
|
|
33452
33891
|
harnessId: harnessIdSchema.parse(targetHarnessId),
|
|
33453
33892
|
cwd: startInput.cwd,
|
|
33454
|
-
title
|
|
33893
|
+
title,
|
|
33455
33894
|
transportModelId: input.model || input.thinkingOptionId ? encodeExternalTransportSelection(targetHarnessId, {
|
|
33456
33895
|
...input.model ? { model: input.model } : {},
|
|
33457
33896
|
...input.thinkingOptionId ? { thinkingOptionId: input.thinkingOptionId } : {}
|
|
@@ -33598,7 +34037,7 @@ var HarnessDelegationCoordinator = class {
|
|
|
33598
34037
|
if (this.#externalThreadBusy(thread) || thread.activeTurnId) {
|
|
33599
34038
|
throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
|
|
33600
34039
|
}
|
|
33601
|
-
const turnId = hostTurnIdSchema.parse(
|
|
34040
|
+
const turnId = hostTurnIdSchema.parse(randomUUID13());
|
|
33602
34041
|
try {
|
|
33603
34042
|
await this.#startExternalTurn(thread, input.message, turnId);
|
|
33604
34043
|
} catch (error51) {
|
|
@@ -33724,10 +34163,10 @@ var HarnessDelegationCoordinator = class {
|
|
|
33724
34163
|
}
|
|
33725
34164
|
};
|
|
33726
34165
|
});
|
|
33727
|
-
const [
|
|
34166
|
+
const [field2, direction] = input.sort.split("-");
|
|
33728
34167
|
rows.sort((left, right) => {
|
|
33729
|
-
const leftTimestamp =
|
|
33730
|
-
const rightTimestamp =
|
|
34168
|
+
const leftTimestamp = field2 === "created" ? left.createdAt : left.updatedAt;
|
|
34169
|
+
const rightTimestamp = field2 === "created" ? right.createdAt : right.updatedAt;
|
|
33731
34170
|
const leftTime = Date.parse(leftTimestamp ?? "");
|
|
33732
34171
|
const rightTime = Date.parse(rightTimestamp ?? "");
|
|
33733
34172
|
return direction === "asc" ? leftTime - rightTime : rightTime - leftTime;
|
|
@@ -33812,9 +34251,14 @@ var HarnessDelegationCoordinator = class {
|
|
|
33812
34251
|
}
|
|
33813
34252
|
async #parentMetadata(parentThreadId) {
|
|
33814
34253
|
const record4 = await this.#repository.find(parentThreadId);
|
|
33815
|
-
if (record4)
|
|
33816
|
-
|
|
33817
|
-
|
|
34254
|
+
if (record4)
|
|
34255
|
+
return {
|
|
34256
|
+
harnessId: record4.harnessId,
|
|
34257
|
+
cwd: record4.cwd,
|
|
34258
|
+
title: record4.title
|
|
34259
|
+
};
|
|
34260
|
+
const metadata = await this.#officialThreadMetadata(parentThreadId).catch(() => ({}));
|
|
34261
|
+
return { harnessId: "codex", ...metadata };
|
|
33818
34262
|
}
|
|
33819
34263
|
async #existingResult(delegation) {
|
|
33820
34264
|
const record4 = await this.#repository.find(delegation.childHostThreadId);
|
|
@@ -36243,10 +36687,10 @@ var SingleNativeCodexAccount = class {
|
|
|
36243
36687
|
};
|
|
36244
36688
|
|
|
36245
36689
|
// packages/host-runtime/src/codex-runtime/official-runtime-owner.ts
|
|
36246
|
-
import { randomUUID as
|
|
36690
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
36247
36691
|
|
|
36248
36692
|
// packages/host-runtime/src/official-request-broker.ts
|
|
36249
|
-
import { randomUUID as
|
|
36693
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
36250
36694
|
var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
|
|
36251
36695
|
var MAX_RETIRED_IDS = 1024;
|
|
36252
36696
|
function isRecord15(value2) {
|
|
@@ -36262,7 +36706,7 @@ var OfficialRequestBroker = class {
|
|
|
36262
36706
|
constructor(input) {
|
|
36263
36707
|
this.#send = input.send;
|
|
36264
36708
|
this.#timeoutMs = input.timeoutMs ?? 3e4;
|
|
36265
|
-
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${
|
|
36709
|
+
this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID14()}`);
|
|
36266
36710
|
}
|
|
36267
36711
|
get pendingCount() {
|
|
36268
36712
|
return this.#pending.size;
|
|
@@ -36616,7 +37060,7 @@ var OfficialRuntimeOwner = class {
|
|
|
36616
37060
|
}
|
|
36617
37061
|
#attach(role, output, onBackendStopped) {
|
|
36618
37062
|
const client = {
|
|
36619
|
-
id:
|
|
37063
|
+
id: randomUUID15(),
|
|
36620
37064
|
role,
|
|
36621
37065
|
output,
|
|
36622
37066
|
...onBackendStopped ? { onBackendStopped } : {},
|
|
@@ -36774,7 +37218,7 @@ var OfficialRuntimeOwner = class {
|
|
|
36774
37218
|
if (!object4(value2)) return client.output(event);
|
|
36775
37219
|
if (typeof value2.id === "string" || typeof value2.id === "number") {
|
|
36776
37220
|
if (typeof value2.method === "string") {
|
|
36777
|
-
const id2 = `codexhost:server:${client.id}:${event.generation}:${
|
|
37221
|
+
const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID15()}`;
|
|
36778
37222
|
client.serverRequests.set(id2, value2.id);
|
|
36779
37223
|
const projected = { ...value2, id: id2 };
|
|
36780
37224
|
return client.output({
|
|
@@ -36950,16 +37394,16 @@ var OfficialRuntimeScope = class {
|
|
|
36950
37394
|
#scheduleRecovery() {
|
|
36951
37395
|
if (!this.#recovery || this.#closed || this.#recoveryTimer || this.#starting) return;
|
|
36952
37396
|
const { delaysMs } = this.#recovery;
|
|
36953
|
-
const
|
|
37397
|
+
const delay7 = delaysMs[Math.min(this.#recoveryAttempt, delaysMs.length - 1)] ?? 0;
|
|
36954
37398
|
this.#recoveryAttempt++;
|
|
36955
37399
|
this.#diagnosticOutput.write(
|
|
36956
|
-
`codexhost: official Codex is unavailable; restarting in ${String(
|
|
37400
|
+
`codexhost: official Codex is unavailable; restarting in ${String(delay7)}ms
|
|
36957
37401
|
`
|
|
36958
37402
|
);
|
|
36959
37403
|
const timer = setTimeout(() => {
|
|
36960
37404
|
this.#recoveryTimer = void 0;
|
|
36961
37405
|
this.start().catch(() => void 0);
|
|
36962
|
-
},
|
|
37406
|
+
}, delay7);
|
|
36963
37407
|
timer.unref();
|
|
36964
37408
|
this.#recoveryTimer = timer;
|
|
36965
37409
|
}
|
|
@@ -37121,9 +37565,9 @@ var RequestRouteObservationTracker = class {
|
|
|
37121
37565
|
};
|
|
37122
37566
|
|
|
37123
37567
|
// packages/host-runtime/src/external-thread-list.ts
|
|
37124
|
-
function unixTimestamp(value2,
|
|
37568
|
+
function unixTimestamp(value2, field2) {
|
|
37125
37569
|
const parsed2 = Date.parse(value2);
|
|
37126
|
-
if (!Number.isFinite(parsed2)) throw new Error(`External Thread ${
|
|
37570
|
+
if (!Number.isFinite(parsed2)) throw new Error(`External Thread ${field2} is invalid`);
|
|
37127
37571
|
return Math.floor(parsed2 / 1e3);
|
|
37128
37572
|
}
|
|
37129
37573
|
function threadId(thread) {
|
|
@@ -37133,11 +37577,11 @@ function threadId(thread) {
|
|
|
37133
37577
|
return thread.id;
|
|
37134
37578
|
}
|
|
37135
37579
|
function threadListTimestamp(thread, sortKey) {
|
|
37136
|
-
const
|
|
37137
|
-
if (!Number.isSafeInteger(
|
|
37580
|
+
const field2 = sortKey === "created_at" ? thread.createdAt : sortKey === "updated_at" ? thread.updatedAt : thread.recencyAt ?? thread.updatedAt;
|
|
37581
|
+
if (!Number.isSafeInteger(field2)) {
|
|
37138
37582
|
throw new Error(`Thread list row has no valid ${sortKey} timestamp`);
|
|
37139
37583
|
}
|
|
37140
|
-
return
|
|
37584
|
+
return field2;
|
|
37141
37585
|
}
|
|
37142
37586
|
function compareTimestamp(left, right, direction) {
|
|
37143
37587
|
if (left === right) return 0;
|
|
@@ -38054,6 +38498,7 @@ var AppServerHost = class {
|
|
|
38054
38498
|
#plugins;
|
|
38055
38499
|
#launchSettings;
|
|
38056
38500
|
#accountInspections = new HarnessAccountInspectionCache();
|
|
38501
|
+
#installationTasks = new HarnessInstallationTasks();
|
|
38057
38502
|
#externalRuntime;
|
|
38058
38503
|
#executionHosts = /* @__PURE__ */ new WeakMap();
|
|
38059
38504
|
#externalPrewarms = new ExternalThreadPrewarms();
|
|
@@ -38084,7 +38529,7 @@ var AppServerHost = class {
|
|
|
38084
38529
|
#sectionMoves = Promise.resolve();
|
|
38085
38530
|
#writer;
|
|
38086
38531
|
/** Console requests share Desktop handling; their replies return to the console. */
|
|
38087
|
-
#consoleRequestPrefix = `codexhost-console:${
|
|
38532
|
+
#consoleRequestPrefix = `codexhost-console:${randomUUID16()}:`;
|
|
38088
38533
|
#consoleReplies = /* @__PURE__ */ new Map();
|
|
38089
38534
|
#nextConsoleRequest = 0;
|
|
38090
38535
|
#subagentThreadStatuses = /* @__PURE__ */ new Map();
|
|
@@ -38222,7 +38667,7 @@ var AppServerHost = class {
|
|
|
38222
38667
|
cancelOfficial: (input) => this.#cancelOfficialDelegationThread(input),
|
|
38223
38668
|
startOfficial: (input) => this.#startOfficialDelegation(input),
|
|
38224
38669
|
listOfficial: (input) => this.#listDelegationThreads(input),
|
|
38225
|
-
|
|
38670
|
+
officialThreadMetadata: (threadId2) => this.#readOfficialThreadMetadata(threadId2),
|
|
38226
38671
|
activeOfficialParents: () => [...this.#activeOfficialTurns.keys()],
|
|
38227
38672
|
externalThreadBusy: (thread) => this.#externalThreadBusy(thread)
|
|
38228
38673
|
});
|
|
@@ -38868,11 +39313,11 @@ var AppServerHost = class {
|
|
|
38868
39313
|
this.#dispatchDesktopReply(request, () => this.#inspectHarness(request));
|
|
38869
39314
|
return;
|
|
38870
39315
|
}
|
|
38871
|
-
if (request.method === HARNESS_INSTALLATION_METHOD) {
|
|
39316
|
+
if (request.method === HARNESS_INSTALLATION_METHOD || request.method === HARNESS_INSTALLATION_START_METHOD || request.method === HARNESS_INSTALLATION_STATUS_METHOD) {
|
|
38872
39317
|
this.#dispatchDesktopReply(request, async () => {
|
|
38873
|
-
await this.#waitForPlugins();
|
|
38874
39318
|
try {
|
|
38875
|
-
|
|
39319
|
+
if (request.method !== HARNESS_INSTALLATION_STATUS_METHOD) await this.#waitForPlugins();
|
|
39320
|
+
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
39321
|
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
|
|
38877
39322
|
} catch (error51) {
|
|
38878
39323
|
await this.#writer.json(
|
|
@@ -38957,6 +39402,19 @@ var AppServerHost = class {
|
|
|
38957
39402
|
await this.#listThreadOwnership(request);
|
|
38958
39403
|
return;
|
|
38959
39404
|
}
|
|
39405
|
+
if (request.method === THREAD_QUESTIONS_LIST_METHOD || request.method === THREAD_QUESTION_RESPOND_METHOD) {
|
|
39406
|
+
const threadId2 = requestObject(request).threadId;
|
|
39407
|
+
this.#dispatchDesktopReply(
|
|
39408
|
+
request,
|
|
39409
|
+
() => this.#handleSharedQuestionRequest(request),
|
|
39410
|
+
request.method === THREAD_QUESTION_RESPOND_METHOD && typeof threadId2 === "string" ? threadId2 : void 0
|
|
39411
|
+
);
|
|
39412
|
+
return;
|
|
39413
|
+
}
|
|
39414
|
+
if (request.method === "codexhost/thread/steering/inspect") {
|
|
39415
|
+
await this.#inspectThreadSteering(request);
|
|
39416
|
+
return;
|
|
39417
|
+
}
|
|
38960
39418
|
if (request.method === "codexhost/thread/model/select") {
|
|
38961
39419
|
await this.#selectThreadModel(request);
|
|
38962
39420
|
return;
|
|
@@ -39534,12 +39992,17 @@ var AppServerHost = class {
|
|
|
39534
39992
|
]);
|
|
39535
39993
|
return thread !== null || childDelegation !== null || delegation !== null;
|
|
39536
39994
|
}
|
|
39537
|
-
async #
|
|
39538
|
-
const response = await this.#requestOfficial("thread/read", { threadId: threadId2 });
|
|
39539
|
-
if (isRecord18(response.error)) return
|
|
39995
|
+
async #readOfficialThreadMetadata(threadId2) {
|
|
39996
|
+
const response = await this.#requestOfficial("thread/read", { threadId: threadId2, includeTurns: false });
|
|
39997
|
+
if (isRecord18(response.error)) return {};
|
|
39540
39998
|
const result = isRecord18(response.result) ? response.result : null;
|
|
39541
39999
|
const thread = result && isRecord18(result.thread) ? result.thread : null;
|
|
39542
|
-
|
|
40000
|
+
if (!thread) return {};
|
|
40001
|
+
const title = typeof thread.name === "string" && thread.name.trim() ? thread.name : thread.preview;
|
|
40002
|
+
return {
|
|
40003
|
+
...typeof thread.cwd === "string" && thread.cwd.trim() ? { cwd: thread.cwd } : {},
|
|
40004
|
+
...typeof title === "string" && title.trim() ? { title } : {}
|
|
40005
|
+
};
|
|
39543
40006
|
}
|
|
39544
40007
|
async #inspectOfficialDelegationTarget(input) {
|
|
39545
40008
|
const response = await this.#requestOfficial("model/list", {});
|
|
@@ -39692,6 +40155,9 @@ var AppServerHost = class {
|
|
|
39692
40155
|
this.#pendingOfficialDelegationThreads.add(threadId2);
|
|
39693
40156
|
let turnId;
|
|
39694
40157
|
try {
|
|
40158
|
+
await this.#requestOfficial("thread/name/set", { threadId: threadId2, name: input.title }).catch(
|
|
40159
|
+
() => void 0
|
|
40160
|
+
);
|
|
39695
40161
|
const turn = await this.#requestOfficial("turn/start", {
|
|
39696
40162
|
threadId: threadId2,
|
|
39697
40163
|
input: [{ type: "text", text: input.task }],
|
|
@@ -39710,7 +40176,7 @@ var AppServerHost = class {
|
|
|
39710
40176
|
throw error51;
|
|
39711
40177
|
}
|
|
39712
40178
|
this.#activeOfficialTurns.set(threadId2, turnId);
|
|
39713
|
-
const delegationId = hostThreadIdSchema.parse(
|
|
40179
|
+
const delegationId = hostThreadIdSchema.parse(randomUUID16());
|
|
39714
40180
|
try {
|
|
39715
40181
|
const source = await this.#repository.find(input.parentThreadId);
|
|
39716
40182
|
const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId2);
|
|
@@ -39898,7 +40364,7 @@ var AppServerHost = class {
|
|
|
39898
40364
|
async #listDelegationThreads(input) {
|
|
39899
40365
|
const [sortKey, sortDirection2] = input.sort.split("-");
|
|
39900
40366
|
const request = {
|
|
39901
|
-
id: `codexhost:delegation-list:${
|
|
40367
|
+
id: `codexhost:delegation-list:${randomUUID16()}`,
|
|
39902
40368
|
method: "thread/list",
|
|
39903
40369
|
params: {
|
|
39904
40370
|
cwd: input.cwd ? [input.cwd] : null,
|
|
@@ -40247,7 +40713,8 @@ var AppServerHost = class {
|
|
|
40247
40713
|
try {
|
|
40248
40714
|
inspection = await adapter.inspect({
|
|
40249
40715
|
...params.data.cwd ? { cwd: params.data.cwd } : {},
|
|
40250
|
-
...params.data.refresh !== void 0 ? { refresh: params.data.refresh } : {}
|
|
40716
|
+
...params.data.refresh !== void 0 ? { refresh: params.data.refresh } : {},
|
|
40717
|
+
...params.data.purpose ? { purpose: params.data.purpose } : {}
|
|
40251
40718
|
});
|
|
40252
40719
|
} catch (error51) {
|
|
40253
40720
|
await this.#writer.json(
|
|
@@ -40440,6 +40907,28 @@ var AppServerHost = class {
|
|
|
40440
40907
|
);
|
|
40441
40908
|
}
|
|
40442
40909
|
}
|
|
40910
|
+
/** Read the same delivery decision that Desktop `turn/steer` will follow. */
|
|
40911
|
+
async #inspectThreadSteering(request) {
|
|
40912
|
+
const params = threadSteeringInspectParamsSchema.safeParse(request.params);
|
|
40913
|
+
if (!params.success) {
|
|
40914
|
+
await this.#writer.json(rpcError(request, -32602, "Invalid Thread steering params"));
|
|
40915
|
+
return;
|
|
40916
|
+
}
|
|
40917
|
+
let delivery;
|
|
40918
|
+
try {
|
|
40919
|
+
const location = await this.#locateExternalThread(params.data.threadId);
|
|
40920
|
+
if (await this.#writeResolutionError(request, location)) return;
|
|
40921
|
+
const thread = location.kind === "external" ? this.#externalRuntime.get(params.data.threadId) : void 0;
|
|
40922
|
+
delivery = location.kind !== "external" ? "official" : thread ? await externalSteeringDelivery(thread, params.data.text) : "newTurn";
|
|
40923
|
+
} catch {
|
|
40924
|
+
await this.#writer.json(
|
|
40925
|
+
rpcError(request, -32081, "Thread steering metadata could not be read")
|
|
40926
|
+
);
|
|
40927
|
+
return;
|
|
40928
|
+
}
|
|
40929
|
+
const result = threadSteeringInspectResultSchema.parse({ delivery });
|
|
40930
|
+
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
|
|
40931
|
+
}
|
|
40443
40932
|
async #inspectThreadCommands(request) {
|
|
40444
40933
|
const params = threadCommandsInspectParamsSchema.safeParse(request.params);
|
|
40445
40934
|
if (!params.success) {
|
|
@@ -40603,7 +41092,7 @@ var AppServerHost = class {
|
|
|
40603
41092
|
if (thread.running || thread.activeTurnId) {
|
|
40604
41093
|
throw new ExternalCommandError(-32072, "External Thread already has an active operation");
|
|
40605
41094
|
}
|
|
40606
|
-
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(
|
|
41095
|
+
const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID16());
|
|
40607
41096
|
const projection = {
|
|
40608
41097
|
projector: new CodexTurnProjector({
|
|
40609
41098
|
threadId: thread.id,
|
|
@@ -40691,6 +41180,26 @@ var AppServerHost = class {
|
|
|
40691
41180
|
if (!projected.effectiveModel) {
|
|
40692
41181
|
throw new Error("Harness Session did not report an effective Model");
|
|
40693
41182
|
}
|
|
41183
|
+
const transportModelId = encodeExternalTransportSelection(thread.harnessId, {
|
|
41184
|
+
...decodeExternalTransportSelection(thread.harnessId, thread.transportModelId) ?? {},
|
|
41185
|
+
model: projected.effectiveModel
|
|
41186
|
+
});
|
|
41187
|
+
thread.transportModelId = transportModelId;
|
|
41188
|
+
thread.requestedModel = projected.effectiveModel;
|
|
41189
|
+
try {
|
|
41190
|
+
thread.record = await this.#repository.setTransportModelId(
|
|
41191
|
+
thread.record.hostThreadId,
|
|
41192
|
+
transportModelId
|
|
41193
|
+
);
|
|
41194
|
+
} catch (error51) {
|
|
41195
|
+
this.#diagnose(error51);
|
|
41196
|
+
}
|
|
41197
|
+
thread.thread = externalThreadValue({
|
|
41198
|
+
record: { ...thread.record, transportModelId },
|
|
41199
|
+
turns: thread.turns,
|
|
41200
|
+
sessionId: thread.sessionId,
|
|
41201
|
+
running: thread.running
|
|
41202
|
+
});
|
|
40694
41203
|
await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(projected) }));
|
|
40695
41204
|
} catch (error51) {
|
|
40696
41205
|
await this.#writer.json(
|
|
@@ -41020,9 +41529,20 @@ var AppServerHost = class {
|
|
|
41020
41529
|
await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
|
|
41021
41530
|
return true;
|
|
41022
41531
|
}
|
|
41532
|
+
/** Refresh history before Desktop acts on native Turn boundaries. */
|
|
41023
41533
|
#refreshExternalThread(thread) {
|
|
41024
41534
|
return this.#externalRuntime.refresh(thread);
|
|
41025
41535
|
}
|
|
41536
|
+
#markExternalHistoryRead(thread, turns) {
|
|
41537
|
+
if (!thread.historyHydrated) return;
|
|
41538
|
+
for (const turnId of thread.steeredTurnIds) {
|
|
41539
|
+
if (turnId !== thread.activeTurnId && turns.some(
|
|
41540
|
+
(turn) => turn.id === turnId && (turn.status === "completed" || turn.status === "failed" || turn.status === "interrupted")
|
|
41541
|
+
)) {
|
|
41542
|
+
thread.steeredTurnIds.delete(turnId);
|
|
41543
|
+
}
|
|
41544
|
+
}
|
|
41545
|
+
}
|
|
41026
41546
|
#persistTerminalIdentity(thread, event) {
|
|
41027
41547
|
return this.#externalRuntime.persistTerminalIdentity(thread, event);
|
|
41028
41548
|
}
|
|
@@ -41224,17 +41744,19 @@ var AppServerHost = class {
|
|
|
41224
41744
|
return;
|
|
41225
41745
|
}
|
|
41226
41746
|
}
|
|
41747
|
+
const readTurns = includeTurns ? [...this.#externalHistoryTurns(thread)] : [];
|
|
41227
41748
|
await this.#writer.json(
|
|
41228
41749
|
rpcEnvelope(request, {
|
|
41229
41750
|
result: {
|
|
41230
41751
|
thread: {
|
|
41231
41752
|
...thread.thread,
|
|
41232
41753
|
...await this.#externalSectionFields(thread.record.hostThreadId),
|
|
41233
|
-
turns:
|
|
41754
|
+
turns: readTurns
|
|
41234
41755
|
}
|
|
41235
41756
|
}
|
|
41236
41757
|
})
|
|
41237
41758
|
);
|
|
41759
|
+
if (includeTurns) this.#markExternalHistoryRead(thread, readTurns);
|
|
41238
41760
|
await this.#replayExternalUsage(thread);
|
|
41239
41761
|
}
|
|
41240
41762
|
async #listExternalHistory(request, thread, params, historyFresh) {
|
|
@@ -41251,6 +41773,9 @@ var AppServerHost = class {
|
|
|
41251
41773
|
const turns = this.#externalHistoryTurns(thread);
|
|
41252
41774
|
const result = request.method === "thread/turns/list" ? listExternalTurns(turns, params) : listExternalItems(turns, params);
|
|
41253
41775
|
await this.#writer.json(rpcEnvelope(request, { result }));
|
|
41776
|
+
if (request.method === "thread/turns/list") {
|
|
41777
|
+
this.#markExternalHistoryRead(thread, result.data);
|
|
41778
|
+
}
|
|
41254
41779
|
} catch (error51) {
|
|
41255
41780
|
await this.#writer.json(
|
|
41256
41781
|
rpcError(
|
|
@@ -41269,7 +41794,7 @@ var AppServerHost = class {
|
|
|
41269
41794
|
return;
|
|
41270
41795
|
}
|
|
41271
41796
|
}
|
|
41272
|
-
const turns = this.#externalHistoryTurns(thread);
|
|
41797
|
+
const turns = [...this.#externalHistoryTurns(thread)];
|
|
41273
41798
|
const responseThread = {
|
|
41274
41799
|
...await this.#withExternalSection(thread.thread),
|
|
41275
41800
|
turns: params.excludeTurns === true ? [] : turns
|
|
@@ -41301,6 +41826,8 @@ var AppServerHost = class {
|
|
|
41301
41826
|
}
|
|
41302
41827
|
})
|
|
41303
41828
|
);
|
|
41829
|
+
if (params.excludeTurns !== true) this.#markExternalHistoryRead(thread, turns);
|
|
41830
|
+
else if (initialTurnsPage) this.#markExternalHistoryRead(thread, initialTurnsPage.data);
|
|
41304
41831
|
} catch (error51) {
|
|
41305
41832
|
await this.#writer.json(
|
|
41306
41833
|
rpcError(
|
|
@@ -41443,10 +41970,15 @@ var AppServerHost = class {
|
|
|
41443
41970
|
assertActive,
|
|
41444
41971
|
typeof requestObject(request).clientUserMessageId === "string" ? requestObject(request).clientUserMessageId : void 0,
|
|
41445
41972
|
requestObject(request)[THREAD_REFERENCE_SOURCE_HOST_PARAM]
|
|
41446
|
-
)
|
|
41973
|
+
),
|
|
41974
|
+
(input) => this.#insertExternalInput(thread, input)
|
|
41447
41975
|
);
|
|
41448
41976
|
try {
|
|
41449
|
-
await this.#writer.json(
|
|
41977
|
+
await this.#writer.json(
|
|
41978
|
+
rpcEnvelope(request, {
|
|
41979
|
+
result: { turnId: started.turnId, delivery: started.delivery }
|
|
41980
|
+
})
|
|
41981
|
+
);
|
|
41450
41982
|
} finally {
|
|
41451
41983
|
started.gate.resolve();
|
|
41452
41984
|
}
|
|
@@ -41462,6 +41994,34 @@ var AppServerHost = class {
|
|
|
41462
41994
|
this.#signalActiveWorkChanged();
|
|
41463
41995
|
}
|
|
41464
41996
|
}
|
|
41997
|
+
/** Native same-Turn input; `insertNativeSteer` owns the delivery and its fallback signal. */
|
|
41998
|
+
async #insertExternalInput(thread, input) {
|
|
41999
|
+
await insertNativeSteer(thread, input, {
|
|
42000
|
+
project: async (turnId, item, clientUserMessageId) => {
|
|
42001
|
+
const projection = this.#projectedTurn(thread, turnId);
|
|
42002
|
+
if (clientUserMessageId) {
|
|
42003
|
+
projection.projector.bindUserMessageClientId(item.itemId, clientUserMessageId);
|
|
42004
|
+
}
|
|
42005
|
+
await this.#projectHarnessOutput(thread, {
|
|
42006
|
+
kind: "event",
|
|
42007
|
+
event: { type: "item.started", turnId, item }
|
|
42008
|
+
});
|
|
42009
|
+
await this.#projectHarnessOutput(thread, {
|
|
42010
|
+
kind: "event",
|
|
42011
|
+
event: {
|
|
42012
|
+
type: "item.completed",
|
|
42013
|
+
turnId,
|
|
42014
|
+
snapshot: { item, outcome: { status: "succeeded" } }
|
|
42015
|
+
}
|
|
42016
|
+
});
|
|
42017
|
+
},
|
|
42018
|
+
diagnose: (error51) => this.#diagnose(error51)
|
|
42019
|
+
});
|
|
42020
|
+
return {
|
|
42021
|
+
turnId: input.turnId,
|
|
42022
|
+
gate: { promise: Promise.resolve(), resolve: () => void 0 }
|
|
42023
|
+
};
|
|
42024
|
+
}
|
|
41465
42025
|
/** Keep command restoration and dispatch identical for start and steer submissions. */
|
|
41466
42026
|
async #beginExternalInputTurn(thread, inputText, assertActive, clientUserMessageId, sourceHostId) {
|
|
41467
42027
|
const text = restoreHarnessCommandMentions(inputText);
|
|
@@ -41519,7 +42079,7 @@ var AppServerHost = class {
|
|
|
41519
42079
|
if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
|
|
41520
42080
|
throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
|
|
41521
42081
|
}
|
|
41522
|
-
const turnId = hostTurnIdSchema.parse(
|
|
42082
|
+
const turnId = hostTurnIdSchema.parse(randomUUID16());
|
|
41523
42083
|
const startedAtMs = Date.now();
|
|
41524
42084
|
const projection = {
|
|
41525
42085
|
projector: new CodexTurnProjector({
|
|
@@ -41779,6 +42339,10 @@ var AppServerHost = class {
|
|
|
41779
42339
|
return;
|
|
41780
42340
|
}
|
|
41781
42341
|
if (event.type === "session.faulted") {
|
|
42342
|
+
for (const pending of [...this.#pendingDesktopQuestions.values()]) {
|
|
42343
|
+
if (pending.shared && pending.thread === thread)
|
|
42344
|
+
this.#retireDesktopQuestion(pending.interaction.interactionId);
|
|
42345
|
+
}
|
|
41782
42346
|
this.#externalSteering.fault(thread.id, new Error(event.error.message));
|
|
41783
42347
|
thread.stateObserver.fault(new Error(event.error.message));
|
|
41784
42348
|
this.#externalRuntime.markSessionUnavailable(thread);
|
|
@@ -41814,11 +42378,20 @@ var AppServerHost = class {
|
|
|
41814
42378
|
}
|
|
41815
42379
|
return;
|
|
41816
42380
|
}
|
|
42381
|
+
if (event.type === "turn.completed" && thread.pendingSteerProjections.size > 0) {
|
|
42382
|
+
await Promise.allSettled([...thread.pendingSteerProjections]);
|
|
42383
|
+
}
|
|
41817
42384
|
const projection = this.#projectedTurn(thread, event.turnId);
|
|
41818
42385
|
await this.#waitForTurnResponse(thread, event.turnId);
|
|
41819
42386
|
if (event.type === "interaction.closed" && thread.ignoredInteractionIds.delete(event.interactionId)) {
|
|
41820
42387
|
return;
|
|
41821
42388
|
}
|
|
42389
|
+
if (event.type === "turn.completed") {
|
|
42390
|
+
for (const pending of [...this.#pendingDesktopQuestions.values()]) {
|
|
42391
|
+
if (pending.shared && pending.thread === thread && pending.interaction.turnId === event.turnId)
|
|
42392
|
+
this.#retireDesktopQuestion(pending.interaction.interactionId);
|
|
42393
|
+
}
|
|
42394
|
+
}
|
|
41822
42395
|
if (event.type === "interaction.closed") {
|
|
41823
42396
|
await this.#resolveDesktopApproval(event.interactionId);
|
|
41824
42397
|
await this.#resolveDesktopQuestion(event.interactionId);
|
|
@@ -41863,6 +42436,7 @@ var AppServerHost = class {
|
|
|
41863
42436
|
thread.activeTurnId = null;
|
|
41864
42437
|
if (!projection.projector.hasOpenDetachedItems) thread.projectedTurns.delete(event.turnId);
|
|
41865
42438
|
thread.responseGates.delete(event.turnId);
|
|
42439
|
+
thread.pendingSteerProjections.clear();
|
|
41866
42440
|
this.#signalActiveWorkChanged();
|
|
41867
42441
|
const delegation = await this.#repository.getDelegationByChild(thread.record.hostThreadId);
|
|
41868
42442
|
if (delegation) {
|
|
@@ -42146,14 +42720,75 @@ var AppServerHost = class {
|
|
|
42146
42720
|
this.#nextApprovalRequestId -= 1;
|
|
42147
42721
|
return requestId;
|
|
42148
42722
|
}
|
|
42723
|
+
async #handleSharedQuestionRequest(request) {
|
|
42724
|
+
const responding = request.method === THREAD_QUESTION_RESPOND_METHOD;
|
|
42725
|
+
const parsed2 = (responding ? threadQuestionRespondParamsSchema : threadQuestionsListParamsSchema).safeParse(request.params);
|
|
42726
|
+
if (!parsed2.success) {
|
|
42727
|
+
await this.#writer.json(rpcError(request, -32602, "Invalid Question params"));
|
|
42728
|
+
return;
|
|
42729
|
+
}
|
|
42730
|
+
const { threadId: threadId2 } = parsed2.data;
|
|
42731
|
+
const thread = this.#externalRuntime.get(threadId2);
|
|
42732
|
+
const pendingQuestions = () => [...this.#pendingDesktopQuestions.values()].filter(
|
|
42733
|
+
(pending) => pending.shared && pending.thread === thread && pending.interaction.turnId === thread?.activeTurnId && (!Number.isFinite(Date.parse(pending.interaction.expiresAt ?? "")) || Date.parse(pending.interaction.expiresAt ?? "") > Date.now())
|
|
42734
|
+
);
|
|
42735
|
+
if (!responding) {
|
|
42736
|
+
const questions = thread && !thread.sessionUnavailable && !this.#externalRuntime.idleRelease.failure(thread) ? pendingQuestions().map((pending) => sharedQuestion(pending.interaction)) : [];
|
|
42737
|
+
await this.#writer.json(
|
|
42738
|
+
rpcEnvelope(request, { result: jsonValueSchema.parse({ questions }) })
|
|
42739
|
+
);
|
|
42740
|
+
return;
|
|
42741
|
+
}
|
|
42742
|
+
const params = threadQuestionRespondParamsSchema.parse(parsed2.data);
|
|
42743
|
+
try {
|
|
42744
|
+
await this.#externalRuntime.idleRelease.runOperation(threadId2, async () => {
|
|
42745
|
+
const pending = pendingQuestions().find(
|
|
42746
|
+
({ interaction }) => interaction.interactionId === params.interactionId && interaction.turnId === params.turnId
|
|
42747
|
+
);
|
|
42748
|
+
if (!thread || this.#externalRuntime.get(threadId2) !== thread || thread.sessionUnavailable || this.#externalRuntime.idleRelease.failure(thread) || !pending || pending.responding) {
|
|
42749
|
+
throw new Error("Question is no longer pending on this Thread and Turn");
|
|
42750
|
+
}
|
|
42751
|
+
const response = {
|
|
42752
|
+
type: "question",
|
|
42753
|
+
answers: params.answers,
|
|
42754
|
+
cancelled: params.cancelled
|
|
42755
|
+
};
|
|
42756
|
+
validateSharedQuestionResponse(pending.interaction, response);
|
|
42757
|
+
pending.responding = true;
|
|
42758
|
+
let result;
|
|
42759
|
+
try {
|
|
42760
|
+
result = await thread.session.execute({
|
|
42761
|
+
type: "interaction.respond",
|
|
42762
|
+
interactionId: pending.interaction.interactionId,
|
|
42763
|
+
response
|
|
42764
|
+
});
|
|
42765
|
+
} catch (error51) {
|
|
42766
|
+
this.#retireDesktopQuestion(pending.interaction.interactionId);
|
|
42767
|
+
throw error51;
|
|
42768
|
+
}
|
|
42769
|
+
if (!result.ok) {
|
|
42770
|
+
pending.responding = false;
|
|
42771
|
+
if (result.error.code === "invalidState")
|
|
42772
|
+
this.#retireDesktopQuestion(pending.interaction.interactionId);
|
|
42773
|
+
throw new Error(result.error.message);
|
|
42774
|
+
}
|
|
42775
|
+
this.#retireDesktopQuestion(pending.interaction.interactionId);
|
|
42776
|
+
await this.#writer.json(rpcEnvelope(request, { result: { accepted: true } }));
|
|
42777
|
+
});
|
|
42778
|
+
} catch (error51) {
|
|
42779
|
+
await this.#writer.json(rpcError(request, -32602, errorMessage4(error51)));
|
|
42780
|
+
}
|
|
42781
|
+
}
|
|
42149
42782
|
async #projectQuestion(thread, interaction) {
|
|
42150
42783
|
const projection = this.#projectedTurn(thread, interaction.turnId);
|
|
42151
42784
|
await this.#waitForTurnResponse(thread, interaction.turnId);
|
|
42152
42785
|
let result;
|
|
42786
|
+
const shared = usesSharedQuestionCard(interaction);
|
|
42153
42787
|
try {
|
|
42788
|
+
if (shared) sharedQuestion(interaction);
|
|
42154
42789
|
result = projection.projector.projectQuestion(
|
|
42155
42790
|
interaction,
|
|
42156
|
-
hostItemIdSchema.parse(
|
|
42791
|
+
hostItemIdSchema.parse(randomUUID16())
|
|
42157
42792
|
);
|
|
42158
42793
|
} catch (error51) {
|
|
42159
42794
|
this.#diagnose(error51);
|
|
@@ -42174,6 +42809,8 @@ var AppServerHost = class {
|
|
|
42174
42809
|
const expiresAtMs = interaction.expiresAt ? Date.parse(interaction.expiresAt) : Number.NaN;
|
|
42175
42810
|
const timeoutMs = Number.isFinite(expiresAtMs) ? Math.max(0, expiresAtMs - Date.now()) : null;
|
|
42176
42811
|
const pending = {
|
|
42812
|
+
shared,
|
|
42813
|
+
responding: false,
|
|
42177
42814
|
thread,
|
|
42178
42815
|
interaction,
|
|
42179
42816
|
projection: result.questionRequest,
|
|
@@ -42185,6 +42822,7 @@ var AppServerHost = class {
|
|
|
42185
42822
|
}, timeoutMs);
|
|
42186
42823
|
}
|
|
42187
42824
|
this.#pendingDesktopQuestions.set(requestId, pending);
|
|
42825
|
+
if (shared) return;
|
|
42188
42826
|
try {
|
|
42189
42827
|
await this.#writer.json({ id: requestId, ...result.questionRequest.request });
|
|
42190
42828
|
} catch (error51) {
|
|
@@ -42201,7 +42839,7 @@ var AppServerHost = class {
|
|
|
42201
42839
|
if (!isRecord18(value2) || !isHostQuestionRequestId(value2.id)) return false;
|
|
42202
42840
|
const requestId = value2.id;
|
|
42203
42841
|
const pending = this.#pendingDesktopQuestions.get(requestId);
|
|
42204
|
-
if (!pending) return true;
|
|
42842
|
+
if (!pending || pending.shared) return true;
|
|
42205
42843
|
return this.#externalRuntime.idleRelease.runOperation(pending.thread.id, async () => {
|
|
42206
42844
|
if (this.#externalRuntime.get(pending.thread.id) !== pending.thread || this.#externalRuntime.idleRelease.failure(pending.thread))
|
|
42207
42845
|
return true;
|
|
@@ -42234,6 +42872,7 @@ var AppServerHost = class {
|
|
|
42234
42872
|
if (this.#externalRuntime.get(pending.thread.id) !== pending.thread || this.#externalRuntime.idleRelease.failure(pending.thread))
|
|
42235
42873
|
return;
|
|
42236
42874
|
await this.#resolveDesktopQuestion(pending.interaction.interactionId);
|
|
42875
|
+
if (pending.responding) return;
|
|
42237
42876
|
const result = await pending.thread.session.execute({
|
|
42238
42877
|
type: "interaction.respond",
|
|
42239
42878
|
interactionId: pending.interaction.interactionId,
|
|
@@ -42256,6 +42895,7 @@ var AppServerHost = class {
|
|
|
42256
42895
|
if (pending.interaction.interactionId !== interactionId) continue;
|
|
42257
42896
|
if (pending.timeout) clearTimeout(pending.timeout);
|
|
42258
42897
|
this.#pendingDesktopQuestions.delete(requestId);
|
|
42898
|
+
if (pending.shared) continue;
|
|
42259
42899
|
await this.#writer.json({
|
|
42260
42900
|
method: "serverRequest/resolved",
|
|
42261
42901
|
params: { threadId: pending.thread.id, requestId }
|
|
@@ -42392,7 +43032,7 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
|
42392
43032
|
var wrapper_default = import_websocket.default;
|
|
42393
43033
|
|
|
42394
43034
|
// packages/host-runtime/src/remote-socket-lock.ts
|
|
42395
|
-
import { randomUUID as
|
|
43035
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
42396
43036
|
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
43037
|
import { uptime } from "node:os";
|
|
42398
43038
|
import path26 from "node:path";
|
|
@@ -42518,7 +43158,7 @@ async function preparePrivateLockDirectory(lockDirectory) {
|
|
|
42518
43158
|
await chmod3(lockDirectory, 448);
|
|
42519
43159
|
}
|
|
42520
43160
|
async function writeLockRecordAtomic(lockDirectory, entryPath, record4) {
|
|
42521
|
-
const temporary = path26.join(lockDirectory, `.tmp-${record4.ownerToken}-${
|
|
43161
|
+
const temporary = path26.join(lockDirectory, `.tmp-${record4.ownerToken}-${randomUUID17()}`);
|
|
42522
43162
|
const handle = await open9(temporary, "wx", 384);
|
|
42523
43163
|
try {
|
|
42524
43164
|
await handle.writeFile(`${JSON.stringify(record4)}
|
|
@@ -42593,7 +43233,7 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
|
|
|
42593
43233
|
const legacyPath = `${socketPath}.initializing`;
|
|
42594
43234
|
const lockDirectory = `${socketPath}.initializers`;
|
|
42595
43235
|
await preparePrivateLockDirectory(lockDirectory);
|
|
42596
|
-
const ownerToken =
|
|
43236
|
+
const ownerToken = randomUUID17();
|
|
42597
43237
|
const entryPath = path26.join(lockDirectory, lockEntryName(ownerToken));
|
|
42598
43238
|
const baseRecord = {
|
|
42599
43239
|
version: 2,
|
|
@@ -43104,12 +43744,12 @@ function createRemoteAppServerWebSocketListener(input) {
|
|
|
43104
43744
|
|
|
43105
43745
|
// packages/host-runtime/src/remote-official-app-server.ts
|
|
43106
43746
|
import { spawn as spawn5 } from "node:child_process";
|
|
43107
|
-
import { randomUUID as
|
|
43747
|
+
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
43108
43748
|
import { lstat as lstat7, rm as rm13, stat as stat7 } from "node:fs/promises";
|
|
43109
43749
|
import path28 from "node:path";
|
|
43110
43750
|
var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
|
|
43111
43751
|
var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
|
|
43112
|
-
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token =
|
|
43752
|
+
function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID18()) {
|
|
43113
43753
|
if (!path28.posix.isAbsolute(desktopControlSocketPath)) {
|
|
43114
43754
|
throw new Error("Desktop control socket path must be absolute");
|
|
43115
43755
|
}
|
|
@@ -44035,10 +44675,10 @@ var DelegationControlRegistry = class {
|
|
|
44035
44675
|
);
|
|
44036
44676
|
}
|
|
44037
44677
|
#compareThreads(left, right, sort) {
|
|
44038
|
-
const
|
|
44678
|
+
const field2 = sort.startsWith("created") ? "createdAt" : "updatedAt";
|
|
44039
44679
|
const direction = sort.endsWith("asc") ? 1 : -1;
|
|
44040
|
-
const leftValue = left[
|
|
44041
|
-
const rightValue = right[
|
|
44680
|
+
const leftValue = left[field2] ? Date.parse(left[field2]) : 0;
|
|
44681
|
+
const rightValue = right[field2] ? Date.parse(right[field2]) : 0;
|
|
44042
44682
|
return (leftValue - rightValue) * direction || left.threadId.localeCompare(right.threadId);
|
|
44043
44683
|
}
|
|
44044
44684
|
async #matching(predicate) {
|
|
@@ -44328,11 +44968,11 @@ async function readRemoteDelegationThread(environment, input) {
|
|
|
44328
44968
|
}
|
|
44329
44969
|
|
|
44330
44970
|
// packages/host-runtime/src/shared-thread-owner.ts
|
|
44331
|
-
import { randomUUID as
|
|
44971
|
+
import { randomUUID as randomUUID20 } from "node:crypto";
|
|
44332
44972
|
import { PassThrough as PassThrough3 } from "node:stream";
|
|
44333
44973
|
|
|
44334
44974
|
// packages/host-runtime/src/shared-thread-peer.ts
|
|
44335
|
-
import { randomUUID as
|
|
44975
|
+
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
44336
44976
|
function object5(value2) {
|
|
44337
44977
|
return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
|
|
44338
44978
|
}
|
|
@@ -44346,7 +44986,7 @@ var StreamThreadPeer = class {
|
|
|
44346
44986
|
input;
|
|
44347
44987
|
output;
|
|
44348
44988
|
stop;
|
|
44349
|
-
#prefix = `shared:${
|
|
44989
|
+
#prefix = `shared:${randomUUID19()}:`;
|
|
44350
44990
|
#pending = /* @__PURE__ */ new Map();
|
|
44351
44991
|
#listeners = /* @__PURE__ */ new Set();
|
|
44352
44992
|
#ended = Promise.withResolvers();
|
|
@@ -44424,7 +45064,7 @@ var SharedThreadOwner = class {
|
|
|
44424
45064
|
input = new PassThrough3();
|
|
44425
45065
|
output = new PassThrough3();
|
|
44426
45066
|
#peer = new StreamThreadPeer(this.output, this.input, () => this.input.end());
|
|
44427
|
-
#prefix = `shared-interaction:${
|
|
45067
|
+
#prefix = `shared-interaction:${randomUUID20()}:`;
|
|
44428
45068
|
#interactions = /* @__PURE__ */ new Map();
|
|
44429
45069
|
#listeners = /* @__PURE__ */ new Set();
|
|
44430
45070
|
#receipts = /* @__PURE__ */ new Map();
|
|
@@ -44734,7 +45374,7 @@ var SharedThreadBridge = class {
|
|
|
44734
45374
|
};
|
|
44735
45375
|
|
|
44736
45376
|
// packages/host-runtime/src/remote-control-app-server.ts
|
|
44737
|
-
import { randomUUID as
|
|
45377
|
+
import { randomUUID as randomUUID21 } from "node:crypto";
|
|
44738
45378
|
import { mkdir as mkdir15, open as open10, rename as rename12, rm as rm14 } from "node:fs/promises";
|
|
44739
45379
|
import path33 from "node:path";
|
|
44740
45380
|
var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
|
|
@@ -44755,7 +45395,7 @@ function nodeCompatibleWindowsPath(value2) {
|
|
|
44755
45395
|
if (value2.startsWith("\\\\?\\")) return value2.slice(4);
|
|
44756
45396
|
return value2;
|
|
44757
45397
|
}
|
|
44758
|
-
function remoteControlBridgePipePath(processId = process.pid, instanceId =
|
|
45398
|
+
function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID21()) {
|
|
44759
45399
|
const safeInstance = instanceId.replaceAll(/[^a-zA-Z0-9-]/gu, "");
|
|
44760
45400
|
if (!safeInstance) throw new Error("Remote Control bridge instance ID is invalid");
|
|
44761
45401
|
return `\\\\.\\pipe\\codexhost-remote-control-${processId}-${safeInstance}`;
|
|
@@ -44770,7 +45410,7 @@ async function publishRemoteControlAppServerDescriptor(plan) {
|
|
|
44770
45410
|
await mkdir15(directory, { recursive: true, mode: 448 });
|
|
44771
45411
|
const temporaryPath = path33.join(
|
|
44772
45412
|
directory,
|
|
44773
|
-
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${
|
|
45413
|
+
`.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID21()}.tmp`
|
|
44774
45414
|
);
|
|
44775
45415
|
const handle = await open10(temporaryPath, "wx", 384);
|
|
44776
45416
|
try {
|
|
@@ -45292,12 +45932,19 @@ function createHostUpdateCoordinator(options2) {
|
|
|
45292
45932
|
}
|
|
45293
45933
|
|
|
45294
45934
|
// packages/host-runtime/src/usage-statistics.ts
|
|
45295
|
-
import { randomUUID as
|
|
45935
|
+
import { randomUUID as randomUUID22 } from "node:crypto";
|
|
45296
45936
|
import { mkdir as mkdir17, readFile as readFile17, readdir as readdir6, rename as rename14, rm as rm16, writeFile as writeFile10 } from "node:fs/promises";
|
|
45297
45937
|
import path36 from "node:path";
|
|
45298
45938
|
import { setImmediate as yieldToEventLoop } from "node:timers/promises";
|
|
45299
45939
|
|
|
45300
45940
|
// packages/harness-adapter/dist/usage-statistics.js
|
|
45941
|
+
var HarnessUsageSourceChangedError = class extends Error {
|
|
45942
|
+
code = "HARNESS_USAGE_SOURCE_CHANGED";
|
|
45943
|
+
/** Plugins may bundle their own copy of this contract, so instanceof is insufficient. */
|
|
45944
|
+
static is(error51) {
|
|
45945
|
+
return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "HARNESS_USAGE_SOURCE_CHANGED";
|
|
45946
|
+
}
|
|
45947
|
+
};
|
|
45301
45948
|
var MAX_SESSION_ID_LENGTH = 512;
|
|
45302
45949
|
var MAX_CWD_LENGTH = 4096;
|
|
45303
45950
|
var MAX_SESSION_TITLE_LENGTH = 200;
|
|
@@ -45309,10 +45956,13 @@ function usageSessionTitle(value2) {
|
|
|
45309
45956
|
return void 0;
|
|
45310
45957
|
if (normalized.length <= MAX_SESSION_TITLE_LENGTH)
|
|
45311
45958
|
return normalized;
|
|
45312
|
-
|
|
45313
|
-
|
|
45314
|
-
|
|
45315
|
-
|
|
45959
|
+
let title = "";
|
|
45960
|
+
for (const character of normalized) {
|
|
45961
|
+
if (title.length + character.length >= MAX_SESSION_TITLE_LENGTH)
|
|
45962
|
+
break;
|
|
45963
|
+
title += character;
|
|
45964
|
+
}
|
|
45965
|
+
return `${title.trimEnd()}…`;
|
|
45316
45966
|
}
|
|
45317
45967
|
function sessionIdOk(value2) {
|
|
45318
45968
|
return typeof value2 === "string" && value2.length > 0 && value2.length <= MAX_SESSION_ID_LENGTH;
|
|
@@ -45336,13 +45986,13 @@ function parseHarnessUsageEntry(value2) {
|
|
|
45336
45986
|
}
|
|
45337
45987
|
if (!tokenCount(entry.inputTokens) || !tokenCount(entry.outputTokens))
|
|
45338
45988
|
return null;
|
|
45339
|
-
for (const
|
|
45989
|
+
for (const field2 of [
|
|
45340
45990
|
"cachedInputTokens",
|
|
45341
45991
|
"cacheWriteInputTokens",
|
|
45342
45992
|
"cacheWrite1hInputTokens",
|
|
45343
45993
|
"reasoningOutputTokens"
|
|
45344
45994
|
]) {
|
|
45345
|
-
if (entry[
|
|
45995
|
+
if (entry[field2] !== void 0 && !tokenCount(entry[field2]))
|
|
45346
45996
|
return null;
|
|
45347
45997
|
}
|
|
45348
45998
|
const cached2 = entry.cachedInputTokens ?? 0;
|
|
@@ -45397,6 +46047,95 @@ function withHostSessionTitles(result, records) {
|
|
|
45397
46047
|
};
|
|
45398
46048
|
}
|
|
45399
46049
|
|
|
46050
|
+
// packages/host-runtime/src/usage-statistics-sources.ts
|
|
46051
|
+
import { setTimeout as delay6 } from "node:timers/promises";
|
|
46052
|
+
async function* readUsageStatisticsSources(capability, sources, signal) {
|
|
46053
|
+
let pending = sources;
|
|
46054
|
+
for (let attempt = 0; ; attempt++) {
|
|
46055
|
+
const changed = [];
|
|
46056
|
+
for (const source of pending) {
|
|
46057
|
+
signal.throwIfAborted();
|
|
46058
|
+
try {
|
|
46059
|
+
const entries = (await capability.readSource(source.id, signal)).map(parseHarnessUsageEntry).filter((entry) => entry !== null);
|
|
46060
|
+
yield { source, entries };
|
|
46061
|
+
} catch (error51) {
|
|
46062
|
+
signal.throwIfAborted();
|
|
46063
|
+
if (HarnessUsageSourceChangedError.is(error51) && attempt < 2) changed.push(source);
|
|
46064
|
+
else yield { source, error: error51 };
|
|
46065
|
+
}
|
|
46066
|
+
}
|
|
46067
|
+
if (!changed.length) return;
|
|
46068
|
+
await delay6(50 * (attempt + 1), void 0, { signal });
|
|
46069
|
+
let current;
|
|
46070
|
+
try {
|
|
46071
|
+
current = new Map(
|
|
46072
|
+
(await capability.listSources(signal)).map((source) => [source.id, source])
|
|
46073
|
+
);
|
|
46074
|
+
} catch (error51) {
|
|
46075
|
+
signal.throwIfAborted();
|
|
46076
|
+
for (const source of changed) yield { source, error: error51 };
|
|
46077
|
+
return;
|
|
46078
|
+
}
|
|
46079
|
+
const next = [];
|
|
46080
|
+
for (const source of changed) {
|
|
46081
|
+
const fresh = current.get(source.id);
|
|
46082
|
+
if (fresh) next.push(fresh);
|
|
46083
|
+
else yield { source, removed: true };
|
|
46084
|
+
}
|
|
46085
|
+
pending = next;
|
|
46086
|
+
}
|
|
46087
|
+
}
|
|
46088
|
+
|
|
46089
|
+
// packages/host-runtime/src/usage-statistics-calendar.ts
|
|
46090
|
+
function dateKey(year, month, day) {
|
|
46091
|
+
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
46092
|
+
}
|
|
46093
|
+
function createUsageStatisticsCalendar(timeZone) {
|
|
46094
|
+
const localZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
46095
|
+
const zone = timeZone ?? localZone;
|
|
46096
|
+
if (zone === localZone) {
|
|
46097
|
+
return {
|
|
46098
|
+
timeZone: zone,
|
|
46099
|
+
at(ms) {
|
|
46100
|
+
const date5 = new Date(ms);
|
|
46101
|
+
return {
|
|
46102
|
+
date: dateKey(date5.getFullYear(), date5.getMonth() + 1, date5.getDate()),
|
|
46103
|
+
weekday: date5.getDay(),
|
|
46104
|
+
hour: date5.getHours()
|
|
46105
|
+
};
|
|
46106
|
+
}
|
|
46107
|
+
};
|
|
46108
|
+
}
|
|
46109
|
+
const format = new Intl.DateTimeFormat("en-US", {
|
|
46110
|
+
timeZone: zone,
|
|
46111
|
+
calendar: "gregory",
|
|
46112
|
+
numberingSystem: "latn",
|
|
46113
|
+
year: "numeric",
|
|
46114
|
+
month: "2-digit",
|
|
46115
|
+
day: "2-digit",
|
|
46116
|
+
hour: "2-digit",
|
|
46117
|
+
hourCycle: "h23"
|
|
46118
|
+
});
|
|
46119
|
+
return {
|
|
46120
|
+
timeZone: zone,
|
|
46121
|
+
at(ms) {
|
|
46122
|
+
const parts = format.formatToParts(ms);
|
|
46123
|
+
const part = (type) => Number(parts.find((value2) => value2.type === type)?.value);
|
|
46124
|
+
const year = part("year"), month = part("month"), day = part("day");
|
|
46125
|
+
return {
|
|
46126
|
+
date: dateKey(year, month, day),
|
|
46127
|
+
weekday: new Date(Date.UTC(year, month - 1, day)).getUTCDay(),
|
|
46128
|
+
hour: part("hour")
|
|
46129
|
+
};
|
|
46130
|
+
}
|
|
46131
|
+
};
|
|
46132
|
+
}
|
|
46133
|
+
function shiftUsageDate(date5, days) {
|
|
46134
|
+
const value2 = /* @__PURE__ */ new Date(`${date5}T12:00:00Z`);
|
|
46135
|
+
value2.setUTCDate(value2.getUTCDate() + days);
|
|
46136
|
+
return dateKey(value2.getUTCFullYear(), value2.getUTCMonth() + 1, value2.getUTCDate());
|
|
46137
|
+
}
|
|
46138
|
+
|
|
45400
46139
|
// packages/host-runtime/src/usage-statistics.ts
|
|
45401
46140
|
var CACHE_VERSION = 7;
|
|
45402
46141
|
var STALE_AFTER_MS = 1e4;
|
|
@@ -45457,17 +46196,6 @@ function expand(value2, intern) {
|
|
|
45457
46196
|
function message(error51) {
|
|
45458
46197
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
45459
46198
|
}
|
|
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
46199
|
var SESSIONS_PER_MEASURE = 50;
|
|
45472
46200
|
var MODELS_PER_SESSION = 16;
|
|
45473
46201
|
function emptyTotals() {
|
|
@@ -45654,23 +46382,27 @@ var UsageStatistics = class {
|
|
|
45654
46382
|
}
|
|
45655
46383
|
for (const { harness: harness2, capability, ids } of listed) {
|
|
45656
46384
|
const cache = this.#cache(harness2);
|
|
45657
|
-
const present =
|
|
46385
|
+
const present = new Set(ids.map(({ id: id2 }) => id2));
|
|
45658
46386
|
let failed = null;
|
|
45659
|
-
|
|
45660
|
-
|
|
45661
|
-
|
|
45662
|
-
|
|
45663
|
-
|
|
45664
|
-
|
|
46387
|
+
const pending = ids.filter(
|
|
46388
|
+
({ id: id2, fingerprint }) => cache.sources.get(id2)?.fingerprint !== fingerprint
|
|
46389
|
+
);
|
|
46390
|
+
this.#progress.read += ids.length - pending.length;
|
|
46391
|
+
try {
|
|
46392
|
+
for await (const result of readUsageStatisticsSources(capability, pending, signal)) {
|
|
46393
|
+
const { id: id2, fingerprint } = result.source;
|
|
46394
|
+
if ("entries" in result) {
|
|
46395
|
+
cache.sources.set(id2, { fingerprint, entries: result.entries });
|
|
45665
46396
|
cache.dirty = true;
|
|
45666
46397
|
this.#generation += 1;
|
|
45667
|
-
}
|
|
45668
|
-
|
|
45669
|
-
|
|
45670
|
-
}
|
|
46398
|
+
} else if ("error" in result) failed ??= message(result.error);
|
|
46399
|
+
else present.delete(id2);
|
|
46400
|
+
this.#progress.read += 1;
|
|
45671
46401
|
await yieldToEventLoop();
|
|
45672
46402
|
}
|
|
45673
|
-
|
|
46403
|
+
} catch (error51) {
|
|
46404
|
+
if (signal.aborted) return;
|
|
46405
|
+
throw error51;
|
|
45674
46406
|
}
|
|
45675
46407
|
for (const id2 of cache.sources.keys()) {
|
|
45676
46408
|
if (!present.has(id2)) {
|
|
@@ -45735,7 +46467,7 @@ var UsageStatistics = class {
|
|
|
45735
46467
|
async #persist(harness2, cache) {
|
|
45736
46468
|
if (!cache.dirty || this.#now() - cache.persistedAtMs < PERSIST_INTERVAL_MS) return;
|
|
45737
46469
|
const file2 = this.#file(harness2);
|
|
45738
|
-
const temporary = `${file2}.${
|
|
46470
|
+
const temporary = `${file2}.${randomUUID22()}.tmp`;
|
|
45739
46471
|
try {
|
|
45740
46472
|
await mkdir17(this.#directory, { recursive: true });
|
|
45741
46473
|
const sources = [...cache.sources].map(([id2, source]) => [
|
|
@@ -45753,9 +46485,10 @@ var UsageStatistics = class {
|
|
|
45753
46485
|
await rm16(temporary, { force: true });
|
|
45754
46486
|
}
|
|
45755
46487
|
}
|
|
45756
|
-
/** Every request once, per Harness in source order,
|
|
45757
|
-
#indexed() {
|
|
45758
|
-
if (this.#index?.generation === this.#generation
|
|
46488
|
+
/** Every request once, per Harness in source order, in the requested calendar. */
|
|
46489
|
+
#indexed(calendar) {
|
|
46490
|
+
if (this.#index?.generation === this.#generation && this.#index.timeZone === calendar.timeZone)
|
|
46491
|
+
return this.#index.entries;
|
|
45759
46492
|
const entries = [];
|
|
45760
46493
|
for (const [harness2, cache] of this.#caches) {
|
|
45761
46494
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -45763,26 +46496,20 @@ var UsageStatistics = class {
|
|
|
45763
46496
|
for (const entry of parsed2) {
|
|
45764
46497
|
if (seen.has(entry.id)) continue;
|
|
45765
46498
|
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
|
-
});
|
|
46499
|
+
entries.push({ harness: harness2, entry, ...calendar.at(entry.occurredAtMs) });
|
|
45774
46500
|
}
|
|
45775
46501
|
}
|
|
45776
46502
|
}
|
|
45777
|
-
this.#index = { generation: this.#generation, entries };
|
|
46503
|
+
this.#index = { generation: this.#generation, timeZone: calendar.timeZone, entries };
|
|
45778
46504
|
return entries;
|
|
45779
46505
|
}
|
|
45780
46506
|
#aggregate(params, now, lookup) {
|
|
45781
46507
|
const { range } = params;
|
|
45782
46508
|
const days = RANGE_DAYS[range];
|
|
45783
|
-
const
|
|
46509
|
+
const calendar = createUsageStatisticsCalendar(params.timeZone);
|
|
46510
|
+
const to = calendar.at(now).date;
|
|
45784
46511
|
let from = null;
|
|
45785
|
-
if (days !== null) from =
|
|
46512
|
+
if (days !== null) from = shiftUsageDate(to, -days + 1);
|
|
45786
46513
|
const inRange = (date5) => (from === null || date5 >= from) && date5 <= to;
|
|
45787
46514
|
const day = params.date !== void 0 && inRange(params.date) ? params.date : null;
|
|
45788
46515
|
const harnessFilter = params.harness ?? null;
|
|
@@ -45823,7 +46550,7 @@ var UsageStatistics = class {
|
|
|
45823
46550
|
const harnessPriced = /* @__PURE__ */ new Map();
|
|
45824
46551
|
const byProject = /* @__PURE__ */ new Map();
|
|
45825
46552
|
const sessions = /* @__PURE__ */ new Map();
|
|
45826
|
-
for (const indexed of this.#indexed()) {
|
|
46553
|
+
for (const indexed of this.#indexed(calendar)) {
|
|
45827
46554
|
const { harness: harness2, entry, date: date5 } = indexed;
|
|
45828
46555
|
if (!inRange(date5)) continue;
|
|
45829
46556
|
const model2 = entry.model ?? null;
|
|
@@ -46351,7 +47078,7 @@ async function runHostRuntime(input) {
|
|
|
46351
47078
|
}
|
|
46352
47079
|
|
|
46353
47080
|
// packages/host-runtime/src/remote-host-install.ts
|
|
46354
|
-
import { createHash as createHash11, randomUUID as
|
|
47081
|
+
import { createHash as createHash11, randomUUID as randomUUID23 } from "node:crypto";
|
|
46355
47082
|
import { constants as fsConstants } from "node:fs";
|
|
46356
47083
|
import {
|
|
46357
47084
|
access as access3,
|
|
@@ -46450,7 +47177,7 @@ async function writeAtomic(filePath, contents, mode) {
|
|
|
46450
47177
|
await mkdir18(path38.dirname(filePath), { recursive: true, mode: 448 });
|
|
46451
47178
|
const temporary = path38.join(
|
|
46452
47179
|
path38.dirname(filePath),
|
|
46453
|
-
`.${path38.basename(filePath)}.${process.pid}.${
|
|
47180
|
+
`.${path38.basename(filePath)}.${process.pid}.${randomUUID23()}.tmp`
|
|
46454
47181
|
);
|
|
46455
47182
|
try {
|
|
46456
47183
|
if (typeof contents === "string") {
|
|
@@ -46474,7 +47201,7 @@ async function writeAtomicExecutable(filePath, sourcePath) {
|
|
|
46474
47201
|
await mkdir18(path38.dirname(filePath), { recursive: true, mode: 448 });
|
|
46475
47202
|
const temporary = path38.join(
|
|
46476
47203
|
path38.dirname(filePath),
|
|
46477
|
-
`.${path38.basename(filePath)}.${process.pid}.${
|
|
47204
|
+
`.${path38.basename(filePath)}.${process.pid}.${randomUUID23()}.tmp`
|
|
46478
47205
|
);
|
|
46479
47206
|
try {
|
|
46480
47207
|
await copyFile4(sourcePath, temporary);
|
|
@@ -47206,6 +47933,7 @@ async function runRemoteHostCli(input) {
|
|
|
47206
47933
|
var HARNESS_BROKER_PROTOCOL_VERSION = 1;
|
|
47207
47934
|
var HARNESS_BROKER_MAX_FRAME_BYTES = 8 * 1024 * 1024;
|
|
47208
47935
|
var HARNESS_BROKER_MAX_PENDING_REQUESTS = 32;
|
|
47936
|
+
var HARNESS_BROKER_SESSION_IMPORT_PAGE_SIZE = 100;
|
|
47209
47937
|
var HARNESS_BROKER_IDLE_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
47210
47938
|
var HARNESS_BROKER_RETIRING_ERROR_CODE = "brokerRetiring";
|
|
47211
47939
|
var harnessBrokerMethodSchema = external_exports.enum([
|
|
@@ -47213,8 +47941,11 @@ var harnessBrokerMethodSchema = external_exports.enum([
|
|
|
47213
47941
|
"adapter.inspectAccount",
|
|
47214
47942
|
"adapter.credits",
|
|
47215
47943
|
"adapter.open",
|
|
47944
|
+
"adapter.sessionImport.list",
|
|
47945
|
+
"adapter.sessionImport.resolve",
|
|
47216
47946
|
"adapter.subagent.readSnapshot",
|
|
47217
47947
|
"session.readSnapshot",
|
|
47948
|
+
"session.readCapabilities",
|
|
47218
47949
|
"session.refreshUsage",
|
|
47219
47950
|
"session.execute",
|
|
47220
47951
|
"session.commands.list",
|
|
@@ -47317,29 +48048,6 @@ function consumeBrokerFrames(socket, onFrame, onError) {
|
|
|
47317
48048
|
});
|
|
47318
48049
|
}
|
|
47319
48050
|
|
|
47320
|
-
// packages/harness-broker/dist/paths.js
|
|
47321
|
-
import os11 from "node:os";
|
|
47322
|
-
import path40 from "node:path";
|
|
47323
|
-
var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
|
|
47324
|
-
var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
|
|
47325
|
-
var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
|
|
47326
|
-
function defaultHarnessBrokerDirectory(environment = process.env) {
|
|
47327
|
-
const home = environment.HOME || os11.homedir();
|
|
47328
|
-
return path40.join(home, ".codexhost", "harness-broker");
|
|
47329
|
-
}
|
|
47330
|
-
function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
|
|
47331
|
-
harnessPluginIdSchema.parse(harnessId);
|
|
47332
|
-
if (harnessId !== "claude-code")
|
|
47333
|
-
return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
|
|
47334
|
-
return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
|
|
47335
|
-
}
|
|
47336
|
-
function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
|
|
47337
|
-
harnessPluginIdSchema.parse(harnessId);
|
|
47338
|
-
if (harnessId !== "claude-code")
|
|
47339
|
-
return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
|
|
47340
|
-
return path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
|
|
47341
|
-
}
|
|
47342
|
-
|
|
47343
48051
|
// packages/harness-broker/dist/validation.js
|
|
47344
48052
|
var cwdSchema = external_exports.string().min(1).max(16384);
|
|
47345
48053
|
var brokerEnvironmentSchema = external_exports.object({
|
|
@@ -47390,13 +48098,42 @@ var brokerOpenInputSchema = external_exports.discriminatedUnion("kind", [
|
|
|
47390
48098
|
forkSchema,
|
|
47391
48099
|
rollbackSchema
|
|
47392
48100
|
]);
|
|
47393
|
-
var brokerInspectInputSchema = external_exports.object({
|
|
48101
|
+
var brokerInspectInputSchema = external_exports.object({
|
|
48102
|
+
cwd: cwdSchema.optional(),
|
|
48103
|
+
refresh: external_exports.boolean().optional(),
|
|
48104
|
+
purpose: external_exports.literal("availability").optional()
|
|
48105
|
+
}).strict();
|
|
48106
|
+
var brokerSessionImportListParamsSchema = external_exports.object({
|
|
48107
|
+
offset: external_exports.number().int().nonnegative().safe(),
|
|
48108
|
+
limit: external_exports.number().int().min(1).max(HARNESS_BROKER_SESSION_IMPORT_PAGE_SIZE)
|
|
48109
|
+
}).strict();
|
|
48110
|
+
var brokerSessionImportResolveParamsSchema = external_exports.object({ nativeSessionId: harnessSessionImportIdSchema }).strict();
|
|
48111
|
+
var brokerSessionImportPageSchema = external_exports.object({
|
|
48112
|
+
candidates: external_exports.array(harnessSessionImportCandidateSchema).max(HARNESS_BROKER_SESSION_IMPORT_PAGE_SIZE),
|
|
48113
|
+
total: external_exports.number().int().nonnegative().safe()
|
|
48114
|
+
}).strict();
|
|
48115
|
+
var brokerSessionImportSourceSchema = external_exports.object({
|
|
48116
|
+
candidate: harnessSessionImportCandidateSchema,
|
|
48117
|
+
nativeRef: nativeSessionRefSchema
|
|
48118
|
+
}).strict().superRefine((source, context) => {
|
|
48119
|
+
if (source.nativeRef.nativeSessionId !== source.candidate.nativeSessionId) {
|
|
48120
|
+
context.addIssue({
|
|
48121
|
+
code: "custom",
|
|
48122
|
+
message: "Session import source identity does not match"
|
|
48123
|
+
});
|
|
48124
|
+
}
|
|
48125
|
+
});
|
|
47394
48126
|
var textInputSchema = external_exports.object({ type: external_exports.literal("text"), text: external_exports.string().max(4e6) }).strict();
|
|
47395
48127
|
var turnStartSchema = external_exports.object({
|
|
47396
48128
|
type: external_exports.literal("turn.start"),
|
|
47397
48129
|
turnId: hostTurnIdSchema,
|
|
47398
48130
|
input: external_exports.array(textInputSchema)
|
|
47399
48131
|
}).strict();
|
|
48132
|
+
var turnSteerSchema = external_exports.object({
|
|
48133
|
+
type: external_exports.literal("turn.steer"),
|
|
48134
|
+
turnId: hostTurnIdSchema,
|
|
48135
|
+
input: external_exports.array(textInputSchema)
|
|
48136
|
+
}).strict();
|
|
47400
48137
|
var turnCancelSchema = external_exports.object({ type: external_exports.literal("turn.cancel"), turnId: hostTurnIdSchema }).strict();
|
|
47401
48138
|
var interactionResponseSchema = external_exports.union([
|
|
47402
48139
|
external_exports.object({
|
|
@@ -47422,6 +48159,7 @@ var permissionSelectSchema = external_exports.object({
|
|
|
47422
48159
|
}).strict();
|
|
47423
48160
|
var brokerHostCommandSchema = external_exports.discriminatedUnion("type", [
|
|
47424
48161
|
turnStartSchema,
|
|
48162
|
+
turnSteerSchema,
|
|
47425
48163
|
turnCancelSchema,
|
|
47426
48164
|
interactionRespondSchema,
|
|
47427
48165
|
modelSelectSchema,
|
|
@@ -47555,8 +48293,31 @@ var harnessOutputSchema = external_exports.custom((value2) => {
|
|
|
47555
48293
|
return false;
|
|
47556
48294
|
});
|
|
47557
48295
|
|
|
48296
|
+
// packages/harness-broker/dist/paths.js
|
|
48297
|
+
import os11 from "node:os";
|
|
48298
|
+
import path40 from "node:path";
|
|
48299
|
+
var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
|
|
48300
|
+
var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
|
|
48301
|
+
var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
|
|
48302
|
+
function defaultHarnessBrokerDirectory(environment = process.env) {
|
|
48303
|
+
const home = environment.HOME || os11.homedir();
|
|
48304
|
+
return path40.join(home, ".codexhost", "harness-broker");
|
|
48305
|
+
}
|
|
48306
|
+
function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
|
|
48307
|
+
harnessPluginIdSchema.parse(harnessId);
|
|
48308
|
+
if (harnessId !== "claude-code")
|
|
48309
|
+
return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
|
|
48310
|
+
return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
|
|
48311
|
+
}
|
|
48312
|
+
function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
|
|
48313
|
+
harnessPluginIdSchema.parse(harnessId);
|
|
48314
|
+
if (harnessId !== "claude-code")
|
|
48315
|
+
return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
|
|
48316
|
+
return path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
|
|
48317
|
+
}
|
|
48318
|
+
|
|
47558
48319
|
// packages/harness-broker/dist/server.js
|
|
47559
|
-
import { randomBytes as randomBytes5, randomUUID as
|
|
48320
|
+
import { randomBytes as randomBytes5, randomUUID as randomUUID24 } from "node:crypto";
|
|
47560
48321
|
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
48322
|
import net4, {} from "node:net";
|
|
47562
48323
|
import path41 from "node:path";
|
|
@@ -47615,7 +48376,7 @@ async function assertNoLiveDescriptor(descriptorPath) {
|
|
|
47615
48376
|
}
|
|
47616
48377
|
}
|
|
47617
48378
|
async function publishDescriptor(descriptorPath, descriptor) {
|
|
47618
|
-
const temporary = `${descriptorPath}.${process.pid}.${
|
|
48379
|
+
const temporary = `${descriptorPath}.${process.pid}.${randomUUID24()}.tmp`;
|
|
47619
48380
|
const handle = await open11(temporary, "wx", 384);
|
|
47620
48381
|
try {
|
|
47621
48382
|
await handle.writeFile(`${JSON.stringify(descriptor)}
|
|
@@ -47640,6 +48401,7 @@ function sessionMetadata(record4) {
|
|
|
47640
48401
|
sessionId: record4.id,
|
|
47641
48402
|
sessionGeneration: record4.generation,
|
|
47642
48403
|
capabilities: record4.session.capabilities,
|
|
48404
|
+
readCapabilities: true,
|
|
47643
48405
|
initialState: {
|
|
47644
48406
|
...initialState,
|
|
47645
48407
|
...record4.nativeRef ? { nativeRef: record4.nativeRef } : {},
|
|
@@ -47692,7 +48454,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
47692
48454
|
await assertNoLiveDescriptor(input.descriptorPath);
|
|
47693
48455
|
if (process.platform !== "win32")
|
|
47694
48456
|
await prepareUnixSocketPath(input.socketPath);
|
|
47695
|
-
const generation = input.generation ??
|
|
48457
|
+
const generation = input.generation ?? randomUUID24();
|
|
47696
48458
|
const token = input.token ?? randomBytes5(32).toString("hex");
|
|
47697
48459
|
const descriptor = {
|
|
47698
48460
|
schemaVersion: 1,
|
|
@@ -47733,7 +48495,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
47733
48495
|
};
|
|
47734
48496
|
const server = net4.createServer((socket) => {
|
|
47735
48497
|
const state = {
|
|
47736
|
-
id:
|
|
48498
|
+
id: randomUUID24(),
|
|
47737
48499
|
socket,
|
|
47738
48500
|
authenticated: false,
|
|
47739
48501
|
inputSequence: 0,
|
|
@@ -47924,11 +48686,74 @@ async function startHarnessBrokerServer(input) {
|
|
|
47924
48686
|
const parsed2 = brokerInspectInputSchema.parse(request.params);
|
|
47925
48687
|
const inspection = await input.adapter.inspect({
|
|
47926
48688
|
...parsed2.cwd ? { cwd: parsed2.cwd } : {},
|
|
47927
|
-
...parsed2.refresh !== void 0 ? { refresh: parsed2.refresh } : {}
|
|
48689
|
+
...parsed2.refresh !== void 0 ? { refresh: parsed2.refresh } : {},
|
|
48690
|
+
...parsed2.purpose !== void 0 ? { purpose: parsed2.purpose } : {}
|
|
47928
48691
|
});
|
|
47929
48692
|
retireWhenIdle = inspection.status !== "ready";
|
|
47930
48693
|
return inspection;
|
|
47931
48694
|
}
|
|
48695
|
+
if (request.method === "adapter.sessionImport.list") {
|
|
48696
|
+
const { limit, offset } = brokerSessionImportListParamsSchema.parse(request.params);
|
|
48697
|
+
const capability = input.adapter.sessionImport;
|
|
48698
|
+
if (!capability?.resolveCandidate) {
|
|
48699
|
+
return {
|
|
48700
|
+
ok: false,
|
|
48701
|
+
error: {
|
|
48702
|
+
code: "unsupported",
|
|
48703
|
+
message: "Harness Session import is unavailable",
|
|
48704
|
+
retryable: false
|
|
48705
|
+
}
|
|
48706
|
+
};
|
|
48707
|
+
}
|
|
48708
|
+
if (offset === 0) {
|
|
48709
|
+
delete state.sessionImportCandidates;
|
|
48710
|
+
const result = await capability.listCandidates();
|
|
48711
|
+
if (!result.ok)
|
|
48712
|
+
return result;
|
|
48713
|
+
state.sessionImportCandidates = result.value.map((candidate) => harnessSessionImportCandidateSchema.parse(candidate));
|
|
48714
|
+
}
|
|
48715
|
+
const candidates = state.sessionImportCandidates;
|
|
48716
|
+
if (!candidates) {
|
|
48717
|
+
return {
|
|
48718
|
+
ok: false,
|
|
48719
|
+
error: {
|
|
48720
|
+
code: "invalidState",
|
|
48721
|
+
message: "Session import snapshot is unavailable; refresh the list",
|
|
48722
|
+
retryable: true
|
|
48723
|
+
}
|
|
48724
|
+
};
|
|
48725
|
+
}
|
|
48726
|
+
const page = candidates.slice(offset, offset + limit);
|
|
48727
|
+
const total = candidates.length;
|
|
48728
|
+
if (offset + page.length >= total)
|
|
48729
|
+
delete state.sessionImportCandidates;
|
|
48730
|
+
return { ok: true, value: { candidates: page, total } };
|
|
48731
|
+
}
|
|
48732
|
+
if (request.method === "adapter.sessionImport.resolve") {
|
|
48733
|
+
const { nativeSessionId } = brokerSessionImportResolveParamsSchema.parse(request.params);
|
|
48734
|
+
const capability = input.adapter.sessionImport;
|
|
48735
|
+
if (!capability?.resolveCandidate) {
|
|
48736
|
+
return {
|
|
48737
|
+
ok: false,
|
|
48738
|
+
error: {
|
|
48739
|
+
code: "unsupported",
|
|
48740
|
+
message: "Harness Session import is unavailable",
|
|
48741
|
+
retryable: false
|
|
48742
|
+
}
|
|
48743
|
+
};
|
|
48744
|
+
}
|
|
48745
|
+
const result = await capability.resolveCandidate(nativeSessionId);
|
|
48746
|
+
if (!result.ok)
|
|
48747
|
+
return result;
|
|
48748
|
+
const source = brokerSessionImportSourceSchema.safeParse(result.value);
|
|
48749
|
+
if (!source.success || source.data.nativeRef.harnessId !== input.adapter.harnessId || source.data.candidate.nativeSessionId !== nativeSessionId) {
|
|
48750
|
+
return {
|
|
48751
|
+
ok: false,
|
|
48752
|
+
error: protocolError("Session import source identity does not match")
|
|
48753
|
+
};
|
|
48754
|
+
}
|
|
48755
|
+
return { ok: true, value: source.data };
|
|
48756
|
+
}
|
|
47932
48757
|
if (request.method === "adapter.subagent.readSnapshot") {
|
|
47933
48758
|
const subagents = input.adapter.subagents;
|
|
47934
48759
|
if (!subagents)
|
|
@@ -47971,7 +48796,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
47971
48796
|
}
|
|
47972
48797
|
};
|
|
47973
48798
|
}
|
|
47974
|
-
const openReservation =
|
|
48799
|
+
const openReservation = randomUUID24();
|
|
47975
48800
|
if (sourceKey)
|
|
47976
48801
|
nativeWriters.set(sourceKey, openReservation);
|
|
47977
48802
|
const provisionalReservation = openInput.kind === "create" ? openReservation : void 0;
|
|
@@ -48115,6 +48940,8 @@ async function startHarnessBrokerServer(input) {
|
|
|
48115
48940
|
let result;
|
|
48116
48941
|
if (command.type === "turn.start")
|
|
48117
48942
|
result = await record5.session.execute(command);
|
|
48943
|
+
else if (command.type === "turn.steer")
|
|
48944
|
+
result = await record5.session.execute(command);
|
|
48118
48945
|
else if (command.type === "turn.cancel")
|
|
48119
48946
|
result = await record5.session.execute(command);
|
|
48120
48947
|
else if (command.type === "interaction.respond") {
|
|
@@ -48146,6 +48973,10 @@ async function startHarnessBrokerServer(input) {
|
|
|
48146
48973
|
}
|
|
48147
48974
|
return result;
|
|
48148
48975
|
}
|
|
48976
|
+
if (request.method === "session.readCapabilities") {
|
|
48977
|
+
const session = requireSession(request.params).session;
|
|
48978
|
+
return session.readCapabilities ? session.readCapabilities() : session.capabilities;
|
|
48979
|
+
}
|
|
48149
48980
|
if (request.method === "session.readSnapshot") {
|
|
48150
48981
|
return requireSession(request.params).session.readSnapshot();
|
|
48151
48982
|
}
|
|
@@ -48272,7 +49103,7 @@ async function startHarnessBrokerServer(input) {
|
|
|
48272
49103
|
}
|
|
48273
49104
|
state.authenticated = true;
|
|
48274
49105
|
state.inputSequence = 1;
|
|
48275
|
-
await send({ kind: "response", id:
|
|
49106
|
+
await send({ kind: "response", id: randomUUID24(), ok: true, value: { ready: true } });
|
|
48276
49107
|
return;
|
|
48277
49108
|
}
|
|
48278
49109
|
const parsed2 = harnessBrokerRequestSchema.safeParse(raw);
|