@askexenow/exe-os 0.9.92 → 0.9.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/deploy/compose/docker-compose.yml +1 -0
  2. package/dist/bin/agentic-ontology-backfill.js +65 -8
  3. package/dist/bin/agentic-reflection-backfill.js +54 -3
  4. package/dist/bin/agentic-semantic-label.js +54 -3
  5. package/dist/bin/backfill-conversations.js +69 -9
  6. package/dist/bin/backfill-responses.js +69 -9
  7. package/dist/bin/backfill-vectors.js +54 -3
  8. package/dist/bin/bulk-sync-postgres.js +66 -8
  9. package/dist/bin/cleanup-stale-review-tasks.js +118 -13
  10. package/dist/bin/cli.js +1605 -456
  11. package/dist/bin/customer-readiness.js +51 -0
  12. package/dist/bin/exe-agent.js +17 -3
  13. package/dist/bin/exe-assign.js +75 -9
  14. package/dist/bin/exe-boot.js +111 -12
  15. package/dist/bin/exe-call.js +17 -3
  16. package/dist/bin/exe-cloud.js +76 -10
  17. package/dist/bin/exe-dispatch.js +133 -18
  18. package/dist/bin/exe-doctor.js +75 -9
  19. package/dist/bin/exe-export-behaviors.js +75 -9
  20. package/dist/bin/exe-forget.js +94 -9
  21. package/dist/bin/exe-gateway.js +132 -18
  22. package/dist/bin/exe-heartbeat.js +118 -13
  23. package/dist/bin/exe-kill.js +75 -9
  24. package/dist/bin/exe-launch-agent.js +75 -9
  25. package/dist/bin/exe-new-employee.js +18 -4
  26. package/dist/bin/exe-pending-messages.js +118 -13
  27. package/dist/bin/exe-pending-notifications.js +118 -13
  28. package/dist/bin/exe-pending-reviews.js +118 -13
  29. package/dist/bin/exe-rename.js +75 -9
  30. package/dist/bin/exe-review.js +75 -9
  31. package/dist/bin/exe-search.js +100 -9
  32. package/dist/bin/exe-session-cleanup.js +133 -18
  33. package/dist/bin/exe-settings.js +1 -0
  34. package/dist/bin/exe-start-codex.js +65 -8
  35. package/dist/bin/exe-start-opencode.js +65 -8
  36. package/dist/bin/exe-status.js +118 -13
  37. package/dist/bin/exe-support.js +1 -0
  38. package/dist/bin/exe-team.js +75 -9
  39. package/dist/bin/git-sweep.js +133 -18
  40. package/dist/bin/graph-backfill.js +65 -8
  41. package/dist/bin/graph-export.js +75 -9
  42. package/dist/bin/intercom-check.js +133 -18
  43. package/dist/bin/scan-tasks.js +133 -18
  44. package/dist/bin/setup.js +55 -4
  45. package/dist/bin/shard-migrate.js +65 -8
  46. package/dist/bin/stack-update.js +57 -1
  47. package/dist/bin/update.js +1 -1
  48. package/dist/gateway/index.js +133 -18
  49. package/dist/hooks/bug-report-worker.js +133 -18
  50. package/dist/hooks/codex-stop-task-finalizer.js +123 -14
  51. package/dist/hooks/commit-complete.js +133 -18
  52. package/dist/hooks/error-recall.js +100 -9
  53. package/dist/hooks/ingest.js +75 -9
  54. package/dist/hooks/instructions-loaded.js +75 -9
  55. package/dist/hooks/notification.js +75 -9
  56. package/dist/hooks/post-compact.js +310 -50
  57. package/dist/hooks/post-tool-combined.js +433 -13
  58. package/dist/hooks/pre-compact.js +133 -18
  59. package/dist/hooks/pre-tool-use.js +118 -13
  60. package/dist/hooks/prompt-submit.js +191 -19
  61. package/dist/hooks/session-end.js +133 -18
  62. package/dist/hooks/session-start.js +143 -13
  63. package/dist/hooks/stop.js +118 -13
  64. package/dist/hooks/subagent-stop.js +118 -13
  65. package/dist/hooks/summary-worker.js +96 -7
  66. package/dist/index.js +133 -18
  67. package/dist/lib/cloud-sync.js +38 -0
  68. package/dist/lib/consolidation.js +3 -1
  69. package/dist/lib/database.js +37 -0
  70. package/dist/lib/db.js +37 -0
  71. package/dist/lib/device-registry.js +37 -0
  72. package/dist/lib/employee-templates.js +17 -3
  73. package/dist/lib/exe-daemon.js +913 -42
  74. package/dist/lib/hybrid-search.js +100 -9
  75. package/dist/lib/license.js +1 -1
  76. package/dist/lib/messaging.js +40 -4
  77. package/dist/lib/schedules.js +54 -3
  78. package/dist/lib/store.js +75 -9
  79. package/dist/lib/tasks.js +58 -9
  80. package/dist/lib/tmux-routing.js +58 -9
  81. package/dist/mcp/server.js +875 -42
  82. package/dist/mcp/tools/create-task.js +67 -12
  83. package/dist/mcp/tools/list-tasks.js +46 -5
  84. package/dist/mcp/tools/send-message.js +40 -4
  85. package/dist/mcp/tools/update-task.js +58 -9
  86. package/dist/runtime/index.js +133 -18
  87. package/dist/tui/App.js +132 -18
  88. package/package.json +1 -1
