token-harness 0.1.24 → 0.1.26

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
@@ -4675,35 +4675,36 @@ function detectUnownedEntries(input) {
4675
4675
  });
4676
4676
  }
4677
4677
  for (const config of input.configs) {
4678
- for (const point of config.interceptionPoints) {
4679
- for (const matcher of config.matchers) {
4680
- for (const [key, resolved] of exclusiveOwners) {
4681
- if (resolved.scope.harness !== config.harnessId)
4682
- continue;
4683
- if (resolved.scope.interceptionPoint !== point)
4684
- continue;
4685
- if (resolved.scope.toolFamily !== matcher)
4686
- continue;
4687
- for (const command of config.commands) {
4688
- const belongsTo = input.identify(command);
4689
- if (belongsTo === resolved.owner)
4690
- continue;
4691
- findings.push({
4692
- code: "unowned-entry-on-exclusive-scope",
4693
- scope: key,
4694
- expectedOwner: resolved.owner,
4695
- configPath: config.configPath,
4696
- matcher,
4697
- command,
4698
- detail: [
4699
- `${key} is an exclusive scope owned by ${resolved.owner}`,
4700
- belongsTo === null ? "An entry here invokes a command Token Harness does not recognise" : `An entry here invokes ${belongsTo}`,
4701
- "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"
4702
- ],
4703
- 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."
4704
- });
4705
- }
4706
- }
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
+ });
4707
4708
  }
4708
4709
  }
4709
4710
  }
@@ -9861,7 +9862,7 @@ var TOOL_VERSION;
9861
9862
  var init_version2 = __esm({
9862
9863
  "apps/cli/dist/src/version.js"() {
9863
9864
  "use strict";
9864
- TOOL_VERSION = "0.1.24";
9865
+ TOOL_VERSION = "0.1.26";
9865
9866
  }
9866
9867
  });
9867
9868
 
