tesseract-agent 0.11.14 → 0.11.16

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.
@@ -11692,8 +11692,8 @@ var capitalizeFirstCharacter, error28;
11692
11692
  var init_lt = __esm({
11693
11693
  "../../node_modules/zod/v4/locales/lt.js"() {
11694
11694
  init_util();
11695
- capitalizeFirstCharacter = (text12) => {
11696
- return text12.charAt(0).toUpperCase() + text12.slice(1);
11695
+ capitalizeFirstCharacter = (text13) => {
11696
+ return text13.charAt(0).toUpperCase() + text13.slice(1);
11697
11697
  };
11698
11698
  error28 = () => {
11699
11699
  const Sizable = {
@@ -22599,6 +22599,14 @@ var init_capabilities = __esm({
22599
22599
  vars: [],
22600
22600
  content: `Whether a personal HeyGen key is set. Never returns the key itself.`
22601
22601
  },
22602
+ {
22603
+ id: "capability.image.has_avatar_free_tier",
22604
+ group: "tools",
22605
+ label: "Free avatar-video tier available?",
22606
+ help: "What the model is told the `image.has_avatar_free_tier` App-Control capability does (image domain, read).",
22607
+ vars: [],
22608
+ content: `Whether the free Tesseract avatar tier can actually serve a request on this deployment \u2014 a signed-in account AND a HeyGen account behind our proxy. Check it before drafting a script: when it is false and the user has no HeyGen key of their own, generate_avatar_video cannot succeed.`
22609
+ },
22602
22610
  {
22603
22611
  id: "capability.image.remove_provider_key",
22604
22612
  group: "tools",
@@ -23039,6 +23047,86 @@ var init_capabilities = __esm({
23039
23047
  vars: [],
23040
23048
  content: `Open the presentation surface in the app so a deck can be picked and presented.`
23041
23049
  },
23050
+ {
23051
+ id: "capability.present.list_decks",
23052
+ group: "tools",
23053
+ label: "List presentations",
23054
+ help: "What the model is told the `present.list_decks` App-Control capability does (present domain, read).",
23055
+ vars: [],
23056
+ content: `Every presentation in the user's library, with its slide count and its deck folder \u2014 the handle every other presentation capability takes. Use it before editing, so you work on the deck the user means rather than making a second one.`
23057
+ },
23058
+ {
23059
+ id: "capability.present.create_deck",
23060
+ group: "tools",
23061
+ label: "Create a presentation",
23062
+ help: "What the model is told the `present.create_deck` App-Control capability does (present domain, write).",
23063
+ vars: [],
23064
+ content: `Make a new, empty Tesseract Stage presentation in the user's library (~/Documents/Tesseract/Presentations) and return its deck folder. This is how you make a presentation \u2014 NOT a PowerPoint file, NOT markdown, NOT an HTML canvas. Pass the title in the user's own words and language. Optionally set a theme: CSS custom properties every slide inherits, e.g. { "--bg": "#FFFFFF", "--ink": "#16130F", "--accent": "#D97757" }. Then write slides with write_slide.`
23065
+ },
23066
+ {
23067
+ id: "capability.present.write_slide",
23068
+ group: "tools",
23069
+ label: "Write a slide",
23070
+ help: "What the model is told the `present.write_slide` App-Control capability does (present domain, write).",
23071
+ vars: [],
23072
+ content: `Write one slide file into a presentation. A slide is a React component in TSX: \`export const meta = { id, title, summary?, notes?, transition?, builds? }\` plus a default-exported component. Path is \`slides/NN-name.tsx\` and FILENAME ORDER IS SLIDE ORDER, so number the prefixes (01, 02, 03\u2026); reordering later is a rename. Shared helpers may live anywhere else in the package and be imported relatively. Always run validate_deck afterwards.`
23073
+ },
23074
+ {
23075
+ id: "capability.present.read_slide",
23076
+ group: "tools",
23077
+ label: "Read a slide",
23078
+ help: "What the model is told the `present.read_slide` App-Control capability does (present domain, read).",
23079
+ vars: [],
23080
+ content: `Read one file back out of a presentation. Use it before editing a slide you did not just write, so a revision preserves what is already there instead of replacing it from memory.`
23081
+ },
23082
+ {
23083
+ id: "capability.present.delete_slide",
23084
+ group: "tools",
23085
+ label: "Delete a slide",
23086
+ help: "What the model is told the `present.delete_slide` App-Control capability does (present domain, write).",
23087
+ vars: [],
23088
+ content: `Remove one file from a presentation. Deleting a slide renumbers nothing \u2014 the remaining filenames still sort, so a gap in the numbering is harmless.`
23089
+ },
23090
+ {
23091
+ id: "capability.present.validate_deck",
23092
+ group: "tools",
23093
+ label: "Check a presentation",
23094
+ help: "What the model is told the `present.validate_deck` App-Control capability does (present domain, read).",
23095
+ vars: [],
23096
+ content: `Compile every slide and report what is wrong \u2014 syntax errors with line numbers, imports that do not resolve, missing or duplicate \`meta\`. ALWAYS call this after writing slides, and fix what it reports before telling the user the presentation is ready: a deck that fails does so in front of an audience. It reports load-time problems only; it cannot catch a mistake that appears only while a slide renders.`
23097
+ },
23098
+ {
23099
+ id: "capability.present.set_deck_theme",
23100
+ group: "tools",
23101
+ label: "Set a presentation's theme",
23102
+ help: "What the model is told the `present.set_deck_theme` App-Control capability does (present domain, write).",
23103
+ vars: [],
23104
+ content: `Replace the CSS custom properties every slide in a presentation inherits \u2014 the deck's look in one place. Restyling a deck is this call, not an edit to every slide.`
23105
+ },
23106
+ {
23107
+ id: "capability.present.add_asset",
23108
+ group: "tools",
23109
+ label: "Add an image to a presentation",
23110
+ help: "What the model is told the `present.add_asset` App-Control capability does (present domain, write).",
23111
+ vars: [],
23112
+ content: `Copy an image, photo or audio file from anywhere on disk INTO the presentation, and get back the path to import from a slide (\`import hero from '../assets/hero.png?url'\`). Do this for anything a slide shows: a presentation must carry its own files, or it breaks the moment it is moved or sent to someone.`
23113
+ },
23114
+ {
23115
+ id: "capability.present.open_deck",
23116
+ group: "tools",
23117
+ label: "Open a presentation",
23118
+ help: "What the model is told the `present.open_deck` App-Control capability does (present domain, write).",
23119
+ vars: [],
23120
+ content: `Open a presentation in the Stage tab so the user can see it. Checks it first and reports the problems instead if it cannot be shown.`
23121
+ },
23122
+ {
23123
+ id: "capability.present.delete_deck",
23124
+ group: "tools",
23125
+ label: "Delete a presentation",
23126
+ help: "What the model is told the `present.delete_deck` App-Control capability does (present domain, write).",
23127
+ vars: [],
23128
+ content: `Delete a whole presentation from the library, permanently. Ask the user first \u2014 this is their document, and there is no undo.`
23129
+ },
23042
23130
  {
23043
23131
  id: "capability.present.end",
23044
23132
  group: "tools",
@@ -23703,6 +23791,14 @@ Apply a plan the user has approved. Requires the plan_hash from tutorial_plan_in
23703
23791
  help: "What the model is told `tutorial_await_decision` does \u2014 blocks until the user approves the tour, asks for changes, or asks to re-pick a target.",
23704
23792
  vars: [],
23705
23793
  content: `Wait for the user to decide on the tour card. Call this straight after tutorial_review_scenario and WAIT \u2014 do not carry on, do not start planning, do not fill the silence. It returns when they approve, ask for changes, or ask for a step to point at something else. Their in-place edits are saved automatically, so whatever wording they left is the wording that ships.`
23794
+ },
23795
+ {
23796
+ id: "tool.capabilities.tesseract_capabilities",
23797
+ group: "tools",
23798
+ label: "tesseract_capabilities",
23799
+ help: "What the model is told the `tesseract_capabilities` tool does \u2014 the one tool that hands it Tesseract's own capability map (docs/CAPABILITIES.md). This description is the only thing deciding whether the model consults the map before answering \u201Cwhat can you do?\u201D or declaring a feature impossible, so it is the highest-leverage entry here. The builder passes the live section index as the `sections` variable.",
23800
+ vars: ["sections"],
23801
+ content: `Return Tesseract's own capability map \u2014 what THE PRODUCT can do, which is far more than the tools you happen to hold this turn (most of Tesseract is UI, services and other clients you never call). Read it BEFORE answering any question about what Tesseract, or you inside it, can do: "what can you do?", "can Tesseract <x>?", "how do I <x> in this app?", "is there a way to", "does it support", "what features", "help me get started" \u2014 and before telling a user something is impossible. It also lists what is deliberately NOT built, which is the most common way to be wrong about this product, so never claim a feature is missing without checking here first. Sections: {{sections}}. Omit \`section\` for the whole map (~22 KB); pass a section number, title or keyword to get just that part when the question is narrow.`
23706
23802
  }
23707
23803
  ];
23708
23804
  }
@@ -23997,6 +24093,17 @@ var init_permissions = __esm({
23997
24093
  }
23998
24094
  });
23999
24095
 
24096
+ // ../../packages/shared/dist/platform-availability.js
24097
+ var HOSTING_AVAILABLE, SSO_AVAILABLE, CLOUD_SERVER_AVAILABLE;
24098
+ var init_platform_availability = __esm({
24099
+ "../../packages/shared/dist/platform-availability.js"() {
24100
+ "use strict";
24101
+ HOSTING_AVAILABLE = false;
24102
+ SSO_AVAILABLE = false;
24103
+ CLOUD_SERVER_AVAILABLE = false;
24104
+ }
24105
+ });
24106
+
24000
24107
  // ../../packages/shared/dist/app-elements.js
24001
24108
  var APP_ELEMENTS, byId, APP_ELEMENT_IDS;
24002
24109
  var init_app_elements = __esm({
@@ -24315,6 +24422,13 @@ function schemaFieldRejected(status2, body) {
24315
24422
  function anthropicBaseUrl(env) {
24316
24423
  return env?.ANTHROPIC_BASE_URL?.trim() || process.env.ANTHROPIC_BASE_URL?.trim() || "https://api.anthropic.com";
24317
24424
  }
24425
+ function isAnthropicEndpoint(env) {
24426
+ try {
24427
+ return /(^|\.)api\.anthropic\.com$/i.test(new URL(anthropicBaseUrl(env)).hostname);
24428
+ } catch {
24429
+ return false;
24430
+ }
24431
+ }
24318
24432
  var OAUTH_BETA_HEADER;
24319
24433
  var init_model_json = __esm({
24320
24434
  "../../packages/shared/dist/model-json.js"() {
@@ -24347,9 +24461,9 @@ function withRunDirective(userText, directive) {
24347
24461
  return `${head}${RUN_DIRECTIVE_MARK}
24348
24462
  ${directive}`;
24349
24463
  }
24350
- function stripRunDirective(text12) {
24351
- const at = text12.indexOf(RUN_DIRECTIVE_MARK);
24352
- return at < 0 ? text12 : text12.slice(0, at).trimEnd();
24464
+ function stripRunDirective(text13) {
24465
+ const at = text13.indexOf(RUN_DIRECTIVE_MARK);
24466
+ return at < 0 ? text13 : text13.slice(0, at).trimEnd();
24353
24467
  }
24354
24468
  var RUN_DIRECTIVE_MARK;
24355
24469
  var init_run_directive = __esm({
@@ -24397,6 +24511,13 @@ var init_digit_recall = __esm({
24397
24511
  }
24398
24512
  });
24399
24513
 
24514
+ // ../../packages/shared/dist/tab-nav.js
24515
+ var init_tab_nav = __esm({
24516
+ "../../packages/shared/dist/tab-nav.js"() {
24517
+ "use strict";
24518
+ }
24519
+ });
24520
+
24400
24521
  // ../../packages/shared/dist/telemetry.js
24401
24522
  var TELEMETRY_EVENTS, EVENT_CATEGORY;
24402
24523
  var init_telemetry = __esm({
@@ -24697,6 +24818,7 @@ var NO_QUOTAS, NO_FEATURES, PLAN_CATALOG;
24697
24818
  var init_plans = __esm({
24698
24819
  "../../packages/shared/dist/plans.js"() {
24699
24820
  "use strict";
24821
+ init_platform_availability();
24700
24822
  NO_QUOTAS = { computeHours: 0, storageGb: 0, egressGb: 0, videoSeconds: 0 };
24701
24823
  NO_FEATURES = {
24702
24824
  sync: false,
@@ -24725,7 +24847,7 @@ var init_plans = __esm({
24725
24847
  tagline: "Your machine, your phone, your voice.",
24726
24848
  features: [
24727
24849
  "Unlimited agent usage",
24728
- "Full IDE: editor, files, agent, browser tool",
24850
+ "It operates this computer \u2014 screen, files and browser",
24729
24851
  "Voice mode",
24730
24852
  "Mobile app \u2014 reach your computer from your phone",
24731
24853
  "Cloud workspace \u2014 your machine and recent projects in one view",
@@ -24744,9 +24866,11 @@ var init_plans = __esm({
24744
24866
  features: [
24745
24867
  "Everything in Free",
24746
24868
  "Unlimited machines \u2014 run agents on all of them",
24747
- "Tesseract cloud server \u2014 a managed always-on agent in the cloud",
24748
- "Deploy to the cloud \u2014 your app on a *.tesseract.dev URL",
24749
- "Includes ~1 always-on service + 20 GB storage + 100 GB bandwidth (overage metered)",
24869
+ ...CLOUD_SERVER_AVAILABLE ? ["Tesseract cloud server \u2014 a managed always-on agent in the cloud"] : [],
24870
+ ...HOSTING_AVAILABLE ? [
24871
+ "Deploy to the cloud \u2014 your app on a *.tesseract.dev URL",
24872
+ "Includes ~1 always-on service + 20 GB storage + 100 GB bandwidth (overage metered)"
24873
+ ] : [],
24750
24874
  "Premium missions \u2014 GDPR, security, UX, performance audits that fix & verify",
24751
24875
  "Sync settings across your devices",
24752
24876
  "Email support"
@@ -24756,10 +24880,10 @@ var init_plans = __esm({
24756
24880
  sync: true,
24757
24881
  mobile: true,
24758
24882
  cloudWorkspace: true,
24759
- cloudServer: true,
24883
+ cloudServer: CLOUD_SERVER_AVAILABLE,
24760
24884
  remoteAgents: true,
24761
24885
  voice: true,
24762
- hosting: true,
24886
+ hosting: HOSTING_AVAILABLE,
24763
24887
  plugins: true,
24764
24888
  missions: true,
24765
24889
  scheduling: true,
@@ -24780,26 +24904,27 @@ var init_plans = __esm({
24780
24904
  "Parallel agents",
24781
24905
  "Advanced browser automation",
24782
24906
  "API access",
24783
- "SSO, audit logs, centralized billing",
24784
- "Pooled cloud hosting \u2014 bigger shared quota",
24907
+ ...SSO_AVAILABLE ? ["Company sign-on and audit log"] : [],
24908
+ "Centralized billing across seats",
24909
+ ...HOSTING_AVAILABLE ? ["Pooled cloud hosting \u2014 bigger shared quota"] : [],
24785
24910
  "Priority support"
24786
24911
  ],
24787
24912
  featurePolicy: {
24788
24913
  sync: true,
24789
24914
  mobile: true,
24790
24915
  cloudWorkspace: true,
24791
- cloudServer: true,
24916
+ cloudServer: CLOUD_SERVER_AVAILABLE,
24792
24917
  remoteAgents: true,
24793
24918
  voice: true,
24794
24919
  team: true,
24795
24920
  parallelAgents: true,
24796
24921
  advancedBrowser: true,
24797
- hosting: true,
24922
+ hosting: HOSTING_AVAILABLE,
24798
24923
  plugins: true,
24799
24924
  missions: true,
24800
24925
  scheduling: true,
24801
24926
  api: true,
24802
- sso: true,
24927
+ sso: SSO_AVAILABLE,
24803
24928
  seats: 2,
24804
24929
  maxMachines: 0
24805
24930
  },
@@ -25520,8 +25645,26 @@ var init_engines = __esm({
25520
25645
  capabilities: CLAUDE_CAPABILITIES,
25521
25646
  runModeTiming: CLAUDE_RUN_MODE_TIMING,
25522
25647
  homepageUrl: "https://docs.claude.com/en/docs/claude-code",
25523
- installCommand: "npm install -g @anthropic-ai/claude-code",
25524
- installHint: "Tesseract can run Claude Code without the standalone CLI; install it to use a copy you manage yourself."
25648
+ // The NATIVE installer, not npm. Two reasons, in order of how often they bite:
25649
+ // 1. npm needs a Node toolchain the machine may simply not have — and a GUI-launched app
25650
+ // sees PATH=/usr/bin:/bin:/usr/sbin:/sbin, so even an nvm-managed node is invisible.
25651
+ // The native installer needs only curl/wget and a shell.
25652
+ // 2. npm would land under our own `--prefix` (~/.tesseract/runtimes/bin), which the thing
25653
+ // that SPAWNS claude (agent-core's findUserInstalledClaude) does not search — so the
25654
+ // install would "succeed" and the engine would still read as missing. The native
25655
+ // installer writes ~/.local/bin/claude, which both the probe and the spawner know.
25656
+ // `install.sh` hard-refuses Windows, and `irm | iex` cannot take the version argument, so
25657
+ // Windows gets the documented scriptblock form rather than a quoting variant.
25658
+ installCommand: "curl -fsSL https://claude.ai/install.sh | bash -s {version}",
25659
+ installCommandWin: "& ([scriptblock]::Create((irm https://claude.ai/install.ps1))) {version}",
25660
+ // Its own updater. A copy managed by brew/winget reports "up to date" and does nothing —
25661
+ // which autoFixUnusable surfaces honestly via its post-update re-check rather than
25662
+ // claiming success.
25663
+ updateCommand: "claude update",
25664
+ // The documented uninstall. Both halves: the launcher and the versions directory.
25665
+ removeCommand: "rm -f ~/.local/bin/claude && rm -rf ~/.local/share/claude",
25666
+ removeCommandWin: 'Remove-Item -Path "$env:USERPROFILE\\.local\\bin\\claude.exe" -Force; Remove-Item -Path "$env:USERPROFILE\\.local\\share\\claude" -Recurse -Force',
25667
+ installHint: "Tesseract runs the Claude Code CLI you have installed rather than bundling one; install it to use this engine."
25525
25668
  },
25526
25669
  "openai-codex": {
25527
25670
  id: "openai-codex",
@@ -26071,6 +26214,7 @@ var init_runner_compat = __esm({
26071
26214
  "use strict";
26072
26215
  init_engines();
26073
26216
  init_providers();
26217
+ init_model_catalog();
26074
26218
  GATEWAY_WIRES = {
26075
26219
  "claude-code": { kind: "anthropic-env" },
26076
26220
  "openai-codex": { kind: "codex-home" },
@@ -26337,6 +26481,10 @@ var init_runtimes = __esm({
26337
26481
  label: ENGINE_CATALOG[id].label,
26338
26482
  cliBinary: ENGINE_CATALOG[id].cliBinary,
26339
26483
  installCommand: ENGINE_CATALOG[id].installCommand,
26484
+ installCommandWin: ENGINE_CATALOG[id].installCommandWin,
26485
+ updateCommand: ENGINE_CATALOG[id].updateCommand,
26486
+ removeCommand: ENGINE_CATALOG[id].removeCommand,
26487
+ removeCommandWin: ENGINE_CATALOG[id].removeCommandWin,
26340
26488
  kind: "engine"
26341
26489
  })),
26342
26490
  { id: "ollama", label: "Ollama", cliBinary: "ollama", installCommand: "curl -fsSL https://ollama.com/install.sh | sh", kind: "tool" },
@@ -26482,26 +26630,47 @@ function providerBase(key2, which2) {
26482
26630
  return fromServer;
26483
26631
  return which2 === "anthropic" ? gatewayAnthropicBaseUrl(key2.baseUrl) : which2 === "openai" ? gatewayOpenAiBaseUrl(key2.baseUrl) : gatewayGeminiBaseUrl(key2.baseUrl);
26484
26632
  }
26633
+ function slotProviders(key2) {
26634
+ const out = /* @__PURE__ */ new Map();
26635
+ for (const slot of Object.keys(TIER_PROVIDER)) {
26636
+ const id = key2.models[slot]?.trim();
26637
+ if (id)
26638
+ out.set(id, TIER_PROVIDER[slot]);
26639
+ }
26640
+ return out;
26641
+ }
26485
26642
  function tiers(engineId, key2, models) {
26486
- const agentTier = engineId === "claude-code" ? { main: key2.models.claude, fast: key2.models.claudeFast } : gatewayProviderForEngine(engineId) === "openai" ? { main: key2.models.codex ?? key2.models.gpt, fast: void 0 } : { main: void 0, fast: void 0 };
26487
- const served = new Set(Object.values(key2.models).filter((v) => typeof v === "string" && !!v));
26643
+ const provider = gatewayProviderForEngine(engineId);
26644
+ const preference = provider ? TIER_PREFERENCE[provider] : void 0;
26645
+ const byModel = slotProviders(key2);
26488
26646
  const asked = (v) => {
26489
26647
  const t = v?.trim();
26490
26648
  if (!t)
26491
26649
  return void 0;
26492
26650
  if (t.includes("/"))
26493
26651
  return t;
26494
- return served.has(t) ? t : void 0;
26652
+ return byModel.get(t) === provider ? t : void 0;
26495
26653
  };
26496
- const main2 = asked(models.main) || agentTier.main || key2.models.high;
26497
- const fast = asked(models.fast) || agentTier.fast || key2.models.low;
26498
- return { main: main2, fast };
26654
+ const pick3 = (slots) => {
26655
+ for (const slot of slots) {
26656
+ const id = key2.models[slot]?.trim();
26657
+ if (id)
26658
+ return id;
26659
+ }
26660
+ return void 0;
26661
+ };
26662
+ const serverDefault = asked(key2.defaults?.model);
26663
+ const main2 = asked(models.main) || serverDefault || preference && pick3(preference.main);
26664
+ const fast = asked(models.fast) || serverDefault || preference && pick3(preference.fast) || main2;
26665
+ return { main: main2 || void 0, fast: fast || void 0 };
26499
26666
  }
26500
26667
  function planGatewayRun(engineId, key2, models, homeBase) {
26501
26668
  const wire = gatewayWireFor(engineId);
26502
26669
  if (!wire)
26503
26670
  return void 0;
26504
26671
  const { main: main2, fast } = tiers(engineId, key2, models);
26672
+ if (!main2 || !fast)
26673
+ return void 0;
26505
26674
  const effort = ENGINE_CATALOG[engineId]?.modelControls.reasoningEfforts?.includes(models.reasoningEffort ?? "") ? models.reasoningEffort : void 0;
26506
26675
  return planEndpointRun(wire.kind, {
26507
26676
  baseUrl: wire.kind === "anthropic-env" ? providerBase(key2, "anthropic") : wire.kind === "gemini-env" ? providerBase(key2, "gemini") : providerBase(key2, "openai"),
@@ -26515,13 +26684,30 @@ function planGatewayRun(engineId, key2, models, homeBase) {
26515
26684
  homeKey: HOME_DIR_NAME[engineId]
26516
26685
  }, homeBase);
26517
26686
  }
26518
- var HOME_DIR_NAME;
26687
+ var TIER_PROVIDER, TIER_PREFERENCE, HOME_DIR_NAME;
26519
26688
  var init_gateway_plan = __esm({
26520
26689
  "../../packages/shared/dist/gateway-plan.js"() {
26521
26690
  "use strict";
26522
26691
  init_runner_compat();
26523
26692
  init_engine_endpoint();
26524
26693
  init_engines();
26694
+ TIER_PROVIDER = {
26695
+ low: "openai",
26696
+ high: "openai",
26697
+ image: "openai",
26698
+ codex: "openai",
26699
+ gpt: "openai",
26700
+ vision: "google-ai",
26701
+ claude: "anthropic",
26702
+ claudeFast: "anthropic"
26703
+ };
26704
+ TIER_PREFERENCE = {
26705
+ // No fast rung of its own on the OpenAI side: Codex is one model plus a reasoning dial,
26706
+ // and the nano model remains the cheap fallback for anything that asks for one.
26707
+ openai: { main: ["codex", "gpt", "high"], fast: ["low", "high"] },
26708
+ anthropic: { main: ["claude"], fast: ["claudeFast", "claude"] },
26709
+ "google-ai": { main: ["vision"], fast: ["vision"] }
26710
+ };
26525
26711
  HOME_DIR_NAME = {
26526
26712
  opencode: "opencode-bundled",
26527
26713
  "openai-codex": "gateway-openai-codex"
@@ -27637,6 +27823,14 @@ var init_stage_types = __esm({
27637
27823
  }
27638
27824
  });
27639
27825
 
27826
+ // ../../packages/shared/dist/deck-package.js
27827
+ var init_deck_package = __esm({
27828
+ "../../packages/shared/dist/deck-package.js"() {
27829
+ "use strict";
27830
+ init_stage_types();
27831
+ }
27832
+ });
27833
+
27640
27834
  // ../../packages/shared/dist/rdesk-client-ipc.js
27641
27835
  var init_rdesk_client_ipc = __esm({
27642
27836
  "../../packages/shared/dist/rdesk-client-ipc.js"() {
@@ -27662,10 +27856,10 @@ var init_user_dialog = __esm({
27662
27856
  });
27663
27857
 
27664
27858
  // ../../packages/shared/dist/session-ops.js
27665
- function cleanTaskNotifications(text12) {
27666
- if (!text12.includes("<task-notification>"))
27667
- return text12;
27668
- return text12.replace(/<task-notification>([\s\S]*?)<\/task-notification>/g, (_all, inner) => {
27859
+ function cleanTaskNotifications(text13) {
27860
+ if (!text13.includes("<task-notification>"))
27861
+ return text13;
27862
+ return text13.replace(/<task-notification>([\s\S]*?)<\/task-notification>/g, (_all, inner) => {
27669
27863
  const g = (name) => {
27670
27864
  const m = new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(inner);
27671
27865
  return m ? m[1].trim() : "";
@@ -27676,8 +27870,8 @@ function cleanTaskNotifications(text12) {
27676
27870
  }).trim();
27677
27871
  }
27678
27872
  function transcriptToText(msgs, cap = MERGE_PER_SOURCE_CAP) {
27679
- const text12 = msgs.map((m) => `${m.role === "user" ? "User" : "Assistant"}: ${cleanTaskNotifications(m.content)}`).join("\n").slice(0, cap);
27680
- return text12.trim() ? text12 : "";
27873
+ const text13 = msgs.map((m) => `${m.role === "user" ? "User" : "Assistant"}: ${cleanTaskNotifications(m.content)}`).join("\n").slice(0, cap);
27874
+ return text13.trim() ? text13 : "";
27681
27875
  }
27682
27876
  function buildMergeSeed(transcripts) {
27683
27877
  return [
@@ -27689,10 +27883,10 @@ function buildMergeSeed(transcripts) {
27689
27883
  ${t}`)
27690
27884
  ].join("\n\n");
27691
27885
  }
27692
- function parseSummaryReply(text12) {
27693
- const m = /^\s*TITLE:\s*(.+?)\s*\n-{3,}\s*\n([\s\S]+)$/.exec(text12);
27886
+ function parseSummaryReply(text13) {
27887
+ const m = /^\s*TITLE:\s*(.+?)\s*\n-{3,}\s*\n([\s\S]+)$/.exec(text13);
27694
27888
  const title = m?.[1]?.trim();
27695
- const summary = (m?.[2] ?? text12).trim();
27889
+ const summary = (m?.[2] ?? text13).trim();
27696
27890
  return title ? { title, summary } : { summary };
27697
27891
  }
27698
27892
  var MERGE_PER_SOURCE_CAP;
@@ -27797,6 +27991,7 @@ var init_dist2 = __esm({
27797
27991
  "use strict";
27798
27992
  init_surface_merge();
27799
27993
  init_permissions();
27994
+ init_platform_availability();
27800
27995
  init_app_elements();
27801
27996
  init_ws_protocol();
27802
27997
  init_context_overflow();
@@ -27807,6 +28002,7 @@ var init_dist2 = __esm({
27807
28002
  init_run_directive();
27808
28003
  init_proactive_compaction();
27809
28004
  init_digit_recall();
28005
+ init_tab_nav();
27810
28006
  init_telemetry();
27811
28007
  init_error_report();
27812
28008
  init_eula();
@@ -27849,6 +28045,7 @@ var init_dist2 = __esm({
27849
28045
  init_chat_slash();
27850
28046
  init_present_protocol();
27851
28047
  init_stage_types();
28048
+ init_deck_package();
27852
28049
  init_rdesk_client_ipc();
27853
28050
  init_user_dialog();
27854
28051
  init_session_ops();
@@ -30539,8 +30736,8 @@ function makeApi(deps, toolId, tier) {
30539
30736
  await h.close();
30540
30737
  return r.cancelled ? null : r.value ?? [];
30541
30738
  },
30542
- notify: async (text12, opts) => {
30543
- await api.open({ kind: "markdown", initial: { markdown: text12, level: opts?.level } });
30739
+ notify: async (text13, opts) => {
30740
+ await api.open({ kind: "markdown", initial: { markdown: text13, level: opts?.level } });
30544
30741
  }
30545
30742
  };
30546
30743
  return api;
@@ -30551,11 +30748,11 @@ function buildToolCtx(deps, sessionId, toolId, log10 = NOOP_LOG, tier = "third-p
30551
30748
  return getSid();
30552
30749
  }, toolId, log: log10 };
30553
30750
  }
30554
- function wrapCtxTool(tool21, ctx2) {
30555
- const raw = tool21.__ctxHandler;
30751
+ function wrapCtxTool(tool22, ctx2) {
30752
+ const raw = tool22.__ctxHandler;
30556
30753
  if (typeof raw !== "function")
30557
- return tool21;
30558
- return { ...tool21, handler: async (args) => raw(args, ctx2) };
30754
+ return tool22;
30755
+ return { ...tool22, handler: async (args) => raw(args, ctx2) };
30559
30756
  }
30560
30757
  var NOOP_LOG;
30561
30758
  var init_surface_ctx = __esm({
@@ -30713,11 +30910,11 @@ var init_hook_bus = __esm({
30713
30910
  // ../../packages/agent-core/dist/jobs/file-tailer.js
30714
30911
  import { statSync } from "node:fs";
30715
30912
  import { open } from "node:fs/promises";
30716
- function parseBackgroundTaskResult(text12) {
30717
- if (!text12 || !text12.includes(".output"))
30913
+ function parseBackgroundTaskResult(text13) {
30914
+ if (!text13 || !text13.includes(".output"))
30718
30915
  return null;
30719
- const id = /\bID:\s*([A-Za-z0-9_-]+)/.exec(text12);
30720
- const path6 = /Output is being written to:\s*([^\s]+\.output)/.exec(text12);
30916
+ const id = /\bID:\s*([A-Za-z0-9_-]+)/.exec(text13);
30917
+ const path6 = /Output is being written to:\s*([^\s]+\.output)/.exec(text13);
30721
30918
  if (!id?.[1] || !path6?.[1])
30722
30919
  return null;
30723
30920
  return { taskId: id[1], outputPath: path6[1] };
@@ -31737,6 +31934,8 @@ var init_parallel_tools = __esm({
31737
31934
  "browser_events",
31738
31935
  "capture_element_styles",
31739
31936
  // ── Listings, capability probes and status reads.
31937
+ // tesseract_capabilities returns an inlined constant — concurrent calls are indistinguishable.
31938
+ "tesseract_capabilities",
31740
31939
  "list_effects",
31741
31940
  "list_upscale_models",
31742
31941
  "list_voices",
@@ -31789,8 +31988,8 @@ var init_tool_spec = __esm({
31789
31988
  import { tool as tool14 } from "@anthropic-ai/claude-agent-sdk";
31790
31989
  function buildScreenControlSdkTools(p) {
31791
31990
  return screenControlSpecs().map((spec) => tool14(spec.name, spec.description, zodShapeFromParams(spec.params), async (args) => {
31792
- const text12 = await p.exec(spec.name, args ?? {});
31793
- return { content: [{ type: "text", text: text12 || "Done." }] };
31991
+ const text13 = await p.exec(spec.name, args ?? {});
31992
+ return { content: [{ type: "text", text: text13 || "Done." }] };
31794
31993
  }));
31795
31994
  }
31796
31995
  var ANNOTATE_STYLES, SCREEN_CONTROL_SHAPES, screenControlSpecs;
@@ -32596,6 +32795,10 @@ ${JSON.stringify(r, null, 2)}`
32596
32795
  { id: "settings.has_search_key", domain: "settings", title: "Web search available?", input: external_exports.object({}), mutation: "read", availability: "host", binding: { kind: "ipc", channel: "serp", verb: "hasKey" } },
32597
32796
  { id: "image.set_avatar_key", domain: "image", title: "Set avatar-video (HeyGen) key", input: external_exports.object({ api_key: external_exports.string().describe("HeyGen API key (secret); blank clears.") }), mutation: "write", availability: "host", binding: { kind: "ipc", channel: "heygen", verb: "setKey" } },
32598
32797
  { id: "image.has_avatar_key", domain: "image", title: "Avatar-video key configured?", input: external_exports.object({}), mutation: "read", availability: "host", binding: { kind: "ipc", channel: "heygen", verb: "hasKey" } },
32798
+ // Whether the FREE brokered tier can serve an avatar video HERE — the user's own key is
32799
+ // the other half, above. Worth asking before drafting a script: the deployment may hold
32800
+ // no HeyGen account, and generate_avatar_video then fails at submit with the work done.
32801
+ { id: "image.has_avatar_free_tier", domain: "image", title: "Free avatar-video tier available?", input: external_exports.object({}), mutation: "read", availability: "host", binding: { kind: "ipc", channel: "heygen", verb: "brokered" } },
32599
32802
  { id: "image.remove_provider_key", domain: "image", title: "Remove image provider key", input: external_exports.object({ provider_id: IMAGE_PROVIDER }), mutation: "write", availability: "host", binding: { kind: "ipc", channel: "imageEdit", verb: "removeKey" } },
32600
32803
  { id: "image.set_default_provider", domain: "image", title: "Set default image provider", input: external_exports.object({ provider_id: IMAGE_PROVIDER }), mutation: "write", availability: "host", binding: { kind: "ipc", channel: "imageEdit", verb: "setDefault" } },
32601
32804
  { id: "image.set_provider_model", domain: "image", title: "Set image provider model", input: external_exports.object({ provider_id: IMAGE_PROVIDER, model: external_exports.string() }), mutation: "write", availability: "host", binding: { kind: "ipc", channel: "imageEdit", verb: "setModel" } },
@@ -32760,6 +32963,134 @@ ${JSON.stringify(r, null, 2)}`
32760
32963
  availability: "desktop",
32761
32964
  binding: { kind: "command", command: "app.openStage" }
32762
32965
  },
32966
+ // ── The presentation LIBRARY: authoring, not driving ──────────────────────────────────
32967
+ // Everything above drives a deck that is already running, and lives in the daemon because
32968
+ // a phone remote reaches it. These WRITE FILES, so they are 'desktop': the library is a
32969
+ // folder in the user's Documents, and only the desktop process can touch it.
32970
+ //
32971
+ // A deck is TSX — the same slide contract the app's own decks use — so the model authors
32972
+ // by writing files and then calling `validate_deck` until it comes back clean. That loop
32973
+ // is the whole design: without it the first sign of a stray bracket on slide 14 is a
32974
+ // blank rectangle at the front of a room.
32975
+ {
32976
+ id: "present.list_decks",
32977
+ domain: "present",
32978
+ title: "List presentations",
32979
+ input: external_exports.object({}),
32980
+ mutation: "read",
32981
+ availability: "desktop",
32982
+ binding: { kind: "ipc", channel: "decklib", verb: "list" }
32983
+ },
32984
+ {
32985
+ id: "present.create_deck",
32986
+ domain: "present",
32987
+ title: "Create a presentation",
32988
+ input: external_exports.object({
32989
+ title: external_exports.string().describe("What the presentation is called. Shown in the library and used for its folder name; keep the user's own wording and language."),
32990
+ description: external_exports.string().optional().describe("One line about what it is for."),
32991
+ theme: external_exports.record(external_exports.string(), external_exports.string()).optional().describe('CSS custom properties applied to every slide, e.g. { "--bg": "#FFFFFF", "--ink": "#16130F", "--accent": "#D97757" }.')
32992
+ }),
32993
+ mutation: "write",
32994
+ availability: "desktop",
32995
+ binding: { kind: "ipc", channel: "decklib", verb: "create" },
32996
+ summarize: (r) => `Created the presentation "${r?.title ?? ""}".`
32997
+ },
32998
+ {
32999
+ id: "present.write_slide",
33000
+ domain: "present",
33001
+ title: "Write a slide",
33002
+ input: external_exports.object({
33003
+ deck: external_exports.string().describe("The deck folder, exactly as `list_decks` or `create_deck` returned it (ends in .tessdeck)."),
33004
+ path: external_exports.string().describe('Path inside the presentation, e.g. "slides/03-pricing.tsx". Filename order IS slide order, so number the prefixes. Helper files may live anywhere in the package.'),
33005
+ source: external_exports.string().describe("The whole file. A slide exports `meta` ({ id, title, summary?, notes?, transition?, builds? }) and a default React component.")
33006
+ }),
33007
+ mutation: "write",
33008
+ availability: "desktop",
33009
+ binding: { kind: "ipc", channel: "decklib", verb: "writeFile" },
33010
+ summarize: (_r, i) => `Wrote ${i.path ?? "a slide"}.`
33011
+ },
33012
+ {
33013
+ id: "present.read_slide",
33014
+ domain: "present",
33015
+ title: "Read a slide",
33016
+ input: external_exports.object({
33017
+ deck: external_exports.string().describe("The deck folder."),
33018
+ path: external_exports.string().describe('Path inside the presentation, e.g. "slides/03-pricing.tsx".')
33019
+ }),
33020
+ mutation: "read",
33021
+ availability: "desktop",
33022
+ binding: { kind: "ipc", channel: "decklib", verb: "readFile" }
33023
+ },
33024
+ {
33025
+ id: "present.delete_slide",
33026
+ domain: "present",
33027
+ title: "Delete a slide",
33028
+ input: external_exports.object({
33029
+ deck: external_exports.string().describe("The deck folder."),
33030
+ path: external_exports.string().describe("Path inside the presentation.")
33031
+ }),
33032
+ mutation: "write",
33033
+ availability: "desktop",
33034
+ binding: { kind: "ipc", channel: "decklib", verb: "deleteFile" },
33035
+ summarize: (_r, i) => `Deleted ${i.path ?? "a slide"}.`
33036
+ },
33037
+ {
33038
+ id: "present.validate_deck",
33039
+ domain: "present",
33040
+ title: "Check a presentation",
33041
+ input: external_exports.object({ deck: external_exports.string().describe("The deck folder.") }),
33042
+ mutation: "read",
33043
+ availability: "desktop",
33044
+ binding: { kind: "ipc", channel: "decklib", verb: "validate" },
33045
+ summarize: (r) => typeof r === "string" ? r : "Checked the presentation."
33046
+ },
33047
+ {
33048
+ id: "present.set_deck_theme",
33049
+ domain: "present",
33050
+ title: "Set a presentation\u2019s theme",
33051
+ input: external_exports.object({
33052
+ deck: external_exports.string().describe("The deck folder."),
33053
+ theme: external_exports.record(external_exports.string(), external_exports.string()).describe(`CSS custom properties, e.g. { "--bg": "#0C0A14", "--ink": "#FFFFFF" }. Replaces the deck's current theme.`)
33054
+ }),
33055
+ mutation: "write",
33056
+ availability: "desktop",
33057
+ binding: { kind: "ipc", channel: "decklib", verb: "setTheme" },
33058
+ summarize: () => "Updated the presentation\u2019s theme."
33059
+ },
33060
+ {
33061
+ id: "present.add_asset",
33062
+ domain: "present",
33063
+ title: "Add an image to a presentation",
33064
+ input: external_exports.object({
33065
+ deck: external_exports.string().describe("The deck folder."),
33066
+ source_path: external_exports.string().describe("Absolute path of the file to copy in \u2014 a generated image, a photo, an audio clip."),
33067
+ name: external_exports.string().optional().describe("Filename to use inside the presentation.")
33068
+ }),
33069
+ mutation: "write",
33070
+ availability: "desktop",
33071
+ binding: { kind: "ipc", channel: "decklib", verb: "addAsset" },
33072
+ summarize: (r) => `Added ${typeof r === "string" ? r : "an asset"} to the presentation.`
33073
+ },
33074
+ {
33075
+ id: "present.open_deck",
33076
+ domain: "present",
33077
+ title: "Open a presentation",
33078
+ input: external_exports.object({ deck: external_exports.string().describe("The deck folder.") }),
33079
+ mutation: "write",
33080
+ availability: "desktop",
33081
+ binding: { kind: "ipc", channel: "decklib", verb: "open" },
33082
+ summarize: () => "Opened the presentation in Stage."
33083
+ },
33084
+ {
33085
+ id: "present.delete_deck",
33086
+ domain: "present",
33087
+ title: "Delete a presentation",
33088
+ input: external_exports.object({ deck: external_exports.string().describe("The deck folder.") }),
33089
+ mutation: "write",
33090
+ availability: "desktop",
33091
+ binding: { kind: "ipc", channel: "decklib", verb: "delete" },
33092
+ summarize: (_r, i) => `Deleted the presentation ${i.deck ?? ""}.`
33093
+ },
32763
33094
  {
32764
33095
  id: "present.end",
32765
33096
  domain: "present",
@@ -32954,6 +33285,75 @@ var init_app_control_tools = __esm({
32954
33285
  }
32955
33286
  });
32956
33287
 
33288
+ // ../../packages/agent-core/dist/capabilities-doc.generated.js
33289
+ var CAPABILITIES_DOC;
33290
+ var init_capabilities_doc_generated = __esm({
33291
+ "../../packages/agent-core/dist/capabilities-doc.generated.js"() {
33292
+ "use strict";
33293
+ CAPABILITIES_DOC = '# Tesseract \u2014 what the product can do\n\nOne-page map of **every user-reachable capability**, derived from the 80 area briefs in\n[`functional-testing/`](functional-testing/). It is the source for the `tesseract_capabilities`\ntool, so the agent can answer "what can you do?" about *Tesseract*, not just about its own toolbelt.\n\n> Read this before telling a user something is or isn\'t possible. \xA718 lists what is deliberately\n> **not** built \u2014 promising any of it is the most common way to be wrong about this product.\n\n---\n\n## 1. What Tesseract is\n\nA desktop-first AI workspace: an always-on agent that can drive your machine, your browser and your\nfiles; plus a fleet layer that makes every machine you own reachable from any of them; plus a set of\ncreative, communication and security products built on the same transport. It ships as **eight\nseparate clients** and is not a single app.\n\n## 2. Clients (each a distinct product)\n\n| Client | What it is |\n|---|---|\n| **Desktop** (Electron, mac/Win/Linux) | The full product. Tab workspace \u2014 **no router**: a recursive split-pane tree of tab groups, **24 tab kinds**, **10 dockable panels** (dock left/right/bottom, float, detach), multi-window, native menu, command + search palettes (**31 stable command ids**), \u23181\u20130 tab assign/recall, per-machine keybinding overrides, memory governor + layout restore. |\n| **Web** (`dist-web`) | Same React renderer over a relay transport. **No local agent, no local engine** \u2014 it always runs on a remote host. Terminals are all remote and pinned to the opening host. Documented stubs: undo-delete, engines, runner configs, window resize; voice keys sit in `localStorage`. Always auth-gated. |\n| **Mobile** (Flutter, iOS/Android/macOS) | A **roaming client** \u2014 it never hosts an agent. Chat with streaming, team chat, present-follower, full password vault (incl. TOTP + native autofill), realtime voice, rdesk viewer, clipboard sync, push. Uniquely: **phone-as-host** (serve your photo library and files to your desktop) and a create-video screen. |\n| **CLI** `tesseract-agent` (npm) | Headless daemon, ~18 commands: `login/logout/whoami`, `run`, service `install/start/stop/restart/status/logs`, `link add`, `runner \u2026`, `net \u2026`, self-update. `--instance <id>` namespaces state dir, service name and device id. Docker-friendly (`login --token` then `run` as PID 1). |\n| **Browser extension** (Chrome MV3) | Claude sidebar (sessions, slash commands, todos, sources, DOM tree, run modes), element picker, vault/autofill popup with biometrics, QR pairing, fullpage + plan views. Talks to the daemon through a native-messaging companion host. |\n| **Remote Desktop** (`apps/rdesk`) | Slim standalone binary, ~\xBC the size \u2014 ships **no AI/browser payload**. Server/client/chooser roles, coexists with the full daemon (demotes itself to client rather than quitting). |\n| **Mesh** (`apps/mesh`) | Slim standalone binary for the private network only \u2014 "moves packets, not pixels". Create a mesh, enrol, list peers. No role chooser by design. |\n| **Thin installer** (Flutter, ~20\u201340 MB) | The default download. Resolves the release feed at run time, picks the arch-correct asset, streams + sha512-verifies, installs, launches. Version-agnostic. |\n\nPlus the **admin/operations console** (`admin.tesseract.dev`: gateway credentials, users and keys,\nerror inspector, remediation trigger, audit log) and the **landing site** with its waitlist.\n\n## 3. The agent\n\n- **Turn lifecycle**: stream, interrupt, rapid-follow-up auto-cancel (first seconds only), stall\n watchdog, orphan-turn recovery, token compaction, usage-limit handling, cost ledger per session.\n- **Run modes**: **5 permission modes \xD7 6 effort levels**, thinking budget, per-turn engine/model pick.\n Default permission mode is `bypassPermissions`.\n- **Interactive cards** (~9): permission request, plan review, elicitation, confirm, verification,\n user dialog, skill UI, archive password, unattended report. "Deny & stop" also aborts the turn.\n- **Block renderers** (~9): mission, subagent, report, sources, provenance, event, notice, surface,\n image grid \u2014 plus tool-run cards joined at render time with 6/8-line clamping.\n- **Composer** (~25 actions): attach, slash commands, @-mention, reverse search, screen-region\n capture, element picker, voice, undo-last-turn, queued-message reorder.\n- **Sessions**: list, search (one host-side search across every engine\'s stored conversations),\n resume, summarize, **fork**, merge, delete-message, keep-alive, focus; session mirror + transfer;\n share a conversation by unguessable capability token.\n- **Subsystems**: reinforced verification, plan splitter, narrator (live status strip, capped at 24\n model calls/turn), hook bus (9 events), option ratings, unattended mode.\n- **Also**: a playable **chess** surface (5 tools) and chat slash toys (`/shrug`, `/tableflip`, \u2026).\n\n## 4. Engines, runners, gateway\n\n- **4 engines \xD7 3 auth modes** (`oauth` / `apiKey` / `localCli`), a 24-capability engine matrix,\n engine + model swap mid-session (model/permission-mode reconcile live; effort/cwd/MCP/system-prompt\n force a respawn).\n- **Runner config pool** with rotation, cooldown and failover; auto-retry is bounded and only fires\n when the turn did no work.\n- **Provider gateway** \u2014 a credential-injecting reverse proxy, **19 routes** across AGENT (anthropic,\n openai, google-ai, groq, xai, deepseek, moonshot, openrouter, custom-openai, customer-litellm,\n azure-openai), EMBEDDING, SEARCH (serpapi), VIDEO (heygen, gemini), VOICE, MEDIA (klipy, unsplash,\n pexels). Virtual keys `tsk_live_*`, budgets, LiteLLM price map, spend ledger, credential pools with\n health-based failover that never crosses a category. Models are named the way their makers\n name them \u2014 `claude-sonnet-4-6`, `claude-haiku-4-5-20251001`, `gpt-6-astra`, `gpt-5.5`,\n `gpt-5.4-mini`, `gpt-5.4-nano`, `gemini-2.5-flash`, `gpt-image-2` ($0.10/image flat) \u2014 and a\n signed-in key may also name a model we do not host as `vendor/model`.\n- **Framework cross-product gate**: the user\'s self-updating `claude` CLI \xD7 the pinned Agent SDK,\n verified nightly across pinned CLI versions.\n\n## 5. Files, editors, viewers\n\n- **Finder-like browser**: list/grid/columns, breadcrumbs, bookmarks + OS favourites, **host\n switcher** (every op can be remote), new/rename (F2)/move/duplicate/cut-copy-paste/delete + undo,\n Get Info, send-to-machine, find-in-files, native drag in **and out** (macOS `NSFilePromiseProvider`\n \u2014 drag a not-yet-downloaded remote file to Finder).\n- **~20 typed viewers/editors**: Monaco source editor, PDF (view + edit), Word/docx, spreadsheets,\n presentations, markdown, data grid, hex, audio, video, font, HTML canvas, diff, info.\n- **Archives as folders**: ~20 formats (zip, 7z, tar, gz/bz2/xz/zst, rar, iso, wim, cab, cpio, lzh\u2026)\n browsed, extracted and **edited in place** from the same tree. `rar`/`iso`/`cab` are read-only.\n Encrypted archives prompt for a password and can remember it.\n- **Image editor**: layered canvas, 10 tools (marquee, lasso, move, crop, paint, eraser, fill,\n eyedropper, text, zoom), 25 rail controls, **200+ AI effect styles**, layers, adjust/resize, markup,\n and 3 AI ops (`prompt`/`inpaint`/`outpaint`), transparent-background output, animate\u2192video.\n- **Video editor**: EDL timeline (cut/trim/reorder/transitions/speed/crop/reframe/flip/reverse/colour\n effects/audio tracks), burned-in captions, **18 MCP tools** \u2014 probe, render, frame extract, silence\n detect, transcribe with diarization, extract/isolate audio, music generation, voice list/clone/TTS,\n avatars, caption export, effects, upscale (ffmpeg + local Real-ESRGAN free; fal-Topaz paid).\n- **Undo & time travel**: agent-driven **file rewind** (undo what a turn wrote), file-tree \u2318Z with a\n per-window trash, workspace snapshots and git checkpoints, canvas/design version history with\n diff-and-restore, and message deletion with uniform semantics across engines.\n- **Native inspectors**: **Flutter** widget inspector (tree, on-device tap-to-pick, properties,\n deterministic Dart source edits, hot reload) and **React Native** (source binding + AST edits).\n\n## 6. Create, Design Studio, Stage, Publish\n\n- **Create** \u2014 5 generative document formats (incl. infographic and poster), ~90 actions: outline\n ops, 10 insert kinds, card generation, AI layouts, export.\n- **Design Studio** \u2014 a 10-stage wizard (pick \u2192 launch/browse \u2192 preview \u2192 target \u2192 inspect \u2192 brief \u2192\n build \u2192 QA \u2192 deploy) over **254 templates across 19 industry verticals**, Figma import, in-studio\n theme/token editing.\n- **Stage** \u2014 presentation engine: decks, slides, transitions, **slide audio** (narration/music/sfx\n with music ducking under narration), a live assistant, presenter mode, zoom/blank. 8 present tools\n let the agent drive the deck; followers converge from absolute-state snapshots.\n- **Export**: PowerPoint (.pptx), deck and card export, PNG.\n- **Publish** \u2014 private/org/public visibility, server-rendered public pages on a 192-bit token, live\n data sources (SSRF-guarded), embeds; **community gallery** with explore/following/team/mine, like,\n follow and clone.\n- **Deploy** \u2014 one-click hosting to `*.tesseract.dev` in per-user hardened containers (cap-drop ALL,\n no-new-privileges, read-only, egress-locked), metered on compute/storage/egress. One of the few\n genuinely entitlement-gated features. A separate **per-user cloud agent** container is provisioned\n on demand so you have a machine in the fleet even with every laptop closed.\n\n## 7. Generative media\n\n| What | Notes |\n|---|---|\n| **Images** | 2 providers (OpenAI gpt-image-2, Google). Generate (4-up by default), edit, inpaint/outpaint, transparent background (inpaint + chroma-key). **$0.10/image**. Ungated, BYO key. |\n| **Stock images** | AI-ranked Unsplash/Pexels search as its own tab. Free tier, rate-limited. |\n| **Video** | Google Veo 3.1 \u2014 4/6/8s clips, 720p/1080p, 16:9 or 9:16, keyframe conditioning (first/last frame), native audio. Free on the bundled tier; otherwise cost-confirmed. Multi-scene storyboards chain clip-to-clip for longer videos. |\n| **Avatar video** | HeyGen talking presenter from a script. |\n| **Music / speech** | ElevenLabs music generation, TTS, and instant **voice cloning**. |\n| **Fonts & brand** | Prompt \u2192 AI glyph sheets \u2192 **vision QC** \u2192 vectorize \u2192 kerning/spacing \u2192 a real installable font. Plus logo/wordmark candidates, SVG lockups and a brand kit. Assembly/vectorize/build are local and free. |\n| **Trending effects** | One-tap video effects (hug/kiss, squish, bring-photo-to-life, age, anime restyle, 3D figurine, outfit change, consent-gated face-swap\u2026). |\n\n## 8. Voice\n\n- **3 realtime providers**: OpenAI Realtime, Gemini Live, ElevenLabs ConvAI \u2014 plus a non-realtime\n **STT\u2192LLM\u2192TTS pipeline cascade**. Audio goes **client\u2194provider direct**; the daemon only mints the\n ephemeral credential and runs the control loop.\n- Group calls, live captions, and the **\u2325Space voice widget**.\n- **Voice as a control modality**: the realtime model is the *operator*, Claude Code is the *worker*.\n It decomposes a spoken request into one small dispatched step at a time, all to the same agent\n session, and is explicitly forbidden from claiming an outcome the agent did not report \u2014 when\n unsure it dispatches a check. Its own screen view is a deliberately low-res ~1 fps grab.\n\n## 9. Computer control\n\n- **Two distinct MCP servers**: `tesseract-computer` (**26 tools** \u2014 raw control: move/click/drag/\n scroll/key/type, see_screen, read_text, read_ui (accessibility), clipboard, windows, apps, open\n url/path, notify, annotate, draw) and `tesseract-screen` (**15 tools** \u2014 a guided\n look \u2192 figure_out_next \u2192 perform_step \u2192 **verify** loop that can fail and retry).\n- Plus `tesseract-os-control`: processes, network, structured fs, AX tree + AX actions, preferred app\n and usage profile, screen overlays (arrow/bubble/highlight/text/popup/choice), and\n `request_user_input` / `confirm_action`.\n- **Click grounding** is AX-tree + a local Moondream vision sidecar (free); screenshots are\n Retina-aware and downscaled to point coordinates so clicks line up.\n- **Off by default** \u2014 `computerControlEnabled` must be turned on.\n- **\u2325Space co-pilot HUD** + **13 daemon-owned windows** (spotlight, pastebar, publisher, annotate,\n draw, overlay, input, choice, consent, control-bar, ai-cursor, rdesk call/client), the tray, screen-\n region capture with multi-display number flash, and `tesseract://` deep links. The HUD is\n deliberately **invisible to the AI\'s own screenshots**.\n\n## 10. Integrated browser\n\n- In-app browser tabs with a shared persist partition, per-tab zoom, OAuth popups, URL-safety and\n proxy routing.\n- **Agent control over CDP**: navigate, snapshot, screenshot (viewport + full page), click (synthetic\n and real trusted input), type, key, eval, cookies, raw CDP for any domain, buffered event draining.\n Drives the **user\'s real logged-in browser** via the companion extension, or the built-in engine.\n- **Inspectors**: DOM tree, properties, native inspector; markup pen; click-to-source (JSX elements\n resolve to their source line).\n- **6 Toolkit mission playbooks**: accessibility, GDPR/cookies, health, performance, SEO, UX review \u2014\n each configures, runs, and emits a structured report.\n- **`appbrowser` collaboration**: presence, cursors, comments and edits on a visible tab.\n\n## 11. Web search\n\n`serp_*` over **121 engines / 1,726 parameters**, ~19 tools grouped by family: web, news, images\n(incl. reverse-image and Google Lens), video (incl. YouTube transcripts), maps/local, shopping,\nmarketplaces (Amazon/eBay/Walmart/Home Depot/Zillow), travel (flights/hotels), places & reviews,\nacademic (Scholar/patents), jobs, finance & trends, app stores, ads transparency, social.\nBrokered free tier: **100 searches/month signed in, 10/month anonymous** \u2014 the only hard per-user\nquota in the product.\n\n## 12. Multi-machine\n\n- **Host registry & fleet**: every machine you sign into registers itself; pick one and run the turn\n there. Dual-role nodes are both client and host at once.\n- **Remote fs + terminals** over the relay (9 relayed channels: agent, signal, browser, frame, fs,\n term, editor, rdesk, present). A remote driver may only launch an enumerated interpreter.\n- **File Provider (macOS)**: remote machines appear as native **Finder locations** \u2014 browse, read,\n write, rename, move, Trash + Put Back, thumbnails, progress. Identity survives rename/move.\n- **Drops** \u2014 AirDrop-like sharing to your own devices or another account. E2E-sealed, blind fan-out\n (first device to accept wins; the sender never learns which), receive policies + receive codes,\n blocks and abuse reports that are deliberately **indistinguishable** from "nobody was there".\n- **Universal clipboard**: text/HTML/images fan out to your other machines; >512 KB syncs a thumbnail\n + reference and pulls the bytes on demand. A privacy gate blocks password-manager and secure-input\n content. Plus **paste history** (\u2318\u21E7V pastebar), clipboard over the rdesk channel, and mobile\n text-only sync.\n- **Peer-link**: agent\u2194agent direct transport with a 3-tier ladder (LAN TLS \u2192 observed public IP \u2192\n UDP hole-punch), cert-pinned, relayed only as a fallback.\n- **Mesh VPN**: own PKI with SAS verification, join tickets, recovery mnemonic, a policy bundle with a\n fail-closed freshness clock, an authenticated Noise data plane, disco/path selection, a 25-pair NAT\n punch matrix, and a privileged `netd` helper that **derives** every route itself (the IPC has no\n "add route" field, by design) with journal-based teardown after a crash or reboot.\n- **Remote desktop**: screen share and control. 3 grant paths (same-account registry, cross-account\n code, unattended password), 3 engines (native, VNC, RDP), display picker, quality, Ctrl+Alt+Del,\n in-session voice on the same peer connection, side chat, and a phone viewer.\n- **Present & collaboration**: a presenter drives followers across devices; join codes; live cursors,\n comments and captions.\n- **Co-view mirroring**: a second device with the same conversation open sees **26 allowlisted\n events**. Permission prompts are deliberately *not* mirrored \u2014 a card you can\'t answer is a dead\n button.\n- **Settings & session sync**: keys, tokens, active engine and model are account-wide; `localCli`\n paths are machine-local and must never cross. Plus continuous folder mirroring (active link).\n\n## 13. Team chat & conferencing\n\nSlack-class: spaces, categories, channels, DMs, threads, mentions, reactions, custom emoji, stickers,\nattachments, forum channels, pins, presence, search (Postgres **or** Elasticsearch), link unfurl,\nGIF/meme, bots + a bot API, incoming webhooks, automations, governance, retention and audit.\n**Huddles** over a self-hosted LiveKit SFU with captions and a summary posted back to the channel;\ntoken minting and webhooks work without the SFU, and captions still work when LiveKit is unconfigured.\n\n## 14. Vault (password manager)\n\nZero-knowledge, Argon2id + AES-GCM, server holds only opaque ciphertext. **5 item types** (logins,\npasskeys, payments, secure notes, personal info), ~28 daemon ops, **4 unlock paths** (master password,\ndevice, biometric, **QR from your phone**), sharing sealed to recipient device keys, transfer,\nimport/export (Chrome, Safari, zip), a generator, TOTP, the **macOS AutoFill provider**, and browser\nautofill through the extension.\n\n## 15. Extensions platform\n\nFamilies: **skills, code plugins, bundle plugins, MCP connectors** (3 transports: stdio/http/sse),\nplus **theme packs**. Marketplace discovery with a security verdict that gates install; enable/disable;\nper-extension encrypted secrets; updates; uninstall. Extensions contribute **tabs, panels, settings\npages, status items, menu items and reskins**. First-party skills are free; marketplace ones are\ngated \u2014 `plugins` is the one entitlement actually enforced.\n\n## 16. App Control \u2014 the AI operating Tesseract itself\n\n**144 capabilities across 19 domains** (`settings, navigation, engines, runners, runtimes,\nextensions, hosts, account, daemon, providers, image, voice, permissions, project, privacy, system,\nfonts, present, tour`), exposed as 2 meta-tools + one executor per domain, each input validated\nagainst its own schema. **There is no confirmation gate \u2014 actions happen immediately, by product\ndecision.**\n\n## 17. Platform\n\n- **Accounts**: invite-only (there is **no public sign-up**; Google sign-in on an unknown email is\n rejected), password + Google, password reset, device registration/claim/keys, a CLI device-code\n flow, and an offline-tolerance contract \u2014 only an explicit 401/403 signs you out.\n- **Plans**: `free`, `standard` (shown as **"Pro"**), `pro` (shown as **"Team"**) \u2014 17 feature flags,\n quotas on compute/storage/egress/video, seats, invites, orgs. Your effective plan is the best across\n every org you belong to.\n- **Missions, cron & unattended**: schedule agent turns that run with nobody present, with catch-up\n after downtime, background tasks and structured reports.\n- **Settings**: **23 sections, ~300 controls** \u2014 appearance, editor, general, runners, agent, voice,\n image editing, search, extensions, background tasks, account, team, sync, privacy, file drops,\n remote desktop, permissions, hooks (9 events), env, about, shortcuts (31 rebindable commands).\n- **Theming**: DTCG design tokens, theme packs with **8 independently switchable facets** (colors,\n shape, fonts, background, decorations, sounds, intro, extraCss) and a 3-entry-point **Safe Mode** to\n recover from a bad pack.\n- **Accessibility & motion**: light/dark \xD7 comfortable/compact density throughout, reduced-motion\n and sound-mute as separate switches, and labelled roles on every interactive element. Animation\n is a product requirement, not a preference \u2014 every show/hide, open/close and surface switch is\n animated (140\u2013220ms), and native unstyled controls are not used.\n- **OS permissions**: 7 tracked (microphone, camera, screen recording, full-disk access, accessibility,\n notifications, local network) with per-platform availability; three require a relaunch after grant.\n- **Observability**: crash/error reporting from 6 producers with separate crash and telemetry consent\n (**opt-out \u2014 on unless explicitly disabled**), fingerprinting and grouping, an error inspector, an\n alerting bridge, in-app issue submission, and a GDPR export-and-erase path.\n- **The always-on background service**: the desktop app *is* the daemon (merged process); the slim\n rdesk and mesh builds and the headless CLI keep the classic separate-service model, installed via\n launchd / systemd / Windows services. It self-heals silently, degrades from GUI to headless rather\n than dying, and only one daemon owns a machine at a time. This is why clipboard sync, remote\n access, scheduled turns and the \u2325Space HUD keep working with no app window open.\n- **Connectivity**: the relay is stateless and queues nothing \u2014 a dropped socket re-bootstraps rather\n than replaying. In-flight turns survive a disconnect and stay interruptible.\n- **Updates**: check \u2192 download \u2192 stage \u2192 apply \u2192 relaunch, with an external reaper, log rotation on\n version change and a What\'s New screen. System events (sleep/wake, lock, AC/battery, clock jump,\n displays, interfaces) drive recovery.\n\n## 18. Deliberately NOT built \u2014 do not promise these\n\n- **Create multiplayer co-editing / comments-in-Create** \u2014 deferred; the stores exist but are unwired.\n- **Marketplace** as a product \u2014 brainstorm only.\n- **Team chat**: voice messages, async video clips, keyword alerts, scheduled send, `/remind`, saved\n messages, guest/single-channel access, outgoing webhooks, AI catch-up/digest, public communities,\n nested threads, Block Kit, workflow builder, read receipts, E2E encryption for team chat.\n- **Create/Gamma parity gaps**: todo blocks, GIF/QR/illustrations, media library, form embeds, Google\n Slides export, theme gallery picker, share analytics, public generate API, custom domains, SEO\n toggle, password-protected publish, sites manager.\n- **Hosting**: the managed DB/auth/storage layer, secrets manager, git sync + 1-click Publish.\n- **Mobile**: file browsing, in-app browser, hosting an agent, rendering canvas/surface blocks.\n- **Web app**: undo-delete, local engines, runner configs, the errors panel, open/save-to-code for\n remote hosts.\n- **Mesh**: there is no VPN tunnel a user can turn on yet \u2014 PKI, protocol and data plane are built,\n route execution is not a shipped user feature. No Windows/macOS netd hosting.\n- **Other**: Homebrew formula, Chrome Web Store listing (the extension installs unpacked), Deepgram\n voice, Office (ZetaOffice) editing, AWS Bedrock and Google Vertex gateway routes, VNC clipboard,\n Wayland-specific clipboard handling, RN live widget tree (blocked upstream), the voice tutorial.\n\n## 19. Honest caveats\n\n- **Entitlements are almost entirely unenforced.** Only `plugins` is gated in production, and the\n desktop client is never gated at all. Both the API and the relay **fail open** on billing errors.\n- **Realtime voice has never run live against a provider** \u2014 treat first-run voice as unproven.\n- **HeyGen avatar video has no key configured** as shipped.\n- **The self-hosted web stack has no per-user data isolation** \u2014 auth there is a login wall over one\n shared workspace root.\n- `standard` = "Pro" and `pro` = "Team" \u2014 the plan id and the display name are inverted.\n';
33294
+ }
33295
+ });
33296
+
33297
+ // ../../packages/agent-core/dist/capabilities-tools.js
33298
+ import { tool as tool17 } from "@anthropic-ai/claude-agent-sdk";
33299
+ function capabilitySections(doc = CAPABILITIES_DOC) {
33300
+ const out = [];
33301
+ const re = /^## (\d+)\. (.+)$/gm;
33302
+ const heads = [];
33303
+ for (let m = re.exec(doc); m; m = re.exec(doc)) {
33304
+ heads.push({ n: Number(m[1]), title: m[2].trim(), at: m.index, end: re.lastIndex });
33305
+ }
33306
+ for (let i = 0; i < heads.length; i++) {
33307
+ const h = heads[i];
33308
+ const stop2 = i + 1 < heads.length ? heads[i + 1].at : doc.length;
33309
+ out.push({ n: h.n, title: h.title, body: doc.slice(h.at, stop2).trimEnd() });
33310
+ }
33311
+ return out;
33312
+ }
33313
+ function findSections(query2, doc = CAPABILITIES_DOC) {
33314
+ const secs = capabilitySections(doc);
33315
+ const q = query2.trim().toLowerCase();
33316
+ if (!q)
33317
+ return [];
33318
+ const asNum = Number(q.replace(/^§/, ""));
33319
+ if (Number.isInteger(asNum) && asNum > 0) {
33320
+ const hit = secs.find((s) => s.n === asNum);
33321
+ if (hit)
33322
+ return [hit];
33323
+ }
33324
+ const byTitle = secs.filter((s) => s.title.toLowerCase().includes(q));
33325
+ if (byTitle.length > 0)
33326
+ return byTitle;
33327
+ return secs.filter((s) => s.body.toLowerCase().includes(q));
33328
+ }
33329
+ function buildCapabilitiesTools() {
33330
+ const index = capabilitySections().map((s) => `${s.n}. ${s.title}`).join(" \xB7 ");
33331
+ return [
33332
+ tool17("tesseract_capabilities", prompt("tool.capabilities.tesseract_capabilities", { sections: index }), {
33333
+ section: external_exports.string().optional().describe('Optional filter: a section number ("12"), a title word ("voice", "vault", "media"), or any keyword to search the body ("rdesk", "clipboard", "figma"). Omit for the full map.')
33334
+ }, async (args) => {
33335
+ const q = args?.section?.trim();
33336
+ if (!q)
33337
+ return text10(CAPABILITIES_DOC);
33338
+ const hits = findSections(q);
33339
+ if (hits.length === 0) {
33340
+ return text10(`No section of Tesseract's capability map matches "${q}". Sections: ${index}. Call tesseract_capabilities with no arguments for the whole map.`);
33341
+ }
33342
+ return text10(hits.map((s) => s.body).join("\n\n"));
33343
+ })
33344
+ ];
33345
+ }
33346
+ var text10;
33347
+ var init_capabilities_tools = __esm({
33348
+ "../../packages/agent-core/dist/capabilities-tools.js"() {
33349
+ "use strict";
33350
+ init_zod();
33351
+ init_prompts();
33352
+ init_capabilities_doc_generated();
33353
+ text10 = (t) => ({ content: [{ type: "text", text: t }] });
33354
+ }
33355
+ });
33356
+
32957
33357
  // ../../packages/serpapi-core/dist/types.js
32958
33358
  var init_types3 = __esm({
32959
33359
  "../../packages/serpapi-core/dist/types.js"() {
@@ -33480,8 +33880,8 @@ function isAbort(e) {
33480
33880
  const name = e?.name ?? "";
33481
33881
  return name === "AbortError" || name === "TimeoutError" || /aborted|abort/i.test(String(e?.message ?? ""));
33482
33882
  }
33483
- function redactSecrets(text12, secret) {
33484
- let out = text12.replace(/((?:api_key|apikey|token|access_token|key)=)[^&\s"'<>]{6,}/gi, "$1***");
33883
+ function redactSecrets(text13, secret) {
33884
+ let out = text13.replace(/((?:api_key|apikey|token|access_token|key)=)[^&\s"'<>]{6,}/gi, "$1***");
33485
33885
  if (secret && secret.length >= 8)
33486
33886
  out = out.split(secret).join("***");
33487
33887
  return out;
@@ -33588,13 +33988,13 @@ var init_client = __esm({
33588
33988
  */
33589
33989
  async searchMarkdown(engine, params, opts = {}) {
33590
33990
  const url2 = await this.buildUrl(engine, params, { ...opts, output: "md" });
33591
- const { res, text: text12, started: started2 } = await this.fetchWithRetry(url2, engine, opts, true);
33991
+ const { res, text: text13, started: started2 } = await this.fetchWithRetry(url2, engine, opts, true);
33592
33992
  this.opts.onUsage?.({ engine, cached: false, billed: true, ms: Date.now() - started2, status: res.status });
33593
- const asError = messageFromBody(text12) && redactSecrets(messageFromBody(text12), (await this.creds().catch(() => void 0))?.apiKey);
33594
- if (asError && text12.trimStart().startsWith("{")) {
33993
+ const asError = messageFromBody(text13) && redactSecrets(messageFromBody(text13), (await this.creds().catch(() => void 0))?.apiKey);
33994
+ if (asError && text13.trimStart().startsWith("{")) {
33595
33995
  throw new SerpApiError(asError, classifySerpError(res.status, asError), { status: res.status, engine });
33596
33996
  }
33597
- return { markdown: text12 };
33997
+ return { markdown: text13 };
33598
33998
  }
33599
33999
  /**
33600
34000
  * Follow a fully-formed SerpApi URL — specifically `serpapi_pagination.next`.
@@ -33632,8 +34032,8 @@ var init_client = __esm({
33632
34032
  const u = _SerpClient.join(baseUrl ?? DEFAULT_BASE_URL, "locations.json");
33633
34033
  u.searchParams.set("q", q);
33634
34034
  u.searchParams.set("limit", String(Math.min(Math.max(1, limit), 10)));
33635
- const { text: text12 } = await this.fetchWithRetry(u.toString(), "locations", {}, false);
33636
- const body = JSON.parse(text12 || "[]");
34035
+ const { text: text13 } = await this.fetchWithRetry(u.toString(), "locations", {}, false);
34036
+ const body = JSON.parse(text13 || "[]");
33637
34037
  return Array.isArray(body) ? body : [];
33638
34038
  }
33639
34039
  /** Retrieve a previously-run search by `search_metadata.id`. 31-day retention; also how you
@@ -33657,8 +34057,8 @@ var init_client = __esm({
33657
34057
  throw new SerpApiError(`Invalid search id "${searchId}".`, "bad_request");
33658
34058
  const u = _SerpClient.join(baseUrl ?? DEFAULT_BASE_URL, `searches/${safe2}.md`);
33659
34059
  u.searchParams.set("api_key", apiKey);
33660
- const { text: text12 } = await this.fetchWithRetry(u.toString(), "archive", {}, false);
33661
- return { markdown: text12 };
34060
+ const { text: text13 } = await this.fetchWithRetry(u.toString(), "archive", {}, false);
34061
+ return { markdown: text13 };
33662
34062
  }
33663
34063
  /** Upload an image (≤500 KB, JPG/PNG/WebP) for use with Lens / reverse-image engines.
33664
34064
  * The returned `image_id` expires after ~10 minutes. */
@@ -33757,9 +34157,9 @@ var init_client = __esm({
33757
34157
  this.opts.onUsage?.({ engine, cached: false, billed, ms: Date.now() - started2, error: msg });
33758
34158
  throw lastErr;
33759
34159
  }
33760
- const text12 = await res.text();
34160
+ const text13 = await res.text();
33761
34161
  if (!res.ok) {
33762
- const bodyMsg = redactSecrets(messageFromBody(text12), secret);
34162
+ const bodyMsg = redactSecrets(messageFromBody(text13), secret);
33763
34163
  const err2 = new SerpApiError(bodyMsg || `SerpApi ${engine} failed (${res.status}).`, classifySerpError(res.status, bodyMsg), { status: res.status, engine });
33764
34164
  if (err2.retryable && attempt < maxRetries && Date.now() < deadline) {
33765
34165
  lastErr = err2;
@@ -33769,7 +34169,7 @@ var init_client = __esm({
33769
34169
  this.opts.onUsage?.({ engine, cached: false, billed, ms: Date.now() - started2, status: res.status, error: bodyMsg.slice(0, 200) });
33770
34170
  throw err2;
33771
34171
  }
33772
- return { res, text: text12, started: started2 };
34172
+ return { res, text: text13, started: started2 };
33773
34173
  }
33774
34174
  throw lastErr ?? new SerpApiError(`SerpApi ${engine} failed.`, "unknown", { engine });
33775
34175
  }
@@ -33786,10 +34186,10 @@ var init_client = __esm({
33786
34186
  if (hit)
33787
34187
  this.cache.delete(key2);
33788
34188
  }
33789
- const { res, text: text12, started: started2 } = await this.fetchWithRetry(url2, engine, opts, billed);
34189
+ const { res, text: text13, started: started2 } = await this.fetchWithRetry(url2, engine, opts, billed);
33790
34190
  let body;
33791
34191
  try {
33792
- body = JSON.parse(text12);
34192
+ body = JSON.parse(text13);
33793
34193
  } catch {
33794
34194
  throw new SerpApiError(`SerpApi ${engine} returned a non-JSON body.`, "unknown", { status: res.status, engine });
33795
34195
  }
@@ -34505,7 +34905,7 @@ var serpapi_tools_exports = {};
34505
34905
  __export(serpapi_tools_exports, {
34506
34906
  buildSerpTools: () => buildSerpTools
34507
34907
  });
34508
- import { tool as tool17 } from "@anthropic-ai/claude-agent-sdk";
34908
+ import { tool as tool18 } from "@anthropic-ai/claude-agent-sdk";
34509
34909
  import { openSync as openSync3, readSync as readSync2, closeSync as closeSync3, statSync as statSync3, readFileSync as readFileSync6 } from "node:fs";
34510
34910
  import { basename as basename2 } from "node:path";
34511
34911
  function imageKind(path6) {
@@ -34539,14 +34939,14 @@ function catalogOnce() {
34539
34939
  }
34540
34940
  function buildSerpTools(deps) {
34541
34941
  const tools = [];
34542
- tools.push(tool17("serp_find", 'Search the SerpApi catalog of 121 search engines to find which one answers a question. Describe what you want in plain language ("hotel reviews", "who is advertising against my brand", "stock price") \u2014 engine ids are not guessable, so START HERE unless you already know the engine. Returns ranked engines with the family tool that runs them and their required parameters.', {
34942
+ tools.push(tool18("serp_find", 'Search the SerpApi catalog of 121 search engines to find which one answers a question. Describe what you want in plain language ("hotel reviews", "who is advertising against my brand", "stock price") \u2014 engine ids are not guessable, so START HERE unless you already know the engine. Returns ranked engines with the family tool that runs them and their required parameters.', {
34543
34943
  query: external_exports.string().describe("What you are trying to find out, in plain language."),
34544
34944
  family: external_exports.string().optional().describe(`Restrict to one family: ${Object.keys(SERP_FAMILIES).join(", ")}.`),
34545
34945
  limit: external_exports.number().int().min(1).max(30).optional().describe("How many engines to return (default 8).")
34546
34946
  }, async (a) => {
34547
34947
  const { query: query2, family, limit } = a ?? {};
34548
34948
  if (family && !(family in SERP_FAMILIES)) {
34549
- return text10(`Unknown family "${family}". Valid families: ${Object.keys(SERP_FAMILIES).join(", ")}.`, true);
34949
+ return text11(`Unknown family "${family}". Valid families: ${Object.keys(SERP_FAMILIES).join(", ")}.`, true);
34550
34950
  }
34551
34951
  const r = await findEngines(query2 ?? "", catalogOnce().filter((e) => !UNAVAILABLE.has(e.id)), {
34552
34952
  limit,
@@ -34561,7 +34961,7 @@ function buildSerpTools(deps) {
34561
34961
  next: "Call serp_describe with an engine id for its full parameter list, then run it with the named family tool."
34562
34962
  });
34563
34963
  }));
34564
- tools.push(tool17("serp_describe", "Describe one or more SerpApi engines in full: every parameter with its meaning, which are required, allowed values, how the engine paginates, and which result keys it returns. Call this before running an engine whose parameters you are unsure about.", {
34964
+ tools.push(tool18("serp_describe", "Describe one or more SerpApi engines in full: every parameter with its meaning, which are required, allowed values, how the engine paginates, and which result keys it returns. Call this before running an engine whose parameters you are unsure about.", {
34565
34965
  engines: external_exports.array(external_exports.string()).min(1).max(MAX_DESCRIBE_ENGINES).describe(`Engine ids, e.g. ["google_hotels", "google_maps"]. At most ${MAX_DESCRIBE_ENGINES} per call \u2014 a full schema is thousands of tokens, so ask for the ones you are actually about to use.`),
34566
34966
  group: external_exports.string().optional().describe('Only describe parameters in this registry group (e.g. "search_query", "localization", "advanced_filters"), to keep the answer short.')
34567
34967
  }, async (a) => {
@@ -34606,10 +35006,10 @@ function buildSerpTools(deps) {
34606
35006
  }
34607
35007
  return json2(out);
34608
35008
  }));
34609
- tools.push(tool17("serp_account", "Check that SerpApi is configured and how many searches remain this month. This call is free and never consumes a search credit. Call it before a long series of searches, or when a search fails with a quota error.", {}, async () => {
35009
+ tools.push(tool18("serp_account", "Check that SerpApi is configured and how many searches remain this month. This call is free and never consumes a search credit. Call it before a long series of searches, or when a search fails with a quota error.", {}, async () => {
34610
35010
  const st = await deps.status();
34611
35011
  if (!st.configured)
34612
- return text10(NO_KEY, true);
35012
+ return text11(NO_KEY, true);
34613
35013
  try {
34614
35014
  const acct = await deps.client.account();
34615
35015
  return json2({
@@ -34625,10 +35025,10 @@ function buildSerpTools(deps) {
34625
35025
  ...st.session ? { this_session: st.session } : {}
34626
35026
  });
34627
35027
  } catch (e) {
34628
- return text10(`Could not read the SerpApi account: ${e instanceof Error ? e.message : String(e)}`, true);
35028
+ return text11(`Could not read the SerpApi account: ${e instanceof Error ? e.message : String(e)}`, true);
34629
35029
  }
34630
35030
  }));
34631
- tools.push(tool17("serp_locations", 'Resolve a place name to the canonical `location` string Google\'s engines expect (e.g. "Austin" \u2192 "Austin, Texas, United States"). Free \u2014 it does not consume a search credit. Use it before passing `location` to a Google engine; an unrecognised location is silently ignored and you get results for the wrong place.', {
35031
+ tools.push(tool18("serp_locations", 'Resolve a place name to the canonical `location` string Google\'s engines expect (e.g. "Austin" \u2192 "Austin, Texas, United States"). Free \u2014 it does not consume a search credit. Use it before passing `location` to a Google engine; an unrecognised location is silently ignored and you get results for the wrong place.', {
34632
35032
  query: external_exports.string().describe('Place name to resolve, e.g. "Chisinau" or "Austin".'),
34633
35033
  limit: external_exports.number().int().min(1).max(10).optional().describe("Maximum matches (SerpApi caps this at 10).")
34634
35034
  }, async (a) => {
@@ -34637,10 +35037,10 @@ function buildSerpTools(deps) {
34637
35037
  const hits = await deps.client.locations(query2, limit ?? 5);
34638
35038
  return json2(hits.map((h) => ({ canonical_name: h.canonical_name, country: h.country_code, type: h.target_type, reach: h.reach })));
34639
35039
  } catch (e) {
34640
- return text10(`Location lookup failed: ${e instanceof Error ? e.message : String(e)}`, true);
35040
+ return text11(`Location lookup failed: ${e instanceof Error ? e.message : String(e)}`, true);
34641
35041
  }
34642
35042
  }));
34643
- tools.push(tool17("serp_archive", "Re-read a search that was already run, by its `search_id` (returned as `_search_id` on every result, and by a `submit_async` submission). FREE \u2014 retrieval never re-runs the search and never spends a credit, and SerpApi keeps results for 31 days. Use it to collect an async submission, to re-read a large result you truncated, or to get the markdown rendering of something you already fetched as JSON \u2014 all without paying again.", {
35043
+ tools.push(tool18("serp_archive", "Re-read a search that was already run, by its `search_id` (returned as `_search_id` on every result, and by a `submit_async` submission). FREE \u2014 retrieval never re-runs the search and never spends a credit, and SerpApi keeps results for 31 days. Use it to collect an async submission, to re-read a large result you truncated, or to get the markdown rendering of something you already fetched as JSON \u2014 all without paying again.", {
34644
35044
  search_id: external_exports.string().describe("The id from `_search_id`, or from a `submit_async` submission."),
34645
35045
  format: external_exports.enum(["json", "markdown"]).optional().describe("`json` (default) is structured; `markdown` is roughly half the tokens but carries no chaining tokens."),
34646
35046
  max_results: external_exports.number().int().min(1).max(100).optional().describe("How many items to keep per result list before truncating (default 10).")
@@ -34648,50 +35048,50 @@ function buildSerpTools(deps) {
34648
35048
  const { search_id, format, max_results } = a ?? {};
34649
35049
  const st = await deps.status();
34650
35050
  if (!st.configured)
34651
- return text10(NO_KEY, true);
35051
+ return text11(NO_KEY, true);
34652
35052
  try {
34653
35053
  if (format === "markdown") {
34654
35054
  const { markdown } = await deps.client.archiveMarkdown(search_id);
34655
- return text10(markdown);
35055
+ return text11(markdown);
34656
35056
  }
34657
35057
  const body = await deps.client.archive(search_id);
34658
35058
  const status2 = body.search_metadata?.status;
34659
35059
  if (status2 && status2 !== "Success") {
34660
- return text10(`Search ${search_id} is ${status2}. This call was free \u2014 call serp_archive again in a moment.`);
35060
+ return text11(`Search ${search_id} is ${status2}. This call was free \u2014 call serp_archive again in a moment.`);
34661
35061
  }
34662
35062
  return json2(compactResponse(body, { maxResults: max_results ?? 10 }));
34663
35063
  } catch (e) {
34664
- return text10(`Could not read search ${search_id}: ${e instanceof Error ? e.message : String(e)}`, true);
35064
+ return text11(`Could not read search ${search_id}: ${e instanceof Error ? e.message : String(e)}`, true);
34665
35065
  }
34666
35066
  }));
34667
- tools.push(tool17("serp_upload_image", "Upload a local image and get back an `image_id` for the engines that search BY an image rather than by text \u2014 `google_lens`, `google_reverse_image`, `bing_reverse_image`, `yandex_images`. Free; it spends no search credit. The id expires after about ten minutes, so upload immediately before the search that uses it. SerpApi accepts JPG, PNG and WebP up to 500 KB.", {
35067
+ tools.push(tool18("serp_upload_image", "Upload a local image and get back an `image_id` for the engines that search BY an image rather than by text \u2014 `google_lens`, `google_reverse_image`, `bing_reverse_image`, `yandex_images`. Free; it spends no search credit. The id expires after about ten minutes, so upload immediately before the search that uses it. SerpApi accepts JPG, PNG and WebP up to 500 KB.", {
34668
35068
  path: external_exports.string().describe("Absolute path to the image file on this machine.")
34669
35069
  }, async (a) => {
34670
35070
  const { path: path6 } = a ?? {};
34671
35071
  const st = await deps.status();
34672
35072
  if (!st.configured)
34673
- return text10(NO_KEY, true);
35073
+ return text11(NO_KEY, true);
34674
35074
  let bytes3;
34675
35075
  try {
34676
35076
  const size = statSync3(path6).size;
34677
35077
  if (size === 0)
34678
- return text10(`${path6} is empty.`, true);
35078
+ return text11(`${path6} is empty.`, true);
34679
35079
  if (size > MAX_IMAGE_BYTES) {
34680
- return text10(`${path6} is ${Math.round(size / 1024)} KB; SerpApi accepts images up to 500 KB. Resize it first.`, true);
35080
+ return text11(`${path6} is ${Math.round(size / 1024)} KB; SerpApi accepts images up to 500 KB. Resize it first.`, true);
34681
35081
  }
34682
35082
  const kind = imageKind(path6);
34683
35083
  if (!kind)
34684
- return text10(`${path6} is not a JPEG, PNG or WebP image \u2014 those are the formats SerpApi accepts, and this tool only uploads images.`, true);
35084
+ return text11(`${path6} is not a JPEG, PNG or WebP image \u2014 those are the formats SerpApi accepts, and this tool only uploads images.`, true);
34685
35085
  bytes3 = readFileSync6(path6);
34686
35086
  } catch (e) {
34687
- return text10(`Could not read ${path6}: ${e instanceof Error ? e.message : String(e)}`, true);
35087
+ return text11(`Could not read ${path6}: ${e instanceof Error ? e.message : String(e)}`, true);
34688
35088
  }
34689
35089
  try {
34690
35090
  const { image_id } = await deps.client.uploadImage(bytes3, basename2(path6));
34691
- return text10(`image_id: ${image_id}
35091
+ return text11(`image_id: ${image_id}
34692
35092
  Pass it as the image parameter of a reverse-image engine (google_lens uses \`url\`; call serp_describe for the exact field). It expires in about ten minutes.`);
34693
35093
  } catch (e) {
34694
- return text10(`Image upload failed: ${e instanceof Error ? e.message : String(e)}`, true);
35094
+ return text11(`Image upload failed: ${e instanceof Error ? e.message : String(e)}`, true);
34695
35095
  }
34696
35096
  }));
34697
35097
  for (const [family, info] of Object.entries(SERP_FAMILIES)) {
@@ -34701,7 +35101,7 @@ Pass it as the image parameter of a reverse-image engine (google_lens uses \`url
34701
35101
  const ids = [...engines2];
34702
35102
  const listing = engines2.map((id) => `${id} \u2014 ${ENGINE_INFO[id]?.purpose ?? ""}`).join("; ");
34703
35103
  const trapped = engines2.filter((id) => ENGINE_INFO[id]?.traps?.length);
34704
- tools.push(tool17(info.tool, `${info.blurb} Pick an \`engine\` and pass its \`params\` (use serp_describe for the exact fields, or serp_find if you are not sure which engine). Each call spends one paid search credit. Engines: ${listing}${trapped.length ? ` \u2014 QUIRKS (serp_describe first): ${trapped.join(", ")}. Some reject the call; others accept a parameter and ignore it, returning confident results for the wrong place.` : ""}`, {
35104
+ tools.push(tool18(info.tool, `${info.blurb} Pick an \`engine\` and pass its \`params\` (use serp_describe for the exact fields, or serp_find if you are not sure which engine). Each call spends one paid search credit. Engines: ${listing}${trapped.length ? ` \u2014 QUIRKS (serp_describe first): ${trapped.join(", ")}. Some reject the call; others accept a parameter and ignore it, returning confident results for the wrong place.` : ""}`, {
34705
35105
  engine: external_exports.enum(ids).describe("Which engine to run."),
34706
35106
  params: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("The engine's own parameters. Names differ per engine \u2014 Yahoo uses `p`, Yandex `text`, Naver `query`, Amazon `k`, eBay `_nkw`. Call serp_describe if unsure."),
34707
35107
  ...PAGE_ARGS,
@@ -34716,13 +35116,13 @@ Pass it as the image parameter of a reverse-image engine (google_lens uses \`url
34716
35116
  async function runEngine(deps, args) {
34717
35117
  const st = await deps.status();
34718
35118
  if (!st.configured)
34719
- return text10(NO_KEY, true);
35119
+ return text11(NO_KEY, true);
34720
35120
  const spec = SERP_SPEC.engines[args.engine];
34721
35121
  if (!spec)
34722
- return text10(`Unknown engine "${args.engine}". Call serp_find to locate the right one.`, true);
35122
+ return text11(`Unknown engine "${args.engine}". Call serp_find to locate the right one.`, true);
34723
35123
  const info = ENGINE_INFO[args.engine];
34724
35124
  if (info?.status) {
34725
- return text10(`\`${args.engine}\` is ${info.status.state} and cannot be used: ${info.status.detail} No credit was spent. ${info.purpose}`, true);
35125
+ return text11(`\`${args.engine}\` is ${info.status.state} and cannot be used: ${info.status.detail} No credit was spent. ${info.purpose}`, true);
34726
35126
  }
34727
35127
  const strategy = pageStrategy(spec);
34728
35128
  const rawParams = { ...args.params ?? {} };
@@ -34737,7 +35137,7 @@ async function runEngine(deps, args) {
34737
35137
  v.warnings.push(`Both \`page_size\` (${args.page_size}) and \`${sizeParam}\` (${explicitSize}) were given; \`page_size\` wins.`);
34738
35138
  }
34739
35139
  if (!v.ok) {
34740
- return text10(`Cannot run \`${args.engine}\` \u2014 no credit spent.
35140
+ return text11(`Cannot run \`${args.engine}\` \u2014 no credit spent.
34741
35141
  ${v.errors.map((e) => `\u2022 ${e}`).join("\n")}
34742
35142
 
34743
35143
  Call serp_describe({engines:["${args.engine}"]}) for the full parameter list.`, true);
@@ -34755,8 +35155,8 @@ Call serp_describe({engines:["${args.engine}"]}) for the full parameter list.`,
34755
35155
  const submitted = await deps.client.search(args.engine, { ...v.params, ...paging }, opts);
34756
35156
  const id = submitted.search_metadata?.id;
34757
35157
  if (!id)
34758
- return text10(`\`${args.engine}\` was submitted but SerpApi returned no search id, so the result cannot be collected. Re-run it without submit_async.`, true);
34759
- return text10(`Submitted \`${args.engine}\` \u2014 search_id: ${id}
35158
+ return text11(`\`${args.engine}\` was submitted but SerpApi returned no search id, so the result cannot be collected. Re-run it without submit_async.`, true);
35159
+ return text11(`Submitted \`${args.engine}\` \u2014 search_id: ${id}
34760
35160
  The credit is already spent. Collect it with serp_archive({ search_id: "${id}" }); that call is free, so retry it until the status is Success.`);
34761
35161
  }
34762
35162
  if (args.format === "markdown") {
@@ -34764,7 +35164,7 @@ The credit is already spent. Collect it with serp_archive({ search_id: "${id}" }
34764
35164
  const warn = v.warnings.length ? `${v.warnings.map((w) => `\u26A0 ${w}`).join("\n")}
34765
35165
 
34766
35166
  ` : "";
34767
- return text10(`${warn}${markdown}`);
35167
+ return text11(`${warn}${markdown}`);
34768
35168
  }
34769
35169
  const body = await deps.client.search(args.engine, { ...v.params, ...paging }, opts);
34770
35170
  const compact2 = compactResponse(body, { maxResults: args.max_results ?? 10 });
@@ -34775,27 +35175,27 @@ The credit is already spent. Collect it with serp_archive({ search_id: "${id}" }
34775
35175
  if (body._page?.hasNext && supportsPaging(spec)) {
34776
35176
  parts.push(body._page.cursor ? `More results available \u2014 call again with cursor: "${body._page.cursor}".` : `More results available \u2014 call again with page: ${(args.page ?? 1) + 1}.`);
34777
35177
  }
34778
- return text10(parts.join("\n\n"));
35178
+ return text11(parts.join("\n\n"));
34779
35179
  } catch (e) {
34780
35180
  const msg = e instanceof Error ? e.message : String(e);
34781
- return text10(`\`${args.engine}\` failed: ${msg}`, true);
35181
+ return text11(`\`${args.engine}\` failed: ${msg}`, true);
34782
35182
  }
34783
35183
  }
34784
- var text10, json2, UNAVAILABLE, MAX_DESCRIBE_ENGINES, MAX_PARAM_DESC, clip, MAX_IMAGE_BYTES, NO_KEY, PAGE_ARGS, OUTPUT_ARGS, cachedCatalog, brief;
35184
+ var text11, json2, UNAVAILABLE, MAX_DESCRIBE_ENGINES, MAX_PARAM_DESC, clip, MAX_IMAGE_BYTES, NO_KEY, PAGE_ARGS, OUTPUT_ARGS, cachedCatalog, brief;
34785
35185
  var init_serpapi_tools = __esm({
34786
35186
  "../../packages/agent-core/dist/serpapi/serpapi-tools.js"() {
34787
35187
  "use strict";
34788
35188
  init_zod();
34789
35189
  init_dist4();
34790
- text10 = (t, isError = false) => ({
35190
+ text11 = (t, isError = false) => ({
34791
35191
  content: [{ type: "text", text: t }],
34792
35192
  ...isError ? { isError: true } : {}
34793
35193
  });
34794
- json2 = (v) => text10(JSON.stringify(v, null, 2));
35194
+ json2 = (v) => text11(JSON.stringify(v, null, 2));
34795
35195
  UNAVAILABLE = new Set(UNAVAILABLE_ENGINES);
34796
35196
  MAX_DESCRIBE_ENGINES = 3;
34797
35197
  MAX_PARAM_DESC = 400;
34798
- clip = (text12, full) => !full && text12 && text12.length > MAX_PARAM_DESC ? `${text12.slice(0, MAX_PARAM_DESC)}\u2026 (truncated \u2014 ask for this engine on its own for the full text)` : text12;
35198
+ clip = (text13, full) => !full && text13 && text13.length > MAX_PARAM_DESC ? `${text13.slice(0, MAX_PARAM_DESC)}\u2026 (truncated \u2014 ask for this engine on its own for the full text)` : text13;
34799
35199
  MAX_IMAGE_BYTES = 500 * 1024;
34800
35200
  NO_KEY = "SerpApi is not configured. Ask the user to add a SerpApi key in Settings \u2192 Search, or to sign in to use the bundled free tier.";
34801
35201
  PAGE_ARGS = {
@@ -34822,13 +35222,13 @@ var init_serpapi_tools = __esm({
34822
35222
  });
34823
35223
 
34824
35224
  // ../../packages/agent-core/dist/report-tools.js
34825
- import { tool as tool18 } from "@anthropic-ai/claude-agent-sdk";
35225
+ import { tool as tool19 } from "@anthropic-ai/claude-agent-sdk";
34826
35226
  function slug(s) {
34827
35227
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "mission";
34828
35228
  }
34829
35229
  function buildReportTools(deps) {
34830
35230
  return [
34831
- tool18("emit_report", prompt("tool.report.emit_report"), {
35231
+ tool19("emit_report", prompt("tool.report.emit_report"), {
34832
35232
  id: external_exports.string().optional().describe("Stable report id to UPDATE an existing report; omit on the first call to create one."),
34833
35233
  playbookId: external_exports.string().describe("The playbook id this report belongs to."),
34834
35234
  title: external_exports.string().describe("Report title (usually the playbook name)."),
@@ -34882,10 +35282,10 @@ var init_report_tools = __esm({
34882
35282
  });
34883
35283
 
34884
35284
  // ../../packages/agent-core/dist/interactive-ui-tools.js
34885
- import { tool as tool19 } from "@anthropic-ai/claude-agent-sdk";
35285
+ import { tool as tool20 } from "@anthropic-ai/claude-agent-sdk";
34886
35286
  function buildInteractiveUiTools(deps) {
34887
35287
  return [
34888
- tool19("ask_form", prompt("tool.interactive-ui.ask_form"), {
35288
+ tool20("ask_form", prompt("tool.interactive-ui.ask_form"), {
34889
35289
  title: external_exports.string().describe("Form heading (plain language)."),
34890
35290
  description: external_exports.string().optional().describe("Short explanation shown above the fields."),
34891
35291
  submitLabel: external_exports.string().optional().describe('Submit button label (default "Submit").'),
@@ -34899,7 +35299,7 @@ function buildInteractiveUiTools(deps) {
34899
35299
  return { content: [{ type: "text", text: `The user submitted the form:
34900
35300
  ${JSON.stringify(res.values ?? {}, null, 2)}` }] };
34901
35301
  }),
34902
- tool19("present_choices", prompt("tool.interactive-ui.present_choices"), {
35302
+ tool20("present_choices", prompt("tool.interactive-ui.present_choices"), {
34903
35303
  title: external_exports.string().describe("The question / heading."),
34904
35304
  description: external_exports.string().optional(),
34905
35305
  options: external_exports.array(choiceOption).min(1),
@@ -34912,7 +35312,7 @@ ${JSON.stringify(res.values ?? {}, null, 2)}` }] };
34912
35312
  return { content: [{ type: "text", text: "The user cancelled the choice (nothing selected)." }] };
34913
35313
  return { content: [{ type: "text", text: `The user selected: ${JSON.stringify(res.selected ?? [])}` }] };
34914
35314
  }),
34915
- tool19("update_progress", prompt("tool.interactive-ui.update_progress"), {
35315
+ tool20("update_progress", prompt("tool.interactive-ui.update_progress"), {
34916
35316
  stages: external_exports.array(external_exports.object({
34917
35317
  label: external_exports.string(),
34918
35318
  status: external_exports.enum(["pending", "active", "done"])
@@ -35037,8 +35437,8 @@ async function exportSession(sessionId, fromCwd) {
35037
35437
  function escapeRe(s) {
35038
35438
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
35039
35439
  }
35040
- function rekey(text12, fromCwd, toCwd) {
35041
- return text12.replace(new RegExp(escapeRe(fromCwd) + '(?=["/\\\\]|$)', "g"), () => toCwd);
35440
+ function rekey(text13, fromCwd, toCwd) {
35441
+ return text13.replace(new RegExp(escapeRe(fromCwd) + '(?=["/\\\\]|$)', "g"), () => toCwd);
35042
35442
  }
35043
35443
  async function importSession(exp, toCwd) {
35044
35444
  const destDir = sessionDir(toCwd);
@@ -35311,13 +35711,13 @@ var init_narrator = __esm({
35311
35711
  prompt("side-llm.narrator.activity", { activity }),
35312
35712
  prompt("side-llm.narrator.ask")
35313
35713
  ].filter(Boolean).join("\n\n");
35314
- const text12 = (await cfg2.complete({ system, prompt: promptText, maxTokens: 48 }))?.trim().replace(/^["']|["']$/g, "");
35315
- if (text12 && text12 !== s.lastText) {
35316
- s.lastText = text12;
35317
- s.log.push(text12);
35714
+ const text13 = (await cfg2.complete({ system, prompt: promptText, maxTokens: 48 }))?.trim().replace(/^["']|["']$/g, "");
35715
+ if (text13 && text13 !== s.lastText) {
35716
+ s.lastText = text13;
35717
+ s.log.push(text13);
35318
35718
  if (s.log.length > LOG_CAP)
35319
35719
  s.log.shift();
35320
- this.emit(id, text12, cfg2.engineLabel);
35720
+ this.emit(id, text13, cfg2.engineLabel);
35321
35721
  }
35322
35722
  } catch {
35323
35723
  } finally {
@@ -35459,15 +35859,15 @@ function recordVerificationDecision(entry) {
35459
35859
  function readUnattendedDecisions(limit = 200, opts) {
35460
35860
  const out = [];
35461
35861
  for (const file2 of [rolledPath(), unattendedLogPath()]) {
35462
- let text12;
35862
+ let text13;
35463
35863
  try {
35464
35864
  if (!existsSync2(file2))
35465
35865
  continue;
35466
- text12 = readFileSync7(file2, "utf8");
35866
+ text13 = readFileSync7(file2, "utf8");
35467
35867
  } catch {
35468
35868
  continue;
35469
35869
  }
35470
- for (const line of text12.split("\n")) {
35870
+ for (const line of text13.split("\n")) {
35471
35871
  if (!line.trim())
35472
35872
  continue;
35473
35873
  try {
@@ -36230,10 +36630,10 @@ function assistantContextOverflow(content, isContextOverflowFn) {
36230
36630
  const blocks = content;
36231
36631
  if (blocks.some((block2) => block2?.type !== "text"))
36232
36632
  return false;
36233
- const text12 = blocks.map((b) => typeof b.text === "string" ? b.text : "").join("\n").trim();
36234
- if (!text12 || text12.length > 400)
36633
+ const text13 = blocks.map((b) => typeof b.text === "string" ? b.text : "").join("\n").trim();
36634
+ if (!text13 || text13.length > 400)
36235
36635
  return false;
36236
- return isContextOverflowFn(text12);
36636
+ return isContextOverflowFn(text13);
36237
36637
  }
36238
36638
  var OVERFLOW_MAX_TRIES, OVERFLOW_COMPACT_MESSAGE, OVERFLOW_RESUME_MESSAGE;
36239
36639
  var init_context_recovery = __esm({
@@ -36343,8 +36743,8 @@ function pendingQueueRows(rows) {
36343
36743
  }
36344
36744
  return keep;
36345
36745
  }
36346
- function stripHostText(text12) {
36347
- return stripRunDirective(text12).trimEnd();
36746
+ function stripHostText(text13) {
36747
+ return stripRunDirective(text13).trimEnd();
36348
36748
  }
36349
36749
  function rejectedByApi(b) {
36350
36750
  if (!b || typeof b !== "object")
@@ -36653,10 +37053,10 @@ function filterHistory(transcript, opts = {}) {
36653
37053
  const parent = resolveParent2(r.parentUuid);
36654
37054
  out.push(JSON.stringify(parent === (r.parentUuid ?? null) ? r : { ...r, parentUuid: parent }));
36655
37055
  }
36656
- const text12 = out.join("\n") + (out.length ? "\n" : "");
37056
+ const text13 = out.join("\n") + (out.length ? "\n" : "");
36657
37057
  stats.rowsOut = out.length;
36658
- stats.bytesOut = Buffer.byteLength(text12, "utf8");
36659
- return { text: text12, stats, spills };
37058
+ stats.bytesOut = Buffer.byteLength(text13, "utf8");
37059
+ return { text: text13, stats, spills };
36660
37060
  }
36661
37061
  var DEFAULT_DROP_TYPES, DEFAULT_KEEP_LAST_TYPES, DEFAULT_KEEP_SYSTEM_SUBTYPES, DEFAULT_KEEP_LAST_ATTACHMENT, DEFAULT_OFFLOAD_RECENT_CALLS, MAX_INLINE_INPUT_BYTES, OFFLOAD_MARK, human;
36662
37062
  var init_history_filter = __esm({
@@ -36689,9 +37089,9 @@ function archiveMetaPath(transcript) {
36689
37089
  function offloadDirFor(transcript) {
36690
37090
  return transcript.replace(/\.jsonl$/, "") + ".offload";
36691
37091
  }
36692
- function contentBytes(text12, liveOnly = true) {
37092
+ function contentBytes(text13, liveOnly = true) {
36693
37093
  let n = 0;
36694
- const all = text12.split("\n");
37094
+ const all = text13.split("\n");
36695
37095
  for (const line of liveOnly ? all.slice(liveRegionStart(all)) : all) {
36696
37096
  if (!line.trim())
36697
37097
  continue;
@@ -36750,9 +37150,9 @@ async function slimTranscriptFile(transcript, opts = {}) {
36750
37150
  const liveText = await readFile4(transcript, "utf8");
36751
37151
  const liveLines = liveText.split("\n").filter((l) => l.trim().length > 0);
36752
37152
  const offloadDir = offloadDirFor(transcript);
36753
- const { text: text12, stats, spills } = filterHistory(liveText, { spillDir: offloadDir, ...opts });
37153
+ const { text: text13, stats, spills } = filterHistory(liveText, { spillDir: offloadDir, ...opts });
36754
37154
  const before = contentBytes(liveText);
36755
- const after = contentBytes(text12);
37155
+ const after = contentBytes(text13);
36756
37156
  const changed = stats.droppedRows > 0 || stats.droppedThinking > 0 || stats.droppedToolUse > 0 || stats.droppedToolResult > 0 || stats.offloaded > 0 || stats.supersededAttachments > 0 || stats.repairedBlocks > 0;
36757
37157
  if (!changed) {
36758
37158
  return { slimmed: false, reason: "nothing to strip", contentBefore: before, contentAfter: after, stats };
@@ -36777,9 +37177,9 @@ async function slimTranscriptFile(transcript, opts = {}) {
36777
37177
  return { slimmed: false, reason: "the transcript changed during the strip \u2014 left as is", contentBefore: before, contentAfter: after, stats };
36778
37178
  }
36779
37179
  const tmp = join11(dirname7(transcript), `.slim-${randomUUID2().slice(0, 8)}.tmp`);
36780
- await writeFile4(tmp, text12, { mode: 384 });
37180
+ await writeFile4(tmp, text13, { mode: 384 });
36781
37181
  await rename(tmp, transcript);
36782
- const outLines = text12.split("\n").filter((l) => l.trim().length > 0);
37182
+ const outLines = text13.split("\n").filter((l) => l.trim().length > 0);
36783
37183
  await writeFile4(archiveMetaPath(transcript), JSON.stringify({ rows: outLines.length, tail: outLines[outLines.length - 1] ?? "" }), { mode: 384 });
36784
37184
  return { slimmed: true, stats, contentBefore: before, contentAfter: after, archive, offloadDir };
36785
37185
  }
@@ -36920,8 +37320,8 @@ async function labelFromTranscript(file2) {
36920
37320
  if (row.type !== "user" && row.message?.role !== "user")
36921
37321
  continue;
36922
37322
  const c = row.message?.content;
36923
- const text12 = typeof c === "string" ? c : Array.isArray(c) ? c.find((b) => b.type === "text")?.text ?? "" : "";
36924
- const s = oneLine(text12);
37323
+ const text13 = typeof c === "string" ? c : Array.isArray(c) ? c.find((b) => b.type === "text")?.text ?? "" : "";
37324
+ const s = oneLine(text13);
36925
37325
  if (s)
36926
37326
  return s;
36927
37327
  }
@@ -37390,33 +37790,33 @@ function annotationIsOrphaned(e, removedUuids) {
37390
37790
  return false;
37391
37791
  return clearDanglingPointers(e, removedUuids) !== e;
37392
37792
  }
37393
- function isPromptEchoOf(e, removedUuids, text12) {
37793
+ function isPromptEchoOf(e, removedUuids, text13) {
37394
37794
  if (e.type !== "last-prompt")
37395
37795
  return false;
37396
37796
  const leaf = typeof e.leafUuid === "string" ? e.leafUuid : void 0;
37397
37797
  if (leaf && removedUuids.has(leaf))
37398
37798
  return true;
37399
- if (!text12)
37799
+ if (!text13)
37400
37800
  return false;
37401
37801
  const echo = typeof e.lastPrompt === "string" ? e.lastPrompt : void 0;
37402
- return echo === text12;
37802
+ return echo === text13;
37403
37803
  }
37404
37804
  function messageText(e) {
37405
37805
  const content = e.message?.content;
37406
37806
  if (typeof content === "string")
37407
37807
  return content;
37408
37808
  if (Array.isArray(content)) {
37409
- const text12 = content.filter((b) => !!b && typeof b === "object" && b.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n");
37410
- return text12 || void 0;
37809
+ const text13 = content.filter((b) => !!b && typeof b === "object" && b.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n");
37810
+ return text13 || void 0;
37411
37811
  }
37412
37812
  return void 0;
37413
37813
  }
37414
- function findUserEntryByText(entries, text12) {
37814
+ function findUserEntryByText(entries, text13) {
37415
37815
  for (let i = entries.length - 1; i >= 0; i--) {
37416
37816
  const e = entries[i];
37417
37817
  if (e.type !== "user" || !e.uuid)
37418
37818
  continue;
37419
- if (messageText(e) === text12)
37819
+ if (messageText(e) === text13)
37420
37820
  return e;
37421
37821
  }
37422
37822
  return void 0;
@@ -37985,10 +38385,10 @@ async function toSessionInfo(s) {
37985
38385
  const spoken = s.cwd ? await lastConversationTime(sessionFile(s.cwd, s.sessionId)) : null;
37986
38386
  return { id: s.sessionId, title, lastModified: spoken ?? s.lastModified, cwd: s.cwd };
37987
38387
  }
37988
- function stripPromptPrefix(text12) {
37989
- text12 = stripRunDirective(text12);
38388
+ function stripPromptPrefix(text13) {
38389
+ text13 = stripRunDirective(text13);
37990
38390
  const isMetadata = (l) => l.startsWith("I'm working on the page:") || l.startsWith("Selected elements:") || l.startsWith("Element ") || l.startsWith(" DOM Path:") || l.startsWith(" XPath:") || l.startsWith(" CSS:") || l.startsWith(" HTML:") || l.startsWith(" Text:") || l.startsWith(" Position:") || l.startsWith("Use the xpath") || l.startsWith("[") && l.includes("image(s) attached");
37991
- const userLines = text12.split("\n").filter((l) => !isMetadata(l));
38391
+ const userLines = text13.split("\n").filter((l) => !isMetadata(l));
37992
38392
  return userLines.join("\n").trim();
37993
38393
  }
37994
38394
  function extractBlocks(message) {
@@ -38007,13 +38407,13 @@ function extractBlocks(message) {
38007
38407
  continue;
38008
38408
  const b = block2;
38009
38409
  if (b.type === "thinking" && typeof b.thinking === "string") {
38010
- const text12 = b.thinking.trim();
38011
- if (text12)
38012
- blocks.push({ kind: "thinking", content: text12 });
38410
+ const text13 = b.thinking.trim();
38411
+ if (text13)
38412
+ blocks.push({ kind: "thinking", content: text13 });
38013
38413
  } else if (b.type === "text" && typeof b.text === "string") {
38014
- const text12 = b.text.trim();
38015
- if (text12 && !text12.startsWith("<ide_") && !text12.startsWith("<system-reminder>")) {
38016
- blocks.push({ kind: "text", content: text12 });
38414
+ const text13 = b.text.trim();
38415
+ if (text13 && !text13.startsWith("<ide_") && !text13.startsWith("<system-reminder>")) {
38416
+ blocks.push({ kind: "text", content: text13 });
38017
38417
  }
38018
38418
  } else if (b.type === "tool_use") {
38019
38419
  const name = b.name ?? "tool";
@@ -38059,9 +38459,9 @@ ${input.command}
38059
38459
  blocks.push({ kind: "tool_use", content: detail, name });
38060
38460
  } else if (b.type === "advisor_tool_result") {
38061
38461
  const c = b.content;
38062
- const text12 = c?.type === "advisor_result" ? (c.text ?? "").trim() : "";
38063
- if (text12)
38064
- blocks.push({ kind: "advisor", content: text12 });
38462
+ const text13 = c?.type === "advisor_result" ? (c.text ?? "").trim() : "";
38463
+ if (text13)
38464
+ blocks.push({ kind: "advisor", content: text13 });
38065
38465
  }
38066
38466
  }
38067
38467
  return blocks;
@@ -38403,8 +38803,8 @@ async function anthropicCall(args) {
38403
38803
  });
38404
38804
  if (res.ok) {
38405
38805
  const j = await res.json();
38406
- const text12 = (j.content ?? []).filter((b) => b.type === "text").map((b) => b.text ?? "").join("").trim() || null;
38407
- return { text: text12, rateLimited: false };
38806
+ const text13 = (j.content ?? []).filter((b) => b.type === "text").map((b) => b.text ?? "").join("").trim() || null;
38807
+ return { text: text13, rateLimited: false };
38408
38808
  }
38409
38809
  let errBody = "";
38410
38810
  try {
@@ -38452,13 +38852,6 @@ async function anthropicCall(args) {
38452
38852
  }
38453
38853
  return { text: null, rateLimited: false };
38454
38854
  }
38455
- function isDirectAnthropic(env) {
38456
- try {
38457
- return /(^|\.)api\.anthropic\.com$/i.test(new URL(anthropicBaseUrl(env)).hostname);
38458
- } catch {
38459
- return false;
38460
- }
38461
- }
38462
38855
  async function buildClaudeNarrationLlm(env) {
38463
38856
  if (!await hasAnthropicCred(env))
38464
38857
  return null;
@@ -38548,7 +38941,7 @@ async function buildClaudeVisionLlm(env) {
38548
38941
  ]
38549
38942
  });
38550
38943
  }
38551
- var execFileP, USAGE_URL, FETCH_TIMEOUT_MS, cache, TTL_MS, RATE_LIMIT_BACKOFF_MS, inFlight, rateLimitedUntil, schemaUnsupported, schemaKey, SMART_TIMEOUT_MS, VISION_TIMEOUT_MS;
38944
+ var execFileP, USAGE_URL, FETCH_TIMEOUT_MS, cache, TTL_MS, RATE_LIMIT_BACKOFF_MS, inFlight, rateLimitedUntil, isDirectAnthropic, schemaUnsupported, schemaKey, SMART_TIMEOUT_MS, VISION_TIMEOUT_MS;
38552
38945
  var init_session_usage = __esm({
38553
38946
  "../../packages/agent-core/dist/session-usage.js"() {
38554
38947
  "use strict";
@@ -38563,6 +38956,7 @@ var init_session_usage = __esm({
38563
38956
  RATE_LIMIT_BACKOFF_MS = 5 * 6e4;
38564
38957
  inFlight = null;
38565
38958
  rateLimitedUntil = 0;
38959
+ isDirectAnthropic = isAnthropicEndpoint;
38566
38960
  schemaUnsupported = /* @__PURE__ */ new Set();
38567
38961
  schemaKey = (base, model) => `${base}|${model}`;
38568
38962
  SMART_TIMEOUT_MS = RV_GRADE_TIMEOUT_MS;
@@ -38692,7 +39086,7 @@ var init_stream_stall = __esm({
38692
39086
  // ../../packages/agent-core/dist/model-switch.js
38693
39087
  function modelFamily(model) {
38694
39088
  const id = (model ?? "").trim().toLowerCase();
38695
- if (!id || id.startsWith("tsr-"))
39089
+ if (!id)
38696
39090
  return void 0;
38697
39091
  return FAMILIES2.find((family) => id.includes(family));
38698
39092
  }
@@ -38728,8 +39122,8 @@ var init_model_switch = __esm({
38728
39122
 
38729
39123
  // ../../packages/agent-core/dist/usage-limit.js
38730
39124
  import { USAGE_LIMIT_ERROR_PREFIXES, USAGE_WARNING_PREFIXES, USAGE_TRANSITION_PREFIXES, ORG_POLICY_LIMIT_PREFIXES } from "@anthropic-ai/claude-agent-sdk";
38731
- function classifyUsageMessage(text12) {
38732
- const t = (text12 ?? "").trim();
39125
+ function classifyUsageMessage(text13) {
39126
+ const t = (text13 ?? "").trim();
38733
39127
  if (!t)
38734
39128
  return void 0;
38735
39129
  const hits = (list) => list.some((p) => t.startsWith(p));
@@ -38765,16 +39159,16 @@ function assistantUsageLimitFallback(content) {
38765
39159
  const blocks = content;
38766
39160
  if (blocks.some((block2) => block2?.type !== "text"))
38767
39161
  return void 0;
38768
- const text12 = blocks.map((block2) => typeof block2.text === "string" ? block2.text : "").join("\n").trim();
38769
- if (!text12 || text12.length > 600)
39162
+ const text13 = blocks.map((block2) => typeof block2.text === "string" ? block2.text : "").join("\n").trim();
39163
+ if (!text13 || text13.length > 600)
38770
39164
  return void 0;
38771
- const signal2 = classifyUsageMessage(text12);
39165
+ const signal2 = classifyUsageMessage(text13);
38772
39166
  if (signal2 !== "limit" && signal2 !== "org-policy")
38773
39167
  return void 0;
38774
- const isoReset = text12.match(/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\b/i)?.[0];
38775
- const resetMatch = text12.match(/(?:reset|resets|available again)(?:s| at| on| in)?\s+([^\n]+)/i);
39168
+ const isoReset = text13.match(/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\b/i)?.[0];
39169
+ const resetMatch = text13.match(/(?:reset|resets|available again)(?:s| at| on| in)?\s+([^\n]+)/i);
38776
39170
  const parsed = Date.parse(isoReset ?? resetMatch?.[1].trim() ?? "");
38777
- return { retryAt: Number.isFinite(parsed) ? parsed : void 0, signal: signal2, scopeText: text12 };
39171
+ return { retryAt: Number.isFinite(parsed) ? parsed : void 0, signal: signal2, scopeText: text13 };
38778
39172
  }
38779
39173
  function usageLimitErrorMessage(rejection) {
38780
39174
  if (rejection.signal === "org-policy") {
@@ -38789,16 +39183,30 @@ function usageLimitIsRotatable(rejection) {
38789
39183
  function usageLimitScopedModel(rejection, current) {
38790
39184
  if (rejection.signal === "org-policy")
38791
39185
  return void 0;
38792
- const text12 = (rejection.scopeText ?? "").trim();
38793
- if (!text12)
39186
+ const text13 = (rejection.scopeText ?? "").trim();
39187
+ if (!text13)
38794
39188
  return void 0;
38795
- const named = /reached your ([A-Za-z0-9.\- ]{1,30}?) limit/i.exec(text12)?.[1]?.trim().toLowerCase();
39189
+ const named = /reached your ([A-Za-z0-9.\- ]{1,30}?) limit/i.exec(text13)?.[1]?.trim().toLowerCase();
38796
39190
  if (!named)
38797
39191
  return void 0;
38798
39192
  if (current && !current.toLowerCase().includes(named))
38799
39193
  return void 0;
38800
39194
  return named;
38801
39195
  }
39196
+ function providerIsServing(content) {
39197
+ if (typeof content === "string")
39198
+ return content.trim().length > 0;
39199
+ if (!Array.isArray(content))
39200
+ return false;
39201
+ return content.some((blk) => {
39202
+ const b = blk;
39203
+ if (!b || typeof b !== "object")
39204
+ return false;
39205
+ if (b.type === "text")
39206
+ return typeof b.text === "string" && b.text.trim().length > 0;
39207
+ return b.type === "tool_use" || b.type === "server_tool_use" || b.type === "thinking";
39208
+ });
39209
+ }
38802
39210
  var init_usage_limit = __esm({
38803
39211
  "../../packages/agent-core/dist/usage-limit.js"() {
38804
39212
  "use strict";
@@ -38829,8 +39237,14 @@ function findUserInstalledClaude(binName) {
38829
39237
  const home = homedir3();
38830
39238
  const abs = [
38831
39239
  join17(home, ".claude", "local", binName),
38832
- // official installer (claude.ai/code)
39240
+ // legacy local npm install (older Claude Code)
38833
39241
  join17(home, ".local", "bin", binName),
39242
+ // the native installer's launcher — where we install
39243
+ // A copy Tesseract itself installed back when it used `npm install -g --prefix`. The probe has
39244
+ // always searched here, this list never did, so such an install read as "installed" in Settings
39245
+ // while the spawn said "not installed". AFTER ~/.local/bin deliberately: a current native
39246
+ // install must win over a stale npm one.
39247
+ join17(home, ".tesseract", "runtimes", "bin", binName),
38834
39248
  join17(home, ".bun", "bin", binName),
38835
39249
  join17(home, ".volta", "bin", binName),
38836
39250
  join17(home, "Library", "pnpm", binName),
@@ -38885,7 +39299,7 @@ function resolveClaudeCodeExecutable() {
38885
39299
  return cachedClaudeExe = bundled;
38886
39300
  }
38887
39301
  }
38888
- throw new Error("Claude Code isn\u2019t installed. Tesseract runs your own agent framework rather than bundling one \u2014 install Claude Code (https://claude.ai/code, or `npm i -g @anthropic-ai/claude-code`), or pick a different engine in Settings.");
39302
+ throw new Error("Claude Code isn\u2019t installed. Tesseract runs the agent framework you have installed rather than bundling one \u2014 install it with `curl -fsSL https://claude.ai/install.sh | bash` (Windows: `irm https://claude.ai/install.ps1 | iex`), or pick a different engine in Settings.");
38889
39303
  }
38890
39304
  function identityEnv() {
38891
39305
  const out = {};
@@ -39077,12 +39491,14 @@ function sessionStoreFor(mode) {
39077
39491
  function unattendedReportDirective(send5) {
39078
39492
  return unattendedModeFor({ optedIn: send5.unattended, origin: send5.origin }) !== "off" ? prompt("agent.system.unattended-report") : "";
39079
39493
  }
39080
- function sdkModelId(model) {
39494
+ function sdkModelId(model, env) {
39081
39495
  const id = model?.trim();
39082
39496
  if (!id)
39083
39497
  return void 0;
39084
39498
  if (process.env.TESSERACT_DISABLE_1M_CONTEXT === "1")
39085
39499
  return id;
39500
+ if (!isAnthropicEndpoint(env))
39501
+ return id;
39086
39502
  if (/[/]/.test(id) || /^[a-z]{2,}\./i.test(id))
39087
39503
  return id;
39088
39504
  return withOneMillionContext(id) ?? id;
@@ -39262,8 +39678,8 @@ function traceFrame(message) {
39262
39678
  const k = b?.type ?? "?";
39263
39679
  kinds.set(k, (kinds.get(k) ?? 0) + 1);
39264
39680
  }
39265
- const text12 = c.find((b) => b?.type === "text")?.text;
39266
- what = [...kinds].map(([k, n]) => n > 1 ? `${k}\xD7${n}` : k).join(",") + (text12 ? ` text:${JSON.stringify(text12.slice(0, 60))}` : "");
39681
+ const text13 = c.find((b) => b?.type === "text")?.text;
39682
+ what = [...kinds].map(([k, n]) => n > 1 ? `${k}\xD7${n}` : k).join(",") + (text13 ? ` text:${JSON.stringify(text13.slice(0, 60))}` : "");
39267
39683
  }
39268
39684
  log(`frame user${parent}${flags.length ? " [" + flags.join(",") + "]" : ""}${what ? " \u2014 " + what : ""}`);
39269
39685
  return;
@@ -39354,8 +39770,8 @@ function describeSystemSubtype(subtype, m) {
39354
39770
  const updateKey = category === "hook" ? `hook:${String(m.hook_name ?? m.hook_event_name ?? subtype)}` : category === "task" ? `task:${String(m.task_id ?? subtype)}` : category === "telemetry" ? `sys:${subtype}` : void 0;
39355
39771
  return { category, name: subtype, title: humanizeName(subtype), fields: salientFields(m), ...updateKey ? { updateKey } : {} };
39356
39772
  }
39357
- const text12 = extractHumanReadable(m);
39358
- return { category: "unknown", name: subtype, title: `system/${subtype}`, ...text12 ? { detail: text12 } : {}, raw: rawFramePreview(m) };
39773
+ const text13 = extractHumanReadable(m);
39774
+ return { category: "unknown", name: subtype, title: `system/${subtype}`, ...text13 ? { detail: text13 } : {}, raw: rawFramePreview(m) };
39359
39775
  }
39360
39776
  function sstr(v) {
39361
39777
  return typeof v === "string" ? v : "";
@@ -39375,24 +39791,24 @@ function prettifyModel(id) {
39375
39791
  return known[id] ?? id.replace(/^claude-/, "").replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
39376
39792
  }
39377
39793
  function taskNotificationNotices(content) {
39378
- let text12 = "";
39794
+ let text13 = "";
39379
39795
  if (typeof content === "string")
39380
- text12 = content;
39796
+ text13 = content;
39381
39797
  else if (Array.isArray(content)) {
39382
39798
  for (const b of content) {
39383
39799
  if (b && typeof b === "object" && b.type === "text")
39384
- text12 += `${sstr(b.text)}
39800
+ text13 += `${sstr(b.text)}
39385
39801
  `;
39386
39802
  }
39387
39803
  }
39388
- if (!text12.includes("<task-notification>"))
39804
+ if (!text13.includes("<task-notification>"))
39389
39805
  return [];
39390
39806
  const tag = (xml3, name) => {
39391
39807
  const m = new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(xml3);
39392
39808
  return m ? m[1].trim() : "";
39393
39809
  };
39394
39810
  const specs = [];
39395
- for (const m of text12.matchAll(/<task-notification>([\s\S]*?)<\/task-notification>/g)) {
39811
+ for (const m of text13.matchAll(/<task-notification>([\s\S]*?)<\/task-notification>/g)) {
39396
39812
  const status2 = (tag(m[1], "status") || "completed").toLowerCase();
39397
39813
  const summary = tag(m[1], "summary") || "Background task finished.";
39398
39814
  const failed = /fail|error/.test(status2);
@@ -39406,10 +39822,10 @@ function taskNotificationNotices(content) {
39406
39822
  function buildNotice(subtype, m) {
39407
39823
  switch (subtype) {
39408
39824
  case "notification": {
39409
- const text12 = sstr(m.text) || "Notification";
39825
+ const text13 = sstr(m.text) || "Notification";
39410
39826
  const priority = ["low", "medium", "high", "immediate"].includes(sstr(m.priority)) ? m.priority : "medium";
39411
39827
  const level = priority === "immediate" ? "error" : priority === "high" ? "warning" : priority === "low" ? "info" : "notice";
39412
- return { category: "notification", level, priority, title: text12, toast: true, inline: true, ...typeof m.timeout_ms === "number" ? { timeoutMs: m.timeout_ms } : {} };
39828
+ return { category: "notification", level, priority, title: text13, toast: true, inline: true, ...typeof m.timeout_ms === "number" ? { timeoutMs: m.timeout_ms } : {} };
39413
39829
  }
39414
39830
  case "informational": {
39415
39831
  const content = sstr(m.content).trim();
@@ -39440,9 +39856,9 @@ function buildNotice(subtype, m) {
39440
39856
  return { category: "memory", level: "info", title: `Recalled ${memories.length} ${memories.length === 1 ? "memory" : "memories"}`, ...names.length ? { body: names.join(" \xB7 ") } : {}, toast: false, inline: true };
39441
39857
  }
39442
39858
  case "permission_denied": {
39443
- const tool21 = sstr(m.tool_name) || "a tool";
39859
+ const tool22 = sstr(m.tool_name) || "a tool";
39444
39860
  const reason = sstr(m.decision_reason) || sstr(m.message);
39445
- return { category: "permission", level: "warning", title: `Blocked: ${tool21}`, ...reason ? { body: reason } : {}, ...sstr(m.tool_use_id) ? { toolUseId: sstr(m.tool_use_id) } : {}, toast: true, inline: true };
39861
+ return { category: "permission", level: "warning", title: `Blocked: ${tool22}`, ...reason ? { body: reason } : {}, ...sstr(m.tool_use_id) ? { toolUseId: sstr(m.tool_use_id) } : {}, toast: true, inline: true };
39446
39862
  }
39447
39863
  case "model_refusal_fallback": {
39448
39864
  const orig = sstr(m.original_model);
@@ -39556,9 +39972,9 @@ ${plan}`;
39556
39972
  return name;
39557
39973
  }
39558
39974
  }
39559
- function computerToolPhrase(tool21, input) {
39975
+ function computerToolPhrase(tool22, input) {
39560
39976
  const s = (v) => typeof v === "string" ? v : "";
39561
- switch (tool21) {
39977
+ switch (tool22) {
39562
39978
  case "see_screen":
39563
39979
  return input.x1 !== void 0 ? "Looking closely at part of the screen" : "Looking at the screen";
39564
39980
  case "click":
@@ -39601,15 +40017,15 @@ function assistantText(content) {
39601
40017
  return content.filter((b) => !!b && typeof b === "object").filter((b) => b.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n").trim();
39602
40018
  }
39603
40019
  function flattenToolResultContent(content) {
39604
- let text12 = "";
40020
+ let text13 = "";
39605
40021
  if (typeof content === "string")
39606
- text12 = content;
40022
+ text13 = content;
39607
40023
  else if (Array.isArray(content)) {
39608
- text12 = content.filter((b) => b && typeof b === "object" && b.type === "text").map((b) => String(b.text ?? "")).join("\n");
40024
+ text13 = content.filter((b) => b && typeof b === "object" && b.type === "text").map((b) => String(b.text ?? "")).join("\n");
39609
40025
  }
39610
- if (text12.length > TOOL_RESULT_CAP)
39611
- return { text: text12.slice(0, TOOL_RESULT_CAP), truncated: true };
39612
- return { text: text12, truncated: false };
40026
+ if (text13.length > TOOL_RESULT_CAP)
40027
+ return { text: text13.slice(0, TOOL_RESULT_CAP), truncated: true };
40028
+ return { text: text13, truncated: false };
39613
40029
  }
39614
40030
  function extractImages(content) {
39615
40031
  if (!Array.isArray(content))
@@ -39791,6 +40207,7 @@ var init_agent_manager = __esm({
39791
40207
  init_screen_control_tools();
39792
40208
  init_computer_control_tools();
39793
40209
  init_app_control_tools();
40210
+ init_capabilities_tools();
39794
40211
  init_serpapi_tools();
39795
40212
  init_report_tools();
39796
40213
  init_interactive_ui_tools();
@@ -39920,7 +40337,9 @@ var init_agent_manager = __esm({
39920
40337
  "await_jobs",
39921
40338
  "job_output",
39922
40339
  "job_list",
39923
- "stop_job"
40340
+ "stop_job",
40341
+ // Returns an inlined constant. There is nothing to wait for.
40342
+ "tesseract_capabilities"
39924
40343
  ]);
39925
40344
  STOP_HARD_KILL_AFTER_MS = 1200;
39926
40345
  STREAM_STALL_MS = 20 * 6e4;
@@ -40186,8 +40605,37 @@ var init_agent_manager = __esm({
40186
40605
  * (then recorded into cronTaskSessions). */
40187
40606
  cronRequestTask = /* @__PURE__ */ new Map();
40188
40607
  /** What each conversation last ran with for Unattended — its own choice, which a scheduled fire into it must
40189
- * honour rather than the machine-wide switch (applyTurnPolicy records it; the cron fire above reads it). */
40608
+ * honour rather than the machine-wide switch (applyTurnPolicy records it; the cron fire above reads it).
40609
+ * Bounded: a daemon that runs for months must not grow a row per conversation forever, and forgetting the
40610
+ * oldest is safe — an unknown conversation falls back to 'safe' rather than to the machine switch. */
40190
40611
  unattendedByConversation = /* @__PURE__ */ new Map();
40612
+ /** How many conversations' Unattended choices are remembered. Generous — one small row each — and bounded
40613
+ * so a long-lived daemon cannot grow this without limit. */
40614
+ static MAX_REMEMBERED_UNATTENDED = 2e3;
40615
+ /**
40616
+ * Everything keyed by a conversation's id that must follow it when the CLI re-ids it mid-flight
40617
+ * (`conversation_reset`). It is the same conversation: the scheduler must keep firing into it rather than
40618
+ * opening a fresh overlapping one, and the Unattended choice made in it still stands — without this, a
40619
+ * reset quietly downgrades the next 3am fire to 'safe' in a conversation the person set up to run alone.
40620
+ */
40621
+ carryConversationTo(prev, next) {
40622
+ for (const [taskId, mapped] of this.cronTaskSessions) {
40623
+ if (mapped === prev)
40624
+ this.cronTaskSessions.set(taskId, next);
40625
+ }
40626
+ const chosen = this.unattendedByConversation.get(prev);
40627
+ if (chosen !== void 0) {
40628
+ this.unattendedByConversation.delete(prev);
40629
+ this.rememberUnattended(next, chosen);
40630
+ }
40631
+ }
40632
+ rememberUnattended(sessionId, unattended) {
40633
+ this.unattendedByConversation.delete(sessionId);
40634
+ this.unattendedByConversation.set(sessionId, unattended);
40635
+ while (this.unattendedByConversation.size > _AgentManager.MAX_REMEMBERED_UNATTENDED) {
40636
+ this.unattendedByConversation.delete(this.unattendedByConversation.keys().next().value);
40637
+ }
40638
+ }
40191
40639
  /** Set (or clear) the skills local-plugin exposed to NEW conversations (Epic H). */
40192
40640
  setSkillsPlugin(config2) {
40193
40641
  this.skillsPlugin = config2;
@@ -40383,6 +40831,12 @@ var init_agent_manager = __esm({
40383
40831
  // never sent to in this daemon's life — is left ABSENT, which for a cron turn means 'safe':
40384
40832
  // unanswerable prompts are declined rather than parked, and nothing is approved on anyone's behalf.
40385
40833
  unattended: targetSessionId ? this.unattendedByConversation.get(targetSessionId) : cfg2.isUnattended?.(),
40834
+ // THE PERSON'S SETTINGS — their block rules, their always-ask rules, their hooks. A scheduled turn
40835
+ // carried NONE of them: a session this fire creates was built without the one layer that refuses
40836
+ // things, on the run nobody is watching. Read at fire time like the switches above, so a rule
40837
+ // written at 23:00 is in force at 03:00. (A conversation already live keeps the settings its
40838
+ // query was built with; this is what a cold or new one starts from.)
40839
+ settings: cfg2.settings?.(),
40386
40840
  // Only for a conversation this fire is CREATING. Verification is per conversation and
40387
40841
  // the machine-wide switch is merely the default a new one starts with, so stamping it
40388
40842
  // onto an existing one overrode the choice the person made there — disarming a loop the
@@ -40449,7 +40903,7 @@ var init_agent_manager = __esm({
40449
40903
  this.onBrowserRequest = onBrowserRequest;
40450
40904
  const __dirname2 = dirname9(fileURLToPath(import.meta.url));
40451
40905
  this.browserCliPath = join17(__dirname2, "browser-cli.js");
40452
- this.narrator = new Narrator((sessionId, text12, engineLabel) => this.send({ type: "agent:narration", sessionId, text: text12, ...engineLabel ? { engineLabel } : {} }, this.liveSessions.get(sessionId)?.origin));
40906
+ this.narrator = new Narrator((sessionId, text13, engineLabel) => this.send({ type: "agent:narration", sessionId, text: text13, ...engineLabel ? { engineLabel } : {} }, this.liveSessions.get(sessionId)?.origin));
40453
40907
  }
40454
40908
  /** Inject (or clear) the cheap model used for the live status narration. The
40455
40909
  * host resolves creds and builds the completion fn (keeping secrets host-side). */
@@ -40619,9 +41073,9 @@ var init_agent_manager = __esm({
40619
41073
  const file2 = await resolveSessionFile(sid, live.cwd).catch(() => null);
40620
41074
  if (!file2)
40621
41075
  return false;
40622
- let text12;
41076
+ let text13;
40623
41077
  try {
40624
- text12 = await readFile8(file2, "utf8");
41078
+ text13 = await readFile8(file2, "utf8");
40625
41079
  } catch {
40626
41080
  return false;
40627
41081
  }
@@ -40629,7 +41083,7 @@ var init_agent_manager = __esm({
40629
41083
  const v = leanReloadVerdict({
40630
41084
  fillPct: usage2.percentage,
40631
41085
  thresholdPct,
40632
- leanBytes: contentBytes(text12),
41086
+ leanBytes: contentBytes(text13),
40633
41087
  strippedBytes: live.strippedContentBytes ?? 0
40634
41088
  });
40635
41089
  if (v.action === "skip") {
@@ -40864,7 +41318,7 @@ var init_agent_manager = __esm({
40864
41318
  return false;
40865
41319
  }
40866
41320
  try {
40867
- await live.query.setModel(sdkModelId(next));
41321
+ await live.query.setModel(sdkModelId(next, live.endpointEnv));
40868
41322
  } catch (err2) {
40869
41323
  log(`[model] ${turnSid}: could not switch to ${next}:`, err2 instanceof Error ? err2.message : String(err2));
40870
41324
  return false;
@@ -41584,7 +42038,7 @@ ${full.slice(-8e3)}`;
41584
42038
  applyTurnPolicy(live, p) {
41585
42039
  live.unattended = unattendedModeFor({ optedIn: p.unattended, origin: p.origin });
41586
42040
  if (p.unattended !== void 0 && live.sessionId)
41587
- this.unattendedByConversation.set(live.sessionId, p.unattended);
42041
+ this.rememberUnattended(live.sessionId, p.unattended);
41588
42042
  if (p.autoCompactPct !== void 0)
41589
42043
  live.autoCompactPct = p.autoCompactPct;
41590
42044
  live.autoDecisions = 0;
@@ -41763,10 +42217,10 @@ ${full.slice(-8e3)}`;
41763
42217
  parts.push(`The user's current request:
41764
42218
  ${live.lastPrompt.slice(0, 1400)}`);
41765
42219
  if (Array.isArray(live.lastAssistantContent)) {
41766
- const text12 = live.lastAssistantContent.filter((b) => b?.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n").trim();
41767
- if (text12)
42220
+ const text13 = live.lastAssistantContent.filter((b) => b?.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n").trim();
42221
+ if (text13)
41768
42222
  parts.push(`What the assistant just said (leading to this question):
41769
- ${text12.slice(0, 1600)}`);
42223
+ ${text13.slice(0, 1600)}`);
41770
42224
  }
41771
42225
  return parts.join("\n\n") || "No additional context available beyond the question itself.";
41772
42226
  }
@@ -42310,9 +42764,9 @@ ${lines}`;
42310
42764
  const transcripts = [];
42311
42765
  for (const sid of sessionIds) {
42312
42766
  const msgs = await this.sessionStore.getSessionMessages(sid).catch(() => []);
42313
- const text12 = transcriptToText(msgs);
42314
- if (text12)
42315
- transcripts.push(text12);
42767
+ const text13 = transcriptToText(msgs);
42768
+ if (text13)
42769
+ transcripts.push(text13);
42316
42770
  }
42317
42771
  if (transcripts.length === 0)
42318
42772
  return;
@@ -42399,7 +42853,7 @@ ${lines}`;
42399
42853
  if (opts.permissionMode)
42400
42854
  await live.query.setPermissionMode(sdkPermissionMode(opts.permissionMode));
42401
42855
  if (opts.model !== void 0) {
42402
- await live.query.setModel(sdkModelId(opts.model));
42856
+ await live.query.setModel(sdkModelId(opts.model, live.endpointEnv));
42403
42857
  live.model = opts.model || void 0;
42404
42858
  this.rememberSessionModel(live.sessionId, live.model);
42405
42859
  }
@@ -42628,7 +43082,7 @@ ${lines}`;
42628
43082
  live.windowId = params.windowId;
42629
43083
  live.pendingTitle = params.message.trim().slice(0, 80);
42630
43084
  if (params.model)
42631
- void live.query.setModel(sdkModelId(params.model)).catch(() => {
43085
+ void live.query.setModel(sdkModelId(params.model, live.endpointEnv)).catch(() => {
42632
43086
  });
42633
43087
  if (params.permissionMode)
42634
43088
  void live.query.setPermissionMode(sdkPermissionMode(params.permissionMode)).catch(() => {
@@ -42945,6 +43399,7 @@ ${prompt("agent.system.long-running")}`;
42945
43399
  }
42946
43400
  async createLiveSession(params) {
42947
43401
  const spawnModel = this.modelForSpawn(params);
43402
+ const spawnEndpoint = { ...params.env ?? {}, ...params.engineEnv ?? {} };
42948
43403
  this.rememberSessionModel(params.sessionId, spawnModel);
42949
43404
  this.rememberSessionModel(params.clientRequestId, spawnModel);
42950
43405
  const openProject = params.projectDir ?? this.projectDir ?? params.sources?.[0];
@@ -43106,7 +43561,7 @@ ${prompt("agent.system.long-running")}`;
43106
43561
  // `modelForSpawn`, not `params.model`: a resume that nobody sent a model with (a
43107
43562
  // wake-up after a background task, a daemon-side continuation) would otherwise open a
43108
43563
  // 1M conversation against 200k. See sessionModels.
43109
- ...spawnModel ? { model: sdkModelId(spawnModel) } : {},
43564
+ ...spawnModel ? { model: sdkModelId(spawnModel, spawnEndpoint) } : {},
43110
43565
  // Clamp to what THIS CLI accepts — an unsupported level is a hard exit-1, not
43111
43566
  // a warning. See clampEffort.
43112
43567
  ...ultracodeEffort ? { effort: ultracodeEffort } : {},
@@ -43115,7 +43570,7 @@ ${prompt("agent.system.long-running")}`;
43115
43570
  // of surfacing an error the user has to act on.
43116
43571
  // Same for the fallback: it REPLACES the main model on an overload, so a bare id here
43117
43572
  // would quietly move a long conversation onto a 200k window mid-run.
43118
- ...params.fallbackModel ? { fallbackModel: sdkModelId(params.fallbackModel) } : {},
43573
+ ...params.fallbackModel ? { fallbackModel: sdkModelId(params.fallbackModel, spawnEndpoint) } : {},
43119
43574
  ...params.enableFileCheckpointing ? { enableFileCheckpointing: true } : {},
43120
43575
  // ON BY DEFAULT. This is what turns a silent helper into one that says what it is
43121
43576
  // doing — a short present-tense line on each progress frame, written by forking the
@@ -43399,6 +43854,7 @@ ${prompt("agent.system.long-running")}`;
43399
43854
  if (this.computerControlProvider) {
43400
43855
  mcp["tesseract-computer"] = createSdkMcpServer2({ name: "tesseract-computer", version: "0.1.0", tools: buildComputerControlSdkTools(this.computerControlProvider) });
43401
43856
  }
43857
+ mcp["tesseract-capabilities"] = createSdkMcpServer2({ name: "tesseract-capabilities", version: "0.1.0", tools: buildCapabilitiesTools() });
43402
43858
  if (this.appControlProvider) {
43403
43859
  const appProvider = this.appControlProvider;
43404
43860
  mcp["tesseract-app"] = createSdkMcpServer2({
@@ -43845,7 +44301,7 @@ ${prompt("agent.system.long-running")}`;
43845
44301
  // rather than the number in the run-mode menu.
43846
44302
  ...this.daemonCompactEnv(params.env),
43847
44303
  // A GATEWAY MODEL ALIAS MUST NOT BE WINDOW-ENFORCED BY THE CLI. Routed through
43848
- // our gateway the id is an alias (`tsr-claude`) the CLI does not know. Harmless
44304
+ // our gateway it may be a retired tier alias the CLI does not know. Harmless
43849
44305
  // for an ordinary query; fatal for its INTERNAL compaction query, which never
43850
44306
  // returns — no frame, 120s stall, killed as "connection went quiet", replayed
43851
44307
  // by the client, and stalled again every two minutes for ever. MEASURED on a
@@ -43870,11 +44326,11 @@ ${prompt("agent.system.long-running")}`;
43870
44326
  });
43871
44327
  let errSeen = 0;
43872
44328
  child.stderr?.on("data", (chunk) => {
43873
- const text12 = String(chunk);
44329
+ const text13 = String(chunk);
43874
44330
  if (errSeen >= 8e3)
43875
44331
  return;
43876
- errSeen += text12.length;
43877
- for (const line of text12.split("\n")) {
44332
+ errSeen += text13.length;
44333
+ for (const line of text13.split("\n")) {
43878
44334
  const t = line.trim();
43879
44335
  if (!t)
43880
44336
  continue;
@@ -44153,9 +44609,9 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
44153
44609
  emit2({ type: "chat:stream", sessionId: sid, delta: "[thinking redacted]", messageId: message.uuid, kind: "thinking", ...parentField });
44154
44610
  } else if (cbt === "advisor_tool_result") {
44155
44611
  const res = event.content_block.content;
44156
- const text12 = res?.type === "advisor_result" ? (res.text ?? "").trim() : "";
44157
- if (text12 && parentToolUseId === void 0)
44158
- emit2({ type: "agent:advisor", sessionId: sid, text: text12 });
44612
+ const text13 = res?.type === "advisor_result" ? (res.text ?? "").trim() : "";
44613
+ if (text13 && parentToolUseId === void 0)
44614
+ emit2({ type: "agent:advisor", sessionId: sid, text: text13 });
44159
44615
  }
44160
44616
  }
44161
44617
  if (event.type === "content_block_delta") {
@@ -44170,26 +44626,26 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
44170
44626
  }
44171
44627
  }
44172
44628
  if (event.delta?.type === "text_delta" && event.delta.text) {
44173
- const text12 = event.delta.text;
44174
- if (/<(?:tool_call|tool_result|function_calls|antml:function_calls)[\s>]/i.test(text12)) {
44629
+ const text13 = event.delta.text;
44630
+ if (/<(?:tool_call|tool_result|function_calls|antml:function_calls)[\s>]/i.test(text13)) {
44175
44631
  insideXmlByKey.set(key2, true);
44176
44632
  break;
44177
44633
  }
44178
44634
  if (insideXmlByKey.get(key2)) {
44179
- if (/<\/(?:tool_call|tool_result|function_calls|antml:function_calls)\s*>/i.test(text12)) {
44635
+ if (/<\/(?:tool_call|tool_result|function_calls|antml:function_calls)\s*>/i.test(text13)) {
44180
44636
  insideXmlByKey.set(key2, false);
44181
44637
  }
44182
44638
  break;
44183
44639
  }
44184
- if (/<\/?(?:invoke|antml:invoke|antml:parameter)[\s>]/.test(text12))
44640
+ if (/<\/?(?:invoke|antml:invoke|antml:parameter)[\s>]/.test(text13))
44185
44641
  break;
44186
- if (/<parameter\s+name=/.test(text12))
44642
+ if (/<parameter\s+name=/.test(text13))
44187
44643
  break;
44188
- if (/^\s*<\/(?:parameter|invoke|function_calls)>\s*$/.test(text12))
44644
+ if (/^\s*<\/(?:parameter|invoke|function_calls)>\s*$/.test(text13))
44189
44645
  break;
44190
44646
  if (parentToolUseId === void 0)
44191
44647
  turnStreamed = true;
44192
- const d = this.applyDeltaHook(text12, "text", sid);
44648
+ const d = this.applyDeltaHook(text13, "text", sid);
44193
44649
  if (d !== null)
44194
44650
  emit2({ type: "chat:stream", sessionId: sid, delta: d, messageId: message.uuid, kind: "text", ...parentField });
44195
44651
  }
@@ -44257,10 +44713,8 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
44257
44713
  live.sessionId = next;
44258
44714
  this.rememberSessionModel(next, live.model);
44259
44715
  this.liveSessions.set(next, live);
44260
- for (const [taskId, mapped] of this.cronTaskSessions) {
44261
- if (mapped === prev)
44262
- this.cronTaskSessions.set(taskId, next);
44263
- }
44716
+ if (prev)
44717
+ this.carryConversationTo(prev, next);
44264
44718
  this.send({ type: "session:created", sessionId: next, clientRequestId: live.clientRequestId }, live.origin);
44265
44719
  emitNotice({ category: "info", level: "notice", title: "This conversation was reset", body: "The agent started a fresh conversation; earlier messages are no longer in its context.", inline: true, toast: false });
44266
44720
  break;
@@ -44310,7 +44764,9 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
44310
44764
  ...typeof uc?.output_tokens === "number" ? { outputTokens: uc.output_tokens } : {}
44311
44765
  });
44312
44766
  }
44313
- const limitRejection = live.usageLimitRejection ?? (r.subtype === "success" ? assistantUsageLimitFallback(live.lastAssistantContent) : void 0);
44767
+ const limitFromReply = r.subtype === "success" ? assistantUsageLimitFallback(live.lastAssistantContent) : void 0;
44768
+ const turnAnswered = r.subtype === "success" && r.is_error !== true && !limitFromReply;
44769
+ const limitRejection = turnAnswered ? void 0 : live.usageLimitRejection ?? limitFromReply;
44314
44770
  const resultText = typeof r.result === "string" ? r.result : "";
44315
44771
  const textOverflow = r.is_error === true && isContextOverflow(resultText) || live.lastAssistantSynthetic === true && assistantContextOverflow(live.lastAssistantContent, isContextOverflow);
44316
44772
  const apiFailure = textOverflow ? null : classifyEngineApiError(resultText);
@@ -44780,6 +45236,10 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
44780
45236
  });
44781
45237
  }
44782
45238
  }
45239
+ if (live.usageLimitRejection && am.message?.model !== "<synthetic>" && providerIsServing(am.message?.content)) {
45240
+ log("Usage limit cleared by a reply that followed it:", sid);
45241
+ live.usageLimitRejection = void 0;
45242
+ }
44783
45243
  if (am.uuid && parentToolUseId === void 0) {
44784
45244
  live.lastAssistantUuid = am.uuid;
44785
45245
  live.lastAssistantContent = am.message?.content;
@@ -44824,20 +45284,20 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
44824
45284
  const tn = toolNameByUseId.get(toolUseId);
44825
45285
  if (tn === "Edit" || tn === "Write" || tn === "MultiEdit" || tn === "NotebookEdit")
44826
45286
  continue;
44827
- const { text: text12, truncated } = flattenToolResultContent(blk.content);
45287
+ const { text: text13, truncated } = flattenToolResultContent(blk.content);
44828
45288
  const images = extractImages(blk.content);
44829
45289
  const isError = blk.is_error === true;
44830
- if (!text12 && images.length === 0 && !isError)
45290
+ if (!text13 && images.length === 0 && !isError)
44831
45291
  continue;
44832
- emit2({ type: "agent:tool_result", sessionId: sid, toolUseId, isError, output: text12, images, truncated, ...agentId ? { agentId } : {} });
44833
- const bg = parseBackgroundTaskResult(text12);
45292
+ emit2({ type: "agent:tool_result", sessionId: sid, toolUseId, isError, output: text13, images, truncated, ...agentId ? { agentId } : {} });
45293
+ const bg = parseBackgroundTaskResult(text13);
44834
45294
  if (bg && !agentId) {
44835
45295
  live.taskToolUse.set(bg.taskId, toolUseId);
44836
45296
  emit2({ type: "agent:task", sessionId: sid, taskId: bg.taskId, phase: "progress", status: "running", ...this.taskIdentity(live, bg.taskId), toolUseId, outputPath: bg.outputPath, isBackgrounded: true });
44837
45297
  this.startTaskTail(live, bg.taskId, bg.outputPath, toolUseId);
44838
45298
  }
44839
45299
  if (isError && !agentId) {
44840
- const why = (text12 || "").replace(/```[\s\S]*?```/g, " ").replace(/[`*]/g, "").replace(/\s+/g, " ").trim().slice(0, 160);
45300
+ const why = (text13 || "").replace(/```[\s\S]*?```/g, " ").replace(/[`*]/g, "").replace(/\s+/g, " ").trim().slice(0, 160);
44841
45301
  this.narrator.observe(sid, `\u2192 that didn't work${why ? `: ${why}` : ""}`);
44842
45302
  }
44843
45303
  } else if (blk?.type === "web_search_tool_result") {
@@ -44869,12 +45329,12 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
44869
45329
  }
44870
45330
  default: {
44871
45331
  const m = message;
44872
- const text12 = extractHumanReadable(m);
45332
+ const text13 = extractHumanReadable(m);
44873
45333
  emitEvent({
44874
45334
  category: "unknown",
44875
45335
  name: m.type || "unknown",
44876
45336
  title: m.type || "unknown frame",
44877
- ...text12 ? { detail: text12 } : {},
45337
+ ...text13 ? { detail: text13 } : {},
44878
45338
  raw: rawFramePreview(m)
44879
45339
  }, parentToolUseId);
44880
45340
  log("unknown SDK message type surfaced with raw data:", m.type || "?");
@@ -46208,11 +46668,11 @@ Element ${i + 1}:`);
46208
46668
  });
46209
46669
 
46210
46670
  // ../../packages/agent-core/dist/present-tools.js
46211
- import { tool as tool20 } from "@anthropic-ai/claude-agent-sdk";
46671
+ import { tool as tool21 } from "@anthropic-ai/claude-agent-sdk";
46212
46672
  function buildPresentSdkTools(p) {
46213
- return PRESENT_TOOL_SPECS.map((spec) => tool20(spec.name, spec.description, zodShapeFromParams(spec.params), async (args) => {
46214
- const text12 = await p.exec(spec.name, args ?? {});
46215
- return { content: [{ type: "text", text: text12 || "Done." }] };
46673
+ return PRESENT_TOOL_SPECS.map((spec) => tool21(spec.name, spec.description, zodShapeFromParams(spec.params), async (args) => {
46674
+ const text13 = await p.exec(spec.name, args ?? {});
46675
+ return { content: [{ type: "text", text: text13 || "Done." }] };
46216
46676
  }));
46217
46677
  }
46218
46678
  function buildPresentPrompt(opts) {
@@ -46325,6 +46785,7 @@ __export(dist_exports2, {
46325
46785
  APP_CONTROL_DOMAINS: () => APP_CONTROL_DOMAINS,
46326
46786
  APP_CONTROL_GENERATED_MARKER: () => APP_CONTROL_GENERATED_MARKER,
46327
46787
  AgentManager: () => AgentManager,
46788
+ CAPABILITIES_DOC: () => CAPABILITIES_DOC,
46328
46789
  DEFAULT_OFFLOAD_RECENT_CALLS: () => DEFAULT_OFFLOAD_RECENT_CALLS,
46329
46790
  DESIGN_CLAUDE_MD: () => DESIGN_CLAUDE_MD,
46330
46791
  DESIGN_DIR: () => DESIGN_DIR,
@@ -46357,6 +46818,7 @@ __export(dist_exports2, {
46357
46818
  archivePathFor: () => archivePathFor,
46358
46819
  autoCompactEnvFor: () => autoCompactEnvFor,
46359
46820
  buildAppControlTools: () => buildAppControlTools,
46821
+ buildCapabilitiesTools: () => buildCapabilitiesTools,
46360
46822
  buildClaudeNarrationLlm: () => buildClaudeNarrationLlm,
46361
46823
  buildClaudeSmartLlm: () => buildClaudeSmartLlm,
46362
46824
  buildClaudeVisionLlm: () => buildClaudeVisionLlm,
@@ -46374,6 +46836,7 @@ __export(dist_exports2, {
46374
46836
  bumpVersion: () => bumpVersion,
46375
46837
  capabilitiesByDomain: () => capabilitiesByDomain,
46376
46838
  capabilityById: () => capabilityById,
46839
+ capabilitySections: () => capabilitySections,
46377
46840
  computerControlSpecs: () => computerControlSpecs,
46378
46841
  computerOperatorPrompt: () => computerOperatorPrompt,
46379
46842
  computerSpecParametersJsonSchema: () => computerSpecParametersJsonSchema,
@@ -46385,6 +46848,7 @@ __export(dist_exports2, {
46385
46848
  engineMessageTokens: () => engineMessageTokens,
46386
46849
  exportSession: () => exportSession,
46387
46850
  filterHistory: () => filterHistory,
46851
+ findSections: () => findSections,
46388
46852
  flattenForDisplay: () => flattenForDisplay,
46389
46853
  getModelCatalog: () => getModelCatalog,
46390
46854
  getTokenPath: () => getTokenPath,
@@ -46478,6 +46942,8 @@ var init_dist5 = __esm({
46478
46942
  init_present_tools();
46479
46943
  init_computer_control_tools();
46480
46944
  init_support_tools();
46945
+ init_capabilities_tools();
46946
+ init_capabilities_doc_generated();
46481
46947
  init_app_control_tools();
46482
46948
  init_registry();
46483
46949
  init_docs2();
@@ -47050,9 +47516,9 @@ function materializeClaudeAuthHome(contents) {
47050
47516
  });
47051
47517
  return home;
47052
47518
  }
47053
- function withClaudeModels(env, main2, fast) {
47519
+ function withClaudeModels(env, main2, fast, longWindow = true) {
47054
47520
  if (main2) {
47055
- env.ANTHROPIC_MODEL = withOneMillionContext(main2) ?? main2;
47521
+ env.ANTHROPIC_MODEL = (longWindow ? withOneMillionContext(main2) : main2) ?? main2;
47056
47522
  }
47057
47523
  if (fast)
47058
47524
  env.ANTHROPIC_SMALL_FAST_MODEL = fast;
@@ -47099,7 +47565,7 @@ function resolveRunnerEnv(spec) {
47099
47565
  if (!baseUrl.trim()) {
47100
47566
  return { CCB_RUNNER_CONFIG_ERROR: `Set an address for ${provider.label} in Settings \u2192 Models & accounts.` };
47101
47567
  }
47102
- return withClaudeModels({ ANTHROPIC_BASE_URL: baseUrl, ANTHROPIC_AUTH_TOKEN: key2, ANTHROPIC_API_KEY: "" }, main2, fast);
47568
+ return withClaudeModels({ ANTHROPIC_BASE_URL: baseUrl, ANTHROPIC_AUTH_TOKEN: key2, ANTHROPIC_API_KEY: "" }, main2, fast, false);
47103
47569
  }
47104
47570
  const endpoint2 = routerEndpointSync({
47105
47571
  providerId,
@@ -47173,7 +47639,10 @@ function readGatewayKey() {
47173
47639
  baseUrl: raw.baseUrl,
47174
47640
  apiKey: raw.apiKey,
47175
47641
  models: raw.models,
47176
- ...raw.endpoints ? { endpoints: raw.endpoints } : {}
47642
+ ...raw.endpoints ? { endpoints: raw.endpoints } : {},
47643
+ // Per-audience defaults (engine + model) travel through too — `tiers()` in shared
47644
+ // honours `defaults.model` on this headless spawn path exactly as the desktop does.
47645
+ ...raw.defaults ? { defaults: raw.defaults } : {}
47177
47646
  };
47178
47647
  }
47179
47648
  } catch {
@@ -47590,9 +48059,9 @@ function rememberedPath(engineId) {
47590
48059
  }
47591
48060
  }
47592
48061
  function which(bin, path6) {
47593
- const tool21 = process.platform === "win32" ? "where" : "which";
48062
+ const tool22 = process.platform === "win32" ? "where" : "which";
47594
48063
  try {
47595
- const out = execFileSync2(tool21, [bin], { env: { ...process.env, PATH: path6 }, timeout: 4e3, encoding: "utf-8" });
48064
+ const out = execFileSync2(tool22, [bin], { env: { ...process.env, PATH: path6 }, timeout: 4e3, encoding: "utf-8" });
47596
48065
  return out.split(/\r?\n/).map((l) => l.trim()).find(Boolean) || void 0;
47597
48066
  } catch {
47598
48067
  return void 0;
@@ -47864,9 +48333,9 @@ function readBody2(req, limitBytes = 4 * 1024 * 1024) {
47864
48333
  });
47865
48334
  }
47866
48335
  function send2(res, code, body, headers = {}) {
47867
- const text12 = JSON.stringify(body);
47868
- res.writeHead(code, { "content-type": "application/json", "content-length": Buffer.byteLength(text12), ...headers });
47869
- res.end(text12);
48336
+ const text13 = JSON.stringify(body);
48337
+ res.writeHead(code, { "content-type": "application/json", "content-length": Buffer.byteLength(text13), ...headers });
48338
+ res.end(text13);
47870
48339
  }
47871
48340
  function portFile() {
47872
48341
  return join28(daemonDir2(), "mcp-endpoint.json");
@@ -47939,13 +48408,13 @@ async function startTesseractMcpEndpoint() {
47939
48408
  return;
47940
48409
  case "tools/call": {
47941
48410
  const name = String(msg.params?.name ?? "");
47942
- const tool21 = byName.get(name);
47943
- if (!tool21) {
48411
+ const tool22 = byName.get(name);
48412
+ if (!tool22) {
47944
48413
  fail4(-32602, `Unknown tool "${name}"`);
47945
48414
  return;
47946
48415
  }
47947
48416
  try {
47948
- const out = await tool21.handler(msg.params?.arguments ?? {}, { sessionId: grant?.sessionId, nested: grant?.extensionId === NESTED_HOLDER });
48417
+ const out = await tool22.handler(msg.params?.arguments ?? {}, { sessionId: grant?.sessionId, nested: grant?.extensionId === NESTED_HOLDER });
47949
48418
  reply3({ content: out.content, ...out.isError ? { isError: true } : {} });
47950
48419
  } catch (e) {
47951
48420
  reply3({ content: [{ type: "text", text: `${name} failed: ${e instanceof Error ? e.message : String(e)}` }], isError: true });
@@ -48099,11 +48568,11 @@ function wrapHostedAsyncTool(t, opts) {
48099
48568
  }
48100
48569
  if (raced.kind === "done") {
48101
48570
  callEnded();
48102
- return text11(raced.out);
48571
+ return text12(raced.out);
48103
48572
  }
48104
48573
  if (raced.kind === "error") {
48105
48574
  callEnded();
48106
- return text11(raced.err instanceof Error ? raced.err.message : String(raced.err), true);
48575
+ return text12(raced.err instanceof Error ? raced.err.message : String(raced.err), true);
48107
48576
  }
48108
48577
  opts.learnedSlow?.add(t.name);
48109
48578
  const sessionId = ctx2?.sessionId;
@@ -48116,7 +48585,7 @@ function wrapHostedAsyncTool(t, opts) {
48116
48585
  });
48117
48586
  opts.noteSession?.(job.id, sessionId, claim);
48118
48587
  callEnded();
48119
- return text11([
48588
+ return text12([
48120
48589
  `Started in the background: job \`${job.id}\`.`,
48121
48590
  `Live output: ${job.logPath}`,
48122
48591
  willNotify ? `You will be notified when it finishes \u2014 do not poll. Continue with other work, or call await_jobs(["${job.id}"]) if you cannot proceed without the result.` : `Call await_jobs(["${job.id}"]) when you need the result, or job_output("${job.id}") to read what it has produced so far.`
@@ -48153,12 +48622,12 @@ function buildHostedJobTools(registry3, opts = {}) {
48153
48622
  handler: async (args, ctx2) => {
48154
48623
  const ids = Array.isArray(args["job_ids"]) ? args["job_ids"].map(String) : [];
48155
48624
  if (ids.length === 0)
48156
- return text11("await_jobs needs at least one job id.", true);
48625
+ return text12("await_jobs needs at least one job id.", true);
48157
48626
  const unknown2 = ids.filter((id) => !registry3.list().some((j) => j.id === id) || !mine(id, ctx2?.sessionId));
48158
48627
  if (unknown2.length)
48159
- return text11(`no such job: ${unknown2.join(", ")}`, true);
48628
+ return text12(`no such job: ${unknown2.join(", ")}`, true);
48160
48629
  const jobs = await registry3.await(ids, typeof args["timeout_ms"] === "number" ? args["timeout_ms"] : 12e4);
48161
- return text11(jobs.map((j) => `${fmt(j)}
48630
+ return text12(jobs.map((j) => `${fmt(j)}
48162
48631
  ${registry3.output(j.id) || "(no output)"}`).join("\n\n"));
48163
48632
  }
48164
48633
  },
@@ -48179,10 +48648,10 @@ ${registry3.output(j.id) || "(no output)"}`).join("\n\n"));
48179
48648
  const id = String(args["job_id"] ?? "");
48180
48649
  const job = registry3.list().find((j) => j.id === id);
48181
48650
  if (!job || !mine(id, ctx2?.sessionId))
48182
- return text11(`no such job: ${id}`, true);
48651
+ return text12(`no such job: ${id}`, true);
48183
48652
  const from = typeof args["from_offset"] === "number" ? args["from_offset"] : 0;
48184
48653
  const out = registry3.output(id, from);
48185
- return text11(`${fmt(job)}
48654
+ return text12(`${fmt(job)}
48186
48655
  ${out || "(nothing yet)"}`);
48187
48656
  }
48188
48657
  },
@@ -48193,7 +48662,7 @@ ${out || "(nothing yet)"}`);
48193
48662
  annotations: { readOnlyHint: true },
48194
48663
  handler: async (_args, ctx2) => {
48195
48664
  const jobs = registry3.list().filter((j) => mine(j.id, ctx2?.sessionId)).sort((a, b) => Number(b.status === "running") - Number(a.status === "running"));
48196
- return text11(jobs.length ? jobs.map(fmt).join("\n\n") : "no jobs.");
48665
+ return text12(jobs.length ? jobs.map(fmt).join("\n\n") : "no jobs.");
48197
48666
  }
48198
48667
  },
48199
48668
  {
@@ -48203,8 +48672,8 @@ ${out || "(nothing yet)"}`);
48203
48672
  handler: async (args, ctx2) => {
48204
48673
  const id = String(args["job_id"] ?? "");
48205
48674
  if (!mine(id, ctx2?.sessionId))
48206
- return text11(`job ${id} was not running.`);
48207
- return text11(registry3.stop(id) ? `stopped job ${id}.` : `job ${id} was not running.`);
48675
+ return text12(`job ${id} was not running.`);
48676
+ return text12(registry3.stop(id) ? `stopped job ${id}.` : `job ${id} was not running.`);
48208
48677
  }
48209
48678
  }
48210
48679
  ];
@@ -48435,12 +48904,12 @@ function createNoticeDispatcher(opts) {
48435
48904
  }
48436
48905
  };
48437
48906
  }
48438
- var text11, NEVER_ASYNC;
48907
+ var text12, NEVER_ASYNC;
48439
48908
  var init_hosted_jobs = __esm({
48440
48909
  "../../packages/host-core/dist/engines/hosted-jobs.js"() {
48441
48910
  "use strict";
48442
48911
  init_jobs();
48443
- text11 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
48912
+ text12 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
48444
48913
  NEVER_ASYNC = /* @__PURE__ */ new Set(["await_jobs", "job_output", "job_list", "stop_job"]);
48445
48914
  }
48446
48915
  });
@@ -48719,7 +49188,7 @@ async function startHostedToolset(deps) {
48719
49188
  return { endpoint: endpoint2, sendBrowserResponse, tasks, ...stopOwnedJob ? { stopJob: stopOwnedJob } : {}, ...rekeyOwnedJobs ? { rekeyJobs: rekeyOwnedJobs } : {}, ...jobProbe ? { jobProbe } : {}, refresh: build };
48720
49189
  }
48721
49190
  function buildHostTaskTools(registry3, run9) {
48722
- const text12 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
49191
+ const text13 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
48723
49192
  return [
48724
49193
  {
48725
49194
  name: "tesseract_spawn_subagent",
@@ -48736,25 +49205,25 @@ function buildHostTaskTools(registry3, run9) {
48736
49205
  const description = String(args.description ?? "sub-task");
48737
49206
  const prompt2 = String(args.prompt ?? "");
48738
49207
  if (!prompt2.trim())
48739
- return text12("prompt is required", true);
49208
+ return text13("prompt is required", true);
48740
49209
  if (ctx2?.nested) {
48741
- return text12("You are already a subagent: delegating again is not allowed. Do this work yourself, or report back to the agent that spawned you.", true);
49210
+ return text13("You are already a subagent: delegating again is not allowed. Do this work yourself, or report back to the agent that spawned you.", true);
48742
49211
  }
48743
49212
  const task = registry3.start("subagent", description);
48744
49213
  task.messages.push({ role: "user", content: prompt2 });
48745
49214
  try {
48746
49215
  const out = await run9(prompt2, { signal: task.abort.signal, sessionId: ctx2?.sessionId });
48747
49216
  if (task.status === "stopped")
48748
- return text12(`Subagent "${description}" was stopped.`, true);
49217
+ return text13(`Subagent "${description}" was stopped.`, true);
48749
49218
  task.status = "done";
48750
49219
  task.result = out;
48751
49220
  task.messages.push({ role: "assistant", content: out });
48752
- return text12(out || "(the subagent returned nothing)");
49221
+ return text13(out || "(the subagent returned nothing)");
48753
49222
  } catch (e) {
48754
49223
  task.status = task.status === "stopped" ? "stopped" : "failed";
48755
49224
  const why = e instanceof Error ? e.message : String(e);
48756
49225
  task.result = why;
48757
- return text12(`Subagent "${description}" failed: ${why}`, true);
49226
+ return text13(`Subagent "${description}" failed: ${why}`, true);
48758
49227
  }
48759
49228
  }
48760
49229
  },
@@ -48765,8 +49234,8 @@ function buildHostTaskTools(registry3, run9) {
48765
49234
  handler: async () => {
48766
49235
  const rows = registry3.list();
48767
49236
  if (!rows.length)
48768
- return text12("No sub-tasks have been started.");
48769
- return text12(rows.map((t) => `${t.id} ${t.status.padEnd(7)} ${t.description}`).join("\n"));
49237
+ return text13("No sub-tasks have been started.");
49238
+ return text13(rows.map((t) => `${t.id} ${t.status.padEnd(7)} ${t.description}`).join("\n"));
48770
49239
  }
48771
49240
  },
48772
49241
  {
@@ -48779,7 +49248,7 @@ function buildHostTaskTools(registry3, run9) {
48779
49248
  },
48780
49249
  handler: async (args) => {
48781
49250
  const id = String(args.taskId ?? "");
48782
- return registry3.stop(id) ? text12(`Stopped ${id}.`) : text12(`${id} is not a running task (unknown, or already finished).`, true);
49251
+ return registry3.stop(id) ? text13(`Stopped ${id}.`) : text13(`${id} is not a running task (unknown, or already finished).`, true);
48783
49252
  }
48784
49253
  }
48785
49254
  ];
@@ -54120,24 +54589,24 @@ var require_text2 = __commonJS({
54120
54589
  }
54121
54590
  }
54122
54591
  var latin1Regex = /^[\u0000-\u00FF]*$/;
54123
- function validateLatin1(text12) {
54124
- if (!latin1Regex.test(text12)) {
54592
+ function validateLatin1(text13) {
54593
+ if (!latin1Regex.test(text13)) {
54125
54594
  throw new Error("invalid latin1 text");
54126
54595
  }
54127
54596
  }
54128
- function decodetEXt(text12, buffer, length) {
54597
+ function decodetEXt(text13, buffer, length) {
54129
54598
  const keyword = readKeyword(buffer);
54130
- text12[keyword] = readLatin1(buffer, length - keyword.length - 1);
54599
+ text13[keyword] = readLatin1(buffer, length - keyword.length - 1);
54131
54600
  }
54132
- function encodetEXt(buffer, keyword, text12) {
54601
+ function encodetEXt(buffer, keyword, text13) {
54133
54602
  validateKeyword(keyword);
54134
- validateLatin1(text12);
54135
- const length = keyword.length + 1 + text12.length;
54603
+ validateLatin1(text13);
54604
+ const length = keyword.length + 1 + text13.length;
54136
54605
  buffer.writeUint32(length);
54137
54606
  buffer.writeChars(exports.textChunkName);
54138
54607
  buffer.writeChars(keyword);
54139
54608
  buffer.writeByte(NULL);
54140
- buffer.writeChars(text12);
54609
+ buffer.writeChars(text13);
54141
54610
  (0, crc_1.writeCrc)(buffer, length + 4);
54142
54611
  }
54143
54612
  function readKeyword(buffer) {
@@ -54721,8 +55190,8 @@ var require_PngEncoder = __commonJS({
54721
55190
  }
54722
55191
  this.encodeData();
54723
55192
  if (this._png.text) {
54724
- for (const [keyword, text12] of Object.entries(this._png.text)) {
54725
- (0, text_1.encodetEXt)(this, keyword, text12);
55193
+ for (const [keyword, text13] of Object.entries(this._png.text)) {
55194
+ (0, text_1.encodetEXt)(this, keyword, text13);
54726
55195
  }
54727
55196
  }
54728
55197
  this.encodeIEND();
@@ -58908,8 +59377,8 @@ var require_build = __commonJS({
58908
59377
  var BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
58909
59378
  var BASE64URL_REGEX = /^[a-zA-Z0-9-_]+$/;
58910
59379
  var Utf8Converter = class {
58911
- static fromString(text12) {
58912
- const s = unescape(encodeURIComponent(text12));
59380
+ static fromString(text13) {
59381
+ const s = unescape(encodeURIComponent(text13));
58913
59382
  const uintArray = new Uint8Array(s.length);
58914
59383
  for (let i = 0; i < s.length; i++) {
58915
59384
  uintArray[i] = s.charCodeAt(i);
@@ -58937,11 +59406,11 @@ var require_build = __commonJS({
58937
59406
  }
58938
59407
  return res;
58939
59408
  }
58940
- static fromString(text12, littleEndian = false) {
58941
- const res = new ArrayBuffer(text12.length * 2);
59409
+ static fromString(text13, littleEndian = false) {
59410
+ const res = new ArrayBuffer(text13.length * 2);
58942
59411
  const dataView = new DataView(res);
58943
- for (let i = 0; i < text12.length; i++) {
58944
- dataView.setUint16(i * 2, text12.charCodeAt(i), littleEndian);
59412
+ for (let i = 0; i < text13.length; i++) {
59413
+ dataView.setUint16(i * 2, text13.charCodeAt(i), littleEndian);
58945
59414
  }
58946
59415
  return res;
58947
59416
  }
@@ -59038,18 +59507,18 @@ var require_build = __commonJS({
59038
59507
  static ToBase64Url(data) {
59039
59508
  return this.ToBase64(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/\=/g, "");
59040
59509
  }
59041
- static FromUtf8String(text12, encoding = _Convert.DEFAULT_UTF8_ENCODING) {
59510
+ static FromUtf8String(text13, encoding = _Convert.DEFAULT_UTF8_ENCODING) {
59042
59511
  switch (encoding) {
59043
59512
  case "ascii":
59044
- return this.FromBinary(text12);
59513
+ return this.FromBinary(text13);
59045
59514
  case "utf8":
59046
- return Utf8Converter.fromString(text12);
59515
+ return Utf8Converter.fromString(text13);
59047
59516
  case "utf16":
59048
59517
  case "utf16be":
59049
- return Utf16Converter.fromString(text12);
59518
+ return Utf16Converter.fromString(text13);
59050
59519
  case "utf16le":
59051
59520
  case "usc2":
59052
- return Utf16Converter.fromString(text12, true);
59521
+ return Utf16Converter.fromString(text13, true);
59053
59522
  default:
59054
59523
  throw new Error(`Unknown type of encoding '${encoding}'`);
59055
59524
  }
@@ -59070,11 +59539,11 @@ var require_build = __commonJS({
59070
59539
  throw new Error(`Unknown type of encoding '${encoding}'`);
59071
59540
  }
59072
59541
  }
59073
- static FromBinary(text12) {
59074
- const stringLength = text12.length;
59542
+ static FromBinary(text13) {
59543
+ const stringLength = text13.length;
59075
59544
  const resultView = new Uint8Array(stringLength);
59076
59545
  for (let i = 0; i < stringLength; i++) {
59077
- resultView[i] = text12.charCodeAt(i);
59546
+ resultView[i] = text13.charCodeAt(i);
59078
59547
  }
59079
59548
  return resultView.buffer;
59080
59549
  }
@@ -59120,8 +59589,8 @@ var require_build = __commonJS({
59120
59589
  static ToUtf16String(buffer, littleEndian = false) {
59121
59590
  return Utf16Converter.toString(buffer, littleEndian);
59122
59591
  }
59123
- static FromUtf16String(text12, littleEndian = false) {
59124
- return Utf16Converter.fromString(text12, littleEndian);
59592
+ static FromUtf16String(text13, littleEndian = false) {
59593
+ return Utf16Converter.fromString(text13, littleEndian);
59125
59594
  }
59126
59595
  static Base64Padding(base643) {
59127
59596
  const padCount = 4 - base643.length % 4;
@@ -62882,15 +63351,15 @@ var require_sequence = __commonJS({
62882
63351
  }
62883
63352
  return normalized;
62884
63353
  }
62885
- function encodeAscii(text12) {
62886
- const bytes3 = new Uint8Array(text12.length);
62887
- for (let i = 0; i < text12.length; i++) {
62888
- bytes3[i] = text12.charCodeAt(i) & 255;
63354
+ function encodeAscii(text13) {
63355
+ const bytes3 = new Uint8Array(text13.length);
63356
+ for (let i = 0; i < text13.length; i++) {
63357
+ bytes3[i] = text13.charCodeAt(i) & 255;
62889
63358
  }
62890
63359
  return bytes3;
62891
63360
  }
62892
- function encodeUtf8(text12) {
62893
- return new TextEncoder().encode(text12);
63361
+ function encodeUtf8(text13) {
63362
+ return new TextEncoder().encode(text13);
62894
63363
  }
62895
63364
  function toPatternBytes(pattern, options) {
62896
63365
  if (typeof pattern === "string") {
@@ -64265,15 +64734,15 @@ var require_binary = __commonJS({
64265
64734
  }
64266
64735
  return result;
64267
64736
  }
64268
- function decode3(text12) {
64269
- const result = new Uint8Array(text12.length);
64270
- for (let i = 0; i < text12.length; i++) {
64271
- result[i] = text12.charCodeAt(i) & 255;
64737
+ function decode3(text13) {
64738
+ const result = new Uint8Array(text13.length);
64739
+ for (let i = 0; i < text13.length; i++) {
64740
+ result[i] = text13.charCodeAt(i) & 255;
64272
64741
  }
64273
64742
  return result;
64274
64743
  }
64275
- function is(text12) {
64276
- return typeof text12 === "string";
64744
+ function is(text13) {
64745
+ return typeof text13 === "string";
64277
64746
  }
64278
64747
  exports.binary = { encode: encode3, decode: decode3, is };
64279
64748
  }
@@ -64308,31 +64777,31 @@ var require_hex = __commonJS({
64308
64777
  throw new TypeError("Hex separators must be non-empty strings");
64309
64778
  }
64310
64779
  }
64311
- function matchSeparator(text12, index, separators) {
64780
+ function matchSeparator(text13, index, separators) {
64312
64781
  for (const separator of separators) {
64313
- if (text12.startsWith(separator, index)) {
64782
+ if (text13.startsWith(separator, index)) {
64314
64783
  return separator;
64315
64784
  }
64316
64785
  }
64317
64786
  return void 0;
64318
64787
  }
64319
- function detectCase(text12) {
64320
- const hasUpper = /[A-F]/.test(text12);
64321
- const hasLower = /[a-f]/.test(text12);
64788
+ function detectCase(text13) {
64789
+ const hasUpper = /[A-F]/.test(text13);
64790
+ const hasLower = /[a-f]/.test(text13);
64322
64791
  return hasUpper && !hasLower ? "upper" : "lower";
64323
64792
  }
64324
- function detectLineSeparator(text12) {
64325
- const match = /\r\n|\n/.exec(text12);
64793
+ function detectLineSeparator(text13) {
64794
+ const match = /\r\n|\n/.exec(text13);
64326
64795
  if (!match) {
64327
64796
  return void 0;
64328
64797
  }
64329
64798
  return match[0] === "\r\n" ? "\r\n" : "\n";
64330
64799
  }
64331
- function compactForDetection(text12) {
64332
- return text12.replace(/[^0-9a-f]/gi, "");
64800
+ function compactForDetection(text13) {
64801
+ return text13.replace(/[^0-9a-f]/gi, "");
64333
64802
  }
64334
- function detectGroup(text12) {
64335
- const segments = text12.match(/[0-9A-Fa-f]+|[^0-9A-Fa-f]+/g) ?? [];
64803
+ function detectGroup(text13) {
64804
+ const segments = text13.match(/[0-9A-Fa-f]+|[^0-9A-Fa-f]+/g) ?? [];
64336
64805
  if (segments.length < 3) {
64337
64806
  return void 0;
64338
64807
  }
@@ -64360,8 +64829,8 @@ var require_hex = __commonJS({
64360
64829
  separator
64361
64830
  };
64362
64831
  }
64363
- function detectFormat(text12) {
64364
- const trimmed = text12.trim();
64832
+ function detectFormat(text13) {
64833
+ const trimmed = text13.trim();
64365
64834
  const prefix = /^0x/i.test(trimmed) ? "0x" : "";
64366
64835
  const body = prefix ? trimmed.slice(2) : trimmed;
64367
64836
  const lineSeparator = detectLineSeparator(body);
@@ -64386,13 +64855,13 @@ var require_hex = __commonJS({
64386
64855
  }
64387
64856
  return format2;
64388
64857
  }
64389
- function normalizeText(text12, options) {
64858
+ function normalizeText(text13, options) {
64390
64859
  const allowPrefix = options.allowPrefix ?? true;
64391
64860
  const separators = [...resolveSeparators(options)].sort((left, right) => right.length - left.length);
64392
64861
  for (const separator of separators) {
64393
64862
  validateSeparator(separator);
64394
64863
  }
64395
- let working = text12.trim();
64864
+ let working = text13.trim();
64396
64865
  if (/^0x/i.test(working)) {
64397
64866
  if (!allowPrefix) {
64398
64867
  throw new TypeError("Hexadecimal text must not include a 0x prefix");
@@ -64443,15 +64912,15 @@ var require_hex = __commonJS({
64443
64912
  }
64444
64913
  return chunks.join(group.separator);
64445
64914
  }
64446
- function normalize3(text12, options = {}) {
64447
- return normalizeText(text12, options);
64915
+ function normalize3(text13, options = {}) {
64916
+ return normalizeText(text13, options);
64448
64917
  }
64449
- function is(text12, options = {}) {
64450
- if (typeof text12 !== "string") {
64918
+ function is(text13, options = {}) {
64919
+ if (typeof text13 !== "string") {
64451
64920
  return false;
64452
64921
  }
64453
64922
  try {
64454
- normalize3(text12, options);
64923
+ normalize3(text13, options);
64455
64924
  return true;
64456
64925
  } catch {
64457
64926
  return false;
@@ -64461,8 +64930,8 @@ var require_hex = __commonJS({
64461
64930
  const bytes3 = (0, index_js_1.toUint8Array)(data);
64462
64931
  const casing = options.case ?? "lower";
64463
64932
  const pairs = Array.from(bytes3, (byte) => {
64464
- const text12 = byte.toString(16).padStart(2, "0");
64465
- return casing === "upper" ? text12.toUpperCase() : text12;
64933
+ const text13 = byte.toString(16).padStart(2, "0");
64934
+ return casing === "upper" ? text13.toUpperCase() : text13;
64466
64935
  });
64467
64936
  let body = "";
64468
64937
  if (options.line) {
@@ -64481,19 +64950,19 @@ var require_hex = __commonJS({
64481
64950
  }
64482
64951
  return `${options.prefix ?? ""}${body}`;
64483
64952
  }
64484
- function decode3(text12, options = {}) {
64485
- const normalized = normalize3(text12, options);
64953
+ function decode3(text13, options = {}) {
64954
+ const normalized = normalize3(text13, options);
64486
64955
  const result = new Uint8Array(normalized.length / 2);
64487
64956
  for (let i = 0; i < normalized.length; i += 2) {
64488
64957
  result[i / 2] = Number.parseInt(normalized.slice(i, i + 2), 16);
64489
64958
  }
64490
64959
  return result;
64491
64960
  }
64492
- function parse4(text12, options = {}) {
64493
- const normalized = normalize3(text12, options);
64961
+ function parse4(text13, options = {}) {
64962
+ const normalized = normalize3(text13, options);
64494
64963
  return {
64495
64964
  bytes: decode3(normalized),
64496
- format: detectFormat(text12),
64965
+ format: detectFormat(text13),
64497
64966
  normalized
64498
64967
  };
64499
64968
  }
@@ -64521,8 +64990,8 @@ var require_utf8 = __commonJS({
64521
64990
  exports.encode = encode3;
64522
64991
  exports.decode = decode3;
64523
64992
  var index_js_1 = require_bytes();
64524
- function encode3(text12) {
64525
- return new TextEncoder().encode(text12);
64993
+ function encode3(text13) {
64994
+ return new TextEncoder().encode(text13);
64526
64995
  }
64527
64996
  function decode3(data) {
64528
64997
  return new TextDecoder("utf-8", { fatal: false }).decode((0, index_js_1.toUint8Array)(data));
@@ -64540,11 +65009,11 @@ var require_utf16 = __commonJS({
64540
65009
  exports.encode = encode3;
64541
65010
  exports.decode = decode3;
64542
65011
  var index_js_1 = require_bytes();
64543
- function encode3(text12, options = {}) {
64544
- const result = new ArrayBuffer(text12.length * 2);
65012
+ function encode3(text13, options = {}) {
65013
+ const result = new ArrayBuffer(text13.length * 2);
64545
65014
  const view = new DataView(result);
64546
- for (let i = 0; i < text12.length; i++) {
64547
- view.setUint16(i * 2, text12.charCodeAt(i), options.littleEndian ?? false);
65015
+ for (let i = 0; i < text13.length; i++) {
65016
+ view.setUint16(i * 2, text13.charCodeAt(i), options.littleEndian ?? false);
64548
65017
  }
64549
65018
  return new Uint8Array(result);
64550
65019
  }
@@ -64578,18 +65047,18 @@ var require_base64 = __commonJS({
64578
65047
  function nodeBuffer() {
64579
65048
  return globalThis.Buffer;
64580
65049
  }
64581
- function normalize3(text12) {
64582
- return text12.replace(/[\n\r\t ]/g, "");
65050
+ function normalize3(text13) {
65051
+ return text13.replace(/[\n\r\t ]/g, "");
64583
65052
  }
64584
- function pad2(text12) {
64585
- const remainder = text12.length % 4;
64586
- return remainder ? text12 + "=".repeat(4 - remainder) : text12;
65053
+ function pad2(text13) {
65054
+ const remainder = text13.length % 4;
65055
+ return remainder ? text13 + "=".repeat(4 - remainder) : text13;
64587
65056
  }
64588
- function is(text12) {
64589
- if (typeof text12 !== "string") {
65057
+ function is(text13) {
65058
+ if (typeof text13 !== "string") {
64590
65059
  return false;
64591
65060
  }
64592
- const normalized = normalize3(text12);
65061
+ const normalized = normalize3(text13);
64593
65062
  return normalized === "" || BASE64_REGEX.test(normalized);
64594
65063
  }
64595
65064
  function encode3(data, _options) {
@@ -64600,8 +65069,8 @@ var require_base64 = __commonJS({
64600
65069
  }
64601
65070
  return btoa((0, binary_js_1.encode)(bytes3));
64602
65071
  }
64603
- function decode3(text12, _options) {
64604
- const normalized = normalize3(text12);
65072
+ function decode3(text13, _options) {
65073
+ const normalized = normalize3(text13);
64605
65074
  if (!is(normalized)) {
64606
65075
  throw new TypeError("Input is not valid Base64 text");
64607
65076
  }
@@ -64627,17 +65096,17 @@ var require_base64url = __commonJS({
64627
65096
  exports.decode = decode3;
64628
65097
  var base64_js_1 = require_base64();
64629
65098
  var BASE64URL_REGEX = /^[A-Za-z0-9_-]*$/;
64630
- function normalize3(text12) {
64631
- return text12.replace(/[\n\r\t ]/g, "");
65099
+ function normalize3(text13) {
65100
+ return text13.replace(/[\n\r\t ]/g, "");
64632
65101
  }
64633
- function is(text12) {
64634
- return typeof text12 === "string" && BASE64URL_REGEX.test(normalize3(text12));
65102
+ function is(text13) {
65103
+ return typeof text13 === "string" && BASE64URL_REGEX.test(normalize3(text13));
64635
65104
  }
64636
65105
  function encode3(data, _options) {
64637
65106
  return base64_js_1.base64.encode(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
64638
65107
  }
64639
- function decode3(text12, _options) {
64640
- const normalized = normalize3(text12);
65108
+ function decode3(text13, _options) {
65109
+ const normalized = normalize3(text13);
64641
65110
  if (!is(normalized)) {
64642
65111
  throw new TypeError("Input is not valid Base64Url text");
64643
65112
  }
@@ -64758,8 +65227,8 @@ var require_ip_converter = __commonJS({
64758
65227
  }
64759
65228
  return ip;
64760
65229
  }
64761
- static parseCIDR(text12) {
64762
- const [addr, prefixStr] = text12.split("/");
65230
+ static parseCIDR(text13) {
65231
+ const [addr, prefixStr] = text13.split("/");
64763
65232
  const prefix = parseInt(prefixStr, 10);
64764
65233
  if (this.isIPv4(addr)) {
64765
65234
  if (prefix < 0 || prefix > 32) {
@@ -64812,9 +65281,9 @@ var require_ip_converter = __commonJS({
64812
65281
  }
64813
65282
  return this.decodeIP(encoding_1.hex.encode(buf));
64814
65283
  }
64815
- static fromString(text12) {
64816
- if (text12.includes("/")) {
64817
- const [addr, prefix] = this.parseCIDR(text12);
65284
+ static fromString(text13) {
65285
+ if (text13.includes("/")) {
65286
+ const [addr, prefix] = this.parseCIDR(text13);
64818
65287
  const maskBytes = new Uint8Array(addr.length);
64819
65288
  let bitsLeft = prefix;
64820
65289
  for (let i = 0; i < maskBytes.length; i++) {
@@ -64831,7 +65300,7 @@ var require_ip_converter = __commonJS({
64831
65300
  out.set(maskBytes, addr.length);
64832
65301
  return out.buffer;
64833
65302
  }
64834
- const bytes3 = this.isIPv4(text12) ? this.parseIPv4(text12) : this.parseIPv6(text12);
65303
+ const bytes3 = this.isIPv4(text13) ? this.parseIPv4(text13) : this.parseIPv6(text13);
64835
65304
  return new Uint8Array(bytes3).buffer;
64836
65305
  }
64837
65306
  };
@@ -72511,24 +72980,24 @@ var require_x509_cjs = __commonJS({
72511
72980
  names.register("I", "2.5.4.43");
72512
72981
  names.register("SN", "2.5.4.4");
72513
72982
  names.register("T", "2.5.4.12");
72514
- function replaceUnknownCharacter(text12, char) {
72983
+ function replaceUnknownCharacter(text13, char) {
72515
72984
  return `\\${pvtsutils.Convert.ToHex(pvtsutils.Convert.FromUtf8String(char)).toUpperCase()}`;
72516
72985
  }
72517
72986
  function escape2(data) {
72518
72987
  return data.replace(/([,+"\\<>;])/g, "\\$1").replace(/^([ #])/, "\\$1").replace(/([ ]$)/, "\\$1").replace(/([\r\n\t])/, replaceUnknownCharacter);
72519
72988
  }
72520
72989
  var Name = class _Name {
72521
- static isASCII(text12) {
72522
- for (let i = 0; i < text12.length; i++) {
72523
- const code = text12.charCodeAt(i);
72990
+ static isASCII(text13) {
72991
+ for (let i = 0; i < text13.length; i++) {
72992
+ const code = text13.charCodeAt(i);
72524
72993
  if (code > 255) {
72525
72994
  return false;
72526
72995
  }
72527
72996
  }
72528
72997
  return true;
72529
72998
  }
72530
- static isPrintableString(text12) {
72531
- return /^[A-Za-z0-9 '()+,-./:=?]*$/g.test(text12);
72999
+ static isPrintableString(text13) {
73000
+ return /^[A-Za-z0-9 '()+,-./:=?]*$/g.test(text13);
72532
73001
  }
72533
73002
  constructor(data, extraNames = {}) {
72534
73003
  this.extraNames = new NameIdentifier();
@@ -77825,12 +78294,12 @@ function formatAddr(afi, addr) {
77825
78294
  s = s + ":";
77826
78295
  return s;
77827
78296
  }
77828
- function parsePrefix(text12) {
77829
- const slash = text12.lastIndexOf("/");
78297
+ function parsePrefix(text13) {
78298
+ const slash = text13.lastIndexOf("/");
77830
78299
  if (slash < 0)
77831
- throw new MeshCodecError("bad-value", `missing / in ${text12}`);
77832
- const host = text12.slice(0, slash);
77833
- const lenStr = text12.slice(slash + 1);
78300
+ throw new MeshCodecError("bad-value", `missing / in ${text13}`);
78301
+ const host = text13.slice(0, slash);
78302
+ const lenStr = text13.slice(slash + 1);
77834
78303
  if (!/^\d{1,3}$/.test(lenStr))
77835
78304
  throw new MeshCodecError("bad-value", `prefix len ${lenStr}`);
77836
78305
  const len = Number(lenStr);
@@ -77839,15 +78308,15 @@ function parsePrefix(text12) {
77839
78308
  throw new MeshCodecError("bad-value", `len ${len} for v${afi}`);
77840
78309
  return makePrefix(afi, mask(addr, len), len);
77841
78310
  }
77842
- function parseAddr(text12) {
77843
- if (text12.includes(":"))
77844
- return { afi: AFI_V6, addr: parseV6(text12) };
77845
- return { afi: AFI_V4, addr: parseV4(text12) };
78311
+ function parseAddr(text13) {
78312
+ if (text13.includes(":"))
78313
+ return { afi: AFI_V6, addr: parseV6(text13) };
78314
+ return { afi: AFI_V4, addr: parseV4(text13) };
77846
78315
  }
77847
- function parseV4(text12) {
77848
- const parts = text12.split(".");
78316
+ function parseV4(text13) {
78317
+ const parts = text13.split(".");
77849
78318
  if (parts.length !== 4)
77850
- throw new MeshCodecError("bad-value", `bad IPv4 ${text12}`);
78319
+ throw new MeshCodecError("bad-value", `bad IPv4 ${text13}`);
77851
78320
  const out = new Uint8Array(4);
77852
78321
  for (let i = 0; i < 4; i++) {
77853
78322
  if (!/^(0|[1-9]\d{0,2})$/.test(parts[i]))
@@ -77859,22 +78328,22 @@ function parseV4(text12) {
77859
78328
  }
77860
78329
  return out;
77861
78330
  }
77862
- function parseV6(text12) {
77863
- if (text12.includes("::")) {
77864
- const halves = text12.split("::");
78331
+ function parseV6(text13) {
78332
+ if (text13.includes("::")) {
78333
+ const halves = text13.split("::");
77865
78334
  if (halves.length !== 2)
77866
- throw new MeshCodecError("bad-value", `bad IPv6 ${text12}`);
78335
+ throw new MeshCodecError("bad-value", `bad IPv6 ${text13}`);
77867
78336
  const head = halves[0] ? halves[0].split(":") : [];
77868
78337
  const tail3 = halves[1] ? halves[1].split(":") : [];
77869
78338
  if (head.length + tail3.length > 7)
77870
- throw new MeshCodecError("bad-value", `bad IPv6 ${text12}`);
78339
+ throw new MeshCodecError("bad-value", `bad IPv6 ${text13}`);
77871
78340
  const zeros = new Array(8 - head.length - tail3.length).fill("0");
77872
- return groupsToBytes([...head, ...zeros, ...tail3], text12);
78341
+ return groupsToBytes([...head, ...zeros, ...tail3], text13);
77873
78342
  }
77874
- const g = text12.split(":");
78343
+ const g = text13.split(":");
77875
78344
  if (g.length !== 8)
77876
- throw new MeshCodecError("bad-value", `bad IPv6 ${text12}`);
77877
- return groupsToBytes(g, text12);
78345
+ throw new MeshCodecError("bad-value", `bad IPv6 ${text13}`);
78346
+ return groupsToBytes(g, text13);
77878
78347
  }
77879
78348
  function groupsToBytes(groups, orig) {
77880
78349
  if (groups.length !== 8)
@@ -85802,13 +86271,18 @@ function scheduledTurn(a) {
85802
86271
  // Absent ⇒ for a cron turn that is 'safe' (unattendedModeFor): declined rather than parked, and nothing
85803
86272
  // approved on anyone's behalf.
85804
86273
  unattended: a.target ? a.prev?.unattended : a.policy.unattended ? true : void 0,
85805
- ...a.target ? {} : { reinforcedVerification: a.policy.reinforcedVerification ? true : void 0 }
86274
+ ...a.target ? {} : { reinforcedVerification: a.policy.reinforcedVerification ? true : void 0 },
86275
+ // THE PERSON'S SETTINGS — their block rules above all — on a fire that OPENS a conversation and so has
86276
+ // no last send to replay them from. Without this the 3am run, the one nobody is watching, is the one
86277
+ // turn their rules do not reach (permission-rules.ts enforces them from exactly this field).
86278
+ ...a.target ? {} : { settings: a.policy.settings }
85806
86279
  };
85807
86280
  }
85808
86281
  function createHostedScheduling(fire) {
85809
86282
  let store = null;
85810
86283
  let isUnattended;
85811
86284
  let isVerified;
86285
+ let settings;
85812
86286
  let stopScheduler = null;
85813
86287
  let cronDeps = { pushEnabled: false };
85814
86288
  let cron = null;
@@ -85832,6 +86306,7 @@ function createHostedScheduling(fire) {
85832
86306
  stopScheduler = null;
85833
86307
  isUnattended = cfg2.isUnattended ?? isUnattended;
85834
86308
  isVerified = cfg2.isVerified ?? isVerified;
86309
+ settings = cfg2.settings ?? settings;
85835
86310
  if (!cfg2.enabled) {
85836
86311
  store = null;
85837
86312
  cronTools = [];
@@ -85871,7 +86346,11 @@ function createHostedScheduling(fire) {
85871
86346
  })();
85872
86347
  },
85873
86348
  policy() {
85874
- return { unattended: isUnattended?.() === true, reinforcedVerification: isVerified?.() === true };
86349
+ return {
86350
+ unattended: isUnattended?.() === true,
86351
+ reinforcedVerification: isVerified?.() === true,
86352
+ settings: settings?.()
86353
+ };
85875
86354
  },
85876
86355
  beginFire(taskId) {
85877
86356
  const id = `cron:${taskId}:${randomUUID12().slice(0, 8)}`;
@@ -85974,8 +86453,8 @@ function listOf(items) {
85974
86453
  const words = items.map((i) => i.text);
85975
86454
  return words.length === 1 ? words[0] : `${words.slice(0, -1).join(", ")} and ${words[words.length - 1]}`;
85976
86455
  }
85977
- function sentence(text12) {
85978
- return `${text12[0].toUpperCase()}${text12.slice(1)}`;
86456
+ function sentence(text13) {
86457
+ return `${text13[0].toUpperCase()}${text13.slice(1)}`;
85979
86458
  }
85980
86459
  function unappliedSettingsNotice(engineLabel, settings, at, inForce = {}) {
85981
86460
  const { items, protective } = unappliedSettings(settings, inForce);
@@ -86011,24 +86490,24 @@ var SHELL_TOOLS = /* @__PURE__ */ new Set(["Bash", "PowerShell", "Shell"]);
86011
86490
  var WRITE_TOOLS = /* @__PURE__ */ new Set(["Edit", "MultiEdit", "Write", "NotebookEdit"]);
86012
86491
  var READ_TOOLS = /* @__PURE__ */ new Set(["Read", "NotebookRead"]);
86013
86492
  var PATH_TOOLS = /* @__PURE__ */ new Set([...WRITE_TOOLS, ...READ_TOOLS]);
86014
- function indexOfUnescaped(text12, char) {
86015
- for (let i = 0; i < text12.length; i++) {
86016
- if (text12[i] !== char)
86493
+ function indexOfUnescaped(text13, char) {
86494
+ for (let i = 0; i < text13.length; i++) {
86495
+ if (text13[i] !== char)
86017
86496
  continue;
86018
86497
  let back = 0;
86019
- for (let j = i - 1; j >= 0 && text12[j] === "\\"; j--)
86498
+ for (let j = i - 1; j >= 0 && text13[j] === "\\"; j--)
86020
86499
  back++;
86021
86500
  if (back % 2 === 0)
86022
86501
  return i;
86023
86502
  }
86024
86503
  return -1;
86025
86504
  }
86026
- function lastIndexOfUnescaped(text12, char) {
86027
- for (let i = text12.length - 1; i >= 0; i--) {
86028
- if (text12[i] !== char)
86505
+ function lastIndexOfUnescaped(text13, char) {
86506
+ for (let i = text13.length - 1; i >= 0; i--) {
86507
+ if (text13[i] !== char)
86029
86508
  continue;
86030
86509
  let back = 0;
86031
- for (let j = i - 1; j >= 0 && text12[j] === "\\"; j--)
86510
+ for (let j = i - 1; j >= 0 && text13[j] === "\\"; j--)
86032
86511
  back++;
86033
86512
  if (back % 2 === 0)
86034
86513
  return i;
@@ -86092,12 +86571,12 @@ function rulesOutOfReach(rules, reach) {
86092
86571
  return true;
86093
86572
  });
86094
86573
  }
86095
- function ruleRequestFor(tool21, detail) {
86574
+ function ruleRequestFor(tool22, detail) {
86096
86575
  const input = detail.input ?? {};
86097
86576
  const command = commandText(input.command);
86098
86577
  const changed = Array.isArray(input.changes) ? input.changes.map((c) => typeof c?.path === "string" ? c.path : void 0) : [];
86099
86578
  const paths = [...detail.paths ?? [], detail.path, typeof input.path === "string" ? input.path : void 0, ...changed].filter((p) => typeof p === "string" && p.length > 0);
86100
- return { tool: tool21, ...command ? { command } : {}, ...paths.length ? { paths } : {} };
86579
+ return { tool: tool22, ...command ? { command } : {}, ...paths.length ? { paths } : {} };
86101
86580
  }
86102
86581
  function commandText(command) {
86103
86582
  if (typeof command === "string")
@@ -86111,9 +86590,9 @@ function describeRuleRequest(request2) {
86111
86590
  return `\`${request2.command}\``;
86112
86591
  const paths = request2.paths ?? [];
86113
86592
  if (paths.length === 1)
86114
- return paths[0];
86593
+ return `\`${paths[0]}\``;
86115
86594
  if (paths.length > 1)
86116
- return `${paths[0]} and ${paths.length - 1} more`;
86595
+ return `\`${paths[0]}\` and ${paths.length - 1} more`;
86117
86596
  return `a ${request2.tool} call`;
86118
86597
  }
86119
86598
  function toolNameForRules(kind, name) {
@@ -86127,6 +86606,8 @@ function toolNameForRules(kind, name) {
86127
86606
  case "write":
86128
86607
  case "file":
86129
86608
  case "filechange":
86609
+ case "delete":
86610
+ case "move":
86130
86611
  return "Edit";
86131
86612
  case "read":
86132
86613
  return "Read";
@@ -86157,12 +86638,13 @@ function commandCandidates(command, depth = 0) {
86157
86638
  add2(command);
86158
86639
  for (const part of splitOnOperators(command)) {
86159
86640
  add2(part);
86160
- const bare = stripPrefixes(part);
86161
- add2(bare);
86162
- if (depth < 3)
86163
- for (const inner of unwrapped(bare))
86164
- for (const c of commandCandidates(inner, depth + 1))
86165
- add2(c);
86641
+ for (const bare of [part, ...wrapperPeels(part)]) {
86642
+ add2(bare);
86643
+ if (depth < 3)
86644
+ for (const inner of unwrapped(bare))
86645
+ for (const c of commandCandidates(inner, depth + 1))
86646
+ add2(c);
86647
+ }
86166
86648
  }
86167
86649
  return [...out];
86168
86650
  }
@@ -86208,18 +86690,60 @@ function splitOnOperators(command) {
86208
86690
  parts.push(current);
86209
86691
  return parts.map((p) => p.trim()).filter(Boolean);
86210
86692
  }
86211
- function stripPrefixes(command) {
86212
- let out = command.trim();
86213
- for (let i = 0; i < 8; i++) {
86214
- const before = out;
86215
- out = out.replace(/^[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|'[^']*'|\S*)\s+/, "");
86216
- out = out.replace(/^(?:sudo|doas|command|builtin|exec|nohup|stdbuf|nice|ionice|env|xargs|time|timeout)\b\s*/, "");
86217
- out = out.replace(/^-[A-Za-z-]+[= ]?\S*\s*/, "");
86218
- out = out.replace(/^\d+(?:\.\d+)?[smhd]?\s+/, "");
86219
- if (out === before)
86220
- break;
86693
+ var WRAPPERS = /* @__PURE__ */ new Set([
86694
+ "sudo",
86695
+ "doas",
86696
+ "command",
86697
+ "builtin",
86698
+ "exec",
86699
+ "nohup",
86700
+ "stdbuf",
86701
+ "nice",
86702
+ "ionice",
86703
+ "env",
86704
+ "xargs",
86705
+ "time",
86706
+ "timeout"
86707
+ ]);
86708
+ function wrapperPeels(command) {
86709
+ const ENV = /^[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|'[^']*'|\S*)\s+/;
86710
+ const WORD = /^(\S+)\s+/;
86711
+ const out = [];
86712
+ const seen = /* @__PURE__ */ new Set();
86713
+ const queue3 = [command.trim()];
86714
+ while (queue3.length && out.length < 24) {
86715
+ const rest = queue3.shift();
86716
+ if (!rest || seen.has(rest))
86717
+ continue;
86718
+ seen.add(rest);
86719
+ const keep = (next2) => {
86720
+ if (next2) {
86721
+ out.push(next2);
86722
+ queue3.push(next2);
86723
+ }
86724
+ };
86725
+ const env = ENV.exec(rest);
86726
+ if (env) {
86727
+ keep(rest.slice(env[0].length));
86728
+ continue;
86729
+ }
86730
+ const word = WORD.exec(rest);
86731
+ if (!word)
86732
+ continue;
86733
+ const token4 = word[1];
86734
+ const isFlag = token4.startsWith("-");
86735
+ const isDuration = /^\d+(?:\.\d+)?[smhd]?$/.test(token4);
86736
+ if (!WRAPPERS.has(token4) && !isFlag && !isDuration)
86737
+ continue;
86738
+ const next = rest.slice(word[0].length);
86739
+ keep(next);
86740
+ if (isFlag) {
86741
+ const value = WORD.exec(next);
86742
+ if (value && !value[1].startsWith("-"))
86743
+ keep(next.slice(value[0].length));
86744
+ }
86221
86745
  }
86222
- return out.trim() || command.trim();
86746
+ return out;
86223
86747
  }
86224
86748
  function unwrapped(command) {
86225
86749
  const out = [];
@@ -86231,8 +86755,8 @@ function unwrapped(command) {
86231
86755
  out.push(stripQuotes(evaled[1]));
86232
86756
  return out;
86233
86757
  }
86234
- function stripQuotes(text12) {
86235
- const t = text12.trim();
86758
+ function stripQuotes(text13) {
86759
+ const t = text13.trim();
86236
86760
  if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"))
86237
86761
  return t.slice(1, -1);
86238
86762
  return t;
@@ -86259,14 +86783,14 @@ function hasWildcard(pattern) {
86259
86783
  }
86260
86784
  return false;
86261
86785
  }
86262
- function matchesWildcard(pattern, text12) {
86786
+ function matchesWildcard(pattern, text13) {
86263
86787
  const STAR = `${MARK}S${MARK}`;
86264
86788
  const BACK = `${MARK}B${MARK}`;
86265
86789
  const processed = pattern.trim().replace(/\\\*/g, STAR).replace(/\\\\/g, BACK);
86266
86790
  let regex = processed.replace(/[.+?^${}()|[\]\\'"]/g, "\\$&").replace(/\*/g, ".*").split(STAR).join("\\*").split(BACK).join("\\\\");
86267
86791
  if (regex.endsWith(" .*") && (processed.match(/\*/g) ?? []).length === 1)
86268
86792
  regex = `${regex.slice(0, -3)}( .*)?`;
86269
- return new RegExp(`^${regex}$`, "s").test(text12.trim());
86793
+ return new RegExp(`^${regex}$`, "s").test(text13.trim());
86270
86794
  }
86271
86795
  var BLOCKED_BY_RULE_NOTICE_ID = "blocked-by-rule";
86272
86796
  function blockedByRuleNotice(engineLabel, at, blocked) {
@@ -86303,10 +86827,6 @@ function opencodeBashDeny(rules) {
86303
86827
  }
86304
86828
  const prefix = /^(.+):\*$/.exec(content)?.[1];
86305
86829
  const pattern = prefix !== void 0 ? `${prefix} *` : content;
86306
- if (prefix === void 0 && !hasWildcard(content) && content.includes("*")) {
86307
- untranslated.push(rule);
86308
- continue;
86309
- }
86310
86830
  patterns.push(pattern, `sudo ${pattern}`, `xargs ${pattern}`);
86311
86831
  expressed.push(rule);
86312
86832
  }
@@ -86321,16 +86841,16 @@ function matchesPath(pattern, path6) {
86321
86841
  }
86322
86842
 
86323
86843
  // ../../packages/host-core/dist/engines/message-locator.js
86324
- function newestSentMessageWithText(messages, text12) {
86325
- if (!text12)
86844
+ function newestSentMessageWithText(messages, text13) {
86845
+ if (!text13)
86326
86846
  return void 0;
86327
86847
  for (let i = messages.length - 1; i >= 0; i--) {
86328
86848
  const m = messages[i];
86329
86849
  if (m.role !== "user" || !m.id)
86330
86850
  continue;
86331
- if (m.text === text12 || m.text.endsWith(`
86851
+ if (m.text === text13 || m.text.endsWith(`
86332
86852
 
86333
- ${text12}`))
86853
+ ${text13}`))
86334
86854
  return m.id;
86335
86855
  }
86336
86856
  return void 0;
@@ -86394,9 +86914,9 @@ async function mergeSessionsVia(deps, sessionIds, opts) {
86394
86914
  const transcripts = [];
86395
86915
  for (const sid of sessionIds) {
86396
86916
  const msgs = await deps.getMessages(sid, opts.projectDir).catch(() => []);
86397
- const text12 = transcriptToText(msgs);
86398
- if (text12)
86399
- transcripts.push(text12);
86917
+ const text13 = transcriptToText(msgs);
86918
+ if (text13)
86919
+ transcripts.push(text13);
86400
86920
  }
86401
86921
  if (transcripts.length === 0)
86402
86922
  return false;
@@ -86419,11 +86939,11 @@ import { homedir as homedir5 } from "node:os";
86419
86939
  function geminiChatsRoot(home = process.env.GEMINI_CLI_HOME || homedir5()) {
86420
86940
  return join29(home, ".gemini", "tmp");
86421
86941
  }
86422
- function parseGeminiSessionFile(file2, text12) {
86942
+ function parseGeminiSessionFile(file2, text13) {
86423
86943
  let header2 = null;
86424
86944
  let seeded = false;
86425
86945
  const messages = [];
86426
- for (const line of text12.split("\n")) {
86946
+ for (const line of text13.split("\n")) {
86427
86947
  if (!line.trim())
86428
86948
  continue;
86429
86949
  let o;
@@ -86468,8 +86988,8 @@ var fileForSession = /* @__PURE__ */ new Map();
86468
86988
  async function findGeminiSessionFile(sessionId, root = geminiChatsRoot()) {
86469
86989
  const known = fileForSession.get(sessionId);
86470
86990
  if (known) {
86471
- const text12 = await readFile10(known, "utf8").catch(() => null);
86472
- const t = text12 === null ? null : parseGeminiSessionFile(known, text12);
86991
+ const text13 = await readFile10(known, "utf8").catch(() => null);
86992
+ const t = text13 === null ? null : parseGeminiSessionFile(known, text13);
86473
86993
  if (t?.header.sessionId === sessionId)
86474
86994
  return t;
86475
86995
  fileForSession.delete(sessionId);
@@ -86484,10 +87004,10 @@ async function findGeminiSessionFile(sessionId, root = geminiChatsRoot()) {
86484
87004
  if (!f.endsWith(".jsonl"))
86485
87005
  continue;
86486
87006
  const full = join29(chats, f);
86487
- const text12 = await readFile10(full, "utf8").catch(() => null);
86488
- if (text12 === null)
87007
+ const text13 = await readFile10(full, "utf8").catch(() => null);
87008
+ if (text13 === null)
86489
87009
  continue;
86490
- const t = parseGeminiSessionFile(full, text12);
87010
+ const t = parseGeminiSessionFile(full, text13);
86491
87011
  if (t?.header.sessionId === sessionId) {
86492
87012
  fileForSession.set(sessionId, full);
86493
87013
  return t;
@@ -86558,14 +87078,14 @@ function createHostedVerification(engineId) {
86558
87078
  const anchor = plan?.trim() ? plan : finalText;
86559
87079
  if (anchor.trim())
86560
87080
  state3 = { ...state3, plan: anchor.slice(0, 4e3) };
86561
- let text12 = finalText;
87081
+ let text13 = finalText;
86562
87082
  let reviewText = "";
86563
87083
  let phaseText = "";
86564
87084
  for (let i = 0; i < rv.RV_MAX_CYCLES * 5 + 4; i++) {
86565
87085
  const gate = state3.phase === "review" ? "review" : state3.phase === "phase-review" ? "phase" : "completeness";
86566
87086
  const still = outstanding?.() ?? [];
86567
87087
  const pending2 = still.length ? still : void 0;
86568
- const call3 = gate === "review" ? rv.reviewGrade(state3, reviewText || text12, todos, pending2) : gate === "phase" ? rv.phaseGrade(state3, state3.lastVerdict?.phaseName ?? "", phaseText || text12, todos, pending2) : rv.completenessGrade(state3, text12, todos, pending2);
87088
+ const call3 = gate === "review" ? rv.reviewGrade(state3, reviewText || text13, todos, pending2) : gate === "phase" ? rv.phaseGrade(state3, state3.lastVerdict?.phaseName ?? "", phaseText || text13, todos, pending2) : rv.completenessGrade(state3, text13, todos, pending2);
86569
87089
  let verdict = null;
86570
87090
  try {
86571
87091
  verdict = rv.parseVerdict(await grade({ model, system: call3.system, prompt: call3.prompt, maxTokens: 16e3, schema: call3.schema }));
@@ -86573,16 +87093,16 @@ function createHostedVerification(engineId) {
86573
87093
  verdict = null;
86574
87094
  }
86575
87095
  if (gone())
86576
- return text12;
87096
+ return text13;
86577
87097
  if (!verdict) {
86578
87098
  standDown(state3.cycles, "The verifier did not return a usable verdict, so this run was not verified.");
86579
- return text12;
87099
+ return text13;
86580
87100
  }
86581
87101
  {
86582
87102
  const why = halt();
86583
87103
  if (why) {
86584
87104
  standDown(state3.cycles, why);
86585
- return text12;
87105
+ return text13;
86586
87106
  }
86587
87107
  }
86588
87108
  const action = rv.rvDecision(verdict, state3);
@@ -86603,45 +87123,45 @@ function createHostedVerification(engineId) {
86603
87123
  summary: verdict.summary
86604
87124
  });
86605
87125
  if (action.kind === "done" || action.kind === "capped")
86606
- return text12;
87126
+ return text13;
86607
87127
  try {
86608
87128
  if (gone())
86609
- return text12;
87129
+ return text13;
86610
87130
  {
86611
87131
  const why = halt();
86612
87132
  if (why) {
86613
87133
  standDown(state3.cycles, why);
86614
- return text12;
87134
+ return text13;
86615
87135
  }
86616
87136
  }
86617
- const before = action.kind === "review" ? reviewText : action.kind === "phase-review" ? phaseText : text12;
87137
+ const before = action.kind === "review" ? reviewText : action.kind === "phase-review" ? phaseText : text13;
86618
87138
  const reply3 = await reprompt(action.prompt);
86619
87139
  if (gone())
86620
- return text12;
87140
+ return text13;
86621
87141
  {
86622
87142
  const why = halt();
86623
87143
  if (why) {
86624
87144
  standDown(state3.cycles, why);
86625
- return text12;
87145
+ return text13;
86626
87146
  }
86627
87147
  }
86628
87148
  if (!reply3 || reply3 === before) {
86629
87149
  standDown(state3.cycles, "The agent did not produce anything new when sent back, so this run was not verified.");
86630
- return text12;
87150
+ return text13;
86631
87151
  }
86632
87152
  if (action.kind === "review")
86633
87153
  reviewText = reply3;
86634
87154
  else if (action.kind === "phase-review")
86635
87155
  phaseText = reply3;
86636
87156
  else
86637
- text12 = reply3;
87157
+ text13 = reply3;
86638
87158
  } catch {
86639
87159
  standDown(state3.cycles, "Verification could not be completed, so this run was not verified.");
86640
- return text12;
87160
+ return text13;
86641
87161
  }
86642
87162
  }
86643
87163
  emit2({ ...base, action: "capped", gate: "completeness", cycle: rv.RV_MAX_CYCLES });
86644
- return text12;
87164
+ return text13;
86645
87165
  }
86646
87166
  };
86647
87167
  }
@@ -86952,7 +87472,7 @@ function createRunTracker(opts) {
86952
87472
  }
86953
87473
  return token4;
86954
87474
  },
86955
- turnEnded(handle3, text12) {
87475
+ turnEnded(handle3, text13) {
86956
87476
  const token4 = handle3;
86957
87477
  const c = convs.get(resolve16(token4.key));
86958
87478
  if (!c)
@@ -86960,14 +87480,14 @@ function createRunTracker(opts) {
86960
87480
  c.live.delete(token4.id);
86961
87481
  const run9 = c.run;
86962
87482
  if (run9 && !run9.closed && token4.request === run9.request) {
86963
- if (text12 === null && token4.carried && run9.waiters.length > 0) {
87483
+ if (text13 === null && token4.carried && run9.waiters.length > 0) {
86964
87484
  opts.log?.(`[run] ${c.key}: the turn delivering a result failed \u2014 the run is not verified`);
86965
87485
  closeRun(c, run9, { reason: NOT_DELIVERED });
86966
87486
  gc(c);
86967
87487
  return;
86968
87488
  }
86969
- if (token4.id !== run9.gradedTurn && text12 !== null)
86970
- run9.lastText = text12;
87489
+ if (token4.id !== run9.gradedTurn && text13 !== null)
87490
+ run9.lastText = text13;
86971
87491
  if (!holdsRun(run9) && !ownTurnRunning(run9)) {
86972
87492
  run9.finishedIdle = true;
86973
87493
  finish2(c, { outcome: "finished", text: run9.lastText });
@@ -87012,7 +87532,7 @@ function createRunTracker(opts) {
87012
87532
  return items.map((i) => describe3(c, i, t, ""));
87013
87533
  return run9.waiters.length > 0 && ownTurnRunning(run9) ? ["the turn reporting the background work is still running"] : void 0;
87014
87534
  },
87015
- openRun(sessionId, task, turn, text12) {
87535
+ openRun(sessionId, task, turn, text13) {
87016
87536
  const c = conv(resolve16(sessionId));
87017
87537
  const token4 = turn;
87018
87538
  const run9 = {
@@ -87023,7 +87543,7 @@ function createRunTracker(opts) {
87023
87543
  conv: c,
87024
87544
  closed: null,
87025
87545
  waiters: [],
87026
- lastText: text12,
87546
+ lastText: text13,
87027
87547
  finishedIdle: false
87028
87548
  };
87029
87549
  if (c.lastPersonTurn > token4.id) {
@@ -88159,25 +88679,25 @@ function validate(schema, value, path6 = "$", out = []) {
88159
88679
  }
88160
88680
  return out;
88161
88681
  }
88162
- function extractJson(text12) {
88163
- const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(text12);
88164
- const candidates = [fenced?.[1], text12].filter((v) => typeof v === "string");
88682
+ function extractJson(text13) {
88683
+ const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(text13);
88684
+ const candidates = [fenced?.[1], text13].filter((v) => typeof v === "string");
88165
88685
  for (const c of candidates) {
88166
88686
  try {
88167
88687
  return JSON.parse(c.trim());
88168
88688
  } catch {
88169
88689
  }
88170
88690
  }
88171
- for (let start3 = 0; start3 < text12.length; start3++) {
88172
- const open10 = text12[start3];
88691
+ for (let start3 = 0; start3 < text13.length; start3++) {
88692
+ const open10 = text13[start3];
88173
88693
  if (open10 !== "{" && open10 !== "[")
88174
88694
  continue;
88175
88695
  const close = open10 === "{" ? "}" : "]";
88176
88696
  let depth = 0;
88177
88697
  let inStr = false;
88178
88698
  let esc3 = false;
88179
- for (let i = start3; i < text12.length; i++) {
88180
- const ch = text12[i];
88699
+ for (let i = start3; i < text13.length; i++) {
88700
+ const ch = text13[i];
88181
88701
  if (inStr) {
88182
88702
  if (esc3)
88183
88703
  esc3 = false;
@@ -88197,7 +88717,7 @@ function extractJson(text12) {
88197
88717
  depth--;
88198
88718
  if (depth === 0) {
88199
88719
  try {
88200
- return JSON.parse(text12.slice(start3, i + 1));
88720
+ return JSON.parse(text13.slice(start3, i + 1));
88201
88721
  } catch {
88202
88722
  break;
88203
88723
  }
@@ -88296,11 +88816,11 @@ function createEngineHttpApi(port, host = "127.0.0.1") {
88296
88816
  });
88297
88817
  if (!res.ok)
88298
88818
  return null;
88299
- const text12 = await res.text();
88300
- if (!text12.trim())
88819
+ const text13 = await res.text();
88820
+ if (!text13.trim())
88301
88821
  return true;
88302
88822
  try {
88303
- const parsed = JSON.parse(text12);
88823
+ const parsed = JSON.parse(text13);
88304
88824
  return parsed === null ? true : parsed;
88305
88825
  } catch {
88306
88826
  return true;
@@ -88549,7 +89069,7 @@ function createEngineTranscript(engineId) {
88549
89069
  return blocks.length ? [row(sid, "assistant", blocks)] : [];
88550
89070
  }
88551
89071
  return {
88552
- userTurn(sid, cwd, text12) {
89072
+ userTurn(sid, cwd, text13) {
88553
89073
  if (!cwd)
88554
89074
  return;
88555
89075
  cwdOf.set(sid, cwd);
@@ -88557,23 +89077,23 @@ function createEngineTranscript(engineId) {
88557
89077
  if (prev)
88558
89078
  void write2(sid, flushAssistant(sid, prev, true));
88559
89079
  open10.set(sid, { cwd, blocks: [], prose: "", reasoning: "", pending: /* @__PURE__ */ new Map() });
88560
- void write2(sid, [row(sid, "user", text12)]);
89080
+ void write2(sid, [row(sid, "user", text13)]);
88561
89081
  },
88562
- assistantText(sid, text12) {
89082
+ assistantText(sid, text13) {
88563
89083
  const t = open10.get(sid);
88564
- if (!t || !text12)
89084
+ if (!t || !text13)
88565
89085
  return;
88566
89086
  if (t.reasoning)
88567
89087
  fold(t);
88568
- t.prose += text12;
89088
+ t.prose += text13;
88569
89089
  },
88570
- thinking(sid, text12) {
89090
+ thinking(sid, text13) {
88571
89091
  const t = open10.get(sid);
88572
- if (!t || !text12)
89092
+ if (!t || !text13)
88573
89093
  return;
88574
89094
  if (t.prose)
88575
89095
  fold(t);
88576
- t.reasoning += text12;
89096
+ t.reasoning += text13;
88577
89097
  },
88578
89098
  toolUse(sid, id, name, input) {
88579
89099
  const t = open10.get(sid);
@@ -88680,13 +89200,13 @@ function createEngineTranscript(engineId) {
88680
89200
  if (!file2)
88681
89201
  return false;
88682
89202
  const run9 = (chain2.get(sid) ?? Promise.resolve()).then(async () => {
88683
- let text12;
89203
+ let text13;
88684
89204
  try {
88685
- text12 = await readFile12(file2, "utf8");
89205
+ text13 = await readFile12(file2, "utf8");
88686
89206
  } catch {
88687
89207
  return false;
88688
89208
  }
88689
- const lines = text12.split("\n");
89209
+ const lines = text13.split("\n");
88690
89210
  const cut = cutLine(lines, at);
88691
89211
  if (cut < 0)
88692
89212
  return false;
@@ -88735,8 +89255,8 @@ ${blk.text.trim()}`);
88735
89255
  else if (blk.type === "tool_use")
88736
89256
  parts.push(`[tool call: ${blk.name ?? "tool"}] ${JSON.stringify(blk.input ?? {})}`);
88737
89257
  else if (blk.type === "tool_result") {
88738
- const text12 = typeof blk.content === "string" ? blk.content : Array.isArray(blk.content) ? blk.content.map((x) => x?.text ?? "").join("\n") : "";
88739
- parts.push(`[tool result${blk.is_error ? " (error)" : ""}] ${text12.trim()}`);
89258
+ const text13 = typeof blk.content === "string" ? blk.content : Array.isArray(blk.content) ? blk.content.map((x) => x?.text ?? "").join("\n") : "";
89259
+ parts.push(`[tool result${blk.is_error ? " (error)" : ""}] ${text13.trim()}`);
88740
89260
  }
88741
89261
  }
88742
89262
  }
@@ -88877,8 +89397,8 @@ function readOutputFromLocation(u) {
88877
89397
  if (!path6)
88878
89398
  return "";
88879
89399
  try {
88880
- const text12 = readFileSync24(path6, "utf8");
88881
- return text12.length > MAX_LOCATION_READ_BYTES ? text12.slice(0, MAX_LOCATION_READ_BYTES) : text12;
89400
+ const text13 = readFileSync24(path6, "utf8");
89401
+ return text13.length > MAX_LOCATION_READ_BYTES ? text13.slice(0, MAX_LOCATION_READ_BYTES) : text13;
88882
89402
  } catch {
88883
89403
  return "";
88884
89404
  }
@@ -88995,7 +89515,8 @@ var OPENCODE_ACP = {
88995
89515
  const SAFE = `${READ},"glob":"allow","grep":"allow","lsp":"allow","todowrite":"allow"`;
88996
89516
  const KEEP_DENY = '"question":"deny","plan_enter":"deny","plan_exit":"deny"';
88997
89517
  const { patterns } = opencodeBashDeny(deny);
88998
- const BLOCK = patterns.length ? `,"bash":{${patterns.map((p) => `${JSON.stringify(p)}:"deny"`).join(",")}}` : "";
89518
+ const BLOCKED = patterns.map((p) => `${JSON.stringify(p)}:"deny"`).join(",");
89519
+ const BLOCK = BLOCKED ? `,"bash":{${BLOCKED}}` : "";
88999
89520
  switch (mode) {
89000
89521
  // Everything asks except the harmless reads — this is the mode that means "supervise me".
89001
89522
  case "default":
@@ -89008,10 +89529,12 @@ var OPENCODE_ACP = {
89008
89529
  return { OPENCODE_PERMISSION: `{"*":"ask","edit":"allow",${SAFE},${KEEP_DENY}${BLOCK}}` };
89009
89530
  // Nothing may change on disk. `deny` rather than `ask` so there is no card offering to
89010
89531
  // break the mode's promise, and no prompt for something plan mode should never do.
89011
- // No `${BLOCK}` here on purpose: a nested `bash` object would REPLACE this blanket deny (last key wins
89012
- // in one object) and the patterns it lists are narrower than "no commands at all".
89532
+ // Plan denies every command already, so the block patterns add nothing — but they are listed ANYWAY,
89533
+ // inside the same `bash` object (`{"*":"deny"}` is what a bare `"deny"` means to its matcher), because
89534
+ // "the rules went to the engine" must be true in every mode. A special case here would make the notice
89535
+ // that reads it (`blockRulesInForce`) quietly wrong the day plan mode's ruleset changes.
89013
89536
  case "plan":
89014
- return { OPENCODE_PERMISSION: `{"*":"ask","edit":"deny","bash":"deny",${SAFE},${KEEP_DENY}}` };
89537
+ return { OPENCODE_PERMISSION: `{"*":"ask","edit":"deny","bash":{"*":"deny"${BLOCKED ? `,${BLOCKED}` : ""}},${SAFE},${KEEP_DENY}}` };
89015
89538
  // bypassPermissions / dontAsk / unset ⇒ leave its own ruleset alone: both of those modes mean
89016
89539
  // "never prompt, let it run", which is what OpenCode's shipped `"*": "allow"` already is. Except for
89017
89540
  // what the person BLOCKED: Claude checks its block rules ahead of bypass (its own
@@ -89200,25 +89723,25 @@ function relFromFileUri(uri, dir2) {
89200
89723
  }
89201
89724
  function collectReplay(out, u) {
89202
89725
  const kind = u.sessionUpdate;
89203
- const text12 = u.content?.text ?? "";
89204
- if (kind === "user_message_chunk" && REPLAY_SCAFFOLD.test(text12))
89726
+ const text13 = u.content?.text ?? "";
89727
+ if (kind === "user_message_chunk" && REPLAY_SCAFFOLD.test(text13))
89205
89728
  return;
89206
89729
  const role = kind === "user_message_chunk" ? "user" : kind === "agent_message_chunk" || kind === "agent_thought_chunk" ? "assistant" : null;
89207
- if (!role || !text12)
89730
+ if (!role || !text13)
89208
89731
  return;
89209
89732
  const blockKind = kind === "agent_thought_chunk" ? "thinking" : "text";
89210
89733
  const last = out[out.length - 1];
89211
89734
  if (last && last.role === role) {
89212
89735
  const lastBlock = last.blocks?.[last.blocks.length - 1];
89213
89736
  if (lastBlock && lastBlock.kind === blockKind)
89214
- lastBlock.content += text12;
89737
+ lastBlock.content += text13;
89215
89738
  else
89216
- (last.blocks ??= []).push({ kind: blockKind, content: text12 });
89739
+ (last.blocks ??= []).push({ kind: blockKind, content: text13 });
89217
89740
  if (blockKind === "text")
89218
- last.content += text12;
89741
+ last.content += text13;
89219
89742
  return;
89220
89743
  }
89221
- out.push({ role, content: blockKind === "text" ? text12 : "", blocks: [{ kind: blockKind, content: text12 }] });
89744
+ out.push({ role, content: blockKind === "text" ? text13 : "", blocks: [{ kind: blockKind, content: text13 }] });
89222
89745
  }
89223
89746
  function readUsage(res) {
89224
89747
  const r = res ?? {};
@@ -89481,19 +90004,19 @@ function createAcpBackend(engine, send5, resolve16, services) {
89481
90004
  const origin = turn.origin;
89482
90005
  switch (u.sessionUpdate) {
89483
90006
  case "agent_message_chunk": {
89484
- const text12 = u.content?.text ?? "";
89485
- if (text12) {
89486
- turn.acc += text12;
89487
- transcript.assistantText(sid, text12);
89488
- send5({ type: "chat:stream", sessionId: sid, clientRequestId: turn.clientRequestId, messageId: turn.messageId, delta: text12, kind: "text" }, origin);
90007
+ const text13 = u.content?.text ?? "";
90008
+ if (text13) {
90009
+ turn.acc += text13;
90010
+ transcript.assistantText(sid, text13);
90011
+ send5({ type: "chat:stream", sessionId: sid, clientRequestId: turn.clientRequestId, messageId: turn.messageId, delta: text13, kind: "text" }, origin);
89489
90012
  }
89490
90013
  break;
89491
90014
  }
89492
90015
  case "agent_thought_chunk": {
89493
- const text12 = u.content?.text ?? "";
89494
- if (text12) {
89495
- transcript.thinking(sid, text12);
89496
- send5({ type: "chat:stream", sessionId: sid, clientRequestId: turn.clientRequestId, messageId: turn.messageId, delta: text12, kind: "thinking" }, origin);
90016
+ const text13 = u.content?.text ?? "";
90017
+ if (text13) {
90018
+ transcript.thinking(sid, text13);
90019
+ send5({ type: "chat:stream", sessionId: sid, clientRequestId: turn.clientRequestId, messageId: turn.messageId, delta: text13, kind: "thinking" }, origin);
89497
90020
  }
89498
90021
  break;
89499
90022
  }
@@ -90000,11 +90523,11 @@ function createAcpBackend(engine, send5, resolve16, services) {
90000
90523
  return out;
90001
90524
  }
90002
90525
  function promptBlocks(params) {
90003
- const text12 = params.message.trim() === "/compact" && engine.compactCommand ? engine.compactCommand : params.message;
90526
+ const text13 = params.message.trim() === "/compact" && engine.compactCommand ? engine.compactCommand : params.message;
90004
90527
  const seed = params.sessionId ? pendingSeed.get(params.sessionId) : void 0;
90005
90528
  const blocks = [{ type: "text", text: seed ? `${seed}
90006
90529
 
90007
- ${text12}` : text12 }];
90530
+ ${text13}` : text13 }];
90008
90531
  const skipped = [];
90009
90532
  if (!supportsCapability(declaredCaps, "attachments"))
90010
90533
  return { blocks, skipped };
@@ -90109,8 +90632,8 @@ ${text12}` : text12 }];
90109
90632
  }
90110
90633
  async function summarizeOnScratch(conn, sessionId, projectDir) {
90111
90634
  const rows = await backend2.getMessages(sessionId, projectDir).catch(() => []);
90112
- const text12 = transcriptToText(rows, 6e4);
90113
- if (!text12)
90635
+ const text13 = transcriptToText(rows, 6e4);
90636
+ if (!text13)
90114
90637
  return null;
90115
90638
  const fresh = await conn.t.request("session/new", { cwd: conn.cwd, mcpServers: [] }).catch(() => null);
90116
90639
  const scratch = fresh?.sessionId;
@@ -90128,7 +90651,7 @@ ${text12}` : text12 }];
90128
90651
  return await promptForText(conn.t, scratch, `${prompt("agent.session-summary")}
90129
90652
 
90130
90653
  --- Conversation ---
90131
- ${text12}`);
90654
+ ${text13}`);
90132
90655
  } finally {
90133
90656
  knownSessions.delete(scratch);
90134
90657
  sessionConfig.delete(scratch);
@@ -90612,8 +91135,11 @@ ${text12}`);
90612
91135
  let finishing = null;
90613
91136
  if (params.permissionMode)
90614
91137
  sessionMode.set(sid, params.permissionMode);
90615
- if (params.settings?.permissions?.deny)
90616
- sessionDeny.set(sid, params.settings.permissions.deny);
91138
+ const denyNow = params.settings?.permissions?.deny;
91139
+ if (denyNow?.length)
91140
+ sessionDeny.set(sid, denyNow);
91141
+ else
91142
+ sessionDeny.delete(sid);
90617
91143
  send5({ type: "agent:status", sessionId: sid, clientRequestId: params.clientRequestId, status: "running" }, origin);
90618
91144
  const schema = supportsCapability(declared, "structuredOutput") ? params.jsonSchema : void 0;
90619
91145
  const enforceable = schema ? canEnforce(schema) : { ok: false };
@@ -91200,13 +91726,13 @@ ${detail}` : detail, !overflow);
91200
91726
  sessionCwd.set(sessionId, projectDir);
91201
91727
  if (!conn)
91202
91728
  return { ok: false, error: `${engineLabel} is not running.` };
91203
- const text12 = await summarizeOnScratch(conn, sessionId, projectDir) ?? await (async () => {
91729
+ const text13 = await summarizeOnScratch(conn, sessionId, projectDir) ?? await (async () => {
91204
91730
  await ensureLoaded(conn, sessionId);
91205
91731
  return promptForText(conn.t, sessionId, prompt("agent.session-summary"));
91206
91732
  })();
91207
- if (!text12)
91733
+ if (!text13)
91208
91734
  return { ok: false, error: `${engineLabel} could not summarise this conversation.` };
91209
- const { title, summary } = parseSummaryReply(text12);
91735
+ const { title, summary } = parseSummaryReply(text13);
91210
91736
  if (title)
91211
91737
  sessionTitles.set(sessionId, title);
91212
91738
  if (title)
@@ -91474,8 +92000,8 @@ ${detail}` : detail, !overflow);
91474
92000
  const seenIds = /* @__PURE__ */ new Set();
91475
92001
  let idx = 0;
91476
92002
  for (const m of log10.messages) {
91477
- const text12 = geminiMessageText(m);
91478
- if (!text12 || REPLAY_SCAFFOLD.test(text12))
92003
+ const text13 = geminiMessageText(m);
92004
+ if (!text13 || REPLAY_SCAFFOLD.test(text13))
91479
92005
  continue;
91480
92006
  if (m.id && seenIds.has(m.id))
91481
92007
  continue;
@@ -91485,7 +92011,7 @@ ${detail}` : detail, !overflow);
91485
92011
  const uuid3 = m.id ?? `acp-user-${idx}`;
91486
92012
  if (role === "user")
91487
92013
  idx++;
91488
- rows.push({ role, content: text12, uuid: uuid3, blocks: [{ kind: "text", content: text12 }] });
92014
+ rows.push({ role, content: text13, uuid: uuid3, blocks: [{ kind: "text", content: text13 }] });
91489
92015
  }
91490
92016
  if (rows.length > 0) {
91491
92017
  const firstUser2 = rows.find((r) => r.role === "user")?.content?.trim();
@@ -91602,20 +92128,20 @@ function codexTranscriptRows(turns, textOf) {
91602
92128
  const kind = String(it.type ?? "");
91603
92129
  if (kind && kind !== "userMessage" && kind !== "agentMessage")
91604
92130
  continue;
91605
- const text12 = textOf(it);
91606
- if (!text12)
92131
+ const text13 = textOf(it);
92132
+ if (!text13)
91607
92133
  continue;
91608
92134
  const role = String(it.role ?? (kind === "userMessage" ? "user" : "assistant")) === "user" ? "user" : "assistant";
91609
92135
  const last = rows[rows.length - 1];
91610
92136
  if (last && last.role === role) {
91611
92137
  last.content += `
91612
- ${text12}`;
92138
+ ${text13}`;
91613
92139
  if (last.turns[last.turns.length - 1] !== ti)
91614
92140
  last.turns.push(ti);
91615
92141
  continue;
91616
92142
  }
91617
92143
  const uuid3 = typeof it.id === "string" && it.id ? it.id : void 0;
91618
- rows.push({ role, content: text12, ...uuid3 ? { uuid: uuid3 } : {}, turns: [ti] });
92144
+ rows.push({ role, content: text13, ...uuid3 ? { uuid: uuid3 } : {}, turns: [ti] });
91619
92145
  }
91620
92146
  });
91621
92147
  return rows;
@@ -91833,9 +92359,9 @@ function itemToolName(item) {
91833
92359
  case "webSearch":
91834
92360
  return "WebSearch";
91835
92361
  case "mcpToolCall": {
91836
- const tool21 = String(i.tool ?? "tool");
92362
+ const tool22 = String(i.tool ?? "tool");
91837
92363
  const server2 = String(i.server ?? "");
91838
- return server2 ? `${server2}_${tool21}` : tool21;
92364
+ return server2 ? `${server2}_${tool22}` : tool22;
91839
92365
  }
91840
92366
  case "dynamicToolCall":
91841
92367
  return String(i.tool ?? "tool");
@@ -92192,8 +92718,8 @@ function createCodexAppServerBackend(send5, resolve16, services) {
92192
92718
  subagentSinks.delete(scratch);
92193
92719
  subagentDone.delete(scratch);
92194
92720
  }
92195
- const text12 = out.join("").trim();
92196
- return text12 || null;
92721
+ const text13 = out.join("").trim();
92722
+ return text13 || null;
92197
92723
  }
92198
92724
  const pendingApprovals = /* @__PURE__ */ new Map();
92199
92725
  const pendingDialogs = /* @__PURE__ */ new Map();
@@ -92218,8 +92744,6 @@ function createCodexAppServerBackend(send5, resolve16, services) {
92218
92744
  const settled = turn ? runningTurnApprovalAnswer(modeNow, turn.sandbox) : "ask";
92219
92745
  if (settled === "allow")
92220
92746
  return Promise.resolve(allow);
92221
- if (settled === "deny")
92222
- return Promise.resolve(deny);
92223
92747
  const requestId = randomUUID17();
92224
92748
  return new Promise((resolveOutcome) => {
92225
92749
  pendingApprovals.set(requestId, { resolve: resolveOutcome, threadId, allow, allowPersist, deny });
@@ -92547,7 +93071,11 @@ function createCodexAppServerBackend(send5, resolve16, services) {
92547
93071
  });
92548
93072
  t.onRequest("item/fileChange/requestApproval", (raw) => {
92549
93073
  const p = raw ?? {};
92550
- return parkApproval(raw, "Edit", { decision: "accept" }, { decision: "acceptForSession" }, { decision: "decline" }, { title: p.reason, path: p.grantRoot });
93074
+ return parkApproval(raw, "Edit", { decision: "accept" }, { decision: "acceptForSession" }, { decision: "decline" }, {
93075
+ title: p.reason,
93076
+ path: p.grantRoot,
93077
+ input: { changes: p.changes, path: p.path }
93078
+ });
92551
93079
  });
92552
93080
  t.onRequest("item/permissions/requestApproval", (raw) => parkApproval(raw, "Permissions", { decision: "accept" }, { decision: "acceptForSession" }, { decision: "decline" }, { title: "Codex is requesting additional permissions" }));
92553
93081
  t.onRequest("execCommandApproval", (raw) => {
@@ -92556,7 +93084,11 @@ function createCodexAppServerBackend(send5, resolve16, services) {
92556
93084
  });
92557
93085
  t.onRequest("applyPatchApproval", (raw) => {
92558
93086
  const p = raw ?? {};
92559
- return parkApproval(raw, "Edit", { decision: "accept" }, { decision: "acceptForSession" }, { decision: "decline" }, { title: p.reason });
93087
+ return parkApproval(raw, "Edit", { decision: "accept" }, { decision: "acceptForSession" }, { decision: "decline" }, {
93088
+ title: p.reason,
93089
+ path: p.grantRoot,
93090
+ input: { changes: p.changes ?? p.fileChanges }
93091
+ });
92560
93092
  });
92561
93093
  t.onRequest("item/tool/requestUserInput", (raw) => {
92562
93094
  const p = raw ?? {};
@@ -93610,13 +94142,13 @@ function createCodexAppServerBackend(send5, resolve16, services) {
93610
94142
  */
93611
94143
  summarizeSession: async (sessionId, projectDir) => {
93612
94144
  const msgs = await backend2.getMessages(sessionId, threadCwd.get(sessionId) ?? spawnedCwd ?? projectDir).catch(() => []);
93613
- const text12 = transcriptToText(msgs, 6e4);
93614
- if (!text12)
94145
+ const text13 = transcriptToText(msgs, 6e4);
94146
+ if (!text13)
93615
94147
  return { ok: false, error: "That conversation has nothing to summarise yet." };
93616
94148
  const reply3 = await promptScratchThread(`${prompt("agent.session-summary")}
93617
94149
 
93618
94150
  --- Conversation ---
93619
- ${text12}`, threadCwd.get(sessionId) ?? spawnedCwd ?? projectDir);
94151
+ ${text13}`, threadCwd.get(sessionId) ?? spawnedCwd ?? projectDir);
93620
94152
  if (!reply3)
93621
94153
  return { ok: false, error: `${label} could not summarise this conversation.` };
93622
94154
  const { title, summary } = parseSummaryReply(reply3);
@@ -93729,8 +94261,8 @@ var seq = 0;
93729
94261
  var now = () => (/* @__PURE__ */ new Date()).toISOString();
93730
94262
  var ctx = [];
93731
94263
  var CTX_MAX = 60;
93732
- function pushCtx(role, text12) {
93733
- const t = (text12 ?? "").trim();
94264
+ function pushCtx(role, text13) {
94265
+ const t = (text13 ?? "").trim();
93734
94266
  if (!t)
93735
94267
  return;
93736
94268
  ctx.push({ role, text: t.length > 300 ? `${t.slice(0, 300)}\u2026` : t });
@@ -93996,23 +94528,23 @@ var HostPluginApi = class {
93996
94528
  secret(envKey2) {
93997
94529
  return this.secretResolver(this.pluginId, envKey2);
93998
94530
  }
93999
- registerTool(tool21) {
94531
+ registerTool(tool22) {
94000
94532
  const prefix = this.pluginId.replace(/[^a-zA-Z0-9_]/g, "_");
94001
- const name = tool21.name.startsWith(`${prefix}_`) ? tool21.name : `${prefix}_${tool21.name}`;
94002
- this.registry.tools.push({ ...tool21, name });
94533
+ const name = tool22.name.startsWith(`${prefix}_`) ? tool22.name : `${prefix}_${tool22.name}`;
94534
+ this.registry.tools.push({ ...tool22, name });
94003
94535
  }
94004
- registerUiTool(tool21) {
94005
- if (!this.requireGrant("surfaces", `UI tool "${tool21.name}"`))
94536
+ registerUiTool(tool22) {
94537
+ if (!this.requireGrant("surfaces", `UI tool "${tool22.name}"`))
94006
94538
  return;
94007
94539
  const prefix = this.pluginId.replace(/[^a-zA-Z0-9_]/g, "_");
94008
- const name = tool21.name.startsWith(`${prefix}_`) ? tool21.name : `${prefix}_${tool21.name}`;
94540
+ const name = tool22.name.startsWith(`${prefix}_`) ? tool22.name : `${prefix}_${tool22.name}`;
94009
94541
  const tier = this.hasGrant("customUI") ? "verified" : "third-party";
94010
94542
  this.registry.tools.push({
94011
94543
  name,
94012
- description: tool21.description,
94013
- inputSchema: tool21.inputSchema,
94014
- handler: async (args) => toResult(await tool21.handler(args, NOOP_UI_CTX)),
94015
- __ctxHandler: async (args, ctx2) => toResult(await tool21.handler(args, ctx2)),
94544
+ description: tool22.description,
94545
+ inputSchema: tool22.inputSchema,
94546
+ handler: async (args) => toResult(await tool22.handler(args, NOOP_UI_CTX)),
94547
+ __ctxHandler: async (args, ctx2) => toResult(await tool22.handler(args, ctx2)),
94016
94548
  __tier: tier
94017
94549
  });
94018
94550
  }
@@ -94122,8 +94654,8 @@ function createOpenClawAdapter(pluginId, config2, secretResolver, registry3) {
94122
94654
  pluginId,
94123
94655
  config: config2,
94124
94656
  secret: (envKey2) => secretResolver(pluginId, envKey2),
94125
- registerTool: (tool21) => {
94126
- const got = typeof tool21 === "function" ? tool21({}) : tool21;
94657
+ registerTool: (tool22) => {
94658
+ const got = typeof tool22 === "function" ? tool22({}) : tool22;
94127
94659
  const arr = Array.isArray(got) ? got : got ? [got] : [];
94128
94660
  for (const t of arr) {
94129
94661
  const c = convertTool(t);
@@ -95589,8 +96121,8 @@ init_prompts();
95589
96121
  // ../../packages/voice-core/dist/pipeline/history.js
95590
96122
  function formatHistoryLines(turns, maxLineChars = 300) {
95591
96123
  return turns.map((t) => {
95592
- const text12 = t.text.replace(/\s+/g, " ").trim();
95593
- const capped = text12.length > maxLineChars ? text12.slice(0, maxLineChars - 1).trimEnd() + "\u2026" : text12;
96124
+ const text13 = t.text.replace(/\s+/g, " ").trim();
96125
+ const capped = text13.length > maxLineChars ? text13.slice(0, maxLineChars - 1).trimEnd() + "\u2026" : text13;
95594
96126
  return `${t.role.toUpperCase()}: ${capped}`;
95595
96127
  }).join("\n");
95596
96128
  }
@@ -95885,15 +96417,15 @@ ${truncate(input.result, 4e3)}`
95885
96417
  }
95886
96418
  };
95887
96419
  function ruleBasedTurn(input) {
95888
- const text12 = input.result.trim();
95889
- const lower = text12.toLowerCase();
96420
+ const text13 = input.result.trim();
96421
+ const lower = text13.toLowerCase();
95890
96422
  let status2 = "done";
95891
96423
  if (/\b(error|failed|could not|cannot|unable to)\b/.test(lower))
95892
96424
  status2 = "error";
95893
- else if (text12.endsWith("?") || /\b(which|should i|do you want|would you like|please confirm|clarif)\b/.test(lower)) {
96425
+ else if (text13.endsWith("?") || /\b(which|should i|do you want|would you like|please confirm|clarif)\b/.test(lower)) {
95894
96426
  status2 = "needs_input";
95895
96427
  }
95896
- const line = firstSentences(stripForSpeech(text12)) || input.recentActivity.slice(-1)[0] || "Done.";
96428
+ const line = firstSentences(stripForSpeech(text13)) || input.recentActivity.slice(-1)[0] || "Done.";
95897
96429
  return { line, status: status2 };
95898
96430
  }
95899
96431
  function stripForSpeech(s) {
@@ -95971,8 +96503,8 @@ var VoiceGuideOrchestrator = class {
95971
96503
  /** The bridge feeds every finalized transcript line here (capped buffer). An
95972
96504
  * assistant line means the guide finished speaking — drain the next queued
95973
96505
  * update immediately instead of waiting out the gap timer. */
95974
- noteTranscript(role, text12) {
95975
- const t = text12.trim();
96506
+ noteTranscript(role, text13) {
96507
+ const t = text13.trim();
95976
96508
  if (!t)
95977
96509
  return;
95978
96510
  this.conversation.push({ role, text: t });
@@ -96506,26 +97038,26 @@ Additional context: ${context}` : task;
96506
97038
  this.deps.emit({ type: "voice:milestone", text: spoken });
96507
97039
  this.say(spoken, { urgent: focused });
96508
97040
  }
96509
- speakMilestone(text12) {
96510
- this.deps.emit({ type: "voice:milestone", text: text12 });
96511
- this.say(text12);
97041
+ speakMilestone(text13) {
97042
+ this.deps.emit({ type: "voice:milestone", text: text13 });
97043
+ this.say(text13);
96512
97044
  }
96513
97045
  // ── One mouth, N sessions: serialized speech ───────────────────────────────
96514
97046
  /** Speak `text`, serializing non-urgent lines so concurrent sessions don't
96515
97047
  * talk over each other. Urgent lines (blocking questions, the focused
96516
97048
  * session's result, critical notices) always go out immediately. */
96517
- say(text12, opts = {}) {
96518
- if (!text12)
97049
+ say(text13, opts = {}) {
97050
+ if (!text13)
96519
97051
  return;
96520
97052
  const now2 = this.now();
96521
97053
  if (opts.urgent || this.sayQueue.length === 0 && now2 - this.lastSayAt >= SPEAK_GAP_MS) {
96522
97054
  this.lastSayAt = now2;
96523
- this.voice?.speakNow(text12);
97055
+ this.voice?.speakNow(text13);
96524
97056
  return;
96525
97057
  }
96526
97058
  if (this.sayQueue.length >= SPEAK_QUEUE_CAP)
96527
97059
  this.sayQueue.shift();
96528
- this.sayQueue.push(text12);
97060
+ this.sayQueue.push(text13);
96529
97061
  this.armSayTimer();
96530
97062
  }
96531
97063
  armSayTimer() {
@@ -96656,11 +97188,11 @@ var ClientProxyProvider = class {
96656
97188
  /** Audio is client↔provider direct — the daemon never sees mic/model PCM. */
96657
97189
  sendAudio(_pcm24k) {
96658
97190
  }
96659
- respondToTool(callId, text12, isError) {
96660
- this.deps.send({ type: "voice:cd:respondToTool", callId, text: text12, isError });
97191
+ respondToTool(callId, text13, isError) {
97192
+ this.deps.send({ type: "voice:cd:respondToTool", callId, text: text13, isError });
96661
97193
  }
96662
- speakNow(text12) {
96663
- this.deps.send({ type: "voice:cd:speak", text: text12 });
97194
+ speakNow(text13) {
97195
+ this.deps.send({ type: "voice:cd:speak", text: text13 });
96664
97196
  }
96665
97197
  close() {
96666
97198
  this.settleConnect(new Error("closed before connect"));
@@ -96680,11 +97212,11 @@ var ClientProxyProvider = class {
96680
97212
  handleToolCall(inv) {
96681
97213
  this.cb.onToolCall(inv);
96682
97214
  }
96683
- handleTranscript(speaker, text12) {
97215
+ handleTranscript(speaker, text13) {
96684
97216
  if (speaker === "user")
96685
- this.cb.onUserTranscript(text12);
97217
+ this.cb.onUserTranscript(text13);
96686
97218
  else
96687
- this.cb.onAgentTranscript(text12);
97219
+ this.cb.onAgentTranscript(text13);
96688
97220
  }
96689
97221
  handleProviderEvent(event, message) {
96690
97222
  switch (event) {
@@ -96916,10 +97448,10 @@ var VoiceControl = class {
96916
97448
  * injection as a user turn and comments on every slide change, which is exactly the
96917
97449
  * running commentary the silence contract forbids.
96918
97450
  */
96919
- injectPresentContext(text12) {
97451
+ injectPresentContext(text13) {
96920
97452
  if (this.ended)
96921
97453
  return;
96922
- this.deps.send({ type: "voice:cd:inject", text: text12, turnComplete: false });
97454
+ this.deps.send({ type: "voice:cd:inject", text: text13, turnComplete: false });
96923
97455
  }
96924
97456
  /**
96925
97457
  * A typed question from the phone, routed as if it had been spoken.
@@ -96927,33 +97459,33 @@ var VoiceControl = class {
96927
97459
  * This one DOES form a turn (turnComplete left at its default): unlike slide context,
96928
97460
  * the presenter is deliberately addressing the assistant and is waiting for an answer.
96929
97461
  */
96930
- askPresent(text12) {
97462
+ askPresent(text13) {
96931
97463
  if (this.ended)
96932
97464
  return;
96933
- this.deps.send({ type: "voice:cd:inject", text: `(The presenter asks you directly: ${text12})` });
97465
+ this.deps.send({ type: "voice:cd:inject", text: `(The presenter asks you directly: ${text13})` });
96934
97466
  }
96935
97467
  async runPresentControl(callId, name, args) {
96936
- let text12 = "";
97468
+ let text13 = "";
96937
97469
  let silent = false;
96938
97470
  let clearPlayback = false;
96939
97471
  let isError = false;
96940
97472
  try {
96941
97473
  const r = await this.deps.execPresentControl(name, args);
96942
- text12 = r.text;
97474
+ text13 = r.text;
96943
97475
  silent = r.silent;
96944
97476
  clearPlayback = r.clearPlayback === true;
96945
97477
  } catch (e) {
96946
- text12 = e instanceof Error ? e.message : "presentation action failed";
97478
+ text13 = e instanceof Error ? e.message : "presentation action failed";
96947
97479
  isError = true;
96948
97480
  }
96949
- log(`voice: present-control ${name} \u2192 ${isError ? "ERROR " : ""}${text12}`);
96950
- recordEvent("tool_result", { name, text: text12, isError });
97481
+ log(`voice: present-control ${name} \u2192 ${isError ? "ERROR " : ""}${text13}`);
97482
+ recordEvent("tool_result", { name, text: text13, isError });
96951
97483
  if (clearPlayback && !isError)
96952
97484
  this.deps.send({ type: "voice:clearPlayback" });
96953
- this.deps.send({ type: "voice:cd:respondToTool", callId, text: text12, isError, silent: silent && !isError });
97485
+ this.deps.send({ type: "voice:cd:respondToTool", callId, text: text13, isError, silent: silent && !isError });
96954
97486
  }
96955
97487
  async runScreenControl(callId, name, args) {
96956
- let text12;
97488
+ let text13;
96957
97489
  let isError = false;
96958
97490
  let finished = false, nudges = 0;
96959
97491
  let slowTimer = null;
@@ -96969,18 +97501,18 @@ var VoiceControl = class {
96969
97501
  };
96970
97502
  scheduleNudge(2e4);
96971
97503
  try {
96972
- text12 = await this.deps.execScreenControl(name, args);
97504
+ text13 = await this.deps.execScreenControl(name, args);
96973
97505
  } catch (e) {
96974
- text12 = e instanceof Error ? e.message : "screen action failed";
97506
+ text13 = e instanceof Error ? e.message : "screen action failed";
96975
97507
  isError = true;
96976
97508
  } finally {
96977
97509
  finished = true;
96978
97510
  if (slowTimer)
96979
97511
  clearTimeout(slowTimer);
96980
97512
  }
96981
- log(`voice: screen-control ${name} \u2192 ${isError ? "ERROR " : ""}${text12}`);
96982
- recordEvent("tool_result", { name, text: text12, isError });
96983
- this.deps.send({ type: "voice:cd:respondToTool", callId, text: text12, isError });
97513
+ log(`voice: screen-control ${name} \u2192 ${isError ? "ERROR " : ""}${text13}`);
97514
+ recordEvent("tool_result", { name, text: text13, isError });
97515
+ this.deps.send({ type: "voice:cd:respondToTool", callId, text: text13, isError });
96984
97516
  }
96985
97517
  async start(msg) {
96986
97518
  if (this.starting)
@@ -97118,13 +97650,13 @@ ${priorText}` : "";
97118
97650
  const callbacks = {
97119
97651
  onOutputAudio: () => {
97120
97652
  },
97121
- onUserTranscript: (text12) => {
97122
- orchestrator.noteTranscript("user", text12);
97123
- this.deps.send({ type: "voice:transcript", speaker: "user", text: text12 });
97653
+ onUserTranscript: (text13) => {
97654
+ orchestrator.noteTranscript("user", text13);
97655
+ this.deps.send({ type: "voice:transcript", speaker: "user", text: text13 });
97124
97656
  },
97125
- onAgentTranscript: (text12) => {
97126
- orchestrator.noteTranscript("assistant", text12);
97127
- this.deps.send({ type: "voice:transcript", speaker: "agent", text: text12 });
97657
+ onAgentTranscript: (text13) => {
97658
+ orchestrator.noteTranscript("assistant", text13);
97659
+ this.deps.send({ type: "voice:transcript", speaker: "agent", text: text13 });
97128
97660
  },
97129
97661
  onToolCall: (inv) => orchestrator.handleToolCall(inv),
97130
97662
  onInterruption: () => this.deps.send({ type: "voice:clearPlayback" }),
@@ -97996,7 +98528,7 @@ var GeminiVeoProvider = class {
97996
98528
  };
97997
98529
 
97998
98530
  // ../../packages/video-core/dist/tesseract.js
97999
- var DEFAULT_MODEL4 = "tsr-video";
98531
+ var DEFAULT_MODEL4 = "veo-3.1-fast-generate-preview";
98000
98532
  var REQUEST_TIMEOUT_MS2 = 9e4;
98001
98533
  var DOWNLOAD_TIMEOUT_MS2 = 18e4;
98002
98534
  var withTimeout4 = (signal2, ms) => signal2 ?? AbortSignal.timeout(ms);
@@ -98490,7 +99022,7 @@ var fmtTime = (sec) => {
98490
99022
  cs -= s * 100;
98491
99023
  return `${h}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}.${String(cs).padStart(2, "0")}`;
98492
99024
  };
98493
- var escapeAss = (text12) => text12.replace(/\\/g, "\\\\").replace(/\{/g, "(").replace(/\}/g, ")").replace(/\r?\n/g, "\\N");
99025
+ var escapeAss = (text13) => text13.replace(/\\/g, "\\\\").replace(/\{/g, "(").replace(/\}/g, ")").replace(/\r?\n/g, "\\N");
98494
99026
  function buildAssSubtitles(cues, style, width, height) {
98495
99027
  const base = Math.round(height / 14);
98496
99028
  const styles = style === "tiktok-bold" ? `Style: Cap,Arial Black,${base},&H00FFFFFF,&H000000FF,&H00000000,&H96000000,-1,0,0,0,100,100,0,0,1,${Math.max(2, Math.round(base / 9))},0,2,60,60,${Math.round(height / 5)},1` : `Style: Cap,Arial,${Math.round(base * 0.72)},&H00FFFFFF,&H000000FF,&H00000000,&H64000000,-1,0,0,0,100,100,0,0,1,2,1,2,40,40,${Math.round(height / 12)},1`;
@@ -99101,7 +99633,7 @@ async function cloneVoiceElevenLabs(name, samples, cfg2, opts) {
99101
99633
  throw new Error("ElevenLabs clone returned no voice_id.");
99102
99634
  return { voiceId: j.voice_id, name: j.name ?? name };
99103
99635
  }
99104
- async function synthesizeSpeechElevenLabs(text12, voiceId, cfg2, opts) {
99636
+ async function synthesizeSpeechElevenLabs(text13, voiceId, cfg2, opts) {
99105
99637
  const base = (cfg2.baseUrl?.trim() || BASE_URL).replace(/\/+$/, "");
99106
99638
  const settings = {};
99107
99639
  if (cfg2.stability != null)
@@ -99115,7 +99647,7 @@ async function synthesizeSpeechElevenLabs(text12, voiceId, cfg2, opts) {
99115
99647
  res = await fetch(`${base}/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=mp3_44100_128`, {
99116
99648
  method: "POST",
99117
99649
  headers: { "xi-api-key": cfg2.apiKey, "Content-Type": "application/json" },
99118
- body: JSON.stringify({ text: text12, model_id: cfg2.model?.trim() || DEFAULT_TTS_MODEL, ...Object.keys(settings).length ? { voice_settings: settings } : {} }),
99650
+ body: JSON.stringify({ text: text13, model_id: cfg2.model?.trim() || DEFAULT_TTS_MODEL, ...Object.keys(settings).length ? { voice_settings: settings } : {} }),
99119
99651
  signal: opts?.signal ?? AbortSignal.timeout(12e4)
99120
99652
  });
99121
99653
  } catch (e) {
@@ -99207,8 +99739,8 @@ var VIDEO_PROVIDERS = [
99207
99739
  {
99208
99740
  id: "tesseract",
99209
99741
  label: "Tesseract \xB7 free (no key)",
99210
- defaultModel: "tsr-video",
99211
- models: ["tsr-video"],
99742
+ defaultModel: "veo-3.1-fast-generate-preview",
99743
+ models: ["veo-3.1-fast-generate-preview"],
99212
99744
  keysUrl: "",
99213
99745
  free: true
99214
99746
  },
@@ -99474,7 +100006,7 @@ var IN_TURN_WAIT_MS = 8 * 6e4;
99474
100006
  var HEARTBEAT_MS2 = 15e3;
99475
100007
  var FAST_MODEL = VIDEO_PROVIDERS.find((p) => p.id === "google").defaultModel;
99476
100008
  var STANDARD_MODEL = "veo-3.1-generate-preview";
99477
- var FREE_MODEL = "tsr-video";
100009
+ var FREE_MODEL = "veo-3.1-fast-generate-preview";
99478
100010
  var clampDuration2 = (n) => [4, 6, 8].reduce((best, d) => Math.abs(d - n) < Math.abs(best - n) ? d : best);
99479
100011
  function creds2() {
99480
100012
  return readDaemonAgentSettings().videoGen;
@@ -100518,11 +101050,11 @@ async function geminiJson(opts) {
100518
101050
  const json3 = await res.json().catch(() => ({}));
100519
101051
  if (!res.ok)
100520
101052
  throw new Error(json3.error?.message ?? `Gemini request failed (${res.status})`);
100521
- const text12 = json3.candidates?.[0]?.content?.parts?.map((p) => p.text ?? "").join("") ?? "";
101053
+ const text13 = json3.candidates?.[0]?.content?.parts?.map((p) => p.text ?? "").join("") ?? "";
100522
101054
  try {
100523
- return JSON.parse(text12);
101055
+ return JSON.parse(text13);
100524
101056
  } catch {
100525
- throw new Error(`Gemini returned non-JSON transcription output: ${text12.slice(0, 200)}`);
101057
+ throw new Error(`Gemini returned non-JSON transcription output: ${text13.slice(0, 200)}`);
100526
101058
  }
100527
101059
  }
100528
101060
  async function transcribeMedia(opts) {
@@ -100656,7 +101188,7 @@ function resolveAvatarCreds(snap, keyFile, envKey2) {
100656
101188
  function heygenCreds() {
100657
101189
  return resolveAvatarCreds(readDaemonAgentSettings(), readDaemonKeyFile("heygen.key"), process.env.HEYGEN_API_KEY ?? null);
100658
101190
  }
100659
- var NO_AVATAR_CREDS = "Avatar videos need either a HeyGen API key (add it in Settings, or set HEYGEN_API_KEY) or a signed-in Tesseract account for the free tier.";
101191
+ var NO_AVATAR_CREDS = "Avatar videos need a HeyGen API key \u2014 add one in Settings, or set HEYGEN_API_KEY. The free tier covers this only when you are signed in AND this server has HeyGen access; one of those is missing here.";
100660
101192
  function readDaemonKeyFile(name) {
100661
101193
  try {
100662
101194
  const home = tesseractHome();
@@ -100875,12 +101407,12 @@ function createDaemonVideoEditRunner() {
100875
101407
  return { ok: false, error: err(e) };
100876
101408
  }
100877
101409
  },
100878
- async synthesizeSpeech(text12, voiceId, outDir, opts) {
101410
+ async synthesizeSpeech(text13, voiceId, outDir, opts) {
100879
101411
  const apiKey = elevenLabsKey();
100880
101412
  if (!apiKey)
100881
101413
  return { ok: false, error: "Text-to-speech needs an ElevenLabs key (Settings \u2192 Voice)." };
100882
101414
  try {
100883
- const audio = await synthesizeSpeechElevenLabs(text12, voiceId, { apiKey, stability: opts?.stability, similarityBoost: opts?.similarityBoost, speed: opts?.speed });
101415
+ const audio = await synthesizeSpeechElevenLabs(text13, voiceId, { apiKey, stability: opts?.stability, similarityBoost: opts?.similarityBoost, speed: opts?.speed });
100884
101416
  const dir2 = outDir ?? join48(musicDir2(), randomUUID24());
100885
101417
  await mkdir9(dir2, { recursive: true });
100886
101418
  const path6 = join48(dir2, "speech.mp3");
@@ -101009,8 +101541,8 @@ function createDaemonSupportSubmit() {
101009
101541
  signal: AbortSignal.timeout(3e4)
101010
101542
  });
101011
101543
  if (!res.ok) {
101012
- const text12 = await res.text().catch(() => "");
101013
- throw new Error(`Report submission failed (${res.status}). ${text12.slice(0, 200)}`);
101544
+ const text13 = await res.text().catch(() => "");
101545
+ throw new Error(`Report submission failed (${res.status}). ${text13.slice(0, 200)}`);
101014
101546
  }
101015
101547
  const body = await res.json();
101016
101548
  if (!body.issueUrl || typeof body.issueNumber !== "number")
@@ -101724,28 +102256,28 @@ async function execPresentControl(name, args) {
101724
102256
  // ../../packages/host-core/dist/app-control-daemon.js
101725
102257
  var DAEMON_TABLE = {
101726
102258
  "present.state": async () => {
101727
- const { text: text12 } = await execPresentControl("deck_overview", {});
101728
- return text12;
102259
+ const { text: text13 } = await execPresentControl("deck_overview", {});
102260
+ return text13;
101729
102261
  },
101730
102262
  "present.deck": async () => {
101731
- const { text: text12 } = await execPresentControl("deck_overview", {});
101732
- return text12;
102263
+ const { text: text13 } = await execPresentControl("deck_overview", {});
102264
+ return text13;
101733
102265
  },
101734
102266
  "present.find_slide": async (input) => {
101735
- const { text: text12 } = await execPresentControl("find_slide", { query: String(input.query ?? "") });
101736
- return text12;
102267
+ const { text: text13 } = await execPresentControl("find_slide", { query: String(input.query ?? "") });
102268
+ return text13;
101737
102269
  },
101738
102270
  "present.goto": async (input) => {
101739
- const { text: text12 } = await execPresentControl("goto_slide", { slide: Number(input.slide) });
101740
- return text12;
102271
+ const { text: text13 } = await execPresentControl("goto_slide", { slide: Number(input.slide) });
102272
+ return text13;
101741
102273
  },
101742
102274
  "present.set_zoom": async (input) => {
101743
- const { text: text12 } = await execPresentControl("set_zoom", { level: Number(input.level) });
101744
- return text12;
102275
+ const { text: text13 } = await execPresentControl("set_zoom", { level: Number(input.level) });
102276
+ return text13;
101745
102277
  },
101746
102278
  "present.set_blank": async (input) => {
101747
- const { text: text12 } = await execPresentControl("set_blank", { blanked: input.blanked === true });
101748
- return text12;
102279
+ const { text: text13 } = await execPresentControl("set_blank", { blanked: input.blanked === true });
102280
+ return text13;
101749
102281
  },
101750
102282
  "present.set_ai": async (input) => {
101751
102283
  if (!isLive())
@@ -102306,7 +102838,10 @@ function refreshDaemonScheduling(b) {
102306
102838
  // and a 3am fire would act on a switch the user changed days ago. The snapshot is
102307
102839
  // already read fresh per turn everywhere else; this reads it fresh per fire.
102308
102840
  isUnattended: () => readDaemonAgentSettings().unattended === true,
102309
- isVerified: () => readDaemonAgentSettings().reinforcedVerification === true
102841
+ isVerified: () => readDaemonAgentSettings().reinforcedVerification === true,
102842
+ // The person's permission rules and hooks, for a fire that OPENS a conversation: it has no earlier turn
102843
+ // to replay them from, and it is the run nobody is watching. Read per fire, like the switches above.
102844
+ settings: () => readDaemonAgentSettings().settings
102310
102845
  });
102311
102846
  }
102312
102847
  function daemonWorkspaceDir() {
@@ -102596,8 +103131,8 @@ async function linuxFavorites() {
102596
103131
  ];
102597
103132
  for (const file2 of candidates) {
102598
103133
  try {
102599
- const text12 = await readFile13(file2, "utf8");
102600
- const favs = finalize2(parseGtkBookmarks(text12));
103134
+ const text13 = await readFile13(file2, "utf8");
103135
+ const favs = finalize2(parseGtkBookmarks(text13));
102601
103136
  if (favs.length)
102602
103137
  return favs;
102603
103138
  } catch {
@@ -102605,9 +103140,9 @@ async function linuxFavorites() {
102605
103140
  }
102606
103141
  return [];
102607
103142
  }
102608
- function parseGtkBookmarks(text12) {
103143
+ function parseGtkBookmarks(text13) {
102609
103144
  const out = [];
102610
- for (const raw of text12.split(/\r?\n/)) {
103145
+ for (const raw of text13.split(/\r?\n/)) {
102611
103146
  const line = raw.trim();
102612
103147
  if (!line.startsWith("file://"))
102613
103148
  continue;
@@ -108807,8 +109342,8 @@ function safeJson(value) {
108807
109342
  return "";
108808
109343
  }
108809
109344
  }
108810
- function firstLine2(text12) {
108811
- return text12.split("\n").map((l) => l.trim()).find(Boolean)?.slice(0, 80) ?? "";
109345
+ function firstLine2(text13) {
109346
+ return text13.split("\n").map((l) => l.trim()).find(Boolean)?.slice(0, 80) ?? "";
108812
109347
  }
108813
109348
  function queryMatcher(query2) {
108814
109349
  const q = query2.trim();
@@ -108816,11 +109351,11 @@ function queryMatcher(query2) {
108816
109351
  return null;
108817
109352
  return new RegExp(q.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "iu");
108818
109353
  }
108819
- function snippetAt(text12, at, length, radius = 60) {
109354
+ function snippetAt(text13, at, length, radius = 60) {
108820
109355
  const from = Math.max(0, at - radius);
108821
- const to = Math.min(text12.length, at + length + radius);
108822
- const body = text12.slice(from, to).replace(/\s+/g, " ").trim();
108823
- return `${from > 0 ? "\u2026" : ""}${body}${to < text12.length ? "\u2026" : ""}`;
109356
+ const to = Math.min(text13.length, at + length + radius);
109357
+ const body = text13.slice(from, to).replace(/\s+/g, " ").trim();
109358
+ return `${from > 0 ? "\u2026" : ""}${body}${to < text13.length ? "\u2026" : ""}`;
108824
109359
  }
108825
109360
 
108826
109361
  // ../../packages/host-core/dist/session-search/text-cache.js
@@ -108876,10 +109411,10 @@ function createTextCache(baseDir) {
108876
109411
  const nl = buf.lastIndexOf(10, end2 - 1);
108877
109412
  end2 = nl >= at ? nl + 1 : Math.max(end2, buf.indexOf(10, end2) + 1 || buf.length);
108878
109413
  }
108879
- const { text: text12, bytes: bytes3 } = completeLines(buf.subarray(at, end2));
109414
+ const { text: text13, bytes: bytes3 } = completeLines(buf.subarray(at, end2));
108880
109415
  if (bytes3 === 0)
108881
109416
  break;
108882
- const out = extractSession(text12, { ...hints, text: "" });
109417
+ const out = extractSession(text13, { ...hints, text: "" });
108883
109418
  if (out.text)
108884
109419
  texts.push(out.text);
108885
109420
  hints = out;
@@ -108887,9 +109422,9 @@ function createTextCache(baseDir) {
108887
109422
  }
108888
109423
  return { extraction: { ...hints, text: "", consumed: at }, texts, bytes: at };
108889
109424
  }
108890
- async function writeText(file2, text12) {
109425
+ async function writeText(file2, text13) {
108891
109426
  const tmp = `${file2}.${process.pid}.${Date.now()}.tmp`;
108892
- await writeFile14(tmp, text12, { mode: 384 });
109427
+ await writeFile14(tmp, text13, { mode: 384 });
108893
109428
  await rename5(tmp, file2);
108894
109429
  }
108895
109430
  async function extractWhole(file2, entry) {
@@ -108916,9 +109451,9 @@ function createTextCache(baseDir) {
108916
109451
  return null;
108917
109452
  }
108918
109453
  const main2 = extractChunked(raw, fromArchive.extraction);
108919
- const text12 = [...fromArchive.texts, ...main2.texts].join("\n");
109454
+ const text13 = [...fromArchive.texts, ...main2.texts].join("\n");
108920
109455
  const textFile = entry?.textFile ?? textFileFor(file2.path);
108921
- await writeText(join65(dir2, textFile), text12);
109456
+ await writeText(join65(dir2, textFile), text13);
108922
109457
  const { text: _t, consumed: _c, ...hints } = main2.extraction;
108923
109458
  return {
108924
109459
  path: file2.path,
@@ -109100,8 +109635,8 @@ function createSessionSearch(deps) {
109100
109635
  continue;
109101
109636
  const index = indexed.get(id);
109102
109637
  const title = entry.hints.customTitle ?? index?.title ?? entry.hints.firstPrompt ?? entry.hints.aiTitle;
109103
- const text12 = await cache6.text(entry);
109104
- const inBody = matcher.exec(text12);
109638
+ const text13 = await cache6.text(entry);
109639
+ const inBody = matcher.exec(text13);
109105
109640
  const inTitle = title ? matcher.test(title) : false;
109106
109641
  if (!inBody && !inTitle)
109107
109642
  continue;
@@ -109113,7 +109648,7 @@ function createSessionSearch(deps) {
109113
109648
  lastModified: entry.hints.lastTimestamp ?? entry.mtimeMs,
109114
109649
  ...cwd ? { cwd } : {},
109115
109650
  engineId,
109116
- ...inBody ? { snippet: snippetAt(text12, inBody.index, inBody[0].length) } : {}
109651
+ ...inBody ? { snippet: snippetAt(text13, inBody.index, inBody[0].length) } : {}
109117
109652
  };
109118
109653
  run9.hits.push(hit);
109119
109654
  found.push(hit);
@@ -111281,12 +111816,12 @@ var RdeskSessionManager = class {
111281
111816
  this.deps.sendControl(sessionId, s.viewer.clientId, { type: "rdesk:muted", mic: !!mute.mic, systemAudio: !!mute.systemAudio });
111282
111817
  }
111283
111818
  /** Host operator → viewer: send an in-session chat line. No-op if the session is gone. */
111284
- sendChat(sessionId, text12) {
111819
+ sendChat(sessionId, text13) {
111285
111820
  const s = this.sessions.get(sessionId);
111286
111821
  if (!s)
111287
111822
  return;
111288
- this.deps.sendControl(sessionId, s.viewer.clientId, { type: "rdesk:chat", text: text12, from: "host", at: Date.now() });
111289
- this.audit({ event: "chat", sessionId, detail: `host: ${text12.slice(0, 80)}` });
111823
+ this.deps.sendControl(sessionId, s.viewer.clientId, { type: "rdesk:chat", text: text13, from: "host", at: Date.now() });
111824
+ this.audit({ event: "chat", sessionId, detail: `host: ${text13.slice(0, 80)}` });
111290
111825
  }
111291
111826
  /** Switch the captured display. */
111292
111827
  async setMonitor(sessionId, monitorId) {
@@ -111318,9 +111853,9 @@ var RdeskSessionManager = class {
111318
111853
  return this.sendKeys(sessionId, msg.combo);
111319
111854
  if (msg.type === "rdesk:chat") {
111320
111855
  const s = this.sessions.get(sessionId);
111321
- const text12 = msg.text.slice(0, 4e3);
111322
- this.deps.onChat?.({ sessionId, viewerName: s?.viewer.name, text: text12 });
111323
- this.audit({ event: "chat", sessionId, detail: text12.slice(0, 80) });
111856
+ const text13 = msg.text.slice(0, 4e3);
111857
+ this.deps.onChat?.({ sessionId, viewerName: s?.viewer.name, text: text13 });
111858
+ this.audit({ event: "chat", sessionId, detail: text13.slice(0, 80) });
111324
111859
  return;
111325
111860
  }
111326
111861
  if (msg.type === "rdesk:av") {
@@ -111963,8 +112498,8 @@ function waylandInputRunner(p, screen) {
111963
112498
  async scroll(o) {
111964
112499
  p.pointerAxis(o.dx ?? 0, o.dy ?? 0);
111965
112500
  },
111966
- async typeText(text12) {
111967
- for (const ch of text12) {
112501
+ async typeText(text13) {
112502
+ for (const ch of text13) {
111968
112503
  const ks = charKeysym(ch);
111969
112504
  if (!ks)
111970
112505
  continue;
@@ -112138,11 +112673,11 @@ var TesseractEngine = class {
112138
112673
  onInput: (ev) => void this.injector?.apply(ev),
112139
112674
  // Clipboard sync (Phase 6): write the viewer's clipboard onto the host so ⌘V pastes
112140
112675
  // into the remote machine. Gated by control access (view-only never writes).
112141
- onClipboard: (text12) => {
112676
+ onClipboard: (text13) => {
112142
112677
  if (this.access === "control") {
112143
112678
  const el2 = electronModule();
112144
112679
  try {
112145
- el2?.clipboard?.writeText(text12);
112680
+ el2?.clipboard?.writeText(text13);
112146
112681
  } catch {
112147
112682
  }
112148
112683
  }
@@ -114560,8 +115095,8 @@ async function startLocalServer(opts) {
114560
115095
  if (!vc || !vc.isPresentMode)
114561
115096
  return null;
114562
115097
  return {
114563
- injectContext: (text12) => vc.injectPresentContext(text12),
114564
- ask: (text12) => vc.askPresent(text12)
115098
+ injectContext: (text13) => vc.injectPresentContext(text13),
115099
+ ask: (text13) => vc.askPresent(text13)
114565
115100
  };
114566
115101
  });
114567
115102
  const unregisterSink = registerAgentSink((msg, origin2) => {
@@ -115685,7 +116220,7 @@ async function getPeerIdentityPub(opts) {
115685
116220
  }
115686
116221
 
115687
116222
  // ../../packages/host-core/dist/mesh/node.js
115688
- import { createSocket as createSocket2 } from "node:dgram";
116223
+ import { createSocket } from "node:dgram";
115689
116224
  import { createRequire as createRequire4 } from "node:module";
115690
116225
  init_credentials();
115691
116226
 
@@ -116212,6 +116747,8 @@ async function netdNodeStatus(meshId) {
116212
116747
  relayed: strs("relayed"),
116213
116748
  policyEpoch: num2("policyEpoch"),
116214
116749
  revoked: b.revoked === true,
116750
+ lan: b.lan === true,
116751
+ lanError: typeof b.lanError === "string" ? b.lanError : null,
116215
116752
  bundleStaleInMs: typeof b.bundleStaleInMs === "number" ? b.bundleStaleInMs : null,
116216
116753
  lastError: typeof b.lastError === "string" ? b.lastError : null,
116217
116754
  localStaticPub: Uint8Array.from(Buffer.from(pubHex, "hex")),
@@ -116394,6 +116931,15 @@ var NetdEngine = class {
116394
116931
  get srflx() {
116395
116932
  return this.#snapshot?.srflx ?? null;
116396
116933
  }
116934
+ /** Whether the HELPER's LAN discovery joined the multicast group — it owns that socket
116935
+ * now, so this is the only honest source for it. */
116936
+ get lan() {
116937
+ return this.#snapshot?.lan === true;
116938
+ }
116939
+ /** Why LAN discovery is off, when it is — the helper records the step that failed. */
116940
+ get lanError() {
116941
+ return this.#snapshot?.lanError ?? null;
116942
+ }
116397
116943
  /** The same over IPv6, advertised alongside rather than instead. */
116398
116944
  get srflx6() {
116399
116945
  return this.#snapshot?.srflx6 ?? null;
@@ -116489,127 +117035,6 @@ ${ts}`);
116489
117035
  }
116490
117036
  }
116491
117037
 
116492
- // ../../packages/host-core/dist/mesh/lan.js
116493
- import { createSocket } from "node:dgram";
116494
- var MAGIC = Buffer.from("TSRL");
116495
- var VERSION2 = 1;
116496
- var LAN_GROUP_V4 = "224.0.0.251";
116497
- var LAN_PORT = 5353;
116498
- var BEACON_LEN = 4 + 1 + 3 + 32 + 32 + 2 + 8;
116499
- var ANNOUNCE_MS = 5e3;
116500
- function encodeBeacon(b) {
116501
- const out = Buffer.alloc(BEACON_LEN);
116502
- MAGIC.copy(out, 0);
116503
- out[4] = VERSION2;
116504
- b.genesisFp.copy(out, 8, 0, 32);
116505
- b.staticPub.copy(out, 40, 0, 32);
116506
- out.writeUInt16BE(b.port, 72);
116507
- out.writeUInt32BE(Math.floor(b.epoch / 4294967296), 74);
116508
- out.writeUInt32BE(b.epoch >>> 0, 78);
116509
- return out;
116510
- }
116511
- function parseBeacon(buf) {
116512
- if (buf.length !== BEACON_LEN)
116513
- return null;
116514
- if (!buf.subarray(0, 4).equals(MAGIC))
116515
- return null;
116516
- if (buf[4] !== VERSION2)
116517
- return null;
116518
- if (buf[5] !== 0 || buf[6] !== 0 || buf[7] !== 0)
116519
- return null;
116520
- const port = buf.readUInt16BE(72);
116521
- if (port < 1)
116522
- return null;
116523
- const epoch2 = buf.readUInt32BE(74) * 4294967296 + buf.readUInt32BE(78);
116524
- return {
116525
- genesisFp: buf.subarray(8, 40),
116526
- staticPub: buf.subarray(40, 72),
116527
- port,
116528
- epoch: epoch2
116529
- };
116530
- }
116531
- var LanDiscovery = class {
116532
- #sock = null;
116533
- #timer = null;
116534
- #joined = false;
116535
- #opts;
116536
- constructor(opts) {
116537
- this.#opts = opts;
116538
- }
116539
- get active() {
116540
- return this.#joined;
116541
- }
116542
- start() {
116543
- if (this.#sock)
116544
- return;
116545
- const sock = createSocket({ type: "udp4", reuseAddr: true });
116546
- sock.on("error", () => {
116547
- this.stop();
116548
- });
116549
- sock.on("message", (msg, rinfo) => this.#onBeacon(msg, rinfo.address));
116550
- sock.bind(LAN_PORT, () => {
116551
- try {
116552
- sock.addMembership(LAN_GROUP_V4);
116553
- sock.setMulticastLoopback(true);
116554
- sock.setMulticastTTL(1);
116555
- this.#joined = true;
116556
- this.#announce();
116557
- } catch {
116558
- this.stop();
116559
- }
116560
- });
116561
- sock.unref?.();
116562
- this.#sock = sock;
116563
- this.#timer = setInterval(() => this.#announce(), ANNOUNCE_MS);
116564
- this.#timer.unref?.();
116565
- }
116566
- stop() {
116567
- if (this.#timer) {
116568
- clearInterval(this.#timer);
116569
- this.#timer = null;
116570
- }
116571
- if (this.#sock) {
116572
- try {
116573
- if (this.#joined)
116574
- this.#sock.dropMembership(LAN_GROUP_V4);
116575
- } catch {
116576
- }
116577
- try {
116578
- this.#sock.close();
116579
- } catch {
116580
- }
116581
- }
116582
- this.#sock = null;
116583
- this.#joined = false;
116584
- }
116585
- #announce() {
116586
- const port = this.#opts.port();
116587
- if (!this.#sock || !this.#joined || port === null)
116588
- return;
116589
- const frame = encodeBeacon({
116590
- genesisFp: this.#opts.genesisFp,
116591
- staticPub: this.#opts.staticPub,
116592
- port,
116593
- epoch: this.#opts.epoch()
116594
- });
116595
- try {
116596
- this.#sock.send(frame, LAN_PORT, LAN_GROUP_V4, () => {
116597
- });
116598
- } catch {
116599
- }
116600
- }
116601
- #onBeacon(msg, address) {
116602
- const b = parseBeacon(msg);
116603
- if (!b)
116604
- return;
116605
- if (!b.genesisFp.equals(this.#opts.genesisFp))
116606
- return;
116607
- if (b.staticPub.equals(this.#opts.staticPub))
116608
- return;
116609
- this.#opts.onPeer(Buffer.from(b.staticPub), address, b.port, b.epoch);
116610
- }
116611
- };
116612
-
116613
117038
  // ../../packages/host-core/dist/mesh/endpoints.js
116614
117039
  function inRange(range, addr) {
116615
117040
  if (addr.length !== range.addr.length)
@@ -116886,7 +117311,6 @@ var MeshNode = class {
116886
117311
  * can be offered a choice that has somewhere to go.
116887
117312
  */
116888
117313
  #exitNodes = /* @__PURE__ */ new Map();
116889
- #lan = null;
116890
117314
  #offRejoin = null;
116891
117315
  #statusTimer = null;
116892
117316
  /**
@@ -116936,7 +117360,8 @@ var MeshNode = class {
116936
117360
  enrolled: this.#identity !== null || this.#loadIdentity() !== null,
116937
117361
  running: this.#engine !== null,
116938
117362
  port: this.#port,
116939
- lan: this.#lan?.active ?? false,
117363
+ lan: this.#engine instanceof NetdEngine ? this.#engine.lan : false,
117364
+ lanError: this.#engine instanceof NetdEngine ? this.#engine.lanError : null,
116940
117365
  reachableAt: this.#engine instanceof NetdEngine ? [this.#engine.mapped, this.#engine.srflx, this.#engine.srflx6].filter((x) => x !== null).join(", ") || null : null,
116941
117366
  // Only the helper publishes names: writing the machine's name table needs root, and
116942
117367
  // the roster comes from the engine the helper runs. An in-process engine has a roster
@@ -117024,7 +117449,6 @@ var MeshNode = class {
117024
117449
  onUp: (port) => {
117025
117450
  this.#port = port;
117026
117451
  this.#join();
117027
- this.#startLan();
117028
117452
  this.#publishStatus();
117029
117453
  }
117030
117454
  });
@@ -117051,7 +117475,6 @@ var MeshNode = class {
117051
117475
  this.#identity = id;
117052
117476
  if (!inNetd) {
117053
117477
  this.#openSocket();
117054
- this.#startLan();
117055
117478
  }
117056
117479
  this.#offRejoin = onMeshRejoin(() => this.#join());
117057
117480
  this.#publishStatus();
@@ -117096,11 +117519,6 @@ var MeshNode = class {
117096
117519
  this.#published = false;
117097
117520
  }
117098
117521
  this.#runningMeshDir = null;
117099
- try {
117100
- this.#lan?.stop();
117101
- } catch {
117102
- }
117103
- this.#lan = null;
117104
117522
  try {
117105
117523
  this.#sock?.close();
117106
117524
  } catch {
@@ -117141,7 +117559,7 @@ var MeshNode = class {
117141
117559
  return Number.isInteger(port) && port > 0 ? { host: ep.slice(0, i), port } : null;
117142
117560
  }
117143
117561
  #openSocket() {
117144
- const sock = createSocket2({ type: "udp6", ipv6Only: false, reuseAddr: true });
117562
+ const sock = createSocket({ type: "udp6", ipv6Only: false, reuseAddr: true });
117145
117563
  sock.on("message", (msg, rinfo) => {
117146
117564
  if (!this.#engine)
117147
117565
  return;
@@ -117166,54 +117584,20 @@ var MeshNode = class {
117166
117584
  sock.unref?.();
117167
117585
  this.#sock = sock;
117168
117586
  }
117169
- /** LAN discovery: the path that needs neither the relay nor a hole punch.
117587
+ /* LAN discovery used to live here, as a multicast beacon in this process
117588
+ * (`./lan.ts`). It has MOVED INTO THE HELPER (`crates/tsmesh-netd/src/lan.rs`,
117589
+ * frame in `tsmesh_proto::lan`).
117170
117590
  *
117171
- * Started alongside the socket, and deliberately independent of the control link —
117172
- * two laptops on the same Wi-Fi with the internet down must still find each other,
117173
- * which is the whole demonstration that the overlay is not relay-dependent. */
117174
- #startLan() {
117175
- const engine = this.#engine;
117176
- if (!engine)
117177
- return;
117178
- try {
117179
- this.#lan = new LanDiscovery({
117180
- genesisFp: Buffer.from(engine.meshId(), "hex"),
117181
- staticPub: engine.localStaticPub(),
117182
- port: () => this.#port,
117183
- epoch: () => engine.policyEpoch(),
117184
- onPeer: (staticPub, address, port, epoch2) => this.#learnLanPeer(staticPub, address, port, epoch2)
117185
- });
117186
- this.#lan.start();
117187
- } catch {
117188
- this.#lan = null;
117189
- }
117190
- }
117191
- /** A beacon arrived. Treated exactly like a relay hint — a candidate, not a fact.
117591
+ * It had to. The beacon only ran while this app was running, so a headless machine --
117592
+ * a server, the thing the network exists to reach -- could not find a peer sharing its
117593
+ * switch. And on the netd path the app was announcing a port held by a different
117594
+ * process entirely. The helper starts at boot with no app and owns the socket, so the
117595
+ * beacon belongs beside it.
117192
117596
  *
117193
- * Including its EPOCH. The beacon has always carried one (`lan.ts`: "port(2) | epoch(8)")
117194
- * for the same reason the relay hint does — so a peer that is behind can be brought up
117195
- * to date — and, like the relay hint's, it was thrown away here. Two laptops on one
117196
- * Wi-Fi with the internet down are the demonstration that the overlay is not
117197
- * relay-dependent; without this they would find each other and then never agree on who
117198
- * else exists. */
117199
- #learnLanPeer(staticPub, address, port, epoch2 = 0) {
117200
- const engine = this.#engine;
117201
- if (!engine)
117202
- return;
117203
- const hex6 = staticPub.toString("hex");
117204
- this.#offerBundleTo(hex6, epoch2);
117205
- try {
117206
- if (!this.#peers.has(hex6)) {
117207
- engine.addPeer(staticPub, 0, Buffer.alloc(16));
117208
- this.#peers.set(hex6, staticPub);
117209
- }
117210
- engine.addPath(staticPub, `${address}:${port}`, false);
117211
- engine.ensureHandshake(staticPub, Date.now());
117212
- this.#drain();
117213
- } catch (e) {
117214
- this.#lastError = e instanceof Error ? e.message : String(e);
117215
- }
117216
- }
117597
+ * Moved rather than duplicated: two implementations of a parser that reads
117598
+ * unauthenticated multicast from every device on the segment is the one risk
117599
+ * docs/MESH.md names as unacceptable.
117600
+ */
117217
117601
  #subscribe() {
117218
117602
  this.#unsubscribe = onMesh((m) => this.#onHint(m));
117219
117603
  }
@@ -117796,11 +118180,11 @@ async function call2(path6, init, auth = true) {
117796
118180
  } catch (e) {
117797
118181
  return fail3("network", e instanceof Error ? e.message : String(e));
117798
118182
  }
117799
- const text12 = await res.text();
118183
+ const text13 = await res.text();
117800
118184
  if (!res.ok) {
117801
- let detail = text12.slice(0, 500);
118185
+ let detail = text13.slice(0, 500);
117802
118186
  try {
117803
- const parsed = JSON.parse(text12);
118187
+ const parsed = JSON.parse(text13);
117804
118188
  if (parsed.message)
117805
118189
  detail = Array.isArray(parsed.message) ? parsed.message.join("; ") : parsed.message;
117806
118190
  } catch {
@@ -117808,7 +118192,7 @@ async function call2(path6, init, auth = true) {
117808
118192
  return fail3(res.status >= 500 ? "server" : "refused", detail);
117809
118193
  }
117810
118194
  try {
117811
- return { ok: true, data: text12 ? JSON.parse(text12) : {} };
118195
+ return { ok: true, data: text13 ? JSON.parse(text13) : {} };
117812
118196
  } catch {
117813
118197
  return fail3("server", "the server sent something that is not JSON");
117814
118198
  }
@@ -118010,18 +118394,18 @@ async function postJoin(origin, body) {
118010
118394
  } catch (e) {
118011
118395
  return fail3("network", e instanceof Error ? e.message : String(e));
118012
118396
  }
118013
- const text12 = await res.text();
118397
+ const text13 = await res.text();
118014
118398
  if (!res.ok) {
118015
- let detail = text12.slice(0, 500);
118399
+ let detail = text13.slice(0, 500);
118016
118400
  try {
118017
- const parsed = JSON.parse(text12);
118401
+ const parsed = JSON.parse(text13);
118018
118402
  if (parsed.message)
118019
118403
  detail = String(parsed.message);
118020
118404
  } catch {
118021
118405
  }
118022
118406
  return fail3(res.status >= 500 ? "server" : "refused", detail);
118023
118407
  }
118024
- return { ok: true, data: JSON.parse(text12) };
118408
+ return { ok: true, data: JSON.parse(text13) };
118025
118409
  }
118026
118410
  async function enrolWithCode(args) {
118027
118411
  return enrolWith(args.name, async (staticPub, sigPub, name) => postJoin(args.origin, { code: args.code, name, staticPub, sigPub }), resolveOrigin(args.origin), args.fromHostname);
@@ -118881,9 +119265,9 @@ import { pipeline } from "node:stream/promises";
118881
119265
 
118882
119266
  // ../../packages/host-core/dist/drops/crypto.js
118883
119267
  import { Transform } from "node:stream";
118884
- var MAGIC2 = Buffer.from("TSD1", "ascii");
119268
+ var MAGIC = Buffer.from("TSD1", "ascii");
118885
119269
  var NONCE_BYTES = 12;
118886
- var HEADER_BYTES = MAGIC2.length + NONCE_BYTES;
119270
+ var HEADER_BYTES = MAGIC.length + NONCE_BYTES;
118887
119271
  var FRAME_BYTES = 1024 * 1024;
118888
119272
  var TAG_BYTES = 16;
118889
119273
  var MAX_FRAME_CIPHERTEXT = FRAME_BYTES + TAG_BYTES + 1024;
@@ -118964,9 +119348,9 @@ function decryptStream(source, keyRaw) {
118964
119348
  cb();
118965
119349
  return;
118966
119350
  }
118967
- if (!head.subarray(0, MAGIC2.length).equals(MAGIC2))
119351
+ if (!head.subarray(0, MAGIC.length).equals(MAGIC))
118968
119352
  throw new Error("not an encrypted drop");
118969
- base = Buffer.from(head.subarray(MAGIC2.length, HEADER_BYTES));
119353
+ base = Buffer.from(head.subarray(MAGIC.length, HEADER_BYTES));
118970
119354
  q.consume(HEADER_BYTES);
118971
119355
  key2 = await importKey(keyRaw);
118972
119356
  }
@@ -119136,7 +119520,7 @@ function createChatAgentRunner(deps) {
119136
119520
  const backend2 = await getSharedBackend();
119137
119521
  const clientRequestId = `chat-agent-${randomUUID32()}`;
119138
119522
  return new Promise((resolve16, reject) => {
119139
- let text12 = "";
119523
+ let text13 = "";
119140
119524
  let settled = false;
119141
119525
  const finish2 = (fn) => {
119142
119526
  if (settled)
@@ -119150,13 +119534,13 @@ function createChatAgentRunner(deps) {
119150
119534
  }
119151
119535
  fn();
119152
119536
  };
119153
- const timer2 = setTimeout(() => finish2(() => text12.trim() ? resolve16(text12) : reject(new Error("the agent took too long"))), TURN_TIMEOUT_MS);
119537
+ const timer2 = setTimeout(() => finish2(() => text13.trim() ? resolve16(text13) : reject(new Error("the agent took too long"))), TURN_TIMEOUT_MS);
119154
119538
  let posting = false;
119155
119539
  let lastSent = "";
119156
119540
  const tick = setInterval(() => {
119157
119541
  if (posting || !onPartial)
119158
119542
  return;
119159
- const snapshot4 = text12.trim();
119543
+ const snapshot4 = text13.trim();
119160
119544
  if (!snapshot4 || snapshot4 === lastSent)
119161
119545
  return;
119162
119546
  lastSent = snapshot4;
@@ -119172,9 +119556,9 @@ function createChatAgentRunner(deps) {
119172
119556
  return;
119173
119557
  if (m.type === "chat:stream") {
119174
119558
  if ((m.kind === "text" || m.kind === void 0) && m.delta)
119175
- text12 += m.delta;
119559
+ text13 += m.delta;
119176
119560
  } else if (m.type === "chat:complete") {
119177
- finish2(() => resolve16(text12));
119561
+ finish2(() => resolve16(text13));
119178
119562
  } else if (m.type === "chat:error") {
119179
119563
  finish2(() => reject(new Error(m.message ?? m.error ?? "the agent errored")));
119180
119564
  }
@@ -121334,7 +121718,7 @@ function backoff2() {
121334
121718
  var daemonClipboardSync = null;
121335
121719
  var REFRESH_INTERVAL_MS2 = 12 * 60 * 60 * 1e3;
121336
121720
  async function runDaemon(opts = {}) {
121337
- const VERSION3 = opts.version ?? process.env.CCB_DAEMON_VERSION ?? "dev";
121721
+ const VERSION2 = opts.version ?? process.env.CCB_DAEMON_VERSION ?? "dev";
121338
121722
  const TAG = opts.tag ?? "host-daemon";
121339
121723
  const KIND = opts.kind ?? "app";
121340
121724
  const log10 = (...args) => console.log(`[${TAG} ${(/* @__PURE__ */ new Date()).toISOString()}]`, ...args);
@@ -121410,14 +121794,14 @@ async function runDaemon(opts = {}) {
121410
121794
  if (!ownsMachine)
121411
121795
  return;
121412
121796
  try {
121413
- writeFileSync44(statusFile2(), JSON.stringify({ pid: process.pid, startedAt: OUR_STARTED_AT, role: process.env.CCB_RDESK_ROLE ?? "host", kind: KIND, version: VERSION3, execPath: process.env.CCB_DAEMON_EXECPATH ?? process.execPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), gui: daemonGuiTrayActive(), ...localInfo ?? {}, ...s }));
121797
+ writeFileSync44(statusFile2(), JSON.stringify({ pid: process.pid, startedAt: OUR_STARTED_AT, role: process.env.CCB_RDESK_ROLE ?? "host", kind: KIND, version: VERSION2, execPath: process.env.CCB_DAEMON_EXECPATH ?? process.execPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), gui: daemonGuiTrayActive(), ...localInfo ?? {}, ...s }));
121414
121798
  chmodSync8(statusFile2(), 384);
121415
121799
  } catch {
121416
121800
  }
121417
121801
  }
121418
121802
  const standaloneViewer = process.env.CCB_RDESK_ROLE === "client";
121419
121803
  if (!standaloneViewer) {
121420
- registerSelfAsDaemon(VERSION3);
121804
+ registerSelfAsDaemon(VERSION2);
121421
121805
  if (KIND === "app") {
121422
121806
  try {
121423
121807
  await evictCliAgent(log10);
@@ -121625,7 +122009,7 @@ async function runDaemon(opts = {}) {
121625
122009
  unregisterSelfAsDaemon();
121626
122010
  process.exit(code);
121627
122011
  }
121628
- startSystemEvents({ version: VERSION3, log: (m) => log10(m) });
122012
+ startSystemEvents({ version: VERSION2, log: (m) => log10(m) });
121629
122013
  const mergedProcess = opts.merged === true;
121630
122014
  const deliberateMergedQuit = () => !!globalThis.__ccbDeliberateQuit;
121631
122015
  const onTermSignal = (sig) => {
@@ -121892,7 +122276,7 @@ async function runDaemon(opts = {}) {
121892
122276
  if (!creds3) {
121893
122277
  timer2 = setInterval(() => writeStatus2({ deviceId: deviceId3, connected: false, localOnly: true }), 6e4);
121894
122278
  writeStatus2({ deviceId: deviceId3, connected: false, localOnly: true });
121895
- log10(`started LOCAL-ONLY (no identity yet) \u2014 local :${localInfo?.localPort ?? "off"}, version ${VERSION3}; will keep trying`);
122279
+ log10(`started LOCAL-ONLY (no identity yet) \u2014 local :${localInfo?.localPort ?? "off"}, version ${VERSION2}; will keep trying`);
121896
122280
  const watch4 = watchForIdentity({ attempt: acquireIdentity, log: (m) => log10(m) });
121897
122281
  identityWatch = watch4;
121898
122282
  setDaemonIdentityReload(async () => {
@@ -122153,14 +122537,14 @@ async function runDaemon(opts = {}) {
122153
122537
  // On macOS the notification carries an inline REPLY box (hasReply) whose text is sent
122154
122538
  // straight back via sendChat — a full operator chat loop with no extra window. Off-mac (no
122155
122539
  // hasReply) it's receive-only for now; the daemon log always records it as a fallback.
122156
- onChat: ({ sessionId, viewerName, text: text12 }) => {
122540
+ onChat: ({ sessionId, viewerName, text: text13 }) => {
122157
122541
  const NotifCtor = electronModule()?.Notification;
122158
122542
  if (!NotifCtor) {
122159
- log10(`[rdesk chat] ${viewerName ?? "viewer"}: ${text12}`);
122543
+ log10(`[rdesk chat] ${viewerName ?? "viewer"}: ${text13}`);
122160
122544
  return;
122161
122545
  }
122162
122546
  try {
122163
- const n = new NotifCtor({ title: `${viewerName ?? "Remote viewer"} \u2014 remote desktop`, body: text12, hasReply: true, replyPlaceholder: "Reply\u2026" });
122547
+ const n = new NotifCtor({ title: `${viewerName ?? "Remote viewer"} \u2014 remote desktop`, body: text13, hasReply: true, replyPlaceholder: "Reply\u2026" });
122164
122548
  n.on("reply", (_e, reply3) => {
122165
122549
  const r = typeof reply3 === "string" ? reply3.trim() : "";
122166
122550
  if (r)
@@ -122500,7 +122884,7 @@ async function runDaemon(opts = {}) {
122500
122884
  log10("e2e responder init failed (staying plaintext)", err2.message);
122501
122885
  }
122502
122886
  }
122503
- startControlLink({ deviceId: c.deviceId, power: createNodePowerController(), tokenSource, version: VERSION3, e2e }, hooks2);
122887
+ startControlLink({ deviceId: c.deviceId, power: createNodePowerController(), tokenSource, version: VERSION2, e2e }, hooks2);
122504
122888
  offRecovery = onSystemEvent(({ event }) => {
122505
122889
  const suspended = isSuspensionSignal(event);
122506
122890
  if (suspended)
@@ -122601,7 +122985,7 @@ async function runDaemon(opts = {}) {
122601
122985
  }
122602
122986
  }
122603
122987
  const who = c.userId ? `user ${c.userId}` : "no account (unclaimed machine)";
122604
- log10(`started \u2014 device ${c.deviceId}, ${who}, relay ${c.backendOrigin}, local :${localInfo?.localPort ?? "off"}, version ${VERSION3}`);
122988
+ log10(`started \u2014 device ${c.deviceId}, ${who}, relay ${c.backendOrigin}, local :${localInfo?.localPort ?? "off"}, version ${VERSION2}`);
122605
122989
  await refresh();
122606
122990
  timer2 = setInterval(() => {
122607
122991
  void refresh();
@@ -122709,8 +123093,8 @@ function installOwnerUid(env = process.env, self2 = typeof process.getuid === "f
122709
123093
  }
122710
123094
  return self2;
122711
123095
  }
122712
- function parseOwnerUid(text12) {
122713
- const m = /--owner-uid(?:<\/string>)?[\s=]*(?:<string>)?(\d+)/.exec(text12);
123096
+ function parseOwnerUid(text13) {
123097
+ const m = /--owner-uid(?:<\/string>)?[\s=]*(?:<string>)?(\d+)/.exec(text13);
122714
123098
  if (!m)
122715
123099
  return void 0;
122716
123100
  const uid = Number(m[1]);
@@ -122767,8 +123151,8 @@ function bundleIdForExec(exec2) {
122767
123151
  return void 0;
122768
123152
  }
122769
123153
  }
122770
- function parseAssociatedBundleId(text12) {
122771
- const m = /<key>AssociatedBundleIdentifiers<\/key>\s*(?:<array>\s*)?<string>([^<]*)<\/string>/.exec(text12);
123154
+ function parseAssociatedBundleId(text13) {
123155
+ const m = /<key>AssociatedBundleIdentifiers<\/key>\s*(?:<array>\s*)?<string>([^<]*)<\/string>/.exec(text13);
122772
123156
  const id = m?.[1]?.trim();
122773
123157
  return id && looksLikeBundleId(id) ? id : void 0;
122774
123158
  }
@@ -122829,10 +123213,25 @@ ${args}
122829
123213
  <integer>30</integer>
122830
123214
  <key>ProcessType</key>
122831
123215
  <string>Interactive</string>
123216
+ <!-- /dev/null, NOT netd.log, and this is load-bearing.
123217
+
123218
+ These two keys used to point at netd.log, and launchd does not rotate what it
123219
+ redirects \u2014 so the file grew for the life of the install. The same omission on
123220
+ Windows reached 136 GB on a CI runner and hung two hours of release builds while
123221
+ looking like an npm problem; macOS had it too and nobody had looked.
123222
+
123223
+ netd now owns netd.log itself and rotates it (tsmesh_netd::logfile, 8 MiB, one
123224
+ previous generation). Leaving launchd pointed at the same path would be WORSE than
123225
+ the bug: after netd renames the file, launchd's descriptor still refers to the
123226
+ renamed inode, so it would append to the "previous generation" forever and no
123227
+ rotation could ever reclaim it. One writer, or none.
123228
+
123229
+ Nothing is lost by discarding this stream: everything netd logs goes through its own
123230
+ sink, and a panic is routed there too by a hook installed with the log file. -->
122832
123231
  <key>StandardErrorPath</key>
122833
- <string>${xml(join91(spec.stateDir, "netd.log"))}</string>
123232
+ <string>/dev/null</string>
122834
123233
  <key>StandardOutPath</key>
122835
- <string>${xml(join91(spec.stateDir, "netd.log"))}</string>
123234
+ <string>/dev/null</string>
122836
123235
  </dict>
122837
123236
  </plist>
122838
123237
  `;
@@ -122920,9 +123319,9 @@ ${plist}TESSERACT_PLIST_EOF`,
122920
123319
  async state() {
122921
123320
  if (!existsSync50(PLIST))
122922
123321
  return { installed: false, running: false };
122923
- const text12 = readFileSync59(PLIST, "utf8");
122924
- const owner = parseOwnerUid(text12);
122925
- const assoc = parseAssociatedBundleId(text12);
123322
+ const text13 = readFileSync59(PLIST, "utf8");
123323
+ const owner = parseOwnerUid(text13);
123324
+ const assoc = parseAssociatedBundleId(text13);
122926
123325
  const running2 = await netdAvailable();
122927
123326
  return {
122928
123327
  installed: true,
@@ -123559,10 +123958,10 @@ import { dirname as dirname42, join as join94 } from "node:path";
123559
123958
  import { homedir as homedir16, userInfo as userInfo2 } from "node:os";
123560
123959
 
123561
123960
  // ../../packages/host-core/dist/service/legacy-label.js
123562
- function definitionIsCli(text12) {
123563
- if (!text12)
123961
+ function definitionIsCli(text13) {
123962
+ if (!text13)
123564
123963
  return false;
123565
- return /node_modules[/\\]tesseract-agent[/\\]/.test(text12) || /[/\\]bin[/\\]tesseract-agent(\.cmd|\.exe)?["'\s]*$/m.test(text12) || /[/\\]bin[/\\]tesseract-agent(\.cmd|\.exe)?[<"'\s]/.test(text12);
123964
+ return /node_modules[/\\]tesseract-agent[/\\]/.test(text13) || /[/\\]bin[/\\]tesseract-agent(\.cmd|\.exe)?["'\s]*$/m.test(text13) || /[/\\]bin[/\\]tesseract-agent(\.cmd|\.exe)?[<"'\s]/.test(text13);
123566
123965
  }
123567
123966
 
123568
123967
  // ../../packages/host-core/dist/service/launchd.js
@@ -124689,7 +125088,9 @@ async function meshCommand(rest, flags) {
124689
125088
  return;
124690
125089
  }
124691
125090
  console.log(`node: running on UDP port ${s.port ?? "?"}`);
124692
- console.log(`node: LAN discovery ${s.lan ? "on" : "off (no multicast on this network)"}`);
125091
+ console.log(
125092
+ `node: LAN discovery ${s.lan ? "on" : `off \u2014 ${s.lanError ?? "no reason was recorded"}`}`
125093
+ );
124693
125094
  if (!("reachableAt" in s)) {
124694
125095
  console.log("reachable at: unknown \u2014 the background service predates this CLI; restart it and ask again");
124695
125096
  } else {