@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
@@ -116,6 +116,39 @@ test("No hardcoded 'yoshi'/'mari' in runtime task routing", () => {
116
116
  if (router.includes('"mari"') || router.includes("'mari'")) return "Hardcoded 'mari' in task-router.ts";
117
117
  return true;
118
118
  });
119
+ test("Build output \u2014 referenced standalone dist/bin scripts are explicit tsup entries", () => {
120
+ const pkg = JSON.parse(readSrc("package.json"));
121
+ const tsup = readSrc("tsup.config.ts");
122
+ const commandDocs = execSync(
123
+ `grep -Rho "dist/bin/[A-Za-z0-9._-]*.js" src/commands package.json 2>/dev/null || true`,
124
+ { encoding: "utf8", cwd: ROOT }
125
+ ).trim().split("\n").filter(Boolean);
126
+ const refs = /* @__PURE__ */ new Set();
127
+ for (const value of Object.values(pkg.bin ?? {})) {
128
+ const match = value.match(/dist\/bin\/([^\/]+)\.js$/);
129
+ if (match?.[1]) refs.add(match[1]);
130
+ }
131
+ for (const script of Object.values(pkg.scripts ?? {})) {
132
+ for (const match of script.matchAll(/dist\/bin\/([A-Za-z0-9._-]+)\.js/g)) {
133
+ if (match[1]) refs.add(match[1]);
134
+ }
135
+ }
136
+ for (const ref of commandDocs) {
137
+ const match = ref.match(/dist\/bin\/([A-Za-z0-9._-]+)\.js$/);
138
+ if (match?.[1]) refs.add(match[1]);
139
+ }
140
+ const missing = [...refs].filter((name) => !tsup.includes(`"bin/${name}"`));
141
+ if (missing.length > 0) return `Missing tsup bin entries: ${missing.join(", ")}`;
142
+ return true;
143
+ });
144
+ test("Providers \u2014 active code imports lib/providers, not gateway/providers", () => {
145
+ const hits = execSync(
146
+ `grep -R "gateway/providers" -n src --include="*.ts" --include="*.tsx" || true`,
147
+ { encoding: "utf8", cwd: ROOT }
148
+ ).trim().split("\n").filter(Boolean).filter((line) => !line.includes("src/gateway/providers/") && !line.includes("src/bin/customer-readiness.ts"));
149
+ if (hits.length > 0) return `Deprecated provider imports: ${hits.slice(0, 3).join("; ")}`;
150
+ return true;
151
+ });
119
152
  console.log(`
120
153
  \x1B[1m${pass + fail} tests: ${pass} passed, ${fail} failed\x1B[0m
121
154
  `);
