@askexenow/exe-os 0.9.60 → 0.9.62

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 (106) hide show
  1. package/deploy/stack-manifests/v0.9.json +62 -13
  2. package/dist/bin/backfill-conversations.js +282 -7
  3. package/dist/bin/backfill-responses.js +282 -7
  4. package/dist/bin/backfill-vectors.js +119 -7
  5. package/dist/bin/cc-doctor.js +376 -0
  6. package/dist/bin/cleanup-stale-review-tasks.js +282 -7
  7. package/dist/bin/cli.js +455 -77
  8. package/dist/bin/customer-readiness.js +33 -0
  9. package/dist/bin/exe-agent-config.js +2 -2
  10. package/dist/bin/exe-agent.js +3 -3
  11. package/dist/bin/exe-assign.js +282 -7
  12. package/dist/bin/exe-boot.js +125 -13
  13. package/dist/bin/exe-call.js +3 -3
  14. package/dist/bin/exe-cloud.js +2 -2
  15. package/dist/bin/exe-dispatch.js +282 -7
  16. package/dist/bin/exe-doctor.js +119 -7
  17. package/dist/bin/exe-export-behaviors.js +282 -7
  18. package/dist/bin/exe-forget.js +336 -7
  19. package/dist/bin/exe-gateway.js +282 -7
  20. package/dist/bin/exe-heartbeat.js +284 -9
  21. package/dist/bin/exe-kill.js +282 -7
  22. package/dist/bin/exe-launch-agent.js +282 -7
  23. package/dist/bin/exe-link.js +121 -9
  24. package/dist/bin/exe-new-employee.js +50 -21
  25. package/dist/bin/exe-pending-messages.js +282 -7
  26. package/dist/bin/exe-pending-notifications.js +282 -7
  27. package/dist/bin/exe-pending-reviews.js +282 -7
  28. package/dist/bin/exe-rename.js +282 -7
  29. package/dist/bin/exe-review.js +282 -7
  30. package/dist/bin/exe-search.js +306 -8
  31. package/dist/bin/exe-session-cleanup.js +282 -7
  32. package/dist/bin/exe-settings.js +2 -2
  33. package/dist/bin/exe-start-codex.js +326 -21
  34. package/dist/bin/exe-start-opencode.js +304 -10
  35. package/dist/bin/exe-status.js +282 -7
  36. package/dist/bin/exe-team.js +282 -7
  37. package/dist/bin/git-sweep.js +282 -7
  38. package/dist/bin/graph-backfill.js +282 -7
  39. package/dist/bin/graph-export.js +282 -7
  40. package/dist/bin/install.js +58 -33
  41. package/dist/bin/intercom-check.js +282 -7
  42. package/dist/bin/pre-build-guard.js +98 -0
  43. package/dist/bin/scan-tasks.js +282 -7
  44. package/dist/bin/setup.js +122 -10
  45. package/dist/bin/shard-migrate.js +282 -7
  46. package/dist/bin/stack-update.js +79 -11
  47. package/dist/bin/update.js +2 -2
  48. package/dist/gateway/index.js +288 -13
  49. package/dist/hooks/bug-report-worker.js +282 -7
  50. package/dist/hooks/codex-stop-task-finalizer.js +282 -7
  51. package/dist/hooks/commit-complete.js +282 -7
  52. package/dist/hooks/error-recall.js +306 -8
  53. package/dist/hooks/exe-heartbeat-hook.js +2 -2
  54. package/dist/hooks/ingest-worker.js +2 -2
  55. package/dist/hooks/ingest.js +282 -7
  56. package/dist/hooks/instructions-loaded.js +282 -7
  57. package/dist/hooks/notification.js +282 -7
  58. package/dist/hooks/post-compact.js +282 -7
  59. package/dist/hooks/post-tool-combined.js +306 -8
  60. package/dist/hooks/pre-compact.js +282 -7
  61. package/dist/hooks/pre-tool-use.js +282 -7
  62. package/dist/hooks/prompt-submit.js +306 -8
  63. package/dist/hooks/session-end.js +282 -7
  64. package/dist/hooks/session-start.js +308 -10
  65. package/dist/hooks/stop.js +282 -7
  66. package/dist/hooks/subagent-stop.js +282 -7
  67. package/dist/hooks/summary-worker.js +125 -13
  68. package/dist/index.js +288 -13
  69. package/dist/lib/agent-config.js +2 -2
  70. package/dist/lib/cloud-sync.js +121 -9
  71. package/dist/lib/config.js +2 -2
  72. package/dist/lib/consolidation.js +2 -2
  73. package/dist/lib/database.js +115 -3
  74. package/dist/lib/db-daemon-client.js +2 -2
  75. package/dist/lib/db.js +115 -3
  76. package/dist/lib/device-registry.js +115 -3
  77. package/dist/lib/embedder.js +2 -2
  78. package/dist/lib/employee-templates.js +3 -3
  79. package/dist/lib/employees.js +2 -2
  80. package/dist/lib/exe-daemon-client.js +2 -2
  81. package/dist/lib/exe-daemon.js +339 -31
  82. package/dist/lib/hybrid-search.js +306 -8
  83. package/dist/lib/identity.js +2 -2
  84. package/dist/lib/license.js +2 -2
  85. package/dist/lib/messaging.js +2 -2
  86. package/dist/lib/reminders.js +2 -2
  87. package/dist/lib/schedules.js +119 -7
  88. package/dist/lib/skill-learning.js +2 -2
  89. package/dist/lib/store.js +282 -7
  90. package/dist/lib/task-router.js +2 -2
  91. package/dist/lib/tasks.js +2 -2
  92. package/dist/lib/tmux-routing.js +2 -2
  93. package/dist/lib/token-spend.js +2 -2
  94. package/dist/mcp/server.js +339 -31
  95. package/dist/mcp/tools/complete-reminder.js +2 -2
  96. package/dist/mcp/tools/create-reminder.js +2 -2
  97. package/dist/mcp/tools/create-task.js +2 -2
  98. package/dist/mcp/tools/deactivate-behavior.js +2 -2
  99. package/dist/mcp/tools/list-reminders.js +2 -2
  100. package/dist/mcp/tools/list-tasks.js +2 -2
  101. package/dist/mcp/tools/send-message.js +2 -2
  102. package/dist/mcp/tools/update-task.js +2 -2
  103. package/dist/runtime/index.js +282 -7
  104. package/dist/tui/App.js +290 -15
  105. package/package.json +3 -2
  106. 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,