@@ -11922,6 +11923,50 @@ var init_windows_command_line = __esm({
11922
11923
  import { spawn } from "node:child_process";
11923
11924
  import { win32 as win324 } from "node:path";
11924
11925
  import process3 from "node:process";
11926
+ function launchGuidedApplication(input) {
11927
+ return new Promise((resolve, reject) => {
11928
+ const child = spawn(input.executable, [input.entryScript, "ui", "--no-open"], {
11929
+ cwd: input.cwd,
11930
+ env: minimalChildEnvironment({ facts: input.facts, ambient: input.env }),
11931
+ shell: false,
11932
+ windowsHide: true,
11933
+ detached: true,
11934
+ stdio: ["ignore", "ignore", "ignore", "ipc"]
11935
+ });
11936
+ let settled = false;
11937
+ const finish5 = (url) => {
11938
+ if (settled)
11939
+ return;
11940
+ settled = true;
11941
+ clearTimeout(timer);
11942
+ if (child.connected)
11943
+ child.disconnect();
11944
+ if (url === null) {
11945
+ child.kill();
11946
+ reject(new Error("The updated app could not start. The current dashboard remains open."));
11947
+ } else {
11948
+ child.unref();
11949
+ resolve(url);
11950
+ }
11951
+ };
11952
+ const timer = setTimeout(() => finish5(null), input.timeoutMs ?? 2e4);
11953
+ child.once("error", () => finish5(null));
11954
+ child.once("exit", () => finish5(null));
11955
+ child.on("message", (message) => {
11956
+ if (message === null || typeof message !== "object")
11957
+ return;
11958
+ const value3 = message;
11959
+ if (value3["type"] !== "token-harness-guide-ready" || typeof value3["url"] !== "string")
11960
+ return;
11961
+ try {
11962
+ const url = new URL(value3["url"]);
11963
+ if (url.protocol === "http:" && url.hostname === "127.0.0.1" && url.port !== "" && url.pathname === "/" && url.search === "" && url.hash === "" && url.username === "" && url.password === "")
11964
+ finish5(url.href);
11965
+ } catch {
11966
+ }
11967
+ });
11968
+ });
11969
+ }
11925
11970
  function boundedCapture(limit) {
11926
11971
  const chunks = [];
11927
11972
  let size = 0;
@@ -14215,7 +14260,9 @@ function readHooks(document2) {
14215
14260
  return [
14216
14261
  {
14217
14262
  eventName: point.eventName,
14263
+ interceptionPoint: point.scopeId,
14218
14264
  matcher: typeof matcher === "string" ? matcher : null,
14265
+ toolFamilies: typeof matcher !== "string" ? MANIFEST.toolFamilies.map((family) => family.id) : MANIFEST.toolFamilies.filter((family) => matcherCoversFamily(matcher, family.id)).map((family) => family.id),
14219
14266
  command: hook["command"],
14220
14267
  entryPointer,
14221
14268
  commandPointer: `${entryPointer}.hooks.${String(hookIndex)}.command`
@@ -14816,7 +14863,7 @@ function record5(value3) {
14816
14863
  function tuple(event, matcher, command) {
14817
14864
  return JSON.stringify([event, matcher, command]);
14818
14865
  }
14819
- async function readCodexHookEnablement(context, config) {
14866
+ async function readCodexHookEnablement(context, config, routingOnly = false) {
14820
14867
  const expected = [];
14821
14868
  try {
14822
14869
  const stat3 = await context.fs.stat(config.path);
@@ -14828,8 +14875,15 @@ async function readCodexHookEnablement(context, config) {
14828
14875
  return null;
14829
14876
  for (const [event, native] of [
14830
14877
  ["PreToolUse", "preToolUse"],
14831
- ["PostToolUse", "postToolUse"]
14878
+ ["PostToolUse", "postToolUse"],
14879
+ ...routingOnly ? [
14880
+ ["UserPromptSubmit", "userPromptSubmit"],
14881
+ ["SubagentStart", "subagentStart"],
14882
+ ["SubagentStop", "subagentStop"]
14883
+ ] : []
14832
14884
  ]) {
14885
+ if (routingOnly && !["UserPromptSubmit", "SubagentStart", "SubagentStop"].includes(event))
14886
+ continue;
14833
14887
  const entries = parsed["hooks"][event];
14834
14888
  if (!Array.isArray(entries))
14835
14889
  continue;
@@ -14838,7 +14892,7 @@ async function readCodexHookEnablement(context, config) {
14838
14892
  continue;
14839
14893
  const matcher = typeof entry["matcher"] === "string" ? entry["matcher"] : null;
14840
14894
  for (const handler of entry["hooks"]) {
14841
- if (record5(handler) && handler["type"] === "command" && typeof handler["command"] === "string") {
14895
+ if (record5(handler) && handler["type"] === "command" && typeof handler["command"] === "string" && (!routingOnly || handler["command"].includes("__internal-prompt-router"))) {
14842
14896
  expected.push(tuple(native, matcher, handler["command"]));
14843
14897
  }
14844
14898
  }
@@ -14960,7 +15014,7 @@ var init_codex_hooks = __esm({
14960
15014
  function isRecord3(value3) {
14961
15015
  return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
14962
15016
  }
14963
- function readHooks2(document2) {
15017
+ function readHooks2(document2, os) {
14964
15018
  if (!isRecord3(document2) || !isRecord3(document2["hooks"]))
14965
15019
  return { points: [], matchers: [], commands: [], hookCommands: [] };
14966
15020
  const hooks = document2["hooks"];
@@ -14981,15 +15035,21 @@ function readHooks2(document2) {
14981
15035
  matchers.push(matcher);
14982
15036
  if (Array.isArray(entry["hooks"])) {
14983
15037
  for (const [hookIndex, hook] of entry["hooks"].entries()) {
14984
- if (isRecord3(hook) && typeof hook["command"] === "string") {
14985
- commands.push(hook["command"]);
15038
+ if (!isRecord3(hook))
15039
+ continue;
15040
+ const commandKey = os === "windows" && typeof hook["commandWindows"] === "string" ? "commandWindows" : "command";
15041
+ const command = hook[commandKey];
15042
+ if (typeof command === "string") {
15043
+ commands.push(command);
14986
15044
  const entryPointer = `hooks.${point.eventName}.${String(entryIndex)}`;
14987
15045
  hookCommands.push({
14988
15046
  eventName: point.eventName,
15047
+ interceptionPoint: point.scopeId,
14989
15048
  matcher,
14990
- command: hook["command"],
15049
+ toolFamilies: matcher === null ? MANIFEST2.toolFamilies.map((family) => family.id) : MANIFEST2.toolFamilies.filter((family) => matcherCoversFamily(matcher, family.id)).map((family) => family.id),
15050
+ command,
14991
15051
  entryPointer,
14992
- commandPointer: `${entryPointer}.hooks.${String(hookIndex)}.command`
15052
+ commandPointer: `${entryPointer}.hooks.${String(hookIndex)}.${commandKey}`
14993
15053
  });
14994
15054
  carries = true;
14995
15055
  }
@@ -15034,7 +15094,7 @@ async function resolveConfig2(declaration, context) {
15034
15094
  };
15035
15095
  }
15036
15096
  try {
15037
- const hooks = readHooks2(JSON.parse(text3));
15097
+ const hooks = readHooks2(JSON.parse(text3), context.facts.os);
15038
15098
  return {
15039
15099
  declaration,
15040
15100
  path,
@@ -16728,7 +16788,13 @@ var init_pi = __esm({
16728
16788
  });
16729
16789
 
16730
16790
  // packages/adapters/dist/src/harnesses/native-prompt-routing.js
16731
- function nativePromptRoutingHookEntries(harness, executable = "token-harness") {
16791
+ function nativePromptRoutingVersionSupported(harness, version3) {
16792
+ const parsed = version3 === null ? null : parseSemanticVersion(version3);
16793
+ if (parsed === null || parsed.prerelease !== null)
16794
+ return false;
16795
+ return harness === "codex" ? parsed.major === 0 && (parsed.minor === 159 && parsed.patch <= 1 || parsed.minor === 160 && parsed.patch === 0) : harness === "claude" && parsed.major === 2 && parsed.minor === 1 && parsed.patch >= 274 && parsed.patch <= 288;
16796
+ }
16797
+ function nativePromptRoutingHookEntries(harness, executable = "token-harness", platform = "linux") {
16732
16798
  return NATIVE_PROMPT_ROUTING_EVENTS.map(({ eventName, commandEvent }) => {
16733
16799
  if (harness === "codex") {
16734
16800
  const command = `${executable} __internal-prompt-router codex ${commandEvent}`;
@@ -16742,7 +16808,11 @@ function nativePromptRoutingHookEntries(harness, executable = "token-harness") {
16742
16808
  handler2["additionalContextLimit"] = 500;
16743
16809
  return { eventName, value: { hooks: [handler2] } };
16744
16810
  }
16745
- const handler = {
16811
+ const handler = platform === "windows" ? {
16812
+ type: "command",
16813
+ command: `${executable} __internal-prompt-router claude ${commandEvent}`,
16814
+ timeout: 10
16815
+ } : {
16746
16816
  type: "command",
16747
16817
  command: executable,
16748
16818
  args: ["__internal-prompt-router", "claude", commandEvent],
@@ -16755,6 +16825,7 @@ var NATIVE_PROMPT_ROUTING_EVENTS;
16755
16825
  var init_native_prompt_routing = __esm({
16756
16826
  "packages/adapters/dist/src/harnesses/native-prompt-routing.js"() {
16757
16827
  "use strict";
16828
+ init_src();
16758
16829
  NATIVE_PROMPT_ROUTING_EVENTS = [
16759
16830
  { eventName: "UserPromptSubmit", commandEvent: "prompt-submit" },
16760
16831
  { eventName: "SubagentStart", commandEvent: "subagent-start" },
@@ -16788,6 +16859,7 @@ var init_harnesses = __esm({
16788
16859
  init_pi();
16789
16860
  init_claude();
16790
16861
  init_native_prompt_routing();
16862
+ init_codex_hooks();
16791
16863
  HARNESS_ADAPTERS = [
16792
16864
  claudeAdapter,
16793
16865
  codexAdapter,
@@ -18349,7 +18421,7 @@ function installAction(context, manifest) {
18349
18421
  packageName: channel.packageId ?? "rtk",
18350
18422
  // The managed Codex hook first exists in this RTK release. Pinning makes a fresh setup's
18351
18423
  // promised surface deterministic instead of installing an older prompt-only build.
18352
- version: "0.50.0"
18424
+ version: "0.51.0"
18353
18425
  };
18354
18426
  }
18355
18427
  function buildRtkPlan(input) {
@@ -18528,9 +18600,15 @@ async function readHarnessActivity(context, harness) {
18528
18600
  failure: null
18529
18601
  };
18530
18602
  }
18603
+ function supportsCodexHook(version3) {
18604
+ if (version3 === null)
18605
+ return false;
18606
+ const parsed = parseSemanticVersion(version3);
18607
+ const minimum = parseSemanticVersion(RTK_CODEX_HOOK_MINIMUM_VERSION);
18608
+ return parsed !== null && minimum !== null && compareVersions(parsed, minimum) >= 0;
18609
+ }
18531
18610
  function hasAttributionHook(context, harness) {
18532
- const command = new RegExp(`^token-harness __internal-rtk-hook ${harness}(?: --restore-rtk)?$`, "i");
18533
- return context.harnessConfigs.some((config) => config.harnessId === harness && config.commands.some((entry) => command.test(entry.trim())));
18611
+ return context.harnessConfigs.some((config) => config.harnessId === harness && config.commands.some((entry) => tokenHarnessRtkHookHarness(entry) === harness));
18534
18612
  }
18535
18613
  async function detect7(context) {
18536
18614
  const evidenceItems = [];
@@ -18554,7 +18632,7 @@ async function detect7(context) {
18554
18632
  remediation: "Check the release notes for analytics or hook changes before applying a plan"
18555
18633
  }));
18556
18634
  }
18557
- const codexHookSupported = version3.version === RTK_CODEX_HOOK_VERSION;
18635
+ const codexHookSupported = supportsCodexHook(version3.version);
18558
18636
  const codexConfiguredWithoutHookSupport = configured.includes(CODEX4) && !codexHookSupported;
18559
18637
  if (codexConfiguredWithoutHookSupport) {
18560
18638
  warnings.push(diagnostic({
@@ -18562,7 +18640,7 @@ async function detect7(context) {
18562
18640
  code: "rtk-codex-hook-unsupported",
18563
18641
  subject: CODEX4,
18564
18642
  message: `RTK ${String(version3.version)} does not provide the Codex hook; its configuration entry cannot capture commands`,
18565
- remediation: `Upgrade RTK to ${RTK_CODEX_HOOK_VERSION}, then refresh and apply the attribution plan`
18643
+ remediation: `Upgrade RTK to ${RTK_CODEX_HOOK_MINIMUM_VERSION}, then refresh and apply the attribution plan`
18566
18644
  }));
18567
18645
  }
18568
18646
  const state = version3.version === null ? configured.length > 0 ? "broken" : "absent" : codexConfiguredWithoutHookSupport && configured.length === 1 ? "broken" : configured.length > 0 ? "configured" : "installed";
@@ -18628,14 +18706,14 @@ async function verify7(context) {
18628
18706
  remediation: version3.version === null ? "Install RTK, or add it to PATH" : null
18629
18707
  });
18630
18708
  const configured = harnessesWiredToRtk(context.harnessConfigs);
18631
- const configuredSupported = configured.filter((harness) => harness === CLAUDE5 || harness === CODEX4 && version3.version === RTK_CODEX_HOOK_VERSION);
18709
+ const configuredSupported = configured.filter((harness) => harness === CLAUDE5 || harness === CODEX4 && supportsCodexHook(version3.version));
18632
18710
  checks.push({
18633
18711
  id: "hook-registered",
18634
18712
  status: configuredSupported.length > 0 ? "pass" : configured.length > 0 ? "fail" : "not-exercised",
18635
18713
  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",
18636
18714
  achievedTier: configuredSupported.length > 0 ? "config-only" : null,
18637
18715
  evidence: [],
18638
- remediation: configured.length > 0 && configuredSupported.length === 0 ? `Upgrade RTK to ${RTK_CODEX_HOOK_VERSION} for Codex hook support` : null
18716
+ remediation: configured.length > 0 && configuredSupported.length === 0 ? `Upgrade RTK to ${RTK_CODEX_HOOK_MINIMUM_VERSION} for Codex hook support` : null
18639
18717
  });
18640
18718
  let receipt = null;
18641
18719
  let bestReceiptTime = Number.NEGATIVE_INFINITY;
@@ -18643,7 +18721,7 @@ async function verify7(context) {
18643
18721
  if (!configured.includes(harness))
18644
18722
  continue;
18645
18723
  const label = harness === CLAUDE5 ? "Claude Code" : "Codex";
18646
- const supported = harness !== CODEX4 || version3.version === RTK_CODEX_HOOK_VERSION;
18724
+ const supported = harness !== CODEX4 || supportsCodexHook(version3.version);
18647
18725
  if (!supported) {
18648
18726
  checks.push({
18649
18727
  id: `rtk-attribution-${harness}`,
@@ -18651,7 +18729,7 @@ async function verify7(context) {
18651
18729
  summary: `RTK ${String(version3.version)} does not provide an active ${label} hook`,
18652
18730
  achievedTier: null,
18653
18731
  evidence: [],
18654
- remediation: `Upgrade RTK to ${RTK_CODEX_HOOK_VERSION}, then refresh and apply the tracking update`
18732
+ remediation: `Upgrade RTK to ${RTK_CODEX_HOOK_MINIMUM_VERSION}, then refresh and apply the tracking update`
18655
18733
  });
18656
18734
  continue;
18657
18735
  }
@@ -19046,7 +19124,20 @@ async function importHistorySource(context, store, path, attributedHarness) {
19046
19124
  };
19047
19125
  }
19048
19126
  function identifiesCommand2(command) {
19049
- return HOOK_COMMAND_PATTERN2.test(command) || PLUGIN_MODULE_PATTERN3.test(command) || /(^|[\\/\s"'])token-harness(?:\.cmd|\.exe)?\s+__internal-rtk-hook(?:\s|$)/i.test(command);
19127
+ return HOOK_COMMAND_PATTERN2.test(command) || PLUGIN_MODULE_PATTERN3.test(command) || tokenHarnessRtkHookHarness(command) !== null;
19128
+ }
19129
+ function tokenHarnessRtkHookHarness(command) {
19130
+ const match = /^\s*(?:"([^"]+)"|'([^']+)'|(\S+))\s+__internal-rtk-hook\s+(claude|codex)(?:\s+--restore-rtk)?\s*$/i.exec(command);
19131
+ if (match === null)
19132
+ return null;
19133
+ const executable = match[1] ?? match[2] ?? match[3];
19134
+ if (executable === void 0)
19135
+ return null;
19136
+ const basename = executable.split(/[\\/]/).at(-1);
19137
+ if (basename === void 0 || !/^token-harness(?:\.cmd|\.exe)?$/i.test(basename)) {
19138
+ return null;
19139
+ }
19140
+ return harnessId((match[4] ?? "").toLowerCase());
19050
19141
  }
19051
19142
  async function plan2(context, request) {
19052
19143
  const version3 = await readVersion(context);
@@ -19070,7 +19161,7 @@ async function plan2(context, request) {
19070
19161
  hookProxyAvailable
19071
19162
  });
19072
19163
  }
19073
- 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;
19164
+ 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;
19074
19165
  var init_rtk = __esm({
19075
19166
  "packages/adapters/dist/src/providers/rtk.js"() {
19076
19167
  "use strict";
@@ -19081,7 +19172,7 @@ var init_rtk = __esm({
19081
19172
  CODEX4 = harnessId("codex");
19082
19173
  OPENCODE3 = harnessId("opencode");
19083
19174
  TRACKED_HARNESSES = [CLAUDE5, CODEX4];
19084
- RTK_CODEX_HOOK_VERSION = "0.50.0";
19175
+ RTK_CODEX_HOOK_MINIMUM_VERSION = "0.50.0";
19085
19176
  MANIFEST7 = {
19086
19177
  schemaVersion: MANIFEST_SCHEMA_VERSION,
19087
19178
  id: RTK2,
@@ -19261,7 +19352,7 @@ var init_rtk = __esm({
19261
19352
  },
19262
19353
  delegatedInstallReviews: null
19263
19354
  };
19264
- TESTED_VERSIONS2 = { minimum: "0.44.0", maximum: "0.50.0" };
19355
+ TESTED_VERSIONS2 = { minimum: "0.44.0", maximum: "0.51.0" };
19265
19356
  VERSION_PATTERN7 = /(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/;
19266
19357
  HOOK_COMMAND_PATTERN2 = /(^|[\\/\s"'])rtk(\.exe)?([\s"']|$)/i;
19267
19358
  PLUGIN_MODULE_PATTERN3 = /(^|[\\/])rtk\.(ts|js|mjs|cjs|mts|cts)$/i;
@@ -20315,7 +20406,20 @@ ${help.stderr}`) : { compact: false, json: false };
20315
20406
  detail: ready ? `mcptoon ${version3} exposes the compact/JSON CLI surfaces used by the managed integration` : `mcptoon ${version3} no longer advertises the compact/JSON CLI surfaces required by the managed integration`
20316
20407
  };
20317
20408
  }
20318
- function mcptoonInstallAction() {
20409
+ async function mcptoonInstallChannel(context) {
20410
+ for (const channel of ["pipx", "uv"]) {
20411
+ const result6 = await context.runner.run({
20412
+ executable: channel,
20413
+ args: ["--version"],
20414
+ cwd: context.projectRoot,
20415
+ timeoutMs: 2e4
20416
+ });
20417
+ if (result6.failure === null && result6.exitCode === 0)
20418
+ return channel;
20419
+ }
20420
+ return null;
20421
+ }
20422
+ function mcptoonInstallAction(channel) {
20319
20423
  return {
20320
20424
  kind: "package-manager-install",
20321
20425
  id: `mcptoon:install:${MCPTOON_REVIEWED_INSTALL_VERSION}`,
@@ -20323,12 +20427,14 @@ function mcptoonInstallAction() {
20323
20427
  requiresNetwork: true,
20324
20428
  requiresElevation: false,
20325
20429
  affectedPaths: [],
20326
- affectedProcesses: ["pipx"],
20327
- preconditions: ["pipx remains runnable and the reviewed mcptoon release remains installable"],
20328
- postconditions: [`mcptoon ${MCPTOON_REVIEWED_INSTALL_VERSION} is installed through pipx`],
20430
+ affectedProcesses: [channel],
20431
+ preconditions: [
20432
+ `${channel} remains runnable and the reviewed mcptoon release remains installable`
20433
+ ],
20434
+ postconditions: [`mcptoon ${MCPTOON_REVIEWED_INSTALL_VERSION} is installed through ${channel}`],
20329
20435
  rollbackData: "package-inventory",
20330
- explanation: `Install reviewed mcptoon ${MCPTOON_REVIEWED_INSTALL_VERSION} in an isolated pipx environment`,
20331
- packageManager: "pipx",
20436
+ explanation: `Install reviewed mcptoon ${MCPTOON_REVIEWED_INSTALL_VERSION} in an isolated ${channel} environment`,
20437
+ packageManager: channel,
20332
20438
  packageName: "mcptoon",
20333
20439
  version: MCPTOON_REVIEWED_INSTALL_VERSION
20334
20440
  };
@@ -20549,13 +20655,8 @@ async function planMcptoonManagedActivation(context, harness) {
20549
20655
  if (activation.actions.length === 0 && !activationSatisfied) {
20550
20656
  return activation;
20551
20657
  }
20552
- const pipx = await context.runner.run({
20553
- executable: "pipx",
20554
- args: ["--version"],
20555
- cwd: context.projectRoot,
20556
- timeoutMs: 2e4
20557
- });
20558
- if (pipx.failure !== null || pipx.exitCode !== 0) {
20658
+ const channel = await mcptoonInstallChannel(context);
20659
+ if (channel === null) {
20559
20660
  return {
20560
20661
  harness,
20561
20662
  target: activation.target,
@@ -20566,22 +20667,22 @@ async function planMcptoonManagedActivation(context, harness) {
20566
20667
  severity: "warning",
20567
20668
  code: "mcptoon-pipx-unavailable",
20568
20669
  subject: harness,
20569
- message: "mcptoon is absent and the isolated pipx installer is not available",
20570
- remediation: "Install pipx, then refresh Token Harness; Token Harness will not bootstrap a Python package manager implicitly"
20670
+ message: "mcptoon needs an isolated installer: pipx or uv",
20671
+ remediation: "Install pipx or uv, then Refresh to enable Install mcptoon. See Installation options for the platform instructions."
20571
20672
  })
20572
20673
  ]
20573
20674
  };
20574
20675
  }
20575
20676
  return {
20576
20677
  ...activation,
20577
- actions: [mcptoonInstallAction(), ...activation.actions],
20678
+ actions: [mcptoonInstallAction(channel), ...activation.actions],
20578
20679
  diagnostics: [
20579
20680
  ...activation.diagnostics,
20580
20681
  diagnostic({
20581
20682
  severity: "info",
20582
20683
  code: "mcptoon-managed-install-planned",
20583
20684
  subject: harness,
20584
- message: `mcptoon is absent; install reviewed ${MCPTOON_REVIEWED_INSTALL_VERSION} through pipx before enabling agent guidance`,
20685
+ message: `mcptoon is absent; install reviewed ${MCPTOON_REVIEWED_INSTALL_VERSION} through ${channel} before enabling agent guidance`,
20585
20686
  remediation: null
20586
20687
  })
20587
20688
  ]
@@ -20715,20 +20816,15 @@ async function mcptoonDetection(context) {
20715
20816
  configuredHarnesses.push(harness);
20716
20817
  }
20717
20818
  }
20718
- const pipx = observation.absent ? await context.runner.run({
20719
- executable: "pipx",
20720
- args: ["--version"],
20721
- cwd: context.projectRoot,
20722
- timeoutMs: 2e4
20723
- }) : null;
20724
- const canInstall = observation.absent && pipx !== null && pipx.failure === null && pipx.exitCode === 0;
20819
+ const channel = observation.absent ? await mcptoonInstallChannel(context) : null;
20820
+ const canInstall = observation.absent && channel !== null;
20725
20821
  const warnings = observation.absent && !canInstall ? [
20726
20822
  diagnostic({
20727
20823
  severity: "warning",
20728
20824
  code: "mcptoon-pipx-unavailable",
20729
20825
  subject: "mcptoon",
20730
- message: "mcptoon is not installed and pipx is not available in this terminal",
20731
- remediation: "Install pipx or make it available on PATH, then refresh. Token Harness will use it to install the reviewed mcptoon build."
20826
+ message: "mcptoon is not installed; pipx or uv is required",
20827
+ remediation: "Install pipx or uv, then Refresh to enable Install mcptoon. Open Installation options for your platform."
20732
20828
  })
20733
20829
  ] : !observation.absent && !observation.ready ? [warning("mcptoon-provider-capability-unavailable", "mcptoon", observation.detail)] : [];
20734
20830
  return {
@@ -20736,7 +20832,7 @@ async function mcptoonDetection(context) {
20736
20832
  state: observation.absent ? "absent" : configuredHarnesses.length > 0 ? "configured" : "installed",
20737
20833
  version: observation.version,
20738
20834
  executable: observation.executable,
20739
- installationChannel: observation.absent ? "pipx" : null,
20835
+ installationChannel: observation.absent ? channel : null,
20740
20836
  versionVerdict: versionVerdict(observation.version, MCPTOON_REVIEWED_BENCHMARK_VERSION),
20741
20837
  configuredHarnesses,
20742
20838
  unmanagedHarnessesConfigured: [],
@@ -20947,6 +21043,16 @@ var init_managed_optimization_tools = __esm({
20947
21043
  requiresNetwork: true,
20948
21044
  requiresElevation: false,
20949
21045
  digestAvailable: false
21046
+ },
21047
+ {
21048
+ id: "uv",
21049
+ packageId: "mcptoon",
21050
+ kind: "uv",
21051
+ priority: 1,
21052
+ platforms: ["windows", "macos", "linux"],
21053
+ requiresNetwork: true,
21054
+ requiresElevation: false,
21055
+ digestAvailable: false
20950
21056
  }
20951
21057
  ],
20952
21058
  metrics: { source: "none", mode: "unavailable", locations: [] },
@@ -21941,7 +22047,7 @@ var init_version_compatibility = __esm({
21941
22047
  GITNEXUS2 = providerId("gitnexus");
21942
22048
  HEADROOM3 = providerId("headroom");
21943
22049
  PACKAGE_UPDATE_BASELINES = /* @__PURE__ */ new Map([
21944
- [RTK3, { minimum: "0.44.0", maximum: "0.50.0" }],
22050
+ [RTK3, { minimum: "0.44.0", maximum: "0.51.0" }],
21945
22051
  [HARNESSTRIM3, { minimum: "0.0.5", maximum: "0.3.1" }],
21946
22052
  [
21947
22053
  MCPTOON2,
@@ -22961,9 +23067,6 @@ var init_argv = __esm({
22961
23067
  function isHarness(value3) {
22962
23068
  return value3 === "claude" || value3 === "codex";
22963
23069
  }
22964
- function expectedVersions(harness) {
22965
- return harness === "codex" ? ["0.159.0", "0.160.0"] : ["2.1.274", "2.1.288"];
22966
- }
22967
23070
  function configTarget(input) {
22968
23071
  if (!isHarness(input.harness) || input.home === null)
22969
23072
  return null;
@@ -22985,8 +23088,8 @@ function configTarget(input) {
22985
23088
  fileContext
22986
23089
  };
22987
23090
  }
22988
- function hookEntries(harness) {
22989
- return nativePromptRoutingHookEntries(harnessId(harness), "token-harness");
23091
+ function hookEntries(harness, platform = "linux") {
23092
+ return nativePromptRoutingHookEntries(harnessId(harness), "token-harness", platform);
22990
23093
  }
22991
23094
  function asRecord(value3) {
22992
23095
  return typeof value3 === "object" && value3 !== null && !Array.isArray(value3) ? value3 : null;
@@ -23026,13 +23129,13 @@ function containsRouterCommand(value3, harness) {
23026
23129
  if (harness === "codex")
23027
23130
  return [handler["command"], handler["commandWindows"]].some((command) => typeof command === "string" && command.includes(ROUTE_MARKER));
23028
23131
  const args = handler["args"];
23029
- return handler["command"] === "token-harness" && Array.isArray(args) && args[0] === ROUTE_MARKER;
23132
+ return typeof handler["command"] === "string" && handler["command"].includes(ROUTE_MARKER) || handler["command"] === "token-harness" && Array.isArray(args) && args[0] === ROUTE_MARKER;
23030
23133
  });
23031
23134
  }
23032
- function configHasExactRouter(hooks, harness) {
23135
+ function configHasExactRouter(hooks, harness, platform) {
23033
23136
  let exactCount = 0;
23034
23137
  let routeCount = 0;
23035
- for (const expected of hookEntries(harness)) {
23138
+ for (const expected of hookEntries(harness, platform)) {
23036
23139
  const live = hooks[expected.eventName];
23037
23140
  const entries = Array.isArray(live) ? live : [];
23038
23141
  const routeEntries = entries.filter((entry) => containsRouterCommand(entry, harness));
@@ -23041,13 +23144,13 @@ function configHasExactRouter(hooks, harness) {
23041
23144
  exactCount += 1;
23042
23145
  }
23043
23146
  return {
23044
- complete: exactCount === hookEntries(harness).length,
23045
- partial: routeCount > 0 && exactCount !== hookEntries(harness).length,
23147
+ complete: exactCount === hookEntries(harness, platform).length,
23148
+ partial: routeCount > 0 && exactCount !== hookEntries(harness, platform).length,
23046
23149
  conflict: routeCount > exactCount
23047
23150
  };
23048
23151
  }
23049
- function routerOwnedArtifacts(journals, path, harness) {
23050
- const expected = hookEntries(harness);
23152
+ function routerOwnedArtifacts(journals, path, harness, platform) {
23153
+ const expected = hookEntries(harness, platform);
23051
23154
  for (const journal of journals) {
23052
23155
  const disabledHere = journal.entries.some((entry) => entry.actionId.startsWith(`native-prompt-routing:${harness}:disable:`) && entry.snapshots.some((snapshot) => snapshot.path === path));
23053
23156
  if (disabledHere && journal.outcome === "committed")
@@ -23086,14 +23189,14 @@ async function planNativePromptRoutingInstall(input) {
23086
23189
  }));
23087
23190
  return { target: null, actions: [], diagnostics };
23088
23191
  }
23089
- if (!expectedVersions(target.harness).includes(target.version ?? "")) {
23192
+ if (!nativePromptRoutingVersionSupported(harnessId(target.harness), target.version)) {
23090
23193
  diagnostics.push(diagnostic({
23091
23194
  severity: "warning",
23092
23195
  code: "prompt-routing-version-unverified",
23093
23196
  subject: target.harness,
23094
- message: `Native prompt routing has no hook fixture for ${target.harness} ${target.version ?? "unknown"}`,
23197
+ message: `Routing is not supported for ${target.harness} ${target.version ?? "(version unknown)"}. Check Token Harness updates in Health and updates, then retry.`,
23095
23198
  path: target.path,
23096
- remediation: "Refresh Token Harness after the installed harness hook schema is fixture-tested"
23199
+ remediation: "Check for Token Harness updates; this agent version needs a verified hook fixture"
23097
23200
  }));
23098
23201
  return { target: target.path, actions: [], diagnostics };
23099
23202
  }
@@ -23143,7 +23246,7 @@ async function planNativePromptRoutingInstall(input) {
23143
23246
  }
23144
23247
  hooks = parsed.hooks;
23145
23248
  }
23146
- const existing = configHasExactRouter(hooks, target.harness);
23249
+ const existing = configHasExactRouter(hooks, target.harness, input.facts.os);
23147
23250
  if (existing.complete) {
23148
23251
  diagnostics.push(diagnostic({
23149
23252
  severity: "info",
@@ -23155,7 +23258,10 @@ async function planNativePromptRoutingInstall(input) {
23155
23258
  }));
23156
23259
  return { target: target.path, actions: [], diagnostics };
23157
23260
  }
23158
- if (existing.partial || existing.conflict) {
23261
+ const legacy = target.harness === "claude" && input.facts.os === "windows" ? configHasExactRouter(hooks, target.harness, "linux") : null;
23262
+ const legacyOwned = legacy?.complete && !legacy.conflict ? routerOwnedArtifacts(await journalsFor({ fs: input.fs, stateRoot: input.stateRoot ?? null }), target.path, target.harness, "linux") : [];
23263
+ const repair = legacyOwned.length === 3;
23264
+ if ((existing.partial || existing.conflict) && !repair) {
23159
23265
  diagnostics.push(diagnostic({
23160
23266
  severity: "error",
23161
23267
  code: "prompt-routing-existing-hook-conflict",
@@ -23166,7 +23272,7 @@ async function planNativePromptRoutingInstall(input) {
23166
23272
  }));
23167
23273
  return { target: target.path, actions: [], diagnostics };
23168
23274
  }
23169
- const entries = hookEntries(target.harness);
23275
+ const entries = hookEntries(target.harness, input.facts.os);
23170
23276
  const action = {
23171
23277
  kind: "merge-json",
23172
23278
  id: actionId(target.harness, "enable", "all"),
@@ -23192,7 +23298,8 @@ async function planNativePromptRoutingInstall(input) {
23192
23298
  })),
23193
23299
  createIfMissing: true
23194
23300
  };
23195
- return { target: target.path, actions: [action], diagnostics };
23301
+ const removals = repair ? await planNativePromptRoutingRemoval({ ...input, stateRoot: input.stateRoot ?? null }) : null;
23302
+ return { target: target.path, actions: [...removals?.actions ?? [], action], diagnostics };
23196
23303
  }
23197
23304
  async function planNativePromptRoutingRemoval(input) {
23198
23305
  const diagnostics = [];
@@ -23207,9 +23314,13 @@ async function planNativePromptRoutingRemoval(input) {
23207
23314
  }));
23208
23315
  return { target: target?.path ?? null, actions: [], diagnostics };
23209
23316
  }
23210
- const expected = hookEntries(target.harness);
23317
+ let expected = hookEntries(target.harness, input.facts.os);
23211
23318
  const journals = await journalsFor({ fs: input.fs, stateRoot: input.stateRoot });
23212
- const artifacts = routerOwnedArtifacts(journals, target.path, target.harness);
23319
+ let artifacts = routerOwnedArtifacts(journals, target.path, target.harness, input.facts.os);
23320
+ if (artifacts.length === 0 && target.harness === "claude" && input.facts.os === "windows") {
23321
+ expected = hookEntries(target.harness, "linux");
23322
+ artifacts = routerOwnedArtifacts(journals, target.path, target.harness, "linux");
23323
+ }
23213
23324
  const actions = expected.flatMap((entry) => {
23214
23325
  const pointer = `hooks.${entry.eventName}`;
23215
23326
  const targetArtifact = artifacts.find((artifact) => artifact.kind === "owned-json-entry" && artifact.pointer === pointer && artifact.valueDigest === jsonValueDigest(entry.value));
@@ -23353,7 +23464,9 @@ async function observeNativePromptRouting(input) {
23353
23464
  subagentsStopped: 0,
23354
23465
  reportedModels: [],
23355
23466
  lastObservedAt: null,
23356
- receiptState: "unavailable"
23467
+ receiptState: "unavailable",
23468
+ enablement: "unknown",
23469
+ verificationTier: "config-only"
23357
23470
  };
23358
23471
  const target = configTarget({ ...input, harness: input.harness });
23359
23472
  if (target === null)
@@ -23414,7 +23527,23 @@ async function observeNativePromptRouting(input) {
23414
23527
  receiptState: eventResult.state
23415
23528
  };
23416
23529
  }
23417
- const match = configHasExactRouter(hooks, harness);
23530
+ const match = configHasExactRouter(hooks, harness, input.facts.os);
23531
+ if (harness === "claude" && input.facts.os === "windows" && (match.partial || match.conflict)) {
23532
+ const legacy = configHasExactRouter(hooks, harness, "linux");
23533
+ const owned = routerOwnedArtifacts(await journalsFor(input), target.path, harness, "linux");
23534
+ if (legacy.complete && !legacy.conflict && owned.length === 3)
23535
+ return {
23536
+ ...base,
23537
+ ...summary,
23538
+ state: "managed",
23539
+ label: "Repair required",
23540
+ configured: false,
23541
+ configPath: target.path,
23542
+ needsRepair: true,
23543
+ receiptState: eventResult.state,
23544
+ detail: "The installed routing hook cannot launch the Windows npm command. Choose Repair routing once; future prompts run automatically."
23545
+ };
23546
+ }
23418
23547
  if (match.conflict || match.partial) {
23419
23548
  return {
23420
23549
  ...base,
@@ -23438,16 +23567,54 @@ async function observeNativePromptRouting(input) {
23438
23567
  receiptState: eventResult.state
23439
23568
  };
23440
23569
  }
23441
- const artifacts = routerOwnedArtifacts(await journalsFor(input), target.path, harness);
23442
- const state = artifacts.length === hookEntries(harness).length ? "managed" : "external";
23570
+ const artifacts = routerOwnedArtifacts(await journalsFor(input), target.path, harness, input.facts.os);
23571
+ const state = artifacts.length === hookEntries(harness, input.facts.os).length ? "managed" : "external";
23443
23572
  const hasRuntimeReceipt = summary.promptSubmissions > 0;
23444
- 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";
23445
- 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.";
23573
+ let enablement = "unknown";
23574
+ if (harness === "codex") {
23575
+ const declaration = findHarnessAdapter(harnessId(harness)).manifest.configFiles.find((file) => file.parser === "json" && file.scope === "user");
23576
+ const check = await readCodexHookEnablement(target.fileContext, {
23577
+ declaration,
23578
+ path: target.path,
23579
+ exists: true,
23580
+ parsed: true,
23581
+ configuredPoints: [],
23582
+ matchers: [],
23583
+ commands: []
23584
+ }, true);
23585
+ if (check?.status === "pass")
23586
+ enablement = "enabled";
23587
+ else if (check?.status === "fail")
23588
+ enablement = /[1-9]\d* untrusted/.test(check.summary) ? "untrusted" : "disabled";
23589
+ } else {
23590
+ const adapter = findHarnessAdapter(harnessId(harness));
23591
+ let disabled = false;
23592
+ let readable = true;
23593
+ for (const declaration of adapter.manifest.configFiles) {
23594
+ const path = resolveConfigPath(declaration, target.fileContext);
23595
+ if ((await input.fs.stat(path))?.kind !== "file")
23596
+ continue;
23597
+ try {
23598
+ const doc = asRecord(JSON.parse(DECODER4.decode(await input.fs.readFile(path))));
23599
+ if (typeof doc?.["disableAllHooks"] === "boolean")
23600
+ disabled = doc["disableAllHooks"];
23601
+ } catch {
23602
+ readable = false;
23603
+ }
23604
+ }
23605
+ enablement = readable ? disabled ? "disabled" : "enabled" : "unknown";
23606
+ }
23607
+ const blocked = enablement === "untrusted" || enablement === "disabled";
23608
+ const label = blocked ? enablement === "untrusted" ? "Authorization required" : "Hooks disabled" : hasRuntimeReceipt ? "Runtime observed" : enablement === "enabled" ? "Ready \xB7 awaiting prompt" : "Configured \xB7 check authorization";
23609
+ const scope = input.projectId === null ? "across projects" : "in this project";
23610
+ const detail2 = blocked ? harness === "codex" ? "Open Codex /hooks. Enable and trust the three Token Harness routing hooks once, then send a prompt." : "Hooks are disabled in Claude settings. Enable hooks in /hooks, then send a prompt." : hasRuntimeReceipt ? `${String(summary.promptSubmissions)} prompt callbacks, ${String(summary.subagentsStarted)} agent starts, ${String(summary.subagentsStopped)} stops ${scope} in the last 30 days. Routing runs automatically on each prompt.${eventResult.state === "limited" ? " Counts are partial." : ""}` : enablement === "enabled" ? "Ready. Send a prompt in a new session; the first callback will appear here automatically. No skill or command is needed per prompt." : harness === "codex" ? "Open Codex /hooks and check the three Token Harness routing hooks are enabled and trusted. Do this once, then send a prompt in a new session." : "Check the Claude hook settings can be read and hooks are enabled in /hooks, then send a prompt in a new session.";
23446
23611
  return {
23447
23612
  ...base,
23448
23613
  state,
23449
23614
  label,
23450
23615
  detail: detail2,
23616
+ enablement,
23617
+ verificationTier: hasRuntimeReceipt && !blocked ? "runtime-observed" : "config-only",
23451
23618
  configPath: target.path,
23452
23619
  configured: true,
23453
23620
  ...summary,
@@ -26821,6 +26988,14 @@ async function computePlan(context) {
26821
26988
  ],
26822
26989
  remediation: "Give each provider a distinct marker pair, or disable one of the providers for this instruction region"
26823
26990
  }));
26991
+ if (providerAdapters.length === 0 && context.provider !== providerId("none") && actions.length === 0) {
26992
+ diagnostics.push(diagnostic({
26993
+ severity: "info",
26994
+ code: "no-providers-registered",
26995
+ message: "No optimization provider is available for this operation",
26996
+ remediation: null
26997
+ }));
26998
+ }
26824
26999
  const conflicts = [...resolution.conflicts, ...markerConflicts];
26825
27000
  const report = {
26826
27001
  // RFC 0006 §Plan persistence: "a digest over the plan's normalized content, so identical
@@ -26869,14 +27044,6 @@ async function computePlan(context) {
26869
27044
  remediation: null
26870
27045
  }));
26871
27046
  }
26872
- if (providerAdapters.length === 0) {
26873
- diagnostics.push(diagnostic({
26874
- severity: "info",
26875
- code: "no-providers-registered",
26876
- message: "No provider adapters are registered in this build, so no plan has actions",
26877
- remediation: null
26878
- }));
26879
- }
26880
27047
  if (resolution.ownership.length > 0 && actions.length === 0 && blocked.length === 0) {
26881
27048
  diagnostics.push(diagnostic({
26882
27049
  severity: "info",
@@ -27348,7 +27515,7 @@ async function runApply(context) {
27348
27515
  now: context.now,
27349
27516
  verifyPostconditions: async () => [
27350
27517
  ...await verifyManagedIntegrationPostconditions(context, computed.managedIntegrations),
27351
- ...await verifyNativePromptRoutingPostconditions(context, actions)
27518
+ ...await verifyNativePromptRoutingPostconditions(planningContext, actions)
27352
27519
  ]
27353
27520
  });
27354
27521
  diagnostics.push(...transaction.diagnostics);
@@ -35474,9 +35641,9 @@ function guideSetupTargets(report, harness) {
35474
35641
  return GUIDE_MANAGED_PROVIDERS.map((provider) => guideSetupTarget(report, harness, provider));
35475
35642
  }
35476
35643
  function explainGuideIssue(diagnostics, fallback) {
35477
- const known = diagnostics.find((entry) => ISSUE_COPY[entry.code] !== void 0);
35644
+ 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);
35478
35645
  if (known !== void 0)
35479
- return ISSUE_COPY[known.code];
35646
+ return known.code === "prompt-routing-version-unverified" ? known.message : ISSUE_COPY[known.code];
35480
35647
  const blocked = diagnostics.find((entry) => /compatibility|unsupported|unreviewed|no-row/.test(entry.code));
35481
35648
  if (blocked !== void 0)
35482
35649
  return "The required automatic capability or safety precondition is not available in the current runtime. Your current settings are preserved.";
@@ -35824,6 +35991,13 @@ var init_guided = __esm({
35824
35991
  "codex-native-policy-unavailable": "Codex did not expose a writable, versioned user setting. No change is proposed.",
35825
35992
  "codex-native-policy-shadowed": "A project or profile overrides this Codex setting. That setting belongs to you and will not be replaced.",
35826
35993
  "no-providers-registered": "No optimization provider was selected for this operation.",
35994
+ "prompt-routing-target-unavailable": "Token Harness could not locate a supported user-level prompt-hook settings file for this agent.",
35995
+ "prompt-routing-version-unverified": "Update Token Harness in Health and updates, then retry routing. This agent version is not supported by this copy.",
35996
+ "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.",
35997
+ "prompt-routing-target-not-file": "A non-file occupies the agent hook settings path, so Token Harness left it unchanged.",
35998
+ "prompt-routing-settings-unmergeable": "The current hook settings cannot be merged safely. Repair the JSON or review the hook manually.",
35999
+ "prompt-routing-already-configured": "Automatic routing hooks are already present. Nothing needs to be changed.",
36000
+ "prompt-routing-existing-hook-conflict": "An existing Token Harness routing hook was changed or only partly installed. It was left untouched for review.",
35827
36001
  "already-in-desired-state": "The supported integration is already configured. Nothing needs to be changed.",
35828
36002
  "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.",
35829
36003
  "delegated-install-failed": "The optimizer installer itself did not complete successfully. Nothing was kept from the failed transaction.",
@@ -35912,6 +36086,8 @@ var init_guided = __esm({
35912
36086
  loading = null;
35913
36087
  readSequence = 0;
35914
36088
  busy = false;
36089
+ restartVersion = null;
36090
+ restartApplication;
35915
36091
  lastApplied = null;
35916
36092
  reading = null;
35917
36093
  cached = null;
@@ -35924,12 +36100,13 @@ var init_guided = __esm({
35924
36100
  random;
35925
36101
  observeGuidance;
35926
36102
  observeRouting;
35927
- constructor(call, now, random, observeGuidance = null, observeRouting = null) {
36103
+ constructor(call, now, random, observeGuidance = null, observeRouting = null, restartApplication = null) {
35928
36104
  this.call = call;
35929
36105
  this.now = now;
35930
36106
  this.random = random;
35931
36107
  this.observeGuidance = observeGuidance;
35932
36108
  this.observeRouting = observeRouting;
36109
+ this.restartApplication = restartApplication;
35933
36110
  }
35934
36111
  status() {
35935
36112
  return {
@@ -36569,21 +36746,40 @@ var init_guided = __esm({
36569
36746
  }
36570
36747
  this.lastApplied = null;
36571
36748
  this.invalidateObservedState();
36749
+ this.record("Re-checking health after the update.", "working");
36750
+ let health;
36751
+ try {
36752
+ health = await this.verifyIntegrations();
36753
+ } catch {
36754
+ health = {
36755
+ ok: false,
36756
+ title: "Health check needs attention",
36757
+ messages: ["Update installed; automatic health check could not finish."],
36758
+ appliedPlans: 0
36759
+ };
36760
+ }
36761
+ if (applicationTarget !== void 0)
36762
+ this.restartVersion = applicationTarget.version;
36572
36763
  const versions = approvedUpdates.map((target) => `${guideUpdateTargetName(target)} ${target.version}`).join(", ");
36573
36764
  const messages2 = [
36574
36765
  appliedCount > 0 ? `Installed and verified the approved update${approvedUpdates.length === 1 ? "" : "s"}: ${versions}.` : `The approved update${approvedUpdates.length === 1 ? " was" : "s were"} already at the target version: ${versions}.`,
36575
- ...applicationTarget === void 0 ? [] : ["Token Harness is updated on disk. Restart this app to load the new version."],
36766
+ ...applicationTarget === void 0 ? [] : [
36767
+ "Token Harness is updated. Choose Restart and re-check to load it and discover new capabilities."
36768
+ ],
36576
36769
  ...providerTargets.length === 0 ? [] : [
36577
36770
  "The active optimizer runtimes were re-read after the operation and match the approved targets.",
36578
36771
  "Reopen a coding agent if an updated optimizer requires it."
36579
36772
  ]
36580
36773
  ];
36774
+ messages2.push(health.ok ? "Health re-check completed automatically." : "Update installed; health needs attention.", ...health.messages);
36581
36775
  this.record(appliedCount > 0 ? "Approved updates installed and verified." : "Approved updates are already at their target versions.", "success");
36582
36776
  return {
36583
36777
  ok: true,
36584
36778
  title: applicationTarget !== void 0 ? "Token Harness updated" : appliedCount > 0 ? "Optimizers updated" : "Approved versions already active",
36585
36779
  messages: messages2,
36586
- appliedPlans: appliedCount
36780
+ appliedPlans: appliedCount,
36781
+ ...health.stack === void 0 ? {} : { stack: health.stack },
36782
+ restartRequired: applicationTarget !== void 0
36587
36783
  };
36588
36784
  }
36589
36785
  if (approval.operation === "candidate-apply" || approval.operation === "candidate-uninstall") {
@@ -36739,6 +36935,34 @@ var init_guided = __esm({
36739
36935
  };
36740
36936
  });
36741
36937
  }
36938
+ async routing() {
36939
+ if (this.observeRouting === null)
36940
+ return { agents: [] };
36941
+ const agents = await Promise.all(["claude", "codex"].map(async (id) => ({
36942
+ id,
36943
+ promptRouting: await this.observeRouting(id)
36944
+ })));
36945
+ if (this.cached !== null) {
36946
+ for (const agent of this.cached.value.agents) {
36947
+ const live = agents.find((item) => item.id === agent.id);
36948
+ if (live !== void 0)
36949
+ agent.promptRouting = live.promptRouting;
36950
+ }
36951
+ }
36952
+ return { agents };
36953
+ }
36954
+ async restart() {
36955
+ return this.exclusive(async () => {
36956
+ if (this.restartVersion === null || this.restartApplication === null)
36957
+ throw new GuideError(409, "Restart is available after a verified Token Harness update.");
36958
+ const installed2 = await this.call(["update"]);
36959
+ if (!sameGuideVersion(installed2.data?.application?.installed ?? null, this.restartVersion))
36960
+ throw new GuideError(409, "The installation changed. Check updates again before restarting.");
36961
+ const url = await this.restartApplication();
36962
+ this.restartVersion = null;
36963
+ return { url };
36964
+ });
36965
+ }
36742
36966
  async checkUpdates() {
36743
36967
  return this.exclusive(async () => {
36744
36968
  this.approval = null;
@@ -36857,54 +37081,90 @@ var init_guided = __esm({
36857
37081
  });
36858
37082
  }
36859
37083
  async verify() {
36860
- return this.exclusive(async () => {
36861
- this.record("Checking the configured integrations without changing them.", "working");
36862
- const messages = [];
36863
- const results = [];
36864
- let ok = true;
36865
- const inventory = await this.call(["doctor"]);
36866
- const present = (inventory.data?.harnesses ?? []).filter((item) => item.state !== "absent" && ["claude", "codex"].includes(item.harnessId));
36867
- if (present.length === 0) {
37084
+ return this.exclusive(() => this.verifyIntegrations());
37085
+ }
37086
+ async verifyIntegrations() {
37087
+ this.record("Checking the configured integrations without changing them.", "working");
37088
+ const messages = [];
37089
+ const results = [];
37090
+ let ok = true;
37091
+ let healthyAtDeclaredTier = true;
37092
+ const inventory = await this.call(["doctor"]);
37093
+ const present = (inventory.data?.harnesses ?? []).filter((item) => item.state !== "absent" && ["claude", "codex"].includes(item.harnessId));
37094
+ if (inventory.data === null) {
37095
+ ok = false;
37096
+ healthyAtDeclaredTier = false;
37097
+ messages.push("The installed-agent inventory could not be read. Refresh and check the local installation.");
37098
+ }
37099
+ if (present.length === 0) {
37100
+ ok = false;
37101
+ healthyAtDeclaredTier = false;
37102
+ messages.push("No supported installed agent was detected, so no integration was checked.");
37103
+ }
37104
+ for (const agent of present) {
37105
+ const harness = agent.harnessId;
37106
+ this.record(`Checking ${name(harness)} configuration and available execution evidence. No settings changed.`, "working");
37107
+ const result6 = await this.call(["verify", "--harness", harness]);
37108
+ const healthy = result6.data?.healthyAtDeclaredTier === true;
37109
+ const versionWarnings = result6.diagnostics.filter((entry) => entry.severity === "warning" && (entry.code === "harness-version-unknown-newer" || entry.code === "provider-version-unknown-newer"));
37110
+ 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");
37111
+ if (failed)
36868
37112
  ok = false;
36869
- messages.push("No supported installed agent could be checked. Refresh after installing or signing in.");
36870
- }
36871
- for (const agent of present) {
36872
- const harness = agent.harnessId;
36873
- this.record(`Checking ${name(harness)} configuration and available execution evidence. No settings changed.`, "working");
36874
- const result6 = await this.call(["verify", "--harness", harness]);
36875
- const healthy = result6.data?.healthyAtDeclaredTier === true;
36876
- if (!healthy)
36877
- ok = false;
36878
- if (result6.data !== null)
36879
- results.push(...result6.data.results);
36880
- 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.")}`);
36881
- }
36882
- if (inventory.data !== null) {
36883
- const fingerprint = stackFingerprint(inventory.data);
36884
- this.verification = {
36885
- fingerprint,
36886
- report: {
36887
- receiptId: null,
36888
- appliedAt: null,
36889
- results,
36890
- healthyAtDeclaredTier: ok
36891
- }
36892
- };
36893
- this.stackBase = {
36894
- detections: [...inventory.data.providers],
36895
- metrics: this.stackBase?.metrics ?? null,
36896
- drift: this.stackBase?.drift ?? [],
36897
- fingerprint
36898
- };
37113
+ if (!healthy)
37114
+ healthyAtDeclaredTier = false;
37115
+ if (result6.data !== null)
37116
+ results.push(...result6.data.results);
37117
+ const prefix = `${name(harness)}: `;
37118
+ if (result6.data === null) {
37119
+ messages.push(prefix + "the verification report could not be read. Refresh and check the local installation.");
37120
+ } else if (healthy) {
37121
+ messages.push(prefix + "the available integration checks passed. This is not proof that every command was reduced.");
37122
+ } else if (failed) {
37123
+ messages.push(prefix + "a known integration check failed. Review the specific check before changing setup.");
37124
+ } else if (result6.data.results.length === 0) {
37125
+ 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.");
36899
37126
  } else {
36900
- this.verification = null;
37127
+ const pendingProviders = [
37128
+ ...new Set(result6.data.results.filter((entry) => entry.status === "not-applicable").map((entry) => name(entry.providerId)))
37129
+ ];
37130
+ const subject = pendingProviders.length > 0 ? pendingProviders.join(" and ") : "Some integrations";
37131
+ 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.`);
36901
37132
  }
36902
- const stack = this.stackSnapshot();
36903
- if (this.cached !== null)
36904
- this.cached.value = { ...this.cached.value, stack };
36905
- this.record("Integration checks completed. No settings changed.", ok ? "success" : "attention");
36906
- return { ok, title: "Integration checks", messages, appliedPlans: 0, stack };
36907
- });
37133
+ if (versionWarnings.length > 0) {
37134
+ 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.");
37135
+ }
37136
+ }
37137
+ if (inventory.data !== null) {
37138
+ const fingerprint = stackFingerprint(inventory.data);
37139
+ this.verification = {
37140
+ fingerprint,
37141
+ report: {
37142
+ receiptId: null,
37143
+ appliedAt: null,
37144
+ results,
37145
+ healthyAtDeclaredTier: healthyAtDeclaredTier && present.length > 0
37146
+ }
37147
+ };
37148
+ this.stackBase = {
37149
+ detections: [...inventory.data.providers],
37150
+ metrics: this.stackBase?.metrics ?? null,
37151
+ drift: this.stackBase?.drift ?? [],
37152
+ fingerprint
37153
+ };
37154
+ } else {
37155
+ this.verification = null;
37156
+ }
37157
+ const stack = this.stackSnapshot();
37158
+ if (this.cached !== null)
37159
+ this.cached.value = { ...this.cached.value, stack };
37160
+ this.record("Integration checks completed. No settings changed.", ok ? "success" : "attention");
37161
+ return {
37162
+ ok,
37163
+ title: ok ? healthyAtDeclaredTier ? "Integration checks passed" : "Configuration checks complete; runtime evidence pending" : "Integration checks need attention",
37164
+ messages,
37165
+ appliedPlans: 0,
37166
+ stack
37167
+ };
36908
37168
  }
36909
37169
  };
36910
37170
  }
@@ -38495,7 +38755,6 @@ var init_guided_capabilities_client = __esm({
38495
38755
  return element;
38496
38756
  };
38497
38757
  const originalFetch = window.fetch.bind(window);
38498
- const managedProviders = new Set(['rtk', 'harnesstrim']);
38499
38758
  const HELP = {
38500
38759
  'claude-effort': ['Change reasoning in Claude', 'Inside Claude Code, use /effort. Token Harness keeps difficult work above its quality floor.', '/effort'],
38501
38760
  'codex-effort': ['Change reasoning in Codex', 'Inside Codex, use /model to review model and reasoning settings.', '/model'],
@@ -38778,44 +39037,16 @@ var init_guided_capabilities_client = __esm({
38778
39037
  if (!root.children.length) root.append(node('p', 'Agent details appear after a supported coding agent is detected.', 'empty'));
38779
39038
  }
38780
39039
 
38781
- function renderRemovalControls(data) {
38782
- const root = $('managed-removal-actions');
38783
- if (!root) return;
38784
- root.replaceChildren();
38785
- const removable = (data.stack?.components || []).filter(component =>
38786
- managedProviders.has(component.providerId) && (component.managedByTokenHarness || component.configured),
38787
- );
38788
- if (!removable.length) {
38789
- root.append(node('p', 'No managed configuration is currently eligible for removal.', 'caption'));
38790
- return;
38791
- }
38792
- for (const component of removable) {
38793
- const row = node('div', undefined, 'maintenance-row');
38794
- const text = node('div');
38795
- const name = component.displayName || (component.providerId === 'rtk' ? 'RTK' : 'HarnessTrim');
38796
- text.append(
38797
- node('strong', name),
38798
- node('p', component.managedByTokenHarness
38799
- ? 'Review removal of Token Harness-owned integration changes.'
38800
- : 'Check whether Token Harness owns any removable changes. The provider installation remains user-owned.', 'caption'),
38801
- );
38802
- row.append(
38803
- text,
38804
- actionButton('Review removal', () => preview(
38805
- { action: 'remove', provider: component.providerId },
38806
- 'Review removal for ' + name,
38807
- 'Remove managed integration',
38808
- 'Integration removed',
38809
- ), 'secondary'),
38810
- );
38811
- root.append(row);
38812
- }
38813
- }
39040
+ window.tokenHarnessReviewRemoval = (provider, name) => preview(
39041
+ { action: 'remove', provider },
39042
+ 'Review removal for ' + name,
39043
+ 'Remove managed setup',
39044
+ 'Managed setup removed',
39045
+ );
38814
39046
 
38815
39047
  function consumeOverview(data) {
38816
39048
  if (!data || !Array.isArray(data.agents)) return;
38817
39049
  renderAgentCapabilities(data);
38818
- renderRemovalControls(data);
38819
39050
  }
38820
39051
 
38821
39052
  window.fetch = async (...args) => {
@@ -38895,7 +39126,7 @@ var init_guided_product_client = __esm({
38895
39126
  const date = value => value ? new Date(value).toLocaleString() : 'not recorded';
38896
39127
  const VIEWS = {
38897
39128
  dashboard: ['Overview', 'Your coding agents, optimization stack, health and measured results in one place.'],
38898
- results: ['Results', 'A dashboard of optimizer results, coding-app links, quality information, and recent activity.'],
39129
+ results: ['Results', 'Measured evidence by optimizer, routing and coding app.'],
38899
39130
  };
38900
39131
  const TOOL_INFO = {
38901
39132
  rtk: {
@@ -38944,6 +39175,8 @@ var init_guided_product_client = __esm({
38944
39175
  let selectedView = 'dashboard';
38945
39176
  let modalRun = 0;
38946
39177
  let pendingTicket = null;
39178
+ let updateCheckStarted = false;
39179
+ let latestUpdateCheck = null;
38947
39180
  const periodCache = new Map();
38948
39181
 
38949
39182
  async function request(path, body) {
@@ -38976,7 +39209,7 @@ var init_guided_product_client = __esm({
38976
39209
 
38977
39210
  function setBusy(value, applying = false) {
38978
39211
  busy = value;
38979
- document.querySelectorAll('[data-action],#refresh,#period').forEach(element => {
39212
+ document.querySelectorAll('[data-action],#refresh,#period,#evidence-filter,#evidence-type,#evidence-sort').forEach(element => {
38980
39213
  element.disabled = value;
38981
39214
  });
38982
39215
  $('live-status').textContent = value
@@ -39112,7 +39345,7 @@ var init_guided_product_client = __esm({
39112
39345
 
39113
39346
  function optimizerIds() {
39114
39347
  const ids = (current?.stack?.components || []).map(component => component.providerId).filter(Boolean);
39115
- return ids.length ? [...new Set(ids)] : Object.keys(TOOL_INFO);
39348
+ return [...new Set([...Object.keys(TOOL_INFO), ...ids])];
39116
39349
  }
39117
39350
 
39118
39351
  function configuredProviders() {
@@ -39240,6 +39473,16 @@ var init_guided_product_client = __esm({
39240
39473
  detail: 'A paired benchmark favored the baseline. Token Harness is not crediting the affected savings.',
39241
39474
  action: 'results',
39242
39475
  };
39476
+ const routingAttention = agents.filter(agent => agent.promptRouting?.needsRepair ||
39477
+ (agent.promptRouting?.configured === true && ['untrusted', 'disabled', 'unknown'].includes(agent.promptRouting.enablement)));
39478
+ if (routingAttention.length)
39479
+ return {
39480
+ label: 'Routing action required',
39481
+ cls: 'warn',
39482
+ title: 'Automatic routing needs attention',
39483
+ detail: routingAttention.map(agent => agent.name + ': ' + agent.promptRouting.detail).join(' '),
39484
+ action: 'routing',
39485
+ };
39243
39486
  if (stack?.state === 'attention')
39244
39487
  return {
39245
39488
  label: 'Needs attention',
@@ -39299,6 +39542,8 @@ var init_guided_product_client = __esm({
39299
39542
  const actions = node('div', undefined, 'inline-actions');
39300
39543
  if (assessment.action === 'verify') {
39301
39544
  actions.append(actionButton('Re-check health', () => readOnlyOperation('verify')));
39545
+ } else if (assessment.action === 'routing') {
39546
+ actions.append(actionButton('Review routing', () => $('coding-agents').scrollIntoView({ block: 'start', behavior: 'smooth' })));
39302
39547
  } else if (assessment.action === 'results') {
39303
39548
  actions.append(navigateButton('View detailed results', 'results'));
39304
39549
  }
@@ -39406,27 +39651,40 @@ var init_guided_product_client = __esm({
39406
39651
  ),
39407
39652
  );
39408
39653
  const routing = agent.promptRouting;
39654
+ const routingConfigured = routing?.configured === true || routing?.enablement === 'enabled' || routing?.enablement === 'untrusted' || (!routing?.enablement && routing?.state === 'managed');
39655
+ const routingObserved = routing?.verificationTier === 'runtime-observed';
39656
+ const routingLabel = routingObserved ? 'Active · callback seen' : routing?.needsRepair ? 'Repair required' : routing?.enablement === 'untrusted' ? 'Trust required' : routing?.enablement === 'disabled' ? 'Hooks disabled' : routing?.configured !== false && routing?.enablement === 'unknown' ? 'Authorization unknown' : routingConfigured ? 'Enabled · awaiting callback' : routing?.state === 'external' ? 'Managed elsewhere' : 'Not enabled';
39409
39657
  const routingCard = node('div', undefined, 'routing-feature');
39410
39658
  const routingHead = node('div', undefined, 'tool-head');
39411
39659
  routingHead.append(
39412
39660
  node('strong', 'Automatic prompt routing'),
39413
- pill(routing?.label || 'Not verified', routing?.state === 'managed' ? 'good' : routing?.state === 'absent' ? '' : 'warn'),
39661
+ pill(routingLabel, routingObserved ? 'good' : routingConfigured || routing?.needsRepair ? 'warn' : ''),
39414
39662
  );
39415
39663
  routingCard.append(
39416
39664
  routingHead,
39417
39665
  node(
39418
39666
  'p',
39419
- routing?.detail || 'A native hook can inject the routing policy on every submitted prompt. Setup and runtime activity are tracked separately.',
39667
+ routing?.detail || (routing?.enablement === 'untrusted'
39668
+ ? 'Open /hooks in Codex and trust this hook. Then submit a prompt to verify the callback.'
39669
+ : routing?.needsRepair
39670
+ ? routing.detail || 'Review and repair the Token Harness routing hook.'
39671
+ : routing?.enablement === 'unknown'
39672
+ ? routing.detail || 'Token Harness could not determine whether this hook is authorized.'
39673
+ : routingConfigured
39674
+ ? routingObserved ? 'Automatic routing is running on submitted prompts.' : 'Configured; submit a prompt and Token Harness will show the callback when it arrives.'
39675
+ : 'Enable once. The native hook then checks every submitted prompt automatically.'),
39420
39676
  'caption',
39421
39677
  ),
39422
39678
  );
39423
39679
  const routingActions = node('div', undefined, 'inline-actions');
39424
- if (routing?.state === 'absent') {
39425
- routingActions.append(actionButton('Enable routing', () => reviewPromptRouting(agent.id, true), 'secondary'));
39426
- } else if (routing?.state === 'managed') {
39427
- routingActions.append(actionButton('Disable routing', () => reviewPromptRouting(agent.id, false), 'secondary'));
39680
+ if (routing?.needsRepair) {
39681
+ routingActions.append(actionButton('Repair routing', () => reviewPromptRouting(agent.id, true), 'secondary'));
39428
39682
  } else if (routing?.state === 'external') {
39429
39683
  routingActions.append(node('span', 'Managed elsewhere · left untouched', 'caption'));
39684
+ } else if (!routingConfigured) {
39685
+ routingActions.append(actionButton('Enable routing', () => reviewPromptRouting(agent.id, true), 'secondary'));
39686
+ } else if (routingConfigured) {
39687
+ routingActions.append(actionButton('Disable routing', () => reviewPromptRouting(agent.id, false), 'secondary'));
39430
39688
  }
39431
39689
  if (routingActions.children.length) routingCard.append(routingActions);
39432
39690
  card.append(routingCard);
@@ -39552,13 +39810,17 @@ var init_guided_product_client = __esm({
39552
39810
  if (!(data.changes || []).length)
39553
39811
  $('modal-content').append(messageBox('No change proposed', (data.notices || []).join(' ') || 'The current routing state or ownership evidence does not support a safe change.'));
39554
39812
  for (const notice of data.notices || []) $('modal-content').append(node('p', notice, 'notice-row'));
39555
- $('modal-content').append(messageBox(
39556
- agentId === 'codex' ? 'Codex trust step' : 'When it takes effect',
39557
- agentId === 'codex'
39558
- ? '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.'
39559
- : 'After Apply, start a new Claude Code session. The dashboard will show configured state first and runtime activity after the next prompt callback.',
39560
- 'safe',
39561
- ));
39813
+ if (data.ticket) {
39814
+ const observed = activeAgents().find(agent => agent.id === agentId)?.promptRouting;
39815
+ const needsTrust = agentId === 'codex' && observed?.enablement === 'untrusted';
39816
+ $('modal-content').append(messageBox(
39817
+ needsTrust ? 'Trust required' : 'When it takes effect',
39818
+ needsTrust
39819
+ ? 'Open /hooks in Codex and trust this hook. Then send a prompt.'
39820
+ : 'Send a prompt in a new session. Token Harness will show the callback when it arrives.',
39821
+ 'safe',
39822
+ ));
39823
+ }
39562
39824
  $('modal-actions').replaceChildren(modalClose(data.ticket ? 'Cancel' : 'Done'));
39563
39825
  if (data.ticket) $('modal-actions').append(actionButton(enabled ? 'Apply routing hook' : 'Remove owned routing hook', () => applyTicket(data.ticket)));
39564
39826
  })
@@ -39654,6 +39916,12 @@ var init_guided_product_client = __esm({
39654
39916
  await ensureSession();
39655
39917
  const result = await request('/api/apply', { ticket });
39656
39918
  if (run !== modalRun) return;
39919
+ if (result.restartRequired) {
39920
+ $('modal-title').textContent = result.title || 'Token Harness update installed';
39921
+ $('modal-content').replaceChildren(messageBox('Restart to finish', (result.messages || []).join(' ') || 'Token Harness must restart before it can check the updated installation.', 'safe'));
39922
+ $('modal-actions').replaceChildren(modalClose('Later'), actionButton('Restart and re-check', restartAndRecheck));
39923
+ return;
39924
+ }
39657
39925
  $('modal-title').textContent = result.title || (result.ok ? 'Setup completed' : 'Setup needs attention');
39658
39926
  $('modal-content').replaceChildren(
39659
39927
  messageBox(result.ok ? 'Applied' : 'Needs attention', (result.messages || []).join(' '), result.ok ? 'safe' : 'warn'),
@@ -39698,6 +39966,24 @@ var init_guided_product_client = __esm({
39698
39966
  }
39699
39967
  }
39700
39968
 
39969
+ async function restartAndRecheck() {
39970
+ if (busy) return;
39971
+ setBusy(true, true);
39972
+ $('modal-content').replaceChildren(progress('Restarting Token Harness', 'The updated app will run its health check when it opens again.'));
39973
+ $('modal-actions').replaceChildren(modalClose('Restarting…', true));
39974
+ try {
39975
+ await ensureSession();
39976
+ const result = await request('/api/restart', {});
39977
+ if (!result.ok) throw new Error((result.messages || []).join(' ') || 'Restart did not complete.');
39978
+ setTimeout(() => window.location.reload(), 700);
39979
+ } catch (error) {
39980
+ $('modal-error').textContent = error.message;
39981
+ $('modal-error').hidden = false;
39982
+ $('modal-actions').replaceChildren(modalClose('Close'));
39983
+ setBusy(false, false);
39984
+ }
39985
+ }
39986
+
39701
39987
  function connectionPresentation(target) {
39702
39988
  if (!target) return { label: 'Not targeted', cls: '' };
39703
39989
  if (target.state === 'connected') return { label: 'Setup detected', cls: 'good' };
@@ -39706,6 +39992,26 @@ var init_guided_product_client = __esm({
39706
39992
  return { label: 'Not applicable', cls: '' };
39707
39993
  }
39708
39994
 
39995
+ function mcptoonInstallOptions() {
39996
+ modal('Install mcptoon prerequisites');
39997
+ $('modal-content').append(
39998
+ node('p', 'Token Harness can install mcptoon after pipx or uv is available. Install one, then Refresh and choose Install & connect.'),
39999
+ );
40000
+ const links = node('div', undefined, 'inline-actions');
40001
+ for (const [label, href] of [
40002
+ ['pipx installation', 'https://pipx.pypa.io/stable/installation/'],
40003
+ ['uv installation', 'https://docs.astral.sh/uv/getting-started/installation/'],
40004
+ ]) {
40005
+ const link = node('a', label, 'button secondary');
40006
+ link.href = href;
40007
+ link.target = '_blank';
40008
+ link.rel = 'noreferrer noopener';
40009
+ links.append(link);
40010
+ }
40011
+ $('modal-content').append(links);
40012
+ $('modal-actions').append(modalClose('Done'));
40013
+ }
40014
+
39709
40015
  function renderConnectionOverview() {
39710
40016
  const root = $('connection-overview');
39711
40017
  if (!root) return;
@@ -39769,8 +40075,18 @@ var init_guided_product_client = __esm({
39769
40075
  () => reviewSetup(id),
39770
40076
  'secondary',
39771
40077
  ),
39772
- );
39773
- else action.append(node('span', 'No action', 'caption'));
40078
+ );
40079
+ const mcptoonUnavailable = id === 'mcptoon' && agents.some(agent => setupTarget(agent.id, id)?.state === 'unavailable');
40080
+ if (mcptoonUnavailable)
40081
+ action.append(actionButton('Installation options', mcptoonInstallOptions, 'secondary'));
40082
+ if (component?.managedByTokenHarness || component?.configured) {
40083
+ const remove = actionButton('Remove managed setup', () => {
40084
+ window.tokenHarnessReviewRemoval?.(id, info.name);
40085
+ }, 'secondary');
40086
+ remove.disabled = busy || typeof window.tokenHarnessReviewRemoval !== 'function';
40087
+ action.append(remove);
40088
+ }
40089
+ if (!action.children.length) action.append(node('span', 'No action', 'caption'));
39774
40090
  row.append(action);
39775
40091
  table.append(row);
39776
40092
  }
@@ -39893,7 +40209,7 @@ var init_guided_product_client = __esm({
39893
40209
  messageBox('Optional candidate lifecycle', 'This is an explicit evaluation setup, not production-stack setup. Token Harness does not silently install or activate candidates.'),
39894
40210
  );
39895
40211
  if (candidate.id === 'mcptoon')
39896
- $('modal-content').append(messageBox('Prerequisites stay yours', 'An approved setup may install the exact reviewed mcptoon build only through an already-installed pipx. Token Harness does not install Python, pipx or administrator prerequisites.'));
40212
+ $('modal-content').append(messageBox('Prerequisites stay yours', 'An approved setup may install the exact reviewed mcptoon build through an already-installed pipx or uv. Token Harness does not install Python, pipx, uv or administrator prerequisites.'));
39897
40213
  if (candidate.id === 'gitnexus')
39898
40214
  $('modal-content').append(messageBox('Index stays yours', 'GitNexus must already be installed on the exact reviewed row. Token Harness can register only the reviewed Claude MCP entry; it never creates or refreshes the repository index.'));
39899
40215
  const agents = activeAgents().filter(agent => supported.includes(agent.id));
@@ -40173,44 +40489,139 @@ var init_guided_product_client = __esm({
40173
40489
  renderMaintenance();
40174
40490
  }
40175
40491
 
40176
- function renderSavings() {
40177
- const root = $('result-savings');
40178
- root.replaceChildren();
40179
- const rows = current?.savings?.rows || [];
40180
- if (!rows.length) {
40181
- root.append(sectionEmpty('No measured optimizer output has been recorded for this period. Missing data is not zero savings.'));
40182
- return;
40492
+ function addEvidenceRow(body, type, name, scope, summary, amount, details) {
40493
+ const row = node('tr');
40494
+ row.dataset.type = type;
40495
+ row.dataset.name = name.toLocaleLowerCase();
40496
+ row.dataset.search = [type, name, scope, summary].join(' ').toLocaleLowerCase();
40497
+ row.dataset.amount = String(amount || 0);
40498
+ const systemCell = node('th');
40499
+ systemCell.scope = 'row';
40500
+ systemCell.append(node('strong', name), node('span', type[0].toUpperCase() + type.slice(1), 'caption'));
40501
+ row.append(systemCell, node('td', scope), node('td', summary));
40502
+ const detailCell = node('td');
40503
+ const disclosure = node('details');
40504
+ disclosure.append(node('summary', 'Details'));
40505
+ for (const detail of details) disclosure.append(node('p', detail, 'caption'));
40506
+ detailCell.append(disclosure);
40507
+ row.append(detailCell);
40508
+ body.append(row);
40509
+ return row;
40510
+ }
40511
+
40512
+ function optimizerEvidenceDetail(row) {
40513
+ const unit = row.unit ? ' ' + row.unit : '';
40514
+ const change = row.before !== null && row.before !== undefined && row.after !== null && row.after !== undefined
40515
+ ? count(row.before) + ' → ' + count(row.after) + unit
40516
+ : count(row.saved) + unit;
40517
+ return [
40518
+ row.impact?.detail || 'Recorded optimizer evidence.',
40519
+ 'Recorded change: ' + change,
40520
+ count(row.operations) + ' operation(s)' + (row.agents?.length ? ' · ' + row.agents.join(', ') : ' · no harness attribution'),
40521
+ ];
40522
+ }
40523
+
40524
+ function routingDetails(agent) {
40525
+ const routing = agent.promptRouting || {};
40526
+ const lines = [];
40527
+ const tier = routing.verificationTier;
40528
+ if (routing.enablement === 'untrusted') lines.push('Action required: open /hooks in Codex and trust this hook, then submit a prompt.');
40529
+ else if (tier === 'runtime-observed') lines.push('Runtime callback observed. Automatic routing runs on submitted prompts.');
40530
+ else if (routing.configured !== false && routing.enablement === 'unknown') lines.push('Authorization is unknown; check the hook status in the coding app.');
40531
+ else if (routing.enablement === 'disabled') lines.push('Hooks are disabled for this coding app.');
40532
+ else if (routing.enablement === 'enabled' || (!routing.enablement && routing.state === 'managed')) lines.push('Configured; waiting for the first runtime callback after a prompt.');
40533
+ else if (routing.state === 'external') lines.push('Routing is managed elsewhere; Token Harness leaves it unchanged.');
40534
+ else lines.push('Automatic routing is not enabled for this coding app.');
40535
+ if (Number.isFinite(routing.promptSubmissions)) lines.push('Prompt callbacks: ' + count(routing.promptSubmissions));
40536
+ if (Number.isFinite(routing.subagentsStarted)) lines.push('Subagents started: ' + count(routing.subagentsStarted));
40537
+ if (Number.isFinite(routing.subagentsStopped)) lines.push('Subagents stopped: ' + count(routing.subagentsStopped));
40538
+ if (routing.reportedModels?.length) lines.push('Reported models: ' + routing.reportedModels.join(', '));
40539
+ if (routing.lastObservedAt) lines.push('Last callback: ' + date(routing.lastObservedAt));
40540
+ return lines;
40541
+ }
40542
+
40543
+ function renderEvidence() {
40544
+ const body = $('result-evidence');
40545
+ body.replaceChildren();
40546
+ const savings = current?.savings?.rows || [];
40547
+ for (const id of optimizerIds()) {
40548
+ const info = optimizerInfo(id);
40549
+ const component = managedComponent(id);
40550
+ const measured = savings.filter(row => row.providerId === id);
40551
+ const scope = component?.configuredHarnesses?.length
40552
+ ? component.configuredHarnesses.map(agentName).join(', ')
40553
+ : 'No setup detected';
40554
+ const summary = measured.length
40555
+ ? measured.map(row => row.measurement + ' · ' + count(row.saved) + (row.unit ? ' ' + row.unit : '')).join(' · ')
40556
+ : 'No measured evidence';
40557
+ const details = measured.length
40558
+ ? measured.flatMap(optimizerEvidenceDetail)
40559
+ : [component?.configured ? 'Setup is detected, but no result was recorded for this period.' : 'No result was recorded for this optimizer in this period.'];
40560
+ addEvidenceRow(body, 'optimizer', info.name, scope, summary, measured.length, details);
40561
+ }
40562
+
40563
+ const routing = current?.value?.routing;
40564
+ const routingAgents = activeAgents();
40565
+ const routingDetailsList = routingAgents.flatMap(agent => [agent.name + ':', ...routingDetails(agent)]);
40566
+ if (routing?.state === 'measured' || routing?.pairs > 0) {
40567
+ routingDetailsList.push((routing.pairs ? count(routing.pairs) + ' quality-passed routed pair(s).' : ''));
40568
+ if (routing.savedLocalTokens !== null && routing.savedLocalTokens !== undefined)
40569
+ routingDetailsList.push(routing.savedLocalTokens >= 0
40570
+ ? count(routing.savedLocalTokens) + ' local tokens saved · end-to-end local usage'
40571
+ : count(Math.abs(routing.savedLocalTokens)) + ' local tokens added · end-to-end local usage');
40572
+ if (routing.allowance5h?.savedPercent !== null && routing.allowance5h?.savedPercent !== undefined)
40573
+ routingDetailsList.push('5h allowance change: ' + count(routing.allowance5h.savedPercent) + '%');
40574
+ if (routing.allowance7d?.savedPercent !== null && routing.allowance7d?.savedPercent !== undefined)
40575
+ routingDetailsList.push('7d allowance change: ' + count(routing.allowance7d.savedPercent) + '%');
40576
+ }
40577
+ const routingSummary = routing?.state === 'blocked-by-quality'
40578
+ ? 'Not credited · quality gate'
40579
+ : routing?.savedLocalTokens !== null && routing?.savedLocalTokens !== undefined
40580
+ ? count(routing.savedLocalTokens) + ' local tokens · end-to-end paired evidence'
40581
+ : routing?.state === 'measured' ? 'Allowance evidence measured' : 'Not measured yet';
40582
+ addEvidenceRow(body, 'routing', 'Automatic prompt routing', routingAgents.map(agent => agent.name).join(', ') || 'No coding app detected', routingSummary, routing?.pairs || 0, routingDetailsList.length ? routingDetailsList : ['No routing measurement has been recorded.']);
40583
+
40584
+ for (const agent of routingAgents) {
40585
+ const linked = savings.filter(row => row.harnesses?.includes(agent.id));
40586
+ const configured = configuredProviders().filter(component => component.configuredHarnesses?.includes(agent.id)).map(component => optimizerInfo(component.providerId).name);
40587
+ const details = [
40588
+ 'Detected optimizer setup: ' + (configured.join(', ') || 'none'),
40589
+ ...routingDetails(agent),
40590
+ ...(linked.length ? linked.flatMap(optimizerEvidenceDetail) : ['No optimizer measurement is directly linked to this coding app.']),
40591
+ ];
40592
+ addEvidenceRow(body, 'harness', agent.name, agent.version ? 'v' + agent.version : 'Version unavailable', linked.length ? linked.map(row => row.provider + ': ' + row.measurement + ' · ' + count(row.saved) + (row.unit ? ' ' + row.unit : '')).join(' · ') : 'No linked measured evidence', linked.length, details);
40593
+ }
40594
+
40595
+ for (const item of current?.value?.candidates || []) {
40596
+ if (!(item.pairs > 0)) continue;
40597
+ const candidate = (current?.optimizationCandidates || []).find(entry => entry.id === item.candidateId);
40598
+ const name = candidate?.name || item.candidateId;
40599
+ addEvidenceRow(body, 'candidate', name, 'Experimental', count(item.pairs) + ' paired result(s)', item.pairs, [
40600
+ count(item.optimizedBetter || 0) + ' optimized better · ' + count(item.baselineBetter || 0) + ' baseline better.',
40601
+ 'Evaluation evidence only; this does not automatically promote or activate the candidate.',
40602
+ ]);
40183
40603
  }
40604
+ applyEvidenceFilters();
40605
+ }
40606
+
40607
+ function applyEvidenceFilters() {
40608
+ const body = $('result-evidence');
40609
+ if (!body) return;
40610
+ const filter = $('evidence-filter').value.trim().toLocaleLowerCase();
40611
+ const type = $('evidence-type').value;
40612
+ const sort = $('evidence-sort').value;
40613
+ const rows = [...body.querySelectorAll('tr')];
40614
+ rows.sort((a, b) => sort === 'evidence'
40615
+ ? Number(b.dataset.amount) - Number(a.dataset.amount) || a.dataset.name.localeCompare(b.dataset.name)
40616
+ : sort === 'type'
40617
+ ? a.dataset.type.localeCompare(b.dataset.type) || a.dataset.name.localeCompare(b.dataset.name)
40618
+ : a.dataset.name.localeCompare(b.dataset.name));
40184
40619
  for (const row of rows) {
40185
- const card = node('article', undefined, 'evidence-row');
40186
- const head = node('div', undefined, 'evidence-head');
40187
- head.append(node('h3', row.provider), pill(row.measurement));
40188
- card.append(head, node('strong', row.impact?.headline || count(row.saved) + ' ' + row.unit, 'evidence-value'), node('p', row.impact?.detail || 'Recorded optimization output.'));
40189
- const facts = node('dl', undefined, 'evidence-facts');
40190
- const values = [
40191
- ['Recorded change', row.before !== null && row.after !== null ? count(row.before) + ' → ' + count(row.after) + ' ' + row.unit : count(Math.abs(row.saved)) + ' ' + row.unit],
40192
- ['Operations', count(row.operations)],
40193
- ['Coding agent', row.agents?.length ? row.agents.join(', ') : 'Not linked to an agent'],
40194
- ];
40195
- for (const [label, value] of values) {
40196
- const wrap = node('div');
40197
- wrap.append(node('dt', label), node('dd', value));
40198
- facts.append(wrap);
40199
- }
40200
- card.append(facts);
40201
- if (!row.agents?.length) {
40202
- card.append(
40203
- node(
40204
- 'p',
40205
- row.providerId === 'rtk'
40206
- ? 'RTK records these reductions but does not record whether Codex or Claude ran each command. The result is real, but Token Harness cannot assign it to either agent.'
40207
- : 'The source did not include a coding-agent identity, so Token Harness keeps this result unassigned.',
40208
- 'caption',
40209
- ),
40210
- );
40211
- }
40212
- root.append(card);
40620
+ const shown = (type === 'all' || row.dataset.type === type) && (!filter || row.dataset.search.includes(filter));
40621
+ row.hidden = !shown;
40622
+ body.append(row);
40213
40623
  }
40624
+ $('evidence-empty').hidden = rows.some(row => !row.hidden);
40214
40625
  }
40215
40626
 
40216
40627
  function measurementHelp() {
@@ -40225,173 +40636,23 @@ var init_guided_product_client = __esm({
40225
40636
  $('modal-actions').append(modalClose('Done'));
40226
40637
  }
40227
40638
 
40228
- function renderCandidateResults() {
40229
- const root = $('candidate-results');
40230
- root.replaceChildren();
40231
- const evidence = current?.value?.candidates || [];
40232
- if (!evidence.some(item => item.pairs > 0)) {
40233
- root.append(sectionEmpty('No experimental candidate has completed paired evidence yet. Experimental tools are optional and do not affect managed setup.'));
40234
- return;
40235
- }
40236
- for (const item of evidence.filter(entry => entry.pairs > 0)) {
40237
- const candidate = EXPERIMENTAL.find(entry => entry.id === item.candidateId);
40238
- if (!candidate) continue;
40239
- const card = node('article', undefined, 'evidence-row');
40240
- card.append(node('h3', candidate.name), node('strong', count(item.pairs) + ' paired result(s)', 'evidence-value'));
40241
- card.append(node('p', count(item.optimizedBetter || 0) + ' optimized better · ' + count(item.baselineBetter || 0) + ' baseline better. This is evaluation evidence, not automatic promotion.'));
40242
- root.append(card);
40243
- }
40244
- }
40245
-
40246
- function renderResultOptimizers() {
40247
- const root = $('result-optimizers');
40248
- if (!root) return;
40249
- root.replaceChildren();
40250
- const rows = current?.savings?.rows || [];
40251
- for (const id of optimizerIds()) {
40252
- const component = managedComponent(id);
40253
- const info = optimizerInfo(id);
40254
- const state = componentState(id, component);
40255
- const card = node('article', undefined, 'tool-card result-overview-card');
40256
- const head = node('div', undefined, 'tool-head');
40257
- head.append(node('h3', info.name), pill(state.label, state.cls));
40258
- card.append(head, node('p', info.role));
40259
- const facts = node('div', undefined, 'tool-facts');
40260
- facts.append(
40261
- node('span', 'Setup detected for'),
40262
- node('strong', component?.configuredHarnesses?.length ? component.configuredHarnesses.map(agentName).join(', ') : 'No detected agent'),
40263
- );
40264
- const measured = rows.filter(row => row.providerId === id);
40265
- card.append(facts);
40266
- if (!measured.length) {
40267
- card.append(
40268
- node(
40269
- 'p',
40270
- component?.configured
40271
- ? 'Setup is detected, but no result was recorded in the selected period.'
40272
- : 'No result was recorded for this optimizer in the selected period.',
40273
- 'caption',
40274
- ),
40275
- );
40276
- } else {
40277
- for (const row of measured) {
40278
- const evidence = node('div', undefined, 'result-signal');
40279
- evidence.append(
40280
- node('span', row.measurement, 'caption'),
40281
- node('strong', row.impact?.headline || count(row.saved) + ' ' + row.unit),
40282
- node('span', count(row.operations) + ' operation' + (row.operations === 1 ? '' : 's'), 'caption'),
40283
- );
40284
- card.append(evidence);
40285
- }
40286
- }
40287
- root.append(card);
40288
- }
40289
- }
40290
-
40291
- function renderResultAgents() {
40292
- const root = $('result-agents');
40293
- if (!root) return;
40294
- root.replaceChildren();
40295
- const rows = current?.savings?.rows || [];
40296
- if (!activeAgents().length) {
40297
- root.append(sectionEmpty('No supported coding agent is currently detected.'));
40298
- return;
40299
- }
40300
- for (const agent of activeAgents()) {
40301
- const setupDetected = configuredProviders().filter(component =>
40302
- component.configuredHarnesses?.includes(agent.id),
40303
- );
40304
- const measured = rows.filter(row => row.harnesses?.includes(agent.id));
40305
- const rtkUnattributed = rows.some(row =>
40306
- row.providerId === 'rtk' && !row.agents?.length,
40307
- );
40308
- const notes = [];
40309
- if (
40310
- setupDetected.some(component => component.providerId === 'rtk') &&
40311
- !measured.some(row => row.providerId === 'rtk')
40312
- ) {
40313
- notes.push(
40314
- rtkUnattributed
40315
- ? 'RTK has saved command-output data, but its history does not say whether Codex or Claude ran each command. Token Harness keeps those results under RTK instead of guessing.'
40316
- : 'RTK setup is detected, but no RTK result can be linked to this agent in the selected period.',
40317
- );
40318
- }
40319
- if (
40320
- setupDetected.some(component => component.providerId === 'harnesstrim') &&
40321
- !measured.some(row => row.providerId === 'harnesstrim')
40322
- ) {
40323
- notes.push(
40324
- 'HarnessTrim setup is detected, but no HarnessTrim result is linked to this app in the selected period. Setup alone does not mean it was used.',
40325
- );
40326
- }
40327
- if (!setupDetected.length && !measured.length) {
40328
- notes.push('No optimizer setup or agent-linked result was found for this coding app.');
40329
- }
40330
- const card = node('article', undefined, 'tool-card result-overview-card');
40331
- const head = node('div', undefined, 'tool-head');
40332
- head.append(node('h3', agent.name), pill(setupDetected.length ? 'Setup detected' : 'No setup', setupDetected.length ? 'good' : ''));
40333
- card.append(
40334
- head,
40335
- node('p', agent.version ? 'v' + agent.version : 'Version unavailable', 'caption'),
40336
- );
40337
- const facts = node('div', undefined, 'tool-facts');
40338
- facts.append(
40339
- node('span', 'Setup found'),
40340
- node('strong', setupDetected.length ? setupDetected.map(component => optimizerInfo(component.providerId).name).join(', ') : 'None'),
40341
- node('span', 'Results linked to this agent'),
40342
- node('strong', measured.length ? measured.map(row => row.provider).join(', ') : 'None in this period'),
40343
- );
40344
- card.append(facts);
40345
- for (const note of notes) card.append(node('p', note, 'caption'));
40346
- root.append(card);
40347
- }
40348
- }
40349
-
40350
40639
  function renderResults() {
40351
40640
  const allowance = allowanceSummary();
40352
40641
  const quality = qualitySummary();
40353
- const configured = configuredProviders();
40354
- const connectionCount = configured.reduce(
40355
- (total, component) => total + (component.configuredHarnesses?.length || 0),
40356
- 0,
40357
- );
40358
- const measuredProviders = new Set(
40359
- (current?.savings?.rows || []).map(row => row.providerId).filter(Boolean),
40360
- );
40642
+ const savings = current?.savings?.rows || [];
40361
40643
  $('result-summary').replaceChildren(
40362
- metricCard('Configured optimizers', count(configured.length), optimizerIds().length + ' optimizer(s) tracked in the stack.', configured.length ? 'positive' : ''),
40363
- metricCard('Setups detected', count(connectionCount), 'Detected optimizer setup links; this is not proof of measured activity.', connectionCount ? 'positive' : ''),
40364
- metricCard('Optimizers with results', count(measuredProviders.size), 'Providers with recorded measurements in the selected period.'),
40644
+ metricCard('Measured output', savings.length ? count(savings.length) + ' evidence record(s)' : 'No records yet', 'Exact, estimated and other measurement classes remain separate.'),
40365
40645
  metricCard('5h / 7d allowance', allowance.value, allowance.detail, allowance.cls),
40366
40646
  metricCard('Quality', quality.value, quality.detail, quality.cls),
40367
40647
  );
40368
40648
  const routed = current?.value?.routing;
40369
- const quotaParts = [];
40370
- if (routed?.allowance5h?.state === 'measured' && routed.allowance5h.savedPercent !== null)
40371
- quotaParts.push(routed.allowance5h.savedPercent >= 0
40372
- ? '5h saved ' + count(routed.allowance5h.savedPercent) + '%'
40373
- : '5h use +' + count(Math.abs(routed.allowance5h.savedPercent)) + '%');
40374
- if (routed?.allowance7d?.state === 'measured' && routed.allowance7d.savedPercent !== null)
40375
- quotaParts.push(routed.allowance7d.savedPercent >= 0
40376
- ? '7d saved ' + count(routed.allowance7d.savedPercent) + '%'
40377
- : '7d use +' + count(Math.abs(routed.allowance7d.savedPercent)) + '%');
40378
- const routingValue = routed?.state === 'blocked-by-quality'
40649
+ const routeStatus = routed?.state === 'blocked-by-quality'
40379
40650
  ? 'Not credited'
40380
40651
  : routed?.savedLocalTokens !== null && routed?.savedLocalTokens !== undefined
40381
- ? (routed.savedLocalTokens >= 0
40382
- ? count(routed.savedLocalTokens) + ' tokens saved' + (routed.localTokenSavingPercent === null ? '' : ' · ' + count(routed.localTokenSavingPercent) + '%')
40383
- : count(Math.abs(routed.savedLocalTokens)) + ' tokens added' + (routed.localTokenSavingPercent === null ? '' : ' · ' + count(Math.abs(routed.localTokenSavingPercent)) + '%'))
40384
- : quotaParts.length ? 'Allowance measured' : routed?.state === 'measured' ? 'Usage unavailable' : 'Not measured yet';
40385
- const routingDetail = routed?.state === 'blocked-by-quality'
40386
- ? routed.basis
40387
- : (quotaParts.length ? quotaParts.join(' · ') + '. ' : '') +
40388
- (routed?.pairs ? count(routed.pairs) + ' quality-passed routed pair(s). ' : '') +
40389
- 'Local tokens and allowance percentages are separate measurements. Actual child model is not exposed by every harness hook.';
40390
- $('result-summary').append(metricCard('Automatic routing', routingValue, routingDetail, routed?.state === 'measured' ? 'positive' : ''));
40391
- renderResultOptimizers();
40392
- renderResultAgents();
40393
- renderSavings();
40394
- renderCandidateResults();
40652
+ ? count(routed.savedLocalTokens) + ' local tokens'
40653
+ : routed?.state === 'measured' ? 'Allowance measured' : 'Not measured yet';
40654
+ $('result-summary').append(metricCard('Automatic routing', routeStatus, routed?.pairs ? count(routed.pairs) + ' quality-passed pair(s). Allowance and local tokens are separate.' : 'Routing savings need paired, quality-gated evidence.', routed?.state === 'measured' ? 'positive' : ''));
40655
+ renderEvidence();
40395
40656
  $('results-period-note').textContent = current?.savings?.firstRecordedAt
40396
40657
  ? 'Recorded from ' + date(current.savings.firstRecordedAt) + ' through ' + date(current.savings.lastRecordedAt)
40397
40658
  : 'No recorded result dates for this period.';
@@ -40400,16 +40661,18 @@ var init_guided_product_client = __esm({
40400
40661
  function renderActivity() {
40401
40662
  const root = $('activity');
40402
40663
  root.replaceChildren();
40403
- const rows = activityState?.activity || [];
40664
+ const rows = [...(activityState?.activity || [])].sort((a, b) => new Date(b.at).getTime() - new Date(a.at).getTime());
40404
40665
  if (!rows.length) {
40405
40666
  root.append(sectionEmpty('No checks or changes have been recorded in this app session.'));
40406
40667
  return;
40407
40668
  }
40408
- for (const item of rows) {
40669
+ const visible = rows.slice(0, 8);
40670
+ for (const item of visible) {
40409
40671
  const row = node('div', undefined, 'activity-row');
40410
40672
  row.append(pill(item.state === 'success' ? 'Done' : item.state === 'attention' ? 'Attention' : 'Working', item.state === 'success' ? 'good' : item.state === 'attention' ? 'warn' : ''), node('span', item.message), node('time', date(item.at), 'caption'));
40411
40673
  root.append(row);
40412
40674
  }
40675
+ if (rows.length > visible.length) root.prepend(node('p', 'Showing the latest ' + visible.length + ' of ' + rows.length + ' entries.', 'caption'));
40413
40676
  }
40414
40677
 
40415
40678
  async function loadActivity() {
@@ -40428,6 +40691,82 @@ var init_guided_product_client = __esm({
40428
40691
  }
40429
40692
  }
40430
40693
 
40694
+ function reviewUpdate(result) {
40695
+ if (!result?.ticket || busy) return;
40696
+ modal('Review Token Harness update');
40697
+ $('modal-content').append(
40698
+ messageBox('Update available', (result.messages || []).join(' ') || result.title || 'A reviewed Token Harness update is ready.'),
40699
+ messageBox('Health re-check', 'After installation, Token Harness will re-check optimizer health automatically.'),
40700
+ );
40701
+ $('modal-actions').append(modalClose('Cancel'), actionButton('Install updates', () => applyTicket(result.ticket)));
40702
+ }
40703
+
40704
+ async function checkUpdatesOnStartup() {
40705
+ if (updateCheckStarted) return;
40706
+ if ($('modal').open) {
40707
+ $('modal').addEventListener('close', checkUpdatesOnStartup, { once: true });
40708
+ return;
40709
+ }
40710
+ if (busy || reading) {
40711
+ setTimeout(checkUpdatesOnStartup, 1000);
40712
+ return;
40713
+ }
40714
+ updateCheckStarted = true;
40715
+ try {
40716
+ await ensureSession();
40717
+ const result = await request('/api/update-check', { period: $('period').value });
40718
+ if (busy || reading || $('modal').open) {
40719
+ updateCheckStarted = false;
40720
+ if ($('modal').open) $('modal').addEventListener('close', checkUpdatesOnStartup, { once: true });
40721
+ else setTimeout(checkUpdatesOnStartup, 1000);
40722
+ return;
40723
+ }
40724
+ latestUpdateCheck = result;
40725
+ if (result.stack && current) {
40726
+ current = { ...current, stack: result.stack };
40727
+ renderDashboard();
40728
+ renderSetup();
40729
+ renderResults();
40730
+ }
40731
+ const root = $('update-notice');
40732
+ root.replaceChildren();
40733
+ if (!result.ticket) {
40734
+ root.hidden = true;
40735
+ return;
40736
+ }
40737
+ const copy = node('div');
40738
+ copy.append(node('strong', result.title || 'Token Harness update available'), node('p', (result.messages || []).join(' ') || 'Review and install the available update.', 'caption'));
40739
+ root.append(copy, actionButton('Review update', () => reviewUpdate(latestUpdateCheck), 'secondary'));
40740
+ root.hidden = false;
40741
+ } catch {
40742
+ // The startup version check is supplementary; Refresh and Health and updates remain available.
40743
+ }
40744
+ }
40745
+
40746
+ async function pollRouting() {
40747
+ if (document.hidden || busy || reading || $('modal').open || !current) return;
40748
+ try {
40749
+ const result = await request('/api/routing');
40750
+ if (busy || reading || $('modal').open || document.activeElement?.closest('#setup-agents, #result-evidence')) return;
40751
+ if (!Array.isArray(result.agents)) return;
40752
+ const byId = new Map(result.agents.map(agent => [agent.id, agent.promptRouting]));
40753
+ const previous = new Map((current.agents || []).map(agent => [agent.id, agent.promptRouting]));
40754
+ const changed = [...byId].some(([id, routing]) => JSON.stringify(previous.get(id)) !== JSON.stringify(routing));
40755
+ if (!changed) return;
40756
+ current = {
40757
+ ...current,
40758
+ agents: (current.agents || []).map(agent => byId.has(agent.id)
40759
+ ? { ...agent, promptRouting: byId.get(agent.id) }
40760
+ : agent),
40761
+ };
40762
+ renderDashboard();
40763
+ renderAgentSetup();
40764
+ renderResults();
40765
+ } catch {
40766
+ // Runtime receipts are supplementary; the overview remains usable if this read fails.
40767
+ }
40768
+ }
40769
+
40431
40770
  function render() {
40432
40771
  renderNotices();
40433
40772
  renderDashboard();
@@ -40460,6 +40799,7 @@ var init_guided_product_client = __esm({
40460
40799
  clearInterval(progressTimer);
40461
40800
  reading = false;
40462
40801
  $('refresh').disabled = false;
40802
+ if (current && !updateCheckStarted) checkUpdatesOnStartup();
40463
40803
  }
40464
40804
  }
40465
40805
 
@@ -40500,6 +40840,9 @@ var init_guided_product_client = __esm({
40500
40840
  });
40501
40841
  $('refresh').addEventListener('click', () => refresh(true));
40502
40842
  $('period').addEventListener('change', changePeriod);
40843
+ $('evidence-filter').addEventListener('input', applyEvidenceFilters);
40844
+ $('evidence-type').addEventListener('change', applyEvidenceFilters);
40845
+ $('evidence-sort').addEventListener('change', applyEvidenceFilters);
40503
40846
  $('measurement-help').addEventListener('click', measurementHelp);
40504
40847
  $('theme').addEventListener('change', () => {
40505
40848
  const value = $('theme').value;
@@ -40515,6 +40858,8 @@ var init_guided_product_client = __esm({
40515
40858
  selectView('dashboard');
40516
40859
  refresh(false);
40517
40860
  setInterval(() => { if (!document.hidden) loadActivity(); }, 4000);
40861
+ setInterval(pollRouting, 15000);
40862
+ document.addEventListener('visibilitychange', () => { if (!document.hidden) pollRouting(); });
40518
40863
  })();
40519
40864
  `;
40520
40865
  }
@@ -40541,9 +40886,13 @@ var init_guided_product_styles = __esm({
40541
40886
  .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}
40542
40887
  .choice-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.6rem;margin:.8rem 0}.choice-button{display:flex;flex-direction:column;align-items:flex-start;text-align:left;gap:.25rem;background:var(--panel);color:var(--text);border:1px solid var(--line);padding:.8rem}.choice-button:hover:not(:disabled){border-color:var(--accent);background:var(--accent-soft)}.choice-button .caption{font-weight:500}
40543
40888
  .result-signal{display:grid;gap:.2rem;border-top:1px solid var(--line);padding:.65rem 0}.result-signal strong{font-size:1rem}.results-header{display:flex;justify-content:space-between;gap:1rem;align-items:end;margin:1rem 0}.results-header h2{margin:0}.results-header p{margin:.2rem 0;color:var(--muted)}
40889
+ .update-notice{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.8rem 1rem;margin:.8rem 0;border:1px solid color-mix(in srgb,var(--accent) 40%,var(--line));border-radius:var(--radius);background:var(--accent-soft)}.update-notice p{margin:.2rem 0 0;color:var(--muted)}
40890
+ .inline-actions a.secondary{display:inline-flex;align-items:center;padding:.68rem 1rem;border-radius:10px;text-decoration:none;font-weight:700}
40891
+ .evidence-panel{padding:0}.evidence-controls{display:flex;align-items:end;gap:.7rem;flex-wrap:wrap;padding:.8rem;border-bottom:1px solid var(--line)}.evidence-controls label{display:grid;gap:.25rem;color:var(--muted);font-size:.82rem}.evidence-controls input,.evidence-controls select{min-width:150px}.evidence-controls input{min-width:min(260px,70vw)}.evidence-table-scroll{overflow-x:auto}.evidence-table{width:100%;border-collapse:collapse;min-width:760px}.evidence-table th,.evidence-table td{padding:.75rem .85rem;text-align:left;vertical-align:top;border-bottom:1px solid var(--line)}.evidence-table thead{background:var(--panel-soft);color:var(--muted);font-size:.8rem}.evidence-table tbody th{min-width:175px;font-weight:600}.evidence-table tbody th span{display:block;margin-top:.2rem}.evidence-table td:nth-child(2){min-width:150px}.evidence-table td:nth-child(3){min-width:240px}.evidence-table td:last-child{min-width:110px}.evidence-table details summary{cursor:pointer;color:var(--accent);font-weight:700}.evidence-table details p{margin:.45rem 0}.evidence-table tr[hidden]{display:none}.activity-scroll{max-height:24rem;overflow-y:auto;overscroll-behavior:contain}.activity-scroll .activity-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:.75rem;padding:.65rem 0;border-bottom:1px solid var(--line)}
40544
40892
  #modal{width:min(720px,calc(100vw - 2rem));max-height:calc(100vh - 2rem);overflow:auto}#modal-content h3{margin:1rem 0 .4rem}#modal-actions{display:flex;justify-content:flex-end;gap:.5rem;flex-wrap:wrap;margin-top:1rem}
40545
40893
  @media(max-width:900px){.dashboard-columns{grid-template-columns:1fr}.tool-grid{grid-template-columns:1fr}.setup-intro{grid-template-columns:1fr}}
40546
- @media(max-width:640px){.dashboard-status{flex-direction:column}.choice-grid{grid-template-columns:1fr}.connection-summary{align-items:flex-start;flex-direction:column}.connection-action{justify-content:flex-start}.maintenance-row{align-items:flex-start;flex-direction:column}.results-header{align-items:flex-start;flex-direction:column}}
40894
+ @media(max-width:640px){.dashboard-status{flex-direction:column}.choice-grid{grid-template-columns:1fr}.connection-summary{align-items:flex-start;flex-direction:column}.connection-action{justify-content:flex-start}.maintenance-row{align-items:flex-start;flex-direction:column}.results-header{align-items:flex-start;flex-direction:column}.update-notice{align-items:flex-start;flex-direction:column}.activity-scroll .activity-row{grid-template-columns:auto minmax(0,1fr)}.activity-scroll .activity-row time{grid-column:2}}
40895
+ @media(max-width:800px){.evidence-table{min-width:0}.evidence-table thead{display:none}.evidence-table tbody{display:block}.evidence-table tr{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);padding:.65rem;border-bottom:1px solid var(--line)}.evidence-table tbody th,.evidence-table td:nth-child(n){min-width:0;padding:.3rem;border:0;overflow-wrap:anywhere}.evidence-table td:nth-child(3),.evidence-table td:last-child{grid-column:1/-1}}
40547
40896
  `;
40548
40897
  }
40549
40898
  });
@@ -41203,6 +41552,7 @@ ${GUIDE_CANDIDATE_READINESS_JS}`;
41203
41552
  <div class="page-heading"><div><h1 id="view-title">Overview</h1><p id="view-description">Your coding agents, optimization stack, health and measured results in one place.</p></div></div>
41204
41553
  <div class="status-line"><span class="read-status" role="status"><span id="reading-spinner" class="spinner" aria-hidden="true"></span><span id="updated">Checking your setup\u2026</span></span><span id="live-status" class="caption">Nothing changes without your approval</span></div>
41205
41554
  <div id="stale-state" class="stale-state" hidden></div><div id="error" class="error" role="alert" hidden></div><div id="notices"></div>
41555
+ <div id="update-notice" class="update-notice" role="status" hidden></div>
41206
41556
 
41207
41557
  <section id="view-dashboard" role="tabpanel" aria-labelledby="tab-dashboard" tabindex="0">
41208
41558
  <section id="dashboard-status" class="dashboard-status"><div><span class="eyebrow">CURRENT STATUS</span><h2>Checking your machine\u2026</h2><p>Finding Claude Code, Codex, recommended optimizers and measured results.</p></div><span class="pill">Checking</span></section>
@@ -41230,7 +41580,6 @@ ${GUIDE_CANDIDATE_READINESS_JS}`;
41230
41580
  <section class="setup-step" id="optimizers">
41231
41581
  <div class="section-title"><div><h2>Optimizer setup</h2><p>This matrix shows which optimizer setup Token Harness detected for each coding app. It does not confirm runtime activity; measured results appear separately when evidence is recorded.</p></div></div>
41232
41582
  <div id="connection-overview" class="connection-overview"><p class="empty">Checking optimizer connections\u2026</p></div>
41233
- <details class="disclosure"><summary>Remove Token Harness-managed configuration</summary><p class="caption">Removal is reviewed first. Token Harness removes only configuration it owns; installed provider software and user-owned configuration may remain.</p><div id="managed-removal-actions" class="maintenance-list"><p class="caption">Checking managed ownership\u2026</p></div></details>
41234
41583
  </section>
41235
41584
 
41236
41585
  <section class="setup-step" id="maintenance">
@@ -41240,15 +41589,15 @@ ${GUIDE_CANDIDATE_READINESS_JS}`;
41240
41589
  </section>
41241
41590
 
41242
41591
  <section id="view-results" role="tabpanel" aria-labelledby="tab-results" tabindex="0" hidden>
41243
- <div class="results-header"><div><h2>Results dashboard</h2><p>See which optimizer setups Token Harness found and which results it actually recorded for each coding app.</p></div><div class="filter-row"><label for="period">Period</label><select id="period"><option value="all">All</option><option value="7d">7 days</option><option value="30d">30 days</option></select><button id="measurement-help" class="secondary" type="button">How results are recorded</button></div></div>
41244
- <div id="result-summary" class="impact-grid" aria-label="Results overview"><article class="metric-card"><span class="metric-label">Optimization stack</span><strong class="metric-value">Checking\u2026</strong></article></div>
41245
- <div class="section-title"><div><h2>By optimizer</h2><p>Detected setup and recorded results for every optimizer in the stack.</p></div></div>
41246
- <div id="result-optimizers" class="tool-grid"><article class="tool-card"><h3>Checking optimizer results\u2026</h3></article></div>
41247
- <div class="section-title"><div><h2>By coding agent</h2><p>Which optimizer setups were detected for each app and which measured results can be linked to it.</p></div></div>
41248
- <div id="result-agents" class="tool-grid"><article class="tool-card"><h3>Checking results by coding app\u2026</h3></article></div>
41249
- <div class="section-title"><div><h2>Measurement evidence</h2><p id="results-period-note">Checking recorded dates\u2026</p></div></div><section class="panel"><div id="result-savings" class="evidence-list"><p class="empty">Checking recorded results\u2026</p></div></section>
41250
- <div class="section-title"><div><h2>Experimental benchmark results</h2><p>Candidate evidence is evaluation only; it never promotes a tool automatically.</p></div></div><section class="panel"><div id="candidate-results" class="evidence-list"><p class="empty">Checking candidate evidence\u2026</p></div></section>
41251
- <div class="section-title"><div><h2>Recent activity</h2><p>Checks and changes from this local app session.</p></div></div><section class="panel"><div id="activity"><p class="empty">No activity yet.</p></div></section>
41592
+ <div class="results-header"><div><h2>Results dashboard</h2><p>Measured evidence by optimizer, routing and coding app. Different classes and units stay separate.</p></div><div class="filter-row"><label for="period">Period</label><select id="period"><option value="all">All</option><option value="7d">7 days</option><option value="30d">30 days</option></select><button id="measurement-help" class="secondary" type="button">How results are recorded</button></div></div>
41593
+ <div id="result-summary" class="impact-grid" aria-label="Results overview"><article class="metric-card"><span class="metric-label">Measured evidence</span><strong class="metric-value">Checking\u2026</strong></article></div>
41594
+ <div class="section-title"><div><h2>Evidence</h2><p id="results-period-note">Checking recorded dates\u2026</p></div></div>
41595
+ <section class="panel evidence-panel">
41596
+ <div class="evidence-controls"><label>Filter <input id="evidence-filter" type="search" placeholder="Optimizer, harness, class\u2026" autocomplete="off"></label><label>Type <select id="evidence-type"><option value="all">All</option><option value="optimizer">Optimizers</option><option value="routing">Routing</option><option value="harness">Coding apps</option><option value="candidate">Experiments</option></select></label><label>Sort <select id="evidence-sort"><option value="name">Name</option><option value="evidence">Evidence count</option><option value="type">Type</option></select></label></div>
41597
+ <div class="evidence-table-scroll"><table class="evidence-table"><thead><tr><th scope="col">System</th><th scope="col">Scope</th><th scope="col">Measured evidence</th><th scope="col">Details</th></tr></thead><tbody id="result-evidence"><tr><td colspan="4">Checking recorded results\u2026</td></tr></tbody></table></div>
41598
+ <p id="evidence-empty" class="empty" hidden>No evidence matches these filters.</p>
41599
+ </section>
41600
+ <div class="section-title"><div><h2>Recent activity</h2><p>Latest checks and changes from this app session.</p></div></div><section class="panel"><div id="activity" class="activity-scroll"><p class="empty">No activity yet.</p></div></section>
41252
41601
  </section>
41253
41602
 
41254
41603
  <footer><span>Local data. No account required.</span><span>Full overview refresh runs only when you choose Refresh.</span></footer>
@@ -41436,6 +41785,10 @@ function createGuideHandler(input) {
41436
41785
  send(200, JSON.stringify(input.service.status()));
41437
41786
  return;
41438
41787
  }
41788
+ if (url.pathname === "/api/routing") {
41789
+ send(200, JSON.stringify(await input.service.routing()));
41790
+ return;
41791
+ }
41439
41792
  if (url.pathname === "/api/candidate-campaign") {
41440
41793
  if (input.candidateCampaign === void 0)
41441
41794
  throw new GuideError(404, "Candidate campaign status is unavailable.");
@@ -41493,6 +41846,12 @@ function createGuideHandler(input) {
41493
41846
  send(200, JSON.stringify(result6));
41494
41847
  return;
41495
41848
  }
41849
+ if (url.pathname === "/api/restart") {
41850
+ if (body === null || typeof body !== "object" || Array.isArray(body) || Object.keys(body).length !== 0)
41851
+ throw new GuideError(400, "Restart accepts no commands or paths.");
41852
+ send(200, JSON.stringify(await input.service.restart()));
41853
+ return;
41854
+ }
41496
41855
  if (url.pathname === "/api/update-check") {
41497
41856
  if (body === null || typeof body !== "object" || Array.isArray(body))
41498
41857
  throw new GuideError(400, "Only an optional reporting period is accepted.");
@@ -42036,6 +42395,7 @@ async function runGuidedUi(options, base) {
42036
42395
  }
42037
42396
  return result6;
42038
42397
  };
42398
+ const entryScript = base.adapters === null || base.adapters === void 0 || base.applicationEntryScript === void 0 || base.applicationEntryScript === null ? null : await base.adapters.fs.canonicalPath?.(base.applicationEntryScript) ?? null;
42039
42399
  const service = new GuideService(guideCall, () => Date.now(), () => randomBytes2(32).toString("hex"), async (harness) => {
42040
42400
  if (base.adapters === null || base.adapters === void 0) {
42041
42401
  return {
@@ -42077,8 +42437,23 @@ async function runGuidedUi(options, base) {
42077
42437
  facts: base.platform,
42078
42438
  paths: base.adapters.paths,
42079
42439
  projectRoot: base.cwd,
42080
- projectId: base.adapters.projectIdFor(base.cwd)
42440
+ projectId: null
42441
+ });
42442
+ }, async () => {
42443
+ if (entryScript === null || base.adapters === null || base.adapters === void 0 || base.platform === null)
42444
+ throw new Error("The installed app entry could not be verified.");
42445
+ const current = await base.adapters.fs.canonicalPath?.(base.applicationEntryScript);
42446
+ if (current !== entryScript || (await base.adapters.fs.stat(entryScript))?.kind !== "file")
42447
+ throw new Error("The app entry changed. Check the installation before restarting.");
42448
+ const url2 = await launchGuidedApplication({
42449
+ executable: process5.execPath,
42450
+ entryScript,
42451
+ cwd: base.cwd,
42452
+ facts: base.platform,
42453
+ env: process5.env
42081
42454
  });
42455
+ setTimeout(() => server.close(), 1e3);
42456
+ return url2;
42082
42457
  });
42083
42458
  const token = randomBytes2(32).toString("hex");
42084
42459
  let authority = "";
@@ -42107,6 +42482,8 @@ async function runGuidedUi(options, base) {
42107
42482
  }
42108
42483
  authority = `127.0.0.1:${address.port}`;
42109
42484
  const url = `http://${authority}/`;
42485
+ if (process5.send !== void 0)
42486
+ process5.send({ type: "token-harness-guide-ready", url });
42110
42487
  process5.stdout.write(`Token Harness is ready: ${url}
42111
42488
 
42112
42489
  Use the browser to review setup, see recorded savings and read the active rules.