@@ -85,8 +85,8 @@ var init_config = __esm({
85
85
  rerankerAutoTrigger: {
86
86
  enabled: true,
87
87
  broadQueryMinCardinality: 5e4,
88
- fetchTopK: 150,
89
- returnTopK: 5
88
+ fetchTopK: 200,
89
+ returnTopK: 20
90
90
  }
91
91
  },
92
92
  graphRagEnabled: true,
@@ -69,8 +69,8 @@ var init_config = __esm({
69
69
  rerankerAutoTrigger: {
70
70
  enabled: true,
71
71
  broadQueryMinCardinality: 5e4,
72
- fetchTopK: 150,
73
- returnTopK: 5
72
+ fetchTopK: 200,
73
+ returnTopK: 20
74
74
  }
75
75
  },
76
76
  graphRagEnabled: true,
@@ -1462,7 +1462,7 @@ var PLATFORM_PROCEDURES = [
1462
1462
  title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
1463
1463
  domain: "tool-use",
1464
1464
  priority: "p1",
1465
- 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."
1465
+ 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."
1466
1466
  }
1467
1467
  ];
1468
1468
  var PLATFORM_PROCEDURE_TITLES = new Set(
@@ -192,8 +192,8 @@ var init_config = __esm({
192
192
  rerankerAutoTrigger: {
193
193
  enabled: true,
194
194
  broadQueryMinCardinality: 5e4,
195
- fetchTopK: 150,
196
- returnTopK: 5
195
+ fetchTopK: 200,
196
+ returnTopK: 20
197
197
  }
198
198
  },
199
199
  graphRagEnabled: true,
@@ -2439,7 +2439,7 @@ async function ensureSchema() {
2439
2439
  ON session_kills(agent_id);
2440
2440
  `);
2441
2441
  await client.execute(`
2442
- CREATE TABLE IF NOT EXISTS global_procedures (
2442
+ CREATE TABLE IF NOT EXISTS company_procedures (
2443
2443
  id TEXT PRIMARY KEY,
2444
2444
  title TEXT NOT NULL,
2445
2445
  content TEXT NOT NULL,
@@ -2450,6 +2450,73 @@ async function ensureSchema() {
2450
2450
  updated_at TEXT NOT NULL
2451
2451
  )
2452
2452
  `);
2453
+ const legacyProcedureObject = await client.execute({
2454
+ sql: "SELECT type FROM sqlite_master WHERE name = 'global_procedures'",
2455
+ args: []
2456
+ });
2457
+ const legacyProcedureType = legacyProcedureObject.rows[0]?.type == null ? null : String(legacyProcedureObject.rows[0].type);
2458
+ if (legacyProcedureType === "table") {
2459
+ await client.execute(`
2460
+ INSERT OR IGNORE INTO company_procedures
2461
+ (id, title, content, priority, domain, active, created_at, updated_at)
2462
+ SELECT id, title, content, priority, domain, active, created_at, updated_at
2463
+ FROM global_procedures
2464
+ `);
2465
+ await client.executeMultiple(`
2466
+ CREATE TRIGGER IF NOT EXISTS global_procedures_mirror_insert
2467
+ AFTER INSERT ON global_procedures
2468
+ BEGIN
2469
+ INSERT OR IGNORE INTO company_procedures
2470
+ (id, title, content, priority, domain, active, created_at, updated_at)
2471
+ VALUES
2472
+ (NEW.id, NEW.title, NEW.content, NEW.priority, NEW.domain, NEW.active, NEW.created_at, NEW.updated_at);
2473
+ END;
2474
+
2475
+ CREATE TRIGGER IF NOT EXISTS global_procedures_mirror_update
2476
+ AFTER UPDATE ON global_procedures
2477
+ BEGIN
2478
+ UPDATE company_procedures
2479
+ SET title = NEW.title,
2480
+ content = NEW.content,
2481
+ priority = NEW.priority,
2482
+ domain = NEW.domain,
2483
+ active = NEW.active,
2484
+ created_at = NEW.created_at,
2485
+ updated_at = NEW.updated_at
2486
+ WHERE id = OLD.id;
2487
+ END;
2488
+ `);
2489
+ } else {
2490
+ await client.execute(`
2491
+ CREATE VIEW IF NOT EXISTS global_procedures AS
2492
+ SELECT id, title, content, priority, domain, active, created_at, updated_at
2493
+ FROM company_procedures
2494
+ `);
2495
+ await client.executeMultiple(`
2496
+ CREATE TRIGGER IF NOT EXISTS global_procedures_insert
2497
+ INSTEAD OF INSERT ON global_procedures
2498
+ BEGIN
2499
+ INSERT INTO company_procedures
2500
+ (id, title, content, priority, domain, active, created_at, updated_at)
2501
+ VALUES
2502
+ (NEW.id, NEW.title, NEW.content, NEW.priority, NEW.domain, NEW.active, NEW.created_at, NEW.updated_at);
2503
+ END;
2504
+
2505
+ CREATE TRIGGER IF NOT EXISTS global_procedures_update
2506
+ INSTEAD OF UPDATE ON global_procedures
2507
+ BEGIN
2508
+ UPDATE company_procedures
2509
+ SET title = NEW.title,
2510
+ content = NEW.content,
2511
+ priority = NEW.priority,
2512
+ domain = NEW.domain,
2513
+ active = NEW.active,
2514
+ created_at = NEW.created_at,
2515
+ updated_at = NEW.updated_at
2516
+ WHERE id = OLD.id;
2517
+ END;
2518
+ `);
2519
+ }
2453
2520
  await client.executeMultiple(`
2454
2521
  CREATE TABLE IF NOT EXISTS conversations (
2455
2522
  id TEXT PRIMARY KEY,
@@ -2589,6 +2656,51 @@ async function ensureSchema() {
2589
2656
  VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
2590
2657
  END;
2591
2658
  `);
2659
+ await client.executeMultiple(`
2660
+ CREATE TABLE IF NOT EXISTS memory_cards (
2661
+ id TEXT PRIMARY KEY,
2662
+ memory_id TEXT NOT NULL,
2663
+ agent_id TEXT NOT NULL,
2664
+ session_id TEXT NOT NULL,
2665
+ project_name TEXT,
2666
+ timestamp TEXT NOT NULL,
2667
+ card_type TEXT NOT NULL,
2668
+ subject TEXT,
2669
+ predicate TEXT,
2670
+ object TEXT,
2671
+ content TEXT NOT NULL,
2672
+ source_ref TEXT,
2673
+ confidence REAL DEFAULT 0.6,
2674
+ active INTEGER DEFAULT 1,
2675
+ created_at TEXT NOT NULL
2676
+ );
2677
+
2678
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
2679
+ ON memory_cards(agent_id, active, timestamp);
2680
+
2681
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
2682
+ ON memory_cards(memory_id);
2683
+
2684
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
2685
+ USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
2686
+
2687
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
2688
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
2689
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
2690
+ END;
2691
+
2692
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
2693
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
2694
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
2695
+ END;
2696
+
2697
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
2698
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
2699
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
2700
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
2701
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
2702
+ END;
2703
+ `);
2592
2704
  try {
2593
2705
  await client.execute({
2594
2706
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
@@ -3326,7 +3438,7 @@ var init_platform_procedures = __esm({
3326
3438
  title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
3327
3439
  domain: "tool-use",
3328
3440
  priority: "p1",
3329
- 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."
3441
+ 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."
3330
3442
  }
3331
3443
  ];
3332
3444
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -3347,7 +3459,7 @@ import { randomUUID as randomUUID3 } from "crypto";
3347
3459
  async function loadGlobalProcedures() {
3348
3460
  const client = getClient();
3349
3461
  const result = await client.execute({
3350
- sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
3462
+ sql: "SELECT * FROM company_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
3351
3463
  args: []
3352
3464
  });
3353
3465
  const allRows = result.rows;
@@ -3376,7 +3488,7 @@ async function storeGlobalProcedure(input) {
3376
3488
  const now = (/* @__PURE__ */ new Date()).toISOString();
3377
3489
  const client = getClient();
3378
3490
  await client.execute({
3379
- sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
3491
+ sql: `INSERT INTO company_procedures (id, title, content, priority, domain, active, created_at, updated_at)
3380
3492
  VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
3381
3493
  args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, now, now]
3382
3494
  });
@@ -3387,7 +3499,7 @@ async function deactivateGlobalProcedure(id) {
3387
3499
  const now = (/* @__PURE__ */ new Date()).toISOString();
3388
3500
  const client = getClient();
3389
3501
  const result = await client.execute({
3390
- sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
3502
+ sql: "UPDATE company_procedures SET active = 0, updated_at = ? WHERE id = ?",
3391
3503
  args: [now, id]
3392
3504
  });
3393
3505
  await loadGlobalProcedures();
@@ -3406,6 +3518,164 @@ ${p.content}`).join("\n\n");
3406
3518
  }
3407
3519
  });
3408
3520
 
3521
+ // src/lib/memory-cards.ts
3522
+ var memory_cards_exports = {};
3523
+ __export(memory_cards_exports, {
3524
+ extractMemoryCards: () => extractMemoryCards,
3525
+ insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
3526
+ searchMemoryCards: () => searchMemoryCards
3527
+ });
3528
+ import { createHash as createHash2 } from "crypto";
3529
+ function stableId(memoryId, type, content) {
3530
+ return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
3531
+ }
3532
+ function cleanText(text) {
3533
+ return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
3534
+ }
3535
+ function splitSentences(text) {
3536
+ return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
3537
+ }
3538
+ function inferCardType(sentence, toolName) {
3539
+ const lower = sentence.toLowerCase();
3540
+ if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
3541
+ if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
3542
+ if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
3543
+ if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
3544
+ if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
3545
+ return "fact";
3546
+ }
3547
+ function extractSubject(sentence, agentId) {
3548
+ const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
3549
+ return explicit?.[1] ?? agentId;
3550
+ }
3551
+ function predicateFor(type) {
3552
+ switch (type) {
3553
+ case "preference":
3554
+ return "prefers";
3555
+ case "belief_update":
3556
+ return "updated";
3557
+ case "decision":
3558
+ return "decided";
3559
+ case "event":
3560
+ return "happened";
3561
+ case "code":
3562
+ return "implemented";
3563
+ default:
3564
+ return "states";
3565
+ }
3566
+ }
3567
+ function extractMemoryCards(row) {
3568
+ const sentences = splitSentences(row.raw_text);
3569
+ const cards = [];
3570
+ for (const sentence of sentences) {
3571
+ const type = inferCardType(sentence, row.tool_name);
3572
+ const subject = extractSubject(sentence, row.agent_id);
3573
+ const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
3574
+ cards.push({
3575
+ id: stableId(row.id, type, content),
3576
+ memory_id: row.id,
3577
+ agent_id: row.agent_id,
3578
+ session_id: row.session_id,
3579
+ project_name: row.project_name ?? null,
3580
+ timestamp: row.timestamp,
3581
+ card_type: type,
3582
+ subject,
3583
+ predicate: predicateFor(type),
3584
+ object: content,
3585
+ content,
3586
+ source_ref: row.id,
3587
+ confidence: type === "fact" ? 0.55 : 0.65
3588
+ });
3589
+ if (cards.length >= MAX_CARDS_PER_MEMORY) break;
3590
+ }
3591
+ return cards;
3592
+ }
3593
+ async function insertMemoryCardsForBatch(rows) {
3594
+ const cards = rows.flatMap(extractMemoryCards);
3595
+ if (cards.length === 0) return 0;
3596
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3597
+ const client = getClient();
3598
+ const stmts = cards.map((card) => ({
3599
+ sql: `INSERT OR IGNORE INTO memory_cards
3600
+ (id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
3601
+ subject, predicate, object, content, source_ref, confidence, active, created_at)
3602
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
3603
+ args: [
3604
+ card.id,
3605
+ card.memory_id,
3606
+ card.agent_id,
3607
+ card.session_id,
3608
+ card.project_name,
3609
+ card.timestamp,
3610
+ card.card_type,
3611
+ card.subject,
3612
+ card.predicate,
3613
+ card.object,
3614
+ card.content,
3615
+ card.source_ref,
3616
+ card.confidence,
3617
+ now
3618
+ ]
3619
+ }));
3620
+ await client.batch(stmts, "write");
3621
+ return cards.length;
3622
+ }
3623
+ function buildMatchExpr(queryText) {
3624
+ 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);
3625
+ if (terms.length === 0) return null;
3626
+ return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
3627
+ }
3628
+ async function searchMemoryCards(queryText, agentId, options) {
3629
+ const limit = options?.limit ?? 10;
3630
+ const matchExpr = buildMatchExpr(queryText);
3631
+ if (!matchExpr) return [];
3632
+ let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
3633
+ c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
3634
+ FROM memory_cards c
3635
+ JOIN memory_cards_fts fts ON c.rowid = fts.rowid
3636
+ WHERE memory_cards_fts MATCH ?
3637
+ AND c.agent_id = ?
3638
+ AND COALESCE(c.active, 1) = 1`;
3639
+ const args = [matchExpr, agentId];
3640
+ if (options?.projectName) {
3641
+ sql += ` AND c.project_name = ?`;
3642
+ args.push(options.projectName);
3643
+ }
3644
+ if (options?.since) {
3645
+ sql += ` AND c.timestamp >= ?`;
3646
+ args.push(options.since);
3647
+ }
3648
+ sql += ` ORDER BY rank LIMIT ?`;
3649
+ args.push(limit);
3650
+ const result = await getClient().execute({ sql, args });
3651
+ return result.rows.map((row) => ({
3652
+ id: `card:${String(row.id)}`,
3653
+ agent_id: String(row.agent_id),
3654
+ agent_role: "memory_card",
3655
+ session_id: String(row.session_id),
3656
+ timestamp: String(row.timestamp),
3657
+ tool_name: `memory_card:${String(row.card_type)}`,
3658
+ project_name: row.project_name == null ? "" : String(row.project_name),
3659
+ has_error: false,
3660
+ raw_text: `[${String(row.card_type)}] ${String(row.content)}
3661
+ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
3662
+ vector: [],
3663
+ importance: 6,
3664
+ status: "active",
3665
+ confidence: Number(row.confidence ?? 0.6),
3666
+ last_accessed: String(row.timestamp)
3667
+ }));
3668
+ }
3669
+ var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
3670
+ var init_memory_cards = __esm({
3671
+ "src/lib/memory-cards.ts"() {
3672
+ "use strict";
3673
+ init_database();
3674
+ MAX_CARDS_PER_MEMORY = 6;
3675
+ MAX_SENTENCE_CHARS = 360;
3676
+ }
3677
+ });
3678
+
3409
3679
  // src/bin/exe-assign.ts
