@askexenow/exe-os 0.9.61 → 0.9.63

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 (103) hide show
  1. package/deploy/stack-manifests/v0.9.json +62 -13
  2. package/dist/bin/backfill-conversations.js +210 -2
  3. package/dist/bin/backfill-responses.js +210 -2
  4. package/dist/bin/backfill-vectors.js +47 -2
  5. package/dist/bin/cleanup-stale-review-tasks.js +210 -2
  6. package/dist/bin/cli.js +488 -25
  7. package/dist/bin/exe-agent-config.js +2 -2
  8. package/dist/bin/exe-agent.js +2 -2
  9. package/dist/bin/exe-assign.js +210 -2
  10. package/dist/bin/exe-boot.js +47 -2
  11. package/dist/bin/exe-call.js +2 -2
  12. package/dist/bin/exe-cloud.js +2 -2
  13. package/dist/bin/exe-dispatch.js +210 -2
  14. package/dist/bin/exe-doctor.js +2691 -1212
  15. package/dist/bin/exe-export-behaviors.js +210 -2
  16. package/dist/bin/exe-forget.js +264 -2
  17. package/dist/bin/exe-gateway.js +210 -2
  18. package/dist/bin/exe-heartbeat.js +212 -4
  19. package/dist/bin/exe-kill.js +210 -2
  20. package/dist/bin/exe-launch-agent.js +210 -2
  21. package/dist/bin/exe-link.js +47 -2
  22. package/dist/bin/exe-new-employee.js +113 -3
  23. package/dist/bin/exe-pending-messages.js +210 -2
  24. package/dist/bin/exe-pending-notifications.js +210 -2
  25. package/dist/bin/exe-pending-reviews.js +210 -2
  26. package/dist/bin/exe-rename.js +210 -2
  27. package/dist/bin/exe-review.js +210 -2
  28. package/dist/bin/exe-search.js +234 -3
  29. package/dist/bin/exe-session-cleanup.js +210 -2
  30. package/dist/bin/exe-settings.js +2 -2
  31. package/dist/bin/exe-start-codex.js +322 -4
  32. package/dist/bin/exe-start-opencode.js +336 -4
  33. package/dist/bin/exe-status.js +210 -2
  34. package/dist/bin/exe-team.js +210 -2
  35. package/dist/bin/git-sweep.js +210 -2
  36. package/dist/bin/graph-backfill.js +210 -2
  37. package/dist/bin/graph-export.js +210 -2
  38. package/dist/bin/install.js +113 -3
  39. package/dist/bin/intercom-check.js +210 -2
  40. package/dist/bin/scan-tasks.js +210 -2
  41. package/dist/bin/setup.js +47 -2
  42. package/dist/bin/shard-migrate.js +210 -2
  43. package/dist/bin/stack-update.js +158 -13
  44. package/dist/bin/update.js +2 -2
  45. package/dist/gateway/index.js +210 -2
  46. package/dist/hooks/bug-report-worker.js +321 -44
  47. package/dist/hooks/codex-stop-task-finalizer.js +210 -2
  48. package/dist/hooks/commit-complete.js +210 -2
  49. package/dist/hooks/error-recall.js +234 -3
  50. package/dist/hooks/exe-heartbeat-hook.js +2 -2
  51. package/dist/hooks/ingest-worker.js +2 -2
  52. package/dist/hooks/ingest.js +210 -2
  53. package/dist/hooks/instructions-loaded.js +210 -2
  54. package/dist/hooks/notification.js +210 -2
  55. package/dist/hooks/post-compact.js +210 -2
  56. package/dist/hooks/post-tool-combined.js +234 -3
  57. package/dist/hooks/pre-compact.js +446 -111
  58. package/dist/hooks/pre-tool-use.js +210 -2
  59. package/dist/hooks/prompt-submit.js +234 -3
  60. package/dist/hooks/session-end.js +347 -124
  61. package/dist/hooks/session-start.js +236 -5
  62. package/dist/hooks/stop.js +210 -2
  63. package/dist/hooks/subagent-stop.js +210 -2
  64. package/dist/hooks/summary-worker.js +171 -74
  65. package/dist/index.js +210 -2
  66. package/dist/lib/agent-config.js +2 -2
  67. package/dist/lib/cloud-sync.js +47 -2
  68. package/dist/lib/config.js +2 -2
  69. package/dist/lib/consolidation.js +2 -2
  70. package/dist/lib/database.js +47 -2
  71. package/dist/lib/db-daemon-client.js +2 -2
  72. package/dist/lib/db.js +47 -2
  73. package/dist/lib/device-registry.js +47 -2
  74. package/dist/lib/embedder.js +2 -2
  75. package/dist/lib/employee-templates.js +2 -2
  76. package/dist/lib/employees.js +2 -2
  77. package/dist/lib/exe-daemon-client.js +2 -2
  78. package/dist/lib/exe-daemon.js +592 -10
  79. package/dist/lib/hybrid-search.js +234 -3
  80. package/dist/lib/identity.js +2 -2
  81. package/dist/lib/license.js +2 -2
  82. package/dist/lib/messaging.js +2 -2
  83. package/dist/lib/reminders.js +2 -2
  84. package/dist/lib/schedules.js +47 -2
  85. package/dist/lib/skill-learning.js +2 -2
  86. package/dist/lib/store.js +210 -2
  87. package/dist/lib/task-router.js +2 -2
  88. package/dist/lib/tasks.js +2 -2
  89. package/dist/lib/tmux-routing.js +2 -2
  90. package/dist/lib/token-spend.js +2 -2
  91. package/dist/mcp/server.js +608 -10
  92. package/dist/mcp/tools/complete-reminder.js +2 -2
  93. package/dist/mcp/tools/create-reminder.js +2 -2
  94. package/dist/mcp/tools/create-task.js +2 -2
  95. package/dist/mcp/tools/deactivate-behavior.js +2 -2
  96. package/dist/mcp/tools/list-reminders.js +2 -2
  97. package/dist/mcp/tools/list-tasks.js +2 -2
  98. package/dist/mcp/tools/send-message.js +2 -2
  99. package/dist/mcp/tools/update-task.js +2 -2
  100. package/dist/runtime/index.js +210 -2
  101. package/dist/tui/App.js +210 -2
  102. package/package.json +3 -2
  103. package/stack.release.json +23 -7
