tesseract-agent 0.7.4 → 0.8.1

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.
Files changed (2) hide show
  1. package/dist-bundle/cli.js +553 -406
  2. package/package.json +1 -1
@@ -3805,7 +3805,7 @@ var init_permissions = __esm({
3805
3805
  {
3806
3806
  id: "full-disk-access",
3807
3807
  label: "Full Disk Access",
3808
- why: "Show the folders you pinned in Finder\u2019s sidebar.",
3808
+ why: "Show the folders you pinned in Finder\u2019s sidebar, and import your Safari logins.",
3809
3809
  icon: "FolderLock",
3810
3810
  category: "system",
3811
3811
  applicablePlatforms: ["darwin"],
@@ -3849,7 +3849,7 @@ var init_permissions = __esm({
3849
3849
  });
3850
3850
 
3851
3851
  // ../../packages/shared/dist/ws-protocol.js
3852
- var MIRRORED_AGENT_EVENTS;
3852
+ var MIRRORED_AGENT_EVENTS, OWN_STUN_HOST, OWN_STUN_PORT, OWN_STUN_URL, PUBLIC_STUN_URLS, DEFAULT_ICE_SERVERS;
3853
3853
  var init_ws_protocol = __esm({
3854
3854
  "../../packages/shared/dist/ws-protocol.js"() {
3855
3855
  "use strict";
@@ -3899,6 +3899,18 @@ var init_ws_protocol = __esm({
3899
3899
  // would stomp a co-viewer's own picker with the driver's host); session:forked
3900
3900
  // and agent:context_usage are driver-only correlation/host-local replies.
3901
3901
  ]);
3902
+ OWN_STUN_HOST = "bridge.fineguide.ai";
3903
+ OWN_STUN_PORT = 3478;
3904
+ OWN_STUN_URL = `stun:${OWN_STUN_HOST}:${OWN_STUN_PORT}`;
3905
+ PUBLIC_STUN_URLS = [
3906
+ "stun:stun.l.google.com:19302",
3907
+ "stun:stun1.l.google.com:19302",
3908
+ "stun:stun.cloudflare.com:3478"
3909
+ ];
3910
+ DEFAULT_ICE_SERVERS = [
3911
+ { urls: OWN_STUN_URL },
3912
+ ...PUBLIC_STUN_URLS.map((urls) => ({ urls }))
3913
+ ];
3902
3914
  }
3903
3915
  });
3904
3916
 
@@ -5266,6 +5278,7 @@ var init_dist = __esm({
5266
5278
  init_surface_merge();
5267
5279
  init_permissions();
5268
5280
  init_ws_protocol();
5281
+ init_ws_protocol();
5269
5282
  init_frame();
5270
5283
  init_domain_id();
5271
5284
  init_plans();
@@ -13087,8 +13100,8 @@ var capitalizeFirstCharacter, error28;
13087
13100
  var init_lt = __esm({
13088
13101
  "../../node_modules/zod/v4/locales/lt.js"() {
13089
13102
  init_util();
13090
- capitalizeFirstCharacter = (text3) => {
13091
- return text3.charAt(0).toUpperCase() + text3.slice(1);
13103
+ capitalizeFirstCharacter = (text4) => {
13104
+ return text4.charAt(0).toUpperCase() + text4.slice(1);
13092
13105
  };
13093
13106
  error28 = () => {
13094
13107
  const Sizable = {
@@ -21598,16 +21611,54 @@ var init_design_tools = __esm({
21598
21611
  }
21599
21612
  });
21600
21613
 
21601
- // ../../packages/agent-core/dist/imagegen-tools.js
21614
+ // ../../packages/agent-core/dist/support-tools.js
21602
21615
  import { tool as tool3 } from "@anthropic-ai/claude-agent-sdk";
21616
+ function buildSupportTools(submit) {
21617
+ return [
21618
+ tool3("submit_issue", [
21619
+ "File a bug report or feature request for the Tesseract app itself (not the user's project).",
21620
+ "Creates a PUBLIC GitHub issue from the title + description you pass, and privately attaches full",
21621
+ "technical diagnostics (app version, OS, logs, settings) for the team. Requires the user to be signed in.",
21622
+ "IMPORTANT: the title and description are PUBLIC \u2014 never put secrets, credentials, tokens, or personal",
21623
+ "information in them. Confirm the wording with the user before filing. Returns the created issue link."
21624
+ ].join(" "), {
21625
+ type: external_exports.enum(["issue", "feature"]).describe("'issue' for a bug/problem, 'feature' for a request/idea"),
21626
+ title: external_exports.string().min(3).describe("A short, specific title (public)."),
21627
+ description: external_exports.string().min(10).describe("A clear description \u2014 what happened / what is wanted, and why (public, markdown ok).")
21628
+ }, async (args) => {
21629
+ try {
21630
+ const res = await submit({
21631
+ type: args.type,
21632
+ title: args.title.trim(),
21633
+ description: args.description.trim()
21634
+ });
21635
+ const kind = args.type === "feature" ? "feature request" : "bug report";
21636
+ return text2(`Filed your ${kind}: ${res.issueUrl} (#${res.issueNumber}). Full technical diagnostics were attached privately for the team.`);
21637
+ } catch (e) {
21638
+ return text2(`Could not file the report: ${e instanceof Error ? e.message : String(e)}`, true);
21639
+ }
21640
+ })
21641
+ ];
21642
+ }
21643
+ var text2;
21644
+ var init_support_tools = __esm({
21645
+ "../../packages/agent-core/dist/support-tools.js"() {
21646
+ "use strict";
21647
+ init_zod();
21648
+ text2 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
21649
+ }
21650
+ });
21651
+
21652
+ // ../../packages/agent-core/dist/imagegen-tools.js
21653
+ import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
21603
21654
  function buildImagegenTools(deps) {
21604
21655
  return [
21605
- tool3("image_providers_status", "Check which AI image-generation providers have an API key configured (OpenAI gpt-image-2 and/or Google Nano Banana Pro). Call this BEFORE generate_image to decide whether to generate, to ask the user which provider to use, or to ask them to add a key.", {}, async () => {
21656
+ tool4("image_providers_status", "Check which AI image-generation providers have an API key configured (OpenAI gpt-image-2 and/or Google Nano Banana Pro). Call this BEFORE generate_image to decide whether to generate, to ask the user which provider to use, or to ask them to add a key.", {}, async () => {
21606
21657
  const s = await deps.status();
21607
21658
  const configured = [s.openai && "openai", s.google && "google"].filter(Boolean);
21608
- return text2(JSON.stringify({ openai: s.openai, google: s.google, anyConfigured: configured.length > 0, configured }));
21659
+ return text3(JSON.stringify({ openai: s.openai, google: s.google, anyConfigured: configured.length > 0, configured }));
21609
21660
  }),
21610
- tool3("generate_image", "Generate images from a text prompt (text-to-image) and display them to the user in the chat. Generates 4 by default. When source_image is set, generates variations seeded by that image (image-to-image). Requires a configured provider \u2014 call image_providers_status first; if none is configured do NOT call this, instead tell the user to add a key.", {
21661
+ tool4("generate_image", "Generate images from a text prompt (text-to-image) and display them to the user in the chat. Generates 4 by default. When source_image is set, generates variations seeded by that image (image-to-image). Requires a configured provider \u2014 call image_providers_status first; if none is configured do NOT call this, instead tell the user to add a key.", {
21611
21662
  prompt: external_exports.string().describe("What to generate \u2014 be descriptive."),
21612
21663
  provider: external_exports.enum(["openai", "google", "both"]).optional().describe("Which provider to use. Omit to auto-pick the only configured one. 'both' generates `count` images from each configured provider."),
21613
21664
  count: external_exports.number().int().min(1).max(8).optional().describe("How many images to generate (default 4)."),
@@ -21618,7 +21669,7 @@ function buildImagegenTools(deps) {
21618
21669
  const configured = ["openai", "google"].filter((p) => status2[p]);
21619
21670
  const want = args.provider === "both" ? [...configured] : args.provider ? [args.provider] : configured.slice(0, 1);
21620
21671
  if (!want.length) {
21621
- return text2("No image-generation provider is configured. Ask the user to add an OpenAI or Google key in Settings \u2192 Image editing before generating.", true);
21672
+ return text3("No image-generation provider is configured. Ask the user to add an OpenAI or Google key in Settings \u2192 Image editing before generating.", true);
21622
21673
  }
21623
21674
  const results = await Promise.all(want.map(async (provider) => {
21624
21675
  if (!status2[provider])
@@ -21631,11 +21682,11 @@ function buildImagegenTools(deps) {
21631
21682
  return { ok: false, summary: `${PROVIDER_LABEL[provider]}: failed \u2014 ${res.error ?? "unknown error"}` };
21632
21683
  }));
21633
21684
  const any2 = results.some((r) => r.ok);
21634
- return text2((any2 ? "Generated and displayed the images in the chat.\n" : "Image generation failed.\n") + results.map((r) => r.summary).join("\n"), !any2);
21685
+ return text3((any2 ? "Generated and displayed the images in the chat.\n" : "Image generation failed.\n") + results.map((r) => r.summary).join("\n"), !any2);
21635
21686
  })
21636
21687
  ];
21637
21688
  }
21638
- var PROVIDER_LABEL, text2;
21689
+ var PROVIDER_LABEL, text3;
21639
21690
  var init_imagegen_tools = __esm({
21640
21691
  "../../packages/agent-core/dist/imagegen-tools.js"() {
21641
21692
  "use strict";
@@ -21644,12 +21695,12 @@ var init_imagegen_tools = __esm({
21644
21695
  openai: "OpenAI (gpt-image-2)",
21645
21696
  google: "Google Nano Banana Pro (gemini-3-pro-image)"
21646
21697
  };
21647
- text2 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
21698
+ text3 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
21648
21699
  }
21649
21700
  });
21650
21701
 
21651
21702
  // ../../packages/agent-core/dist/canvas-tools.js
21652
- import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
21703
+ import { tool as tool5 } from "@anthropic-ai/claude-agent-sdk";
21653
21704
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "node:fs";
21654
21705
  import { join as join5 } from "node:path";
21655
21706
  function slugify3(s) {
@@ -21657,7 +21708,7 @@ function slugify3(s) {
21657
21708
  }
21658
21709
  function buildCanvasTools(deps) {
21659
21710
  return [
21660
- tool4("render_canvas", "Render an HTML document as a live, sandboxed Canvas docked beside the chat (like OpenAI Canvas), for INTERACTIVE or multi-part PROJECTS (apps, tools, dashboards, anything the user will interact with at size). For a SMALL self-contained snippet or animation, do NOT use this \u2014 instead just include it as a fenced ```html (or ```svg) code block in your reply; it renders live inline in the message. To TRANSFORM an existing canvas, call again with the SAME id and the full updated HTML \u2014 it re-renders in place. Before composing the HTML, consult the canvas-design skill for design fundamentals (and chart-design / diagram-design when the canvas is a chart or a diagram) so the result looks deliberately designed. Returns the canvas file path.", {
21711
+ tool5("render_canvas", "Render an HTML document as a live, sandboxed Canvas docked beside the chat (like OpenAI Canvas), for INTERACTIVE or multi-part PROJECTS (apps, tools, dashboards, anything the user will interact with at size). For a SMALL self-contained snippet or animation, do NOT use this \u2014 instead just include it as a fenced ```html (or ```svg) code block in your reply; it renders live inline in the message. To TRANSFORM an existing canvas, call again with the SAME id and the full updated HTML \u2014 it re-renders in place. Before composing the HTML, consult the canvas-design skill for design fundamentals (and chart-design / diagram-design when the canvas is a chart or a diagram) so the result looks deliberately designed. Returns the canvas file path.", {
21661
21712
  html: external_exports.string().describe("The full HTML document to render (include <html>/<body>; put CSS/JS inline)."),
21662
21713
  title: external_exports.string().optional().describe("Short title for the canvas tab."),
21663
21714
  id: external_exports.string().optional().describe("Stable id to UPDATE an existing canvas; omit to create a new one.")
@@ -21680,10 +21731,10 @@ var init_canvas_tools = __esm({
21680
21731
  });
21681
21732
 
21682
21733
  // ../../packages/agent-core/dist/surface-tools.js
21683
- import { tool as tool5 } from "@anthropic-ai/claude-agent-sdk";
21734
+ import { tool as tool6 } from "@anthropic-ai/claude-agent-sdk";
21684
21735
  function buildSurfaceTools(deps) {
21685
21736
  return [
21686
- tool5("open_surface", "Open a rich, live UI surface in the chat and return its surfaceId. Use for anything richer than text that the user watches or interacts with: a streaming progress panel, a table/chart that grows, a report, an interactive HTML/canvas mini-app. `content` carries the kind-specific body \u2014 markdown:{markdown}, html/canvas:{html}, image:{images:[{path,mime,alt?}]}, video:{src}, progress:{stages:[{label,status}],note?}, table:{columns,rows}, chart:{chart,series}, report:{report}, stream:{chunk|rows}. `placement`: inline (in the feed) | pinned (kept at the top while you keep working) | docked (side panel). Set `indefinite:true` for a live monitor that should keep updating past this turn. Then call update_surface to stream/patch it, and close_surface when done. For a small static snippet, just include it as a fenced code block instead.", {
21737
+ tool6("open_surface", "Open a rich, live UI surface in the chat and return its surfaceId. Use for anything richer than text that the user watches or interacts with: a streaming progress panel, a table/chart that grows, a report, an interactive HTML/canvas mini-app. `content` carries the kind-specific body \u2014 markdown:{markdown}, html/canvas:{html}, image:{images:[{path,mime,alt?}]}, video:{src}, progress:{stages:[{label,status}],note?}, table:{columns,rows}, chart:{chart,series}, report:{report}, stream:{chunk|rows}. `placement`: inline (in the feed) | pinned (kept at the top while you keep working) | docked (side panel). Set `indefinite:true` for a live monitor that should keep updating past this turn. Then call update_surface to stream/patch it, and close_surface when done. For a small static snippet, just include it as a fenced code block instead.", {
21687
21738
  kind: external_exports.enum(KINDS),
21688
21739
  title: external_exports.string().optional().describe("Short title shown on the surface."),
21689
21740
  placement: external_exports.enum(PLACEMENTS).optional().describe("inline | pinned | docked (default inline)."),
@@ -21697,7 +21748,7 @@ function buildSurfaceTools(deps) {
21697
21748
  return { content: [{ type: "text", text: `Could not open surface: ${e instanceof Error ? e.message : String(e)}` }] };
21698
21749
  }
21699
21750
  }),
21700
- tool5("update_surface", "Update an open surface. `op`: replace (swap the whole payload), patch (shallow-merge changed fields \u2014 e.g. a progress note), append (add a stream chunk / table rows / chart points). Set final:true when the surface is finished (it stops accepting updates and, if pinned, unpins into history).", {
21751
+ tool6("update_surface", "Update an open surface. `op`: replace (swap the whole payload), patch (shallow-merge changed fields \u2014 e.g. a progress note), append (add a stream chunk / table rows / chart points). Set final:true when the surface is finished (it stops accepting updates and, if pinned, unpins into history).", {
21701
21752
  surfaceId: external_exports.string(),
21702
21753
  op: external_exports.enum(OPS).optional().describe("replace | patch | append (default patch)."),
21703
21754
  content: external_exports.any().optional().describe("Kind-specific payload body or delta."),
@@ -21711,11 +21762,11 @@ function buildSurfaceTools(deps) {
21711
21762
  return { content: [{ type: "text", text: `Could not update surface ${args.surfaceId}: ${e instanceof Error ? e.message : String(e)}` }] };
21712
21763
  }
21713
21764
  }),
21714
- tool5("close_surface", "Close and dispose an open surface.", { surfaceId: external_exports.string() }, async (args) => {
21765
+ tool6("close_surface", "Close and dispose an open surface.", { surfaceId: external_exports.string() }, async (args) => {
21715
21766
  deps.close(args.surfaceId);
21716
21767
  return { content: [{ type: "text", text: `Closed surface ${args.surfaceId}.` }] };
21717
21768
  }),
21718
- tool5("wait_for_surface_event", 'Block until the next interaction on an interactive surface, then return it \u2014 e.g. the user makes a chess move, clicks, or submits a form. Drive an interactive surface in a loop: open_surface (HTML that calls window.tessSurface.emit(name,detail) on interaction) \u2192 wait_for_surface_event \u2192 act + update_surface(op:"patch", content:{data:{...}}) to redraw in place \u2192 wait again. Returns {name, detail}, or a note if the surface closed / timed out.', { surfaceId: external_exports.string(), timeoutSeconds: external_exports.number().optional().describe("Max seconds to wait (default 300).") }, async (args) => {
21769
+ tool6("wait_for_surface_event", 'Block until the next interaction on an interactive surface, then return it \u2014 e.g. the user makes a chess move, clicks, or submits a form. Drive an interactive surface in a loop: open_surface (HTML that calls window.tessSurface.emit(name,detail) on interaction) \u2192 wait_for_surface_event \u2192 act + update_surface(op:"patch", content:{data:{...}}) to redraw in place \u2192 wait again. Returns {name, detail}, or a note if the surface closed / timed out.', { surfaceId: external_exports.string(), timeoutSeconds: external_exports.number().optional().describe("Max seconds to wait (default 300).") }, async (args) => {
21719
21770
  const ev = await deps.waitForEvent(args.surfaceId, args.timeoutSeconds ? Math.round(args.timeoutSeconds * 1e3) : void 0);
21720
21771
  return { content: [{ type: "text", text: ev ? `Surface event on ${args.surfaceId}: ${JSON.stringify(ev)}` : `No event on ${args.surfaceId} (surface closed or timed out).` }] };
21721
21772
  })
@@ -21742,7 +21793,7 @@ var init_chess_surface_html_generated = __esm({
21742
21793
  });
21743
21794
 
21744
21795
  // ../../packages/agent-core/dist/chess-tools.js
21745
- import { tool as tool6 } from "@anthropic-ai/claude-agent-sdk";
21796
+ import { tool as tool7 } from "@anthropic-ai/claude-agent-sdk";
21746
21797
  async function commandRoundTrip(deps, surfaceId, command, replyName, timeoutMs = 2e4) {
21747
21798
  const seq2 = Date.now();
21748
21799
  deps.update(surfaceId, { op: "patch", content: { data: { command, seq: seq2 } } });
@@ -21758,7 +21809,7 @@ async function commandRoundTrip(deps, surfaceId, command, replyName, timeoutMs =
21758
21809
  }
21759
21810
  function buildChessTools(deps) {
21760
21811
  return [
21761
- tool6("play_chess", `Open an interactive chess board in the conversation so the user can play a full game against a built-in chess engine. The user plays White and moves by clicking a piece then its destination; the engine (Black) replies automatically \u2014 the board runs itself, so you do NOT make or narrate the moves. Call this whenever the user wants to play chess (e.g. "let's play chess", "start a game"). After it opens, briefly tell them the board is ready. To answer questions about the game or give a hint, call chess_status / chess_hint \u2014 do not guess the position.`, {}, async () => {
21812
+ tool7("play_chess", `Open an interactive chess board in the conversation so the user can play a full game against a built-in chess engine. The user plays White and moves by clicking a piece then its destination; the engine (Black) replies automatically \u2014 the board runs itself, so you do NOT make or narrate the moves. Call this whenever the user wants to play chess (e.g. "let's play chess", "start a game"). After it opens, briefly tell them the board is ready. To answer questions about the game or give a hint, call chess_status / chess_hint \u2014 do not guess the position.`, {}, async () => {
21762
21813
  try {
21763
21814
  liveChessSurfaceId = deps.open({
21764
21815
  kind: "html",
@@ -21776,7 +21827,7 @@ function buildChessTools(deps) {
21776
21827
  return { content: [{ type: "text", text: `Could not open the chess board: ${e instanceof Error ? e.message : String(e)}` }] };
21777
21828
  }
21778
21829
  }),
21779
- tool6("chess_status", 'Read the CURRENT state of the running chess board \u2014 FEN, move list (PGN/SAN), whose turn it is, and the result if the game is over. Use this before answering any question about the position ("whose turn?", "what happened?", "am I winning?") instead of guessing. Returns nothing useful if no board is open (call play_chess first).', {}, async () => {
21830
+ tool7("chess_status", 'Read the CURRENT state of the running chess board \u2014 FEN, move list (PGN/SAN), whose turn it is, and the result if the game is over. Use this before answering any question about the position ("whose turn?", "what happened?", "am I winning?") instead of guessing. Returns nothing useful if no board is open (call play_chess first).', {}, async () => {
21780
21831
  if (!liveChessSurfaceId)
21781
21832
  return { content: [{ type: "text", text: "No chess board is open. Call play_chess first." }] };
21782
21833
  const st = await commandRoundTrip(deps, liveChessSurfaceId, "report", "state");
@@ -21785,7 +21836,7 @@ function buildChessTools(deps) {
21785
21836
  return { content: [{ type: "text", text: `Current chess position:
21786
21837
  ${JSON.stringify(st, null, 2)}` }] };
21787
21838
  }),
21788
- tool6("chess_hint", `Ask the built-in engine for the best move in the CURRENT position and highlight it on the board for the user. Use when the user asks for a hint / help / "what should I play?". Returns the engine's suggested move (from-to). Only meaningful when it's the user's (White's) turn and a board is open.`, {}, async () => {
21839
+ tool7("chess_hint", `Ask the built-in engine for the best move in the CURRENT position and highlight it on the board for the user. Use when the user asks for a hint / help / "what should I play?". Returns the engine's suggested move (from-to). Only meaningful when it's the user's (White's) turn and a board is open.`, {}, async () => {
21789
21840
  if (!liveChessSurfaceId)
21790
21841
  return { content: [{ type: "text", text: "No chess board is open. Call play_chess first." }] };
21791
21842
  const hint = await commandRoundTrip(deps, liveChessSurfaceId, "hint", "hint", 25e3);
@@ -21793,13 +21844,13 @@ ${JSON.stringify(st, null, 2)}` }] };
21793
21844
  return { content: [{ type: "text", text: "Could not get a hint (the board may be mid-move or closed)." }] };
21794
21845
  return { content: [{ type: "text", text: `Engine hint (highlighted on the board): ${JSON.stringify(hint)}` }] };
21795
21846
  }),
21796
- tool6("chess_new_game", "Reset the open chess board to a fresh starting position (the user plays White and moves first). Use when the user wants to start over / play again / rematch.", {}, async () => {
21847
+ tool7("chess_new_game", "Reset the open chess board to a fresh starting position (the user plays White and moves first). Use when the user wants to start over / play again / rematch.", {}, async () => {
21797
21848
  if (!liveChessSurfaceId)
21798
21849
  return { content: [{ type: "text", text: "No chess board is open. Call play_chess first." }] };
21799
21850
  deps.update(liveChessSurfaceId, { op: "patch", content: { data: { command: "newgame", seq: Date.now() } } });
21800
21851
  return { content: [{ type: "text", text: "Started a fresh game \u2014 the board is reset, the user plays White and moves first." }] };
21801
21852
  }),
21802
- tool6("chess_set_difficulty", `Set the chess engine's strength on the open board. Use when the user asks to make it easier or harder (e.g. "go easy on me", "make it harder", "play your best"). Levels: easy (weak) \xB7 medium (default) \xB7 hard \xB7 max (full strength). Takes effect on the engine's next move.`, { level: external_exports.enum(["easy", "medium", "hard", "max"]) }, async (args) => {
21853
+ tool7("chess_set_difficulty", `Set the chess engine's strength on the open board. Use when the user asks to make it easier or harder (e.g. "go easy on me", "make it harder", "play your best"). Levels: easy (weak) \xB7 medium (default) \xB7 hard \xB7 max (full strength). Takes effect on the engine's next move.`, { level: external_exports.enum(["easy", "medium", "hard", "max"]) }, async (args) => {
21803
21854
  if (!liveChessSurfaceId)
21804
21855
  return { content: [{ type: "text", text: "No chess board is open. Call play_chess first." }] };
21805
21856
  deps.update(liveChessSurfaceId, { op: "patch", content: { data: { command: "level", level: args.level, seq: Date.now() } } });
@@ -21929,8 +21980,8 @@ function makeApi(deps, toolId, tier) {
21929
21980
  await h.close();
21930
21981
  return r.cancelled ? null : r.value ?? [];
21931
21982
  },
21932
- notify: async (text3, opts) => {
21933
- await api.open({ kind: "markdown", initial: { markdown: text3, level: opts?.level } });
21983
+ notify: async (text4, opts) => {
21984
+ await api.open({ kind: "markdown", initial: { markdown: text4, level: opts?.level } });
21934
21985
  }
21935
21986
  };
21936
21987
  return api;
@@ -21941,11 +21992,11 @@ function buildToolCtx(deps, sessionId, toolId, log4 = NOOP_LOG, tier = "third-pa
21941
21992
  return getSid();
21942
21993
  }, toolId, log: log4 };
21943
21994
  }
21944
- function wrapCtxTool(tool11, ctx2) {
21945
- const raw = tool11.__ctxHandler;
21995
+ function wrapCtxTool(tool12, ctx2) {
21996
+ const raw = tool12.__ctxHandler;
21946
21997
  if (typeof raw !== "function")
21947
- return tool11;
21948
- return { ...tool11, handler: async (args) => raw(args, ctx2) };
21998
+ return tool12;
21999
+ return { ...tool12, handler: async (args) => raw(args, ctx2) };
21949
22000
  }
21950
22001
  var NOOP_LOG;
21951
22002
  var init_surface_ctx = __esm({
@@ -22101,7 +22152,7 @@ var init_hook_bus = __esm({
22101
22152
  });
22102
22153
 
22103
22154
  // ../../packages/agent-core/dist/screen-control-tools.js
22104
- import { tool as tool7 } from "@anthropic-ai/claude-agent-sdk";
22155
+ import { tool as tool8 } from "@anthropic-ai/claude-agent-sdk";
22105
22156
  function specParametersJsonSchema(spec) {
22106
22157
  const properties = {};
22107
22158
  const required2 = [];
@@ -22122,9 +22173,9 @@ function zodShapeFromParams(params) {
22122
22173
  return shape;
22123
22174
  }
22124
22175
  function buildScreenControlSdkTools(p) {
22125
- return SCREEN_CONTROL_SPECS.map((spec) => tool7(spec.name, spec.description, zodShapeFromParams(spec.params), async (args) => {
22126
- const text3 = await p.exec(spec.name, args ?? {});
22127
- return { content: [{ type: "text", text: text3 || "Done." }] };
22176
+ return SCREEN_CONTROL_SPECS.map((spec) => tool8(spec.name, spec.description, zodShapeFromParams(spec.params), async (args) => {
22177
+ const text4 = await p.exec(spec.name, args ?? {});
22178
+ return { content: [{ type: "text", text: text4 || "Done." }] };
22128
22179
  }));
22129
22180
  }
22130
22181
  var ANNOTATE_STYLES, SCREEN_CONTROL_SPECS;
@@ -22239,7 +22290,7 @@ var init_screen_control_tools = __esm({
22239
22290
  });
22240
22291
 
22241
22292
  // ../../packages/agent-core/dist/computer-control-tools.js
22242
- import { tool as tool8 } from "@anthropic-ai/claude-agent-sdk";
22293
+ import { tool as tool9 } from "@anthropic-ai/claude-agent-sdk";
22243
22294
  function computerSpecParametersJsonSchema(spec) {
22244
22295
  const properties = {};
22245
22296
  const required2 = [];
@@ -22260,7 +22311,7 @@ function zodShapeFromParams2(params) {
22260
22311
  return shape;
22261
22312
  }
22262
22313
  function buildComputerControlSdkTools(p) {
22263
- return COMPUTER_CONTROL_SPECS.map((spec) => tool8(spec.name, spec.description, zodShapeFromParams2(spec.params), async (args) => {
22314
+ return COMPUTER_CONTROL_SPECS.map((spec) => tool9(spec.name, spec.description, zodShapeFromParams2(spec.params), async (args) => {
22264
22315
  if (spec.name === "see_screen") {
22265
22316
  const a = args ?? {};
22266
22317
  const region = a.x1 !== void 0 && a.y1 !== void 0 && a.x2 !== void 0 && a.y2 !== void 0 ? [a.y1, a.x1, a.y2, a.x2] : void 0;
@@ -22404,13 +22455,13 @@ WHEN YOUR REPLIES ARE READ ALOUD (voice): keep them SHORT and conversational \u2
22404
22455
  });
22405
22456
 
22406
22457
  // ../../packages/agent-core/dist/report-tools.js
22407
- import { tool as tool9 } from "@anthropic-ai/claude-agent-sdk";
22458
+ import { tool as tool10 } from "@anthropic-ai/claude-agent-sdk";
22408
22459
  function slug(s) {
22409
22460
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "mission";
22410
22461
  }
22411
22462
  function buildReportTools(deps) {
22412
22463
  return [
22413
- tool9("emit_report", `Deliver the structured findings of a mission playbook run as a Report card in the chat (this is the deliverable \u2014 do NOT just write findings as prose). Call it ONCE near the end with all findings grouped into the playbook's sections. To UPDATE after fixing/verifying a finding (Fix / Re-run), call again with the SAME id and finding ids, changing each finding's status \u2014 it re-renders in place. For "legal" bucket reports, never claim the site is compliant/certified; describe risks and route the verdict to a human.`, {
22464
+ tool10("emit_report", `Deliver the structured findings of a mission playbook run as a Report card in the chat (this is the deliverable \u2014 do NOT just write findings as prose). Call it ONCE near the end with all findings grouped into the playbook's sections. To UPDATE after fixing/verifying a finding (Fix / Re-run), call again with the SAME id and finding ids, changing each finding's status \u2014 it re-renders in place. For "legal" bucket reports, never claim the site is compliant/certified; describe risks and route the verdict to a human.`, {
22414
22465
  id: external_exports.string().optional().describe("Stable report id to UPDATE an existing report; omit on the first call to create one."),
22415
22466
  playbookId: external_exports.string().describe("The playbook id this report belongs to."),
22416
22467
  title: external_exports.string().describe("Report title (usually the playbook name)."),
@@ -22463,10 +22514,10 @@ var init_report_tools = __esm({
22463
22514
  });
22464
22515
 
22465
22516
  // ../../packages/agent-core/dist/interactive-ui-tools.js
22466
- import { tool as tool10 } from "@anthropic-ai/claude-agent-sdk";
22517
+ import { tool as tool11 } from "@anthropic-ai/claude-agent-sdk";
22467
22518
  function buildInteractiveUiTools(deps) {
22468
22519
  return [
22469
- tool10("ask_form", "Show the user a FORM in the chat and wait for them to fill it in. Use this to collect structured input mid-task (settings, scope, details) instead of asking in prose. Returns the submitted values (or that the user cancelled). Prefer this over free-text questions when the answer is structured.", {
22520
+ tool11("ask_form", "Show the user a FORM in the chat and wait for them to fill it in. Use this to collect structured input mid-task (settings, scope, details) instead of asking in prose. Returns the submitted values (or that the user cancelled). Prefer this over free-text questions when the answer is structured.", {
22470
22521
  title: external_exports.string().describe("Form heading (plain language)."),
22471
22522
  description: external_exports.string().optional().describe("Short explanation shown above the fields."),
22472
22523
  submitLabel: external_exports.string().optional().describe('Submit button label (default "Submit").'),
@@ -22480,7 +22531,7 @@ function buildInteractiveUiTools(deps) {
22480
22531
  return { content: [{ type: "text", text: `The user submitted the form:
22481
22532
  ${JSON.stringify(res.values ?? {}, null, 2)}` }] };
22482
22533
  }),
22483
- tool10("present_choices", "Show the user a CHOICE picker in the chat and wait for them to choose. Use this to let the user make a decision or pick from options (single or multi-select). Returns the selected value(s) (or cancellation).", {
22534
+ tool11("present_choices", "Show the user a CHOICE picker in the chat and wait for them to choose. Use this to let the user make a decision or pick from options (single or multi-select). Returns the selected value(s) (or cancellation).", {
22484
22535
  title: external_exports.string().describe("The question / heading."),
22485
22536
  description: external_exports.string().optional(),
22486
22537
  options: external_exports.array(choiceOption).min(1),
@@ -22493,7 +22544,7 @@ ${JSON.stringify(res.values ?? {}, null, 2)}` }] };
22493
22544
  return { content: [{ type: "text", text: "The user cancelled the choice (nothing selected)." }] };
22494
22545
  return { content: [{ type: "text", text: `The user selected: ${JSON.stringify(res.selected ?? [])}` }] };
22495
22546
  }),
22496
- tool10("update_progress", `Update the live Mission card so the user sees ongoing status. Call this whenever you move between stages (and once at the start). Pass the FULL ordered stage list each time with each stage's current status, plus a short "what I'm doing now" note. This is a one-way feedback channel \u2014 it returns immediately, does not wait for the user.`, {
22547
+ tool11("update_progress", `Update the live Mission card so the user sees ongoing status. Call this whenever you move between stages (and once at the start). Pass the FULL ordered stage list each time with each stage's current status, plus a short "what I'm doing now" note. This is a one-way feedback channel \u2014 it returns immediately, does not wait for the user.`, {
22497
22548
  stages: external_exports.array(external_exports.object({
22498
22549
  label: external_exports.string(),
22499
22550
  status: external_exports.enum(["pending", "active", "done"])
@@ -22608,8 +22659,8 @@ async function exportSession(sessionId, fromCwd) {
22608
22659
  function escapeRe(s) {
22609
22660
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22610
22661
  }
22611
- function rekey(text3, fromCwd, toCwd) {
22612
- return text3.replace(new RegExp(escapeRe(fromCwd) + '(?=["/\\\\]|$)', "g"), () => toCwd);
22662
+ function rekey(text4, fromCwd, toCwd) {
22663
+ return text4.replace(new RegExp(escapeRe(fromCwd) + '(?=["/\\\\]|$)', "g"), () => toCwd);
22613
22664
  }
22614
22665
  async function importSession(exp, toCwd) {
22615
22666
  const destDir = sessionDir(toCwd);
@@ -22862,13 +22913,13 @@ ${s.log.map((l) => `- ${l}`).join("\n")}` : "",
22862
22913
  ${activity}`,
22863
22914
  "One-line status of what it is doing now:"
22864
22915
  ].filter(Boolean).join("\n\n");
22865
- const text3 = (await cfg2.complete({ system, prompt, maxTokens: 48 }))?.trim().replace(/^["']|["']$/g, "");
22866
- if (text3 && text3 !== s.lastText) {
22867
- s.lastText = text3;
22868
- s.log.push(text3);
22916
+ const text4 = (await cfg2.complete({ system, prompt, maxTokens: 48 }))?.trim().replace(/^["']|["']$/g, "");
22917
+ if (text4 && text4 !== s.lastText) {
22918
+ s.lastText = text4;
22919
+ s.log.push(text4);
22869
22920
  if (s.log.length > LOG_CAP)
22870
22921
  s.log.shift();
22871
- this.emit(id, text3, cfg2.engineLabel);
22922
+ this.emit(id, text4, cfg2.engineLabel);
22872
22923
  }
22873
22924
  } catch {
22874
22925
  } finally {
@@ -23020,9 +23071,9 @@ function transcriptMatches(raw, q) {
23020
23071
  }
23021
23072
  return false;
23022
23073
  }
23023
- function stripPromptPrefix(text3) {
23074
+ function stripPromptPrefix(text4) {
23024
23075
  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");
23025
- const userLines = text3.split("\n").filter((l) => !isMetadata(l));
23076
+ const userLines = text4.split("\n").filter((l) => !isMetadata(l));
23026
23077
  return userLines.join("\n").trim();
23027
23078
  }
23028
23079
  function extractBlocks(message) {
@@ -23041,13 +23092,13 @@ function extractBlocks(message) {
23041
23092
  continue;
23042
23093
  const b = block;
23043
23094
  if (b.type === "thinking" && typeof b.thinking === "string") {
23044
- const text3 = b.thinking.trim();
23045
- if (text3)
23046
- blocks.push({ kind: "thinking", content: text3 });
23095
+ const text4 = b.thinking.trim();
23096
+ if (text4)
23097
+ blocks.push({ kind: "thinking", content: text4 });
23047
23098
  } else if (b.type === "text" && typeof b.text === "string") {
23048
- const text3 = b.text.trim();
23049
- if (text3 && !text3.startsWith("<ide_") && !text3.startsWith("<system-reminder>")) {
23050
- blocks.push({ kind: "text", content: text3 });
23099
+ const text4 = b.text.trim();
23100
+ if (text4 && !text4.startsWith("<ide_") && !text4.startsWith("<system-reminder>")) {
23101
+ blocks.push({ kind: "text", content: text4 });
23051
23102
  }
23052
23103
  } else if (b.type === "tool_use") {
23053
23104
  const name = b.name ?? "tool";
@@ -23093,9 +23144,9 @@ ${input.command}
23093
23144
  blocks.push({ kind: "tool_use", content: detail });
23094
23145
  } else if (b.type === "advisor_tool_result") {
23095
23146
  const c = b.content;
23096
- const text3 = c?.type === "advisor_result" ? (c.text ?? "").trim() : "";
23097
- if (text3)
23098
- blocks.push({ kind: "advisor", content: text3 });
23147
+ const text4 = c?.type === "advisor_result" ? (c.text ?? "").trim() : "";
23148
+ if (text4)
23149
+ blocks.push({ kind: "advisor", content: text4 });
23099
23150
  }
23100
23151
  }
23101
23152
  return blocks;
@@ -23762,8 +23813,8 @@ function describeSystemSubtype(subtype, m) {
23762
23813
  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;
23763
23814
  return { category, name: subtype, title: humanizeName(subtype), fields: salientFields(m), ...updateKey ? { updateKey } : {} };
23764
23815
  }
23765
- const text3 = extractHumanReadable(m);
23766
- return { category: "unknown", name: subtype, title: `system/${subtype}`, ...text3 ? { detail: text3 } : {}, raw: rawFramePreview(m) };
23816
+ const text4 = extractHumanReadable(m);
23817
+ return { category: "unknown", name: subtype, title: `system/${subtype}`, ...text4 ? { detail: text4 } : {}, raw: rawFramePreview(m) };
23767
23818
  }
23768
23819
  function sstr(v) {
23769
23820
  return typeof v === "string" ? v : "";
@@ -23781,24 +23832,24 @@ function prettifyModel(id) {
23781
23832
  return known[id] ?? id.replace(/^claude-/, "").replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
23782
23833
  }
23783
23834
  function taskNotificationNotices(content) {
23784
- let text3 = "";
23835
+ let text4 = "";
23785
23836
  if (typeof content === "string")
23786
- text3 = content;
23837
+ text4 = content;
23787
23838
  else if (Array.isArray(content)) {
23788
23839
  for (const b of content) {
23789
23840
  if (b && typeof b === "object" && b.type === "text")
23790
- text3 += `${sstr(b.text)}
23841
+ text4 += `${sstr(b.text)}
23791
23842
  `;
23792
23843
  }
23793
23844
  }
23794
- if (!text3.includes("<task-notification>"))
23845
+ if (!text4.includes("<task-notification>"))
23795
23846
  return [];
23796
23847
  const tag = (xml2, name) => {
23797
23848
  const m = new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(xml2);
23798
23849
  return m ? m[1].trim() : "";
23799
23850
  };
23800
23851
  const specs = [];
23801
- for (const m of text3.matchAll(/<task-notification>([\s\S]*?)<\/task-notification>/g)) {
23852
+ for (const m of text4.matchAll(/<task-notification>([\s\S]*?)<\/task-notification>/g)) {
23802
23853
  const status2 = (tag(m[1], "status") || "completed").toLowerCase();
23803
23854
  const summary = tag(m[1], "summary") || "Background task finished.";
23804
23855
  const failed = /fail|error/.test(status2);
@@ -23809,10 +23860,10 @@ function taskNotificationNotices(content) {
23809
23860
  }
23810
23861
  return specs;
23811
23862
  }
23812
- function cleanTaskNotifications(text3) {
23813
- if (!text3.includes("<task-notification>"))
23814
- return text3;
23815
- return text3.replace(/<task-notification>([\s\S]*?)<\/task-notification>/g, (_all, inner) => {
23863
+ function cleanTaskNotifications(text4) {
23864
+ if (!text4.includes("<task-notification>"))
23865
+ return text4;
23866
+ return text4.replace(/<task-notification>([\s\S]*?)<\/task-notification>/g, (_all, inner) => {
23816
23867
  const g = (name) => {
23817
23868
  const m = new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(inner);
23818
23869
  return m ? m[1].trim() : "";
@@ -23825,10 +23876,10 @@ function cleanTaskNotifications(text3) {
23825
23876
  function buildNotice(subtype, m) {
23826
23877
  switch (subtype) {
23827
23878
  case "notification": {
23828
- const text3 = sstr(m.text) || "Notification";
23879
+ const text4 = sstr(m.text) || "Notification";
23829
23880
  const priority = ["low", "medium", "high", "immediate"].includes(sstr(m.priority)) ? m.priority : "medium";
23830
23881
  const level = priority === "immediate" ? "error" : priority === "high" ? "warning" : priority === "low" ? "info" : "notice";
23831
- return { category: "notification", level, priority, title: text3, toast: true, inline: true, ...typeof m.timeout_ms === "number" ? { timeoutMs: m.timeout_ms } : {} };
23882
+ return { category: "notification", level, priority, title: text4, toast: true, inline: true, ...typeof m.timeout_ms === "number" ? { timeoutMs: m.timeout_ms } : {} };
23832
23883
  }
23833
23884
  case "informational": {
23834
23885
  const content = sstr(m.content).trim();
@@ -23859,9 +23910,9 @@ function buildNotice(subtype, m) {
23859
23910
  return { category: "memory", level: "info", title: `Recalled ${memories.length} ${memories.length === 1 ? "memory" : "memories"}`, ...names.length ? { body: names.join(" \xB7 ") } : {}, toast: false, inline: true };
23860
23911
  }
23861
23912
  case "permission_denied": {
23862
- const tool11 = sstr(m.tool_name) || "a tool";
23913
+ const tool12 = sstr(m.tool_name) || "a tool";
23863
23914
  const reason = sstr(m.decision_reason) || sstr(m.message);
23864
- return { category: "permission", level: "warning", title: `Blocked: ${tool11}`, ...reason ? { body: reason } : {}, ...sstr(m.tool_use_id) ? { toolUseId: sstr(m.tool_use_id) } : {}, toast: true, inline: true };
23915
+ return { category: "permission", level: "warning", title: `Blocked: ${tool12}`, ...reason ? { body: reason } : {}, ...sstr(m.tool_use_id) ? { toolUseId: sstr(m.tool_use_id) } : {}, toast: true, inline: true };
23865
23916
  }
23866
23917
  case "model_refusal_fallback": {
23867
23918
  const orig = sstr(m.original_model);
@@ -23975,9 +24026,9 @@ ${plan}`;
23975
24026
  return name;
23976
24027
  }
23977
24028
  }
23978
- function computerToolPhrase(tool11, input) {
24029
+ function computerToolPhrase(tool12, input) {
23979
24030
  const s = (v) => typeof v === "string" ? v : "";
23980
- switch (tool11) {
24031
+ switch (tool12) {
23981
24032
  case "see_screen":
23982
24033
  return input.x1 !== void 0 ? "Looking closely at part of the screen" : "Looking at the screen";
23983
24034
  case "click":
@@ -24013,15 +24064,15 @@ function computerToolPhrase(tool11, input) {
24013
24064
  }
24014
24065
  }
24015
24066
  function flattenToolResultContent(content) {
24016
- let text3 = "";
24067
+ let text4 = "";
24017
24068
  if (typeof content === "string")
24018
- text3 = content;
24069
+ text4 = content;
24019
24070
  else if (Array.isArray(content)) {
24020
- text3 = content.filter((b) => b && typeof b === "object" && b.type === "text").map((b) => String(b.text ?? "")).join("\n");
24071
+ text4 = content.filter((b) => b && typeof b === "object" && b.type === "text").map((b) => String(b.text ?? "")).join("\n");
24021
24072
  }
24022
- if (text3.length > TOOL_RESULT_CAP)
24023
- return { text: text3.slice(0, TOOL_RESULT_CAP), truncated: true };
24024
- return { text: text3, truncated: false };
24073
+ if (text4.length > TOOL_RESULT_CAP)
24074
+ return { text: text4.slice(0, TOOL_RESULT_CAP), truncated: true };
24075
+ return { text: text4, truncated: false };
24025
24076
  }
24026
24077
  function extractImages(content) {
24027
24078
  if (!Array.isArray(content))
@@ -24119,6 +24170,7 @@ var init_agent_manager = __esm({
24119
24170
  init_dist2();
24120
24171
  init_cron_tools();
24121
24172
  init_design_tools();
24173
+ init_support_tools();
24122
24174
  init_imagegen_tools();
24123
24175
  init_canvas_tools();
24124
24176
  init_surface_tools();
@@ -24281,6 +24333,9 @@ var init_agent_manager = __esm({
24281
24333
  hookBus = null;
24282
24334
  screenControlProvider = null;
24283
24335
  computerControlProvider = null;
24336
+ /** In-app issue reporter (`tesseract-support`: submit_issue). Non-null ⇒ NEW
24337
+ * conversations get the tool; the host does the collect-diagnostics + authed POST. */
24338
+ supportSubmit = null;
24284
24339
  /** M6 — scheduling. Built lazily by setCronConfig when cron is enabled. */
24285
24340
  cronStore = null;
24286
24341
  cronScheduler = null;
@@ -24402,6 +24457,11 @@ var init_agent_manager = __esm({
24402
24457
  setComputerControl(provider) {
24403
24458
  this.computerControlProvider = provider;
24404
24459
  }
24460
+ /** Inject the in-app issue reporter (`tesseract-support`: submit_issue). The provider
24461
+ * collects diagnostics + POSTs to the cloud API host-side (auth stays host-side). */
24462
+ setSupportSubmit(provider) {
24463
+ this.supportSubmit = provider;
24464
+ }
24405
24465
  /** M6 — enable/disable model-facing scheduling. When enabled, builds a CronStore
24406
24466
  * (durable at `file`/`storeDir` if given, else session-only), starts the scheduler
24407
24467
  * whose fires dispatch a turn, and exposes the Cron / Sleep / PushNotification tools
@@ -24473,7 +24533,7 @@ var init_agent_manager = __esm({
24473
24533
  this.onBrowserRequest = onBrowserRequest;
24474
24534
  const __dirname = dirname5(fileURLToPath(import.meta.url));
24475
24535
  this.browserCliPath = join9(__dirname, "browser-cli.js");
24476
- this.narrator = new Narrator((sessionId, text3, engineLabel) => this.send({ type: "agent:narration", sessionId, text: text3, ...engineLabel ? { engineLabel } : {} }, this.liveSessions.get(sessionId)?.origin));
24536
+ this.narrator = new Narrator((sessionId, text4, engineLabel) => this.send({ type: "agent:narration", sessionId, text: text4, ...engineLabel ? { engineLabel } : {} }, this.liveSessions.get(sessionId)?.origin));
24477
24537
  }
24478
24538
  /** Inject (or clear) the cheap model used for the live status narration. The
24479
24539
  * host resolves creds and builds the completion fn (keeping secrets host-side). */
@@ -24686,10 +24746,10 @@ ${full.slice(-8e3)}`;
24686
24746
  parts.push(`The user's current request:
24687
24747
  ${live.lastPrompt.slice(0, 1400)}`);
24688
24748
  if (Array.isArray(live.lastAssistantContent)) {
24689
- const text3 = live.lastAssistantContent.filter((b) => b?.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n").trim();
24690
- if (text3)
24749
+ const text4 = live.lastAssistantContent.filter((b) => b?.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n").trim();
24750
+ if (text4)
24691
24751
  parts.push(`What the assistant just said (leading to this question):
24692
- ${text3.slice(0, 1600)}`);
24752
+ ${text4.slice(0, 1600)}`);
24693
24753
  }
24694
24754
  return parts.join("\n\n") || "No additional context available beyond the question itself.";
24695
24755
  }
@@ -24905,9 +24965,9 @@ ${qText}`;
24905
24965
  const transcripts = [];
24906
24966
  for (const sid of sessionIds) {
24907
24967
  const msgs = await this.sessionStore.getSessionMessages(sid).catch(() => []);
24908
- const text3 = msgs.map((m) => `${m.role === "user" ? "User" : "Assistant"}: ${cleanTaskNotifications(m.content)}`).join("\n").slice(0, PER_SOURCE_CAP);
24909
- if (text3.trim())
24910
- transcripts.push(text3);
24968
+ const text4 = msgs.map((m) => `${m.role === "user" ? "User" : "Assistant"}: ${cleanTaskNotifications(m.content)}`).join("\n").slice(0, PER_SOURCE_CAP);
24969
+ if (text4.trim())
24970
+ transcripts.push(text4);
24911
24971
  }
24912
24972
  if (transcripts.length === 0)
24913
24973
  return;
@@ -25224,13 +25284,13 @@ CRITICAL RULES:
25224
25284
  ls.steerFlushTimer = setTimeout(() => this.flushSteer(ls), STEER_COALESCE_MS);
25225
25285
  return;
25226
25286
  }
25227
- const tail2 = live.queue[live.queue.length - 1];
25228
- if (tail2 && (tail2.origin ?? void 0) === (params.origin ?? void 0) && (tail2.sources === void 0 && params.sources === void 0 || tail2.sources !== void 0 && params.sources !== void 0 && sourcesEqual(tail2.sources, params.sources)) && typeof tail2.msg.message.content === "string") {
25229
- tail2.msg.message.content += "\n\n" + userText;
25287
+ const tail3 = live.queue[live.queue.length - 1];
25288
+ if (tail3 && (tail3.origin ?? void 0) === (params.origin ?? void 0) && (tail3.sources === void 0 && params.sources === void 0 || tail3.sources !== void 0 && params.sources !== void 0 && sourcesEqual(tail3.sources, params.sources)) && typeof tail3.msg.message.content === "string") {
25289
+ tail3.msg.message.content += "\n\n" + userText;
25230
25290
  if (params.browserId !== void 0)
25231
- tail2.browserId = params.browserId;
25291
+ tail3.browserId = params.browserId;
25232
25292
  if (params.windowId !== void 0)
25233
- tail2.windowId = params.windowId;
25293
+ tail3.windowId = params.windowId;
25234
25294
  return;
25235
25295
  }
25236
25296
  live.queue.push({
@@ -25440,6 +25500,9 @@ CRITICAL RULES:
25440
25500
  if (this.computerControlProvider) {
25441
25501
  mcp["tesseract-computer"] = createSdkMcpServer({ name: "tesseract-computer", version: "0.1.0", tools: buildComputerControlSdkTools(this.computerControlProvider) });
25442
25502
  }
25503
+ if (this.supportSubmit) {
25504
+ mcp["tesseract-support"] = createSdkMcpServer({ name: "tesseract-support", version: "0.1.0", tools: buildSupportTools(this.supportSubmit) });
25505
+ }
25443
25506
  {
25444
25507
  const projectDir = this.projectDir;
25445
25508
  const canvasTools = buildCanvasTools({
@@ -25867,9 +25930,9 @@ ${params.appendSystemPrompt}` : ""), live.sessionId) },
25867
25930
  emit2({ type: "chat:stream", sessionId: sid, delta: "[thinking redacted]", messageId: message.uuid, kind: "thinking", ...parentField });
25868
25931
  } else if (cbt === "advisor_tool_result") {
25869
25932
  const res = event.content_block.content;
25870
- const text3 = res?.type === "advisor_result" ? (res.text ?? "").trim() : "";
25871
- if (text3 && parentToolUseId === void 0)
25872
- emit2({ type: "agent:advisor", sessionId: sid, text: text3 });
25933
+ const text4 = res?.type === "advisor_result" ? (res.text ?? "").trim() : "";
25934
+ if (text4 && parentToolUseId === void 0)
25935
+ emit2({ type: "agent:advisor", sessionId: sid, text: text4 });
25873
25936
  }
25874
25937
  }
25875
25938
  if (event.type === "content_block_delta") {
@@ -25884,26 +25947,26 @@ ${params.appendSystemPrompt}` : ""), live.sessionId) },
25884
25947
  }
25885
25948
  }
25886
25949
  if (event.delta?.type === "text_delta" && event.delta.text) {
25887
- const text3 = event.delta.text;
25888
- if (/<(?:tool_call|tool_result|function_calls|antml:function_calls)[\s>]/i.test(text3)) {
25950
+ const text4 = event.delta.text;
25951
+ if (/<(?:tool_call|tool_result|function_calls|antml:function_calls)[\s>]/i.test(text4)) {
25889
25952
  insideXmlByKey.set(key2, true);
25890
25953
  break;
25891
25954
  }
25892
25955
  if (insideXmlByKey.get(key2)) {
25893
- if (/<\/(?:tool_call|tool_result|function_calls|antml:function_calls)\s*>/i.test(text3)) {
25956
+ if (/<\/(?:tool_call|tool_result|function_calls|antml:function_calls)\s*>/i.test(text4)) {
25894
25957
  insideXmlByKey.set(key2, false);
25895
25958
  }
25896
25959
  break;
25897
25960
  }
25898
- if (/<\/?(?:invoke|antml:invoke|antml:parameter)[\s>]/.test(text3))
25961
+ if (/<\/?(?:invoke|antml:invoke|antml:parameter)[\s>]/.test(text4))
25899
25962
  break;
25900
- if (/<parameter\s+name=/.test(text3))
25963
+ if (/<parameter\s+name=/.test(text4))
25901
25964
  break;
25902
- if (/^\s*<\/(?:parameter|invoke|function_calls)>\s*$/.test(text3))
25965
+ if (/^\s*<\/(?:parameter|invoke|function_calls)>\s*$/.test(text4))
25903
25966
  break;
25904
25967
  if (parentToolUseId === void 0)
25905
25968
  turnStreamed = true;
25906
- const d = this.applyDeltaHook(text3, "text", sid);
25969
+ const d = this.applyDeltaHook(text4, "text", sid);
25907
25970
  if (d !== null)
25908
25971
  emit2({ type: "chat:stream", sessionId: sid, delta: d, messageId: message.uuid, kind: "text", ...parentField });
25909
25972
  }
@@ -26294,14 +26357,14 @@ ${params.appendSystemPrompt}` : ""), live.sessionId) },
26294
26357
  const tn = toolNameByUseId.get(toolUseId);
26295
26358
  if (tn === "Edit" || tn === "Write" || tn === "MultiEdit" || tn === "NotebookEdit")
26296
26359
  continue;
26297
- const { text: text3, truncated } = flattenToolResultContent(blk.content);
26360
+ const { text: text4, truncated } = flattenToolResultContent(blk.content);
26298
26361
  const images = extractImages(blk.content);
26299
26362
  const isError = blk.is_error === true;
26300
- if (!text3 && images.length === 0 && !isError)
26363
+ if (!text4 && images.length === 0 && !isError)
26301
26364
  continue;
26302
- emit2({ type: "agent:tool_result", sessionId: sid, toolUseId, isError, output: text3, images, truncated, ...agentId ? { agentId } : {} });
26365
+ emit2({ type: "agent:tool_result", sessionId: sid, toolUseId, isError, output: text4, images, truncated, ...agentId ? { agentId } : {} });
26303
26366
  if (isError && !agentId) {
26304
- const why = (text3 || "").replace(/```[\s\S]*?```/g, " ").replace(/[`*]/g, "").replace(/\s+/g, " ").trim().slice(0, 160);
26367
+ const why = (text4 || "").replace(/```[\s\S]*?```/g, " ").replace(/[`*]/g, "").replace(/\s+/g, " ").trim().slice(0, 160);
26305
26368
  this.narrator.observe(sid, `\u2192 that didn't work${why ? `: ${why}` : ""}`);
26306
26369
  }
26307
26370
  } else if (blk?.type === "web_search_tool_result") {
@@ -26333,12 +26396,12 @@ ${params.appendSystemPrompt}` : ""), live.sessionId) },
26333
26396
  }
26334
26397
  default: {
26335
26398
  const m = message;
26336
- const text3 = extractHumanReadable(m);
26399
+ const text4 = extractHumanReadable(m);
26337
26400
  emitEvent({
26338
26401
  category: "unknown",
26339
26402
  name: m.type || "unknown",
26340
26403
  title: m.type || "unknown frame",
26341
- ...text3 ? { detail: text3 } : {},
26404
+ ...text4 ? { detail: text4 } : {},
26342
26405
  raw: rawFramePreview(m)
26343
26406
  }, parentToolUseId);
26344
26407
  log("unknown SDK message type surfaced with raw data:", m.type || "?");
@@ -26731,6 +26794,7 @@ __export(dist_exports, {
26731
26794
  buildComputerControlSdkTools: () => buildComputerControlSdkTools,
26732
26795
  buildImagegenTools: () => buildImagegenTools,
26733
26796
  buildScreenControlSdkTools: () => buildScreenControlSdkTools,
26797
+ buildSupportTools: () => buildSupportTools,
26734
26798
  buildToolCtx: () => buildToolCtx,
26735
26799
  bumpVersion: () => bumpVersion,
26736
26800
  computerSpecParametersJsonSchema: () => computerSpecParametersJsonSchema,
@@ -26782,6 +26846,7 @@ var init_dist4 = __esm({
26782
26846
  init_imagegen_tools();
26783
26847
  init_screen_control_tools();
26784
26848
  init_computer_control_tools();
26849
+ init_support_tools();
26785
26850
  init_design_tokens2();
26786
26851
  }
26787
26852
  });
@@ -28486,8 +28551,8 @@ var require_build = __commonJS({
28486
28551
  var BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
28487
28552
  var BASE64URL_REGEX = /^[a-zA-Z0-9-_]+$/;
28488
28553
  var Utf8Converter = class {
28489
- static fromString(text3) {
28490
- const s = unescape(encodeURIComponent(text3));
28554
+ static fromString(text4) {
28555
+ const s = unescape(encodeURIComponent(text4));
28491
28556
  const uintArray = new Uint8Array(s.length);
28492
28557
  for (let i = 0; i < s.length; i++) {
28493
28558
  uintArray[i] = s.charCodeAt(i);
@@ -28515,11 +28580,11 @@ var require_build = __commonJS({
28515
28580
  }
28516
28581
  return res;
28517
28582
  }
28518
- static fromString(text3, littleEndian = false) {
28519
- const res = new ArrayBuffer(text3.length * 2);
28583
+ static fromString(text4, littleEndian = false) {
28584
+ const res = new ArrayBuffer(text4.length * 2);
28520
28585
  const dataView = new DataView(res);
28521
- for (let i = 0; i < text3.length; i++) {
28522
- dataView.setUint16(i * 2, text3.charCodeAt(i), littleEndian);
28586
+ for (let i = 0; i < text4.length; i++) {
28587
+ dataView.setUint16(i * 2, text4.charCodeAt(i), littleEndian);
28523
28588
  }
28524
28589
  return res;
28525
28590
  }
@@ -28616,18 +28681,18 @@ var require_build = __commonJS({
28616
28681
  static ToBase64Url(data) {
28617
28682
  return this.ToBase64(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/\=/g, "");
28618
28683
  }
28619
- static FromUtf8String(text3, encoding = _Convert.DEFAULT_UTF8_ENCODING) {
28684
+ static FromUtf8String(text4, encoding = _Convert.DEFAULT_UTF8_ENCODING) {
28620
28685
  switch (encoding) {
28621
28686
  case "ascii":
28622
- return this.FromBinary(text3);
28687
+ return this.FromBinary(text4);
28623
28688
  case "utf8":
28624
- return Utf8Converter.fromString(text3);
28689
+ return Utf8Converter.fromString(text4);
28625
28690
  case "utf16":
28626
28691
  case "utf16be":
28627
- return Utf16Converter.fromString(text3);
28692
+ return Utf16Converter.fromString(text4);
28628
28693
  case "utf16le":
28629
28694
  case "usc2":
28630
- return Utf16Converter.fromString(text3, true);
28695
+ return Utf16Converter.fromString(text4, true);
28631
28696
  default:
28632
28697
  throw new Error(`Unknown type of encoding '${encoding}'`);
28633
28698
  }
@@ -28648,11 +28713,11 @@ var require_build = __commonJS({
28648
28713
  throw new Error(`Unknown type of encoding '${encoding}'`);
28649
28714
  }
28650
28715
  }
28651
- static FromBinary(text3) {
28652
- const stringLength = text3.length;
28716
+ static FromBinary(text4) {
28717
+ const stringLength = text4.length;
28653
28718
  const resultView = new Uint8Array(stringLength);
28654
28719
  for (let i = 0; i < stringLength; i++) {
28655
- resultView[i] = text3.charCodeAt(i);
28720
+ resultView[i] = text4.charCodeAt(i);
28656
28721
  }
28657
28722
  return resultView.buffer;
28658
28723
  }
@@ -28698,8 +28763,8 @@ var require_build = __commonJS({
28698
28763
  static ToUtf16String(buffer, littleEndian = false) {
28699
28764
  return Utf16Converter.toString(buffer, littleEndian);
28700
28765
  }
28701
- static FromUtf16String(text3, littleEndian = false) {
28702
- return Utf16Converter.fromString(text3, littleEndian);
28766
+ static FromUtf16String(text4, littleEndian = false) {
28767
+ return Utf16Converter.fromString(text4, littleEndian);
28703
28768
  }
28704
28769
  static Base64Padding(base643) {
28705
28770
  const padCount = 4 - base643.length % 4;
@@ -32426,7 +32491,7 @@ var require_sequence = __commonJS({
32426
32491
  exports.startsWith = startsWith;
32427
32492
  exports.endsWith = endsWith;
32428
32493
  exports.slice = slice;
32429
- exports.tail = tail2;
32494
+ exports.tail = tail3;
32430
32495
  exports.copy = copy;
32431
32496
  exports.compare = compare;
32432
32497
  var buffer_source_js_1 = require_buffer_source();
@@ -32460,15 +32525,15 @@ var require_sequence = __commonJS({
32460
32525
  }
32461
32526
  return normalized;
32462
32527
  }
32463
- function encodeAscii(text3) {
32464
- const bytes = new Uint8Array(text3.length);
32465
- for (let i = 0; i < text3.length; i++) {
32466
- bytes[i] = text3.charCodeAt(i) & 255;
32528
+ function encodeAscii(text4) {
32529
+ const bytes = new Uint8Array(text4.length);
32530
+ for (let i = 0; i < text4.length; i++) {
32531
+ bytes[i] = text4.charCodeAt(i) & 255;
32467
32532
  }
32468
32533
  return bytes;
32469
32534
  }
32470
- function encodeUtf8(text3) {
32471
- return new TextEncoder().encode(text3);
32535
+ function encodeUtf8(text4) {
32536
+ return new TextEncoder().encode(text4);
32472
32537
  }
32473
32538
  function toPatternBytes(pattern, options) {
32474
32539
  if (typeof pattern === "string") {
@@ -32548,7 +32613,7 @@ var require_sequence = __commonJS({
32548
32613
  }
32549
32614
  return bytes.subarray(normalizedStart, normalizedEnd);
32550
32615
  }
32551
- function tail2(data, length) {
32616
+ function tail3(data, length) {
32552
32617
  const bytes = (0, buffer_source_js_1.toUint8Array)(data);
32553
32618
  const normalizedLength = Number.isFinite(length) ? Math.max(0, Math.trunc(length)) : 0;
32554
32619
  if (normalizedLength >= bytes.byteLength) {
@@ -33843,15 +33908,15 @@ var require_binary = __commonJS({
33843
33908
  }
33844
33909
  return result;
33845
33910
  }
33846
- function decode3(text3) {
33847
- const result = new Uint8Array(text3.length);
33848
- for (let i = 0; i < text3.length; i++) {
33849
- result[i] = text3.charCodeAt(i) & 255;
33911
+ function decode3(text4) {
33912
+ const result = new Uint8Array(text4.length);
33913
+ for (let i = 0; i < text4.length; i++) {
33914
+ result[i] = text4.charCodeAt(i) & 255;
33850
33915
  }
33851
33916
  return result;
33852
33917
  }
33853
- function is(text3) {
33854
- return typeof text3 === "string";
33918
+ function is(text4) {
33919
+ return typeof text4 === "string";
33855
33920
  }
33856
33921
  exports.binary = { encode: encode3, decode: decode3, is };
33857
33922
  }
@@ -33886,31 +33951,31 @@ var require_hex = __commonJS({
33886
33951
  throw new TypeError("Hex separators must be non-empty strings");
33887
33952
  }
33888
33953
  }
33889
- function matchSeparator(text3, index, separators) {
33954
+ function matchSeparator(text4, index, separators) {
33890
33955
  for (const separator of separators) {
33891
- if (text3.startsWith(separator, index)) {
33956
+ if (text4.startsWith(separator, index)) {
33892
33957
  return separator;
33893
33958
  }
33894
33959
  }
33895
33960
  return void 0;
33896
33961
  }
33897
- function detectCase(text3) {
33898
- const hasUpper = /[A-F]/.test(text3);
33899
- const hasLower = /[a-f]/.test(text3);
33962
+ function detectCase(text4) {
33963
+ const hasUpper = /[A-F]/.test(text4);
33964
+ const hasLower = /[a-f]/.test(text4);
33900
33965
  return hasUpper && !hasLower ? "upper" : "lower";
33901
33966
  }
33902
- function detectLineSeparator(text3) {
33903
- const match = /\r\n|\n/.exec(text3);
33967
+ function detectLineSeparator(text4) {
33968
+ const match = /\r\n|\n/.exec(text4);
33904
33969
  if (!match) {
33905
33970
  return void 0;
33906
33971
  }
33907
33972
  return match[0] === "\r\n" ? "\r\n" : "\n";
33908
33973
  }
33909
- function compactForDetection(text3) {
33910
- return text3.replace(/[^0-9a-f]/gi, "");
33974
+ function compactForDetection(text4) {
33975
+ return text4.replace(/[^0-9a-f]/gi, "");
33911
33976
  }
33912
- function detectGroup(text3) {
33913
- const segments = text3.match(/[0-9A-Fa-f]+|[^0-9A-Fa-f]+/g) ?? [];
33977
+ function detectGroup(text4) {
33978
+ const segments = text4.match(/[0-9A-Fa-f]+|[^0-9A-Fa-f]+/g) ?? [];
33914
33979
  if (segments.length < 3) {
33915
33980
  return void 0;
33916
33981
  }
@@ -33938,8 +34003,8 @@ var require_hex = __commonJS({
33938
34003
  separator
33939
34004
  };
33940
34005
  }
33941
- function detectFormat(text3) {
33942
- const trimmed = text3.trim();
34006
+ function detectFormat(text4) {
34007
+ const trimmed = text4.trim();
33943
34008
  const prefix = /^0x/i.test(trimmed) ? "0x" : "";
33944
34009
  const body = prefix ? trimmed.slice(2) : trimmed;
33945
34010
  const lineSeparator = detectLineSeparator(body);
@@ -33964,13 +34029,13 @@ var require_hex = __commonJS({
33964
34029
  }
33965
34030
  return format2;
33966
34031
  }
33967
- function normalizeText(text3, options) {
34032
+ function normalizeText(text4, options) {
33968
34033
  const allowPrefix = options.allowPrefix ?? true;
33969
34034
  const separators = [...resolveSeparators(options)].sort((left, right) => right.length - left.length);
33970
34035
  for (const separator of separators) {
33971
34036
  validateSeparator(separator);
33972
34037
  }
33973
- let working = text3.trim();
34038
+ let working = text4.trim();
33974
34039
  if (/^0x/i.test(working)) {
33975
34040
  if (!allowPrefix) {
33976
34041
  throw new TypeError("Hexadecimal text must not include a 0x prefix");
@@ -34021,15 +34086,15 @@ var require_hex = __commonJS({
34021
34086
  }
34022
34087
  return chunks.join(group.separator);
34023
34088
  }
34024
- function normalize2(text3, options = {}) {
34025
- return normalizeText(text3, options);
34089
+ function normalize2(text4, options = {}) {
34090
+ return normalizeText(text4, options);
34026
34091
  }
34027
- function is(text3, options = {}) {
34028
- if (typeof text3 !== "string") {
34092
+ function is(text4, options = {}) {
34093
+ if (typeof text4 !== "string") {
34029
34094
  return false;
34030
34095
  }
34031
34096
  try {
34032
- normalize2(text3, options);
34097
+ normalize2(text4, options);
34033
34098
  return true;
34034
34099
  } catch {
34035
34100
  return false;
@@ -34039,8 +34104,8 @@ var require_hex = __commonJS({
34039
34104
  const bytes = (0, index_js_1.toUint8Array)(data);
34040
34105
  const casing = options.case ?? "lower";
34041
34106
  const pairs = Array.from(bytes, (byte) => {
34042
- const text3 = byte.toString(16).padStart(2, "0");
34043
- return casing === "upper" ? text3.toUpperCase() : text3;
34107
+ const text4 = byte.toString(16).padStart(2, "0");
34108
+ return casing === "upper" ? text4.toUpperCase() : text4;
34044
34109
  });
34045
34110
  let body = "";
34046
34111
  if (options.line) {
@@ -34059,19 +34124,19 @@ var require_hex = __commonJS({
34059
34124
  }
34060
34125
  return `${options.prefix ?? ""}${body}`;
34061
34126
  }
34062
- function decode3(text3, options = {}) {
34063
- const normalized = normalize2(text3, options);
34127
+ function decode3(text4, options = {}) {
34128
+ const normalized = normalize2(text4, options);
34064
34129
  const result = new Uint8Array(normalized.length / 2);
34065
34130
  for (let i = 0; i < normalized.length; i += 2) {
34066
34131
  result[i / 2] = Number.parseInt(normalized.slice(i, i + 2), 16);
34067
34132
  }
34068
34133
  return result;
34069
34134
  }
34070
- function parse3(text3, options = {}) {
34071
- const normalized = normalize2(text3, options);
34135
+ function parse3(text4, options = {}) {
34136
+ const normalized = normalize2(text4, options);
34072
34137
  return {
34073
34138
  bytes: decode3(normalized),
34074
- format: detectFormat(text3),
34139
+ format: detectFormat(text4),
34075
34140
  normalized
34076
34141
  };
34077
34142
  }
@@ -34099,8 +34164,8 @@ var require_utf8 = __commonJS({
34099
34164
  exports.encode = encode3;
34100
34165
  exports.decode = decode3;
34101
34166
  var index_js_1 = require_bytes();
34102
- function encode3(text3) {
34103
- return new TextEncoder().encode(text3);
34167
+ function encode3(text4) {
34168
+ return new TextEncoder().encode(text4);
34104
34169
  }
34105
34170
  function decode3(data) {
34106
34171
  return new TextDecoder("utf-8", { fatal: false }).decode((0, index_js_1.toUint8Array)(data));
@@ -34118,11 +34183,11 @@ var require_utf16 = __commonJS({
34118
34183
  exports.encode = encode3;
34119
34184
  exports.decode = decode3;
34120
34185
  var index_js_1 = require_bytes();
34121
- function encode3(text3, options = {}) {
34122
- const result = new ArrayBuffer(text3.length * 2);
34186
+ function encode3(text4, options = {}) {
34187
+ const result = new ArrayBuffer(text4.length * 2);
34123
34188
  const view = new DataView(result);
34124
- for (let i = 0; i < text3.length; i++) {
34125
- view.setUint16(i * 2, text3.charCodeAt(i), options.littleEndian ?? false);
34189
+ for (let i = 0; i < text4.length; i++) {
34190
+ view.setUint16(i * 2, text4.charCodeAt(i), options.littleEndian ?? false);
34126
34191
  }
34127
34192
  return new Uint8Array(result);
34128
34193
  }
@@ -34156,18 +34221,18 @@ var require_base64 = __commonJS({
34156
34221
  function nodeBuffer() {
34157
34222
  return globalThis.Buffer;
34158
34223
  }
34159
- function normalize2(text3) {
34160
- return text3.replace(/[\n\r\t ]/g, "");
34224
+ function normalize2(text4) {
34225
+ return text4.replace(/[\n\r\t ]/g, "");
34161
34226
  }
34162
- function pad(text3) {
34163
- const remainder = text3.length % 4;
34164
- return remainder ? text3 + "=".repeat(4 - remainder) : text3;
34227
+ function pad(text4) {
34228
+ const remainder = text4.length % 4;
34229
+ return remainder ? text4 + "=".repeat(4 - remainder) : text4;
34165
34230
  }
34166
- function is(text3) {
34167
- if (typeof text3 !== "string") {
34231
+ function is(text4) {
34232
+ if (typeof text4 !== "string") {
34168
34233
  return false;
34169
34234
  }
34170
- const normalized = normalize2(text3);
34235
+ const normalized = normalize2(text4);
34171
34236
  return normalized === "" || BASE64_REGEX.test(normalized);
34172
34237
  }
34173
34238
  function encode3(data, _options) {
@@ -34178,8 +34243,8 @@ var require_base64 = __commonJS({
34178
34243
  }
34179
34244
  return btoa((0, binary_js_1.encode)(bytes));
34180
34245
  }
34181
- function decode3(text3, _options) {
34182
- const normalized = normalize2(text3);
34246
+ function decode3(text4, _options) {
34247
+ const normalized = normalize2(text4);
34183
34248
  if (!is(normalized)) {
34184
34249
  throw new TypeError("Input is not valid Base64 text");
34185
34250
  }
@@ -34205,17 +34270,17 @@ var require_base64url = __commonJS({
34205
34270
  exports.decode = decode3;
34206
34271
  var base64_js_1 = require_base64();
34207
34272
  var BASE64URL_REGEX = /^[A-Za-z0-9_-]*$/;
34208
- function normalize2(text3) {
34209
- return text3.replace(/[\n\r\t ]/g, "");
34273
+ function normalize2(text4) {
34274
+ return text4.replace(/[\n\r\t ]/g, "");
34210
34275
  }
34211
- function is(text3) {
34212
- return typeof text3 === "string" && BASE64URL_REGEX.test(normalize2(text3));
34276
+ function is(text4) {
34277
+ return typeof text4 === "string" && BASE64URL_REGEX.test(normalize2(text4));
34213
34278
  }
34214
34279
  function encode3(data, _options) {
34215
34280
  return base64_js_1.base64.encode(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
34216
34281
  }
34217
- function decode3(text3, _options) {
34218
- const normalized = normalize2(text3);
34282
+ function decode3(text4, _options) {
34283
+ const normalized = normalize2(text4);
34219
34284
  if (!is(normalized)) {
34220
34285
  throw new TypeError("Input is not valid Base64Url text");
34221
34286
  }
@@ -34336,8 +34401,8 @@ var require_ip_converter = __commonJS({
34336
34401
  }
34337
34402
  return ip;
34338
34403
  }
34339
- static parseCIDR(text3) {
34340
- const [addr, prefixStr] = text3.split("/");
34404
+ static parseCIDR(text4) {
34405
+ const [addr, prefixStr] = text4.split("/");
34341
34406
  const prefix = parseInt(prefixStr, 10);
34342
34407
  if (this.isIPv4(addr)) {
34343
34408
  if (prefix < 0 || prefix > 32) {
@@ -34390,9 +34455,9 @@ var require_ip_converter = __commonJS({
34390
34455
  }
34391
34456
  return this.decodeIP(encoding_1.hex.encode(buf));
34392
34457
  }
34393
- static fromString(text3) {
34394
- if (text3.includes("/")) {
34395
- const [addr, prefix] = this.parseCIDR(text3);
34458
+ static fromString(text4) {
34459
+ if (text4.includes("/")) {
34460
+ const [addr, prefix] = this.parseCIDR(text4);
34396
34461
  const maskBytes = new Uint8Array(addr.length);
34397
34462
  let bitsLeft = prefix;
34398
34463
  for (let i = 0; i < maskBytes.length; i++) {
@@ -34409,7 +34474,7 @@ var require_ip_converter = __commonJS({
34409
34474
  out.set(maskBytes, addr.length);
34410
34475
  return out.buffer;
34411
34476
  }
34412
- const bytes = this.isIPv4(text3) ? this.parseIPv4(text3) : this.parseIPv6(text3);
34477
+ const bytes = this.isIPv4(text4) ? this.parseIPv4(text4) : this.parseIPv6(text4);
34413
34478
  return new Uint8Array(bytes).buffer;
34414
34479
  }
34415
34480
  };
@@ -42089,24 +42154,24 @@ var require_x509_cjs = __commonJS({
42089
42154
  names.register("I", "2.5.4.43");
42090
42155
  names.register("SN", "2.5.4.4");
42091
42156
  names.register("T", "2.5.4.12");
42092
- function replaceUnknownCharacter(text3, char) {
42157
+ function replaceUnknownCharacter(text4, char) {
42093
42158
  return `\\${pvtsutils.Convert.ToHex(pvtsutils.Convert.FromUtf8String(char)).toUpperCase()}`;
42094
42159
  }
42095
42160
  function escape2(data) {
42096
42161
  return data.replace(/([,+"\\<>;])/g, "\\$1").replace(/^([ #])/, "\\$1").replace(/([ ]$)/, "\\$1").replace(/([\r\n\t])/, replaceUnknownCharacter);
42097
42162
  }
42098
42163
  var Name = class _Name {
42099
- static isASCII(text3) {
42100
- for (let i = 0; i < text3.length; i++) {
42101
- const code = text3.charCodeAt(i);
42164
+ static isASCII(text4) {
42165
+ for (let i = 0; i < text4.length; i++) {
42166
+ const code = text4.charCodeAt(i);
42102
42167
  if (code > 255) {
42103
42168
  return false;
42104
42169
  }
42105
42170
  }
42106
42171
  return true;
42107
42172
  }
42108
- static isPrintableString(text3) {
42109
- return /^[A-Za-z0-9 '()+,-./:=?]*$/g.test(text3);
42173
+ static isPrintableString(text4) {
42174
+ return /^[A-Za-z0-9 '()+,-./:=?]*$/g.test(text4);
42110
42175
  }
42111
42176
  constructor(data, extraNames = {}) {
42112
42177
  this.extraNames = new NameIdentifier();
@@ -46707,12 +46772,12 @@ import { createHash as createHash5 } from "node:crypto";
46707
46772
  import { spawn as spawn9 } from "node:child_process";
46708
46773
  import { fileURLToPath as fileURLToPath2 } from "node:url";
46709
46774
  import { homedir as homedir16 } from "node:os";
46710
- import { dirname as dirname17, join as join40, resolve as resolve9 } from "node:path";
46775
+ import { dirname as dirname17, join as join41, resolve as resolve9 } from "node:path";
46711
46776
  import { createInterface } from "node:readline/promises";
46712
46777
 
46713
46778
  // ../../packages/host-core/dist/control-link.js
46714
46779
  import { hostname as hostname3 } from "node:os";
46715
- import { join as join31, basename as basename6 } from "node:path";
46780
+ import { join as join32, basename as basename6 } from "node:path";
46716
46781
  import { mkdirSync as mkdirSync12 } from "node:fs";
46717
46782
 
46718
46783
  // ../../node_modules/ws/wrapper.mjs
@@ -46734,15 +46799,15 @@ function canonicalForGuard(p) {
46734
46799
  const abs = resolve(p);
46735
46800
  let dir2 = dirname(abs);
46736
46801
  const leaf = basename(abs);
46737
- const tail2 = [];
46802
+ const tail3 = [];
46738
46803
  for (; ; ) {
46739
46804
  try {
46740
- return join(realpathSync.native(dir2), ...tail2, leaf);
46805
+ return join(realpathSync.native(dir2), ...tail3, leaf);
46741
46806
  } catch {
46742
46807
  const parent = dirname(dir2);
46743
46808
  if (parent === dir2)
46744
46809
  return abs;
46745
- tail2.unshift(basename(dir2));
46810
+ tail3.unshift(basename(dir2));
46746
46811
  dir2 = parent;
46747
46812
  }
46748
46813
  }
@@ -47135,7 +47200,7 @@ var E2ESessions = class {
47135
47200
  };
47136
47201
 
47137
47202
  // ../../packages/host-core/dist/daemon-agent.js
47138
- import { join as join19 } from "node:path";
47203
+ import { join as join20 } from "node:path";
47139
47204
 
47140
47205
  // ../../packages/host-core/dist/surface-hub.js
47141
47206
  init_dist();
@@ -47630,6 +47695,7 @@ async function createClaudeCodeBackend(send3, onBrowserRequest, loadPluginRuntim
47630
47695
  setImageGen: (runner3) => manager2.setImageGen(runner3),
47631
47696
  setScreenControl: (provider) => manager2.setScreenControl(provider),
47632
47697
  setComputerControl: (provider) => manager2.setComputerControl(provider),
47698
+ setSupportSubmit: (provider) => manager2.setSupportSubmit(provider),
47633
47699
  setRunMode: (sessionId, opts) => manager2.setRunMode(sessionId, opts),
47634
47700
  setSessionKeepAlive: (sessionId, keep, holder) => manager2.setSessionKeepAlive(sessionId, keep, holder),
47635
47701
  warmSession: (params) => manager2.warmSession(params),
@@ -47959,9 +48025,9 @@ var geminiAdapter = {
47959
48025
  },
47960
48026
  translate(event, raw, emit2, ctx2) {
47961
48027
  const o = asObj3(event);
47962
- const text3 = o ? typeof o.response === "string" ? o.response : bestEffortText(o) : typeof event === "string" ? event : raw;
47963
- if (text3)
47964
- emit2({ type: "chat:stream", sessionId: ctx2.sessionId, clientRequestId: ctx2.clientRequestId, delta: text3, messageId: ctx2.messageId, kind: "text" });
48028
+ const text4 = o ? typeof o.response === "string" ? o.response : bestEffortText(o) : typeof event === "string" ? event : raw;
48029
+ if (text4)
48030
+ emit2({ type: "chat:stream", sessionId: ctx2.sessionId, clientRequestId: ctx2.clientRequestId, delta: text4, messageId: ctx2.messageId, kind: "text" });
47965
48031
  const tools = o?.tools;
47966
48032
  if (Array.isArray(tools)) {
47967
48033
  for (const t of tools) {
@@ -47987,25 +48053,25 @@ var openclawAdapter = {
47987
48053
  translate(event, raw, emit2, ctx2) {
47988
48054
  const o = asObj4(event);
47989
48055
  const result = asObj4(o?.result) ?? o;
47990
- let text3 = "";
48056
+ let text4 = "";
47991
48057
  const payloads = result?.payloads;
47992
48058
  if (Array.isArray(payloads)) {
47993
- text3 = payloads.map((p) => {
48059
+ text4 = payloads.map((p) => {
47994
48060
  const t = asObj4(p)?.text;
47995
48061
  return typeof t === "string" ? t : "";
47996
48062
  }).filter(Boolean).join("\n");
47997
48063
  }
47998
- if (!text3) {
48064
+ if (!text4) {
47999
48065
  const fav = asObj4(result?.meta)?.finalAssistantVisibleText;
48000
48066
  if (typeof fav === "string")
48001
- text3 = fav;
48067
+ text4 = fav;
48002
48068
  }
48003
- if (!text3)
48004
- text3 = o ? bestEffortText(result ?? o) : typeof event === "string" ? event : raw;
48005
- if (text3)
48006
- emit2({ type: "chat:stream", sessionId: ctx2.sessionId, clientRequestId: ctx2.clientRequestId, delta: text3, messageId: ctx2.messageId, kind: "text" });
48069
+ if (!text4)
48070
+ text4 = o ? bestEffortText(result ?? o) : typeof event === "string" ? event : raw;
48071
+ if (text4)
48072
+ emit2({ type: "chat:stream", sessionId: ctx2.sessionId, clientRequestId: ctx2.clientRequestId, delta: text4, messageId: ctx2.messageId, kind: "text" });
48007
48073
  const status2 = typeof o?.status === "string" ? o.status : void 0;
48008
- if (!text3 && status2 && status2 !== "ok" && status2 !== "accepted") {
48074
+ if (!text4 && status2 && status2 !== "ok" && status2 !== "accepted") {
48009
48075
  const summary = typeof o?.summary === "string" && o.summary ? o.summary : `OpenClaw run ${status2}.`;
48010
48076
  emit2({ type: "chat:error", sessionId: ctx2.sessionId, clientRequestId: ctx2.clientRequestId, error: summary });
48011
48077
  }
@@ -48057,8 +48123,8 @@ var seq = 0;
48057
48123
  var now = () => (/* @__PURE__ */ new Date()).toISOString();
48058
48124
  var ctx = [];
48059
48125
  var CTX_MAX = 60;
48060
- function pushCtx(role, text3) {
48061
- const t = (text3 ?? "").trim();
48126
+ function pushCtx(role, text4) {
48127
+ const t = (text4 ?? "").trim();
48062
48128
  if (!t)
48063
48129
  return;
48064
48130
  ctx.push({ role, text: t.length > 300 ? `${t.slice(0, 300)}\u2026` : t });
@@ -48300,23 +48366,23 @@ var HostPluginApi = class {
48300
48366
  secret(envKey2) {
48301
48367
  return this.secretResolver(this.pluginId, envKey2);
48302
48368
  }
48303
- registerTool(tool11) {
48369
+ registerTool(tool12) {
48304
48370
  const prefix = this.pluginId.replace(/[^a-zA-Z0-9_]/g, "_");
48305
- const name = tool11.name.startsWith(`${prefix}_`) ? tool11.name : `${prefix}_${tool11.name}`;
48306
- this.registry.tools.push({ ...tool11, name });
48371
+ const name = tool12.name.startsWith(`${prefix}_`) ? tool12.name : `${prefix}_${tool12.name}`;
48372
+ this.registry.tools.push({ ...tool12, name });
48307
48373
  }
48308
- registerUiTool(tool11) {
48309
- if (!this.requireGrant("surfaces", `UI tool "${tool11.name}"`))
48374
+ registerUiTool(tool12) {
48375
+ if (!this.requireGrant("surfaces", `UI tool "${tool12.name}"`))
48310
48376
  return;
48311
48377
  const prefix = this.pluginId.replace(/[^a-zA-Z0-9_]/g, "_");
48312
- const name = tool11.name.startsWith(`${prefix}_`) ? tool11.name : `${prefix}_${tool11.name}`;
48378
+ const name = tool12.name.startsWith(`${prefix}_`) ? tool12.name : `${prefix}_${tool12.name}`;
48313
48379
  const tier = this.hasGrant("customUI") ? "verified" : "third-party";
48314
48380
  this.registry.tools.push({
48315
48381
  name,
48316
- description: tool11.description,
48317
- inputSchema: tool11.inputSchema,
48318
- handler: async (args) => toResult(await tool11.handler(args, NOOP_UI_CTX)),
48319
- __ctxHandler: async (args, ctx2) => toResult(await tool11.handler(args, ctx2)),
48382
+ description: tool12.description,
48383
+ inputSchema: tool12.inputSchema,
48384
+ handler: async (args) => toResult(await tool12.handler(args, NOOP_UI_CTX)),
48385
+ __ctxHandler: async (args, ctx2) => toResult(await tool12.handler(args, ctx2)),
48320
48386
  __tier: tier
48321
48387
  });
48322
48388
  }
@@ -48426,8 +48492,8 @@ function createOpenClawAdapter(pluginId, config2, secretResolver, registry2) {
48426
48492
  pluginId,
48427
48493
  config: config2,
48428
48494
  secret: (envKey2) => secretResolver(pluginId, envKey2),
48429
- registerTool: (tool11) => {
48430
- const got = typeof tool11 === "function" ? tool11({}) : tool11;
48495
+ registerTool: (tool12) => {
48496
+ const got = typeof tool12 === "function" ? tool12({}) : tool12;
48431
48497
  const arr = Array.isArray(got) ? got : got ? [got] : [];
48432
48498
  for (const t of arr) {
48433
48499
  const c = convertTool(t);
@@ -49124,9 +49190,9 @@ function augmentedPath() {
49124
49190
  return parts.join(sep8);
49125
49191
  }
49126
49192
  function which(bin, path5) {
49127
- const tool11 = process.platform === "win32" ? "where" : "which";
49193
+ const tool12 = process.platform === "win32" ? "where" : "which";
49128
49194
  try {
49129
- const out = execFileSync2(tool11, [bin], { env: { ...process.env, PATH: path5 }, timeout: 4e3, encoding: "utf-8" });
49195
+ const out = execFileSync2(tool12, [bin], { env: { ...process.env, PATH: path5 }, timeout: 4e3, encoding: "utf-8" });
49130
49196
  return out.split(/\r?\n/).map((l) => l.trim()).find(Boolean) || void 0;
49131
49197
  } catch {
49132
49198
  return void 0;
@@ -49841,8 +49907,8 @@ function iso639(lang) {
49841
49907
  // ../../packages/voice-core/dist/pipeline/history.js
49842
49908
  function formatHistoryLines(turns, maxLineChars = 300) {
49843
49909
  return turns.map((t) => {
49844
- const text3 = t.text.replace(/\s+/g, " ").trim();
49845
- const capped = text3.length > maxLineChars ? text3.slice(0, maxLineChars - 1).trimEnd() + "\u2026" : text3;
49910
+ const text4 = t.text.replace(/\s+/g, " ").trim();
49911
+ const capped = text4.length > maxLineChars ? text4.slice(0, maxLineChars - 1).trimEnd() + "\u2026" : text4;
49846
49912
  return `${t.role.toUpperCase()}: ${capped}`;
49847
49913
  }).join("\n");
49848
49914
  }
@@ -50131,15 +50197,15 @@ ${truncate(input.result, 4e3)}`
50131
50197
  }
50132
50198
  };
50133
50199
  function ruleBasedTurn(input) {
50134
- const text3 = input.result.trim();
50135
- const lower = text3.toLowerCase();
50200
+ const text4 = input.result.trim();
50201
+ const lower = text4.toLowerCase();
50136
50202
  let status2 = "done";
50137
50203
  if (/\b(error|failed|could not|cannot|unable to)\b/.test(lower))
50138
50204
  status2 = "error";
50139
- else if (text3.endsWith("?") || /\b(which|should i|do you want|would you like|please confirm|clarif)\b/.test(lower)) {
50205
+ else if (text4.endsWith("?") || /\b(which|should i|do you want|would you like|please confirm|clarif)\b/.test(lower)) {
50140
50206
  status2 = "needs_input";
50141
50207
  }
50142
- const line = firstSentences(stripForSpeech(text3)) || input.recentActivity.slice(-1)[0] || "Done.";
50208
+ const line = firstSentences(stripForSpeech(text4)) || input.recentActivity.slice(-1)[0] || "Done.";
50143
50209
  return { line, status: status2 };
50144
50210
  }
50145
50211
  function stripForSpeech(s) {
@@ -50224,8 +50290,8 @@ var VoiceGuideOrchestrator = class {
50224
50290
  /** The bridge feeds every finalized transcript line here (capped buffer). An
50225
50291
  * assistant line means the guide finished speaking — drain the next queued
50226
50292
  * update immediately instead of waiting out the gap timer. */
50227
- noteTranscript(role, text3) {
50228
- const t = text3.trim();
50293
+ noteTranscript(role, text4) {
50294
+ const t = text4.trim();
50229
50295
  if (!t)
50230
50296
  return;
50231
50297
  this.conversation.push({ role, text: t });
@@ -50759,26 +50825,26 @@ Additional context: ${context}` : task;
50759
50825
  this.deps.emit({ type: "voice:milestone", text: spoken });
50760
50826
  this.say(spoken, { urgent: focused });
50761
50827
  }
50762
- speakMilestone(text3) {
50763
- this.deps.emit({ type: "voice:milestone", text: text3 });
50764
- this.say(text3);
50828
+ speakMilestone(text4) {
50829
+ this.deps.emit({ type: "voice:milestone", text: text4 });
50830
+ this.say(text4);
50765
50831
  }
50766
50832
  // ── One mouth, N sessions: serialized speech ───────────────────────────────
50767
50833
  /** Speak `text`, serializing non-urgent lines so concurrent sessions don't
50768
50834
  * talk over each other. Urgent lines (blocking questions, the focused
50769
50835
  * session's result, critical notices) always go out immediately. */
50770
- say(text3, opts = {}) {
50771
- if (!text3)
50836
+ say(text4, opts = {}) {
50837
+ if (!text4)
50772
50838
  return;
50773
50839
  const now2 = this.now();
50774
50840
  if (opts.urgent || this.sayQueue.length === 0 && now2 - this.lastSayAt >= SPEAK_GAP_MS) {
50775
50841
  this.lastSayAt = now2;
50776
- this.voice?.speakNow(text3);
50842
+ this.voice?.speakNow(text4);
50777
50843
  return;
50778
50844
  }
50779
50845
  if (this.sayQueue.length >= SPEAK_QUEUE_CAP)
50780
50846
  this.sayQueue.shift();
50781
- this.sayQueue.push(text3);
50847
+ this.sayQueue.push(text4);
50782
50848
  this.armSayTimer();
50783
50849
  }
50784
50850
  armSayTimer() {
@@ -50908,11 +50974,11 @@ var ClientProxyProvider = class {
50908
50974
  /** Audio is client↔provider direct — the daemon never sees mic/model PCM. */
50909
50975
  sendAudio(_pcm24k) {
50910
50976
  }
50911
- respondToTool(callId, text3, isError) {
50912
- this.deps.send({ type: "voice:cd:respondToTool", callId, text: text3, isError });
50977
+ respondToTool(callId, text4, isError) {
50978
+ this.deps.send({ type: "voice:cd:respondToTool", callId, text: text4, isError });
50913
50979
  }
50914
- speakNow(text3) {
50915
- this.deps.send({ type: "voice:cd:speak", text: text3 });
50980
+ speakNow(text4) {
50981
+ this.deps.send({ type: "voice:cd:speak", text: text4 });
50916
50982
  }
50917
50983
  close() {
50918
50984
  this.settleConnect(new Error("closed before connect"));
@@ -50932,11 +50998,11 @@ var ClientProxyProvider = class {
50932
50998
  handleToolCall(inv) {
50933
50999
  this.cb.onToolCall(inv);
50934
51000
  }
50935
- handleTranscript(speaker, text3) {
51001
+ handleTranscript(speaker, text4) {
50936
51002
  if (speaker === "user")
50937
- this.cb.onUserTranscript(text3);
51003
+ this.cb.onUserTranscript(text4);
50938
51004
  else
50939
- this.cb.onAgentTranscript(text3);
51005
+ this.cb.onAgentTranscript(text4);
50940
51006
  }
50941
51007
  handleProviderEvent(event, message) {
50942
51008
  switch (event) {
@@ -51151,7 +51217,7 @@ var VoiceControl = class {
51151
51217
  }
51152
51218
  /** Run a direct screen-control tool (os-control) and answer the operator's tool-call. */
51153
51219
  async runScreenControl(callId, name, args) {
51154
- let text3;
51220
+ let text4;
51155
51221
  let isError = false;
51156
51222
  let finished = false, nudges = 0;
51157
51223
  let slowTimer = null;
@@ -51167,18 +51233,18 @@ var VoiceControl = class {
51167
51233
  };
51168
51234
  scheduleNudge(2e4);
51169
51235
  try {
51170
- text3 = await this.deps.execScreenControl(name, args);
51236
+ text4 = await this.deps.execScreenControl(name, args);
51171
51237
  } catch (e) {
51172
- text3 = e instanceof Error ? e.message : "screen action failed";
51238
+ text4 = e instanceof Error ? e.message : "screen action failed";
51173
51239
  isError = true;
51174
51240
  } finally {
51175
51241
  finished = true;
51176
51242
  if (slowTimer)
51177
51243
  clearTimeout(slowTimer);
51178
51244
  }
51179
- log(`voice: screen-control ${name} \u2192 ${isError ? "ERROR " : ""}${text3}`);
51180
- recordEvent("tool_result", { name, text: text3, isError });
51181
- this.deps.send({ type: "voice:cd:respondToTool", callId, text: text3, isError });
51245
+ log(`voice: screen-control ${name} \u2192 ${isError ? "ERROR " : ""}${text4}`);
51246
+ recordEvent("tool_result", { name, text: text4, isError });
51247
+ this.deps.send({ type: "voice:cd:respondToTool", callId, text: text4, isError });
51182
51248
  }
51183
51249
  async start(msg) {
51184
51250
  if (this.starting)
@@ -51300,13 +51366,13 @@ ${priorText}` : "";
51300
51366
  const callbacks = {
51301
51367
  onOutputAudio: () => {
51302
51368
  },
51303
- onUserTranscript: (text3) => {
51304
- orchestrator.noteTranscript("user", text3);
51305
- this.deps.send({ type: "voice:transcript", speaker: "user", text: text3 });
51369
+ onUserTranscript: (text4) => {
51370
+ orchestrator.noteTranscript("user", text4);
51371
+ this.deps.send({ type: "voice:transcript", speaker: "user", text: text4 });
51306
51372
  },
51307
- onAgentTranscript: (text3) => {
51308
- orchestrator.noteTranscript("assistant", text3);
51309
- this.deps.send({ type: "voice:transcript", speaker: "agent", text: text3 });
51373
+ onAgentTranscript: (text4) => {
51374
+ orchestrator.noteTranscript("assistant", text4);
51375
+ this.deps.send({ type: "voice:transcript", speaker: "agent", text: text4 });
51310
51376
  },
51311
51377
  onToolCall: (inv) => orchestrator.handleToolCall(inv),
51312
51378
  onInterruption: () => this.deps.send({ type: "voice:clearPlayback" }),
@@ -51639,6 +51705,109 @@ function createDaemonImageGenRunner() {
51639
51705
  };
51640
51706
  }
51641
51707
 
51708
+ // ../../packages/host-core/dist/support-submit.js
51709
+ import { openSync as openSync2, fstatSync, readSync, closeSync as closeSync2 } from "node:fs";
51710
+ import { join as join19 } from "node:path";
51711
+
51712
+ // ../../packages/host-core/dist/host-metrics.js
51713
+ import os from "node:os";
51714
+ function primaryIpv4(ifaces = os.networkInterfaces()) {
51715
+ for (const name of Object.keys(ifaces)) {
51716
+ for (const ni of ifaces[name] ?? []) {
51717
+ if (ni.family === "IPv4" && !ni.internal)
51718
+ return ni.address;
51719
+ }
51720
+ }
51721
+ return void 0;
51722
+ }
51723
+ function staticMetrics(version2) {
51724
+ const cpus = os.cpus();
51725
+ return {
51726
+ version: version2 || void 0,
51727
+ arch: os.arch(),
51728
+ cpuModel: cpus[0]?.model?.trim() || void 0,
51729
+ cpuCount: cpus.length || void 0,
51730
+ totalMem: os.totalmem() || void 0,
51731
+ ip: primaryIpv4()
51732
+ };
51733
+ }
51734
+ function dynamicMetrics() {
51735
+ const la = os.loadavg();
51736
+ return {
51737
+ load: la[0] > 0 ? Number(la[0].toFixed(2)) : void 0,
51738
+ // loadavg is [0,0,0] on Windows
51739
+ freeMem: os.freemem() || void 0,
51740
+ uptime: Math.round(os.uptime()) || void 0
51741
+ };
51742
+ }
51743
+
51744
+ // ../../packages/host-core/dist/support-submit.js
51745
+ var LOG_TAIL_BYTES = 64 * 1024;
51746
+ function tail2(path5, bytes = LOG_TAIL_BYTES) {
51747
+ let fd = null;
51748
+ try {
51749
+ fd = openSync2(path5, "r");
51750
+ const size = fstatSync(fd).size;
51751
+ const len = Math.min(size, bytes);
51752
+ const start2 = Math.max(0, size - len);
51753
+ const buf = Buffer.alloc(len);
51754
+ readSync(fd, buf, 0, len, start2);
51755
+ return buf.toString("utf8");
51756
+ } catch {
51757
+ return "";
51758
+ } finally {
51759
+ if (fd !== null) {
51760
+ try {
51761
+ closeSync2(fd);
51762
+ } catch {
51763
+ }
51764
+ }
51765
+ }
51766
+ }
51767
+ function createDaemonSupportSubmit() {
51768
+ return async (input) => {
51769
+ const creds2 = readCredentials();
51770
+ if (!creds2) {
51771
+ throw new Error("Not signed in on this machine \u2014 sign in (or share this machine) to file a report from chat.");
51772
+ }
51773
+ const daemonLog = tail2(join19(daemonDir(), "daemon.log"));
51774
+ const diagnostics = {
51775
+ collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
51776
+ source: "daemon",
51777
+ host: { ...staticMetrics(), ...dynamicMetrics() },
51778
+ platform: process.platform,
51779
+ arch: process.arch,
51780
+ node: process.versions.node,
51781
+ userId: creds2.userId,
51782
+ logs: { daemon: daemonLog }
51783
+ };
51784
+ const res = await fetch(`${creds2.apiOrigin.replace(/\/$/, "")}/api/core/tesseract/support/issue`, {
51785
+ method: "POST",
51786
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${creds2.accessToken}` },
51787
+ body: JSON.stringify({
51788
+ type: input.type === "feature" ? "feature" : "issue",
51789
+ title: input.title,
51790
+ description: input.description,
51791
+ // NEVER route logs to the PUBLIC issue on the agent path: they're auto-collected
51792
+ // (not human-reviewed) and can carry usernames/paths/ids. The daemon log is already
51793
+ // attached PRIVATELY via `diagnostics` above. Public logs are the desktop form's
51794
+ // job (human-reviewed opt-in) only.
51795
+ includeLogsInIssue: false,
51796
+ diagnostics
51797
+ }),
51798
+ signal: AbortSignal.timeout(3e4)
51799
+ });
51800
+ if (!res.ok) {
51801
+ const text4 = await res.text().catch(() => "");
51802
+ throw new Error(`Report submission failed (${res.status}). ${text4.slice(0, 200)}`);
51803
+ }
51804
+ const body = await res.json();
51805
+ if (!body.issueUrl || typeof body.issueNumber !== "number")
51806
+ throw new Error("Malformed response from the report API.");
51807
+ return { issueUrl: body.issueUrl, issueNumber: body.issueNumber };
51808
+ };
51809
+ }
51810
+
51642
51811
  // ../../packages/host-core/dist/daemon-agent.js
51643
51812
  init_dist2();
51644
51813
  var sinks = /* @__PURE__ */ new Set();
@@ -51700,7 +51869,7 @@ function buildSharedBackend(engineId) {
51700
51869
  },
51701
51870
  resolver,
51702
51871
  // Daemon plugins (review #3): operator-controlled <daemonDir>/plugins, env-var secrets.
51703
- buildDaemonPluginLoader(join19(daemonDir(), "plugins"))
51872
+ buildDaemonPluginLoader(join20(daemonDir(), "plugins"))
51704
51873
  ).then((b) => {
51705
51874
  if (token2 !== buildToken)
51706
51875
  return b;
@@ -51728,6 +51897,11 @@ function buildSharedBackend(engineId) {
51728
51897
  } catch (e) {
51729
51898
  log("imagegen: setup failed:", e instanceof Error ? e.message : String(e));
51730
51899
  }
51900
+ try {
51901
+ b.setSupportSubmit?.(createDaemonSupportSubmit());
51902
+ } catch (e) {
51903
+ log("support: setup failed:", e instanceof Error ? e.message : String(e));
51904
+ }
51731
51905
  return b;
51732
51906
  });
51733
51907
  }
@@ -51766,7 +51940,7 @@ function refreshDaemonScheduling(b) {
51766
51940
  }
51767
51941
  b.configureScheduling({
51768
51942
  enabled,
51769
- file: join19(dir2, "scheduled_tasks.json"),
51943
+ file: join20(dir2, "scheduled_tasks.json"),
51770
51944
  // projectDir omitted ⇒ fires track the daemon's currently-open project (setConfig).
51771
51945
  isOwner: schedulingLock ? () => schedulingLock.isOwner() : void 0
51772
51946
  });
@@ -51775,16 +51949,16 @@ var VOICE_GATEWAY = process.env.CCB_VOICE_GATEWAY !== "0";
51775
51949
 
51776
51950
  // ../../packages/host-core/dist/fs-remote.js
51777
51951
  import { readdir as readdir3, readFile as readFile8, writeFile as writeFile5, mkdir as mkdir5, cp, rm, rename as renameAsync, stat as stat2 } from "node:fs/promises";
51778
- import { openSync as openSync2, readSync, writeSync, closeSync as closeSync2, statSync as statSync4, existsSync as existsSync8, mkdtempSync, rmSync as rmSync2, readFileSync as readFileSync9, readdirSync as readdirSync4, watch, realpathSync as realpathSync2, constants as fsConstants } from "node:fs";
51952
+ import { openSync as openSync3, readSync as readSync2, writeSync, closeSync as closeSync3, statSync as statSync4, existsSync as existsSync8, mkdtempSync, rmSync as rmSync2, readFileSync as readFileSync9, readdirSync as readdirSync4, watch, realpathSync as realpathSync2, constants as fsConstants } from "node:fs";
51779
51953
  import { tmpdir as tmpdir2 } from "node:os";
51780
- import { basename as basename3, dirname as dirname7, join as join21, relative as relative4, resolve as resolve5, sep as sep4, isAbsolute as isAbsolute4 } from "node:path";
51954
+ import { basename as basename3, dirname as dirname7, join as join22, relative as relative4, resolve as resolve5, sep as sep4, isAbsolute as isAbsolute4 } from "node:path";
51781
51955
  import { execFile as execFile3 } from "node:child_process";
51782
51956
  import { promisify as promisify2 } from "node:util";
51783
51957
 
51784
51958
  // ../../packages/host-core/dist/fs-stats.js
51785
51959
  init_dist();
51786
51960
  import { readdir as readdir2, lstat, readFile as readFile7 } from "node:fs/promises";
51787
- import { join as join20 } from "node:path";
51961
+ import { join as join21 } from "node:path";
51788
51962
  var TEXT_CAP = 5 * 1024 * 1024;
51789
51963
  async function dirStats(root, opts) {
51790
51964
  const start2 = Date.now();
@@ -51815,11 +51989,11 @@ async function dirStats(root, opts) {
51815
51989
  if (opts?.excludeHeavy && STATS_HEAVY_DIRS.has(e.name))
51816
51990
  continue;
51817
51991
  dirCount++;
51818
- stack.push(join20(dir2, e.name));
51992
+ stack.push(join21(dir2, e.name));
51819
51993
  } else if (e.isFile()) {
51820
51994
  fileCount++;
51821
51995
  try {
51822
- totalBytes += (await lstat(join20(dir2, e.name))).size;
51996
+ totalBytes += (await lstat(join21(dir2, e.name))).size;
51823
51997
  } catch {
51824
51998
  }
51825
51999
  }
@@ -51854,7 +52028,7 @@ async function codeStats(root) {
51854
52028
  continue;
51855
52029
  if (e.isDirectory()) {
51856
52030
  if (!STATS_HEAVY_DIRS.has(e.name))
51857
- stack.push(join20(dir2, e.name));
52031
+ stack.push(join21(dir2, e.name));
51858
52032
  continue;
51859
52033
  }
51860
52034
  if (!e.isFile())
@@ -51862,7 +52036,7 @@ async function codeStats(root) {
51862
52036
  const lang = langForFilename(e.name);
51863
52037
  if (!lang)
51864
52038
  continue;
51865
- const full = join20(dir2, e.name);
52039
+ const full = join21(dir2, e.name);
51866
52040
  let size = 0;
51867
52041
  try {
51868
52042
  size = (await lstat(full)).size;
@@ -51955,7 +52129,7 @@ async function listAllFilesUnder(dir2) {
51955
52129
  return;
51956
52130
  if (ent.name === ".DS_Store")
51957
52131
  continue;
51958
- const full = join21(d, ent.name);
52132
+ const full = join22(d, ent.name);
51959
52133
  if (ent.isDirectory()) {
51960
52134
  if (!LISTALL_SKIP_DIRS.has(ent.name))
51961
52135
  await walk(full);
@@ -52072,18 +52246,18 @@ function resolveParent(raw, root) {
52072
52246
  if (raw === "" || raw === "~")
52073
52247
  return root;
52074
52248
  if (raw.startsWith("~/"))
52075
- return join21(root, raw.slice(2));
52076
- return isAbsolute4(raw) ? raw : join21(root, raw);
52249
+ return join22(root, raw.slice(2));
52250
+ return isAbsolute4(raw) ? raw : join22(root, raw);
52077
52251
  }
52078
52252
  function resolveUniqueName(dir2, name) {
52079
- const direct = join21(dir2, name);
52253
+ const direct = join22(dir2, name);
52080
52254
  if (!existsSync8(direct))
52081
52255
  return direct;
52082
52256
  const dot = name.lastIndexOf(".");
52083
52257
  const base = dot > 0 ? name.slice(0, dot) : name;
52084
52258
  const ext = dot > 0 ? name.slice(dot) : "";
52085
52259
  for (let i = 2; i < 1e4; i++) {
52086
- const candidate = join21(dir2, `${base} ${i}${ext}`);
52260
+ const candidate = join22(dir2, `${base} ${i}${ext}`);
52087
52261
  if (!existsSync8(candidate))
52088
52262
  return candidate;
52089
52263
  }
@@ -52156,12 +52330,12 @@ async function renderThumbnailImpl(real, maxPx) {
52156
52330
  return { error: "Thumbnails are only available on macOS hosts." };
52157
52331
  let dir2 = null;
52158
52332
  try {
52159
- dir2 = mkdtempSync(join21(tmpdir2(), "fp-thumb-"));
52333
+ dir2 = mkdtempSync(join22(tmpdir2(), "fp-thumb-"));
52160
52334
  await execFileAsync("qlmanage", ["-t", "-s", String(maxPx), "-o", dir2, real], { timeout: 1e4, killSignal: "SIGKILL" }).catch(() => void 0);
52161
52335
  const produced = readdirSync4(dir2).find((f) => f.toLowerCase().endsWith(".png"));
52162
52336
  if (!produced)
52163
52337
  return { error: "No thumbnail available." };
52164
- return { png: readFileSync9(join21(dir2, produced)).toString("base64") };
52338
+ return { png: readFileSync9(join22(dir2, produced)).toString("base64") };
52165
52339
  } catch (err) {
52166
52340
  return { error: String(err.message) };
52167
52341
  } finally {
@@ -52201,7 +52375,7 @@ var MAX_STAT_PATHS = 4096;
52201
52375
  var SAFE_SEG = /^[A-Za-z0-9._-]+$/;
52202
52376
  var TRASH_RETENTION_MS = 14 * 24 * 60 * 60 * 1e3;
52203
52377
  function pruneTrash(root) {
52204
- const trashDir = join21(root, TRASH_DIR);
52378
+ const trashDir = join22(root, TRASH_DIR);
52205
52379
  if (!existsSync8(trashDir))
52206
52380
  return;
52207
52381
  const cutoff = Date.now() - TRASH_RETENTION_MS;
@@ -52210,9 +52384,9 @@ function pruneTrash(root) {
52210
52384
  if (!e.isDirectory())
52211
52385
  continue;
52212
52386
  try {
52213
- const meta4 = JSON.parse(readFileSync9(join21(trashDir, e.name, ".fp-meta.json"), "utf-8"));
52387
+ const meta4 = JSON.parse(readFileSync9(join22(trashDir, e.name, ".fp-meta.json"), "utf-8"));
52214
52388
  if ((meta4.deletedAt ?? 0) < cutoff)
52215
- rmSync2(join21(trashDir, e.name), { recursive: true, force: true });
52389
+ rmSync2(join22(trashDir, e.name), { recursive: true, force: true });
52216
52390
  } catch {
52217
52391
  }
52218
52392
  }
@@ -52238,12 +52412,12 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52238
52412
  return entries.map((e) => {
52239
52413
  let id = null;
52240
52414
  try {
52241
- id = statId(join21(real, e.name));
52415
+ id = statId(join22(real, e.name));
52242
52416
  } catch {
52243
52417
  }
52244
52418
  return {
52245
52419
  name: e.name,
52246
- path: join21(dir2, e.name),
52420
+ path: join22(dir2, e.name),
52247
52421
  isDir: e.isDirectory(),
52248
52422
  ignored: ignored.has(e.name),
52249
52423
  size: id?.size,
@@ -52324,9 +52498,9 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52324
52498
  try {
52325
52499
  if (off === 0) {
52326
52500
  await mkdir5(dirname7(real), { recursive: true });
52327
- fd = openSync2(real, "w");
52501
+ fd = openSync3(real, "w");
52328
52502
  } else
52329
- fd = openSync2(real, "r+");
52503
+ fd = openSync3(real, "r+");
52330
52504
  if (buf.length > 0)
52331
52505
  writeSync(fd, buf, 0, buf.length, off);
52332
52506
  return { ok: true, bytesWritten: buf.length };
@@ -52335,7 +52509,7 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52335
52509
  } finally {
52336
52510
  if (fd != null)
52337
52511
  try {
52338
- closeSync2(fd);
52512
+ closeSync3(fd);
52339
52513
  } catch {
52340
52514
  }
52341
52515
  }
@@ -52377,16 +52551,16 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52377
52551
  return { base64: "", bytesRead: 0 };
52378
52552
  let fd = null;
52379
52553
  try {
52380
- fd = openSync2(real, "r");
52554
+ fd = openSync3(real, "r");
52381
52555
  const buf = Buffer.alloc(len);
52382
- const bytesRead = readSync(fd, buf, 0, len, off);
52556
+ const bytesRead = readSync2(fd, buf, 0, len, off);
52383
52557
  return { base64: buf.subarray(0, bytesRead).toString("base64"), bytesRead };
52384
52558
  } catch (err) {
52385
52559
  return { error: String(err.message) };
52386
52560
  } finally {
52387
52561
  if (fd != null)
52388
52562
  try {
52389
- closeSync2(fd);
52563
+ closeSync3(fd);
52390
52564
  } catch {
52391
52565
  }
52392
52566
  }
@@ -52410,7 +52584,7 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52410
52584
  const name = String(a[1] ?? "").trim();
52411
52585
  if (!validName(name))
52412
52586
  return { ok: false, error: "Invalid project name." };
52413
- const target = join21(parent, name);
52587
+ const target = join22(parent, name);
52414
52588
  if (!insideOk(target))
52415
52589
  return { ok: false, error: "Refusing to create a project outside the shared root." };
52416
52590
  if (existsSync8(target))
@@ -52428,7 +52602,7 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52428
52602
  const name = String(a[1] ?? "").trim();
52429
52603
  if (!validName(name))
52430
52604
  return { ok: false, error: "Invalid name." };
52431
- const target = join21(parent, name);
52605
+ const target = join22(parent, name);
52432
52606
  if (!insideOk(target))
52433
52607
  return OUTSIDE("create");
52434
52608
  if (existsSync8(target))
@@ -52450,7 +52624,7 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52450
52624
  return { ok: false, error: "Invalid name." };
52451
52625
  if (!insideOk(oldPath))
52452
52626
  return OUTSIDE("rename");
52453
- const newPath = join21(dirname7(oldPath), newName);
52627
+ const newPath = join22(dirname7(oldPath), newName);
52454
52628
  if (existsSync8(newPath))
52455
52629
  return { ok: false, error: `A file named "${newName}" already exists.` };
52456
52630
  try {
@@ -52484,19 +52658,19 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52484
52658
  try {
52485
52659
  pruneTrash(root);
52486
52660
  const id = `${Date.now().toString(36)}-${(trashSeq++).toString(36)}`;
52487
- const itemDir = join21(root, TRASH_DIR, id);
52661
+ const itemDir = join22(root, TRASH_DIR, id);
52488
52662
  await mkdir5(itemDir, { recursive: true });
52489
52663
  const name = basename3(p);
52490
- const trashedPath = join21(itemDir, name);
52664
+ const trashedPath = join22(itemDir, name);
52491
52665
  await moveItem(p, trashedPath);
52492
- await writeFile5(join21(itemDir, ".fp-meta.json"), JSON.stringify({ originalPath: resolve5(p), name, deletedAt: Date.now() }));
52666
+ await writeFile5(join22(itemDir, ".fp-meta.json"), JSON.stringify({ originalPath: resolve5(p), name, deletedAt: Date.now() }));
52493
52667
  return { ok: true, trashId: id, path: trashedPath };
52494
52668
  } catch (err) {
52495
52669
  return { ok: false, error: String(err.message) };
52496
52670
  }
52497
52671
  }
52498
52672
  case "listTrash": {
52499
- const trashDir = join21(root, TRASH_DIR);
52673
+ const trashDir = join22(root, TRASH_DIR);
52500
52674
  if (!existsSync8(trashDir))
52501
52675
  return [];
52502
52676
  try {
@@ -52505,8 +52679,8 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52505
52679
  if (!e.isDirectory())
52506
52680
  continue;
52507
52681
  try {
52508
- const meta4 = JSON.parse(readFileSync9(join21(trashDir, e.name, ".fp-meta.json"), "utf-8"));
52509
- out.push({ trashId: e.name, name: meta4.name, path: join21(trashDir, e.name, meta4.name), originalPath: meta4.originalPath, deletedAt: meta4.deletedAt });
52682
+ const meta4 = JSON.parse(readFileSync9(join22(trashDir, e.name, ".fp-meta.json"), "utf-8"));
52683
+ out.push({ trashId: e.name, name: meta4.name, path: join22(trashDir, e.name, meta4.name), originalPath: meta4.originalPath, deletedAt: meta4.deletedAt });
52510
52684
  } catch {
52511
52685
  }
52512
52686
  }
@@ -52519,14 +52693,14 @@ async function runRemoteFsOp(root, op, args, quotaKey) {
52519
52693
  const id = String(a[0] ?? "");
52520
52694
  if (!SAFE_SEG.test(id))
52521
52695
  return { ok: false, error: "Bad trash id." };
52522
- const itemDir = join21(root, TRASH_DIR, id);
52696
+ const itemDir = join22(root, TRASH_DIR, id);
52523
52697
  if (!existsSync8(itemDir))
52524
52698
  return { ok: false, error: "Not in trash." };
52525
52699
  try {
52526
- const meta4 = JSON.parse(readFileSync9(join21(itemDir, ".fp-meta.json"), "utf-8"));
52700
+ const meta4 = JSON.parse(readFileSync9(join22(itemDir, ".fp-meta.json"), "utf-8"));
52527
52701
  if (!validName(meta4.name))
52528
52702
  return { ok: false, error: "Bad trashed name." };
52529
- const src = join21(itemDir, meta4.name);
52703
+ const src = join22(itemDir, meta4.name);
52530
52704
  let dest = meta4.originalPath;
52531
52705
  if (!insideOk(dest))
52532
52706
  return OUTSIDE("restore");
@@ -52620,7 +52794,7 @@ function watchRemoteRoot(root, key2, onChange) {
52620
52794
  const rel = String(filename);
52621
52795
  if (rel.split(sep4).some((seg) => IGNORED.has(seg)))
52622
52796
  return;
52623
- pending.add(join21(resolved, rel));
52797
+ pending.add(join22(resolved, rel));
52624
52798
  if (timer)
52625
52799
  clearTimeout(timer);
52626
52800
  timer = setTimeout(() => {
@@ -52832,46 +53006,14 @@ function releaseDcClient(clientId) {
52832
53006
  }
52833
53007
  }
52834
53008
 
52835
- // ../../packages/host-core/dist/host-metrics.js
52836
- import os from "node:os";
52837
- function primaryIpv4(ifaces = os.networkInterfaces()) {
52838
- for (const name of Object.keys(ifaces)) {
52839
- for (const ni of ifaces[name] ?? []) {
52840
- if (ni.family === "IPv4" && !ni.internal)
52841
- return ni.address;
52842
- }
52843
- }
52844
- return void 0;
52845
- }
52846
- function staticMetrics(version2) {
52847
- const cpus = os.cpus();
52848
- return {
52849
- version: version2 || void 0,
52850
- arch: os.arch(),
52851
- cpuModel: cpus[0]?.model?.trim() || void 0,
52852
- cpuCount: cpus.length || void 0,
52853
- totalMem: os.totalmem() || void 0,
52854
- ip: primaryIpv4()
52855
- };
52856
- }
52857
- function dynamicMetrics() {
52858
- const la = os.loadavg();
52859
- return {
52860
- load: la[0] > 0 ? Number(la[0].toFixed(2)) : void 0,
52861
- // loadavg is [0,0,0] on Windows
52862
- freeMem: os.freemem() || void 0,
52863
- uptime: Math.round(os.uptime()) || void 0
52864
- };
52865
- }
52866
-
52867
53009
  // ../../packages/host-core/dist/fs-transfer.js
52868
53010
  import { readdir as readdir4, lstat as lstat2, mkdir as mkdir6, chmod, rm as rm2, readlink, symlink, stat as stat3 } from "node:fs/promises";
52869
- import { openSync as openSync3, readSync as readSync2, closeSync as closeSync3, existsSync as existsSync9, createWriteStream } from "node:fs";
52870
- import { dirname as dirname8, join as join23, relative as relative6, sep as sep6 } from "node:path";
53011
+ import { openSync as openSync4, readSync as readSync3, closeSync as closeSync4, existsSync as existsSync9, createWriteStream } from "node:fs";
53012
+ import { dirname as dirname8, join as join24, relative as relative6, sep as sep6 } from "node:path";
52871
53013
 
52872
53014
  // ../../packages/host-core/dist/active-link/paths.js
52873
53015
  import { homedir as homedir11 } from "node:os";
52874
- import { join as join22, relative as relative5, sep as sep5 } from "node:path";
53016
+ import { join as join23, relative as relative5, sep as sep5 } from "node:path";
52875
53017
  function activeLinkEnabled() {
52876
53018
  return process.env.CCB_ACTIVE_LINK !== "0";
52877
53019
  }
@@ -52897,7 +53039,7 @@ function toPosixRel(root, abs) {
52897
53039
  return relative5(root, abs).split(sep5).join("/");
52898
53040
  }
52899
53041
  function fromPosixRel(root, rel) {
52900
- return join22(root, rel.split("/").join(sep5));
53042
+ return join23(root, rel.split("/").join(sep5));
52901
53043
  }
52902
53044
  function isExcludedAbs(abs, root) {
52903
53045
  const rel = toPosixRel(root, abs);
@@ -52906,10 +53048,10 @@ function isExcludedAbs(abs, root) {
52906
53048
  return rel.split("/").some(isExcludedName);
52907
53049
  }
52908
53050
  function activeLinkRoot() {
52909
- return process.env.CCB_ACTIVE_LINK_DIR ?? join22(homedir11(), ".tesseract", "active-link");
53051
+ return process.env.CCB_ACTIVE_LINK_DIR ?? join23(homedir11(), ".tesseract", "active-link");
52910
53052
  }
52911
53053
  function linkStateDir(linkId) {
52912
- return join22(activeLinkRoot(), linkId);
53054
+ return join23(activeLinkRoot(), linkId);
52913
53055
  }
52914
53056
 
52915
53057
  // ../../packages/host-core/dist/fs-transfer.js
@@ -52922,9 +53064,9 @@ function clearTimer(t) {
52922
53064
  return null;
52923
53065
  }
52924
53066
  function uniqueDir(parent, name) {
52925
- let candidate = join23(parent, name);
53067
+ let candidate = join24(parent, name);
52926
53068
  for (let i = 2; existsSync9(candidate) && i < 1e4; i++)
52927
- candidate = join23(parent, `${name} ${i}`);
53069
+ candidate = join24(parent, `${name} ${i}`);
52928
53070
  return candidate;
52929
53071
  }
52930
53072
  var producers = /* @__PURE__ */ new Map();
@@ -52967,7 +53109,7 @@ async function buildManifest(root, followSymlinks, excludeHeavy) {
52967
53109
  continue;
52968
53110
  if (e.isDirectory() && excludeHeavy && HEAVY_DIRS.has(e.name))
52969
53111
  continue;
52970
- const abs = join23(dir2, e.name);
53112
+ const abs = join24(dir2, e.name);
52971
53113
  const rel = relative6(root, abs).split(sep6).join("/");
52972
53114
  const st = await lstat2(abs).catch(() => null);
52973
53115
  if (!st)
@@ -53034,14 +53176,14 @@ async function startOutboundTransfer(msg, controllerClientId, ownHostId2, hostRo
53034
53176
  for (let fileIx = 0; fileIx < manifest.files.length && !state.cancelled; fileIx++) {
53035
53177
  const f = manifest.files[fileIx];
53036
53178
  if (f.kind === "symlink") {
53037
- const target = await readlink(join23(srcPath, f.rel.split("/").join(sep6))).catch(() => "");
53179
+ const target = await readlink(join24(srcPath, f.rel.split("/").join(sep6))).catch(() => "");
53038
53180
  send3({ type: "fs:transferChunk", transferId, toHost, fileIx, rel: f.rel, mode: f.mode, kind: "symlink", offset: 0, base64: Buffer.from(target, "utf-8").toString("base64"), eof: true }, { hostId: toHost });
53039
53181
  continue;
53040
53182
  }
53041
- const abs = join23(srcPath, f.rel.split("/").join(sep6));
53183
+ const abs = join24(srcPath, f.rel.split("/").join(sep6));
53042
53184
  let fd = null;
53043
53185
  try {
53044
- fd = openSync3(abs, "r");
53186
+ fd = openSync4(abs, "r");
53045
53187
  if (f.size === 0) {
53046
53188
  send3({ type: "fs:transferChunk", transferId, toHost, fileIx, rel: f.rel, mode: f.mode, kind: "file", offset: 0, base64: "", eof: true }, { hostId: toHost });
53047
53189
  } else {
@@ -53051,7 +53193,7 @@ async function startOutboundTransfer(msg, controllerClientId, ownHostId2, hostRo
53051
53193
  break;
53052
53194
  const len = Math.min(CHUNK2, f.size - offset);
53053
53195
  const buf = Buffer.alloc(len);
53054
- const read = readSync2(fd, buf, 0, len, offset);
53196
+ const read = readSync3(fd, buf, 0, len, offset);
53055
53197
  send3({ type: "fs:transferChunk", transferId, toHost, fileIx, rel: f.rel, mode: f.mode, kind: "file", offset, base64: buf.subarray(0, read).toString("base64"), eof: offset + len >= f.size }, { hostId: toHost });
53056
53198
  state.sentBytes += read;
53057
53199
  }
@@ -53059,7 +53201,7 @@ async function startOutboundTransfer(msg, controllerClientId, ownHostId2, hostRo
53059
53201
  } catch (e) {
53060
53202
  if (fd != null)
53061
53203
  try {
53062
- closeSync3(fd);
53204
+ closeSync4(fd);
53063
53205
  } catch {
53064
53206
  }
53065
53207
  failProducer(transferId, `Couldn't read ${f.rel}: ${e.message}`);
@@ -53067,7 +53209,7 @@ async function startOutboundTransfer(msg, controllerClientId, ownHostId2, hostRo
53067
53209
  } finally {
53068
53210
  if (fd != null)
53069
53211
  try {
53070
- closeSync3(fd);
53212
+ closeSync4(fd);
53071
53213
  } catch {
53072
53214
  }
53073
53215
  }
@@ -53150,7 +53292,7 @@ async function beginInboundTransfer(msg, hostRoot, send3) {
53150
53292
  failNoState("Invalid destination name.");
53151
53293
  return;
53152
53294
  }
53153
- let destRoot = join23(parent, msg.destName);
53295
+ let destRoot = join24(parent, msg.destName);
53154
53296
  let createdRoot = false;
53155
53297
  if (existsSync9(destRoot)) {
53156
53298
  if (msg.onCollision === "abort") {
@@ -53192,7 +53334,7 @@ async function beginInboundTransfer(msg, hostRoot, send3) {
53192
53334
  try {
53193
53335
  await mkdir6(destRoot, { recursive: true });
53194
53336
  for (const d of msg.dirs) {
53195
- const abs = join23(destRoot, d.rel.split("/").join(sep6));
53337
+ const abs = join24(destRoot, d.rel.split("/").join(sep6));
53196
53338
  if (isInsideRoot(abs, destRoot))
53197
53339
  await mkdir6(abs, { recursive: true }).catch(() => {
53198
53340
  });
@@ -53206,7 +53348,7 @@ async function writeInboundChunk(msg, send3) {
53206
53348
  if (!s || s.cancelled)
53207
53349
  return;
53208
53350
  armConsumerWatchdog(msg.transferId, send3);
53209
- const abs = join23(s.destRoot, msg.rel.split("/").join(sep6));
53351
+ const abs = join24(s.destRoot, msg.rel.split("/").join(sep6));
53210
53352
  if (msg.rel.includes("..") || !isInsideRoot(abs, s.destRoot)) {
53211
53353
  failConsumer(msg.transferId, `Refusing a path outside the destination: ${msg.rel}`, send3);
53212
53354
  return;
@@ -53214,7 +53356,7 @@ async function writeInboundChunk(msg, send3) {
53214
53356
  try {
53215
53357
  if (msg.kind === "symlink") {
53216
53358
  const target = Buffer.from(msg.base64, "base64").toString("utf-8");
53217
- const resolved = join23(dirname8(abs), target);
53359
+ const resolved = join24(dirname8(abs), target);
53218
53360
  if (isInsideRoot(resolved, s.destRoot)) {
53219
53361
  await mkdir6(dirname8(abs), { recursive: true }).catch(() => {
53220
53362
  });
@@ -53301,7 +53443,7 @@ function cancelTransfersForClient(clientId, send3) {
53301
53443
 
53302
53444
  // ../../packages/host-core/dist/peer-link/index.js
53303
53445
  import { homedir as homedir12 } from "node:os";
53304
- import { join as join24 } from "node:path";
53446
+ import { join as join25 } from "node:path";
53305
53447
 
53306
53448
  // ../../packages/host-core/dist/peer-link/manager.js
53307
53449
  init_tls_direct();
@@ -53361,12 +53503,17 @@ async function dialLadder(opts) {
53361
53503
  }
53362
53504
 
53363
53505
  // ../../packages/host-core/dist/peer-link/manager.js
53506
+ init_dist();
53364
53507
  var LISTEN_PORT = Number(process.env.CCB_P2P_PORT ?? 0);
53365
53508
  var UDP_PORT = Number(process.env.CCB_P2P_UDP_PORT ?? 0);
53366
53509
  var RENDEZVOUS_TIMEOUT_MS = 25e3;
53367
53510
  var INBOUND_WAIT_MS = 2e4;
53368
- var DEFAULT_STUN_HOST = "stun.l.google.com";
53369
- var DEFAULT_STUN_PORT = 19302;
53511
+ var DEFAULT_STUN_SERVERS = [
53512
+ { host: OWN_STUN_HOST, port: OWN_STUN_PORT },
53513
+ // our coturn first
53514
+ { host: "stun.l.google.com", port: 19302 }
53515
+ // public fallback
53516
+ ];
53370
53517
  var provisionedStun = null;
53371
53518
  function provisionStun(host, port = 3478) {
53372
53519
  if (host)
@@ -53381,7 +53528,7 @@ function resolveStunServers() {
53381
53528
  list.push({ host: env, port: Number(process.env.CCB_STUN_PORT ?? 3478) });
53382
53529
  if (provisionedStun)
53383
53530
  list.push(provisionedStun);
53384
- list.push({ host: DEFAULT_STUN_HOST, port: DEFAULT_STUN_PORT });
53531
+ list.push(...DEFAULT_STUN_SERVERS);
53385
53532
  const seen = /* @__PURE__ */ new Set();
53386
53533
  return list.filter((s) => {
53387
53534
  const k = `${s.host}:${s.port}`;
@@ -53798,8 +53945,8 @@ var PeerLinkManager = class {
53798
53945
  // ../../packages/host-core/dist/peer-link/index.js
53799
53946
  var P2P_ENABLED = process.env.CCB_P2P !== "0";
53800
53947
  function identityPaths() {
53801
- const dir2 = process.env.CCB_P2P_DIR ?? join24(homedir12(), ".tesseract");
53802
- return { certPath: join24(dir2, "peer-cert.pem"), keyPath: join24(dir2, "peer-key.pem") };
53948
+ const dir2 = process.env.CCB_P2P_DIR ?? join25(homedir12(), ".tesseract");
53949
+ return { certPath: join25(dir2, "peer-cert.pem"), keyPath: join25(dir2, "peer-key.pem") };
53803
53950
  }
53804
53951
  var manager = null;
53805
53952
  function peerLinkManager() {
@@ -53816,7 +53963,7 @@ async function openPeerLink(peerHostId, ctx2) {
53816
53963
  // ../../packages/host-core/dist/active-link/engine.js
53817
53964
  import { lstat as lstat7, readlink as readlink4, rm as rm3, mkdir as mkdir8, symlink as symlink2, rename as rename2, utimes as utimes2, writeFile as writeFile6 } from "node:fs/promises";
53818
53965
  import { existsSync as existsSync12 } from "node:fs";
53819
- import { dirname as dirname13, join as join29, resolve as resolve8 } from "node:path";
53966
+ import { dirname as dirname13, join as join30, resolve as resolve8 } from "node:path";
53820
53967
 
53821
53968
  // ../../packages/host-core/dist/active-link/blocks.js
53822
53969
  import { createHash as createHash3 } from "node:crypto";
@@ -54081,7 +54228,7 @@ var BlockAssembler = class {
54081
54228
 
54082
54229
  // ../../packages/host-core/dist/active-link/manifest.js
54083
54230
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync11, mkdirSync as mkdirSync10, existsSync as existsSync11, renameSync as renameSync5 } from "node:fs";
54084
- import { join as join25 } from "node:path";
54231
+ import { join as join26 } from "node:path";
54085
54232
 
54086
54233
  // ../../packages/host-core/dist/active-link/reconcile.js
54087
54234
  var ABSENT = { kind: "absent", t: -Infinity, hash: "" };
@@ -54117,7 +54264,7 @@ var LinkManifest = class {
54117
54264
  this.dir = dir2;
54118
54265
  }
54119
54266
  file() {
54120
- return join25(this.dir, "manifest.json");
54267
+ return join26(this.dir, "manifest.json");
54121
54268
  }
54122
54269
  load() {
54123
54270
  try {
@@ -54219,7 +54366,7 @@ var LinkManifest = class {
54219
54366
 
54220
54367
  // ../../packages/host-core/dist/active-link/scanner.js
54221
54368
  import { readdir as readdir5, lstat as lstat3, readlink as readlink2 } from "node:fs/promises";
54222
- import { join as join26, sep as sep7 } from "node:path";
54369
+ import { join as join27, sep as sep7 } from "node:path";
54223
54370
  async function walkRels(root, extraIgnore) {
54224
54371
  const out = [];
54225
54372
  async function rec(dir2) {
@@ -54234,7 +54381,7 @@ async function walkRels(root, extraIgnore) {
54234
54381
  continue;
54235
54382
  if (e.isDirectory() && HEAVY_DIRS.has(e.name))
54236
54383
  continue;
54237
- const abs = join26(dir2, e.name);
54384
+ const abs = join27(dir2, e.name);
54238
54385
  if (extraIgnore?.(abs))
54239
54386
  continue;
54240
54387
  if (e.isDirectory())
@@ -54273,7 +54420,7 @@ async function scanTree(root, prior, allow, extraIgnore) {
54273
54420
  return { records };
54274
54421
  }
54275
54422
  function absOf(root, rel) {
54276
- return join26(root, rel.split("/").join(sep7));
54423
+ return join27(root, rel.split("/").join(sep7));
54277
54424
  }
54278
54425
 
54279
54426
  // ../../packages/host-core/dist/active-link/gitignore.js
@@ -56298,7 +56445,7 @@ var ActiveLinkEngine = class {
56298
56445
  }
56299
56446
  async start() {
56300
56447
  this.emit({ type: "status", linkId: this.opts.linkId, state: "scanning" });
56301
- await rm3(join29(this.stateDir, ".staging"), { recursive: true, force: true }).catch(() => {
56448
+ await rm3(join30(this.stateDir, ".staging"), { recursive: true, force: true }).catch(() => {
56302
56449
  });
56303
56450
  this.manifest.load();
56304
56451
  await this.reconcileScan();
@@ -56926,7 +57073,7 @@ var ActiveLinkEngine = class {
56926
57073
  this.inboundWatchdog.clear();
56927
57074
  }
56928
57075
  stagingPath(rel, tag) {
56929
- return join29(this.stateDir, ".staging", `${hashString(rel)}.${tag}`);
57076
+ return join30(this.stateDir, ".staging", `${hashString(rel)}.${tag}`);
56930
57077
  }
56931
57078
  pruneSuppress() {
56932
57079
  const now2 = this.now();
@@ -56952,9 +57099,9 @@ var ActiveLinkEngine = class {
56952
57099
 
56953
57100
  // ../../packages/host-core/dist/active-link/config.js
56954
57101
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync12, mkdirSync as mkdirSync11, existsSync as existsSync13, renameSync as renameSync6, watch as watch3 } from "node:fs";
56955
- import { join as join30 } from "node:path";
57102
+ import { join as join31 } from "node:path";
56956
57103
  function configPath2() {
56957
- return join30(activeLinkRoot(), "links.json");
57104
+ return join31(activeLinkRoot(), "links.json");
56958
57105
  }
56959
57106
  function loadLinkConfigs() {
56960
57107
  try {
@@ -56991,7 +57138,7 @@ function saveLinkConfig(cfg2) {
56991
57138
  writeAll(links);
56992
57139
  }
56993
57140
  function pendingPath() {
56994
- return join30(activeLinkRoot(), "pending-deprovisions.json");
57141
+ return join31(activeLinkRoot(), "pending-deprovisions.json");
56995
57142
  }
56996
57143
  function loadPendingDeprovisions() {
56997
57144
  try {
@@ -57626,7 +57773,7 @@ function fetchIceServers() {
57626
57773
  const i = iceWaiters.indexOf(resolve10);
57627
57774
  if (i >= 0) {
57628
57775
  iceWaiters.splice(i, 1);
57629
- resolve10([{ urls: "stun:stun.l.google.com:19302" }]);
57776
+ resolve10(DEFAULT_ICE_SERVERS);
57630
57777
  }
57631
57778
  }, 2500);
57632
57779
  });
@@ -57810,9 +57957,9 @@ function provisionActiveLinkMirror(payload) {
57810
57957
  const remoteSubfolder = typeof payload.remoteSubfolder === "string" ? payload.remoteSubfolder : void 0;
57811
57958
  let localRoot;
57812
57959
  if (remoteParent && remoteSubfolder) {
57813
- localRoot = join31(remoteParent, safeFolderName(remoteSubfolder));
57960
+ localRoot = join32(remoteParent, safeFolderName(remoteSubfolder));
57814
57961
  } else {
57815
- localRoot = join31(HOST_ROOT, "Tesseract Mirrors", safeFolderName(projectName));
57962
+ localRoot = join32(HOST_ROOT, "Tesseract Mirrors", safeFolderName(projectName));
57816
57963
  }
57817
57964
  if (loadLinkConfigs().some((c) => c.localRoot === localRoot && c.linkId !== linkId)) {
57818
57965
  localRoot = `${localRoot}-${linkId.slice(0, 6)}`;
@@ -59015,16 +59162,16 @@ async function startLocalServer(opts) {
59015
59162
 
59016
59163
  // ../../packages/host-core/dist/daemon-runtime.js
59017
59164
  import { readFileSync as readFileSync14, writeFileSync as writeFileSync15, existsSync as existsSync17, mkdirSync as mkdirSync15, unlinkSync as unlinkSync2, chmodSync as chmodSync4 } from "node:fs";
59018
- import { join as join34 } from "node:path";
59165
+ import { join as join35 } from "node:path";
59019
59166
  import { randomBytes as randomBytes5 } from "node:crypto";
59020
59167
  import { hostname as hostname4 } from "node:os";
59021
59168
 
59022
59169
  // ../../packages/host-core/dist/device-identity.js
59023
- import { join as join32 } from "node:path";
59170
+ import { join as join33 } from "node:path";
59024
59171
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, existsSync as existsSync15, mkdirSync as mkdirSync13, renameSync as renameSync7, chmodSync as chmodSync3 } from "node:fs";
59025
59172
  var cached2 = null;
59026
59173
  function identityPath() {
59027
- return join32(daemonDir(), "identity.json");
59174
+ return join33(daemonDir(), "identity.json");
59028
59175
  }
59029
59176
  async function loadOrCreateDeviceIdentity() {
59030
59177
  if (cached2)
@@ -59289,9 +59436,9 @@ function createNodePowerController() {
59289
59436
 
59290
59437
  // ../../packages/host-core/dist/activity/activity-tracker.js
59291
59438
  import { promises as fsp, writeFileSync as writeFileSync14, mkdirSync as mkdirSync14, existsSync as existsSync16 } from "node:fs";
59292
- import { join as join33 } from "node:path";
59439
+ import { join as join34 } from "node:path";
59293
59440
  function activityProfilePath() {
59294
- return join33(daemonDir(), "activity-profile.json");
59441
+ return join34(daemonDir(), "activity-profile.json");
59295
59442
  }
59296
59443
  var MAX_APPS = 300;
59297
59444
  var MAX_AGE_DAYS = 120;
@@ -59423,8 +59570,8 @@ async function runDaemon(opts = {}) {
59423
59570
  const VERSION = opts.version ?? process.env.CCB_DAEMON_VERSION ?? "dev";
59424
59571
  const TAG = opts.tag ?? "host-daemon";
59425
59572
  const log4 = (...args) => console.log(`[${TAG} ${(/* @__PURE__ */ new Date()).toISOString()}]`, ...args);
59426
- const pidfile = () => join34(daemonDir(), "daemon.lock");
59427
- const statusFile = () => join34(daemonDir(), "status.json");
59573
+ const pidfile = () => join35(daemonDir(), "daemon.lock");
59574
+ const statusFile = () => join35(daemonDir(), "status.json");
59428
59575
  const isAlive2 = (pid) => {
59429
59576
  try {
59430
59577
  process.kill(pid, 0);
@@ -59571,7 +59718,7 @@ async function runDaemon(opts = {}) {
59571
59718
  if (r.status === 401) {
59572
59719
  log4("device token no longer valid \u2014 dropping to local-only on restart");
59573
59720
  try {
59574
- unlinkSync2(join34(daemonDir(), "credentials.json"));
59721
+ unlinkSync2(join35(daemonDir(), "credentials.json"));
59575
59722
  } catch {
59576
59723
  }
59577
59724
  shutdown(0);
@@ -59643,7 +59790,7 @@ import { platform as platform2 } from "node:os";
59643
59790
 
59644
59791
  // ../../packages/host-core/dist/service/launchd.js
59645
59792
  import { writeFileSync as writeFileSync16, existsSync as existsSync18, mkdirSync as mkdirSync16, unlinkSync as unlinkSync3 } from "node:fs";
59646
- import { dirname as dirname14, join as join35 } from "node:path";
59793
+ import { dirname as dirname14, join as join36 } from "node:path";
59647
59794
  import { homedir as homedir14, userInfo } from "node:os";
59648
59795
 
59649
59796
  // ../../packages/host-core/dist/service/exec.js
@@ -59667,10 +59814,10 @@ function xml(s) {
59667
59814
  }
59668
59815
  function makeLaunchd(instanceId) {
59669
59816
  const label = SERVICE_LABEL_BASE + (instanceId ? `.${instanceId}` : "");
59670
- const plistPath = () => join35(homedir14(), "Library", "LaunchAgents", `${label}.plist`);
59817
+ const plistPath = () => join36(homedir14(), "Library", "LaunchAgents", `${label}.plist`);
59671
59818
  const domainTarget = () => `gui/${userInfo().uid}`;
59672
59819
  const serviceTarget = () => `${domainTarget()}/${label}`;
59673
- const logFile = () => join35(daemonDir(), "daemon.log");
59820
+ const logFile = () => join36(daemonDir(), "daemon.log");
59674
59821
  function buildPlist(spec) {
59675
59822
  const args = [spec.exec, ...spec.args].map((a) => ` <string>${xml(a)}</string>`).join("\n");
59676
59823
  const env = Object.entries(spec.env).map(([k, v]) => ` <key>${xml(k)}</key>
@@ -59765,7 +59912,7 @@ ${env}
59765
59912
 
59766
59913
  // ../../packages/host-core/dist/service/systemd.js
59767
59914
  import { writeFileSync as writeFileSync17, existsSync as existsSync19, mkdirSync as mkdirSync17, unlinkSync as unlinkSync4 } from "node:fs";
59768
- import { dirname as dirname15, join as join36 } from "node:path";
59915
+ import { dirname as dirname15, join as join37 } from "node:path";
59769
59916
  import { homedir as homedir15, userInfo as userInfo2 } from "node:os";
59770
59917
  function shq(s) {
59771
59918
  return `"${s.replace(/(["\\$`])/g, "\\$1")}"`;
@@ -59773,8 +59920,8 @@ function shq(s) {
59773
59920
  function makeSystemd(instanceId) {
59774
59921
  const unit = `tesseract-host${instanceId ? `-${instanceId}` : ""}.service`;
59775
59922
  const unitPath = () => {
59776
- const base = process.env.XDG_CONFIG_HOME || join36(homedir15(), ".config");
59777
- return join36(base, "systemd", "user", unit);
59923
+ const base = process.env.XDG_CONFIG_HOME || join37(homedir15(), ".config");
59924
+ return join37(base, "systemd", "user", unit);
59778
59925
  };
59779
59926
  function buildUnit(spec) {
59780
59927
  const execStart = [spec.exec, ...spec.args].map(shq).join(" ");
@@ -59845,11 +59992,11 @@ WantedBy=default.target
59845
59992
 
59846
59993
  // ../../packages/host-core/dist/service/windows.js
59847
59994
  import { writeFileSync as writeFileSync18, existsSync as existsSync20, mkdirSync as mkdirSync18, unlinkSync as unlinkSync5 } from "node:fs";
59848
- import { dirname as dirname16, join as join37 } from "node:path";
59995
+ import { dirname as dirname16, join as join38 } from "node:path";
59849
59996
  function makeWindowsTask(instanceId) {
59850
59997
  const task = `Fineguide\\TesseractHost${instanceId ? `-${instanceId}` : ""}`;
59851
- const wrapperPath = () => join37(daemonDir(), `run-host${instanceId ? `-${instanceId}` : ""}.cmd`);
59852
- const logFile = () => join37(daemonDir(), "daemon.log");
59998
+ const wrapperPath = () => join38(daemonDir(), `run-host${instanceId ? `-${instanceId}` : ""}.cmd`);
59999
+ const logFile = () => join38(daemonDir(), "daemon.log");
59853
60000
  const oneLine2 = (s) => s.replace(/[\r\n]+/g, " ");
59854
60001
  const envVal = (v) => oneLine2(v).replace(/%/g, "%%").replace(/"/g, "");
59855
60002
  const cmdArg = (a) => `"${oneLine2(a).replace(/"/g, "")}"`;
@@ -59931,7 +60078,7 @@ function getServiceController(instanceId) {
59931
60078
  var import_qrcode_terminal = __toESM(require_main(), 1);
59932
60079
  import { randomUUID as randomUUID9 } from "node:crypto";
59933
60080
  import { existsSync as existsSync21, rmSync as rmSync3 } from "node:fs";
59934
- import { join as join38 } from "node:path";
60081
+ import { join as join39 } from "node:path";
59935
60082
 
59936
60083
  // src/config.ts
59937
60084
  import { hostname as hostname5 } from "node:os";
@@ -60132,7 +60279,7 @@ async function logout() {
60132
60279
  }
60133
60280
  for (const f of ["credentials.json", "status.json", "daemon.lock"]) {
60134
60281
  try {
60135
- const p = join38(daemonDir(), f);
60282
+ const p = join39(daemonDir(), f);
60136
60283
  if (existsSync21(p)) rmSync3(p);
60137
60284
  } catch {
60138
60285
  }
@@ -60291,7 +60438,7 @@ function startSelfUpdater(current) {
60291
60438
  }
60292
60439
 
60293
60440
  // src/service.ts
60294
- import { join as join39 } from "node:path";
60441
+ import { join as join40 } from "node:path";
60295
60442
  import { platform as platform3 } from "node:os";
60296
60443
  import { existsSync as existsSync22, readFileSync as readFileSync15 } from "node:fs";
60297
60444
  function controller(instanceId) {
@@ -60306,7 +60453,7 @@ function buildSpec(cliEntry) {
60306
60453
  exec: process.execPath,
60307
60454
  args: [cliEntry, "run"],
60308
60455
  env: { CCB_DAEMON_DIR: daemonDir() },
60309
- logPath: join39(daemonDir(), "daemon.log")
60456
+ logPath: join40(daemonDir(), "daemon.log")
60310
60457
  };
60311
60458
  }
60312
60459
  var isAlive = (pid) => {
@@ -60318,7 +60465,7 @@ var isAlive = (pid) => {
60318
60465
  }
60319
60466
  };
60320
60467
  function runningDaemonInfo() {
60321
- const lock = join39(daemonDir(), "daemon.lock");
60468
+ const lock = join40(daemonDir(), "daemon.lock");
60322
60469
  try {
60323
60470
  if (!existsSync22(lock)) return null;
60324
60471
  const pid = Number(readFileSync15(lock, "utf-8").trim());
@@ -60357,7 +60504,7 @@ async function logs(instanceId, follow) {
60357
60504
  // src/cli.ts
60358
60505
  function pkgVersion() {
60359
60506
  try {
60360
- const p = join40(dirname17(fileURLToPath2(import.meta.url)), "..", "package.json");
60507
+ const p = join41(dirname17(fileURLToPath2(import.meta.url)), "..", "package.json");
60361
60508
  return JSON.parse(readFileSync16(p, "utf8")).version ?? "0.0.0";
60362
60509
  } catch {
60363
60510
  return "0.0.0";
@@ -60620,7 +60767,7 @@ async function main() {
60620
60767
  process.exit(1);
60621
60768
  }
60622
60769
  instance = flags.instance;
60623
- process.env.CCB_DAEMON_DIR = join40(homedir16(), ".tesseract", `daemon-${instance}`);
60770
+ process.env.CCB_DAEMON_DIR = join41(homedir16(), ".tesseract", `daemon-${instance}`);
60624
60771
  }
60625
60772
  const force = flags.yes === true || flags.force === true;
60626
60773
  const cliEntry = fileURLToPath2(import.meta.url);