@askexenow/exe-os 0.9.38 → 0.9.39

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 (69) hide show
  1. package/dist/bin/backfill-conversations.js +34 -7
  2. package/dist/bin/backfill-responses.js +34 -7
  3. package/dist/bin/backfill-vectors.js +34 -7
  4. package/dist/bin/cleanup-stale-review-tasks.js +35 -8
  5. package/dist/bin/cli.js +72 -42
  6. package/dist/bin/exe-agent.js +11 -3
  7. package/dist/bin/exe-assign.js +34 -7
  8. package/dist/bin/exe-boot.js +48 -18
  9. package/dist/bin/exe-call.js +132 -340
  10. package/dist/bin/exe-dispatch.js +34 -7
  11. package/dist/bin/exe-doctor.js +37 -10
  12. package/dist/bin/exe-export-behaviors.js +36 -9
  13. package/dist/bin/exe-forget.js +34 -7
  14. package/dist/bin/exe-gateway.js +40 -12
  15. package/dist/bin/exe-heartbeat.js +35 -8
  16. package/dist/bin/exe-kill.js +34 -7
  17. package/dist/bin/exe-launch-agent.js +285 -1079
  18. package/dist/bin/exe-new-employee.js +29 -10
  19. package/dist/bin/exe-pending-messages.js +34 -7
  20. package/dist/bin/exe-pending-notifications.js +34 -7
  21. package/dist/bin/exe-pending-reviews.js +34 -7
  22. package/dist/bin/exe-rename.js +41 -13
  23. package/dist/bin/exe-review.js +34 -7
  24. package/dist/bin/exe-search.js +36 -9
  25. package/dist/bin/exe-session-cleanup.js +36 -9
  26. package/dist/bin/exe-start-codex.js +36 -9
  27. package/dist/bin/exe-start-opencode.js +36 -9
  28. package/dist/bin/exe-status.js +35 -8
  29. package/dist/bin/exe-team.js +34 -7
  30. package/dist/bin/git-sweep.js +34 -7
  31. package/dist/bin/graph-backfill.js +34 -7
  32. package/dist/bin/graph-export.js +34 -7
  33. package/dist/bin/install.js +2 -1
  34. package/dist/bin/intercom-check.js +36 -9
  35. package/dist/bin/scan-tasks.js +34 -7
  36. package/dist/bin/setup.js +18 -17
  37. package/dist/bin/shard-migrate.js +34 -7
  38. package/dist/gateway/index.js +38 -10
  39. package/dist/hooks/bug-report-worker.js +38 -10
  40. package/dist/hooks/codex-stop-task-finalizer.js +36 -9
  41. package/dist/hooks/commit-complete.js +34 -7
  42. package/dist/hooks/error-recall.js +36 -9
  43. package/dist/hooks/ingest.js +36 -8
  44. package/dist/hooks/instructions-loaded.js +42 -10
  45. package/dist/hooks/notification.js +34 -7
  46. package/dist/hooks/post-compact.js +34 -7
  47. package/dist/hooks/post-tool-combined.js +37 -10
  48. package/dist/hooks/pre-compact.js +35 -8
  49. package/dist/hooks/pre-tool-use.js +36 -8
  50. package/dist/hooks/prompt-submit.js +41 -13
  51. package/dist/hooks/session-end.js +35 -8
  52. package/dist/hooks/session-start.js +47 -14
  53. package/dist/hooks/stop.js +35 -8
  54. package/dist/hooks/subagent-stop.js +34 -7
  55. package/dist/hooks/summary-worker.js +43 -16
  56. package/dist/index.js +36 -8
  57. package/dist/lib/consolidation.js +2 -1
  58. package/dist/lib/employee-templates.js +2 -1
  59. package/dist/lib/employees.js +2 -1
  60. package/dist/lib/exe-daemon.js +136 -36
  61. package/dist/lib/hybrid-search.js +36 -9
  62. package/dist/lib/identity.js +8 -3
  63. package/dist/lib/schedules.js +34 -7
  64. package/dist/lib/store.js +34 -7
  65. package/dist/mcp/server.js +133 -33
  66. package/dist/mcp/tools/create-task.js +10 -4
  67. package/dist/runtime/index.js +34 -7
  68. package/dist/tui/App.js +40 -11
  69. package/package.json +1 -1
@@ -727,7 +727,8 @@ function isMultiInstance(agentName, employees) {
727
727
  return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
728
728
  }
729
729
  function addEmployee(employees, employee) {
730
- const normalized = { ...employee, name: employee.name.toLowerCase() };
730
+ const { systemPrompt: _legacyPrompt, ...rest } = employee;
731
+ const normalized = { ...rest, name: employee.name.toLowerCase() };
731
732
  if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
732
733
  throw new Error(`Employee '${normalized.name}' already exists`);
733
734
  }
@@ -3646,7 +3647,7 @@ __export(shard_manager_exports, {
3646
3647
  shardExists: () => shardExists
3647
3648
  });
3648
3649
  import path9 from "path";
