tesseract-agent 0.11.3 → 0.11.7

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.
@@ -3378,7 +3378,7 @@ var require_stream = __commonJS({
3378
3378
  };
3379
3379
  duplex._final = function(callback) {
3380
3380
  if (ws.readyState === ws.CONNECTING) {
3381
- ws.once("open", function open7() {
3381
+ ws.once("open", function open8() {
3382
3382
  duplex._final(callback);
3383
3383
  });
3384
3384
  return;
@@ -3399,7 +3399,7 @@ var require_stream = __commonJS({
3399
3399
  };
3400
3400
  duplex._write = function(chunk, encoding, callback) {
3401
3401
  if (ws.readyState === ws.CONNECTING) {
3402
- ws.once("open", function open7() {
3402
+ ws.once("open", function open8() {
3403
3403
  duplex._write(chunk, encoding, callback);
3404
3404
  });
3405
3405
  return;
@@ -24207,9 +24207,9 @@ function extractJsonObject(raw) {
24207
24207
  function extractJsonArray(raw) {
24208
24208
  return extractBalanced(raw, "[", "]");
24209
24209
  }
24210
- function extractBalanced(raw, open7, close) {
24210
+ function extractBalanced(raw, open8, close) {
24211
24211
  const s = raw.replace(/^```(?:json)?\s*/i, "").replace(/\s*```\s*$/i, "");
24212
- const start3 = s.indexOf(open7);
24212
+ const start3 = s.indexOf(open8);
24213
24213
  if (start3 < 0)
24214
24214
  return null;
24215
24215
  let depth = 0, inStr = false, esc3 = false;
@@ -24226,7 +24226,7 @@ function extractBalanced(raw, open7, close) {
24226
24226
  }
24227
24227
  if (c === '"')
24228
24228
  inStr = true;
24229
- else if (c === open7)
24229
+ else if (c === open8)
24230
24230
  depth++;
24231
24231
  else if (c === close) {
24232
24232
  depth--;
@@ -27550,6 +27550,32 @@ var init_mesh_node_name = __esm({
27550
27550
  }
27551
27551
  });
27552
27552
 
27553
+ // ../../packages/shared/dist/host-id.js
27554
+ function parseHostId(hostId) {
27555
+ if (!hostId)
27556
+ return null;
27557
+ const i = hostId.indexOf(":");
27558
+ if (i < 0 || hostId.slice(0, i) !== "electron")
27559
+ return null;
27560
+ const rest = hostId.slice(i + 1);
27561
+ const j = rest.indexOf(":");
27562
+ if (j < 0)
27563
+ return null;
27564
+ const owner = rest.slice(0, j);
27565
+ const deviceId3 = rest.slice(j + 1);
27566
+ if (!owner || !deviceId3)
27567
+ return null;
27568
+ return { kind: "electron", owner, deviceId: deviceId3 };
27569
+ }
27570
+ function hostDeviceId(hostId) {
27571
+ return parseHostId(hostId)?.deviceId ?? null;
27572
+ }
27573
+ var init_host_id = __esm({
27574
+ "../../packages/shared/dist/host-id.js"() {
27575
+ "use strict";
27576
+ }
27577
+ });
27578
+
27553
27579
  // ../../packages/shared/dist/index.js
27554
27580
  var init_dist2 = __esm({
27555
27581
  "../../packages/shared/dist/index.js"() {
@@ -27610,6 +27636,7 @@ var init_dist2 = __esm({
27610
27636
  init_user_dialog();
27611
27637
  init_session_ops();
27612
27638
  init_mesh_node_name();
27639
+ init_host_id();
27613
27640
  }
27614
27641
  });
27615
27642
 
@@ -29167,17 +29194,17 @@ function markerPair(path6) {
29167
29194
  return { open: `// ${MARKER}:start`, close: `// ${MARKER}:end` };
29168
29195
  }
29169
29196
  function upsertMarkedBlock(path6, source, block2, anchor) {
29170
- const { open: open7, close } = markerPair(path6);
29171
- const start3 = source.indexOf(open7);
29197
+ const { open: open8, close } = markerPair(path6);
29198
+ const start3 = source.indexOf(open8);
29172
29199
  const end2 = source.indexOf(close);
29173
29200
  if (start3 !== -1 && end2 !== -1 && end2 > start3) {
29174
- const existing = source.slice(start3 + open7.length, end2);
29201
+ const existing = source.slice(start3 + open8.length, end2);
29175
29202
  const next = `
29176
29203
  ${block2}
29177
29204
  `;
29178
29205
  if (existing === next)
29179
29206
  return { ok: true, source, changed: false };
29180
- return { ok: true, source: source.slice(0, start3 + open7.length) + next + source.slice(end2), changed: true };
29207
+ return { ok: true, source: source.slice(0, start3 + open8.length) + next + source.slice(end2), changed: true };
29181
29208
  }
29182
29209
  if (start3 !== -1 || end2 !== -1) {
29183
29210
  return { ok: false, why: `found only one of the ${MARKER} markers \u2014 remove the stray one by hand and re-run` };
@@ -29189,7 +29216,7 @@ ${block2}
29189
29216
  return { ok: false, why: "could not find where to insert \u2014 the file does not look like the shape we expected" };
29190
29217
  const at = m.index + m[0].length;
29191
29218
  return { ok: true, source: `${source.slice(0, at)}
29192
- ${open7}
29219
+ ${open8}
29193
29220
  ${block2}
29194
29221
  ${close}${source.slice(at)}`, changed: true };
29195
29222
  }
@@ -31045,6 +31072,19 @@ var init_work_ledger = __esm({
31045
31072
  * gone: what the barrier needs is the answer to "what happened to the thing I was waiting
31046
31073
  * for", asked after it stopped existing.
31047
31074
  */
31075
+ /**
31076
+ * Proof of life: the producer said something about this item (a progress frame, an
31077
+ * inventory that still lists it, a registry that still says running). Its deadline moves
31078
+ * out again, so a long-running job that keeps reporting is never mistaken for a hung one
31079
+ * and never swept while it is really working. Detached items have no deadline to move.
31080
+ */
31081
+ touch(id, now2) {
31082
+ const item = this.items.get(id);
31083
+ if (!item || item.disposition !== "awaited")
31084
+ return false;
31085
+ this.items.set(id, { ...item, deadline: now2 + DEFAULT_DEADLINE_MS[item.kind] });
31086
+ return true;
31087
+ }
31048
31088
  settle(id, outcome = "completed") {
31049
31089
  const had = this.items.delete(id);
31050
31090
  if (had) {
@@ -31123,6 +31163,10 @@ var init_work_ledger = __esm({
31123
31163
  for (const t of inv.tasks ?? []) {
31124
31164
  seen.add(t.id);
31125
31165
  const subagent = t.type === "subagent";
31166
+ if (this.items.has(t.id)) {
31167
+ this.touch(t.id, now2);
31168
+ continue;
31169
+ }
31126
31170
  this.register({
31127
31171
  id: t.id,
31128
31172
  kind: subagent ? "subagent" : "engine-task",
@@ -31165,7 +31209,7 @@ var init_work_ledger = __esm({
31165
31209
  else
31166
31210
  waiting.push(item);
31167
31211
  }
31168
- return { quiescent: waiting.length === 0, waiting, overdue, detached };
31212
+ return { quiescent: waiting.length === 0 && overdue.length === 0, waiting, overdue, detached };
31169
31213
  }
31170
31214
  /**
31171
31215
  * One line per item, for the grader and the closing report.
@@ -37093,14 +37137,72 @@ var init_cost_ledger = __esm({
37093
37137
  }
37094
37138
  });
37095
37139
 
37140
+ // ../../packages/agent-core/dist/session-activity.js
37141
+ import { open as open3 } from "node:fs/promises";
37142
+ function lastTimestampIn(chunk) {
37143
+ let last = null;
37144
+ const re = /"timestamp":"([^"]{10,40})"/g;
37145
+ let m;
37146
+ while ((m = re.exec(chunk)) !== null) {
37147
+ const t = Date.parse(m[1]);
37148
+ if (Number.isFinite(t))
37149
+ last = t;
37150
+ }
37151
+ return last;
37152
+ }
37153
+ async function lastConversationTime(file2) {
37154
+ let fh;
37155
+ try {
37156
+ fh = await open3(file2, "r");
37157
+ } catch {
37158
+ return null;
37159
+ }
37160
+ try {
37161
+ const size = (await fh.stat()).size;
37162
+ if (size === 0)
37163
+ return null;
37164
+ let end2 = size;
37165
+ let scanned = 0;
37166
+ while (end2 > 0 && scanned < ACTIVITY_MAX_SCAN_BYTES) {
37167
+ const start3 = Math.max(0, end2 - ACTIVITY_WINDOW_BYTES);
37168
+ const len = end2 - start3;
37169
+ const buf = Buffer.alloc(len);
37170
+ const { bytesRead } = await fh.read(buf, 0, len, start3);
37171
+ const found = lastTimestampIn(buf.subarray(0, bytesRead).toString("utf8"));
37172
+ if (found !== null)
37173
+ return found;
37174
+ scanned += len;
37175
+ end2 = start3 + OVERLAP > start3 ? Math.max(0, start3 + OVERLAP) : start3;
37176
+ if (start3 === 0)
37177
+ break;
37178
+ }
37179
+ return null;
37180
+ } catch {
37181
+ return null;
37182
+ } finally {
37183
+ await fh.close().catch(() => {
37184
+ });
37185
+ }
37186
+ }
37187
+ var ACTIVITY_WINDOW_BYTES, ACTIVITY_MAX_SCAN_BYTES, OVERLAP;
37188
+ var init_session_activity = __esm({
37189
+ "../../packages/agent-core/dist/session-activity.js"() {
37190
+ "use strict";
37191
+ ACTIVITY_WINDOW_BYTES = 64 * 1024;
37192
+ ACTIVITY_MAX_SCAN_BYTES = 2 * 1024 * 1024;
37193
+ OVERLAP = 64;
37194
+ }
37195
+ });
37196
+
37096
37197
  // ../../packages/agent-core/dist/session-store.js
37097
37198
  import { readFile as readFile5, stat as stat2 } from "node:fs/promises";
37098
37199
  import { listSessions, getSessionMessages, getSubagentMessages as sdkGetSubagentMessages, forkSession } from "@anthropic-ai/claude-agent-sdk";
37099
- function toSessionInfo(s) {
37200
+ async function toSessionInfo(s) {
37100
37201
  const fromFirst = stripPromptPrefix(s.firstPrompt ?? "").slice(0, 80);
37101
37202
  const fromSummary = stripPromptPrefix(s.summary ?? "").slice(0, 80);
37102
37203
  const title = s.customTitle || fromFirst || fromSummary || `Session ${s.sessionId.slice(0, 8)}`;
37103
- return { id: s.sessionId, title, lastModified: s.lastModified, cwd: s.cwd };
37204
+ const spoken = s.cwd ? await lastConversationTime(sessionFile(s.cwd, s.sessionId)) : null;
37205
+ return { id: s.sessionId, title, lastModified: spoken ?? s.lastModified, cwd: s.cwd };
37104
37206
  }
37105
37207
  function transcriptMatches(raw, q) {
37106
37208
  for (const line of raw.split("\n")) {
@@ -37220,12 +37322,14 @@ ${input.command}
37220
37322
  }
37221
37323
  return blocks;
37222
37324
  }
37223
- var SEARCH_SCAN_LIMIT, SEARCH_RESULT_LIMIT, SEARCH_MAX_FILE_BYTES, FORK_RETRY_ATTEMPTS, FORK_RETRY_DELAY_MS, delay, SessionStore;
37325
+ var newestFirst, SEARCH_SCAN_LIMIT, SEARCH_RESULT_LIMIT, SEARCH_MAX_FILE_BYTES, FORK_RETRY_ATTEMPTS, FORK_RETRY_DELAY_MS, delay, SessionStore;
37224
37326
  var init_session_store = __esm({
37225
37327
  "../../packages/agent-core/dist/session-store.js"() {
37226
37328
  "use strict";
37227
37329
  init_session_transfer();
37228
37330
  init_history_slim();
37331
+ init_session_activity();
37332
+ newestFirst = (a, b) => b.lastModified - a.lastModified;
37229
37333
  SEARCH_SCAN_LIMIT = 200;
37230
37334
  SEARCH_RESULT_LIMIT = 50;
37231
37335
  SEARCH_MAX_FILE_BYTES = 8 * 1024 * 1024;
@@ -37239,7 +37343,7 @@ var init_session_store = __esm({
37239
37343
  async getSessions(projectDir) {
37240
37344
  try {
37241
37345
  const sessions3 = projectDir ? await listSessions({ dir: projectDir, limit: 50 }) : await listSessions({ limit: 50 });
37242
- return sessions3.map(toSessionInfo);
37346
+ return (await Promise.all(sessions3.map(toSessionInfo))).sort(newestFirst);
37243
37347
  } catch (err2) {
37244
37348
  return [];
37245
37349
  }
@@ -37260,7 +37364,7 @@ var init_session_store = __esm({
37260
37364
  }
37261
37365
  const out = [];
37262
37366
  for (const s of sessions3) {
37263
- const info = toSessionInfo(s);
37367
+ const info = await toSessionInfo(s);
37264
37368
  if (info.title.toLowerCase().includes(q)) {
37265
37369
  out.push(info);
37266
37370
  } else if (s.cwd) {
@@ -37278,7 +37382,7 @@ var init_session_store = __esm({
37278
37382
  if (out.length >= SEARCH_RESULT_LIMIT)
37279
37383
  break;
37280
37384
  }
37281
- return out;
37385
+ return out.sort(newestFirst);
37282
37386
  }
37283
37387
  async getSessionMessages(sessionId, projectDir) {
37284
37388
  try {
@@ -37308,6 +37412,7 @@ var init_session_store = __esm({
37308
37412
  rawToMessages(raw) {
37309
37413
  const messages = [];
37310
37414
  for (const entry of raw) {
37415
+ const ts = typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
37311
37416
  const blocks = extractBlocks(entry.message);
37312
37417
  if (blocks.length === 0 && entry.type === "user")
37313
37418
  continue;
@@ -37323,7 +37428,8 @@ var init_session_store = __esm({
37323
37428
  blocks: entry.type === "assistant" ? blocks : void 0,
37324
37429
  // Thread the per-message SDK uuid so the renderer can pass it as
37325
37430
  // session:fork.upToMessageId ("fork from here").
37326
- uuid: typeof entry.uuid === "string" ? entry.uuid : void 0
37431
+ uuid: typeof entry.uuid === "string" ? entry.uuid : void 0,
37432
+ ...Number.isFinite(ts) ? { timestamp: ts } : {}
37327
37433
  });
37328
37434
  }
37329
37435
  return messages;
@@ -37923,6 +38029,9 @@ function setBrowserExtensionProbe(fn) {
37923
38029
  function isTurnBearingFrame(type) {
37924
38030
  return type === "assistant" || type === "stream_event" || type === "user";
37925
38031
  }
38032
+ function turnStillOpening(openedAt, now2) {
38033
+ return openedAt !== void 0 && now2 - openedAt < TURN_OPENING_GRACE_MS;
38034
+ }
37926
38035
  function findUserInstalledClaude(binName) {
37927
38036
  const home = homedir3();
37928
38037
  const abs = [
@@ -38814,7 +38923,7 @@ ${next}` : next;
38814
38923
  function autoDecisionSubject(prompt2) {
38815
38924
  return prompt2.kind === "permission" ? prompt2.tool : void 0;
38816
38925
  }
38817
- var browserExtensionConnected, SLIM_KEEP_RECENT_TURNS, cachedClaudeExe, unsupportedCliOptions, rejectedCliArgs, CAPS_VERSION, capsLoaded, EFFORT_LADDER, cachedEfforts, modelEffortLevels, sharedSessionStore, monoNowMs, sessionCwdCache, cachedNodeExe, HUMAN_READABLE_FIELDS, SYSTEM_EVENT_CATEGORY, TOOL_RESULT_CAP, MAX_RESULT_IMAGES, MAX_IMAGE_BASE64, PERMISSION_MODES, EDIT_PREVIEW_CAP, AsyncMessagePump, IDLE_REAP_MS, EFFORT_SWAP_DEBOUNCE_MS, MODERATE_IDLE_MS, STEER_COALESCE_MS, AUTO_BACKGROUND_SECONDS, TASK_REGISTER_SECONDS, JOB_NOTICE_COALESCE_MS, JOB_NOTICE_WORK_ID, QUIESCENCE_MAX_MS, QUIESCENCE_POLL_MS, BATCH_WAIT_MS, INLINE_TOOL_NAMES, STOP_HARD_KILL_AFTER_MS, STREAM_STALL_MS, STREAM_FIRST_FRAME_MS, RV_TASK_MAX, OPTION_RATING_JSON_SCHEMA, AgentManager;
38926
+ var browserExtensionConnected, TURN_OPENING_GRACE_MS, SLIM_KEEP_RECENT_TURNS, cachedClaudeExe, unsupportedCliOptions, rejectedCliArgs, CAPS_VERSION, capsLoaded, EFFORT_LADDER, cachedEfforts, modelEffortLevels, sharedSessionStore, monoNowMs, sessionCwdCache, cachedNodeExe, HUMAN_READABLE_FIELDS, SYSTEM_EVENT_CATEGORY, TOOL_RESULT_CAP, MAX_RESULT_IMAGES, MAX_IMAGE_BASE64, PERMISSION_MODES, EDIT_PREVIEW_CAP, AsyncMessagePump, IDLE_REAP_MS, EFFORT_SWAP_DEBOUNCE_MS, MODERATE_IDLE_MS, STEER_COALESCE_MS, AUTO_BACKGROUND_SECONDS, TASK_REGISTER_SECONDS, JOB_NOTICE_COALESCE_MS, JOB_NOTICE_WORK_ID, QUIESCENCE_MAX_MS, QUIESCENCE_POLL_MS, BATCH_WAIT_MS, INLINE_TOOL_NAMES, STOP_HARD_KILL_AFTER_MS, STREAM_STALL_MS, STREAM_FIRST_FRAME_MS, RV_TASK_MAX, OPTION_RATING_JSON_SCHEMA, AgentManager;
38818
38927
  var init_agent_manager = __esm({
38819
38928
  "../../packages/agent-core/dist/agent-manager.js"() {
38820
38929
  "use strict";
@@ -38874,6 +38983,7 @@ var init_agent_manager = __esm({
38874
38983
  init_stream_stall();
38875
38984
  init_usage_limit();
38876
38985
  browserExtensionConnected = () => false;
38986
+ TURN_OPENING_GRACE_MS = 5 * 6e4;
38877
38987
  SLIM_KEEP_RECENT_TURNS = 3;
38878
38988
  unsupportedCliOptions = /* @__PURE__ */ new Set();
38879
38989
  rejectedCliArgs = /* @__PURE__ */ new Map();
@@ -38944,7 +39054,7 @@ var init_agent_manager = __esm({
38944
39054
  TASK_REGISTER_SECONDS = 3;
38945
39055
  JOB_NOTICE_COALESCE_MS = 400;
38946
39056
  JOB_NOTICE_WORK_ID = "pending-job-notices";
38947
- QUIESCENCE_MAX_MS = 20 * 6e4;
39057
+ QUIESCENCE_MAX_MS = 12 * 60 * 6e4;
38948
39058
  QUIESCENCE_POLL_MS = 500;
38949
39059
  BATCH_WAIT_MS = 6e4;
38950
39060
  INLINE_TOOL_NAMES = /* @__PURE__ */ new Set([
@@ -40001,19 +40111,23 @@ ${full.slice(-8e3)}`;
40001
40111
  this.clearWorkNarration(live, narrated);
40002
40112
  return;
40003
40113
  }
40004
- const v = live.ledger.verdict(Date.now());
40114
+ const now2 = Date.now();
40115
+ live.ledger.sweep(now2);
40116
+ this.refreshLedgerFromRegistry(live, now2);
40117
+ const v = live.ledger.verdict(now2);
40005
40118
  if (v.quiescent)
40006
40119
  break;
40007
- if (Date.now() - started2 >= QUIESCENCE_MAX_MS) {
40120
+ if (now2 - started2 >= QUIESCENCE_MAX_MS) {
40008
40121
  cappedOut = true;
40009
40122
  break;
40010
40123
  }
40011
40124
  if (!narrated && live.sessionId) {
40012
40125
  narrated = true;
40126
+ const running2 = v.waiting.length + v.overdue.length;
40013
40127
  this.send({
40014
40128
  type: "agent:narration",
40015
40129
  sessionId: live.sessionId,
40016
- text: `Waiting for ${v.waiting.length} background ${v.waiting.length === 1 ? "task" : "tasks"} to finish\u2026`,
40130
+ text: `Waiting for ${running2} background ${running2 === 1 ? "task" : "tasks"} to finish\u2026`,
40017
40131
  engineLabel: "Claude Code"
40018
40132
  }, live.origin);
40019
40133
  }
@@ -40044,6 +40158,7 @@ ${full.slice(-8e3)}`;
40044
40158
  log(`[turn] ${live.sessionId || "(pending)"} started a turn on its own \u2014 marking busy`);
40045
40159
  live.streaming = true;
40046
40160
  live.turnSeq++;
40161
+ live.turnOpeningAt = void 0;
40047
40162
  live.lastActivity = Date.now();
40048
40163
  if (live.idleTimer) {
40049
40164
  clearTimeout(live.idleTimer);
@@ -42584,6 +42699,8 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
42584
42699
  const parentToolUseId = message.parent_tool_use_id ?? void 0;
42585
42700
  if (!live.streaming && !live.reaped && isTurnBearingFrame(message.type))
42586
42701
  this.adoptSelfStartedTurn(live);
42702
+ if (!live.streaming && !live.reaped && (live.turnsDone ?? 0) > 0 && message.type === "system" && message.subtype === "init")
42703
+ live.turnOpeningAt = Date.now();
42587
42704
  switch (message.type) {
42588
42705
  case "stream_event": {
42589
42706
  const event = message.event;
@@ -42726,6 +42843,8 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
42726
42843
  }
42727
42844
  case "result": {
42728
42845
  this.emitLifecycle("Stop", { sessionId: sid, subtype: message.subtype ?? null });
42846
+ live.turnsDone = (live.turnsDone ?? 0) + 1;
42847
+ live.turnOpeningAt = void 0;
42729
42848
  flushPendingThinking();
42730
42849
  const r = message;
42731
42850
  const resultSid = r.session_id || "";
@@ -42935,6 +43054,7 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
42935
43054
  const taskId = sstr(m.task_id);
42936
43055
  if (!taskId)
42937
43056
  break;
43057
+ live.ledger.touch(taskId, Date.now());
42938
43058
  const u = m.usage;
42939
43059
  emit2({
42940
43060
  type: "agent:task",
@@ -42973,6 +43093,8 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
42973
43093
  if (status2 === "completed" || status2 === "failed" || status2 === "killed") {
42974
43094
  this.clearAutoBackground(live, taskId);
42975
43095
  live.taskIds.delete(taskId);
43096
+ } else {
43097
+ live.ledger.touch(taskId, Date.now());
42976
43098
  }
42977
43099
  break;
42978
43100
  }
@@ -42984,6 +43106,8 @@ ${unattendedReportDirective(params)}` : ""), live.sessionId) },
42984
43106
  case "background_tasks_changed": {
42985
43107
  const listed = new Set((Array.isArray(m.tasks) ? m.tasks : []).map((t) => sstr(t?.task_id)).filter(Boolean));
42986
43108
  live.taskIds = listed;
43109
+ for (const id of listed)
43110
+ live.ledger.touch(id, Date.now());
42987
43111
  break;
42988
43112
  }
42989
43113
  case "task_notification": {
@@ -43526,7 +43650,7 @@ ${err2.stack}` : ""}` : String(err2);
43526
43650
  // Blocked on its own background work. A turn that dispatched a build emits nothing while
43527
43651
  // it waits, and that silence is the intended behaviour — not a dead stream. Reads the
43528
43652
  // ledger, so it goes false on its own once every awaited item has passed its deadline.
43529
- awaitingWork: live.ledger.verdict(Date.now()).waiting.length > 0,
43653
+ awaitingWork: !live.ledger.verdict(Date.now()).quiescent,
43530
43654
  idleMs: monoNowMs() - (live.lastFrameAt ?? 0),
43531
43655
  windowMs: live.stallWindowMs ?? STREAM_STALL_MS
43532
43656
  });
@@ -43717,7 +43841,8 @@ ${err2.stack}` : ""}` : String(err2);
43717
43841
  for (const id of [...claimed])
43718
43842
  if (!live.ledger.has(id))
43719
43843
  claimed.delete(id);
43720
- const watched = live.ledger.verdict(started2).waiting.filter((i) => !claimed.has(i.id)).map((i) => ({ id: i.id, description: i.description, kind: i.kind }));
43844
+ const v0 = live.ledger.verdict(started2);
43845
+ const watched = [...v0.waiting, ...v0.overdue].filter((i) => !claimed.has(i.id)).map((i) => ({ id: i.id, description: i.description, kind: i.kind }));
43721
43846
  for (const w of watched)
43722
43847
  claimed.add(w.id);
43723
43848
  if (watched.length === 0)
@@ -44291,10 +44416,12 @@ ${lines.join("\n")}
44291
44416
  hasWorkInFlight(live) {
44292
44417
  if (live.gradePending)
44293
44418
  return true;
44419
+ if (turnStillOpening(live.turnOpeningAt, Date.now()))
44420
+ return true;
44294
44421
  if ((live.awaitDepth ?? 0) > 0)
44295
44422
  return true;
44296
44423
  try {
44297
- if (live.ledger.verdict(Date.now()).waiting.length > 0)
44424
+ if (!live.ledger.verdict(Date.now()).quiescent)
44298
44425
  return true;
44299
44426
  } catch {
44300
44427
  }
@@ -44305,6 +44432,24 @@ ${lines.join("\n")}
44305
44432
  }
44306
44433
  return false;
44307
44434
  }
44435
+ /** The job registry is the authority on daemon-owned jobs: anything it still reports as
44436
+ * running is alive, whatever the ledger's deadline says — touch it (or put it back if a
44437
+ * sweep already took it). */
44438
+ refreshLedgerFromRegistry(live, now2) {
44439
+ let jobs;
44440
+ try {
44441
+ jobs = live.jobs?.list() ?? [];
44442
+ } catch {
44443
+ return;
44444
+ }
44445
+ for (const j of jobs) {
44446
+ if (j.status !== "running")
44447
+ continue;
44448
+ if (!live.ledger.touch(j.id, now2)) {
44449
+ live.ledger.register({ id: j.id, kind: "tool-job", description: `${j.kind ?? "job"}: ${j.description ?? j.id}` }, now2);
44450
+ }
44451
+ }
44452
+ }
44308
44453
  reapIdleSession(sessionId, force = false) {
44309
44454
  const live = this.liveSessions.get(sessionId);
44310
44455
  if (!live || live.streaming || live.reaped)
@@ -81321,8 +81466,8 @@ var mesh_ca_exports = {};
81321
81466
  __export(mesh_ca_exports, {
81322
81467
  netCaCommand: () => netCaCommand
81323
81468
  });
81324
- import { chmodSync as chmodSync8, existsSync as existsSync49, mkdirSync as mkdirSync45, readFileSync as readFileSync54, writeFileSync as writeFileSync46 } from "node:fs";
81325
- import { join as join87, resolve as resolve13 } from "node:path";
81469
+ import { chmodSync as chmodSync8, existsSync as existsSync50, mkdirSync as mkdirSync46, readFileSync as readFileSync55, writeFileSync as writeFileSync47 } from "node:fs";
81470
+ import { join as join88, resolve as resolve13 } from "node:path";
81326
81471
  import { createInterface as createInterface2 } from "node:readline";
81327
81472
  function die(msg) {
81328
81473
  console.error(msg);
@@ -81353,28 +81498,28 @@ async function readPassphrase(prompt2) {
81353
81498
  }
81354
81499
  }
81355
81500
  function writeSecretFile(p, bytes2) {
81356
- writeFileSync46(p, bytes2, { mode: 384 });
81501
+ writeFileSync47(p, bytes2, { mode: 384 });
81357
81502
  try {
81358
81503
  chmodSync8(p, 384);
81359
81504
  } catch {
81360
81505
  }
81361
81506
  }
81362
81507
  function ensureDir(p) {
81363
- mkdirSync45(p, { recursive: true, mode: 448 });
81508
+ mkdirSync46(p, { recursive: true, mode: 448 });
81364
81509
  try {
81365
81510
  chmodSync8(p, 448);
81366
81511
  } catch {
81367
81512
  }
81368
81513
  }
81369
81514
  async function openCa(dir2) {
81370
- const gPath = join87(dir2, "genesis.bin");
81371
- const sPath = join87(dir2, "ca.sealed");
81372
- if (!existsSync49(gPath) || !existsSync49(sPath)) {
81515
+ const gPath = join88(dir2, "genesis.bin");
81516
+ const sPath = join88(dir2, "ca.sealed");
81517
+ if (!existsSync50(gPath) || !existsSync50(sPath)) {
81373
81518
  die(`No mesh CA in ${dir2}. Run: tesseract-agent net init --org NAME --ca-dir ${dir2}`);
81374
81519
  }
81375
- const genesisBytes = new Uint8Array(readFileSync54(gPath));
81520
+ const genesisBytes = new Uint8Array(readFileSync55(gPath));
81376
81521
  const genesis = decodeGenesis(genesisBytes);
81377
- const sealed = decodeRecoveryBundle(new Uint8Array(readFileSync54(sPath)));
81522
+ const sealed = decodeRecoveryBundle(new Uint8Array(readFileSync55(sPath)));
81378
81523
  const pass = await readPassphrase("CA passphrase: ");
81379
81524
  let seed;
81380
81525
  try {
@@ -81390,7 +81535,7 @@ async function netCaCommand(rest, flags) {
81390
81535
  if (sub === "init") {
81391
81536
  const org = typeof flags.org === "string" ? flags.org.trim() : "";
81392
81537
  if (!org) die("Usage: tesseract-agent net init --org NAME [--ca-dir DIR]");
81393
- if (existsSync49(join87(caDir, "ca.sealed"))) {
81538
+ if (existsSync50(join88(caDir, "ca.sealed"))) {
81394
81539
  die(`A mesh CA already exists in ${caDir}. Refusing to overwrite it.`);
81395
81540
  }
81396
81541
  const pass = await readPassphrase("New CA passphrase: ");
@@ -81412,9 +81557,9 @@ async function netCaCommand(rest, flags) {
81412
81557
  const genesisBytes = encodeGenesis(genesis);
81413
81558
  const fp = await genesisFingerprint(genesis);
81414
81559
  ensureDir(caDir);
81415
- writeFileSync46(join87(caDir, "genesis.bin"), genesisBytes);
81416
- writeSecretFile(join87(caDir, "ca.sealed"), encodeRecoveryBundle(await sealCaKey(seed, pass, `${org} mesh CA`)));
81417
- writeSecretFile(join87(caDir, "disablement.secret"), hex3(disable.secret));
81560
+ writeFileSync47(join88(caDir, "genesis.bin"), genesisBytes);
81561
+ writeSecretFile(join88(caDir, "ca.sealed"), encodeRecoveryBundle(await sealCaKey(seed, pass, `${org} mesh CA`)));
81562
+ writeSecretFile(join88(caDir, "disablement.secret"), hex3(disable.secret));
81418
81563
  console.log(`
81419
81564
  Mesh created for "${org}".`);
81420
81565
  console.log(` fingerprint: ${hex3(fp)}`);
@@ -81429,7 +81574,7 @@ Mesh created for "${org}".`);
81429
81574
  console.log(` ${hex3(disable.secret)}`);
81430
81575
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
81431
81576
  console.log(`
81432
- A copy of the disablement secret is in ${join87(caDir, "disablement.secret")}.`);
81577
+ A copy of the disablement secret is in ${join88(caDir, "disablement.secret")}.`);
81433
81578
  console.log("Move it somewhere the CA directory is not \u2014 holding both in one place");
81434
81579
  console.log("defeats the point of having two.");
81435
81580
  const caFlag = caDir === resolve13("./mesh-ca") ? "" : ` --ca-dir ${caDir}`;
@@ -81482,14 +81627,14 @@ Next, issue an identity for a machine (pick a free address in ${formatPrefix(gen
81482
81627
  [{ keyIndex: 0, privateKey: ca.privateKey }]
81483
81628
  );
81484
81629
  ensureDir(outDir);
81485
- writeFileSync46(join87(outDir, "genesis.bin"), genesisBytes);
81486
- writeFileSync46(join87(outDir, "node.cert"), encodeCert(cert));
81487
- writeSecretFile(join87(outDir, "node.key"), await exportStaticPrivate(nodeKey));
81630
+ writeFileSync47(join88(outDir, "genesis.bin"), genesisBytes);
81631
+ writeFileSync47(join88(outDir, "node.cert"), encodeCert(cert));
81632
+ writeSecretFile(join88(outDir, "node.key"), await exportStaticPrivate(nodeKey));
81488
81633
  console.log(`Minted "${name}" at ${ip4}.`);
81489
81634
  console.log(` ${outDir}`);
81490
81635
  console.log("\nCopy that directory to the node and run there:");
81491
- console.log(` tesseract-agent net enroll --genesis ${join87(outDir, "genesis.bin")} \\`);
81492
- console.log(` --cert ${join87(outDir, "node.cert")} --key ${join87(outDir, "node.key")}`);
81636
+ console.log(` tesseract-agent net enroll --genesis ${join88(outDir, "genesis.bin")} \\`);
81637
+ console.log(` --cert ${join88(outDir, "node.cert")} --key ${join88(outDir, "node.key")}`);
81493
81638
  console.log("\nnode.key is the node's identity \u2014 send it over a channel you trust, and");
81494
81639
  console.log("delete this copy once the node has it.");
81495
81640
  return;
@@ -81525,8 +81670,8 @@ Next, issue an identity for a machine (pick a free address in ${formatPrefix(gen
81525
81670
  ip4Exceptions: []
81526
81671
  };
81527
81672
  const signed = await signBundle(bundle, [{ keyIndex: 0, privateKey: ca.privateKey }]);
81528
- const out = resolve13(typeof flags.out === "string" ? flags.out : join87(caDir, "bundle.bin"));
81529
- writeFileSync46(out, encodeSignedBundle(signed));
81673
+ const out = resolve13(typeof flags.out === "string" ? flags.out : join88(caDir, "bundle.bin"));
81674
+ writeFileSync47(out, encodeSignedBundle(signed));
81530
81675
  console.log(`Signed policy bundle (epoch ${epoch2}) \u2192 ${out}`);
81531
81676
  console.log("Every node must receive it; the relay distributes it, or copy it to");
81532
81677
  console.log(`each node's mesh directory as bundle.bin.`);
@@ -81548,17 +81693,43 @@ var init_mesh_ca = __esm({
81548
81693
 
81549
81694
  // src/cli.ts
81550
81695
  init_base_paths();
81551
- import { existsSync as existsSync50, mkdtempSync as mkdtempSync4, readFileSync as readFileSync56, rmSync as rmSync13 } from "node:fs";
81696
+ import { existsSync as existsSync51, mkdtempSync as mkdtempSync4, readFileSync as readFileSync57, rmSync as rmSync13 } from "node:fs";
81552
81697
  import { createHash as createHash9 } from "node:crypto";
81553
81698
  import { execFileSync as execFileSync6, spawn as spawn14 } from "node:child_process";
81554
81699
  import { fileURLToPath as fileURLToPath8 } from "node:url";
81555
81700
  import { tmpdir as tmpdir8 } from "node:os";
81556
- import { dirname as dirname40, join as join88, resolve as resolve15 } from "node:path";
81701
+ import { dirname as dirname41, join as join89, resolve as resolve15 } from "node:path";
81557
81702
  import { createInterface as createInterface3 } from "node:readline/promises";
81558
81703
 
81559
81704
  // ../../packages/host-core/dist/control-link.js
81560
81705
  import { hostname as hostname4 } from "node:os";
81561
81706
 
81707
+ // ../../packages/host-core/dist/hook-fanout.js
81708
+ function composeHooks(sets, onError) {
81709
+ return new Proxy({}, {
81710
+ get(_target, key2) {
81711
+ if (typeof key2 !== "string")
81712
+ return void 0;
81713
+ const fns = sets.map((s) => s[key2]).filter((f) => typeof f === "function");
81714
+ if (fns.length === 0)
81715
+ return void 0;
81716
+ const owners = sets.filter((s) => typeof s[key2] === "function");
81717
+ return (...args) => {
81718
+ for (let i = 0; i < fns.length; i++) {
81719
+ try {
81720
+ fns[i].apply(owners[i], args);
81721
+ } catch (err2) {
81722
+ onError?.(key2, err2);
81723
+ }
81724
+ }
81725
+ };
81726
+ },
81727
+ has(_target, key2) {
81728
+ return typeof key2 === "string" && sets.some((s) => typeof s[key2] === "function");
81729
+ }
81730
+ });
81731
+ }
81732
+
81562
81733
  // ../../packages/host-core/dist/engines/rewind-result.js
81563
81734
  var strings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string" && x.length > 0) : [];
81564
81735
  function toRewindOutcome(res, noHistory) {
@@ -84817,21 +84988,21 @@ function createMcpHealth(deps = {}) {
84817
84988
  let servers = {};
84818
84989
  const disabled2 = /* @__PURE__ */ new Set();
84819
84990
  const cache5 = /* @__PURE__ */ new Map();
84820
- const inflight = /* @__PURE__ */ new Map();
84991
+ const inflight2 = /* @__PURE__ */ new Map();
84821
84992
  async function probeCached(name, spec) {
84822
84993
  const hit = cache5.get(name);
84823
84994
  if (hit && now2() - hit.at < TTL_MS3)
84824
84995
  return hit.row;
84825
- const running2 = inflight.get(name);
84996
+ const running2 = inflight2.get(name);
84826
84997
  if (running2)
84827
84998
  return running2;
84828
84999
  const p = probe(name, spec).catch((e) => ({ name, status: "failed", error: e?.message ?? "probe failed" })).then((row) => {
84829
85000
  const full = { ...row, name };
84830
85001
  cache5.set(name, { at: now2(), row: full });
84831
- inflight.delete(name);
85002
+ inflight2.delete(name);
84832
85003
  return full;
84833
85004
  });
84834
- inflight.set(name, p);
85005
+ inflight2.set(name, p);
84835
85006
  return p;
84836
85007
  }
84837
85008
  return {
@@ -84851,7 +85022,7 @@ function createMcpHealth(deps = {}) {
84851
85022
  },
84852
85023
  async reconnect(name) {
84853
85024
  cache5.delete(name);
84854
- inflight.delete(name);
85025
+ inflight2.delete(name);
84855
85026
  if (servers[name] && !disabled2.has(name))
84856
85027
  await probeCached(name, servers[name]);
84857
85028
  },
@@ -84994,10 +85165,10 @@ function extractJson(text12) {
84994
85165
  }
84995
85166
  }
84996
85167
  for (let start3 = 0; start3 < text12.length; start3++) {
84997
- const open7 = text12[start3];
84998
- if (open7 !== "{" && open7 !== "[")
85168
+ const open8 = text12[start3];
85169
+ if (open8 !== "{" && open8 !== "[")
84999
85170
  continue;
85000
- const close = open7 === "{" ? "}" : "]";
85171
+ const close = open8 === "{" ? "}" : "]";
85001
85172
  let depth = 0;
85002
85173
  let inStr = false;
85003
85174
  let esc3 = false;
@@ -85016,7 +85187,7 @@ function extractJson(text12) {
85016
85187
  inStr = true;
85017
85188
  continue;
85018
85189
  }
85019
- if (ch === open7)
85190
+ if (ch === open8)
85020
85191
  depth++;
85021
85192
  else if (ch === close) {
85022
85193
  depth--;
@@ -90282,7 +90453,6 @@ var LAUNCH_MARKERS = [
90282
90453
  "CCB_FORCE_DAEMON_GUI",
90283
90454
  "CCB_HOST_DAEMON",
90284
90455
  "CCB_RDESK_ROLE",
90285
- "CCB_RDESK_SERVER",
90286
90456
  "CCB_RDESK_CLIENT",
90287
90457
  "CCB_RDESK_ONLY",
90288
90458
  "CCB_MESH_APP",
@@ -90297,7 +90467,7 @@ function mainAppChildEnv(env) {
90297
90467
  return out;
90298
90468
  }
90299
90469
  function ownBinaryIsMainApp(env) {
90300
- return !env.CCB_RDESK_ROLE && env.CCB_RDESK_SERVER !== "1" && env.CCB_RDESK_CLIENT !== "1" && env.CCB_MESH_APP !== "1";
90470
+ return !env.CCB_RDESK_ROLE && env.CCB_RDESK_CLIENT !== "1" && env.CCB_MESH_APP !== "1";
90301
90471
  }
90302
90472
 
90303
90473
  // ../../packages/host-core/dist/gui/dock-policy.js
@@ -91224,11 +91394,11 @@ var GUIDE_TOOLS = describedBy("tool.voice-guide", GUIDE_TOOL_SHAPES);
91224
91394
  var defaultGreeting = () => prompt("voice.greeting");
91225
91395
  function buildGuidePrompt(opts = {}) {
91226
91396
  const project = opts.projectName ? prompt("voice.guide.project-clause", { projectName: opts.projectName }) : "";
91227
- const open7 = (opts.sessions ?? []).map((s) => s.label?.trim()).filter((l) => !!l);
91228
- const openLine = open7.length > 0 ? prompt("voice.guide.open-sessions", {
91229
- count: open7.length,
91230
- plural: open7.length === 1 ? "" : "s",
91231
- labels: open7.map((l) => `"${l}"`).join(", "),
91397
+ const open8 = (opts.sessions ?? []).map((s) => s.label?.trim()).filter((l) => !!l);
91398
+ const openLine = open8.length > 0 ? prompt("voice.guide.open-sessions", {
91399
+ count: open8.length,
91400
+ plural: open8.length === 1 ? "" : "s",
91401
+ labels: open8.map((l) => `"${l}"`).join(", "),
91232
91402
  toolStatus: TOOL_STATUS
91233
91403
  }) : "";
91234
91404
  return [
@@ -95868,8 +96038,8 @@ async function falTopazEnhance(path6, spec, opts) {
95868
96038
  const dir2 = opts.outDir ?? workDir();
95869
96039
  mkdirSync22(dir2, { recursive: true });
95870
96040
  const outPath = join43(dir2, "enhanced.mp4");
95871
- const { writeFileSync: writeFileSync47 } = await import("node:fs");
95872
- writeFileSync47(outPath, Buffer.from(await dl.arrayBuffer()));
96041
+ const { writeFileSync: writeFileSync48 } = await import("node:fs");
96042
+ writeFileSync48(outPath, Buffer.from(await dl.arrayBuffer()));
95873
96043
  const out = await probeMedia(outPath).catch(() => null);
95874
96044
  opts.onProgress?.(100, "Enhance complete");
95875
96045
  return { path: outPath, mime: MIME, width: out?.width ?? null, height: out?.height ?? null, durationSec: out?.durationSec ?? p.durationSec, summary: `fal Topaz ${spec.model ?? "Proteus"} \xD7${spec.upscaleFactor ?? 2}` };
@@ -99984,7 +100154,7 @@ init_credentials();
99984
100154
  init_credentials();
99985
100155
  import { hostname as hostname3, platform } from "node:os";
99986
100156
  import { randomUUID as randomUUID23 } from "node:crypto";
99987
- import { chmodSync as chmodSync3, existsSync as existsSync23, mkdirSync as mkdirSync26, readFileSync as readFileSync36, writeFileSync as writeFileSync24 } from "node:fs";
100157
+ import { chmodSync as chmodSync3, existsSync as existsSync23, mkdirSync as mkdirSync26, readFileSync as readFileSync36, statSync as statSync14, unlinkSync as unlinkSync3, writeFileSync as writeFileSync24 } from "node:fs";
99988
100158
  import { join as join53 } from "node:path";
99989
100159
  var FILE = () => join53(daemonDir2(), "machine-identity.json");
99990
100160
  function readMachineIdentity() {
@@ -100024,25 +100194,88 @@ function tokenUsable(m) {
100024
100194
  const ms = Date.parse(m.expiresAt);
100025
100195
  return Number.isFinite(ms) && ms - Date.now() > 24 * 60 * 60 * 1e3;
100026
100196
  }
100197
+ var inflight = null;
100027
100198
  async function ensureMachineIdentity(opts) {
100199
+ if (inflight)
100200
+ return inflight;
100201
+ inflight = ensureMachineIdentityOnce(opts).finally(() => {
100202
+ inflight = null;
100203
+ });
100204
+ return inflight;
100205
+ }
100206
+ var LOCK = () => join53(daemonDir2(), "machine-identity.lock");
100207
+ var LOCK_STALE_MS = 3e4;
100208
+ function tryRegistrationLock() {
100209
+ const f = LOCK();
100210
+ for (let attempt = 0; attempt < 2; attempt++) {
100211
+ try {
100212
+ mkdirSync26(daemonDir2(), { recursive: true, mode: 448 });
100213
+ writeFileSync24(f, String(process.pid), { flag: "wx" });
100214
+ return true;
100215
+ } catch {
100216
+ try {
100217
+ if (Date.now() - statSync14(f).mtimeMs < LOCK_STALE_MS)
100218
+ return false;
100219
+ unlinkSync3(f);
100220
+ } catch {
100221
+ return false;
100222
+ }
100223
+ }
100224
+ }
100225
+ return false;
100226
+ }
100227
+ function releaseRegistrationLock() {
100228
+ try {
100229
+ unlinkSync3(LOCK());
100230
+ } catch {
100231
+ }
100232
+ }
100233
+ async function waitForIdentity(ms) {
100234
+ const until = Date.now() + ms;
100235
+ while (Date.now() < until) {
100236
+ await new Promise((r) => setTimeout(r, 250));
100237
+ const m = readMachineIdentity();
100238
+ if (m)
100239
+ return m;
100240
+ }
100241
+ return null;
100242
+ }
100243
+ async function ensureMachineIdentityOnce(opts) {
100028
100244
  const { apiOrigin: apiOrigin2, backendOrigin: backendOrigin2, isAllowedOrigin: isAllowedOrigin3, log: log9 } = opts;
100029
100245
  if (!isAllowedOrigin3(apiOrigin2)) {
100030
100246
  log9?.(`machine identity: refusing a non-default server: ${apiOrigin2}`);
100031
100247
  return null;
100032
100248
  }
100033
100249
  let m = readMachineIdentity();
100250
+ if (m && opts.deviceId)
100251
+ m = adoptPersistentDeviceId(opts.deviceId, log9).identity ?? m;
100034
100252
  try {
100035
100253
  if (!m) {
100036
- const reg = await postJson(`${apiOrigin2}/api/core/tesseract/identity/device`, { label: hostname3().slice(0, 120), platform: platform() });
100037
- m = {
100038
- deviceToken: reg.token,
100039
- publicId: reg.publicId,
100040
- deviceId: randomUUID23().slice(0, 8),
100041
- apiOrigin: apiOrigin2,
100042
- backendOrigin: backendOrigin2
100043
- };
100044
- write(m);
100045
- log9?.(`machine identity: registered \u2014 this machine can be reached as ${reg.publicId}`);
100254
+ if (!tryRegistrationLock()) {
100255
+ m = await waitForIdentity(1e4);
100256
+ if (!m) {
100257
+ log9?.("machine identity: another process is registering this machine \u2014 will use its identity on the next tick");
100258
+ return null;
100259
+ }
100260
+ } else {
100261
+ try {
100262
+ m = readMachineIdentity();
100263
+ if (!m) {
100264
+ const reg = await postJson(`${apiOrigin2}/api/core/tesseract/identity/device`, { label: hostname3().slice(0, 120), platform: platform() });
100265
+ m = {
100266
+ deviceToken: reg.token,
100267
+ publicId: reg.publicId,
100268
+ deviceId: opts.deviceId ?? randomUUID23().slice(0, 8),
100269
+ apiOrigin: apiOrigin2,
100270
+ backendOrigin: backendOrigin2
100271
+ };
100272
+ write(m);
100273
+ log9?.(`machine identity: registered \u2014 this machine can be reached as ${reg.publicId}`);
100274
+ }
100275
+ } finally {
100276
+ releaseRegistrationLock();
100277
+ }
100278
+ }
100046
100279
  }
100047
100280
  if (!tokenUsable(m)) {
100048
100281
  const t = await postJson(`${apiOrigin2}/auth/device/relay-token`, { deviceToken: m.deviceToken, deviceId: m.deviceId });
@@ -100056,6 +100289,18 @@ async function ensureMachineIdentity(opts) {
100056
100289
  return m && tokenUsable(m) ? m : null;
100057
100290
  }
100058
100291
  }
100292
+ function adoptPersistentDeviceId(deviceId3, log9) {
100293
+ const m = readMachineIdentity();
100294
+ if (!m || !deviceId3 || m.deviceId === deviceId3)
100295
+ return { identity: m, migratedFrom: null };
100296
+ const old = m.deviceId;
100297
+ const next = { ...m, deviceId: deviceId3 };
100298
+ delete next.accessToken;
100299
+ delete next.expiresAt;
100300
+ write(next);
100301
+ log9?.(`machine identity: device id ${old} \u2192 ${deviceId3} (the id this computer has whether signed in or not)`);
100302
+ return { identity: next, migratedFrom: old };
100303
+ }
100059
100304
 
100060
100305
  // ../../packages/host-core/dist/rdesk/server-auth.js
100061
100306
  var DEFAULT_API = (process.env.CCB_TESSERACT_API ?? "https://app.tesseract.dev").replace(/\/$/, "");
@@ -100099,7 +100344,7 @@ import { dirname as dirname27, join as join58, resolve as resolve11 } from "node
100099
100344
  // ../../packages/host-core/dist/active-link/blocks.js
100100
100345
  import { createHash as createHash5 } from "node:crypto";
100101
100346
  import { createReadStream as createReadStream2 } from "node:fs";
100102
- import { open as open3, mkdir as mkdir12, rename as rename2, chmod as chmod2, utimes, unlink } from "node:fs/promises";
100347
+ import { open as open4, mkdir as mkdir12, rename as rename2, chmod as chmod2, utimes, unlink } from "node:fs/promises";
100103
100348
  import { dirname as dirname24 } from "node:path";
100104
100349
  var CHUNK3 = 1024 * 1024;
100105
100350
  var MAX_INFLIGHT2 = 8 * CHUNK3;
@@ -100229,7 +100474,7 @@ var StagingWriter = class {
100229
100474
  async ensureOpen() {
100230
100475
  if (!this.fh) {
100231
100476
  await mkdir12(dirname24(this.stagingPath), { recursive: true });
100232
- this.fh = await open3(this.stagingPath, "w");
100477
+ this.fh = await open4(this.stagingPath, "w");
100233
100478
  }
100234
100479
  return this.fh;
100235
100480
  }
@@ -100292,7 +100537,7 @@ var BlockAssembler = class {
100292
100537
  }
100293
100538
  async open() {
100294
100539
  await mkdir12(dirname24(this.stagingPath), { recursive: true });
100295
- this.fh = await open3(this.stagingPath, "w");
100540
+ this.fh = await open4(this.stagingPath, "w");
100296
100541
  }
100297
100542
  /** Write a received block at its byte offset (index * CHUNK). */
100298
100543
  async writeBlock(index, buf) {
@@ -100307,7 +100552,7 @@ var BlockAssembler = class {
100307
100552
  await this.open();
100308
100553
  let lf = null;
100309
100554
  try {
100310
- lf = await open3(localAbs, "r");
100555
+ lf = await open4(localAbs, "r");
100311
100556
  const buf = Buffer.alloc(len);
100312
100557
  const { bytesRead } = await lf.read(buf, 0, len, localOffset);
100313
100558
  if (bytesRead !== len)
@@ -100569,7 +100814,7 @@ async function gitSyncedFiles(root) {
100569
100814
 
100570
100815
  // ../../packages/host-core/dist/active-link/session.js
100571
100816
  import { createHash as createHash6 } from "node:crypto";
100572
- import { lstat as lstat4, readlink as readlink3, open as open4 } from "node:fs/promises";
100817
+ import { lstat as lstat4, readlink as readlink3, open as open5 } from "node:fs/promises";
100573
100818
  var OutboundSender = class {
100574
100819
  deps;
100575
100820
  queue = [];
@@ -100663,7 +100908,7 @@ var OutboundSender = class {
100663
100908
  const running2 = createHash6("sha256");
100664
100909
  let fh;
100665
100910
  try {
100666
- fh = await open4(abs, "r");
100911
+ fh = await open5(abs, "r");
100667
100912
  } catch {
100668
100913
  return;
100669
100914
  }
@@ -100734,7 +100979,7 @@ var OutboundSender = class {
100734
100979
  const mode = st.mode;
100735
100980
  let fh;
100736
100981
  try {
100737
- fh = await open4(abs, "r");
100982
+ fh = await open5(abs, "r");
100738
100983
  } catch {
100739
100984
  return;
100740
100985
  }
@@ -100995,7 +101240,7 @@ function readdirp(root, options = {}) {
100995
101240
 
100996
101241
  // ../../node_modules/chokidar/esm/handler.js
100997
101242
  import { watchFile, unwatchFile, watch as fs_watch } from "fs";
100998
- import { open as open5, stat as stat7, lstat as lstat6, realpath as fsrealpath } from "fs/promises";
101243
+ import { open as open6, stat as stat7, lstat as lstat6, realpath as fsrealpath } from "fs/promises";
100999
101244
  import * as sysPath from "path";
101000
101245
  import { type as osType } from "os";
101001
101246
  var STR_DATA = "data";
@@ -101379,7 +101624,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
101379
101624
  cont.watcherUnusable = true;
101380
101625
  if (isWindows2 && error51.code === "EPERM") {
101381
101626
  try {
101382
- const fd = await open5(path6, "r");
101627
+ const fd = await open6(path6, "r");
101383
101628
  await fd.close();
101384
101629
  broadcastErr(error51);
101385
101630
  } catch (err2) {
@@ -101497,9 +101742,9 @@ var NodeFsHandler = class {
101497
101742
  if (this.fsw.closed) {
101498
101743
  return;
101499
101744
  }
101500
- const dirname41 = sysPath.dirname(file2);
101745
+ const dirname42 = sysPath.dirname(file2);
101501
101746
  const basename14 = sysPath.basename(file2);
101502
- const parent = this.fsw._getWatchedDir(dirname41);
101747
+ const parent = this.fsw._getWatchedDir(dirname42);
101503
101748
  let prevStats = stats;
101504
101749
  if (parent.has(basename14))
101505
101750
  return;
@@ -101526,7 +101771,7 @@ var NodeFsHandler = class {
101526
101771
  prevStats = newStats2;
101527
101772
  }
101528
101773
  } catch (error51) {
101529
- this.fsw._remove(dirname41, basename14);
101774
+ this.fsw._remove(dirname42, basename14);
101530
101775
  }
101531
101776
  } else if (parent.has(basename14)) {
101532
101777
  const at = newStats.atimeMs;
@@ -103725,6 +103970,7 @@ function turnRekeyed(from, to) {
103725
103970
  var HOST_ROOT = resolveHostRoot();
103726
103971
  var HOST_CONTAIN = resolveContainmentRoot() ?? void 0;
103727
103972
  var hooks = null;
103973
+ var hookSets = [];
103728
103974
  var socket = null;
103729
103975
  var heartbeat = null;
103730
103976
  var reconnectTimer = null;
@@ -103883,7 +104129,7 @@ async function ensureP2pReady() {
103883
104129
  }
103884
104130
  }
103885
104131
  function ownHostId() {
103886
- const mine = serverHosts.find((h) => h.hostId.endsWith(`:${deviceId}`));
104132
+ const mine = serverHosts.find((h) => h.deviceId === deviceId);
103887
104133
  return mine?.hostId ?? "local";
103888
104134
  }
103889
104135
  var lastOwnHostLog = null;
@@ -103897,9 +104143,10 @@ function logOwnHostVerdict() {
103897
104143
  }
103898
104144
  function presentedHosts() {
103899
104145
  const out = serverHosts.slice();
103900
- if (!out.some((h) => h.hostId.endsWith(`:${deviceId}`))) {
104146
+ if (!out.some((h) => h.deviceId === deviceId)) {
103901
104147
  out.unshift({
103902
104148
  hostId: "local",
104149
+ deviceId,
103903
104150
  name: hostname4(),
103904
104151
  kind: "electron",
103905
104152
  platform: process.platform,
@@ -103914,7 +104161,7 @@ function presentedHosts() {
103914
104161
  }
103915
104162
  function connectedFsHosts() {
103916
104163
  const mine = ownHostId();
103917
- return serverHosts.filter((h) => h.online && h.hostId !== mine && !h.hostId.endsWith(`:${deviceId}`)).filter((h) => h.kind === "electron" || h.kind === "cloud").filter((h) => !h.caps || h.caps.includes("fs")).map((h) => ({ hostId: h.hostId, label: h.name || (h.kind === "cloud" ? "Cloud agent" : "Remote machine") }));
104164
+ return serverHosts.filter((h) => h.online && h.hostId !== mine && h.deviceId !== deviceId).filter((h) => h.kind === "electron" || h.kind === "cloud").filter((h) => !h.caps || h.caps.includes("fs")).map((h) => ({ hostId: h.hostId, label: h.name || (h.kind === "cloud" ? "Cloud agent" : "Remote machine") }));
103918
104165
  }
103919
104166
  function listHosts() {
103920
104167
  return presentedHosts();
@@ -104095,7 +104342,12 @@ function resumeActiveLinks() {
104095
104342
  for (const { linkId } of listActiveLinks())
104096
104343
  if (!configured.has(linkId))
104097
104344
  void disconnectActiveLink(linkId);
104098
- for (const cfg2 of configs) {
104345
+ for (const stored of configs) {
104346
+ const peerDevice = hostDeviceId(stored.peerHostId);
104347
+ const live = peerDevice ? serverHosts.find((h) => h.deviceId === peerDevice) : void 0;
104348
+ const cfg2 = live && live.hostId !== stored.peerHostId ? { ...stored, peerHostId: live.hostId } : stored;
104349
+ if (cfg2 !== stored)
104350
+ saveLinkConfig(cfg2);
104099
104351
  connectActiveLink({
104100
104352
  linkId: cfg2.linkId,
104101
104353
  localRoot: cfg2.localRoot,
@@ -104695,10 +104947,19 @@ function handleHostChannel(payload) {
104695
104947
  return;
104696
104948
  }
104697
104949
  if (payload.type === "host:register:denied") {
104950
+ const d = payload;
104951
+ if (d.reason === "revoked") {
104952
+ stopHeartbeat();
104953
+ teardownHostRole();
104954
+ const message2 = typeof payload.message === "string" ? payload.message : "This computer was removed from the account.";
104955
+ console.log(`[control-link] host:register DENIED reason=revoked \u2014 ${message2}`);
104956
+ hooks?.notify({ type: "notify", level: "warning", message: message2 });
104957
+ hooks?.onDeviceRevoked?.();
104958
+ return;
104959
+ }
104698
104960
  entitlementDenied = true;
104699
104961
  stopHeartbeat();
104700
104962
  const message = typeof payload.message === "string" ? payload.message : "Running agents on your own machines requires a paid plan.";
104701
- const d = payload;
104702
104963
  console.log(`[control-link] host:register DENIED reason=${String(d.reason ?? "?")} feature=${String(d.feature ?? "?")} limit=${String(d.limit ?? "?")} \u2014 ${message}`);
104703
104964
  hooks?.notify({ type: "notify", level: "warning", message });
104704
104965
  scheduleEntitlementRetry();
@@ -105186,7 +105447,9 @@ function startControlLink(config2, h) {
105186
105447
  deviceId = config2.deviceId;
105187
105448
  backendOrigin = config2.tokenSource.backendOrigin;
105188
105449
  hostVersion = config2.version;
105189
- hooks = h;
105450
+ if (!hookSets.includes(h))
105451
+ hookSets.push(h);
105452
+ hooks = composeHooks(hookSets, (hook, err2) => console.warn(`[control-link] ${hook} listener failed:`, err2 instanceof Error ? err2.message : err2));
105190
105453
  stopped = false;
105191
105454
  if (config2.e2e && !hostSessions) {
105192
105455
  const e2e = config2.e2e;
@@ -105232,6 +105495,8 @@ function refreshControlLink() {
105232
105495
  if (accountChanged) {
105233
105496
  serverHosts = [];
105234
105497
  serverSelected = false;
105498
+ entitlementDenied = false;
105499
+ cancelEntitlementRetry();
105235
105500
  teardownHostRole();
105236
105501
  hooks.pushHosts(presentedHosts());
105237
105502
  hooks.ownHostResolved(ownHostId());
@@ -106730,7 +106995,7 @@ function rdeskSharingEnabled() {
106730
106995
  // ../../packages/host-core/dist/rdesk/password.js
106731
106996
  init_credentials();
106732
106997
  import { scryptSync, randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual4, randomInt } from "node:crypto";
106733
- import { readFileSync as readFileSync41, writeFileSync as writeFileSync29, existsSync as existsSync28, unlinkSync as unlinkSync3 } from "node:fs";
106998
+ import { readFileSync as readFileSync41, writeFileSync as writeFileSync29, existsSync as existsSync28, unlinkSync as unlinkSync4 } from "node:fs";
106734
106999
  import { join as join63 } from "node:path";
106735
107000
  function pwFile() {
106736
107001
  return join63(daemonDir2(), "rdesk-password.json");
@@ -106776,11 +107041,11 @@ function readRdeskPasswordPlain() {
106776
107041
  function setRdeskPassword(password) {
106777
107042
  if (!password) {
106778
107043
  try {
106779
- unlinkSync3(pwFile());
107044
+ unlinkSync4(pwFile());
106780
107045
  } catch {
106781
107046
  }
106782
107047
  try {
106783
- unlinkSync3(pwPlainFile());
107048
+ unlinkSync4(pwPlainFile());
106784
107049
  } catch {
106785
107050
  }
106786
107051
  return;
@@ -107471,7 +107736,7 @@ async function seal(key2, plaintext, aad) {
107471
107736
  const ct = await aesSeal(key2, nonce2, plaintext, aad);
107472
107737
  return `${ENVELOPE}:${b64u(nonce2)}:${b64u(ct)}`;
107473
107738
  }
107474
- async function open6(key2, envelope2, aad) {
107739
+ async function open7(key2, envelope2, aad) {
107475
107740
  const parts = envelope2.split(":");
107476
107741
  if (parts.length !== 3 || parts[0] !== ENVELOPE)
107477
107742
  throw new Error("malformed vault envelope");
@@ -107484,7 +107749,7 @@ async function wrapVaultKey(masterKey, vaultKey) {
107484
107749
  return seal(await wrappingKey(masterKey), vaultKey, WRAP_AAD);
107485
107750
  }
107486
107751
  async function unwrapVaultKey(masterKey, wrapped) {
107487
- return open6(await wrappingKey(masterKey), wrapped, WRAP_AAD);
107752
+ return open7(await wrappingKey(masterKey), wrapped, WRAP_AAD);
107488
107753
  }
107489
107754
  async function createVault(masterPassword, kdf2 = defaultKdfParams()) {
107490
107755
  const masterKey = deriveMasterKey(masterPassword, kdf2);
@@ -107517,7 +107782,7 @@ async function recoverWithKey(recoveryKey, meta4) {
107517
107782
  throw new Error("no recovery key is set for this vault");
107518
107783
  const kek = await importAesKey(parseRecoveryKey(recoveryKey));
107519
107784
  try {
107520
- return await open6(kek, meta4.recoveryWrappedVaultKey, RECOVERY_AAD);
107785
+ return await open7(kek, meta4.recoveryWrappedVaultKey, RECOVERY_AAD);
107521
107786
  } catch {
107522
107787
  throw new Error("Incorrect recovery key");
107523
107788
  }
@@ -107538,7 +107803,7 @@ async function encryptItem(vaultKey, item) {
107538
107803
  }
107539
107804
  async function decryptItem(vaultKey, enc) {
107540
107805
  const key2 = await importAesKey(vaultKey);
107541
- return JSON.parse(fromUtf8(await open6(key2, enc.ciphertext, itemAad(enc.id))));
107806
+ return JSON.parse(fromUtf8(await open7(key2, enc.ciphertext, itemAad(enc.id))));
107542
107807
  }
107543
107808
  function tombstone(id, updatedAt) {
107544
107809
  return { id, ciphertext: "", updatedAt, deleted: true };
@@ -108401,7 +108666,7 @@ function makeDaemonVaultApi(getOrigin, getToken2) {
108401
108666
 
108402
108667
  // ../../packages/host-core/dist/vault/persistence.js
108403
108668
  init_base_paths();
108404
- import { existsSync as existsSync29, mkdirSync as mkdirSync31, readFileSync as readFileSync42, writeFileSync as writeFileSync30, unlinkSync as unlinkSync4 } from "node:fs";
108669
+ import { existsSync as existsSync29, mkdirSync as mkdirSync31, readFileSync as readFileSync42, writeFileSync as writeFileSync30, unlinkSync as unlinkSync5 } from "node:fs";
108405
108670
  import { dirname as dirname29 } from "node:path";
108406
108671
  function vaultStoreFile() {
108407
108672
  return homePath(".tesseract", "vault", "vault.json");
@@ -108447,7 +108712,7 @@ function makeVaultPersistence(file2 = vaultStoreFile, deviceKeyFile = vaultDevic
108447
108712
  clearDeviceKey() {
108448
108713
  try {
108449
108714
  if (existsSync29(deviceKeyFile()))
108450
- unlinkSync4(deviceKeyFile());
108715
+ unlinkSync5(deviceKeyFile());
108451
108716
  } catch {
108452
108717
  }
108453
108718
  }
@@ -109624,16 +109889,16 @@ async function startLocalServer(opts) {
109624
109889
 
109625
109890
  // ../../packages/host-core/dist/daemon-runtime.js
109626
109891
  init_base_paths();
109627
- import { readFileSync as readFileSync49, writeFileSync as writeFileSync40, existsSync as existsSync39, mkdirSync as mkdirSync41, unlinkSync as unlinkSync6, chmodSync as chmodSync7, statSync as statSync14 } from "node:fs";
109892
+ import { readFileSync as readFileSync50, writeFileSync as writeFileSync41, existsSync as existsSync40, mkdirSync as mkdirSync42, unlinkSync as unlinkSync7, chmodSync as chmodSync7, statSync as statSync15 } from "node:fs";
109628
109893
  import { execFileSync as execFileSync5 } from "node:child_process";
109629
- import { join as join77 } from "node:path";
109894
+ import { join as join78 } from "node:path";
109630
109895
  import { randomBytes as randomBytes10 } from "node:crypto";
109631
109896
  import { hostname as hostname5 } from "node:os";
109632
109897
 
109633
109898
  // ../../packages/shared/dist/daemon-registry.js
109634
109899
  init_base_paths();
109635
109900
  import { execFileSync as execFileSync3 } from "node:child_process";
109636
- import { existsSync as existsSync31, mkdirSync as mkdirSync34, readdirSync as readdirSync11, readFileSync as readFileSync45, readlinkSync, unlinkSync as unlinkSync5, writeFileSync as writeFileSync33 } from "node:fs";
109901
+ import { existsSync as existsSync31, mkdirSync as mkdirSync34, readdirSync as readdirSync11, readFileSync as readFileSync45, readlinkSync, unlinkSync as unlinkSync6, writeFileSync as writeFileSync33 } from "node:fs";
109637
109902
  import { join as join65 } from "node:path";
109638
109903
  var SUPERVISOR_PID = Number(process.env.CCB_DAEMON_SUPERVISOR_PID ?? 0) || 0;
109639
109904
  delete process.env.CCB_DAEMON_SUPERVISOR_PID;
@@ -109714,7 +109979,7 @@ function registerSelfAsDaemon(version2) {
109714
109979
  }
109715
109980
  function forgetDaemon(pid) {
109716
109981
  try {
109717
- unlinkSync5(recordPath(pid));
109982
+ unlinkSync6(recordPath(pid));
109718
109983
  } catch {
109719
109984
  }
109720
109985
  invalidateSupervisorCache();
@@ -109922,6 +110187,7 @@ var BundleOfferLedger = class {
109922
110187
  init_dist6();
109923
110188
 
109924
110189
  // ../../packages/host-core/dist/mesh/netd-client.js
110190
+ import { existsSync as existsSync33, readdirSync as readdirSync12 } from "node:fs";
109925
110191
  import { connect as connect2 } from "node:net";
109926
110192
  import { platform as platform3 } from "node:process";
109927
110193
  var NETD_WIRE_VERSION = 2;
@@ -109934,6 +110200,17 @@ function netdEndpoint() {
109934
110200
  return "/var/run/tesseract-netd.sock";
109935
110201
  return "/run/tesseract-netd.sock";
109936
110202
  }
110203
+ function netdListening() {
110204
+ const ep = endpointOverride() ?? netdEndpoint();
110205
+ if (process.platform !== "win32")
110206
+ return existsSync33(ep);
110207
+ try {
110208
+ const name = ep.replace(/^\\\\\.\\pipe\\/, "");
110209
+ return readdirSync12("\\\\.\\pipe\\").includes(name);
110210
+ } catch {
110211
+ return false;
110212
+ }
110213
+ }
109937
110214
  function endpointOverride() {
109938
110215
  return process.env.CCB_NETD_SOCKET ?? null;
109939
110216
  }
@@ -110295,9 +110572,6 @@ var NetdEngine = class {
110295
110572
  }
110296
110573
  };
110297
110574
 
110298
- // ../../packages/host-core/dist/mesh/node.js
110299
- import { existsSync as existsSync34 } from "node:fs";
110300
-
110301
110575
  // ../../packages/host-core/dist/mesh/bundle-refresh.js
110302
110576
  init_dist6();
110303
110577
  var CONTEXT = "tsr-bundle-fetch-v1";
@@ -110334,7 +110608,7 @@ ${ts}`);
110334
110608
 
110335
110609
  // ../../packages/host-core/dist/mesh/config.js
110336
110610
  init_credentials();
110337
- import { chmodSync as chmodSync5, existsSync as existsSync33, mkdirSync as mkdirSync36, readdirSync as readdirSync12, readFileSync as readFileSync47, renameSync as renameSync11, rmSync as rmSync7, writeFileSync as writeFileSync35 } from "node:fs";
110611
+ import { chmodSync as chmodSync5, existsSync as existsSync34, mkdirSync as mkdirSync36, readdirSync as readdirSync13, readFileSync as readFileSync47, renameSync as renameSync11, rmSync as rmSync7, writeFileSync as writeFileSync35 } from "node:fs";
110338
110612
  import { dirname as dirname31, join as join68 } from "node:path";
110339
110613
  function meshDir() {
110340
110614
  return join68(daemonDir2(), "mesh");
@@ -110378,14 +110652,14 @@ var FILES = {
110378
110652
  function readIfPresent(name, dir2 = meshDir()) {
110379
110653
  const p = join68(dir2, name);
110380
110654
  try {
110381
- return existsSync33(p) ? new Uint8Array(readFileSync47(p)) : void 0;
110655
+ return existsSync34(p) ? new Uint8Array(readFileSync47(p)) : void 0;
110382
110656
  } catch {
110383
110657
  return void 0;
110384
110658
  }
110385
110659
  }
110386
110660
  function migrateSingleMesh() {
110387
110661
  const legacyGenesis = join68(meshDir(), FILES.genesis);
110388
- if (!existsSync33(legacyGenesis))
110662
+ if (!existsSync34(legacyGenesis))
110389
110663
  return null;
110390
110664
  const id = meshIdFromCert(readIfPresent(FILES.cert)) ?? LEGACY_MESH_ID;
110391
110665
  const dest = oneMeshDir(id);
@@ -110394,11 +110668,11 @@ function migrateSingleMesh() {
110394
110668
  chmodSync5(dest, 448);
110395
110669
  for (const f of Object.values(FILES)) {
110396
110670
  const from = join68(meshDir(), f);
110397
- if (existsSync33(from))
110671
+ if (existsSync34(from))
110398
110672
  renameSync11(from, join68(dest, f));
110399
110673
  }
110400
110674
  const key2 = join68(dest, FILES.key);
110401
- if (existsSync33(key2))
110675
+ if (existsSync34(key2))
110402
110676
  chmodSync5(key2, 384);
110403
110677
  } catch {
110404
110678
  return null;
@@ -110409,7 +110683,7 @@ function listMeshIds() {
110409
110683
  migrateSingleMesh();
110410
110684
  let names;
110411
110685
  try {
110412
- names = readdirSync12(meshesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
110686
+ names = readdirSync13(meshesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
110413
110687
  } catch {
110414
110688
  return [];
110415
110689
  }
@@ -110704,7 +110978,7 @@ function loadMeshCore() {
110704
110978
  }
110705
110979
  var meshCore = loadMeshCore();
110706
110980
  function meshEngineStatus() {
110707
- if (process.env.CCB_MESH_IN_DAEMON !== "1" && existsSync34(netdEndpoint())) {
110981
+ if (process.env.CCB_MESH_IN_DAEMON !== "1" && netdListening()) {
110708
110982
  return { available: true, reason: null };
110709
110983
  }
110710
110984
  return { available: meshCore.available === true, reason: meshCore.loadError ?? null };
@@ -110934,7 +111208,14 @@ var MeshNode = class {
110934
111208
  reason: "this machine was removed from the network \u2014 ask an admin for a new invitation"
110935
111209
  };
110936
111210
  }
110937
- const inNetd = process.env.CCB_MESH_IN_DAEMON !== "1" && existsSync34(netdEndpoint());
111211
+ const forcedInDaemon = process.env.CCB_MESH_IN_DAEMON === "1";
111212
+ const inNetd = !forcedInDaemon && netdListening();
111213
+ if (!inNetd && !forcedInDaemon) {
111214
+ return {
111215
+ ok: false,
111216
+ reason: "the network helper is not running, so nothing can open the tunnel \u2014 install it with `tesseract-agent net helper install`"
111217
+ };
111218
+ }
110938
111219
  if (!inNetd && !meshCore.available) {
110939
111220
  return { ok: false, reason: `mesh engine unavailable: ${meshCore.loadError ?? "no prebuilt"}` };
110940
111221
  }
@@ -111670,14 +111951,32 @@ function startNodes(log9) {
111670
111951
  return [];
111671
111952
  }
111672
111953
  const started2 = meshNode().start();
111673
- log9(started2.ok ? "mesh: node up" : `mesh: not started \u2014 ${started2.reason}`);
111674
- return started2.ok && only !== void 0 ? [only] : [];
111954
+ if (started2.ok) {
111955
+ log9("mesh: node up");
111956
+ return only !== void 0 ? [only] : [];
111957
+ }
111958
+ const refusal = { running: false, enrolled: true, lastError: started2.reason };
111959
+ if (only !== void 0)
111960
+ writeStatus(refusal, only);
111961
+ writeStatus(refusal);
111962
+ log9(`mesh: not started \u2014 ${started2.reason}`);
111963
+ return [];
111675
111964
  }
111676
111965
  const running2 = [];
111966
+ let failedPrimary = null;
111677
111967
  for (const r of meshManager().startAll()) {
111678
- log9(r.ok ? `mesh ${r.meshId}: up` : `mesh ${r.meshId}: not started \u2014 ${r.reason}`);
111679
- if (r.ok)
111968
+ if (r.ok) {
111969
+ log9(`mesh ${r.meshId}: up`);
111680
111970
  running2.push(r.meshId);
111971
+ continue;
111972
+ }
111973
+ writeStatus({ running: false, enrolled: true, lastError: r.reason }, r.meshId);
111974
+ if (failedPrimary === null)
111975
+ failedPrimary = r.reason ?? "the node did not start";
111976
+ log9(`mesh ${r.meshId}: not started \u2014 ${r.reason}`);
111977
+ }
111978
+ if (running2.length === 0 && failedPrimary !== null) {
111979
+ writeStatus({ running: false, enrolled: true, lastError: failedPrimary });
111681
111980
  }
111682
111981
  return running2;
111683
111982
  }
@@ -111748,7 +112047,7 @@ function initDropReceiveUi(deps = {}) {
111748
112047
  log5("reveal failed:", err2 instanceof Error ? err2.message : String(err2));
111749
112048
  }
111750
112049
  };
111751
- const open7 = () => {
112050
+ const open8 = () => {
111752
112051
  const el2 = electronModule();
111753
112052
  if (!el2)
111754
112053
  return;
@@ -111759,7 +112058,7 @@ function initDropReceiveUi(deps = {}) {
111759
112058
  title: "Files received",
111760
112059
  body: `${describe3(e)} \xB7 ${formatBytes(e.bytesDone)}`,
111761
112060
  actions: [{ id: "reveal", label: "Show in Finder" }, { id: "open", label: "Open" }],
111762
- onAction: (id) => id === "open" ? open7() : reveal(),
112061
+ onAction: (id) => id === "open" ? open8() : reveal(),
111763
112062
  // Clicking the banner body is the only reliable action on macOS (buttons need
111764
112063
  // an expanded banner and are suppressed under Focus), so make it do the useful
111765
112064
  // thing rather than nothing.
@@ -112183,8 +112482,8 @@ async function fetchBlobDrop(opts) {
112183
112482
  if (opts.sealedKey) {
112184
112483
  if (!opts.sealingPrivate)
112185
112484
  throw new Error("This device has no sealing key, so it cannot open the transfer.");
112186
- const open7 = opts.openSeal ?? openFromPrivateKey;
112187
- contentKey = await open7(await opts.sealingPrivate(), opts.sealedKey, new TextEncoder().encode(opts.dropId));
112485
+ const open8 = opts.openSeal ?? openFromPrivateKey;
112486
+ contentKey = await open8(await opts.sealingPrivate(), opts.sealedKey, new TextEncoder().encode(opts.dropId));
112188
112487
  }
112189
112488
  const totalBytes = opts.items.reduce((n, i) => n + (i.kind === "file" ? i.size : 0), 0);
112190
112489
  let bytesDone = 0;
@@ -113760,10 +114059,42 @@ function closeRdeskCallWindow() {
113760
114059
  // ../../packages/host-core/dist/daemon-runtime.js
113761
114060
  init_credentials();
113762
114061
 
114062
+ // ../../packages/shared/dist/identity.js
114063
+ init_base_paths();
114064
+ import { existsSync as existsSync39, mkdirSync as mkdirSync41, readFileSync as readFileSync49, writeFileSync as writeFileSync40 } from "node:fs";
114065
+ import { dirname as dirname35, join as join77 } from "node:path";
114066
+ import { randomUUID as randomUUID29 } from "node:crypto";
114067
+ function deviceIdFile() {
114068
+ return join77(tesseractHome(), "device-id.json");
114069
+ }
114070
+ function readPersistedDeviceId() {
114071
+ try {
114072
+ const raw = JSON.parse(readFileSync49(deviceIdFile(), "utf-8"));
114073
+ return typeof raw.deviceId === "string" && raw.deviceId ? raw.deviceId : null;
114074
+ } catch {
114075
+ return null;
114076
+ }
114077
+ }
114078
+ function persistentDeviceId() {
114079
+ const cur = readPersistedDeviceId();
114080
+ if (cur)
114081
+ return cur;
114082
+ const id = randomUUID29().slice(0, 8);
114083
+ try {
114084
+ const f = deviceIdFile();
114085
+ const dir2 = dirname35(f);
114086
+ if (!existsSync39(dir2))
114087
+ mkdirSync41(dir2, { recursive: true });
114088
+ writeFileSync40(f, JSON.stringify({ deviceId: id }));
114089
+ } catch {
114090
+ }
114091
+ return id;
114092
+ }
114093
+
113763
114094
  // ../../packages/host-core/dist/error-report.js
113764
114095
  init_dist2();
113765
114096
  init_credentials();
113766
- import { randomUUID as randomUUID29 } from "node:crypto";
114097
+ import { randomUUID as randomUUID30 } from "node:crypto";
113767
114098
  import { release as osRelease, arch as osArch } from "node:os";
113768
114099
  var MAX_QUEUE = 100;
113769
114100
  var FLUSH_INTERVAL_MS = 3e4;
@@ -113815,7 +114146,7 @@ function captureDaemonError(error51, opts = {}) {
113815
114146
  return;
113816
114147
  const creds3 = readCredentials();
113817
114148
  const report = {
113818
- reportId: randomUUID29(),
114149
+ reportId: randomUUID30(),
113819
114150
  occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
113820
114151
  schemaVersion: 1,
113821
114152
  surface,
@@ -113912,8 +114243,8 @@ async function runDaemon(opts = {}) {
113912
114243
  log9("paths", JSON.stringify(sealBasePaths()));
113913
114244
  const OUR_STARTED_AT = procStartedAt(process.pid);
113914
114245
  let ownsMachine = false;
113915
- const pidfile = () => join77(daemonDir2(), "daemon.lock");
113916
- const statusFile = () => join77(daemonDir2(), "status.json");
114246
+ const pidfile = () => join78(daemonDir2(), "daemon.lock");
114247
+ const statusFile = () => join78(daemonDir2(), "status.json");
113917
114248
  const isAlive2 = (pid) => {
113918
114249
  if (!Number.isFinite(pid) || pid <= 0)
113919
114250
  return false;
@@ -113926,7 +114257,7 @@ async function runDaemon(opts = {}) {
113926
114257
  };
113927
114258
  const lockHeldByAnother = () => {
113928
114259
  try {
113929
- const pid = Number(readFileSync49(pidfile(), "utf-8").trim());
114260
+ const pid = Number(readFileSync50(pidfile(), "utf-8").trim());
113930
114261
  return Number.isFinite(pid) && pid > 0 && pid !== process.pid && isAlive2(pid);
113931
114262
  } catch {
113932
114263
  return false;
@@ -113934,7 +114265,7 @@ async function runDaemon(opts = {}) {
113934
114265
  };
113935
114266
  const lockHeldByYieldingSubset = () => {
113936
114267
  try {
113937
- const pid = Number(readFileSync49(pidfile(), "utf-8").trim());
114268
+ const pid = Number(readFileSync50(pidfile(), "utf-8").trim());
113938
114269
  if (!Number.isFinite(pid) || pid <= 0 || pid === process.pid || !isAlive2(pid))
113939
114270
  return false;
113940
114271
  return liveDaemons().some((d) => d.pid === pid && d.rdeskOnly === true);
@@ -113945,22 +114276,22 @@ async function runDaemon(opts = {}) {
113945
114276
  function acquireLock2() {
113946
114277
  const f = pidfile();
113947
114278
  try {
113948
- if (!existsSync39(daemonDir2()))
113949
- mkdirSync41(daemonDir2(), { recursive: true, mode: 448 });
114279
+ if (!existsSync40(daemonDir2()))
114280
+ mkdirSync42(daemonDir2(), { recursive: true, mode: 448 });
113950
114281
  } catch {
113951
114282
  }
113952
114283
  for (let attempt = 0; attempt < 2; attempt++) {
113953
114284
  try {
113954
- writeFileSync40(f, String(process.pid), { flag: "wx" });
114285
+ writeFileSync41(f, String(process.pid), { flag: "wx" });
113955
114286
  return true;
113956
114287
  } catch {
113957
114288
  try {
113958
- const prev = Number(readFileSync49(f, "utf-8").trim());
114289
+ const prev = Number(readFileSync50(f, "utf-8").trim());
113959
114290
  if (!prev)
113960
114291
  return false;
113961
114292
  if (prev !== process.pid && isAlive2(prev))
113962
114293
  return false;
113963
- unlinkSync6(f);
114294
+ unlinkSync7(f);
113964
114295
  } catch {
113965
114296
  return false;
113966
114297
  }
@@ -113971,8 +114302,8 @@ async function runDaemon(opts = {}) {
113971
114302
  function releaseLock() {
113972
114303
  try {
113973
114304
  const f = pidfile();
113974
- if (existsSync39(f) && Number(readFileSync49(f, "utf-8").trim()) === process.pid)
113975
- unlinkSync6(f);
114305
+ if (existsSync40(f) && Number(readFileSync50(f, "utf-8").trim()) === process.pid)
114306
+ unlinkSync7(f);
113976
114307
  } catch {
113977
114308
  }
113978
114309
  }
@@ -113981,7 +114312,7 @@ async function runDaemon(opts = {}) {
113981
114312
  if (!ownsMachine)
113982
114313
  return;
113983
114314
  try {
113984
- writeFileSync40(statusFile(), JSON.stringify({ pid: process.pid, startedAt: OUR_STARTED_AT, role: process.env.CCB_RDESK_ROLE ?? "host", version: VERSION3, execPath: process.env.CCB_DAEMON_EXECPATH ?? process.execPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), gui: daemonGuiTrayActive(), ...localInfo ?? {}, ...s }));
114315
+ writeFileSync41(statusFile(), JSON.stringify({ pid: process.pid, startedAt: OUR_STARTED_AT, role: process.env.CCB_RDESK_ROLE ?? "host", version: VERSION3, execPath: process.env.CCB_DAEMON_EXECPATH ?? process.execPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), gui: daemonGuiTrayActive(), ...localInfo ?? {}, ...s }));
113985
114316
  chmodSync7(statusFile(), 384);
113986
114317
  } catch {
113987
114318
  }
@@ -114028,6 +114359,19 @@ async function runDaemon(opts = {}) {
114028
114359
  const activityTracker = createActivityTracker({ log: log9 });
114029
114360
  let activityTimer = null;
114030
114361
  let creds3 = readCredentials();
114362
+ try {
114363
+ const ownId = persistentDeviceId();
114364
+ const { migratedFrom } = adoptPersistentDeviceId(ownId, (m) => log9(m));
114365
+ if (migratedFrom) {
114366
+ try {
114367
+ opts.onDeviceIdMigrated?.(migratedFrom, ownId);
114368
+ } catch (e) {
114369
+ log9("device id migration hook failed", e.message);
114370
+ }
114371
+ }
114372
+ } catch (e) {
114373
+ log9("device id reconcile skipped", e.message);
114374
+ }
114031
114375
  let machine = null;
114032
114376
  const acquireIdentity = async () => {
114033
114377
  const signedIn = readCredentials();
@@ -114039,6 +114383,7 @@ async function runDaemon(opts = {}) {
114039
114383
  apiOrigin: apiOriginForMachine(),
114040
114384
  backendOrigin: backendOriginForMachine(),
114041
114385
  isAllowedOrigin: isAllowedApiOrigin,
114386
+ deviceId: persistentDeviceId(),
114042
114387
  log: (msg) => log9(msg)
114043
114388
  });
114044
114389
  machine = m;
@@ -114490,6 +114835,7 @@ async function runDaemon(opts = {}) {
114490
114835
  apiOrigin: c.apiOrigin,
114491
114836
  backendOrigin: c.backendOrigin,
114492
114837
  isAllowedOrigin: isAllowedApiOrigin,
114838
+ deviceId: persistentDeviceId(),
114493
114839
  log: (m) => log9(m)
114494
114840
  });
114495
114841
  if (!next?.accessToken) {
@@ -114516,7 +114862,7 @@ async function runDaemon(opts = {}) {
114516
114862
  if (r.status === 401) {
114517
114863
  log9("device token no longer valid \u2014 dropping to local-only on restart");
114518
114864
  try {
114519
- unlinkSync6(join77(daemonDir2(), "credentials.json"));
114865
+ unlinkSync7(join78(daemonDir2(), "credentials.json"));
114520
114866
  } catch {
114521
114867
  }
114522
114868
  shutdown(0, "token-revoked-401");
@@ -114535,7 +114881,7 @@ async function runDaemon(opts = {}) {
114535
114881
  scheduleRefreshRetry("the api was unreachable");
114536
114882
  }
114537
114883
  }
114538
- setDaemonIdentityReload(async () => {
114884
+ const reloadIdentity = async () => {
114539
114885
  const fresh = readCredentials();
114540
114886
  const next = nextDaemonIdentity(fresh, { accessToken, userId: c.userId });
114541
114887
  if (next.kind === "unchanged")
@@ -114552,6 +114898,7 @@ async function runDaemon(opts = {}) {
114552
114898
  apiOrigin: c.apiOrigin,
114553
114899
  backendOrigin: c.backendOrigin,
114554
114900
  isAllowedOrigin: isAllowedApiOrigin,
114901
+ deviceId: persistentDeviceId(),
114555
114902
  log: (msg) => log9(msg)
114556
114903
  });
114557
114904
  if (!m?.accessToken) {
@@ -114563,7 +114910,8 @@ async function runDaemon(opts = {}) {
114563
114910
  accessToken = m.accessToken;
114564
114911
  log9("signed out \u2014 this machine speaks for itself again");
114565
114912
  refreshControlLink();
114566
- });
114913
+ };
114914
+ setDaemonIdentityReload(reloadIdentity);
114567
114915
  registerTesseractEngine({ getIceServers: () => fetchIceServers() });
114568
114916
  registerVncEngine();
114569
114917
  registerRdpEngine();
@@ -114814,7 +115162,7 @@ async function runDaemon(opts = {}) {
114814
115162
  let freeTicks = 0;
114815
115163
  const lockHolder = () => {
114816
115164
  try {
114817
- return Number(readFileSync49(pidfile(), "utf-8").trim()) || 0;
115165
+ return Number(readFileSync50(pidfile(), "utf-8").trim()) || 0;
114818
115166
  } catch {
114819
115167
  return 0;
114820
115168
  }
@@ -114891,7 +115239,7 @@ async function runDaemon(opts = {}) {
114891
115239
  // open. getRdeskClientWebContents() is null for the SERVER / full-app daemon (no client
114892
115240
  // window) → those sends are no-ops, so this is inert outside the rdesk-client role.
114893
115241
  pushHosts: (hosts) => {
114894
- writeStatus2({ deviceId: c.deviceId, connected: true });
115242
+ writeStatus2({ deviceId: c.deviceId, ownHostId: ownHost(), connected: true });
114895
115243
  getRdeskClientWebContents()?.send("hostlink:hosts", hosts);
114896
115244
  },
114897
115245
  ownHostResolved: (own2) => {
@@ -114975,6 +115323,18 @@ async function runDaemon(opts = {}) {
114975
115323
  deliverRdeskSignal: (payload, hostId, sessionId) => {
114976
115324
  getRdeskClientWebContents()?.send("rdesk:signal", { payload, hostId, sessionId });
114977
115325
  },
115326
+ // The account removed this machine (Remove in My Computers on another device, CLI logout).
115327
+ // Drop the account credentials and speak for the machine itself again — the same switch a
115328
+ // sign-out makes. The host app's own hook additionally turns sharing off, so it does not
115329
+ // simply provision a new token and come straight back.
115330
+ onDeviceRevoked: () => {
115331
+ log9("this machine was removed from the account \u2014 dropping its credentials; it speaks for itself again");
115332
+ try {
115333
+ unlinkSync7(join78(daemonDir2(), "credentials.json"));
115334
+ } catch {
115335
+ }
115336
+ void reloadIdentity();
115337
+ },
114978
115338
  // Universal clipboard sync: a copy (or fetch/chunk control frame) from another of the account's
114979
115339
  // devices → hand it to the daemon's clipboard-sync (created in onOwned).
114980
115340
  onClipboard: (entry, fromClientId) => daemonClipboardSync?.onRemote(entry, fromClientId),
@@ -115023,7 +115383,7 @@ async function runDaemon(opts = {}) {
115023
115383
  if (appPid > 0 && appPid !== process.pid) {
115024
115384
  const quitMarker = () => {
115025
115385
  try {
115026
- return Number(readFileSync49(join77(daemonDir2(), "app-quit.marker"), "utf-8").trim()) || 0;
115386
+ return Number(readFileSync50(join78(daemonDir2(), "app-quit.marker"), "utf-8").trim()) || 0;
115027
115387
  } catch {
115028
115388
  return 0;
115029
115389
  }
@@ -115048,7 +115408,7 @@ async function runDaemon(opts = {}) {
115048
115408
  log9(`desktop app (pid ${appPid}) is gone with NO clean-quit marker \u2014 reporting`);
115049
115409
  const tail3 = (name) => {
115050
115410
  try {
115051
- const buf = readFileSync49(join77(daemonDir2(), name), "utf-8");
115411
+ const buf = readFileSync50(join78(daemonDir2(), name), "utf-8");
115052
115412
  return buf.length > 4096 ? buf.slice(-4096) : buf;
115053
115413
  } catch {
115054
115414
  return void 0;
@@ -115079,14 +115439,14 @@ async function runDaemon(opts = {}) {
115079
115439
  }
115080
115440
  try {
115081
115441
  const DAEMON_LOG_CAP = 2 * 1024 * 1024;
115082
- const daemonLogFile = join77(daemonDir2(), "daemon.log");
115442
+ const daemonLogFile = join78(daemonDir2(), "daemon.log");
115083
115443
  const capTimer = setInterval(() => {
115084
115444
  try {
115085
- if (existsSync39(daemonLogFile) && statSync14(daemonLogFile).size > DAEMON_LOG_CAP) {
115086
- const buf = readFileSync49(daemonLogFile, "utf-8");
115445
+ if (existsSync40(daemonLogFile) && statSync15(daemonLogFile).size > DAEMON_LOG_CAP) {
115446
+ const buf = readFileSync50(daemonLogFile, "utf-8");
115087
115447
  const kept = `\u2026[daemon.log capped at ${(/* @__PURE__ */ new Date()).toISOString()}]\u2026
115088
115448
  ` + buf.slice(-DAEMON_LOG_CAP / 2);
115089
- writeFileSync40(daemonLogFile, kept);
115449
+ writeFileSync41(daemonLogFile, kept);
115090
115450
  }
115091
115451
  } catch {
115092
115452
  }
@@ -115396,15 +115756,15 @@ init_credentials();
115396
115756
 
115397
115757
  // ../../packages/host-core/dist/net-service/ensure-installed.js
115398
115758
  import { execFile as execFile14 } from "node:child_process";
115399
- import { existsSync as existsSync43 } from "node:fs";
115400
- import { dirname as dirname36, join as join81 } from "node:path";
115759
+ import { existsSync as existsSync44 } from "node:fs";
115760
+ import { dirname as dirname37, join as join82 } from "node:path";
115401
115761
  import { promisify as promisify10 } from "node:util";
115402
115762
 
115403
115763
  // ../../packages/host-core/dist/net-service/launchd-system.js
115404
115764
  import { spawn as spawn9 } from "node:child_process";
115405
- import { existsSync as existsSync40, mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync41, rmSync as rmSync10, readFileSync as readFileSync50 } from "node:fs";
115765
+ import { existsSync as existsSync41, mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync42, rmSync as rmSync10, readFileSync as readFileSync51 } from "node:fs";
115406
115766
  import { tmpdir as tmpdir6 } from "node:os";
115407
- import { join as join78 } from "node:path";
115767
+ import { join as join79 } from "node:path";
115408
115768
 
115409
115769
  // ../../packages/host-core/dist/net-service/owner-uid.js
115410
115770
  function installOwnerUid(env = process.env, self2 = typeof process.getuid === "function" ? process.getuid() : 0) {
@@ -115496,9 +115856,9 @@ ${args}
115496
115856
  <key>ProcessType</key>
115497
115857
  <string>Interactive</string>
115498
115858
  <key>StandardErrorPath</key>
115499
- <string>${xml(join78(spec.stateDir, "netd.log"))}</string>
115859
+ <string>${xml(join79(spec.stateDir, "netd.log"))}</string>
115500
115860
  <key>StandardOutPath</key>
115501
- <string>${xml(join78(spec.stateDir, "netd.log"))}</string>
115861
+ <string>${xml(join79(spec.stateDir, "netd.log"))}</string>
115502
115862
  </dict>
115503
115863
  </plist>
115504
115864
  `;
@@ -115511,10 +115871,10 @@ function runForCode(cmd, args) {
115511
115871
  });
115512
115872
  }
115513
115873
  async function elevate(script) {
115514
- const dir2 = mkdtempSync2(join78(tmpdir6(), "tesseract-netd-"));
115515
- const path6 = join78(dir2, "install.sh");
115874
+ const dir2 = mkdtempSync2(join79(tmpdir6(), "tesseract-netd-"));
115875
+ const path6 = join79(dir2, "install.sh");
115516
115876
  try {
115517
- writeFileSync41(path6, script, { mode: 384 });
115877
+ writeFileSync42(path6, script, { mode: 384 });
115518
115878
  if (await alreadyElevated()) {
115519
115879
  return { code: await runForCode("/bin/sh", [path6]), declined: false };
115520
115880
  }
@@ -115573,9 +115933,9 @@ ${plist}TESSERACT_PLIST_EOF`,
115573
115933
  };
115574
115934
  },
115575
115935
  async state() {
115576
- if (!existsSync40(PLIST))
115936
+ if (!existsSync41(PLIST))
115577
115937
  return { installed: false, running: false };
115578
- const owner = parseOwnerUid(readFileSync50(PLIST, "utf8"));
115938
+ const owner = parseOwnerUid(readFileSync51(PLIST, "utf8"));
115579
115939
  const running2 = await netdAvailable();
115580
115940
  return {
115581
115941
  installed: true,
@@ -115593,7 +115953,7 @@ ${plist}TESSERACT_PLIST_EOF`,
115593
115953
 
115594
115954
  // ../../packages/host-core/dist/net-service/systemd-system.js
115595
115955
  import { spawn as spawn11 } from "node:child_process";
115596
- import { existsSync as existsSync41, readFileSync as readFileSync51 } from "node:fs";
115956
+ import { existsSync as existsSync42, readFileSync as readFileSync52 } from "node:fs";
115597
115957
 
115598
115958
  // ../../packages/host-core/dist/service/exec.js
115599
115959
  import { execFile as execFile11, spawn as spawn10 } from "node:child_process";
@@ -115629,6 +115989,8 @@ async function elevated(script) {
115629
115989
  }
115630
115990
  var UNIT = "tesseract-netd.service";
115631
115991
  var UNIT_PATH = `/etc/systemd/system/${UNIT}`;
115992
+ var SYSTEM_EXEC_DIR = "/usr/local/libexec/tesseract-netd";
115993
+ var SYSTEM_EXEC = `${SYSTEM_EXEC_DIR}/tesseract-netd`;
115632
115994
  function unitVal(v) {
115633
115995
  return v.replace(/%/g, "%%");
115634
115996
  }
@@ -115700,8 +116062,12 @@ WantedBy=multi-user.target
115700
116062
  function buildInstallScript(spec) {
115701
116063
  return [
115702
116064
  `install -d -m 0700 ${sh2(spec.stateDir)}`,
116065
+ // Copy the helper to the root-owned system path and run it from there — see SYSTEM_EXEC.
116066
+ // BEFORE the unit is written and started, so the ExecStart it names already exists.
116067
+ `install -d -m 0755 ${sh2(SYSTEM_EXEC_DIR)}`,
116068
+ `install -m 0755 ${sh2(spec.exec)} ${sh2(SYSTEM_EXEC)}`,
115703
116069
  `cat > ${sh2(UNIT_PATH)} <<'TESSERACT_UNIT_EOF'
115704
- ${buildUnit(spec)}TESSERACT_UNIT_EOF`,
116070
+ ${buildUnit({ ...spec, exec: SYSTEM_EXEC })}TESSERACT_UNIT_EOF`,
115705
116071
  "systemctl daemon-reload",
115706
116072
  `systemctl enable ${UNIT}`,
115707
116073
  // RESTART, not `enable --now`. `--now` only STARTS, so on a REINSTALL it leaves the
@@ -115730,15 +116096,19 @@ function makeSystemdSystem() {
115730
116096
  const script = [
115731
116097
  `systemctl disable --now ${UNIT} || true`,
115732
116098
  `rm -f ${sh2(UNIT_PATH)}`,
116099
+ // The copied binary too — see SYSTEM_EXEC. Leaving a root-owned setuid-adjacent
116100
+ // binary behind after an uninstall is exactly the kind of thing a security review
116101
+ // flags, and it is ours to clean up.
116102
+ `rm -rf ${sh2(SYSTEM_EXEC_DIR)}`,
115733
116103
  "systemctl daemon-reload"
115734
116104
  ].join("\n");
115735
116105
  const code = await elevated(script);
115736
116106
  return code === 0 ? { ok: true } : { ok: false, detail: `removing the helper failed (exit ${code})` };
115737
116107
  },
115738
116108
  async state() {
115739
- if (!existsSync41(UNIT_PATH))
116109
+ if (!existsSync42(UNIT_PATH))
115740
116110
  return { installed: false, running: false };
115741
- const owner = parseOwnerUid(readFileSync51(UNIT_PATH, "utf8"));
116111
+ const owner = parseOwnerUid(readFileSync52(UNIT_PATH, "utf8"));
115742
116112
  const active = await tryRun("systemctl", ["is-active", UNIT]);
115743
116113
  const running2 = active.stdout.trim() === "active";
115744
116114
  const own2 = owner === void 0 ? {} : { ownerUid: owner };
@@ -115763,9 +116133,9 @@ function sh2(s) {
115763
116133
 
115764
116134
  // ../../packages/host-core/dist/net-service/windows-service.js
115765
116135
  import { execFile as execFile12, spawn as spawn12 } from "node:child_process";
115766
- import { mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync42, rmSync as rmSync11 } from "node:fs";
116136
+ import { mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync43, rmSync as rmSync11 } from "node:fs";
115767
116137
  import { tmpdir as tmpdir7 } from "node:os";
115768
- import { join as join79 } from "node:path";
116138
+ import { join as join80 } from "node:path";
115769
116139
  import { promisify as promisify8 } from "node:util";
115770
116140
  var run6 = promisify8(execFile12);
115771
116141
  var SERVICE = "TesseractNetd";
@@ -115793,9 +116163,9 @@ function buildBinaryPath(spec) {
115793
116163
  return parts.map((p) => `"${p}"`).join(" ");
115794
116164
  }
115795
116165
  async function elevatePowerShell(script) {
115796
- const dir2 = mkdtempSync3(join79(tmpdir7(), "tesseract-netd-"));
115797
- const inner = join79(dir2, "install.ps1");
115798
- writeFileSync42(inner, script, { encoding: "utf8" });
116166
+ const dir2 = mkdtempSync3(join80(tmpdir7(), "tesseract-netd-"));
116167
+ const inner = join80(dir2, "install.ps1");
116168
+ writeFileSync43(inner, script, { encoding: "utf8" });
115799
116169
  if (await alreadyElevated()) {
115800
116170
  return new Promise((resolve16) => {
115801
116171
  const p = spawn12("powershell.exe", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", inner], { stdio: "inherit" });
@@ -115810,8 +116180,8 @@ async function elevatePowerShell(script) {
115810
116180
  p.on("close", (code) => finish(code ?? 1));
115811
116181
  });
115812
116182
  }
115813
- const outer = join79(dir2, "elevate.ps1");
115814
- writeFileSync42(outer, [
116183
+ const outer = join80(dir2, "elevate.ps1");
116184
+ writeFileSync43(outer, [
115815
116185
  '$ErrorActionPreference = "Stop"',
115816
116186
  "try {",
115817
116187
  ` $p = Start-Process -FilePath "powershell.exe" -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File",${ps(inner)}) -Verb RunAs -Wait -PassThru`,
@@ -115999,15 +116369,15 @@ function makeNetService() {
115999
116369
  }
116000
116370
 
116001
116371
  // ../../packages/host-core/dist/net-service/netd-binary.js
116002
- import { existsSync as existsSync42 } from "node:fs";
116003
- import { dirname as dirname35, join as join80 } from "node:path";
116372
+ import { existsSync as existsSync43 } from "node:fs";
116373
+ import { dirname as dirname36, join as join81 } from "node:path";
116004
116374
  import { fileURLToPath as fileURLToPath7 } from "node:url";
116005
116375
  function netdBinaryName() {
116006
116376
  return process.platform === "win32" ? "tesseract-netd.exe" : "tesseract-netd";
116007
116377
  }
116008
116378
  function override2() {
116009
116379
  const p = process.env.CCB_NETD_BIN;
116010
- return p && existsSync42(p) ? p : null;
116380
+ return p && existsSync43(p) ? p : null;
116011
116381
  }
116012
116382
  function netdBinaryPath() {
116013
116383
  const fromEnv = override2();
@@ -116017,24 +116387,24 @@ function netdBinaryPath() {
116017
116387
  const candidates = [];
116018
116388
  const resources = process.resourcesPath;
116019
116389
  if (resources)
116020
- candidates.push(join80(resources, "netd", name));
116390
+ candidates.push(join81(resources, "netd", name));
116021
116391
  try {
116022
- const here = dirname35(fileURLToPath7(import.meta.url));
116023
- candidates.push(join80(here, "..", "..", "netd", name));
116024
- candidates.push(join80(here, "..", "..", "..", "netd", name));
116392
+ const here = dirname36(fileURLToPath7(import.meta.url));
116393
+ candidates.push(join81(here, "..", "..", "netd", name));
116394
+ candidates.push(join81(here, "..", "..", "..", "netd", name));
116025
116395
  const triple = `${process.platform}-${process.arch}`;
116026
- for (const root of [here, join80(here, ".."), join80(here, "..", "..")]) {
116027
- candidates.push(join80(root, "mesh-core", "prebuilds", triple, "netd", name));
116396
+ for (const root of [here, join81(here, ".."), join81(here, "..", "..")]) {
116397
+ candidates.push(join81(root, "mesh-core", "prebuilds", triple, "netd", name));
116028
116398
  }
116029
116399
  } catch {
116030
116400
  }
116031
116401
  if (process.env.CCB_REPO_ROOT) {
116032
- candidates.push(join80(process.env.CCB_REPO_ROOT, "crates", "target", "release", name));
116402
+ candidates.push(join81(process.env.CCB_REPO_ROOT, "crates", "target", "release", name));
116033
116403
  }
116034
- candidates.push(join80(process.cwd(), "crates", "target", "release", name));
116404
+ candidates.push(join81(process.cwd(), "crates", "target", "release", name));
116035
116405
  for (const c of candidates) {
116036
116406
  try {
116037
- if (existsSync42(c))
116407
+ if (existsSync43(c))
116038
116408
  return c;
116039
116409
  } catch {
116040
116410
  }
@@ -116076,7 +116446,7 @@ async function ensureNetHelperInstalled() {
116076
116446
  if (st.installed && !mismatched)
116077
116447
  return { ok: true, already: true };
116078
116448
  const exec2 = netdBinaryPath();
116079
- if (exec2 && process.platform === "win32" && !existsSync43(join81(dirname36(exec2), "wintun.dll"))) {
116449
+ if (exec2 && process.platform === "win32" && !existsSync44(join82(dirname37(exec2), "wintun.dll"))) {
116080
116450
  return {
116081
116451
  ok: false,
116082
116452
  reason: "no-binary",
@@ -116128,8 +116498,8 @@ import { platform as platform6 } from "node:os";
116128
116498
 
116129
116499
  // ../../packages/host-core/dist/service/launchd.js
116130
116500
  init_credentials();
116131
- import { writeFileSync as writeFileSync43, existsSync as existsSync44, mkdirSync as mkdirSync42, unlinkSync as unlinkSync7 } from "node:fs";
116132
- import { dirname as dirname37, join as join82 } from "node:path";
116501
+ import { writeFileSync as writeFileSync44, existsSync as existsSync45, mkdirSync as mkdirSync43, unlinkSync as unlinkSync8 } from "node:fs";
116502
+ import { dirname as dirname38, join as join83 } from "node:path";
116133
116503
  import { homedir as homedir13, userInfo as userInfo2 } from "node:os";
116134
116504
  function xml2(s) {
116135
116505
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -116137,10 +116507,10 @@ function xml2(s) {
116137
116507
  function makeLaunchd(instanceId) {
116138
116508
  const suffix = instanceSuffix(instanceId);
116139
116509
  const label = SERVICE_LABEL_BASE + (suffix ? `.${suffix}` : "");
116140
- const plistPath = () => join82(homedir13(), "Library", "LaunchAgents", `${label}.plist`);
116510
+ const plistPath = () => join83(homedir13(), "Library", "LaunchAgents", `${label}.plist`);
116141
116511
  const domainTarget = () => `gui/${userInfo2().uid}`;
116142
116512
  const serviceTarget = () => `${domainTarget()}/${label}`;
116143
- const logFile = () => join82(daemonDir2(), "daemon.log");
116513
+ const logFile = () => join83(daemonDir2(), "daemon.log");
116144
116514
  const workDirOf = (spec) => spec.workingDirectory ?? daemonDir2();
116145
116515
  function buildPlist2(spec) {
116146
116516
  const args = [spec.exec, ...spec.args].map((a) => ` <string>${xml2(a)}</string>`).join("\n");
@@ -116215,10 +116585,10 @@ ${env}
116215
116585
  };
116216
116586
  return {
116217
116587
  async install(spec) {
116218
- mkdirSync42(workDirOf(spec), { recursive: true });
116219
- mkdirSync42(dirname37(plistPath()), { recursive: true });
116220
- mkdirSync42(dirname37(spec.logPath), { recursive: true });
116221
- writeFileSync43(plistPath(), buildPlist2(spec));
116588
+ mkdirSync43(workDirOf(spec), { recursive: true });
116589
+ mkdirSync43(dirname38(plistPath()), { recursive: true });
116590
+ mkdirSync43(dirname38(spec.logPath), { recursive: true });
116591
+ writeFileSync44(plistPath(), buildPlist2(spec));
116222
116592
  await run5("launchctl", ["bootout", serviceTarget()]).catch(() => {
116223
116593
  });
116224
116594
  await untilGone();
@@ -116234,9 +116604,9 @@ ${env}
116234
116604
  async uninstall() {
116235
116605
  await run5("launchctl", ["bootout", serviceTarget()]).catch(() => {
116236
116606
  });
116237
- if (existsSync44(plistPath())) {
116607
+ if (existsSync45(plistPath())) {
116238
116608
  try {
116239
- unlinkSync7(plistPath());
116609
+ unlinkSync8(plistPath());
116240
116610
  } catch {
116241
116611
  }
116242
116612
  }
@@ -116245,7 +116615,7 @@ ${env}
116245
116615
  await this.install(spec);
116246
116616
  },
116247
116617
  async isInstalled() {
116248
- return existsSync44(plistPath());
116618
+ return existsSync45(plistPath());
116249
116619
  },
116250
116620
  async start() {
116251
116621
  await run5("launchctl", ["bootstrap", domainTarget(), plistPath()]).catch(() => {
@@ -116262,7 +116632,7 @@ ${env}
116262
116632
  },
116263
116633
  async logs(follow) {
116264
116634
  const f = logFile();
116265
- if (!existsSync44(f)) {
116635
+ if (!existsSync45(f)) {
116266
116636
  console.log(`No log yet at ${f} \u2014 has the service started?`);
116267
116637
  return;
116268
116638
  }
@@ -116273,8 +116643,8 @@ ${env}
116273
116643
 
116274
116644
  // ../../packages/host-core/dist/service/systemd.js
116275
116645
  init_credentials();
116276
- import { writeFileSync as writeFileSync44, existsSync as existsSync45, mkdirSync as mkdirSync43, unlinkSync as unlinkSync8 } from "node:fs";
116277
- import { dirname as dirname38, join as join83 } from "node:path";
116646
+ import { writeFileSync as writeFileSync45, existsSync as existsSync46, mkdirSync as mkdirSync44, unlinkSync as unlinkSync9 } from "node:fs";
116647
+ import { dirname as dirname39, join as join84 } from "node:path";
116278
116648
  import { homedir as homedir14, userInfo as userInfo3 } from "node:os";
116279
116649
  function unitVal2(v) {
116280
116650
  return v.replace(/%/g, "%%");
@@ -116286,8 +116656,8 @@ function makeSystemd(instanceId) {
116286
116656
  const suffix = instanceSuffix(instanceId);
116287
116657
  const unit = `tesseract-host${suffix ? `-${suffix}` : ""}.service`;
116288
116658
  const unitPath = () => {
116289
- const base = process.env.XDG_CONFIG_HOME || join83(homedir14(), ".config");
116290
- return join83(base, "systemd", "user", unit);
116659
+ const base = process.env.XDG_CONFIG_HOME || join84(homedir14(), ".config");
116660
+ return join84(base, "systemd", "user", unit);
116291
116661
  };
116292
116662
  const workDirOf = (spec) => spec.workingDirectory ?? daemonDir2();
116293
116663
  function buildUnit2(spec) {
@@ -116314,10 +116684,10 @@ WantedBy=default.target
116314
116684
  }
116315
116685
  return {
116316
116686
  async install(spec) {
116317
- mkdirSync43(workDirOf(spec), { recursive: true });
116318
- mkdirSync43(dirname38(unitPath()), { recursive: true });
116319
- mkdirSync43(dirname38(spec.logPath), { recursive: true });
116320
- writeFileSync44(unitPath(), buildUnit2(spec));
116687
+ mkdirSync44(workDirOf(spec), { recursive: true });
116688
+ mkdirSync44(dirname39(unitPath()), { recursive: true });
116689
+ mkdirSync44(dirname39(spec.logPath), { recursive: true });
116690
+ writeFileSync45(unitPath(), buildUnit2(spec));
116321
116691
  await run5("loginctl", ["enable-linger", userInfo3().username]).catch(() => {
116322
116692
  });
116323
116693
  await run5("systemctl", ["--user", "daemon-reload"]).catch(() => {
@@ -116329,9 +116699,9 @@ WantedBy=default.target
116329
116699
  async uninstall() {
116330
116700
  await run5("systemctl", ["--user", "disable", "--now", unit]).catch(() => {
116331
116701
  });
116332
- if (existsSync45(unitPath())) {
116702
+ if (existsSync46(unitPath())) {
116333
116703
  try {
116334
- unlinkSync8(unitPath());
116704
+ unlinkSync9(unitPath());
116335
116705
  } catch {
116336
116706
  }
116337
116707
  }
@@ -116342,7 +116712,7 @@ WantedBy=default.target
116342
116712
  await this.install(spec);
116343
116713
  },
116344
116714
  async isInstalled() {
116345
- return existsSync45(unitPath());
116715
+ return existsSync46(unitPath());
116346
116716
  },
116347
116717
  async start() {
116348
116718
  await run5("systemctl", ["--user", "start", unit]);
@@ -116354,8 +116724,8 @@ WantedBy=default.target
116354
116724
  await runInherit("systemctl", ["--user", "status", unit, "--no-pager"]);
116355
116725
  },
116356
116726
  async logs(follow) {
116357
- const f = join83(daemonDir2(), "daemon.log");
116358
- if (existsSync45(f)) {
116727
+ const f = join84(daemonDir2(), "daemon.log");
116728
+ if (existsSync46(f)) {
116359
116729
  await runInherit("tail", follow ? ["-f", f] : ["-n", "200", f]);
116360
116730
  return;
116361
116731
  }
@@ -116367,12 +116737,12 @@ WantedBy=default.target
116367
116737
 
116368
116738
  // ../../packages/host-core/dist/service/windows.js
116369
116739
  init_credentials();
116370
- import { writeFileSync as writeFileSync45, existsSync as existsSync46, mkdirSync as mkdirSync44, unlinkSync as unlinkSync9, readFileSync as readFileSync52 } from "node:fs";
116371
- import { dirname as dirname39, join as join84 } from "node:path";
116740
+ import { writeFileSync as writeFileSync46, existsSync as existsSync47, mkdirSync as mkdirSync45, unlinkSync as unlinkSync10, readFileSync as readFileSync53 } from "node:fs";
116741
+ import { dirname as dirname40, join as join85 } from "node:path";
116372
116742
  function publishedDaemonPid(dir2) {
116373
116743
  for (const f of ["status.json", "daemon.lock"]) {
116374
116744
  try {
116375
- const raw = readFileSync52(join84(dir2, f), "utf-8");
116745
+ const raw = readFileSync53(join85(dir2, f), "utf-8");
116376
116746
  const pid = f === "status.json" ? Number(JSON.parse(raw).pid) : Number(raw.trim());
116377
116747
  if (Number.isInteger(pid) && pid > 0)
116378
116748
  return pid;
@@ -116384,8 +116754,8 @@ function publishedDaemonPid(dir2) {
116384
116754
  function makeWindowsTask(instanceId) {
116385
116755
  const suffix = instanceSuffix(instanceId);
116386
116756
  const task = `Fineguide\\TesseractHost${suffix ? `-${suffix}` : ""}`;
116387
- const wrapperPath = () => join84(daemonDir2(), `run-host${suffix ? `-${suffix}` : ""}.cmd`);
116388
- const logFile = () => join84(daemonDir2(), "daemon.log");
116757
+ const wrapperPath = () => join85(daemonDir2(), `run-host${suffix ? `-${suffix}` : ""}.cmd`);
116758
+ const logFile = () => join85(daemonDir2(), "daemon.log");
116389
116759
  const oneLine2 = (s) => s.replace(/[\r\n]+/g, " ");
116390
116760
  const envVal = (v) => oneLine2(v).replace(/%/g, "%%").replace(/"/g, "");
116391
116761
  const cmdArg = (a) => `"${oneLine2(a).replace(/"/g, "")}"`;
@@ -116401,10 +116771,10 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
116401
116771
  }
116402
116772
  return {
116403
116773
  async install(spec) {
116404
- mkdirSync44(spec.workingDirectory ?? daemonDir2(), { recursive: true });
116405
- mkdirSync44(dirname39(spec.logPath), { recursive: true });
116406
- mkdirSync44(dirname39(wrapperPath()), { recursive: true });
116407
- writeFileSync45(wrapperPath(), buildWrapper(spec));
116774
+ mkdirSync45(spec.workingDirectory ?? daemonDir2(), { recursive: true });
116775
+ mkdirSync45(dirname40(spec.logPath), { recursive: true });
116776
+ mkdirSync45(dirname40(wrapperPath()), { recursive: true });
116777
+ writeFileSync46(wrapperPath(), buildWrapper(spec));
116408
116778
  await run5("schtasks", ["/Create", "/TN", task, "/SC", "ONLOGON", "/RL", "LIMITED", "/F", "/TR", `"${wrapperPath()}"`]);
116409
116779
  await run5("schtasks", ["/Run", "/TN", task]).catch(() => {
116410
116780
  });
@@ -116412,9 +116782,9 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
116412
116782
  async uninstall() {
116413
116783
  await run5("schtasks", ["/Delete", "/TN", task, "/F"]).catch(() => {
116414
116784
  });
116415
- if (existsSync46(wrapperPath())) {
116785
+ if (existsSync47(wrapperPath())) {
116416
116786
  try {
116417
- unlinkSync9(wrapperPath());
116787
+ unlinkSync10(wrapperPath());
116418
116788
  } catch {
116419
116789
  }
116420
116790
  }
@@ -116486,7 +116856,7 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
116486
116856
  },
116487
116857
  async logs(follow) {
116488
116858
  const f = logFile();
116489
- if (!existsSync46(f)) {
116859
+ if (!existsSync47(f)) {
116490
116860
  console.log(`No log yet at ${f} \u2014 has the task run?`);
116491
116861
  return;
116492
116862
  }
@@ -116517,9 +116887,8 @@ init_safe_kill();
116517
116887
 
116518
116888
  // src/auth.ts
116519
116889
  var import_qrcode_terminal = __toESM(require_main(), 1);
116520
- import { randomUUID as randomUUID30 } from "node:crypto";
116521
- import { existsSync as existsSync47, rmSync as rmSync12 } from "node:fs";
116522
- import { join as join85 } from "node:path";
116890
+ import { existsSync as existsSync48, rmSync as rmSync12 } from "node:fs";
116891
+ import { join as join86 } from "node:path";
116523
116892
 
116524
116893
  // src/config.ts
116525
116894
  import { hostname as hostname6 } from "node:os";
@@ -116659,7 +117028,7 @@ async function login(opts) {
116659
117028
  process.exit(1);
116660
117029
  }
116661
117030
  }
116662
- const deviceId3 = readCredentials()?.deviceId ?? process.env.CCB_DEVICE_ID ?? randomUUID30().slice(0, 8);
117031
+ const deviceId3 = readCredentials()?.deviceId ?? process.env.CCB_DEVICE_ID ?? persistentDeviceId();
116663
117032
  const label = opts.name ?? defaultLabel();
116664
117033
  if (opts.token) {
116665
117034
  const dt = await fetchJson(`${api}/auth/device-token`, {
@@ -116720,8 +117089,8 @@ async function logout() {
116720
117089
  }
116721
117090
  for (const f of ["credentials.json", "status.json", "daemon.lock"]) {
116722
117091
  try {
116723
- const p = join85(daemonDir2(), f);
116724
- if (existsSync47(p)) rmSync12(p);
117092
+ const p = join86(daemonDir2(), f);
117093
+ if (existsSync48(p)) rmSync12(p);
116725
117094
  } catch {
116726
117095
  }
116727
117096
  }
@@ -116879,9 +117248,9 @@ function startSelfUpdater(current) {
116879
117248
  }
116880
117249
 
116881
117250
  // src/service.ts
116882
- import { join as join86 } from "node:path";
117251
+ import { join as join87 } from "node:path";
116883
117252
  import { platform as platform7 } from "node:os";
116884
- import { existsSync as existsSync48, readFileSync as readFileSync53 } from "node:fs";
117253
+ import { existsSync as existsSync49, readFileSync as readFileSync54 } from "node:fs";
116885
117254
  function controller(instanceId) {
116886
117255
  const c = getServiceController(instanceId);
116887
117256
  if (!c) {
@@ -116894,7 +117263,7 @@ function buildSpec(cliEntry) {
116894
117263
  exec: process.execPath,
116895
117264
  args: [cliEntry, "run"],
116896
117265
  env: { CCB_DAEMON_DIR: daemonDir2() },
116897
- logPath: join86(daemonDir2(), "daemon.log")
117266
+ logPath: join87(daemonDir2(), "daemon.log")
116898
117267
  };
116899
117268
  }
116900
117269
  var isAlive = (pid) => {
@@ -116906,10 +117275,10 @@ var isAlive = (pid) => {
116906
117275
  }
116907
117276
  };
116908
117277
  function runningDaemonInfo() {
116909
- const lock = join86(daemonDir2(), "daemon.lock");
117278
+ const lock = join87(daemonDir2(), "daemon.lock");
116910
117279
  try {
116911
- if (!existsSync48(lock)) return null;
116912
- const pid = Number(readFileSync53(lock, "utf-8").trim());
117280
+ if (!existsSync49(lock)) return null;
117281
+ const pid = Number(readFileSync54(lock, "utf-8").trim());
116913
117282
  if (!pid || !isAlive(pid)) return null;
116914
117283
  return { pid, device: readCredentials()?.deviceId };
116915
117284
  } catch {
@@ -116943,7 +117312,7 @@ async function logs(instanceId, follow) {
116943
117312
  }
116944
117313
 
116945
117314
  // src/net.ts
116946
- import { readFileSync as readFileSync55 } from "node:fs";
117315
+ import { readFileSync as readFileSync56 } from "node:fs";
116947
117316
  import { randomBytes as randomBytes11 } from "node:crypto";
116948
117317
  import { hostname as hostname7 } from "node:os";
116949
117318
  import { resolve as resolve14 } from "node:path";
@@ -117008,7 +117377,7 @@ function readOrDie(label, p) {
117008
117377
  process.exit(1);
117009
117378
  }
117010
117379
  try {
117011
- return new Uint8Array(readFileSync55(resolve14(p)));
117380
+ return new Uint8Array(readFileSync56(resolve14(p)));
117012
117381
  } catch (e) {
117013
117382
  console.error(`net enroll: could not read --${label} ${p}: ${e instanceof Error ? e.message : e}`);
117014
117383
  process.exit(1);
@@ -117075,6 +117444,10 @@ async function netCommand(rest, flags) {
117075
117444
  return;
117076
117445
  }
117077
117446
  console.log("mesh engine: ok");
117447
+ if (s.running === false) {
117448
+ console.log(`node: NOT RUNNING \u2014 ${s.lastError ?? "no reason was recorded"}`);
117449
+ return;
117450
+ }
117078
117451
  console.log(`node: running on UDP port ${s.port ?? "?"}`);
117079
117452
  console.log(`node: LAN discovery ${s.lan ? "on" : "off (no multicast on this network)"}`);
117080
117453
  const established = s.established ?? [];
@@ -117561,8 +117934,8 @@ async function netCommand(rest, flags) {
117561
117934
  // src/cli.ts
117562
117935
  function pkgVersion() {
117563
117936
  try {
117564
- const p = join88(dirname40(fileURLToPath8(import.meta.url)), "..", "package.json");
117565
- return JSON.parse(readFileSync56(p, "utf8")).version ?? "0.0.0";
117937
+ const p = join89(dirname41(fileURLToPath8(import.meta.url)), "..", "package.json");
117938
+ return JSON.parse(readFileSync57(p, "utf8")).version ?? "0.0.0";
117566
117939
  } catch {
117567
117940
  return "0.0.0";
117568
117941
  }
@@ -117790,7 +118163,7 @@ async function linkCommand(rest, flags) {
117790
118163
  process.exit(1);
117791
118164
  }
117792
118165
  async function captureClaudeSubscription(flags) {
117793
- const home = mkdtempSync4(join88(tmpdir8(), "tesseract-claude-login-"));
118166
+ const home = mkdtempSync4(join89(tmpdir8(), "tesseract-claude-login-"));
117794
118167
  const binary = typeof flags["claude-path"] === "string" ? flags["claude-path"] : process.env.CCB_ENGINE_PATH_CLAUDE_CODE || "claude";
117795
118168
  const args = ["auth", "login", "--claudeai"];
117796
118169
  if (typeof flags.email === "string") args.push("--email", flags.email);
@@ -117807,8 +118180,8 @@ async function captureClaudeSubscription(flags) {
117807
118180
  child.once("close", (exitCode, signal) => resolveCode(signal ? 1 : exitCode ?? 1));
117808
118181
  });
117809
118182
  if (code !== 0) throw new Error(`Claude sign-in did not complete (exit ${code}).`);
117810
- const file2 = join88(home, ".credentials.json");
117811
- if (existsSync50(file2)) return readFileSync56(file2, "utf8");
118183
+ const file2 = join89(home, ".credentials.json");
118184
+ if (existsSync51(file2)) return readFileSync57(file2, "utf8");
117812
118185
  if (process.platform === "darwin") {
117813
118186
  const value = execFileSync6("security", [
117814
118187
  "find-generic-password",
@@ -117890,7 +118263,7 @@ async function runnerCommand(rest, flags) {
117890
118263
  process.exit(1);
117891
118264
  }
117892
118265
  const oauthFilePath = typeof flags["oauth-file"] === "string" ? resolve15(flags["oauth-file"]) : void 0;
117893
- const oauthAuthFile = oauthFilePath ? readFileSync56(oauthFilePath, "utf8") : void 0;
118266
+ const oauthAuthFile = oauthFilePath ? readFileSync57(oauthFilePath, "utf8") : void 0;
117894
118267
  if (oauthAuthFile) {
117895
118268
  try {
117896
118269
  JSON.parse(oauthAuthFile);