@askexenow/exe-os 0.9.33 → 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.
- package/dist/bin/backfill-conversations.js +228 -12
- package/dist/bin/backfill-responses.js +228 -12
- package/dist/bin/backfill-vectors.js +31 -4
- package/dist/bin/cleanup-stale-review-tasks.js +235 -12
- package/dist/bin/cli.js +265 -22
- package/dist/bin/exe-assign.js +228 -12
- package/dist/bin/exe-boot.js +56 -13
- package/dist/bin/exe-cloud.js +3 -3
- package/dist/bin/exe-dispatch.js +243 -15
- package/dist/bin/exe-doctor.js +34 -9
- package/dist/bin/exe-export-behaviors.js +235 -12
- package/dist/bin/exe-forget.js +244 -18
- package/dist/bin/exe-gateway.js +243 -15
- package/dist/bin/exe-heartbeat.js +235 -12
- package/dist/bin/exe-kill.js +235 -12
- package/dist/bin/exe-launch-agent.js +126 -4
- package/dist/bin/exe-link.js +28 -5
- package/dist/bin/exe-pending-messages.js +235 -12
- package/dist/bin/exe-pending-notifications.js +235 -12
- package/dist/bin/exe-pending-reviews.js +235 -12
- package/dist/bin/exe-rename.js +26 -2
- package/dist/bin/exe-review.js +235 -12
- package/dist/bin/exe-search.js +235 -12
- package/dist/bin/exe-session-cleanup.js +243 -15
- package/dist/bin/exe-settings.js +1 -1
- package/dist/bin/exe-start-codex.js +126 -4
- package/dist/bin/exe-start-opencode.js +126 -4
- package/dist/bin/exe-status.js +235 -12
- package/dist/bin/exe-team.js +235 -12
- package/dist/bin/git-sweep.js +243 -15
- package/dist/bin/graph-backfill.js +110 -4
- package/dist/bin/graph-export.js +235 -12
- package/dist/bin/intercom-check.js +243 -15
- package/dist/bin/scan-tasks.js +243 -15
- package/dist/bin/setup.js +32 -9
- package/dist/bin/shard-migrate.js +110 -4
- package/dist/gateway/index.js +243 -15
- package/dist/hooks/bug-report-worker.js +243 -15
- package/dist/hooks/codex-stop-task-finalizer.js +238 -14
- package/dist/hooks/commit-complete.js +243 -15
- package/dist/hooks/error-recall.js +244 -12
- package/dist/hooks/exe-heartbeat-hook.js +9 -0
- package/dist/hooks/ingest.js +244 -12
- package/dist/hooks/instructions-loaded.js +244 -12
- package/dist/hooks/notification.js +244 -12
- package/dist/hooks/post-compact.js +247 -13
- package/dist/hooks/post-tool-combined.js +251 -12
- package/dist/hooks/pre-compact.js +255 -16
- package/dist/hooks/pre-tool-use.js +247 -13
- package/dist/hooks/prompt-submit.js +255 -16
- package/dist/hooks/session-end.js +255 -16
- package/dist/hooks/session-start.js +251 -12
- package/dist/hooks/stop.js +247 -13
- package/dist/hooks/subagent-stop.js +247 -13
- package/dist/hooks/summary-worker.js +36 -8
- package/dist/index.js +243 -15
- package/dist/lib/cloud-sync.js +28 -5
- package/dist/lib/consolidation.js +3 -1
- package/dist/lib/database.js +25 -1
- package/dist/lib/db.js +25 -1
- package/dist/lib/device-registry.js +26 -2
- package/dist/lib/exe-daemon.js +22905 -9125
- package/dist/lib/hybrid-search.js +235 -12
- package/dist/lib/schedules.js +31 -4
- package/dist/lib/store.js +228 -12
- package/dist/lib/tasks.js +8 -3
- package/dist/lib/tmux-routing.js +8 -3
- package/dist/mcp/server.js +411 -164
- package/dist/mcp/tools/create-task.js +20 -4
- package/dist/mcp/tools/deactivate-behavior.js +9 -0
- package/dist/mcp/tools/list-tasks.js +12 -1
- package/dist/mcp/tools/send-message.js +12 -1
- package/dist/mcp/tools/update-task.js +24 -3
- package/dist/runtime/index.js +243 -15
- package/dist/tui/App.js +243 -15
- package/package.json +1 -1
|
@@ -1582,6 +1582,7 @@ var init_db_daemon_client = __esm({
|
|
|
1582
1582
|
// src/lib/database.ts
|
|
1583
1583
|
var database_exports = {};
|
|
1584
1584
|
__export(database_exports, {
|
|
1585
|
+
SOFT_DELETE_RETENTION_DAYS: () => SOFT_DELETE_RETENTION_DAYS,
|
|
1585
1586
|
disposeDatabase: () => disposeDatabase,
|
|
1586
1587
|
disposeTurso: () => disposeTurso,
|
|
1587
1588
|
ensureSchema: () => ensureSchema,
|
|
@@ -1738,10 +1739,17 @@ async function ensureSchema() {
|
|
|
1738
1739
|
INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
|
|
1739
1740
|
END;
|
|
1740
1741
|
|
|
1741
|
-
CREATE TRIGGER IF NOT EXISTS memories_fts_au AFTER UPDATE ON memories
|
|
1742
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_au AFTER UPDATE ON memories
|
|
1743
|
+
WHEN new.status IS NULL OR new.status != 'deleted' BEGIN
|
|
1742
1744
|
INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
|
|
1743
1745
|
INSERT INTO memories_fts(rowid, raw_text) VALUES (new.rowid, new.raw_text);
|
|
1744
1746
|
END;
|
|
1747
|
+
|
|
1748
|
+
-- Soft-delete trigger: remove from FTS when status changes to 'deleted'
|
|
1749
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_soft_delete AFTER UPDATE ON memories
|
|
1750
|
+
WHEN new.status = 'deleted' AND (old.status IS NULL OR old.status != 'deleted') BEGIN
|
|
1751
|
+
INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
|
|
1752
|
+
END;
|
|
1745
1753
|
`);
|
|
1746
1754
|
await client.executeMultiple(`
|
|
1747
1755
|
CREATE TABLE IF NOT EXISTS sync_meta (
|
|
@@ -2144,6 +2152,13 @@ async function ensureSchema() {
|
|
|
2144
2152
|
});
|
|
2145
2153
|
} catch {
|
|
2146
2154
|
}
|
|
2155
|
+
try {
|
|
2156
|
+
await client.execute({
|
|
2157
|
+
sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
|
|
2158
|
+
args: []
|
|
2159
|
+
});
|
|
2160
|
+
} catch {
|
|
2161
|
+
}
|
|
2147
2162
|
try {
|
|
2148
2163
|
await client.execute({
|
|
2149
2164
|
sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
|
|
@@ -2194,6 +2209,14 @@ async function ensureSchema() {
|
|
|
2194
2209
|
);
|
|
2195
2210
|
} catch {
|
|
2196
2211
|
}
|
|
2212
|
+
try {
|
|
2213
|
+
await client.execute(
|
|
2214
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2215
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2216
|
+
WHERE content_hash IS NOT NULL`
|
|
2217
|
+
);
|
|
2218
|
+
} catch {
|
|
2219
|
+
}
|
|
2197
2220
|
await client.executeMultiple(`
|
|
2198
2221
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2199
2222
|
id TEXT PRIMARY KEY,
|
|
@@ -2680,7 +2703,7 @@ async function disposeDatabase() {
|
|
|
2680
2703
|
_resilientClient = null;
|
|
2681
2704
|
}
|
|
2682
2705
|
}
|
|
2683
|
-
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
|
|
2706
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
|
|
2684
2707
|
var init_database = __esm({
|
|
2685
2708
|
"src/lib/database.ts"() {
|
|
2686
2709
|
"use strict";
|
|
@@ -2694,6 +2717,7 @@ var init_database = __esm({
|
|
|
2694
2717
|
_daemonClient = null;
|
|
2695
2718
|
_adapterClient = null;
|
|
2696
2719
|
initTurso = initDatabase;
|
|
2720
|
+
SOFT_DELETE_RETENTION_DAYS = 7;
|
|
2697
2721
|
disposeTurso = disposeDatabase;
|
|
2698
2722
|
}
|
|
2699
2723
|
});
|
|
@@ -2862,7 +2886,8 @@ async function ensureShardSchema(client) {
|
|
|
2862
2886
|
}
|
|
2863
2887
|
for (const idx of [
|
|
2864
2888
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
2865
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
2889
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
2890
|
+
"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"
|
|
2866
2891
|
]) {
|
|
2867
2892
|
try {
|
|
2868
2893
|
await client.execute(idx);
|
|
@@ -3272,7 +3297,6 @@ ${p.content}`).join("\n\n");
|
|
|
3272
3297
|
// src/lib/store.ts
|
|
3273
3298
|
init_memory();
|
|
3274
3299
|
init_database();
|
|
3275
|
-
import { createHash } from "crypto";
|
|
3276
3300
|
|
|
3277
3301
|
// src/lib/keychain.ts
|
|
3278
3302
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
@@ -3505,6 +3529,9 @@ var StateBus = class {
|
|
|
3505
3529
|
};
|
|
3506
3530
|
var orgBus = new StateBus();
|
|
3507
3531
|
|
|
3532
|
+
// src/lib/memory-write-governor.ts
|
|
3533
|
+
import { createHash } from "crypto";
|
|
3534
|
+
|
|
3508
3535
|
// src/lib/store.ts
|
|
3509
3536
|
var INIT_MAX_RETRIES = 3;
|
|
3510
3537
|
var INIT_RETRY_DELAY_MS = 1e3;
|
|
@@ -1672,6 +1672,7 @@ var init_db_daemon_client = __esm({
|
|
|
1672
1672
|
// src/lib/database.ts
|
|
1673
1673
|
var database_exports = {};
|
|
1674
1674
|
__export(database_exports, {
|
|
1675
|
+
SOFT_DELETE_RETENTION_DAYS: () => SOFT_DELETE_RETENTION_DAYS,
|
|
1675
1676
|
disposeDatabase: () => disposeDatabase,
|
|
1676
1677
|
disposeTurso: () => disposeTurso,
|
|
1677
1678
|
ensureSchema: () => ensureSchema,
|
|
@@ -1828,10 +1829,17 @@ async function ensureSchema() {
|
|
|
1828
1829
|
INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
|
|
1829
1830
|
END;
|
|
1830
1831
|
|
|
1831
|
-
CREATE TRIGGER IF NOT EXISTS memories_fts_au AFTER UPDATE ON memories
|
|
1832
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_au AFTER UPDATE ON memories
|
|
1833
|
+
WHEN new.status IS NULL OR new.status != 'deleted' BEGIN
|
|
1832
1834
|
INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
|
|
1833
1835
|
INSERT INTO memories_fts(rowid, raw_text) VALUES (new.rowid, new.raw_text);
|
|
1834
1836
|
END;
|
|
1837
|
+
|
|
1838
|
+
-- Soft-delete trigger: remove from FTS when status changes to 'deleted'
|
|
1839
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_soft_delete AFTER UPDATE ON memories
|
|
1840
|
+
WHEN new.status = 'deleted' AND (old.status IS NULL OR old.status != 'deleted') BEGIN
|
|
1841
|
+
INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
|
|
1842
|
+
END;
|
|
1835
1843
|
`);
|
|
1836
1844
|
await client.executeMultiple(`
|
|
1837
1845
|
CREATE TABLE IF NOT EXISTS sync_meta (
|
|
@@ -2234,6 +2242,13 @@ async function ensureSchema() {
|
|
|
2234
2242
|
});
|
|
2235
2243
|
} catch {
|
|
2236
2244
|
}
|
|
2245
|
+
try {
|
|
2246
|
+
await client.execute({
|
|
2247
|
+
sql: `ALTER TABLE memories ADD COLUMN deleted_at TEXT`,
|
|
2248
|
+
args: []
|
|
2249
|
+
});
|
|
2250
|
+
} catch {
|
|
2251
|
+
}
|
|
2237
2252
|
try {
|
|
2238
2253
|
await client.execute({
|
|
2239
2254
|
sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
|
|
@@ -2284,6 +2299,14 @@ async function ensureSchema() {
|
|
|
2284
2299
|
);
|
|
2285
2300
|
} catch {
|
|
2286
2301
|
}
|
|
2302
|
+
try {
|
|
2303
|
+
await client.execute(
|
|
2304
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2305
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2306
|
+
WHERE content_hash IS NOT NULL`
|
|
2307
|
+
);
|
|
2308
|
+
} catch {
|
|
2309
|
+
}
|
|
2287
2310
|
await client.executeMultiple(`
|
|
2288
2311
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2289
2312
|
id TEXT PRIMARY KEY,
|
|
@@ -2770,7 +2793,7 @@ async function disposeDatabase() {
|
|
|
2770
2793
|
_resilientClient = null;
|
|
2771
2794
|
}
|
|
2772
2795
|
}
|
|
2773
|
-
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
|
|
2796
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, SOFT_DELETE_RETENTION_DAYS, disposeTurso;
|
|
2774
2797
|
var init_database = __esm({
|
|
2775
2798
|
"src/lib/database.ts"() {
|
|
2776
2799
|
"use strict";
|
|
@@ -2784,6 +2807,7 @@ var init_database = __esm({
|
|
|
2784
2807
|
_daemonClient = null;
|
|
2785
2808
|
_adapterClient = null;
|
|
2786
2809
|
initTurso = initDatabase;
|
|
2810
|
+
SOFT_DELETE_RETENTION_DAYS = 7;
|
|
2787
2811
|
disposeTurso = disposeDatabase;
|
|
2788
2812
|
}
|
|
2789
2813
|
});
|
|
@@ -3028,6 +3052,196 @@ var init_state_bus = __esm({
|
|
|
3028
3052
|
}
|
|
3029
3053
|
});
|
|
3030
3054
|
|
|
3055
|
+
// src/lib/memory-write-governor.ts
|
|
3056
|
+
import { createHash } from "crypto";
|
|
3057
|
+
function normalizeMemoryText(text) {
|
|
3058
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3059
|
+
}
|
|
3060
|
+
function classifyMemoryType(input) {
|
|
3061
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
3062
|
+
const tool = input.tool_name.toLowerCase();
|
|
3063
|
+
const text = input.raw_text.toLowerCase();
|
|
3064
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3065
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3066
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3067
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3068
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3069
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3070
|
+
return "raw";
|
|
3071
|
+
}
|
|
3072
|
+
function shouldDropMemory(text) {
|
|
3073
|
+
const normalized = normalizeMemoryText(text);
|
|
3074
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3075
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3076
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3077
|
+
}
|
|
3078
|
+
return { drop: false };
|
|
3079
|
+
}
|
|
3080
|
+
function shouldSkipEmbedding(input) {
|
|
3081
|
+
const type = classifyMemoryType(input);
|
|
3082
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3083
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
3084
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
3085
|
+
return false;
|
|
3086
|
+
}
|
|
3087
|
+
function hashMemoryContent(text) {
|
|
3088
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3089
|
+
}
|
|
3090
|
+
function scopedDedupArgs(input) {
|
|
3091
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
3092
|
+
}
|
|
3093
|
+
function governMemoryRecord(record) {
|
|
3094
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3095
|
+
const memoryType = classifyMemoryType({
|
|
3096
|
+
raw_text: normalized,
|
|
3097
|
+
agent_id: record.agent_id,
|
|
3098
|
+
project_name: record.project_name,
|
|
3099
|
+
tool_name: record.tool_name,
|
|
3100
|
+
memory_type: record.memory_type
|
|
3101
|
+
});
|
|
3102
|
+
const drop = shouldDropMemory(normalized);
|
|
3103
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3104
|
+
raw_text: normalized,
|
|
3105
|
+
agent_id: record.agent_id,
|
|
3106
|
+
project_name: record.project_name,
|
|
3107
|
+
tool_name: record.tool_name,
|
|
3108
|
+
memory_type: memoryType
|
|
3109
|
+
});
|
|
3110
|
+
return {
|
|
3111
|
+
record: {
|
|
3112
|
+
...record,
|
|
3113
|
+
raw_text: normalized,
|
|
3114
|
+
memory_type: memoryType,
|
|
3115
|
+
vector: skipEmbedding ? null : record.vector
|
|
3116
|
+
},
|
|
3117
|
+
contentHash: hashMemoryContent(normalized),
|
|
3118
|
+
shouldDrop: drop.drop,
|
|
3119
|
+
dropReason: drop.reason,
|
|
3120
|
+
skipEmbedding,
|
|
3121
|
+
hygiene: {
|
|
3122
|
+
dedup: true,
|
|
3123
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3124
|
+
}
|
|
3125
|
+
};
|
|
3126
|
+
}
|
|
3127
|
+
async function findScopedDuplicate(input) {
|
|
3128
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3129
|
+
const client = getClient2();
|
|
3130
|
+
const args = scopedDedupArgs(input);
|
|
3131
|
+
let sql = `SELECT id FROM memories
|
|
3132
|
+
WHERE content_hash = ?
|
|
3133
|
+
AND agent_id = ?
|
|
3134
|
+
AND project_name = ?
|
|
3135
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3136
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3137
|
+
if (input.excludeId) {
|
|
3138
|
+
sql += " AND id != ?";
|
|
3139
|
+
args.push(input.excludeId);
|
|
3140
|
+
}
|
|
3141
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3142
|
+
const result = await client.execute({ sql, args });
|
|
3143
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3144
|
+
}
|
|
3145
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3146
|
+
try {
|
|
3147
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3148
|
+
const client = getClient2();
|
|
3149
|
+
const current = await client.execute({
|
|
3150
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3151
|
+
importance, timestamp
|
|
3152
|
+
FROM memories
|
|
3153
|
+
WHERE id = ?
|
|
3154
|
+
LIMIT 1`,
|
|
3155
|
+
args: [memoryId]
|
|
3156
|
+
});
|
|
3157
|
+
const row = current.rows[0];
|
|
3158
|
+
if (!row) return;
|
|
3159
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3160
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
3161
|
+
const agentId = String(row.agent_id);
|
|
3162
|
+
const projectName = String(row.project_name);
|
|
3163
|
+
if (contentHash) {
|
|
3164
|
+
await client.execute({
|
|
3165
|
+
sql: `UPDATE memories
|
|
3166
|
+
SET status = 'deleted',
|
|
3167
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3168
|
+
WHERE id != ?
|
|
3169
|
+
AND content_hash = ?
|
|
3170
|
+
AND agent_id = ?
|
|
3171
|
+
AND project_name = ?
|
|
3172
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3173
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3174
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
3175
|
+
});
|
|
3176
|
+
}
|
|
3177
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3178
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3179
|
+
const old = await client.execute({
|
|
3180
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3181
|
+
args: [supersedesId]
|
|
3182
|
+
});
|
|
3183
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3184
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3185
|
+
await client.batch([
|
|
3186
|
+
{
|
|
3187
|
+
sql: `UPDATE memories
|
|
3188
|
+
SET status = 'archived',
|
|
3189
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3190
|
+
WHERE id = ?`,
|
|
3191
|
+
args: [supersedesId]
|
|
3192
|
+
},
|
|
3193
|
+
{
|
|
3194
|
+
sql: `UPDATE memories
|
|
3195
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3196
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3197
|
+
WHERE id = ?`,
|
|
3198
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3199
|
+
}
|
|
3200
|
+
], "write");
|
|
3201
|
+
}
|
|
3202
|
+
} catch (err) {
|
|
3203
|
+
process.stderr.write(
|
|
3204
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3205
|
+
`
|
|
3206
|
+
);
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3210
|
+
if (memoryIds.length === 0) return;
|
|
3211
|
+
const run = () => {
|
|
3212
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3213
|
+
};
|
|
3214
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3215
|
+
else setTimeout(run, 0);
|
|
3216
|
+
}
|
|
3217
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
3218
|
+
var init_memory_write_governor = __esm({
|
|
3219
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3220
|
+
"use strict";
|
|
3221
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3222
|
+
"decision",
|
|
3223
|
+
"adr",
|
|
3224
|
+
"behavior",
|
|
3225
|
+
"procedure"
|
|
3226
|
+
]);
|
|
3227
|
+
NOISE_DROP_PATTERNS = [
|
|
3228
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3229
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3230
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3231
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3232
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3233
|
+
];
|
|
3234
|
+
SKIP_EMBED_PATTERNS = [
|
|
3235
|
+
/tmux capture-pane\b/i,
|
|
3236
|
+
/docker ps\b/i,
|
|
3237
|
+
/docker images\b/i,
|
|
3238
|
+
/git status\b/i,
|
|
3239
|
+
/grep .*node_modules/i,
|
|
3240
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3241
|
+
];
|
|
3242
|
+
}
|
|
3243
|
+
});
|
|
3244
|
+
|
|
3031
3245
|
// src/lib/shard-manager.ts
|
|
3032
3246
|
var shard_manager_exports = {};
|
|
3033
3247
|
__export(shard_manager_exports, {
|
|
@@ -3192,7 +3406,8 @@ async function ensureShardSchema(client) {
|
|
|
3192
3406
|
}
|
|
3193
3407
|
for (const idx of [
|
|
3194
3408
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
3195
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
3409
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
3410
|
+
"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"
|
|
3196
3411
|
]) {
|
|
3197
3412
|
try {
|
|
3198
3413
|
await client.execute(idx);
|
|
@@ -3617,7 +3832,6 @@ __export(store_exports, {
|
|
|
3617
3832
|
vectorToBlob: () => vectorToBlob,
|
|
3618
3833
|
writeMemory: () => writeMemory
|
|
3619
3834
|
});
|
|
3620
|
-
import { createHash } from "crypto";
|
|
3621
3835
|
function isBusyError2(err) {
|
|
3622
3836
|
if (err instanceof Error) {
|
|
3623
3837
|
const msg = err.message.toLowerCase();
|
|
@@ -3731,17 +3945,24 @@ async function writeMemory(record) {
|
|
|
3731
3945
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
3732
3946
|
);
|
|
3733
3947
|
}
|
|
3734
|
-
const
|
|
3735
|
-
if (
|
|
3948
|
+
const governed = governMemoryRecord(record);
|
|
3949
|
+
if (governed.shouldDrop) return;
|
|
3950
|
+
record = governed.record;
|
|
3951
|
+
const contentHash = governed.contentHash;
|
|
3952
|
+
const memoryType = record.memory_type ?? "raw";
|
|
3953
|
+
if (_pendingRecords.some(
|
|
3954
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
3955
|
+
)) {
|
|
3736
3956
|
return;
|
|
3737
3957
|
}
|
|
3738
3958
|
try {
|
|
3739
|
-
const
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3959
|
+
const existing = await findScopedDuplicate({
|
|
3960
|
+
contentHash,
|
|
3961
|
+
agentId: record.agent_id,
|
|
3962
|
+
projectName: record.project_name,
|
|
3963
|
+
memoryType
|
|
3743
3964
|
});
|
|
3744
|
-
if (existing
|
|
3965
|
+
if (existing) return;
|
|
3745
3966
|
} catch {
|
|
3746
3967
|
}
|
|
3747
3968
|
const dbRow = {
|
|
@@ -3772,7 +3993,7 @@ async function writeMemory(record) {
|
|
|
3772
3993
|
tier: record.tier ?? classifyTier(record),
|
|
3773
3994
|
supersedes_id: record.supersedes_id ?? null,
|
|
3774
3995
|
draft: record.draft ? 1 : 0,
|
|
3775
|
-
memory_type:
|
|
3996
|
+
memory_type: memoryType,
|
|
3776
3997
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
3777
3998
|
content_hash: contentHash,
|
|
3778
3999
|
intent: record.intent ?? null,
|
|
@@ -3931,6 +4152,7 @@ async function flushBatch() {
|
|
|
3931
4152
|
const globalClient = getClient();
|
|
3932
4153
|
const globalStmts = batch.map(buildStmt);
|
|
3933
4154
|
await globalClient.batch(globalStmts, "write");
|
|
4155
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
3934
4156
|
_pendingRecords.splice(0, batch.length);
|
|
3935
4157
|
try {
|
|
3936
4158
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4189,6 +4411,7 @@ var init_store = __esm({
|
|
|
4189
4411
|
init_keychain();
|
|
4190
4412
|
init_config();
|
|
4191
4413
|
init_state_bus();
|
|
4414
|
+
init_memory_write_governor();
|
|
4192
4415
|
INIT_MAX_RETRIES = 3;
|
|
4193
4416
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
4194
4417
|
_pendingRecords = [];
|