@@ -2904,7 +2904,7 @@ async function ensureSchema() {
2904
2904
  ON session_kills(agent_id);
2905
2905
  `);
2906
2906
  await client.execute(`
2907
- CREATE TABLE IF NOT EXISTS global_procedures (
2907
+ CREATE TABLE IF NOT EXISTS company_procedures (
2908
2908
  id TEXT PRIMARY KEY,
2909
2909
  title TEXT NOT NULL,
2910
2910
  content TEXT NOT NULL,
@@ -2915,6 +2915,73 @@ async function ensureSchema() {
2915
2915
  updated_at TEXT NOT NULL
2916
2916
  )
2917
2917
  `);
2918
+ const legacyProcedureObject = await client.execute({
2919
+ sql: "SELECT type FROM sqlite_master WHERE name = 'global_procedures'",
2920
+ args: []
2921
+ });
2922
+ const legacyProcedureType = legacyProcedureObject.rows[0]?.type == null ? null : String(legacyProcedureObject.rows[0].type);
2923
+ if (legacyProcedureType === "table") {
2924
+ await client.execute(`
2925
+ INSERT OR IGNORE INTO company_procedures
2926
+ (id, title, content, priority, domain, active, created_at, updated_at)
2927
+ SELECT id, title, content, priority, domain, active, created_at, updated_at
2928
+ FROM global_procedures
2929
+ `);
2930
+ await client.executeMultiple(`
2931
+ CREATE TRIGGER IF NOT EXISTS global_procedures_mirror_insert
2932
+ AFTER INSERT ON global_procedures
2933
+ BEGIN
2934
+ INSERT OR IGNORE INTO company_procedures
2935
+ (id, title, content, priority, domain, active, created_at, updated_at)
2936
+ VALUES
2937
+ (NEW.id, NEW.title, NEW.content, NEW.priority, NEW.domain, NEW.active, NEW.created_at, NEW.updated_at);
2938
+ END;
2939
+
2940
+ CREATE TRIGGER IF NOT EXISTS global_procedures_mirror_update
2941
+ AFTER UPDATE ON global_procedures
2942
+ BEGIN
2943
+ UPDATE company_procedures
2944
+ SET title = NEW.title,
2945
+ content = NEW.content,
2946
+ priority = NEW.priority,
2947
+ domain = NEW.domain,
2948
+ active = NEW.active,
2949
+ created_at = NEW.created_at,
2950
+ updated_at = NEW.updated_at
2951
+ WHERE id = OLD.id;
2952
+ END;
2953
+ `);
2954
+ } else {
2955
+ await client.execute(`
2956
+ CREATE VIEW IF NOT EXISTS global_procedures AS
2957
+ SELECT id, title, content, priority, domain, active, created_at, updated_at
2958
+ FROM company_procedures
2959
+ `);
2960
+ await client.executeMultiple(`
2961
+ CREATE TRIGGER IF NOT EXISTS global_procedures_insert
2962
+ INSTEAD OF INSERT ON global_procedures
2963
+ BEGIN
2964
+ INSERT INTO company_procedures
2965
+ (id, title, content, priority, domain, active, created_at, updated_at)
2966
+ VALUES
2967
+ (NEW.id, NEW.title, NEW.content, NEW.priority, NEW.domain, NEW.active, NEW.created_at, NEW.updated_at);
2968
+ END;
2969
+
2970
+ CREATE TRIGGER IF NOT EXISTS global_procedures_update
2971
+ INSTEAD OF UPDATE ON global_procedures
2972
+ BEGIN
2973
+ UPDATE company_procedures
2974
+ SET title = NEW.title,
2975
+ content = NEW.content,
2976
+ priority = NEW.priority,
2977
+ domain = NEW.domain,
2978
+ active = NEW.active,
2979
+ created_at = NEW.created_at,
2980
+ updated_at = NEW.updated_at
2981
+ WHERE id = OLD.id;
2982
+ END;
2983
+ `);
2984
+ }
2918
2985
  await client.executeMultiple(`
2919
2986
  CREATE TABLE IF NOT EXISTS conversations (
2920
2987
  id TEXT PRIMARY KEY,
@@ -3054,6 +3121,51 @@ async function ensureSchema() {
3054
3121
  VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
3055
3122
  END;
3056
3123
  `);
3124
+ await client.executeMultiple(`
3125
+ CREATE TABLE IF NOT EXISTS memory_cards (
3126
+ id TEXT PRIMARY KEY,
3127
+ memory_id TEXT NOT NULL,
3128
+ agent_id TEXT NOT NULL,
3129
+ session_id TEXT NOT NULL,
3130
+ project_name TEXT,
3131
+ timestamp TEXT NOT NULL,
3132
+ card_type TEXT NOT NULL,
3133
+ subject TEXT,
3134
+ predicate TEXT,
3135
+ object TEXT,
3136
+ content TEXT NOT NULL,
3137
+ source_ref TEXT,
3138
+ confidence REAL DEFAULT 0.6,
3139
+ active INTEGER DEFAULT 1,
3140
+ created_at TEXT NOT NULL
3141
+ );
3142
+
3143
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
3144
+ ON memory_cards(agent_id, active, timestamp);
3145
+
3146
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
3147
+ ON memory_cards(memory_id);
3148
+
3149
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
3150
+ USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
3151
+
3152
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
3153
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
3154
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
3155
+ END;
3156
+
3157
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
3158
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
3159
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
3160
+ END;
3161
+
3162
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
3163
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
3164
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
3165
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
3166
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
3167
+ END;
3168
+ `);
3057
3169
  try {
3058
3170
  await client.execute({
3059
3171
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
@@ -4263,7 +4375,7 @@ var init_platform_procedures = __esm({
4263
4375
  title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
4264
4376
  domain: "tool-use",
4265
4377
  priority: "p1",
4266
- content: "create_trigger: set up a scheduled recurring agent job (cron). list_triggers: view active triggers. load_skill: load a slash-command skill dynamically. apply_starter_pack: import a pre-built behavior + identity pack for a role. export_orchestration: export full org state (tasks, behaviors, identities) as portable JSON. import_orchestration: import org state into a new instance. deploy_client: deploy a customer client instance. query_company_brain: unified RAG query across all company knowledge. create_reminder: set a text reminder (shown in boot brief). list_reminders: view pending reminders. complete_reminder: mark a reminder done. global_procedure: manage customer-owned company procedures (Layer 0; actions: store, list, deactivate). Legacy aliases: store_global_procedure, list_global_procedures, deactivate_global_procedure."
4378
+ content: "create_trigger: set up a scheduled recurring agent job (cron). list_triggers: view active triggers. load_skill: load a slash-command skill dynamically. apply_starter_pack: import a pre-built behavior + identity pack for a role. export_orchestration: export full org state (tasks, behaviors, identities) as portable JSON. import_orchestration: import org state into a new instance. deploy_client: deploy a customer client instance. query_company_brain: unified RAG query across all company knowledge. create_reminder: set a text reminder (shown in boot brief). list_reminders: view pending reminders. complete_reminder: mark a reminder done. company_procedure: manage customer-owned company procedures (Layer 0; actions: store, list, deactivate). Legacy aliases: global_procedure, store_global_procedure, list_global_procedures, deactivate_global_procedure."
4267
4379
  }
4268
4380
  ];
4269
4381
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -4284,7 +4396,7 @@ import { randomUUID as randomUUID2 } from "crypto";
4284
4396
  async function loadGlobalProcedures() {
4285
4397
  const client = getClient();
4286
4398
  const result = await client.execute({
4287
- sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
4399
+ sql: "SELECT * FROM company_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
4288
4400
  args: []
4289
4401
  });
4290
4402
  const allRows = result.rows;
@@ -4313,7 +4425,7 @@ async function storeGlobalProcedure(input2) {
4313
4425
  const now = (/* @__PURE__ */ new Date()).toISOString();
4314
4426
  const client = getClient();
4315
4427
  await client.execute({
4316
- sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
4428
+ sql: `INSERT INTO company_procedures (id, title, content, priority, domain, active, created_at, updated_at)
4317
4429
  VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
4318
4430
  args: [id, input2.title, input2.content, input2.priority ?? "p0", input2.domain ?? null, now, now]
4319
4431
  });
@@ -4324,7 +4436,7 @@ async function deactivateGlobalProcedure(id) {
4324
4436
  const now = (/* @__PURE__ */ new Date()).toISOString();
4325
4437
  const client = getClient();
4326
4438
  const result = await client.execute({
4327
- sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
4439
+ sql: "UPDATE company_procedures SET active = 0, updated_at = ? WHERE id = ?",
4328
4440
  args: [now, id]
4329
4441
  });
4330
4442
  await loadGlobalProcedures();
@@ -4343,6 +4455,164 @@ ${p.content}`).join("\n\n");
4343
4455
  }
4344
4456
  });
4345
4457
 
4458
+ // src/lib/memory-cards.ts
4459
+ var memory_cards_exports = {};
4460
+ __export(memory_cards_exports, {
4461
+ extractMemoryCards: () => extractMemoryCards,
4462
+ insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
4463
+ searchMemoryCards: () => searchMemoryCards
4464
+ });
4465
+ import { createHash as createHash2 } from "crypto";
4466
+ function stableId(memoryId, type, content) {
4467
+ return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
4468
+ }
4469
+ function cleanText(text) {
4470
+ return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
4471
+ }
4472
+ function splitSentences(text) {
4473
+ return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
4474
+ }
4475
+ function inferCardType(sentence, toolName) {
4476
+ const lower = sentence.toLowerCase();
4477
+ if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
4478
+ if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
4479
+ if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
4480
+ if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
4481
+ if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
4482
+ return "fact";
4483
+ }
4484
+ function extractSubject(sentence, agentId) {
4485
+ const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
4486
+ return explicit?.[1] ?? agentId;
4487
+ }
4488
+ function predicateFor(type) {
4489
+ switch (type) {
4490
+ case "preference":
4491
+ return "prefers";
4492
+ case "belief_update":
4493
+ return "updated";
4494
+ case "decision":
4495
+ return "decided";
4496
+ case "event":
4497
+ return "happened";
4498
+ case "code":
4499
+ return "implemented";
4500
+ default:
4501
+ return "states";
4502
+ }
4503
+ }
4504
+ function extractMemoryCards(row) {
4505
+ const sentences = splitSentences(row.raw_text);
4506
+ const cards = [];
4507
+ for (const sentence of sentences) {
4508
+ const type = inferCardType(sentence, row.tool_name);
4509
+ const subject = extractSubject(sentence, row.agent_id);
4510
+ const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
4511
+ cards.push({
4512
+ id: stableId(row.id, type, content),
4513
+ memory_id: row.id,
4514
+ agent_id: row.agent_id,
4515
+ session_id: row.session_id,
4516
+ project_name: row.project_name ?? null,
4517
+ timestamp: row.timestamp,
4518
+ card_type: type,
4519
+ subject,
4520
+ predicate: predicateFor(type),
4521
+ object: content,
4522
+ content,
4523
+ source_ref: row.id,
4524
+ confidence: type === "fact" ? 0.55 : 0.65
4525
+ });
4526
+ if (cards.length >= MAX_CARDS_PER_MEMORY) break;
4527
+ }
4528
+ return cards;
4529
+ }
4530
+ async function insertMemoryCardsForBatch(rows) {
4531
+ const cards = rows.flatMap(extractMemoryCards);
4532
+ if (cards.length === 0) return 0;
4533
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4534
+ const client = getClient();
4535
+ const stmts = cards.map((card) => ({
4536
+ sql: `INSERT OR IGNORE INTO memory_cards
4537
+ (id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
4538
+ subject, predicate, object, content, source_ref, confidence, active, created_at)
4539
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
4540
+ args: [
4541
+ card.id,
4542
+ card.memory_id,
4543
+ card.agent_id,
4544
+ card.session_id,
4545
+ card.project_name,
4546
+ card.timestamp,
4547
+ card.card_type,
4548
+ card.subject,
4549
+ card.predicate,
4550
+ card.object,
4551
+ card.content,
4552
+ card.source_ref,
4553
+ card.confidence,
4554
+ now
4555
+ ]
4556
+ }));
4557
+ await client.batch(stmts, "write");
4558
+ return cards.length;
4559
+ }
4560
+ function buildMatchExpr(queryText) {
4561
+ 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);
4562
+ if (terms.length === 0) return null;
4563
+ return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
4564
+ }
4565
+ async function searchMemoryCards(queryText, agentId, options) {
4566
+ const limit = options?.limit ?? 10;
4567
+ const matchExpr = buildMatchExpr(queryText);
4568
+ if (!matchExpr) return [];
4569
+ let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
4570
+ c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
4571
+ FROM memory_cards c
4572
+ JOIN memory_cards_fts fts ON c.rowid = fts.rowid
4573
+ WHERE memory_cards_fts MATCH ?
4574
+ AND c.agent_id = ?
4575
+ AND COALESCE(c.active, 1) = 1`;
4576
+ const args = [matchExpr, agentId];
4577
+ if (options?.projectName) {
4578
+ sql += ` AND c.project_name = ?`;
4579
+ args.push(options.projectName);
4580
+ }
4581
+ if (options?.since) {
4582
+ sql += ` AND c.timestamp >= ?`;
4583
+ args.push(options.since);
4584
+ }
4585
+ sql += ` ORDER BY rank LIMIT ?`;
4586
+ args.push(limit);
4587
+ const result = await getClient().execute({ sql, args });
4588
+ return result.rows.map((row) => ({
4589
+ id: `card:${String(row.id)}`,
4590
+ agent_id: String(row.agent_id),
4591
+ agent_role: "memory_card",
4592
+ session_id: String(row.session_id),
4593
+ timestamp: String(row.timestamp),
4594
+ tool_name: `memory_card:${String(row.card_type)}`,
4595
+ project_name: row.project_name == null ? "" : String(row.project_name),
4596
+ has_error: false,
4597
+ raw_text: `[${String(row.card_type)}] ${String(row.content)}
4598
+ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
4599
+ vector: [],
4600
+ importance: 6,
4601
+ status: "active",
4602
+ confidence: Number(row.confidence ?? 0.6),
4603
+ last_accessed: String(row.timestamp)
4604
+ }));
4605
+ }
4606
+ var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
4607
+ var init_memory_cards = __esm({
4608
+ "src/lib/memory-cards.ts"() {
4609
+ "use strict";
4610
+ init_database();
4611
+ MAX_CARDS_PER_MEMORY = 6;
4612
+ MAX_SENTENCE_CHARS = 360;
4613
+ }
4614
+ });
4615
+
4346
4616
  // src/lib/store.ts
