token-harness 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/token-harness.mjs CHANGED
@@ -759,6 +759,27 @@ function parseBoundaryPolicy(value3) {
759
759
  return void 0;
760
760
  return { model, reasoningEffort, verbosity, verification: "config-only" };
761
761
  }
762
+ function parseNativeRoutingObservation(value3) {
763
+ if (value3 === null)
764
+ return null;
765
+ const row2 = record(value3);
766
+ if (row2 === null)
767
+ return void 0;
768
+ const configured = row2["configured"];
769
+ const promptSubmissions = row2["promptSubmissions"];
770
+ const subagentsStarted = row2["subagentsStarted"];
771
+ const subagentsStopped = row2["subagentsStopped"];
772
+ const reportedModels = row2["reportedModels"];
773
+ if (!(configured === null || typeof configured === "boolean") || !Number.isSafeInteger(promptSubmissions) || typeof promptSubmissions !== "number" || promptSubmissions < 0 || !Number.isSafeInteger(subagentsStarted) || typeof subagentsStarted !== "number" || subagentsStarted < 0 || !Number.isSafeInteger(subagentsStopped) || typeof subagentsStopped !== "number" || subagentsStopped < 0 || !Array.isArray(reportedModels) || !reportedModels.every((model) => typeof model === "string" && model.length <= 80))
774
+ return void 0;
775
+ return {
776
+ configured,
777
+ promptSubmissions,
778
+ subagentsStarted,
779
+ subagentsStopped,
780
+ reportedModels: [...new Set(reportedModels)]
781
+ };
782
+ }
762
783
  function parseTaskBenchmarkCapture(value3) {
763
784
  const row2 = record(value3);
764
785
  if (row2 === null) {
@@ -785,7 +806,9 @@ function parseTaskBenchmarkCapture(value3) {
785
806
  const localSessionsBefore = parsedLocalSessions === void 0 ? null : parsedLocalSessions;
786
807
  const hasContextAtStart = Object.hasOwn(row2, "contextAtStart");
787
808
  const contextAtStart = hasContextAtStart ? parseTaskBenchmarkContextSnapshot(row2["contextAtStart"]) : void 0;
788
- if (typeof benchmarkId !== "string" || !isTaskBenchmarkId(benchmarkId) || typeof variant !== "string" || !isTaskBenchmarkVariant(variant) || typeof taskClass !== "string" || !isTaskClass(taskClass) || typeof harnessId2 !== "string" || !isHarnessId(harnessId2) || typeof projectId !== "string" || projectId === "" || model === void 0 || reasoningEffort === void 0 || verbosity === void 0 || !validInstant(startedAt) || usageBefore === null || parsedLocalSessions === void 0 || hasContextAtStart && contextAtStart === void 0) {
809
+ const hasNativeRoutingAtStart = Object.hasOwn(row2, "nativeRoutingAtStart");
810
+ const nativeRoutingAtStart = hasNativeRoutingAtStart ? parseNativeRoutingObservation(row2["nativeRoutingAtStart"]) : void 0;
811
+ if (typeof benchmarkId !== "string" || !isTaskBenchmarkId(benchmarkId) || typeof variant !== "string" || !isTaskBenchmarkVariant(variant) || typeof taskClass !== "string" || !isTaskClass(taskClass) || typeof harnessId2 !== "string" || !isHarnessId(harnessId2) || typeof projectId !== "string" || projectId === "" || model === void 0 || reasoningEffort === void 0 || verbosity === void 0 || !validInstant(startedAt) || usageBefore === null || parsedLocalSessions === void 0 || hasContextAtStart && contextAtStart === void 0 || hasNativeRoutingAtStart && nativeRoutingAtStart === void 0) {
789
812
  return {
790
813
  ok: false,
791
814
  reason: "invalid-shape",
@@ -807,6 +830,7 @@ function parseTaskBenchmarkCapture(value3) {
807
830
  startedAt,
808
831
  usageBefore,
809
832
  ...hasContextAtStart ? { contextAtStart: contextAtStart ?? null } : {},
833
+ ...hasNativeRoutingAtStart ? { nativeRoutingAtStart: nativeRoutingAtStart ?? null } : {},
810
834
  localSessionsBefore
811
835
  }
812
836
  };
@@ -842,7 +866,11 @@ function parseTaskBenchmarkReceipt(value3) {
842
866
  const contextAtStart = hasContextAtStart ? parseTaskBenchmarkContextSnapshot(row2["contextAtStart"]) : void 0;
843
867
  const hasContextAtFinish = Object.hasOwn(row2, "contextAtFinish");
844
868
  const contextAtFinish = hasContextAtFinish ? parseTaskBenchmarkContextSnapshot(row2["contextAtFinish"]) : void 0;
845
- if (typeof benchmarkId !== "string" || benchmarkId === "" || typeof variant !== "string" || !isTaskBenchmarkVariant(variant) || typeof taskClass !== "string" || !isTaskClass(taskClass) || typeof harnessId2 !== "string" || !isHarnessId(harnessId2) || model === void 0 || reasoningEffort === void 0 || verbosity === void 0 || !validInstant(startedAt) || !validInstant(completedAt) || Date.parse(completedAt) < Date.parse(startedAt) || usageBefore === null || usageAfter === null || localUsage === void 0 || outcome2 === null || hasBoundaryPolicy && policyAtFinish === void 0 || hasContextAtStart && contextAtStart === void 0 || hasContextAtFinish && contextAtFinish === void 0) {
869
+ const hasNativeRoutingAtStart = Object.hasOwn(row2, "nativeRoutingAtStart");
870
+ const nativeRoutingAtStart = hasNativeRoutingAtStart ? parseNativeRoutingObservation(row2["nativeRoutingAtStart"]) : void 0;
871
+ const hasNativeRoutingAtFinish = Object.hasOwn(row2, "nativeRoutingAtFinish");
872
+ const nativeRoutingAtFinish = hasNativeRoutingAtFinish ? parseNativeRoutingObservation(row2["nativeRoutingAtFinish"]) : void 0;
873
+ if (typeof benchmarkId !== "string" || benchmarkId === "" || typeof variant !== "string" || !isTaskBenchmarkVariant(variant) || typeof taskClass !== "string" || !isTaskClass(taskClass) || typeof harnessId2 !== "string" || !isHarnessId(harnessId2) || model === void 0 || reasoningEffort === void 0 || verbosity === void 0 || !validInstant(startedAt) || !validInstant(completedAt) || Date.parse(completedAt) < Date.parse(startedAt) || usageBefore === null || usageAfter === null || localUsage === void 0 || outcome2 === null || hasBoundaryPolicy && policyAtFinish === void 0 || hasContextAtStart && contextAtStart === void 0 || hasContextAtFinish && contextAtFinish === void 0 || hasNativeRoutingAtStart && nativeRoutingAtStart === void 0 || hasNativeRoutingAtFinish && nativeRoutingAtFinish === void 0) {
846
874
  return {
847
875
  ok: false,
848
876
  reason: "invalid-shape",
@@ -868,7 +896,9 @@ function parseTaskBenchmarkReceipt(value3) {
868
896
  outcome: outcome2,
869
897
  ...hasContextAtStart ? { contextAtStart: contextAtStart ?? null } : {},
870
898
  ...hasContextAtFinish ? { contextAtFinish: contextAtFinish ?? null } : {},
871
- ...hasBoundaryPolicy ? { policyAtFinish: policyAtFinish ?? null } : {}
899
+ ...hasBoundaryPolicy ? { policyAtFinish: policyAtFinish ?? null } : {},
900
+ ...hasNativeRoutingAtStart ? { nativeRoutingAtStart: nativeRoutingAtStart ?? null } : {},
901
+ ...hasNativeRoutingAtFinish ? { nativeRoutingAtFinish: nativeRoutingAtFinish ?? null } : {}
872
902
  }
873
903
  };
874
904
  }
@@ -888,7 +918,9 @@ function completeTaskBenchmarkCapture(capture, input) {
888
918
  usageAfter: input.usageAfter,
889
919
  localUsage: input.localUsage ?? null,
890
920
  ...capture.contextAtStart !== void 0 ? { contextAtStart: capture.contextAtStart } : {},
921
+ ...capture.nativeRoutingAtStart !== void 0 ? { nativeRoutingAtStart: capture.nativeRoutingAtStart } : {},
891
922
  ...input.contextAtFinish !== void 0 ? { contextAtFinish: input.contextAtFinish } : {},
923
+ ...input.nativeRoutingAtFinish !== void 0 ? { nativeRoutingAtFinish: input.nativeRoutingAtFinish } : {},
892
924
  ...input.policyAtFinish !== void 0 ? { policyAtFinish: input.policyAtFinish } : {},
893
925
  outcome: {
894
926
  qualityGate: input.qualityGate,
@@ -1096,7 +1128,8 @@ function buildTaskBenchmarkMatrix(pairs, selection = {
1096
1128
  baselineLocalTokens,
1097
1129
  optimizedLocalTokens,
1098
1130
  localTokenSavingPercent: !bothQualityPassed || baselineLocalTokens === null || optimizedLocalTokens === null ? null : roundedPercent(baselineLocalTokens - optimizedLocalTokens, baselineLocalTokens),
1099
- quota: comparison.quota
1131
+ quota: comparison.quota,
1132
+ ...nativeRoutingComparison(baseline, optimized)
1100
1133
  };
1101
1134
  }).sort((left, right) => TASK_CLASS_ORDER.indexOf(left.taskClass) - TASK_CLASS_ORDER.indexOf(right.taskClass) || left.benchmarkId.localeCompare(right.benchmarkId));
1102
1135
  const byTaskClass = TASK_CLASS_ORDER.map((taskClass) => ({
@@ -1110,6 +1143,36 @@ function buildTaskBenchmarkMatrix(pairs, selection = {
1110
1143
  selection
1111
1144
  };
1112
1145
  }
1146
+ function nativeRoutingComparison(baseline, optimized) {
1147
+ const bStart = baseline.nativeRoutingAtStart;
1148
+ const bFinish = baseline.nativeRoutingAtFinish;
1149
+ const oStart = optimized.nativeRoutingAtStart;
1150
+ const oFinish = optimized.nativeRoutingAtFinish;
1151
+ if (bStart === void 0 && bFinish === void 0 && oStart === void 0 && oFinish === void 0)
1152
+ return {};
1153
+ const qualityGatesPassed = baseline.outcome.qualityGate === "passed" && optimized.outcome.qualityGate === "passed";
1154
+ if (bStart == null || bFinish == null || oStart == null || oFinish == null || bStart.configured === null || oStart.configured === null) {
1155
+ return {
1156
+ nativeRouting: {
1157
+ verdict: "unknown",
1158
+ baselineSubagents: bFinish?.subagentsStarted ?? null,
1159
+ optimizedSubagents: oFinish?.subagentsStarted ?? null,
1160
+ optimizedReportedModels: oFinish?.reportedModels ?? [],
1161
+ qualityGatesPassed
1162
+ }
1163
+ };
1164
+ }
1165
+ const attributed = bStart.configured === false && bFinish.configured === false && bFinish.subagentsStarted === 0 && oStart.configured === true && oFinish.configured === true && oFinish.promptSubmissions > 0 && oFinish.subagentsStarted > 0;
1166
+ return {
1167
+ nativeRouting: {
1168
+ verdict: attributed ? "attributed" : "not-attributed",
1169
+ baselineSubagents: bFinish.subagentsStarted,
1170
+ optimizedSubagents: oFinish.subagentsStarted,
1171
+ optimizedReportedModels: [...oFinish.reportedModels],
1172
+ qualityGatesPassed
1173
+ }
1174
+ };
1175
+ }
1113
1176
  var TASK_BENCHMARK_RECEIPT_SCHEMA_VERSION, TASK_BENCHMARK_CAPTURE_SCHEMA_VERSION, BENCHMARK_ID, WINDOW_SCOPES, WINDOW_SOURCES, WINDOW_CONFIDENCES, WINDOW_KINDS, QUOTA_SCOPE_PRIORITY, TASK_CLASS_ORDER;
1114
1177
  var init_benchmark = __esm({
1115
1178
  "packages/core/dist/src/domain/benchmark.js"() {
@@ -4144,11 +4207,19 @@ function findCompatibilityRule(rules, query) {
4144
4207
  candidates.push(rule);
4145
4208
  }
4146
4209
  if (query.observedVersions !== void 0) {
4147
- const matchesObservedTuple = (rule) => Object.entries(rule.testedVersions).every(([provider, version3]) => query.observedVersions?.[provider] === version3) && Object.entries(rule.testedHarnessVersions ?? {}).every(([harness, version3]) => query.observedHarnessVersions?.[harness] === version3);
4210
+ const matchesObservedTuple = (rule) => {
4211
+ if (rule.providers.some((provider) => rule.testedVersions[provider] === void 0)) {
4212
+ return false;
4213
+ }
4214
+ const testedHarnessVersion = rule.testedHarnessVersions?.[query.harness];
4215
+ if (rule.outcome === "ordered" && testedHarnessVersion === void 0)
4216
+ return false;
4217
+ return Object.entries(rule.testedVersions).every(([provider, version3]) => query.observedVersions?.[provider] === version3) && (testedHarnessVersion === void 0 || query.observedHarnessVersions?.[query.harness] === testedHarnessVersion);
4218
+ };
4148
4219
  const exact = candidates.find(matchesObservedTuple);
4149
4220
  if (exact !== void 0)
4150
4221
  return exact;
4151
- const matchingDimensions = (rule) => Object.entries(rule.testedVersions).filter(([provider, version3]) => query.observedVersions?.[provider] === version3).length + Object.entries(rule.testedHarnessVersions ?? {}).filter(([harness, version3]) => query.observedHarnessVersions?.[harness] === version3).length;
4222
+ const matchingDimensions = (rule) => Object.entries(rule.testedVersions).filter(([provider, version3]) => query.observedVersions?.[provider] === version3).length + (rule.testedHarnessVersions?.[query.harness] !== void 0 && query.observedHarnessVersions?.[query.harness] === rule.testedHarnessVersions[query.harness] ? 1 : 0);
4152
4223
  candidates.sort((left, right) => matchingDimensions(right) - matchingDimensions(left));
4153
4224
  }
4154
4225
  return candidates[0] ?? null;
@@ -4160,26 +4231,24 @@ function coversVersion(recorded, observed) {
4160
4231
  }
4161
4232
  function staleRecordedVersions(rule, observed) {
4162
4233
  const stale2 = [];
4163
- for (const [provider, recorded] of Object.entries(rule.testedVersions)) {
4234
+ for (const provider of rule.providers) {
4235
+ const recorded = rule.testedVersions[provider];
4164
4236
  const seen = observed[provider] ?? null;
4165
- const recordedVersion = parseSemanticVersion(recorded);
4237
+ const recordedVersion = recorded === void 0 ? null : parseSemanticVersion(recorded);
4166
4238
  const seenVersion = seen === null ? null : parseSemanticVersion(seen);
4167
4239
  if (recordedVersion !== null && seenVersion !== null && coversVersion(recordedVersion, seenVersion)) {
4168
4240
  continue;
4169
4241
  }
4170
- stale2.push({ provider, recorded, observed: seen });
4242
+ stale2.push({ provider, recorded: recorded ?? null, observed: seen });
4171
4243
  }
4172
4244
  return stale2;
4173
4245
  }
4174
- function staleRecordedHarnessVersions(rule, observed) {
4175
- const stale2 = [];
4176
- for (const [harness, recorded] of Object.entries(rule.testedHarnessVersions ?? {})) {
4177
- const seen = observed[harness] ?? null;
4178
- if (seen === recorded)
4179
- continue;
4180
- stale2.push({ harness, recorded, observed: seen });
4181
- }
4182
- return stale2;
4246
+ function staleRecordedHarnessVersions(rule, observed, harness) {
4247
+ const recorded = rule.testedHarnessVersions?.[harness];
4248
+ if (recorded === void 0 && rule.outcome !== "ordered")
4249
+ return [];
4250
+ const seen = observed[harness] ?? null;
4251
+ return recorded !== void 0 && seen === recorded ? [] : [{ harness, recorded: recorded ?? null, observed: seen }];
4183
4252
  }
4184
4253
  var init_compatibility = __esm({
4185
4254
  "packages/core/dist/src/domain/compatibility.js"() {
@@ -4606,35 +4675,36 @@ function detectUnownedEntries(input) {
4606
4675
  });
4607
4676
  }
4608
4677
  for (const config of input.configs) {
4609
- for (const point of config.interceptionPoints) {
4610
- for (const matcher of config.matchers) {
4611
- for (const [key, resolved] of exclusiveOwners) {
4612
- if (resolved.scope.harness !== config.harnessId)
4613
- continue;
4614
- if (resolved.scope.interceptionPoint !== point)
4615
- continue;
4616
- if (resolved.scope.toolFamily !== matcher)
4617
- continue;
4618
- for (const command of config.commands) {
4619
- const belongsTo = input.identify(command);
4620
- if (belongsTo === resolved.owner)
4621
- continue;
4622
- findings.push({
4623
- code: "unowned-entry-on-exclusive-scope",
4624
- scope: key,
4625
- expectedOwner: resolved.owner,
4626
- configPath: config.configPath,
4627
- matcher,
4628
- command,
4629
- detail: [
4630
- `${key} is an exclusive scope owned by ${resolved.owner}`,
4631
- belongsTo === null ? "An entry here invokes a command Token Harness does not recognise" : `An entry here invokes ${belongsTo}`,
4632
- "The harness runs every matching hook rather than only the first, so both would transform the same payload and the saving would be counted twice"
4633
- ],
4634
- remediation: "Remove the competing entry, or assign the scope to it explicitly with `profile: custom`. Token Harness will not remove a third party\u2019s entry."
4635
- });
4636
- }
4637
- }
4678
+ const observedHooks = config.hookCommands === void 0 ? config.interceptionPoints.flatMap((interceptionPoint) => config.matchers.flatMap((toolFamily) => config.commands.map((command) => ({
4679
+ interceptionPoint,
4680
+ toolFamilies: [toolFamily],
4681
+ command
4682
+ })))) : config.hookCommands;
4683
+ for (const hook of observedHooks) {
4684
+ for (const [key, resolved] of exclusiveOwners) {
4685
+ if (resolved.scope.harness !== config.harnessId)
4686
+ continue;
4687
+ if (resolved.scope.interceptionPoint !== hook.interceptionPoint)
4688
+ continue;
4689
+ if (!hook.toolFamilies.includes(resolved.scope.toolFamily))
4690
+ continue;
4691
+ const belongsTo = input.identify(hook.command);
4692
+ if (belongsTo === resolved.owner)
4693
+ continue;
4694
+ findings.push({
4695
+ code: "unowned-entry-on-exclusive-scope",
4696
+ scope: key,
4697
+ expectedOwner: resolved.owner,
4698
+ configPath: config.configPath,
4699
+ matcher: resolved.scope.toolFamily,
4700
+ command: hook.command,
4701
+ detail: [
4702
+ `${key} is an exclusive scope owned by ${resolved.owner}`,
4703
+ belongsTo === null ? "An entry here invokes a command Token Harness does not recognise" : `An entry here invokes ${belongsTo}`,
4704
+ "The harness runs every matching hook rather than only the first, so both would transform the same payload and the saving would be counted twice"
4705
+ ],
4706
+ remediation: "Remove the competing entry, or assign the scope to it explicitly with `profile: custom`. Token Harness will not remove a third party\u2019s entry."
4707
+ });
4638
4708
  }
4639
4709
  }
4640
4710
  }
@@ -4808,7 +4878,7 @@ function narrowChannelOverlaps(context) {
4808
4878
  ...input.observedHarnessVersions === void 0 ? {} : { observedHarnessVersions: input.observedHarnessVersions }
4809
4879
  });
4810
4880
  const staleProviders = found === null ? [] : staleRecordedVersions(found, input.observedVersions);
4811
- const staleHarnesses = found === null ? [] : staleRecordedHarnessVersions(found, input.observedHarnessVersions ?? {});
4881
+ const staleHarnesses = found === null ? [] : staleRecordedHarnessVersions(found, input.observedHarnessVersions ?? {}, harness);
4812
4882
  const stale2 = [...staleProviders, ...staleHarnesses];
4813
4883
  const rule = stale2.length > 0 ? null : found;
4814
4884
  if (found !== null && stale2.length > 0) {
@@ -4819,8 +4889,8 @@ function narrowChannelOverlaps(context) {
4819
4889
  detail: [
4820
4890
  `${owners.join(" and ")} both use ${capability} on ${harness}/${toolFamily} at different interception points`,
4821
4891
  `Rule ${found.id} was tested at ${[
4822
- ...staleProviders.map((entry) => `${entry.provider} ${entry.recorded}`),
4823
- ...staleHarnesses.map((entry) => `${entry.harness} ${entry.recorded}`)
4892
+ ...staleProviders.map((entry) => `${entry.provider} ${entry.recorded ?? "not recorded"}`),
4893
+ ...staleHarnesses.map((entry) => `${entry.harness} ${entry.recorded ?? "not recorded"}`)
4824
4894
  ].join(", ")}`,
4825
4895
  `Installed now: ${[
4826
4896
  ...staleProviders.map((entry) => `${entry.provider} ${entry.observed ?? "unknown"}`),
@@ -4921,7 +4991,9 @@ function resolveContested(context) {
4921
4991
  ...input.observedHarnessVersions === void 0 ? {} : { observedHarnessVersions: input.observedHarnessVersions }
4922
4992
  });
4923
4993
  const stale2 = found === null ? [] : staleRecordedVersions(found, input.observedVersions);
4924
- const rule = stale2.length > 0 ? null : found;
4994
+ const staleHarnesses = found === null ? [] : staleRecordedHarnessVersions(found, input.observedHarnessVersions ?? {}, scope.harness);
4995
+ const staleAll = [...stale2, ...staleHarnesses];
4996
+ const rule = staleAll.length > 0 ? null : found;
4925
4997
  if (rule === null) {
4926
4998
  if (found !== null) {
4927
4999
  conflicts.push({
@@ -4930,11 +5002,17 @@ function resolveContested(context) {
4930
5002
  claimants,
4931
5003
  detail: [
4932
5004
  `${claimants.join(" and ")} both claim ${capability} on ${formatCapabilityScope(scope)}`,
4933
- `Rule ${found.id} was tested at ${stale2.map((entry) => `${entry.provider} ${entry.recorded}`).join(", ")}`,
4934
- `Installed now: ${stale2.map((entry) => `${entry.provider} ${entry.observed ?? "unknown"}`).join(", ")}`,
5005
+ `Rule ${found.id} was tested at ${[
5006
+ ...stale2.map((entry) => `${entry.provider} ${entry.recorded ?? "not recorded"}`),
5007
+ ...staleHarnesses.map((entry) => `${entry.harness} ${entry.recorded ?? "not recorded"}`)
5008
+ ].join(", ")}`,
5009
+ `Installed now: ${[
5010
+ ...stale2.map((entry) => `${entry.provider} ${entry.observed ?? "unknown"}`),
5011
+ ...staleHarnesses.map((entry) => `${entry.harness} ${entry.observed ?? "unknown"}`)
5012
+ ].join(", ")}`,
4935
5013
  "A compatibility result covers the versions it records, so this one is withdrawn rather than applied outside them"
4936
5014
  ],
4937
- remediation: `Re-test ${found.id} against the installed versions and update its \`testedVersions\`, or assign the scope explicitly with \`profile: custom\``
5015
+ remediation: `Re-test ${found.id} against the installed provider and harness versions, record the evidence for ${scope.harness}, or assign the scope explicitly with \`profile: custom\``
4938
5016
  });
4939
5017
  return;
4940
5018
  }
@@ -9784,7 +9862,7 @@ var TOOL_VERSION;
9784
9862
  var init_version2 = __esm({
9785
9863
  "apps/cli/dist/src/version.js"() {
9786
9864
  "use strict";
9787
- TOOL_VERSION = "0.1.23";
9865
+ TOOL_VERSION = "0.1.25";
9788
9866
  }
9789
9867
  });
9790
9868
 
@@ -14138,7 +14216,9 @@ function readHooks(document2) {
14138
14216
  return [
14139
14217
  {
14140
14218
  eventName: point.eventName,
14219
+ interceptionPoint: point.scopeId,
14141
14220
  matcher: typeof matcher === "string" ? matcher : null,
14221
+ toolFamilies: typeof matcher !== "string" ? MANIFEST.toolFamilies.map((family) => family.id) : MANIFEST.toolFamilies.filter((family) => matcherCoversFamily(matcher, family.id)).map((family) => family.id),
14142
14222
  command: hook["command"],
14143
14223
  entryPointer,
14144
14224
  commandPointer: `${entryPointer}.hooks.${String(hookIndex)}.command`
@@ -14677,7 +14757,10 @@ var init_claude = __esm({
14677
14757
  versionCommand: { executable: "claude", args: ["--version"] },
14678
14758
  interceptionPoints: [
14679
14759
  { scopeId: "pre-tool-use", eventName: "PreToolUse" },
14680
- { scopeId: "post-tool-use", eventName: "PostToolUse" }
14760
+ { scopeId: "post-tool-use", eventName: "PostToolUse" },
14761
+ { scopeId: "user-prompt-submit", eventName: "UserPromptSubmit" },
14762
+ { scopeId: "subagent-start", eventName: "SubagentStart" },
14763
+ { scopeId: "subagent-stop", eventName: "SubagentStop" }
14681
14764
  ],
14682
14765
  configFiles: [
14683
14766
  {
@@ -14686,7 +14769,13 @@ var init_claude = __esm({
14686
14769
  parser: "json",
14687
14770
  primary: true,
14688
14771
  interceptionFormat: "hooks-event-command-list",
14689
- interceptionPoints: ["pre-tool-use", "post-tool-use"]
14772
+ interceptionPoints: [
14773
+ "pre-tool-use",
14774
+ "post-tool-use",
14775
+ "user-prompt-submit",
14776
+ "subagent-start",
14777
+ "subagent-stop"
14778
+ ]
14690
14779
  },
14691
14780
  { path: ".claude/settings.json", scope: "project", parser: "json", primary: false },
14692
14781
  { path: ".claude/settings.local.json", scope: "project", parser: "json", primary: false }
@@ -14874,7 +14963,7 @@ var init_codex_hooks = __esm({
14874
14963
  function isRecord3(value3) {
14875
14964
  return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
14876
14965
  }
14877
- function readHooks2(document2) {
14966
+ function readHooks2(document2, os) {
14878
14967
  if (!isRecord3(document2) || !isRecord3(document2["hooks"]))
14879
14968
  return { points: [], matchers: [], commands: [], hookCommands: [] };
14880
14969
  const hooks = document2["hooks"];
@@ -14895,15 +14984,21 @@ function readHooks2(document2) {
14895
14984
  matchers.push(matcher);
14896
14985
  if (Array.isArray(entry["hooks"])) {
14897
14986
  for (const [hookIndex, hook] of entry["hooks"].entries()) {
14898
- if (isRecord3(hook) && typeof hook["command"] === "string") {
14899
- commands.push(hook["command"]);
14987
+ if (!isRecord3(hook))
14988
+ continue;
14989
+ const commandKey = os === "windows" && typeof hook["commandWindows"] === "string" ? "commandWindows" : "command";
14990
+ const command = hook[commandKey];
14991
+ if (typeof command === "string") {
14992
+ commands.push(command);
14900
14993
  const entryPointer = `hooks.${point.eventName}.${String(entryIndex)}`;
14901
14994
  hookCommands.push({
14902
14995
  eventName: point.eventName,
14996
+ interceptionPoint: point.scopeId,
14903
14997
  matcher,
14904
- command: hook["command"],
14998
+ toolFamilies: matcher === null ? MANIFEST2.toolFamilies.map((family) => family.id) : MANIFEST2.toolFamilies.filter((family) => matcherCoversFamily(matcher, family.id)).map((family) => family.id),
14999
+ command,
14905
15000
  entryPointer,
14906
- commandPointer: `${entryPointer}.hooks.${String(hookIndex)}.command`
15001
+ commandPointer: `${entryPointer}.hooks.${String(hookIndex)}.${commandKey}`
14907
15002
  });
14908
15003
  carries = true;
14909
15004
  }
@@ -14948,7 +15043,7 @@ async function resolveConfig2(declaration, context) {
14948
15043
  };
14949
15044
  }
14950
15045
  try {
14951
- const hooks = readHooks2(JSON.parse(text3));
15046
+ const hooks = readHooks2(JSON.parse(text3), context.facts.os);
14952
15047
  return {
14953
15048
  declaration,
14954
15049
  path,
@@ -15854,7 +15949,10 @@ var init_codex = __esm({
15854
15949
  */
15855
15950
  interceptionPoints: [
15856
15951
  { scopeId: "pre-tool-use", eventName: "PreToolUse" },
15857
- { scopeId: "post-tool-use", eventName: "PostToolUse" }
15952
+ { scopeId: "post-tool-use", eventName: "PostToolUse" },
15953
+ { scopeId: "user-prompt-submit", eventName: "UserPromptSubmit" },
15954
+ { scopeId: "subagent-start", eventName: "SubagentStart" },
15955
+ { scopeId: "subagent-stop", eventName: "SubagentStop" }
15858
15956
  ],
15859
15957
  configFiles: [
15860
15958
  { path: ".codex/config.toml", scope: "user", parser: "toml", primary: true },
@@ -15864,7 +15962,13 @@ var init_codex = __esm({
15864
15962
  parser: "json",
15865
15963
  primary: false,
15866
15964
  interceptionFormat: "hooks-event-command-list",
15867
- interceptionPoints: ["pre-tool-use", "post-tool-use"]
15965
+ interceptionPoints: [
15966
+ "pre-tool-use",
15967
+ "post-tool-use",
15968
+ "user-prompt-submit",
15969
+ "subagent-start",
15970
+ "subagent-stop"
15971
+ ]
15868
15972
  }
15869
15973
  ],
15870
15974
  toolFamilies: [
@@ -16632,10 +16736,49 @@ var init_pi = __esm({
16632
16736
  }
16633
16737
  });
16634
16738
 
16739
+ // packages/adapters/dist/src/harnesses/native-prompt-routing.js
16740
+ function nativePromptRoutingHookEntries(harness, executable = "token-harness") {
16741
+ return NATIVE_PROMPT_ROUTING_EVENTS.map(({ eventName, commandEvent }) => {
16742
+ if (harness === "codex") {
16743
+ const command = `${executable} __internal-prompt-router codex ${commandEvent}`;
16744
+ const handler2 = {
16745
+ type: "command",
16746
+ command,
16747
+ commandWindows: command,
16748
+ timeout: 10
16749
+ };
16750
+ if (commandEvent === "prompt-submit")
16751
+ handler2["additionalContextLimit"] = 500;
16752
+ return { eventName, value: { hooks: [handler2] } };
16753
+ }
16754
+ const handler = {
16755
+ type: "command",
16756
+ command: executable,
16757
+ args: ["__internal-prompt-router", "claude", commandEvent],
16758
+ timeout: 10
16759
+ };
16760
+ return { eventName, value: { hooks: [handler] } };
16761
+ });
16762
+ }
16763
+ var NATIVE_PROMPT_ROUTING_EVENTS;
16764
+ var init_native_prompt_routing = __esm({
16765
+ "packages/adapters/dist/src/harnesses/native-prompt-routing.js"() {
16766
+ "use strict";
16767
+ NATIVE_PROMPT_ROUTING_EVENTS = [
16768
+ { eventName: "UserPromptSubmit", commandEvent: "prompt-submit" },
16769
+ { eventName: "SubagentStart", commandEvent: "subagent-start" },
16770
+ { eventName: "SubagentStop", commandEvent: "subagent-stop" }
16771
+ ];
16772
+ }
16773
+ });
16774
+
16635
16775
  // packages/adapters/dist/src/harnesses/index.js
16636
16776
  function listHarnessAdapters() {
16637
16777
  return HARNESS_ADAPTERS;
16638
16778
  }
16779
+ function findHarnessAdapter(id) {
16780
+ return HARNESS_ADAPTERS.find((adapter) => adapter.manifest.id === id) ?? null;
16781
+ }
16639
16782
  var HARNESS_ADAPTERS;
16640
16783
  var init_harnesses = __esm({
16641
16784
  "packages/adapters/dist/src/harnesses/index.js"() {
@@ -16653,6 +16796,7 @@ var init_harnesses = __esm({
16653
16796
  init_opencode();
16654
16797
  init_pi();
16655
16798
  init_claude();
16799
+ init_native_prompt_routing();
16656
16800
  HARNESS_ADAPTERS = [
16657
16801
  claudeAdapter,
16658
16802
  codexAdapter,
@@ -17702,11 +17846,11 @@ async function plan(context, request) {
17702
17846
  }));
17703
17847
  continue;
17704
17848
  }
17705
- const actionId = `harnesstrim-${harness.id}-hook-${digestText(target.configPath).slice(7, 15)}`;
17849
+ const actionId2 = `harnesstrim-${harness.id}-hook-${digestText(target.configPath).slice(7, 15)}`;
17706
17850
  actions.push(appendCommandHookAction({
17707
17851
  target,
17708
17852
  providerId: HARNESSTRIM2,
17709
- actionId,
17853
+ actionId: actionId2,
17710
17854
  command,
17711
17855
  explanation: `Register HarnessTrim after ${harness.displayName} Bash commands and record reductions in ${metricsPath}${codexActivationNote(harness.id)}`
17712
17856
  }));
@@ -18214,7 +18358,7 @@ function installAction(context, manifest) {
18214
18358
  packageName: channel.packageId ?? "rtk",
18215
18359
  // The managed Codex hook first exists in this RTK release. Pinning makes a fresh setup's
18216
18360
  // promised surface deterministic instead of installing an older prompt-only build.
18217
- version: "0.50.0"
18361
+ version: "0.51.0"
18218
18362
  };
18219
18363
  }
18220
18364
  function buildRtkPlan(input) {
@@ -18393,9 +18537,15 @@ async function readHarnessActivity(context, harness) {
18393
18537
  failure: null
18394
18538
  };
18395
18539
  }
18540
+ function supportsCodexHook(version3) {
18541
+ if (version3 === null)
18542
+ return false;
18543
+ const parsed = parseSemanticVersion(version3);
18544
+ const minimum = parseSemanticVersion(RTK_CODEX_HOOK_MINIMUM_VERSION);
18545
+ return parsed !== null && minimum !== null && compareVersions(parsed, minimum) >= 0;
18546
+ }
18396
18547
  function hasAttributionHook(context, harness) {
18397
- const command = new RegExp(`^token-harness __internal-rtk-hook ${harness}(?: --restore-rtk)?$`, "i");
18398
- return context.harnessConfigs.some((config) => config.harnessId === harness && config.commands.some((entry) => command.test(entry.trim())));
18548
+ return context.harnessConfigs.some((config) => config.harnessId === harness && config.commands.some((entry) => tokenHarnessRtkHookHarness(entry) === harness));
18399
18549
  }
18400
18550
  async function detect7(context) {
18401
18551
  const evidenceItems = [];
@@ -18419,7 +18569,7 @@ async function detect7(context) {
18419
18569
  remediation: "Check the release notes for analytics or hook changes before applying a plan"
18420
18570
  }));
18421
18571
  }
18422
- const codexHookSupported = version3.version === RTK_CODEX_HOOK_VERSION;
18572
+ const codexHookSupported = supportsCodexHook(version3.version);
18423
18573
  const codexConfiguredWithoutHookSupport = configured.includes(CODEX4) && !codexHookSupported;
18424
18574
  if (codexConfiguredWithoutHookSupport) {
18425
18575
  warnings.push(diagnostic({
@@ -18427,7 +18577,7 @@ async function detect7(context) {
18427
18577
  code: "rtk-codex-hook-unsupported",
18428
18578
  subject: CODEX4,
18429
18579
  message: `RTK ${String(version3.version)} does not provide the Codex hook; its configuration entry cannot capture commands`,
18430
- remediation: `Upgrade RTK to ${RTK_CODEX_HOOK_VERSION}, then refresh and apply the attribution plan`
18580
+ remediation: `Upgrade RTK to ${RTK_CODEX_HOOK_MINIMUM_VERSION}, then refresh and apply the attribution plan`
18431
18581
  }));
18432
18582
  }
18433
18583
  const state = version3.version === null ? configured.length > 0 ? "broken" : "absent" : codexConfiguredWithoutHookSupport && configured.length === 1 ? "broken" : configured.length > 0 ? "configured" : "installed";
@@ -18493,14 +18643,14 @@ async function verify7(context) {
18493
18643
  remediation: version3.version === null ? "Install RTK, or add it to PATH" : null
18494
18644
  });
18495
18645
  const configured = harnessesWiredToRtk(context.harnessConfigs);
18496
- const configuredSupported = configured.filter((harness) => harness === CLAUDE5 || harness === CODEX4 && version3.version === RTK_CODEX_HOOK_VERSION);
18646
+ const configuredSupported = configured.filter((harness) => harness === CLAUDE5 || harness === CODEX4 && supportsCodexHook(version3.version));
18497
18647
  checks.push({
18498
18648
  id: "hook-registered",
18499
18649
  status: configuredSupported.length > 0 ? "pass" : configured.length > 0 ? "fail" : "not-exercised",
18500
18650
  summary: configuredSupported.length > 0 ? `wired to ${configuredSupported.join(", ")}` : configured.length > 0 ? `RTK ${String(version3.version)} cannot run its Codex hook` : "no harness configuration names rtk",
18501
18651
  achievedTier: configuredSupported.length > 0 ? "config-only" : null,
18502
18652
  evidence: [],
18503
- remediation: configured.length > 0 && configuredSupported.length === 0 ? `Upgrade RTK to ${RTK_CODEX_HOOK_VERSION} for Codex hook support` : null
18653
+ remediation: configured.length > 0 && configuredSupported.length === 0 ? `Upgrade RTK to ${RTK_CODEX_HOOK_MINIMUM_VERSION} for Codex hook support` : null
18504
18654
  });
18505
18655
  let receipt = null;
18506
18656
  let bestReceiptTime = Number.NEGATIVE_INFINITY;
@@ -18508,7 +18658,7 @@ async function verify7(context) {
18508
18658
  if (!configured.includes(harness))
18509
18659
  continue;
18510
18660
  const label = harness === CLAUDE5 ? "Claude Code" : "Codex";
18511
- const supported = harness !== CODEX4 || version3.version === RTK_CODEX_HOOK_VERSION;
18661
+ const supported = harness !== CODEX4 || supportsCodexHook(version3.version);
18512
18662
  if (!supported) {
18513
18663
  checks.push({
18514
18664
  id: `rtk-attribution-${harness}`,
@@ -18516,7 +18666,7 @@ async function verify7(context) {
18516
18666
  summary: `RTK ${String(version3.version)} does not provide an active ${label} hook`,
18517
18667
  achievedTier: null,
18518
18668
  evidence: [],
18519
- remediation: `Upgrade RTK to ${RTK_CODEX_HOOK_VERSION}, then refresh and apply the tracking update`
18669
+ remediation: `Upgrade RTK to ${RTK_CODEX_HOOK_MINIMUM_VERSION}, then refresh and apply the tracking update`
18520
18670
  });
18521
18671
  continue;
18522
18672
  }
@@ -18911,7 +19061,20 @@ async function importHistorySource(context, store, path, attributedHarness) {
18911
19061
  };
18912
19062
  }
18913
19063
  function identifiesCommand2(command) {
18914
- return HOOK_COMMAND_PATTERN2.test(command) || PLUGIN_MODULE_PATTERN3.test(command) || /(^|[\\/\s"'])token-harness(?:\.cmd|\.exe)?\s+__internal-rtk-hook(?:\s|$)/i.test(command);
19064
+ return HOOK_COMMAND_PATTERN2.test(command) || PLUGIN_MODULE_PATTERN3.test(command) || tokenHarnessRtkHookHarness(command) !== null;
19065
+ }
19066
+ function tokenHarnessRtkHookHarness(command) {
19067
+ const match = /^\s*(?:"([^"]+)"|'([^']+)'|(\S+))\s+__internal-rtk-hook\s+(claude|codex)(?:\s+--restore-rtk)?\s*$/i.exec(command);
19068
+ if (match === null)
19069
+ return null;
19070
+ const executable = match[1] ?? match[2] ?? match[3];
19071
+ if (executable === void 0)
19072
+ return null;
19073
+ const basename = executable.split(/[\\/]/).at(-1);
19074
+ if (basename === void 0 || !/^token-harness(?:\.cmd|\.exe)?$/i.test(basename)) {
19075
+ return null;
19076
+ }
19077
+ return harnessId((match[4] ?? "").toLowerCase());
18915
19078
  }
18916
19079
  async function plan2(context, request) {
18917
19080
  const version3 = await readVersion(context);
@@ -18935,7 +19098,7 @@ async function plan2(context, request) {
18935
19098
  hookProxyAvailable
18936
19099
  });
18937
19100
  }
18938
- var RTK2, CLAUDE5, CODEX4, OPENCODE3, TRACKED_HARNESSES, RTK_CODEX_HOOK_VERSION, MANIFEST7, TESTED_VERSIONS2, VERSION_PATTERN7, HOOK_COMMAND_PATTERN2, PLUGIN_MODULE_PATTERN3, HARNESS_ACTIVITY_QUERY, STALE_RECEIPT_DAYS, HISTORY_QUERY, GENERATION_QUERY, IMPORT_BATCH_SIZE, SOURCE_LABEL, rtkAdapter;
19101
+ var RTK2, CLAUDE5, CODEX4, OPENCODE3, TRACKED_HARNESSES, RTK_CODEX_HOOK_MINIMUM_VERSION, MANIFEST7, TESTED_VERSIONS2, VERSION_PATTERN7, HOOK_COMMAND_PATTERN2, PLUGIN_MODULE_PATTERN3, HARNESS_ACTIVITY_QUERY, STALE_RECEIPT_DAYS, HISTORY_QUERY, GENERATION_QUERY, IMPORT_BATCH_SIZE, SOURCE_LABEL, rtkAdapter;
18939
19102
  var init_rtk = __esm({
18940
19103
  "packages/adapters/dist/src/providers/rtk.js"() {
18941
19104
  "use strict";
@@ -18946,7 +19109,7 @@ var init_rtk = __esm({
18946
19109
  CODEX4 = harnessId("codex");
18947
19110
  OPENCODE3 = harnessId("opencode");
18948
19111
  TRACKED_HARNESSES = [CLAUDE5, CODEX4];
18949
- RTK_CODEX_HOOK_VERSION = "0.50.0";
19112
+ RTK_CODEX_HOOK_MINIMUM_VERSION = "0.50.0";
18950
19113
  MANIFEST7 = {
18951
19114
  schemaVersion: MANIFEST_SCHEMA_VERSION,
18952
19115
  id: RTK2,
@@ -19126,7 +19289,7 @@ var init_rtk = __esm({
19126
19289
  },
19127
19290
  delegatedInstallReviews: null
19128
19291
  };
19129
- TESTED_VERSIONS2 = { minimum: "0.44.0", maximum: "0.50.0" };
19292
+ TESTED_VERSIONS2 = { minimum: "0.44.0", maximum: "0.51.0" };
19130
19293
  VERSION_PATTERN7 = /(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/;
19131
19294
  HOOK_COMMAND_PATTERN2 = /(^|[\\/\s"'])rtk(\.exe)?([\s"']|$)/i;
19132
19295
  PLUGIN_MODULE_PATTERN3 = /(^|[\\/])rtk\.(ts|js|mjs|cjs|mts|cts)$/i;
@@ -21806,7 +21969,7 @@ var init_version_compatibility = __esm({
21806
21969
  GITNEXUS2 = providerId("gitnexus");
21807
21970
  HEADROOM3 = providerId("headroom");
21808
21971
  PACKAGE_UPDATE_BASELINES = /* @__PURE__ */ new Map([
21809
- [RTK3, { minimum: "0.44.0", maximum: "0.50.0" }],
21972
+ [RTK3, { minimum: "0.44.0", maximum: "0.51.0" }],
21810
21973
  [HARNESSTRIM3, { minimum: "0.0.5", maximum: "0.3.1" }],
21811
21974
  [
21812
21975
  MCPTOON2,
@@ -22453,6 +22616,8 @@ function parseArgv(argv2, plannedCommands = PLANNED_COMMANDS) {
22453
22616
  contextSnapshot: null,
22454
22617
  nativePolicy: false,
22455
22618
  agentSkill: false,
22619
+ agentRouting: false,
22620
+ disableAgentRouting: false,
22456
22621
  verbose: false,
22457
22622
  yes: false
22458
22623
  };
@@ -22491,6 +22656,10 @@ function parseArgv(argv2, plannedCommands = PLANNED_COMMANDS) {
22491
22656
  options.nativePolicy = true;
22492
22657
  if (name2 === "--agent-skill")
22493
22658
  options.agentSkill = true;
22659
+ if (name2 === "--agent-routing")
22660
+ options.agentRouting = true;
22661
+ if (name2 === "--disable-agent-routing")
22662
+ options.disableAgentRouting = true;
22494
22663
  if (name2 === "--verbose")
22495
22664
  options.verbose = true;
22496
22665
  continue;
@@ -22727,6 +22896,14 @@ function parseArgv(argv2, plannedCommands = PLANNED_COMMANDS) {
22727
22896
  }));
22728
22897
  return usageError(json, diagnostics);
22729
22898
  }
22899
+ if (options.agentRouting && options.disableAgentRouting) {
22900
+ diagnostics.push(diagnostic({
22901
+ severity: "error",
22902
+ code: "conflicting-prompt-routing-flags",
22903
+ message: "--agent-routing and --disable-agent-routing cannot be used together",
22904
+ remediation: "Choose one prompt-routing state to plan"
22905
+ }));
22906
+ }
22730
22907
  if (!isAvailableCommand(command)) {
22731
22908
  const planned = plannedCommands.includes(command);
22732
22909
  diagnostics.push(planned ? diagnostic({
@@ -22796,7 +22973,557 @@ var init_argv = __esm({
22796
22973
  "--tasks-left",
22797
22974
  "--context-snapshot"
22798
22975
  ]);
22799
- BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["--json", "--native-policy", "--agent-skill", "--verbose", "--yes"]);
22976
+ BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
22977
+ "--json",
22978
+ "--native-policy",
22979
+ "--agent-skill",
22980
+ "--agent-routing",
22981
+ "--disable-agent-routing",
22982
+ "--verbose",
22983
+ "--yes"
22984
+ ]);
22985
+ }
22986
+ });
22987
+
22988
+ // apps/cli/dist/src/prompt-router.js
22989
+ function isHarness(value3) {
22990
+ return value3 === "claude" || value3 === "codex";
22991
+ }
22992
+ function expectedVersions(harness) {
22993
+ return harness === "codex" ? ["0.159.0", "0.160.0"] : ["2.1.274", "2.1.288"];
22994
+ }
22995
+ function configTarget(input) {
22996
+ if (!isHarness(input.harness) || input.home === null)
22997
+ return null;
22998
+ const adapter = findHarnessAdapter(harnessId(input.harness));
22999
+ const declaration = adapter?.manifest.configFiles.find((file) => file.scope === "user" && file.parser === "json" && file.interceptionPoints?.includes("user-prompt-submit") === true);
23000
+ if (declaration === void 0 || adapter === null)
23001
+ return null;
23002
+ const fileContext = {
23003
+ fs: input.fs,
23004
+ runner: input.runner,
23005
+ facts: input.facts,
23006
+ paths: { ...input.paths, home: input.home },
23007
+ projectRoot: input.projectRoot
23008
+ };
23009
+ return {
23010
+ harness: input.harness,
23011
+ path: resolveConfigPath(declaration, fileContext),
23012
+ version: input.version,
23013
+ fileContext
23014
+ };
23015
+ }
23016
+ function hookEntries(harness) {
23017
+ return nativePromptRoutingHookEntries(harnessId(harness), "token-harness");
23018
+ }
23019
+ function asRecord(value3) {
23020
+ return typeof value3 === "object" && value3 !== null && !Array.isArray(value3) ? value3 : null;
23021
+ }
23022
+ function parseHookDocument(text3) {
23023
+ let decoded;
23024
+ try {
23025
+ decoded = JSON.parse(text3);
23026
+ } catch {
23027
+ return { ok: false, reason: "The hook settings file is malformed JSON or contains comments." };
23028
+ }
23029
+ const root = asRecord(decoded);
23030
+ if (root === null)
23031
+ return { ok: false, reason: "The hook settings root must be a JSON object." };
23032
+ const hooksValue = root["hooks"];
23033
+ if (hooksValue === void 0)
23034
+ return { ok: true, hooks: {} };
23035
+ const hooks = asRecord(hooksValue);
23036
+ if (hooks === null)
23037
+ return { ok: false, reason: "The settings hooks property must be an object." };
23038
+ for (const { eventName } of hookEntries("codex")) {
23039
+ const entries = hooks[eventName];
23040
+ if (entries !== void 0 && !Array.isArray(entries))
23041
+ return { ok: false, reason: `The ${eventName} hook property must be an array.` };
23042
+ }
23043
+ return { ok: true, hooks };
23044
+ }
23045
+ function containsRouterCommand(value3, harness) {
23046
+ const row2 = asRecord(value3);
23047
+ const hooks = row2?.["hooks"];
23048
+ if (!Array.isArray(hooks))
23049
+ return false;
23050
+ return hooks.some((hook) => {
23051
+ const handler = asRecord(hook);
23052
+ if (handler === null)
23053
+ return false;
23054
+ if (harness === "codex")
23055
+ return [handler["command"], handler["commandWindows"]].some((command) => typeof command === "string" && command.includes(ROUTE_MARKER));
23056
+ const args = handler["args"];
23057
+ return handler["command"] === "token-harness" && Array.isArray(args) && args[0] === ROUTE_MARKER;
23058
+ });
23059
+ }
23060
+ function configHasExactRouter(hooks, harness) {
23061
+ let exactCount = 0;
23062
+ let routeCount = 0;
23063
+ for (const expected of hookEntries(harness)) {
23064
+ const live = hooks[expected.eventName];
23065
+ const entries = Array.isArray(live) ? live : [];
23066
+ const routeEntries = entries.filter((entry) => containsRouterCommand(entry, harness));
23067
+ routeCount += routeEntries.length;
23068
+ if (routeEntries.some((entry) => jsonValueDigest(entry) === jsonValueDigest(expected.value)))
23069
+ exactCount += 1;
23070
+ }
23071
+ return {
23072
+ complete: exactCount === hookEntries(harness).length,
23073
+ partial: routeCount > 0 && exactCount !== hookEntries(harness).length,
23074
+ conflict: routeCount > exactCount
23075
+ };
23076
+ }
23077
+ function routerOwnedArtifacts(journals, path, harness) {
23078
+ const expected = hookEntries(harness);
23079
+ for (const journal of journals) {
23080
+ const disabledHere = journal.entries.some((entry) => entry.actionId.startsWith(`native-prompt-routing:${harness}:disable:`) && entry.snapshots.some((snapshot) => snapshot.path === path));
23081
+ if (disabledHere && journal.outcome === "committed")
23082
+ return [];
23083
+ const relevant = journal.ownership.filter((artifact) => artifact.kind === "owned-json-entry" && artifact.path === path && artifact.placement === "array-element" && expected.some((entry) => artifact.pointer === `hooks.${entry.eventName}` && artifact.valueDigest === jsonValueDigest(entry.value)));
23084
+ if (relevant.length > 0)
23085
+ return journal.outcome === "committed" ? relevant : [];
23086
+ }
23087
+ return [];
23088
+ }
23089
+ async function journalsFor(input) {
23090
+ if (input.stateRoot === null)
23091
+ return [];
23092
+ const journalRoot = input.fs.join(input.stateRoot, "journals");
23093
+ if ((await input.fs.stat(journalRoot))?.kind !== "directory")
23094
+ return [];
23095
+ return new FileJournalStore({
23096
+ fs: input.fs,
23097
+ journalRoot,
23098
+ backupRoot: input.fs.join(input.stateRoot, "backups")
23099
+ }).list();
23100
+ }
23101
+ function actionId(harness, intent, eventName) {
23102
+ return `native-prompt-routing:${harness}:${intent}:${eventName}`;
23103
+ }
23104
+ async function planNativePromptRoutingInstall(input) {
23105
+ const diagnostics = [];
23106
+ const target = configTarget(input);
23107
+ if (target === null) {
23108
+ diagnostics.push(diagnostic({
23109
+ severity: "warning",
23110
+ code: "prompt-routing-target-unavailable",
23111
+ subject: input.harness,
23112
+ message: "No supported user-scope native prompt hook target is available",
23113
+ remediation: "Resolve the user home and harness installation, then refresh Token Harness"
23114
+ }));
23115
+ return { target: null, actions: [], diagnostics };
23116
+ }
23117
+ if (!expectedVersions(target.harness).includes(target.version ?? "")) {
23118
+ diagnostics.push(diagnostic({
23119
+ severity: "warning",
23120
+ code: "prompt-routing-version-unverified",
23121
+ subject: target.harness,
23122
+ message: `Native prompt routing has no hook fixture for ${target.harness} ${target.version ?? "unknown"}`,
23123
+ path: target.path,
23124
+ remediation: "Refresh Token Harness after the installed harness hook schema is fixture-tested"
23125
+ }));
23126
+ return { target: target.path, actions: [], diagnostics };
23127
+ }
23128
+ const runtimeCheck = await input.runner.run({
23129
+ executable: "token-harness",
23130
+ args: ["__internal-prompt-router", target.harness, "--check"],
23131
+ cwd: input.projectRoot,
23132
+ timeoutMs: 3e3,
23133
+ maxOutputBytes: 256
23134
+ });
23135
+ if (runtimeCheck.failure !== null || runtimeCheck.exitCode !== 0 || runtimeCheck.stdout.trim() !== PROMPT_ROUTER_CHECK_MARKER) {
23136
+ diagnostics.push(diagnostic({
23137
+ severity: "error",
23138
+ code: "prompt-routing-runtime-unavailable",
23139
+ subject: target.harness,
23140
+ message: "The Token Harness executable found on PATH cannot serve the native prompt hook",
23141
+ path: target.path,
23142
+ remediation: "Install or update Token Harness so the same executable is available to the coding agent, then refresh and plan again"
23143
+ }));
23144
+ return { target: target.path, actions: [], diagnostics };
23145
+ }
23146
+ const stat3 = await input.fs.stat(target.path);
23147
+ if (stat3 !== null && stat3.kind !== "file") {
23148
+ diagnostics.push(diagnostic({
23149
+ severity: "error",
23150
+ code: "prompt-routing-target-not-file",
23151
+ subject: target.harness,
23152
+ message: "A non-file occupies the native hook settings path",
23153
+ path: target.path,
23154
+ remediation: "Move the conflicting path and refresh Token Harness"
23155
+ }));
23156
+ return { target: target.path, actions: [], diagnostics };
23157
+ }
23158
+ let hooks = {};
23159
+ if (stat3 !== null) {
23160
+ const parsed = parseHookDocument(DECODER4.decode(await input.fs.readFile(target.path)));
23161
+ if (!parsed.ok) {
23162
+ diagnostics.push(diagnostic({
23163
+ severity: "error",
23164
+ code: "prompt-routing-settings-unmergeable",
23165
+ subject: target.harness,
23166
+ message: parsed.reason,
23167
+ path: target.path,
23168
+ remediation: "Repair the JSON settings file or configure native prompt routing manually"
23169
+ }));
23170
+ return { target: target.path, actions: [], diagnostics };
23171
+ }
23172
+ hooks = parsed.hooks;
23173
+ }
23174
+ const existing = configHasExactRouter(hooks, target.harness);
23175
+ if (existing.complete) {
23176
+ diagnostics.push(diagnostic({
23177
+ severity: "info",
23178
+ code: "prompt-routing-already-configured",
23179
+ subject: target.harness,
23180
+ message: "Native prompt routing hooks are already present; no settings are changed",
23181
+ path: target.path,
23182
+ remediation: null
23183
+ }));
23184
+ return { target: target.path, actions: [], diagnostics };
23185
+ }
23186
+ if (existing.partial || existing.conflict) {
23187
+ diagnostics.push(diagnostic({
23188
+ severity: "error",
23189
+ code: "prompt-routing-existing-hook-conflict",
23190
+ subject: target.harness,
23191
+ message: "A partial or modified Token Harness prompt hook already exists and was left untouched",
23192
+ path: target.path,
23193
+ remediation: "Review the existing native routing entries before planning another change"
23194
+ }));
23195
+ return { target: target.path, actions: [], diagnostics };
23196
+ }
23197
+ const entries = hookEntries(target.harness);
23198
+ const action = {
23199
+ kind: "merge-json",
23200
+ id: actionId(target.harness, "enable", "all"),
23201
+ riskClass: "reversible",
23202
+ requiresNetwork: false,
23203
+ requiresElevation: false,
23204
+ affectedPaths: [target.path],
23205
+ affectedProcesses: [target.harness],
23206
+ preconditions: [
23207
+ "the harness hook settings remain absent or valid JSON",
23208
+ "no Token Harness native prompt-routing hooks are already present"
23209
+ ],
23210
+ postconditions: entries.map((entry) => `${entry.eventName} has one Token Harness-owned hook`),
23211
+ rollbackData: "file-snapshot",
23212
+ explanation: `Enable automatic native prompt routing for ${target.harness}` + (target.harness === "codex" ? "; manually enable and trust this hook in Codex after applying" : "; start a new Claude Code session after applying"),
23213
+ path: target.path,
23214
+ ownedPointers: entries.map((entry) => `hooks.${entry.eventName}`),
23215
+ operations: entries.map((entry) => ({
23216
+ kind: "append",
23217
+ pointer: `hooks.${entry.eventName}`,
23218
+ value: entry.value,
23219
+ expectedValueDigest: null
23220
+ })),
23221
+ createIfMissing: true
23222
+ };
23223
+ return { target: target.path, actions: [action], diagnostics };
23224
+ }
23225
+ async function planNativePromptRoutingRemoval(input) {
23226
+ const diagnostics = [];
23227
+ const target = configTarget(input);
23228
+ if (target === null || input.stateRoot === null) {
23229
+ diagnostics.push(diagnostic({
23230
+ severity: "warning",
23231
+ code: "prompt-routing-removal-unavailable",
23232
+ subject: input.harness,
23233
+ message: "The owned native prompt-routing configuration could not be located safely",
23234
+ remediation: "Refresh Token Harness from the signed-in user environment"
23235
+ }));
23236
+ return { target: target?.path ?? null, actions: [], diagnostics };
23237
+ }
23238
+ const expected = hookEntries(target.harness);
23239
+ const journals = await journalsFor({ fs: input.fs, stateRoot: input.stateRoot });
23240
+ const artifacts = routerOwnedArtifacts(journals, target.path, target.harness);
23241
+ const actions = expected.flatMap((entry) => {
23242
+ const pointer = `hooks.${entry.eventName}`;
23243
+ const targetArtifact = artifacts.find((artifact) => artifact.kind === "owned-json-entry" && artifact.pointer === pointer && artifact.valueDigest === jsonValueDigest(entry.value));
23244
+ if (targetArtifact === void 0)
23245
+ return [];
23246
+ const reverses = actionId(target.harness, "enable", "all");
23247
+ return [
23248
+ {
23249
+ kind: "remove-owned-change",
23250
+ id: actionId(target.harness, "disable", entry.eventName),
23251
+ riskClass: "reversible",
23252
+ requiresNetwork: false,
23253
+ requiresElevation: false,
23254
+ affectedPaths: [target.path],
23255
+ affectedProcesses: [target.harness],
23256
+ preconditions: [`${entry.eventName} still contains the exact Token Harness-owned hook`],
23257
+ postconditions: [`${entry.eventName} no longer contains the owned prompt-routing hook`],
23258
+ rollbackData: "file-snapshot",
23259
+ explanation: `Disable automatic native prompt routing for ${target.harness}`,
23260
+ path: target.path,
23261
+ reverses,
23262
+ target: targetArtifact
23263
+ }
23264
+ ];
23265
+ });
23266
+ if (actions.length === 0)
23267
+ diagnostics.push(diagnostic({
23268
+ severity: "info",
23269
+ code: "prompt-routing-not-owned",
23270
+ subject: target.harness,
23271
+ message: "Token Harness owns no native prompt-routing hooks here, so nothing is removed",
23272
+ path: target.path,
23273
+ remediation: null
23274
+ }));
23275
+ return { target: target.path, actions, diagnostics };
23276
+ }
23277
+ async function readEvents(input) {
23278
+ if (input.stateRoot === null)
23279
+ return { state: "unavailable", events: [] };
23280
+ const directory = input.fs.join(input.stateRoot, "prompt-routing");
23281
+ if ((await input.fs.stat(directory))?.kind !== "directory")
23282
+ return { state: "available", events: [] };
23283
+ const files = (await input.fs.readDirectory(directory)).filter((name2) => /^events-\d{4}-\d{2}\.jsonl$/.test(name2)).sort().reverse();
23284
+ const events = [];
23285
+ let scannedBytes = 0;
23286
+ try {
23287
+ for (const file of files) {
23288
+ const path = input.fs.join(directory, file);
23289
+ const stat3 = await input.fs.stat(path);
23290
+ if (stat3 === null || stat3.kind !== "file")
23291
+ continue;
23292
+ if (stat3.byteLength > MAX_EVENT_FILE_BYTES || scannedBytes + stat3.byteLength > MAX_EVENT_SCAN_BYTES)
23293
+ return { state: "limited", events };
23294
+ const bytes = await input.fs.readFile(path);
23295
+ if (bytes.byteLength !== stat3.byteLength)
23296
+ return { state: "limited", events };
23297
+ scannedBytes += bytes.byteLength;
23298
+ const text3 = DECODER4.decode(bytes);
23299
+ for (const line of text3.split("\n")) {
23300
+ if (line === "")
23301
+ continue;
23302
+ try {
23303
+ const value3 = JSON.parse(line);
23304
+ if (!isPromptRouterEvent(value3))
23305
+ continue;
23306
+ if (input.harness !== void 0 && value3.harness !== input.harness)
23307
+ continue;
23308
+ if (input.projectId !== void 0 && value3.projectId !== input.projectId)
23309
+ continue;
23310
+ if (input.since !== void 0 && value3.timestamp < input.since)
23311
+ continue;
23312
+ events.push(value3);
23313
+ } catch {
23314
+ }
23315
+ }
23316
+ if (input.since !== void 0 && file.slice(7, 14) < input.since.slice(0, 7))
23317
+ break;
23318
+ }
23319
+ return { state: "available", events };
23320
+ } catch {
23321
+ return { state: "unavailable", events: [] };
23322
+ }
23323
+ }
23324
+ function isPromptRouterEvent(value3) {
23325
+ const row2 = asRecord(value3);
23326
+ return row2?.["schemaVersion"] === 1 && typeof row2["timestamp"] === "string" && Number.isFinite(Date.parse(row2["timestamp"])) && (row2["harness"] === "claude" || row2["harness"] === "codex") && typeof row2["projectId"] === "string" && ["prompt-submit", "subagent-start", "subagent-stop"].includes(String(row2["type"])) && (row2["model"] === null || typeof row2["model"] === "string" && row2["model"].length <= 80) && (row2["agentType"] === null || typeof row2["agentType"] === "string" && row2["agentType"].length <= 80);
23327
+ }
23328
+ async function recordNativePromptRoutingHook(input) {
23329
+ if (input.fs === null || input.stateRoot === null || input.projectId === null)
23330
+ return;
23331
+ let payload = null;
23332
+ if (input.event !== "prompt-submit" && input.hookInput !== null) {
23333
+ try {
23334
+ payload = asRecord(JSON.parse(input.hookInput));
23335
+ } catch {
23336
+ payload = null;
23337
+ }
23338
+ }
23339
+ const agentTypeRaw = payload?.["agent_type"];
23340
+ const agentType = input.event !== "prompt-submit" && typeof agentTypeRaw === "string" && agentTypeRaw.length <= 80 ? agentTypeRaw : null;
23341
+ const timestamp = new Date(input.now).toISOString();
23342
+ const event = {
23343
+ schemaVersion: 1,
23344
+ timestamp,
23345
+ harness: input.harness,
23346
+ projectId: input.projectId,
23347
+ type: input.event,
23348
+ // Hook payload model fields can identify the root session, not the spawned child. Until an
23349
+ // adapter has a versioned child-model field, keep actual worker identity unknown.
23350
+ model: null,
23351
+ agentType
23352
+ };
23353
+ const partition = `events-${timestamp.slice(0, 7)}.jsonl`;
23354
+ const directory = input.fs.join(input.stateRoot, "prompt-routing");
23355
+ await input.fs.createDirectory(directory);
23356
+ await input.fs.appendFile(input.fs.join(directory, partition), UTF84.encode(`${JSON.stringify(event)}
23357
+ `));
23358
+ }
23359
+ function summarizeEvents(events) {
23360
+ return {
23361
+ promptSubmissions: events.filter((event) => event.type === "prompt-submit").length,
23362
+ subagentsStarted: events.filter((event) => event.type === "subagent-start").length,
23363
+ subagentsStopped: events.filter((event) => event.type === "subagent-stop").length,
23364
+ reportedModels: [
23365
+ ...new Set(events.filter((event) => event.type === "subagent-start" || event.type === "subagent-stop").flatMap((event) => event.model === null ? [] : [event.model]))
23366
+ ],
23367
+ lastObservedAt: events.map((event) => event.timestamp).sort().at(-1) ?? null
23368
+ };
23369
+ }
23370
+ async function observeNativePromptRouting(input) {
23371
+ const harness = isHarness(input.harness) ? input.harness : "codex";
23372
+ const base = {
23373
+ harness,
23374
+ state: "unavailable",
23375
+ label: "Not verified",
23376
+ detail: "Native prompt routing could not be checked on this harness.",
23377
+ configPath: null,
23378
+ configured: null,
23379
+ promptSubmissions: 0,
23380
+ subagentsStarted: 0,
23381
+ subagentsStopped: 0,
23382
+ reportedModels: [],
23383
+ lastObservedAt: null,
23384
+ receiptState: "unavailable"
23385
+ };
23386
+ const target = configTarget({ ...input, harness: input.harness });
23387
+ if (target === null)
23388
+ return base;
23389
+ const eventResult = await readEvents({
23390
+ fs: input.fs,
23391
+ stateRoot: input.stateRoot,
23392
+ harness,
23393
+ ...input.projectId === null ? {} : { projectId: input.projectId },
23394
+ since: new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3).toISOString()
23395
+ });
23396
+ const summary = summarizeEvents(eventResult.events);
23397
+ const stat3 = await input.fs.stat(target.path);
23398
+ if (stat3 === null) {
23399
+ return {
23400
+ ...base,
23401
+ state: "absent",
23402
+ label: "Disabled",
23403
+ detail: "Automatic routing is off. No Token Harness native prompt hook is installed.",
23404
+ configPath: target.path,
23405
+ configured: false,
23406
+ ...summary,
23407
+ receiptState: eventResult.state
23408
+ };
23409
+ }
23410
+ if (stat3.kind !== "file")
23411
+ return {
23412
+ ...base,
23413
+ state: "conflict",
23414
+ label: "Path conflict",
23415
+ detail: "A non-file occupies the native hook settings path.",
23416
+ configPath: target.path,
23417
+ ...summary,
23418
+ receiptState: eventResult.state
23419
+ };
23420
+ let hooks;
23421
+ try {
23422
+ const parsed = parseHookDocument(DECODER4.decode(await input.fs.readFile(target.path)));
23423
+ if (!parsed.ok)
23424
+ return {
23425
+ ...base,
23426
+ state: "conflict",
23427
+ label: "Settings need review",
23428
+ detail: parsed.reason,
23429
+ configPath: target.path,
23430
+ ...summary,
23431
+ receiptState: eventResult.state
23432
+ };
23433
+ hooks = parsed.hooks;
23434
+ } catch {
23435
+ return {
23436
+ ...base,
23437
+ state: "unavailable",
23438
+ label: "Not verified",
23439
+ detail: "The hook settings file could not be read safely.",
23440
+ configPath: target.path,
23441
+ ...summary,
23442
+ receiptState: eventResult.state
23443
+ };
23444
+ }
23445
+ const match = configHasExactRouter(hooks, harness);
23446
+ if (match.conflict || match.partial) {
23447
+ return {
23448
+ ...base,
23449
+ state: "conflict",
23450
+ label: "Custom hook needs review",
23451
+ detail: "A partial or edited Token Harness prompt-routing hook was found and was not changed.",
23452
+ configPath: target.path,
23453
+ ...summary,
23454
+ receiptState: eventResult.state
23455
+ };
23456
+ }
23457
+ if (!match.complete) {
23458
+ return {
23459
+ ...base,
23460
+ state: "absent",
23461
+ label: "Disabled",
23462
+ detail: "Automatic routing is off. No Token Harness native prompt hook is installed.",
23463
+ configPath: target.path,
23464
+ configured: false,
23465
+ ...summary,
23466
+ receiptState: eventResult.state
23467
+ };
23468
+ }
23469
+ const artifacts = routerOwnedArtifacts(await journalsFor(input), target.path, harness);
23470
+ const state = artifacts.length === hookEntries(harness).length ? "managed" : "external";
23471
+ const hasRuntimeReceipt = summary.promptSubmissions > 0;
23472
+ const label = state === "external" ? hasRuntimeReceipt ? "Runtime observed \xB7 external" : "Enabled externally" : hasRuntimeReceipt ? "Runtime observed" : harness === "codex" ? "Configured \xB7 trust or runtime pending" : "Configured \xB7 runtime pending";
23473
+ const detail2 = summary.promptSubmissions > 0 ? `${String(summary.promptSubmissions)} prompt hook(s), ${String(summary.subagentsStarted)} native agent start(s), ${String(summary.subagentsStopped)} stop(s) observed in this project during the last 30 days.${eventResult.state === "limited" ? " Counts are partial because the local receipt scan reached its safety limit." : eventResult.state === "unavailable" ? " Local runtime receipts could not be read." : ""}` : harness === "codex" ? "The hook is configured. Review and trust it in Codex with /hooks, then submit a prompt to produce a runtime receipt." : "The hook is configured. Start a new Claude Code session, submit a prompt, and Token Harness will show the runtime receipt.";
23474
+ return {
23475
+ ...base,
23476
+ state,
23477
+ label,
23478
+ detail: detail2,
23479
+ configPath: target.path,
23480
+ configured: true,
23481
+ ...summary,
23482
+ receiptState: eventResult.state
23483
+ };
23484
+ }
23485
+ async function nativeRoutingObservationForBenchmark(input) {
23486
+ const observed = await observeNativePromptRouting({
23487
+ ...input,
23488
+ projectId: input.projectId
23489
+ });
23490
+ const configured = observed.configured;
23491
+ if (input.startedAt === void 0)
23492
+ return {
23493
+ configured,
23494
+ promptSubmissions: 0,
23495
+ subagentsStarted: 0,
23496
+ subagentsStopped: 0,
23497
+ reportedModels: []
23498
+ };
23499
+ const found = await readEvents({
23500
+ fs: input.fs,
23501
+ stateRoot: input.stateRoot,
23502
+ harness: observed.harness,
23503
+ projectId: input.projectId,
23504
+ since: input.startedAt
23505
+ });
23506
+ const summary = summarizeEvents(found.events);
23507
+ return {
23508
+ configured,
23509
+ promptSubmissions: summary.promptSubmissions,
23510
+ subagentsStarted: summary.subagentsStarted,
23511
+ subagentsStopped: summary.subagentsStopped,
23512
+ reportedModels: summary.reportedModels
23513
+ };
23514
+ }
23515
+ var UTF84, DECODER4, ROUTE_MARKER, MAX_EVENT_FILE_BYTES, MAX_EVENT_SCAN_BYTES, PROMPT_ROUTER_CHECK_MARKER;
23516
+ var init_prompt_router = __esm({
23517
+ "apps/cli/dist/src/prompt-router.js"() {
23518
+ "use strict";
23519
+ init_src();
23520
+ init_src3();
23521
+ UTF84 = new TextEncoder();
23522
+ DECODER4 = new TextDecoder("utf-8", { fatal: true });
23523
+ ROUTE_MARKER = "__internal-prompt-router";
23524
+ MAX_EVENT_FILE_BYTES = 4 * 1024 * 1024;
23525
+ MAX_EVENT_SCAN_BYTES = 16 * 1024 * 1024;
23526
+ PROMPT_ROUTER_CHECK_MARKER = "token-harness-prompt-router-v1";
22800
23527
  }
22801
23528
  });
22802
23529
 
@@ -24065,7 +24792,7 @@ var init_agent_skill = __esm({
24065
24792
  "apps/cli/dist/src/agent-skill.js"() {
24066
24793
  "use strict";
24067
24794
  init_src();
24068
- TOKEN_HARNESS_AGENT_SKILL = "---\nname: token-harness\ndescription: Optimizes local Claude Code or Codex work against observed subscription allowance, context pressure, quality floors, and project-local benchmark evidence using the Token Harness CLI. Use when the user asks to conserve or maximize coding-agent allowance, choose reasoning/model/verbosity deliberately, check whether a task fits current quota, or explicitly asks to use Token Harness.\n---\n\n# Token Harness\n\nUse Token Harness as a local deterministic policy engine. Do not reproduce its quota math or invent provider conversions yourself.\n\n## Default workflow\n\n1. Confirm `token-harness --version` works. If it is missing, do not install it silently. If the user asked to install or set up Token Harness, follow that request; otherwise explain that the local CLI is required.\n2. Identify the harness you are currently running as: `claude` for Claude Code or `codex` for Codex. Do not guess from repository files.\n3. Classify the current task conservatively:\n - `mechanical`: formatting, rename, lookup, simple edits, deterministic scaffolding.\n - `standard`: ordinary implementation, tests, focused bug fixes.\n - `hard`: multi-file reasoning, ambiguous failures, migrations, difficult reviews.\n - `critical`: architecture, security-sensitive work, releases, or high-regression-risk changes.\n If uncertain between two classes, use the higher class.\n4. For a substantial task, or whenever the user asks about allowance/efficiency, run:\n\n `token-harness optimize --harness <claude|codex> --task <class> --profile balanced --json`\n\n5. Treat the JSON result as evidence, not as permission to mutate configuration. Prefer recommendations that reduce avoidable context or session overhead before lowering a quality floor.\n6. Continue with the user's task. Mention Token Harness only when it materially changes the plan, recommends a user-visible action, or lacks enough evidence.\n\nDo not run Token Harness before every trivial tool call. One observation at a meaningful task boundary is normally enough; re-observe when the task class changes materially, after a quota reset, after a substantial session/context change, or when the user asks.\n\n## Active context evidence\n\nWhen the current conversation or your own tool results directly establish useful task-state evidence, you may pass a short-lived `--context-snapshot` file to `optimize`. This metadata is for the CLI; never ask the user to write or understand the JSON. Skip the snapshot when no actionable evidence is directly observable or a temporary file cannot be safely created and removed.\n\n- Set task boundary, validation and quality only from explicit task state and checks you observed. Use `unknown` when those facts are missing or ambiguous.\n- Mark material superseded or condensable only when its current state is directly clear. Include `byteLength` only when tooling measured the exact local bytes; otherwise use `null`. Never estimate bytes from tokens.\n- Set reducer attribution only when directly known; otherwise use `unknown`. Do not include transcript text, prompts, tool payloads, source text, paths, MCP names or schemas.\n- Add a checkpoint byte ceiling only when you will use that same ceiling for the existing bounded `token-harness handoff` command. Omit it when no artifact budget is configured.\n- Create the metadata file temporarily, run `optimize`, then remove it. Treat the decision as advice; do not mask, summarize, compact or start a session on the user's behalf.\n\n## Explicit workload\n\nOnly pass `--tasks-left N` when the remaining accepted-task count is explicit from the user or an explicit task list already in the conversation. Never infer it from token history, source files, GitHub issues, or a guessed backlog. When it is explicit, add it to the same advisory call:\n\n`token-harness optimize --harness <claude|codex> --task <class> --profile balanced --tasks-left <N> --json`\n\nFor multiple independent new tasks whose explicit list can be classified by task class, Token Harness can compare Claude and Codex with:\n\n`token-harness schedule --current <current> --candidate <other> --workload mechanical=N,standard=N,hard=N,critical=N --json`\n\nOmit zero-count classes. This is for queued new work, not an in-progress handoff. Never switch harnesses automatically from this result.\n\n## Persistent native changes\n\n`optimize` is advisory. If it recommends a persistent model/reasoning/verbosity change and the user wants it applied:\n\n1. Build a reviewed plan with `token-harness plan --harness <claude|codex> --native-policy --task <class> --profile balanced --json`.\n2. Summarize the exact proposed change, scope, and any limitations to the user.\n3. Apply only after the user explicitly approves the proposed mutation. Use the returned plan id with `token-harness apply --plan <id> --yes`.\n4. Do not treat a persisted preference as a live change to an already-running session. Follow the plan/result instructions about when it takes effect.\n\nNever silently change authentication, billing, provider, model routing, hooks, trust, or purchase/redeem credits.\n\n## Evidence rules\n\n- Never equate local token counts with subscription quota.\n- Never compare raw Claude and Codex percentages as if they were the same currency.\n- Unknown allowance or benchmark evidence stays unknown.\n- Preserve task quality floors; do not lower effort merely because a cheaper setting exists.\n- Prefer project-local measured outcomes and backend quota deltas when Token Harness exposes them.\n- Do not add an MCP server or background model just to use this skill. The local CLI is the tool surface.\n";
24795
+ TOKEN_HARNESS_AGENT_SKILL = "---\nname: token-harness\ndescription: Optimizes local Claude Code or Codex work against observed subscription allowance, context pressure, quality floors, and project-local benchmark evidence using the Token Harness CLI. Guides native subagent model routing for substantial bounded coding tasks. Use for substantial coding work where native delegation may apply, or when the user asks about allowance, model/effort/verbosity choices, quota fit, or Token Harness.\n---\n\n# Token Harness\n\nUse Token Harness as a local deterministic policy engine. Do not reproduce its quota math or invent provider conversions yourself.\n\n## Automatic routing\n\nWhen enabled in the Token Harness dashboard, a native prompt hook supplies the routing policy on every submitted prompt. This works without invoking this skill or prefixing the prompt with a command. The hook asks the coding agent to delegate only eligible bounded work; it does not change the root model or prove which child model ran. Use this skill when the user asks for explicit quota-aware advice or a benchmark.\n\n## Default workflow\n\n1. Confirm `token-harness --version` works. If it is missing, do not install it silently. If the user asked to install or set up Token Harness, follow that request; otherwise explain that the local CLI is required.\n2. Identify the harness you are currently running as: `claude` for Claude Code or `codex` for Codex. Do not guess from repository files.\n3. Classify the current task conservatively:\n - `mechanical`: formatting, rename, lookup, simple edits, deterministic scaffolding.\n - `standard`: ordinary implementation, tests, focused bug fixes.\n - `hard`: multi-file reasoning, ambiguous failures, migrations, difficult reviews.\n - `critical`: architecture, security-sensitive work, releases, or high-regression-risk changes.\n If uncertain between two classes, use the higher class.\n4. For a substantial task, or whenever the user asks about allowance/efficiency, run:\n\n `token-harness optimize --harness <claude|codex> --task <class> --profile balanced --json`\n\n5. Treat the JSON result as evidence, not as permission to mutate configuration. Prefer recommendations that reduce avoidable context or session overhead before lowering a quality floor.\n6. Continue with the user's task. Mention Token Harness only when it materially changes the plan, recommends a user-visible action, or lacks enough evidence.\n\nDo not run Token Harness before every trivial tool call. One observation at a meaningful task boundary is normally enough; re-observe when the task class changes materially, after a quota reset, after a substantial session/context change, or when the user asks.\n\n## Active context evidence\n\nWhen the current conversation or your own tool results directly establish useful task-state evidence, you may pass a short-lived `--context-snapshot` file to `optimize`. This metadata is for the CLI; never ask the user to write or understand the JSON. Skip the snapshot when no actionable evidence is directly observable or a temporary file cannot be safely created and removed.\n\n- Set task boundary, validation and quality only from explicit task state and checks you observed. Use `unknown` when those facts are missing or ambiguous.\n- Mark material superseded or condensable only when its current state is directly clear. Include `byteLength` only when tooling measured the exact local bytes; otherwise use `null`. Never estimate bytes from tokens.\n- Set reducer attribution only when directly known; otherwise use `unknown`. Do not include transcript text, prompts, tool payloads, source text, paths, MCP names or schemas.\n- Add a checkpoint byte ceiling only when you will use that same ceiling for the existing bounded `token-harness handoff` command. Omit it when no artifact budget is configured.\n- Create the metadata file temporarily, run `optimize`, then remove it. Treat the decision as advice; do not mask, summarize, compact or start a session on the user's behalf.\n\n## Explicit workload\n\nOnly pass `--tasks-left N` when the remaining accepted-task count is explicit from the user or an explicit task list already in the conversation. Never infer it from token history, source files, GitHub issues, or a guessed backlog. When it is explicit, add it to the same advisory call:\n\n`token-harness optimize --harness <claude|codex> --task <class> --profile balanced --tasks-left <N> --json`\n\nFor multiple independent new tasks whose explicit list can be classified by task class, Token Harness can compare Claude and Codex with:\n\n`token-harness schedule --current <current> --candidate <other> --workload mechanical=N,standard=N,hard=N,critical=N --json`\n\nOmit zero-count classes. This is for queued new work, not an in-progress handoff. Never switch harnesses automatically from this result.\n\n## Native subagent model routing\n\nUse native subagents as the only model-routing surface. This routes delegated work; it never changes the model already selected for the root conversation. Keep Codex as the first supported path.\n\nFor Codex, when the task is substantial and contains a complete, bounded implementation unit that can be handed off without duplicating work, delegate that unit to one native subagent with `model: gpt-6-luna` if Luna is present in the current Codex model picker/catalog. Set the model explicitly in the native spawn request: when it is omitted, Codex inherits the root model and reasoning effort, so a generic delegation is not a cost-routed delegation. If a higher-priority instruction forbids specifying the child model, skip cost routing and continue with the root model. Keep the root model responsible for task framing, integration, and acceptance review. Do not run the same implementation in both agents. Use at most one cost-routed worker at a time.\n\nSkip routing for trivial tasks, tightly coupled or shared-write work, architecture/security/release decisions, work that needs the root model's full context or judgment throughout, when the user asks not to delegate, when the root model is Luna or cannot be identified, or when the requested model is not currently available. Do not substitute an unverified model ID or silently fall back to another harness. If no supported route is available, continue with the current root model.\n\nFor Claude Code, apply the same bounded-task rules only when Claude Code is already configured and authenticated and native subagents are available. Request the current native `haiku` alias for an eligible worker; do not configure Claude Code or authenticate on the user's behalf.\n\nTreat the selected child model as a routing request until Codex or Claude Code visibly reports the worker's actual model. A skill instruction is not runtime telemetry. Subagents add context and coordination overhead and can consume more total tokens than single-agent work; do not claim token, quota, or cost savings without paired, quality-gated usage evidence for the same harness and task class.\n\n## Persistent native changes\n\n`optimize` is advisory. If it recommends a persistent model/reasoning/verbosity change and the user wants it applied:\n\n1. Build a reviewed plan with `token-harness plan --harness <claude|codex> --native-policy --task <class> --profile balanced --json`.\n2. Summarize the exact proposed change, scope, and any limitations to the user.\n3. Apply only after the user explicitly approves the proposed mutation. Use the returned plan id with `token-harness apply --plan <id> --yes`.\n4. Do not treat a persisted preference as a live change to an already-running session. Follow the plan/result instructions about when it takes effect.\n\nNever silently change authentication, billing, provider, model routing, hooks, trust, or purchase/redeem credits.\n\n## Evidence rules\n\n- Never equate local token counts with subscription quota.\n- Never compare raw Claude and Codex percentages as if they were the same currency.\n- Unknown allowance or benchmark evidence stays unknown.\n- Preserve task quality floors; do not lower effort merely because a cheaper setting exists.\n- Prefer project-local measured outcomes and backend quota deltas when Token Harness exposes them.\n- Do not add an MCP server or background model just to use this skill. The local CLI is the tool surface.\n";
24069
24796
  ENCODER = new TextEncoder();
24070
24797
  SKILL_DIGEST = digestBytes(ENCODER.encode(TOKEN_HARNESS_AGENT_SKILL));
24071
24798
  TARGETS = {
@@ -26045,6 +26772,41 @@ async function computePlan(context) {
26045
26772
  }
26046
26773
  }
26047
26774
  }
26775
+ if (context.agentRouting === true || context.disableAgentRouting === true) {
26776
+ const harness = context.harness;
26777
+ if (harness !== harnessId("claude") && harness !== CODEX12) {
26778
+ diagnostics.push(diagnostic({
26779
+ severity: "warning",
26780
+ code: "prompt-routing-harness-required",
26781
+ subject: harness,
26782
+ message: "Automatic prompt routing requires an explicit Claude Code or Codex harness",
26783
+ remediation: "Choose the detected agent in the guided app, or pass --harness claude|codex"
26784
+ }));
26785
+ } else if (context.adapters === null) {
26786
+ diagnostics.push(diagnostic({
26787
+ severity: "warning",
26788
+ code: "prompt-routing-adapters-unavailable",
26789
+ subject: harness,
26790
+ message: "The native prompt hook could not be planned without filesystem adapters",
26791
+ remediation: "Refresh Token Harness from a supported local environment"
26792
+ }));
26793
+ } else {
26794
+ const input = {
26795
+ fs: context.adapters.fs,
26796
+ home: context.home,
26797
+ harness,
26798
+ version: versions.harnesses[harness] ?? null,
26799
+ runner: context.adapters.runner,
26800
+ facts: context.platform,
26801
+ paths: context.adapters.paths,
26802
+ projectRoot: context.projectRoot,
26803
+ stateRoot: context.stateRoot
26804
+ };
26805
+ const routingPlan = context.agentRouting ? await planNativePromptRoutingInstall(input) : await planNativePromptRoutingRemoval(input);
26806
+ actions.push(...routingPlan.actions);
26807
+ diagnostics.push(...routingPlan.diagnostics);
26808
+ }
26809
+ }
26048
26810
  if (context.nativePolicy === true && context.harness === harnessId("claude")) {
26049
26811
  if (context.taskClass === void 0 || context.taskClass === null) {
26050
26812
  diagnostics.push(diagnostic({
@@ -26087,6 +26849,14 @@ async function computePlan(context) {
26087
26849
  ],
26088
26850
  remediation: "Give each provider a distinct marker pair, or disable one of the providers for this instruction region"
26089
26851
  }));
26852
+ if (providerAdapters.length === 0 && context.provider !== providerId("none") && actions.length === 0) {
26853
+ diagnostics.push(diagnostic({
26854
+ severity: "info",
26855
+ code: "no-providers-registered",
26856
+ message: "No optimization provider is available for this operation",
26857
+ remediation: null
26858
+ }));
26859
+ }
26090
26860
  const conflicts = [...resolution.conflicts, ...markerConflicts];
26091
26861
  const report = {
26092
26862
  // RFC 0006 §Plan persistence: "a digest over the plan's normalized content, so identical
@@ -26135,14 +26905,6 @@ async function computePlan(context) {
26135
26905
  remediation: null
26136
26906
  }));
26137
26907
  }
26138
- if (providerAdapters.length === 0) {
26139
- diagnostics.push(diagnostic({
26140
- severity: "info",
26141
- code: "no-providers-registered",
26142
- message: "No provider adapters are registered in this build, so no plan has actions",
26143
- remediation: null
26144
- }));
26145
- }
26146
26908
  if (resolution.ownership.length > 0 && actions.length === 0 && blocked.length === 0) {
26147
26909
  diagnostics.push(diagnostic({
26148
26910
  severity: "info",
@@ -26227,6 +26989,7 @@ var init_plan2 = __esm({
26227
26989
  init_src3();
26228
26990
  init_src();
26229
26991
  init_agent_skill();
26992
+ init_prompt_router();
26230
26993
  init_apply();
26231
26994
  init_context_cost2();
26232
26995
  init_optimize();
@@ -26303,6 +27066,48 @@ async function verifyManagedIntegrationPostconditions(context, integrations) {
26303
27066
  }
26304
27067
  return diagnostics;
26305
27068
  }
27069
+ async function verifyNativePromptRoutingPostconditions(context, actions) {
27070
+ const routing = actions.filter((action) => action.id.startsWith("native-prompt-routing:"));
27071
+ if (routing.length === 0)
27072
+ return [];
27073
+ if (context.adapters === null || context.stateRoot === null || context.harness !== harnessId("claude") && context.harness !== harnessId("codex")) {
27074
+ return [
27075
+ diagnostic({
27076
+ severity: "error",
27077
+ code: "prompt-routing-postcondition-unavailable",
27078
+ subject: context.harness,
27079
+ message: "Native prompt-routing configuration could not be read after the change",
27080
+ remediation: "Keep the transaction rollback and review a fresh plan from the local agent environment"
27081
+ })
27082
+ ];
27083
+ }
27084
+ const observed = await observeNativePromptRouting({
27085
+ fs: context.adapters.fs,
27086
+ home: context.home,
27087
+ stateRoot: context.stateRoot,
27088
+ harness: context.harness,
27089
+ version: null,
27090
+ runner: context.adapters.runner,
27091
+ facts: context.platform,
27092
+ paths: context.adapters.paths,
27093
+ projectRoot: context.projectRoot,
27094
+ projectId: context.adapters.projectIdFor(context.projectRoot)
27095
+ });
27096
+ const shouldBeEnabled = routing.some((action) => action.id.includes(":enable:"));
27097
+ const satisfied = shouldBeEnabled ? observed.configured === true : observed.configured === false;
27098
+ if (satisfied)
27099
+ return [];
27100
+ return [
27101
+ diagnostic({
27102
+ severity: "error",
27103
+ code: "prompt-routing-postcondition-unmet",
27104
+ subject: context.harness,
27105
+ path: observed.configPath,
27106
+ message: `Native prompt-routing hooks were not observed in the requested state after the change: ${observed.label}`,
27107
+ remediation: "Review the hook settings and allow the transaction to restore its backup"
27108
+ })
27109
+ ];
27110
+ }
26306
27111
  function transactionIdFor(planId, at) {
26307
27112
  const digest = digestText(`${planId} ${at}`);
26308
27113
  return digest.slice(digest.indexOf(":") + 1, digest.indexOf(":") + 13);
@@ -26369,6 +27174,8 @@ async function runApply(context) {
26369
27174
  const diagnostics = [];
26370
27175
  let stored = null;
26371
27176
  let storedAgentSkill = false;
27177
+ let storedAgentRouting = false;
27178
+ let storedAgentRoutingRemoval = false;
26372
27179
  let planningContext = context;
26373
27180
  const rejectedReport = () => ({
26374
27181
  ...emptyReport3("rejected"),
@@ -26422,11 +27229,15 @@ async function runApply(context) {
26422
27229
  return finish3("rejected", EXIT_CODES["precondition-drift"], rejectedReport(), diagnostics);
26423
27230
  }
26424
27231
  storedAgentSkill = stored.actions.some((action) => action.id.startsWith("agent-skill:"));
27232
+ storedAgentRouting = stored.actions.some((action) => action.id.startsWith("native-prompt-routing:") && action.id.includes(":enable:"));
27233
+ storedAgentRoutingRemoval = stored.actions.some((action) => action.id.startsWith("native-prompt-routing:") && action.id.includes(":disable:"));
26425
27234
  planningContext = {
26426
27235
  ...context,
26427
27236
  harness: stored.harness,
26428
27237
  provider,
26429
- agentSkill: storedAgentSkill
27238
+ agentSkill: storedAgentSkill,
27239
+ agentRouting: storedAgentRouting,
27240
+ disableAgentRouting: storedAgentRoutingRemoval
26430
27241
  };
26431
27242
  } catch {
26432
27243
  diagnostics.push(diagnostic({
@@ -26450,6 +27261,16 @@ async function runApply(context) {
26450
27261
  }));
26451
27262
  return finish3("rejected", EXIT_CODES["precondition-drift"], rejectedReport(), diagnostics);
26452
27263
  }
27264
+ if (stored !== null && (storedAgentRouting || storedAgentRoutingRemoval) && computed.report.planId !== stored.planId) {
27265
+ diagnostics.push(diagnostic({
27266
+ severity: "error",
27267
+ code: "prompt-routing-plan-drift",
27268
+ subject: stored.harness,
27269
+ message: "The native prompt-routing target or ownership changed after the reviewed preview",
27270
+ remediation: "Review a fresh prompt-routing preview; nothing was written"
27271
+ }));
27272
+ return finish3("rejected", EXIT_CODES["precondition-drift"], rejectedReport(), diagnostics);
27273
+ }
26453
27274
  if (computed.blocked.length > 0 && computed.report.actions.length === 0) {
26454
27275
  return finish3("rejected", EXIT_CODES["unsupported-environment"], rejectedReport(), diagnostics);
26455
27276
  }
@@ -26553,7 +27374,10 @@ async function runApply(context) {
26553
27374
  // RFC 0004 §Process policy: an installer reaches the machine through the runner or not at all.
26554
27375
  runner: context.adapters.runner,
26555
27376
  now: context.now,
26556
- verifyPostconditions: async () => verifyManagedIntegrationPostconditions(context, computed.managedIntegrations)
27377
+ verifyPostconditions: async () => [
27378
+ ...await verifyManagedIntegrationPostconditions(context, computed.managedIntegrations),
27379
+ ...await verifyNativePromptRoutingPostconditions(context, actions)
27380
+ ]
26557
27381
  });
26558
27382
  diagnostics.push(...transaction.diagnostics);
26559
27383
  const report = {
@@ -26589,6 +27413,7 @@ var init_apply = __esm({
26589
27413
  "use strict";
26590
27414
  init_src();
26591
27415
  init_src3();
27416
+ init_prompt_router();
26592
27417
  init_candidate_lifecycle();
26593
27418
  init_plan2();
26594
27419
  init_snapshot_safety();
@@ -26888,6 +27713,18 @@ async function runBenchmarkStart(context) {
26888
27713
  runContext(observedContext),
26889
27714
  runHistory({ ...observedContext, since: "1d", until: null })
26890
27715
  ]);
27716
+ const nativeRoutingAtStart = context.adapters === null ? null : await nativeRoutingObservationForBenchmark({
27717
+ fs: context.adapters.fs,
27718
+ home: context.home,
27719
+ stateRoot: context.stateRoot,
27720
+ harness,
27721
+ version: null,
27722
+ runner: context.adapters.runner,
27723
+ facts: context.platform,
27724
+ paths: context.adapters.paths,
27725
+ projectRoot: context.projectRoot,
27726
+ projectId
27727
+ });
26891
27728
  const budget = budgetResult.data?.harnesses.find((item) => item.harnessId === harness);
26892
27729
  const contextObservation = contextResult.data?.harnesses.find((item) => item.harnessId === harness);
26893
27730
  const policy = benchmarkPolicySnapshot(contextObservation);
@@ -26906,7 +27743,8 @@ async function runBenchmarkStart(context) {
26906
27743
  startedAt,
26907
27744
  usageBefore: budget?.windows ?? [],
26908
27745
  contextAtStart,
26909
- localSessionsBefore
27746
+ localSessionsBefore,
27747
+ nativeRoutingAtStart
26910
27748
  };
26911
27749
  if (!await writeJson(context, paths.capturePath, capture)) {
26912
27750
  return commandResult({
@@ -27091,6 +27929,19 @@ async function runBenchmarkFinish(context) {
27091
27929
  runContext(completedContext),
27092
27930
  runHistory({ ...completedContext, since: "1d", until: null })
27093
27931
  ]);
27932
+ const nativeRoutingAtFinish = context.adapters === null ? null : await nativeRoutingObservationForBenchmark({
27933
+ fs: context.adapters.fs,
27934
+ home: context.home,
27935
+ stateRoot: context.stateRoot,
27936
+ harness: parsed.capture.harnessId,
27937
+ version: null,
27938
+ runner: context.adapters.runner,
27939
+ facts: context.platform,
27940
+ paths: context.adapters.paths,
27941
+ projectRoot: context.projectRoot,
27942
+ projectId,
27943
+ startedAt: parsed.capture.startedAt
27944
+ });
27094
27945
  const budget = budgetResult.data?.harnesses.find((item) => item.harnessId === parsed.capture.harnessId);
27095
27946
  const localUsage = parsed.capture.localSessionsBefore !== null && historyResult.data?.source.state === "available" ? deriveTaskLocalUsage(parsed.capture.localSessionsBefore, snapshotTaskLocalSessions(historyResult.data.sessions), parsed.capture.startedAt, completedAt) : null;
27096
27947
  const finishContextObservation = contextResult.data?.harnesses.find((item) => item.harnessId === parsed.capture.harnessId);
@@ -27102,7 +27953,8 @@ async function runBenchmarkFinish(context) {
27102
27953
  failedAttempts,
27103
27954
  localUsage,
27104
27955
  contextAtFinish: taskBenchmarkContextSnapshot(finishContextObservation),
27105
- policyAtFinish: benchmarkPolicySnapshot(finishContextObservation)
27956
+ policyAtFinish: benchmarkPolicySnapshot(finishContextObservation),
27957
+ nativeRoutingAtFinish
27106
27958
  });
27107
27959
  if (!completed.ok) {
27108
27960
  return commandResult({
@@ -27159,6 +28011,7 @@ var init_benchmark_capture = __esm({
27159
28011
  init_budget2();
27160
28012
  init_context_cost2();
27161
28013
  init_history2();
28014
+ init_prompt_router();
27162
28015
  CLAUDE13 = harnessId("claude");
27163
28016
  CODEX13 = harnessId("codex");
27164
28017
  CAPTURE_HARNESSES = /* @__PURE__ */ new Set([CLAUDE13, CODEX13]);
@@ -33774,12 +34627,19 @@ not-exercised, which is not a failure.`,
33774
34627
 
33775
34628
  Usage
33776
34629
  token-harness plan [--json] [--harness <id>] [--provider <id>] [--project <dir>]
34630
+ [--agent-routing | --disable-agent-routing]
33777
34631
  [--native-policy] [--task <class>] [--profile <name>]
33778
34632
  [--reserve <0-95>] [--tasks-left <n>]
33779
34633
 
33780
34634
  Read-only. Exits 0 when a plan was produced, and 4 when a hard conflict prevents
33781
34635
  apply. Nothing is changed either way.
33782
34636
 
34637
+ --agent-routing adds the native per-prompt hook for the selected Claude Code or Codex
34638
+ harness. --disable-agent-routing removes only exact hook entries owned by Token Harness.
34639
+ Both changes use the normal stored-plan, approval, verification and rollback path. Claude
34640
+ loads the change in a new session; Codex requires the user to review and trust the hook in
34641
+ /hooks. Configuration is shown separately from runtime callbacks in the guided app.
34642
+
33783
34643
  --native-policy adds reviewed Codex native settings derived from the same optimizer
33784
34644
  policy as token-harness optimize. This build manages reasoning effort and verbosity
33785
34645
  only. A field coming from project config or a selected profile is left untouched.
@@ -33998,6 +34858,8 @@ async function run(options) {
33998
34858
  nativePolicy: invocation.options.nativePolicy,
33999
34859
  env: options.env ?? {},
34000
34860
  agentSkill: invocation.options.agentSkill,
34861
+ agentRouting: invocation.options.agentRouting,
34862
+ disableAgentRouting: invocation.options.disableAgentRouting,
34001
34863
  since: invocation.options.since,
34002
34864
  until: invocation.options.until,
34003
34865
  planId: invocation.options.plan,
@@ -34488,6 +35350,48 @@ function allowanceEvidence(entries, scope, quality) {
34488
35350
  pairs: deltas.length
34489
35351
  };
34490
35352
  }
35353
+ function routedAllowanceEvidence(entries, scope) {
35354
+ const deltas = entries.flatMap((entry) => {
35355
+ const quota = entry.quota;
35356
+ if (quota === null || quota.scope !== scope || quota.confidence !== "authoritative")
35357
+ return [];
35358
+ return [quota.baselineDeltaUsedPercent - quota.optimizedDeltaUsedPercent];
35359
+ });
35360
+ const savedPercent = median2(deltas);
35361
+ return {
35362
+ state: savedPercent === null ? "not-measured" : "measured",
35363
+ scope,
35364
+ savedPercent: savedPercent === null ? null : roundOne(savedPercent),
35365
+ equivalentMinutes: scope === "five-hour" && savedPercent !== null ? roundOne(savedPercent * 3) : null,
35366
+ pairs: deltas.length
35367
+ };
35368
+ }
35369
+ function routingEvidence(entries) {
35370
+ const routed = entries.filter((entry) => entry.nativeRouting?.verdict === "attributed");
35371
+ const eligible = routed.filter((entry) => entry.nativeRouting?.qualityGatesPassed === true);
35372
+ const local = eligible.filter((entry) => entry.baselineLocalTokens !== null && entry.optimizedLocalTokens !== null);
35373
+ const baselineLocalTokens = local.length ? local.reduce((total, entry) => total + (entry.baselineLocalTokens ?? 0), 0) : null;
35374
+ const optimizedLocalTokens = local.length ? local.reduce((total, entry) => total + (entry.optimizedLocalTokens ?? 0), 0) : null;
35375
+ const savedLocalTokens = baselineLocalTokens === null || optimizedLocalTokens === null ? null : baselineLocalTokens - optimizedLocalTokens;
35376
+ const localTokenSavingPercent = baselineLocalTokens === null || optimizedLocalTokens === null || baselineLocalTokens <= 0 ? null : roundOne(savedLocalTokens / baselineLocalTokens * 100);
35377
+ const qualityBlockedPairs = routed.length - eligible.length;
35378
+ return {
35379
+ state: routed.length === 0 ? "not-measured" : eligible.length === 0 ? "blocked-by-quality" : "measured",
35380
+ pairs: eligible.length,
35381
+ qualityBlockedPairs,
35382
+ localPairs: local.length,
35383
+ baselineLocalTokens,
35384
+ optimizedLocalTokens,
35385
+ savedLocalTokens,
35386
+ localTokenSavingPercent,
35387
+ allowance5h: routedAllowanceEvidence(eligible, "five-hour"),
35388
+ allowance7d: routedAllowanceEvidence(eligible, "weekly"),
35389
+ reportedChildModels: [
35390
+ ...new Set(eligible.flatMap((entry) => entry.nativeRouting?.optimizedReportedModels ?? []))
35391
+ ],
35392
+ basis: routed.length === 0 ? "No paired benchmark currently proves that a native prompt hook ran and started a subagent." : eligible.length === 0 ? "Routing callbacks were observed, but all attributed pairs failed the quality gate; no savings are credited." : local.length > 0 || eligible.some((entry) => entry.quota?.confidence === "authoritative") ? "Exact local token counts and authoritative quota deltas are reported in separate units, only for attributed pairs that passed both quality gates." : "Routing was observed and both quality gates passed, but local token or authoritative quota usage was unavailable; no savings amount is inferred."
35393
+ };
35394
+ }
34491
35395
  function guidedValueEvidence(report) {
34492
35396
  const entries = report?.entries ?? [];
34493
35397
  const quality = qualityEvidence(entries);
@@ -34496,6 +35400,7 @@ function guidedValueEvidence(report) {
34496
35400
  allowance5h: allowanceEvidence(entries, "five-hour", quality),
34497
35401
  allowance7d: allowanceEvidence(entries, "weekly", quality),
34498
35402
  quality,
35403
+ routing: routingEvidence(entries),
34499
35404
  candidates: (report?.candidateEvidence ?? []).map((item) => ({ ...item })),
34500
35405
  apiCost: {
34501
35406
  state: "not-measured",
@@ -34597,7 +35502,7 @@ function guideSetupTargets(report, harness) {
34597
35502
  return GUIDE_MANAGED_PROVIDERS.map((provider) => guideSetupTarget(report, harness, provider));
34598
35503
  }
34599
35504
  function explainGuideIssue(diagnostics, fallback) {
34600
- const known = diagnostics.find((entry) => ISSUE_COPY[entry.code] !== void 0);
35505
+ const known = diagnostics.find((entry) => entry.severity === "error" && ISSUE_COPY[entry.code] !== void 0) ?? diagnostics.find((entry) => entry.severity === "warning" && ISSUE_COPY[entry.code] !== void 0) ?? diagnostics.find((entry) => entry.severity === "info" && ISSUE_COPY[entry.code] !== void 0);
34601
35506
  if (known !== void 0)
34602
35507
  return ISSUE_COPY[known.code];
34603
35508
  const blocked = diagnostics.find((entry) => /compatibility|unsupported|unreviewed|no-row/.test(entry.code));
@@ -34740,7 +35645,7 @@ function guidanceView(id, observation) {
34740
35645
  ...observation.state === "absent" ? { action: { kind: "skill", label: "Enable in-session guidance", harness: id } } : {}
34741
35646
  };
34742
35647
  }
34743
- function agentRules(id, providers, context, guidance) {
35648
+ function agentRules(id, providers, context, guidance, promptRouting) {
34744
35649
  const observation = context?.harnesses.find((item) => item.harnessId === id);
34745
35650
  const reasoning = reasoningView(id, observation);
34746
35651
  return [
@@ -34790,6 +35695,29 @@ function agentRules(id, providers, context, guidance) {
34790
35695
  next: guidance?.state === "managed" ? "Keep coding normally. Ask the agent to use Token Harness when you want an explicit quota-aware check." : guidance?.state === "external" ? "The matching skill can be used as-is. Token Harness keeps it user-owned." : guidance?.state === "conflict" ? "Review the existing skill manually. Token Harness will not overwrite it." : "Enable this once, then keep coding normally. Ask the agent to use Token Harness for a task when you want an explicit check.",
34791
35696
  ...guidance?.action ? { action: guidance.action } : {}
34792
35697
  },
35698
+ {
35699
+ id: `${id}-prompt-routing`,
35700
+ title: "Automatic prompt routing",
35701
+ state: promptRouting?.label ?? "Not verified",
35702
+ mode: promptRouting?.state === "absent" ? "not-enabled" : promptRouting?.state === "managed" || promptRouting?.state === "external" ? "automatic" : "integration",
35703
+ what: promptRouting?.detail ?? "Adds a native prompt hook that supplies the routing policy on every submitted prompt.",
35704
+ why: "Eligible bounded work may use a cheaper native subagent. The root conversation model stays unchanged, and the model decides whether a native subagent is appropriate.",
35705
+ evidence: promptRouting?.promptSubmissions ? `${String(promptRouting.promptSubmissions)} prompt callback(s) and ${String(promptRouting.subagentsStarted)} subagent start(s) observed in the last 30 days. Actual child model is shown only when the harness reports it.` : promptRouting?.configured ? "The hook is configured, but no prompt callback has been observed yet. Configuration alone is not runtime proof." : "No runtime routing evidence has been recorded yet.",
35706
+ next: promptRouting?.state === "absent" ? "Enable routing once, restart or trust the hook if the harness requires it, then keep using prompts normally." : promptRouting?.state === "managed" ? "Routing is enabled. Disable it here if you want to stop injecting the policy on each prompt." : promptRouting?.state === "external" ? "This hook is user-owned. Token Harness can report it but will not remove it." : promptRouting?.detail ?? "Refresh to inspect the native prompt-hook state.",
35707
+ ...promptRouting?.state === "absent" ? {
35708
+ action: {
35709
+ kind: "routing-enable",
35710
+ label: "Enable automatic routing",
35711
+ harness: id
35712
+ }
35713
+ } : promptRouting?.state === "managed" ? {
35714
+ action: {
35715
+ kind: "routing-disable",
35716
+ label: "Disable automatic routing",
35717
+ harness: id
35718
+ }
35719
+ } : {}
35720
+ },
34793
35721
  {
34794
35722
  id: `${id}-mcp`,
34795
35723
  title: "Connected tools",
@@ -34924,6 +35852,13 @@ var init_guided = __esm({
34924
35852
  "codex-native-policy-unavailable": "Codex did not expose a writable, versioned user setting. No change is proposed.",
34925
35853
  "codex-native-policy-shadowed": "A project or profile overrides this Codex setting. That setting belongs to you and will not be replaced.",
34926
35854
  "no-providers-registered": "No optimization provider was selected for this operation.",
35855
+ "prompt-routing-target-unavailable": "Token Harness could not locate a supported user-level prompt-hook settings file for this agent.",
35856
+ "prompt-routing-version-unverified": "Automatic routing is not available for this agent version until its prompt-hook format has been verified.",
35857
+ "prompt-routing-runtime-unavailable": "The Token Harness hook command could not run from this dashboard environment. Make Token Harness available on PATH, then review routing again.",
35858
+ "prompt-routing-target-not-file": "A non-file occupies the agent hook settings path, so Token Harness left it unchanged.",
35859
+ "prompt-routing-settings-unmergeable": "The current hook settings cannot be merged safely. Repair the JSON or review the hook manually.",
35860
+ "prompt-routing-already-configured": "Automatic routing hooks are already present. Nothing needs to be changed.",
35861
+ "prompt-routing-existing-hook-conflict": "An existing Token Harness routing hook was changed or only partly installed. It was left untouched for review.",
34927
35862
  "already-in-desired-state": "The supported integration is already configured. Nothing needs to be changed.",
34928
35863
  "delegated-install-snapshot-too-large": "The optimizer setup found too much unrelated data inside its rollback boundary. Nothing was changed. Update Token Harness or use a narrower project directory before retrying.",
34929
35864
  "delegated-install-failed": "The optimizer installer itself did not complete successfully. Nothing was kept from the failed transaction.",
@@ -35023,11 +35958,13 @@ var init_guided = __esm({
35023
35958
  now;
35024
35959
  random;
35025
35960
  observeGuidance;
35026
- constructor(call, now, random, observeGuidance = null) {
35961
+ observeRouting;
35962
+ constructor(call, now, random, observeGuidance = null, observeRouting = null) {
35027
35963
  this.call = call;
35028
35964
  this.now = now;
35029
35965
  this.random = random;
35030
35966
  this.observeGuidance = observeGuidance;
35967
+ this.observeRouting = observeRouting;
35031
35968
  }
35032
35969
  status() {
35033
35970
  return {
@@ -35099,6 +36036,7 @@ var init_guided = __esm({
35099
36036
  const empty2 = () => ({ data: null, diagnostics: [], exitCode: 9 });
35100
36037
  let doctor = empty2(), budget = empty2(), context = empty2();
35101
36038
  let guidance;
36039
+ let promptRouting;
35102
36040
  const observe = async (id, args) => {
35103
36041
  let result6;
35104
36042
  try {
@@ -35116,7 +36054,7 @@ var init_guided = __esm({
35116
36054
  loading.agents = this.agentView(doctor, budget, context, {
35117
36055
  rules: loading.stages.find((item) => item.id === "rules")?.state !== "working",
35118
36056
  allowance: loading.stages.find((item) => item.id === "allowance")?.state !== "working"
35119
- }, guidance);
36057
+ }, guidance, promptRouting);
35120
36058
  };
35121
36059
  const [, , , metrics, status, benchmark] = await Promise.all([
35122
36060
  observe("agents", ["doctor"]).then((result6) => {
@@ -35143,6 +36081,29 @@ var init_guided = __esm({
35143
36081
  }
35144
36082
  }));
35145
36083
  }
36084
+ if (this.observeRouting !== null) {
36085
+ promptRouting = {};
36086
+ await Promise.all(["claude", "codex"].map(async (harness) => {
36087
+ try {
36088
+ promptRouting[harness] = await this.observeRouting(harness);
36089
+ } catch {
36090
+ promptRouting[harness] = {
36091
+ harness,
36092
+ state: "unavailable",
36093
+ label: "Not verified",
36094
+ detail: "Native prompt-hook status could not be checked.",
36095
+ configPath: null,
36096
+ configured: null,
36097
+ promptSubmissions: 0,
36098
+ subagentsStarted: 0,
36099
+ subagentsStopped: 0,
36100
+ reportedModels: [],
36101
+ lastObservedAt: null,
36102
+ receiptState: "unavailable"
36103
+ };
36104
+ }
36105
+ }));
36106
+ }
35146
36107
  updateAgents();
35147
36108
  }),
35148
36109
  observe("savings", [
@@ -35156,7 +36117,7 @@ var init_guided = __esm({
35156
36117
  observe("checks", ["status"]),
35157
36118
  observe("value", ["benchmark-matrix"])
35158
36119
  ]);
35159
- const agents = this.agentView(doctor, budget, context, { rules: true, allowance: true }, guidance);
36120
+ const agents = this.agentView(doctor, budget, context, { rules: true, allowance: true }, guidance, promptRouting);
35160
36121
  const notices = [];
35161
36122
  if (doctor.data === null)
35162
36123
  notices.push("The agent inventory could not be read. Check the local installation and refresh.");
@@ -35184,7 +36145,7 @@ var init_guided = __esm({
35184
36145
  notices
35185
36146
  };
35186
36147
  }
35187
- agentView(doctor, budget, context, complete2, guidance) {
36148
+ agentView(doctor, budget, context, complete2, guidance, promptRouting) {
35188
36149
  const present = (doctor.data?.harnesses ?? []).filter((item) => item.state !== "absent" && (item.harnessId === "claude" || item.harnessId === "codex"));
35189
36150
  return present.map((agent) => {
35190
36151
  const providers = (doctor.data?.providers ?? []).filter((provider) => provider.state === "configured" && provider.configuredHarnesses.includes(agent.harnessId)).map((p) => p.providerId);
@@ -35207,8 +36168,9 @@ var init_guided = __esm({
35207
36168
  effort: observed?.nativeEffort?.current ?? observed?.reasoningEffort ?? null,
35208
36169
  reasoning: reasoningView(agent.harnessId, observed),
35209
36170
  ...guidance?.[agent.harnessId] ? { guidance: guidance[agent.harnessId] } : {},
36171
+ ...promptRouting?.[agent.harnessId] ? { promptRouting: promptRouting[agent.harnessId] } : {},
35210
36172
  allowanceAction: allowanceAction(usage?.diagnostics ?? []),
35211
- rules: agentRules(agent.harnessId, providers, context.data, guidance?.[agent.harnessId]),
36173
+ rules: agentRules(agent.harnessId, providers, context.data, guidance?.[agent.harnessId], promptRouting?.[agent.harnessId]),
35212
36174
  allowance: (usage?.windows ?? []).map((window) => ({
35213
36175
  label: window.scope === "five-hour" ? "5-hour allowance" : `${window.scope} allowance`,
35214
36176
  remaining: window.remainingPercent,
@@ -35243,11 +36205,13 @@ var init_guided = __esm({
35243
36205
  "setup",
35244
36206
  "effort",
35245
36207
  "skill",
36208
+ "routing-enable",
36209
+ "routing-disable",
35246
36210
  "undo",
35247
36211
  "remove",
35248
36212
  "candidate-setup",
35249
36213
  "candidate-remove"
35250
- ].includes(action) || data["harness"] !== void 0 && !["claude", "codex"].includes(String(data["harness"])) || data["harnesses"] !== void 0 && !validHarnesses || data["harnesses"] !== void 0 && action !== "setup" || data["harnesses"] !== void 0 && data["harness"] !== void 0 || data["task"] !== void 0 && !TASKS.has(String(data["task"])) || data["provider"] !== void 0 && !["rtk", "harnesstrim", "mcptoon", "gitnexus", "headroom"].includes(String(data["provider"])) || data["candidate"] !== void 0 && !["mcptoon", "gitnexus"].includes(String(data["candidate"])) || action === "effort" && (data["harness"] === void 0 || data["task"] === void 0) || action === "skill" && data["harness"] === void 0 || action === "remove" && (data["provider"] === void 0 || data["harness"] !== void 0 || data["harnesses"] !== void 0 || data["task"] !== void 0 || data["candidate"] !== void 0) || data["provider"] !== void 0 && action !== "remove" && action !== "setup" || candidateAction && (data["candidate"] === void 0 || data["harness"] === void 0 || data["provider"] !== void 0 || data["task"] !== void 0) || !candidateAction && data["candidate"] !== void 0)
36214
+ ].includes(action) || data["harness"] !== void 0 && !["claude", "codex"].includes(String(data["harness"])) || data["harnesses"] !== void 0 && !validHarnesses || data["harnesses"] !== void 0 && action !== "setup" || data["harnesses"] !== void 0 && data["harness"] !== void 0 || data["task"] !== void 0 && !TASKS.has(String(data["task"])) || data["provider"] !== void 0 && !["rtk", "harnesstrim", "mcptoon", "gitnexus", "headroom"].includes(String(data["provider"])) || data["candidate"] !== void 0 && !["mcptoon", "gitnexus"].includes(String(data["candidate"])) || action === "effort" && (data["harness"] === void 0 || data["task"] === void 0) || action === "skill" && data["harness"] === void 0 || (action === "routing-enable" || action === "routing-disable") && data["harness"] === void 0 || action === "remove" && (data["provider"] === void 0 || data["harness"] !== void 0 || data["harnesses"] !== void 0 || data["task"] !== void 0 || data["candidate"] !== void 0) || data["provider"] !== void 0 && action !== "remove" && action !== "setup" || candidateAction && (data["candidate"] === void 0 || data["harness"] === void 0 || data["provider"] !== void 0 || data["task"] !== void 0) || !candidateAction && data["candidate"] !== void 0)
35251
36215
  throw new GuideError(400, "Choose a supported agent and action.");
35252
36216
  return this.exclusive(async () => {
35253
36217
  this.approval = null;
@@ -35435,13 +36399,17 @@ var init_guided = __esm({
35435
36399
  args.push("--provider", setupProvider);
35436
36400
  if (data["action"] === "skill") {
35437
36401
  args.push("--provider", "none", "--agent-skill");
36402
+ } else if (data["action"] === "routing-enable") {
36403
+ args.push("--provider", "none", "--agent-routing");
36404
+ } else if (data["action"] === "routing-disable") {
36405
+ args.push("--provider", "none", "--disable-agent-routing");
35438
36406
  } else if (data["action"] === "effort")
35439
36407
  args.push("--provider", "none", "--native-policy", "--task", String(data["task"]), "--profile", data["task"] === "mechanical" ? "economy" : data["task"] === "standard" ? "balanced" : "quality");
35440
36408
  const result6 = await this.call(args);
35441
36409
  const report = result6.data;
35442
36410
  if (report === null || result6.exitCode !== 0 || report.conflicts.length > 0 || report.actions.length === 0 || !report.persisted || report.planId === null) {
35443
36411
  const subject = setupProvider !== null ? `${name(agent.harnessId)} \xB7 ${name(setupProvider)}` : name(agent.harnessId);
35444
- notices.push(`${subject}: ${explainGuideIssue(result6.diagnostics, data["action"] === "effort" ? "No supported preference change is needed or available. Your current preference is kept." : data["action"] === "skill" ? "In-session guidance is already present, or an existing user-owned skill location was left untouched." : "No safe setup change is available for the current provider, agent version and platform.")}`);
36412
+ notices.push(`${subject}: ${explainGuideIssue(result6.diagnostics, data["action"] === "effort" ? "No supported preference change is needed or available. Your current preference is kept." : data["action"] === "skill" ? "In-session guidance is already present, or an existing user-owned skill location was left untouched." : data["action"] === "routing-enable" || data["action"] === "routing-disable" ? "No safe native prompt-routing change is available for the current harness, hook state and ownership evidence." : "No safe setup change is available for the current provider, agent version and platform.")}`);
35445
36413
  continue;
35446
36414
  }
35447
36415
  plans.push(report.planId);
@@ -35451,6 +36419,8 @@ var init_guided = __esm({
35451
36419
  description: "Installs one reviewed Token Harness Agent Skill in the standard user skill directory. It does not change model, login, billing, hooks, trust, or the current conversation.",
35452
36420
  files: 1
35453
36421
  });
36422
+ } else if (data["action"] === "routing-enable" || data["action"] === "routing-disable") {
36423
+ changes.push(...report.actions.map((action2) => describeChange(action2, agent.harnessId)));
35454
36424
  } else {
35455
36425
  changes.push(...report.actions.map((action2) => describeChange(action2, agent.harnessId)));
35456
36426
  }
@@ -35468,7 +36438,7 @@ var init_guided = __esm({
35468
36438
  plans,
35469
36439
  transactionId: null,
35470
36440
  provider: null,
35471
- description: data["action"] === "effort" ? "Task preference" : data["action"] === "skill" ? "In-session guidance" : "Integration setup",
36441
+ description: data["action"] === "effort" ? "Task preference" : data["action"] === "skill" ? "In-session guidance" : data["action"] === "routing-enable" || data["action"] === "routing-disable" ? "Automatic prompt routing" : "Integration setup",
35472
36442
  operation: "apply",
35473
36443
  network
35474
36444
  };
@@ -35480,7 +36450,7 @@ var init_guided = __esm({
35480
36450
  notices,
35481
36451
  expiresAt: id === null ? null : new Date(expires).toISOString(),
35482
36452
  network,
35483
- restart: data["action"] === "effort" || data["action"] === "skill"
36453
+ restart: data["action"] === "effort" || data["action"] === "skill" || data["action"] === "routing-enable" || data["action"] === "routing-disable"
35484
36454
  };
35485
36455
  });
35486
36456
  }
@@ -35927,22 +36897,51 @@ var init_guided = __esm({
35927
36897
  const messages = [];
35928
36898
  const results = [];
35929
36899
  let ok = true;
36900
+ let healthyAtDeclaredTier = true;
35930
36901
  const inventory = await this.call(["doctor"]);
35931
36902
  const present = (inventory.data?.harnesses ?? []).filter((item) => item.state !== "absent" && ["claude", "codex"].includes(item.harnessId));
36903
+ if (inventory.data === null) {
36904
+ ok = false;
36905
+ healthyAtDeclaredTier = false;
36906
+ messages.push("The installed-agent inventory could not be read. Refresh and check the local installation.");
36907
+ }
35932
36908
  if (present.length === 0) {
35933
36909
  ok = false;
35934
- messages.push("No supported installed agent could be checked. Refresh after installing or signing in.");
36910
+ healthyAtDeclaredTier = false;
36911
+ messages.push("No supported installed agent was detected, so no integration was checked.");
35935
36912
  }
35936
36913
  for (const agent of present) {
35937
36914
  const harness = agent.harnessId;
35938
36915
  this.record(`Checking ${name(harness)} configuration and available execution evidence. No settings changed.`, "working");
35939
36916
  const result6 = await this.call(["verify", "--harness", harness]);
35940
36917
  const healthy = result6.data?.healthyAtDeclaredTier === true;
35941
- if (!healthy)
36918
+ const versionWarnings = result6.diagnostics.filter((entry) => entry.severity === "warning" && (entry.code === "harness-version-unknown-newer" || entry.code === "provider-version-unknown-newer"));
36919
+ const failed = result6.data === null || result6.exitCode !== 0 || result6.diagnostics.some((entry) => entry.severity === "error" || entry.severity === "warning" && !versionWarnings.includes(entry)) || result6.data.results.some((entry) => entry.status === "degraded" || entry.status === "failed");
36920
+ if (failed)
35942
36921
  ok = false;
36922
+ if (!healthy)
36923
+ healthyAtDeclaredTier = false;
35943
36924
  if (result6.data !== null)
35944
36925
  results.push(...result6.data.results);
35945
- messages.push(`${name(harness)}: ${healthy ? "the available integration checks passed. This is not proof that every command was reduced." : explainGuideIssue(result6.diagnostics, "execution could not be fully confirmed. The agent may be absent, an integration may not be enabled, or runtime evidence may be unavailable.")}`);
36926
+ const prefix = `${name(harness)}: `;
36927
+ if (result6.data === null) {
36928
+ messages.push(prefix + "the verification report could not be read. Refresh and check the local installation.");
36929
+ } else if (healthy) {
36930
+ messages.push(prefix + "the available integration checks passed. This is not proof that every command was reduced.");
36931
+ } else if (failed) {
36932
+ messages.push(prefix + "a known integration check failed. Review the specific check before changing setup.");
36933
+ } else if (result6.data.results.length === 0) {
36934
+ messages.push(prefix + "the agent is detected, but no managed optimizer connection is present to verify. Review setup only if you want to connect one.");
36935
+ } else {
36936
+ const pendingProviders = [
36937
+ ...new Set(result6.data.results.filter((entry) => entry.status === "not-applicable").map((entry) => name(entry.providerId)))
36938
+ ];
36939
+ const subject = pendingProviders.length > 0 ? pendingProviders.join(" and ") : "Some integrations";
36940
+ messages.push(`${prefix}${subject} have not produced enough attributable runtime evidence for ${name(harness)} yet. This is an evidence gap, not a finding that the setup is broken. If you do not use this agent on this machine, no action is required.`);
36941
+ }
36942
+ if (versionWarnings.length > 0) {
36943
+ messages.push(prefix + "the installed version is newer than Token Harness\u2019s recorded compatibility sample; read-only checks can continue, but review the version before changing its integration.");
36944
+ }
35946
36945
  }
35947
36946
  if (inventory.data !== null) {
35948
36947
  const fingerprint = stackFingerprint(inventory.data);
@@ -35952,7 +36951,7 @@ var init_guided = __esm({
35952
36951
  receiptId: null,
35953
36952
  appliedAt: null,
35954
36953
  results,
35955
- healthyAtDeclaredTier: ok
36954
+ healthyAtDeclaredTier: healthyAtDeclaredTier && present.length > 0
35956
36955
  }
35957
36956
  };
35958
36957
  this.stackBase = {
@@ -35968,7 +36967,13 @@ var init_guided = __esm({
35968
36967
  if (this.cached !== null)
35969
36968
  this.cached.value = { ...this.cached.value, stack };
35970
36969
  this.record("Integration checks completed. No settings changed.", ok ? "success" : "attention");
35971
- return { ok, title: "Integration checks", messages, appliedPlans: 0, stack };
36970
+ return {
36971
+ ok,
36972
+ title: ok ? healthyAtDeclaredTier ? "Integration checks passed" : "Configuration checks complete; runtime evidence pending" : "Integration checks need attention",
36973
+ messages,
36974
+ appliedPlans: 0,
36975
+ stack
36976
+ };
35972
36977
  });
35973
36978
  }
35974
36979
  };
@@ -38470,6 +39475,31 @@ var init_guided_product_client = __esm({
38470
39475
  'caption',
38471
39476
  ),
38472
39477
  );
39478
+ const routing = agent.promptRouting;
39479
+ const routingCard = node('div', undefined, 'routing-feature');
39480
+ const routingHead = node('div', undefined, 'tool-head');
39481
+ routingHead.append(
39482
+ node('strong', 'Automatic prompt routing'),
39483
+ pill(routing?.label || 'Not verified', routing?.state === 'managed' ? 'good' : routing?.state === 'absent' ? '' : 'warn'),
39484
+ );
39485
+ routingCard.append(
39486
+ routingHead,
39487
+ node(
39488
+ 'p',
39489
+ routing?.detail || 'A native hook can inject the routing policy on every submitted prompt. Setup and runtime activity are tracked separately.',
39490
+ 'caption',
39491
+ ),
39492
+ );
39493
+ const routingActions = node('div', undefined, 'inline-actions');
39494
+ if (routing?.state === 'absent') {
39495
+ routingActions.append(actionButton('Enable routing', () => reviewPromptRouting(agent.id, true), 'secondary'));
39496
+ } else if (routing?.state === 'managed') {
39497
+ routingActions.append(actionButton('Disable routing', () => reviewPromptRouting(agent.id, false), 'secondary'));
39498
+ } else if (routing?.state === 'external') {
39499
+ routingActions.append(node('span', 'Managed elsewhere · left untouched', 'caption'));
39500
+ }
39501
+ if (routingActions.children.length) routingCard.append(routingActions);
39502
+ card.append(routingCard);
38473
39503
  if (baseline.unavailable.length) {
38474
39504
  const details = node('details', undefined, 'agent-details');
38475
39505
  details.append(node('summary', 'Connection limitations'));
@@ -38561,6 +39591,57 @@ var init_guided_product_client = __esm({
38561
39591
  });
38562
39592
  }
38563
39593
 
39594
+ function reviewPromptRouting(agentId, enabled) {
39595
+ if (busy) return;
39596
+ const run = modal((enabled ? 'Enable' : 'Disable') + ' automatic routing · ' + agentName(agentId));
39597
+ $('modal-content').append(
39598
+ messageBox(
39599
+ 'How this works',
39600
+ enabled
39601
+ ? 'Token Harness adds a native UserPromptSubmit hook that supplies a short routing policy on each prompt. The agent may delegate eligible bounded work to a lower-cost native subagent; the root model stays the same.'
39602
+ : 'Token Harness removes only the exact native routing entries it owns. User-edited or manually installed hooks remain untouched.',
39603
+ ),
39604
+ progress('Preparing a read-only plan', 'No harness settings change until you approve the exact preview.'),
39605
+ );
39606
+ $('modal-actions').append(modalClose('Cancel'));
39607
+ setBusy(true, false);
39608
+ ensureSession()
39609
+ .then(() => request('/api/preview', {
39610
+ action: enabled ? 'routing-enable' : 'routing-disable',
39611
+ harness: agentId,
39612
+ }))
39613
+ .then(data => {
39614
+ if (run !== modalRun || !$('modal').open) return;
39615
+ pendingTicket = data.ticket;
39616
+ $('modal-content').replaceChildren();
39617
+ for (const change of data.changes || []) {
39618
+ const item = node('article', undefined, 'preview-change');
39619
+ item.append(node('h3', change.title), node('p', change.description));
39620
+ $('modal-content').append(item);
39621
+ }
39622
+ if (!(data.changes || []).length)
39623
+ $('modal-content').append(messageBox('No change proposed', (data.notices || []).join(' ') || 'The current routing state or ownership evidence does not support a safe change.'));
39624
+ for (const notice of data.notices || []) $('modal-content').append(node('p', notice, 'notice-row'));
39625
+ if (data.ticket) $('modal-content').append(messageBox(
39626
+ agentId === 'codex' ? 'Codex trust step' : 'When it takes effect',
39627
+ agentId === 'codex'
39628
+ ? 'After Apply, review and trust the UserPromptSubmit hook in Codex using /hooks. Until a callback is observed, the dashboard will show it as configured but not runtime verified.'
39629
+ : 'After Apply, start a new Claude Code session. The dashboard will show configured state first and runtime activity after the next prompt callback.',
39630
+ 'safe',
39631
+ ));
39632
+ $('modal-actions').replaceChildren(modalClose(data.ticket ? 'Cancel' : 'Done'));
39633
+ if (data.ticket) $('modal-actions').append(actionButton(enabled ? 'Apply routing hook' : 'Remove owned routing hook', () => applyTicket(data.ticket)));
39634
+ })
39635
+ .catch(error => {
39636
+ if (run !== modalRun) return;
39637
+ $('modal-error').textContent = error.message;
39638
+ $('modal-error').hidden = false;
39639
+ })
39640
+ .finally(() => {
39641
+ if (run === modalRun) setBusy(false, false);
39642
+ });
39643
+ }
39644
+
38564
39645
  function reviewSetup(providerId = null) {
38565
39646
  if (busy) return;
38566
39647
  const choices = setupChoiceData(providerId);
@@ -39251,10 +40332,6 @@ var init_guided_product_client = __esm({
39251
40332
  node('strong', component?.configuredHarnesses?.length ? component.configuredHarnesses.map(agentName).join(', ') : 'No detected agent'),
39252
40333
  );
39253
40334
  const measured = rows.filter(row => row.providerId === id);
39254
- facts.append(
39255
- node('span', 'Recorded results'),
39256
- node('strong', measured.length ? measured.length + ' recorded result' + (measured.length === 1 ? '' : 's') : 'None in this period'),
39257
- );
39258
40335
  card.append(facts);
39259
40336
  if (!measured.length) {
39260
40337
  card.append(
@@ -39358,6 +40435,29 @@ var init_guided_product_client = __esm({
39358
40435
  metricCard('5h / 7d allowance', allowance.value, allowance.detail, allowance.cls),
39359
40436
  metricCard('Quality', quality.value, quality.detail, quality.cls),
39360
40437
  );
40438
+ const routed = current?.value?.routing;
40439
+ const quotaParts = [];
40440
+ if (routed?.allowance5h?.state === 'measured' && routed.allowance5h.savedPercent !== null)
40441
+ quotaParts.push(routed.allowance5h.savedPercent >= 0
40442
+ ? '5h saved ' + count(routed.allowance5h.savedPercent) + '%'
40443
+ : '5h use +' + count(Math.abs(routed.allowance5h.savedPercent)) + '%');
40444
+ if (routed?.allowance7d?.state === 'measured' && routed.allowance7d.savedPercent !== null)
40445
+ quotaParts.push(routed.allowance7d.savedPercent >= 0
40446
+ ? '7d saved ' + count(routed.allowance7d.savedPercent) + '%'
40447
+ : '7d use +' + count(Math.abs(routed.allowance7d.savedPercent)) + '%');
40448
+ const routingValue = routed?.state === 'blocked-by-quality'
40449
+ ? 'Not credited'
40450
+ : routed?.savedLocalTokens !== null && routed?.savedLocalTokens !== undefined
40451
+ ? (routed.savedLocalTokens >= 0
40452
+ ? count(routed.savedLocalTokens) + ' tokens saved' + (routed.localTokenSavingPercent === null ? '' : ' · ' + count(routed.localTokenSavingPercent) + '%')
40453
+ : count(Math.abs(routed.savedLocalTokens)) + ' tokens added' + (routed.localTokenSavingPercent === null ? '' : ' · ' + count(Math.abs(routed.localTokenSavingPercent)) + '%'))
40454
+ : quotaParts.length ? 'Allowance measured' : routed?.state === 'measured' ? 'Usage unavailable' : 'Not measured yet';
40455
+ const routingDetail = routed?.state === 'blocked-by-quality'
40456
+ ? routed.basis
40457
+ : (quotaParts.length ? quotaParts.join(' · ') + '. ' : '') +
40458
+ (routed?.pairs ? count(routed.pairs) + ' quality-passed routed pair(s). ' : '') +
40459
+ 'Local tokens and allowance percentages are separate measurements. Actual child model is not exposed by every harness hook.';
40460
+ $('result-summary').append(metricCard('Automatic routing', routingValue, routingDetail, routed?.state === 'measured' ? 'positive' : ''));
39361
40461
  renderResultOptimizers();
39362
40462
  renderResultAgents();
39363
40463
  renderSavings();
@@ -39505,6 +40605,7 @@ var init_guided_product_styles = __esm({
39505
40605
  .setup-step{margin:1.6rem 0}.step-heading{display:grid;grid-template-columns:34px 1fr;gap:.65rem;align-items:start;margin-bottom:.7rem}.step-number{display:grid;place-items:center;width:32px;height:32px;border-radius:9px;background:var(--accent);color:#fff;font-weight:900}.step-heading h2{margin:0}.step-heading p{margin:.2rem 0;color:var(--muted)}
39506
40606
  .connection-overview{display:grid;gap:.75rem}.connection-summary{display:flex;align-items:center;justify-content:space-between;gap:1rem;background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:1rem}.connection-summary p{margin:.15rem 0 0}.connection-scroll{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius);background:var(--panel)}.connection-table{min-width:max(720px,100%)}.connection-row{display:grid;grid-template-columns:minmax(170px,1.25fr) repeat(var(--connection-columns),minmax(130px,1fr)) minmax(155px,.8fr);align-items:center;gap:.6rem;padding:.72rem .8rem;border-bottom:1px solid var(--line)}.connection-row:last-child{border-bottom:0}.connection-head{background:var(--panel-soft);color:var(--muted);font-size:.8rem}.connection-name{display:grid;gap:.12rem}.connection-cell,.connection-action{min-width:0}.connection-action{display:flex;justify-content:flex-end}.tool-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.8rem}.candidate-comparison-toolbar{grid-column:1/-1;justify-content:flex-end;align-self:start}.tool-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:1rem;box-shadow:var(--shadow)}.tool-card.experimental{border-style:dashed}.tool-card.compact{box-shadow:none}.tool-card>p{color:var(--muted);margin:.65rem 0}.tool-head{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.tool-head h3{margin:0}.tool-facts{display:grid;grid-template-columns:auto 1fr;gap:.3rem .75rem;border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:.65rem 0;margin:.65rem 0}.tool-facts span{color:var(--muted);font-size:.8rem}.tool-facts strong{font-size:.85rem}
39507
40607
  .connection-role{max-width:28ch}.setup-choice-list{display:grid;gap:.55rem;margin:.9rem 0}.setup-choice-list h3{margin:.25rem 0 0}.setup-choice{display:grid;grid-template-columns:auto 1fr;align-items:start;gap:.7rem;padding:.8rem;border:1px solid var(--line);border-radius:12px;background:var(--panel);cursor:pointer}.setup-choice:hover{border-color:var(--accent);background:var(--accent-soft)}.setup-choice input{inline-size:1.1rem;block-size:1.1rem;margin:.15rem 0 0;accent-color:var(--accent)}.setup-choice-copy{display:grid;gap:.2rem}.setup-choice-limitation{color:var(--muted)}
40608
+ .routing-feature{margin:.8rem 0;padding:.8rem;border:1px solid var(--line);border-radius:12px;background:var(--panel-soft)}.routing-feature .tool-head{align-items:center}.routing-feature p{margin:.55rem 0;color:var(--muted)}
39508
40609
  .managed-action-box{margin-top:.8rem;background:var(--panel-soft);border:1px solid var(--line);border-radius:12px;padding:.85rem}.managed-action-box p{margin:.1rem 0 .65rem}
39509
40610
  .maintenance-list{display:grid;gap:.55rem}.maintenance-row{display:flex;align-items:center;justify-content:space-between;gap:1rem;background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:.8rem}.maintenance-row p{margin:.15rem 0}
39510
40611
  .explain-box{background:var(--panel-soft);border:1px solid var(--line);border-radius:12px;padding:.8rem;margin:.6rem 0}.explain-box p{margin:.25rem 0;color:var(--muted)}.explain-box.warn{background:var(--warn-soft);border-color:color-mix(in srgb,var(--warn) 35%,var(--line))}.explain-box.safe{background:var(--good-soft);border-color:color-mix(in srgb,var(--good) 30%,var(--line))}.operation-progress{margin:.75rem 0;padding:.8rem;border:1px solid var(--line);border-radius:12px}.operation-progress p{margin:.35rem 0 0}
@@ -40185,7 +41286,7 @@ ${GUIDE_CANDIDATE_READINESS_JS}`;
40185
41286
  </div>
40186
41287
 
40187
41288
  <section class="setup-step" id="coding-agents">
40188
- <div class="section-title"><div><h2>Coding agents</h2><p>Detected coding apps are shown here as status. Optimizer setup is managed centrally below; a detected setup does not prove that it ran or recorded results.</p></div></div>
41289
+ <div class="section-title"><div><h2>Coding agents</h2><p>Enable automatic per-prompt routing here for each detected coding app. The card distinguishes hook configuration from callbacks actually observed at runtime.</p></div></div>
40189
41290
  <div id="setup-agents" class="tool-grid"><article class="tool-card"><h3>Checking agents\u2026</h3></article></div>
40190
41291
  <details class="disclosure advanced-disclosure">
40191
41292
  <summary>Agent details and optional reasoning settings</summary>
@@ -40653,6 +41754,19 @@ async function runAsDatabaseReader(argv2) {
40653
41754
  process5.exitCode = 0;
40654
41755
  return true;
40655
41756
  }
41757
+ function parsePromptRouterEvent(value3) {
41758
+ if (value3 === "prompt-submit" || value3 === "subagent-start" || value3 === "subagent-stop")
41759
+ return value3;
41760
+ return null;
41761
+ }
41762
+ function emitPromptRouterContext(harness) {
41763
+ process5.stdout.write(JSON.stringify({
41764
+ hookSpecificOutput: {
41765
+ hookEventName: "UserPromptSubmit",
41766
+ additionalContext: ROUTING_CONTEXT[harness]
41767
+ }
41768
+ }) + "\n");
41769
+ }
40656
41770
  async function readStandardInput() {
40657
41771
  const chunks = [];
40658
41772
  let bytes = 0;
@@ -40677,6 +41791,16 @@ async function main(argv2) {
40677
41791
  }
40678
41792
  return;
40679
41793
  }
41794
+ if (argv2[0] === PROMPT_ROUTER_FLAG && argv2[2] === "--check") {
41795
+ if (argv2[1] === "claude" || argv2[1] === "codex") {
41796
+ process5.stdout.write(`${PROMPT_ROUTER_CHECK_MARKER2}
41797
+ `);
41798
+ process5.exitCode = EXIT_CODES.ok;
41799
+ } else {
41800
+ process5.exitCode = EXIT_CODES["usage-error"];
41801
+ }
41802
+ return;
41803
+ }
40680
41804
  const opensGuide = argv2.length === 0 || argv2[0] === "start" || argv2[0] === "ui";
40681
41805
  const readOnly = argv2.includes("--read-only");
40682
41806
  const uiInvocation = opensGuide ? parseUiArgs(argv2.slice(1).filter((arg) => arg !== "--read-only")) : null;
@@ -40746,6 +41870,34 @@ Run token-harness ui --help for usage.
40746
41870
  env: process5.env,
40747
41871
  stdoutIsTty: process5.stdout.isTTY === true
40748
41872
  };
41873
+ if (argv2[0] === PROMPT_ROUTER_FLAG) {
41874
+ const selected = argv2[1];
41875
+ const event = parsePromptRouterEvent(argv2[2]);
41876
+ if (selected !== "claude" && selected !== "codex" || event === null) {
41877
+ process5.exitCode = EXIT_CODES.ok;
41878
+ return;
41879
+ }
41880
+ const input = await readStandardInput();
41881
+ if (resolution.ok && fs !== null && input !== null) {
41882
+ try {
41883
+ const projectId = attribution.salt === null ? null : deriveProjectId(process5.cwd(), attribution.salt, resolution.environment.facts.os === "windows");
41884
+ await recordNativePromptRoutingHook({
41885
+ fs,
41886
+ stateRoot: resolution.environment.paths.state,
41887
+ harness: selected,
41888
+ event,
41889
+ projectId,
41890
+ now: (/* @__PURE__ */ new Date()).toISOString(),
41891
+ hookInput: input
41892
+ });
41893
+ } catch {
41894
+ }
41895
+ }
41896
+ if (event === "prompt-submit")
41897
+ emitPromptRouterContext(selected);
41898
+ process5.exitCode = EXIT_CODES.ok;
41899
+ return;
41900
+ }
40749
41901
  if (argv2[0] === RTK_HOOK_PROXY_FLAG) {
40750
41902
  const selected = argv2[1];
40751
41903
  if (selected !== "claude" && selected !== "codex") {
@@ -40968,6 +42120,35 @@ async function runGuidedUi(options, base) {
40968
42120
  stateRoot: base.stateRoot ?? null,
40969
42121
  harness
40970
42122
  });
42123
+ }, async (harness) => {
42124
+ if (base.adapters === null || base.adapters === void 0 || base.platform === null) {
42125
+ return {
42126
+ harness,
42127
+ state: "unavailable",
42128
+ label: "Not verified",
42129
+ detail: "The local filesystem is unavailable, so native prompt routing cannot be checked.",
42130
+ configPath: null,
42131
+ configured: null,
42132
+ promptSubmissions: 0,
42133
+ subagentsStarted: 0,
42134
+ subagentsStopped: 0,
42135
+ reportedModels: [],
42136
+ lastObservedAt: null,
42137
+ receiptState: "unavailable"
42138
+ };
42139
+ }
42140
+ return observeNativePromptRouting({
42141
+ fs: base.adapters.fs,
42142
+ home: base.home,
42143
+ stateRoot: base.stateRoot ?? null,
42144
+ harness: harnessId(harness),
42145
+ version: null,
42146
+ runner: base.adapters.runner,
42147
+ facts: base.platform,
42148
+ paths: base.adapters.paths,
42149
+ projectRoot: base.cwd,
42150
+ projectId: base.adapters.projectIdFor(base.cwd)
42151
+ });
40971
42152
  });
40972
42153
  const token = randomBytes2(32).toString("hex");
40973
42154
  let authority = "";
@@ -41068,7 +42249,7 @@ async function runSavingsView(args, base) {
41068
42249
  }
41069
42250
  return result6.exitCode;
41070
42251
  }
41071
- var RTK_HOOK_PROXY_FLAG, MAX_HOOK_INPUT_BYTES, UI_SECURITY_HEADERS;
42252
+ var RTK_HOOK_PROXY_FLAG, PROMPT_ROUTER_FLAG, PROMPT_ROUTER_CHECK_MARKER2, MAX_HOOK_INPUT_BYTES, ROUTING_CONTEXT, UI_SECURITY_HEADERS;
41072
42253
  var init_main = __esm({
41073
42254
  "apps/cli/dist/src/main.js"() {
41074
42255
  "use strict";
@@ -41079,11 +42260,19 @@ var init_main = __esm({
41079
42260
  init_version2();
41080
42261
  init_guided();
41081
42262
  init_agent_skill();
42263
+ init_prompt_router();
41082
42264
  init_guided_candidate_campaign_status();
41083
42265
  init_guided_http();
41084
42266
  init_rtk_hook_proxy();
42267
+ init_prompt_router();
41085
42268
  RTK_HOOK_PROXY_FLAG = "__internal-rtk-hook";
42269
+ PROMPT_ROUTER_FLAG = "__internal-prompt-router";
42270
+ PROMPT_ROUTER_CHECK_MARKER2 = "token-harness-prompt-router-v1";
41086
42271
  MAX_HOOK_INPUT_BYTES = 1024 * 1024;
42272
+ ROUTING_CONTEXT = {
42273
+ codex: "For substantial coding work, delegate at most one independent bounded subtask to a native subagent with gpt-6-luna if available and the root is not Luna. Keep trivial, coupled, security, architecture, release, and integration decisions on the root. Specify the model; if unavailable, stay on the root. The root reviews. Claim savings only from paired, quality-gated measurements.",
42274
+ claude: "For substantial coding work, delegate at most one independent bounded subtask to a native subagent with the current Haiku alias if available and cheaper than the root. Keep trivial, coupled, security, architecture, release, and integration decisions on the root. Specify the model; if unavailable, stay on the root. The root reviews. Claim savings only from paired, quality-gated measurements."
42275
+ };
41087
42276
  UI_SECURITY_HEADERS = {
41088
42277
  "Cache-Control": "no-store",
41089
42278
  "Content-Security-Policy": "default-src 'self'; script-src 'self'; style-src 'self'; connect-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'",