@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/tui/App.js CHANGED
@@ -3098,6 +3098,14 @@ async function ensureSchema() {
3098
3098
  );
3099
3099
  } catch {
3100
3100
  }
3101
+ try {
3102
+ await client.execute(
3103
+ `CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
3104
+ ON memories(content_hash, agent_id, project_name, memory_type)
3105
+ WHERE content_hash IS NOT NULL`
3106
+ );
3107
+ } catch {
3108
+ }
3101
3109
  await client.executeMultiple(`
3102
3110
  CREATE TABLE IF NOT EXISTS entities (
3103
3111
  id TEXT PRIMARY KEY,
@@ -7053,7 +7061,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
7053
7061
  }
7054
7062
  if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
7055
7063
  if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
7056
- envPrefix = `${envPrefix} ANTHROPIC_MODEL=${agentRtConfig.model}`;
7064
+ let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
7065
+ if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
7066
+ ccModel += "[1m]";
7067
+ }
7068
+ envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
7057
7069
  }
7058
7070
  }
7059
7071
  let spawnCommand;
@@ -11072,6 +11084,196 @@ var init_wiki_client = __esm({
11072
11084
  }
11073
11085
  });
11074
11086
 
11087
+ // src/lib/memory-write-governor.ts
11088
+ import { createHash } from "crypto";
11089
+ function normalizeMemoryText(text) {
11090
+ return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
11091
+ }
11092
+ function classifyMemoryType(input) {
11093
+ if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
11094
+ const tool = input.tool_name.toLowerCase();
11095
+ const text = input.raw_text.toLowerCase();
11096
+ if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
11097
+ if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
11098
+ if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
11099
+ if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
11100
+ if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
11101
+ if (tool === "store_memory" || tool === "manual") return "observation";
11102
+ return "raw";
11103
+ }
11104
+ function shouldDropMemory(text) {
11105
+ const normalized = normalizeMemoryText(text);
11106
+ if (normalized.length < 10) return { drop: true, reason: "too_short" };
11107
+ if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
11108
+ return { drop: true, reason: "known_boilerplate_noise" };
11109
+ }
11110
+ return { drop: false };
11111
+ }
11112
+ function shouldSkipEmbedding(input) {
11113
+ const type = classifyMemoryType(input);
11114
+ if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
11115
+ if (type === "raw" && input.raw_text.length > 2e4) return true;
11116
+ if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
11117
+ return false;
11118
+ }
11119
+ function hashMemoryContent(text) {
11120
+ return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
11121
+ }
11122
+ function scopedDedupArgs(input) {
11123
+ return [input.contentHash, input.agentId, input.projectName, input.memoryType];
11124
+ }
11125
+ function governMemoryRecord(record) {
11126
+ const normalized = normalizeMemoryText(record.raw_text);
11127
+ const memoryType = classifyMemoryType({
11128
+ raw_text: normalized,
11129
+ agent_id: record.agent_id,
11130
+ project_name: record.project_name,
11131
+ tool_name: record.tool_name,
11132
+ memory_type: record.memory_type
11133
+ });
11134
+ const drop = shouldDropMemory(normalized);
11135
+ const skipEmbedding = shouldSkipEmbedding({
11136
+ raw_text: normalized,
11137
+ agent_id: record.agent_id,
11138
+ project_name: record.project_name,
11139
+ tool_name: record.tool_name,
11140
+ memory_type: memoryType
11141
+ });
11142
+ return {
11143
+ record: {
11144
+ ...record,
11145
+ raw_text: normalized,
11146
+ memory_type: memoryType,
11147
+ vector: skipEmbedding ? null : record.vector
11148
+ },
11149
+ contentHash: hashMemoryContent(normalized),
11150
+ shouldDrop: drop.drop,
11151
+ dropReason: drop.reason,
11152
+ skipEmbedding,
11153
+ hygiene: {
11154
+ dedup: true,
11155
+ supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
11156
+ }
11157
+ };
11158
+ }
11159
+ async function findScopedDuplicate(input) {
11160
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
11161
+ const client = getClient2();
11162
+ const args = scopedDedupArgs(input);
11163
+ let sql = `SELECT id FROM memories
11164
+ WHERE content_hash = ?
11165
+ AND agent_id = ?
11166
+ AND project_name = ?
11167
+ AND COALESCE(memory_type, 'raw') = ?
11168
+ AND COALESCE(status, 'active') != 'deleted'`;
11169
+ if (input.excludeId) {
11170
+ sql += " AND id != ?";
11171
+ args.push(input.excludeId);
11172
+ }
11173
+ sql += " ORDER BY timestamp DESC LIMIT 1";
11174
+ const result = await client.execute({ sql, args });
11175
+ return result.rows[0]?.id ? String(result.rows[0].id) : null;
11176
+ }
11177
+ async function runPostWriteMemoryHygiene(memoryId) {
11178
+ try {
11179
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
11180
+ const client = getClient2();
11181
+ const current = await client.execute({
11182
+ sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
11183
+ importance, timestamp
11184
+ FROM memories
11185
+ WHERE id = ?
11186
+ LIMIT 1`,
11187
+ args: [memoryId]
11188
+ });
11189
+ const row = current.rows[0];
11190
+ if (!row) return;
11191
+ const memoryType = String(row.memory_type ?? "raw");
11192
+ const contentHash = row.content_hash ? String(row.content_hash) : null;
11193
+ const agentId = String(row.agent_id);
11194
+ const projectName = String(row.project_name);
11195
+ if (contentHash) {
11196
+ await client.execute({
11197
+ sql: `UPDATE memories
11198
+ SET status = 'deleted',
11199
+ outcome = COALESCE(outcome, 'superseded')
11200
+ WHERE id != ?
11201
+ AND content_hash = ?
11202
+ AND agent_id = ?
11203
+ AND project_name = ?
11204
+ AND COALESCE(memory_type, 'raw') = ?
11205
+ AND COALESCE(status, 'active') = 'active'`,
11206
+ args: [memoryId, contentHash, agentId, projectName, memoryType]
11207
+ });
11208
+ }
11209
+ const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
11210
+ if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
11211
+ const old = await client.execute({
11212
+ sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
11213
+ args: [supersedesId]
11214
+ });
11215
+ const oldImportance = Number(old.rows[0]?.importance ?? 0);
11216
+ const newImportance = Number(row.importance ?? 0);
11217
+ await client.batch([
11218
+ {
11219
+ sql: `UPDATE memories
11220
+ SET status = 'archived',
11221
+ outcome = COALESCE(outcome, 'superseded')
11222
+ WHERE id = ?`,
11223
+ args: [supersedesId]
11224
+ },
11225
+ {
11226
+ sql: `UPDATE memories
11227
+ SET importance = MAX(COALESCE(importance, 5), ?),
11228
+ parent_memory_id = COALESCE(parent_memory_id, ?)
11229
+ WHERE id = ?`,
11230
+ args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
11231
+ }
11232
+ ], "write");
11233
+ }
11234
+ } catch (err) {
11235
+ process.stderr.write(
11236
+ `[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
11237
+ `
11238
+ );
11239
+ }
11240
+ }
11241
+ function schedulePostWriteMemoryHygiene(memoryIds) {
11242
+ if (memoryIds.length === 0) return;
11243
+ const run = () => {
11244
+ void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
11245
+ };
11246
+ if (typeof setImmediate === "function") setImmediate(run);
11247
+ else setTimeout(run, 0);
11248
+ }
11249
+ var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
11250
+ var init_memory_write_governor = __esm({
11251
+ "src/lib/memory-write-governor.ts"() {
11252
+ "use strict";
11253
+ HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
11254
+ "decision",
11255
+ "adr",
11256
+ "behavior",
11257
+ "procedure"
11258
+ ]);
11259
+ NOISE_DROP_PATTERNS = [
11260
+ /^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
11261
+ /^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
11262
+ /^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
11263
+ /^\s*Intercom is a speedup, not delivery/im,
11264
+ /^\s*Context bar reads as USAGE not remaining/im
11265
+ ];
11266
+ SKIP_EMBED_PATTERNS = [
11267
+ /tmux capture-pane\b/i,
11268
+ /docker ps\b/i,
11269
+ /docker images\b/i,
11270
+ /git status\b/i,
11271
+ /grep .*node_modules/i,
11272
+ /npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
11273
+ ];
11274
+ }
11275
+ });
11276
+
11075
11277
  // src/lib/shard-manager.ts
