@askexenow/exe-os 0.9.34 → 0.9.35

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 (70) hide show
  1. package/dist/bin/backfill-conversations.js +210 -10
  2. package/dist/bin/backfill-responses.js +210 -10
  3. package/dist/bin/backfill-vectors.js +13 -2
  4. package/dist/bin/cleanup-stale-review-tasks.js +217 -10
  5. package/dist/bin/cli.js +222 -11
  6. package/dist/bin/exe-assign.js +210 -10
  7. package/dist/bin/exe-boot.js +24 -3
  8. package/dist/bin/exe-dispatch.js +222 -11
  9. package/dist/bin/exe-doctor.js +13 -2
  10. package/dist/bin/exe-export-behaviors.js +217 -10
  11. package/dist/bin/exe-forget.js +217 -10
  12. package/dist/bin/exe-gateway.js +222 -11
  13. package/dist/bin/exe-heartbeat.js +217 -10
  14. package/dist/bin/exe-kill.js +217 -10
  15. package/dist/bin/exe-launch-agent.js +92 -2
  16. package/dist/bin/exe-link.js +8 -0
  17. package/dist/bin/exe-pending-messages.js +217 -10
  18. package/dist/bin/exe-pending-notifications.js +217 -10
  19. package/dist/bin/exe-pending-reviews.js +217 -10
  20. package/dist/bin/exe-rename.js +8 -0
  21. package/dist/bin/exe-review.js +217 -10
  22. package/dist/bin/exe-search.js +217 -10
  23. package/dist/bin/exe-session-cleanup.js +222 -11
  24. package/dist/bin/exe-start-codex.js +92 -2
  25. package/dist/bin/exe-start-opencode.js +92 -2
  26. package/dist/bin/exe-status.js +217 -10
  27. package/dist/bin/exe-team.js +217 -10
  28. package/dist/bin/git-sweep.js +222 -11
  29. package/dist/bin/graph-backfill.js +92 -2
  30. package/dist/bin/graph-export.js +217 -10
  31. package/dist/bin/intercom-check.js +222 -11
  32. package/dist/bin/scan-tasks.js +222 -11
  33. package/dist/bin/setup.js +8 -0
  34. package/dist/bin/shard-migrate.js +92 -2
  35. package/dist/gateway/index.js +222 -11
  36. package/dist/hooks/bug-report-worker.js +222 -11
  37. package/dist/hooks/codex-stop-task-finalizer.js +217 -10
  38. package/dist/hooks/commit-complete.js +222 -11
  39. package/dist/hooks/error-recall.js +217 -10
  40. package/dist/hooks/ingest.js +217 -10
  41. package/dist/hooks/instructions-loaded.js +217 -10
  42. package/dist/hooks/notification.js +217 -10
  43. package/dist/hooks/post-compact.js +217 -10
  44. package/dist/hooks/post-tool-combined.js +217 -10
  45. package/dist/hooks/pre-compact.js +222 -11
  46. package/dist/hooks/pre-tool-use.js +217 -10
  47. package/dist/hooks/prompt-submit.js +222 -11
  48. package/dist/hooks/session-end.js +222 -11
  49. package/dist/hooks/session-start.js +217 -10
  50. package/dist/hooks/stop.js +217 -10
  51. package/dist/hooks/subagent-stop.js +217 -10
  52. package/dist/hooks/summary-worker.js +14 -1
  53. package/dist/index.js +222 -11
  54. package/dist/lib/cloud-sync.js +8 -0
  55. package/dist/lib/consolidation.js +3 -1
  56. package/dist/lib/database.js +8 -0
  57. package/dist/lib/db.js +8 -0
  58. package/dist/lib/device-registry.js +8 -0
  59. package/dist/lib/exe-daemon.js +1667 -1413
  60. package/dist/lib/hybrid-search.js +217 -10
  61. package/dist/lib/schedules.js +13 -2
  62. package/dist/lib/store.js +210 -10
  63. package/dist/lib/tasks.js +5 -1
  64. package/dist/lib/tmux-routing.js +5 -1
  65. package/dist/mcp/server.js +222 -11
  66. package/dist/mcp/tools/create-task.js +5 -1
  67. package/dist/mcp/tools/update-task.js +5 -1
  68. package/dist/runtime/index.js +222 -11
  69. package/dist/tui/App.js +222 -11
  70. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3086,6 +3086,14 @@ async function ensureSchema() {
3086
3086
  );
3087
3087
  } catch {
3088
3088
  }