@@ -266,8 +266,8 @@ var init_config = __esm({
266
266
  rerankerAutoTrigger: {
267
267
  enabled: true,
268
268
  broadQueryMinCardinality: 5e4,
269
- fetchTopK: 150,
270
- returnTopK: 5
269
+ fetchTopK: 200,
270
+ returnTopK: 20
271
271
  }
272
272
  },
273
273
  graphRagEnabled: true,
@@ -1893,6 +1893,15 @@ var init_database_adapter = __esm({
1893
1893
  });
1894
1894
 
1895
1895
  // src/lib/daemon-protocol.ts
1896
+ var daemon_protocol_exports = {};
1897
+ __export(daemon_protocol_exports, {
1898
+ deserializeArgs: () => deserializeArgs,
1899
+ deserializeResultSet: () => deserializeResultSet,
1900
+ deserializeValue: () => deserializeValue,
1901
+ serializeArgs: () => serializeArgs,
1902
+ serializeResultSet: () => serializeResultSet,
1903
+ serializeValue: () => serializeValue
1904
+ });
1896
1905
  function serializeValue(v) {
1897
1906
  if (v === null || v === void 0) return null;
1898
1907
  if (typeof v === "bigint") return Number(v);
@@ -1917,6 +1926,32 @@ function deserializeValue(v) {
1917
1926
  }
1918
1927
  return v;
1919
1928
  }
1929
+ function serializeArgs(args) {
1930
+ return args.map(serializeValue);
1931
+ }
1932
+ function deserializeArgs(args) {
1933
+ return args.map(deserializeValue);
1934
+ }
1935
+ function serializeResultSet(rs) {
1936
+ const rows = [];
1937
+ for (const row of rs.rows) {
1938
+ const obj = {};
1939
+ for (let i = 0; i < rs.columns.length; i++) {
1940
+ const col = rs.columns[i];
1941
+ if (col !== void 0) {
1942
+ obj[col] = serializeValue(row[i]);
1943
+ }
1944
+ }
1945
+ rows.push(obj);
1946
+ }
1947
+ return {
1948
+ columns: [...rs.columns],
1949
+ columnTypes: [...rs.columnTypes ?? []],
1950
+ rows,
1951
+ rowsAffected: typeof rs.rowsAffected === "bigint" ? Number(rs.rowsAffected) : rs.rowsAffected ?? 0,
1952
+ lastInsertRowid: rs.lastInsertRowid != null ? typeof rs.lastInsertRowid === "bigint" ? Number(rs.lastInsertRowid) : rs.lastInsertRowid : null
1953
+ };
1954
+ }
1920
1955
  function deserializeResultSet(srs) {
1921
1956
  const rows = srs.rows.map((obj) => {
1922
1957
  const values = srs.columns.map(
@@ -3154,6 +3189,51 @@ async function ensureSchema() {
3154
3189
  VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
3155
3190
  END;
3156
3191
  `);
3192
+ await client.executeMultiple(`
3193
+ CREATE TABLE IF NOT EXISTS memory_cards (
3194
+ id TEXT PRIMARY KEY,
3195
+ memory_id TEXT NOT NULL,
3196
+ agent_id TEXT NOT NULL,
3197
+ session_id TEXT NOT NULL,
3198
+ project_name TEXT,
3199
+ timestamp TEXT NOT NULL,
3200
+ card_type TEXT NOT NULL,
3201
+ subject TEXT,
3202
+ predicate TEXT,
3203
+ object TEXT,
3204
+ content TEXT NOT NULL,
3205
+ source_ref TEXT,
3206
+ confidence REAL DEFAULT 0.6,
3207
+ active INTEGER DEFAULT 1,
3208
+ created_at TEXT NOT NULL
3209
+ );
3210
+
3211
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
3212
+ ON memory_cards(agent_id, active, timestamp);
3213
+
3214
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
3215
+ ON memory_cards(memory_id);
3216
+
3217
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
3218
+ USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
3219
+
3220
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
3221
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
3222
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
3223
+ END;
3224
+
3225
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
3226
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
3227
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
3228
+ END;
3229
+
3230
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
3231
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
3232
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
3233
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
3234
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
3235
+ END;
3236
+ `);
3157
3237
  try {
3158
3238
  await client.execute({
3159
3239
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
@@ -4541,6 +4621,164 @@ ${p.content}`).join("\n\n");
4541
4621
  }
4542
4622
  });
4543
4623
 
4624
+ // src/lib/memory-cards.ts
4625
+ var memory_cards_exports = {};
4626
+ __export(memory_cards_exports, {
4627
+ extractMemoryCards: () => extractMemoryCards,
4628
+ insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
4629
+ searchMemoryCards: () => searchMemoryCards
4630
+ });
4631
+ import { createHash as createHash2 } from "crypto";
4632
+ function stableId(memoryId, type, content) {
4633
+ return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
4634
+ }
4635
+ function cleanText(text3) {
4636
+ return text3.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
4637
+ }
4638
+ function splitSentences(text3) {
4639
+ return cleanText(text3).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
4640
+ }
4641
+ function inferCardType(sentence, toolName) {
4642
+ const lower = sentence.toLowerCase();
4643
+ if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
4644
+ if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
4645
+ if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
4646
+ if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
4647
+ if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
4648
+ return "fact";
4649
+ }
4650
+ function extractSubject(sentence, agentId) {
4651
+ const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
4652
+ return explicit?.[1] ?? agentId;
4653
+ }
4654
+ function predicateFor(type) {
4655
+ switch (type) {
4656
+ case "preference":
4657
+ return "prefers";
4658
+ case "belief_update":
4659
+ return "updated";
4660
+ case "decision":
4661
+ return "decided";
4662
+ case "event":
4663
+ return "happened";
4664
+ case "code":
4665
+ return "implemented";
4666
+ default:
4667
+ return "states";
4668
+ }
4669
+ }
4670
+ function extractMemoryCards(row) {
4671
+ const sentences = splitSentences(row.raw_text);
4672
+ const cards = [];
4673
+ for (const sentence of sentences) {
4674
+ const type = inferCardType(sentence, row.tool_name);
4675
+ const subject = extractSubject(sentence, row.agent_id);
4676
+ const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
4677
+ cards.push({
4678
+ id: stableId(row.id, type, content),
4679
+ memory_id: row.id,
4680
+ agent_id: row.agent_id,
4681
+ session_id: row.session_id,
4682
+ project_name: row.project_name ?? null,
4683
+ timestamp: row.timestamp,
4684
+ card_type: type,
4685
+ subject,
4686
+ predicate: predicateFor(type),
4687
+ object: content,
4688
+ content,
4689
+ source_ref: row.id,
4690
+ confidence: type === "fact" ? 0.55 : 0.65
4691
+ });
4692
+ if (cards.length >= MAX_CARDS_PER_MEMORY) break;
4693
+ }
4694
+ return cards;
4695
+ }
4696
+ async function insertMemoryCardsForBatch(rows) {
4697
+ const cards = rows.flatMap(extractMemoryCards);
4698
+ if (cards.length === 0) return 0;
4699
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4700
+ const client = getClient();
4701
+ const stmts = cards.map((card) => ({
4702
+ sql: `INSERT OR IGNORE INTO memory_cards
4703
+ (id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
4704
+ subject, predicate, object, content, source_ref, confidence, active, created_at)
4705
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
4706
+ args: [
4707
+ card.id,
4708
+ card.memory_id,
4709
+ card.agent_id,
4710
+ card.session_id,
4711
+ card.project_name,
4712
+ card.timestamp,
4713
+ card.card_type,
4714
+ card.subject,
4715
+ card.predicate,
4716
+ card.object,
4717
+ card.content,
4718
+ card.source_ref,
4719
+ card.confidence,
4720
+ now
4721
+ ]
4722
+ }));
4723
+ await client.batch(stmts, "write");
4724
+ return cards.length;
4725
+ }
4726
+ function buildMatchExpr(queryText) {
4727
+ const terms = queryText.toLowerCase().split(/\s+/).filter((t) => t.length >= 3).map((t) => t.replace(/[^a-z0-9_]/g, "")).filter((t) => t.length >= 3).slice(0, 12);
4728
+ if (terms.length === 0) return null;
4729
+ return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
4730
+ }
4731
+ async function searchMemoryCards(queryText, agentId, options) {
4732
+ const limit = options?.limit ?? 10;
4733
+ const matchExpr = buildMatchExpr(queryText);
4734
+ if (!matchExpr) return [];
4735
+ let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
4736
+ c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
4737
+ FROM memory_cards c
4738
+ JOIN memory_cards_fts fts ON c.rowid = fts.rowid
4739
+ WHERE memory_cards_fts MATCH ?
4740
+ AND c.agent_id = ?
4741
+ AND COALESCE(c.active, 1) = 1`;
4742
+ const args = [matchExpr, agentId];
4743
+ if (options?.projectName) {
4744
+ sql += ` AND c.project_name = ?`;
4745
+ args.push(options.projectName);
4746
+ }
4747
+ if (options?.since) {
4748
+ sql += ` AND c.timestamp >= ?`;
4749
+ args.push(options.since);
4750
+ }
4751
+ sql += ` ORDER BY rank LIMIT ?`;
4752
+ args.push(limit);
4753
+ const result = await getClient().execute({ sql, args });
4754
+ return result.rows.map((row) => ({
4755
+ id: `card:${String(row.id)}`,
4756
+ agent_id: String(row.agent_id),
4757
+ agent_role: "memory_card",
4758
+ session_id: String(row.session_id),
4759
+ timestamp: String(row.timestamp),
4760
+ tool_name: `memory_card:${String(row.card_type)}`,
4761
+ project_name: row.project_name == null ? "" : String(row.project_name),
4762
+ has_error: false,
4763
+ raw_text: `[${String(row.card_type)}] ${String(row.content)}
4764
+ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
4765
+ vector: [],
4766
+ importance: 6,
4767
+ status: "active",
4768
+ confidence: Number(row.confidence ?? 0.6),
4769
+ last_accessed: String(row.timestamp)
4770
+ }));
4771
+ }
4772
+ var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
4773
+ var init_memory_cards = __esm({
4774
+ "src/lib/memory-cards.ts"() {
4775
+ "use strict";
4776
+ init_database();
4777
+ MAX_CARDS_PER_MEMORY = 6;
4778
+ MAX_SENTENCE_CHARS = 360;
4779
+ }
4780
+ });
4781
+
4544
4782
  // src/lib/store.ts
4545
4783
  var store_exports = {};
4546
4784
  __export(store_exports, {
@@ -4879,6 +5117,11 @@ async function flushBatch() {
4879
5117
  const globalClient = getClient();
4880
5118
  const globalStmts = batch.map(buildStmt);
4881
5119
  await globalClient.batch(globalStmts, "write");
5120
+ try {
5121
+ const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
5122
+ await insertMemoryCardsForBatch2(batch);
5123
+ } catch {
5124
+ }
4882
5125
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
4883
5126
  _pendingRecords.splice(0, batch.length);
4884
5127
  try {
@@ -6319,9 +6562,18 @@ async function hybridSearch(queryText, agentId, options) {
6319
6562
  } catch {
6320
6563
  }
6321
6564
  }
6322
- const [ftsResults, vectorResults, grepResults] = await Promise.all([
6565
+ const includeStructuredCards = effectiveIsBroad || effectiveOptions.includeStructuredCards === true;
6566
+ const [ftsResults, vectorResults, cardResults, grepResults] = await Promise.all([
6323
6567
  lightweightSearch(effectiveQuery, agentId, fetchOptions),
6324
6568
  queryVector ? searchMemories(queryVector, agentId, fetchOptions) : Promise.resolve([]),
6569
+ includeStructuredCards ? (async () => {
6570
+ try {
6571
+ const { searchMemoryCards: searchMemoryCards2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
6572
+ return await searchMemoryCards2(effectiveQuery, agentId, fetchOptions);
6573
+ } catch {
6574
+ return [];
6575
+ }
6576
+ })() : Promise.resolve([]),
6325
6577
  grepPromise
6326
6578
  ]);
6327
6579
  const lists = [];
@@ -6334,6 +6586,10 @@ async function hybridSearch(queryText, agentId, options) {
6334
6586
  lists.push(vectorResults);
6335
6587
  weights.push(1);
6336
6588
  }
6589
+ if (cardResults.length > 0) {
6590
+ lists.push(cardResults);
6591
+ weights.push(1.2);
6592
+ }
6337
6593
  if (grepResults.length > 0) {
6338
6594
  lists.push(grepResults);
6339
6595
  weights.push(0.5);
@@ -6402,6 +6658,7 @@ async function hybridSearch(queryText, agentId, options) {
6402
6658
  signals: {
6403
6659
  fts: ftsResults.length,
6404
6660
  vector: vectorResults.length,
6661
+ cards: cardResults.length,
6405
6662
  grep: grepResults.length,
6406
6663
  entityBoost: entityBoostRan,
6407
6664
  reranker: rerankedAndBlended !== null,
@@ -6551,6 +6808,15 @@ async function lightweightSearch(queryText, agentId, options) {
6551
6808
  if (options?.includeSource && results.length > 0) {
6552
6809
  await attachDocumentMetadata(results);
6553
6810
  }
6811
+ if (options?.includeStructuredCards !== true) return results;
6812
+ try {
6813
+ const { searchMemoryCards: searchMemoryCards2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
6814
+ const cardResults = await searchMemoryCards2(queryText, agentId, options);
6815
+ if (cardResults.length > 0) {
6816
+ return rrfMergeMulti([results, cardResults], limit, RRF_K, [1, 1.2]);
6817
+ }
6818
+ } catch {
6819
+ }
6554
6820
  return results;
6555
6821
  }
6556
6822
  async function ftsQuery(client, matchExpr, agentId, options, limit) {
@@ -11647,7 +11913,7 @@ __export(identity_exports, {
11647
11913
  import { existsSync as existsSync20, mkdirSync as mkdirSync10, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "fs";
11648
11914
  import { readdirSync as readdirSync7 } from "fs";
11649
11915
  import path26 from "path";
11650
- import { createHash as createHash2 } from "crypto";
11916
+ import { createHash as createHash3 } from "crypto";
11651
11917
  function ensureDir2() {
11652
11918
  if (!existsSync20(IDENTITY_DIR2)) {
11653
11919
  mkdirSync10(IDENTITY_DIR2, { recursive: true });
@@ -11694,7 +11960,7 @@ function parseFrontmatter(raw) {
11694
11960
  };
11695
11961
  }
11696
11962
  function contentHash(content) {
11697
- return createHash2("sha256").update(content).digest("hex").slice(0, 16);
11963
+ return createHash3("sha256").update(content).digest("hex").slice(0, 16);
11698
11964
  }
11699
11965
  function getIdentity(agentId) {
11700
11966
  const filePath = identityPath(agentId);
@@ -12622,6 +12888,78 @@ var init_worker_gate = __esm({
12622
12888
  }
12623
12889
  });
12624
12890
 
12891
+ // src/bin/fast-db-init.ts
12892
+ var fast_db_init_exports = {};
12893
+ __export(fast_db_init_exports, {
12894
+ fastDbInit: () => fastDbInit
12895
+ });
12896
+ async function fastDbInit() {
12897
+ const { isInitialized: isInitialized2, getClient: getClient2, setExternalClient: setExternalClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
12898
+ if (isInitialized2()) {
12899
+ return getClient2();
12900
+ }
12901
+ try {
12902
+ const { connectEmbedDaemon: connectEmbedDaemon2, sendDaemonRequest: sendDaemonRequest2, isClientConnected: isClientConnected2 } = await Promise.resolve().then(() => (init_exe_daemon_client(), exe_daemon_client_exports));
12903
+ const { deserializeResultSet: deserializeResultSet2 } = await Promise.resolve().then(() => (init_daemon_protocol(), daemon_protocol_exports));
12904
+ await connectEmbedDaemon2();
12905
+ if (isClientConnected2()) {
12906
+ const daemonClient = {
12907
+ async execute(stmt) {
12908
+ const sql = typeof stmt === "string" ? stmt : stmt.sql;
12909
+ const args = typeof stmt === "string" ? [] : Array.isArray(stmt.args) ? stmt.args : [];
12910
+ const resp = await sendDaemonRequest2({ type: "db-execute", sql, args });
12911
+ if (resp.error) throw new Error(String(resp.error));
12912
+ if (resp.db) return deserializeResultSet2(resp.db);
12913
+ throw new Error("Unexpected daemon response");
12914
+ },
12915
+ async batch(stmts, mode) {
12916
+ const statements = stmts.map((s) => {
12917
+ const sql = typeof s === "string" ? s : s.sql;
12918
+ const args = typeof s === "string" ? [] : Array.isArray(s.args) ? s.args : [];
12919
+ return { sql, args };
12920
+ });
12921
+ const resp = await sendDaemonRequest2({ type: "db-batch", statements, mode: mode ?? "deferred" });
12922
+ if (resp.error) throw new Error(String(resp.error));
12923
+ const batchResults = resp["db-batch"];
12924
+ if (batchResults) return batchResults.map(deserializeResultSet2);
12925
+ throw new Error("Unexpected daemon batch response");
12926
+ },
12927
+ async transaction(_mode) {
12928
+ throw new Error("Transactions not supported via daemon socket");
12929
+ },
12930
+ async executeMultiple(_sql) {
12931
+ throw new Error("executeMultiple not supported via daemon socket");
12932
+ },
12933
+ async migrate(_stmts) {
12934
+ throw new Error("migrate not supported via daemon socket");
12935
+ },
12936
+ sync() {
12937
+ return Promise.resolve(void 0);
12938
+ },
12939
+ close() {
12940
+ },
12941
+ get closed() {
12942
+ return false;
12943
+ },
12944
+ get protocol() {
12945
+ return "file";
12946
+ }
12947
+ };
12948
+ setExternalClient2(daemonClient);
12949
+ return daemonClient;
12950
+ }
12951
+ } catch {
12952
+ }
12953
+ const { initStore: initStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
12954
+ await initStore2({ lightweight: true });
12955
+ return getClient2();
12956
+ }
12957
+ var init_fast_db_init = __esm({
12958
+ "src/bin/fast-db-init.ts"() {
12959
+ "use strict";
12960
+ }
12961
+ });
12962
+
12625
12963
  // src/lib/db-backup.ts
12626
12964
  var db_backup_exports = {};
12627
12965
  __export(db_backup_exports, {
@@ -18454,8 +18792,6 @@ init_database();
18454
18792
  import { z as z56 } from "zod";
18455
18793
 
18456
18794
  // src/bin/exe-doctor.ts
18457
- init_store();
18458
- init_database();
18459
18795
  import os14 from "os";
18460
18796
 
18461
18797
  // src/lib/is-main.ts
@@ -18739,6 +19075,140 @@ async function detectConflicts(client, projectFilter, agentFilter2) {
18739
19075
  };
18740
19076
  }
18741
19077
 
19078
+ // src/adapters/runtime-hook-manifest.ts
19079
+ var EXE_HOOKS = {
19080
+ postToolCombined: "dist/hooks/post-tool-combined.js",
19081
+ sessionStart: "dist/hooks/session-start.js",
19082
+ promptSubmit: "dist/hooks/prompt-submit.js",
19083
+ heartbeat: "dist/hooks/exe-heartbeat-hook.js",
19084
+ stop: "dist/hooks/stop.js",
19085
+ preToolUse: "dist/hooks/pre-tool-use.js",
19086
+ subagentStop: "dist/hooks/subagent-stop.js",
19087
+ preCompact: "dist/hooks/pre-compact.js",
19088
+ postCompact: "dist/hooks/post-compact.js",
19089
+ sessionEnd: "dist/hooks/session-end.js",
19090
+ notification: "dist/hooks/notification.js",
19091
+ instructionsLoaded: "dist/hooks/instructions-loaded.js"
19092
+ };
19093
+ var EXE_HOOK_MANIFEST = [
19094
+ {
19095
+ key: "postToolCombined",
19096
+ event: "PostToolUse",
19097
+ commandMarker: EXE_HOOKS.postToolCombined,
19098
+ owner: "exe-os",
19099
+ purpose: "Single PostToolUse entrypoint for ingestion, error recall, summaries, and bug detection.",
19100
+ runtimes: ["claude", "codex", "opencode"],
19101
+ checkpointRole: "none"
19102
+ },
19103
+ {
19104
+ key: "sessionStart",
19105
+ event: "SessionStart",
19106
+ commandMarker: EXE_HOOKS.sessionStart,
19107
+ owner: "exe-os",
19108
+ purpose: "Loads agent identity, procedures, and boot context.",
19109
+ runtimes: ["claude", "codex", "opencode"],
19110
+ checkpointRole: "none"
19111
+ },
19112
+ {
19113
+ key: "promptSubmit",
19114
+ event: "UserPromptSubmit",
19115
+ commandMarker: EXE_HOOKS.promptSubmit,
19116
+ owner: "exe-os",
19117
+ purpose: "Injects current tasks, pending reviews, and local context before each prompt.",
19118
+ runtimes: ["claude", "codex", "opencode"],
19119
+ checkpointRole: "none"
19120
+ },
19121
+ {
19122
+ key: "heartbeat",
19123
+ event: "UserPromptSubmit",
19124
+ commandMarker: EXE_HOOKS.heartbeat,
19125
+ owner: "exe-os",
19126
+ purpose: "Lightweight heartbeat/status sidecar for Claude Code sessions.",
19127
+ runtimes: ["claude"],
19128
+ checkpointRole: "none"
19129
+ },
19130
+ {
19131
+ key: "stop",
19132
+ event: "Stop",
19133
+ commandMarker: EXE_HOOKS.stop,
19134
+ owner: "exe-os",
19135
+ purpose: "Finalizes task state, capacity signals, and emergency checkpointing.",
19136
+ runtimes: ["claude", "codex", "opencode"],
19137
+ checkpointRole: "capacity_checkpoint"
19138
+ },
19139
+ {
19140
+ key: "preToolUse",
19141
+ event: "PreToolUse",
19142
+ commandMarker: EXE_HOOKS.preToolUse,
19143
+ owner: "exe-os",
19144
+ purpose: "Preflight guardrails before shell/tool execution.",
19145
+ runtimes: ["claude", "codex", "opencode"],
19146
+ checkpointRole: "none"
19147
+ },
19148
+ {
19149
+ key: "subagentStop",
19150
+ event: "SubagentStop",
19151
+ commandMarker: EXE_HOOKS.subagentStop,
19152
+ owner: "exe-os",
19153
+ purpose: "Captures subagent completion context.",
19154
+ runtimes: ["claude"],
19155
+ checkpointRole: "none"
19156
+ },
19157
+ {
19158
+ key: "preCompact",
19159
+ event: "PreCompact",
19160
+ commandMarker: EXE_HOOKS.preCompact,
19161
+ owner: "exe-os",
19162
+ purpose: "Writes active-task snapshot and compaction recovery context.",
19163
+ runtimes: ["claude"],
19164
+ checkpointRole: "recovery_context"
19165
+ },
19166
+ {
19167
+ key: "postCompact",
19168
+ event: "PostCompact",
19169
+ commandMarker: EXE_HOOKS.postCompact,
19170
+ owner: "exe-os",
19171
+ purpose: "Rehydrates recovery context after compaction.",
19172
+ runtimes: ["claude"],
19173
+ checkpointRole: "recovery_context"
19174
+ },
19175
+ {
19176
+ key: "sessionEnd",
19177
+ event: "SessionEnd",
19178
+ commandMarker: EXE_HOOKS.sessionEnd,
19179
+ owner: "exe-os",
19180
+ purpose: "Stores session-end checkpoint and triages orphaned in-progress tasks.",
19181
+ runtimes: ["claude"],
19182
+ checkpointRole: "session_summary"
19183
+ },
19184
+ {
19185
+ key: "notification",
19186
+ event: "Notification",
19187
+ commandMarker: EXE_HOOKS.notification,
19188
+ owner: "exe-os",
19189
+ purpose: "Captures runtime notifications and nudges.",
19190
+ runtimes: ["claude"],
19191
+ checkpointRole: "none"
19192
+ },
19193
+ {
19194
+ key: "instructionsLoaded",
19195
+ event: "InstructionsLoaded",
19196
+ commandMarker: EXE_HOOKS.instructionsLoaded,
19197
+ owner: "exe-os",
19198
+ purpose: "Applies runtime instruction post-processing.",
19199
+ runtimes: ["claude"],
19200
+ checkpointRole: "none"
19201
+ }
19202
+ ];
19203
+ var LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS = [
19204
+ "dist/hooks/ingest.js",
19205
+ "dist/hooks/error-recall.js",
19206
+ "dist/hooks/ingest-worker.js"
19207
+ ];
19208
+ function manifestEntryForCommand(command) {
19209
+ return EXE_HOOK_MANIFEST.find((entry) => command.includes(entry.commandMarker));
19210
+ }
19211
+
18742
19212
  // src/bin/exe-doctor.ts
18743
19213
  function parseFlags(argv) {
18744
19214
  const flags = { fix: false, dryRun: false, verbose: false, conflicts: false };
@@ -18937,6 +19407,121 @@ function auditHookHealth() {
18937
19407
  const topPatterns = [...patternCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([pattern, count]) => ({ pattern, count }));
18938
19408
  return { logExists: true, totalLines, errorsLastHour, topPatterns };
18939
19409
  }
19410
+ function safeReadJson(filePath) {
19411
+ if (!existsSync27(filePath)) return null;
19412
+ try {
19413
+ return JSON.parse(readFileSync20(filePath, "utf-8"));
19414
+ } catch {
19415
+ return null;
19416
+ }
19417
+ }
19418
+ function collectHookCommandsFromClaudeSettings(settings) {
19419
+ const hooks = settings?.hooks;
19420
+ if (!hooks || typeof hooks !== "object") return [];
19421
+ const commands = [];
19422
+ for (const [event, groups] of Object.entries(hooks)) {
19423
+ if (!Array.isArray(groups)) continue;
19424
+ for (const group of groups) {
19425
+ const hooksForGroup = group?.hooks;
19426
+ if (!Array.isArray(hooksForGroup)) continue;
19427
+ for (const hook of hooksForGroup) {
19428
+ const command = hook?.command;
19429
+ if (typeof command === "string") commands.push({ event, command });
19430
+ }
19431
+ }
19432
+ }
19433
+ return commands;
19434
+ }
19435
+ function collectHookCommandsFromCodexHooks(config2) {
19436
+ const commands = [];
19437
+ if (!config2 || typeof config2 !== "object") return commands;
19438
+ const root = config2;
19439
+ for (const [event, value] of Object.entries(root)) {
19440
+ const entries = Array.isArray(value) ? value : value && typeof value === "object" ? Object.values(value) : [];
19441
+ for (const entry of entries) {
19442
+ if (typeof entry === "string") commands.push({ event, command: entry });
19443
+ const command = entry?.command;
19444
+ if (typeof command === "string") commands.push({ event, command });
19445
+ }
19446
+ }
19447
+ return commands;
19448
+ }
19449
+ function buildHookOwnershipIssues(runtime, commands) {
19450
+ const issues = [];
19451
+ for (const marker of LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS) {
19452
+ const count = commands.filter((cmd) => cmd.command.includes(marker)).length;
19453
+ if (count > 0) {
19454
+ issues.push({
19455
+ runtime,
19456
+ event: "PostToolUse",
19457
+ marker,
19458
+ count,
19459
+ message: `Legacy split PostToolUse hook still installed: ${marker}`
19460
+ });
19461
+ }
19462
+ }
19463
+ for (const entry of EXE_HOOK_MANIFEST.filter((hook) => hook.runtimes.includes(runtime))) {
19464
+ const matching = commands.filter((cmd) => cmd.command.includes(entry.commandMarker));
19465
+ if (matching.length > 1) {
19466
+ issues.push({
19467
+ runtime,
19468
+ event: entry.event,
19469
+ marker: entry.commandMarker,
19470
+ count: matching.length,
19471
+ message: `Duplicate exe-os hook owner for ${entry.event}: ${entry.commandMarker}`
19472
+ });
19473
+ }
19474
+ for (const cmd of matching) {
19475
+ if (cmd.event !== entry.event) {
19476
+ issues.push({
19477
+ runtime,
19478
+ event: cmd.event,
19479
+ marker: entry.commandMarker,
19480
+ count: 1,
19481
+ message: `exe-os hook ${entry.commandMarker} is registered under ${cmd.event}, expected ${entry.event}`
19482
+ });
19483
+ }
19484
+ }
19485
+ }
19486
+ for (const cmd of commands) {
19487
+ if (!cmd.command.includes("dist/hooks/")) continue;
19488
+ if (!cmd.command.includes("exe-os")) continue;
19489
+ const entry = manifestEntryForCommand(cmd.command);
19490
+ const isLegacy = LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS.some((marker) => cmd.command.includes(marker));
19491
+ if (!entry && !isLegacy) {
19492
+ issues.push({
19493
+ runtime,
19494
+ event: cmd.event,
19495
+ marker: "dist/hooks/",
19496
+ count: 1,
19497
+ message: `Unknown exe-os hook command not present in ownership manifest: ${cmd.command.slice(0, 160)}`
19498
+ });
19499
+ }
19500
+ }
19501
+ return issues;
19502
+ }
19503
+ function auditHookOwnership() {
19504
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
19505
+ const checkedFiles = [];
19506
+ const issues = [];
19507
+ const claudeSettingsPath = path32.join(home, ".claude", "settings.json");
19508
+ const claudeSettings = safeReadJson(claudeSettingsPath);
19509
+ if (claudeSettings) {
19510
+ checkedFiles.push(claudeSettingsPath);
19511
+ issues.push(...buildHookOwnershipIssues("claude", collectHookCommandsFromClaudeSettings(claudeSettings)));
19512
+ }
19513
+ const codexHooksPath = path32.join(home, ".codex", "hooks.json");
19514
+ const codexHooks = safeReadJson(codexHooksPath);
19515
+ if (codexHooks) {
19516
+ checkedFiles.push(codexHooksPath);
19517
+ issues.push(...buildHookOwnershipIssues("codex", collectHookCommandsFromCodexHooks(codexHooks)));
19518
+ }
19519
+ return {
19520
+ checkedFiles,
19521
+ issues,
19522
+ staleLegacyHooks: issues.filter((issue) => issue.message.includes("Legacy split"))
19523
+ };
19524
+ }
18940
19525
  async function auditShards() {
18941
19526
  try {
18942
19527
  const { auditShardHealth: auditShardHealth2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -18981,7 +19566,8 @@ async function runAudit(client, flags) {
18981
19566
  }
18982
19567
  const duplicateCount = duplicates.reduce((sum, d) => sum + d.delete_ids.length, 0);
18983
19568
  const hookHealth = auditHookHealth();
18984
- return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts, hookHealth, shards };
19569
+ const hookOwnership = auditHookOwnership();
19570
+ return { stats, nullVectors, duplicates, duplicateCount, bloated, fts, orphanedProjects, conflicts, hookHealth, hookOwnership, shards };
18985
19571
  }
18986
19572
  function indicator(value, warn) {
18987
19573
  if (value === 0) return "\u{1F7E2}";
@@ -19060,6 +19646,15 @@ function formatReport(report, flags) {
19060
19646
  lines.push(` ${p.count}x: ${p.pattern}`);
19061
19647
  }
19062
19648
  }
19649
+ const ho = report.hookOwnership;
19650
+ if (ho.issues.length === 0) {
19651
+ lines.push(`\u{1F7E2} Hook ownership: ${ho.checkedFiles.length > 0 ? "manifest clean" : "no local hook config found"}`);
19652
+ } else {
19653
+ lines.push(`\u{1F534} Hook ownership: ${fmtNum(ho.issues.length)} issue(s)`);
19654
+ for (const issue of ho.issues.slice(0, 5)) {
19655
+ lines.push(` [${issue.runtime}/${issue.event}] ${issue.message}`);
19656
+ }
19657
+ }
19063
19658
  const sh = report.shards;
19064
19659
  if (sh.total > 0) {
19065
19660
  if (sh.unreadable === 0) {
@@ -19129,6 +19724,9 @@ function formatReport(report, flags) {
19129
19724
  if (report.conflicts.superseded > 0) {
19130
19725
  recs.push(`${fmtNum(report.conflicts.superseded)} superseded memories can be deactivated`);
19131
19726
  }
19727
+ if (report.hookOwnership.issues.length > 0) {
19728
+ recs.push(`Run exe-os install to refresh hook config; remove stale exe-os hook commands if they remain`);
19729
+ }
19132
19730
  if (recs.length > 0) {
19133
19731
  lines.push("Recommendations:");
19134
19732
  for (const r of recs) {
@@ -19262,8 +19860,8 @@ function splitAtSentences(text3, maxChunkSize) {
19262
19860
  }
19263
19861
  async function main(argv = process.argv.slice(2)) {
19264
19862
  const flags = parseFlags(argv);
19265
- await initStore();
19266
- const client = getClient();
19863
+ const { fastDbInit: fastDbInit2 } = await Promise.resolve().then(() => (init_fast_db_init(), fast_db_init_exports));
19864
+ const client = await fastDbInit2();
19267
19865
  const report = await runAudit(client, flags);
19268
19866
  console.log(formatReport(report, flags));
19269
19867
  if (flags.fix || flags.dryRun) {