11076
11278
  var shard_manager_exports = {};
11077
11279
  __export(shard_manager_exports, {
@@ -11236,7 +11438,8 @@ async function ensureShardSchema(client) {
11236
11438
  }
11237
11439
  for (const idx of [
11238
11440
  "CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
11239
- "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
11441
+ "CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
11442
+ "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"
11240
11443
  ]) {
11241
11444
  try {
11242
11445
  await client.execute(idx);
@@ -11412,7 +11615,6 @@ __export(store_exports, {
11412
11615
  vectorToBlob: () => vectorToBlob,
11413
11616
  writeMemory: () => writeMemory
11414
11617
  });
11415
- import { createHash } from "crypto";
11416
11618
  function isBusyError2(err) {
11417
11619
  if (err instanceof Error) {
11418
11620
  const msg = err.message.toLowerCase();
@@ -11526,17 +11728,24 @@ async function writeMemory(record) {
11526
11728
  `Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
11527
11729
  );
11528
11730
  }
11529
- const contentHash = createHash("md5").update(record.raw_text).digest("hex");
11530
- if (_pendingRecords.some((r) => r.content_hash === contentHash && r.agent_id === record.agent_id)) {
11731
+ const governed = governMemoryRecord(record);
11732
+ if (governed.shouldDrop) return;
11733
+ record = governed.record;
11734
+ const contentHash = governed.contentHash;
11735
+ const memoryType = record.memory_type ?? "raw";
11736
+ if (_pendingRecords.some(
11737
+ (r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
11738
+ )) {
11531
11739
  return;
11532
11740
  }
11533
11741
  try {
11534
- const client = getClient();
11535
- const existing = await client.execute({
11536
- sql: "SELECT id FROM memories WHERE content_hash = ? AND agent_id = ? LIMIT 1",
11537
- args: [contentHash, record.agent_id]
11742
+ const existing = await findScopedDuplicate({
11743
+ contentHash,
11744
+ agentId: record.agent_id,
11745
+ projectName: record.project_name,
11746
+ memoryType
11538
11747
  });
11539
- if (existing.rows.length > 0) return;
11748
+ if (existing) return;
11540
11749
  } catch {
11541
11750
  }
11542
11751
  const dbRow = {
@@ -11567,7 +11776,7 @@ async function writeMemory(record) {
11567
11776
  tier: record.tier ?? classifyTier(record),
11568
11777
  supersedes_id: record.supersedes_id ?? null,
11569
11778
  draft: record.draft ? 1 : 0,
11570
- memory_type: record.memory_type ?? "raw",
11779
+ memory_type: memoryType,
11571
11780
  trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
11572
11781
  content_hash: contentHash,
11573
11782
  intent: record.intent ?? null,
@@ -11726,6 +11935,7 @@ async function flushBatch() {
11726
11935
  const globalClient = getClient();
11727
11936
  const globalStmts = batch.map(buildStmt);
11728
11937
  await globalClient.batch(globalStmts, "write");
11938
+ schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
11729
11939
  _pendingRecords.splice(0, batch.length);
11730
11940
  try {
11731
11941
  const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
@@ -11984,6 +12194,7 @@ var init_store = __esm({
11984
12194
  init_keychain();
11985
12195
  init_config();
11986
12196
  init_state_bus();
12197
+ init_memory_write_governor();
11987
12198
  INIT_MAX_RETRIES = 3;
11988
12199
  INIT_RETRY_DELAY_MS = 1e3;
11989
12200
  _pendingRecords = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askexenow/exe-os",
3
- "version": "0.9.34",
3
+ "version": "0.9.35",
4
4
  "description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",