3410
3680
  init_employees();
3411
3681
 
@@ -4342,6 +4612,11 @@ async function flushBatch() {
4342
4612
  const globalClient = getClient();
4343
4613
  const globalStmts = batch.map(buildStmt);
4344
4614
  await globalClient.batch(globalStmts, "write");
4615
+ try {
4616
+ const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
4617
+ await insertMemoryCardsForBatch2(batch);
4618
+ } catch {
4619
+ }
4345
4620
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
4346
4621
  _pendingRecords.splice(0, batch.length);
4347
4622
  try {
@@ -258,8 +258,8 @@ var init_config = __esm({
258
258
  rerankerAutoTrigger: {
259
259
  enabled: true,
260
260
  broadQueryMinCardinality: 5e4,
261
- fetchTopK: 150,
262
- returnTopK: 5
261
+ fetchTopK: 200,
262
+ returnTopK: 20
263
263
  }
264
264
  },
265
265
  graphRagEnabled: true,
@@ -2581,7 +2581,7 @@ async function ensureSchema() {
2581
2581
  ON session_kills(agent_id);
2582
2582
  `);
2583
2583
  await client.execute(`
2584
- CREATE TABLE IF NOT EXISTS global_procedures (
2584
+ CREATE TABLE IF NOT EXISTS company_procedures (
2585
2585
  id TEXT PRIMARY KEY,
2586
2586
  title TEXT NOT NULL,
2587
2587
  content TEXT NOT NULL,
@@ -2592,6 +2592,73 @@ async function ensureSchema() {
2592
2592
  updated_at TEXT NOT NULL
2593
2593
  )
2594
2594
  `);
2595
+ const legacyProcedureObject = await client.execute({
2596
+ sql: "SELECT type FROM sqlite_master WHERE name = 'global_procedures'",
2597
+ args: []
2598
+ });
2599
+ const legacyProcedureType = legacyProcedureObject.rows[0]?.type == null ? null : String(legacyProcedureObject.rows[0].type);
2600
+ if (legacyProcedureType === "table") {
2601
+ await client.execute(`
2602
+ INSERT OR IGNORE INTO company_procedures
2603
+ (id, title, content, priority, domain, active, created_at, updated_at)
2604
+ SELECT id, title, content, priority, domain, active, created_at, updated_at
2605
+ FROM global_procedures
2606
+ `);
2607
+ await client.executeMultiple(`
2608
+ CREATE TRIGGER IF NOT EXISTS global_procedures_mirror_insert
2609
+ AFTER INSERT ON global_procedures
2610
+ BEGIN
2611
+ INSERT OR IGNORE INTO company_procedures
2612
+ (id, title, content, priority, domain, active, created_at, updated_at)
2613
+ VALUES
2614
+ (NEW.id, NEW.title, NEW.content, NEW.priority, NEW.domain, NEW.active, NEW.created_at, NEW.updated_at);
2615
+ END;
2616
+
2617
+ CREATE TRIGGER IF NOT EXISTS global_procedures_mirror_update
2618
+ AFTER UPDATE ON global_procedures
2619
+ BEGIN
2620
+ UPDATE company_procedures
2621
+ SET title = NEW.title,
2622
+ content = NEW.content,
2623
+ priority = NEW.priority,
2624
+ domain = NEW.domain,
2625
+ active = NEW.active,
2626
+ created_at = NEW.created_at,
2627
+ updated_at = NEW.updated_at
2628
+ WHERE id = OLD.id;
2629
+ END;
2630
+ `);
2631
+ } else {
2632
+ await client.execute(`
2633
+ CREATE VIEW IF NOT EXISTS global_procedures AS
2634
+ SELECT id, title, content, priority, domain, active, created_at, updated_at
2635
+ FROM company_procedures
2636
+ `);
2637
+ await client.executeMultiple(`
2638
+ CREATE TRIGGER IF NOT EXISTS global_procedures_insert
2639
+ INSTEAD OF INSERT ON global_procedures
2640
+ BEGIN
2641
+ INSERT INTO company_procedures
2642
+ (id, title, content, priority, domain, active, created_at, updated_at)
2643
+ VALUES
2644
+ (NEW.id, NEW.title, NEW.content, NEW.priority, NEW.domain, NEW.active, NEW.created_at, NEW.updated_at);
2645
+ END;
2646
+
2647
+ CREATE TRIGGER IF NOT EXISTS global_procedures_update
2648
+ INSTEAD OF UPDATE ON global_procedures
2649
+ BEGIN
2650
+ UPDATE company_procedures
2651
+ SET title = NEW.title,
2652
+ content = NEW.content,
2653
+ priority = NEW.priority,
2654
+ domain = NEW.domain,
2655
+ active = NEW.active,
2656
+ created_at = NEW.created_at,
2657
+ updated_at = NEW.updated_at
2658
+ WHERE id = OLD.id;
2659
+ END;
2660
+ `);
2661
+ }
2595
2662
  await client.executeMultiple(`
2596
2663
  CREATE TABLE IF NOT EXISTS conversations (
2597
2664
  id TEXT PRIMARY KEY,
@@ -2731,6 +2798,51 @@ async function ensureSchema() {
2731
2798
  VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
2732
2799
  END;
2733
2800
  `);
2801
+ await client.executeMultiple(`
2802
+ CREATE TABLE IF NOT EXISTS memory_cards (
2803
+ id TEXT PRIMARY KEY,
2804
+ memory_id TEXT NOT NULL,
2805
+ agent_id TEXT NOT NULL,
2806
+ session_id TEXT NOT NULL,
2807
+ project_name TEXT,
2808
+ timestamp TEXT NOT NULL,
2809
+ card_type TEXT NOT NULL,
2810
+ subject TEXT,
2811
+ predicate TEXT,
2812
+ object TEXT,
2813
+ content TEXT NOT NULL,
2814
+ source_ref TEXT,
2815
+ confidence REAL DEFAULT 0.6,
2816
+ active INTEGER DEFAULT 1,
2817
+ created_at TEXT NOT NULL
2818
+ );
2819
+
2820
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
2821
+ ON memory_cards(agent_id, active, timestamp);
2822
+
2823
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
2824
+ ON memory_cards(memory_id);
2825
+
2826
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
2827
+ USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
2828
+
2829
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
2830
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
2831
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
2832
+ END;
2833
+
2834
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
2835
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
2836
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
2837
+ END;
2838
+
2839
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
2840
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
2841
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
2842
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
2843
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
2844
+ END;
2845
+ `);
2734
2846
  try {
2735
2847
  await client.execute({
2736
2848
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
@@ -3053,7 +3165,7 @@ var init_platform_procedures = __esm({
3053
3165
  title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
3054
3166
  domain: "tool-use",
3055
3167
  priority: "p1",
3056
- 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."
3168
+ 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."
3057
3169
  }
3058
3170
  ];
3059
3171
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -3074,7 +3186,7 @@ import { randomUUID as randomUUID2 } from "crypto";
3074
3186
  async function loadGlobalProcedures() {
3075
3187
  const client = getClient();
3076
3188
  const result = await client.execute({
3077
- sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
3189
+ sql: "SELECT * FROM company_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
3078
3190
  args: []
3079
3191
  });
3080
3192
  const allRows = result.rows;
@@ -3103,7 +3215,7 @@ async function storeGlobalProcedure(input) {
3103
3215
  const now = (/* @__PURE__ */ new Date()).toISOString();
3104
3216
  const client = getClient();
3105
3217
  await client.execute({
3106
- sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
3218
+ sql: `INSERT INTO company_procedures (id, title, content, priority, domain, active, created_at, updated_at)
3107
3219
  VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
3108
3220
  args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, now, now]
3109
3221
  });
@@ -3114,7 +3226,7 @@ async function deactivateGlobalProcedure(id) {
3114
3226
  const now = (/* @__PURE__ */ new Date()).toISOString();
3115
3227
  const client = getClient();
3116
3228
  const result = await client.execute({
3117
- sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
3229
+ sql: "UPDATE company_procedures SET active = 0, updated_at = ? WHERE id = ?",
3118
3230
  args: [now, id]
3119
3231
  });
3120
3232
  await loadGlobalProcedures();
@@ -9332,12 +9444,12 @@ async function cloudSync(config) {
9332
9444
  try {
9333
9445
  await cloudPushGlobalProcedures(config);
9334
9446
  } catch (err) {
9335
- logError(`[cloud-sync] Global procedures push: ${err instanceof Error ? err.message : String(err)}`);
9447
+ logError(`[cloud-sync] Company procedures push: ${err instanceof Error ? err.message : String(err)}`);
9336
9448
  }
9337
9449
  try {
9338
9450
  await cloudPullGlobalProcedures(config);
9339
9451
  } catch (err) {
9340
- logError(`[cloud-sync] Global procedures pull: ${err instanceof Error ? err.message : String(err)}`);
9452
+ logError(`[cloud-sync] Company procedures pull: ${err instanceof Error ? err.message : String(err)}`);
9341
9453
  }
9342
9454
  const countRows = async (sql) => {
9343
9455
  try {
@@ -9746,12 +9858,12 @@ async function cloudPullBlob(route, config) {
9746
9858
  }
9747
9859
  async function cloudPushGlobalProcedures(config) {
9748
9860
  const client = getClient();
9749
- const result = await client.execute("SELECT * FROM global_procedures LIMIT 1000");
9861
+ const result = await client.execute("SELECT * FROM company_procedures LIMIT 1000");
9750
9862
  const rows = result.rows;
9751
9863
  const { ok } = await cloudPushBlob(
9752
9864
  "/sync/push-global-procedures",
9753
9865
  rows,
9754
- "last_global_procedures_push_version",
9866
+ "last_company_procedures_push_version",
9755
9867
  config
9756
9868
  );
9757
9869
  return ok;
@@ -9764,7 +9876,7 @@ async function cloudPullGlobalProcedures(config) {
9764
9876
  if (!remoteProcs || remoteProcs.length === 0) return { pulled: 0 };
9765
9877
  const client = getClient();
9766
9878
  const stmts = remoteProcs.map((p) => ({
9767
- sql: `INSERT INTO global_procedures
9879
+ sql: `INSERT INTO company_procedures
9768
9880
  (id, title, content, priority, domain, active, created_at, updated_at)
9769
9881
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
9770
9882
  ON CONFLICT(id) DO UPDATE SET
@@ -9774,7 +9886,7 @@ async function cloudPullGlobalProcedures(config) {
9774
9886
  domain = excluded.domain,
9775
9887
  active = excluded.active,
9776
9888
  updated_at = excluded.updated_at
9777
- WHERE excluded.updated_at > global_procedures.updated_at`,
9889
+ WHERE excluded.updated_at > company_procedures.updated_at`,
9778
9890
  args: [
9779
9891
  sqlSafe(p.id),
9780
9892
  sqlSafe(p.title),