3649
- import { existsSync as existsSync9, mkdirSync as mkdirSync2, readdirSync } from "fs";
3650
+ import { existsSync as existsSync9, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync2 } from "fs";
3650
3651
  import { createClient as createClient2 } from "@libsql/client";
3651
3652
  function initShardManager(encryptionKey) {
3652
3653
  _encryptionKey = encryptionKey;
@@ -3668,7 +3669,7 @@ function getShardClient(projectName) {
3668
3669
  if (!_encryptionKey) {
3669
3670
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
3670
3671
  }
3671
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3672
+ const safeName = safeShardName(projectName);
3672
3673
  if (!safeName || safeName === "unknown") {
3673
3674
  throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
3674
3675
  }
@@ -3690,9 +3691,12 @@ function getShardClient(projectName) {
3690
3691
  return client;
3691
3692
  }
3692
3693
  function shardExists(projectName) {
3693
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3694
+ const safeName = safeShardName(projectName);
3694
3695
  return existsSync9(path9.join(SHARDS_DIR, `${safeName}.db`));
3695
3696
  }
3697
+ function safeShardName(projectName) {
3698
+ return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3699
+ }
3696
3700
  function listShards() {
3697
3701
  if (!existsSync9(SHARDS_DIR)) return [];
3698
3702
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
@@ -3786,7 +3790,8 @@ async function ensureShardSchema(client) {
3786
3790
  "ALTER TABLE memories ADD COLUMN token_cost REAL",
3787
3791
  "ALTER TABLE memories ADD COLUMN audience TEXT",
3788
3792
  "ALTER TABLE memories ADD COLUMN language_type TEXT",
3789
- "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
3793
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
3794
+ "ALTER TABLE memories ADD COLUMN deleted_at TEXT"
3790
3795
  ]) {
3791
3796
  try {
3792
3797
  await client.execute(col);
@@ -3882,9 +3887,32 @@ async function ensureShardSchema(client) {
3882
3887
  }
3883
3888
  }
3884
3889
  async function getReadyShardClient(projectName) {
3885
- const client = getShardClient(projectName);
3886
- await ensureShardSchema(client);
3887
- return client;
3890
+ const safeName = safeShardName(projectName);
3891
+ let client = getShardClient(projectName);
3892
+ try {
3893
+ await ensureShardSchema(client);
3894
+ return client;
3895
+ } catch (err) {
3896
+ const message = err instanceof Error ? err.message : String(err);
3897
+ if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
3898
+ client.close();
3899
+ _shards.delete(safeName);
3900
+ _shardLastAccess.delete(safeName);
3901
+ const dbPath = path9.join(SHARDS_DIR, `${safeName}.db`);
3902
+ if (existsSync9(dbPath)) {
3903
+ const stat = statSync2(dbPath);
3904
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3905
+ const archivedPath = path9.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
3906
+ renameSync3(dbPath, archivedPath);
3907
+ process.stderr.write(
3908
+ `[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
3909
+ `
3910
+ );
3911
+ }
3912
+ client = getShardClient(projectName);
3913
+ await ensureShardSchema(client);
3914
+ return client;
3915
+ }
3888
3916
  }
3889
3917
  function evictLRU() {
3890
3918
  let oldest = null;
@@ -5178,7 +5206,7 @@ __export(memory_queue_exports, {
5178
5206
  enqueueMemory: () => enqueueMemory,
5179
5207
  queueDepth: () => queueDepth
5180
5208
  });
5181
- import { appendFileSync, readFileSync as readFileSync7, renameSync as renameSync3, unlinkSync as unlinkSync3, existsSync as existsSync11, statSync as statSync2 } from "fs";
5209
+ import { appendFileSync, readFileSync as readFileSync7, renameSync as renameSync4, unlinkSync as unlinkSync3, existsSync as existsSync11, statSync as statSync3 } from "fs";
5182
5210
  import path11 from "path";
5183
5211
  function enqueueMemory(entry) {
5184
5212
  appendFileSync(QUEUE_PATH, JSON.stringify(entry) + "\n");
@@ -5194,13 +5222,13 @@ function drainQueue() {
5194
5222
  }
5195
5223
  if (!existsSync11(QUEUE_PATH)) return entries;
5196
5224
  try {
5197
- const stat = statSync2(QUEUE_PATH);
5225
+ const stat = statSync3(QUEUE_PATH);
5198
5226
  if (stat.size === 0) return entries;
5199
5227
  } catch {
5200
5228
  return entries;
5201
5229
  }
5202
5230
  try {
5203
- renameSync3(QUEUE_PATH, PROCESSING_PATH);
5231
+ renameSync4(QUEUE_PATH, PROCESSING_PATH);
5204
5232
  } catch {
5205
5233
  return entries;
5206
5234
  }
@@ -5661,7 +5689,7 @@ __export(file_grep_exports, {
5661
5689
  grepProjectFiles: () => grepProjectFiles
5662
5690
  });
5663
5691
  import { execSync as execSync4 } from "child_process";
5664
- import { readFileSync as readFileSync8, readdirSync as readdirSync2, statSync as statSync3, existsSync as existsSync13 } from "fs";
5692
+ import { readFileSync as readFileSync8, readdirSync as readdirSync2, statSync as statSync4, existsSync as existsSync13 } from "fs";
5665
5693
  import path14 from "path";
5666
5694
  import crypto3 from "crypto";
5667
5695
  function hasRipgrep() {
@@ -5778,7 +5806,7 @@ function grepWithNodeFs(pattern, projectRoot, patterns) {
5778
5806
  for (const filePath of files.slice(0, MAX_FILES)) {
5779
5807
  const absPath = path14.join(projectRoot, filePath);
5780
5808
  try {
5781
- const stat = statSync3(absPath);
5809
+ const stat = statSync4(absPath);
5782
5810
  if (stat.size > MAX_FILE_SIZE) continue;
5783
5811
  const content = readFileSync8(absPath, "utf8");
5784
5812
  const lines = content.split("\n");
@@ -7349,6 +7377,12 @@ var init_active_agent = __esm({
7349
7377
 
7350
7378
  // src/mcp/tools/recall-my-memory.ts
7351
7379
  import { z } from "zod";
7380
+ function formatMemoryBody(rawText, maxChars) {
7381
+ if (rawText.length <= maxChars) return rawText;
7382
+ const marker = ` \u2026 [truncated; +${rawText.length - maxChars} chars \u2014 re-call with max_chars up to 20000 for more]`;
7383
+ const sliceLen = Math.max(0, maxChars - marker.length);
7384
+ return `${rawText.slice(0, sliceLen)}${marker}`;
7385
+ }
7352
7386
  function formatSourceLine(record) {
7353
7387
  const doc2 = record.document_metadata;
7354
7388
  if (!doc2) return "";
@@ -7374,6 +7408,7 @@ function registerRecallMyMemory(server) {
7374
7408
  has_error: z.boolean().optional().describe("Filter for error-containing memories"),
7375
7409
  tool_name: z.string().optional().describe("Filter by tool name (Bash, Write, etc)"),
7376
7410
  limit: z.coerce.number().optional().default(10).describe("Max results to return"),
7411
+ max_chars: z.coerce.number().int().min(100).max(2e4).optional().default(2e3).describe("Max characters to include per memory result. Use a higher value for canonical plans/runbooks."),
7377
7412
  since: z.string().optional().describe("ISO 8601 timestamp \u2014 only return memories at or after this time"),
7378
7413
  include_archived: z.boolean().optional().default(false).describe(
7379
7414
  "Include deprecated (archived) memories alongside active ones. Default false."
@@ -7395,6 +7430,7 @@ function registerRecallMyMemory(server) {
7395
7430
  has_error,
7396
7431
  tool_name,
7397
7432
  limit,
7433
+ max_chars,
7398
7434
  since,
7399
7435
  include_archived,
7400
7436
  workspace_id,
@@ -7440,7 +7476,7 @@ function registerRecallMyMemory(server) {
7440
7476
  }
7441
7477
  const formatted = results.map((r) => {
7442
7478
  const header = `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}`;
7443
- const body = r.raw_text.slice(0, 500);
7479
+ const body = formatMemoryBody(r.raw_text, max_chars ?? 2e3);
7444
7480
  const parts = [header];
7445
7481
  if (r.source_path) {
7446
7482
  const typeTag = r.source_type && r.source_type !== "text" ? ` [${r.source_type}]` : "";
@@ -7485,6 +7521,12 @@ var init_recall_my_memory = __esm({
7485
7521
 
7486
7522
  // src/mcp/tools/ask-team-memory.ts
7487
7523
  import { z as z2 } from "zod";
7524
+ function formatMemoryBody2(rawText, maxChars) {
7525
+ if (rawText.length <= maxChars) return rawText;
7526
+ const marker = ` \u2026 [truncated; +${rawText.length - maxChars} chars \u2014 re-call with max_chars up to 20000 for more]`;
7527
+ const sliceLen = Math.max(0, maxChars - marker.length);
7528
+ return `${rawText.slice(0, sliceLen)}${marker}`;
7529
+ }
7488
7530
  function canSeeRaw(queryingRole, targetRole) {
7489
7531
  if (queryingRole === "COO") return true;
7490
7532
  if (queryingRole === "CTO" && [
@@ -7509,6 +7551,7 @@ function registerAskTeamMemory(server) {
7509
7551
  query: z2.string().describe("What to search for"),
7510
7552
  project_name: z2.string().optional().describe("Filter by project name"),
7511
7553
  limit: z2.coerce.number().optional().default(10).describe("Max results to return"),
7554
+ max_chars: z2.coerce.number().int().min(100).max(2e4).optional().default(2e3).describe("Max characters to include per memory result. Use a higher value for canonical plans/runbooks."),
7512
7555
  since: z2.string().optional().describe("ISO 8601 timestamp \u2014 only return memories at or after this time"),
7513
7556
  include_archived: z2.boolean().optional().default(false).describe(
7514
7557
  "Include deprecated (archived) memories alongside active ones. Default false."
@@ -7519,7 +7562,7 @@ function registerAskTeamMemory(server) {
7519
7562
  retrieval_mode: z2.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. Raw visibility is still ACL-gated. ${formatRetrievalModes()}`)
7520
7563
  }
7521
7564
  },
7522
- async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw, retrieval_mode }) => {
7565
+ async ({ team_member, query, project_name, limit, max_chars, since, include_archived, include_raw: _include_raw, retrieval_mode }) => {
7523
7566
  try {
7524
7567
  const { agentId: queryingAgentId, agentRole: queryingAgentRole } = getActiveAgent();
7525
7568
  const employees = loadEmployeesSync();
@@ -7552,7 +7595,7 @@ function registerAskTeamMemory(server) {
7552
7595
  }
7553
7596
  const formatted = results.map(
7554
7597
  (r) => `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}
7555
- ${r.raw_text.slice(0, 500)}`
7598
+ ${formatMemoryBody2(r.raw_text, max_chars ?? 2e3)}`
7556
7599
  ).join("\n\n---\n\n");
7557
7600
  return {
7558
7601
  content: [
@@ -7830,8 +7873,8 @@ async function validateLicense(apiKey, deviceId) {
7830
7873
  }
7831
7874
  function getCacheAgeMs() {
7832
7875
  try {
7833
- const { statSync: statSync7 } = __require("fs");
7834
- const s = statSync7(CACHE_PATH);
7876
+ const { statSync: statSync8 } = __require("fs");
7877
+ const s = statSync8(CACHE_PATH);
7835
7878
  return Date.now() - s.mtimeMs;
7836
7879
  } catch {
7837
7880
  return Infinity;
@@ -8395,7 +8438,8 @@ var init_wiki_client = __esm({
8395
8438
  // src/lib/unified-search.ts
8396
8439
  function truncate(text3, max) {
8397
8440
  if (text3.length <= max) return text3;
8398
- return text3.slice(0, max - 1) + "\u2026";
8441
+ const marker = ` \u2026 [truncated; +${text3.length - max} chars]`;
8442
+ return text3.slice(0, Math.max(0, max - marker.length)) + marker;
8399
8443
  }
8400
8444
  async function searchMemories2(query, agentId, limit) {
8401
8445
  const { hybridSearch: hybridSearch2 } = await Promise.resolve().then(() => (init_hybrid_search(), hybrid_search_exports));
@@ -8631,6 +8675,12 @@ var init_search_everything = __esm({
8631
8675
 
8632
8676
  // src/mcp/tools/get-session-context.ts
8633
8677
  import { z as z6 } from "zod";
8678
+ function formatMemoryBody3(rawText, maxChars) {
8679
+ if (rawText.length <= maxChars) return rawText;
8680
+ const marker = ` \u2026 [truncated; +${rawText.length - maxChars} chars \u2014 re-call with max_chars up to 20000 for more]`;
8681
+ const sliceLen = Math.max(0, maxChars - marker.length);
8682
+ return `${rawText.slice(0, sliceLen)}${marker}`;
8683
+ }
8634
8684
  function registerGetSessionContext(server) {
8635
8685
  server.registerTool(
8636
8686
  "get_session_context",
@@ -8642,10 +8692,11 @@ function registerGetSessionContext(server) {
8642
8692
  target_timestamp: z6.string().describe(
8643
8693
  "ISO 8601 timestamp to center the context window around"
8644
8694
  ),
8645
- window_size: z6.number().optional().default(3).describe("Number of memories before and after the target")
8695
+ window_size: z6.number().optional().default(3).describe("Number of memories before and after the target"),
8696
+ max_chars: z6.coerce.number().int().min(100).max(2e4).optional().default(2e3).describe("Max characters to include per memory result.")
8646
8697
  }
8647
8698
  },
8648
- async ({ session_id, target_timestamp, window_size }) => {
8699
+ async ({ session_id, target_timestamp, window_size, max_chars }) => {
8649
8700
  const client = getClient();
8650
8701
  const result = await client.execute({
8651
8702
  sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
@@ -8691,7 +8742,7 @@ function registerGetSessionContext(server) {
8691
8742
  const windowMemories = sorted.slice(start, end);
8692
8743
  const formatted = windowMemories.map(
8693
8744
  (r) => `[${r.timestamp}] ${r.tool_name} (${r.project_name})${r.has_error ? " [ERROR]" : ""}
8694
- ${r.raw_text.slice(0, 500)}`
8745
+ ${formatMemoryBody3(r.raw_text, max_chars ?? 2e3)}`
8695
8746
  ).join("\n\n---\n\n");
8696
8747
  return {
8697
8748
  content: [
@@ -9837,7 +9888,7 @@ __export(intercom_queue_exports, {
9837
9888
  queueIntercom: () => queueIntercom,
9838
9889
  readQueue: () => readQueue
9839
9890
  });
9840
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, renameSync as renameSync4, existsSync as existsSync17, mkdirSync as mkdirSync6 } from "fs";
9891
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, renameSync as renameSync5, existsSync as existsSync17, mkdirSync as mkdirSync6 } from "fs";
9841
9892
  import path21 from "path";
9842
9893
  import os9 from "os";
9843
9894
  function ensureDir() {
@@ -9856,7 +9907,7 @@ function writeQueue(queue) {
9856
9907
  ensureDir();
9857
9908
  const tmp = `${QUEUE_PATH2}.tmp`;
9858
9909
  writeFileSync10(tmp, JSON.stringify(queue, null, 2));
9859
- renameSync4(tmp, QUEUE_PATH2);
9910
+ renameSync5(tmp, QUEUE_PATH2);
9860
9911
  }
9861
9912
  function queueIntercom(targetSession, reason) {
9862
9913
  const queue = readQueue();
@@ -12987,6 +13038,9 @@ function ensureDir2() {
12987
13038
  function identityPath(agentId) {
12988
13039
  return path28.join(IDENTITY_DIR2, `${agentId}.md`);
12989
13040
  }
13041
+ function sanitizeIdentityBody(body) {
13042
+ return body.replace(/<!--[\s\S]*?-->/g, "").trim();
13043
+ }
12990
13044
  function parseFrontmatter(raw) {
12991
13045
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
12992
13046
  if (!match) {
@@ -12999,11 +13053,11 @@ function parseFrontmatter(raw) {
12999
13053
  created_by: "system",
13000
13054
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
13001
13055
  },
13002
- body: raw
13056
+ body: sanitizeIdentityBody(raw)
13003
13057
  };
13004
13058
  }
13005
13059
  const yamlStr = match[1];
13006
- const body = match[2].trim();
13060
+ const body = sanitizeIdentityBody(match[2]);
13007
13061
  const fm = {};
13008
13062
  for (const line of yamlStr.split("\n")) {
13009
13063
  const kv = line.match(/^(\w+):\s*(.+)$/);
@@ -13068,7 +13122,9 @@ function listIdentities() {
13068
13122
  const summary = lines[0]?.trim().slice(0, 120) ?? identity.frontmatter.title;
13069
13123
  results.push({
13070
13124
  agentId,
13071
- title: `${identity.frontmatter.title} (${identity.frontmatter.role.toUpperCase()})`,
13125
+ // User-facing/team-facing title only. `frontmatter.role` is internal
13126
+ // routing metadata and must not leak as an external title.
13127
+ title: identity.frontmatter.title,
13072
13128
  summary
13073
13129
  });
13074
13130
  }
@@ -13859,6 +13915,40 @@ var init_list_tasks = __esm({
13859
13915
 
13860
13916
  // src/mcp/tools/get-task.ts
13861
13917
  import { z as z13 } from "zod";
13918
+ async function diagnoseMissingTask(client, identifier) {
13919
+ const shortUuid = /^[a-f0-9]{7,12}$/i.test(identifier);
13920
+ const args = [];
13921
+ const clauses = [];
13922
+ if (shortUuid) {
13923
+ clauses.push("id LIKE ?");
13924
+ args.push(`${identifier}%`);
13925
+ }
13926
+ clauses.push("task_file LIKE ?");
13927
+ args.push(`%${identifier}%`);
13928
+ clauses.push("title LIKE ?");
13929
+ args.push(`%${identifier}%`);
13930
+ const result = await client.execute({
13931
+ sql: `SELECT id, title, status, assigned_to, project_name, session_scope, task_file
13932
+ FROM tasks
13933
+ WHERE ${clauses.map((c) => `(${c})`).join(" OR ")}
13934
+ ORDER BY updated_at DESC
13935
+ LIMIT 10`,
13936
+ args
13937
+ });
13938
+ if (result.rows.length === 0) return null;
13939
+ const scoped = sessionScopeFilter();
13940
+ const scopeNote = scoped.args.length > 0 ? `Current session scope appears to be ${String(scoped.args[0])}. get_task is session-scoped by default.` : "No current session scope detected.";
13941
+ const matches = result.rows.map((r) => {
13942
+ const id = String(r.id);
13943
+ return `- ${id.slice(0, 8)} ${String(r.title)} [${String(r.status)}] assigned_to=${String(r.assigned_to)} project=${String(r.project_name)} session_scope=${String(r.session_scope ?? "NULL")}`;
13944
+ }).join("\n");
13945
+ return `Task not found in the current scoped lookup, but similar task rows exist. ${scopeNote}
13946
+
13947
+ Matches across all scopes/statuses:
13948
+ ${matches}
13949
+
13950
+ Use the full UUID from the matching row, switch to the owning coordinator session, or list tasks with the correct project/session scope.`;
13951
+ }
13862
13952
  function registerGetTask(server) {
13863
13953
  server.registerTool(
13864
13954
  "get_task",
@@ -13871,7 +13961,16 @@ function registerGetTask(server) {
13871
13961
  },
13872
13962
  async ({ task_id }) => {
13873
13963
  const client = getClient();
13874
- const row = await resolveTask(client, task_id);
13964
+ let row;
13965
+ try {
13966
+ row = await resolveTask(client, task_id);
13967
+ } catch (err) {
13968
+ const fallback = await diagnoseMissingTask(client, task_id);
13969
+ if (fallback) {
13970
+ return { content: [{ type: "text", text: fallback }], isError: true };
13971
+ }
13972
+ throw err;
13973
+ }
13875
13974
  const contextText = row.context ? String(row.context) : "";
13876
13975
  const hasEmbeddedMandatoryReminder = contextText.includes('update_task with status "done"') || contextText.includes("update_task(done)");
13877
13976
  const lines = [
@@ -13967,6 +14066,7 @@ var init_get_task = __esm({
13967
14066
  "use strict";
13968
14067
  init_tasks();
13969
14068
  init_database();
14069
+ init_task_scope();
13970
14070
  init_employees();
13971
14071
  }
13972
14072
  });
@@ -19513,7 +19613,7 @@ var init_import_orchestration = __esm({
19513
19613
 
19514
19614
  // src/mcp/tools/load-skill.ts
19515
19615
  import { z as z50 } from "zod";
19516
- import { readFileSync as readFileSync23, readdirSync as readdirSync9, statSync as statSync4 } from "fs";
19616
+ import { readFileSync as readFileSync23, readdirSync as readdirSync9, statSync as statSync5 } from "fs";
19517
19617
  import path35 from "path";
19518
19618
  import { homedir as homedir2 } from "os";
19519
19619
  function listAvailableSkills() {
@@ -19522,9 +19622,9 @@ function listAvailableSkills() {
19522
19622
  return entries.filter((entry) => {
19523
19623
  try {
19524
19624
  const entryPath = path35.join(SKILLS_DIR, entry);
19525
- if (!statSync4(entryPath).isDirectory()) return false;
19625
+ if (!statSync5(entryPath).isDirectory()) return false;
19526
19626
  const skillFile = path35.join(entryPath, "SKILL.md");
19527
- statSync4(skillFile);
19627
+ statSync5(skillFile);
19528
19628
  return true;
19529
19629
  } catch {
19530
19630
  return false;
@@ -22954,7 +23054,7 @@ __export(db_backup_exports, {
22954
23054
  listBackups: () => listBackups,
22955
23055
  rotateBackups: () => rotateBackups
22956
23056
  });
22957
- import { copyFileSync as copyFileSync2, existsSync as existsSync33, mkdirSync as mkdirSync15, readdirSync as readdirSync12, unlinkSync as unlinkSync10, statSync as statSync5 } from "fs";
23057
+ import { copyFileSync as copyFileSync2, existsSync as existsSync33, mkdirSync as mkdirSync15, readdirSync as readdirSync12, unlinkSync as unlinkSync10, statSync as statSync6 } from "fs";
22958
23058
  import path41 from "path";
22959
23059
  function findActiveDb() {
22960
23060
  for (const name of DB_NAMES) {
@@ -22998,7 +23098,7 @@ function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
22998
23098
  if (!file.endsWith(".db") && !file.endsWith(".db-wal") && !file.endsWith(".db-shm")) continue;
22999
23099
  const filePath = path41.join(BACKUP_DIR, file);
23000
23100
  try {
23001
- const stat = statSync5(filePath);
23101
+ const stat = statSync6(filePath);
23002
23102
  if (stat.mtimeMs < cutoff) {
23003
23103
  unlinkSync10(filePath);
23004
23104
  deleted++;
@@ -23016,7 +23116,7 @@ function listBackups() {
23016
23116
  const files = readdirSync12(BACKUP_DIR).filter((f) => f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm"));
23017
23117
  return files.map((name) => {
23018
23118
  const p = path41.join(BACKUP_DIR, name);
23019
- const stat = statSync5(p);
23119
+ const stat = statSync6(p);
23020
23120
  return { path: p, name, size: stat.size, date: stat.mtime };
23021
23121
  }).sort((a, b) => b.date.getTime() - a.date.getTime());
23022
23122
  } catch {
@@ -23982,7 +24082,7 @@ __export(cloud_sync_exports, {
23982
24082
  pushToPostgres: () => pushToPostgres,
23983
24083
  recordRosterDeletion: () => recordRosterDeletion
23984
24084
  });
23985
- import { readFileSync as readFileSync29, writeFileSync as writeFileSync21, existsSync as existsSync36, readdirSync as readdirSync13, mkdirSync as mkdirSync17, appendFileSync as appendFileSync3, unlinkSync as unlinkSync12, openSync as openSync2, closeSync as closeSync2, statSync as statSync6 } from "fs";
24085
+ import { readFileSync as readFileSync29, writeFileSync as writeFileSync21, existsSync as existsSync36, readdirSync as readdirSync13, mkdirSync as mkdirSync17, appendFileSync as appendFileSync3, unlinkSync as unlinkSync12, openSync as openSync2, closeSync as closeSync2, statSync as statSync7 } from "fs";
23986
24086
  import crypto18 from "crypto";
23987
24087
  import path44 from "path";
23988
24088
  import { homedir as homedir6 } from "os";
@@ -24474,7 +24574,7 @@ async function cloudSync(config2) {
24474
24574
  const { getLatestBackup: getLatestBackup2 } = await Promise.resolve().then(() => (init_db_backup(), db_backup_exports));
24475
24575
  const latestBackup = getLatestBackup2();
24476
24576
  if (latestBackup) {
24477
- const backupSize = statSync6(latestBackup).size;
24577
+ const backupSize = statSync7(latestBackup).size;
24478
24578
  const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
24479
24579
  if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
24480
24580
  const backupData = readFileSync29(latestBackup);
@@ -3238,7 +3238,7 @@ __export(shard_manager_exports, {
3238
3238
  shardExists: () => shardExists
3239
3239
  });
3240
3240
  import path7 from "path";
3241
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync } from "fs";
3241
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync2 } from "fs";
3242
3242
  import { createClient as createClient2 } from "@libsql/client";
3243
3243
  function initShardManager(encryptionKey) {
3244
3244
  _encryptionKey = encryptionKey;
@@ -3260,7 +3260,7 @@ function getShardClient(projectName) {
3260
3260
  if (!_encryptionKey) {
3261
3261
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
3262
3262
  }
3263
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3263
+ const safeName = safeShardName(projectName);
3264
3264
  if (!safeName || safeName === "unknown") {
3265
3265
  throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
3266
3266
  }
@@ -3282,9 +3282,12 @@ function getShardClient(projectName) {
3282
3282
  return client;
3283
3283
  }
3284
3284
  function shardExists(projectName) {
3285
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3285
+ const safeName = safeShardName(projectName);
3286
3286
  return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
3287
3287
  }
3288
+ function safeShardName(projectName) {
3289
+ return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
3290
+ }
3288
3291
  function listShards() {
3289
3292
  if (!existsSync7(SHARDS_DIR)) return [];
3290
3293
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
@@ -3378,7 +3381,8 @@ async function ensureShardSchema(client) {
3378
3381
  "ALTER TABLE memories ADD COLUMN token_cost REAL",
3379
3382
  "ALTER TABLE memories ADD COLUMN audience TEXT",
3380
3383
  "ALTER TABLE memories ADD COLUMN language_type TEXT",
3381
- "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
3384
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
3385
+ "ALTER TABLE memories ADD COLUMN deleted_at TEXT"
3382
3386
  ]) {
3383
3387
  try {
3384
3388
  await client.execute(col);
@@ -3474,9 +3478,32 @@ async function ensureShardSchema(client) {
3474
3478
  }
3475
3479
  }
3476
3480
  async function getReadyShardClient(projectName) {
3477
- const client = getShardClient(projectName);
3478
- await ensureShardSchema(client);
3479
- return client;
3481
+ const safeName = safeShardName(projectName);
3482
+ let client = getShardClient(projectName);
3483
+ try {
3484
+ await ensureShardSchema(client);
3485
+ return client;
3486
+ } catch (err) {
3487
+ const message = err instanceof Error ? err.message : String(err);
3488
+ if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
3489
+ client.close();
3490
+ _shards.delete(safeName);
3491
+ _shardLastAccess.delete(safeName);
3492
+ const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
3493
+ if (existsSync7(dbPath)) {
3494
+ const stat = statSync2(dbPath);
3495
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3496
+ const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
3497
+ renameSync3(dbPath, archivedPath);
3498
+ process.stderr.write(
3499
+ `[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
3500
+ `
3501
+ );
3502
+ }
3503
+ client = getShardClient(projectName);
3504
+ await ensureShardSchema(client);
3505
+ return client;
3506
+ }
3480
3507
  }
3481
3508
  function evictLRU() {
3482
3509
  let oldest = null;
@@ -4751,7 +4778,7 @@ __export(file_grep_exports, {
4751
4778
  grepProjectFiles: () => grepProjectFiles
4752
4779
  });
4753
4780
  import { execSync as execSync4 } from "child_process";
4754
- import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync9 } from "fs";
4781
+ import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync3, existsSync as existsSync9 } from "fs";
4755
4782
  import path10 from "path";
4756
4783
  import crypto2 from "crypto";
4757
4784
  function hasRipgrep() {
@@ -4868,7 +4895,7 @@ function grepWithNodeFs(pattern, projectRoot, patterns) {
4868
4895
  for (const filePath of files.slice(0, MAX_FILES)) {
4869
4896
  const absPath = path10.join(projectRoot, filePath);
4870
4897
  try {
4871
- const stat = statSync2(absPath);
4898
+ const stat = statSync3(absPath);
4872
4899
  if (stat.size > MAX_FILE_SIZE) continue;
4873
4900
  const content = readFileSync5(absPath, "utf8");
4874
4901
  const lines = content.split("\n");
@@ -169,6 +169,9 @@ function ensureDir() {
169
169
  function identityPath(agentId) {
170
170
  return path4.join(IDENTITY_DIR2, `${agentId}.md`);
171
171
  }
172
+ function sanitizeIdentityBody(body) {
173
+ return body.replace(/<!--[\s\S]*?-->/g, "").trim();
174
+ }
172
175
  function parseFrontmatter(raw) {
173
176
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
174
177
  if (!match) {
@@ -181,11 +184,11 @@ function parseFrontmatter(raw) {
181
184
  created_by: "system",
182
185
  updated_at: (/* @__PURE__ */ new Date()).toISOString()
183
186
  },
184
- body: raw
187
+ body: sanitizeIdentityBody(raw)
185
188
  };
186
189
  }
187
190
  const yamlStr = match[1];
188
- const body = match[2].trim();
191
+ const body = sanitizeIdentityBody(match[2]);
189
192
  const fm = {};
190
193
  for (const line of yamlStr.split("\n")) {
191
194
  const kv = line.match(/^(\w+):\s*(.+)$/);
@@ -250,7 +253,9 @@ function listIdentities() {
250
253
  const summary = lines[0]?.trim().slice(0, 120) ?? identity.frontmatter.title;
251
254
  results.push({
252
255
  agentId,
253
- title: `${identity.frontmatter.title} (${identity.frontmatter.role.toUpperCase()})`,
256
+ // User-facing/team-facing title only. `frontmatter.role` is internal
257
+ // routing metadata and must not leak as an external title.
258
+ title: identity.frontmatter.title,
254
259
  summary
255
260
  });
256
261
  }
@@ -2600,7 +2600,7 @@ __export(shard_manager_exports, {
2600
2600
  shardExists: () => shardExists
2601
2601
  });
2602
2602
  import path7 from "path";
2603
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync } from "fs";
2603
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync, renameSync as renameSync3, statSync as statSync2 } from "fs";
2604
2604
  import { createClient as createClient2 } from "@libsql/client";
2605
2605
  function initShardManager(encryptionKey) {
2606
2606
  _encryptionKey = encryptionKey;
@@ -2622,7 +2622,7 @@ function getShardClient(projectName) {
2622
2622
  if (!_encryptionKey) {
2623
2623
  throw new Error("Shard manager not initialized. Call initShardManager() first.");
2624
2624
  }
2625
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2625
+ const safeName = safeShardName(projectName);
2626
2626
  if (!safeName || safeName === "unknown") {
2627
2627
  throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
2628
2628
  }
@@ -2644,9 +2644,12 @@ function getShardClient(projectName) {
2644
2644
  return client;
2645
2645
  }
2646
2646
  function shardExists(projectName) {
2647
- const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2647
+ const safeName = safeShardName(projectName);
2648
2648
  return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
2649
2649
  }
2650
+ function safeShardName(projectName) {
2651
+ return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2652
+ }
2650
2653
  function listShards() {
2651
2654
  if (!existsSync7(SHARDS_DIR)) return [];
2652
2655
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
@@ -2740,7 +2743,8 @@ async function ensureShardSchema(client) {
2740
2743
  "ALTER TABLE memories ADD COLUMN token_cost REAL",
2741
2744
  "ALTER TABLE memories ADD COLUMN audience TEXT",
2742
2745
  "ALTER TABLE memories ADD COLUMN language_type TEXT",
2743
- "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
2746
+ "ALTER TABLE memories ADD COLUMN parent_memory_id TEXT",
2747
+ "ALTER TABLE memories ADD COLUMN deleted_at TEXT"
2744
2748
  ]) {
2745
2749
  try {
2746
2750
  await client.execute(col);
@@ -2836,9 +2840,32 @@ async function ensureShardSchema(client) {
2836
2840
  }
2837
2841
  }
2838
2842
  async function getReadyShardClient(projectName) {
2839
- const client = getShardClient(projectName);
2840
- await ensureShardSchema(client);
2841
- return client;
2843
+ const safeName = safeShardName(projectName);
2844
+ let client = getShardClient(projectName);
2845
+ try {
2846
+ await ensureShardSchema(client);
2847
+ return client;
2848
+ } catch (err) {
2849
+ const message = err instanceof Error ? err.message : String(err);
2850
+ if (!/SQLITE_NOTADB|file is not a database/i.test(message)) throw err;
2851
+ client.close();
2852
+ _shards.delete(safeName);
2853
+ _shardLastAccess.delete(safeName);
2854
+ const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
2855
+ if (existsSync7(dbPath)) {
2856
+ const stat = statSync2(dbPath);
2857
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2858
+ const archivedPath = path7.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
2859
+ renameSync3(dbPath, archivedPath);
2860
+ process.stderr.write(
2861
+ `[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
2862
+ `
2863
+ );
2864
+ }
2865
+ client = getShardClient(projectName);
2866
+ await ensureShardSchema(client);
2867
+ return client;
2868
+ }
2842
2869
  }
2843
2870
  function evictLRU() {
2844
2871
  let oldest = null;