3089
+ try {
3090
+ await client.execute(
3091
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
3092
+ ON memories(content_hash, agent_id, project_name, memory_type)
3093
+ WHERE content_hash IS NOT NULL`
3094
+ );
3095
+ } catch {
3096
+ }
3089
3097
  await client.executeMultiple(`
3090
3098
  CREATE TABLE IF NOT EXISTS entities (
3091
3099
  id TEXT PRIMARY KEY,
@@ -6688,7 +6696,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6688
6696
  }
6689
6697
  if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
6690
6698
  if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
6691
- envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
6699
+ let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
6700
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
6701
+ ccModel += "[1m]";
6702
+ }
6703
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
6692
6704
  }
6693
6705
  }
6694
6706
  let spawnCommand;
@@ -7002,6 +7014,196 @@ var init_keychain = __esm({
7002
7014
  }
7003
7015
  });
7004
7016
 
7017
+ // src/lib/memory-write-governor.ts
7018
+ import { createHash } from "crypto";
7019
+ function normalizeMemoryText(text) {
7020
+ return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
7021
+ }
7022
+ function classifyMemoryType(input) {
7023
+ if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
7024
+ const tool = input.tool_name.toLowerCase();
7025
+ const text = input.raw_text.toLowerCase();
7026
+ if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
7027
+ if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
7028
+ if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
7029
+ if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
7030
+ if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
7031
+ if (tool === "store_memory" || tool === "manual") return "observation";
7032
+ return "raw";
7033
+ }
7034
+ function shouldDropMemory(text) {
7035
+ const normalized = normalizeMemoryText(text);
7036
+ if (normalized.length < 10) return { drop: true, reason: "too_short" };
7037
+ if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
7038
+ return { drop: true, reason: "known_boilerplate_noise" };
7039
+ }
7040
+ return { drop: false };
7041
+ }
7042
+ function shouldSkipEmbedding(input) {
7043
+ const type = classifyMemoryType(input);
7044
+ if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
7045
+ if (type === "raw" && input.raw_text.length > 2e4) return true;
7046
+ if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
7047
+ return false;
7048
+ }
7049
+ function hashMemoryContent(text) {
7050
+ return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
7051
+ }
7052
+ function scopedDedupArgs(input) {
7053
+ return [input.contentHash, input.agentId, input.projectName, input.memoryType];
7054
+ }
7055
+ function governMemoryRecord(record) {
7056
+ const normalized = normalizeMemoryText(record.raw_text);
7057
+ const memoryType = classifyMemoryType({
7058
+ raw_text: normalized,
7059
+ agent_id: record.agent_id,
7060
+ project_name: record.project_name,
7061
+ tool_name: record.tool_name,
7062
+ memory_type: record.memory_type
7063
+ });
7064
+ const drop = shouldDropMemory(normalized);
7065
+ const skipEmbedding = shouldSkipEmbedding({
7066
+ raw_text: normalized,
7067
+ agent_id: record.agent_id,
7068
+ project_name: record.project_name,
7069
+ tool_name: record.tool_name,
7070
+ memory_type: memoryType
7071
+ });
7072
+ return {
7073
+ record: {
7074
+ ...record,
7075
+ raw_text: normalized,
7076
+ memory_type: memoryType,
7077
+ vector: skipEmbedding ? null : record.vector
7078
+ },
7079
+ contentHash: hashMemoryContent(normalized),
7080
+ shouldDrop: drop.drop,
7081
+ dropReason: drop.reason,
7082
+ skipEmbedding,
7083
+ hygiene: {
7084
+ dedup: true,
7085
+ supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
7086
+ }
7087
+ };
7088
+ }
7089
+ async function findScopedDuplicate(input) {
7090
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
7091
+ const client = getClient2();
7092
+ const args = scopedDedupArgs(input);
7093
+ let sql = `SELECT id FROM memories
7094
+ WHERE content_hash = ?
7095
+ AND agent_id = ?
7096
+ AND project_name = ?
7097
+ AND COALESCE(memory_type, 'raw') = ?
7098
+ AND COALESCE(status, 'active') != 'deleted'`;
7099
+ if (input.excludeId) {
7100
+ sql += " AND id != ?";
7101
+ args.push(input.excludeId);
7102
+ }
7103
+ sql += " ORDER BY timestamp DESC LIMIT 1";
7104
+ const result = await client.execute({ sql, args });
7105
+ return result.rows[0]?.id ? String(result.rows[0].id) : null;
7106
+ }
7107
+ async function runPostWriteMemoryHygiene(memoryId) {
7108
+ try {
7109
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
7110
+ const client = getClient2();
7111
+ const current = await client.execute({
7112
+ sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
7113
+ importance, timestamp
7114
+ FROM memories
7115
+ WHERE id = ?
7116
+ LIMIT 1`,
7117
+ args: [memoryId]
7118
+ });
7119
+ const row = current.rows[0];
7120
+ if (!row) return;
7121
+ const memoryType = String(row.memory_type ?? "raw");
7122
+ const contentHash = row.content_hash ? String(row.content_hash) : null;
7123
+ const agentId = String(row.agent_id);
7124
+ const projectName = String(row.project_name);
7125
+ if (contentHash) {
7126
+ await client.execute({
7127
+ sql: `UPDATE memories
7128
+ SET status = 'deleted',
7129
+ outcome = COALESCE(outcome, 'superseded')
7130
+ WHERE id != ?
7131
+ AND content_hash = ?
7132
+ AND agent_id = ?
7133
+ AND project_name = ?
7134
+ AND COALESCE(memory_type, 'raw') = ?
7135
+ AND COALESCE(status, 'active') = 'active'`,
7136
+ args: [memoryId, contentHash, agentId, projectName, memoryType]
7137
+ });
7138
+ }
7139
+ const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
7140
+ if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
7141
+ const old = await client.execute({
7142
+ sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
7143
+ args: [supersedesId]
7144
+ });
7145
+ const oldImportance = Number(old.rows[0]?.importance ?? 0);
7146
+ const newImportance = Number(row.importance ?? 0);
7147
+ await client.batch([
7148
+ {
7149
+ sql: `UPDATE memories
7150
+ SET status = 'archived',
7151
+ outcome = COALESCE(outcome, 'superseded')
7152
+ WHERE id = ?`,
7153
+ args: [supersedesId]
7154
+ },
7155
+ {
7156
+ sql: `UPDATE memories
7157
+ SET importance = MAX(COALESCE(importance, 5), ?),
7158
+ parent_memory_id = COALESCE(parent_memory_id, ?)
7159
+ WHERE id = ?`,
7160
+ args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
7161
+ }
7162
+ ], "write");
7163
+ }
7164
+ } catch (err) {
7165
+ process.stderr.write(
7166
+ `[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
7167
+ `
7168
+ );
7169
+ }
7170
+ }
7171
+ function schedulePostWriteMemoryHygiene(memoryIds) {
7172
+ if (memoryIds.length === 0) return;
7173
+ const run = () => {
7174
+ void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
7175
+ };
7176
+ if (typeof setImmediate === "function") setImmediate(run);
7177
+ else setTimeout(run, 0);
7178
+ }
7179
+ var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
7180
+ var init_memory_write_governor = __esm({
7181
+ "src/lib/memory-write-governor.ts"() {
7182
+ "use strict";
7183
+ HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
7184
+ "decision",
7185
+ "adr",
7186
+ "behavior",
7187
+ "procedure"
7188
+ ]);
7189
+ NOISE_DROP_PATTERNS = [
7190
+ /^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
7191
+ /^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
7192
+ /^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
7193
+ /^\s*Intercom is a speedup, not delivery/im,
7194
+ /^\s*Context bar reads as USAGE not remaining/im
7195
+ ];
7196
+ SKIP_EMBED_PATTERNS = [
7197
+ /tmux capture-pane\b/i,
7198
+ /docker ps\b/i,
7199
+ /docker images\b/i,
7200
+ /git status\b/i,
7201
+ /grep .*node_modules/i,
7202
+ /npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
7203
+ ];
7204
+ }
7205
+ });
7206
+
7005
7207
  // src/lib/shard-manager.ts
7006
7208
  var shard_manager_exports = {};
7007
7209
  __export(shard_manager_exports, {
@@ -7166,7 +7368,8 @@ async function ensureShardSchema(client) {
7166
7368
  }
7167
7369
  for (const idx of [
7168
7370
  "CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
7169
- "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
7371
+ "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
7372
+ "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"
7170
7373
  ]) {
7171
7374
  try {
7172
7375
  await client.execute(idx);
@@ -7591,7 +7794,6 @@ __export(store_exports, {
7591
7794
  vectorToBlob: () => vectorToBlob,
7592
7795
  writeMemory: () => writeMemory
7593
7796
  });
7594
- import { createHash } from "crypto";
7595
7797
  function isBusyError2(err) {
7596
7798
  if (err instanceof Error) {
7597
7799
  const msg = err.message.toLowerCase();
@@ -7705,17 +7907,24 @@ async function writeMemory(record) {
7705
7907
  `Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
7706
7908
  );
7707
7909
  }
7708
- const contentHash = createHash("md5").update(record.raw_text).digest("hex");
7709
- if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
7910
+ const governed = governMemoryRecord(record);
7911
+ if (governed.shouldDrop) return;
7912
+ record = governed.record;
7913
+ const contentHash = governed.contentHash;
7914
+ const memoryType = record.memory_type ?? "raw";
7915
+ if (_pendingRecords.some(
7916
+ (r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
7917
+ )) {
7710
7918
  return;
7711
7919
  }
7712
7920
  try {
7713
- const client = getClient();
7714
- const existing = await client.execute({
7715
- sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
7716
- args: [contentHash, record.agent_id]
7921
+ const existing = await findScopedDuplicate({
7922
+ contentHash,
7923
+ agentId: record.agent_id,
7924
+ projectName: record.project_name,
7925
+ memoryType
7717
7926
  });
7718
- if (existing.rows.length > 0) return;
7927
+ if (existing) return;
7719
7928
  } catch {
7720
7929
  }
7721
7930
  const dbRow = {
@@ -7746,7 +7955,7 @@ async function writeMemory(record) {
7746
7955
  tier: record.tier ?? classifyTier(record),
7747
7956
  supersedes_id: record.supersedes_id ?? null,
7748
7957
  draft: record.draft ? 1 : 0,
7749
- memory_type: record.memory_type ?? "raw",
7958
+ memory_type: memoryType,
7750
7959
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
7751
7960
  content_hash: contentHash,
7752
7961
  intent: record.intent ?? null,
@@ -7905,6 +8114,7 @@ async function flushBatch() {
7905
8114
  const globalClient = getClient();
7906
8115
  const globalStmts = batch.map(buildStmt);
7907
8116
  await globalClient.batch(globalStmts, "write");
8117
+ schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
7908
8118
  _pendingRecords.splice(0, batch.length);
7909
8119
  try {
7910
8120
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -8163,6 +8373,7 @@ var init_store = __esm({
8163
8373
  init_keychain();
8164
8374
  init_config();
8165
8375
  init_state_bus();
8376
+ init_memory_write_governor();
8166
8377
  INIT_MAX_RETRIES = 3;
8167
8378
  INIT_RETRY_DELAY_MS = 1e3;
8168
8379
  _pendingRecords = [];
@@ -2021,6 +2021,14 @@ async function ensureSchema() {
2021
2021
  );
2022
2022
  } catch {
2023
2023
  }
2024
+ try {
2025
+ await client.execute(
2026
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
2027
+ ON memories(content_hash, agent_id, project_name, memory_type)
2028
+ WHERE content_hash IS NOT NULL`
2029
+ );
2030
+ } catch {
2031
+ }
2024
2032
  await client.executeMultiple(`
2025
2033
  CREATE TABLE IF NOT EXISTS entities (
2026
2034
  id TEXT PRIMARY KEY,
@@ -550,7 +550,6 @@ import { randomUUID } from "crypto";
550
550
  // src/lib/store.ts
551
551
  init_memory();
552
552
  init_database();
553
- import { createHash } from "crypto";
554
553
 
555
554
  // src/lib/keychain.ts
556
555
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
@@ -611,6 +610,9 @@ var StateBus = class {
611
610
  };
612
611
  var orgBus = new StateBus();
613
612
 
613
+ // src/lib/memory-write-governor.ts
614
+ import { createHash } from "crypto";
615
+
614
616
  // src/lib/store.ts
615
617
  function vectorToBlob(vector) {
616
618
  const f32 = vector instanceof Float32Array ? vector : new Float32Array(vector);
@@ -1937,6 +1937,14 @@ async function ensureSchema() {
1937
1937
  );
1938
1938
  } catch {
1939
1939
  }
1940
+ try {
1941
+ await client.execute(
1942
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
1943
+ ON memories(content_hash, agent_id, project_name, memory_type)
1944
+ WHERE content_hash IS NOT NULL`
1945
+ );
1946
+ } catch {
1947
+ }
1940
1948
  await client.executeMultiple(`
1941
1949
  CREATE TABLE IF NOT EXISTS entities (
1942
1950
  id TEXT PRIMARY KEY,
package/dist/lib/db.js CHANGED
@@ -1937,6 +1937,14 @@ async function ensureSchema() {
1937
1937
  );
1938
1938
  } catch {
1939
1939
  }
1940
+ try {
1941
+ await client.execute(
1942
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
1943
+ ON memories(content_hash, agent_id, project_name, memory_type)
1944
+ WHERE content_hash IS NOT NULL`
1945
+ );
1946
+ } catch {
1947
+ }
1940
1948
  await client.executeMultiple(`
1941
1949
  CREATE TABLE IF NOT EXISTS entities (
1942
1950
  id TEXT PRIMARY KEY,
@@ -1966,6 +1966,14 @@ async function ensureSchema() {
1966
1966
  );
1967
1967
  } catch {
1968
1968
  }
1969
+ try {
1970
+ await client.execute(
1971
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
1972
+ ON memories(content_hash, agent_id, project_name, memory_type)
1973
+ WHERE content_hash IS NOT NULL`
1974
+ );
1975
+ } catch {
1976
+ }
1969
1977
  await client.executeMultiple(`
1970
1978
  CREATE TABLE IF NOT EXISTS entities (
1971
1979
  id TEXT PRIMARY KEY,