@askexenow/exe-os 0.9.34 → 0.9.36

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 (76) hide show
  1. package/dist/bin/backfill-conversations.js +212 -11
  2. package/dist/bin/backfill-responses.js +212 -11
  3. package/dist/bin/backfill-vectors.js +14 -3
  4. package/dist/bin/cleanup-stale-review-tasks.js +224 -12
  5. package/dist/bin/cli.js +265 -23
  6. package/dist/bin/exe-agent.js +1 -1
  7. package/dist/bin/exe-assign.js +217 -12
  8. package/dist/bin/exe-boot.js +25 -4
  9. package/dist/bin/exe-call.js +7 -5
  10. package/dist/bin/exe-dispatch.js +229 -13
  11. package/dist/bin/exe-doctor.js +14 -3
  12. package/dist/bin/exe-export-behaviors.js +301 -14
  13. package/dist/bin/exe-forget.js +245 -21
  14. package/dist/bin/exe-gateway.js +229 -13
  15. package/dist/bin/exe-heartbeat.js +224 -12
  16. package/dist/bin/exe-kill.js +224 -12
  17. package/dist/bin/exe-launch-agent.js +177 -9
  18. package/dist/bin/exe-link.js +8 -0
  19. package/dist/bin/exe-new-employee.js +26 -2
  20. package/dist/bin/exe-pending-messages.js +224 -12
  21. package/dist/bin/exe-pending-notifications.js +224 -12
  22. package/dist/bin/exe-pending-reviews.js +224 -12
  23. package/dist/bin/exe-rename.js +9 -1
  24. package/dist/bin/exe-review.js +224 -12
  25. package/dist/bin/exe-search.js +246 -21
  26. package/dist/bin/exe-session-cleanup.js +229 -13
  27. package/dist/bin/exe-start-codex.js +161 -5
  28. package/dist/bin/exe-start-opencode.js +172 -5
  29. package/dist/bin/exe-status.js +224 -12
  30. package/dist/bin/exe-team.js +224 -12
  31. package/dist/bin/git-sweep.js +229 -13
  32. package/dist/bin/graph-backfill.js +94 -3
  33. package/dist/bin/graph-export.js +224 -12
  34. package/dist/bin/install.js +25 -1
  35. package/dist/bin/intercom-check.js +229 -13
  36. package/dist/bin/scan-tasks.js +229 -13
  37. package/dist/bin/setup.js +15 -5
  38. package/dist/bin/shard-migrate.js +94 -3
  39. package/dist/gateway/index.js +229 -13
  40. package/dist/hooks/bug-report-worker.js +229 -13
  41. package/dist/hooks/codex-stop-task-finalizer.js +224 -12
  42. package/dist/hooks/commit-complete.js +229 -13
  43. package/dist/hooks/error-recall.js +246 -21
  44. package/dist/hooks/ingest.js +224 -12
  45. package/dist/hooks/instructions-loaded.js +224 -12
  46. package/dist/hooks/notification.js +224 -12
  47. package/dist/hooks/post-compact.js +224 -12
  48. package/dist/hooks/post-tool-combined.js +246 -21
  49. package/dist/hooks/pre-compact.js +229 -13
  50. package/dist/hooks/pre-tool-use.js +234 -18
  51. package/dist/hooks/prompt-submit.js +346 -23
  52. package/dist/hooks/session-end.js +229 -13
  53. package/dist/hooks/session-start.js +418 -42
  54. package/dist/hooks/stop.js +224 -12
  55. package/dist/hooks/subagent-stop.js +224 -12
  56. package/dist/hooks/summary-worker.js +15 -2
  57. package/dist/index.js +229 -13
  58. package/dist/lib/cloud-sync.js +8 -0
  59. package/dist/lib/consolidation.js +3 -1
  60. package/dist/lib/database.js +8 -0
  61. package/dist/lib/db.js +8 -0
  62. package/dist/lib/device-registry.js +8 -0
  63. package/dist/lib/employee-templates.js +7 -5
  64. package/dist/lib/exe-daemon.js +1776 -1433
  65. package/dist/lib/hybrid-search.js +246 -21
  66. package/dist/lib/schedules.js +14 -3
  67. package/dist/lib/store.js +217 -12
  68. package/dist/lib/tasks.js +5 -1
  69. package/dist/lib/tmux-routing.js +5 -1
  70. package/dist/mcp/server.js +331 -37
  71. package/dist/mcp/tools/create-task.js +5 -1
  72. package/dist/mcp/tools/update-task.js +5 -1
  73. package/dist/runtime/index.js +229 -13
  74. package/dist/tui/App.js +229 -13
  75. package/package.json +1 -1
  76. package/src/commands/exe/save.md +48 -0