@@ -2776,6 +2776,20 @@ async function ensureSchema() {
2776
2776
  });
2777
2777
  } catch {
2778
2778
  }
2779
+ try {
2780
+ await client.execute({
2781
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
2782
+ args: []
2783
+ });
2784
+ } catch {
2785
+ }
2786
+ try {
2787
+ await client.execute({
2788
+ sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
2789
+ args: []
2790
+ });
2791
+ } catch {
2792
+ }
2779
2793
  await client.executeMultiple(`
2780
2794
  CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
2781
2795
  content_text,
@@ -3027,6 +3041,22 @@ async function ensureSchema() {
3027
3041
  );
3028
3042
  } catch {
3029
3043
  }
3044
+ for (const col of [
3045
+ "ALTER TABLE memories ADD COLUMN valid_from TEXT",
3046
+ "ALTER TABLE memories ADD COLUMN invalid_at TEXT"
3047
+ ]) {
3048
+ try {
3049
+ await client.execute(col);
3050
+ } catch {
3051
+ }
3052
+ }
3053
+ try {
3054
+ await client.execute({
3055
+ sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
3056
+ args: []
3057
+ });
3058
+ } catch {
3059
+ }
3030
3060
  try {
3031
3061
  await client.execute({
3032
3062
  sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
@@ -3069,6 +3099,13 @@ async function ensureSchema() {
3069
3099
  } catch {
3070
3100
  }
3071
3101
  }
3102
+ try {
3103
+ await client.execute({
3104
+ sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
3105
+ args: []
3106
+ });
3107
+ } catch {
3108
+ }
3072
3109
  try {
3073
3110
  await client.execute({
3074
3111
  sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
@@ -4207,6 +4244,20 @@ var init_platform_procedures = __esm({
4207
4244
  priority: "p1",
4208
4245
  content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
4209
4246
  },
4247
+ // --- Tool guidance ---
4248
+ {
4249
+ title: "How to use company_actions \u2014 execute business actions through gateway connectors",
4250
+ domain: "tools",
4251
+ priority: "p2",
4252
+ content: "The company_actions tool executes business actions through gateway connectors (e.g. send WhatsApp, trigger workflows, update CRM). It routes through the exe-gateway on the VPS. Actions are defined by the customer's gateway configuration \u2014 each connector (WhatsApp, Shopify, email, etc.) exposes specific actions. Use query_company_brain to find available data first, then company_actions to act on it. Requires gateway auth token. Read-only founders should NOT use this \u2014 it mutates external state."
4253
+ },
4254
+ // --- Release awareness ---
4255
+ {
4256
+ title: "What's New check \u2014 surface new features after update",
4257
+ domain: "support",
4258
+ priority: "p1",
4259
+ content: "Once per session (COO boot only, never repeat), check if the installed exe-os version is newer than the last session. If it is, read the bundled release-notes.json (at the package root) and surface a brief summary to the founder: 'Updated to exe-os vX.Y.Z \u2014 N new features, M fixes.' List the top 3 features by name. This helps the founder know what they got from the update. If release-notes.json doesn't exist or the version hasn't changed, skip silently. Never repeat this check in the same session."
4260
+ },
4210
4261
  // --- Platform vs Customer ownership ---
4211
4262
  {
4212
4263
  title: "What the platform provides vs what you customize",
@@ -4295,13 +4346,13 @@ var init_platform_procedures = __esm({
4295
4346
  title: "MCP tools \u2014 memory, decision, and search",
4296
4347
  domain: "tool-use",
4297
4348
  priority: "p1",
4298
- content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
4349
+ content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). Supports as_of param for bi-temporal queries (what did I know at time X?), kind param to filter by memory type (decision, procedure, observation, raw, conversation, behavior). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. Supports kind param and procedure_for domain tag for procedure-type memories. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. memory(action="supersede") / supersede: replace an old memory with a new version (old_id + new text). decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
4299
4350
  },
4300
4351
  {
4301
4352
  title: "MCP tools \u2014 task orchestration",
4302
4353
  domain: "tool-use",
4303
4354
  priority: "p1",
4304
- content: 'task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.'
4355
+ content: `task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. Supports spawn_runtime and spawn_model params to override the agent's default runtime/model for a specific task. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.`
4305
4356
  },
