@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
@@ -2720,6 +2720,14 @@ async function ensureSchema() {
2720
2720
  );
2721
2721
  } catch {
2722
2722
  }
2723
+ try {
2724
+ await client.execute(
2725
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
2726
+ ON memories(content_hash, agent_id, project_name, memory_type)
2727
+ WHERE content_hash IS NOT NULL`
2728
+ );
2729
+ } catch {
2730
+ }
2723
2731
  await client.executeMultiple(`
2724
2732
  CREATE TABLE IF NOT EXISTS entities (
2725
2733
  id TEXT PRIMARY KEY,
@@ -3580,6 +3588,197 @@ var init_state_bus = __esm({
3580
3588
  }
3581
3589
  });
3582
3590
 
3591
+ // src/lib/memory-write-governor.ts
3592
+ import { createHash } from "crypto";
3593
+ function normalizeMemoryText(text) {
3594
+ return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
3595
+ }
3596
+ function classifyMemoryType(input) {
3597
+ if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
3598
+ const tool = input.tool_name.toLowerCase();
3599
+ const text = input.raw_text.toLowerCase();
3600
+ if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
3601
+ if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
3602
+ if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
3603
+ if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
3604
+ if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
3605
+ if (tool === "store_memory" || tool === "manual") return "observation";
3606
+ return "raw";
3607
+ }
3608
+ function shouldDropMemory(text) {
3609
+ const normalized = normalizeMemoryText(text);
3610
+ if (normalized.length < 10) return { drop: true, reason: "too_short" };
3611
+ if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
3612
+ return { drop: true, reason: "known_boilerplate_noise" };
3613
+ }
3614
+ return { drop: false };
3615
+ }
3616
+ function shouldSkipEmbedding(input) {
3617
+ const type = classifyMemoryType(input);
3618
+ if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
3619
+ if (type === "raw" && input.raw_text.length > 2e4) return true;
3620
+ if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
3621
+ return false;
3622
+ }
3623
+ function hashMemoryContent(text) {
3624
+ return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
3625
+ }
3626
+ function scopedDedupArgs(input) {
3627
+ return [input.contentHash, input.agentId, input.projectName, input.memoryType];
3628
+ }
3629
+ function governMemoryRecord(record) {
3630
+ const normalized = normalizeMemoryText(record.raw_text);
3631
+ const memoryType = classifyMemoryType({
3632
+ raw_text: normalized,
3633
+ agent_id: record.agent_id,
3634
+ project_name: record.project_name,
3635
+ tool_name: record.tool_name,
3636
+ memory_type: record.memory_type
3637
+ });
3638
+ const drop = shouldDropMemory(normalized);
3639
+ const skipEmbedding = shouldSkipEmbedding({
3640
+ raw_text: normalized,
3641
+ agent_id: record.agent_id,
3642
+ project_name: record.project_name,
3643
+ tool_name: record.tool_name,
3644
+ memory_type: memoryType
3645
+ });
3646
+ return {
3647
+ record: {
3648
+ ...record,
3649
+ raw_text: normalized,
3650
+ memory_type: memoryType,
3651
+ vector: skipEmbedding ? null : record.vector
3652
+ },
3653
+ contentHash: hashMemoryContent(normalized),
3654
+ shouldDrop: drop.drop,
3655
+ dropReason: drop.reason,
3656
+ skipEmbedding,
3657
+ hygiene: {
3658
+ dedup: true,
3659
+ supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
3660
+ }
3661
+ };
3662
+ }
3663
+ async function findScopedDuplicate(input) {
3664
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
3665
+ const client = getClient2();
3666
+ const args = scopedDedupArgs(input);
3667
+ let sql = `SELECT id FROM memories
3668
+ WHERE content_hash = ?
3669
+ AND agent_id = ?
3670
+ AND project_name = ?
3671
+ AND COALESCE(memory_type, 'raw') = ?
3672
+ AND COALESCE(status, 'active') != 'deleted'`;
3673
+ if (input.excludeId) {
3674
+ sql += " AND id != ?";
3675
+ args.push(input.excludeId);
3676
+ }
3677
+ sql += " ORDER BY timestamp DESC LIMIT 1";
3678
+ const result = await client.execute({ sql, args });
3679
+ return result.rows[0]?.id ? String(result.rows[0].id) : null;
3680
+ }
3681
+ async function runPostWriteMemoryHygiene(memoryId) {
3682
+ try {
3683
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
3684
+ const client = getClient2();
3685
+ const current = await client.execute({
3686
+ sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
3687
+ importance, timestamp
3688
+ FROM memories
3689
+ WHERE id = ?
3690
+ LIMIT 1`,
3691
+ args: [memoryId]
3692
+ });
3693
+ const row = current.rows[0];
3694
+ if (!row) return;
3695
+ const memoryType = String(row.memory_type ?? "raw");
3696
+ const contentHash2 = row.content_hash ? String(row.content_hash) : null;
3697
+ const agentId = String(row.agent_id);
3698
+ const projectName = String(row.project_name);
3699
+ if (contentHash2) {
3700
+ await client.execute({
3701
+ sql: `UPDATE memories
3702
+ SET status = 'deleted',
3703
+ outcome = COALESCE(outcome, 'superseded')
3704
+ WHERE id != ?
3705
+ AND content_hash = ?
3706
+ AND agent_id = ?
3707
+ AND project_name = ?
3708
+ AND COALESCE(memory_type, 'raw') = ?
3709
+ AND COALESCE(status, 'active') = 'active'`,
3710
+ args: [memoryId, contentHash2, agentId, projectName, memoryType]
3711
+ });
3712
+ }
3713
+ const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
3714
+ if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
3715
+ const old = await client.execute({
3716
+ sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
3717
+ args: [supersedesId]
3718
+ });
3719
+ const oldImportance = Number(old.rows[0]?.importance ?? 0);
3720
+ const newImportance = Number(row.importance ?? 0);
3721
+ await client.batch([
3722
+ {
3723
+ sql: `UPDATE memories
3724
+ SET status = 'archived',
3725
+ outcome = COALESCE(outcome, 'superseded')
3726
+ WHERE id = ?`,
3727
+ args: [supersedesId]
3728
+ },
3729
+ {
3730
+ sql: `UPDATE memories
3731
+ SET importance = MAX(COALESCE(importance, 5), ?),
3732
+ parent_memory_id = COALESCE(parent_memory_id, ?)
3733
+ WHERE id = ?`,
3734
+ args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
3735
+ }
3736
+ ], "write");
3737
+ }
3738
+ } catch (err) {
3739
+ process.stderr.write(
3740
+ `[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
3741
+ `
3742
+ );
3743
+ }
3744
+ }
3745
+ function schedulePostWriteMemoryHygiene(memoryIds) {
3746
+ if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
3747
+ if (memoryIds.length === 0) return;
3748
+ const run = () => {
3749
+ void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
3750
+ };
3751
+ if (typeof setImmediate === "function") setImmediate(run);
3752
+ else setTimeout(run, 0);
3753
+ }
3754
+ var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
3755
+ var init_memory_write_governor = __esm({
3756
+ "src/lib/memory-write-governor.ts"() {
3757
+ "use strict";
3758
+ HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
3759
+ "decision",
3760
+ "adr",
3761
+ "behavior",
3762
+ "procedure"
3763
+ ]);
3764
+ NOISE_DROP_PATTERNS = [
3765
+ /^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
3766
+ /^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
3767
+ /^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
3768
+ /^\s*Intercom is a speedup, not delivery/im,
3769
+ /^\s*Context bar reads as USAGE not remaining/im
3770
+ ];
3771
+ SKIP_EMBED_PATTERNS = [
3772
+ /tmux capture-pane\b/i,
3773
+ /docker ps\b/i,
3774
+ /docker images\b/i,
3775
+ /git status\b/i,
3776
+ /grep .*node_modules/i,
3777
+ /npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
3778
+ ];
3779
+ }
3780
+ });
3781
+
3583
3782
  // src/lib/shard-manager.ts
3584
3783
  var shard_manager_exports = {};
3585
3784
  __export(shard_manager_exports, {
@@ -3744,7 +3943,8 @@ async function ensureShardSchema(client) {
3744
3943
  }
3745
3944
  for (const idx of [
3746
3945
  "CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
3747
- "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
3946
+ "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
3947
+ "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"
3748
3948
  ]) {
3749
3949
  try {
3750
3950
  await client.execute(idx);
@@ -3938,7 +4138,7 @@ var init_platform_procedures = __esm({
3938
4138
  title: "Chain of command \u2014 who talks to whom",
3939
4139
  domain: "workflow",
3940
4140
  priority: "p0",
3941
- 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."
4141
+ 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."
3942
4142
  },
3943
4143
  {
3944
4144
  title: "Single dispatch path \u2014 create_task only",
@@ -4169,7 +4369,6 @@ __export(store_exports, {
4169
4369
  vectorToBlob: () => vectorToBlob,
4170
4370
  writeMemory: () => writeMemory
4171
4371
  });
4172
- import { createHash } from "crypto";
4173
4372
  function isBusyError2(err) {
4174
4373
  if (err instanceof Error) {
4175
4374
  const msg = err.message.toLowerCase();
@@ -4283,17 +4482,24 @@ async function writeMemory(record) {
4283
4482
  `Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
4284
4483
  );
4285
4484
  }
4286
- const contentHash2 = createHash("md5").update(record.raw_text).digest("hex");
4287
- if (_pendingRecords.some((r) => r.content_hash === contentHash2 && r.agent_id === record.agent_id)) {
4485
+ const governed = governMemoryRecord(record);
4486
+ if (governed.shouldDrop) return;
4487
+ record = governed.record;
4488
+ const contentHash2 = governed.contentHash;
4489
+ const memoryType = record.memory_type ?? "raw";
4490
+ if (_pendingRecords.some(
4491
+ (r) => r.content_hash === contentHash2 && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
4492
+ )) {
4288
4493
  return;
4289
4494
  }
4290
4495
  try {
4291
- const client = getClient();
4292
- const existing = await client.execute({
4293
- sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
4294
- args: [contentHash2, record.agent_id]
4496
+ const existing = await findScopedDuplicate({
4497
+ contentHash: contentHash2,
4498
+ agentId: record.agent_id,
4499
+ projectName: record.project_name,
4500
+ memoryType
4295
4501
  });
4296
- if (existing.rows.length > 0) return;
4502
+ if (existing) return;
4297
4503
  } catch {
4298
4504
  }
4299
4505
  const dbRow = {
@@ -4324,7 +4530,7 @@ async function writeMemory(record) {
4324
4530
  tier: record.tier ?? classifyTier(record),
4325
4531
  supersedes_id: record.supersedes_id ?? null,
4326
4532
  draft: record.draft ? 1 : 0,
4327
- memory_type: record.memory_type ?? "raw",
4533
+ memory_type: memoryType,
4328
4534
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
4329
4535
  content_hash: contentHash2,
4330
4536
  intent: record.intent ?? null,
@@ -4483,6 +4689,7 @@ async function flushBatch() {
4483
4689
  const globalClient = getClient();
4484
4690
  const globalStmts = batch.map(buildStmt);
4485
4691
  await globalClient.batch(globalStmts, "write");
4692
+ schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
4486
4693
  _pendingRecords.splice(0, batch.length);
4487
4694
  try {
4488
4695
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -4603,7 +4810,11 @@ async function searchMemories(queryVector, agentId, options) {
4603
4810
  sql += ` AND timestamp >= ?`;
4604
4811
  args.push(options.since);
4605
4812
  }
4606
- if (options?.memoryType) {
4813
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
4814
+ const uniqueTypes = [...new Set(options.memoryTypes)];
4815
+ sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
4816
+ args.push(...uniqueTypes);
4817
+ } else if (options?.memoryType) {
4607
4818
  sql += ` AND memory_type = ?`;
4608
4819
  args.push(options.memoryType);
4609
4820
  }
@@ -4741,6 +4952,7 @@ var init_store = __esm({
4741
4952
  init_keychain();
4742
4953
  init_config();
4743
4954
  init_state_bus();
4955
+ init_memory_write_governor();
4744
4956
  INIT_MAX_RETRIES = 3;
4745
4957
  INIT_RETRY_DELAY_MS = 1e3;
4746
4958
  _pendingRecords = [];
@@ -5832,6 +6044,17 @@ __export(hybrid_search_exports, {
5832
6044
  rrfMerge: () => rrfMerge,
5833
6045
  rrfMergeMulti: () => rrfMergeMulti
5834
6046
  });
6047
+ function appendMemoryTypeFilter(sql, args, column, options) {
6048
+ if (options?.memoryTypes && options.memoryTypes.length > 0) {
6049
+ const uniqueTypes = [...new Set(options.memoryTypes)];
6050
+ sql += ` AND ${column} IN (${uniqueTypes.map(() => "?").join(",")})`;
6051
+ args.push(...uniqueTypes);
6052
+ } else if (options?.memoryType) {
6053
+ sql += ` AND ${column} = ?`;
6054
+ args.push(options.memoryType);
6055
+ }
6056
+ return sql;
6057
+ }
5835
6058
  async function hybridSearch(queryText, agentId, options) {
5836
6059
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
5837
6060
  const config2 = await loadConfig2();
@@ -6060,6 +6283,7 @@ async function estimateCardinality(agentId, options) {
6060
6283
  sql += ` AND timestamp >= ?`;
6061
6284
  args.push(options.since);
6062
6285
  }
6286
+ sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
6063
6287
  try {
6064
6288
  const result = await client.execute({ sql, args });
6065
6289
  return Number(result.rows[0]?.cnt) || 0;
@@ -6181,10 +6405,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
6181
6405
  sql += ` AND m.timestamp >= ?`;
6182
6406
  args.push(options.since);
6183
6407
  }
6184
- if (options?.memoryType) {
6185
- sql += ` AND m.memory_type = ?`;
6186
- args.push(options.memoryType);
6187
- }
6408
+ sql = appendMemoryTypeFilter(sql, args, "m.memory_type", options);
6188
6409
  sql += ` ORDER BY rank LIMIT ?`;
6189
6410
  args.push(limit);
6190
6411
  const result = await client.execute({ sql, args });
@@ -6241,9 +6462,16 @@ async function recentRecords(agentId, options, limit, textFilter) {
6241
6462
  AND timestamp >= ? AND timestamp <= ?
6242
6463
  AND COALESCE(status, 'active') = 'active'
6243
6464
  AND ${options?.includeRaw === false ? "COALESCE(memory_type, 'raw') != 'raw'" : "1 = 1"}
6465
+ ${options?.memoryTypes?.length ? `AND memory_type IN (${options.memoryTypes.map(() => "?").join(",")})` : options?.memoryType ? "AND memory_type = ?" : ""}
6244
6466
  AND COALESCE(confidence, 0.7) >= 0.3
6245
6467
  ORDER BY timestamp DESC LIMIT ?`,
6246
- args: [agentId, windowStart, killedAt, boundarySlots]
6468
+ args: [
6469
+ agentId,
6470
+ windowStart,
6471
+ killedAt,
6472
+ ...options?.memoryTypes?.length ? [...new Set(options.memoryTypes)] : options?.memoryType ? [options.memoryType] : [],
6473
+ boundarySlots
6474
+ ]
6247
6475
  });
6248
6476
  for (const row of boundaryResult.rows) {
6249
6477
  sessionBoundaryMemories.push(rowToMemoryRecord(row));
@@ -6289,10 +6517,7 @@ async function recentRecords(agentId, options, limit, textFilter) {
6289
6517
  sql += ` AND timestamp >= ?`;
6290
6518
  args.push(options.since);
6291
6519
  }
6292
- if (options?.memoryType) {
6293
- sql += ` AND memory_type = ?`;
6294
- args.push(options.memoryType);
6295
- }
6520
+ sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
6296
6521
  if (textFilter) {
6297
6522
  sql += ` AND raw_text LIKE '%' || ? || '%'`;
6298
6523
  args.push(textFilter);
@@ -8973,7 +9198,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
8973
9198
  }
8974
9199
  if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
8975
9200
  if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
8976
- envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
9201
+ let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
9202
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
9203
+ ccModel += "[1m]";
9204
+ }
9205
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
8977
9206
  }
8978
9207
  }
8979
9208
  let spawnCommand;
@@ -12474,6 +12703,63 @@ init_hybrid_search();
12474
12703
  init_store();
12475
12704
  init_active_agent();
12476
12705
  import { z } from "zod";
12706
+
12707
+ // src/lib/memory-retrieval-modes.ts
12708
+ var RETRIEVAL_MODES = [
12709
+ "all",
12710
+ "decisions_only",
12711
+ "behaviors_only",
12712
+ "procedures_only",
12713
+ "operational",
12714
+ "no_raw",
12715
+ "recent_high_value"
12716
+ ];
12717
+ var RETRIEVAL_MODE_DESCRIPTIONS = {
12718
+ all: "All visible memory types.",
12719
+ decisions_only: "Only decisions and ADRs.",
12720
+ behaviors_only: "Only durable behavior/correction memories.",
12721
+ procedures_only: "Only procedures/runbooks.",
12722
+ operational: "Raw operational/debug/tool output.",
12723
+ no_raw: "All non-raw memory types.",
12724
+ recent_high_value: "High-value durable memory types, intended for recency recovery."
12725
+ };
12726
+ function applyRetrievalMode(base, mode) {
12727
+ if (!mode || mode === "all") return base;
12728
+ const next = { ...base };
12729
+ switch (mode) {
12730
+ case "decisions_only":
12731
+ next.memoryTypes = ["decision", "adr"];
12732
+ next.includeRaw = false;
12733
+ break;
12734
+ case "behaviors_only":
12735
+ next.memoryTypes = ["behavior"];
12736
+ next.includeRaw = false;
12737
+ break;
12738
+ case "procedures_only":
12739
+ next.memoryTypes = ["procedure"];
12740
+ next.includeRaw = false;
12741
+ break;
12742
+ case "operational":
12743
+ next.memoryTypes = ["raw", "observation"];
12744
+ next.includeRaw = true;
12745
+ break;
12746
+ case "no_raw":
12747
+ next.includeRaw = false;
12748
+ break;
12749
+ case "recent_high_value":
12750
+ next.memoryTypes = ["decision", "adr", "behavior", "procedure"];
12751
+ next.includeRaw = false;
12752
+ break;
12753
+ default:
12754
+ return next;
12755
+ }
12756
+ return next;
12757
+ }
12758
+ function formatRetrievalModes() {
12759
+ return RETRIEVAL_MODES.map((mode) => `${mode}: ${RETRIEVAL_MODE_DESCRIPTIONS[mode]}`).join("; ");
12760
+ }
12761
+
12762
+ // src/mcp/tools/recall-my-memory.ts
12477
12763
  function formatSourceLine(record) {
12478
12764
  const doc2 = record.document_metadata;
12479
12765
  if (!doc2) return "";
@@ -12509,7 +12795,8 @@ function registerRecallMyMemory(server2) {
12509
12795
  ),
12510
12796
  include_source: z.boolean().optional().default(false).describe(
12511
12797
  "When true, attach parent document metadata (filename, mime, source_type) to each result. Default false."
12512
- )
12798
+ ),
12799
+ retrieval_mode: z.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. ${formatRetrievalModes()}`)
12513
12800
  }
12514
12801
  },
12515
12802
  async ({
@@ -12523,7 +12810,8 @@ function registerRecallMyMemory(server2) {
12523
12810
  include_archived,
12524
12811
  workspace_id,
12525
12812
  user_id,
12526
- include_source
12813
+ include_source,
12814
+ retrieval_mode
12527
12815
  }) => {
12528
12816
  try {
12529
12817
  if (!recent && !query) {
@@ -12533,7 +12821,7 @@ function registerRecallMyMemory(server2) {
12533
12821
  };
12534
12822
  }
12535
12823
  const { agentId } = getActiveAgent();
12536
- const searchOptions = {
12824
+ const searchOptions = applyRetrievalMode({
12537
12825
  projectName: project_name,
12538
12826
  hasError: has_error,
12539
12827
  toolName: tool_name,
@@ -12544,7 +12832,7 @@ function registerRecallMyMemory(server2) {
12544
12832
  includeSource: include_source,
12545
12833
  includeDrafts: true,
12546
12834
  ...user_id !== void 0 ? { userId: user_id } : {}
12547
- };
12835
+ }, retrieval_mode);
12548
12836
  let results;
12549
12837
  if (recent) {
12550
12838
  results = await recentRecords(agentId, searchOptions, limit, query);
@@ -12632,10 +12920,11 @@ function registerAskTeamMemory(server2) {
12632
12920
  ),
12633
12921
  include_raw: z2.boolean().optional().default(false).describe(
12634
12922
  "Include raw technical memories when ACL allows it (default: non-raw memories only for cross-agent reads)"
12635
- )
12923
+ ),
12924
+ retrieval_mode: z2.enum(RETRIEVAL_MODES).optional().default("all").describe(`Typed retrieval mode. Raw visibility is still ACL-gated. ${formatRetrievalModes()}`)
12636
12925
  }
12637
12926
  },
12638
- async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw }) => {
12927
+ async ({ team_member, query, project_name, limit, since, include_archived, include_raw: _include_raw, retrieval_mode }) => {
12639
12928
  try {
12640
12929
  const { agentId: queryingAgentId, agentRole: queryingAgentRole } = getActiveAgent();
12641
12930
  const employees = loadEmployeesSync();
@@ -12644,16 +12933,18 @@ function registerAskTeamMemory(server2) {
12644
12933
  const targetRole = targetEmployee?.role ?? "";
12645
12934
  const hasRawAccess = canSeeRaw(queryingRole, targetRole);
12646
12935
  const effectiveIncludeRaw = _include_raw && hasRawAccess;
12647
- const results = await hybridSearch(query, team_member, {
12936
+ const requestedMode = retrieval_mode ?? "all";
12937
+ const safeMode = !effectiveIncludeRaw && ["all", "operational"].includes(requestedMode) ? "no_raw" : requestedMode;
12938
+ const searchOptions = applyRetrievalMode({
12648
12939
  projectName: project_name,
12649
12940
  limit,
12650
12941
  since,
12651
12942
  includeArchived: include_archived,
12652
12943
  includeDrafts: false,
12653
- includeRaw: effectiveIncludeRaw,
12654
- memoryType: void 0
12655
- // Show all memory types — privacy enforced by draft filter + ACL, not type filter
12656
- });
12944
+ includeRaw: effectiveIncludeRaw
12945
+ }, safeMode);
12946
+ if (!effectiveIncludeRaw) searchOptions.includeRaw = false;
12947
+ const results = await hybridSearch(query, team_member, searchOptions);
12657
12948
  if (results.length === 0) {
12658
12949
  return {
12659
12950
  content: [
@@ -15484,7 +15775,7 @@ created_by: system
15484
15775
  ---
15485
15776
  ## Identity
15486
15777
 
15487
- You are {{agent_name}}, the Chief Operating Officer at {{company_name}}.
15778
+ You are {{agent_name}}, the {{title}} at {{company_name}}.
15488
15779
 
15489
15780
  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.
15490
15781
 
@@ -15571,11 +15862,13 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
15571
15862
  var CLIENT_COO_PLACEHOLDERS = [
15572
15863
  "agent_name",
15573
15864
  "company_name",
15574
- "founder_name"
15865
+ "founder_name",
15866
+ "title"
15575
15867
  ];
15576
15868
  function renderClientCOOTemplate(vars) {
15869
+ const resolved = { ...vars, title: vars.title || "Chief Operating Officer" };
15577
15870
  for (const key of CLIENT_COO_PLACEHOLDERS) {
15578
- const value = vars[key];
15871
+ const value = resolved[key];
15579
15872
  if (typeof value !== "string" || value.length === 0) {
15580
15873
  throw new Error(
15581
15874
  `renderClientCOOTemplate: missing required variable "${key}"`
@@ -15584,7 +15877,7 @@ function renderClientCOOTemplate(vars) {
15584
15877
  }
15585
15878
  let out = CLIENT_COO_TEMPLATE;
15586
15879
  for (const key of CLIENT_COO_PLACEHOLDERS) {
15587
- out = out.split(`{{${key}}}`).join(vars[key]);
15880
+ out = out.split(`{{${key}}}`).join(resolved[key]);
15588
15881
  }
15589
15882
  if (vars.industry_context) {
15590
15883
  out += "\n" + vars.industry_context;
@@ -15750,6 +16043,7 @@ ${vars}`);
15750
16043
  agent_name,
15751
16044
  company_name,
15752
16045
  founder_name,
16046
+ title: "Chief Operating Officer",
15753
16047
  industry_context: pack.identityContext ?? void 0
15754
16048
  });
15755
16049
  cooSummaryLines = [
@@ -2628,7 +2628,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
2628
2628
  }
2629
2629
  if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
2630
2630
  if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
2631
- envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
2631
+ let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
2632
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
2633
+ ccModel += "[1m]";
2634
+ }
2635
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
2632
2636
  }
2633
2637
  }
2634
2638
  let spawnCommand;
@@ -2392,7 +2392,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
2392
2392
  }
2393
2393
  if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
2394
2394
  if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
2395
- envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
2395
+ let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
2396
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
2397
+ ccModel += "[1m]";
2398
+ }
2399
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
2396
2400
  }
2397
2401
  }
2398
2402
  let spawnCommand;