package/dist/bin/setup.js CHANGED
@@ -3504,6 +3504,14 @@ async function ensureSchema() {
3504
3504
  );
3505
3505
  } catch {
3506
3506
  }
3507
+ try {
3508
+ await client.execute(
3509
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
3510
+ ON memories(content_hash, agent_id, project_name, memory_type)
3511
+ WHERE content_hash IS NOT NULL`
3512
+ );
3513
+ } catch {
3514
+ }
3507
3515
  await client.executeMultiple(`
3508
3516
  CREATE TABLE IF NOT EXISTS entities (
3509
3517
  id TEXT PRIMARY KEY,
@@ -5651,7 +5659,7 @@ var init_platform_procedures = __esm({
5651
5659
  title: "Chain of command \u2014 who talks to whom",
5652
5660
  domain: "workflow",
5653
5661
  priority: "p0",
5654
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
5662
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
5655
5663
  },
5656
5664
  {
5657
5665
  title: "Single dispatch path \u2014 create_task only",
@@ -5856,8 +5864,9 @@ function personalizePrompt(prompt, templateName, actualName) {
5856
5864
  return prompt.replace(new RegExp(`\\bYou are ${escaped}\\b`, "g"), `You are ${actualName}`);
5857
5865
  }
5858
5866
  function renderClientCOOTemplate(vars) {
5867
+ const resolved = { ...vars, title: vars.title || "Chief Operating Officer" };
5859
5868
  for (const key of CLIENT_COO_PLACEHOLDERS) {
5860
- const value = vars[key];
5869
+ const value = resolved[key];
5861
5870
  if (typeof value !== "string" || value.length === 0) {
5862
5871
  throw new Error(
5863
5872
  `renderClientCOOTemplate: missing required variable "${key}"`
@@ -5866,7 +5875,7 @@ function renderClientCOOTemplate(vars) {
5866
5875
  }
5867
5876
  let out = CLIENT_COO_TEMPLATE;
5868
5877
  for (const key of CLIENT_COO_PLACEHOLDERS) {
5869
- out = out.split(`{{${key}}}`).join(vars[key]);
5878
+ out = out.split(`{{${key}}}`).join(resolved[key]);
5870
5879
  }
5871
5880
  if (vars.industry_context) {
5872
5881
  out += "\n" + vars.industry_context;
@@ -6343,7 +6352,7 @@ created_by: system
6343
6352
  ---
6344
6353
  ## Identity
6345
6354
 
6346
- You are {{agent_name}}, the Chief Operating Officer at {{company_name}}.
6355
+ You are {{agent_name}}, the {{title}} at {{company_name}}.
6347
6356
 
6348
6357
  You are {{founder_name}}'s most reliable teammate in business \u2014 the knowledgeable older sibling who has been through it all. You have seen projects succeed and fail. You know what matters and what is noise. You do not get anxious about problems; you see them coming, stay calm, and handle them.
6349
6358
 
@@ -6430,7 +6439,8 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
6430
6439
  CLIENT_COO_PLACEHOLDERS = [
6431
6440
  "agent_name",
6432
6441
  "company_name",
6433
- "founder_name"
6442
+ "founder_name",
6443
+ "title"
6434
6444
  ];
6435
6445
  }
6436
6446
  });
@@ -2073,6 +2073,14 @@ async function ensureSchema() {
2073
2073
  );
2074
2074
  } catch {
2075
2075
  }
2076
+ try {
2077
+ await client.execute(
2078
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
2079
+ ON memories(content_hash, agent_id, project_name, memory_type)
2080
+ WHERE content_hash IS NOT NULL`
2081
+ );
2082
+ } catch {
2083
+ }
2076
2084
  await client.executeMultiple(`
2077
2085
  CREATE TABLE IF NOT EXISTS entities (
2078
2086
  id TEXT PRIMARY KEY,
@@ -2742,7 +2750,8 @@ async function ensureShardSchema(client) {
2742
2750
  }
2743
2751
  for (const idx of [
2744
2752
  "CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
2745
- "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
2753
+ "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
2754
+ "CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash ON memories(content_hash, agent_id, project_name, memory_type) WHERE content_hash IS NOT NULL"
2746
2755
  ]) {
2747
2756
  try {
2748
2757
  await client.execute(idx);
@@ -2936,7 +2945,7 @@ var init_platform_procedures = __esm({
2936
2945
  title: "Chain of command \u2014 who talks to whom",
2937
2946
  domain: "workflow",
2938
2947
  priority: "p0",
2939
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
2948
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
2940
2949
  },
2941
2950
  {
2942
2951
  title: "Single dispatch path \u2014 create_task only",
@@ -3152,7 +3161,6 @@ ${p.content}`).join("\n\n");
3152
3161
  // src/lib/store.ts
3153
3162
  init_memory();
3154
3163
  init_database();
3155
- import { createHash } from "crypto";
3156
3164
 
3157
3165
  // src/lib/keychain.ts
3158
3166
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
@@ -3385,6 +3393,88 @@ var StateBus = class {
3385
3393
  };
3386
3394
  var orgBus = new StateBus();
3387
3395
 
3396
+ // src/lib/memory-write-governor.ts
3397
+ import { createHash } from "crypto";
3398
+ var HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
3399
+ "decision",
3400
+ "adr",
3401
+ "behavior",
3402
+ "procedure"
3403
+ ]);
3404
+ async function runPostWriteMemoryHygiene(memoryId) {
3405
+ try {
3406
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
3407
+ const client = getClient2();
3408
+ const current = await client.execute({
3409
+ sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
3410
+ importance, timestamp
3411
+ FROM memories
3412
+ WHERE id = ?
3413
+ LIMIT 1`,
3414
+ args: [memoryId]
3415
+ });
3416
+ const row = current.rows[0];
3417
+ if (!row) return;
3418
+ const memoryType = String(row.memory_type ?? "raw");
3419
+ const contentHash = row.content_hash ? String(row.content_hash) : null;
3420
+ const agentId = String(row.agent_id);
3421
+ const projectName = String(row.project_name);
3422
+ if (contentHash) {
3423
+ await client.execute({
3424
+ sql: `UPDATE memories
3425
+ SET status = 'deleted',
3426
+ outcome = COALESCE(outcome, 'superseded')
3427
+ WHERE id != ?
3428
+ AND content_hash = ?
3429
+ AND agent_id = ?
3430
+ AND project_name = ?
3431
+ AND COALESCE(memory_type, 'raw') = ?
3432
+ AND COALESCE(status, 'active') = 'active'`,
3433
+ args: [memoryId, contentHash, agentId, projectName, memoryType]
3434
+ });
3435
+ }
3436
+ const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
3437
+ if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
3438
+ const old = await client.execute({
3439
+ sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
3440
+ args: [supersedesId]
3441
+ });
3442
+ const oldImportance = Number(old.rows[0]?.importance ?? 0);
3443
+ const newImportance = Number(row.importance ?? 0);
3444
+ await client.batch([
3445
+ {
3446
+ sql: `UPDATE memories
3447
+ SET status = 'archived',
3448
+ outcome = COALESCE(outcome, 'superseded')
3449
+ WHERE id = ?`,
3450
+ args: [supersedesId]
3451
+ },
3452
+ {
3453
+ sql: `UPDATE memories
3454
+ SET importance = MAX(COALESCE(importance, 5), ?),
3455
+ parent_memory_id = COALESCE(parent_memory_id, ?)
3456
+ WHERE id = ?`,
3457
+ args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
3458
+ }
3459
+ ], "write");
3460
+ }
3461
+ } catch (err) {
3462
+ process.stderr.write(
3463
+ `[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
3464
+ `
3465
+ );
3466
+ }
3467
+ }
3468
+ function schedulePostWriteMemoryHygiene(memoryIds) {
3469
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
3470
+ if (memoryIds.length === 0) return;
3471
+ const run = () => {
3472
+ void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
3473
+ };
3474
+ if (typeof setImmediate === "function") setImmediate(run);
3475
+ else setTimeout(run, 0);
3476
+ }
3477
+
3388
3478
  // src/lib/store.ts
3389
3479
  var INIT_MAX_RETRIES = 3;
3390
3480
  var INIT_RETRY_DELAY_MS = 1e3;
@@ -3584,6 +3674,7 @@ async function flushBatch() {
3584
3674
  const globalClient = getClient();
3585
3675
  const globalStmts = batch.map(buildStmt);
3586
3676
  await globalClient.batch(globalStmts, "write");
3677
+ schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
3587
3678
  _pendingRecords.splice(0, batch.length);
3588
3679
  try {
3589
3680
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -2932,6 +2932,14 @@ async function ensureSchema() {
2932
2932
  );
2933
2933
  } catch {
2934
2934
  }
2935
+ try {
2936
+ await client.execute(
2937
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
2938
+ ON memories(content_hash, agent_id, project_name, memory_type)
2939
+ WHERE content_hash IS NOT NULL`
2940
+ );
2941
+ } catch {
2942
+ }
2935
2943
  await client.executeMultiple(`
2936
2944
  CREATE TABLE IF NOT EXISTS entities (
2937
2945
  id TEXT PRIMARY KEY,
@@ -3690,6 +3698,197 @@ var init_keychain = __esm({
3690
3698
  }
3691
3699
  });
3692
3700
 
3701
+ // src/lib/memory-write-governor.ts
3702
+ import { createHash } from "crypto";
3703
+ function normalizeMemoryText(text) {
3704
+ return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
3705
+ }
3706
+ function classifyMemoryType(input) {
3707
+ if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
3708
+ const tool = input.tool_name.toLowerCase();
3709
+ const text = input.raw_text.toLowerCase();
3710
+ if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
3711
+ if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
3712
+ if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
3713
+ if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
3714
+ if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
3715
+ if (tool === "store_memory" || tool === "manual") return "observation";
3716
+ return "raw";
3717
+ }
3718
+ function shouldDropMemory(text) {
3719
+ const normalized = normalizeMemoryText(text);
3720
+ if (normalized.length < 10) return { drop: true, reason: "too_short" };
3721
+ if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
3722
+ return { drop: true, reason: "known_boilerplate_noise" };
3723
+ }
3724
+ return { drop: false };
3725
+ }
3726
+ function shouldSkipEmbedding(input) {
3727
+ const type = classifyMemoryType(input);
3728
+ if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
3729
+ if (type === "raw" && input.raw_text.length > 2e4) return true;
3730
+ if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
3731
+ return false;
3732
+ }
3733
+ function hashMemoryContent(text) {
3734
+ return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
3735
+ }
3736
+ function scopedDedupArgs(input) {
3737
+ return [input.contentHash, input.agentId, input.projectName, input.memoryType];
3738
+ }
3739
+ function governMemoryRecord(record) {
3740
+ const normalized = normalizeMemoryText(record.raw_text);
3741
+ const memoryType = classifyMemoryType({
3742
+ raw_text: normalized,
3743
+ agent_id: record.agent_id,
3744
+ project_name: record.project_name,
3745
+ tool_name: record.tool_name,
3746
+ memory_type: record.memory_type
3747
+ });
3748
+ const drop = shouldDropMemory(normalized);
3749
+ const skipEmbedding = shouldSkipEmbedding({
3750
+ raw_text: normalized,
3751
+ agent_id: record.agent_id,
3752
+ project_name: record.project_name,
3753
+ tool_name: record.tool_name,
3754
+ memory_type: memoryType
3755
+ });
3756
+ return {
3757
+ record: {
3758
+ ...record,
3759
+ raw_text: normalized,
3760
+ memory_type: memoryType,
3761
+ vector: skipEmbedding ? null : record.vector
3762
+ },
3763
+ contentHash: hashMemoryContent(normalized),
3764
+ shouldDrop: drop.drop,
3765
+ dropReason: drop.reason,
3766
+ skipEmbedding,
3767
+ hygiene: {
3768
+ dedup: true,
3769
+ supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
3770
+ }
3771
+ };
3772
+ }
3773
+ async function findScopedDuplicate(input) {
3774
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
3775
+ const client = getClient2();
3776
+ const args = scopedDedupArgs(input);
3777
+ let sql = `SELECT id FROM memories
3778
+ WHERE content_hash = ?
3779
+ AND agent_id = ?
3780
+ AND project_name = ?
3781
+ AND COALESCE(memory_type, 'raw') = ?
3782
+ AND COALESCE(status, 'active') != 'deleted'`;
3783
+ if (input.excludeId) {
3784
+ sql += " AND id != ?";
3785
+ args.push(input.excludeId);
3786
+ }
3787
+ sql += " ORDER BY timestamp DESC LIMIT 1";
3788
+ const result = await client.execute({ sql, args });
3789
+ return result.rows[0]?.id ? String(result.rows[0].id) : null;
3790
+ }
3791
+ async function runPostWriteMemoryHygiene(memoryId) {
3792
+ try {
3793
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
3794
+ const client = getClient2();
3795
+ const current = await client.execute({
3796
+ sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
3797
+ importance, timestamp
3798
+ FROM memories
3799
+ WHERE id = ?
3800
+ LIMIT 1`,
3801
+ args: [memoryId]
3802
+ });
3803
+ const row = current.rows[0];
3804
+ if (!row) return;
3805
+ const memoryType = String(row.memory_type ?? "raw");
3806
+ const contentHash = row.content_hash ? String(row.content_hash) : null;
3807
+ const agentId = String(row.agent_id);
3808
+ const projectName = String(row.project_name);
3809
+ if (contentHash) {
3810
+ await client.execute({
3811
+ sql: `UPDATE memories
3812
+ SET status = 'deleted',
3813
+ outcome = COALESCE(outcome, 'superseded')
3814
+ WHERE id != ?
3815
+ AND content_hash = ?
3816
+ AND agent_id = ?
3817
+ AND project_name = ?
3818
+ AND COALESCE(memory_type, 'raw') = ?
3819
+ AND COALESCE(status, 'active') = 'active'`,
3820
+ args: [memoryId, contentHash, agentId, projectName, memoryType]
3821
+ });
3822
+ }
3823
+ const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
3824
+ if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
3825
+ const old = await client.execute({
3826
+ sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
3827
+ args: [supersedesId]
3828
+ });
3829
+ const oldImportance = Number(old.rows[0]?.importance ?? 0);
3830
+ const newImportance = Number(row.importance ?? 0);
3831
+ await client.batch([
3832
+ {
3833
+ sql: `UPDATE memories
3834
+ SET status = 'archived',
3835
+ outcome = COALESCE(outcome, 'superseded')
3836
+ WHERE id = ?`,
3837
+ args: [supersedesId]
3838
+ },
3839
+ {
3840
+ sql: `UPDATE memories
3841
+ SET importance = MAX(COALESCE(importance, 5), ?),
3842
+ parent_memory_id = COALESCE(parent_memory_id, ?)
3843
+ WHERE id = ?`,
3844
+ args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
3845
+ }
3846
+ ], "write");
3847
+ }
3848
+ } catch (err) {
3849
+ process.stderr.write(
3850
+ `[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
3851
+ `
3852
+ );
3853
+ }
3854
+ }
3855
+ function schedulePostWriteMemoryHygiene(memoryIds) {
3856
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
3857
+ if (memoryIds.length === 0) return;
3858
+ const run = () => {
3859
+ void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
3860
+ };
3861
+ if (typeof setImmediate === "function") setImmediate(run);
3862
+ else setTimeout(run, 0);
3863
+ }
3864
+ var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
3865
+ var init_memory_write_governor = __esm({
3866
+ "src/lib/memory-write-governor.ts"() {
3867
+ "use strict";
3868
+ HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
3869
+ "decision",
3870
+ "adr",
3871
+ "behavior",
3872
+ "procedure"
3873
+ ]);
3874
+ NOISE_DROP_PATTERNS = [
3875
+ /^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
3876
+ /^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
3877
+ /^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
3878
+ /^\s*Intercom is a speedup, not delivery/im,
3879
+ /^\s*Context bar reads as USAGE not remaining/im
3880
+ ];
3881
+ SKIP_EMBED_PATTERNS = [
3882
+ /tmux capture-pane\b/i,
3883
+ /docker ps\b/i,
3884
+ /docker images\b/i,
3885
+ /git status\b/i,
3886
+ /grep .*node_modules/i,
3887
+ /npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
3888
+ ];
3889
+ }
3890
+ });
3891
+
3693
3892
  // src/lib/shard-manager.ts
3694
3893
  var shard_manager_exports = {};
3695
3894
  __export(shard_manager_exports, {
@@ -3854,7 +4053,8 @@ async function ensureShardSchema(client) {
3854
4053
  }
3855
4054
  for (const idx of [
3856
4055
  "CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
3857
- "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
4056
+ "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
4057
+ "CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash ON memories(content_hash, agent_id, project_name, memory_type) WHERE content_hash IS NOT NULL"
3858
4058
  ]) {
3859
4059
  try {
3860
4060
  await client.execute(idx);
@@ -4048,7 +4248,7 @@ var init_platform_procedures = __esm({
4048
4248
  title: "Chain of command \u2014 who talks to whom",
4049
4249
  domain: "workflow",
4050
4250
  priority: "p0",
4051
- content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
4251
+ content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
4052
4252
  },
4053
4253
  {
4054
4254
  title: "Single dispatch path \u2014 create_task only",
@@ -4279,7 +4479,6 @@ __export(store_exports, {
4279
4479
  vectorToBlob: () => vectorToBlob,
4280
4480
  writeMemory: () => writeMemory
4281
4481
  });
4282
- import { createHash } from "crypto";
4283
4482
  function isBusyError2(err) {
4284
4483
  if (err instanceof Error) {
4285
4484
  const msg = err.message.toLowerCase();
@@ -4393,17 +4592,24 @@ async function writeMemory(record) {
4393
4592
  `Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
4394
4593
  );
4395
4594
  }
4396
- const contentHash = createHash("md5").update(record.raw_text).digest("hex");
4397
- if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
4595
+ const governed = governMemoryRecord(record);
4596
+ if (governed.shouldDrop) return;
4597
+ record = governed.record;
4598
+ const contentHash = governed.contentHash;
4599
+ const memoryType = record.memory_type ?? "raw";
4600
+ if (_pendingRecords.some(
4601
+ (r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
4602
+ )) {
4398
4603
  return;
4399
4604
  }
4400
4605
  try {
4401
- const client = getClient();
4402
- const existing = await client.execute({
4403
- sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
4404
- args: [contentHash, record.agent_id]
4606
+ const existing = await findScopedDuplicate({
4607
+ contentHash,
4608
+ agentId: record.agent_id,
4609
+ projectName: record.project_name,
4610
+ memoryType
4405
4611
  });
4406
- if (existing.rows.length > 0) return;
4612
+ if (existing) return;
4407
4613
  } catch {
4408
4614
  }
4409
4615
  const dbRow = {
@@ -4434,7 +4640,7 @@ async function writeMemory(record) {
4434
4640
  tier: record.tier ?? classifyTier(record),
4435
4641
  supersedes_id: record.supersedes_id ?? null,
4436
4642
  draft: record.draft ? 1 : 0,
4437
- memory_type: record.memory_type ?? "raw",
4643
+ memory_type: memoryType,
4438
4644
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
4439
4645
  content_hash: contentHash,
4440
4646
  intent: record.intent ?? null,
@@ -4593,6 +4799,7 @@ async function flushBatch() {
4593
4799
  const globalClient = getClient();
4594
4800
  const globalStmts = batch.map(buildStmt);
4595
4801
  await globalClient.batch(globalStmts, "write");
4802
+ schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
4596
4803
  _pendingRecords.splice(0, batch.length);
4597
4804
  try {
4598
4805
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -4713,7 +4920,11 @@ async function searchMemories(queryVector, agentId, options) {
4713
4920
  sql += ` AND timestamp >= ?`;
4714
4921
  args.push(options.since);
4715
4922
  }
4716
- if (options?.memoryType) {
4923
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
4924
+ const uniqueTypes = [...new Set(options.memoryTypes)];
4925
+ sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
4926
+ args.push(...uniqueTypes);
4927
+ } else if (options?.memoryType) {
4717
4928
  sql += ` AND memory_type = ?`;
4718
4929
  args.push(options.memoryType);
4719
4930
  }
@@ -4851,6 +5062,7 @@ var init_store = __esm({
4851
5062
  init_keychain();
4852
5063
  init_config();
4853
5064
  init_state_bus();
5065
+ init_memory_write_governor();
4854
5066
  INIT_MAX_RETRIES = 3;
4855
5067
  INIT_RETRY_DELAY_MS = 1e3;
4856
5068
  _pendingRecords = [];
@@ -9293,7 +9505,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
9293
9505
  }
9294
9506
  if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
9295
9507
  if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
9296
- envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
9508
+ let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
9509
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
9510
+ ccModel += "[1m]";
9511
+ }
9512
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
9297
9513
  }
9298
9514
  }
9299
9515
  let spawnCommand;