4306
4357
  {
4307
4358
  title: "MCP tools \u2014 knowledge graph (GraphRAG)",
@@ -4331,7 +4382,7 @@ var init_platform_procedures = __esm({
4331
4382
  title: "MCP tools \u2014 admin, config, and operations",
4332
4383
  domain: "tool-use",
4333
4384
  priority: "p1",
4334
- content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. mcp_ping(): daemon health + license status + tool usage stats.'
4385
+ content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. diagnostics(action="tool_search"): semantic tool discovery \u2014 find relevant MCP tools by natural language query. Returns top-K tools ranked by relevance. diagnostics(action="drift"): identity drift detection \u2014 score how far an agent has drifted from its role identity. Returns drift score + recommendations. mcp_ping(): daemon health + license status + tool usage stats.'
4335
4386
  }
4336
4387
  ];
4337
4388
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -5015,6 +5066,8 @@ async function writeMemory(record) {
5015
5066
  source_type: record.source_type ?? null,
5016
5067
  tier: record.tier ?? classifyTier(record),
5017
5068
  supersedes_id: record.supersedes_id ?? null,
5069
+ valid_from: record.valid_from ?? record.timestamp,
5070
+ invalid_at: record.invalid_at ?? null,
5018
5071
  draft: record.draft ? 1 : 0,
5019
5072
  memory_type: memoryType,
5020
5073
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
@@ -5033,7 +5086,8 @@ async function writeMemory(record) {
5033
5086
  token_cost: record.token_cost ?? null,
5034
5087
  audience: record.audience ?? null,
5035
5088
  language_type: record.language_type ?? inferLanguageType(record),
5036
- parent_memory_id: record.parent_memory_id ?? null
5089
+ parent_memory_id: record.parent_memory_id ?? null,
5090
+ procedure_for: record.procedure_for ?? null
5037
5091
  };
5038
5092
  _pendingRecords.push(dbRow);
5039
5093
  orgBus.emit({
@@ -5088,6 +5142,8 @@ async function flushBatch() {
5088
5142
  const sourceType = row.source_type ?? null;
5089
5143
  const tier = row.tier ?? 3;
5090
5144
  const supersedesId = row.supersedes_id ?? null;
5145
+ const validFrom = row.valid_from ?? row.timestamp;
5146
+ const invalidAt = row.invalid_at ?? null;
5091
5147
  const draft = row.draft ? 1 : 0;
5092
5148
  const memoryType = row.memory_type ?? "raw";
5093
5149
  const trajectory = row.trajectory ?? null;
@@ -5107,15 +5163,16 @@ async function flushBatch() {
5107
5163
  const audience = row.audience ?? null;
5108
5164
  const languageType = row.language_type ?? null;
5109
5165
  const parentMemoryId = row.parent_memory_id ?? null;
5166
+ const procedureFor = row.procedure_for ?? null;
5110
5167
  const cols = `id, agent_id, agent_role, session_id, timestamp,
5111
5168
  tool_name, project_name,
5112
5169
  has_error, raw_text, vector, version, task_id, importance, status,
5113
5170
  confidence, last_accessed,
5114
5171
  workspace_id, document_id, user_id, char_offset, page_number,
5115
- source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
5172
+ source_path, source_type, tier, supersedes_id, valid_from, invalid_at, draft, memory_type, trajectory, content_hash,
5116
5173
  intent, outcome, domain, referenced_entities, retrieval_count,
5117
5174
  chain_position, review_status, context_window_pct, file_paths, commit_hash,
5118
- duration_ms, token_cost, audience, language_type, parent_memory_id`;
5175
+ duration_ms, token_cost, audience, language_type, parent_memory_id, procedure_for`;
5119
5176
  const metaArgs = [
5120
5177
  intent,
5121
5178
  outcome,
@@ -5131,7 +5188,8 @@ async function flushBatch() {
5131
5188
  tokenCost,
5132
5189
  audience,
5133
5190
  languageType,
5134
- parentMemoryId
5191
+ parentMemoryId,
5192
+ procedureFor
5135
5193
  ];
5136
5194
  const baseArgs = [
5137
5195
  row.id,
@@ -5160,6 +5218,8 @@ async function flushBatch() {
5160
5218
  sourceType,
5161
5219
  tier,
5162
5220
  supersedesId,
5221
+ validFrom,
5222
+ invalidAt,
5163
5223
  draft,
5164
5224
  memoryType,
5165
5225
  trajectory,
@@ -5167,8 +5227,8 @@ async function flushBatch() {
5167
5227
  ];
5168
5228
  return {
5169
5229
  sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
5170
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
5171
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5230
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
5231
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
5172
5232
  args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
5173
5233
  };
5174
5234
  };
@@ -5284,6 +5344,12 @@ async function searchMemories(queryVector, agentId, options) {
5284
5344
  AND vector IS NOT NULL${statusFilter}${draftFilter}
5285
5345
  AND COALESCE(confidence, 0.7) >= 0.3`;
5286
5346
  const args = [agentId];
5347
+ if (options?.asOf) {
5348
+ sql += ` AND (valid_from IS NULL OR valid_from <= ?) AND (invalid_at IS NULL OR invalid_at > ?)`;
5349
+ args.push(options.asOf, options.asOf);
5350
+ } else {
5351
+ sql += ` AND invalid_at IS NULL`;
5352
+ }
5287
5353
  const scope = buildWikiScopeFilter(options, "");
5288
5354
  sql += scope.clause;
5289
5355
  args.push(...scope.args);
@@ -5752,7 +5818,7 @@ import { pathToFileURL as pathToFileURL2 } from "url";
5752
5818
  import os8 from "os";
5753
5819
  import path11 from "path";
5754
5820
  import { jwtVerify, importSPKI } from "jose";
5755
- var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
5821
+ var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE;
5756
5822
  var init_license = __esm({
5757
5823
  "src/lib/license.ts"() {
5758
5824
  "use strict";
@@ -5760,6 +5826,7 @@ var init_license = __esm({
5760
5826
  LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
5761
5827
  CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
5762
5828
  DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
5829
+ API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
5763
5830
  }
5764
5831
  });
5765
5832
 
@@ -5803,6 +5870,9 @@ import { fileURLToPath as fileURLToPath2 } from "url";
5803
5870
  function getMySession() {
5804
5871
  return getTransport().getMySession();
5805
5872
  }
5873
+ function isRootSession(name) {
5874
+ return name.length > 0 && !name.includes("-");
5875
+ }
5806
5876
  function extractRootExe(name) {
5807
5877
  if (!name) return null;
5808
5878
  if (!name.includes("-")) return name;
@@ -5821,6 +5891,7 @@ function resolveExeSession() {
5821
5891
  const mySession = getMySession();
5822
5892
  if (!mySession) return null;
5823
5893
  const fromSessionName = extractRootExe(mySession);
5894
+ let candidate = null;
5824
5895
  try {
5825
5896
  const key = getSessionKey();
5826
5897
  const parentExe = getParentExe(key);
@@ -5831,13 +5902,47 @@ function resolveExeSession() {
5831
5902
  `[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
5832
5903
  `
5833
5904
  );
5834
- return fromSessionName;
5905
+ candidate = fromSessionName;
5906
+ } else {
5907
+ candidate = fromCache;
5835
5908
  }
5836
- return fromCache;
5837
5909
  }
5838
5910
  } catch {
5839
5911
  }
5840
- return fromSessionName ?? mySession;
5912
+ if (!candidate) {
5913
+ candidate = fromSessionName ?? mySession;
5914
+ }
5915
+ if (candidate && isRootSession(candidate)) {
5916
+ try {
5917
+ const transport = getTransport();
5918
+ const liveSessions = transport.listSessions();
5919
+ if (!liveSessions.includes(candidate)) {
5920
+ const liveRoots = liveSessions.filter((s) => isRootSession(s));
5921
+ if (liveRoots.length === 1) {
5922
+ process.stderr.write(
5923
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
5924
+ `
5925
+ );
5926
+ return liveRoots[0];
5927
+ } else if (liveRoots.length > 1) {
5928
+ const base = candidate.replace(/\d+$/, "");
5929
+ const match = liveRoots.find((s) => s.startsWith(base));
5930
+ const chosen = match ?? liveRoots[0];
5931
+ process.stderr.write(
5932
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
5933
+ `
5934
+ );
5935
+ return chosen;
5936
+ }
5937
+ process.stderr.write(
5938
+ `[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
5939
+ `
5940
+ );
5941
+ }
5942
+ } catch {
5943
+ }
5944
+ }
5945
+ return candidate;
5841
5946
  }
5842
5947
  var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
5843
5948
  var init_tmux_routing = __esm({