@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
@@ -257,8 +257,8 @@ var init_config = __esm({
257
257
  rerankerAutoTrigger: {
258
258
  enabled: true,
259
259
  broadQueryMinCardinality: 5e4,
260
- fetchTopK: 150,
261
- returnTopK: 5
260
+ fetchTopK: 200,
261
+ returnTopK: 20
262
262
  }
263
263
  },
264
264
  graphRagEnabled: true,
@@ -3299,6 +3299,51 @@ async function ensureSchema() {
3299
3299
  VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
3300
3300
  END;
3301
3301
  `);
3302
+ await client.executeMultiple(`
3303
+ CREATE TABLE IF NOT EXISTS memory_cards (
3304
+ id TEXT PRIMARY KEY,
3305
+ memory_id TEXT NOT NULL,
3306
+ agent_id TEXT NOT NULL,
3307
+ session_id TEXT NOT NULL,
3308
+ project_name TEXT,
3309
+ timestamp TEXT NOT NULL,
3310
+ card_type TEXT NOT NULL,
3311
+ subject TEXT,
3312
+ predicate TEXT,
3313
+ object TEXT,
3314
+ content TEXT NOT NULL,
3315
+ source_ref TEXT,
3316
+ confidence REAL DEFAULT 0.6,
3317
+ active INTEGER DEFAULT 1,
3318
+ created_at TEXT NOT NULL
3319
+ );
3320
+
3321
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
3322
+ ON memory_cards(agent_id, active, timestamp);
3323
+
3324
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
3325
+ ON memory_cards(memory_id);
3326
+
3327
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
3328
+ USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
3329
+
3330
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
3331
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
3332
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
3333
+ END;
3334
+
3335
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
3336
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
3337
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
3338
+ END;
3339
+
3340
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
3341
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
3342
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
3343
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
3344
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
3345
+ END;
3346
+ `);
3302
3347
  try {
3303
3348
  await client.execute({
3304
3349
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
@@ -6680,15 +6725,15 @@ var init_task_scope = __esm({
6680
6725
 
6681
6726
  // src/lib/keychain.ts
6682
6727
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
6683
- import { existsSync as existsSync16 } from "fs";
6728
+ import { existsSync as existsSync17 } from "fs";
6684
6729
  import { execSync as execSync8 } from "child_process";
6685
- import path20 from "path";
6730
+ import path21 from "path";
6686
6731
  import os12 from "os";
6687
6732
  function getKeyDir() {
6688
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path20.join(os12.homedir(), ".exe-os");
6733
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path21.join(os12.homedir(), ".exe-os");
6689
6734
  }
6690
6735
  function getKeyPath() {
6691
- return path20.join(getKeyDir(), "master.key");
6736
+ return path21.join(getKeyDir(), "master.key");
6692
6737
  }
6693
6738
  function macKeychainGet() {
6694
6739
  if (process.platform !== "darwin") return null;
@@ -6836,7 +6881,7 @@ async function getMasterKey() {
6836
6881
  }
6837
6882
  }
6838
6883
  const keyPath = getKeyPath();
6839
- if (!existsSync16(keyPath)) {
6884
+ if (!existsSync17(keyPath)) {
6840
6885
  process.stderr.write(
6841
6886
  `[keychain] Key not found at ${keyPath} (HOME=${os12.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
6842
6887
  `
@@ -7110,12 +7155,12 @@ __export(shard_manager_exports, {
7110
7155
  listShards: () => listShards,
7111
7156
  shardExists: () => shardExists
7112
7157
  });
7113
- import path21 from "path";
7114
- import { existsSync as existsSync17, mkdirSync as mkdirSync9, readdirSync as readdirSync5, renameSync as renameSync4, statSync as statSync2 } from "fs";
7158
+ import path22 from "path";
7159
+ import { existsSync as existsSync18, mkdirSync as mkdirSync9, readdirSync as readdirSync5, renameSync as renameSync5, statSync as statSync3 } from "fs";
7115
7160
  import { createClient as createClient2 } from "@libsql/client";
7116
7161
  function initShardManager(encryptionKey) {
7117
7162
  _encryptionKey = encryptionKey;
7118
- if (!existsSync17(SHARDS_DIR)) {
7163
+ if (!existsSync18(SHARDS_DIR)) {
7119
7164
  mkdirSync9(SHARDS_DIR, { recursive: true });
7120
7165
  }
7121
7166
  _shardingEnabled = true;
@@ -7145,7 +7190,7 @@ function getShardClient(projectName) {
7145
7190
  while (_shards.size >= MAX_OPEN_SHARDS) {
7146
7191
  evictLRU();
7147
7192
  }
7148
- const dbPath = path21.join(SHARDS_DIR, `${safeName}.db`);
7193
+ const dbPath = path22.join(SHARDS_DIR, `${safeName}.db`);
7149
7194
  const client = createClient2({
7150
7195
  url: `file:${dbPath}`,
7151
7196
  encryptionKey: _encryptionKey
@@ -7156,13 +7201,13 @@ function getShardClient(projectName) {
7156
7201
  }
7157
7202
  function shardExists(projectName) {
7158
7203
  const safeName = safeShardName(projectName);
7159
- return existsSync17(path21.join(SHARDS_DIR, `${safeName}.db`));
7204
+ return existsSync18(path22.join(SHARDS_DIR, `${safeName}.db`));
7160
7205
  }
7161
7206
  function safeShardName(projectName) {
7162
7207
  return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
7163
7208
  }
7164
7209
  function listShards() {
7165
- if (!existsSync17(SHARDS_DIR)) return [];
7210
+ if (!existsSync18(SHARDS_DIR)) return [];
7166
7211
  return readdirSync5(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
7167
7212
  }
7168
7213
  async function auditShardHealth(options = {}) {
@@ -7174,8 +7219,8 @@ async function auditShardHealth(options = {}) {
7174
7219
  const names = listShards();
7175
7220
  const shards = [];
7176
7221
  for (const name of names) {
7177
- const dbPath = path21.join(SHARDS_DIR, `${name}.db`);
7178
- const stat = statSync2(dbPath);
7222
+ const dbPath = path22.join(SHARDS_DIR, `${name}.db`);
7223
+ const stat = statSync3(dbPath);
7179
7224
  const item = {
7180
7225
  name,
7181
7226
  path: dbPath,
@@ -7209,8 +7254,8 @@ async function auditShardHealth(options = {}) {
7209
7254
  _shards.delete(name);
7210
7255
  _shardLastAccess.delete(name);
7211
7256
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7212
- const archivedPath = path21.join(SHARDS_DIR, `${name}.db.broken-${stamp}`);
7213
- renameSync4(dbPath, archivedPath);
7257
+ const archivedPath = path22.join(SHARDS_DIR, `${name}.db.broken-${stamp}`);
7258
+ renameSync5(dbPath, archivedPath);
7214
7259
  item.archivedPath = archivedPath;
7215
7260
  }
7216
7261
  } finally {
@@ -7426,12 +7471,12 @@ async function getReadyShardClient(projectName) {
7426
7471
  client.close();
7427
7472
  _shards.delete(safeName);
7428
7473
  _shardLastAccess.delete(safeName);
7429
- const dbPath = path21.join(SHARDS_DIR, `${safeName}.db`);
7430
- if (existsSync17(dbPath)) {
7431
- const stat = statSync2(dbPath);
7474
+ const dbPath = path22.join(SHARDS_DIR, `${safeName}.db`);
7475
+ if (existsSync18(dbPath)) {
7476
+ const stat = statSync3(dbPath);
7432
7477
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7433
- const archivedPath = path21.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
7434
- renameSync4(dbPath, archivedPath);
7478
+ const archivedPath = path22.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
7479
+ renameSync5(dbPath, archivedPath);
7435
7480
  process.stderr.write(
7436
7481
  `[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
7437
7482
  `
@@ -7498,7 +7543,7 @@ var init_shard_manager = __esm({
7498
7543
  "src/lib/shard-manager.ts"() {
7499
7544
  "use strict";
7500
7545
  init_config();
7501
- SHARDS_DIR = path21.join(EXE_AI_DIR, "shards");
7546
+ SHARDS_DIR = path22.join(EXE_AI_DIR, "shards");
7502
7547
  SHARD_IDLE_MS = 5 * 60 * 1e3;
7503
7548
  MAX_OPEN_SHARDS = 10;
7504
7549
  EVICTION_INTERVAL_MS = 60 * 1e3;
@@ -7765,6 +7810,164 @@ ${p.content}`).join("\n\n");
7765
7810
  }
7766
7811
  });
7767
7812
 
7813
+ // src/lib/memory-cards.ts
7814
+ var memory_cards_exports = {};
7815
+ __export(memory_cards_exports, {
7816
+ extractMemoryCards: () => extractMemoryCards,
7817
+ insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
7818
+ searchMemoryCards: () => searchMemoryCards
7819
+ });
7820
+ import { createHash as createHash2 } from "crypto";
7821
+ function stableId(memoryId, type, content) {
7822
+ return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
7823
+ }
7824
+ function cleanText(text) {
7825
+ return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
7826
+ }
7827
+ function splitSentences(text) {
7828
+ return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
7829
+ }
7830
+ function inferCardType(sentence, toolName) {
7831
+ const lower = sentence.toLowerCase();
7832
+ if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
7833
+ if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
7834
+ if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
7835
+ if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
7836
+ if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
7837
+ return "fact";
7838
+ }
7839
+ function extractSubject(sentence, agentId) {
7840
+ const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
7841
+ return explicit?.[1] ?? agentId;
7842
+ }
7843
+ function predicateFor(type) {
7844
+ switch (type) {
7845
+ case "preference":
7846
+ return "prefers";
7847
+ case "belief_update":
7848
+ return "updated";
7849
+ case "decision":
7850
+ return "decided";
7851
+ case "event":
7852
+ return "happened";
7853
+ case "code":
7854
+ return "implemented";
7855
+ default:
7856
+ return "states";
7857
+ }
7858
+ }
7859
+ function extractMemoryCards(row) {
7860
+ const sentences = splitSentences(row.raw_text);
7861
+ const cards = [];
7862
+ for (const sentence of sentences) {
7863
+ const type = inferCardType(sentence, row.tool_name);
7864
+ const subject = extractSubject(sentence, row.agent_id);
7865
+ const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
7866
+ cards.push({
7867
+ id: stableId(row.id, type, content),
7868
+ memory_id: row.id,
7869
+ agent_id: row.agent_id,
7870
+ session_id: row.session_id,
7871
+ project_name: row.project_name ?? null,
7872
+ timestamp: row.timestamp,
7873
+ card_type: type,
7874
+ subject,
7875
+ predicate: predicateFor(type),
7876
+ object: content,
7877
+ content,
7878
+ source_ref: row.id,
7879
+ confidence: type === "fact" ? 0.55 : 0.65
7880
+ });
7881
+ if (cards.length >= MAX_CARDS_PER_MEMORY) break;
7882
+ }
7883
+ return cards;
7884
+ }
7885
+ async function insertMemoryCardsForBatch(rows) {
7886
+ const cards = rows.flatMap(extractMemoryCards);
7887
+ if (cards.length === 0) return 0;
7888
+ const now = (/* @__PURE__ */ new Date()).toISOString();
7889
+ const client = getClient();
7890
+ const stmts = cards.map((card) => ({
7891
+ sql: `INSERT OR IGNORE INTO memory_cards
7892
+ (id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
7893
+ subject, predicate, object, content, source_ref, confidence, active, created_at)
7894
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
7895
+ args: [
7896
+ card.id,
7897
+ card.memory_id,
7898
+ card.agent_id,
7899
+ card.session_id,
7900
+ card.project_name,
7901
+ card.timestamp,
7902
+ card.card_type,
7903
+ card.subject,
7904
+ card.predicate,
7905
+ card.object,
7906
+ card.content,
7907
+ card.source_ref,
7908
+ card.confidence,
7909
+ now
7910
+ ]
7911
+ }));
7912
+ await client.batch(stmts, "write");
7913
+ return cards.length;
7914
+ }
7915
+ function buildMatchExpr(queryText) {
7916
+ 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);
7917
+ if (terms.length === 0) return null;
7918
+ return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
7919
+ }
7920
+ async function searchMemoryCards(queryText, agentId, options) {
7921
+ const limit = options?.limit ?? 10;
7922
+ const matchExpr = buildMatchExpr(queryText);
7923
+ if (!matchExpr) return [];
7924
+ let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
7925
+ c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
7926
+ FROM memory_cards c
7927
+ JOIN memory_cards_fts fts ON c.rowid = fts.rowid
7928
+ WHERE memory_cards_fts MATCH ?
7929
+ AND c.agent_id = ?
7930
+ AND COALESCE(c.active, 1) = 1`;
7931
+ const args = [matchExpr, agentId];
7932
+ if (options?.projectName) {
7933
+ sql += ` AND c.project_name = ?`;
7934
+ args.push(options.projectName);
7935
+ }
7936
+ if (options?.since) {
7937
+ sql += ` AND c.timestamp >= ?`;
7938
+ args.push(options.since);
7939
+ }
7940
+ sql += ` ORDER BY rank LIMIT ?`;
7941
+ args.push(limit);
7942
+ const result = await getClient().execute({ sql, args });
7943
+ return result.rows.map((row) => ({
7944
+ id: `card:${String(row.id)}`,
7945
+ agent_id: String(row.agent_id),
7946
+ agent_role: "memory_card",
7947
+ session_id: String(row.session_id),
7948
+ timestamp: String(row.timestamp),
7949
+ tool_name: `memory_card:${String(row.card_type)}`,
7950
+ project_name: row.project_name == null ? "" : String(row.project_name),
7951
+ has_error: false,
7952
+ raw_text: `[${String(row.card_type)}] ${String(row.content)}
7953
+ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
7954
+ vector: [],
7955
+ importance: 6,
7956
+ status: "active",
7957
+ confidence: Number(row.confidence ?? 0.6),
7958
+ last_accessed: String(row.timestamp)
7959
+ }));
7960
+ }
7961
+ var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
7962
+ var init_memory_cards = __esm({
7963
+ "src/lib/memory-cards.ts"() {
7964
+ "use strict";
7965
+ init_database();
7966
+ MAX_CARDS_PER_MEMORY = 6;
7967
+ MAX_SENTENCE_CHARS = 360;
7968
+ }
7969
+ });
7970
+
7768
7971
  // src/lib/store.ts
7769
7972
  var store_exports = {};
7770
7973
  __export(store_exports, {
@@ -8103,6 +8306,11 @@ async function flushBatch() {
8103
8306
  const globalClient = getClient();
8104
8307
  const globalStmts = batch.map(buildStmt);
8105
8308
  await globalClient.batch(globalStmts, "write");
8309
+ try {
8310
+ const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
8311
+ await insertMemoryCardsForBatch2(batch);
8312
+ } catch {
8313
+ }
8106
8314
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
8107
8315
  _pendingRecords.splice(0, batch.length);
8108
8316
  try {
@@ -8450,78 +8658,6 @@ var init_fast_db_init = __esm({
8450
8658
  }
8451
8659
  });
8452
8660
 
8453
- // src/lib/memory-queue.ts
8454
- import { appendFileSync as appendFileSync2, readFileSync as readFileSync14, renameSync as renameSync5, unlinkSync as unlinkSync8, existsSync as existsSync18, statSync as statSync3 } from "fs";
8455
- import path22 from "path";
8456
- function enqueueMemory(entry) {
8457
- appendFileSync2(QUEUE_PATH2, JSON.stringify(entry) + "\n");
8458
- }
8459
- var QUEUE_PATH2, PROCESSING_PATH, TTL_MS2;
8460
- var init_memory_queue = __esm({
8461
- "src/lib/memory-queue.ts"() {
8462
- "use strict";
8463
- init_config();
8464
- QUEUE_PATH2 = path22.join(EXE_AI_DIR, "memory-queue.jsonl");
8465
- PROCESSING_PATH = QUEUE_PATH2 + ".processing";
8466
- TTL_MS2 = 24 * 60 * 60 * 1e3;
8467
- }
8468
- });
8469
-
8470
- // src/lib/memory-queue-client.ts
8471
- var memory_queue_client_exports = {};
8472
- __export(memory_queue_client_exports, {
8473
- batchWriteMemoryViaDaemon: () => batchWriteMemoryViaDaemon,
8474
- writeMemoryViaDaemon: () => writeMemoryViaDaemon
8475
- });
8476
- async function writeMemoryViaDaemon(entry) {
8477
- if (process.env.EXE_IS_DAEMON === "1") {
8478
- enqueueMemory(entry);
8479
- return false;
8480
- }
8481
- if (!isClientConnected()) {
8482
- enqueueMemory(entry);
8483
- return false;
8484
- }
8485
- try {
8486
- const response = await sendDaemonRequest({
8487
- type: "write-memory",
8488
- entry
8489
- });
8490
- if (response.ok) return true;
8491
- enqueueMemory(entry);
8492
- return false;
8493
- } catch {
8494
- enqueueMemory(entry);
8495
- return false;
8496
- }
8497
- }
8498
- async function batchWriteMemoryViaDaemon(entries) {
8499
- if (entries.length === 0) return 0;
8500
- if (process.env.EXE_IS_DAEMON === "1" || !isClientConnected()) {
8501
- for (const entry of entries) enqueueMemory(entry);
8502
- return 0;
8503
- }
8504
- try {
8505
- const response = await sendDaemonRequest({
8506
- type: "batch-write-memory",
8507
- entries
8508
- });
8509
- if (response.ok) return response.count ?? entries.length;
8510
- for (const entry of entries) enqueueMemory(entry);
8511
- return 0;
8512
- } catch {
8513
- for (const entry of entries) enqueueMemory(entry);
8514
- return 0;
8515
- }
8516
- }
8517
- var init_memory_queue_client = __esm({
8518
- "src/lib/memory-queue-client.ts"() {
8519
- "use strict";
8520
- init_exe_daemon_client();
8521
- init_memory_queue();
8522
- }
8523
- });
8524
-
8525
8661
  // src/lib/active-agent.ts
8526
8662
  init_config();
8527
8663
  init_session_key();
@@ -8632,6 +8768,209 @@ function getActiveAgent() {
8632
8768
 
8633
8769
  // src/adapters/claude/hooks/pre-compact.ts
8634
8770
  init_task_scope();
8771
+
8772
+ // src/lib/auto-checkpoint.ts
8773
+ var FILE_RE = /(?:^|\s)([\w./-]+\.(?:ts|tsx|js|jsx|json|md|yml|yaml|sql|go|py|css|scss|html|sh))(?:\b|$)/g;
8774
+ var DECISION_RE = /\b(decision:|decided:|we decided|founder directive|captured in .*architecture|source of truth)\b/i;
8775
+ function asString(value, fallback = "") {
8776
+ if (value == null) return fallback;
8777
+ return String(value);
8778
+ }
8779
+ function compactLine(text, max = 220) {
8780
+ return text.replace(/\s+/g, " ").trim().slice(0, max);
8781
+ }
8782
+ function topEntries(counts, limit) {
8783
+ return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, limit).map(([name, count]) => `${name}(${count})`);
8784
+ }
8785
+ function buildAutoCheckpoint(input2) {
8786
+ const maxSamples = input2.maxSamples ?? 8;
8787
+ const projectCounts = /* @__PURE__ */ new Map();
8788
+ const toolCounts = /* @__PURE__ */ new Map();
8789
+ const files = /* @__PURE__ */ new Set();
8790
+ const errors = [];
8791
+ const samples = [];
8792
+ const decisionTexts = [];
8793
+ for (const row of input2.memories) {
8794
+ const tool = asString(row.tool_name, "unknown");
8795
+ const project = asString(row.project_name, input2.projectName || "unknown");
8796
+ const raw = asString(row.raw_text);
8797
+ const hasError = row.has_error === 1 || row.has_error === true;
8798
+ toolCounts.set(tool, (toolCounts.get(tool) ?? 0) + 1);
8799
+ projectCounts.set(project, (projectCounts.get(project) ?? 0) + 1);
8800
+ if (hasError && errors.length < 5) errors.push(compactLine(raw, 180));
8801
+ if (samples.length < maxSamples && raw.length > 30) {
8802
+ samples.push(`[${tool}] ${compactLine(raw)}`);
8803
+ }
8804
+ if (DECISION_RE.test(raw) && decisionTexts.length < 5) {
8805
+ decisionTexts.push(`AUTO DECISION CANDIDATE [${input2.agentId}]: ${compactLine(raw, 500)}`);
8806
+ }
8807
+ for (const match of raw.matchAll(FILE_RE)) {
8808
+ if (match[1]) files.add(match[1]);
8809
+ if (files.size >= 20) break;
8810
+ }
8811
+ }
8812
+ const taskLines = (input2.tasks ?? []).slice(0, 10).map((task) => {
8813
+ const status = asString(task.status, "unknown");
8814
+ const priority = asString(task.priority, "?").toUpperCase();
8815
+ const title = asString(task.title, "untitled");
8816
+ const taskFile = asString(task.task_file);
8817
+ return `- [${status}/${priority}] ${title}${taskFile ? ` (${taskFile})` : ""}`;
8818
+ });
8819
+ const parts = [
8820
+ `CONTEXT CHECKPOINT [auto:${input2.reason}]`,
8821
+ `Agent: ${input2.agentId} (${input2.agentRole})`,
8822
+ `Session: ${input2.sessionId}`,
8823
+ `Project: ${input2.projectName}`,
8824
+ `Time: ${(/* @__PURE__ */ new Date()).toISOString()}`,
8825
+ "",
8826
+ "## Recent Activity",
8827
+ `- Memories scanned: ${input2.memories.length}`,
8828
+ `- Projects: ${topEntries(projectCounts, 5).join(", ") || input2.projectName}`,
8829
+ `- Tools: ${topEntries(toolCounts, 8).join(", ") || "none"}`
8830
+ ];
8831
+ if (taskLines.length > 0) {
8832
+ parts.push("", "## Open / Active Tasks", ...taskLines);
8833
+ }
8834
+ if (files.size > 0) {
8835
+ parts.push("", "## Files Mentioned", ...[...files].slice(0, 20).map((f) => `- ${f}`));
8836
+ }
8837
+ if (samples.length > 0) {
8838
+ parts.push("", "## Important Recent Traces", ...samples.map((s) => `- ${s}`));
8839
+ }
8840
+ if (errors.length > 0) {
8841
+ parts.push("", "## Errors / Risks", ...errors.map((e) => `- ${e}`));
8842
+ }
8843
+ if (decisionTexts.length > 0) {
8844
+ parts.push("", "## Decision Candidates", ...decisionTexts.map((d) => `- ${d.replace(/^AUTO DECISION CANDIDATE \\[[^\\]]+\\]: /, "")}`));
8845
+ }
8846
+ return {
8847
+ checkpointText: parts.join("\n"),
8848
+ decisionTexts
8849
+ };
8850
+ }
8851
+
8852
+ // src/lib/memory-queue-client.ts
8853
+ init_exe_daemon_client();
8854
+
8855
+ // src/lib/memory-queue.ts
8856
+ init_config();
8857
+ import { appendFileSync as appendFileSync2, readFileSync as readFileSync14, renameSync as renameSync4, unlinkSync as unlinkSync8, existsSync as existsSync16, statSync as statSync2 } from "fs";
8858
+ import path20 from "path";
8859
+ var QUEUE_PATH2 = path20.join(EXE_AI_DIR, "memory-queue.jsonl");
8860
+ var PROCESSING_PATH = QUEUE_PATH2 + ".processing";
8861
+ var TTL_MS2 = 24 * 60 * 60 * 1e3;
8862
+ function enqueueMemory(entry) {
8863
+ appendFileSync2(QUEUE_PATH2, JSON.stringify(entry) + "\n");
8864
+ }
8865
+
8866
+ // src/lib/memory-queue-client.ts
8867
+ async function writeMemoryViaDaemon(entry) {
8868
+ if (process.env.EXE_IS_DAEMON === "1") {
8869
+ enqueueMemory(entry);
8870
+ return false;
8871
+ }
8872
+ if (!isClientConnected()) {
8873
+ enqueueMemory(entry);
8874
+ return false;
8875
+ }
8876
+ try {
8877
+ const response = await sendDaemonRequest({
8878
+ type: "write-memory",
8879
+ entry
8880
+ });
8881
+ if (response.ok) return true;
8882
+ enqueueMemory(entry);
8883
+ return false;
8884
+ } catch {
8885
+ enqueueMemory(entry);
8886
+ return false;
8887
+ }
8888
+ }
8889
+
8890
+ // src/lib/checkpoint-orchestrator.ts
8891
+ function toolNameForReason(reason) {
8892
+ switch (reason) {
8893
+ case "periodic":
8894
+ return "auto-summary";
8895
+ case "session-end":
8896
+ return "SessionEnd";
8897
+ case "pre-compact":
8898
+ return "pre-compact-hook";
8899
+ case "capacity-signal":
8900
+ return "auto-checkpoint";
8901
+ }
8902
+ }
8903
+ function importanceForReason(reason, override) {
8904
+ if (override !== void 0) return override;
8905
+ switch (reason) {
8906
+ case "periodic":
8907
+ return 7;
8908
+ case "session-end":
8909
+ case "pre-compact":
8910
+ case "capacity-signal":
8911
+ return 8;
8912
+ }
8913
+ }
8914
+ function buildContinuityCheckpoint(input2) {
8915
+ const { checkpointText, decisionTexts } = buildAutoCheckpoint({
8916
+ agentId: input2.agentId,
8917
+ agentRole: input2.agentRole,
8918
+ sessionId: input2.sessionId,
8919
+ projectName: input2.projectName,
8920
+ reason: input2.reason,
8921
+ memories: input2.memories ?? [],
8922
+ tasks: input2.tasks ?? [],
8923
+ maxSamples: input2.maxSamples
8924
+ });
8925
+ const extra = input2.extraSections?.filter((section) => section.trim().length > 0) ?? [];
8926
+ return {
8927
+ checkpointText: extra.length > 0 ? `${checkpointText}
8928
+
8929
+ ${extra.join("\n\n")}` : checkpointText,
8930
+ decisionTexts
8931
+ };
8932
+ }
8933
+ async function writeContinuityCheckpoint(input2) {
8934
+ const result = buildContinuityCheckpoint(input2);
8935
+ const now = (/* @__PURE__ */ new Date()).toISOString();
8936
+ await writeMemoryViaDaemon({
8937
+ raw_text: result.checkpointText,
8938
+ agent_id: input2.agentId,
8939
+ agent_role: input2.agentRole,
8940
+ session_id: input2.sessionId,
8941
+ tool_name: toolNameForReason(input2.reason),
8942
+ project_name: input2.projectName,
8943
+ timestamp: now,
8944
+ importance: importanceForReason(input2.reason, input2.importance),
8945
+ task_id: input2.taskId,
8946
+ memory_type: "checkpoint"
8947
+ });
8948
+ const decisionLimit = input2.reason === "periodic" ? 3 : 5;
8949
+ for (const decisionText of result.decisionTexts.slice(0, decisionLimit)) {
8950
+ await writeMemoryViaDaemon({
8951
+ raw_text: decisionText,
8952
+ agent_id: input2.agentId,
8953
+ agent_role: input2.agentRole,
8954
+ session_id: input2.sessionId,
8955
+ tool_name: "auto-decision",
8956
+ project_name: input2.projectName,
8957
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
8958
+ importance: 8,
8959
+ memory_type: "decision"
8960
+ });
8961
+ }
8962
+ return result;
8963
+ }
8964
+ async function checkpointActiveTask(input2) {
8965
+ const { writeCheckpoint: writeCheckpoint2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
8966
+ await writeCheckpoint2({
8967
+ taskId: input2.taskId,
8968
+ step: input2.step ?? "pre-compaction-checkpoint",
8969
+ contextSummary: `Auto-checkpoint before context compaction. Task: ${input2.taskTitle}. Session: ${input2.sessionId}. Project: ${input2.projectName}.`
8970
+ });
8971
+ }
8972
+
8973
+ // src/adapters/claude/hooks/pre-compact.ts
8635
8974
  if (!process.env.AGENT_ID) {
8636
8975
  process.env.AGENT_ID = "default";
8637
8976
  process.env.AGENT_ROLE = "employee";
@@ -8674,11 +9013,11 @@ ${taskLines}`);
8674
9013
  const taskId = String(task.id);
8675
9014
  const taskTitle = String(task.title);
8676
9015
  try {
8677
- const { writeCheckpoint: writeCheckpoint2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
8678
- await writeCheckpoint2({
9016
+ await checkpointActiveTask({
8679
9017
  taskId,
8680
- step: "pre-compaction-checkpoint",
8681
- contextSummary: `Auto-checkpoint before context compaction. Task: ${taskTitle}. Session: ${payload.session_id}. Project: ${projectName}.`
9018
+ taskTitle,
9019
+ sessionId: payload.session_id,
9020
+ projectName
8682
9021
  });
8683
9022
  } catch {
8684
9023
  }
@@ -8701,18 +9040,14 @@ ${taskLines}`);
8701
9040
  if (lastCheckpoint?.files_touched?.length) {
8702
9041
  recoveryLines.push(`Files: ${lastCheckpoint.files_touched.join(", ")}`);
8703
9042
  }
8704
- const { writeMemoryViaDaemon: writeMemoryViaDaemon2 } = await Promise.resolve().then(() => (init_memory_queue_client(), memory_queue_client_exports));
8705
- await writeMemoryViaDaemon2({
8706
- raw_text: recoveryLines.join("\n"),
8707
- agent_id: agent.agentId,
8708
- agent_role: agent.agentRole,
8709
- session_id: payload.session_id,
8710
- tool_name: "pre-compact-hook",
8711
- project_name: projectName,
8712
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
8713
- importance: 8,
8714
- task_id: taskId,
8715
- memory_type: "checkpoint"
9043
+ await writeContinuityCheckpoint({
9044
+ agentId: agent.agentId,
9045
+ agentRole: agent.agentRole,
9046
+ sessionId: payload.session_id,
9047
+ projectName,
9048
+ reason: "pre-compact",
9049
+ taskId,
9050
+ extraSections: [recoveryLines.join("\n")]
8716
9051
  });
8717
9052
  } catch {
8718
9053
  }