4347
4617
  var store_exports = {};
4348
4618
  __export(store_exports, {
@@ -4681,6 +4951,11 @@ async function flushBatch() {
4681
4951
  const globalClient = getClient();
4682
4952
  const globalStmts = batch.map(buildStmt);
4683
4953
  await globalClient.batch(globalStmts, "write");
4954
+ try {
4955
+ const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
4956
+ await insertMemoryCardsForBatch2(batch);
4957
+ } catch {
4958
+ }
4684
4959
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
4685
4960
  _pendingRecords.splice(0, batch.length);
4686
4961
  try {
@@ -6189,9 +6464,18 @@ async function hybridSearch(queryText, agentId, options) {
6189
6464
  } catch {
6190
6465
  }
6191
6466
  }
6192
- const [ftsResults, vectorResults, grepResults] = await Promise.all([
6467
+ const includeStructuredCards = effectiveIsBroad || effectiveOptions.includeStructuredCards === true;
6468
+ const [ftsResults, vectorResults, cardResults, grepResults] = await Promise.all([
6193
6469
  lightweightSearch(effectiveQuery, agentId, fetchOptions),
6194
6470
  queryVector ? searchMemories(queryVector, agentId, fetchOptions) : Promise.resolve([]),
6471
+ includeStructuredCards ? (async () => {
6472
+ try {
6473
+ const { searchMemoryCards: searchMemoryCards2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
6474
+ return await searchMemoryCards2(effectiveQuery, agentId, fetchOptions);
6475
+ } catch {
6476
+ return [];
6477
+ }
6478
+ })() : Promise.resolve([]),
6195
6479
  grepPromise
6196
6480
  ]);
6197
6481
  const lists = [];
@@ -6204,6 +6488,10 @@ async function hybridSearch(queryText, agentId, options) {
6204
6488
  lists.push(vectorResults);
6205
6489
  weights.push(1);
6206
6490
  }
6491
+ if (cardResults.length > 0) {
6492
+ lists.push(cardResults);
6493
+ weights.push(1.2);
6494
+ }
6207
6495
  if (grepResults.length > 0) {
6208
6496
  lists.push(grepResults);
6209
6497
  weights.push(0.5);
@@ -6272,6 +6560,7 @@ async function hybridSearch(queryText, agentId, options) {
6272
6560
  signals: {
6273
6561
  fts: ftsResults.length,
6274
6562
  vector: vectorResults.length,
6563
+ cards: cardResults.length,
6275
6564
  grep: grepResults.length,
6276
6565
  entityBoost: entityBoostRan,
6277
6566
  reranker: rerankedAndBlended !== null,
@@ -6421,6 +6710,15 @@ async function lightweightSearch(queryText, agentId, options) {
6421
6710
  if (options?.includeSource && results.length > 0) {
6422
6711
  await attachDocumentMetadata(results);
6423
6712
  }
6713
+ if (options?.includeStructuredCards !== true) return results;
6714
+ try {
6715
+ const { searchMemoryCards: searchMemoryCards2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
6716
+ const cardResults = await searchMemoryCards2(queryText, agentId, options);
6717
+ if (cardResults.length > 0) {
6718
+ return rrfMergeMulti([results, cardResults], limit, RRF_K, [1, 1.2]);
6719
+ }
6720
+ } catch {
6721
+ }
6424
6722
  return results;
6425
6723
  }
6426
6724
  async function ftsQuery(client, matchExpr, agentId, options, limit) {
@@ -7629,7 +7927,7 @@ __export(identity_exports, {
7629
7927
  import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "fs";
7630
7928
  import { readdirSync as readdirSync5 } from "fs";
7631
7929
  import path20 from "path";
7632
- import { createHash as createHash2 } from "crypto";
7930
+ import { createHash as createHash3 } from "crypto";
7633
7931
  function ensureDir() {
7634
7932
  if (!existsSync16(IDENTITY_DIR2)) {
7635
7933
  mkdirSync8(IDENTITY_DIR2, { recursive: true });
@@ -7676,7 +7974,7 @@ function parseFrontmatter(raw) {
7676
7974
  };
7677
7975
  }
7678
7976
  function contentHash(content) {
7679
- return createHash2("sha256").update(content).digest("hex").slice(0, 16);
7977
+ return createHash3("sha256").update(content).digest("hex").slice(0, 16);
7680
7978
  }
7681
7979
  function getIdentity(agentId) {
7682
7980
  const filePath = identityPath(agentId);