orion-super-agent-dev 0.1.23 → 0.1.25

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/out/main.js CHANGED
@@ -2230,7 +2230,7 @@ var require_react_jsx_runtime_development = __commonJS({
2230
2230
  if (process.env.NODE_ENV !== "production") {
2231
2231
  (function() {
2232
2232
  "use strict";
2233
- var React32 = require_react();
2233
+ var React33 = require_react();
2234
2234
  var REACT_ELEMENT_TYPE = Symbol.for("react.element");
2235
2235
  var REACT_PORTAL_TYPE = Symbol.for("react.portal");
2236
2236
  var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
@@ -2256,7 +2256,7 @@ var require_react_jsx_runtime_development = __commonJS({
2256
2256
  }
2257
2257
  return null;
2258
2258
  }
2259
- var ReactSharedInternals = React32.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
2259
+ var ReactSharedInternals = React33.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
2260
2260
  function error(format2) {
2261
2261
  {
2262
2262
  {
@@ -9963,9 +9963,9 @@ var require_react_reconciler_development = __commonJS({
9963
9963
  module2.exports = function $$$reconciler($$$hostConfig) {
9964
9964
  var exports3 = {};
9965
9965
  "use strict";
9966
- var React32 = require_react();
9966
+ var React33 = require_react();
9967
9967
  var Scheduler = require_scheduler();
9968
- var ReactSharedInternals = React32.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
9968
+ var ReactSharedInternals = React33.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
9969
9969
  var suppressWarning = false;
9970
9970
  function setSuppressWarning(newSuppressWarning) {
9971
9971
  {
@@ -29178,6 +29178,8 @@ var require_duetEntry = __commonJS({
29178
29178
  }();
29179
29179
  Object.defineProperty(exports2, "__esModule", { value: true });
29180
29180
  exports2.DUET_HANDOFF_BRIEF_MAX_CHARS = exports2.DUET_HANDOFF_CAPABILITY = exports2.DUET_HANDOFF_TOOL = exports2.DUET_ENTRY_OPTIONS = exports2.DUET_ENTRY_INFO = exports2.DUET_ENTRY_KEY = exports2.DUET_ENTRY_DEFAULT = exports2.DUET_ENTRIES = void 0;
29181
+ exports2.isModelRoutedEntry = isModelRoutedEntry;
29182
+ exports2.effectiveDuetEntry = effectiveDuetEntry;
29181
29183
  exports2.duetEntryLabel = duetEntryLabel2;
29182
29184
  exports2.normalizeDuetEntry = normalizeDuetEntry2;
29183
29185
  exports2.duetHandoffBrief = duetHandoffBrief2;
@@ -29193,7 +29195,10 @@ var require_duetEntry = __commonJS({
29193
29195
  var path14 = __importStar(__require("node:path"));
29194
29196
  var atomicWrite_js_1 = require_atomicWrite();
29195
29197
  var settingsPaths_js_1 = require_settingsPaths();
29196
- exports2.DUET_ENTRIES = ["planner", "router"];
29198
+ exports2.DUET_ENTRIES = ["planner", "router", "executor"];
29199
+ function isModelRoutedEntry(entry) {
29200
+ return entry === "router" || entry === "executor";
29201
+ }
29197
29202
  exports2.DUET_ENTRY_DEFAULT = "planner";
29198
29203
  exports2.DUET_ENTRY_KEY = "duetEntry";
29199
29204
  exports2.DUET_ENTRY_INFO = {
@@ -29213,8 +29218,18 @@ var require_duetEntry = __commonJS({
29213
29218
  value: "router",
29214
29219
  label: "Router decides",
29215
29220
  description: "Local model routes. No planner call."
29221
+ },
29222
+ {
29223
+ value: "executor",
29224
+ label: "Executor decides",
29225
+ description: "Your executor routes. No planner call, no download."
29216
29226
  }
29217
29227
  ];
29228
+ function effectiveDuetEntry(setting, routerState) {
29229
+ if (setting === "router" && routerState !== "ready")
29230
+ return { entry: "planner", downgraded: true };
29231
+ return { entry: setting, downgraded: false };
29232
+ }
29218
29233
  function duetEntryLabel2(entry) {
29219
29234
  return exports2.DUET_ENTRY_OPTIONS.find((option) => option.value === entry)?.label ?? entry;
29220
29235
  }
@@ -29222,7 +29237,7 @@ var require_duetEntry = __commonJS({
29222
29237
  if (typeof raw !== "string")
29223
29238
  return null;
29224
29239
  const value = raw.trim();
29225
- return value === "planner" || value === "router" ? value : null;
29240
+ return value === "planner" || value === "router" || value === "executor" ? value : null;
29226
29241
  }
29227
29242
  exports2.DUET_HANDOFF_TOOL = "hand_off";
29228
29243
  exports2.DUET_HANDOFF_CAPABILITY = "duet_handoff";
@@ -29345,6 +29360,67 @@ var require_duetEntry = __commonJS({
29345
29360
  }
29346
29361
  });
29347
29362
 
29363
+ // ../packages/orion-client-core/dist/duetExecutorGateStatus.js
29364
+ var require_duetExecutorGateStatus = __commonJS({
29365
+ "../packages/orion-client-core/dist/duetExecutorGateStatus.js"(exports2) {
29366
+ "use strict";
29367
+ Object.defineProperty(exports2, "__esModule", { value: true });
29368
+ exports2.executorGateStatusLine = executorGateStatusLine2;
29369
+ exports2.executorGateFallbackNote = executorGateFallbackNote;
29370
+ exports2.executorGateOptionAvailability = executorGateOptionAvailability;
29371
+ function unavailableWhy(reason, problem) {
29372
+ switch (reason) {
29373
+ case "not_resolved":
29374
+ return "its endpoint is not configured";
29375
+ case "unreachable":
29376
+ return "it is not answering";
29377
+ case "no_completions":
29378
+ return "it has no /v1/completions route";
29379
+ case "thinking":
29380
+ return "its completions route answers thinking text, not a plain token";
29381
+ case "unparseable":
29382
+ return "it did not answer E or P";
29383
+ case "error":
29384
+ return `the gate call failed (${problem})`;
29385
+ }
29386
+ }
29387
+ function executorGateStatusLine2(status) {
29388
+ switch (status.state) {
29389
+ case "ready":
29390
+ return `Executor gate: ${status.target.model} on '${status.target.name}' \xB7 ${status.mode} \xB7 threshold ${status.threshold} \xB7 ${status.calibration.passed}/${status.calibration.total} scenarios \xB7 ready`;
29391
+ case "miscalibrated":
29392
+ return `Executor gate: ${status.target.model} on '${status.target.name}' misrouted ${status.calibration.failed.length} of ${status.calibration.total} probe scenarios (${status.mode}, threshold ${status.threshold}) \u2014 tune executorGate.threshold on that endpoint.`;
29393
+ case "platform":
29394
+ return "Executor gate: the Duet executor is a platform model \u2014 this entry routes on Duet's rules.";
29395
+ case "unavailable":
29396
+ return `Executor gate: not asking \u2014 ${unavailableWhy(status.reason, status.problem)}.`;
29397
+ }
29398
+ }
29399
+ function executorGateFallbackNote(status) {
29400
+ const why = status.state === "platform" ? "the Duet executor is a platform model" : status.state === "unavailable" ? unavailableWhy(status.reason, status.problem) : "it could not run";
29401
+ return `Executor decides could not ask your executor (${why}) \u2014 this turn routed on Duet's rules instead.`;
29402
+ }
29403
+ function executorGateOptionAvailability(status) {
29404
+ if (status === null || status.state === "ready")
29405
+ return { disabled: false, note: null };
29406
+ switch (status.state) {
29407
+ case "platform":
29408
+ return { disabled: false, note: "The executor is a platform model \u2014 routes on Duet's rules." };
29409
+ case "miscalibrated":
29410
+ return {
29411
+ disabled: false,
29412
+ note: `The gate misrouted ${status.calibration.failed.length} of ${status.calibration.total} probe scenarios \u2014 tune executorGate.threshold on that endpoint.`
29413
+ };
29414
+ case "unavailable":
29415
+ return {
29416
+ disabled: false,
29417
+ note: `The executor cannot be asked right now (${unavailableWhy(status.reason, status.problem)}) \u2014 routes on Duet's rules.`
29418
+ };
29419
+ }
29420
+ }
29421
+ }
29422
+ });
29423
+
29348
29424
  // ../packages/orion-client-core/dist/duetRouterModel.js
29349
29425
  var require_duetRouterModel = __commonJS({
29350
29426
  "../packages/orion-client-core/dist/duetRouterModel.js"(exports2) {
@@ -29400,7 +29476,6 @@ var require_duetRouterModel = __commonJS({
29400
29476
  exports2.classifyWithHeads = classifyWithHeads;
29401
29477
  exports2.createDuetRouter = createDuetRouter;
29402
29478
  exports2.createTransformersDuetRouterEncoder = createTransformersDuetRouterEncoder;
29403
- exports2.effectiveDuetEntry = effectiveDuetEntry;
29404
29479
  exports2.duetRouterDisplayName = duetRouterDisplayName2;
29405
29480
  exports2.duetRouterStatusLine = duetRouterStatusLine2;
29406
29481
  exports2.duetRouterDowngradeNote = duetRouterDowngradeNote;
@@ -29412,6 +29487,8 @@ var require_duetRouterModel = __commonJS({
29412
29487
  var fs15 = __importStar(__require("node:fs/promises"));
29413
29488
  var os9 = __importStar(__require("node:os"));
29414
29489
  var path14 = __importStar(__require("node:path"));
29490
+ var duetEntry_js_1 = require_duetEntry();
29491
+ var duetExecutorGateStatus_js_1 = require_duetExecutorGateStatus();
29415
29492
  exports2.DUET_ROUTER_WIRE_KEY = "duet_router";
29416
29493
  exports2.DUET_ROUTER_BUNDLE_FORMAT = "orion-router-bundle.v1";
29417
29494
  exports2.DUET_ROUTER_MODEL_ID = "orion/orion-pe-router-1.0";
@@ -29425,13 +29502,16 @@ var require_duetRouterModel = __commonJS({
29425
29502
  ];
29426
29503
  function duetRouterWireForSegment(verdict) {
29427
29504
  return {
29505
+ source: verdict.source,
29428
29506
  model: verdict.model,
29429
29507
  version: verdict.version,
29430
29508
  verdict: verdict.verdict,
29431
29509
  p_plan: round6(verdict.pPlan),
29432
29510
  asks_for_plan: verdict.asksForPlan,
29433
29511
  high_risk: verdict.highRisk,
29434
- reason: verdict.reason
29512
+ reason: verdict.reason,
29513
+ ...verdict.margin !== void 0 ? { margin: round6(verdict.margin) } : {},
29514
+ ...verdict.mode !== void 0 ? { mode: verdict.mode } : {}
29435
29515
  };
29436
29516
  }
29437
29517
  function orionModelsDir(homeDir = os9.homedir()) {
@@ -29662,6 +29742,7 @@ var require_duetRouterModel = __commonJS({
29662
29742
  if (!vector)
29663
29743
  throw new Error("router encoder returned no vector");
29664
29744
  return {
29745
+ source: "orion_router",
29665
29746
  ...classifyWithHeads(vector, bundle),
29666
29747
  model: bundle.name,
29667
29748
  version: bundle.version,
@@ -29731,11 +29812,6 @@ var require_duetRouterModel = __commonJS({
29731
29812
  }
29732
29813
  };
29733
29814
  }
29734
- function effectiveDuetEntry(setting, routerState) {
29735
- if (setting === "router" && routerState !== "ready")
29736
- return { entry: "planner", downgraded: true };
29737
- return { entry: setting, downgraded: false };
29738
- }
29739
29815
  function duetRouterDisplayName2(name2, version) {
29740
29816
  const trimmed = name2.trim();
29741
29817
  const v2 = version.trim();
@@ -29757,7 +29833,9 @@ var require_duetRouterModel = __commonJS({
29757
29833
  const why = status.state === "missing" ? "it is not installed" : status.state === "invalid" ? `it is unusable (${status.problem})` : `it failed to load${"problem" in status && status.problem ? ` (${status.problem})` : ""}`;
29758
29834
  return `Router decides needs the Orion router model and ${why} \u2014 this turn ran through the planner instead.`;
29759
29835
  }
29760
- function duetEntryOptionAvailability2(entry, status) {
29836
+ function duetEntryOptionAvailability2(entry, status, executorStatus = null) {
29837
+ if (entry === "executor")
29838
+ return (0, duetExecutorGateStatus_js_1.executorGateOptionAvailability)(executorStatus);
29761
29839
  if (entry !== "router" || status === null || status.state === "ready")
29762
29840
  return { disabled: false, note: null };
29763
29841
  return {
@@ -29797,6 +29875,7 @@ var require_duetRouterModel = __commonJS({
29797
29875
  let router = null;
29798
29876
  let building = null;
29799
29877
  let noted = false;
29878
+ let executorNoted = false;
29800
29879
  const status = async (o = {}) => {
29801
29880
  const now2 = Date.now();
29802
29881
  if (!o.refresh && cached !== null && now2 - cached.at < exports2.DUET_ROUTER_STATUS_TTL_MS)
@@ -29808,11 +29887,18 @@ var require_duetRouterModel = __commonJS({
29808
29887
  const downgrade = (why) => {
29809
29888
  const note = noted ? null : duetRouterDowngradeNote(why);
29810
29889
  noted = true;
29811
- return { ...effectiveDuetEntry("router", why.state), verdict: null, note };
29890
+ return { ...(0, duetEntry_js_1.effectiveDuetEntry)("router", why.state), verdict: null, note };
29812
29891
  };
29813
29892
  return {
29814
29893
  status,
29815
- async prepareTurn(setting, text) {
29894
+ async prepareTurn(setting, text, ctx = {}) {
29895
+ if (setting === "executor") {
29896
+ if (opts.executorGate !== void 0)
29897
+ return opts.executorGate.prepareTurn(text, ctx);
29898
+ const note = executorNoted ? null : (0, duetExecutorGateStatus_js_1.executorGateFallbackNote)({ state: "unavailable", reason: "error", problem: "this host has no executor gate" });
29899
+ executorNoted = true;
29900
+ return { entry: "executor", verdict: null, note };
29901
+ }
29816
29902
  if (setting !== "router")
29817
29903
  return { entry: setting, verdict: null, note: null };
29818
29904
  if (text.trim() === "")
@@ -29846,6 +29932,8 @@ var require_duetRouterModel = __commonJS({
29846
29932
  invalidate() {
29847
29933
  cached = null;
29848
29934
  noted = false;
29935
+ executorNoted = false;
29936
+ opts.executorGate?.invalidate();
29849
29937
  const live = router;
29850
29938
  router = null;
29851
29939
  building = null;
@@ -30164,6 +30252,7 @@ var require_duetPlan = __commonJS({
30164
30252
  exports2.duetReplanFollowupPrompt = duetReplanFollowupPrompt2;
30165
30253
  exports2.recordDuetTurnOutcome = recordDuetTurnOutcome;
30166
30254
  exports2.foldDuetTurnEnd = foldDuetTurnEnd2;
30255
+ var duetEntry_js_1 = require_duetEntry();
30167
30256
  exports2.DUET_PLAN_MAX_LEN = 65536;
30168
30257
  exports2.DUET_PLAN_MAX_VERSION = 1e4;
30169
30258
  exports2.DUET_PLAN_GRANTS = ["default", "workspace_write"];
@@ -30306,7 +30395,7 @@ var require_duetPlan = __commonJS({
30306
30395
  return false;
30307
30396
  const noPlan = duetPlanWireForSegment(record) === void 0;
30308
30397
  if (noPlan) {
30309
- if (entry !== "router")
30398
+ if (!(0, duetEntry_js_1.isModelRoutedEntry)(entry))
30310
30399
  return false;
30311
30400
  if (highRiskRequest(text))
30312
30401
  return false;
@@ -30320,7 +30409,7 @@ var require_duetPlan = __commonJS({
30320
30409
  return false;
30321
30410
  if (record.userNegativeFeedback)
30322
30411
  return false;
30323
- if (entry !== "router")
30412
+ if (!(0, duetEntry_js_1.isModelRoutedEntry)(entry))
30324
30413
  return continuationRequest(text);
30325
30414
  return verdict ? verdict.verdict === "execute" : true;
30326
30415
  }
@@ -33386,6 +33475,8 @@ var require_segmentDriver = __commonJS({
33386
33475
  body2.workspace_root = routing.workspaceRoot;
33387
33476
  if (routing.clientType !== void 0)
33388
33477
  body2.client_type = routing.clientType;
33478
+ if (routing.clientVersion !== void 0)
33479
+ body2.client_version = routing.clientVersion;
33389
33480
  if (routing.mode !== void 0)
33390
33481
  body2.mode = routing.mode;
33391
33482
  if (routing.reasoning !== void 0)
@@ -34679,7 +34770,10 @@ var require_frames = __commonJS({
34679
34770
  if (typeof frame.id !== "string") {
34680
34771
  throw new FrameDecodeError("malformed renew_bearer frame");
34681
34772
  }
34682
- return { type: "renew_bearer", id: frame.id };
34773
+ const decoded = { type: "renew_bearer", id: frame.id };
34774
+ if (typeof frame.refused === "string")
34775
+ decoded.refused = frame.refused;
34776
+ return decoded;
34683
34777
  }
34684
34778
  case "rpc_result": {
34685
34779
  if (typeof frame.id !== "string" || !("result" in frame)) {
@@ -35269,11 +35363,12 @@ var require_customProviders = __commonJS({
35269
35363
  };
35270
35364
  }();
35271
35365
  Object.defineProperty(exports2, "__esModule", { value: true });
35272
- exports2.EXECUTOR_LIVENESS_TIMEOUT_MS = exports2.EXECUTOR_LIVENESS_TTL_MS = exports2.PROBE_TIMEOUT_MS = exports2.ROUTING_MODELS_KEY = exports2.MAX_CONTEXT_WINDOW = exports2.MIN_CONTEXT_WINDOW = void 0;
35366
+ exports2.EXECUTOR_LIVENESS_TIMEOUT_MS = exports2.EXECUTOR_LIVENESS_TTL_MS = exports2.PROBE_TIMEOUT_MS = exports2.EXECUTOR_GATE_THRESHOLD_BOUND = exports2.EXECUTOR_GATE_DEFAULT_THRESHOLD = exports2.EXECUTOR_GATE_KEY = exports2.ROUTING_MODELS_KEY = exports2.MAX_CONTEXT_WINDOW = exports2.MIN_CONTEXT_WINDOW = void 0;
35273
35367
  exports2.customProviderSettingsPath = customProviderSettingsPath;
35274
35368
  exports2.clampContextWindow = clampContextWindow;
35275
35369
  exports2.normalizeModelConfig = normalizeModelConfig;
35276
35370
  exports2.normalizeRoutingModels = normalizeRoutingModels;
35371
+ exports2.normalizeExecutorGate = normalizeExecutorGate;
35277
35372
  exports2.loadCustomProviders = loadCustomProviders3;
35278
35373
  exports2.getCustomProvider = getCustomProvider2;
35279
35374
  exports2.saveCustomProvider = saveCustomProvider3;
@@ -35303,6 +35398,9 @@ var require_customProviders = __commonJS({
35303
35398
  exports2.MIN_CONTEXT_WINDOW = 1024;
35304
35399
  exports2.MAX_CONTEXT_WINDOW = 2e6;
35305
35400
  exports2.ROUTING_MODELS_KEY = "routingModels";
35401
+ exports2.EXECUTOR_GATE_KEY = "executorGate";
35402
+ exports2.EXECUTOR_GATE_DEFAULT_THRESHOLD = 0;
35403
+ exports2.EXECUTOR_GATE_THRESHOLD_BOUND = 20;
35306
35404
  var CUSTOM_REF_PREFIX = "custom:";
35307
35405
  var FILE_TIERS = ["user", "project", "local"];
35308
35406
  function customProviderSettingsPath(tier, opts = {}) {
@@ -35372,6 +35470,16 @@ var require_customProviders = __commonJS({
35372
35470
  }
35373
35471
  return Object.keys(out2).length > 0 ? out2 : void 0;
35374
35472
  }
35473
+ function normalizeExecutorGate(raw) {
35474
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw))
35475
+ return void 0;
35476
+ const threshold = raw.threshold;
35477
+ if (typeof threshold !== "number" || !Number.isFinite(threshold))
35478
+ return void 0;
35479
+ return {
35480
+ threshold: Math.max(-exports2.EXECUTOR_GATE_THRESHOLD_BOUND, Math.min(exports2.EXECUTOR_GATE_THRESHOLD_BOUND, threshold))
35481
+ };
35482
+ }
35375
35483
  function toEntry(name2, raw) {
35376
35484
  if (typeof raw !== "object" || raw === null || Array.isArray(raw))
35377
35485
  return null;
@@ -35397,6 +35505,9 @@ var require_customProviders = __commonJS({
35397
35505
  const routingModels = normalizeRoutingModels(value[exports2.ROUTING_MODELS_KEY]);
35398
35506
  if (routingModels !== void 0)
35399
35507
  entry.routingModels = routingModels;
35508
+ const executorGate = normalizeExecutorGate(value[exports2.EXECUTOR_GATE_KEY]);
35509
+ if (executorGate !== void 0)
35510
+ entry.executorGate = executorGate;
35400
35511
  return entry;
35401
35512
  }
35402
35513
  async function readTier(tier, opts) {
@@ -35667,7 +35778,8 @@ var require_customProviders = __commonJS({
35667
35778
  // keyless is valid — local servers ignore auth
35668
35779
  wire: entry.wire,
35669
35780
  ...entry.modelConfig ? { modelConfig: entry.modelConfig } : {},
35670
- ...entry.routingModels ? { routingModels: entry.routingModels } : {}
35781
+ ...entry.routingModels ? { routingModels: entry.routingModels } : {},
35782
+ ...entry.executorGate ? { executorGate: entry.executorGate } : {}
35671
35783
  };
35672
35784
  routingByRef.set(provider, routing);
35673
35785
  while (routingByRef.size > ROUTING_CACHE_MAX) {
@@ -35783,6 +35895,7 @@ var require_customProviders = __commonJS({
35783
35895
  const wire = { ...routing };
35784
35896
  delete wire.modelConfig;
35785
35897
  delete wire.routingModels;
35898
+ delete wire.executorGate;
35786
35899
  const declared = routing.modelConfig?.[modelId];
35787
35900
  if (declared === void 0)
35788
35901
  return wire;
@@ -36018,75 +36131,9 @@ var require_duetRouterInstall = __commonJS({
36018
36131
  }
36019
36132
  });
36020
36133
 
36021
- // ../packages/orion-client-core/dist/runs/common.js
36022
- var require_common = __commonJS({
36023
- "../packages/orion-client-core/dist/runs/common.js"(exports2) {
36024
- "use strict";
36025
- Object.defineProperty(exports2, "__esModule", { value: true });
36026
- exports2.mintRunId = mintRunId;
36027
- exports2.runsRootFor = runsRootFor2;
36028
- exports2.readJsonFile = readJsonFile;
36029
- exports2.writeJsonFile = writeJsonFile;
36030
- exports2.ensureDirFor = ensureDirFor;
36031
- exports2.listDirNames = listDirNames;
36032
- exports2.dayKey = dayKey;
36033
- exports2.clipTail = clipTail;
36034
- var fs_1 = __require("fs");
36035
- var os_1 = __require("os");
36036
- var path_1 = __require("path");
36037
- var atomicWrite_js_1 = require_atomicWrite();
36038
- var experienceStore_js_1 = require_experienceStore();
36039
- var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
36040
- var ID_SUFFIX_LEN = 6;
36041
- function mintRunId(prefix, nowMs = Date.now(), rand = Math.random) {
36042
- let suffix = "";
36043
- for (let i2 = 0; i2 < ID_SUFFIX_LEN; i2 += 1) {
36044
- suffix += ID_ALPHABET[Math.floor(rand() * ID_ALPHABET.length) % ID_ALPHABET.length];
36045
- }
36046
- return `${prefix}_${String(nowMs).padStart(13, "0")}_${suffix}`;
36047
- }
36048
- function runsRootFor2(kind, workspaceRoot, home = (0, os_1.homedir)()) {
36049
- return (0, path_1.join)((0, experienceStore_js_1.projectDirFor)(workspaceRoot, home), "runs", kind);
36050
- }
36051
- async function readJsonFile(path14) {
36052
- try {
36053
- const raw = await fs_1.promises.readFile(path14, "utf8");
36054
- return JSON.parse(raw);
36055
- } catch {
36056
- return null;
36057
- }
36058
- }
36059
- async function writeJsonFile(path14, value) {
36060
- await ensureDirFor(path14);
36061
- await (0, atomicWrite_js_1.atomicWriteFile)(path14, JSON.stringify(value, null, 2));
36062
- }
36063
- async function ensureDirFor(path14) {
36064
- await fs_1.promises.mkdir((0, path_1.dirname)(path14), { recursive: true });
36065
- }
36066
- async function listDirNames(path14) {
36067
- try {
36068
- return await fs_1.promises.readdir(path14);
36069
- } catch {
36070
- return [];
36071
- }
36072
- }
36073
- function dayKey(nowMs = Date.now()) {
36074
- const d2 = new Date(nowMs);
36075
- const month = `${d2.getMonth() + 1}`.padStart(2, "0");
36076
- const day = `${d2.getDate()}`.padStart(2, "0");
36077
- return `${d2.getFullYear()}-${month}-${day}`;
36078
- }
36079
- function clipTail(text, max) {
36080
- if (text.length <= max)
36081
- return text;
36082
- return `\u2026${text.slice(text.length - (max - 1))}`;
36083
- }
36084
- }
36085
- });
36086
-
36087
- // ../packages/orion-client-core/dist/customProviderModels.js
36088
- var require_customProviderModels = __commonJS({
36089
- "../packages/orion-client-core/dist/customProviderModels.js"(exports2) {
36134
+ // ../packages/orion-client-core/dist/duetRoutingLog.js
36135
+ var require_duetRoutingLog = __commonJS({
36136
+ "../packages/orion-client-core/dist/duetRoutingLog.js"(exports2) {
36090
36137
  "use strict";
36091
36138
  var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
36092
36139
  if (k2 === void 0) k2 = k;
@@ -36126,289 +36173,238 @@ var require_customProviderModels = __commonJS({
36126
36173
  };
36127
36174
  }();
36128
36175
  Object.defineProperty(exports2, "__esModule", { value: true });
36129
- exports2.CATALOG_GC_MS = exports2.CATALOG_TTL_MS = exports2.CATALOG_SCHEMA_VERSION = void 0;
36130
- exports2.catalogPathFor = catalogPathFor;
36131
- exports2.endpointCatalog = endpointCatalog2;
36132
- exports2.findProbedModel = findProbedModel;
36133
- exports2.resolveModelSettings = resolveModelSettings2;
36134
- exports2.catalogModelIds = catalogModelIds2;
36135
- exports2.clearEndpointCatalog = clearEndpointCatalog3;
36136
- exports2.endpointModelViews = endpointModelViews2;
36137
- exports2.updateCustomProviderModels = updateCustomProviderModels2;
36176
+ exports2.DUET_ROUTING_LOG_DEFAULT_MODE = exports2.DUET_ROUTING_LOG_KEY = exports2.DUET_ROUTING_LOG_HEAD_CHARS = exports2.DUET_ROUTING_LOG_MAX_BYTES = exports2.DUET_ROUTING_LOG_SCHEMA = void 0;
36177
+ exports2.duetRoutingLogPath = duetRoutingLogPath2;
36178
+ exports2.newDecisionId = newDecisionId;
36179
+ exports2.sessionKey = sessionKey;
36180
+ exports2.lexicalSimilarity = lexicalSimilarity;
36181
+ exports2.planDiffRatio = planDiffRatio;
36182
+ exports2.clearDuetRoutingLogCache = clearDuetRoutingLogCache;
36183
+ exports2.duetRoutingLogMode = duetRoutingLogMode2;
36184
+ exports2.redactRowForMode = redactRowForMode;
36185
+ exports2.appendDuetRoutingRow = appendDuetRoutingRow;
36186
+ exports2.readDuetRoutingLog = readDuetRoutingLog2;
36187
+ exports2.summarizeDuetRoutingLog = summarizeDuetRoutingLog2;
36188
+ exports2.formatDuetRoutingLogSummary = formatDuetRoutingLogSummary2;
36138
36189
  var node_crypto_1 = __require("node:crypto");
36190
+ var fs15 = __importStar(__require("node:fs/promises"));
36139
36191
  var os9 = __importStar(__require("node:os"));
36140
36192
  var path14 = __importStar(__require("node:path"));
36141
- var customProviders_1 = require_customProviders();
36142
- var common_1 = require_common();
36143
- exports2.CATALOG_SCHEMA_VERSION = 1;
36144
- exports2.CATALOG_TTL_MS = 9e5;
36145
- exports2.CATALOG_GC_MS = 45 * 24 * 60 * 60 * 1e3;
36146
- function catalogPathFor(baseUrl, homeDir = os9.homedir()) {
36147
- const digest = (0, node_crypto_1.createHash)("sha256").update(normalizeBaseUrl(baseUrl)).digest("hex").slice(0, 16);
36148
- return path14.join(homeDir, ".orion", "cache", "models", `${digest}.json`);
36193
+ var settingsPaths_js_1 = require_settingsPaths();
36194
+ exports2.DUET_ROUTING_LOG_SCHEMA = 3;
36195
+ exports2.DUET_ROUTING_LOG_MAX_BYTES = 5 * 1024 * 1024;
36196
+ exports2.DUET_ROUTING_LOG_HEAD_CHARS = 200;
36197
+ exports2.DUET_ROUTING_LOG_KEY = "duetRoutingLog";
36198
+ exports2.DUET_ROUTING_LOG_DEFAULT_MODE = "full";
36199
+ function duetRoutingLogPath2(opts = {}) {
36200
+ return path14.join(opts.homeDir ?? os9.homedir(), ".orion", "duet-routing-decisions.jsonl");
36149
36201
  }
36150
- function normalizeBaseUrl(baseUrl) {
36151
- return baseUrl.trim().replace(/\/+$/, "");
36202
+ function newDecisionId() {
36203
+ return (0, node_crypto_1.randomUUID)();
36152
36204
  }
36153
- async function readRecordFromDisk(baseUrl) {
36154
- const record = await (0, common_1.readJsonFile)(catalogPathFor(baseUrl));
36155
- if (record === null)
36156
- return null;
36157
- if (record.version !== exports2.CATALOG_SCHEMA_VERSION)
36158
- return null;
36159
- if (normalizeBaseUrl(record.baseUrl ?? "") !== normalizeBaseUrl(baseUrl))
36160
- return null;
36161
- if (!Array.isArray(record.models))
36162
- return null;
36163
- return record;
36205
+ function sessionKey(sessionId) {
36206
+ if (sessionId === void 0 || sessionId === "")
36207
+ return void 0;
36208
+ return (0, node_crypto_1.createHash)("sha256").update(sessionId).digest("hex").slice(0, 12);
36164
36209
  }
36165
- var sweptThisProcess = false;
36166
- async function gcEndpointCatalogs(now2, homeDir = os9.homedir()) {
36167
- if (sweptThisProcess)
36168
- return;
36169
- sweptThisProcess = true;
36170
- try {
36171
- const dir = path14.dirname(catalogPathFor("x", homeDir));
36172
- const fs15 = await Promise.resolve().then(() => __importStar(__require("node:fs/promises")));
36173
- for (const name2 of await fs15.readdir(dir)) {
36174
- if (!name2.endsWith(".json"))
36175
- continue;
36176
- const file = path14.join(dir, name2);
36177
- try {
36178
- const record = await (0, common_1.readJsonFile)(file);
36179
- const age = typeof record?.fetchedAt === "number" ? now2 - record.fetchedAt : now2 - (await fs15.stat(file)).mtimeMs;
36180
- if (age > exports2.CATALOG_GC_MS)
36181
- await fs15.rm(file, { force: true });
36182
- } catch {
36183
- }
36184
- }
36185
- } catch {
36186
- }
36210
+ function tokens(text) {
36211
+ return new Set(text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1));
36187
36212
  }
36188
- async function writeRecordToDisk(record) {
36189
- try {
36190
- await (0, common_1.writeJsonFile)(catalogPathFor(record.baseUrl), record);
36191
- } catch {
36192
- }
36193
- void gcEndpointCatalogs(record.fetchedAt);
36213
+ function jaccard(a, b2) {
36214
+ if (a.size === 0 && b2.size === 0)
36215
+ return 1;
36216
+ let inter = 0;
36217
+ for (const t of a)
36218
+ if (b2.has(t))
36219
+ inter += 1;
36220
+ const union = a.size + b2.size - inter;
36221
+ return union === 0 ? 0 : inter / union;
36194
36222
  }
36195
- var memory = /* @__PURE__ */ new Map();
36196
- var inFlight2 = /* @__PURE__ */ new Map();
36197
- function depsWith(deps2) {
36198
- return {
36199
- now: deps2.now ?? (() => Date.now()),
36200
- probe: deps2.probe ?? customProviders_1.probeModels,
36201
- readRecord: deps2.readRecord ?? readRecordFromDisk,
36202
- writeRecord: deps2.writeRecord ?? writeRecordToDisk
36203
- };
36223
+ function lexicalSimilarity(a, b2) {
36224
+ return Math.round(jaccard(tokens(a), tokens(b2)) * 1e3) / 1e3;
36204
36225
  }
36205
- async function probeAndStore(entry, d2) {
36206
- const key = normalizeBaseUrl(entry.baseUrl);
36207
- const existing = inFlight2.get(key);
36208
- if (existing !== void 0)
36209
- return existing;
36210
- const run3 = (async () => {
36211
- const models = await d2.probe(entry.baseUrl, await (0, customProviders_1.resolveApiKey)(entry));
36212
- if (models === null || models.length === 0)
36213
- return models;
36214
- const record = {
36215
- version: exports2.CATALOG_SCHEMA_VERSION,
36216
- baseUrl: entry.baseUrl,
36217
- fetchedAt: d2.now(),
36218
- models
36219
- };
36220
- memory.set(key, record);
36221
- await d2.writeRecord(record);
36222
- return models;
36223
- })().finally(() => inFlight2.delete(key));
36224
- inFlight2.set(key, run3);
36225
- return run3;
36226
+ function planDiffRatio(before, after) {
36227
+ const lines = (plan) => new Set(plan.split(/\r?\n/).map((l3) => l3.trim()).filter((l3) => l3 !== ""));
36228
+ return Math.round((1 - jaccard(lines(before), lines(after))) * 1e3) / 1e3;
36226
36229
  }
36227
- async function endpointCatalog2(entry, options = {}) {
36228
- const d2 = depsWith(options);
36229
- const key = normalizeBaseUrl(entry.baseUrl);
36230
- let record = memory.get(key) ?? null;
36231
- if (record === null) {
36232
- record = await d2.readRecord(entry.baseUrl);
36233
- if (record !== null)
36234
- memory.set(key, record);
36235
- }
36236
- if (options.cachedOnly === true)
36237
- return record?.models ?? [];
36238
- const fresh = record !== null && d2.now() - record.fetchedAt < exports2.CATALOG_TTL_MS;
36239
- if (record !== null && fresh && options.force !== true)
36240
- return record.models;
36241
- if (record !== null) {
36242
- void probeAndStore(entry, d2).catch(() => void 0);
36243
- return record.models;
36244
- }
36245
- return await probeAndStore(entry, d2) ?? [];
36230
+ var MODE_CACHE_TTL_MS = 5e3;
36231
+ var modeCache = /* @__PURE__ */ new Map();
36232
+ function clearDuetRoutingLogCache() {
36233
+ modeCache.clear();
36246
36234
  }
36247
- function findProbedModel(models, id) {
36248
- return models.find((model) => model.id === id);
36235
+ function coerceMode(raw) {
36236
+ return raw === "full" || raw === "head" || raw === "off" ? raw : null;
36249
36237
  }
36250
- function resolveModelSettings2(entry, modelId, catalog = []) {
36251
- const declared = entry.modelConfig?.[modelId];
36252
- const probed = findProbedModel(catalog, modelId);
36253
- const resolved = {};
36254
- const contextWindow = declared?.contextWindow ?? probed?.contextWindow;
36255
- if (contextWindow !== void 0)
36256
- resolved.contextWindow = contextWindow;
36257
- const maxOutputTokens = declared?.maxOutputTokens ?? probed?.maxOutputTokens;
36258
- if (maxOutputTokens !== void 0)
36259
- resolved.maxOutputTokens = maxOutputTokens;
36260
- if (probed?.reasoning !== void 0)
36261
- resolved.reasoning = probed.reasoning;
36262
- for (const knob of ["temperature", "topP", "topK", "repetitionPenalty"]) {
36263
- const value = declared?.[knob];
36264
- if (typeof value === "number")
36265
- resolved[knob] = value;
36238
+ async function readTierMode(file) {
36239
+ if (file === null)
36240
+ return null;
36241
+ try {
36242
+ const parsed = JSON.parse(await fs15.readFile(file, "utf8"));
36243
+ return coerceMode(parsed?.[exports2.DUET_ROUTING_LOG_KEY]?.mode);
36244
+ } catch {
36245
+ return null;
36266
36246
  }
36267
- return resolved;
36268
- }
36269
- function catalogModelIds2(entry, catalog) {
36270
- return entry.models?.length ? entry.models : catalog.map((model) => model.id);
36271
36247
  }
36272
- function clearEndpointCatalog3(baseUrl) {
36273
- if (baseUrl === void 0) {
36274
- memory.clear();
36275
- inFlight2.clear();
36276
- sweptThisProcess = false;
36277
- return;
36248
+ async function duetRoutingLogMode2(opts = {}) {
36249
+ const home = opts.homeDir ?? os9.homedir();
36250
+ const ws = opts.workspaceRoot ?? null;
36251
+ const key = `${home}\0${ws ?? ""}`;
36252
+ const hit = modeCache.get(key);
36253
+ if (hit !== void 0 && Date.now() - hit.at < MODE_CACHE_TTL_MS)
36254
+ return hit.mode;
36255
+ let mode = exports2.DUET_ROUTING_LOG_DEFAULT_MODE;
36256
+ const tiers = ["user", "project", "local"];
36257
+ for (const tier of tiers) {
36258
+ const found = await readTierMode((0, settingsPaths_js_1.settingsFilePath)(tier, { homeDir: home, workspaceRoot: ws }));
36259
+ if (found !== null)
36260
+ mode = found;
36278
36261
  }
36279
- const key = normalizeBaseUrl(baseUrl);
36280
- memory.delete(key);
36281
- inFlight2.delete(key);
36262
+ modeCache.set(key, { at: Date.now(), mode });
36263
+ return mode;
36282
36264
  }
36283
- async function endpointModelViews2(entry, options = {}) {
36284
- const catalog = await endpointCatalog2(entry, options);
36285
- const pinned = new Set(entry.models ?? []);
36286
- const ids = [...pinned, ...catalog.map((model) => model.id).filter((id) => !pinned.has(id))];
36287
- return ids.map((id) => {
36288
- const resolved = resolveModelSettings2(entry, id, catalog);
36289
- const declared = entry.modelConfig?.[id];
36290
- const view = { id, pinned: pinned.has(id) };
36291
- if (resolved.contextWindow !== void 0)
36292
- view.contextWindow = resolved.contextWindow;
36293
- if (resolved.maxOutputTokens !== void 0)
36294
- view.maxOutputTokens = resolved.maxOutputTokens;
36295
- if (resolved.reasoning !== void 0)
36296
- view.reasoning = resolved.reasoning;
36297
- if (declared?.contextWindow !== void 0 || declared?.maxOutputTokens !== void 0) {
36298
- view.source = "user";
36299
- } else if (view.contextWindow !== void 0 || view.maxOutputTokens !== void 0) {
36300
- view.source = "endpoint";
36301
- }
36302
- return view;
36303
- });
36265
+ function head(text, max) {
36266
+ return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
36304
36267
  }
36305
- async function updateCustomProviderModels2(name2, update, tier = "user", opts = {}) {
36306
- const entry = await (0, customProviders_1.getCustomProvider)(name2, opts);
36307
- if (entry === null)
36308
- return false;
36309
- const next = { ...entry };
36310
- if (update.models !== void 0) {
36311
- if (update.models.length)
36312
- next.models = update.models;
36313
- else
36314
- delete next.models;
36268
+ function redactRowForMode(row, mode) {
36269
+ if (mode === "off")
36270
+ return null;
36271
+ if (mode === "full")
36272
+ return row;
36273
+ if (row.kind === "planner") {
36274
+ return row.brief === void 0 ? row : { ...row, brief: head(row.brief, exports2.DUET_ROUTING_LOG_HEAD_CHARS) };
36315
36275
  }
36316
- if (update.modelConfig !== void 0) {
36317
- const kept = Object.entries(update.modelConfig).map(([id, raw]) => [id, (0, customProviders_1.normalizeModelConfig)(raw)]).filter(([, value]) => value !== void 0 && Object.keys(value).length > 0);
36318
- if (kept.length)
36319
- next.modelConfig = Object.fromEntries(kept);
36320
- else
36321
- delete next.modelConfig;
36276
+ if (row.kind !== "decision")
36277
+ return row;
36278
+ return {
36279
+ ...row,
36280
+ prompt: head(row.prompt, exports2.DUET_ROUTING_LOG_HEAD_CHARS),
36281
+ assumptions: row.assumptions.map((a) => ({ id: a.id, text: head(a.text, 100) }))
36282
+ };
36283
+ }
36284
+ var writeQueues = /* @__PURE__ */ new Map();
36285
+ async function writeRow(row, file, opts) {
36286
+ const redacted = redactRowForMode(row, await duetRoutingLogMode2(opts));
36287
+ if (redacted === null)
36288
+ return;
36289
+ await fs15.mkdir(path14.dirname(file), { recursive: true });
36290
+ try {
36291
+ const stat = await fs15.stat(file);
36292
+ if (stat.size >= exports2.DUET_ROUTING_LOG_MAX_BYTES)
36293
+ await fs15.rename(file, `${file}.1`);
36294
+ } catch {
36322
36295
  }
36323
- await (0, customProviders_1.saveCustomProvider)(next, tier, opts);
36324
- clearEndpointCatalog3(entry.baseUrl);
36325
- return true;
36296
+ await fs15.appendFile(file, `${JSON.stringify(redacted)}
36297
+ `, "utf8");
36326
36298
  }
36327
- }
36328
- });
36329
-
36330
- // ../packages/orion-client-core/dist/duetExecutorCatalog.js
36331
- var require_duetExecutorCatalog = __commonJS({
36332
- "../packages/orion-client-core/dist/duetExecutorCatalog.js"(exports2) {
36333
- "use strict";
36334
- Object.defineProperty(exports2, "__esModule", { value: true });
36335
- exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = void 0;
36336
- exports2.localExecutorOptions = localExecutorOptions2;
36337
- exports2.duetExecutorChoiceFor = duetExecutorChoiceFor2;
36338
- exports2.isLocalExecutorChoice = isLocalExecutorChoice;
36339
- exports2.resolveDuetExecutorChoice = resolveDuetExecutorChoice2;
36340
- var customProviders_js_1 = require_customProviders();
36341
- var customProviderModels_js_1 = require_customProviderModels();
36342
- exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = 3e3;
36343
- async function localExecutorOptions2(input = {}) {
36344
- const { catalog, timeoutMs, ...opts } = input;
36345
- let entries;
36299
+ async function appendDuetRoutingRow(row, opts = {}) {
36300
+ const file = duetRoutingLogPath2(opts);
36301
+ const previous = writeQueues.get(file) ?? Promise.resolve();
36302
+ const next = previous.then(() => writeRow(row, file, opts)).catch(() => void 0);
36303
+ writeQueues.set(file, next);
36304
+ await next;
36305
+ if (writeQueues.get(file) === next)
36306
+ writeQueues.delete(file);
36307
+ }
36308
+ async function readDuetRoutingLog2(opts = {}) {
36309
+ let text;
36346
36310
  try {
36347
- entries = await (0, customProviders_js_1.loadCustomProviders)(opts);
36311
+ text = await fs15.readFile(duetRoutingLogPath2(opts), "utf8");
36348
36312
  } catch {
36349
36313
  return [];
36350
36314
  }
36351
- if (entries.length === 0)
36352
- return [];
36353
- const read = (options) => Promise.all(entries.map(async (entry) => {
36315
+ const rows = [];
36316
+ for (const line of text.split("\n")) {
36317
+ if (line.trim() === "")
36318
+ continue;
36354
36319
  try {
36355
- const views = await (0, customProviderModels_js_1.endpointModelViews)(entry, options);
36356
- return views.map((view) => {
36357
- const option = {
36358
- provider: `custom:${entry.name}`,
36359
- endpoint: entry.name,
36360
- model: view.id,
36361
- pinned: view.pinned
36362
- };
36363
- if (view.contextWindow !== void 0)
36364
- option.contextWindow = view.contextWindow;
36365
- if (view.maxOutputTokens !== void 0)
36366
- option.maxOutputTokens = view.maxOutputTokens;
36367
- return option;
36368
- });
36320
+ const parsed = JSON.parse(line);
36321
+ if (parsed.kind === "decision" || parsed.kind === "turn_end" || parsed.kind === "followup" || parsed.kind === "planner") {
36322
+ rows.push(parsed);
36323
+ }
36369
36324
  } catch {
36370
- return [];
36371
36325
  }
36372
- })).then((perEndpoint) => perEndpoint.flat());
36373
- const full = read(catalog ?? {});
36374
- const budget = timeoutMs ?? exports2.LOCAL_EXECUTOR_READ_BUDGET_MS;
36375
- if (catalog?.cachedOnly === true || budget <= 0)
36376
- return full;
36377
- let timer;
36378
- const fallback = new Promise((resolve5) => {
36379
- timer = setTimeout(() => resolve5(read({ ...catalog, cachedOnly: true })), budget);
36380
- });
36381
- try {
36382
- return await Promise.race([full, fallback]);
36383
- } finally {
36384
- if (timer !== void 0)
36385
- clearTimeout(timer);
36386
- void full.catch(() => void 0);
36387
36326
  }
36327
+ return rows;
36388
36328
  }
36389
- function duetExecutorChoiceFor2(option) {
36390
- return {
36391
- provider: option.provider,
36392
- model: option.model,
36393
- ...option.contextWindow !== void 0 ? { contextWindow: option.contextWindow } : {}
36329
+ function summarizeDuetRoutingLog2(rows) {
36330
+ const summary = {
36331
+ decisions: 0,
36332
+ routes: { plan: 0, execute: 0 },
36333
+ stage1PlanReasons: {},
36334
+ advisorEvaluated: 0,
36335
+ advisorFlagged: {},
36336
+ turnEnds: { completed: 0, error: 0, cancelled: 0 },
36337
+ followups: 0,
36338
+ missedEscalations: 0,
36339
+ flaggedWithoutNewPlan: 0,
36340
+ flaggedBarelyChanged: 0,
36341
+ repeats: 0,
36342
+ entries: { planner: 0, router: 0, executor: 0 },
36343
+ plannerVerdicts: { hand_off: 0, plan: 0 }
36394
36344
  };
36395
- }
36396
- function isLocalExecutorChoice(choice) {
36397
- return typeof choice?.provider === "string" && choice.provider.startsWith("custom:");
36398
- }
36399
- async function resolveDuetExecutorChoice2(choice, input = {}) {
36400
- if (!isLocalExecutorChoice(choice) || choice.contextWindow !== void 0)
36401
- return choice;
36402
- const found = (await localExecutorOptions2(input)).find((option) => option.provider === choice.provider && option.model === choice.model);
36403
- return found === void 0 ? choice : { ...choice, ...duetExecutorChoiceFor2(found), ...choice.effort ? { effort: choice.effort } : {} };
36404
- }
36405
- }
36406
- });
36407
-
36408
- // ../packages/orion-client-core/dist/duetRoutingSignals.js
36409
- var require_duetRoutingSignals = __commonJS({
36410
- "../packages/orion-client-core/dist/duetRoutingSignals.js"(exports2) {
36411
- "use strict";
36345
+ const decisions = /* @__PURE__ */ new Map();
36346
+ for (const row of rows) {
36347
+ if (row.kind !== "decision")
36348
+ continue;
36349
+ decisions.set(row.id, row);
36350
+ summary.decisions += 1;
36351
+ summary.routes[row.route] += 1;
36352
+ summary.entries[row.entry ?? "router"] += 1;
36353
+ if (row.stage1.verdict === "plan") {
36354
+ summary.stage1PlanReasons[row.stage1.reason] = (summary.stage1PlanReasons[row.stage1.reason] ?? 0) + 1;
36355
+ }
36356
+ if (row.advisor !== null) {
36357
+ summary.advisorEvaluated += 1;
36358
+ if (row.advisor.reason !== null) {
36359
+ summary.advisorFlagged[row.advisor.reason] = (summary.advisorFlagged[row.advisor.reason] ?? 0) + 1;
36360
+ }
36361
+ }
36362
+ }
36363
+ for (const row of rows) {
36364
+ if (row.kind === "turn_end") {
36365
+ summary.turnEnds[row.outcome] += 1;
36366
+ } else if (row.kind === "planner") {
36367
+ summary.plannerVerdicts[row.verdict] += 1;
36368
+ } else if (row.kind === "followup") {
36369
+ summary.followups += 1;
36370
+ const decided = decisions.get(row.decisionId);
36371
+ if (row.nextPromptSimilarity !== null && row.nextPromptSimilarity >= 0.8)
36372
+ summary.repeats += 1;
36373
+ if (decided === void 0)
36374
+ continue;
36375
+ if (decided.route === "execute" && (row.replanActor || row.nextExplicitPlanRequest)) {
36376
+ summary.missedEscalations += 1;
36377
+ }
36378
+ if (decided.advisor?.flagged) {
36379
+ if (!row.planVersionChanged)
36380
+ summary.flaggedWithoutNewPlan += 1;
36381
+ else if (row.planDiffRatio !== null && row.planDiffRatio < 0.1)
36382
+ summary.flaggedBarelyChanged += 1;
36383
+ }
36384
+ }
36385
+ }
36386
+ return summary;
36387
+ }
36388
+ function formatDuetRoutingLogSummary2(summary, file, mode) {
36389
+ const byKey = (m2) => Object.entries(m2).sort((a, b2) => b2[1] - a[1]).map(([k, n]) => `${k} ${n}`).join(", ") || "none";
36390
+ return [
36391
+ `Duet routing journal: ${file} (mode: ${mode})`,
36392
+ `decisions ${summary.decisions} \u2014 plan ${summary.routes.plan}, execute ${summary.routes.execute}`,
36393
+ `entry: planner ${summary.entries.planner}, router ${summary.entries.router}, executor ${summary.entries.executor}`,
36394
+ `planner verdicts: handed off ${summary.plannerVerdicts.hand_off}, planned ${summary.plannerVerdicts.plan}`,
36395
+ `stage-1 plan rules: ${byKey(summary.stage1PlanReasons)}`,
36396
+ `advisor evaluated ${summary.advisorEvaluated}; flagged: ${byKey(summary.advisorFlagged)}`,
36397
+ `turn ends \u2014 completed ${summary.turnEnds.completed}, error ${summary.turnEnds.error}, cancelled ${summary.turnEnds.cancelled}`,
36398
+ `follow-ups ${summary.followups} \u2014 missed escalations ${summary.missedEscalations}, flagged without a new plan ${summary.flaggedWithoutNewPlan}, flagged but barely changed ${summary.flaggedBarelyChanged}, repeats ${summary.repeats}`
36399
+ ];
36400
+ }
36401
+ }
36402
+ });
36403
+
36404
+ // ../packages/orion-client-core/dist/duetRoutingSignals.js
36405
+ var require_duetRoutingSignals = __commonJS({
36406
+ "../packages/orion-client-core/dist/duetRoutingSignals.js"(exports2) {
36407
+ "use strict";
36412
36408
  Object.defineProperty(exports2, "__esModule", { value: true });
36413
36409
  exports2.ROUTING_JUDGE_MAX_TOKENS = exports2.ROUTING_JUDGE_TIMEOUT_MS = exports2.ROUTING_SIGNAL_TIMEOUT_MS = void 0;
36414
36410
  exports2.cosineSimilarity = cosineSimilarity;
@@ -36584,276 +36580,6 @@ Does this message invalidate any plan assumption or require architectural re-pla
36584
36580
  }
36585
36581
  });
36586
36582
 
36587
- // ../packages/orion-client-core/dist/duetRoutingLog.js
36588
- var require_duetRoutingLog = __commonJS({
36589
- "../packages/orion-client-core/dist/duetRoutingLog.js"(exports2) {
36590
- "use strict";
36591
- var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
36592
- if (k2 === void 0) k2 = k;
36593
- var desc = Object.getOwnPropertyDescriptor(m2, k);
36594
- if (!desc || ("get" in desc ? !m2.__esModule : desc.writable || desc.configurable)) {
36595
- desc = { enumerable: true, get: function() {
36596
- return m2[k];
36597
- } };
36598
- }
36599
- Object.defineProperty(o, k2, desc);
36600
- } : function(o, m2, k, k2) {
36601
- if (k2 === void 0) k2 = k;
36602
- o[k2] = m2[k];
36603
- });
36604
- var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v2) {
36605
- Object.defineProperty(o, "default", { enumerable: true, value: v2 });
36606
- } : function(o, v2) {
36607
- o["default"] = v2;
36608
- });
36609
- var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
36610
- var ownKeys = function(o) {
36611
- ownKeys = Object.getOwnPropertyNames || function(o2) {
36612
- var ar = [];
36613
- for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
36614
- return ar;
36615
- };
36616
- return ownKeys(o);
36617
- };
36618
- return function(mod2) {
36619
- if (mod2 && mod2.__esModule) return mod2;
36620
- var result = {};
36621
- if (mod2 != null) {
36622
- for (var k = ownKeys(mod2), i2 = 0; i2 < k.length; i2++) if (k[i2] !== "default") __createBinding(result, mod2, k[i2]);
36623
- }
36624
- __setModuleDefault(result, mod2);
36625
- return result;
36626
- };
36627
- }();
36628
- Object.defineProperty(exports2, "__esModule", { value: true });
36629
- exports2.DUET_ROUTING_LOG_DEFAULT_MODE = exports2.DUET_ROUTING_LOG_KEY = exports2.DUET_ROUTING_LOG_HEAD_CHARS = exports2.DUET_ROUTING_LOG_MAX_BYTES = exports2.DUET_ROUTING_LOG_SCHEMA = void 0;
36630
- exports2.duetRoutingLogPath = duetRoutingLogPath2;
36631
- exports2.newDecisionId = newDecisionId;
36632
- exports2.sessionKey = sessionKey;
36633
- exports2.lexicalSimilarity = lexicalSimilarity;
36634
- exports2.planDiffRatio = planDiffRatio;
36635
- exports2.clearDuetRoutingLogCache = clearDuetRoutingLogCache;
36636
- exports2.duetRoutingLogMode = duetRoutingLogMode2;
36637
- exports2.redactRowForMode = redactRowForMode;
36638
- exports2.appendDuetRoutingRow = appendDuetRoutingRow;
36639
- exports2.readDuetRoutingLog = readDuetRoutingLog2;
36640
- exports2.summarizeDuetRoutingLog = summarizeDuetRoutingLog2;
36641
- exports2.formatDuetRoutingLogSummary = formatDuetRoutingLogSummary2;
36642
- var node_crypto_1 = __require("node:crypto");
36643
- var fs15 = __importStar(__require("node:fs/promises"));
36644
- var os9 = __importStar(__require("node:os"));
36645
- var path14 = __importStar(__require("node:path"));
36646
- var settingsPaths_js_1 = require_settingsPaths();
36647
- exports2.DUET_ROUTING_LOG_SCHEMA = 3;
36648
- exports2.DUET_ROUTING_LOG_MAX_BYTES = 5 * 1024 * 1024;
36649
- exports2.DUET_ROUTING_LOG_HEAD_CHARS = 200;
36650
- exports2.DUET_ROUTING_LOG_KEY = "duetRoutingLog";
36651
- exports2.DUET_ROUTING_LOG_DEFAULT_MODE = "full";
36652
- function duetRoutingLogPath2(opts = {}) {
36653
- return path14.join(opts.homeDir ?? os9.homedir(), ".orion", "duet-routing-decisions.jsonl");
36654
- }
36655
- function newDecisionId() {
36656
- return (0, node_crypto_1.randomUUID)();
36657
- }
36658
- function sessionKey(sessionId) {
36659
- if (sessionId === void 0 || sessionId === "")
36660
- return void 0;
36661
- return (0, node_crypto_1.createHash)("sha256").update(sessionId).digest("hex").slice(0, 12);
36662
- }
36663
- function tokens(text) {
36664
- return new Set(text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length > 1));
36665
- }
36666
- function jaccard(a, b2) {
36667
- if (a.size === 0 && b2.size === 0)
36668
- return 1;
36669
- let inter = 0;
36670
- for (const t of a)
36671
- if (b2.has(t))
36672
- inter += 1;
36673
- const union = a.size + b2.size - inter;
36674
- return union === 0 ? 0 : inter / union;
36675
- }
36676
- function lexicalSimilarity(a, b2) {
36677
- return Math.round(jaccard(tokens(a), tokens(b2)) * 1e3) / 1e3;
36678
- }
36679
- function planDiffRatio(before, after) {
36680
- const lines = (plan) => new Set(plan.split(/\r?\n/).map((l3) => l3.trim()).filter((l3) => l3 !== ""));
36681
- return Math.round((1 - jaccard(lines(before), lines(after))) * 1e3) / 1e3;
36682
- }
36683
- var MODE_CACHE_TTL_MS = 5e3;
36684
- var modeCache = /* @__PURE__ */ new Map();
36685
- function clearDuetRoutingLogCache() {
36686
- modeCache.clear();
36687
- }
36688
- function coerceMode(raw) {
36689
- return raw === "full" || raw === "head" || raw === "off" ? raw : null;
36690
- }
36691
- async function readTierMode(file) {
36692
- if (file === null)
36693
- return null;
36694
- try {
36695
- const parsed = JSON.parse(await fs15.readFile(file, "utf8"));
36696
- return coerceMode(parsed?.[exports2.DUET_ROUTING_LOG_KEY]?.mode);
36697
- } catch {
36698
- return null;
36699
- }
36700
- }
36701
- async function duetRoutingLogMode2(opts = {}) {
36702
- const home = opts.homeDir ?? os9.homedir();
36703
- const ws = opts.workspaceRoot ?? null;
36704
- const key = `${home}\0${ws ?? ""}`;
36705
- const hit = modeCache.get(key);
36706
- if (hit !== void 0 && Date.now() - hit.at < MODE_CACHE_TTL_MS)
36707
- return hit.mode;
36708
- let mode = exports2.DUET_ROUTING_LOG_DEFAULT_MODE;
36709
- const tiers = ["user", "project", "local"];
36710
- for (const tier of tiers) {
36711
- const found = await readTierMode((0, settingsPaths_js_1.settingsFilePath)(tier, { homeDir: home, workspaceRoot: ws }));
36712
- if (found !== null)
36713
- mode = found;
36714
- }
36715
- modeCache.set(key, { at: Date.now(), mode });
36716
- return mode;
36717
- }
36718
- function head(text, max) {
36719
- return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
36720
- }
36721
- function redactRowForMode(row, mode) {
36722
- if (mode === "off")
36723
- return null;
36724
- if (mode === "full")
36725
- return row;
36726
- if (row.kind === "planner") {
36727
- return row.brief === void 0 ? row : { ...row, brief: head(row.brief, exports2.DUET_ROUTING_LOG_HEAD_CHARS) };
36728
- }
36729
- if (row.kind !== "decision")
36730
- return row;
36731
- return {
36732
- ...row,
36733
- prompt: head(row.prompt, exports2.DUET_ROUTING_LOG_HEAD_CHARS),
36734
- assumptions: row.assumptions.map((a) => ({ id: a.id, text: head(a.text, 100) }))
36735
- };
36736
- }
36737
- var writeQueues = /* @__PURE__ */ new Map();
36738
- async function writeRow(row, file, opts) {
36739
- const redacted = redactRowForMode(row, await duetRoutingLogMode2(opts));
36740
- if (redacted === null)
36741
- return;
36742
- await fs15.mkdir(path14.dirname(file), { recursive: true });
36743
- try {
36744
- const stat = await fs15.stat(file);
36745
- if (stat.size >= exports2.DUET_ROUTING_LOG_MAX_BYTES)
36746
- await fs15.rename(file, `${file}.1`);
36747
- } catch {
36748
- }
36749
- await fs15.appendFile(file, `${JSON.stringify(redacted)}
36750
- `, "utf8");
36751
- }
36752
- async function appendDuetRoutingRow(row, opts = {}) {
36753
- const file = duetRoutingLogPath2(opts);
36754
- const previous = writeQueues.get(file) ?? Promise.resolve();
36755
- const next = previous.then(() => writeRow(row, file, opts)).catch(() => void 0);
36756
- writeQueues.set(file, next);
36757
- await next;
36758
- if (writeQueues.get(file) === next)
36759
- writeQueues.delete(file);
36760
- }
36761
- async function readDuetRoutingLog2(opts = {}) {
36762
- let text;
36763
- try {
36764
- text = await fs15.readFile(duetRoutingLogPath2(opts), "utf8");
36765
- } catch {
36766
- return [];
36767
- }
36768
- const rows = [];
36769
- for (const line of text.split("\n")) {
36770
- if (line.trim() === "")
36771
- continue;
36772
- try {
36773
- const parsed = JSON.parse(line);
36774
- if (parsed.kind === "decision" || parsed.kind === "turn_end" || parsed.kind === "followup" || parsed.kind === "planner") {
36775
- rows.push(parsed);
36776
- }
36777
- } catch {
36778
- }
36779
- }
36780
- return rows;
36781
- }
36782
- function summarizeDuetRoutingLog2(rows) {
36783
- const summary = {
36784
- decisions: 0,
36785
- routes: { plan: 0, execute: 0 },
36786
- stage1PlanReasons: {},
36787
- advisorEvaluated: 0,
36788
- advisorFlagged: {},
36789
- turnEnds: { completed: 0, error: 0, cancelled: 0 },
36790
- followups: 0,
36791
- missedEscalations: 0,
36792
- flaggedWithoutNewPlan: 0,
36793
- flaggedBarelyChanged: 0,
36794
- repeats: 0,
36795
- entries: { planner: 0, router: 0 },
36796
- plannerVerdicts: { hand_off: 0, plan: 0 }
36797
- };
36798
- const decisions = /* @__PURE__ */ new Map();
36799
- for (const row of rows) {
36800
- if (row.kind !== "decision")
36801
- continue;
36802
- decisions.set(row.id, row);
36803
- summary.decisions += 1;
36804
- summary.routes[row.route] += 1;
36805
- summary.entries[row.entry ?? "router"] += 1;
36806
- if (row.stage1.verdict === "plan") {
36807
- summary.stage1PlanReasons[row.stage1.reason] = (summary.stage1PlanReasons[row.stage1.reason] ?? 0) + 1;
36808
- }
36809
- if (row.advisor !== null) {
36810
- summary.advisorEvaluated += 1;
36811
- if (row.advisor.reason !== null) {
36812
- summary.advisorFlagged[row.advisor.reason] = (summary.advisorFlagged[row.advisor.reason] ?? 0) + 1;
36813
- }
36814
- }
36815
- }
36816
- for (const row of rows) {
36817
- if (row.kind === "turn_end") {
36818
- summary.turnEnds[row.outcome] += 1;
36819
- } else if (row.kind === "planner") {
36820
- summary.plannerVerdicts[row.verdict] += 1;
36821
- } else if (row.kind === "followup") {
36822
- summary.followups += 1;
36823
- const decided = decisions.get(row.decisionId);
36824
- if (row.nextPromptSimilarity !== null && row.nextPromptSimilarity >= 0.8)
36825
- summary.repeats += 1;
36826
- if (decided === void 0)
36827
- continue;
36828
- if (decided.route === "execute" && (row.replanActor || row.nextExplicitPlanRequest)) {
36829
- summary.missedEscalations += 1;
36830
- }
36831
- if (decided.advisor?.flagged) {
36832
- if (!row.planVersionChanged)
36833
- summary.flaggedWithoutNewPlan += 1;
36834
- else if (row.planDiffRatio !== null && row.planDiffRatio < 0.1)
36835
- summary.flaggedBarelyChanged += 1;
36836
- }
36837
- }
36838
- }
36839
- return summary;
36840
- }
36841
- function formatDuetRoutingLogSummary2(summary, file, mode) {
36842
- const byKey = (m2) => Object.entries(m2).sort((a, b2) => b2[1] - a[1]).map(([k, n]) => `${k} ${n}`).join(", ") || "none";
36843
- return [
36844
- `Duet routing journal: ${file} (mode: ${mode})`,
36845
- `decisions ${summary.decisions} \u2014 plan ${summary.routes.plan}, execute ${summary.routes.execute}`,
36846
- `entry: planner ${summary.entries.planner}, router ${summary.entries.router}`,
36847
- `planner verdicts: handed off ${summary.plannerVerdicts.hand_off}, planned ${summary.plannerVerdicts.plan}`,
36848
- `stage-1 plan rules: ${byKey(summary.stage1PlanReasons)}`,
36849
- `advisor evaluated ${summary.advisorEvaluated}; flagged: ${byKey(summary.advisorFlagged)}`,
36850
- `turn ends \u2014 completed ${summary.turnEnds.completed}, error ${summary.turnEnds.error}, cancelled ${summary.turnEnds.cancelled}`,
36851
- `follow-ups ${summary.followups} \u2014 missed escalations ${summary.missedEscalations}, flagged without a new plan ${summary.flaggedWithoutNewPlan}, flagged but barely changed ${summary.flaggedBarelyChanged}, repeats ${summary.repeats}`
36852
- ];
36853
- }
36854
- }
36855
- });
36856
-
36857
36583
  // ../packages/orion-client-core/dist/duetRoutingAdvisor.js
36858
36584
  var require_duetRoutingAdvisor = __commonJS({
36859
36585
  "../packages/orion-client-core/dist/duetRoutingAdvisor.js"(exports2) {
@@ -37180,13 +36906,23 @@ var require_duetRoutingAdvisor = __commonJS({
37180
36906
  } catch {
37181
36907
  }
37182
36908
  }
37183
- function stage1Verdict(record, text, entry) {
36909
+ function scorerReason(verdict, highRisk) {
36910
+ const base = verdict.source === "executor_gate" ? "executor_gate" : "router_model";
36911
+ return highRisk ? `${base}_high_risk` : base;
36912
+ }
36913
+ function stage1Verdict(record, text, entry, verdict = null) {
37184
36914
  if ((0, duetPlan_js_1.explicitPlanRequest)(text))
37185
36915
  return { verdict: "plan", reason: "explicit_plan_request" };
37186
36916
  if (record === null) {
37187
36917
  if ((0, duetPlan_js_1.highRiskRequest)(text))
37188
36918
  return { verdict: "plan", reason: "plan_invalid" };
37189
- return entry === "planner" ? { verdict: "plan", reason: "planner_entry" } : { verdict: "execute", reason: "no_plan" };
36919
+ if (entry === "planner")
36920
+ return { verdict: "plan", reason: "planner_entry" };
36921
+ if (verdict?.verdict === "plan")
36922
+ return { verdict: "plan", reason: scorerReason(verdict, false) };
36923
+ if (verdict?.highRisk)
36924
+ return { verdict: "plan", reason: scorerReason(verdict, true) };
36925
+ return { verdict: "execute", reason: "no_plan" };
37190
36926
  }
37191
36927
  if (record.scopeChanged)
37192
36928
  return { verdict: "plan", reason: "scope_changed" };
@@ -37200,6 +36936,8 @@ var require_duetRoutingAdvisor = __commonJS({
37200
36936
  if (entry === "planner") {
37201
36937
  return (0, duetPlan_js_1.continuationRequest)(text) ? { verdict: "execute", reason: "continuation" } : { verdict: "plan", reason: "planner_entry" };
37202
36938
  }
36939
+ if (verdict?.verdict === "plan")
36940
+ return { verdict: "plan", reason: scorerReason(verdict, false) };
37203
36941
  return { verdict: "execute", reason: "plan_valid" };
37204
36942
  }
37205
36943
  function executorContext(workspaceRoot) {
@@ -37274,7 +37012,10 @@ var require_duetRoutingAdvisor = __commonJS({
37274
37012
  asksForPlan: input.routerVerdict.asksForPlan,
37275
37013
  highRisk: input.routerVerdict.highRisk,
37276
37014
  reason: input.routerVerdict.reason,
37277
- latencyMs: input.routerVerdict.latencyMs
37015
+ latencyMs: input.routerVerdict.latencyMs,
37016
+ source: input.routerVerdict.source,
37017
+ ...input.routerVerdict.margin !== void 0 ? { margin: Math.round(input.routerVerdict.margin * 1e6) / 1e6 } : {},
37018
+ ...input.routerVerdict.mode !== void 0 ? { mode: input.routerVerdict.mode } : {}
37278
37019
  } : null;
37279
37020
  const sink = sinkFor(input.log, input.homeDir, input.workspaceRoot);
37280
37021
  try {
@@ -37325,7 +37066,7 @@ var require_duetRoutingAdvisor = __commonJS({
37325
37066
  if (standing === null) {
37326
37067
  resetForVersion(state, null);
37327
37068
  if (text !== "") {
37328
- const stage12 = stage1Verdict(null, text, entry);
37069
+ const stage12 = stage1Verdict(null, text, entry, input.routerVerdict ?? null);
37329
37070
  journal(stage12, null, stage12.verdict, []);
37330
37071
  }
37331
37072
  return untouched(record);
@@ -37337,7 +37078,7 @@ var require_duetRoutingAdvisor = __commonJS({
37337
37078
  if (text === "")
37338
37079
  return untouched(record);
37339
37080
  const assumptions = parsePlanAssumptions(plan.plan);
37340
- const stage1 = stage1Verdict(plan, text, entry);
37081
+ const stage1 = stage1Verdict(plan, text, entry, input.routerVerdict ?? null);
37341
37082
  if (stage1.verdict === "plan") {
37342
37083
  journal(stage1, null, "plan", assumptions);
37343
37084
  return untouched(record);
@@ -37386,82 +37127,953 @@ var require_duetRoutingAdvisor = __commonJS({
37386
37127
  }, now2);
37387
37128
  }
37388
37129
  }
37389
- if (candidate !== null && state.turnsUnderVersion < exports2.DUET_ADVISOR_THRESHOLDS.cooldownTurns) {
37390
- decision.guards.cooldown = true;
37391
- candidate = null;
37392
- }
37393
- let advised = plan;
37394
- if (candidate !== null) {
37395
- advised = candidate.flag === "user_negative_feedback" ? { ...plan, userNegativeFeedback: true } : { ...plan, architectureDecisionRequired: true };
37396
- decision.flagged = candidate.flag;
37397
- decision.reason = candidate.reason;
37398
- }
37399
- decision.latencyMs = Math.max(0, now2() - started);
37400
- journal(stage1, decision, decision.flagged !== null ? "plan" : "execute", assumptions);
37401
- return {
37402
- record: advised,
37403
- flagged: decision.flagged,
37404
- reason: decision.reason,
37405
- assumptionIds: candidate?.ids ?? [],
37406
- decision,
37407
- note: duetRoutingAdviceNote(decision.reason, candidate?.ids ?? [])
37408
- };
37130
+ if (candidate !== null && state.turnsUnderVersion < exports2.DUET_ADVISOR_THRESHOLDS.cooldownTurns) {
37131
+ decision.guards.cooldown = true;
37132
+ candidate = null;
37133
+ }
37134
+ let advised = plan;
37135
+ if (candidate !== null) {
37136
+ advised = candidate.flag === "user_negative_feedback" ? { ...plan, userNegativeFeedback: true } : { ...plan, architectureDecisionRequired: true };
37137
+ decision.flagged = candidate.flag;
37138
+ decision.reason = candidate.reason;
37139
+ }
37140
+ decision.latencyMs = Math.max(0, now2() - started);
37141
+ journal(stage1, decision, decision.flagged !== null ? "plan" : "execute", assumptions);
37142
+ return {
37143
+ record: advised,
37144
+ flagged: decision.flagged,
37145
+ reason: decision.reason,
37146
+ assumptionIds: candidate?.ids ?? [],
37147
+ decision,
37148
+ note: duetRoutingAdviceNote(decision.reason, candidate?.ids ?? [])
37149
+ };
37150
+ } catch {
37151
+ return untouched(record);
37152
+ }
37153
+ }
37154
+ function round3(value) {
37155
+ return Math.round(value * 1e3) / 1e3;
37156
+ }
37157
+ async function describeDuetRouting2(workspaceRoot) {
37158
+ try {
37159
+ const choice = await (0, duetMode_js_1.loadDuetExecutor)({ workspaceRoot: workspaceRoot ?? null });
37160
+ if (choice === null || !(0, customProviders_js_1.isCustomProviderRef)(choice.provider))
37161
+ return { kind: "platform" };
37162
+ const name2 = (0, customProviders_js_1.parseCustomProviderRef)(choice.provider) ?? "";
37163
+ const entry = await (0, customProviders_js_1.getCustomProvider)(name2, { workspaceRoot: workspaceRoot ?? null });
37164
+ if (entry === null)
37165
+ return { kind: "missing", name: name2 };
37166
+ return {
37167
+ kind: "local",
37168
+ name: name2,
37169
+ loopback: (0, customProviders_js_1.isLoopbackEndpoint)(entry.baseUrl),
37170
+ embeddings: entry.routingModels?.embeddings !== void 0,
37171
+ rerank: entry.routingModels?.rerank !== void 0,
37172
+ judge: entry.routingModels?.judge ?? null
37173
+ };
37174
+ } catch {
37175
+ return { kind: "platform" };
37176
+ }
37177
+ }
37178
+ function duetRoutingSummaryLine2(summary) {
37179
+ switch (summary.kind) {
37180
+ case "platform":
37181
+ return "Duet routing: rules only \u2014 a local executor with routing models unlocks re-ask detection and plan-assumption checks.";
37182
+ case "missing":
37183
+ return "Duet routing: rules only.";
37184
+ case "local": {
37185
+ const { name: name2, loopback, embeddings, rerank } = summary;
37186
+ if (!embeddings && !rerank) {
37187
+ return `Duet routing: rules only \u2014 add routingModels to '${name2}' to unlock re-ask detection and plan-assumption checks (the /local-ai skill can set this up).`;
37188
+ }
37189
+ if (!loopback) {
37190
+ return `Duet routing: rules only \u2014 semantic checks run only against a loopback endpoint, and '${name2}' is not one.`;
37191
+ }
37192
+ const parts2 = [];
37193
+ const via = [];
37194
+ if (embeddings) {
37195
+ parts2.push("re-ask detection");
37196
+ via.push("embeddings");
37197
+ }
37198
+ if (rerank) {
37199
+ parts2.push("plan-assumption checks");
37200
+ via.push("rerank");
37201
+ }
37202
+ return `Duet routing: rules + ${parts2.join(" + ")} (${via.join(" + ")} on '${name2}').`;
37203
+ }
37204
+ }
37205
+ }
37206
+ }
37207
+ });
37208
+
37209
+ // ../packages/orion-client-core/dist/duetExecutorGate.js
37210
+ var require_duetExecutorGate = __commonJS({
37211
+ "../packages/orion-client-core/dist/duetExecutorGate.js"(exports2) {
37212
+ "use strict";
37213
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
37214
+ if (k2 === void 0) k2 = k;
37215
+ var desc = Object.getOwnPropertyDescriptor(m2, k);
37216
+ if (!desc || ("get" in desc ? !m2.__esModule : desc.writable || desc.configurable)) {
37217
+ desc = { enumerable: true, get: function() {
37218
+ return m2[k];
37219
+ } };
37220
+ }
37221
+ Object.defineProperty(o, k2, desc);
37222
+ } : function(o, m2, k, k2) {
37223
+ if (k2 === void 0) k2 = k;
37224
+ o[k2] = m2[k];
37225
+ });
37226
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v2) {
37227
+ Object.defineProperty(o, "default", { enumerable: true, value: v2 });
37228
+ } : function(o, v2) {
37229
+ o["default"] = v2;
37230
+ });
37231
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
37232
+ var ownKeys = function(o) {
37233
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
37234
+ var ar = [];
37235
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
37236
+ return ar;
37237
+ };
37238
+ return ownKeys(o);
37239
+ };
37240
+ return function(mod2) {
37241
+ if (mod2 && mod2.__esModule) return mod2;
37242
+ var result = {};
37243
+ if (mod2 != null) {
37244
+ for (var k = ownKeys(mod2), i2 = 0; i2 < k.length; i2++) if (k[i2] !== "default") __createBinding(result, mod2, k[i2]);
37245
+ }
37246
+ __setModuleDefault(result, mod2);
37247
+ return result;
37248
+ };
37249
+ }();
37250
+ Object.defineProperty(exports2, "__esModule", { value: true });
37251
+ exports2.EXECUTOR_GATE_PROBE_SCENARIOS = exports2.EXECUTOR_GATE_MIN_CALIBRATION = exports2.EXECUTOR_GATE_MISSING_LOGPROB = exports2.EXECUTOR_GATE_PLAN_HEAD_CHARS = exports2.EXECUTOR_GATE_REQUEST_MAX_CHARS = exports2.EXECUTOR_GATE_STATUS_TTL_MS = exports2.EXECUTOR_GATE_TIMEOUT_MS = exports2.EXECUTOR_GATE_PROMPT_VERSION = exports2.EXECUTOR_GATE_SOURCE = void 0;
37252
+ exports2.resolveExecutorGateTarget = resolveExecutorGateTarget;
37253
+ exports2.resolveExecutorGateTargetFromSettings = resolveExecutorGateTargetFromSettings;
37254
+ exports2.executorGateStateFrom = executorGateStateFrom;
37255
+ exports2.renderExecutorGatePrompt = renderExecutorGatePrompt;
37256
+ exports2.executorGateLetterOf = executorGateLetterOf;
37257
+ exports2.parseExecutorGateResponse = parseExecutorGateResponse;
37258
+ exports2.decideExecutorGate = decideExecutorGate;
37259
+ exports2.askExecutorGate = askExecutorGate;
37260
+ exports2.executorGateProbeState = executorGateProbeState;
37261
+ exports2.probeExecutorGate = probeExecutorGate;
37262
+ exports2.describeDuetExecutorGate = describeDuetExecutorGate;
37263
+ exports2.clearDuetExecutorGateCache = clearDuetExecutorGateCache;
37264
+ exports2.describeDuetExecutorGateCached = describeDuetExecutorGateCached2;
37265
+ exports2.createDuetExecutorGate = createDuetExecutorGate2;
37266
+ var os9 = __importStar(__require("node:os"));
37267
+ var customProviders_js_1 = require_customProviders();
37268
+ var duetMode_js_1 = require_duetMode();
37269
+ var duetPlan_js_1 = require_duetPlan();
37270
+ var duetRoutingAdvisor_js_1 = require_duetRoutingAdvisor();
37271
+ var duetExecutorGateStatus_js_1 = require_duetExecutorGateStatus();
37272
+ exports2.EXECUTOR_GATE_SOURCE = "executor_gate";
37273
+ exports2.EXECUTOR_GATE_PROMPT_VERSION = "1";
37274
+ exports2.EXECUTOR_GATE_TIMEOUT_MS = 8e3;
37275
+ exports2.EXECUTOR_GATE_STATUS_TTL_MS = 5 * 6e4;
37276
+ exports2.EXECUTOR_GATE_REQUEST_MAX_CHARS = 2e3;
37277
+ exports2.EXECUTOR_GATE_PLAN_HEAD_CHARS = 1200;
37278
+ exports2.EXECUTOR_GATE_MISSING_LOGPROB = -30;
37279
+ exports2.EXECUTOR_GATE_MIN_CALIBRATION = 3;
37280
+ var DEFAULT_RESOLVE_DEPS = {
37281
+ choice: (workspaceRoot) => (0, duetMode_js_1.duetExecutorWireForSegment)(workspaceRoot),
37282
+ routing: (provider) => (0, customProviders_js_1.endpointRoutingFor)(provider),
37283
+ alive: (workspaceRoot) => (0, customProviders_js_1.duetExecutorEndpointForSegment)(workspaceRoot) !== void 0
37284
+ };
37285
+ function resolveExecutorGateTarget(workspaceRoot, deps2 = DEFAULT_RESOLVE_DEPS) {
37286
+ try {
37287
+ const choice = deps2.choice(workspaceRoot);
37288
+ if (choice === void 0 || !(0, customProviders_js_1.isCustomProviderRef)(choice.provider))
37289
+ return { state: "platform" };
37290
+ const name2 = (0, customProviders_js_1.parseCustomProviderRef)(choice.provider) ?? "";
37291
+ const routing = deps2.routing(choice.provider);
37292
+ if (routing === void 0) {
37293
+ return { state: "unavailable", reason: "not_resolved", problem: "the executor's endpoint is not configured", name: name2 };
37294
+ }
37295
+ if (!deps2.alive(workspaceRoot)) {
37296
+ return { state: "unavailable", reason: "unreachable", problem: "the executor is not answering", name: name2 };
37297
+ }
37298
+ return {
37299
+ state: "ready",
37300
+ target: {
37301
+ name: routing.name,
37302
+ baseUrl: routing.baseUrl,
37303
+ ...routing.apiKey ? { apiKey: routing.apiKey } : {},
37304
+ model: choice.model,
37305
+ threshold: routing.executorGate?.threshold ?? customProviders_js_1.EXECUTOR_GATE_DEFAULT_THRESHOLD
37306
+ }
37307
+ };
37308
+ } catch {
37309
+ return { state: "unavailable", reason: "error", problem: "the executor could not be resolved" };
37310
+ }
37311
+ }
37312
+ async function resolveExecutorGateTargetFromSettings(opts) {
37313
+ try {
37314
+ const tiers = { workspaceRoot: opts.workspaceRoot ?? null, ...opts.homeDir ? { homeDir: opts.homeDir } : {} };
37315
+ const choice = await (0, duetMode_js_1.loadDuetExecutor)(tiers);
37316
+ if (choice === null || !(0, customProviders_js_1.isCustomProviderRef)(choice.provider))
37317
+ return { state: "platform" };
37318
+ const name2 = (0, customProviders_js_1.parseCustomProviderRef)(choice.provider) ?? "";
37319
+ const entry = await (0, customProviders_js_1.getCustomProvider)(name2, tiers);
37320
+ if (entry === null) {
37321
+ return { state: "unavailable", reason: "not_resolved", problem: "the executor's endpoint is not configured", name: name2 };
37322
+ }
37323
+ const apiKey = await (0, customProviders_js_1.resolveApiKey)(entry);
37324
+ if (!await (0, customProviders_js_1.endpointIsReachable)(entry.baseUrl, apiKey, opts.fetchImpl)) {
37325
+ return { state: "unavailable", reason: "unreachable", problem: "the executor is not answering", name: name2 };
37326
+ }
37327
+ return {
37328
+ state: "ready",
37329
+ target: {
37330
+ name: entry.name,
37331
+ baseUrl: entry.baseUrl,
37332
+ ...apiKey ? { apiKey } : {},
37333
+ model: choice.model,
37334
+ threshold: entry.executorGate?.threshold ?? customProviders_js_1.EXECUTOR_GATE_DEFAULT_THRESHOLD
37335
+ }
37336
+ };
37337
+ } catch {
37338
+ return { state: "unavailable", reason: "error", problem: "the executor could not be resolved" };
37339
+ }
37340
+ }
37341
+ function clipCodePoints(text, max) {
37342
+ const points = Array.from(text);
37343
+ return points.length <= max ? text : `${points.slice(0, max - 1).join("")}\u2026`;
37344
+ }
37345
+ function executorGateStateFrom(record, request) {
37346
+ const standing = record != null && (0, duetPlan_js_1.duetPlanWireForSegment)(record) !== void 0 ? record : null;
37347
+ return {
37348
+ planVersion: standing?.version ?? 0,
37349
+ planValid: standing !== null,
37350
+ planHead: standing === null ? "" : clipCodePoints(standing.plan.trim(), exports2.EXECUTOR_GATE_PLAN_HEAD_CHARS),
37351
+ assumptions: standing === null ? [] : (0, duetRoutingAdvisor_js_1.parsePlanAssumptions)(standing.plan).map((a) => ({ id: a.id, text: a.text })),
37352
+ planningFailures: standing?.planningFailures ?? 0,
37353
+ executorFailures: standing?.executorFailures ?? 0,
37354
+ scopeChanged: standing?.scopeChanged ?? false,
37355
+ architectureDecisionRequired: standing?.architectureDecisionRequired ?? false,
37356
+ userNegativeFeedback: standing?.userNegativeFeedback ?? false,
37357
+ request: clipCodePoints(request.trim(), exports2.EXECUTOR_GATE_REQUEST_MAX_CHARS)
37358
+ };
37359
+ }
37360
+ function stableJson(value) {
37361
+ const sort = (v2) => {
37362
+ if (Array.isArray(v2))
37363
+ return v2.map(sort);
37364
+ if (typeof v2 === "object" && v2 !== null) {
37365
+ return Object.fromEntries(Object.keys(v2).sort().map((k) => [k, sort(v2[k])]));
37366
+ }
37367
+ return v2;
37368
+ };
37369
+ return JSON.stringify(sort(value));
37370
+ }
37371
+ function renderExecutorGatePrompt(state) {
37372
+ const taskState = stableJson({
37373
+ plan_version: state.planVersion,
37374
+ plan_valid: state.planValid,
37375
+ planning_failures: state.planningFailures,
37376
+ executor_failures: state.executorFailures,
37377
+ flags: {
37378
+ scope_changed: state.scopeChanged,
37379
+ architecture_decision_required: state.architectureDecisionRequired,
37380
+ user_negative_feedback: state.userNegativeFeedback
37381
+ }
37382
+ });
37383
+ const capsule = stableJson({ assumptions: state.assumptions });
37384
+ const unresolved = state.executorFailures > 0 || state.planningFailures > 0 ? `${state.executorFailures} executor failure(s) and ${state.planningFailures} planning failure(s) under this plan` : "none";
37385
+ const corrections = state.userNegativeFeedback ? "the user pushed back on the current approach" : "none";
37386
+ return [
37387
+ "Routing gate for a coding agent. Decide if the current turn can be executed",
37388
+ "with the existing plan, or needs a new plan from the senior planner.",
37389
+ "",
37390
+ "E = EXECUTION_ONLY - the current plan is valid and local execution continues",
37391
+ "P = PLAN_REQUIRED - a new or revised plan would materially help",
37392
+ "",
37393
+ "Prefer E unless planning is genuinely needed.",
37394
+ "",
37395
+ "--- TASK STATE ---",
37396
+ taskState,
37397
+ "--- CONTEXT CAPSULE ---",
37398
+ capsule,
37399
+ "--- CURRENT PLAN ---",
37400
+ state.planHead === "" ? "(none)" : state.planHead,
37401
+ "--- UNRESOLVED ERRORS ---",
37402
+ unresolved,
37403
+ "--- RECENT USER CORRECTIONS ---",
37404
+ corrections,
37405
+ "--- LATEST USER REQUEST ---",
37406
+ state.request,
37407
+ "",
37408
+ "Answer with exactly one letter, E or P.",
37409
+ "Answer:"
37410
+ ].join("\n");
37411
+ }
37412
+ function executorGateLetterOf(token) {
37413
+ const bare2 = token.replace(/^[\s▁Ġ]+/u, "").replace(/\s+$/u, "");
37414
+ return bare2 === "E" || bare2 === "P" ? bare2 : null;
37415
+ }
37416
+ function topLogprobs(choice) {
37417
+ const lp = choice.logprobs;
37418
+ if (typeof lp !== "object" || lp === null)
37419
+ return null;
37420
+ const out2 = {};
37421
+ const add = (token, logprob) => {
37422
+ if (typeof token === "string" && typeof logprob === "number" && Number.isFinite(logprob)) {
37423
+ out2[token] = Math.max(out2[token] ?? Number.NEGATIVE_INFINITY, logprob);
37424
+ }
37425
+ };
37426
+ const legacy = lp.top_logprobs;
37427
+ if (Array.isArray(legacy) && typeof legacy[0] === "object" && legacy[0] !== null && !Array.isArray(legacy[0])) {
37428
+ for (const [token, logprob] of Object.entries(legacy[0]))
37429
+ add(token, logprob);
37430
+ }
37431
+ const content = lp.content;
37432
+ if (Array.isArray(content) && typeof content[0] === "object" && content[0] !== null) {
37433
+ const first = content[0];
37434
+ add(first.token, first.logprob);
37435
+ if (Array.isArray(first.top_logprobs)) {
37436
+ for (const row of first.top_logprobs) {
37437
+ add(row?.token, row?.logprob);
37438
+ }
37439
+ }
37440
+ }
37441
+ const tokens = lp.tokens;
37442
+ const tokenLogprobs = lp.token_logprobs;
37443
+ if (Array.isArray(tokens) && Array.isArray(tokenLogprobs))
37444
+ add(tokens[0], tokenLogprobs[0]);
37445
+ return Object.keys(out2).length > 0 ? out2 : null;
37446
+ }
37447
+ function parseExecutorGateResponse(body2) {
37448
+ const choice = body2?.choices?.[0];
37449
+ if (typeof choice !== "object" || choice === null) {
37450
+ return { ok: false, reason: "unparseable", problem: "the completions response carried no choice" };
37451
+ }
37452
+ const c3 = choice;
37453
+ const message = c3.message;
37454
+ const raw = typeof c3.text === "string" ? c3.text : typeof message?.content === "string" ? message.content : "";
37455
+ const trimmed = raw.trim();
37456
+ if (trimmed.startsWith("<")) {
37457
+ return {
37458
+ ok: false,
37459
+ reason: "thinking",
37460
+ problem: `the executor answered with thinking on (it began "${trimmed.slice(0, 8)}")`
37461
+ };
37462
+ }
37463
+ const letter = executorGateLetterOf(raw);
37464
+ const top = topLogprobs(c3);
37465
+ if (top !== null) {
37466
+ let logE = null;
37467
+ let logP = null;
37468
+ for (const [token, logprob] of Object.entries(top)) {
37469
+ const l3 = executorGateLetterOf(token);
37470
+ if (l3 === "E")
37471
+ logE = Math.max(logE ?? Number.NEGATIVE_INFINITY, logprob);
37472
+ if (l3 === "P")
37473
+ logP = Math.max(logP ?? Number.NEGATIVE_INFINITY, logprob);
37474
+ }
37475
+ if (logE !== null || logP !== null) {
37476
+ return {
37477
+ ok: true,
37478
+ answer: {
37479
+ mode: "logprob",
37480
+ letter,
37481
+ logE: logE ?? exports2.EXECUTOR_GATE_MISSING_LOGPROB,
37482
+ logP: logP ?? exports2.EXECUTOR_GATE_MISSING_LOGPROB,
37483
+ raw
37484
+ }
37485
+ };
37486
+ }
37487
+ }
37488
+ if (letter !== null)
37489
+ return { ok: true, answer: { mode: "greedy", letter, logE: null, logP: null, raw } };
37490
+ return {
37491
+ ok: false,
37492
+ reason: "unparseable",
37493
+ problem: `the executor answered "${trimmed.slice(0, 16)}", not E or P`
37494
+ };
37495
+ }
37496
+ function decideExecutorGate(answer, threshold) {
37497
+ if (answer.mode === "logprob" && answer.logE !== null && answer.logP !== null) {
37498
+ const margin = answer.logP - answer.logE;
37499
+ return { plan: margin >= threshold, margin, pPlan: 1 / (1 + Math.exp(-margin)) };
37500
+ }
37501
+ if (answer.letter === null)
37502
+ return null;
37503
+ return { plan: answer.letter === "P", margin: null, pPlan: answer.letter === "P" ? 1 : 0 };
37504
+ }
37505
+ async function askExecutorGate(target, prompt, opts = {}) {
37506
+ const started = Date.now();
37507
+ const doFetch = opts.fetchImpl ?? fetch;
37508
+ const headers = { "Content-Type": "application/json" };
37509
+ if (target.apiKey)
37510
+ headers.Authorization = `Bearer ${target.apiKey}`;
37511
+ try {
37512
+ const res = await doFetch(`${target.baseUrl.replace(/\/+$/, "")}/completions`, {
37513
+ method: "POST",
37514
+ headers,
37515
+ body: JSON.stringify({
37516
+ model: target.model,
37517
+ prompt,
37518
+ max_tokens: 1,
37519
+ temperature: 0,
37520
+ logprobs: 5,
37521
+ stream: false
37522
+ }),
37523
+ signal: AbortSignal.timeout(opts.timeoutMs ?? exports2.EXECUTOR_GATE_TIMEOUT_MS)
37524
+ });
37525
+ const latencyMs = Date.now() - started;
37526
+ if (res.status === 404 || res.status === 405 || res.status === 501) {
37527
+ return {
37528
+ ok: false,
37529
+ reason: "no_completions",
37530
+ problem: `the executor has no completions route (${res.status})`,
37531
+ latencyMs
37532
+ };
37533
+ }
37534
+ if (!res.ok)
37535
+ return { ok: false, reason: "error", problem: `the executor answered ${res.status}`, latencyMs };
37536
+ const parsed = parseExecutorGateResponse(await res.json());
37537
+ if (!parsed.ok)
37538
+ return { ok: false, reason: parsed.reason, problem: parsed.problem, latencyMs };
37539
+ return { ok: true, answer: parsed.answer, latencyMs };
37540
+ } catch (e) {
37541
+ const timedOut = e instanceof Error && e.name === "TimeoutError";
37542
+ return {
37543
+ ok: false,
37544
+ reason: "error",
37545
+ problem: timedOut ? "the gate call timed out" : `the gate call failed (${e instanceof Error ? e.message : String(e)})`,
37546
+ latencyMs: Date.now() - started
37547
+ };
37548
+ }
37549
+ }
37550
+ exports2.EXECUTOR_GATE_PROBE_SCENARIOS = [
37551
+ { request: "Create this application with auth, billing and audit logging", expect: "P" },
37552
+ { request: "Implement the next endpoint", expect: "E" },
37553
+ { request: "We can no longer use the current authentication architecture", expect: "P" },
37554
+ { request: "continue", expect: "E" }
37555
+ ];
37556
+ function executorGateProbeState(request) {
37557
+ return {
37558
+ planVersion: 3,
37559
+ planValid: true,
37560
+ planHead: "# Plan: orders-service (FastAPI)\n1. Add POST /orders and GET /orders/{id}\n2. Wire the billing call behind a feature flag\n3. Tests for both endpoints",
37561
+ assumptions: [
37562
+ { id: "A1", text: "the service keeps its central authentication middleware" },
37563
+ { id: "A2", text: "billing stays behind the existing Stripe client" }
37564
+ ],
37565
+ planningFailures: 0,
37566
+ executorFailures: 0,
37567
+ scopeChanged: false,
37568
+ architectureDecisionRequired: false,
37569
+ userNegativeFeedback: false,
37570
+ request
37571
+ };
37572
+ }
37573
+ async function probeExecutorGate(target, opts = {}) {
37574
+ const started = Date.now();
37575
+ let mode = null;
37576
+ const failed = [];
37577
+ for (const scenario of exports2.EXECUTOR_GATE_PROBE_SCENARIOS) {
37578
+ const asked = await askExecutorGate(target, renderExecutorGatePrompt(executorGateProbeState(scenario.request)), opts);
37579
+ if (!asked.ok)
37580
+ return { state: "unavailable", reason: asked.reason, problem: asked.problem, name: target.name };
37581
+ mode ??= asked.answer.mode;
37582
+ const decision = decideExecutorGate(asked.answer, target.threshold);
37583
+ if (decision === null || (decision.plan ? "P" : "E") !== scenario.expect)
37584
+ failed.push(scenario.request);
37585
+ }
37586
+ const calibration = {
37587
+ passed: exports2.EXECUTOR_GATE_PROBE_SCENARIOS.length - failed.length,
37588
+ total: exports2.EXECUTOR_GATE_PROBE_SCENARIOS.length,
37589
+ failed
37590
+ };
37591
+ const common = {
37592
+ target: { name: target.name, model: target.model },
37593
+ mode: mode ?? "greedy",
37594
+ threshold: target.threshold,
37595
+ calibration,
37596
+ latencyMs: Date.now() - started
37597
+ };
37598
+ return calibration.passed >= exports2.EXECUTOR_GATE_MIN_CALIBRATION ? { state: "ready", ...common } : { state: "miscalibrated", ...common };
37599
+ }
37600
+ async function describeDuetExecutorGate(opts = {}) {
37601
+ const resolved = await resolveExecutorGateTargetFromSettings(opts);
37602
+ if (resolved.state !== "ready")
37603
+ return resolved;
37604
+ return probeExecutorGate(resolved.target, { fetchImpl: opts.fetchImpl, timeoutMs: opts.timeoutMs });
37605
+ }
37606
+ var describeCache = /* @__PURE__ */ new Map();
37607
+ function clearDuetExecutorGateCache() {
37608
+ describeCache.clear();
37609
+ }
37610
+ async function describeDuetExecutorGateCached2(opts = {}) {
37611
+ const now2 = opts.now ?? Date.now;
37612
+ const key = `${opts.homeDir ?? os9.homedir()}\0${opts.workspaceRoot ?? ""}`;
37613
+ const hit = describeCache.get(key);
37614
+ if (!opts.refresh && hit !== void 0 && now2() - hit.at < (opts.ttlMs ?? exports2.EXECUTOR_GATE_STATUS_TTL_MS)) {
37615
+ return hit.status;
37616
+ }
37617
+ const status = await describeDuetExecutorGate(opts);
37618
+ describeCache.set(key, { at: now2(), status });
37619
+ return status;
37620
+ }
37621
+ function createDuetExecutorGate2(opts = {}) {
37622
+ const now2 = opts.now ?? Date.now;
37623
+ const ttl = opts.statusTtlMs ?? exports2.EXECUTOR_GATE_STATUS_TTL_MS;
37624
+ let cached = null;
37625
+ let noted = false;
37626
+ const fallback = (why) => {
37627
+ const note = noted ? null : (0, duetExecutorGateStatus_js_1.executorGateFallbackNote)(why);
37628
+ noted = true;
37629
+ return { entry: "executor", verdict: null, note };
37630
+ };
37631
+ return {
37632
+ async status(o = {}) {
37633
+ const resolved = await resolveExecutorGateTargetFromSettings({
37634
+ workspaceRoot: o.workspaceRoot,
37635
+ ...opts.homeDir ? { homeDir: opts.homeDir } : {},
37636
+ fetchImpl: opts.fetchImpl
37637
+ });
37638
+ if (resolved.state !== "ready")
37639
+ return resolved;
37640
+ const key = `${resolved.target.baseUrl} ${resolved.target.model} ${resolved.target.threshold}`;
37641
+ if (!o.refresh && cached !== null && cached.key === key && now2() - cached.at < ttl)
37642
+ return cached.status;
37643
+ const status = await probeExecutorGate(resolved.target, { fetchImpl: opts.fetchImpl, timeoutMs: opts.timeoutMs });
37644
+ cached = { at: now2(), key, status };
37645
+ return status;
37646
+ },
37647
+ async prepareTurn(text, ctx) {
37648
+ if (text.trim() === "")
37649
+ return { entry: "executor", verdict: null, note: null };
37650
+ const resolved = resolveExecutorGateTarget(ctx.workspaceRoot, opts.resolveDeps);
37651
+ if (resolved.state !== "ready") {
37652
+ opts.onError?.("resolve", resolved.state === "platform" ? "platform executor" : resolved.problem);
37653
+ return fallback(resolved);
37654
+ }
37655
+ const { target } = resolved;
37656
+ const prompt = renderExecutorGatePrompt(executorGateStateFrom(ctx.record, text));
37657
+ const asked = await askExecutorGate(target, prompt, { fetchImpl: opts.fetchImpl, timeoutMs: opts.timeoutMs });
37658
+ if (!asked.ok) {
37659
+ opts.onError?.("ask", asked.problem);
37660
+ return fallback({ state: "unavailable", reason: asked.reason, problem: asked.problem });
37661
+ }
37662
+ const decision = decideExecutorGate(asked.answer, target.threshold);
37663
+ if (decision === null) {
37664
+ const said = asked.answer.raw.trim();
37665
+ opts.onError?.("ask", `undecidable answer "${said}"`);
37666
+ return fallback({ state: "unavailable", reason: "unparseable", problem: `the executor answered "${said}"` });
37667
+ }
37668
+ noted = false;
37669
+ const verdict = {
37670
+ source: exports2.EXECUTOR_GATE_SOURCE,
37671
+ verdict: decision.plan ? "plan" : "execute",
37672
+ pPlan: decision.pPlan,
37673
+ asksForPlan: false,
37674
+ highRisk: false,
37675
+ reason: exports2.EXECUTOR_GATE_SOURCE,
37676
+ model: target.model,
37677
+ version: exports2.EXECUTOR_GATE_PROMPT_VERSION,
37678
+ latencyMs: asked.latencyMs,
37679
+ mode: asked.answer.mode,
37680
+ ...decision.margin !== null ? { margin: decision.margin } : {}
37681
+ };
37682
+ return { entry: "executor", verdict, note: null };
37683
+ },
37684
+ invalidate() {
37685
+ cached = null;
37686
+ noted = false;
37687
+ }
37688
+ };
37689
+ }
37690
+ }
37691
+ });
37692
+
37693
+ // ../packages/orion-client-core/dist/runs/common.js
37694
+ var require_common = __commonJS({
37695
+ "../packages/orion-client-core/dist/runs/common.js"(exports2) {
37696
+ "use strict";
37697
+ Object.defineProperty(exports2, "__esModule", { value: true });
37698
+ exports2.mintRunId = mintRunId;
37699
+ exports2.runsRootFor = runsRootFor2;
37700
+ exports2.readJsonFile = readJsonFile;
37701
+ exports2.writeJsonFile = writeJsonFile;
37702
+ exports2.ensureDirFor = ensureDirFor;
37703
+ exports2.listDirNames = listDirNames;
37704
+ exports2.dayKey = dayKey;
37705
+ exports2.clipTail = clipTail;
37706
+ var fs_1 = __require("fs");
37707
+ var os_1 = __require("os");
37708
+ var path_1 = __require("path");
37709
+ var atomicWrite_js_1 = require_atomicWrite();
37710
+ var experienceStore_js_1 = require_experienceStore();
37711
+ var ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
37712
+ var ID_SUFFIX_LEN = 6;
37713
+ function mintRunId(prefix, nowMs = Date.now(), rand = Math.random) {
37714
+ let suffix = "";
37715
+ for (let i2 = 0; i2 < ID_SUFFIX_LEN; i2 += 1) {
37716
+ suffix += ID_ALPHABET[Math.floor(rand() * ID_ALPHABET.length) % ID_ALPHABET.length];
37717
+ }
37718
+ return `${prefix}_${String(nowMs).padStart(13, "0")}_${suffix}`;
37719
+ }
37720
+ function runsRootFor2(kind, workspaceRoot, home = (0, os_1.homedir)()) {
37721
+ return (0, path_1.join)((0, experienceStore_js_1.projectDirFor)(workspaceRoot, home), "runs", kind);
37722
+ }
37723
+ async function readJsonFile(path14) {
37724
+ try {
37725
+ const raw = await fs_1.promises.readFile(path14, "utf8");
37726
+ return JSON.parse(raw);
37727
+ } catch {
37728
+ return null;
37729
+ }
37730
+ }
37731
+ async function writeJsonFile(path14, value) {
37732
+ await ensureDirFor(path14);
37733
+ await (0, atomicWrite_js_1.atomicWriteFile)(path14, JSON.stringify(value, null, 2));
37734
+ }
37735
+ async function ensureDirFor(path14) {
37736
+ await fs_1.promises.mkdir((0, path_1.dirname)(path14), { recursive: true });
37737
+ }
37738
+ async function listDirNames(path14) {
37739
+ try {
37740
+ return await fs_1.promises.readdir(path14);
37741
+ } catch {
37742
+ return [];
37743
+ }
37744
+ }
37745
+ function dayKey(nowMs = Date.now()) {
37746
+ const d2 = new Date(nowMs);
37747
+ const month = `${d2.getMonth() + 1}`.padStart(2, "0");
37748
+ const day = `${d2.getDate()}`.padStart(2, "0");
37749
+ return `${d2.getFullYear()}-${month}-${day}`;
37750
+ }
37751
+ function clipTail(text, max) {
37752
+ if (text.length <= max)
37753
+ return text;
37754
+ return `\u2026${text.slice(text.length - (max - 1))}`;
37755
+ }
37756
+ }
37757
+ });
37758
+
37759
+ // ../packages/orion-client-core/dist/customProviderModels.js
37760
+ var require_customProviderModels = __commonJS({
37761
+ "../packages/orion-client-core/dist/customProviderModels.js"(exports2) {
37762
+ "use strict";
37763
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m2, k, k2) {
37764
+ if (k2 === void 0) k2 = k;
37765
+ var desc = Object.getOwnPropertyDescriptor(m2, k);
37766
+ if (!desc || ("get" in desc ? !m2.__esModule : desc.writable || desc.configurable)) {
37767
+ desc = { enumerable: true, get: function() {
37768
+ return m2[k];
37769
+ } };
37770
+ }
37771
+ Object.defineProperty(o, k2, desc);
37772
+ } : function(o, m2, k, k2) {
37773
+ if (k2 === void 0) k2 = k;
37774
+ o[k2] = m2[k];
37775
+ });
37776
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v2) {
37777
+ Object.defineProperty(o, "default", { enumerable: true, value: v2 });
37778
+ } : function(o, v2) {
37779
+ o["default"] = v2;
37780
+ });
37781
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
37782
+ var ownKeys = function(o) {
37783
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
37784
+ var ar = [];
37785
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
37786
+ return ar;
37787
+ };
37788
+ return ownKeys(o);
37789
+ };
37790
+ return function(mod2) {
37791
+ if (mod2 && mod2.__esModule) return mod2;
37792
+ var result = {};
37793
+ if (mod2 != null) {
37794
+ for (var k = ownKeys(mod2), i2 = 0; i2 < k.length; i2++) if (k[i2] !== "default") __createBinding(result, mod2, k[i2]);
37795
+ }
37796
+ __setModuleDefault(result, mod2);
37797
+ return result;
37798
+ };
37799
+ }();
37800
+ Object.defineProperty(exports2, "__esModule", { value: true });
37801
+ exports2.CATALOG_GC_MS = exports2.CATALOG_TTL_MS = exports2.CATALOG_SCHEMA_VERSION = void 0;
37802
+ exports2.catalogPathFor = catalogPathFor;
37803
+ exports2.endpointCatalog = endpointCatalog2;
37804
+ exports2.findProbedModel = findProbedModel;
37805
+ exports2.resolveModelSettings = resolveModelSettings2;
37806
+ exports2.catalogModelIds = catalogModelIds2;
37807
+ exports2.clearEndpointCatalog = clearEndpointCatalog3;
37808
+ exports2.endpointModelViews = endpointModelViews2;
37809
+ exports2.updateCustomProviderModels = updateCustomProviderModels2;
37810
+ var node_crypto_1 = __require("node:crypto");
37811
+ var os9 = __importStar(__require("node:os"));
37812
+ var path14 = __importStar(__require("node:path"));
37813
+ var customProviders_1 = require_customProviders();
37814
+ var common_1 = require_common();
37815
+ exports2.CATALOG_SCHEMA_VERSION = 1;
37816
+ exports2.CATALOG_TTL_MS = 9e5;
37817
+ exports2.CATALOG_GC_MS = 45 * 24 * 60 * 60 * 1e3;
37818
+ function catalogPathFor(baseUrl, homeDir = os9.homedir()) {
37819
+ const digest = (0, node_crypto_1.createHash)("sha256").update(normalizeBaseUrl(baseUrl)).digest("hex").slice(0, 16);
37820
+ return path14.join(homeDir, ".orion", "cache", "models", `${digest}.json`);
37821
+ }
37822
+ function normalizeBaseUrl(baseUrl) {
37823
+ return baseUrl.trim().replace(/\/+$/, "");
37824
+ }
37825
+ async function readRecordFromDisk(baseUrl) {
37826
+ const record = await (0, common_1.readJsonFile)(catalogPathFor(baseUrl));
37827
+ if (record === null)
37828
+ return null;
37829
+ if (record.version !== exports2.CATALOG_SCHEMA_VERSION)
37830
+ return null;
37831
+ if (normalizeBaseUrl(record.baseUrl ?? "") !== normalizeBaseUrl(baseUrl))
37832
+ return null;
37833
+ if (!Array.isArray(record.models))
37834
+ return null;
37835
+ return record;
37836
+ }
37837
+ var sweptThisProcess = false;
37838
+ async function gcEndpointCatalogs(now2, homeDir = os9.homedir()) {
37839
+ if (sweptThisProcess)
37840
+ return;
37841
+ sweptThisProcess = true;
37842
+ try {
37843
+ const dir = path14.dirname(catalogPathFor("x", homeDir));
37844
+ const fs15 = await Promise.resolve().then(() => __importStar(__require("node:fs/promises")));
37845
+ for (const name2 of await fs15.readdir(dir)) {
37846
+ if (!name2.endsWith(".json"))
37847
+ continue;
37848
+ const file = path14.join(dir, name2);
37849
+ try {
37850
+ const record = await (0, common_1.readJsonFile)(file);
37851
+ const age = typeof record?.fetchedAt === "number" ? now2 - record.fetchedAt : now2 - (await fs15.stat(file)).mtimeMs;
37852
+ if (age > exports2.CATALOG_GC_MS)
37853
+ await fs15.rm(file, { force: true });
37854
+ } catch {
37855
+ }
37856
+ }
37409
37857
  } catch {
37410
- return untouched(record);
37411
37858
  }
37412
37859
  }
37413
- function round3(value) {
37414
- return Math.round(value * 1e3) / 1e3;
37415
- }
37416
- async function describeDuetRouting2(workspaceRoot) {
37860
+ async function writeRecordToDisk(record) {
37417
37861
  try {
37418
- const choice = await (0, duetMode_js_1.loadDuetExecutor)({ workspaceRoot: workspaceRoot ?? null });
37419
- if (choice === null || !(0, customProviders_js_1.isCustomProviderRef)(choice.provider))
37420
- return { kind: "platform" };
37421
- const name2 = (0, customProviders_js_1.parseCustomProviderRef)(choice.provider) ?? "";
37422
- const entry = await (0, customProviders_js_1.getCustomProvider)(name2, { workspaceRoot: workspaceRoot ?? null });
37423
- if (entry === null)
37424
- return { kind: "missing", name: name2 };
37425
- return {
37426
- kind: "local",
37427
- name: name2,
37428
- loopback: (0, customProviders_js_1.isLoopbackEndpoint)(entry.baseUrl),
37429
- embeddings: entry.routingModels?.embeddings !== void 0,
37430
- rerank: entry.routingModels?.rerank !== void 0,
37431
- judge: entry.routingModels?.judge ?? null
37432
- };
37862
+ await (0, common_1.writeJsonFile)(catalogPathFor(record.baseUrl), record);
37433
37863
  } catch {
37434
- return { kind: "platform" };
37435
37864
  }
37865
+ void gcEndpointCatalogs(record.fetchedAt);
37436
37866
  }
37437
- function duetRoutingSummaryLine2(summary) {
37438
- switch (summary.kind) {
37439
- case "platform":
37440
- return "Duet routing: rules only \u2014 a local executor with routing models unlocks re-ask detection and plan-assumption checks.";
37441
- case "missing":
37442
- return "Duet routing: rules only.";
37443
- case "local": {
37444
- const { name: name2, loopback, embeddings, rerank } = summary;
37445
- if (!embeddings && !rerank) {
37446
- return `Duet routing: rules only \u2014 add routingModels to '${name2}' to unlock re-ask detection and plan-assumption checks (the /local-ai skill can set this up).`;
37447
- }
37448
- if (!loopback) {
37449
- return `Duet routing: rules only \u2014 semantic checks run only against a loopback endpoint, and '${name2}' is not one.`;
37450
- }
37451
- const parts2 = [];
37452
- const via = [];
37453
- if (embeddings) {
37454
- parts2.push("re-ask detection");
37455
- via.push("embeddings");
37456
- }
37457
- if (rerank) {
37458
- parts2.push("plan-assumption checks");
37459
- via.push("rerank");
37460
- }
37461
- return `Duet routing: rules + ${parts2.join(" + ")} (${via.join(" + ")} on '${name2}').`;
37867
+ var memory = /* @__PURE__ */ new Map();
37868
+ var inFlight2 = /* @__PURE__ */ new Map();
37869
+ function depsWith(deps2) {
37870
+ return {
37871
+ now: deps2.now ?? (() => Date.now()),
37872
+ probe: deps2.probe ?? customProviders_1.probeModels,
37873
+ readRecord: deps2.readRecord ?? readRecordFromDisk,
37874
+ writeRecord: deps2.writeRecord ?? writeRecordToDisk
37875
+ };
37876
+ }
37877
+ async function probeAndStore(entry, d2) {
37878
+ const key = normalizeBaseUrl(entry.baseUrl);
37879
+ const existing = inFlight2.get(key);
37880
+ if (existing !== void 0)
37881
+ return existing;
37882
+ const run3 = (async () => {
37883
+ const models = await d2.probe(entry.baseUrl, await (0, customProviders_1.resolveApiKey)(entry));
37884
+ if (models === null || models.length === 0)
37885
+ return models;
37886
+ const record = {
37887
+ version: exports2.CATALOG_SCHEMA_VERSION,
37888
+ baseUrl: entry.baseUrl,
37889
+ fetchedAt: d2.now(),
37890
+ models
37891
+ };
37892
+ memory.set(key, record);
37893
+ await d2.writeRecord(record);
37894
+ return models;
37895
+ })().finally(() => inFlight2.delete(key));
37896
+ inFlight2.set(key, run3);
37897
+ return run3;
37898
+ }
37899
+ async function endpointCatalog2(entry, options = {}) {
37900
+ const d2 = depsWith(options);
37901
+ const key = normalizeBaseUrl(entry.baseUrl);
37902
+ let record = memory.get(key) ?? null;
37903
+ if (record === null) {
37904
+ record = await d2.readRecord(entry.baseUrl);
37905
+ if (record !== null)
37906
+ memory.set(key, record);
37907
+ }
37908
+ if (options.cachedOnly === true)
37909
+ return record?.models ?? [];
37910
+ const fresh = record !== null && d2.now() - record.fetchedAt < exports2.CATALOG_TTL_MS;
37911
+ if (record !== null && fresh && options.force !== true)
37912
+ return record.models;
37913
+ if (record !== null) {
37914
+ void probeAndStore(entry, d2).catch(() => void 0);
37915
+ return record.models;
37916
+ }
37917
+ return await probeAndStore(entry, d2) ?? [];
37918
+ }
37919
+ function findProbedModel(models, id) {
37920
+ return models.find((model) => model.id === id);
37921
+ }
37922
+ function resolveModelSettings2(entry, modelId, catalog = []) {
37923
+ const declared = entry.modelConfig?.[modelId];
37924
+ const probed = findProbedModel(catalog, modelId);
37925
+ const resolved = {};
37926
+ const contextWindow = declared?.contextWindow ?? probed?.contextWindow;
37927
+ if (contextWindow !== void 0)
37928
+ resolved.contextWindow = contextWindow;
37929
+ const maxOutputTokens = declared?.maxOutputTokens ?? probed?.maxOutputTokens;
37930
+ if (maxOutputTokens !== void 0)
37931
+ resolved.maxOutputTokens = maxOutputTokens;
37932
+ if (probed?.reasoning !== void 0)
37933
+ resolved.reasoning = probed.reasoning;
37934
+ for (const knob of ["temperature", "topP", "topK", "repetitionPenalty"]) {
37935
+ const value = declared?.[knob];
37936
+ if (typeof value === "number")
37937
+ resolved[knob] = value;
37938
+ }
37939
+ return resolved;
37940
+ }
37941
+ function catalogModelIds2(entry, catalog) {
37942
+ return entry.models?.length ? entry.models : catalog.map((model) => model.id);
37943
+ }
37944
+ function clearEndpointCatalog3(baseUrl) {
37945
+ if (baseUrl === void 0) {
37946
+ memory.clear();
37947
+ inFlight2.clear();
37948
+ sweptThisProcess = false;
37949
+ return;
37950
+ }
37951
+ const key = normalizeBaseUrl(baseUrl);
37952
+ memory.delete(key);
37953
+ inFlight2.delete(key);
37954
+ }
37955
+ async function endpointModelViews2(entry, options = {}) {
37956
+ const catalog = await endpointCatalog2(entry, options);
37957
+ const pinned = new Set(entry.models ?? []);
37958
+ const ids = [...pinned, ...catalog.map((model) => model.id).filter((id) => !pinned.has(id))];
37959
+ return ids.map((id) => {
37960
+ const resolved = resolveModelSettings2(entry, id, catalog);
37961
+ const declared = entry.modelConfig?.[id];
37962
+ const view = { id, pinned: pinned.has(id) };
37963
+ if (resolved.contextWindow !== void 0)
37964
+ view.contextWindow = resolved.contextWindow;
37965
+ if (resolved.maxOutputTokens !== void 0)
37966
+ view.maxOutputTokens = resolved.maxOutputTokens;
37967
+ if (resolved.reasoning !== void 0)
37968
+ view.reasoning = resolved.reasoning;
37969
+ if (declared?.contextWindow !== void 0 || declared?.maxOutputTokens !== void 0) {
37970
+ view.source = "user";
37971
+ } else if (view.contextWindow !== void 0 || view.maxOutputTokens !== void 0) {
37972
+ view.source = "endpoint";
37973
+ }
37974
+ return view;
37975
+ });
37976
+ }
37977
+ async function updateCustomProviderModels2(name2, update, tier = "user", opts = {}) {
37978
+ const entry = await (0, customProviders_1.getCustomProvider)(name2, opts);
37979
+ if (entry === null)
37980
+ return false;
37981
+ const next = { ...entry };
37982
+ if (update.models !== void 0) {
37983
+ if (update.models.length)
37984
+ next.models = update.models;
37985
+ else
37986
+ delete next.models;
37987
+ }
37988
+ if (update.modelConfig !== void 0) {
37989
+ const kept = Object.entries(update.modelConfig).map(([id, raw]) => [id, (0, customProviders_1.normalizeModelConfig)(raw)]).filter(([, value]) => value !== void 0 && Object.keys(value).length > 0);
37990
+ if (kept.length)
37991
+ next.modelConfig = Object.fromEntries(kept);
37992
+ else
37993
+ delete next.modelConfig;
37994
+ }
37995
+ await (0, customProviders_1.saveCustomProvider)(next, tier, opts);
37996
+ clearEndpointCatalog3(entry.baseUrl);
37997
+ return true;
37998
+ }
37999
+ }
38000
+ });
38001
+
38002
+ // ../packages/orion-client-core/dist/duetExecutorCatalog.js
38003
+ var require_duetExecutorCatalog = __commonJS({
38004
+ "../packages/orion-client-core/dist/duetExecutorCatalog.js"(exports2) {
38005
+ "use strict";
38006
+ Object.defineProperty(exports2, "__esModule", { value: true });
38007
+ exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = void 0;
38008
+ exports2.localExecutorOptions = localExecutorOptions2;
38009
+ exports2.duetExecutorChoiceFor = duetExecutorChoiceFor2;
38010
+ exports2.isLocalExecutorChoice = isLocalExecutorChoice;
38011
+ exports2.resolveDuetExecutorChoice = resolveDuetExecutorChoice2;
38012
+ var customProviders_js_1 = require_customProviders();
38013
+ var customProviderModels_js_1 = require_customProviderModels();
38014
+ exports2.LOCAL_EXECUTOR_READ_BUDGET_MS = 3e3;
38015
+ async function localExecutorOptions2(input = {}) {
38016
+ const { catalog, timeoutMs, ...opts } = input;
38017
+ let entries;
38018
+ try {
38019
+ entries = await (0, customProviders_js_1.loadCustomProviders)(opts);
38020
+ } catch {
38021
+ return [];
38022
+ }
38023
+ if (entries.length === 0)
38024
+ return [];
38025
+ const read = (options) => Promise.all(entries.map(async (entry) => {
38026
+ try {
38027
+ const views = await (0, customProviderModels_js_1.endpointModelViews)(entry, options);
38028
+ return views.map((view) => {
38029
+ const option = {
38030
+ provider: `custom:${entry.name}`,
38031
+ endpoint: entry.name,
38032
+ model: view.id,
38033
+ pinned: view.pinned
38034
+ };
38035
+ if (view.contextWindow !== void 0)
38036
+ option.contextWindow = view.contextWindow;
38037
+ if (view.maxOutputTokens !== void 0)
38038
+ option.maxOutputTokens = view.maxOutputTokens;
38039
+ return option;
38040
+ });
38041
+ } catch {
38042
+ return [];
37462
38043
  }
38044
+ })).then((perEndpoint) => perEndpoint.flat());
38045
+ const full = read(catalog ?? {});
38046
+ const budget = timeoutMs ?? exports2.LOCAL_EXECUTOR_READ_BUDGET_MS;
38047
+ if (catalog?.cachedOnly === true || budget <= 0)
38048
+ return full;
38049
+ let timer;
38050
+ const fallback = new Promise((resolve5) => {
38051
+ timer = setTimeout(() => resolve5(read({ ...catalog, cachedOnly: true })), budget);
38052
+ });
38053
+ try {
38054
+ return await Promise.race([full, fallback]);
38055
+ } finally {
38056
+ if (timer !== void 0)
38057
+ clearTimeout(timer);
38058
+ void full.catch(() => void 0);
37463
38059
  }
37464
38060
  }
38061
+ function duetExecutorChoiceFor2(option) {
38062
+ return {
38063
+ provider: option.provider,
38064
+ model: option.model,
38065
+ ...option.contextWindow !== void 0 ? { contextWindow: option.contextWindow } : {}
38066
+ };
38067
+ }
38068
+ function isLocalExecutorChoice(choice) {
38069
+ return typeof choice?.provider === "string" && choice.provider.startsWith("custom:");
38070
+ }
38071
+ async function resolveDuetExecutorChoice2(choice, input = {}) {
38072
+ if (!isLocalExecutorChoice(choice) || choice.contextWindow !== void 0)
38073
+ return choice;
38074
+ const found = (await localExecutorOptions2(input)).find((option) => option.provider === choice.provider && option.model === choice.model);
38075
+ return found === void 0 ? choice : { ...choice, ...duetExecutorChoiceFor2(found), ...choice.effort ? { effort: choice.effort } : {} };
38076
+ }
37465
38077
  }
37466
38078
  });
37467
38079
 
@@ -38387,6 +38999,58 @@ var require_agentStore = __commonJS({
38387
38999
  }
38388
39000
  });
38389
39001
 
39002
+ // ../packages/orion-client-core/dist/goalClaim.js
39003
+ var require_goalClaim = __commonJS({
39004
+ "../packages/orion-client-core/dist/goalClaim.js"(exports2) {
39005
+ "use strict";
39006
+ Object.defineProperty(exports2, "__esModule", { value: true });
39007
+ exports2.GOAL_REPORT_TOOL = exports2.GOAL_CAPABILITY = void 0;
39008
+ exports2.readGoalReportInput = readGoalReportInput;
39009
+ exports2.goalClaimFromWire = goalClaimFromWire3;
39010
+ exports2.goalReportToolResult = goalReportToolResult3;
39011
+ exports2.GOAL_CAPABILITY = "goal";
39012
+ exports2.GOAL_REPORT_TOOL = "goal_report";
39013
+ function readGoalReportInput(input) {
39014
+ if (!input || typeof input !== "object")
39015
+ return null;
39016
+ const r2 = input;
39017
+ if (typeof r2.done !== "boolean")
39018
+ return null;
39019
+ const note = r2.done ? r2.verified : r2.outstanding;
39020
+ return { done: r2.done, note: typeof note === "string" ? note.trim() : "" };
39021
+ }
39022
+ function goalClaimFromWire3(messages) {
39023
+ if (!Array.isArray(messages))
39024
+ return null;
39025
+ let claim = null;
39026
+ for (const message of messages) {
39027
+ const m2 = message;
39028
+ if (!m2 || m2.role !== "assistant" || !Array.isArray(m2.content))
39029
+ continue;
39030
+ for (const block of m2.content) {
39031
+ const b2 = block;
39032
+ if (!b2 || b2.type !== "tool_use" || b2.name !== exports2.GOAL_REPORT_TOOL)
39033
+ continue;
39034
+ const parsed = readGoalReportInput(b2.input);
39035
+ if (parsed !== null)
39036
+ claim = parsed;
39037
+ }
39038
+ }
39039
+ return claim;
39040
+ }
39041
+ function goalReportToolResult3(params) {
39042
+ const claim = readGoalReportInput(params);
39043
+ if (claim === null) {
39044
+ return "goal_report needs `done` as a boolean: false while ANY part of the goal remains (say what in `outstanding`), true only when every part is verified complete (name what you ran in `verified`).";
39045
+ }
39046
+ if (claim.done) {
39047
+ return "Completion claim recorded. An independent check now reviews the evidence of what you actually did \u2014 the goal ends only if it confirms; otherwise you will be told what is still outstanding. End your turn now.";
39048
+ }
39049
+ return "Status recorded \u2014 the goal continues. If you can take the next step now, keep working; otherwise end your turn and you will be continued.";
39050
+ }
39051
+ }
39052
+ });
39053
+
38390
39054
  // ../packages/orion-client-core/dist/goalMarker.js
38391
39055
  var require_goalMarker = __commonJS({
38392
39056
  "../packages/orion-client-core/dist/goalMarker.js"(exports2) {
@@ -38808,7 +39472,8 @@ var require_goalEvaluate = __commonJS({
38808
39472
  const params = { goal: args2.goal, evidence };
38809
39473
  if (args2.sessionId)
38810
39474
  params.session_id = args2.sessionId;
38811
- const chosen = await configuredEvaluatorModel(args2);
39475
+ const sessionFallback = args2.sessionModel && !args2.sessionProvider?.startsWith("custom") ? { model: args2.sessionModel, provider: args2.sessionProvider ?? "" } : void 0;
39476
+ const chosen = await configuredEvaluatorModel(args2) ?? sessionFallback;
38812
39477
  if (chosen) {
38813
39478
  params.model = chosen.model;
38814
39479
  if (chosen.provider)
@@ -38825,15 +39490,18 @@ var require_goalRunner = __commonJS({
38825
39490
  "../packages/orion-client-core/dist/goalRunner.js"(exports2) {
38826
39491
  "use strict";
38827
39492
  Object.defineProperty(exports2, "__esModule", { value: true });
38828
- exports2.GoalRunner = exports2.GOAL_CONTINUE_DISPLAY = exports2.GOAL_REASON_PROMPT_MAX_CHARS = exports2.GOAL_REASON_MAX_CHARS = exports2.GOAL_MAX_EVALUATOR_FAILURES = exports2.DEFAULT_GOAL_MAX_WALL_MS = exports2.DEFAULT_GOAL_MAX_TURNS = exports2.GOAL_INSTRUCTION = void 0;
39493
+ exports2.GoalRunner = exports2.GOAL_CONTINUE_DISPLAY = exports2.GOAL_REASON_PROMPT_MAX_CHARS = exports2.GOAL_REASON_MAX_CHARS = exports2.GOAL_UNCLAIMED_CHECK_INTERVAL = exports2.GOAL_MAX_EVALUATOR_FAILURES = exports2.DEFAULT_GOAL_MAX_WALL_MS = exports2.DEFAULT_GOAL_MAX_TURNS = exports2.GOAL_INSTRUCTION = void 0;
38829
39494
  exports2.buildGoalPrompt = buildGoalPrompt;
38830
39495
  exports2.buildContinuationPrompt = buildContinuationPrompt;
38831
39496
  exports2.finalAssistantTextFromWire = finalAssistantTextFromWire2;
38832
39497
  exports2.describeGoalEnd = describeGoalEnd;
38833
- exports2.goalReasonLine = goalReasonLine2;
39498
+ exports2.goalReasonLine = goalReasonLine3;
38834
39499
  exports2.goalEndRow = goalEndRow2;
38835
39500
  exports2.goalNotMetRow = goalNotMetRow2;
38836
39501
  exports2.goalStartDisplay = goalStartDisplay2;
39502
+ exports2.goalFromStartDisplay = goalFromStartDisplay;
39503
+ exports2.goalSetRow = goalSetRow2;
39504
+ exports2.goalRoundReason = goalRoundReason2;
38837
39505
  exports2.GOAL_INSTRUCTION = [
38838
39506
  "",
38839
39507
  "---",
@@ -38842,11 +39510,14 @@ var require_goalRunner = __commonJS({
38842
39510
  "Do not end your turn with a plan, an intention, or a promise about work you have not done \u2014",
38843
39511
  "if the next step is clear, take it now instead of describing it.",
38844
39512
  "",
38845
- "You do NOT decide when the goal is finished: an independent check reviews each turn against",
38846
- "the goal and continues you if anything is outstanding. Reading code is not verifying it \u2014",
38847
- "run the tests, execute the command, show the output. State plainly what you did and what the",
38848
- "result actually was; an unverified claim counts for nothing, and reporting a failure honestly",
38849
- "is always better than glossing it."
39513
+ "End every turn by calling the goal_report tool \u2014 a status line in prose is not a report.",
39514
+ "While ANY part of the goal remains, report done: false and say in `outstanding` exactly what",
39515
+ 'is missing. Be ruthlessly honest \u2014 an honest "not done" costs nothing and keeps you going.',
39516
+ "Report done: true only when you have VERIFIED every part \u2014 ran the tests, executed the",
39517
+ "command, saw the output \u2014 and name in `verified` what you ran and what it showed.",
39518
+ "Your report is a claim, not a verdict: an independent check reviews the evidence of what you",
39519
+ "actually did before the goal can end, and an unverified claim is simply sent back. Reading",
39520
+ "code is not verifying it; reporting a failure honestly is always better than glossing it."
38850
39521
  ].join("\n");
38851
39522
  function buildGoalPrompt(goal) {
38852
39523
  return `# Goal
@@ -38854,7 +39525,7 @@ ${goal}
38854
39525
  ${exports2.GOAL_INSTRUCTION}`;
38855
39526
  }
38856
39527
  function buildContinuationPrompt(goal, reason) {
38857
- const line = reason ? goalReasonLine2(reason, exports2.GOAL_REASON_PROMPT_MAX_CHARS) : "";
39528
+ const line = reason ? goalReasonLine3(reason, exports2.GOAL_REASON_PROMPT_MAX_CHARS) : "";
38858
39529
  const outstanding = line === "" ? "" : `
38859
39530
 
38860
39531
  ## What the completion check reported
@@ -38887,6 +39558,7 @@ ${exports2.GOAL_INSTRUCTION}`;
38887
39558
  exports2.DEFAULT_GOAL_MAX_TURNS = 0;
38888
39559
  exports2.DEFAULT_GOAL_MAX_WALL_MS = 0;
38889
39560
  exports2.GOAL_MAX_EVALUATOR_FAILURES = 3;
39561
+ exports2.GOAL_UNCLAIMED_CHECK_INTERVAL = 5;
38890
39562
  function describeGoalEnd(reason) {
38891
39563
  switch (reason) {
38892
39564
  case "done":
@@ -38907,7 +39579,7 @@ ${exports2.GOAL_INSTRUCTION}`;
38907
39579
  }
38908
39580
  exports2.GOAL_REASON_MAX_CHARS = 140;
38909
39581
  exports2.GOAL_REASON_PROMPT_MAX_CHARS = 500;
38910
- function goalReasonLine2(reason, max = exports2.GOAL_REASON_MAX_CHARS) {
39582
+ function goalReasonLine3(reason, max = exports2.GOAL_REASON_MAX_CHARS) {
38911
39583
  const flat = reason.replace(/\s+/g, " ").trim();
38912
39584
  if (flat.length <= max)
38913
39585
  return flat;
@@ -38934,7 +39606,7 @@ ${exports2.GOAL_INSTRUCTION}`;
38934
39606
  }
38935
39607
  }
38936
39608
  function goalNotMetRow2(reason) {
38937
- const line = goalReasonLine2(reason);
39609
+ const line = goalReasonLine3(reason);
38938
39610
  return {
38939
39611
  glyph: "\u25CE",
38940
39612
  text: line === "" ? "Not met yet" : `Not met yet \u2014 ${line}`,
@@ -38946,10 +39618,29 @@ ${exports2.GOAL_INSTRUCTION}`;
38946
39618
  function goalStartDisplay2(goal) {
38947
39619
  return `/goal ${goal}`;
38948
39620
  }
39621
+ function goalFromStartDisplay(display) {
39622
+ return (display.startsWith("/goal ") ? display.slice("/goal ".length) : display).trim();
39623
+ }
39624
+ function goalSetRow2(goal) {
39625
+ const line = goal.replace(/\s+/g, " ").trim();
39626
+ return {
39627
+ glyph: "\u25CE",
39628
+ text: line === "" ? "Goal set" : `Goal set: ${line}`,
39629
+ done: false,
39630
+ progress: true
39631
+ };
39632
+ }
39633
+ function goalRoundReason2(round) {
39634
+ if (round.ruling)
39635
+ return round.ruling.evaluated ? round.ruling.reason : "";
39636
+ if (round.claim && !round.claim.done)
39637
+ return round.claim.note;
39638
+ return "";
39639
+ }
38949
39640
  function readOutcome(outcome) {
38950
39641
  if (typeof outcome === "string")
38951
- return { text: outcome, evidence: outcome };
38952
- return { text: outcome.text ?? "", evidence: outcome.evidence ?? "" };
39642
+ return { text: outcome, evidence: outcome, claim: null };
39643
+ return { text: outcome.text ?? "", evidence: outcome.evidence ?? "", claim: outcome.claim ?? null };
38953
39644
  }
38954
39645
  var GoalRunner3 = class {
38955
39646
  deps;
@@ -38962,10 +39653,17 @@ ${exports2.GOAL_INSTRUCTION}`;
38962
39653
  /** Wall-clock anchor for the envelope, from the injected clock. */
38963
39654
  startedAt = 0;
38964
39655
  /** Consecutive evaluator calls that produced no verdict. Any real ruling —
38965
- * including "not yet" — resets it. */
39656
+ * including "not yet" — resets it. Untouched on rounds that run no check:
39657
+ * they say nothing about the evaluator either way. */
38966
39658
  evaluatorFailures = 0;
38967
39659
  /** The evaluator's last account of what is outstanding. */
38968
39660
  lastReason = "";
39661
+ /** Consecutive rounds settled without a check. At
39662
+ * [`GOAL_UNCLAIMED_CHECK_INTERVAL`] the backstop runs one; reset on every
39663
+ * check run, claimed or backstop. */
39664
+ uncheckedRounds = 0;
39665
+ /** The agent's own last `goal_report`. */
39666
+ lastClaim = null;
38969
39667
  constructor(deps2) {
38970
39668
  this.deps = deps2;
38971
39669
  }
@@ -38975,7 +39673,8 @@ ${exports2.GOAL_INSTRUCTION}`;
38975
39673
  goal: this.goal,
38976
39674
  endReason: this.endReason,
38977
39675
  turns: this.turns,
38978
- lastReason: this.lastReason === "" ? null : this.lastReason
39676
+ lastReason: this.lastReason === "" ? null : this.lastReason,
39677
+ lastClaim: this.lastClaim
38979
39678
  };
38980
39679
  }
38981
39680
  /** The user's stop (Esc, `/goal stop`, banner button). The in-flight turn is
@@ -38995,6 +39694,8 @@ ${exports2.GOAL_INSTRUCTION}`;
38995
39694
  this.turns = 0;
38996
39695
  this.evaluatorFailures = 0;
38997
39696
  this.lastReason = "";
39697
+ this.uncheckedRounds = 0;
39698
+ this.lastClaim = null;
38998
39699
  this.emit();
38999
39700
  this.startedAt = (this.deps.now ?? Date.now)();
39000
39701
  let prompt = buildGoalPrompt(goal);
@@ -39008,30 +39709,40 @@ ${exports2.GOAL_INSTRUCTION}`;
39008
39709
  this.turns += 1;
39009
39710
  if (this.stopRequested)
39010
39711
  return this.finish("stopped");
39011
- const { text, evidence } = readOutcome(outcome);
39012
- const ruling = await this.rule(goal, evidence, text);
39712
+ const { text, evidence, claim } = readOutcome(outcome);
39713
+ this.lastClaim = claim;
39714
+ this.uncheckedRounds += 1;
39715
+ const check2 = claim?.done === true ? "claimed" : this.uncheckedRounds >= exports2.GOAL_UNCLAIMED_CHECK_INTERVAL || this.envelopeVerdict(this.turns) !== null ? "backstop" : "none";
39716
+ let ruling = null;
39717
+ if (check2 !== "none") {
39718
+ this.uncheckedRounds = 0;
39719
+ ruling = await this.rule(goal, evidence, text);
39720
+ }
39013
39721
  if (this.stopRequested)
39014
39722
  return this.finish("stopped");
39015
- if (ruling.evaluated && ruling.ok) {
39016
- this.lastReason = ruling.reason;
39017
- return this.finish("done");
39018
- }
39019
- if (ruling.evaluated && !ruling.achievable) {
39020
- this.lastReason = ruling.reason;
39021
- return this.finish("not_achievable");
39022
- }
39023
- if (ruling.evaluated) {
39024
- this.evaluatorFailures = 0;
39025
- } else if ((this.evaluatorFailures += 1) >= exports2.GOAL_MAX_EVALUATOR_FAILURES) {
39026
- this.lastReason = ruling.reason;
39027
- return this.finish("evaluator_failed");
39723
+ if (ruling) {
39724
+ if (ruling.evaluated && ruling.ok) {
39725
+ this.lastReason = ruling.reason;
39726
+ return this.finish("done");
39727
+ }
39728
+ if (ruling.evaluated && !ruling.achievable) {
39729
+ this.lastReason = ruling.reason;
39730
+ return this.finish("not_achievable");
39731
+ }
39732
+ if (ruling.evaluated) {
39733
+ this.evaluatorFailures = 0;
39734
+ this.lastReason = ruling.reason;
39735
+ } else if ((this.evaluatorFailures += 1) >= exports2.GOAL_MAX_EVALUATOR_FAILURES) {
39736
+ this.lastReason = ruling.reason;
39737
+ return this.finish("evaluator_failed");
39738
+ }
39028
39739
  }
39029
39740
  const ceiling = this.envelopeVerdict(this.turns);
39030
39741
  if (ceiling !== null)
39031
39742
  return this.finish(ceiling);
39032
- this.lastReason = ruling.reason;
39743
+ this.deps.onRound?.({ turns: this.turns, check: check2, ruling, claim });
39033
39744
  this.emit();
39034
- prompt = buildContinuationPrompt(goal, ruling.evaluated ? ruling.reason : void 0);
39745
+ prompt = buildContinuationPrompt(goal, ruling?.evaluated ? ruling.reason : void 0);
39035
39746
  }
39036
39747
  }
39037
39748
  /** One completion ruling, with the evaluator's own failures absorbed. A judge
@@ -40898,7 +41609,7 @@ var require_agentAuth = __commonJS({
40898
41609
  "../packages/orion-client-core/dist/auth/agentAuth.js"(exports2) {
40899
41610
  "use strict";
40900
41611
  Object.defineProperty(exports2, "__esModule", { value: true });
40901
- exports2.USAGE_TOPUP_COVERING_LABEL = exports2.NO_USAGE_LIMIT_LABEL = exports2.AgentSession = exports2.TOKEN_REQUEST_TIMEOUT_MS = exports2.AgentAuthError = void 0;
41612
+ exports2.USAGE_TOPUP_COVERING_LABEL = exports2.NO_USAGE_LIMIT_LABEL = exports2.AgentSession = exports2.BRAIN_RENEW_DEADLINE_MS = exports2.RENEW_BUDGET_MS = exports2.SECRET_READ_TIMEOUT_MS = exports2.TOKEN_REQUEST_TIMEOUT_MS = exports2.AgentAuthError = void 0;
40902
41613
  exports2.isAgentSessionKey = isAgentSessionKey;
40903
41614
  exports2.pkcePair = pkcePair;
40904
41615
  exports2.buildConnectUrl = buildConnectUrl;
@@ -40979,6 +41690,16 @@ var require_agentAuth = __commonJS({
40979
41690
  const value = jwtClaim(token, claim);
40980
41691
  return typeof value === "string" && value ? value : null;
40981
41692
  }
41693
+ function remainingValidityMs(token) {
41694
+ const exp = jwtClaim(token, "exp");
41695
+ return typeof exp === "number" && Number.isFinite(exp) ? exp * 1e3 - Date.now() : 0;
41696
+ }
41697
+ function sleep(ms) {
41698
+ return new Promise((resolve5) => {
41699
+ const timer = setTimeout(resolve5, ms);
41700
+ timer.unref?.();
41701
+ });
41702
+ }
40982
41703
  async function pkcePair() {
40983
41704
  const raw = new Uint8Array(48);
40984
41705
  globalThis.crypto.getRandomValues(raw);
@@ -41066,16 +41787,54 @@ var require_agentAuth = __commonJS({
41066
41787
  }
41067
41788
  var FRESH_TOKEN_BUFFER_MS = 6e4;
41068
41789
  var EARLY_REFRESH_MS = 10 * 6e4;
41790
+ exports2.SECRET_READ_TIMEOUT_MS = 5e3;
41791
+ exports2.RENEW_BUDGET_MS = 55e3;
41792
+ exports2.BRAIN_RENEW_DEADLINE_MS = 9e4;
41793
+ var RENEWED_TOKEN_MIN_REMAINING_MS = 5 * 6e4;
41794
+ var READ_TIMED_OUT = Symbol("orion.secret-read-timed-out");
41069
41795
  var AgentSession = class {
41070
41796
  store;
41071
41797
  apiBaseUrl;
41072
41798
  options;
41073
41799
  inflightRefresh = null;
41800
+ /** The last token set THIS process saved — a write-through mirror of {@link save}, never
41801
+ * of sibling processes' writes (those live only in the shared store). Lets a renewal
41802
+ * answer with our own recent mint when the store read itself is wedged. NEVER used to
41803
+ * START a refresh: a cached refresh token may be rotated-away by a sibling, and replaying
41804
+ * one late revokes the whole token family server-side. */
41805
+ lastSaved = null;
41074
41806
  constructor(store, apiBaseUrl, options = {}) {
41075
41807
  this.store = store;
41076
41808
  this.apiBaseUrl = apiBaseUrl;
41077
41809
  this.options = options;
41078
41810
  }
41811
+ /** Breadcrumb line (see {@link AgentSessionOptions.trace}); a throwing sink is the host's
41812
+ * bug and must never break the auth path. */
41813
+ trace(line) {
41814
+ try {
41815
+ this.options.trace?.(line);
41816
+ } catch {
41817
+ }
41818
+ }
41819
+ /** One bounded store read. {@link READ_TIMED_OUT} = the store did not answer (timed out
41820
+ * or threw) — an UNREACHABLE store, distinct from `null` = the key is definitively
41821
+ * absent. The renewal path branches on that difference: absent means signed out (fail
41822
+ * closed now); unreachable means retry and degrade, never a declared sign-out. */
41823
+ async boundedRead(key) {
41824
+ const timeoutMs = this.options.secretReadTimeoutMs ?? exports2.SECRET_READ_TIMEOUT_MS;
41825
+ let timer;
41826
+ const timeout = new Promise((resolve5) => {
41827
+ timer = setTimeout(() => resolve5(READ_TIMED_OUT), timeoutMs);
41828
+ timer.unref?.();
41829
+ });
41830
+ try {
41831
+ const read = Promise.resolve(this.store.get(key)).then((value) => value || null, () => READ_TIMED_OUT);
41832
+ return await Promise.race([read, timeout]);
41833
+ } finally {
41834
+ if (timer !== void 0)
41835
+ clearTimeout(timer);
41836
+ }
41837
+ }
41079
41838
  async currentAccessToken() {
41080
41839
  return await this.store.get(ACCESS_KEY) || null;
41081
41840
  }
@@ -41095,9 +41854,7 @@ var require_agentAuth = __commonJS({
41095
41854
  const token = await this.currentAccessToken();
41096
41855
  if (!token)
41097
41856
  return null;
41098
- const exp = jwtClaim(token, "exp");
41099
- const expiresAtMs = typeof exp === "number" && Number.isFinite(exp) ? exp * 1e3 : 0;
41100
- const remainingMs = expiresAtMs - Date.now();
41857
+ const remainingMs = remainingValidityMs(token);
41101
41858
  if (remainingMs > EARLY_REFRESH_MS)
41102
41859
  return token;
41103
41860
  if (remainingMs > FRESH_TOKEN_BUFFER_MS) {
@@ -41107,6 +41864,64 @@ var require_agentAuth = __commonJS({
41107
41864
  await this.refresh();
41108
41865
  return this.currentAccessToken();
41109
41866
  }
41867
+ /** The FAIL-CLOSED renewal answer for the local brain's `renew_bearer` request — invoked
41868
+ * only after the gateway REFUSED a bearer (401), which makes the server's verdict the
41869
+ * ground truth this method never argues with. Its contract:
41870
+ * - it never answers with `refused` (the token just declared dead) nor with a near-dead
41871
+ * token — a mint is forced instead;
41872
+ * - a DIFFERENT stored token with comfortable validity (a sibling process already
41873
+ * renewed through the shared store) is the answer immediately, no mint;
41874
+ * - otherwise it mints, retrying transient failures with backoff under `renewBudgetMs`,
41875
+ * re-reading the store between tries — a sibling's mint landing while ours failed
41876
+ * (the rotation race's other half, reply-lost rotations included) is a heal;
41877
+ * - a wedged store degrades to this process's own last save for the ACCESS token
41878
+ * (never for starting a refresh — rotation safety, see {@link refresh});
41879
+ * - `null` means the account genuinely cannot produce a fresh token (signed out,
41880
+ * family revoked, or the budget lapsed with everything unreachable) — the brain then
41881
+ * surfaces the honest auth error.
41882
+ *
41883
+ * {@link currentFreshAccessToken} stays the PROACTIVE read with its deliberate fail-OPEN
41884
+ * degradation ("the stored token stands"); this is the REACTIVE one, and the two must
41885
+ * not be merged: the fail-open answer is exactly what let the 2026-08-24/25 stage turns
41886
+ * die — it handed the refused token straight back, and the one heal was spent. */
41887
+ async renewedAccessToken(refused) {
41888
+ const budget = this.options.renewBudgetMs ?? exports2.RENEW_BUDGET_MS;
41889
+ const backoffBase = this.options.renewBackoffBaseMs ?? 500;
41890
+ const deadline = Date.now() + budget;
41891
+ const answerable = (token2, minted) => typeof token2 === "string" && token2 !== "" && token2 !== refused && // A mint vouches for freshness by EVENT (it just happened server-side), sidestepping
41892
+ // the local clock entirely — a fast client clock must not veto a genuinely new token.
41893
+ (minted || remainingValidityMs(token2) > RENEWED_TOKEN_MIN_REMAINING_MS);
41894
+ const storedAccess = async () => {
41895
+ const read = await this.boundedRead(ACCESS_KEY);
41896
+ if (read !== READ_TIMED_OUT)
41897
+ return { token: read, wedged: false };
41898
+ return { token: this.lastSaved?.accessToken ?? null, wedged: true };
41899
+ };
41900
+ let { token, wedged } = await storedAccess();
41901
+ if (answerable(token, false)) {
41902
+ this.trace(wedged ? "renew: answered from the process cache (store unreachable), no mint" : "renew: answered from the store (sibling renewal), no mint");
41903
+ return token;
41904
+ }
41905
+ for (let attempt = 0; ; attempt += 1) {
41906
+ const minted = await this.refresh();
41907
+ ({ token, wedged } = await storedAccess());
41908
+ if (answerable(token, minted)) {
41909
+ this.trace(minted ? `renew: minted and answered (attempt ${attempt + 1})` : "renew: a sibling's mint landed \u2014 answered");
41910
+ return token;
41911
+ }
41912
+ const refreshToken = await this.boundedRead(REFRESH_KEY);
41913
+ if (refreshToken === null) {
41914
+ this.trace("renew: no session (signed out / revoked) \u2014 fail-closed");
41915
+ return null;
41916
+ }
41917
+ const wait = Math.min(Math.min(8e3, backoffBase * 2 ** attempt), deadline - Date.now());
41918
+ if (wait <= 0)
41919
+ break;
41920
+ await sleep(wait);
41921
+ }
41922
+ this.trace(`renew: budget (${budget}ms) exhausted \u2014 fail-closed`);
41923
+ return null;
41924
+ }
41110
41925
  /** The plan the user is on (free/pro/…), for display + upgrade CTAs. */
41111
41926
  async tier() {
41112
41927
  return await this.store.get(TIER_KEY) || null;
@@ -41243,6 +42058,7 @@ var require_agentAuth = __commonJS({
41243
42058
  return Boolean(await this.store.get(REFRESH_KEY));
41244
42059
  }
41245
42060
  async save(tokens) {
42061
+ this.lastSaved = tokens;
41246
42062
  await this.store.store(ACCESS_KEY, tokens.accessToken);
41247
42063
  await this.store.store(REFRESH_KEY, tokens.refreshToken);
41248
42064
  await this.store.store(TIER_KEY, tokens.tier);
@@ -41263,20 +42079,47 @@ var require_agentAuth = __commonJS({
41263
42079
  return inflight;
41264
42080
  }
41265
42081
  async doRefresh() {
41266
- const refreshToken = await this.store.get(REFRESH_KEY);
42082
+ const started = Date.now();
42083
+ const refreshToken = await this.boundedRead(REFRESH_KEY);
42084
+ if (refreshToken === READ_TIMED_OUT) {
42085
+ this.trace(`refresh: store read unanswered after ${Date.now() - started}ms \u2014 transient`);
42086
+ return false;
42087
+ }
41267
42088
  if (!refreshToken)
41268
42089
  return false;
41269
42090
  try {
41270
- await this.save(await refreshTokens({
42091
+ const minted = await refreshTokens({
41271
42092
  apiBaseUrl: this.apiBaseUrl(),
41272
42093
  refreshToken,
41273
42094
  requestTimeoutMs: this.options.requestTimeoutMs
41274
- }));
42095
+ });
42096
+ if (!minted.accessToken) {
42097
+ this.trace("refresh: malformed 200 (empty access token) \u2014 transient");
42098
+ return false;
42099
+ }
42100
+ const tokens = minted.refreshToken ? minted : { ...minted, refreshToken };
42101
+ const written = await Promise.race([
42102
+ this.save(tokens).then(() => true, () => false),
42103
+ sleep(3 * (this.options.secretReadTimeoutMs ?? exports2.SECRET_READ_TIMEOUT_MS)).then(() => false)
42104
+ ]);
42105
+ this.trace(written ? `refresh: minted in ${Date.now() - started}ms` : `refresh: minted in ${Date.now() - started}ms, store write still pending \u2014 tokens live in the process cache`);
41275
42106
  return true;
41276
42107
  } catch (err2) {
41277
42108
  if (err2 instanceof AgentAuthError && isDefinitiveAuthRejection(err2)) {
42109
+ const current2 = await this.boundedRead(REFRESH_KEY);
42110
+ if (current2 === READ_TIMED_OUT) {
42111
+ this.trace("refresh: rejected, but the store is unreachable \u2014 clear deferred");
42112
+ return false;
42113
+ }
42114
+ if (current2 && current2 !== refreshToken) {
42115
+ this.trace("refresh: rejection was a rotation-race replay \u2014 sibling's session adopted");
42116
+ return true;
42117
+ }
42118
+ this.trace("refresh: definitively rejected \u2014 session cleared");
41278
42119
  await this.clear();
42120
+ return false;
41279
42121
  }
42122
+ this.trace(`refresh: transient failure (${err2 instanceof AgentAuthError ? err2.status : "malformed reply"})`);
41280
42123
  return false;
41281
42124
  }
41282
42125
  }
@@ -41288,6 +42131,7 @@ var require_agentAuth = __commonJS({
41288
42131
  await this.clear();
41289
42132
  }
41290
42133
  async clear() {
42134
+ this.lastSaved = null;
41291
42135
  await this.store.delete(ACCESS_KEY);
41292
42136
  await this.store.delete(REFRESH_KEY);
41293
42137
  await this.store.delete(TIER_KEY);
@@ -41571,8 +42415,8 @@ var require_browserLogin = __commonJS({
41571
42415
  } catch {
41572
42416
  }
41573
42417
  }
41574
- function createAgentSession3(secrets, config) {
41575
- return new agentAuth_1.AgentSession(secrets, () => config.accountsApiUrl);
42418
+ function createAgentSession3(secrets, config, options = {}) {
42419
+ return new agentAuth_1.AgentSession(secrets, () => config.accountsApiUrl, options);
41576
42420
  }
41577
42421
  async function signInViaBrowser3(session, config, deps2 = {}) {
41578
42422
  if (await session.isSignedIn())
@@ -69930,7 +70774,7 @@ var require_connection = __commonJS({
69930
70774
  return;
69931
70775
  }
69932
70776
  case "renew_bearer": {
69933
- void this.answerRenew(frame.id);
70777
+ void this.answerRenew(frame.id, frame.refused);
69934
70778
  return;
69935
70779
  }
69936
70780
  case "rpc_result": {
@@ -69948,15 +70792,19 @@ var require_connection = __commonJS({
69948
70792
  return;
69949
70793
  }
69950
70794
  }
69951
- /** Run (or join) the ONE in-flight refresh and answer the renew request with its result.
69952
- * A throwing or absent auth layer answers "no bearer" — a failed renewal at the brain,
69953
- * never a connection fault. */
69954
- async answerRenew(id) {
70795
+ /** Run (or join) the ONE in-flight renewal and answer the renew request with its result.
70796
+ * Joiners share the in-flight answer even when their `refused` differs (a turn's main
70797
+ * call and its interim passes usually 401 on the SAME bearer; when they don't, a shared
70798
+ * answer the gateway still refuses just triggers that call's second renew round, which
70799
+ * runs fresh with ITS refused token — self-correcting, never a loop). A throwing or
70800
+ * absent auth layer answers "no bearer" — a failed renewal at the brain, never a
70801
+ * connection fault. */
70802
+ async answerRenew(id, refused) {
69955
70803
  let bearer = null;
69956
70804
  if (this.renewBearer) {
69957
70805
  this.renewInFlight ??= (async () => {
69958
70806
  try {
69959
- return await this.renewBearer();
70807
+ return await this.renewBearer(refused);
69960
70808
  } catch {
69961
70809
  return null;
69962
70810
  } finally {
@@ -70770,6 +71618,8 @@ var require_dist = __commonJS({
70770
71618
  __exportStar(require_duetEntry(), exports2);
70771
71619
  __exportStar(require_duetRouterModel(), exports2);
70772
71620
  __exportStar(require_duetRouterInstall(), exports2);
71621
+ __exportStar(require_duetExecutorGate(), exports2);
71622
+ __exportStar(require_duetExecutorGateStatus(), exports2);
70773
71623
  __exportStar(require_duetPlan(), exports2);
70774
71624
  __exportStar(require_duetPlanners(), exports2);
70775
71625
  __exportStar(require_repoIdentity(), exports2);
@@ -70780,6 +71630,7 @@ var require_dist = __commonJS({
70780
71630
  __exportStar(require_duetRoutingAdvisor(), exports2);
70781
71631
  __exportStar(require_cron(), exports2);
70782
71632
  __exportStar(require_agentStore(), exports2);
71633
+ __exportStar(require_goalClaim(), exports2);
70783
71634
  __exportStar(require_goalMarker(), exports2);
70784
71635
  __exportStar(require_goalEvidence(), exports2);
70785
71636
  __exportStar(require_goalEvaluate(), exports2);
@@ -71764,7 +72615,8 @@ var require_toolVisibility = __commonJS({
71764
72615
  exports2.SILENT_TOOLS = /* @__PURE__ */ new Set([
71765
72616
  "ask_user",
71766
72617
  "exit_plan_mode",
71767
- "await_agents"
72618
+ "await_agents",
72619
+ "goal_report"
71768
72620
  ]);
71769
72621
  function isSilentTool3(name2) {
71770
72622
  return typeof name2 === "string" && exports2.SILENT_TOOLS.has(name2);
@@ -87802,8 +88654,19 @@ var darkTheme = {
87802
88654
  contextCometFragment: "#7c5cbf",
87803
88655
  contextCometDust: "#4a3d66",
87804
88656
  border: "#808080",
87805
- diffAdd: "#38a660",
87806
- diffRemove: "#b3596b",
88657
+ // Diff layers (see the Theme interface): near-black bands a step apart, loud
88658
+ // color reserved for the +/- decorations, bright off-white plain text. The
88659
+ // hues are Orion's own family — EMERALD for additions (cooler than a leaf
88660
+ // green; the decoration green IS the app's semantic green, autoAccept, so
88661
+ // the diff and the posture/success chrome speak one color) and ROSE for
88662
+ // removals (sits naturally beside the violet brand).
88663
+ diffAdd: "#3fb950",
88664
+ diffRemove: "#e5484d",
88665
+ diffAddBg: "#022711",
88666
+ diffRemoveBg: "#330210",
88667
+ diffAddWordBg: "#044921",
88668
+ diffRemoveWordBg: "#4d0416",
88669
+ diffText: "#f8f8f2",
87807
88670
  diffContext: "#808080",
87808
88671
  gutter: "#808080",
87809
88672
  synKeyword: "#569cd6",
@@ -87813,11 +88676,6 @@ var darkTheme = {
87813
88676
  synType: "#4ec9b0",
87814
88677
  synComment: "#6a9955",
87815
88678
  synControl: "#c586c0",
87816
- // Per-line diff BASE bands (muted). The brighter diffAdd/diffRemove ride on top
87817
- // as word-level change highlights, so a small edit shows a two-tone line instead
87818
- // of one flat wash.
87819
- diffAddBg: "#225c2b",
87820
- diffRemoveBg: "#7a2936",
87821
88679
  autoAccept: "#3fb950",
87822
88680
  planMode: "#38bdf8",
87823
88681
  duetMode: "#a78bfa",
@@ -87858,8 +88716,17 @@ var lightTheme = {
87858
88716
  contextCometFragment: "#8b6fd4",
87859
88717
  contextCometDust: "#b9a9dd",
87860
88718
  border: "#808080",
87861
- diffAdd: "#2f9d44",
87862
- diffRemove: "#d1454b",
88719
+ // Diff layers (see the Theme interface), mirrored for a light terminal: the
88720
+ // bands are the palest wash, the word step is deeper, decorations deeper
88721
+ // still. Same Orion family as dark — emerald additions (decoration green =
88722
+ // autoAccept, the app's semantic green) and rose removals.
88723
+ diffAdd: "#15803d",
88724
+ diffRemove: "#cf2240",
88725
+ diffAddBg: "#d9fbe8",
88726
+ diffRemoveBg: "#ffdce4",
88727
+ diffAddWordBg: "#aff5cd",
88728
+ diffRemoveWordBg: "#ffc2cf",
88729
+ diffText: "#333333",
87863
88730
  diffContext: "#808080",
87864
88731
  gutter: "#808080",
87865
88732
  synKeyword: "#0000ff",
@@ -87869,8 +88736,6 @@ var lightTheme = {
87869
88736
  synType: "#267f99",
87870
88737
  synComment: "#008000",
87871
88738
  synControl: "#af00db",
87872
- diffAddBg: "#a6f3b0",
87873
- diffRemoveBg: "#ffc9d0",
87874
88739
  autoAccept: "#15803d",
87875
88740
  planMode: "#267f99",
87876
88741
  duetMode: "#7c3aed",
@@ -88114,6 +88979,11 @@ async function transportBearer(session, store, fallback) {
88114
88979
  if (!token) await syncAccountGate(session, store);
88115
88980
  return token ?? fallback ?? null;
88116
88981
  }
88982
+ async function renewedTransportBearer(session, store, refused, fallback) {
88983
+ const token = await session.renewedAccessToken(refused);
88984
+ if (!token) await syncAccountGate(session, store);
88985
+ return token ?? fallback ?? null;
88986
+ }
88117
88987
  var SIGN_IN_FIRST_MESSAGE = "Sign in first with /signin to start chatting.";
88118
88988
  function isAuthDeadError(e) {
88119
88989
  return /\bhttp 401\b/.test(e instanceof Error ? e.message : String(e));
@@ -89101,11 +89971,6 @@ function appendLiveCode(s, id, delta) {
89101
89971
  if (!live.liveCode || live.liveCode.id !== id) return s;
89102
89972
  return { ...s, live: { ...live, liveCode: { ...live.liveCode, code: live.liveCode.code + delta } } };
89103
89973
  }
89104
- function endLiveCode(s, id) {
89105
- const live = s.live;
89106
- if (!live?.liveCode || live.liveCode.id !== id) return s;
89107
- return { ...s, live: { ...live, liveCode: null } };
89108
- }
89109
89974
  function startTool(s, name2, input) {
89110
89975
  const flushed = flushLive(s);
89111
89976
  const live = flushed.live ?? emptyLive();
@@ -89134,7 +89999,11 @@ function settleToolEnd(s, id, success, detail) {
89134
89999
  }
89135
90000
  const rest = { ...s.live.pendingWrites };
89136
90001
  delete rest[id];
89137
- const nextLive = { ...s.live, pendingWrites: rest, liveCode: null };
90002
+ const nextLive = {
90003
+ ...s.live,
90004
+ pendingWrites: rest,
90005
+ liveCode: s.live.liveCode && s.live.liveCode.id === id ? null : s.live.liveCode
90006
+ };
89138
90007
  if (success) {
89139
90008
  return { ...s, live: nextLive };
89140
90009
  }
@@ -89189,7 +90058,10 @@ function fileModified(s, d2) {
89189
90058
  affectedFiles: d2.affectedFiles,
89190
90059
  trust: d2.trust
89191
90060
  };
89192
- return { ...f, settled: [...f.settled, item] };
90061
+ const block = f.live?.liveCode;
90062
+ const settlesBlock = !!block && (d2.toolId ? block.id === d2.toolId : block.path === d2.path);
90063
+ const live = settlesBlock && f.live ? { ...f.live, liveCode: null } : f.live;
90064
+ return { ...f, live, settled: [...f.settled, item] };
89193
90065
  }
89194
90066
  function applyTurnComplete(s, data) {
89195
90067
  const flushed = flushLive(s);
@@ -90235,7 +91107,7 @@ function remoteView(r2) {
90235
91107
  footer: "Switch with /remote on|off \xB7 hide or show this session with /remote hide|show."
90236
91108
  };
90237
91109
  }
90238
- function goalView(running, goal, turns = 0, lastReason = null) {
91110
+ function goalView(running, goal, turns = 0, lastReason = null, lastClaim = null) {
90239
91111
  if (!running) {
90240
91112
  return {
90241
91113
  title: "Goal",
@@ -90244,7 +91116,12 @@ function goalView(running, goal, turns = 0, lastReason = null) {
90244
91116
  };
90245
91117
  }
90246
91118
  const rows = [statusRow("info", "Running", goal), statusRow("info", "Turns", String(turns))];
90247
- if (lastReason) rows.push(statusRow("pending", "Last check", lastReason));
91119
+ if (lastClaim) {
91120
+ const claim = lastClaim.done ? "done" : "not done";
91121
+ const note = (0, import_client_core15.goalReasonLine)(lastClaim.note);
91122
+ rows.push(statusRow("info", "Agent reports", note ? `${claim} \u2014 ${note}` : claim));
91123
+ }
91124
+ if (lastReason) rows.push(statusRow("pending", "Last check", (0, import_client_core15.goalReasonLine)(lastReason)));
90248
91125
  return {
90249
91126
  title: "Goal",
90250
91127
  tone: "info",
@@ -91458,30 +92335,32 @@ ${(0, import_client_core20.duetRoutingSummaryLine)(await (0, import_client_core2
91458
92335
  kind: "local",
91459
92336
  name: "duet-entry",
91460
92337
  aliases: ["entry"],
91461
- description: "Choose who decides plan vs execute in Duet mode \u2014 the planner, or the router",
91462
- keywords: ["duet", "planner", "router", "plan", "execute", "hand off"],
91463
- argumentHint: "[planner|router]",
92338
+ description: "Choose who decides plan vs execute in Duet mode \u2014 the planner, the router, or your executor",
92339
+ keywords: ["duet", "planner", "router", "executor", "plan", "execute", "hand off"],
92340
+ argumentHint: "[planner|router|executor]",
91464
92341
  run: async (args2, ctx) => {
91465
92342
  const workspaceRoot = ctx.config?.workspaceRoot;
91466
92343
  const typed = (0, import_client_core20.normalizeDuetEntry)(args2);
91467
92344
  const routerStatus = await (0, import_client_core20.describeDuetRouterModel)().catch(() => null);
92345
+ const executorStatus = await (0, import_client_core20.describeDuetExecutorGateCached)({ workspaceRoot }).catch(() => null);
91468
92346
  const save = async (entry) => {
91469
- const availability = (0, import_client_core20.duetEntryOptionAvailability)(entry, routerStatus);
92347
+ const availability = (0, import_client_core20.duetEntryOptionAvailability)(entry, routerStatus, executorStatus);
91470
92348
  if (availability.disabled) {
91471
92349
  ctx.print(`${(0, import_client_core20.duetEntryLabel)(entry)}: ${availability.note ?? "unavailable"}`, "warning");
91472
- if (routerStatus !== null) ctx.print((0, import_client_core20.duetRouterStatusLine)(routerStatus), "info");
92350
+ if (entry === "router" && routerStatus !== null) ctx.print((0, import_client_core20.duetRouterStatusLine)(routerStatus), "info");
91473
92351
  return;
91474
92352
  }
91475
92353
  await (0, import_client_core20.setDuetEntry)(entry);
91476
92354
  const option = import_client_core20.DUET_ENTRY_OPTIONS.find((o) => o.value === entry);
91477
92355
  ctx.print(`${import_client_core20.DUET_ENTRY_INFO.label}: ${(0, import_client_core20.duetEntryLabel)(entry)} \u2014 ${option?.description ?? ""}`, "success");
92356
+ if (entry === "executor" && executorStatus !== null) ctx.print((0, import_client_core20.executorGateStatusLine)(executorStatus), "info");
91478
92357
  };
91479
92358
  if (typed !== null) {
91480
92359
  await save(typed);
91481
92360
  return;
91482
92361
  }
91483
92362
  if (args2.trim() !== "") {
91484
- ctx.print("Usage: /duet-entry [planner|router]", "warning");
92363
+ ctx.print("Usage: /duet-entry [planner|router|executor]", "warning");
91485
92364
  return;
91486
92365
  }
91487
92366
  const active = await (0, import_client_core20.loadDuetEntry)({ workspaceRoot });
@@ -91491,11 +92370,13 @@ ${(0, import_client_core20.duetRoutingSummaryLine)(await (0, import_client_core2
91491
92370
  kind: "select",
91492
92371
  title: `${import_client_core20.DUET_ENTRY_INFO.label} \xB7 current: ${(0, import_client_core20.duetEntryLabel)(active)}`,
91493
92372
  options: import_client_core20.DUET_ENTRY_OPTIONS.map((option) => {
91494
- const availability = (0, import_client_core20.duetEntryOptionAvailability)(option.value, routerStatus);
92373
+ const availability = (0, import_client_core20.duetEntryOptionAvailability)(option.value, routerStatus, executorStatus);
91495
92374
  return {
91496
92375
  label: option.label,
91497
92376
  value: option.value,
91498
- // What it needs beats what it does when it cannot be picked.
92377
+ // The row's note — what this pick means on THIS machine (a refusal reason for
92378
+ // the router, the rules-floor explainer for the executor) — beats the generic
92379
+ // description.
91499
92380
  hint: availability.note ?? (option.value === active ? "(active)" : option.description),
91500
92381
  accent: option.value === active
91501
92382
  };
@@ -93180,7 +94061,7 @@ Answer with /loops answer <text>, or /loops deny.`,
93180
94061
  kind: "local",
93181
94062
  name: "goal",
93182
94063
  aliases: ["goals"],
93183
- description: "Work continuously until the goal is complete \u2014 the agent decides when it's done",
94064
+ description: "Work continuously until the goal is complete \u2014 an independent check confirms it's done",
93184
94065
  argumentHint: "<what to accomplish | status | stop>",
93185
94066
  // Starting a goal starts a TURN — typed mid-turn it defers to the queue
93186
94067
  // (runs when the turn ends) rather than racing the live stream. The verb
@@ -93200,7 +94081,7 @@ Answer with /loops answer <text>, or /loops deny.`,
93200
94081
  }
93201
94082
  if (arg === "" || lower === "status") {
93202
94083
  const st2 = ctx.goals.status();
93203
- return ctx.printInfo(goalView(st2.running, st2.goal, st2.turns ?? 0, st2.lastReason ?? null));
94084
+ return ctx.printInfo(goalView(st2.running, st2.goal, st2.turns ?? 0, st2.lastReason ?? null, st2.lastClaim ?? null));
93204
94085
  }
93205
94086
  if (ctx.goals.status().running) {
93206
94087
  return ctx.print("A goal is already running \u2014 /goal stop first, or steer it by typing normally.", "warning");
@@ -93786,6 +94667,9 @@ function renderLane(transcript, app, ev) {
93786
94667
  transcript.setState(
93787
94668
  (s) => fileModified(s, {
93788
94669
  path: String(d2.path ?? ""),
94670
+ // The causing call — pairs the diff card with the frozen live code
94671
+ // block it settles (rewind-emitted events legitimately omit it).
94672
+ toolId: typeof d2.tool_id === "string" ? d2.tool_id : void 0,
93789
94673
  diff: typeof d2.diff === "string" ? d2.diff : null,
93790
94674
  insertions: typeof d2.insertions === "number" ? d2.insertions : 0,
93791
94675
  deletions: typeof d2.deletions === "number" ? d2.deletions : 0,
@@ -93996,11 +94880,8 @@ function renderLane(transcript, app, ev) {
93996
94880
  }
93997
94881
  break;
93998
94882
  }
93999
- case "tool_input_end": {
94000
- const id = typeof d2.tool_id === "string" ? d2.tool_id : "";
94001
- if (id) transcript.setState((s) => endLiveCode(s, id));
94883
+ case "tool_input_end":
94002
94884
  break;
94003
- }
94004
94885
  case "tool_progress": {
94005
94886
  const kind = typeof d2.kind === "string" ? d2.kind : "working";
94006
94887
  app.setState((s) => ({ ...s, statusText: `${kind}\u2026` }));
@@ -94130,7 +95011,7 @@ function makeGoalRunTurn(deps2) {
94130
95011
  }
94131
95012
  switch (outcome.kind) {
94132
95013
  case "complete":
94133
- return { text: outcome.finalText, evidence: outcome.evidence };
95014
+ return { text: outcome.finalText, evidence: outcome.evidence, claim: outcome.claim };
94134
95015
  case "cancelled":
94135
95016
  return "";
94136
95017
  case "error":
@@ -94575,7 +95456,7 @@ var WorkPlanApprovalBridge = class {
94575
95456
  var import_client_ui_core20 = __toESM(require_dist2(), 1);
94576
95457
 
94577
95458
  // src/components/layout/Transcript.tsx
94578
- var import_react27 = __toESM(require_react(), 1);
95459
+ var import_react28 = __toESM(require_react(), 1);
94579
95460
 
94580
95461
  // src/components/messages/MessageView.tsx
94581
95462
  var import_react23 = __toESM(require_react(), 1);
@@ -110590,7 +111471,27 @@ function expandTabs2(s) {
110590
111471
  }
110591
111472
  return out2;
110592
111473
  }
110593
- function wordRuns(shown, lang, changed, baseBg, brightBg, syntax, theme) {
111474
+ function diffLineStyle(theme, kind) {
111475
+ switch (kind) {
111476
+ case "add":
111477
+ return {
111478
+ bg: theme.diffAddBg,
111479
+ wordBg: theme.diffAddWordBg,
111480
+ accent: theme.diffAdd,
111481
+ text: theme.diffText
111482
+ };
111483
+ case "del":
111484
+ return {
111485
+ bg: theme.diffRemoveBg,
111486
+ wordBg: theme.diffRemoveWordBg,
111487
+ accent: theme.diffRemove,
111488
+ text: theme.diffText
111489
+ };
111490
+ case "context":
111491
+ return { accent: theme.gutter, text: theme.diffText };
111492
+ }
111493
+ }
111494
+ function wordRuns(shown, lang, changed, baseBg, brightBg, syntax, plainFg, theme) {
110594
111495
  let text;
110595
111496
  let fgs;
110596
111497
  if (syntax) {
@@ -110598,12 +111499,12 @@ function wordRuns(shown, lang, changed, baseBg, brightBg, syntax, theme) {
110598
111499
  text = spans.map((s) => s.text).join("");
110599
111500
  fgs = [];
110600
111501
  for (const sp of spans) {
110601
- const fg = synColor(theme, sp.kind);
111502
+ const fg = synColor(theme, sp.kind) ?? plainFg;
110602
111503
  for (let c3 = 0; c3 < sp.text.length; c3++) fgs.push(fg);
110603
111504
  }
110604
111505
  } else {
110605
111506
  text = shown;
110606
- fgs = new Array(shown.length).fill(void 0);
111507
+ fgs = new Array(shown.length).fill(plainFg);
110607
111508
  }
110608
111509
  const bgAt = (k) => changed[k] ? brightBg : baseBg;
110609
111510
  const runs = [];
@@ -110639,8 +111540,10 @@ function StructuredDiff({
110639
111540
  }
110640
111541
  const isAdd = l3.type === "add";
110641
111542
  const isDel = l3.type === "del";
110642
- const bg = isAdd ? theme.diffAddBg : isDel ? theme.diffRemoveBg : void 0;
110643
- const accent = isAdd ? theme.diffAdd : isDel ? theme.diffRemove : theme.gutter;
111543
+ const { bg, wordBg, accent, text } = diffLineStyle(
111544
+ theme,
111545
+ isAdd ? "add" : isDel ? "del" : "context"
111546
+ );
110644
111547
  const marker = isAdd ? "+" : isDel ? "-" : " ";
110645
111548
  const num = isDel ? l3.oldNo : l3.newNo;
110646
111549
  const raw = expandTabs2(l3.text ?? "");
@@ -110657,7 +111560,7 @@ function StructuredDiff({
110657
111560
  while (changed.length < shown.length) changed.push(false);
110658
111561
  }
110659
111562
  }
110660
- const body2 = changed ? wordRuns(shown, lang, changed, bg, accent, isAdd, theme) : isDel ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Text2, { children: shown }) : (highlightCode(shown, lang)[0] ?? []).map((sp, k) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Text2, { color: synColor(theme, sp.kind), children: sp.text }, k));
111563
+ const body2 = changed ? wordRuns(shown, lang, changed, bg, wordBg, isAdd, text, theme) : isDel ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Text2, { color: text, children: shown }) : (highlightCode(shown, lang)[0] ?? []).map((sp, k) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Text2, { color: synColor(theme, sp.kind) ?? text, children: sp.text }, k));
110661
111564
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Text2, { backgroundColor: bg, children: [
110662
111565
  /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Text2, { color: accent, children: [
110663
111566
  gutter(num),
@@ -111165,7 +112068,7 @@ function OrionRing() {
111165
112068
 
111166
112069
  // src/services/version.ts
111167
112070
  function tuiVersion() {
111168
- return "0.1.23".length > 0 ? "0.1.23" : null;
112071
+ return "0.1.25".length > 0 ? "0.1.25" : null;
111169
112072
  }
111170
112073
 
111171
112074
  // src/components/layout/WelcomeCard.tsx
@@ -111204,18 +112107,48 @@ var import_client_ui_core9 = __toESM(require_dist2(), 1);
111204
112107
  var import_client_core29 = __toESM(require_dist(), 1);
111205
112108
 
111206
112109
  // src/components/messages/Thinking.tsx
112110
+ var import_react24 = __toESM(require_react(), 1);
111207
112111
  var import_jsx_runtime40 = __toESM(require_jsx_runtime(), 1);
111208
- var LIVE_LINES = 12;
111209
- var LIVE_CHARS = 1200;
111210
- function thinkingTail(text) {
111211
- const tail = text.split("\n").slice(-LIVE_LINES).join("\n").trimEnd();
111212
- return tail.length > LIVE_CHARS ? `\u2026${tail.slice(-LIVE_CHARS)}` : tail;
112112
+ var LIVE_ROWS = 12;
112113
+ function wrapPlain(line, width) {
112114
+ const rows = [];
112115
+ let row = null;
112116
+ for (const word of line.split(" ")) {
112117
+ let w2 = word;
112118
+ while (w2.length > width) {
112119
+ if (row !== null) {
112120
+ rows.push(row);
112121
+ row = null;
112122
+ }
112123
+ rows.push(w2.slice(0, width));
112124
+ w2 = w2.slice(width);
112125
+ }
112126
+ if (w2 === "" && word !== "") continue;
112127
+ if (row === null) row = w2;
112128
+ else if (row.length + 1 + w2.length <= width) row += ` ${w2}`;
112129
+ else {
112130
+ rows.push(row);
112131
+ row = w2;
112132
+ }
112133
+ }
112134
+ if (row !== null) rows.push(row);
112135
+ return rows.length ? rows : [""];
112136
+ }
112137
+ function thinkingTailRows(text, width) {
112138
+ const w2 = Math.max(1, Math.floor(width));
112139
+ const tail = text.split("\n").slice(-LIVE_ROWS).join("\n").trimEnd();
112140
+ if (!tail) return [];
112141
+ const rows = [];
112142
+ for (const line of tail.split("\n")) rows.push(...wrapPlain(line, w2));
112143
+ return rows.slice(-LIVE_ROWS);
111213
112144
  }
111214
112145
  function Thinking({
111215
112146
  text,
111216
112147
  spinner = ""
111217
112148
  }) {
111218
112149
  const { columns } = useTerminalSize();
112150
+ const width = Math.max(20, columns - 4);
112151
+ const rows = import_react24.default.useMemo(() => thinkingTailRows(text, width), [text, width]);
111219
112152
  if (!text.trim()) return null;
111220
112153
  return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Box2, { flexDirection: "column", marginTop: 1, children: [
111221
112154
  /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(Box2, { flexDirection: "row", children: [
@@ -111223,7 +112156,7 @@ function Thinking({
111223
112156
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ThemedText, { dim: true, italic: true, children: "Thinking" }),
111224
112157
  spinner ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ThemedText, { colorKey: "spinner", children: ` ${spinner}` }) : null
111225
112158
  ] }),
111226
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Box2, { paddingLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Box2, { width: Math.max(20, columns - 4), children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ThemedText, { dim: true, italic: true, wrap: "wrap", children: thinkingTail(text) }) }) })
112159
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Box2, { paddingLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Box2, { width, flexDirection: "column", children: rows.map((row, i2) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(ThemedText, { dim: true, italic: true, wrap: "truncate-end", children: row.length ? row : " " }, i2)) }) })
111227
112160
  ] });
111228
112161
  }
111229
112162
 
@@ -111301,21 +112234,21 @@ function LiveCode({
111301
112234
  }
111302
112235
 
111303
112236
  // src/hooks/useStore.ts
111304
- var import_react24 = __toESM(require_react(), 1);
112237
+ var import_react25 = __toESM(require_react(), 1);
111305
112238
  function useStoreSelector(store, selector) {
111306
- return (0, import_react24.useSyncExternalStore)(
112239
+ return (0, import_react25.useSyncExternalStore)(
111307
112240
  store.subscribe,
111308
112241
  () => selector(store.getState())
111309
112242
  );
111310
112243
  }
111311
112244
 
111312
112245
  // src/hooks/useTranscriptEviction.ts
111313
- var import_react26 = __toESM(require_react(), 1);
112246
+ var import_react27 = __toESM(require_react(), 1);
111314
112247
 
111315
112248
  // src/vendor/ink/hooks/use-committed-rows.ts
111316
- var import_react25 = __toESM(require_react(), 1);
112249
+ var import_react26 = __toESM(require_react(), 1);
111317
112250
  function useCommittedRows() {
111318
- return (0, import_react25.useContext)(CommittedRowsContext);
112251
+ return (0, import_react26.useContext)(CommittedRowsContext);
111319
112252
  }
111320
112253
 
111321
112254
  // src/hooks/useTranscriptEviction.ts
@@ -111341,14 +112274,14 @@ function useTranscriptEviction({
111341
112274
  getItemsContainer
111342
112275
  }) {
111343
112276
  const api = useCommittedRows();
111344
- const forkSize = (0, import_react26.useContext)(TerminalSizeContext);
112277
+ const forkSize = (0, import_react27.useContext)(TerminalSizeContext);
111345
112278
  const fallbackSize = useTerminalSize();
111346
112279
  const rows = forkSize?.rows ?? fallbackSize.rows;
111347
112280
  const evictedCount = useStoreSelector(transcriptStore, (s) => s.evictedCount);
111348
112281
  const committedCount = useStoreSelector(transcriptStore, (s) => s.committedCount);
111349
- const apiRef = (0, import_react26.useRef)(api);
112282
+ const apiRef = (0, import_react27.useRef)(api);
111350
112283
  apiRef.current = api;
111351
- (0, import_react26.useLayoutEffect)(() => {
112284
+ (0, import_react27.useLayoutEffect)(() => {
111352
112285
  const snap = (s) => ({
111353
112286
  sessionId: s.sessionId,
111354
112287
  settledLength: s.settled.length,
@@ -111363,7 +112296,7 @@ function useTranscriptEviction({
111363
112296
  prev = s;
111364
112297
  });
111365
112298
  }, [transcriptStore]);
111366
- (0, import_react26.useEffect)(() => {
112299
+ (0, import_react27.useEffect)(() => {
111367
112300
  if (!enabled || !api || items.length <= 1) return;
111368
112301
  const container = getItemsContainer();
111369
112302
  if (!container) return;
@@ -111411,15 +112344,15 @@ function Transcript({
111411
112344
  const subAgents = useStoreSelector(appStore, (s) => s.subAgents);
111412
112345
  const subagentsAwaiting = useStoreSelector(appStore, (s) => s.subagentsAwaiting);
111413
112346
  const { columns } = useTerminalSize();
111414
- const items = import_react27.default.useMemo(
112347
+ const items = import_react28.default.useMemo(
111415
112348
  () => groupToolRuns(evictedCount > 0 ? settled.slice(evictedCount) : settled),
111416
112349
  [settled, evictedCount]
111417
112350
  );
111418
- const itemsContainerRef = import_react27.default.useRef(null);
111419
- const setItemsContainer = import_react27.default.useCallback((el) => {
112351
+ const itemsContainerRef = import_react28.default.useRef(null);
112352
+ const setItemsContainer = import_react28.default.useCallback((el) => {
111420
112353
  itemsContainerRef.current = el;
111421
112354
  }, []);
111422
- const getItemsContainer = import_react27.default.useCallback(() => itemsContainerRef.current, []);
112355
+ const getItemsContainer = import_react28.default.useCallback(() => itemsContainerRef.current, []);
111423
112356
  useTranscriptEviction({ enabled: evictionEnabled, transcriptStore, items, getItemsContainer });
111424
112357
  const running = live?.runningTool ?? null;
111425
112358
  const foldTail = running && !verbose ? trailingToolRun(items) : null;
@@ -111453,10 +112386,10 @@ function Transcript({
111453
112386
  }
111454
112387
 
111455
112388
  // src/components/layout/ReplFooter.tsx
111456
- var import_react46 = __toESM(require_react(), 1);
112389
+ var import_react47 = __toESM(require_react(), 1);
111457
112390
 
111458
112391
  // src/components/tools/PlanCard.tsx
111459
- var import_react28 = __toESM(require_react(), 1);
112392
+ var import_react29 = __toESM(require_react(), 1);
111460
112393
  var import_jsx_runtime43 = __toESM(require_jsx_runtime(), 1);
111461
112394
  function planStepView(index, currentStep) {
111462
112395
  const done2 = index + 1 < currentStep;
@@ -111481,8 +112414,8 @@ function PlanCard({ plan }) {
111481
112414
  const total = plan.steps.length;
111482
112415
  const allDone = total > 0 && plan.current_step > total;
111483
112416
  const planKey = `${plan.current_step}|${plan.steps.join("\0")}`;
111484
- const [hiddenKey, setHiddenKey] = import_react28.default.useState(null);
111485
- import_react28.default.useEffect(() => {
112417
+ const [hiddenKey, setHiddenKey] = import_react29.default.useState(null);
112418
+ import_react29.default.useEffect(() => {
111486
112419
  if (!allDone) return;
111487
112420
  const t = setTimeout(() => setHiddenKey(planKey), DONE_HOLD_MS);
111488
112421
  return () => clearTimeout(t);
@@ -111516,7 +112449,7 @@ function PlanCard({ plan }) {
111516
112449
  }
111517
112450
 
111518
112451
  // src/components/tools/SubAgentCard.tsx
111519
- var import_react29 = __toESM(require_react(), 1);
112452
+ var import_react30 = __toESM(require_react(), 1);
111520
112453
  var import_client_core30 = __toESM(require_dist(), 1);
111521
112454
  var import_client_ui_core10 = __toESM(require_dist2(), 1);
111522
112455
  var import_jsx_runtime44 = __toESM(require_jsx_runtime(), 1);
@@ -111536,8 +112469,8 @@ function SubAgentList({
111536
112469
  }) {
111537
112470
  const running = agents.filter((a) => a.phase !== "finished");
111538
112471
  const visible = !awaiting && running.length > 0;
111539
- const [now2, setNow] = import_react29.default.useState(() => Date.now());
111540
- import_react29.default.useEffect(() => {
112472
+ const [now2, setNow] = import_react30.default.useState(() => Date.now());
112473
+ import_react30.default.useEffect(() => {
111541
112474
  if (!visible) return void 0;
111542
112475
  const timer = setInterval(() => setNow(Date.now()), 1e3);
111543
112476
  return () => clearInterval(timer);
@@ -111553,7 +112486,7 @@ function SubAgentList({
111553
112486
  }
111554
112487
 
111555
112488
  // src/components/input/PromptInput.tsx
111556
- var import_react31 = __toESM(require_react(), 1);
112489
+ var import_react32 = __toESM(require_react(), 1);
111557
112490
 
111558
112491
  // src/components/input/slashSegments.ts
111559
112492
  function segmentSlice(text, offset, ranges) {
@@ -112330,7 +113263,7 @@ function vimKeypress(st2, buffer, input, key) {
112330
113263
  }
112331
113264
 
112332
113265
  // src/voice/useHoldToTalk.ts
112333
- var import_react30 = __toESM(require_react(), 1);
113266
+ var import_react31 = __toESM(require_react(), 1);
112334
113267
  var REPEAT_GAP_MS = 120;
112335
113268
  var WARMUP_THRESHOLD = 2;
112336
113269
  var HOLD_THRESHOLD = 5;
@@ -112488,9 +113421,9 @@ function spliceTranscript(value, cursor, text) {
112488
113421
  return { value: before + inserted + after, cursor: cursor + lead.length + text.length };
112489
113422
  }
112490
113423
  function useHoldToTalk(opts) {
112491
- const optsRef = (0, import_react30.useRef)(opts);
113424
+ const optsRef = (0, import_react31.useRef)(opts);
112492
113425
  optsRef.current = opts;
112493
- const machineRef = (0, import_react30.useRef)(null);
113426
+ const machineRef = (0, import_react31.useRef)(null);
112494
113427
  if (!machineRef.current) {
112495
113428
  machineRef.current = createHoldToTalk(
112496
113429
  {
@@ -112570,37 +113503,37 @@ function PromptInput({
112570
113503
  mode,
112571
113504
  permissionMode
112572
113505
  }) {
112573
- const [value, setValue2] = (0, import_react31.useState)("");
112574
- const [cursor, setCursor] = (0, import_react31.useState)(0);
112575
- const [history, setHistory] = (0, import_react31.useState)(
113506
+ const [value, setValue2] = (0, import_react32.useState)("");
113507
+ const [cursor, setCursor] = (0, import_react32.useState)(0);
113508
+ const [history, setHistory] = (0, import_react32.useState)(
112576
113509
  () => (initialHistory ?? []).slice(0, HISTORY_LIMIT)
112577
113510
  );
112578
- const [vimState, setVimState] = (0, import_react31.useState)(() => initialVimState("insert"));
112579
- const [menuIdx, setMenuIdx] = (0, import_react31.useState)(0);
112580
- const [menuDismissed, setMenuDismissed] = (0, import_react31.useState)(false);
112581
- const [search, setSearch] = (0, import_react31.useState)(null);
112582
- const [escArmed, setEscArmed] = (0, import_react31.useState)(false);
112583
- const [exitArmed, setExitArmed] = (0, import_react31.useState)(null);
112584
- const [postureFlash, setPostureFlash] = (0, import_react31.useState)(false);
112585
- const chordRef = (0, import_react31.useRef)(emptyChord());
112586
- const escAtRef = (0, import_react31.useRef)(0);
112587
- const exitAtRef = (0, import_react31.useRef)(0);
112588
- const valueRef = (0, import_react31.useRef)(value);
113511
+ const [vimState, setVimState] = (0, import_react32.useState)(() => initialVimState("insert"));
113512
+ const [menuIdx, setMenuIdx] = (0, import_react32.useState)(0);
113513
+ const [menuDismissed, setMenuDismissed] = (0, import_react32.useState)(false);
113514
+ const [search, setSearch] = (0, import_react32.useState)(null);
113515
+ const [escArmed, setEscArmed] = (0, import_react32.useState)(false);
113516
+ const [exitArmed, setExitArmed] = (0, import_react32.useState)(null);
113517
+ const [postureFlash, setPostureFlash] = (0, import_react32.useState)(false);
113518
+ const chordRef = (0, import_react32.useRef)(emptyChord());
113519
+ const escAtRef = (0, import_react32.useRef)(0);
113520
+ const exitAtRef = (0, import_react32.useRef)(0);
113521
+ const valueRef = (0, import_react32.useRef)(value);
112589
113522
  valueRef.current = value;
112590
- const cursorRef = (0, import_react31.useRef)(cursor);
113523
+ const cursorRef = (0, import_react32.useRef)(cursor);
112591
113524
  cursorRef.current = cursor;
112592
- const pasteLedger = (0, import_react31.useRef)({ nextId: 1, texts: /* @__PURE__ */ new Map() });
112593
- const recall = (0, import_react31.useRef)(NOT_RECALLING);
112594
- const wheelRef = (0, import_react31.useRef)(createWheelAccel());
112595
- const flashTimer = (0, import_react31.useRef)(null);
112596
- const firstPosture = (0, import_react31.useRef)(true);
113525
+ const pasteLedger = (0, import_react32.useRef)({ nextId: 1, texts: /* @__PURE__ */ new Map() });
113526
+ const recall = (0, import_react32.useRef)(NOT_RECALLING);
113527
+ const wheelRef = (0, import_react32.useRef)(createWheelAccel());
113528
+ const flashTimer = (0, import_react32.useRef)(null);
113529
+ const firstPosture = (0, import_react32.useRef)(true);
112597
113530
  const theme = useTheme();
112598
113531
  const { rows } = useTerminalSize();
112599
- const [voiceState, setVoiceState] = (0, import_react31.useState)("idle");
112600
- const [voiceProgress, setVoiceProgress] = (0, import_react31.useState)(null);
112601
- const [voiceError, setVoiceError] = (0, import_react31.useState)(null);
112602
- const [voiceBlink, setVoiceBlink] = (0, import_react31.useState)(false);
112603
- (0, import_react31.useEffect)(() => {
113532
+ const [voiceState, setVoiceState] = (0, import_react32.useState)("idle");
113533
+ const [voiceProgress, setVoiceProgress] = (0, import_react32.useState)(null);
113534
+ const [voiceError, setVoiceError] = (0, import_react32.useState)(null);
113535
+ const [voiceBlink, setVoiceBlink] = (0, import_react32.useState)(false);
113536
+ (0, import_react32.useEffect)(() => {
112604
113537
  if (voiceState !== "recording") return;
112605
113538
  const t = setInterval(() => setVoiceBlink((b2) => !b2), 600);
112606
113539
  return () => {
@@ -112608,7 +113541,7 @@ function PromptInput({
112608
113541
  setVoiceBlink(false);
112609
113542
  };
112610
113543
  }, [voiceState]);
112611
- const micRef = (0, import_react31.useRef)(null);
113544
+ const micRef = (0, import_react32.useRef)(null);
112612
113545
  const holdToTalk = useHoldToTalk({
112613
113546
  getBuffer: () => ({ value: valueRef.current, cursor: cursorRef.current }),
112614
113547
  applyBuffer: (v2, c3) => {
@@ -112644,11 +113577,11 @@ function PromptInput({
112644
113577
  }
112645
113578
  }
112646
113579
  });
112647
- (0, import_react31.useEffect)(() => () => holdToTalk.dispose(), []);
112648
- (0, import_react31.useEffect)(() => {
113580
+ (0, import_react32.useEffect)(() => () => holdToTalk.dispose(), []);
113581
+ (0, import_react32.useEffect)(() => {
112649
113582
  if (vim) setVimState(initialVimState("insert"));
112650
113583
  }, [vim]);
112651
- (0, import_react31.useEffect)(() => {
113584
+ (0, import_react32.useEffect)(() => {
112652
113585
  if (firstPosture.current) {
112653
113586
  firstPosture.current = false;
112654
113587
  return;
@@ -112660,7 +113593,7 @@ function PromptInput({
112660
113593
  if (flashTimer.current) clearTimeout(flashTimer.current);
112661
113594
  };
112662
113595
  }, [mode, permissionMode]);
112663
- const pickedMentions = (0, import_react31.useRef)(/* @__PURE__ */ new Set());
113596
+ const pickedMentions = (0, import_react32.useRef)(/* @__PURE__ */ new Set());
112664
113597
  const suggestionsFor = (v2) => v2.startsWith("/") && !v2.includes(" ") ? getCompletions?.(v2) ?? [] : [];
112665
113598
  const suggestions = suggestionsFor(value);
112666
113599
  const mPfx = mentionPrefix(value, cursor);
@@ -112668,18 +113601,18 @@ function PromptInput({
112668
113601
  const menuFiles = fileSuggestions.length > 0;
112669
113602
  const menuLen = menuFiles ? fileSuggestions.length : suggestions.length;
112670
113603
  const menuOpen = !menuDismissed && menuLen > 0 && (!vim || vimState.mode === "insert");
112671
- const notifyMenuRef = (0, import_react31.useRef)(onMenuOpenChange);
113604
+ const notifyMenuRef = (0, import_react32.useRef)(onMenuOpenChange);
112672
113605
  notifyMenuRef.current = onMenuOpenChange;
112673
- (0, import_react31.useEffect)(() => {
113606
+ (0, import_react32.useEffect)(() => {
112674
113607
  notifyMenuRef.current?.(menuOpen);
112675
113608
  }, [menuOpen]);
112676
- (0, import_react31.useEffect)(() => () => notifyMenuRef.current?.(false), []);
112677
- (0, import_react31.useEffect)(() => {
113609
+ (0, import_react32.useEffect)(() => () => notifyMenuRef.current?.(false), []);
113610
+ (0, import_react32.useEffect)(() => {
112678
113611
  for (const path14 of pickedMentions.current) {
112679
113612
  if (!value.includes(`${import_client_core32.FILE_MENTION_LEADER}${path14}`)) pickedMentions.current.delete(path14);
112680
113613
  }
112681
113614
  }, [value]);
112682
- (0, import_react31.useEffect)(() => {
113615
+ (0, import_react32.useEffect)(() => {
112683
113616
  setMenuIdx(0);
112684
113617
  setMenuDismissed(false);
112685
113618
  setEscArmed(false);
@@ -113131,7 +114064,7 @@ function PromptInput({
113131
114064
  }
113132
114065
 
113133
114066
  // src/hooks/useIndexBadge.ts
113134
- var import_react32 = __toESM(require_react(), 1);
114067
+ var import_react33 = __toESM(require_react(), 1);
113135
114068
  var READY_BADGE_LINGER_MS = 3e3;
113136
114069
  function shouldShowIndexBadge(mode, phase, lingerElapsed) {
113137
114070
  if (mode !== "on") return true;
@@ -113139,8 +114072,8 @@ function shouldShowIndexBadge(mode, phase, lingerElapsed) {
113139
114072
  return !lingerElapsed;
113140
114073
  }
113141
114074
  function useIndexBadgeVisible(mode, phase, lingerMs = READY_BADGE_LINGER_MS) {
113142
- const [lingerElapsed, setLingerElapsed] = (0, import_react32.useState)(false);
113143
- (0, import_react32.useEffect)(() => {
114075
+ const [lingerElapsed, setLingerElapsed] = (0, import_react33.useState)(false);
114076
+ (0, import_react33.useEffect)(() => {
113144
114077
  setLingerElapsed(false);
113145
114078
  if (phase !== "ready") return;
113146
114079
  const timer = setTimeout(() => setLingerElapsed(true), lingerMs);
@@ -113303,7 +114236,7 @@ function StatusBar({
113303
114236
  }
113304
114237
 
113305
114238
  // src/components/dialogs/AskUserPrompt.tsx
113306
- var import_react33 = __toESM(require_react(), 1);
114239
+ var import_react34 = __toESM(require_react(), 1);
113307
114240
  var import_client_ui_core11 = __toESM(require_dist2(), 1);
113308
114241
 
113309
114242
  // src/components/dialogs/LineEditor.tsx
@@ -113355,15 +114288,15 @@ function AskUserPrompt({
113355
114288
  guardMs = 250
113356
114289
  }) {
113357
114290
  const { requestId, sessionId } = pending;
113358
- const card = (0, import_react33.useMemo)(() => (0, import_client_ui_core11.buildAskCard)(pending.request), [pending.request]);
114291
+ const card = (0, import_react34.useMemo)(() => (0, import_client_ui_core11.buildAskCard)(pending.request), [pending.request]);
113359
114292
  const questions = card.questions;
113360
- const [selections, setSelections] = (0, import_react33.useState)(
114293
+ const [selections, setSelections] = (0, import_react34.useState)(
113361
114294
  () => questions.map(() => import_client_ui_core11.EMPTY_SELECTION)
113362
114295
  );
113363
- const [index, setIndex] = (0, import_react33.useState)(0);
113364
- const [cursor, setCursor] = (0, import_react33.useState)(0);
113365
- const [draft, setDraft] = (0, import_react33.useState)(null);
113366
- const guard = (0, import_react33.useRef)({ id: requestId, at: Date.now() });
114296
+ const [index, setIndex] = (0, import_react34.useState)(0);
114297
+ const [cursor, setCursor] = (0, import_react34.useState)(0);
114298
+ const [draft, setDraft] = (0, import_react34.useState)(null);
114299
+ const guard = (0, import_react34.useRef)({ id: requestId, at: Date.now() });
113367
114300
  if (guard.current.id !== requestId) {
113368
114301
  guard.current = { id: requestId, at: Date.now() };
113369
114302
  }
@@ -113509,7 +114442,7 @@ function writtenInPreview(selection) {
113509
114442
  }
113510
114443
 
113511
114444
  // src/components/dialogs/FeedbackPrompt.tsx
113512
- var import_react34 = __toESM(require_react(), 1);
114445
+ var import_react35 = __toESM(require_react(), 1);
113513
114446
  var import_client_ui_core12 = __toESM(require_dist2(), 1);
113514
114447
  var import_jsx_runtime53 = __toESM(require_jsx_runtime(), 1);
113515
114448
  function FeedbackPrompt({
@@ -113519,10 +114452,10 @@ function FeedbackPrompt({
113519
114452
  guardMs = 250
113520
114453
  }) {
113521
114454
  const { requestId } = pending;
113522
- const [score, setScore] = (0, import_react34.useState)(0);
113523
- const [why, setWhy] = (0, import_react34.useState)(null);
114455
+ const [score, setScore] = (0, import_react35.useState)(0);
114456
+ const [why, setWhy] = (0, import_react35.useState)(null);
113524
114457
  const theme = useTheme();
113525
- const guard = (0, import_react34.useRef)({ id: requestId, at: Date.now() });
114458
+ const guard = (0, import_react35.useRef)({ id: requestId, at: Date.now() });
113526
114459
  if (guard.current.id !== requestId) {
113527
114460
  guard.current = { id: requestId, at: Date.now() };
113528
114461
  }
@@ -113571,13 +114504,13 @@ function FeedbackPrompt({
113571
114504
  }
113572
114505
 
113573
114506
  // src/components/dialogs/PermissionPrompt.tsx
113574
- var import_react36 = __toESM(require_react(), 1);
114507
+ var import_react37 = __toESM(require_react(), 1);
113575
114508
  var import_client_ui_core13 = __toESM(require_dist2(), 1);
113576
114509
  var import_client_ui_core14 = __toESM(require_dist2(), 1);
113577
114510
  var import_client_core34 = __toESM(require_dist(), 1);
113578
114511
 
113579
114512
  // src/components/dialogs/SelectList.tsx
113580
- var import_react35 = __toESM(require_react(), 1);
114513
+ var import_react36 = __toESM(require_react(), 1);
113581
114514
  var import_jsx_runtime54 = __toESM(require_jsx_runtime(), 1);
113582
114515
  function SelectList({
113583
114516
  title,
@@ -113589,17 +114522,17 @@ function SelectList({
113589
114522
  maxVisible
113590
114523
  }) {
113591
114524
  const { rows } = useTerminalSize();
113592
- const [query, setQuery] = (0, import_react35.useState)("");
113593
- const view = (0, import_react35.useMemo)(() => {
114525
+ const [query, setQuery] = (0, import_react36.useState)("");
114526
+ const view = (0, import_react36.useMemo)(() => {
113594
114527
  if (!filterable) return options;
113595
114528
  const q2 = query.trim().toLowerCase();
113596
114529
  if (!q2) return options;
113597
114530
  return options.filter((o) => !o.separator && o.label.toLowerCase().includes(q2));
113598
114531
  }, [options, query, filterable]);
113599
114532
  const selectable = view.flatMap((o, i2) => o.separator ? [] : [i2]);
113600
- const [idx, setIdx] = (0, import_react35.useState)(selectable[0] ?? 0);
114533
+ const [idx, setIdx] = (0, import_react36.useState)(selectable[0] ?? 0);
113601
114534
  const safeIdx = selectable.includes(idx) ? idx : selectable[0] ?? 0;
113602
- (0, import_react35.useEffect)(() => {
114535
+ (0, import_react36.useEffect)(() => {
113603
114536
  if (filterable) setIdx(selectable[0] ?? 0);
113604
114537
  }, [query, filterable]);
113605
114538
  const move = (dir) => {
@@ -113700,12 +114633,12 @@ function PermissionPrompt({
113700
114633
  guardMs = 250
113701
114634
  }) {
113702
114635
  const { data, sessionId } = pending;
113703
- const model = (0, import_react36.useMemo)(
114636
+ const model = (0, import_react37.useMemo)(
113704
114637
  () => (0, import_client_ui_core13.buildPermissionCard)(data, { agentLabel: pending.agentLabel ?? null }),
113705
114638
  [data, pending.agentLabel]
113706
114639
  );
113707
- const [stage, setStage] = (0, import_react36.useState)({ kind: "choose" });
113708
- const guard = (0, import_react36.useRef)({ id: data.request_id, at: Date.now() });
114640
+ const [stage, setStage] = (0, import_react37.useState)({ kind: "choose" });
114641
+ const guard = (0, import_react37.useRef)({ id: data.request_id, at: Date.now() });
113709
114642
  if (guard.current.id !== data.request_id) {
113710
114643
  guard.current = { id: data.request_id, at: Date.now() };
113711
114644
  if (stage.kind !== "choose") setStage({ kind: "choose" });
@@ -113880,7 +114813,7 @@ function PermissionPrompt({
113880
114813
  }
113881
114814
 
113882
114815
  // src/components/dialogs/EndpointsPanel.tsx
113883
- var import_react37 = __toESM(require_react(), 1);
114816
+ var import_react38 = __toESM(require_react(), 1);
113884
114817
  var import_jsx_runtime56 = __toESM(require_jsx_runtime(), 1);
113885
114818
  function maskedKeyState(e) {
113886
114819
  if (e.apiKey) return `key \u2022\u2022\u2022\u2022${e.apiKey.slice(-4)}`;
@@ -113910,20 +114843,20 @@ function EndpointsPanel({
113910
114843
  deps: deps2,
113911
114844
  onClose
113912
114845
  }) {
113913
- const [overlay, setOverlay] = (0, import_react37.useState)(null);
113914
- const [name2, setName] = (0, import_react37.useState)("");
113915
- const [url, setUrl] = (0, import_react37.useState)("");
113916
- const [wire, setWire] = (0, import_react37.useState)("openai");
113917
- const [key, setKey] = (0, import_react37.useState)("");
113918
- const [selected, setSelected] = (0, import_react37.useState)(/* @__PURE__ */ new Set());
113919
- const [discovered, setDiscovered] = (0, import_react37.useState)(null);
113920
- const [modelConfig, setModelConfig] = (0, import_react37.useState)({});
113921
- const [editing, setEditing] = (0, import_react37.useState)(null);
113922
- const [configDraft, setConfigDraft] = (0, import_react37.useState)("");
113923
- const [savedPins, setSavedPins] = (0, import_react37.useState)(/* @__PURE__ */ new Set());
113924
- const [savedConfig, setSavedConfig] = (0, import_react37.useState)({});
113925
- const [fetching, setFetching] = (0, import_react37.useState)(false);
113926
- const [note, setNote] = (0, import_react37.useState)(null);
114846
+ const [overlay, setOverlay] = (0, import_react38.useState)(null);
114847
+ const [name2, setName] = (0, import_react38.useState)("");
114848
+ const [url, setUrl] = (0, import_react38.useState)("");
114849
+ const [wire, setWire] = (0, import_react38.useState)("openai");
114850
+ const [key, setKey] = (0, import_react38.useState)("");
114851
+ const [selected, setSelected] = (0, import_react38.useState)(/* @__PURE__ */ new Set());
114852
+ const [discovered, setDiscovered] = (0, import_react38.useState)(null);
114853
+ const [modelConfig, setModelConfig] = (0, import_react38.useState)({});
114854
+ const [editing, setEditing] = (0, import_react38.useState)(null);
114855
+ const [configDraft, setConfigDraft] = (0, import_react38.useState)("");
114856
+ const [savedPins, setSavedPins] = (0, import_react38.useState)(/* @__PURE__ */ new Set());
114857
+ const [savedConfig, setSavedConfig] = (0, import_react38.useState)({});
114858
+ const [fetching, setFetching] = (0, import_react38.useState)(false);
114859
+ const [note, setNote] = (0, import_react38.useState)(null);
113927
114860
  const slots = [
113928
114861
  ...deps2.entries.map((_2, index) => ({ kind: "entry", index })),
113929
114862
  { kind: "field", field: "name" },
@@ -113933,9 +114866,9 @@ function EndpointsPanel({
113933
114866
  { kind: "action", action: "fetch" },
113934
114867
  { kind: "action", action: "save" }
113935
114868
  ];
113936
- const [at, setAt] = (0, import_react37.useState)(deps2.entries.length);
114869
+ const [at, setAt] = (0, import_react38.useState)(deps2.entries.length);
113937
114870
  const slot = slots[Math.min(at, slots.length - 1)];
113938
- const [verifiedFor, setVerifiedFor] = (0, import_react37.useState)(null);
114871
+ const [verifiedFor, setVerifiedFor] = (0, import_react38.useState)(null);
113939
114872
  const fingerprint = `${url.trim()}\0${key}`;
113940
114873
  const verified = verifiedFor === fingerprint;
113941
114874
  const resetForm = () => {
@@ -114422,7 +115355,7 @@ function EndpointsPanel({
114422
115355
  }
114423
115356
 
114424
115357
  // src/components/dialogs/PermissionRulesPanel.tsx
114425
- var import_react38 = __toESM(require_react(), 1);
115358
+ var import_react39 = __toESM(require_react(), 1);
114426
115359
  var import_client_core35 = __toESM(require_dist(), 1);
114427
115360
  var import_client_ui_core15 = __toESM(require_dist2(), 1);
114428
115361
  var import_jsx_runtime57 = __toESM(require_jsx_runtime(), 1);
@@ -114432,7 +115365,7 @@ function PermissionRulesPanel({
114432
115365
  add,
114433
115366
  onClose
114434
115367
  }) {
114435
- const [stage, setStage] = (0, import_react38.useState)({ kind: "list" });
115368
+ const [stage, setStage] = (0, import_react39.useState)({ kind: "list" });
114436
115369
  use_input_default((input, key) => {
114437
115370
  if (stage.kind !== "list") {
114438
115371
  if (stage.kind === "add-rule") {
@@ -114532,7 +115465,7 @@ function PermissionRulesPanel({
114532
115465
  }
114533
115466
 
114534
115467
  // src/components/dialogs/PlanApprovalPrompt.tsx
114535
- var import_react39 = __toESM(require_react(), 1);
115468
+ var import_react40 = __toESM(require_react(), 1);
114536
115469
  var import_jsx_runtime58 = __toESM(require_jsx_runtime(), 1);
114537
115470
  function PlanApprovalPrompt({
114538
115471
  pending,
@@ -114541,7 +115474,7 @@ function PlanApprovalPrompt({
114541
115474
  guardMs = 250
114542
115475
  }) {
114543
115476
  const { requestId, sessionId } = pending;
114544
- const guard = (0, import_react39.useRef)({ id: requestId, at: Date.now() });
115477
+ const guard = (0, import_react40.useRef)({ id: requestId, at: Date.now() });
114545
115478
  if (guard.current.id !== requestId) guard.current = { id: requestId, at: Date.now() };
114546
115479
  use_input_default((input, key) => {
114547
115480
  if (key.ctrl && input === "c") {
@@ -114575,7 +115508,7 @@ function PlanApprovalPrompt({
114575
115508
  }
114576
115509
 
114577
115510
  // src/components/dialogs/WorkPlanApprovalPrompt.tsx
114578
- var import_react40 = __toESM(require_react(), 1);
115511
+ var import_react41 = __toESM(require_react(), 1);
114579
115512
  var import_client_core36 = __toESM(require_dist(), 1);
114580
115513
  var import_jsx_runtime59 = __toESM(require_jsx_runtime(), 1);
114581
115514
  function WorkPlanApprovalPrompt({
@@ -114585,7 +115518,7 @@ function WorkPlanApprovalPrompt({
114585
115518
  guardMs = 250
114586
115519
  }) {
114587
115520
  const { requestId, plan } = pending;
114588
- const guard = (0, import_react40.useRef)({ id: requestId, at: Date.now() });
115521
+ const guard = (0, import_react41.useRef)({ id: requestId, at: Date.now() });
114589
115522
  if (guard.current.id !== requestId) guard.current = { id: requestId, at: Date.now() };
114590
115523
  use_input_default((input, key) => {
114591
115524
  if (key.ctrl && input === "c") {
@@ -114654,7 +115587,7 @@ function ConfirmDialog({ dialog }) {
114654
115587
  }
114655
115588
 
114656
115589
  // src/components/dialogs/HooksBrowser.tsx
114657
- var import_react41 = __toESM(require_react(), 1);
115590
+ var import_react42 = __toESM(require_react(), 1);
114658
115591
  var import_jsx_runtime63 = __toESM(require_jsx_runtime(), 1);
114659
115592
  function matcherLabel(m2) {
114660
115593
  if (!m2 || typeof m2 !== "object") return "(any)";
@@ -114722,9 +115655,9 @@ function HooksBrowser({
114722
115655
  hooks,
114723
115656
  onClose
114724
115657
  }) {
114725
- const [event, setEvent] = (0, import_react41.useState)(null);
114726
- const [matcher, setMatcher] = (0, import_react41.useState)(null);
114727
- const [hookIdx, setHookIdx] = (0, import_react41.useState)(null);
115658
+ const [event, setEvent] = (0, import_react42.useState)(null);
115659
+ const [matcher, setMatcher] = (0, import_react42.useState)(null);
115660
+ const [hookIdx, setHookIdx] = (0, import_react42.useState)(null);
114728
115661
  if (event === null) {
114729
115662
  const events = [...new Set(hooks.map((h) => h.event ?? "(unknown)"))].sort();
114730
115663
  const options = events.map((e) => {
@@ -114777,7 +115710,7 @@ function HooksBrowser({
114777
115710
  }
114778
115711
 
114779
115712
  // src/components/dialogs/PluginManager.tsx
114780
- var import_react42 = __toESM(require_react(), 1);
115713
+ var import_react43 = __toESM(require_react(), 1);
114781
115714
  var import_client_core37 = __toESM(require_dist(), 1);
114782
115715
  var import_jsx_runtime64 = __toESM(require_jsx_runtime(), 1);
114783
115716
  function pluginId(p) {
@@ -114796,8 +115729,8 @@ function PluginManager({
114796
115729
  install,
114797
115730
  onClose
114798
115731
  }) {
114799
- const [view, setView] = (0, import_react42.useState)({ at: "list" });
114800
- const [busy, setBusy] = (0, import_react42.useState)(false);
115732
+ const [view, setView] = (0, import_react43.useState)({ at: "list" });
115733
+ const [busy, setBusy] = (0, import_react43.useState)(false);
114801
115734
  const finish = (work) => {
114802
115735
  setBusy(true);
114803
115736
  void work.finally(() => {
@@ -114950,7 +115883,7 @@ Install "${view.id}" from "${view.catalog}" (${scope} scope)?`,
114950
115883
  }
114951
115884
 
114952
115885
  // src/components/dialogs/RewindPicker.tsx
114953
- var import_react43 = __toESM(require_react(), 1);
115886
+ var import_react44 = __toESM(require_react(), 1);
114954
115887
  var import_jsx_runtime65 = __toESM(require_jsx_runtime(), 1);
114955
115888
  function statLabel(t) {
114956
115889
  if (!t.files) return "no code changes";
@@ -114965,8 +115898,8 @@ function RewindPicker({
114965
115898
  apply: apply2,
114966
115899
  onClose
114967
115900
  }) {
114968
- const [picked, setPicked] = (0, import_react43.useState)(null);
114969
- const [busy, setBusy] = (0, import_react43.useState)(false);
115901
+ const [picked, setPicked] = (0, import_react44.useState)(null);
115902
+ const [busy, setBusy] = (0, import_react44.useState)(false);
114970
115903
  if (busy) {
114971
115904
  return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(Box2, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(ThemedText, { dim: true, children: "Working\u2026" }) });
114972
115905
  }
@@ -115004,7 +115937,7 @@ function RewindPicker({
115004
115937
  }
115005
115938
 
115006
115939
  // src/components/dialogs/McpManager.tsx
115007
- var import_react44 = __toESM(require_react(), 1);
115940
+ var import_react45 = __toESM(require_react(), 1);
115008
115941
  var import_jsx_runtime66 = __toESM(require_jsx_runtime(), 1);
115009
115942
  function statusLabel(s) {
115010
115943
  return s.status === "needs_auth" ? "needs auth" : s.status ?? "?";
@@ -115022,8 +115955,8 @@ function McpManager({
115022
115955
  act,
115023
115956
  onClose
115024
115957
  }) {
115025
- const [view, setView] = (0, import_react44.useState)({ at: "list" });
115026
- const [busy, setBusy] = (0, import_react44.useState)(false);
115958
+ const [view, setView] = (0, import_react45.useState)({ at: "list" });
115959
+ const [busy, setBusy] = (0, import_react45.useState)(false);
115027
115960
  const finish = (work, backTo = { at: "list" }) => {
115028
115961
  setBusy(true);
115029
115962
  void work.finally(() => {
@@ -115471,7 +116404,7 @@ function UsageMetricsPanel({
115471
116404
  }
115472
116405
 
115473
116406
  // src/components/status/WorkingStatus.tsx
115474
- var import_react45 = __toESM(require_react(), 1);
116407
+ var import_react46 = __toESM(require_react(), 1);
115475
116408
  var import_jsx_runtime69 = __toESM(require_jsx_runtime(), 1);
115476
116409
  var FRAME_MS = 50;
115477
116410
  function WorkingStatus({
@@ -115479,14 +116412,14 @@ function WorkingStatus({
115479
116412
  label,
115480
116413
  now: now2 = Date.now
115481
116414
  }) {
115482
- const startRef = (0, import_react45.useRef)(now2());
115483
- const wordsRef = (0, import_react45.useRef)(shuffleWords(LOADING_WORDS));
115484
- const wordIdxRef = (0, import_react45.useRef)(0);
115485
- const wordStartRef = (0, import_react45.useRef)(startRef.current);
115486
- const dwellRef = (0, import_react45.useRef)(nextCycleMs());
115487
- const [, forceFrame] = (0, import_react45.useState)(0);
116415
+ const startRef = (0, import_react46.useRef)(now2());
116416
+ const wordsRef = (0, import_react46.useRef)(shuffleWords(LOADING_WORDS));
116417
+ const wordIdxRef = (0, import_react46.useRef)(0);
116418
+ const wordStartRef = (0, import_react46.useRef)(startRef.current);
116419
+ const dwellRef = (0, import_react46.useRef)(nextCycleMs());
116420
+ const [, forceFrame] = (0, import_react46.useState)(0);
115488
116421
  const tokens = useStoreSelector(store, (s) => s.turnOutputTokens);
115489
- (0, import_react45.useEffect)(() => {
116422
+ (0, import_react46.useEffect)(() => {
115490
116423
  const timer = setInterval(() => {
115491
116424
  const n2 = now2();
115492
116425
  if (!label && n2 - startRef.current < META_REVEAL_AFTER_MS && n2 - wordStartRef.current >= dwellRef.current) {
@@ -115638,11 +116571,11 @@ function ReplFooter({
115638
116571
  (s) => s.pendingPermissions.length > 0 || !!s.pendingPlanApproval || !!s.pendingAskUser || !!s.pendingWorkPlan
115639
116572
  );
115640
116573
  const closePanel = () => appStore.setState((s) => ({ ...s, activePanel: null }));
115641
- const onQueuePop = import_react46.default.useCallback(
116574
+ const onQueuePop = import_react47.default.useCallback(
115642
116575
  (draft) => popEditableQueue(appStore, draft),
115643
116576
  [appStore]
115644
116577
  );
115645
- const [menuOpen, setMenuOpen] = import_react46.default.useState(false);
116578
+ const [menuOpen, setMenuOpen] = import_react47.default.useState(false);
115646
116579
  return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(import_jsx_runtime72.Fragment, { children: [
115647
116580
  streaming && !parked && /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(WorkingStatus, { store: appStore }),
115648
116581
  plan && /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(PlanCard, { plan }),
@@ -115758,7 +116691,7 @@ function ReplFooter({
115758
116691
  }
115759
116692
 
115760
116693
  // src/components/layout/FullscreenLayout.tsx
115761
- var import_react47 = __toESM(require_react(), 1);
116694
+ var import_react48 = __toESM(require_react(), 1);
115762
116695
  var import_jsx_runtime73 = __toESM(require_jsx_runtime(), 1);
115763
116696
  function FullscreenLayout({
115764
116697
  appStore,
@@ -115780,7 +116713,7 @@ function FullscreenLayout({
115780
116713
  onCycleMode
115781
116714
  }) {
115782
116715
  const { columns, rows } = useTerminalSize();
115783
- const scrollRef = (0, import_react47.useRef)(null);
116716
+ const scrollRef = (0, import_react48.useRef)(null);
115784
116717
  const onScroll = (delta) => {
115785
116718
  const sb = scrollRef.current;
115786
116719
  if (!sb) return;
@@ -115815,7 +116748,7 @@ function FullscreenLayout({
115815
116748
  }
115816
116749
 
115817
116750
  // src/components/dialogs/AgentsDashboard.tsx
115818
- var import_react48 = __toESM(require_react(), 1);
116751
+ var import_react49 = __toESM(require_react(), 1);
115819
116752
  var import_client_core40 = __toESM(require_dist(), 1);
115820
116753
  var import_client_ui_core17 = __toESM(require_dist2(), 1);
115821
116754
  var import_strip_ansi4 = __toESM(require_strip_ansi(), 1);
@@ -115862,51 +116795,51 @@ function AgentsDashboard({
115862
116795
  onClose
115863
116796
  }) {
115864
116797
  const { rows } = useTerminalSize();
115865
- const [screen, setScreen] = (0, import_react48.useState)({ kind: "list" });
115866
- const [cursor, setCursor] = (0, import_react48.useState)(0);
115867
- const [busy, setBusy] = (0, import_react48.useState)(false);
115868
- const [error, setError] = (0, import_react48.useState)(null);
115869
- const [liveJob, setLiveJob] = (0, import_react48.useState)(null);
115870
- const [events, setEvents] = (0, import_react48.useState)([]);
115871
- const [pollError, setPollError] = (0, import_react48.useState)(null);
115872
- const [diff3, setDiff] = (0, import_react48.useState)(null);
115873
- const diffFetchedFor = (0, import_react48.useRef)(null);
115874
- const [liveItems, setLiveItems] = (0, import_react48.useState)([]);
115875
- const [liveTerm, setLiveTerm] = (0, import_react48.useState)("");
115876
- const [liveFrames, setLiveFrames] = (0, import_react48.useState)(0);
115877
- const liveIdRef = (0, import_react48.useRef)(0);
115878
- const [messaging, setMessaging] = (0, import_react48.useState)(false);
115879
- const [messageText, setMessageText] = (0, import_react48.useState)("");
115880
- const [messageNote, setMessageNote] = (0, import_react48.useState)(null);
115881
- const [tokenStatus, setTokenStatus] = (0, import_react48.useState)(null);
115882
- const [tokenBusy, setTokenBusy] = (0, import_react48.useState)(false);
115883
- const [tokenNote, setTokenNote] = (0, import_react48.useState)(null);
115884
- const [tokenInput, setTokenInput] = (0, import_react48.useState)(false);
115885
- const [tokenDraft, setTokenDraft] = (0, import_react48.useState)("");
115886
- const [jiraStatus, setJiraStatus] = (0, import_react48.useState)(null);
115887
- const [jiraBusy, setJiraBusy] = (0, import_react48.useState)(false);
115888
- const [jiraNote, setJiraNote] = (0, import_react48.useState)(null);
115889
- const [jiraInput, setJiraInput] = (0, import_react48.useState)(null);
115890
- const [form, setForm] = (0, import_react48.useState)(EMPTY_FORM);
115891
- const [field2, setField] = (0, import_react48.useState)(0);
116798
+ const [screen, setScreen] = (0, import_react49.useState)({ kind: "list" });
116799
+ const [cursor, setCursor] = (0, import_react49.useState)(0);
116800
+ const [busy, setBusy] = (0, import_react49.useState)(false);
116801
+ const [error, setError] = (0, import_react49.useState)(null);
116802
+ const [liveJob, setLiveJob] = (0, import_react49.useState)(null);
116803
+ const [events, setEvents] = (0, import_react49.useState)([]);
116804
+ const [pollError, setPollError] = (0, import_react49.useState)(null);
116805
+ const [diff3, setDiff] = (0, import_react49.useState)(null);
116806
+ const diffFetchedFor = (0, import_react49.useRef)(null);
116807
+ const [liveItems, setLiveItems] = (0, import_react49.useState)([]);
116808
+ const [liveTerm, setLiveTerm] = (0, import_react49.useState)("");
116809
+ const [liveFrames, setLiveFrames] = (0, import_react49.useState)(0);
116810
+ const liveIdRef = (0, import_react49.useRef)(0);
116811
+ const [messaging, setMessaging] = (0, import_react49.useState)(false);
116812
+ const [messageText, setMessageText] = (0, import_react49.useState)("");
116813
+ const [messageNote, setMessageNote] = (0, import_react49.useState)(null);
116814
+ const [tokenStatus, setTokenStatus] = (0, import_react49.useState)(null);
116815
+ const [tokenBusy, setTokenBusy] = (0, import_react49.useState)(false);
116816
+ const [tokenNote, setTokenNote] = (0, import_react49.useState)(null);
116817
+ const [tokenInput, setTokenInput] = (0, import_react49.useState)(false);
116818
+ const [tokenDraft, setTokenDraft] = (0, import_react49.useState)("");
116819
+ const [jiraStatus, setJiraStatus] = (0, import_react49.useState)(null);
116820
+ const [jiraBusy, setJiraBusy] = (0, import_react49.useState)(false);
116821
+ const [jiraNote, setJiraNote] = (0, import_react49.useState)(null);
116822
+ const [jiraInput, setJiraInput] = (0, import_react49.useState)(null);
116823
+ const [form, setForm] = (0, import_react49.useState)(EMPTY_FORM);
116824
+ const [field2, setField] = (0, import_react49.useState)(0);
115892
116825
  const jobs = panel.jobs;
115893
116826
  const safeCursor = Math.min(cursor, Math.max(0, jobs.length - 1));
115894
116827
  const detailId = screen.kind === "detail" ? screen.id : null;
115895
116828
  const detailJob = detailId ? liveJob ?? jobs.find((j2) => j2.id === detailId) ?? null : null;
115896
- const panelRef = (0, import_react48.useRef)(panel);
116829
+ const panelRef = (0, import_react49.useRef)(panel);
115897
116830
  panelRef.current = panel;
115898
- const screenRef = (0, import_react48.useRef)(screen);
116831
+ const screenRef = (0, import_react49.useRef)(screen);
115899
116832
  screenRef.current = screen;
115900
- const oauthAlive = (0, import_react48.useRef)(true);
115901
- const oauthTimer = (0, import_react48.useRef)(null);
115902
- (0, import_react48.useEffect)(
116833
+ const oauthAlive = (0, import_react49.useRef)(true);
116834
+ const oauthTimer = (0, import_react49.useRef)(null);
116835
+ (0, import_react49.useEffect)(
115903
116836
  () => () => {
115904
116837
  oauthAlive.current = false;
115905
116838
  if (oauthTimer.current) clearTimeout(oauthTimer.current);
115906
116839
  },
115907
116840
  []
115908
116841
  );
115909
- (0, import_react48.useEffect)(() => {
116842
+ (0, import_react49.useEffect)(() => {
115910
116843
  if (!detailId) return;
115911
116844
  let cancelled = false;
115912
116845
  let timer = null;
@@ -115948,7 +116881,7 @@ function AgentsDashboard({
115948
116881
  };
115949
116882
  }, [detailId]);
115950
116883
  const branchName = detailJob?.branch_name ?? null;
115951
- (0, import_react48.useEffect)(() => {
116884
+ (0, import_react49.useEffect)(() => {
115952
116885
  if (!detailId || !branchName) return;
115953
116886
  const key = `${detailId}:${branchName}`;
115954
116887
  if (diffFetchedFor.current === key) return;
@@ -115966,7 +116899,7 @@ function AgentsDashboard({
115966
116899
  };
115967
116900
  }, [detailId, branchName]);
115968
116901
  const liveSessionId = detailJob && !(0, import_client_core40.isTerminal)(detailJob.status) && detailJob.session_id ? detailJob.session_id : null;
115969
- (0, import_react48.useEffect)(() => {
116902
+ (0, import_react49.useEffect)(() => {
115970
116903
  if (!liveSessionId) return;
115971
116904
  liveIdRef.current = 0;
115972
116905
  setLiveItems([]);
@@ -115987,7 +116920,7 @@ function AgentsDashboard({
115987
116920
  });
115988
116921
  return () => sub.dispose();
115989
116922
  }, [liveSessionId]);
115990
- (0, import_react48.useEffect)(() => {
116923
+ (0, import_react49.useEffect)(() => {
115991
116924
  let cancelled = false;
115992
116925
  void (async () => {
115993
116926
  try {
@@ -116643,14 +117576,14 @@ function LaunchFormView({ form, field: field2 }) {
116643
117576
  }
116644
117577
 
116645
117578
  // src/components/layout/TerminalTitle.tsx
116646
- var import_react50 = __toESM(require_react(), 1);
117579
+ var import_react51 = __toESM(require_react(), 1);
116647
117580
 
116648
117581
  // src/vendor/ink/hooks/use-terminal-title.ts
116649
- var import_react49 = __toESM(require_react(), 1);
117582
+ var import_react50 = __toESM(require_react(), 1);
116650
117583
  var import_strip_ansi5 = __toESM(require_strip_ansi(), 1);
116651
117584
  function useTerminalTitle(title) {
116652
- const writeRaw = (0, import_react49.useContext)(TerminalWriteContext);
116653
- (0, import_react49.useEffect)(() => {
117585
+ const writeRaw = (0, import_react50.useContext)(TerminalWriteContext);
117586
+ (0, import_react50.useEffect)(() => {
116654
117587
  if (title === null || !writeRaw) return;
116655
117588
  const clean = (0, import_strip_ansi5.default)(title);
116656
117589
  if (process.platform === "win32") {
@@ -116676,8 +117609,8 @@ function composeTerminalTitle(sessionTitle, streaming, frame) {
116676
117609
  function TerminalTitle({ appStore }) {
116677
117610
  const sessionTitle = useStoreSelector(appStore, (s) => s.sessionTitle);
116678
117611
  const streaming = useStoreSelector(appStore, (s) => s.status === "streaming");
116679
- const [frame, setFrame] = (0, import_react50.useState)(0);
116680
- (0, import_react50.useEffect)(() => {
117612
+ const [frame, setFrame] = (0, import_react51.useState)(0);
117613
+ (0, import_react51.useEffect)(() => {
116681
117614
  if (!streaming) return;
116682
117615
  const id = setInterval(
116683
117616
  () => setFrame((f) => (f + 1) % TITLE_ANIMATION_FRAMES.length),
@@ -116776,11 +117709,11 @@ function Root({
116776
117709
  }
116777
117710
 
116778
117711
  // src/components/layout/SignInScreen.tsx
116779
- var import_react52 = __toESM(require_react(), 1);
117712
+ var import_react53 = __toESM(require_react(), 1);
116780
117713
  var import_client_core41 = __toESM(require_dist(), 1);
116781
117714
 
116782
117715
  // src/components/layout/splash/Splash.tsx
116783
- var import_react51 = __toESM(require_react(), 1);
117716
+ var import_react52 = __toESM(require_react(), 1);
116784
117717
 
116785
117718
  // src/components/layout/splash/halfblock.ts
116786
117719
  var BLOCK = [" ", "\u2580", "\u2584", "\u2588"];
@@ -117099,7 +118032,7 @@ var TONE = {
117099
118032
  function Splash({ columns, rows, frame, copy }) {
117100
118033
  const theme = useTheme();
117101
118034
  const height = splashHeight(rows);
117102
- const shell2 = import_react51.default.useMemo(() => orbShell(), []);
118035
+ const shell2 = import_react52.default.useMemo(() => orbShell(), []);
117103
118036
  const grid = splashFrame({ width: columns, rows: height, frame, shell: shell2, copy });
117104
118037
  return /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(Box2, { flexDirection: "column", children: grid.map((spans, y2) => /* @__PURE__ */ (0, import_jsx_runtime77.jsx)(Text2, { wrap: "truncate", children: spans.length === 0 ? " " : spans.map((span, i2) => renderSpan(span, i2, theme)) }, y2)) });
117105
118038
  }
@@ -117145,15 +118078,15 @@ function SignInScreen({
117145
118078
  onSignedIn
117146
118079
  }) {
117147
118080
  const { exit } = use_app_default();
117148
- const [phase, setPhase] = import_react52.default.useState("idle");
117149
- const [url, setUrl] = import_react52.default.useState(null);
117150
- const [error, setError] = import_react52.default.useState(null);
117151
- const [frame, setFrame] = import_react52.default.useState(0);
118081
+ const [phase, setPhase] = import_react53.default.useState("idle");
118082
+ const [url, setUrl] = import_react53.default.useState(null);
118083
+ const [error, setError] = import_react53.default.useState(null);
118084
+ const [frame, setFrame] = import_react53.default.useState(0);
117152
118085
  const { columns, rows } = useTerminalSize();
117153
- const caps = import_react52.default.useMemo(() => detectTerminal2(), []);
118086
+ const caps = import_react53.default.useMemo(() => detectTerminal2(), []);
117154
118087
  const copy = splashCopy(phase, error, url, columns);
117155
118088
  const useSplash = !splashDisabled() && caps.unicode && splashFits(columns, rows, copy.length);
117156
- import_react52.default.useEffect(() => {
118089
+ import_react53.default.useEffect(() => {
117157
118090
  if (!useSplash || phase !== "idle") return;
117158
118091
  const t = setInterval(() => setFrame((f) => f + 1), TICK_MS);
117159
118092
  return () => clearInterval(t);
@@ -117917,7 +118850,9 @@ async function runHeadless(flags2) {
117917
118850
  const config = loadConfig();
117918
118851
  if (flags2.workspace) config.workspaceRoot = flags2.workspace;
117919
118852
  const secrets = createSecretStore();
117920
- const session = (0, import_client_core46.createAgentSession)(secrets, config);
118853
+ const session = (0, import_client_core46.createAgentSession)(secrets, config, {
118854
+ trace: (line) => console.error(`[orion-auth] ${line}`)
118855
+ });
117921
118856
  const signedIn = await session.isSignedIn();
117922
118857
  if (!signedIn && !process.env.ORION_AUTH_TOKEN) {
117923
118858
  throw new Error(
@@ -117958,8 +118893,10 @@ async function runHeadless(flags2) {
117958
118893
  }),
117959
118894
  gatewayUrl: () => config.apiUrl,
117960
118895
  clientVersion: tuiVersion() ?? "0.0.0-dev",
117961
- // Mid-segment token-expiry heal — same closure as the transport authToken below.
117962
- renewBearer: async () => await session.currentFreshAccessToken() ?? process.env.ORION_AUTH_TOKEN ?? null,
118896
+ // Mid-segment token-expiry heal — the FAIL-CLOSED renewal, not the fail-open
118897
+ // freshness read the transport authToken below uses (that degradation hands the
118898
+ // refused token back and burns the heal).
118899
+ renewBearer: async (refused) => await session.renewedAccessToken(refused) ?? process.env.ORION_AUTH_TOKEN ?? null,
117963
118900
  log: brainLog
117964
118901
  });
117965
118902
  const turnTransport = (0, import_client_core46.createTurnTransport)({
@@ -118002,6 +118939,7 @@ async function runHeadless(flags2) {
118002
118939
  () => permissionStore.rules()
118003
118940
  );
118004
118941
  executor.enableFileHistorySpill();
118942
+ executor.registerHostTool(import_client_core46.GOAL_REPORT_TOOL, async (params) => (0, import_client_core46.goalReportToolResult)(params));
118005
118943
  const boundary = createBoundaryHandlers({
118006
118944
  bridge,
118007
118945
  executor,
@@ -118033,6 +118971,9 @@ async function runHeadless(flags2) {
118033
118971
  permissionMode: a.permissionMode,
118034
118972
  workspaceRoot: config.workspaceRoot,
118035
118973
  clientType: "tui",
118974
+ // Omitted (not placeholdered) in an unstamped dev/test run — see the interactive
118975
+ // path in main.tsx for why the two absences must stay distinguishable.
118976
+ clientVersion: tuiVersion() ?? void 0,
118036
118977
  mode: a.mode,
118037
118978
  reasoning: a.reasoning,
118038
118979
  tokenSaving: a.tokenSaving,
@@ -118060,7 +119001,8 @@ async function runHeadless(flags2) {
118060
119001
  getMessages: () => snapshot,
118061
119002
  getClientState: () => clientState,
118062
119003
  routing: routing(),
118063
- clientCapabilities: [],
119004
+ // Every headless turn is a goal round — the claim tool is always on.
119005
+ clientCapabilities: [import_client_core46.GOAL_CAPABILITY],
118064
119006
  drainQueuedInput: () => [],
118065
119007
  getOrionResources: () => (0, import_client_core46.buildOrionSnapshot)(config.workspaceRoot, void 0, sessionId),
118066
119008
  getFileHistoryManifest: () => executor.fileHistoryManifest(sessionId)
@@ -118076,7 +119018,11 @@ async function runHeadless(flags2) {
118076
119018
  throw new Error(typeof data.error === "string" ? data.error : "turn failed");
118077
119019
  }
118078
119020
  if (Array.isArray(data.messages)) messages = data.messages;
118079
- return { text: extractFinalAssistantText(data), evidence: (0, import_client_core46.goalEvidenceFromWire)(data.messages) };
119021
+ return {
119022
+ text: extractFinalAssistantText(data),
119023
+ evidence: (0, import_client_core46.goalEvidenceFromWire)(data.messages),
119024
+ claim: (0, import_client_core46.goalClaimFromWire)(data.messages)
119025
+ };
118080
119026
  };
118081
119027
  const { endReason, turns } = await runGoalLoop({
118082
119028
  goal: flags2.goal,
@@ -118089,7 +119035,12 @@ async function runHeadless(flags2) {
118089
119035
  evidence,
118090
119036
  sessionId,
118091
119037
  // Lets the check read the user's `goalEvaluate` model choice.
118092
- workspaceRoot: config.workspaceRoot ?? null
119038
+ workspaceRoot: config.workspaceRoot ?? null,
119039
+ // The run's own model — the fallback when no evaluator model is
119040
+ // configured, so the check never lands on the gateway's deployment
119041
+ // default (see the interactive TUI's identical wiring).
119042
+ sessionModel: routing().model,
119043
+ sessionProvider: routing().provider
118093
119044
  });
118094
119045
  if (ruling.evaluated && !ruling.ok && ruling.achievable) {
118095
119046
  process.stderr.write(`[headless] not met yet \u2014 ${(0, import_client_core46.goalReasonLine)(ruling.reason)}
@@ -118253,6 +119204,11 @@ async function main() {
118253
119204
  const duetAdvisorState = (0, import_client_core49.createDuetAdvisorState)();
118254
119205
  const duetRouterGate = (0, import_client_core49.createDuetRouterGate)({
118255
119206
  loadEncoder: (0, import_client_core49.createDefaultDuetRouterEncoder)(),
119207
+ // "Executor decides": the same gate object owns the executor's one-token scorer, so the
119208
+ // turn path below has ONE call whichever entry is set (`duetExecutorGate.ts`).
119209
+ executorGate: (0, import_client_core49.createDuetExecutorGate)({
119210
+ onError: (stage, problem) => console.error(`[duet-executor-gate] ${stage} failed: ${problem}`)
119211
+ }),
118256
119212
  onError: (stage, error) => (
118257
119213
  // Same breadcrumb the IDE and the Power App leave (the log redirect captures it, so it
118258
119214
  // never corrupts the alt screen): without it a load or classify failure is invisible
@@ -118327,7 +119283,11 @@ async function main() {
118327
119283
  }
118328
119284
  });
118329
119285
  const secrets = createSecretStore();
118330
- const session = (0, import_client_core49.createAgentSession)(secrets, config);
119286
+ const session = (0, import_client_core49.createAgentSession)(secrets, config, {
119287
+ // Renewal/refresh breadcrumbs (step outcomes + timings, never tokens) — the evidence
119288
+ // the 2026-08-22 refresh-wedge investigation lacked.
119289
+ trace: (line) => console.error(`[orion-auth] ${line}`)
119290
+ });
118331
119291
  const outcomes = new import_client_core49.OutcomeReporter({
118332
119292
  apiBaseUrl: () => config.accountsApiUrl,
118333
119293
  accessToken: () => session.currentAccessToken()
@@ -118400,10 +119360,10 @@ async function main() {
118400
119360
  }),
118401
119361
  gatewayUrl: () => config.apiUrl,
118402
119362
  clientVersion: tuiVersion() ?? "0.0.0-dev",
118403
- // Mid-segment token-expiry heal: the SAME bearer seam the per-segment authToken uses —
118404
- // an expired stored token forces its refresh, so calling it again IS the renewal (the
118405
- // brain retries once with the result); an emptied store re-gates the chat.
118406
- renewBearer: () => transportBearer(session, appStore, process.env.ORION_AUTH_TOKEN),
119363
+ // Mid-segment token-expiry heal: the FAIL-CLOSED renewal seam, NOT the fail-open
119364
+ // per-segment authToken read — the refused token rides in so the answer is decided
119365
+ // on token identity, never local clocks; an emptied store re-gates the chat.
119366
+ renewBearer: (refused) => renewedTransportBearer(session, appStore, refused, process.env.ORION_AUTH_TOKEN),
118407
119367
  log: brainLog
118408
119368
  });
118409
119369
  return brainInstance;
@@ -119142,6 +120102,11 @@ async function main() {
119142
120102
  workspaceRoot: config.workspaceRoot,
119143
120103
  clientType: "tui",
119144
120104
  // usage-telemetry surface tag
120105
+ // …and the build behind that tag. `tuiVersion()` is null in an unstamped dev/test run,
120106
+ // which becomes `undefined` here so the key is OMITTED rather than sent as a placeholder:
120107
+ // "not reported" and "reported but unreadable" are different states downstream, and a dev
120108
+ // build is the former.
120109
+ clientVersion: tuiVersion() ?? void 0,
119145
120110
  // mode/reasoning/context_window ride the body too (rule 1) so a cold pod keeps
119146
120111
  // plan/ask read-only + the right model settings — not a per-pod set_* RPC.
119147
120112
  mode: a.mode,
@@ -119226,7 +120191,11 @@ async function main() {
119226
120191
  if (appStore.getState().mode === "duet") {
119227
120192
  const routed = await duetRouterGate.prepareTurn(
119228
120193
  (0, import_client_core49.duetEntryWireForSegment)(config.workspaceRoot),
119229
- routerText
120194
+ routerText,
120195
+ // What the executor gate's prompt is built from: the standing record as it stands
120196
+ // BEFORE the advisor runs (the advisor may flag it for this turn; the gate asks the
120197
+ // executor about the request under the plan the user actually approved).
120198
+ { workspaceRoot: config.workspaceRoot, record: appStore.getState().duetPlan }
119230
120199
  );
119231
120200
  duetEntry = routed.entry;
119232
120201
  duetRouterVerdict = routed.verdict;
@@ -119305,7 +120274,10 @@ async function main() {
119305
120274
  import_client_core49.DUET_REPLAN_CAPABILITY,
119306
120275
  // …and runs the planner's `hand_off` (leg marker, phase line, journal), so
119307
120276
  // planner entry may offer it (further leg-gated backend-side).
119308
- import_client_core49.DUET_HANDOFF_CAPABILITY
120277
+ import_client_core49.DUET_HANDOFF_CAPABILITY,
120278
+ // `goal` lights up the goal_report claim tool, and only while a goal is
120279
+ // actually driving this conversation — an ordinary chat never sees it.
120280
+ ...goalRunner !== null ? [import_client_core49.GOAL_CAPABILITY] : []
119309
120281
  ],
119310
120282
  extraBody: {
119311
120283
  ...appStore.getState().subagentsEnabled ? agentManager.parentExtraBody() : {},
@@ -119381,7 +120353,8 @@ async function main() {
119381
120353
  endSettle = {
119382
120354
  kind: "complete",
119383
120355
  finalText: (0, import_client_core49.finalAssistantTextFromWire)(data.messages),
119384
- evidence: (0, import_client_core49.goalEvidenceFromWire)(data.messages)
120356
+ evidence: (0, import_client_core49.goalEvidenceFromWire)(data.messages),
120357
+ claim: (0, import_client_core49.goalClaimFromWire)(data.messages)
119385
120358
  };
119386
120359
  (0, import_client_core48.recordTurnMetrics)({
119387
120360
  app: "tui",
@@ -119562,6 +120535,7 @@ async function main() {
119562
120535
  );
119563
120536
  return (0, import_client_core49.duetHandoffResult)();
119564
120537
  });
120538
+ executor.registerHostTool(import_client_core49.GOAL_REPORT_TOOL, async (params) => (0, import_client_core49.goalReportToolResult)(params));
119565
120539
  const loopService = new LoopService({
119566
120540
  workspaceRoot: config.workspaceRoot,
119567
120541
  schedulePath: loopSchedulePathFor((0, import_client_core49.runsRootFor)("loops", config.workspaceRoot)),
@@ -119635,12 +120609,27 @@ async function main() {
119635
120609
  // stranger's routing.
119636
120610
  sessionId: goalSessionId ?? void 0,
119637
120611
  // Lets the check read the user's `goalEvaluate` model choice.
119638
- workspaceRoot: currentRouting().workspaceRoot ?? null
120612
+ workspaceRoot: currentRouting().workspaceRoot ?? null,
120613
+ // The session's model as THIS CLIENT knows it — the fallback when no
120614
+ // evaluator model is configured. The gateway's own session record can
120615
+ // still hold the deployment default for a local-brain session (routing
120616
+ // rides segment bodies), and a check on that default is a check on a
120617
+ // model this session never used.
120618
+ sessionModel: currentRouting().model,
120619
+ sessionProvider: currentRouting().provider
119639
120620
  });
119640
- if (ruling.evaluated && !ruling.ok && ruling.achievable) {
119641
- transcriptStore.setState((s) => appendGoalNoteFor(s, goalSessionId, (0, import_client_core49.goalNotMetRow)(ruling.reason)));
119642
- }
119643
120621
  return ruling;
120622
+ },
120623
+ // A round that did NOT meet the goal says so — in the judge's words when a
120624
+ // check ran, in the agent's own honest not-done report when none did
120625
+ // (goalRoundReason is the one mapping, shared by every client). Without it
120626
+ // a long goal is a wall of identical continuation lines and a stuck one is
120627
+ // indistinguishable from a working one.
120628
+ onRound: (round) => {
120629
+ const reason = (0, import_client_core49.goalRoundReason)(round);
120630
+ if (reason !== "") {
120631
+ transcriptStore.setState((s) => appendGoalNoteFor(s, goalSessionId, (0, import_client_core49.goalNotMetRow)(reason)));
120632
+ }
119644
120633
  }
119645
120634
  });
119646
120635
  goalRunner = runner;
@@ -119656,6 +120645,7 @@ async function main() {
119656
120645
  runCommand: routeInput
119657
120646
  });
119658
120647
  });
120648
+ transcriptStore.setState((s) => appendGoalNoteFor(s, goalSessionId, (0, import_client_core49.goalSetRow)(goal)));
119659
120649
  };
119660
120650
  const enqueueSteer = (text) => {
119661
120651
  appStore.setState((s) => ({ ...s, queuedMessages: [...s.queuedMessages, queuedSteer(text)] }));