@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
@@ -313,8 +313,8 @@ var init_config = __esm({
313
313
  rerankerAutoTrigger: {
314
314
  enabled: true,
315
315
  broadQueryMinCardinality: 5e4,
316
- fetchTopK: 150,
317
- returnTopK: 5
316
+ fetchTopK: 200,
317
+ returnTopK: 20
318
318
  }
319
319
  },
320
320
  graphRagEnabled: true,
@@ -2603,7 +2603,7 @@ async function ensureSchema() {
2603
2603
  ON session_kills(agent_id);
2604
2604
  `);
2605
2605
  await client.execute(`
2606
- CREATE TABLE IF NOT EXISTS global_procedures (
2606
+ CREATE TABLE IF NOT EXISTS company_procedures (
2607
2607
  id TEXT PRIMARY KEY,
2608
2608
  title TEXT NOT NULL,
2609
2609
  content TEXT NOT NULL,
@@ -2614,6 +2614,73 @@ async function ensureSchema() {
2614
2614
  updated_at TEXT NOT NULL
2615
2615
  )
2616
2616
  `);
2617
+ const legacyProcedureObject = await client.execute({
2618
+ sql: "SELECT type FROM sqlite_master WHERE name = 'global_procedures'",
2619
+ args: []
2620
+ });
2621
+ const legacyProcedureType = legacyProcedureObject.rows[0]?.type == null ? null : String(legacyProcedureObject.rows[0].type);
2622
+ if (legacyProcedureType === "table") {
2623
+ await client.execute(`
2624
+ INSERT OR IGNORE INTO company_procedures
2625
+ (id, title, content, priority, domain, active, created_at, updated_at)
2626
+ SELECT id, title, content, priority, domain, active, created_at, updated_at
2627
+ FROM global_procedures
2628
+ `);
2629
+ await client.executeMultiple(`
2630
+ CREATE TRIGGER IF NOT EXISTS global_procedures_mirror_insert
2631
+ AFTER INSERT ON global_procedures
2632
+ BEGIN
2633
+ INSERT OR IGNORE INTO company_procedures
2634
+ (id, title, content, priority, domain, active, created_at, updated_at)
2635
+ VALUES
2636
+ (NEW.id, NEW.title, NEW.content, NEW.priority, NEW.domain, NEW.active, NEW.created_at, NEW.updated_at);
2637
+ END;
2638
+
2639
+ CREATE TRIGGER IF NOT EXISTS global_procedures_mirror_update
2640
+ AFTER UPDATE ON global_procedures
2641
+ BEGIN
2642
+ UPDATE company_procedures
2643
+ SET title = NEW.title,
2644
+ content = NEW.content,
2645
+ priority = NEW.priority,
2646
+ domain = NEW.domain,
2647
+ active = NEW.active,
2648
+ created_at = NEW.created_at,
2649
+ updated_at = NEW.updated_at
2650
+ WHERE id = OLD.id;
2651
+ END;
2652
+ `);
2653
+ } else {
2654
+ await client.execute(`
2655
+ CREATE VIEW IF NOT EXISTS global_procedures AS
2656
+ SELECT id, title, content, priority, domain, active, created_at, updated_at
2657
+ FROM company_procedures
2658
+ `);
2659
+ await client.executeMultiple(`
2660
+ CREATE TRIGGER IF NOT EXISTS global_procedures_insert
2661
+ INSTEAD OF INSERT ON global_procedures
2662
+ BEGIN
2663
+ INSERT INTO company_procedures
2664
+ (id, title, content, priority, domain, active, created_at, updated_at)
2665
+ VALUES
2666
+ (NEW.id, NEW.title, NEW.content, NEW.priority, NEW.domain, NEW.active, NEW.created_at, NEW.updated_at);
2667
+ END;
2668
+
2669
+ CREATE TRIGGER IF NOT EXISTS global_procedures_update
2670
+ INSTEAD OF UPDATE ON global_procedures
2671
+ BEGIN
2672
+ UPDATE company_procedures
2673
+ SET title = NEW.title,
2674
+ content = NEW.content,
2675
+ priority = NEW.priority,
2676
+ domain = NEW.domain,
2677
+ active = NEW.active,
2678
+ created_at = NEW.created_at,
2679
+ updated_at = NEW.updated_at
2680
+ WHERE id = OLD.id;
2681
+ END;
2682
+ `);
2683
+ }
2617
2684
  await client.executeMultiple(`
2618
2685
  CREATE TABLE IF NOT EXISTS conversations (
2619
2686
  id TEXT PRIMARY KEY,
@@ -2753,6 +2820,51 @@ async function ensureSchema() {
2753
2820
  VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
2754
2821
  END;
2755
2822
  `);
2823
+ await client.executeMultiple(`
2824
+ CREATE TABLE IF NOT EXISTS memory_cards (
2825
+ id TEXT PRIMARY KEY,
2826
+ memory_id TEXT NOT NULL,
2827
+ agent_id TEXT NOT NULL,
2828
+ session_id TEXT NOT NULL,
2829
+ project_name TEXT,
2830
+ timestamp TEXT NOT NULL,
2831
+ card_type TEXT NOT NULL,
2832
+ subject TEXT,
2833
+ predicate TEXT,
2834
+ object TEXT,
2835
+ content TEXT NOT NULL,
2836
+ source_ref TEXT,
2837
+ confidence REAL DEFAULT 0.6,
2838
+ active INTEGER DEFAULT 1,
2839
+ created_at TEXT NOT NULL
2840
+ );
2841
+
2842
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
2843
+ ON memory_cards(agent_id, active, timestamp);
2844
+
2845
+ CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
2846
+ ON memory_cards(memory_id);
2847
+
2848
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
2849
+ USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
2850
+
2851
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
2852
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
2853
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
2854
+ END;
2855
+
2856
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
2857
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
2858
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
2859
+ END;
2860
+
2861
+ CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
2862
+ INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
2863
+ VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
2864
+ INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
2865
+ VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
2866
+ END;
2867
+ `);
2756
2868
  try {
2757
2869
  await client.execute({
2758
2870
  sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
@@ -3962,7 +4074,7 @@ var init_platform_procedures = __esm({
3962
4074
  title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
3963
4075
  domain: "tool-use",
3964
4076
  priority: "p1",
3965
- 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."
4077
+ 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."
3966
4078
  }
3967
4079
  ];
3968
4080
  PLATFORM_PROCEDURE_TITLES = new Set(
@@ -3983,7 +4095,7 @@ import { randomUUID as randomUUID2 } from "crypto";
3983
4095
  async function loadGlobalProcedures() {
3984
4096
  const client = getClient();
3985
4097
  const result = await client.execute({
3986
- sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
4098
+ sql: "SELECT * FROM company_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
3987
4099
  args: []
3988
4100
  });
3989
4101
  const allRows = result.rows;
@@ -4012,7 +4124,7 @@ async function storeGlobalProcedure(input) {
4012
4124
  const now = (/* @__PURE__ */ new Date()).toISOString();
4013
4125
  const client = getClient();
4014
4126
  await client.execute({
4015
- sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
4127
+ sql: `INSERT INTO company_procedures (id, title, content, priority, domain, active, created_at, updated_at)
4016
4128
  VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
4017
4129
  args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, now, now]
4018
4130
  });
@@ -4023,7 +4135,7 @@ async function deactivateGlobalProcedure(id) {
4023
4135
  const now = (/* @__PURE__ */ new Date()).toISOString();
4024
4136
  const client = getClient();
4025
4137
  const result = await client.execute({
4026
- sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
4138
+ sql: "UPDATE company_procedures SET active = 0, updated_at = ? WHERE id = ?",
4027
4139
  args: [now, id]
4028
4140
  });
4029
4141
  await loadGlobalProcedures();
@@ -4042,6 +4154,164 @@ ${p.content}`).join("\n\n");
4042
4154
  }
4043
4155
  });
4044
4156
 
4157
+ // src/lib/memory-cards.ts
4158
+ var memory_cards_exports = {};
4159
+ __export(memory_cards_exports, {
4160
+ extractMemoryCards: () => extractMemoryCards,
4161
+ insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
4162
+ searchMemoryCards: () => searchMemoryCards
4163
+ });
4164
+ import { createHash as createHash2 } from "crypto";
4165
+ function stableId(memoryId, type, content) {
4166
+ return createHash2("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
4167
+ }
4168
+ function cleanText(text) {
4169
+ return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
4170
+ }
4171
+ function splitSentences(text) {
4172
+ return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
4173
+ }
4174
+ function inferCardType(sentence, toolName) {
4175
+ const lower = sentence.toLowerCase();
4176
+ if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
4177
+ if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
4178
+ if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
4179
+ if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
4180
+ if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
4181
+ return "fact";
4182
+ }
4183
+ function extractSubject(sentence, agentId) {
4184
+ const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
4185
+ return explicit?.[1] ?? agentId;
4186
+ }
4187
+ function predicateFor(type) {
4188
+ switch (type) {
4189
+ case "preference":
4190
+ return "prefers";
4191
+ case "belief_update":
4192
+ return "updated";
4193
+ case "decision":
4194
+ return "decided";
4195
+ case "event":
4196
+ return "happened";
4197
+ case "code":
4198
+ return "implemented";
4199
+ default:
4200
+ return "states";
4201
+ }
4202
+ }
4203
+ function extractMemoryCards(row) {
4204
+ const sentences = splitSentences(row.raw_text);
4205
+ const cards = [];
4206
+ for (const sentence of sentences) {
4207
+ const type = inferCardType(sentence, row.tool_name);
4208
+ const subject = extractSubject(sentence, row.agent_id);
4209
+ const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
4210
+ cards.push({
4211
+ id: stableId(row.id, type, content),
4212
+ memory_id: row.id,
4213
+ agent_id: row.agent_id,
4214
+ session_id: row.session_id,
4215
+ project_name: row.project_name ?? null,
4216
+ timestamp: row.timestamp,
4217
+ card_type: type,
4218
+ subject,
4219
+ predicate: predicateFor(type),
4220
+ object: content,
4221
+ content,
4222
+ source_ref: row.id,
4223
+ confidence: type === "fact" ? 0.55 : 0.65
4224
+ });
4225
+ if (cards.length >= MAX_CARDS_PER_MEMORY) break;
4226
+ }
4227
+ return cards;
4228
+ }
4229
+ async function insertMemoryCardsForBatch(rows) {
4230
+ const cards = rows.flatMap(extractMemoryCards);
4231
+ if (cards.length === 0) return 0;
4232
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4233
+ const client = getClient();
4234
+ const stmts = cards.map((card) => ({
4235
+ sql: `INSERT OR IGNORE INTO memory_cards
4236
+ (id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
4237
+ subject, predicate, object, content, source_ref, confidence, active, created_at)
4238
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
4239
+ args: [
4240
+ card.id,
4241
+ card.memory_id,
4242
+ card.agent_id,
4243
+ card.session_id,
4244
+ card.project_name,
4245
+ card.timestamp,
4246
+ card.card_type,
4247
+ card.subject,
4248
+ card.predicate,
4249
+ card.object,
4250
+ card.content,
4251
+ card.source_ref,
4252
+ card.confidence,
4253
+ now
4254
+ ]
4255
+ }));
4256
+ await client.batch(stmts, "write");
4257
+ return cards.length;
4258
+ }
4259
+ function buildMatchExpr(queryText) {
4260
+ 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);
4261
+ if (terms.length === 0) return null;
4262
+ return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
4263
+ }
4264
+ async function searchMemoryCards(queryText, agentId, options) {
4265
+ const limit = options?.limit ?? 10;
4266
+ const matchExpr = buildMatchExpr(queryText);
4267
+ if (!matchExpr) return [];
4268
+ let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
4269
+ c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
4270
+ FROM memory_cards c
4271
+ JOIN memory_cards_fts fts ON c.rowid = fts.rowid
4272
+ WHERE memory_cards_fts MATCH ?
4273
+ AND c.agent_id = ?
4274
+ AND COALESCE(c.active, 1) = 1`;
4275
+ const args = [matchExpr, agentId];
4276
+ if (options?.projectName) {
4277
+ sql += ` AND c.project_name = ?`;
4278
+ args.push(options.projectName);
4279
+ }
4280
+ if (options?.since) {
4281
+ sql += ` AND c.timestamp >= ?`;
4282
+ args.push(options.since);
4283
+ }
4284
+ sql += ` ORDER BY rank LIMIT ?`;
4285
+ args.push(limit);
4286
+ const result = await getClient().execute({ sql, args });
4287
+ return result.rows.map((row) => ({
4288
+ id: `card:${String(row.id)}`,
4289
+ agent_id: String(row.agent_id),
4290
+ agent_role: "memory_card",
4291
+ session_id: String(row.session_id),
4292
+ timestamp: String(row.timestamp),
4293
+ tool_name: `memory_card:${String(row.card_type)}`,
4294
+ project_name: row.project_name == null ? "" : String(row.project_name),
4295
+ has_error: false,
4296
+ raw_text: `[${String(row.card_type)}] ${String(row.content)}
4297
+ Source memory: ${String(row.source_ref ?? row.memory_id)}`,
4298
+ vector: [],
4299
+ importance: 6,
4300
+ status: "active",
4301
+ confidence: Number(row.confidence ?? 0.6),
4302
+ last_accessed: String(row.timestamp)
4303
+ }));
4304
+ }
4305
+ var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
4306
+ var init_memory_cards = __esm({
4307
+ "src/lib/memory-cards.ts"() {
4308
+ "use strict";
4309
+ init_database();
4310
+ MAX_CARDS_PER_MEMORY = 6;
4311
+ MAX_SENTENCE_CHARS = 360;
4312
+ }
4313
+ });
4314
+
4045
4315
  // src/lib/store.ts
4046
4316
  var store_exports = {};
4047
4317
  __export(store_exports, {
@@ -4380,6 +4650,11 @@ async function flushBatch() {
4380
4650
  const globalClient = getClient();
4381
4651
  const globalStmts = batch.map(buildStmt);
4382
4652
  await globalClient.batch(globalStmts, "write");
4653
+ try {
4654
+ const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
4655
+ await insertMemoryCardsForBatch2(batch);
4656
+ } catch {
4657
+ }
4383
4658
  schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
4384
4659
  _pendingRecords.splice(0, batch.length);
4385
4660
  try {
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/bin/pre-build-guard.ts
4
+ import { execSync } from "child_process";
5
+ import { lstatSync } from "fs";
6
+ import path from "path";
7
+ function isSymlinked() {
8
+ try {
9
+ const npmRoot = execSync("npm root -g", { encoding: "utf8" }).trim();
10
+ const exeOsPath = path.join(npmRoot, "exe-os");
11
+ const stat = lstatSync(exeOsPath);
12
+ return stat.isSymbolicLink();
13
+ } catch {
14
+ return false;
15
+ }
16
+ }
17
+ function countMcpProcesses() {
18
+ try {
19
+ const result = execSync("pgrep -f 'node.*mcp/server.js' || true", {
20
+ encoding: "utf8"
21
+ });
22
+ return result.trim().split("\n").filter(Boolean).length;
23
+ } catch {
24
+ return 0;
25
+ }
26
+ }
27
+ function isWorktree() {
28
+ try {
29
+ const gitDir = execSync("git rev-parse --git-dir 2>/dev/null", {
30
+ encoding: "utf8"
31
+ }).trim();
32
+ return gitDir.includes(".git/worktrees/");
33
+ } catch {
34
+ return false;
35
+ }
36
+ }
37
+ function isBlockedAgent() {
38
+ const agentId = process.env.AGENT_ID?.toLowerCase();
39
+ if (!agentId) return null;
40
+ const agentRole = process.env.AGENT_ROLE?.toLowerCase();
41
+ if (agentRole === "coo" || agentRole === "cto") return null;
42
+ return agentId;
43
+ }
44
+ function main() {
45
+ if (isWorktree()) {
46
+ console.error(
47
+ "\n\u{1F6AB} [exe-os] BLOCKED: Cannot run deploy from a git worktree."
48
+ );
49
+ console.error(
50
+ " Deploying from a worktree re-registers all CC hooks pointing at the"
51
+ );
52
+ console.error(
53
+ " worktree dist/. When the worktree is deleted, every hook breaks."
54
+ );
55
+ console.error(
56
+ " Use `npm run build` only. Deploy runs from the main repo root.\n"
57
+ );
58
+ process.exit(1);
59
+ }
60
+ const blockedAgent = isBlockedAgent();
61
+ if (blockedAgent) {
62
+ console.error(
63
+ `
64
+ \u{1F6AB} [exe-os] BLOCKED: Agent "${blockedAgent}" cannot run deploy.`
65
+ );
66
+ console.error(
67
+ " Only the coordinator (COO) and CTO may deploy. Engineers and"
68
+ );
69
+ console.error(
70
+ " specialists use `npm run build` only.\n"
71
+ );
72
+ process.exit(1);
73
+ }
74
+ if (!isSymlinked()) {
75
+ return;
76
+ }
77
+ const mcpCount = countMcpProcesses();
78
+ if (mcpCount === 0) {
79
+ return;
80
+ }
81
+ console.error(
82
+ `
83
+ \u26A0\uFE0F [exe-os] DEV MODE: ${mcpCount} active MCP server process(es) detected.`
84
+ );
85
+ console.error(
86
+ " Rebuilding will overwrite dist/ files they reference, causing disconnections."
87
+ );
88
+ console.error(
89
+ " MCP servers will auto-reconnect on the next tool call, but in-flight"
90
+ );
91
+ console.error(
92
+ " operations may fail with SQLITE_BUSY during the reconnect storm."
93
+ );
94
+ console.error(
95
+ " Consider: wait for idle agents, or restart the MCP server after build.\n"
96
+ );
97
+ }
98
+ main();