tesseract-agent 0.10.7 → 0.10.9

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.
@@ -80,16 +80,25 @@ function deriveSystemDirs(home) {
80
80
  music: join(home, "Music")
81
81
  };
82
82
  }
83
+ function expandTilde(p) {
84
+ if (p === "~")
85
+ return USER_HOME;
86
+ if (p.startsWith("~/") || p.startsWith("~\\"))
87
+ return join(USER_HOME, p.slice(2));
88
+ return p;
89
+ }
83
90
  function memoEnvRoot() {
84
91
  const memo = /* @__PURE__ */ new Map();
85
- return (envVar, fallback) => {
86
- const hit = memo.get(envVar);
92
+ return (envVars, fallback) => {
93
+ const names = Array.isArray(envVars) ? envVars : [envVars];
94
+ const memoKey = names.join("|");
95
+ const hit = memo.get(memoKey);
87
96
  if (hit !== void 0)
88
97
  return hit;
89
- const raw = process.env[envVar];
90
- const value = raw && raw.trim() ? resolve(STARTUP_CWD, raw.trim()) : fallback();
98
+ const raw = names.map((n) => process.env[n]).find((v) => v && v.trim());
99
+ const value = raw ? resolve(STARTUP_CWD, expandTilde(raw.trim())) : fallback();
91
100
  if (!peeking)
92
- memo.set(envVar, value);
101
+ memo.set(memoKey, value);
93
102
  return value;
94
103
  };
95
104
  }
@@ -100,13 +109,30 @@ function homePath(...segments) {
100
109
  return join(USER_HOME, ...segments);
101
110
  }
102
111
  function tesseractHome() {
103
- return envRoot("CCB_TESSERACT_DIR", () => join(USER_HOME, ".tesseract"));
112
+ return envRoot([...TESSERACT_HOME_ENV_VARS], () => join(USER_HOME, ".tesseract"));
113
+ }
114
+ function isAlternateHome() {
115
+ return tesseractHome() !== installedTesseractHome();
116
+ }
117
+ function homeTag() {
118
+ if (!isAlternateHome())
119
+ return "";
120
+ let h = 2166136261;
121
+ const path6 = tesseractHome();
122
+ for (let i = 0; i < path6.length; i++) {
123
+ h ^= path6.charCodeAt(i);
124
+ h = Math.imul(h, 16777619);
125
+ }
126
+ return (h >>> 0).toString(36);
127
+ }
128
+ function installedTesseractHome() {
129
+ return join(USER_HOME, ".tesseract");
104
130
  }
105
131
  function tessPath(...segments) {
106
132
  return join(tesseractHome(), ...segments);
107
133
  }
108
134
  function daemonDir() {
109
- return envRoot("CCB_DAEMON_DIR", () => join(tesseractHome(), "daemon"));
135
+ return envRoot(["TESSERACT_DAEMON_DIR", "CCB_DAEMON_DIR"], () => join(tesseractHome(), "daemon"));
110
136
  }
111
137
  function daemonPath(...segments) {
112
138
  return join(daemonDir(), ...segments);
@@ -140,7 +166,7 @@ function sealBasePaths() {
140
166
  claudeConfigDir();
141
167
  return snapshotBasePaths();
142
168
  }
143
- var STARTUP_CWD, USER_HOME, TEMP_DIR, systemDirs, envRoot, peeking, dropsDir;
169
+ var STARTUP_CWD, USER_HOME, TEMP_DIR, systemDirs, envRoot, peeking, dropsDir, TESSERACT_HOME_ENV_VARS;
144
170
  var init_base_paths = __esm({
145
171
  "../../packages/shared/dist/base-paths.js"() {
146
172
  "use strict";
@@ -151,6 +177,7 @@ var init_base_paths = __esm({
151
177
  envRoot = memoEnvRoot();
152
178
  peeking = false;
153
179
  dropsDir = () => join(systemDirs.downloads, "Tesseract");
180
+ TESSERACT_HOME_ENV_VARS = ["TESSERACT_HOMEDIR", "CCB_TESSERACT_DIR"];
154
181
  }
155
182
  });
156
183
 
@@ -3983,6 +4010,20 @@ var init_app_elements = __esm({
3983
4010
  title: "Search",
3984
4011
  description: "Opens search and the command palette \u2014 the fastest way to find anything."
3985
4012
  },
4013
+ {
4014
+ id: "guide.dock",
4015
+ area: "guide",
4016
+ title: "The guide",
4017
+ // No `reveal`: the dock only exists while the guide is summoned, and a tour step that
4018
+ // silently opened it would be pointing at something it had just conjured.
4019
+ description: "Sits in the bottom corner when summoned. Type or say what you want and she does it."
4020
+ },
4021
+ {
4022
+ id: "titlebar.guide",
4023
+ area: "titlebar",
4024
+ title: "Ask the guide",
4025
+ description: "Opens the guide \u2014 say or type what you want and she does it, or shows you where."
4026
+ },
3986
4027
  {
3987
4028
  id: "titlebar.settings",
3988
4029
  area: "titlebar",
@@ -4226,8 +4267,8 @@ function parseModelJsonArray(raw) {
4226
4267
  function schemaRejected(status2) {
4227
4268
  return status2 === 400 || status2 === 422;
4228
4269
  }
4229
- function anthropicBaseUrl() {
4230
- return process.env.ANTHROPIC_BASE_URL?.trim() || "https://api.anthropic.com";
4270
+ function anthropicBaseUrl(env) {
4271
+ return env?.ANTHROPIC_BASE_URL?.trim() || process.env.ANTHROPIC_BASE_URL?.trim() || "https://api.anthropic.com";
4231
4272
  }
4232
4273
  var OAUTH_BETA_HEADER;
4233
4274
  var init_model_json = __esm({
@@ -4251,6 +4292,56 @@ var init_domain_id = __esm({
4251
4292
  }
4252
4293
  });
4253
4294
 
4295
+ // ../../packages/shared/dist/run-directive.js
4296
+ function withRunDirective(userText, directive) {
4297
+ if (!directive.trim())
4298
+ return userText;
4299
+ const head = userText ? `${userText}
4300
+
4301
+ ` : "";
4302
+ return `${head}${RUN_DIRECTIVE_MARK}
4303
+ ${directive}`;
4304
+ }
4305
+ var RUN_DIRECTIVE_MARK;
4306
+ var init_run_directive = __esm({
4307
+ "../../packages/shared/dist/run-directive.js"() {
4308
+ "use strict";
4309
+ RUN_DIRECTIVE_MARK = "<!-- tesseract:run-directive -->";
4310
+ }
4311
+ });
4312
+
4313
+ // ../../packages/shared/dist/proactive-compaction.js
4314
+ function proactiveCompactionVerdict(a) {
4315
+ if (a.inFlight)
4316
+ return "skip";
4317
+ if (typeof a.pct !== "number" || !Number.isFinite(a.pct) || a.pct <= 0 || a.pct >= 100)
4318
+ return "skip";
4319
+ if (typeof a.usagePct !== "number" || !Number.isFinite(a.usagePct))
4320
+ return "skip";
4321
+ if (a.usagePct > IMPOSSIBLE_FILL_PCT)
4322
+ return "skip";
4323
+ if (a.usagePct < a.pct)
4324
+ return "reset";
4325
+ if (typeof a.lastCompactPct === "number" && a.usagePct < a.lastCompactPct + PROACTIVE_REGROWTH_POINTS)
4326
+ return "skip";
4327
+ return "compact";
4328
+ }
4329
+ var PROACTIVE_REGROWTH_POINTS, IMPOSSIBLE_FILL_PCT;
4330
+ var init_proactive_compaction = __esm({
4331
+ "../../packages/shared/dist/proactive-compaction.js"() {
4332
+ "use strict";
4333
+ PROACTIVE_REGROWTH_POINTS = 5;
4334
+ IMPOSSIBLE_FILL_PCT = 100;
4335
+ }
4336
+ });
4337
+
4338
+ // ../../packages/shared/dist/digit-recall.js
4339
+ var init_digit_recall = __esm({
4340
+ "../../packages/shared/dist/digit-recall.js"() {
4341
+ "use strict";
4342
+ }
4343
+ });
4344
+
4254
4345
  // ../../packages/shared/dist/telemetry.js
4255
4346
  var TELEMETRY_EVENTS, EVENT_CATEGORY;
4256
4347
  var init_telemetry = __esm({
@@ -4678,14 +4769,67 @@ var init_hosting = __esm({
4678
4769
  }
4679
4770
  });
4680
4771
 
4772
+ // ../../packages/shared/dist/model-long-context.js
4773
+ function supportsOneMillionContext(model) {
4774
+ const id = (model ?? "").trim();
4775
+ if (!id)
4776
+ return false;
4777
+ if (/haiku/i.test(id))
4778
+ return false;
4779
+ return ONE_MILLION_FAMILIES.some((re) => re.test(id));
4780
+ }
4781
+ function hasOneMillionSuffix(model) {
4782
+ return /\[1m\]$/i.test((model ?? "").trim());
4783
+ }
4784
+ function withOneMillionContext(model) {
4785
+ const id = model?.trim();
4786
+ if (!id)
4787
+ return model;
4788
+ if (hasOneMillionSuffix(id))
4789
+ return id;
4790
+ if (!supportsOneMillionContext(id))
4791
+ return id;
4792
+ return `${id}${SUFFIX}`;
4793
+ }
4794
+ function withoutOneMillionContext(model) {
4795
+ const id = model?.trim();
4796
+ if (!id)
4797
+ return model;
4798
+ return id.replace(/\[1m\]$/i, "");
4799
+ }
4800
+ var ONE_MILLION_FAMILIES, SUFFIX;
4801
+ var init_model_long_context = __esm({
4802
+ "../../packages/shared/dist/model-long-context.js"() {
4803
+ "use strict";
4804
+ ONE_MILLION_FAMILIES = [
4805
+ /(^|[/.])claude-sonnet-(4-6|4-7|4-8|5)\b/i,
4806
+ /(^|[/.])claude-opus-(4-6|4-7|4-8|5)\b/i,
4807
+ /(^|[/.])claude-fable-5\b/i,
4808
+ // The CLI's own short aliases.
4809
+ /^(sonnet|opus|fable)$/i
4810
+ ];
4811
+ SUFFIX = "[1m]";
4812
+ }
4813
+ });
4814
+
4681
4815
  // ../../packages/shared/dist/settings.js
4682
4816
  function canCallDirectly(modelId) {
4683
4817
  return !!modelId && MODEL_OPTIONS.some((m) => m.id === modelId);
4684
4818
  }
4685
- var MODEL_OPTIONS, DEFAULT_VERIFIER_MODEL;
4819
+ function isCliModelAlias(model) {
4820
+ return CLI_MODEL_ALIASES.test((model ?? "").trim());
4821
+ }
4822
+ function verifierModelLadder(model) {
4823
+ const bare = withoutOneMillionContext(model) ?? model;
4824
+ const first = canCallDirectly(bare) ? bare : DEFAULT_VERIFIER_MODEL;
4825
+ const rest = MODEL_OPTIONS.map((m) => m.id).filter((id) => id !== first && !/haiku/i.test(id));
4826
+ return [first, ...rest];
4827
+ }
4828
+ var MODEL_OPTIONS, DEFAULT_VERIFIER_MODEL, CLI_MODEL_ALIASES;
4686
4829
  var init_settings = __esm({
4687
4830
  "../../packages/shared/dist/settings.js"() {
4688
4831
  "use strict";
4832
+ init_model_long_context();
4689
4833
  MODEL_OPTIONS = [
4690
4834
  { id: "claude-opus-5", label: "Claude Opus 5" },
4691
4835
  { id: "claude-sonnet-5", label: "Claude Sonnet 5" },
@@ -4695,6 +4839,7 @@ var init_settings = __esm({
4695
4839
  { id: "claude-haiku-4-5", label: "Claude Haiku 4.5" }
4696
4840
  ];
4697
4841
  DEFAULT_VERIFIER_MODEL = MODEL_OPTIONS[0].id;
4842
+ CLI_MODEL_ALIASES = /^(?:default|sonnet|opus|haiku|fable)(?:\[1m\])?$/i;
4698
4843
  }
4699
4844
  });
4700
4845
 
@@ -6373,9 +6518,9 @@ function kebab(s) {
6373
6518
  return s.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase();
6374
6519
  }
6375
6520
  function tokenCssVarName(path6, token3) {
6376
- const override2 = token3 ? tessExt(token3)?.cssVar : void 0;
6377
- if (override2) {
6378
- const name = override2.startsWith("--") ? override2 : `--${override2}`;
6521
+ const override3 = token3 ? tessExt(token3)?.cssVar : void 0;
6522
+ if (override3) {
6523
+ const name = override3.startsWith("--") ? override3 : `--${override3}`;
6379
6524
  if (/^--[A-Za-z0-9-]+$/.test(name))
6380
6525
  return name;
6381
6526
  }
@@ -7229,6 +7374,9 @@ var init_dist = __esm({
7229
7374
  init_ws_protocol();
7230
7375
  init_frame();
7231
7376
  init_domain_id();
7377
+ init_run_directive();
7378
+ init_proactive_compaction();
7379
+ init_digit_recall();
7232
7380
  init_telemetry();
7233
7381
  init_error_report();
7234
7382
  init_eula();
@@ -7920,8 +8068,9 @@ function materializeClaudeAuthHome(contents) {
7920
8068
  return home;
7921
8069
  }
7922
8070
  function withClaudeModels(env, main2, fast) {
7923
- if (main2)
7924
- env.ANTHROPIC_MODEL = main2;
8071
+ if (main2) {
8072
+ env.ANTHROPIC_MODEL = process.env.TESSERACT_DISABLE_1M_CONTEXT === "1" ? main2 : withOneMillionContext(main2) ?? main2;
8073
+ }
7925
8074
  if (fast)
7926
8075
  env.ANTHROPIC_SMALL_FAST_MODEL = fast;
7927
8076
  return env;
@@ -7948,14 +8097,14 @@ function resolveRunnerEnv(spec) {
7948
8097
  return {};
7949
8098
  const key2 = spec?.secret?.trim();
7950
8099
  if (provider.claudeEnterprise) {
7951
- const run5 = claudeEnterpriseRun(provider.claudeEnterprise, { secret: key2, baseUrl: spec?.baseUrl, main: main2, fast });
7952
- if (run5.error)
7953
- return { CCB_RUNNER_CONFIG_ERROR: run5.error };
7954
- if (!run5.file)
7955
- return run5.env;
8100
+ const run8 = claudeEnterpriseRun(provider.claudeEnterprise, { secret: key2, baseUrl: spec?.baseUrl, main: main2, fast });
8101
+ if (run8.error)
8102
+ return { CCB_RUNNER_CONFIG_ERROR: run8.error };
8103
+ if (!run8.file)
8104
+ return run8.env;
7956
8105
  try {
7957
- const path6 = materializeEnterpriseCredential(run5.file.suggestedName, run5.file.contents);
7958
- return { ...run5.env, [run5.file.envVar]: path6 };
8106
+ const path6 = materializeEnterpriseCredential(run8.file.suggestedName, run8.file.contents);
8107
+ return { ...run8.env, [run8.file.envVar]: path6 };
7959
8108
  } catch (e) {
7960
8109
  return { CCB_RUNNER_CONFIG_ERROR: `Could not write the ${provider.label} credential on this machine: ${e.message}` };
7961
8110
  }
@@ -8022,6 +8171,7 @@ var init_resolve = __esm({
8022
8171
  "../../packages/host-core/dist/runners/resolve.js"() {
8023
8172
  "use strict";
8024
8173
  init_base_paths();
8174
+ init_model_long_context();
8025
8175
  init_file_lock();
8026
8176
  init_dist();
8027
8177
  init_proxy_router();
@@ -8562,21 +8712,27 @@ function readDaemonAgentSettings() {
8562
8712
  return snap;
8563
8713
  }
8564
8714
  }
8715
+ function gatewayCanCall(model, snapshot4) {
8716
+ const tiers2 = snapshot4.gatewayTiers;
8717
+ if (!tiers2?.length)
8718
+ return true;
8719
+ return tiers2.includes(model) || snapshot4.gatewayDirectNaming === true;
8720
+ }
8565
8721
  function gatewayTierRejection(model) {
8566
8722
  if (!model)
8567
8723
  return null;
8568
- const tiers2 = readDaemonAgentSettings().gatewayTiers;
8569
- if (!tiers2?.length || tiers2.includes(model))
8724
+ const snap = readDaemonAgentSettings();
8725
+ if (gatewayCanCall(model, snap))
8570
8726
  return null;
8571
- return { model, tiers: [...tiers2] };
8727
+ return { model, tiers: [...snap.gatewayTiers ?? []] };
8572
8728
  }
8573
8729
  function gatewayTierClamp(model) {
8574
8730
  if (!model)
8575
8731
  return model;
8576
- const tiers2 = readDaemonAgentSettings().gatewayTiers;
8577
- if (!tiers2?.length || tiers2.includes(model))
8732
+ const snap = readDaemonAgentSettings();
8733
+ if (gatewayCanCall(model, snap))
8578
8734
  return model;
8579
- console.warn(`[gateway] Model "${model}" isn't served by this device's gateway key (${tiers2.join(", ")}) \u2014 dropping it so the gateway picks one it can reach.`);
8735
+ console.warn(`[gateway] Model "${model}" isn't served by this device's gateway key (${(snap.gatewayTiers ?? []).join(", ")}) \u2014 dropping it so the gateway picks one it can reach.`);
8580
8736
  return void 0;
8581
8737
  }
8582
8738
  function chatSendToParams(msg, defaults) {
@@ -8603,6 +8759,10 @@ function chatSendToParams(msg, defaults) {
8603
8759
  // one OFF for one conversation could not actually turn it off.
8604
8760
  ...msg.unattended !== void 0 ? { unattended: msg.unattended } : {},
8605
8761
  ...msg.reinforcedVerification !== void 0 ? { reinforcedVerification: msg.reinforcedVerification } : {},
8762
+ // Forwarded even at 0/100 (both mean "no proactive compaction"), for the same reason as
8763
+ // the two flags above: falling through to the machine-wide number would make a
8764
+ // conversation that opted out of compaction impossible to express.
8765
+ ...msg.autoCompactPct !== void 0 ? { autoCompactPct: msg.autoCompactPct } : {},
8606
8766
  ...msg.autoContinuation ? { autoContinuation: true } : {},
8607
8767
  ...msg.model ? { model: msg.model } : {},
8608
8768
  ...msg.jsonSchema ? { jsonSchema: msg.jsonSchema } : {},
@@ -8672,11 +8832,15 @@ function mergeDaemonAgentSettings(params) {
8672
8832
  // local override (single-config CLI). Enabled skills' env is folded in. Empty ⇒
8673
8833
  // ambient Claude.
8674
8834
  engineEnv: params.engineEnv ?? {
8675
- ...poolActiveEngineEnv() ?? (s.runnerSpec ? resolveRunnerEnv(s.runnerSpec) : resolveOverrideEngineEnv()),
8835
+ ...daemonEngineEnv(),
8676
8836
  ...s.skillEnv ?? {}
8677
8837
  }
8678
8838
  };
8679
8839
  }
8840
+ function daemonEngineEnv() {
8841
+ const s = readDaemonAgentSettings();
8842
+ return poolActiveEngineEnv() ?? (s.runnerSpec ? resolveRunnerEnv(s.runnerSpec) : resolveOverrideEngineEnv());
8843
+ }
8680
8844
  var init_daemon_settings = __esm({
8681
8845
  "../../packages/host-core/dist/daemon-settings.js"() {
8682
8846
  "use strict";
@@ -12031,10 +12195,10 @@ var init_schemas = __esm({
12031
12195
  $ZodType.init(inst, def);
12032
12196
  const desc = Object.getOwnPropertyDescriptor(def, "shape");
12033
12197
  if (!desc?.get) {
12034
- const sh = def.shape;
12198
+ const sh3 = def.shape;
12035
12199
  Object.defineProperty(def, "shape", {
12036
12200
  get: () => {
12037
- const newSh = { ...sh };
12201
+ const newSh = { ...sh3 };
12038
12202
  Object.defineProperty(def, "shape", {
12039
12203
  value: newSh
12040
12204
  });
@@ -28539,8 +28703,8 @@ function prompt(id, vars) {
28539
28703
  }
28540
28704
  return "";
28541
28705
  }
28542
- const override2 = snapshot2.entries[id];
28543
- return interpolatePrompt(typeof override2 === "string" ? override2 : spec.content, vars);
28706
+ const override3 = snapshot2.entries[id];
28707
+ return interpolatePrompt(typeof override3 === "string" ? override3 : spec.content, vars);
28544
28708
  }
28545
28709
  function describedBy(idPrefix, specs, key2 = (s) => s.name) {
28546
28710
  return specs.map((spec) => Object.defineProperty({ ...spec }, "description", {
@@ -28681,7 +28845,7 @@ function buildPack(s) {
28681
28845
  const dual = (lv) => ({ $value: lv[0], $extensions: { "com.tesseract": { modes: { dark: lv[1] } } } });
28682
28846
  const val = (v) => Array.isArray(v) ? dual(v) : { $value: v };
28683
28847
  const r = s.radius ?? { sm: "6px", md: "10px", lg: "16px" };
28684
- const sh = s.shadow ?? {
28848
+ const sh3 = s.shadow ?? {
28685
28849
  sm: "0 1px 2px rgb(0 0 0 / 0.06)",
28686
28850
  md: "0 4px 12px rgb(0 0 0 / 0.08)",
28687
28851
  lg: "0 12px 32px rgb(0 0 0 / 0.12)"
@@ -28726,7 +28890,7 @@ function buildPack(s) {
28726
28890
  xl: { $value: "40px" }
28727
28891
  },
28728
28892
  radius: { $type: "dimension", sm: { $value: r.sm }, md: { $value: r.md }, lg: { $value: r.lg }, full: { $value: "9999px" } },
28729
- shadow: { $type: "shadow", sm: { $value: sh.sm }, md: { $value: sh.md }, lg: { $value: sh.lg } }
28893
+ shadow: { $type: "shadow", sm: { $value: sh3.sm }, md: { $value: sh3.md }, lg: { $value: sh3.lg } }
28730
28894
  };
28731
28895
  return { $packSchema: DESIGN_PACK_SCHEMA, id: s.id, name: s.name, description: s.description, style: s.style, tokens: tokens3 };
28732
28896
  }
@@ -31689,7 +31853,7 @@ var init_job_registry = __esm({
31689
31853
  * the calling tool can return `{ id, logPath }` to the model in the same tick, so the
31690
31854
  * turn continues instead of blocking. `run` is deliberately NOT awaited here.
31691
31855
  */
31692
- start(kind, description, run5) {
31856
+ start(kind, description, run8) {
31693
31857
  const id = makeId(++this.seq);
31694
31858
  const logPath = join16(this.dir, `${id}.output`);
31695
31859
  const abort = new AbortController();
@@ -31709,7 +31873,7 @@ var init_job_registry = __esm({
31709
31873
  this.evict();
31710
31874
  void (async () => {
31711
31875
  try {
31712
- const tail3 = await run5((chunk) => this.write(id, chunk), abort.signal);
31876
+ const tail3 = await run8((chunk) => this.write(id, chunk), abort.signal);
31713
31877
  if (typeof tail3 === "string" && tail3)
31714
31878
  this.write(id, tail3);
31715
31879
  this.settle(id, abort.signal.aborted ? "stopped" : "completed", abort.signal.aborted ? 130 : 0);
@@ -33458,9 +33622,9 @@ function paginationSignature(engine) {
33458
33622
  return [...engine.pagination.params].sort().join("+");
33459
33623
  }
33460
33624
  function pageStrategy(engine) {
33461
- const override2 = OVERRIDES[engine.id];
33462
- if (override2)
33463
- return override2;
33625
+ const override3 = OVERRIDES[engine.id];
33626
+ if (override3)
33627
+ return override3;
33464
33628
  const sig = paginationSignature(engine);
33465
33629
  if (!sig)
33466
33630
  return { kind: "none", reason: "This engine declares no pagination parameters." };
@@ -36608,27 +36772,18 @@ function autoCompactEnvFor(pct2, supplied) {
36608
36772
  function shouldCompactProactively(a) {
36609
36773
  if (a.mode === "off")
36610
36774
  return "skip";
36611
- if (a.inFlight)
36612
- return "skip";
36613
- if (typeof a.pct !== "number" || !Number.isFinite(a.pct) || a.pct <= 0 || a.pct >= 100)
36614
- return "skip";
36615
- if (typeof a.usagePct !== "number" || !Number.isFinite(a.usagePct))
36616
- return "skip";
36617
- if (a.usagePct < a.pct)
36618
- return "reset";
36619
- if (typeof a.lastCompactPct === "number" && a.usagePct < a.lastCompactPct + PROACTIVE_REGROWTH_POINTS)
36620
- return "skip";
36621
- return "compact";
36775
+ return proactiveCompactionVerdict(a);
36622
36776
  }
36623
- var OVERFLOW_MAX_TRIES, OVERFLOW_COMPACT_MESSAGE, OVERFLOW_RESUME_MESSAGE, PROACTIVE_REGROWTH_POINTS;
36777
+ var OVERFLOW_MAX_TRIES, OVERFLOW_COMPACT_MESSAGE, OVERFLOW_RESUME_MESSAGE;
36624
36778
  var init_context_recovery = __esm({
36625
36779
  "../../packages/agent-core/dist/context-recovery.js"() {
36626
36780
  "use strict";
36781
+ init_dist();
36627
36782
  init_unattended_log();
36783
+ init_dist();
36628
36784
  OVERFLOW_MAX_TRIES = 3;
36629
36785
  OVERFLOW_COMPACT_MESSAGE = "/compact";
36630
36786
  OVERFLOW_RESUME_MESSAGE = "Continue.";
36631
- PROACTIVE_REGROWTH_POINTS = 5;
36632
36787
  }
36633
36788
  });
36634
36789
 
@@ -37456,13 +37611,16 @@ async function fetchSessionUsage(env) {
37456
37611
  }
37457
37612
  async function anthropicHeaders(env) {
37458
37613
  const apiKey = env?.ANTHROPIC_API_KEY?.trim() || process.env.ANTHROPIC_API_KEY?.trim() || "";
37459
- const oauth = apiKey ? "" : await resolveOauthToken(env) || "";
37460
- if (!apiKey && !oauth)
37614
+ const authToken = apiKey ? "" : env?.ANTHROPIC_AUTH_TOKEN?.trim() || "";
37615
+ const oauth = apiKey || authToken ? "" : await resolveOauthToken(env) || "";
37616
+ if (!apiKey && !authToken && !oauth)
37461
37617
  return null;
37462
37618
  const headers = { "content-type": "application/json", "anthropic-version": "2023-06-01" };
37463
37619
  if (apiKey)
37464
37620
  headers["x-api-key"] = apiKey;
37465
- else {
37621
+ else if (authToken) {
37622
+ headers.authorization = `Bearer ${authToken}`;
37623
+ } else {
37466
37624
  headers.authorization = `Bearer ${oauth}`;
37467
37625
  headers["anthropic-beta"] = OAUTH_BETA_HEADER;
37468
37626
  }
@@ -37472,27 +37630,31 @@ async function hasAnthropicCred(env) {
37472
37630
  return await anthropicHeaders(env) !== null;
37473
37631
  }
37474
37632
  async function anthropicMessage(args) {
37633
+ return (await anthropicCall(args)).text;
37634
+ }
37635
+ async function anthropicCall(args) {
37475
37636
  const { env, model, system, content, maxTokens, timeoutMs, label } = args;
37476
37637
  const attempts = Math.max(1, args.attempts ?? 1);
37477
37638
  const budgetMs = args.budgetMs ?? attempts * timeoutMs + 4e3;
37478
37639
  const deadline = Date.now() + budgetMs;
37479
- const base = { model, max_tokens: maxTokens, system, messages: [{ role: "user", content }] };
37480
- let body = JSON.stringify(args.schema ? { ...base, output_config: { format: { type: "json_schema", schema: args.schema } } } : base);
37481
- let schemaDropped = false;
37640
+ const base = { ...model ? { model } : {}, max_tokens: maxTokens, system, messages: [{ role: "user", content }] };
37641
+ const useSchema = !!args.schema && !schemaUnsupported.has(schemaKey(anthropicBaseUrl(env), model));
37642
+ let body = JSON.stringify(useSchema ? { ...base, output_config: { format: { type: "json_schema", schema: args.schema } } } : base);
37643
+ let schemaDropped = !useSchema;
37482
37644
  const headers = await anthropicHeaders(env);
37483
37645
  if (!headers)
37484
- return null;
37646
+ return { text: null, rateLimited: false };
37485
37647
  for (let attempt = 0; attempt < attempts; attempt++) {
37486
37648
  const remaining = deadline - Date.now();
37487
37649
  if (remaining < 1e3) {
37488
37650
  log(`${label}: out of budget after ${attempt} attempt(s) \u2014 giving up rather than starting a leg that cannot finish.`);
37489
- return null;
37651
+ return { text: null, rateLimited: false };
37490
37652
  }
37491
37653
  const ac = new AbortController();
37492
37654
  const legMs = Math.min(timeoutMs, remaining);
37493
37655
  const legTimer = setTimeout(() => ac.abort(new Error("The operation was aborted due to timeout")), legMs);
37494
37656
  try {
37495
- const res = await fetch(`${anthropicBaseUrl()}/v1/messages`, {
37657
+ const res = await fetch(`${anthropicBaseUrl(env)}/v1/messages`, {
37496
37658
  method: "POST",
37497
37659
  headers,
37498
37660
  body,
@@ -37500,23 +37662,34 @@ async function anthropicMessage(args) {
37500
37662
  });
37501
37663
  if (res.ok) {
37502
37664
  const j = await res.json();
37503
- return (j.content ?? []).filter((b) => b.type === "text").map((b) => b.text ?? "").join("").trim() || null;
37665
+ const text12 = (j.content ?? []).filter((b) => b.type === "text").map((b) => b.text ?? "").join("").trim() || null;
37666
+ return { text: text12, rateLimited: false };
37504
37667
  }
37505
37668
  if (schemaRejected(res.status) && args.schema && !schemaDropped) {
37506
37669
  schemaDropped = true;
37670
+ schemaUnsupported.add(schemaKey(anthropicBaseUrl(env), model));
37507
37671
  body = JSON.stringify(base);
37508
37672
  log(`${label}: the endpoint rejected output_config (${model}) \u2014 retrying without the schema and parsing the reply as text.`);
37509
37673
  attempt--;
37510
37674
  continue;
37511
37675
  }
37512
- if ((res.status === 429 || res.status === 529) && attempt < attempts - 1) {
37513
- const wait = Math.max(0, Math.min(800 * (attempt + 1) * (attempt + 1), deadline - Date.now()));
37676
+ const rateLimited = res.status === 429 || res.status === 529;
37677
+ const modelRejected = (res.status === 400 || res.status === 403 || res.status === 404) && !!model;
37678
+ if (rateLimited && attempt < attempts - 1) {
37679
+ let stated = 0;
37680
+ try {
37681
+ stated = Number(res.headers?.get?.("retry-after")) * 1e3;
37682
+ } catch {
37683
+ stated = 0;
37684
+ }
37685
+ const backoff3 = Number.isFinite(stated) && stated > 0 ? stated : 800 * (attempt + 1) * (attempt + 1);
37686
+ const wait = Math.max(0, Math.min(backoff3, deadline - Date.now()));
37514
37687
  log(`${label}: HTTP ${res.status} (${model}) \u2014 retry ${attempt + 1} in ${wait}ms`);
37515
37688
  await new Promise((r) => setTimeout(r, wait));
37516
37689
  continue;
37517
37690
  }
37518
37691
  log(`${label}: HTTP ${res.status} (${model})`);
37519
- return null;
37692
+ return { text: null, rateLimited, modelRejected };
37520
37693
  } catch (err2) {
37521
37694
  if (args.retryOnThrow && attempt < attempts - 1) {
37522
37695
  const wait = Math.max(0, Math.min(800 * (attempt + 1) * (attempt + 1), deadline - Date.now()));
@@ -37525,19 +37698,27 @@ async function anthropicMessage(args) {
37525
37698
  continue;
37526
37699
  }
37527
37700
  log(`${label}: call failed:`, err2 instanceof Error ? err2.message : String(err2));
37528
- return null;
37701
+ return { text: null, rateLimited: false };
37529
37702
  } finally {
37530
37703
  clearTimeout(legTimer);
37531
37704
  }
37532
37705
  }
37533
- return null;
37706
+ return { text: null, rateLimited: false };
37707
+ }
37708
+ function isDirectAnthropic(env) {
37709
+ try {
37710
+ return /(^|\.)api\.anthropic\.com$/i.test(new URL(anthropicBaseUrl(env)).hostname);
37711
+ } catch {
37712
+ return false;
37713
+ }
37534
37714
  }
37535
37715
  async function buildClaudeNarrationLlm(env) {
37536
37716
  if (!await hasAnthropicCred(env))
37537
37717
  return null;
37718
+ const model = isDirectAnthropic(env) ? "claude-haiku-4-5" : env?.ANTHROPIC_SMALL_FAST_MODEL?.trim() || env?.ANTHROPIC_MODEL?.trim() || "";
37538
37719
  const complete = ({ system, prompt: prompt2, maxTokens, schema }) => anthropicMessage({
37539
37720
  env,
37540
- model: "claude-haiku-4-5",
37721
+ model,
37541
37722
  system,
37542
37723
  content: prompt2,
37543
37724
  maxTokens,
@@ -37547,43 +37728,60 @@ async function buildClaudeNarrationLlm(env) {
37547
37728
  });
37548
37729
  return { complete, engineLabel: "Claude Code" };
37549
37730
  }
37550
- async function buildClaudeSmartLlm(env) {
37551
- if (!await hasAnthropicCred(env))
37731
+ function graderLadder(model, env) {
37732
+ if (isDirectAnthropic(env))
37733
+ return verifierModelLadder(model);
37734
+ const configured = env?.ANTHROPIC_MODEL?.trim();
37735
+ const named = model?.trim();
37736
+ const wanted2 = named && !isCliModelAlias(named) ? named : configured;
37737
+ return [...new Set([wanted2, configured].filter((m) => !!m))];
37738
+ }
37739
+ async function buildClaudeSmartLlm(builderEnv) {
37740
+ return async ({ model, system, prompt: prompt2, maxTokens, schema, env: callEnv }) => {
37741
+ const env = callEnv && Object.keys(callEnv).length ? callEnv : builderEnv;
37742
+ const deadline = Date.now() + RV_GRADE_ATTEMPTS * RV_GRADE_TIMEOUT_MS + RV_GRADE_BACKOFF_MS;
37743
+ const ladder = graderLadder(model, env);
37744
+ let rejectedOnce = false;
37745
+ for (let i = 0; i < Math.max(1, ladder.length); i++) {
37746
+ const remaining = deadline - Date.now();
37747
+ if (remaining < 2e3)
37748
+ break;
37749
+ const out = await anthropicCall({
37750
+ env,
37751
+ schema,
37752
+ model: ladder[i] ?? "",
37753
+ // No `thinking` on purpose: the accepted shape differs per model generation
37754
+ // (adaptive-only, budget_tokens, disabled-at-effort), and a 400 here costs the whole
37755
+ // verification pass. The models we call think by default where it matters.
37756
+ system,
37757
+ content: prompt2,
37758
+ maxTokens,
37759
+ timeoutMs: Math.min(SMART_TIMEOUT_MS, remaining),
37760
+ label: "verifier",
37761
+ // TWO attempts, not three (RV_GRADE_ATTEMPTS) — see the deadline above. Only the
37762
+ // FIRST model gets them: a fallback leg exists because the first was rate-limited,
37763
+ // and spending the remaining budget re-asking one model would leave none for the
37764
+ // model that can actually answer.
37765
+ attempts: i === 0 ? RV_GRADE_ATTEMPTS : 1,
37766
+ retryOnThrow: i === 0,
37767
+ budgetMs: remaining
37768
+ });
37769
+ if (out.text) {
37770
+ if (i > 0)
37771
+ log(`verifier: graded with ${ladder[i]} \u2014 ${ladder[0]} was unavailable`);
37772
+ return out.text;
37773
+ }
37774
+ if (out.rateLimited)
37775
+ continue;
37776
+ if (out.modelRejected && !rejectedOnce) {
37777
+ rejectedOnce = true;
37778
+ continue;
37779
+ }
37780
+ return null;
37781
+ }
37782
+ log("verifier: every model was rate-limited or out of budget \u2014 this run cannot be graded now");
37552
37783
  return null;
37553
- return ({ model, system, prompt: prompt2, maxTokens, schema }) => anthropicMessage({
37554
- env,
37555
- schema,
37556
- // Only a model this endpoint actually serves. `/^claude-/` was a PROVIDER-NAME test
37557
- // standing in for "can this be called": it passed a gateway tier alias or a dated id
37558
- // straight through (400 → the schema-drop retry → 400 again → every verified run on that
37559
- // model reporting "the verifier did not return a usable verdict"), and it FAILED
37560
- // `us.anthropic.claude-*`, silently downgrading a Claude session's grader. The catalog
37561
- // answers the question the regex was imitating.
37562
- model: canCallDirectly(model) ? model : DEFAULT_VERIFIER_MODEL,
37563
- // No `thinking` / `output_config` on purpose: the accepted shape differs per model
37564
- // generation (adaptive-only, budget_tokens, disabled-at-effort), and a 400 here costs
37565
- // the whole verification pass. The models we call think by default where it matters.
37566
- system,
37567
- content: prompt2,
37568
- maxTokens,
37569
- timeoutMs: SMART_TIMEOUT_MS,
37570
- label: "verifier",
37571
- // TWO attempts, not three (RV_GRADE_ATTEMPTS). The desktop gives a grade
37572
- // RV_VERDICT_GRACE_MS before it stops waiting and ends the run itself; a third attempt
37573
- // plus backoff pushes the sum past it, so the verdict would land after the client had
37574
- // already moved on — and then dispatch a "continue and finish it" turn into whatever
37575
- // the user started next.
37576
- attempts: RV_GRADE_ATTEMPTS,
37577
- retryOnThrow: true,
37578
- // The ATTEMPT PLAN, not the client's grace — the two are different numbers on purpose.
37579
- // The desktop stops waiting at RV_VERDICT_GRACE_MS (180s), ends the run itself, and a
37580
- // late verdict then dispatches a "continue and finish it" turn on top of whatever the
37581
- // user started next. The shared constants already encode the gap: 2 x 75s + 4s = 154s of
37582
- // trying, leaving 26s for the verdict to actually get back and be applied. Budgeting to
37583
- // the grace itself would spend that margin and land the answer exactly as the client
37584
- // gives up, which is a race rather than a deadline.
37585
- budgetMs: RV_GRADE_ATTEMPTS * RV_GRADE_TIMEOUT_MS + RV_GRADE_BACKOFF_MS
37586
- });
37784
+ };
37587
37785
  }
37588
37786
  async function buildClaudeVisionLlm(env) {
37589
37787
  if (!await hasAnthropicCred(env))
@@ -37603,7 +37801,7 @@ async function buildClaudeVisionLlm(env) {
37603
37801
  ]
37604
37802
  });
37605
37803
  }
37606
- var execFileP, USAGE_URL, FETCH_TIMEOUT_MS, cache4, TTL_MS, SMART_TIMEOUT_MS, VISION_TIMEOUT_MS;
37804
+ var execFileP, USAGE_URL, FETCH_TIMEOUT_MS, cache4, TTL_MS, schemaUnsupported, schemaKey, SMART_TIMEOUT_MS, VISION_TIMEOUT_MS;
37607
37805
  var init_session_usage = __esm({
37608
37806
  "../../packages/agent-core/dist/session-usage.js"() {
37609
37807
  "use strict";
@@ -37615,6 +37813,8 @@ var init_session_usage = __esm({
37615
37813
  FETCH_TIMEOUT_MS = 5e3;
37616
37814
  cache4 = null;
37617
37815
  TTL_MS = 2e4;
37816
+ schemaUnsupported = /* @__PURE__ */ new Set();
37817
+ schemaKey = (base, model) => `${base}|${model}`;
37618
37818
  SMART_TIMEOUT_MS = RV_GRADE_TIMEOUT_MS;
37619
37819
  VISION_TIMEOUT_MS = 2e4;
37620
37820
  }
@@ -38061,6 +38261,26 @@ function sessionStoreFor(mode) {
38061
38261
  function unattendedReportDirective(send4) {
38062
38262
  return unattendedModeFor({ optedIn: send4.unattended, origin: send4.origin }) !== "off" ? prompt("agent.system.unattended-report") : "";
38063
38263
  }
38264
+ function sdkModelId(model) {
38265
+ const id = model?.trim();
38266
+ if (!id)
38267
+ return void 0;
38268
+ if (process.env.TESSERACT_DISABLE_1M_CONTEXT === "1")
38269
+ return id;
38270
+ if (/[/]/.test(id) || /^[a-z]{2,}\./i.test(id))
38271
+ return id;
38272
+ return withOneMillionContext(id) ?? id;
38273
+ }
38274
+ function anthropicEnvOf(env) {
38275
+ const keys = ["ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_API_KEY", "ANTHROPIC_MODEL", "ANTHROPIC_SMALL_FAST_MODEL", "CLAUDE_CODE_OAUTH_TOKEN", "CLAUDE_CONFIG_DIR"];
38276
+ const out = {};
38277
+ for (const k of keys) {
38278
+ const v = env[k];
38279
+ if (typeof v === "string" && v.trim())
38280
+ out[k] = v;
38281
+ }
38282
+ return out;
38283
+ }
38064
38284
  function unknownModelEnv(model) {
38065
38285
  const id = (model ?? "").trim();
38066
38286
  if (!id || /^claude-/i.test(id))
@@ -38324,8 +38544,8 @@ function taskNotificationNotices(content) {
38324
38544
  }
38325
38545
  if (!text12.includes("<task-notification>"))
38326
38546
  return [];
38327
- const tag = (xml2, name) => {
38328
- const m = new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(xml2);
38547
+ const tag = (xml3, name) => {
38548
+ const m = new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(xml3);
38329
38549
  return m ? m[1].trim() : "";
38330
38550
  };
38331
38551
  const specs = [];
@@ -38614,6 +38834,12 @@ function withPinnedSource(sources, pinned) {
38614
38834
  return sources;
38615
38835
  return [...sources, pinned];
38616
38836
  }
38837
+ function isCompactionPrompt(prompt2) {
38838
+ const p = (prompt2 ?? "").trim();
38839
+ if (!p.startsWith("/compact"))
38840
+ return false;
38841
+ return p.length === "/compact".length || /^[\s\n]/.test(p.slice("/compact".length));
38842
+ }
38617
38843
  function buildMobileClause(dir2) {
38618
38844
  try {
38619
38845
  let fw = "";
@@ -38711,6 +38937,8 @@ var init_agent_manager = __esm({
38711
38937
  init_reinforced_verification();
38712
38938
  init_unattended_log();
38713
38939
  init_context_recovery();
38940
+ init_model_long_context();
38941
+ init_dist();
38714
38942
  init_dist();
38715
38943
  init_dist();
38716
38944
  init_base_paths();
@@ -39173,6 +39401,26 @@ var init_agent_manager = __esm({
39173
39401
  * to pick them up (the SDK can't hot-swap mcpServers mid-query). Discarding only forfeits a
39174
39402
  * ~2-3s pre-warm on the next new conversation, and only fires on infrequent plugin/project
39175
39403
  * changes — never on the per-turn hot path. */
39404
+ /**
39405
+ * THE QUERY FACTORY — a test seam, and nothing else.
39406
+ *
39407
+ * `sendMessage` builds its own Query through the SDK, which is why the one thing every stall
39408
+ * watchdog test assumed could not be tested: that a turn ARMS the clock. Those tests arm it by
39409
+ * hand (`touchStream(live, true)`) and assert what it does, so deleting the arming call left the
39410
+ * whole file green while a stalled turn hung forever — the exact outage the watchdog exists to
39411
+ * prevent. The gap was papered over with an empty `it.skip` whose note read "needs a spawn seam
39412
+ * AgentManager does not expose". This is that seam.
39413
+ *
39414
+ * Deliberately narrow: it replaces ONLY the construction of the Query, so everything before it —
39415
+ * policy, arming, session bookkeeping, the option build — is the real code path under test. It is
39416
+ * NOT an extension point: nothing in the app calls it, and a plugin that wants to change how a
39417
+ * turn runs should be an engine backend instead.
39418
+ */
39419
+ queryFactory = query;
39420
+ /** Replace the Query factory (pass null to restore the SDK's). Tests only — see queryFactory. */
39421
+ setQueryFactoryForTests(factory) {
39422
+ this.queryFactory = factory ?? query;
39423
+ }
39176
39424
  setPluginTools(tools) {
39177
39425
  this.pluginTools = tools;
39178
39426
  if (this.warmEmpty)
@@ -39211,7 +39459,7 @@ var init_agent_manager = __esm({
39211
39459
  * doing it would spend two turns on one reclaim.
39212
39460
  */
39213
39461
  async maybeCompactProactively(live) {
39214
- const pct2 = (() => {
39462
+ const pct2 = live.autoCompactPct ?? (() => {
39215
39463
  try {
39216
39464
  return this.autoCompactPct?.();
39217
39465
  } catch {
@@ -39324,6 +39572,13 @@ var init_agent_manager = __esm({
39324
39572
  this.narrator.setConfig(cfg2);
39325
39573
  this.cheapLlm = cfg2?.complete ?? null;
39326
39574
  }
39575
+ /** The endpoint + credential this HOST runs agents against, for the manager's own
39576
+ * on-demand model calls (see summarizeSession). Injected by the host, which is the only
39577
+ * side that can resolve it — see host-core `daemonEngineEnv`. */
39578
+ hostEnv = null;
39579
+ setHostEnv(env) {
39580
+ this.hostEnv = env && Object.keys(env).length ? env : null;
39581
+ }
39327
39582
  /** Summarize a session transcript into concise Markdown with the injected cheap
39328
39583
  * (Haiku) model. Runs in the daemon — the desktop forwards the request rather
39329
39584
  * than calling a model itself. Keeps the HEAD + TAIL of a long transcript. */
@@ -39333,7 +39588,7 @@ var init_agent_manager = __esm({
39333
39588
  let llm = this.cheapLlm;
39334
39589
  if (!llm) {
39335
39590
  try {
39336
- llm = (await buildClaudeNarrationLlm())?.complete ?? null;
39591
+ llm = (await buildClaudeNarrationLlm(this.hostEnv ?? void 0))?.complete ?? null;
39337
39592
  } catch {
39338
39593
  }
39339
39594
  }
@@ -39530,7 +39785,15 @@ ${full.slice(-8e3)}`;
39530
39785
  }
39531
39786
  const todos = live.todos?.map((t) => ({ content: t.content, status: String(t.status) }));
39532
39787
  const call3 = gate === "review" ? reviewGrade(rv, finalText, todos) : gate === "phase" ? phaseGrade(rv, rv.lastVerdict?.phaseName ?? "", finalText, todos) : completenessGrade(rv, finalText, todos);
39533
- const raw = await llm({ model: live.model, system: call3.system, prompt: call3.prompt, maxTokens: 16e3, schema: call3.schema });
39788
+ const raw = await llm({
39789
+ model: live.model,
39790
+ system: call3.system,
39791
+ prompt: call3.prompt,
39792
+ maxTokens: 16e3,
39793
+ schema: call3.schema,
39794
+ // Grade THIS session on the endpoint it is running on — see live.endpointEnv.
39795
+ env: live.endpointEnv
39796
+ });
39534
39797
  if (live.rv !== rv || live.reaped) {
39535
39798
  if (live.reaped || live.rv === void 0) {
39536
39799
  emitVerification({ action: "done", gate, cycle: rv.cycles, maxCycles: RV_MAX_CYCLES, unavailable: "This run ended before it could be verified." });
@@ -39608,6 +39871,8 @@ ${full.slice(-8e3)}`;
39608
39871
  * and the 20-cycle cap silently stops capping anything. */
39609
39872
  applyTurnPolicy(live, p) {
39610
39873
  live.unattended = unattendedModeFor({ optedIn: p.unattended, origin: p.origin });
39874
+ if (p.autoCompactPct !== void 0)
39875
+ live.autoCompactPct = p.autoCompactPct;
39611
39876
  live.autoDecisions = 0;
39612
39877
  if (p.model !== void 0)
39613
39878
  live.model = p.model || void 0;
@@ -40314,7 +40579,7 @@ ${lines}`;
40314
40579
  if (opts.permissionMode)
40315
40580
  await live.query.setPermissionMode(opts.permissionMode);
40316
40581
  if (opts.model !== void 0) {
40317
- await live.query.setModel(opts.model || void 0);
40582
+ await live.query.setModel(sdkModelId(opts.model));
40318
40583
  live.model = opts.model || void 0;
40319
40584
  }
40320
40585
  if (opts.maxThinkingTokens !== void 0)
@@ -40434,7 +40699,7 @@ ${lines}`;
40434
40699
  live.windowId = params.windowId;
40435
40700
  live.pendingTitle = params.message.trim().slice(0, 80);
40436
40701
  if (params.model)
40437
- void live.query.setModel(params.model || void 0).catch(() => {
40702
+ void live.query.setModel(sdkModelId(params.model)).catch(() => {
40438
40703
  });
40439
40704
  if (params.permissionMode)
40440
40705
  void live.query.setPermissionMode(params.permissionMode).catch(() => {
@@ -40609,6 +40874,7 @@ ${prompt("agent.system.project-dir", { dir: projectDir })}` : "";
40609
40874
  windowId: params.windowId,
40610
40875
  sources: params.sources,
40611
40876
  unattended: params.unattended,
40877
+ autoCompactPct: params.autoCompactPct,
40612
40878
  reinforcedVerification: params.reinforcedVerification,
40613
40879
  task: params.message,
40614
40880
  rvInjected: params.rvInjected,
@@ -40674,12 +40940,17 @@ ${prompt("agent.system.project-dir", { dir: projectDir })}` : "";
40674
40940
  const lateDirective = live.unattendedReportSent ? "" : unattendedReportDirective(params);
40675
40941
  if (lateDirective)
40676
40942
  live.unattendedReportSent = true;
40943
+ const hostTurn = (params.autoContinuation || params.rvInjected) && !userText.trimStart().startsWith("/");
40677
40944
  const sdkMsg = {
40678
40945
  type: "user",
40679
40946
  parent_tool_use_id: null,
40680
- message: { role: "user", content: lateDirective ? `${userText}
40681
-
40682
- ${lateDirective}` : userText }
40947
+ // MARKED, so a client can show the user's own words and not the instruction we
40948
+ // appended to them — the engine writes this combined text into its transcript, so it
40949
+ // comes back on every resume (see shared/run-directive).
40950
+ message: {
40951
+ role: "user",
40952
+ content: lateDirective ? withRunDirective(userText, lateDirective) : hostTurn ? withRunDirective("", userText) : userText
40953
+ }
40683
40954
  };
40684
40955
  live.pump.push(sdkMsg);
40685
40956
  }
@@ -40794,14 +41065,19 @@ ${lateDirective}` : userText }
40794
41065
  // it. It only *permits* bypass — the active behavior is still governed by
40795
41066
  // permissionMode, so it's safe to set unconditionally.
40796
41067
  allowDangerouslySkipPermissions: true,
40797
- ...params.model ? { model: params.model } : {},
41068
+ // Suffixed for the long window where the family has one — see sdkModelId. Without
41069
+ // this the CLI reports a 200k window for a 1M model and compaction acts on a fill
41070
+ // that is up to five times too high.
41071
+ ...params.model ? { model: sdkModelId(params.model) } : {},
40798
41072
  // Clamp to what THIS CLI accepts — an unsupported level is a hard exit-1, not
40799
41073
  // a warning. See clampEffort.
40800
41074
  ...ultracodeEffort ? { effort: ultracodeEffort } : {},
40801
41075
  // Model-level fallback. Ours rotates CREDENTIALS on failure; this rotates the
40802
41076
  // MODEL before the turn fails at all, so an overloaded primary degrades instead
40803
41077
  // of surfacing an error the user has to act on.
40804
- ...params.fallbackModel ? { fallbackModel: params.fallbackModel } : {},
41078
+ // Same for the fallback: it REPLACES the main model on an overload, so a bare id here
41079
+ // would quietly move a long conversation onto a 200k window mid-run.
41080
+ ...params.fallbackModel ? { fallbackModel: sdkModelId(params.fallbackModel) } : {},
40805
41081
  ...params.enableFileCheckpointing ? { enableFileCheckpointing: true } : {},
40806
41082
  ...params.agentProgressSummaries ? { agentProgressSummaries: true } : {},
40807
41083
  ...params.includeHookEvents ? { includeHookEvents: true } : {},
@@ -41401,6 +41677,7 @@ ${lateDirective}` : userText }
41401
41677
  ...params.engineEnv ?? {},
41402
41678
  CCB_IPC_PORT: String(live.ipcPort)
41403
41679
  };
41680
+ live.endpointEnv = anthropicEnvOf(spawnEnv);
41404
41681
  const child = spawn3(options.command, options.args, {
41405
41682
  cwd: options.cwd,
41406
41683
  env: spawnEnv,
@@ -41520,7 +41797,7 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
41520
41797
  abortController,
41521
41798
  ...params.sessionId && { resume: params.sessionId }
41522
41799
  };
41523
- live.query = params.warm && params.sessionId ? (await startup({ options: queryOptions })).query(pump) : query({ prompt: pump, options: queryOptions });
41800
+ live.query = params.warm && params.sessionId ? (await startup({ options: queryOptions })).query(pump) : this.queryFactory({ prompt: pump, options: queryOptions });
41524
41801
  } catch (err2) {
41525
41802
  for (const s of live.ipcSockets) {
41526
41803
  try {
@@ -42442,6 +42719,11 @@ ${err2.stack}` : ""}` : String(err2);
42442
42719
  * the stream was actually alive. */
42443
42720
  touchStream(live, firstFrame = false) {
42444
42721
  live.lastFrameAt = monoNowMs();
42722
+ if (isCompactionPrompt(live.lastPrompt)) {
42723
+ live.stallWindowMs = void 0;
42724
+ this.clearStall(live);
42725
+ return;
42726
+ }
42445
42727
  const window2 = firstFrame ? STREAM_FIRST_FRAME_MS : STREAM_STALL_MS;
42446
42728
  live.stallWindowMs = window2;
42447
42729
  if (!live.streaming) {
@@ -42486,7 +42768,7 @@ ${err2.stack}` : ""}` : String(err2);
42486
42768
  this.armStall(live, decision.ms);
42487
42769
  return;
42488
42770
  }
42489
- log(`Stream stall: no frames for ${STREAM_STALL_MS}ms on session ${live.sessionId || "(pending)"} \u2014 killing the dead turn so it can be retried`);
42771
+ log(`Stream stall: no frames for ${live.stallWindowMs ?? STREAM_STALL_MS}ms on session ${live.sessionId || "(pending)"} \u2014 killing the dead turn so it can be retried`);
42490
42772
  live.stalled = true;
42491
42773
  this.hardKillSession(live);
42492
42774
  }
@@ -43942,10 +44224,10 @@ async function startHostedToolset(deps) {
43942
44224
  if (asyncTools) {
43943
44225
  try {
43944
44226
  hostedJobs = await Promise.resolve().then(() => (init_hosted_jobs(), hosted_jobs_exports));
43945
- const { tmpdir: tmpdir7 } = await import("node:os");
44227
+ const { tmpdir: tmpdir9 } = await import("node:os");
43946
44228
  const { join: joinPath3 } = await import("node:path");
43947
44229
  const made = hostedJobs.createHostedJobRegistry({
43948
- dir: joinPath3(tmpdir7(), "tesseract-hosted-jobs", randomUUID9()),
44230
+ dir: joinPath3(tmpdir9(), "tesseract-hosted-jobs", randomUUID9()),
43949
44231
  notifyModel: deps.notifyModel
43950
44232
  });
43951
44233
  jobs = made.registry;
@@ -44012,7 +44294,7 @@ async function startHostedToolset(deps) {
44012
44294
  await build();
44013
44295
  return { endpoint: endpoint2, sendBrowserResponse, tasks, refresh: build };
44014
44296
  }
44015
- function buildHostTaskTools(registry3, run5) {
44297
+ function buildHostTaskTools(registry3, run8) {
44016
44298
  const text12 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
44017
44299
  return [
44018
44300
  {
@@ -44034,7 +44316,7 @@ function buildHostTaskTools(registry3, run5) {
44034
44316
  const task = registry3.start("subagent", description);
44035
44317
  task.messages.push({ role: "user", content: prompt2 });
44036
44318
  try {
44037
- const out = await run5(prompt2, { signal: task.abort.signal });
44319
+ const out = await run8(prompt2, { signal: task.abort.signal });
44038
44320
  if (task.status === "stopped")
44039
44321
  return text12(`Subagent "${description}" was stopped.`, true);
44040
44322
  task.status = "done";
@@ -78654,8 +78936,8 @@ var mesh_ca_exports = {};
78654
78936
  __export(mesh_ca_exports, {
78655
78937
  netCaCommand: () => netCaCommand
78656
78938
  });
78657
- import { chmodSync as chmodSync8, existsSync as existsSync44, mkdirSync as mkdirSync44, readFileSync as readFileSync50, writeFileSync as writeFileSync43 } from "node:fs";
78658
- import { join as join82, resolve as resolve13 } from "node:path";
78939
+ import { chmodSync as chmodSync8, existsSync as existsSync48, mkdirSync as mkdirSync44, readFileSync as readFileSync50, writeFileSync as writeFileSync45 } from "node:fs";
78940
+ import { join as join86, resolve as resolve13 } from "node:path";
78659
78941
  import { createInterface } from "node:readline";
78660
78942
  function die(msg) {
78661
78943
  console.error(msg);
@@ -78686,7 +78968,7 @@ async function readPassphrase(prompt2) {
78686
78968
  }
78687
78969
  }
78688
78970
  function writeSecretFile(p, bytes2) {
78689
- writeFileSync43(p, bytes2, { mode: 384 });
78971
+ writeFileSync45(p, bytes2, { mode: 384 });
78690
78972
  try {
78691
78973
  chmodSync8(p, 384);
78692
78974
  } catch {
@@ -78700,9 +78982,9 @@ function ensureDir(p) {
78700
78982
  }
78701
78983
  }
78702
78984
  async function openCa(dir2) {
78703
- const gPath = join82(dir2, "genesis.bin");
78704
- const sPath = join82(dir2, "ca.sealed");
78705
- if (!existsSync44(gPath) || !existsSync44(sPath)) {
78985
+ const gPath = join86(dir2, "genesis.bin");
78986
+ const sPath = join86(dir2, "ca.sealed");
78987
+ if (!existsSync48(gPath) || !existsSync48(sPath)) {
78706
78988
  die(`No mesh CA in ${dir2}. Run: tesseract-agent net init --org NAME --ca-dir ${dir2}`);
78707
78989
  }
78708
78990
  const genesisBytes = new Uint8Array(readFileSync50(gPath));
@@ -78723,7 +79005,7 @@ async function netCaCommand(rest, flags) {
78723
79005
  if (sub === "init") {
78724
79006
  const org = typeof flags.org === "string" ? flags.org.trim() : "";
78725
79007
  if (!org) die("Usage: tesseract-agent net init --org NAME [--ca-dir DIR]");
78726
- if (existsSync44(join82(caDir, "ca.sealed"))) {
79008
+ if (existsSync48(join86(caDir, "ca.sealed"))) {
78727
79009
  die(`A mesh CA already exists in ${caDir}. Refusing to overwrite it.`);
78728
79010
  }
78729
79011
  const pass = await readPassphrase("New CA passphrase: ");
@@ -78745,9 +79027,9 @@ async function netCaCommand(rest, flags) {
78745
79027
  const genesisBytes = encodeGenesis(genesis);
78746
79028
  const fp = await genesisFingerprint(genesis);
78747
79029
  ensureDir(caDir);
78748
- writeFileSync43(join82(caDir, "genesis.bin"), genesisBytes);
78749
- writeSecretFile(join82(caDir, "ca.sealed"), encodeRecoveryBundle(await sealCaKey(seed, pass, `${org} mesh CA`)));
78750
- writeSecretFile(join82(caDir, "disablement.secret"), hex3(disable.secret));
79030
+ writeFileSync45(join86(caDir, "genesis.bin"), genesisBytes);
79031
+ writeSecretFile(join86(caDir, "ca.sealed"), encodeRecoveryBundle(await sealCaKey(seed, pass, `${org} mesh CA`)));
79032
+ writeSecretFile(join86(caDir, "disablement.secret"), hex3(disable.secret));
78751
79033
  console.log(`
78752
79034
  Mesh created for "${org}".`);
78753
79035
  console.log(` fingerprint: ${hex3(fp)}`);
@@ -78762,7 +79044,7 @@ Mesh created for "${org}".`);
78762
79044
  console.log(` ${hex3(disable.secret)}`);
78763
79045
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
78764
79046
  console.log(`
78765
- A copy of the disablement secret is in ${join82(caDir, "disablement.secret")}.`);
79047
+ A copy of the disablement secret is in ${join86(caDir, "disablement.secret")}.`);
78766
79048
  console.log("Move it somewhere the CA directory is not \u2014 holding both in one place");
78767
79049
  console.log("defeats the point of having two.");
78768
79050
  const caFlag = caDir === resolve13("./mesh-ca") ? "" : ` --ca-dir ${caDir}`;
@@ -78815,14 +79097,14 @@ Next, issue an identity for a machine (pick a free address in ${formatPrefix(gen
78815
79097
  [{ keyIndex: 0, privateKey: ca.privateKey }]
78816
79098
  );
78817
79099
  ensureDir(outDir);
78818
- writeFileSync43(join82(outDir, "genesis.bin"), genesisBytes);
78819
- writeFileSync43(join82(outDir, "node.cert"), encodeCert(cert));
78820
- writeSecretFile(join82(outDir, "node.key"), await exportStaticPrivate(nodeKey));
79100
+ writeFileSync45(join86(outDir, "genesis.bin"), genesisBytes);
79101
+ writeFileSync45(join86(outDir, "node.cert"), encodeCert(cert));
79102
+ writeSecretFile(join86(outDir, "node.key"), await exportStaticPrivate(nodeKey));
78821
79103
  console.log(`Minted "${name}" at ${ip4}.`);
78822
79104
  console.log(` ${outDir}`);
78823
79105
  console.log("\nCopy that directory to the node and run there:");
78824
- console.log(` tesseract-agent net enroll --genesis ${join82(outDir, "genesis.bin")} \\`);
78825
- console.log(` --cert ${join82(outDir, "node.cert")} --key ${join82(outDir, "node.key")}`);
79106
+ console.log(` tesseract-agent net enroll --genesis ${join86(outDir, "genesis.bin")} \\`);
79107
+ console.log(` --cert ${join86(outDir, "node.cert")} --key ${join86(outDir, "node.key")}`);
78826
79108
  console.log("\nnode.key is the node's identity \u2014 send it over a channel you trust, and");
78827
79109
  console.log("delete this copy once the node has it.");
78828
79110
  return;
@@ -78858,8 +79140,8 @@ Next, issue an identity for a machine (pick a free address in ${formatPrefix(gen
78858
79140
  ip4Exceptions: []
78859
79141
  };
78860
79142
  const signed = await signBundle(bundle, [{ keyIndex: 0, privateKey: ca.privateKey }]);
78861
- const out = resolve13(typeof flags.out === "string" ? flags.out : join82(caDir, "bundle.bin"));
78862
- writeFileSync43(out, encodeSignedBundle(signed));
79143
+ const out = resolve13(typeof flags.out === "string" ? flags.out : join86(caDir, "bundle.bin"));
79144
+ writeFileSync45(out, encodeSignedBundle(signed));
78863
79145
  console.log(`Signed policy bundle (epoch ${epoch2}) \u2192 ${out}`);
78864
79146
  console.log("Every node must receive it; the relay distributes it, or copy it to");
78865
79147
  console.log(`each node's mesh directory as bundle.bin.`);
@@ -78881,12 +79163,12 @@ var init_mesh_ca = __esm({
78881
79163
 
78882
79164
  // src/cli.ts
78883
79165
  init_base_paths();
78884
- import { existsSync as existsSync45, mkdtempSync as mkdtempSync2, readFileSync as readFileSync52, rmSync as rmSync11 } from "node:fs";
79166
+ import { existsSync as existsSync49, mkdtempSync as mkdtempSync4, readFileSync as readFileSync52, rmSync as rmSync13 } from "node:fs";
78885
79167
  import { createHash as createHash9 } from "node:crypto";
78886
- import { execFileSync as execFileSync6, spawn as spawn11 } from "node:child_process";
78887
- import { fileURLToPath as fileURLToPath7 } from "node:url";
78888
- import { tmpdir as tmpdir6 } from "node:os";
78889
- import { dirname as dirname36, join as join83, resolve as resolve15 } from "node:path";
79168
+ import { execFileSync as execFileSync6, spawn as spawn14 } from "node:child_process";
79169
+ import { fileURLToPath as fileURLToPath8 } from "node:url";
79170
+ import { tmpdir as tmpdir8 } from "node:os";
79171
+ import { dirname as dirname38, join as join87, resolve as resolve15 } from "node:path";
78890
79172
  import { createInterface as createInterface2 } from "node:readline/promises";
78891
79173
 
78892
79174
  // ../../packages/host-core/dist/control-link.js
@@ -80445,6 +80727,7 @@ async function createClaudeCodeBackend(send4, onBrowserRequest, loadPluginRuntim
80445
80727
  respondToPermission: (requestId, decision, callerOrigin) => manager2.respondToPermission(requestId, decision, callerOrigin),
80446
80728
  setNarrationLlm: (cfg2) => manager2.setNarrationLlm(cfg2),
80447
80729
  setVerifierLlm: (fn) => manager2.setVerifierLlm(fn),
80730
+ setHostEnv: (env) => manager2.setHostEnv(env),
80448
80731
  setImageGen: (runner3) => manager2.setImageGen(runner3),
80449
80732
  setSerpApi: (deps) => manager2.setSerpApi(deps),
80450
80733
  setVideoGen: (runner3) => manager2.setVideoGen(runner3),
@@ -81749,9 +82032,9 @@ function resolveBundledMcpBin(basename14, envOverride) {
81749
82032
  if (cached3 !== void 0)
81750
82033
  return cached3;
81751
82034
  const candidates = [];
81752
- const override2 = envOverride ? process.env[envOverride] : void 0;
81753
- if (override2)
81754
- candidates.push(override2);
82035
+ const override3 = envOverride ? process.env[envOverride] : void 0;
82036
+ if (override3)
82037
+ candidates.push(override3);
81755
82038
  const rp = process.resourcesPath;
81756
82039
  if (rp)
81757
82040
  candidates.push(join26(rp, "host-daemon", basename14));
@@ -83029,7 +83312,7 @@ function createAcpBackend(engine, send4, resolve16, onBrowserRequest, loadPlugin
83029
83312
  return;
83030
83313
  return sendMessage({ ...prev, message, sessionId: sid, autoContinuation: true });
83031
83314
  },
83032
- log: (m) => console.warn(`[${LABEL2}] ${m}`)
83315
+ log: (m) => console.warn(`[${LABEL3}] ${m}`)
83033
83316
  });
83034
83317
  return noticeDispatcher;
83035
83318
  };
@@ -83251,7 +83534,7 @@ function createAcpBackend(engine, send4, resolve16, onBrowserRequest, loadPlugin
83251
83534
  ...cappedOut ? { cappedOut: true } : {}
83252
83535
  }, turn.origin);
83253
83536
  },
83254
- log: (m, e) => console.warn(`[${LABEL2}] ${m}`, e ?? "")
83537
+ log: (m, e) => console.warn(`[${LABEL3}] ${m}`, e ?? "")
83255
83538
  });
83256
83539
  });
83257
83540
  }
@@ -83489,7 +83772,7 @@ function createAcpBackend(engine, send4, resolve16, onBrowserRequest, loadPlugin
83489
83772
  ...cappedOut ? { cappedOut: true } : {}
83490
83773
  }, turn.origin);
83491
83774
  },
83492
- log: (m, e) => console.warn(`[${LABEL2}] ${m}`, e ?? "")
83775
+ log: (m, e) => console.warn(`[${LABEL3}] ${m}`, e ?? "")
83493
83776
  });
83494
83777
  });
83495
83778
  });
@@ -83542,13 +83825,13 @@ function createAcpBackend(engine, send4, resolve16, onBrowserRequest, loadPlugin
83542
83825
  agentMcp = agentCaps?.mcpCapabilities;
83543
83826
  const authed = await withTimeout2(authenticateIfOffered(t, init?.authMethods), AUTH_TIMEOUT_MS, `${engine.label} did not finish authenticating.`).catch(() => false);
83544
83827
  if (init?.authMethods?.length && !authed) {
83545
- console.warn(`[${LABEL2}] no authentication method was accepted; session/load and resume may fail.`);
83828
+ console.warn(`[${LABEL3}] no authentication method was accepted; session/load and resume may fail.`);
83546
83829
  }
83547
83830
  if (apiPort) {
83548
83831
  const api = createEngineHttpApi(apiPort, engine.httpApi?.host ?? "127.0.0.1");
83549
83832
  httpApi = await api.ready() ? api : null;
83550
83833
  if (!httpApi)
83551
- console.warn(`[${LABEL2}] its HTTP API did not come up on ${apiPort}; using the ACP path only.`);
83834
+ console.warn(`[${LABEL3}] its HTTP API did not come up on ${apiPort}; using the ACP path only.`);
83552
83835
  }
83553
83836
  } catch (e) {
83554
83837
  try {
@@ -83895,7 +84178,9 @@ ${text12}`);
83895
84178
  const usage2 = contextUsageFor(live);
83896
84179
  const verdict = shouldCompactProactively({
83897
84180
  mode: unattendedModeFor({ optedIn: params.unattended, origin: params.origin }),
83898
- pct: readDaemonAgentSettings().autoCompactPct,
84181
+ // The conversation's own threshold when its client sent one (per-conversation there),
84182
+ // else the machine-wide setting.
84183
+ pct: params.autoCompactPct ?? readDaemonAgentSettings().autoCompactPct,
83899
84184
  usagePct: typeof usage2?.percentage === "number" ? usage2.percentage : null,
83900
84185
  lastCompactPct: proactiveCompactedAt.get(live) ?? null,
83901
84186
  inFlight: false
@@ -83907,7 +84192,7 @@ ${text12}`);
83907
84192
  if (verdict !== "compact")
83908
84193
  return;
83909
84194
  proactiveCompactedAt.set(live, usage2?.percentage ?? 0);
83910
- console.warn(`[${LABEL2}] auto-compact: ${Math.round(usage2?.percentage ?? 0)}% of the window used \u2014 compacting`);
84195
+ console.warn(`[${LABEL3}] auto-compact: ${Math.round(usage2?.percentage ?? 0)}% of the window used \u2014 compacting`);
83911
84196
  await sendMessage({ ...params, message: OVERFLOW_COMPACT_MESSAGE, sessionId: live, autoContinuation: true });
83912
84197
  const now2 = sessionRekey.get(live) ?? live;
83913
84198
  if (now2 !== live) {
@@ -83915,7 +84200,7 @@ ${text12}`);
83915
84200
  proactiveCompactedAt.delete(live);
83916
84201
  }
83917
84202
  } catch (err2) {
83918
- console.warn(`[${LABEL2}] auto-compact failed:`, err2 instanceof Error ? err2.message : String(err2));
84203
+ console.warn(`[${LABEL3}] auto-compact failed:`, err2 instanceof Error ? err2.message : String(err2));
83919
84204
  }
83920
84205
  }
83921
84206
  async function sendMessage(params) {
@@ -84234,7 +84519,7 @@ ${detail}` : detail, !overflow);
84234
84519
  }
84235
84520
  }
84236
84521
  const declared = declaredCaps;
84237
- const LABEL2 = engine.label;
84522
+ const LABEL3 = engine.label;
84238
84523
  let hostedBoot = null;
84239
84524
  async function ensureHostedToolset() {
84240
84525
  if (!declared.toolInjection || hostedEndpoint)
@@ -84266,7 +84551,7 @@ ${detail}` : detail, !overflow);
84266
84551
  // own permission gate, and it cannot disturb the parent's turn state.
84267
84552
  runSubagent: async (prompt2, { signal }) => {
84268
84553
  if (!transport || !spawnedCwd)
84269
- throw new Error(`${LABEL2} is not running.`);
84554
+ throw new Error(`${LABEL3} is not running.`);
84270
84555
  const res = await transport.request("session/new", { cwd: spawnedCwd, mcpServers: [] });
84271
84556
  const sub = res?.sessionId;
84272
84557
  if (!sub)
@@ -84293,7 +84578,7 @@ ${detail}` : detail, !overflow);
84293
84578
  hostTasks = ht.tasks;
84294
84579
  refreshHostedTools = ht.refresh;
84295
84580
  } catch (e) {
84296
- console.warn(`[${LABEL2}] host toolset unavailable:`, e);
84581
+ console.warn(`[${LABEL3}] host toolset unavailable:`, e);
84297
84582
  }
84298
84583
  })();
84299
84584
  await hostedBoot;
@@ -85108,7 +85393,7 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
85108
85393
  const HOSTED_TOKEN_ENV = "TESSERACT_MCP_TOKEN";
85109
85394
  const label = engineById(ENGINE_ID2)?.label ?? "Codex";
85110
85395
  const declared = engineById(ENGINE_ID2)?.capabilities ?? {};
85111
- const LABEL2 = label;
85396
+ const LABEL3 = label;
85112
85397
  const lastSendParams = /* @__PURE__ */ new Map();
85113
85398
  let noticeDispatcher = null;
85114
85399
  const jobNotices = () => {
@@ -85196,7 +85481,7 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
85196
85481
  hostTasks = ht.tasks;
85197
85482
  refreshHostedTools = ht.refresh;
85198
85483
  } catch (e) {
85199
- console.warn(`[${LABEL2}] host toolset unavailable:`, e);
85484
+ console.warn(`[${LABEL3}] host toolset unavailable:`, e);
85200
85485
  }
85201
85486
  })();
85202
85487
  await hostedBoot;
@@ -85722,7 +86007,9 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
85722
86007
  const usage2 = contextUsageFor(threadId);
85723
86008
  const verdict = shouldCompactProactively({
85724
86009
  mode: unattendedModeFor({ optedIn: params.unattended, origin: params.origin }),
85725
- pct: readDaemonAgentSettings().autoCompactPct,
86010
+ // The conversation's own threshold when its client sent one (per-conversation there),
86011
+ // else the machine-wide setting.
86012
+ pct: params.autoCompactPct ?? readDaemonAgentSettings().autoCompactPct,
85726
86013
  usagePct: typeof usage2?.percentage === "number" ? usage2.percentage : null,
85727
86014
  lastCompactPct: proactiveCompactedAt.get(threadId) ?? null,
85728
86015
  inFlight: false
@@ -85734,10 +86021,10 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
85734
86021
  if (verdict !== "compact")
85735
86022
  return;
85736
86023
  proactiveCompactedAt.set(threadId, usage2?.percentage ?? 0);
85737
- console.warn(`[${LABEL2}] auto-compact: ${Math.round(usage2?.percentage ?? 0)}% of the window used \u2014 compacting`);
86024
+ console.warn(`[${LABEL3}] auto-compact: ${Math.round(usage2?.percentage ?? 0)}% of the window used \u2014 compacting`);
85738
86025
  await sendMessage({ ...params, message: OVERFLOW_COMPACT_MESSAGE, sessionId: threadId, autoContinuation: true });
85739
86026
  } catch (err2) {
85740
- console.warn(`[${LABEL2}] auto-compact failed:`, err2 instanceof Error ? err2.message : String(err2));
86027
+ console.warn(`[${LABEL3}] auto-compact failed:`, err2 instanceof Error ? err2.message : String(err2));
85741
86028
  }
85742
86029
  }
85743
86030
  async function sendMessage(params) {
@@ -87196,8 +87483,8 @@ var pluginTtsProviders = [];
87196
87483
  var loadedGeneration = [];
87197
87484
  var loadQueue = Promise.resolve();
87198
87485
  function loadPluginRuntime(opts) {
87199
- const run5 = () => loadPluginRuntimeSerial(opts);
87200
- const next = loadQueue.then(run5, run5);
87486
+ const run8 = () => loadPluginRuntimeSerial(opts);
87487
+ const next = loadQueue.then(run8, run8);
87201
87488
  loadQueue = next.catch(() => void 0);
87202
87489
  return next;
87203
87490
  }
@@ -87565,8 +87852,22 @@ import { randomUUID as randomUUID13 } from "node:crypto";
87565
87852
  import { join as join34 } from "node:path";
87566
87853
 
87567
87854
  // ../../packages/host-core/dist/gui/daemon-gui.js
87568
- init_credentials();
87569
87855
  import { join as join33, dirname as dirname14 } from "node:path";
87856
+
87857
+ // ../../packages/shared/dist/debug-mode.js
87858
+ init_base_paths();
87859
+
87860
+ // ../../packages/host-core/dist/service/types.js
87861
+ init_base_paths();
87862
+ var SERVICE_LABEL_BASE = "dev.tesseract.app.host";
87863
+ function instanceSuffix(instanceId) {
87864
+ if (instanceId)
87865
+ return instanceId;
87866
+ return homeTag();
87867
+ }
87868
+
87869
+ // ../../packages/host-core/dist/gui/daemon-gui.js
87870
+ init_credentials();
87570
87871
  import { fileURLToPath as fileURLToPath5 } from "node:url";
87571
87872
  import { spawn as spawn5, spawnSync } from "node:child_process";
87572
87873
  import { existsSync as existsSync14 } from "node:fs";
@@ -87614,13 +87915,16 @@ function createDockPolicy(fx) {
87614
87915
  if (!armed)
87615
87916
  return;
87616
87917
  const want = count > 0 ? "regular" : "accessory";
87617
- if (want === applied)
87918
+ const transition = want !== applied;
87919
+ if (want === "accessory" && !transition)
87618
87920
  return;
87619
87921
  safely("setActivationPolicy", () => fx.setActivationPolicy(want));
87620
87922
  applied = want;
87621
- safely("log", () => fx.log?.(`dock policy \u2192 ${want} (${count} main window${count === 1 ? "" : "s"})`));
87622
- if (want === "regular")
87623
- safely("applyDockIcon", () => fx.applyDockIcon());
87923
+ if (transition) {
87924
+ safely("log", () => fx.log?.(`dock policy \u2192 ${want} (${count} main window${count === 1 ? "" : "s"})`));
87925
+ if (want === "regular")
87926
+ safely("applyDockIcon", () => fx.applyDockIcon());
87927
+ }
87624
87928
  };
87625
87929
  return {
87626
87930
  arm() {
@@ -89893,7 +90197,7 @@ var VoiceControl = class {
89893
90197
  };
89894
90198
  let llm = null;
89895
90199
  try {
89896
- const cfg2 = await buildClaudeNarrationLlm();
90200
+ const cfg2 = await buildClaudeNarrationLlm(daemonEngineEnv());
89897
90201
  llm = cfg2?.complete ?? null;
89898
90202
  } catch {
89899
90203
  }
@@ -90100,17 +90404,17 @@ async function launchCompanionBrowser() {
90100
90404
  if (!first) {
90101
90405
  throw new Error('No browser on this machine has the Tesseract Companion extension installed, so there is nothing to drive. Install the Companion in Chrome (or another Chromium browser), or use target:"internal" to use the browser inside Tesseract.');
90102
90406
  }
90103
- const { execFile: execFile11 } = await import("node:child_process");
90104
- const run5 = (cmd, args) => new Promise((resolve16, reject) => {
90105
- execFile11(cmd, args, { timeout: 15e3 }, (err2) => err2 ? reject(err2) : resolve16());
90407
+ const { execFile: execFile15 } = await import("node:child_process");
90408
+ const run8 = (cmd, args) => new Promise((resolve16, reject) => {
90409
+ execFile15(cmd, args, { timeout: 15e3 }, (err2) => err2 ? reject(err2) : resolve16());
90106
90410
  });
90107
90411
  try {
90108
90412
  if (process.platform === "darwin")
90109
- await run5("open", ["-a", first.launch]);
90413
+ await run8("open", ["-a", first.launch]);
90110
90414
  else if (process.platform === "win32")
90111
- await run5("cmd", ["/c", "start", "", first.launch]);
90415
+ await run8("cmd", ["/c", "start", "", first.launch]);
90112
90416
  else
90113
- await run5(first.launch, []);
90417
+ await run8(first.launch, []);
90114
90418
  } catch (err2) {
90115
90419
  throw new Error(`Could not start ${first.name}: ${err2 instanceof Error ? err2.message : String(err2)}`);
90116
90420
  }
@@ -91370,10 +91674,10 @@ function buildEnhanceChain(spec) {
91370
91674
  steps.push(`upscale\xD7${f}`);
91371
91675
  resizes = true;
91372
91676
  }
91373
- const sh = spec.sharpen ?? "light";
91374
- if (sh !== "none") {
91375
- parts.push(`cas=strength=${SHARPEN[sh]}`);
91376
- steps.push(`sharpen:${sh}`);
91677
+ const sh3 = spec.sharpen ?? "light";
91678
+ if (sh3 !== "none") {
91679
+ parts.push(`cas=strength=${SHARPEN[sh3]}`);
91680
+ steps.push(`sharpen:${sh3}`);
91377
91681
  }
91378
91682
  if (spec.deband) {
91379
91683
  parts.push("deband");
@@ -92304,11 +92608,11 @@ function pickProvider(c) {
92304
92608
  return null;
92305
92609
  }
92306
92610
  function modelFor(id, pc, quality) {
92307
- const override2 = pc.model?.trim();
92611
+ const override3 = pc.model?.trim();
92308
92612
  if (id === "tesseract")
92309
- return override2 || FREE_MODEL;
92310
- if (override2)
92311
- return override2;
92613
+ return override3 || FREE_MODEL;
92614
+ if (override3)
92615
+ return override3;
92312
92616
  return quality === "standard" ? STANDARD_MODEL : FAST_MODEL;
92313
92617
  }
92314
92618
  function estimateFor(id, model, durationSec) {
@@ -93148,8 +93452,8 @@ async function falTopazEnhance(path6, spec, opts) {
93148
93452
  const dir2 = opts.outDir ?? workDir();
93149
93453
  mkdirSync21(dir2, { recursive: true });
93150
93454
  const outPath = join42(dir2, "enhanced.mp4");
93151
- const { writeFileSync: writeFileSync44 } = await import("node:fs");
93152
- writeFileSync44(outPath, Buffer.from(await dl.arrayBuffer()));
93455
+ const { writeFileSync: writeFileSync46 } = await import("node:fs");
93456
+ writeFileSync46(outPath, Buffer.from(await dl.arrayBuffer()));
93153
93457
  const out = await probeMedia(outPath).catch(() => null);
93154
93458
  opts.onProgress?.(100, "Enhance complete");
93155
93459
  return { path: outPath, mime: MIME, width: out?.width ?? null, height: out?.height ?? null, durationSec: out?.durationSec ?? p.durationSec, summary: `fal Topaz ${spec.model ?? "Proteus"} \xD7${spec.upscaleFactor ?? 2}` };
@@ -94984,17 +95288,25 @@ function buildSharedBackend(engineId) {
94984
95288
  return b;
94985
95289
  backend = b;
94986
95290
  refreshDaemonScheduling(b);
94987
- void buildClaudeNarrationLlm().then((cfg2) => {
95291
+ const runnerEnv = (() => {
95292
+ try {
95293
+ return daemonEngineEnv();
95294
+ } catch {
95295
+ return void 0;
95296
+ }
95297
+ })();
95298
+ b.setHostEnv?.(runnerEnv ?? null);
95299
+ void buildClaudeNarrationLlm(runnerEnv).then((cfg2) => {
94988
95300
  if (cfg2) {
94989
95301
  b.setNarrationLlm?.(cfg2);
94990
- log("narration: enabled (Claude Haiku)");
95302
+ log(`narration: enabled (${runnerEnv?.ANTHROPIC_BASE_URL ?? "api.anthropic.com"})`);
94991
95303
  } else
94992
95304
  log("narration: disabled \u2014 no Claude creds resolved");
94993
95305
  }).catch((e) => log("narration: setup failed:", e instanceof Error ? e.message : String(e)));
94994
- void buildClaudeSmartLlm().then((fn) => {
95306
+ void buildClaudeSmartLlm(runnerEnv).then((fn) => {
94995
95307
  if (fn) {
94996
95308
  b.setVerifierLlm?.(fn);
94997
- log("reinforced-verification: grader enabled");
95309
+ log(`reinforced-verification: grader enabled (${runnerEnv?.ANTHROPIC_BASE_URL ?? "api.anthropic.com"})`);
94998
95310
  } else
94999
95311
  log("reinforced-verification: disabled \u2014 no Claude creds resolved");
95000
95312
  }).catch((e) => log("reinforced-verification: setup failed:", e instanceof Error ? e.message : String(e)));
@@ -98763,9 +99075,9 @@ var NodeFsHandler = class {
98763
99075
  if (this.fsw.closed) {
98764
99076
  return;
98765
99077
  }
98766
- const dirname37 = sysPath.dirname(file2);
99078
+ const dirname39 = sysPath.dirname(file2);
98767
99079
  const basename14 = sysPath.basename(file2);
98768
- const parent = this.fsw._getWatchedDir(dirname37);
99080
+ const parent = this.fsw._getWatchedDir(dirname39);
98769
99081
  let prevStats = stats;
98770
99082
  if (parent.has(basename14))
98771
99083
  return;
@@ -98792,7 +99104,7 @@ var NodeFsHandler = class {
98792
99104
  prevStats = newStats2;
98793
99105
  }
98794
99106
  } catch (error51) {
98795
- this.fsw._remove(dirname37, basename14);
99107
+ this.fsw._remove(dirname39, basename14);
98796
99108
  }
98797
99109
  } else if (parent.has(basename14)) {
98798
99110
  const at = newStats.atimeMs;
@@ -103235,8 +103547,8 @@ async function wakeDisplay(log9) {
103235
103547
  if (process.platform !== "darwin")
103236
103548
  return;
103237
103549
  try {
103238
- const { spawn: spawn12 } = await import("node:child_process");
103239
- spawn12("caffeinate", ["-u", "-t", "5"], { detached: true, stdio: "ignore" }).unref();
103550
+ const { spawn: spawn15 } = await import("node:child_process");
103551
+ spawn15("caffeinate", ["-u", "-t", "5"], { detached: true, stdio: "ignore" }).unref();
103240
103552
  log9?.("display was asleep \u2014 declared user activity to wake it");
103241
103553
  await new Promise((r) => setTimeout(r, 1200));
103242
103554
  } catch {
@@ -104072,9 +104384,9 @@ function hasRdeskPassword() {
104072
104384
  function verifyRdeskPassword(password) {
104073
104385
  if (!password)
104074
104386
  return false;
104075
- const override2 = process.env.CCB_RDESK_PASSWORD;
104076
- if (override2)
104077
- return password.length === override2.length && timingSafeEqual4(Buffer.from(password), Buffer.from(override2));
104387
+ const override3 = process.env.CCB_RDESK_PASSWORD;
104388
+ if (override3)
104389
+ return password.length === override3.length && timingSafeEqual4(Buffer.from(password), Buffer.from(override3));
104078
104390
  try {
104079
104391
  const { salt, hash: hash2 } = JSON.parse(readFileSync40(pwFile(), "utf8"));
104080
104392
  const got = scryptSync(password, Buffer.from(salt, "hex"), 32);
@@ -107499,6 +107811,16 @@ var LanDiscovery = class {
107499
107811
  var _a3;
107500
107812
  var requireCjs = createRequire4(import.meta.url);
107501
107813
  function loadMeshCore() {
107814
+ for (const spec of [
107815
+ "@fineguide-tesseract/mesh-core",
107816
+ "./mesh-core/index.js",
107817
+ "../mesh-core/index.js"
107818
+ ]) {
107819
+ try {
107820
+ return requireCjs(spec);
107821
+ } catch {
107822
+ }
107823
+ }
107502
107824
  try {
107503
107825
  return requireCjs("@fineguide-tesseract/mesh-core");
107504
107826
  } catch (e) {
@@ -109411,12 +109733,12 @@ function watchForIdentity(deps) {
109411
109733
  const wait = Math.min(max, Math.round(delay3 * (1 + (random() * 2 - 1) * JITTER)));
109412
109734
  timer2 = setTimeout(() => {
109413
109735
  timer2 = null;
109414
- void run5("backoff");
109736
+ void run8("backoff");
109415
109737
  }, wait);
109416
109738
  timer2.unref?.();
109417
109739
  delay3 = Math.min(max, Math.round(delay3 * FACTOR));
109418
109740
  };
109419
- async function run5(reason) {
109741
+ async function run8(reason) {
109420
109742
  if (stopped2 || settled || inFlight2)
109421
109743
  return;
109422
109744
  inFlight2 = true;
@@ -109448,10 +109770,10 @@ function watchForIdentity(deps) {
109448
109770
  return;
109449
109771
  delay3 = first;
109450
109772
  clear();
109451
- void run5(reason);
109773
+ void run8(reason);
109452
109774
  };
109453
109775
  unsubscribe = (deps.subscribe ?? subscribeToWakeSignals)(nudge);
109454
- void run5("boot");
109776
+ void run8("boot");
109455
109777
  return {
109456
109778
  ready,
109457
109779
  nudge,
@@ -112050,9 +112372,8 @@ function meshIdOf(cert) {
112050
112372
  // ../../packages/host-core/dist/mesh/full-tunnel.js
112051
112373
  function fullTunnelState(i) {
112052
112374
  const no2 = (reason) => ({ allowed: false, reason, warnings: [] });
112053
- if (i.platform !== "linux") {
112054
- const name = i.platform === "darwin" ? "macOS" : i.platform === "win32" ? "Windows" : i.platform;
112055
- return no2(`Routing all traffic needs the network helper, which does not exist on ${name} yet.`);
112375
+ if (i.platform !== "linux" && i.platform !== "darwin" && i.platform !== "win32") {
112376
+ return no2(`Routing all traffic needs the network helper, which does not exist on ${i.platform} yet.`);
112056
112377
  }
112057
112378
  if (!i.engineAvailable) {
112058
112379
  return no2("This build shipped without the network engine, so no traffic can be routed. That is a packaging fault \u2014 please report it.");
@@ -112105,21 +112426,685 @@ function bundleGrantsExitNode(bundle) {
112105
112426
  // ../../packages/host-core/dist/mesh/machine-owner.js
112106
112427
  init_credentials();
112107
112428
 
112108
- // ../../packages/host-core/dist/service/exec.js
112109
- import { execFile as execFile10, spawn as spawn9 } from "node:child_process";
112429
+ // ../../packages/host-core/dist/net-service/ensure-installed.js
112430
+ import { execFile as execFile14 } from "node:child_process";
112431
+ import { existsSync as existsSync42 } from "node:fs";
112432
+ import { dirname as dirname34, join as join80 } from "node:path";
112433
+ import { promisify as promisify10 } from "node:util";
112434
+
112435
+ // ../../packages/host-core/dist/net-service/launchd-system.js
112436
+ import { spawn as spawn9 } from "node:child_process";
112437
+ import { existsSync as existsSync39, mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync40, rmSync as rmSync10 } from "node:fs";
112438
+ import { tmpdir as tmpdir6 } from "node:os";
112439
+ import { join as join77 } from "node:path";
112440
+
112441
+ // ../../packages/host-core/dist/net-service/elevation.js
112442
+ import { execFile as execFile10 } from "node:child_process";
112110
112443
  import { promisify as promisify6 } from "node:util";
112111
112444
  var run4 = promisify6(execFile10);
112112
- function runInherit(cmd, args) {
112445
+ async function alreadyElevated() {
112446
+ if (process.platform === "win32") {
112447
+ try {
112448
+ const { stdout } = await run4("powershell.exe", [
112449
+ "-NoProfile",
112450
+ "-Command",
112451
+ "(New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)"
112452
+ ]);
112453
+ return String(stdout).trim().toLowerCase() === "true";
112454
+ } catch {
112455
+ return false;
112456
+ }
112457
+ }
112458
+ return typeof process.getuid === "function" && process.getuid() === 0;
112459
+ }
112460
+
112461
+ // ../../packages/host-core/dist/net-service/launchd-system.js
112462
+ var LABEL2 = "dev.tesseract.netd";
112463
+ var PLIST = `/Library/LaunchDaemons/${LABEL2}.plist`;
112464
+ function xml(s) {
112465
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
112466
+ }
112467
+ function sh(s) {
112468
+ return `'${s.replace(/'/g, `'\\''`)}'`;
112469
+ }
112470
+ function buildPlist(spec) {
112471
+ const argv = [
112472
+ spec.exec,
112473
+ "--state-dir",
112474
+ spec.stateDir,
112475
+ "--socket",
112476
+ spec.socket,
112477
+ "--owner-uid",
112478
+ String(spec.ownerUid)
112479
+ ];
112480
+ const args = argv.map((a) => ` <string>${xml(a)}</string>`).join("\n");
112481
+ return `<?xml version="1.0" encoding="UTF-8"?>
112482
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
112483
+ <plist version="1.0">
112484
+ <dict>
112485
+ <key>Label</key>
112486
+ <string>${LABEL2}</string>
112487
+ <key>ProgramArguments</key>
112488
+ <array>
112489
+ ${args}
112490
+ </array>
112491
+ <key>RunAtLoad</key>
112492
+ <true/>
112493
+ <!-- on-failure only, exactly like systemd's Restart=on-failure: a helper that exits 0
112494
+ has been asked to stop, and restarting it would fight the operator. -->
112495
+ <key>KeepAlive</key>
112496
+ <dict>
112497
+ <key>SuccessfulExit</key>
112498
+ <false/>
112499
+ </dict>
112500
+ <!-- launchd has no equivalent of systemd's StartLimitBurst, so a PERMANENT failure \u2014
112501
+ netd refusing to start on an unreadable journal \u2014 respawns forever rather than
112502
+ landing in a failed state. 30s keeps that out of the log and off the CPU; the
112503
+ remedy is still 'net doctor', which reads the real table. -->
112504
+ <key>ThrottleInterval</key>
112505
+ <integer>30</integer>
112506
+ <key>ProcessType</key>
112507
+ <string>Interactive</string>
112508
+ <key>StandardErrorPath</key>
112509
+ <string>${xml(join77(spec.stateDir, "netd.log"))}</string>
112510
+ <key>StandardOutPath</key>
112511
+ <string>${xml(join77(spec.stateDir, "netd.log"))}</string>
112512
+ </dict>
112513
+ </plist>
112514
+ `;
112515
+ }
112516
+ function runForCode(cmd, args) {
112113
112517
  return new Promise((resolve16) => {
112114
112518
  const p = spawn9(cmd, args, { stdio: "inherit" });
112519
+ p.on("error", () => resolve16(127));
112520
+ p.on("close", (code) => resolve16(code ?? 1));
112521
+ });
112522
+ }
112523
+ async function elevate(script) {
112524
+ const dir2 = mkdtempSync2(join77(tmpdir6(), "tesseract-netd-"));
112525
+ const path6 = join77(dir2, "install.sh");
112526
+ try {
112527
+ writeFileSync40(path6, script, { mode: 384 });
112528
+ if (await alreadyElevated()) {
112529
+ return { code: await runForCode("/bin/sh", [path6]), declined: false };
112530
+ }
112531
+ const code = await runForCode("osascript", [
112532
+ "-e",
112533
+ `do shell script "/bin/sh " & quoted form of "${path6}" with administrator privileges`
112534
+ ]);
112535
+ return { code, declined: code === 1 };
112536
+ } finally {
112537
+ try {
112538
+ rmSync10(dir2, { recursive: true, force: true });
112539
+ } catch {
112540
+ }
112541
+ }
112542
+ }
112543
+ function makeLaunchDaemon() {
112544
+ return {
112545
+ supported: process.platform === "darwin",
112546
+ async install(spec) {
112547
+ const plist = buildPlist(spec);
112548
+ const script = [
112549
+ "set -e",
112550
+ `/usr/bin/install -d -m 0700 -o root -g wheel ${sh(spec.stateDir)}`,
112551
+ `cat > ${sh(PLIST)} <<'TESSERACT_PLIST_EOF'
112552
+ ${plist}TESSERACT_PLIST_EOF`,
112553
+ // launchd REFUSES to load a plist that is group- or world-writable, and says so in
112554
+ // a way that reads as a permissions problem with the binary rather than the file.
112555
+ `chown root:wheel ${sh(PLIST)}`,
112556
+ `chmod 644 ${sh(PLIST)}`,
112557
+ // bootout first so a reinstall replaces a loaded job rather than failing with
112558
+ // "service already loaded". `|| true` because not-loaded is the ordinary case.
112559
+ `/bin/launchctl bootout system/${LABEL2} 2>/dev/null || true`,
112560
+ `/bin/launchctl bootstrap system ${sh(PLIST)}`,
112561
+ `/bin/launchctl enable system/${LABEL2}`
112562
+ ].join("\n");
112563
+ const { code, declined } = await elevate(`${script}
112564
+ `);
112565
+ if (code !== 0) {
112566
+ return {
112567
+ ok: false,
112568
+ detail: declined ? "the elevation prompt was declined" : `installing the helper failed (exit ${code})`
112569
+ };
112570
+ }
112571
+ return { ok: true };
112572
+ },
112573
+ async uninstall() {
112574
+ const script = [
112575
+ `/bin/launchctl bootout system/${LABEL2} 2>/dev/null || true`,
112576
+ `rm -f ${sh(PLIST)}`
112577
+ ].join("\n");
112578
+ const { code, declined } = await elevate(`${script}
112579
+ `);
112580
+ return code === 0 ? { ok: true } : {
112581
+ ok: false,
112582
+ detail: declined ? "the elevation prompt was declined" : `removing the helper failed (exit ${code})`
112583
+ };
112584
+ },
112585
+ async state() {
112586
+ if (!existsSync39(PLIST))
112587
+ return { installed: false, running: false };
112588
+ const running2 = await netdAvailable();
112589
+ return {
112590
+ installed: true,
112591
+ running: running2,
112592
+ ...running2 ? {} : {
112593
+ detail: `the helper is installed but not answering \u2014 check ${LABEL2} in Console, or reinstall it`
112594
+ }
112595
+ };
112596
+ },
112597
+ async openApprovalSettings() {
112598
+ }
112599
+ };
112600
+ }
112601
+
112602
+ // ../../packages/host-core/dist/net-service/systemd-system.js
112603
+ import { spawn as spawn11 } from "node:child_process";
112604
+ import { existsSync as existsSync40 } from "node:fs";
112605
+
112606
+ // ../../packages/host-core/dist/service/exec.js
112607
+ import { execFile as execFile11, spawn as spawn10 } from "node:child_process";
112608
+ import { promisify as promisify7 } from "node:util";
112609
+ var run5 = promisify7(execFile11);
112610
+ function runInherit(cmd, args) {
112611
+ return new Promise((resolve16) => {
112612
+ const p = spawn10(cmd, args, { stdio: "inherit" });
112115
112613
  p.on("error", () => resolve16());
112116
112614
  p.on("close", () => resolve16());
112117
112615
  });
112118
112616
  }
112119
112617
 
112120
112618
  // ../../packages/host-core/dist/net-service/systemd-system.js
112619
+ function runForCode2(cmd, args) {
112620
+ return new Promise((resolve16) => {
112621
+ const p = spawn11(cmd, args, { stdio: "inherit" });
112622
+ p.on("error", () => resolve16(127));
112623
+ p.on("close", (code) => resolve16(code ?? 1));
112624
+ });
112625
+ }
112626
+ async function tryRun(cmd, args) {
112627
+ try {
112628
+ const { stdout } = await run5(cmd, args);
112629
+ return { stdout: String(stdout), code: 0 };
112630
+ } catch (e) {
112631
+ const err2 = e;
112632
+ return { stdout: String(err2.stdout ?? ""), code: typeof err2.code === "number" ? err2.code : 1 };
112633
+ }
112634
+ }
112635
+ async function elevated(script) {
112636
+ return await alreadyElevated() ? runForCode2("sh", ["-c", script]) : runForCode2("pkexec", ["sh", "-c", script]);
112637
+ }
112121
112638
  var UNIT = "tesseract-netd.service";
112122
112639
  var UNIT_PATH = `/etc/systemd/system/${UNIT}`;
112640
+ function unitVal(v) {
112641
+ return v.replace(/%/g, "%%");
112642
+ }
112643
+ function buildUnit(spec) {
112644
+ const exec2 = [
112645
+ spec.exec,
112646
+ "--state-dir",
112647
+ spec.stateDir,
112648
+ "--socket",
112649
+ spec.socket,
112650
+ "--owner-uid",
112651
+ String(spec.ownerUid)
112652
+ ].map(unitVal).join(" ");
112653
+ return `[Unit]
112654
+ Description=Tesseract network helper (mesh routes and tunnel device)
112655
+ Documentation=https://tesseract.dev/docs/mesh
112656
+ After=network-online.target
112657
+ Wants=network-online.target
112658
+ # A START LIMIT, because some failures are PERMANENT and restarting cannot fix them. An
112659
+ # unreadable journal is the one that proved it: netd refuses to start while routes may be
112660
+ # installed that it cannot identify, and without this the unit loops forever \u2014 measured at
112661
+ # 7 attempts in 30s on a real box, filling the log and never reaching a state an operator
112662
+ # can see as "stopped, needs attention". After 5 failures in 60s systemd gives up and marks
112663
+ # it failed, which is what state() reports.
112664
+ #
112665
+ # These belong in [Unit]: they are documented in systemd.unit(5), not systemd.service(5),
112666
+ # and systemd silently IGNORES them in the [Service] section \u2014 which is where I first put
112667
+ # them.
112668
+ StartLimitIntervalSec=60
112669
+ StartLimitBurst=5
112670
+
112671
+ [Service]
112672
+ # notify, so 'systemctl start' does not return before the socket exists \u2014 otherwise the
112673
+ # app connects to a service systemd calls started and gets ENOENT.
112674
+ Type=notify
112675
+ NotifyAccess=main
112676
+ ExecStart=${exec2}
112677
+ # Exactly what programming routes and opening a tun device need. NOT setcap: that grants
112678
+ # the capability to the FILE, so anything executing it inherits the grant, and it is
112679
+ # silently ignored on AppImage's nosuid FUSE mount \u2014 the only auto-updating Linux target.
112680
+ AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
112681
+ CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW
112682
+ NoNewPrivileges=yes
112683
+ # This process is reachable over a socket by anything on the machine. Everything below
112684
+ # bounds what a bug in it could reach.
112685
+ ProtectSystem=strict
112686
+ ProtectHome=yes
112687
+ PrivateTmp=yes
112688
+ ProtectKernelModules=yes
112689
+ ProtectKernelLogs=yes
112690
+ ProtectControlGroups=yes
112691
+ RestrictSUIDSGID=yes
112692
+ RestrictNamespaces=yes
112693
+ LockPersonality=yes
112694
+ MemoryDenyWriteExecute=yes
112695
+ SystemCallArchitectures=native
112696
+ # The journal directory is the ONLY thing it may write.
112697
+ ReadWritePaths=${unitVal(spec.stateDir)}
112698
+ DeviceAllow=/dev/net/tun rw
112699
+ # on-failure, never always: a helper that exits 0 has been asked to stop, and restarting
112700
+ # it would fight the operator.
112701
+ Restart=on-failure
112702
+ RestartSec=5
112703
+
112704
+ [Install]
112705
+ WantedBy=multi-user.target
112706
+ `;
112707
+ }
112708
+ function makeSystemdSystem() {
112709
+ return {
112710
+ supported: process.platform === "linux",
112711
+ async install(spec) {
112712
+ const unit = buildUnit(spec);
112713
+ const script = [
112714
+ `install -d -m 0700 ${sh2(spec.stateDir)}`,
112715
+ `cat > ${sh2(UNIT_PATH)} <<'TESSERACT_UNIT_EOF'
112716
+ ${unit}TESSERACT_UNIT_EOF`,
112717
+ "systemctl daemon-reload",
112718
+ `systemctl enable --now ${UNIT}`
112719
+ ].join("\n");
112720
+ const code = await elevated(script);
112721
+ if (code !== 0) {
112722
+ const declined = code === 126 || code === 127;
112723
+ return {
112724
+ ok: false,
112725
+ detail: declined ? "the elevation prompt was declined" : `installing the helper failed (exit ${code})`
112726
+ };
112727
+ }
112728
+ return { ok: true };
112729
+ },
112730
+ async uninstall() {
112731
+ const script = [
112732
+ `systemctl disable --now ${UNIT} || true`,
112733
+ `rm -f ${sh2(UNIT_PATH)}`,
112734
+ "systemctl daemon-reload"
112735
+ ].join("\n");
112736
+ const code = await elevated(script);
112737
+ return code === 0 ? { ok: true } : { ok: false, detail: `removing the helper failed (exit ${code})` };
112738
+ },
112739
+ async state() {
112740
+ if (!existsSync40(UNIT_PATH))
112741
+ return { installed: false, running: false };
112742
+ const active = await tryRun("systemctl", ["is-active", UNIT]);
112743
+ const running2 = active.stdout.trim() === "active";
112744
+ if (running2)
112745
+ return { installed: true, running: true };
112746
+ const show = await tryRun("systemctl", ["show", UNIT, "--property=Result", "--value"]);
112747
+ const result = show.stdout.trim();
112748
+ return {
112749
+ installed: true,
112750
+ running: false,
112751
+ ...result && result !== "success" ? { detail: `the helper failed: ${result}` } : {}
112752
+ };
112753
+ },
112754
+ async openApprovalSettings() {
112755
+ }
112756
+ };
112757
+ }
112758
+ function sh2(s) {
112759
+ return `'${s.replace(/'/g, `'\\''`)}'`;
112760
+ }
112761
+
112762
+ // ../../packages/host-core/dist/net-service/windows-service.js
112763
+ import { execFile as execFile12, spawn as spawn12 } from "node:child_process";
112764
+ import { mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync41, rmSync as rmSync11 } from "node:fs";
112765
+ import { tmpdir as tmpdir7 } from "node:os";
112766
+ import { join as join78 } from "node:path";
112767
+ import { promisify as promisify8 } from "node:util";
112768
+ var run6 = promisify8(execFile12);
112769
+ var SERVICE = "TesseractNetd";
112770
+ var DISPLAY = "Tesseract network helper";
112771
+ var ERROR_CANCELLED = 1223;
112772
+ function ps(s) {
112773
+ return `'${s.replace(/'/g, "''")}'`;
112774
+ }
112775
+ function buildBinaryPath(spec) {
112776
+ const parts = [
112777
+ spec.exec,
112778
+ // NOT optional, and its absence is silent. The SCM launches the process and waits for it
112779
+ // to call `StartServiceCtrlDispatcher`; without this flag netd runs its console path
112780
+ // instead, never reports a status, and the SCM gives up — leaving a service that is
112781
+ // registered, visible in services.msc, refuses to start, and reports exit code 0. That
112782
+ // exact state was reproduced on the Windows build machine before the flag existed.
112783
+ "--service",
112784
+ "--state-dir",
112785
+ spec.stateDir,
112786
+ "--socket",
112787
+ spec.socket
112788
+ ];
112789
+ if (spec.ownerSid)
112790
+ parts.push("--owner-sid", spec.ownerSid);
112791
+ return parts.map((p) => `"${p}"`).join(" ");
112792
+ }
112793
+ async function elevatePowerShell(script) {
112794
+ const dir2 = mkdtempSync3(join78(tmpdir7(), "tesseract-netd-"));
112795
+ const inner = join78(dir2, "install.ps1");
112796
+ writeFileSync41(inner, script, { encoding: "utf8" });
112797
+ if (await alreadyElevated()) {
112798
+ return new Promise((resolve16) => {
112799
+ const p = spawn12("powershell.exe", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", inner], { stdio: "inherit" });
112800
+ const finish = (code) => {
112801
+ try {
112802
+ rmSync11(dir2, { recursive: true, force: true });
112803
+ } catch {
112804
+ }
112805
+ resolve16({ code, declined: false });
112806
+ };
112807
+ p.on("error", () => finish(127));
112808
+ p.on("close", (code) => finish(code ?? 1));
112809
+ });
112810
+ }
112811
+ const outer = join78(dir2, "elevate.ps1");
112812
+ writeFileSync41(outer, [
112813
+ '$ErrorActionPreference = "Stop"',
112814
+ "try {",
112815
+ ` $p = Start-Process -FilePath "powershell.exe" -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File",${ps(inner)}) -Verb RunAs -Wait -PassThru`,
112816
+ " exit $p.ExitCode",
112817
+ "} catch {",
112818
+ ` exit ${ERROR_CANCELLED}`,
112819
+ "}"
112820
+ ].join("\n"), { encoding: "utf8" });
112821
+ return new Promise((resolve16) => {
112822
+ const p = spawn12("powershell.exe", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", outer], { stdio: "inherit" });
112823
+ const finish = (code) => {
112824
+ try {
112825
+ rmSync11(dir2, { recursive: true, force: true });
112826
+ } catch {
112827
+ }
112828
+ resolve16({ code, declined: code === ERROR_CANCELLED });
112829
+ };
112830
+ p.on("error", () => finish(127));
112831
+ p.on("close", (code) => finish(code ?? 1));
112832
+ });
112833
+ }
112834
+ function buildInstallScript(spec) {
112835
+ const bin = buildBinaryPath(spec);
112836
+ return [
112837
+ '$ErrorActionPreference = "Stop"',
112838
+ `New-Item -ItemType Directory -Force -Path ${ps(spec.stateDir)} | Out-Null`,
112839
+ // A reinstall must replace, not fail. Stop first: New-Service refuses a name that
112840
+ // exists, and sc.exe delete on a running service only marks it for deletion.
112841
+ `$existing = Get-Service -Name ${ps(SERVICE)} -ErrorAction SilentlyContinue`,
112842
+ "if ($existing) {",
112843
+ ` Stop-Service -Name ${ps(SERVICE)} -Force -ErrorAction SilentlyContinue`,
112844
+ ` & sc.exe delete ${SERVICE} | Out-Null`,
112845
+ " Start-Sleep -Milliseconds 500",
112846
+ "}",
112847
+ `New-Service -Name ${ps(SERVICE)} -BinaryPathName ${ps(bin)} -DisplayName ${ps(DISPLAY)} -Description ${ps("Programs the routes for Tesseract private networks and owns the tunnel device.")} -StartupType Automatic | Out-Null`,
112848
+ // Restart on failure, three times, then stop trying. The Windows equivalent of
112849
+ // systemd's Restart=on-failure with a start limit — netd refuses to start while an
112850
+ // unreadable journal may mean routes are installed, and that is a PERMANENT failure
112851
+ // no amount of restarting fixes.
112852
+ `& sc.exe failure ${SERVICE} reset= 86400 actions= restart/5000/restart/5000/restart/5000 | Out-Null`,
112853
+ `Start-Service -Name ${ps(SERVICE)}`,
112854
+ "exit 0"
112855
+ ].join("\n");
112856
+ }
112857
+ function buildUninstallScript() {
112858
+ return [
112859
+ `Stop-Service -Name ${ps(SERVICE)} -Force -ErrorAction SilentlyContinue`,
112860
+ `& sc.exe delete ${SERVICE} | Out-Null`,
112861
+ "exit 0"
112862
+ ].join("\n");
112863
+ }
112864
+ function makeWindowsService() {
112865
+ return {
112866
+ supported: process.platform === "win32",
112867
+ async install(spec) {
112868
+ const { code, declined } = await elevatePowerShell(`${buildInstallScript(spec)}
112869
+ `);
112870
+ if (code !== 0) {
112871
+ return {
112872
+ ok: false,
112873
+ detail: declined ? "the elevation prompt was declined" : `installing the helper failed (exit ${code})`
112874
+ };
112875
+ }
112876
+ return { ok: true };
112877
+ },
112878
+ async uninstall() {
112879
+ const { code, declined } = await elevatePowerShell(`${buildUninstallScript()}
112880
+ `);
112881
+ return code === 0 ? { ok: true } : {
112882
+ ok: false,
112883
+ detail: declined ? "the elevation prompt was declined" : `removing the helper failed (exit ${code})`
112884
+ };
112885
+ },
112886
+ async state() {
112887
+ try {
112888
+ const { stdout } = await run6("sc.exe", ["query", SERVICE]);
112889
+ const out = String(stdout);
112890
+ const running2 = /STATE\s*:\s*4\b/.test(out);
112891
+ if (running2)
112892
+ return { installed: true, running: true };
112893
+ return {
112894
+ installed: true,
112895
+ running: false,
112896
+ detail: "the helper is installed but not running \u2014 reinstall it, or start the Tesseract network helper service"
112897
+ };
112898
+ } catch {
112899
+ return { installed: false, running: false };
112900
+ }
112901
+ },
112902
+ async openApprovalSettings() {
112903
+ }
112904
+ };
112905
+ }
112906
+
112907
+ // ../../packages/host-core/dist/net-service/windows-nat.js
112908
+ import { execFile as execFile13 } from "node:child_process";
112909
+ import { promisify as promisify9 } from "node:util";
112910
+ var run7 = promisify9(execFile13);
112911
+ var NAT_FEATURE = "Containers-HNS";
112912
+ async function natCapability() {
112913
+ if (process.platform !== "win32") {
112914
+ return { available: true, reason: "", needsRestart: false };
112915
+ }
112916
+ try {
112917
+ const { stdout } = await run7("powershell.exe", [
112918
+ "-NoProfile",
112919
+ "-NonInteractive",
112920
+ "-Command",
112921
+ "if (Get-CimClass -Namespace root/StandardCimv2 -ClassName MSFT_NetNat -ErrorAction SilentlyContinue) { 'yes' } else { 'no' }"
112922
+ ]);
112923
+ if (String(stdout).trim() === "yes") {
112924
+ return { available: true, reason: "", needsRestart: false };
112925
+ }
112926
+ } catch {
112927
+ }
112928
+ return {
112929
+ available: false,
112930
+ reason: "Windows needs one more component before this machine can be the way out for others. It is an optional Windows feature, and turning it on needs a restart. Nothing else about the private network needs it \u2014 this machine can already join, and route all of its own traffic through someone else.",
112931
+ needsRestart: true
112932
+ };
112933
+ }
112934
+ function buildEnableNatScript() {
112935
+ return [
112936
+ '$ErrorActionPreference = "Stop"',
112937
+ // -NoRestart, ALWAYS. We report that a restart is needed; we never perform one. An
112938
+ // application that reboots a machine is one nobody leaves running.
112939
+ `$r = Enable-WindowsOptionalFeature -Online -FeatureName ${NAT_FEATURE} -All -NoRestart`,
112940
+ // 3010 is ERROR_SUCCESS_REBOOT_REQUIRED and is a SUCCESS. Treating it as a failure
112941
+ // would tell the user their install failed on the machine where it worked.
112942
+ "if ($r.RestartNeeded) { exit 3010 }",
112943
+ "exit 0"
112944
+ ].join("\n");
112945
+ }
112946
+ async function enableNatProvider() {
112947
+ if (process.platform !== "win32") {
112948
+ return { ok: false, reason: "unsupported", detail: "this is a Windows-only component" };
112949
+ }
112950
+ const { code, declined } = await elevatePowerShell(`${buildEnableNatScript()}
112951
+ `);
112952
+ if (code === 0)
112953
+ return { ok: true, restartRequired: false };
112954
+ if (code === 3010)
112955
+ return { ok: true, restartRequired: true };
112956
+ return {
112957
+ ok: false,
112958
+ reason: declined ? "declined" : "failed",
112959
+ detail: declined ? "the elevation prompt was declined" : `enabling the Windows NAT component failed (exit ${code})`
112960
+ };
112961
+ }
112962
+
112963
+ // ../../packages/host-core/dist/net-service/index.js
112964
+ function inert(reason) {
112965
+ return {
112966
+ supported: false,
112967
+ async install() {
112968
+ return { ok: false, detail: reason };
112969
+ },
112970
+ async uninstall() {
112971
+ return { ok: false, detail: reason };
112972
+ },
112973
+ async state() {
112974
+ return { installed: false, running: false, detail: reason };
112975
+ },
112976
+ async openApprovalSettings() {
112977
+ }
112978
+ };
112979
+ }
112980
+ function makeNetService() {
112981
+ switch (process.platform) {
112982
+ case "linux":
112983
+ return makeSystemdSystem();
112984
+ // A root LaunchDaemon, not a System Extension. The extension is still the right end
112985
+ // state — it brings split DNS, On-Demand and an OS kill switch — but it is an Xcode
112986
+ // project, a second signing identity and a user approval, and none of that is needed to
112987
+ // open a utun and program routes. See `launchd-system.ts`.
112988
+ case "darwin":
112989
+ return makeLaunchDaemon();
112990
+ // A LocalSystem service, separate from the daemon's per-user Scheduled Task, which stays
112991
+ // unprivileged. See `windows-service.ts`.
112992
+ case "win32":
112993
+ return makeWindowsService();
112994
+ default:
112995
+ return inert(`no network helper for ${process.platform}`);
112996
+ }
112997
+ }
112998
+
112999
+ // ../../packages/host-core/dist/net-service/netd-binary.js
113000
+ import { existsSync as existsSync41 } from "node:fs";
113001
+ import { dirname as dirname33, join as join79 } from "node:path";
113002
+ import { fileURLToPath as fileURLToPath7 } from "node:url";
113003
+ function netdBinaryName() {
113004
+ return process.platform === "win32" ? "tesseract-netd.exe" : "tesseract-netd";
113005
+ }
113006
+ function override2() {
113007
+ const p = process.env.CCB_NETD_BIN;
113008
+ return p && existsSync41(p) ? p : null;
113009
+ }
113010
+ function netdBinaryPath() {
113011
+ const fromEnv = override2();
113012
+ if (fromEnv)
113013
+ return fromEnv;
113014
+ const name = netdBinaryName();
113015
+ const candidates = [];
113016
+ const resources = process.resourcesPath;
113017
+ if (resources)
113018
+ candidates.push(join79(resources, "netd", name));
113019
+ try {
113020
+ const here = dirname33(fileURLToPath7(import.meta.url));
113021
+ candidates.push(join79(here, "..", "..", "netd", name));
113022
+ candidates.push(join79(here, "..", "..", "..", "netd", name));
113023
+ const triple = `${process.platform}-${process.arch}`;
113024
+ for (const root of [here, join79(here, ".."), join79(here, "..", "..")]) {
113025
+ candidates.push(join79(root, "mesh-core", "prebuilds", triple, "netd", name));
113026
+ }
113027
+ } catch {
113028
+ }
113029
+ if (process.env.CCB_REPO_ROOT) {
113030
+ candidates.push(join79(process.env.CCB_REPO_ROOT, "crates", "target", "release", name));
113031
+ }
113032
+ candidates.push(join79(process.cwd(), "crates", "target", "release", name));
113033
+ for (const c of candidates) {
113034
+ try {
113035
+ if (existsSync41(c))
113036
+ return c;
113037
+ } catch {
113038
+ }
113039
+ }
113040
+ return null;
113041
+ }
113042
+
113043
+ // ../../packages/host-core/dist/net-service/ensure-installed.js
113044
+ function stateDir() {
113045
+ switch (process.platform) {
113046
+ case "win32":
113047
+ return "C:\\ProgramData\\Tesseract\\netd";
113048
+ case "darwin":
113049
+ return "/Library/Application Support/Tesseract/netd";
113050
+ default:
113051
+ return "/var/lib/tesseract-netd";
113052
+ }
113053
+ }
113054
+ async function ownerSid() {
113055
+ if (process.platform !== "win32")
113056
+ return void 0;
113057
+ try {
113058
+ const { stdout } = await promisify10(execFile14)("whoami", ["/user", "/fo", "csv", "/nh"]);
113059
+ const m = /"(S-1-[0-9-]+)"/.exec(String(stdout));
113060
+ return m?.[1];
113061
+ } catch {
113062
+ return void 0;
113063
+ }
113064
+ }
113065
+ async function ensureNetHelperInstalled() {
113066
+ const svc = makeNetService();
113067
+ if (!svc.supported) {
113068
+ const st2 = await svc.state();
113069
+ return { ok: false, reason: "unsupported", detail: st2.detail ?? "no helper on this platform" };
113070
+ }
113071
+ const st = await svc.state();
113072
+ if (st.installed)
113073
+ return { ok: true, already: true };
113074
+ const exec2 = netdBinaryPath();
113075
+ if (exec2 && process.platform === "win32" && !existsSync42(join80(dirname34(exec2), "wintun.dll"))) {
113076
+ return {
113077
+ ok: false,
113078
+ reason: "no-binary",
113079
+ detail: "this build shipped the network helper without wintun.dll, so it cannot open a tunnel"
113080
+ };
113081
+ }
113082
+ if (!exec2) {
113083
+ return {
113084
+ ok: false,
113085
+ reason: "no-binary",
113086
+ detail: "this build did not ship the network helper"
113087
+ };
113088
+ }
113089
+ const r = await svc.install({
113090
+ exec: exec2,
113091
+ stateDir: stateDir(),
113092
+ socket: netdEndpoint(),
113093
+ ...await ownerSid().then((sid) => sid ? { ownerSid: sid } : {}),
113094
+ // The uid whose requests may mutate. Read HERE, at install time, by the process the
113095
+ // user is actually running — the helper starts as a system service with no session, so
113096
+ // reading it there would be wrong in every interesting case.
113097
+ ownerUid: typeof process.getuid === "function" ? process.getuid() : 0
113098
+ });
113099
+ if (r.ok)
113100
+ return { ok: true, already: false };
113101
+ const declined = /declin|cancel/i.test(r.detail ?? "");
113102
+ return {
113103
+ ok: false,
113104
+ reason: declined ? "declined" : "failed",
113105
+ detail: r.detail ?? "installing the helper failed"
113106
+ };
113107
+ }
112123
113108
 
112124
113109
  // ../../packages/host-core/dist/clipboard/clipboard-sync.js
112125
113110
  var MAX_IMAGE_BYTES3 = 10 * 1024 * 1024;
@@ -112138,28 +113123,24 @@ import { platform as platform6 } from "node:os";
112138
113123
 
112139
113124
  // ../../packages/host-core/dist/service/launchd.js
112140
113125
  init_credentials();
112141
- import { writeFileSync as writeFileSync40, existsSync as existsSync39, mkdirSync as mkdirSync41, unlinkSync as unlinkSync7 } from "node:fs";
112142
- import { dirname as dirname33, join as join77 } from "node:path";
113126
+ import { writeFileSync as writeFileSync42, existsSync as existsSync43, mkdirSync as mkdirSync41, unlinkSync as unlinkSync7 } from "node:fs";
113127
+ import { dirname as dirname35, join as join81 } from "node:path";
112143
113128
  import { homedir as homedir13, userInfo as userInfo2 } from "node:os";
112144
-
112145
- // ../../packages/host-core/dist/service/types.js
112146
- var SERVICE_LABEL_BASE = "dev.tesseract.app.host";
112147
-
112148
- // ../../packages/host-core/dist/service/launchd.js
112149
- function xml(s) {
113129
+ function xml2(s) {
112150
113130
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
112151
113131
  }
112152
113132
  function makeLaunchd(instanceId) {
112153
- const label = SERVICE_LABEL_BASE + (instanceId ? `.${instanceId}` : "");
112154
- const plistPath = () => join77(homedir13(), "Library", "LaunchAgents", `${label}.plist`);
113133
+ const suffix = instanceSuffix(instanceId);
113134
+ const label = SERVICE_LABEL_BASE + (suffix ? `.${suffix}` : "");
113135
+ const plistPath = () => join81(homedir13(), "Library", "LaunchAgents", `${label}.plist`);
112155
113136
  const domainTarget = () => `gui/${userInfo2().uid}`;
112156
113137
  const serviceTarget = () => `${domainTarget()}/${label}`;
112157
- const logFile = () => join77(daemonDir2(), "daemon.log");
113138
+ const logFile = () => join81(daemonDir2(), "daemon.log");
112158
113139
  const workDirOf = (spec) => spec.workingDirectory ?? daemonDir2();
112159
- function buildPlist(spec) {
112160
- const args = [spec.exec, ...spec.args].map((a) => ` <string>${xml(a)}</string>`).join("\n");
112161
- const env = Object.entries(spec.env).map(([k, v]) => ` <key>${xml(k)}</key>
112162
- <string>${xml(v)}</string>`).join("\n");
113140
+ function buildPlist2(spec) {
113141
+ const args = [spec.exec, ...spec.args].map((a) => ` <string>${xml2(a)}</string>`).join("\n");
113142
+ const env = Object.entries(spec.env).map(([k, v]) => ` <key>${xml2(k)}</key>
113143
+ <string>${xml2(v)}</string>`).join("\n");
112163
113144
  return `<?xml version="1.0" encoding="UTF-8"?>
112164
113145
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
112165
113146
  <plist version="1.0">
@@ -112175,7 +113156,7 @@ ${args}
112175
113156
  ${env}
112176
113157
  </dict>
112177
113158
  <key>WorkingDirectory</key>
112178
- <string>${xml(workDirOf(spec))}</string>
113159
+ <string>${xml2(workDirOf(spec))}</string>
112179
113160
  <key>RunAtLoad</key>
112180
113161
  <true/>
112181
113162
  <key>KeepAlive</key>
@@ -112190,9 +113171,9 @@ ${env}
112190
113171
  <key>LimitLoadToSessionType</key>
112191
113172
  <string>Aqua</string>
112192
113173
  <key>StandardOutPath</key>
112193
- <string>${xml(spec.logPath)}</string>
113174
+ <string>${xml2(spec.logPath)}</string>
112194
113175
  <key>StandardErrorPath</key>
112195
- <string>${xml(spec.logPath)}</string>
113176
+ <string>${xml2(spec.logPath)}</string>
112196
113177
  </dict>
112197
113178
  </plist>
112198
113179
  `;
@@ -112200,21 +113181,21 @@ ${env}
112200
113181
  return {
112201
113182
  async install(spec) {
112202
113183
  mkdirSync41(workDirOf(spec), { recursive: true });
112203
- mkdirSync41(dirname33(plistPath()), { recursive: true });
112204
- mkdirSync41(dirname33(spec.logPath), { recursive: true });
112205
- writeFileSync40(plistPath(), buildPlist(spec));
112206
- await run4("launchctl", ["bootout", serviceTarget()]).catch(() => {
113184
+ mkdirSync41(dirname35(plistPath()), { recursive: true });
113185
+ mkdirSync41(dirname35(spec.logPath), { recursive: true });
113186
+ writeFileSync42(plistPath(), buildPlist2(spec));
113187
+ await run5("launchctl", ["bootout", serviceTarget()]).catch(() => {
112207
113188
  });
112208
- await run4("launchctl", ["bootstrap", domainTarget(), plistPath()]);
112209
- await run4("launchctl", ["enable", serviceTarget()]).catch(() => {
113189
+ await run5("launchctl", ["bootstrap", domainTarget(), plistPath()]);
113190
+ await run5("launchctl", ["enable", serviceTarget()]).catch(() => {
112210
113191
  });
112211
- await run4("launchctl", ["kickstart", "-k", serviceTarget()]).catch(() => {
113192
+ await run5("launchctl", ["kickstart", "-k", serviceTarget()]).catch(() => {
112212
113193
  });
112213
113194
  },
112214
113195
  async uninstall() {
112215
- await run4("launchctl", ["bootout", serviceTarget()]).catch(() => {
113196
+ await run5("launchctl", ["bootout", serviceTarget()]).catch(() => {
112216
113197
  });
112217
- if (existsSync39(plistPath())) {
113198
+ if (existsSync43(plistPath())) {
112218
113199
  try {
112219
113200
  unlinkSync7(plistPath());
112220
113201
  } catch {
@@ -112225,16 +113206,16 @@ ${env}
112225
113206
  await this.install(spec);
112226
113207
  },
112227
113208
  async isInstalled() {
112228
- return existsSync39(plistPath());
113209
+ return existsSync43(plistPath());
112229
113210
  },
112230
113211
  async start() {
112231
- await run4("launchctl", ["bootstrap", domainTarget(), plistPath()]).catch(() => {
113212
+ await run5("launchctl", ["bootstrap", domainTarget(), plistPath()]).catch(() => {
112232
113213
  });
112233
- await run4("launchctl", ["kickstart", serviceTarget()]).catch(() => {
113214
+ await run5("launchctl", ["kickstart", serviceTarget()]).catch(() => {
112234
113215
  });
112235
113216
  },
112236
113217
  async stop() {
112237
- await run4("launchctl", ["bootout", serviceTarget()]).catch(() => {
113218
+ await run5("launchctl", ["bootout", serviceTarget()]).catch(() => {
112238
113219
  });
112239
113220
  },
112240
113221
  async status() {
@@ -112242,7 +113223,7 @@ ${env}
112242
113223
  },
112243
113224
  async logs(follow) {
112244
113225
  const f = logFile();
112245
- if (!existsSync39(f)) {
113226
+ if (!existsSync43(f)) {
112246
113227
  console.log(`No log yet at ${f} \u2014 has the service started?`);
112247
113228
  return;
112248
113229
  }
@@ -112253,20 +113234,21 @@ ${env}
112253
113234
 
112254
113235
  // ../../packages/host-core/dist/service/systemd.js
112255
113236
  init_credentials();
112256
- import { writeFileSync as writeFileSync41, existsSync as existsSync40, mkdirSync as mkdirSync42, unlinkSync as unlinkSync8 } from "node:fs";
112257
- import { dirname as dirname34, join as join78 } from "node:path";
113237
+ import { writeFileSync as writeFileSync43, existsSync as existsSync44, mkdirSync as mkdirSync42, unlinkSync as unlinkSync8 } from "node:fs";
113238
+ import { dirname as dirname36, join as join82 } from "node:path";
112258
113239
  import { homedir as homedir14, userInfo as userInfo3 } from "node:os";
112259
- function unitVal(v) {
113240
+ function unitVal2(v) {
112260
113241
  return v.replace(/%/g, "%%");
112261
113242
  }
112262
113243
  function shq(s) {
112263
113244
  return `"${s.replace(/(["\\$`])/g, "\\$1")}"`;
112264
113245
  }
112265
113246
  function makeSystemd(instanceId) {
112266
- const unit = `tesseract-host${instanceId ? `-${instanceId}` : ""}.service`;
113247
+ const suffix = instanceSuffix(instanceId);
113248
+ const unit = `tesseract-host${suffix ? `-${suffix}` : ""}.service`;
112267
113249
  const unitPath = () => {
112268
- const base = process.env.XDG_CONFIG_HOME || join78(homedir14(), ".config");
112269
- return join78(base, "systemd", "user", unit);
113250
+ const base = process.env.XDG_CONFIG_HOME || join82(homedir14(), ".config");
113251
+ return join82(base, "systemd", "user", unit);
112270
113252
  };
112271
113253
  const workDirOf = (spec) => spec.workingDirectory ?? daemonDir2();
112272
113254
  function buildUnit2(spec) {
@@ -112280,7 +113262,7 @@ Wants=network-online.target
112280
113262
  [Service]
112281
113263
  Type=simple
112282
113264
  ${env}
112283
- WorkingDirectory=${unitVal(workDirOf(spec))}
113265
+ WorkingDirectory=${unitVal2(workDirOf(spec))}
112284
113266
  ExecStart=${execStart}
112285
113267
  Restart=on-failure
112286
113268
  RestartSec=30
@@ -112294,40 +113276,40 @@ WantedBy=default.target
112294
113276
  return {
112295
113277
  async install(spec) {
112296
113278
  mkdirSync42(workDirOf(spec), { recursive: true });
112297
- mkdirSync42(dirname34(unitPath()), { recursive: true });
112298
- mkdirSync42(dirname34(spec.logPath), { recursive: true });
112299
- writeFileSync41(unitPath(), buildUnit2(spec));
112300
- await run4("loginctl", ["enable-linger", userInfo3().username]).catch(() => {
113279
+ mkdirSync42(dirname36(unitPath()), { recursive: true });
113280
+ mkdirSync42(dirname36(spec.logPath), { recursive: true });
113281
+ writeFileSync43(unitPath(), buildUnit2(spec));
113282
+ await run5("loginctl", ["enable-linger", userInfo3().username]).catch(() => {
112301
113283
  });
112302
- await run4("systemctl", ["--user", "daemon-reload"]).catch(() => {
113284
+ await run5("systemctl", ["--user", "daemon-reload"]).catch(() => {
112303
113285
  });
112304
- await run4("systemctl", ["--user", "enable", unit]).catch(() => {
113286
+ await run5("systemctl", ["--user", "enable", unit]).catch(() => {
112305
113287
  });
112306
- await run4("systemctl", ["--user", "restart", unit]);
113288
+ await run5("systemctl", ["--user", "restart", unit]);
112307
113289
  },
112308
113290
  async uninstall() {
112309
- await run4("systemctl", ["--user", "disable", "--now", unit]).catch(() => {
113291
+ await run5("systemctl", ["--user", "disable", "--now", unit]).catch(() => {
112310
113292
  });
112311
- if (existsSync40(unitPath())) {
113293
+ if (existsSync44(unitPath())) {
112312
113294
  try {
112313
113295
  unlinkSync8(unitPath());
112314
113296
  } catch {
112315
113297
  }
112316
113298
  }
112317
- await run4("systemctl", ["--user", "daemon-reload"]).catch(() => {
113299
+ await run5("systemctl", ["--user", "daemon-reload"]).catch(() => {
112318
113300
  });
112319
113301
  },
112320
113302
  async restart(spec) {
112321
113303
  await this.install(spec);
112322
113304
  },
112323
113305
  async isInstalled() {
112324
- return existsSync40(unitPath());
113306
+ return existsSync44(unitPath());
112325
113307
  },
112326
113308
  async start() {
112327
- await run4("systemctl", ["--user", "start", unit]);
113309
+ await run5("systemctl", ["--user", "start", unit]);
112328
113310
  },
112329
113311
  async stop() {
112330
- await run4("systemctl", ["--user", "stop", unit]);
113312
+ await run5("systemctl", ["--user", "stop", unit]);
112331
113313
  },
112332
113314
  async status() {
112333
113315
  await runInherit("systemctl", ["--user", "status", unit, "--no-pager"]);
@@ -112340,12 +113322,13 @@ WantedBy=default.target
112340
113322
 
112341
113323
  // ../../packages/host-core/dist/service/windows.js
112342
113324
  init_credentials();
112343
- import { writeFileSync as writeFileSync42, existsSync as existsSync41, mkdirSync as mkdirSync43, unlinkSync as unlinkSync9 } from "node:fs";
112344
- import { dirname as dirname35, join as join79 } from "node:path";
113325
+ import { writeFileSync as writeFileSync44, existsSync as existsSync45, mkdirSync as mkdirSync43, unlinkSync as unlinkSync9 } from "node:fs";
113326
+ import { dirname as dirname37, join as join83 } from "node:path";
112345
113327
  function makeWindowsTask(instanceId) {
112346
- const task = `Fineguide\\TesseractHost${instanceId ? `-${instanceId}` : ""}`;
112347
- const wrapperPath = () => join79(daemonDir2(), `run-host${instanceId ? `-${instanceId}` : ""}.cmd`);
112348
- const logFile = () => join79(daemonDir2(), "daemon.log");
113328
+ const suffix = instanceSuffix(instanceId);
113329
+ const task = `Fineguide\\TesseractHost${suffix ? `-${suffix}` : ""}`;
113330
+ const wrapperPath = () => join83(daemonDir2(), `run-host${suffix ? `-${suffix}` : ""}.cmd`);
113331
+ const logFile = () => join83(daemonDir2(), "daemon.log");
112349
113332
  const oneLine2 = (s) => s.replace(/[\r\n]+/g, " ");
112350
113333
  const envVal = (v) => oneLine2(v).replace(/%/g, "%%").replace(/"/g, "");
112351
113334
  const cmdArg = (a) => `"${oneLine2(a).replace(/"/g, "")}"`;
@@ -112362,17 +113345,17 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
112362
113345
  return {
112363
113346
  async install(spec) {
112364
113347
  mkdirSync43(spec.workingDirectory ?? daemonDir2(), { recursive: true });
112365
- mkdirSync43(dirname35(spec.logPath), { recursive: true });
112366
- mkdirSync43(dirname35(wrapperPath()), { recursive: true });
112367
- writeFileSync42(wrapperPath(), buildWrapper(spec));
112368
- await run4("schtasks", ["/Create", "/TN", task, "/SC", "ONLOGON", "/RL", "LIMITED", "/F", "/TR", `"${wrapperPath()}"`]);
112369
- await run4("schtasks", ["/Run", "/TN", task]).catch(() => {
113348
+ mkdirSync43(dirname37(spec.logPath), { recursive: true });
113349
+ mkdirSync43(dirname37(wrapperPath()), { recursive: true });
113350
+ writeFileSync44(wrapperPath(), buildWrapper(spec));
113351
+ await run5("schtasks", ["/Create", "/TN", task, "/SC", "ONLOGON", "/RL", "LIMITED", "/F", "/TR", `"${wrapperPath()}"`]);
113352
+ await run5("schtasks", ["/Run", "/TN", task]).catch(() => {
112370
113353
  });
112371
113354
  },
112372
113355
  async uninstall() {
112373
- await run4("schtasks", ["/Delete", "/TN", task, "/F"]).catch(() => {
113356
+ await run5("schtasks", ["/Delete", "/TN", task, "/F"]).catch(() => {
112374
113357
  });
112375
- if (existsSync41(wrapperPath())) {
113358
+ if (existsSync45(wrapperPath())) {
112376
113359
  try {
112377
113360
  unlinkSync9(wrapperPath());
112378
113361
  } catch {
@@ -112384,17 +113367,17 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
112384
113367
  },
112385
113368
  async isInstalled() {
112386
113369
  try {
112387
- await run4("schtasks", ["/Query", "/TN", task]);
113370
+ await run5("schtasks", ["/Query", "/TN", task]);
112388
113371
  return true;
112389
113372
  } catch {
112390
113373
  return false;
112391
113374
  }
112392
113375
  },
112393
113376
  async start() {
112394
- await run4("schtasks", ["/Run", "/TN", task]);
113377
+ await run5("schtasks", ["/Run", "/TN", task]);
112395
113378
  },
112396
113379
  async stop() {
112397
- await run4("schtasks", ["/End", "/TN", task]).catch(() => {
113380
+ await run5("schtasks", ["/End", "/TN", task]).catch(() => {
112398
113381
  });
112399
113382
  },
112400
113383
  async status() {
@@ -112402,7 +113385,7 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
112402
113385
  },
112403
113386
  async logs(follow) {
112404
113387
  const f = logFile();
112405
- if (!existsSync41(f)) {
113388
+ if (!existsSync45(f)) {
112406
113389
  console.log(`No log yet at ${f} \u2014 has the task run?`);
112407
113390
  return;
112408
113391
  }
@@ -112434,8 +113417,8 @@ init_safe_kill();
112434
113417
  // src/auth.ts
112435
113418
  var import_qrcode_terminal = __toESM(require_main(), 1);
112436
113419
  import { randomUUID as randomUUID29 } from "node:crypto";
112437
- import { existsSync as existsSync42, rmSync as rmSync10 } from "node:fs";
112438
- import { join as join80 } from "node:path";
113420
+ import { existsSync as existsSync46, rmSync as rmSync12 } from "node:fs";
113421
+ import { join as join84 } from "node:path";
112439
113422
 
112440
113423
  // src/config.ts
112441
113424
  import { hostname as hostname6 } from "node:os";
@@ -112636,8 +113619,8 @@ async function logout() {
112636
113619
  }
112637
113620
  for (const f of ["credentials.json", "status.json", "daemon.lock"]) {
112638
113621
  try {
112639
- const p = join80(daemonDir2(), f);
112640
- if (existsSync42(p)) rmSync10(p);
113622
+ const p = join84(daemonDir2(), f);
113623
+ if (existsSync46(p)) rmSync12(p);
112641
113624
  } catch {
112642
113625
  }
112643
113626
  }
@@ -112657,7 +113640,7 @@ function whoami() {
112657
113640
  }
112658
113641
 
112659
113642
  // src/self-update.ts
112660
- import { spawn as spawn10 } from "node:child_process";
113643
+ import { spawn as spawn13 } from "node:child_process";
112661
113644
  import { createPublicKey, verify as cryptoVerify } from "node:crypto";
112662
113645
  var RESTART_EXIT_CODE = 75;
112663
113646
  var REGISTRY_BASE = "https://registry.npmjs.org/tesseract-agent";
@@ -112732,7 +113715,7 @@ function installVersion(target) {
112732
113715
  log8(`installing tesseract-agent@${target} \u2026`);
112733
113716
  let child;
112734
113717
  try {
112735
- child = spawn10(npm, ["install", "-g", `tesseract-agent@${target}`], { stdio: ["ignore", "inherit", "inherit"] });
113718
+ child = spawn13(npm, ["install", "-g", `tesseract-agent@${target}`], { stdio: ["ignore", "inherit", "inherit"] });
112736
113719
  } catch (e) {
112737
113720
  log8("npm spawn threw:", e instanceof Error ? e.message : String(e));
112738
113721
  resolve16(false);
@@ -112795,9 +113778,9 @@ function startSelfUpdater(current) {
112795
113778
  }
112796
113779
 
112797
113780
  // src/service.ts
112798
- import { join as join81 } from "node:path";
113781
+ import { join as join85 } from "node:path";
112799
113782
  import { platform as platform7 } from "node:os";
112800
- import { existsSync as existsSync43, readFileSync as readFileSync49 } from "node:fs";
113783
+ import { existsSync as existsSync47, readFileSync as readFileSync49 } from "node:fs";
112801
113784
  function controller(instanceId) {
112802
113785
  const c = getServiceController(instanceId);
112803
113786
  if (!c) {
@@ -112810,7 +113793,7 @@ function buildSpec(cliEntry) {
112810
113793
  exec: process.execPath,
112811
113794
  args: [cliEntry, "run"],
112812
113795
  env: { CCB_DAEMON_DIR: daemonDir2() },
112813
- logPath: join81(daemonDir2(), "daemon.log")
113796
+ logPath: join85(daemonDir2(), "daemon.log")
112814
113797
  };
112815
113798
  }
112816
113799
  var isAlive = (pid) => {
@@ -112822,9 +113805,9 @@ var isAlive = (pid) => {
112822
113805
  }
112823
113806
  };
112824
113807
  function runningDaemonInfo() {
112825
- const lock = join81(daemonDir2(), "daemon.lock");
113808
+ const lock = join85(daemonDir2(), "daemon.lock");
112826
113809
  try {
112827
- if (!existsSync43(lock)) return null;
113810
+ if (!existsSync47(lock)) return null;
112828
113811
  const pid = Number(readFileSync49(lock, "utf-8").trim());
112829
113812
  if (!pid || !isAlive(pid)) return null;
112830
113813
  return { pid, device: readCredentials()?.deviceId };
@@ -112877,6 +113860,16 @@ function usage() {
112877
113860
  Join a network. The token is all you need;
112878
113861
  the name defaults to this machine's hostname.
112879
113862
  tesseract-agent net leave MESH [--yes] Forget a mesh entirely, key included
113863
+ tesseract-agent net helper [status|install|uninstall|enable-nat]
113864
+ The privileged network helper, which is what
113865
+ actually programs the routes. Without it a
113866
+ machine joins, holds a certificate, shows a
113867
+ roster \u2014 and carries no packets. Run the
113868
+ install under sudo (Windows: an elevated
113869
+ shell); there is nothing to prompt on a server.
113870
+ enable-nat is WINDOWS ONLY and only needed to
113871
+ be the way out FOR OTHERS \u2014 it turns on a
113872
+ Windows optional feature and needs a restart.
112880
113873
 
112881
113874
  Running a network (needs a signed-in account):
112882
113875
  tesseract-agent net new [NAME] Create a network and print its join token.
@@ -113058,9 +114051,80 @@ async function netCommand(rest, flags) {
113058
114051
  updateLocal(meshId, { enabled: sub === "up" });
113059
114052
  console.log(`${meshId} ${sub === "up" ? "enabled" : "disabled"}`);
113060
114053
  }
113061
- console.log("Run `tesseract-agent restart` for this to take effect now.");
114054
+ if (sub === "down") {
114055
+ const stillOn = listMeshIds().filter((id) => readLocal(id)?.enabled !== false);
114056
+ const r = await syncRoutes(stillOn);
114057
+ if (r.helperAbsent) {
114058
+ console.log("The network helper is not installed, so nothing was routed anyway.");
114059
+ } else {
114060
+ if (r.down.length) console.log(`routes removed: ${r.down.join(", ")}`);
114061
+ for (const f of r.failed) console.error(`routes ${f.meshId}: ${f.reason}`);
114062
+ }
114063
+ } else if (!await netdAvailable()) {
114064
+ console.log("The network helper is not installed, so nothing will be routed yet.");
114065
+ console.log("Install it with: sudo tesseract-agent net helper install");
114066
+ }
114067
+ console.log("Run `tesseract-agent restart` to start or stop the node itself.");
113062
114068
  return;
113063
114069
  }
114070
+ if (sub === "helper") {
114071
+ const action = rest[1] ?? "status";
114072
+ const svc = makeNetService();
114073
+ if (action === "status") {
114074
+ const st = await svc.state();
114075
+ const bin = netdBinaryPath();
114076
+ console.log(`platform ${process.platform}${svc.supported ? "" : " (no helper for this platform)"}`);
114077
+ console.log(`binary ${bin ?? "NOT SHIPPED IN THIS BUILD"}`);
114078
+ console.log(`installed ${st.installed ? "yes" : "no"}`);
114079
+ console.log(`running ${st.running ? "yes" : "no"}`);
114080
+ console.log(`answering ${await netdAvailable() ? "yes" : "no"}`);
114081
+ if (st.detail) console.log(`note ${st.detail}`);
114082
+ const nat = await natCapability();
114083
+ console.log(`way out for others ${nat.available ? "yes" : "NOT YET"}`);
114084
+ if (!nat.available) {
114085
+ console.log(` ${nat.reason}`);
114086
+ console.log(" Turn it on with: tesseract-agent net helper enable-nat");
114087
+ }
114088
+ return;
114089
+ }
114090
+ if (action === "enable-nat") {
114091
+ const nat = await natCapability();
114092
+ if (nat.available) {
114093
+ console.log("This machine can already be the way out for others. Nothing to do.");
114094
+ return;
114095
+ }
114096
+ const r = await enableNatProvider();
114097
+ if (r.ok) {
114098
+ console.log("The Windows NAT component is enabled.");
114099
+ if (r.restartRequired) {
114100
+ console.log("RESTART REQUIRED to finish. Nothing was restarted for you.");
114101
+ }
114102
+ return;
114103
+ }
114104
+ console.error(`net helper enable-nat: ${r.detail}`);
114105
+ process.exit(r.reason === "unsupported" ? 2 : 1);
114106
+ }
114107
+ if (action === "install") {
114108
+ const r = await ensureNetHelperInstalled();
114109
+ if (r.ok) {
114110
+ console.log(r.already ? "The network helper is already installed." : "The network helper is installed.");
114111
+ return;
114112
+ }
114113
+ console.error(`net helper install: ${r.detail}`);
114114
+ process.exit(r.reason === "unsupported" || r.reason === "no-binary" ? 2 : 1);
114115
+ }
114116
+ if (action === "uninstall") {
114117
+ const r = await svc.uninstall();
114118
+ if (r.ok) {
114119
+ console.log("The network helper is removed.");
114120
+ return;
114121
+ }
114122
+ console.error(`net helper uninstall: ${r.detail ?? "failed"}`);
114123
+ process.exit(1);
114124
+ }
114125
+ console.error(`net helper: unknown action ${action} (status | install | uninstall | enable-nat)`);
114126
+ process.exit(1);
114127
+ }
113064
114128
  if (sub === "join") {
113065
114129
  const token3 = rest[1] ?? str2(flags.token);
113066
114130
  const code = str2(flags.code);
@@ -113380,7 +114444,7 @@ async function netCommand(rest, flags) {
113380
114444
  // src/cli.ts
113381
114445
  function pkgVersion() {
113382
114446
  try {
113383
- const p = join83(dirname36(fileURLToPath7(import.meta.url)), "..", "package.json");
114447
+ const p = join87(dirname38(fileURLToPath8(import.meta.url)), "..", "package.json");
113384
114448
  return JSON.parse(readFileSync52(p, "utf8")).version ?? "0.0.0";
113385
114449
  } catch {
113386
114450
  return "0.0.0";
@@ -113437,7 +114501,7 @@ async function superviseDaemon(cliEntry) {
113437
114501
  let stopping3 = false;
113438
114502
  let child = null;
113439
114503
  const spawnWorker = () => {
113440
- const c = spawn11(process.execPath, [cliEntry, "__worker"], { stdio: "inherit", env: process.env });
114504
+ const c = spawn14(process.execPath, [cliEntry, "__worker"], { stdio: "inherit", env: process.env });
113441
114505
  child = c;
113442
114506
  let settled = false;
113443
114507
  const settle = (fn) => {
@@ -113609,7 +114673,7 @@ async function linkCommand(rest, flags) {
113609
114673
  process.exit(1);
113610
114674
  }
113611
114675
  async function captureClaudeSubscription(flags) {
113612
- const home = mkdtempSync2(join83(tmpdir6(), "tesseract-claude-login-"));
114676
+ const home = mkdtempSync4(join87(tmpdir8(), "tesseract-claude-login-"));
113613
114677
  const binary = typeof flags["claude-path"] === "string" ? flags["claude-path"] : process.env.CCB_ENGINE_PATH_CLAUDE_CODE || "claude";
113614
114678
  const args = ["auth", "login", "--claudeai"];
113615
114679
  if (typeof flags.email === "string") args.push("--email", flags.email);
@@ -113618,7 +114682,7 @@ async function captureClaudeSubscription(flags) {
113618
114682
  console.log("Open the authorization URL in any browser; paste the returned code here if Claude asks for it.");
113619
114683
  try {
113620
114684
  const code = await new Promise((resolveCode, reject) => {
113621
- const child = spawn11(binary, args, {
114685
+ const child = spawn14(binary, args, {
113622
114686
  env: { ...process.env, CLAUDE_CONFIG_DIR: home },
113623
114687
  stdio: "inherit"
113624
114688
  });
@@ -113626,8 +114690,8 @@ async function captureClaudeSubscription(flags) {
113626
114690
  child.once("close", (exitCode, signal) => resolveCode(signal ? 1 : exitCode ?? 1));
113627
114691
  });
113628
114692
  if (code !== 0) throw new Error(`Claude sign-in did not complete (exit ${code}).`);
113629
- const file2 = join83(home, ".credentials.json");
113630
- if (existsSync45(file2)) return readFileSync52(file2, "utf8");
114693
+ const file2 = join87(home, ".credentials.json");
114694
+ if (existsSync49(file2)) return readFileSync52(file2, "utf8");
113631
114695
  if (process.platform === "darwin") {
113632
114696
  const value = execFileSync6("security", [
113633
114697
  "find-generic-password",
@@ -113639,7 +114703,7 @@ async function captureClaudeSubscription(flags) {
113639
114703
  }
113640
114704
  throw new Error("Claude reported success but no credentials were captured.");
113641
114705
  } finally {
113642
- rmSync11(home, { recursive: true, force: true });
114706
+ rmSync13(home, { recursive: true, force: true });
113643
114707
  }
113644
114708
  }
113645
114709
  async function runnerCommand(rest, flags) {
@@ -113754,7 +114818,7 @@ async function main() {
113754
114818
  process.env.CCB_DAEMON_DIR = tessPath(`daemon-${instance}`);
113755
114819
  }
113756
114820
  const force = flags.yes === true || flags.force === true;
113757
- const cliEntry = fileURLToPath7(import.meta.url);
114821
+ const cliEntry = fileURLToPath8(import.meta.url);
113758
114822
  switch (cmd) {
113759
114823
  case "login":
113760
114824
  await login({