@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.
- package/dist/bin/backfill-conversations.js +210 -10
- package/dist/bin/backfill-responses.js +210 -10
- package/dist/bin/backfill-vectors.js +13 -2
- package/dist/bin/cleanup-stale-review-tasks.js +217 -10
- package/dist/bin/cli.js +222 -11
- package/dist/bin/exe-assign.js +210 -10
- package/dist/bin/exe-boot.js +24 -3
- package/dist/bin/exe-dispatch.js +222 -11
- package/dist/bin/exe-doctor.js +13 -2
- package/dist/bin/exe-export-behaviors.js +217 -10
- package/dist/bin/exe-forget.js +217 -10
- package/dist/bin/exe-gateway.js +222 -11
- package/dist/bin/exe-heartbeat.js +217 -10
- package/dist/bin/exe-kill.js +217 -10
- package/dist/bin/exe-launch-agent.js +92 -2
- package/dist/bin/exe-link.js +8 -0
- package/dist/bin/exe-pending-messages.js +217 -10
- package/dist/bin/exe-pending-notifications.js +217 -10
- package/dist/bin/exe-pending-reviews.js +217 -10
- package/dist/bin/exe-rename.js +8 -0
- package/dist/bin/exe-review.js +217 -10
- package/dist/bin/exe-search.js +217 -10
- package/dist/bin/exe-session-cleanup.js +222 -11
- package/dist/bin/exe-start-codex.js +92 -2
- package/dist/bin/exe-start-opencode.js +92 -2
- package/dist/bin/exe-status.js +217 -10
- package/dist/bin/exe-team.js +217 -10
- package/dist/bin/git-sweep.js +222 -11
- package/dist/bin/graph-backfill.js +92 -2
- package/dist/bin/graph-export.js +217 -10
- package/dist/bin/intercom-check.js +222 -11
- package/dist/bin/scan-tasks.js +222 -11
- package/dist/bin/setup.js +8 -0
- package/dist/bin/shard-migrate.js +92 -2
- package/dist/gateway/index.js +222 -11
- package/dist/hooks/bug-report-worker.js +222 -11
- package/dist/hooks/codex-stop-task-finalizer.js +217 -10
- package/dist/hooks/commit-complete.js +222 -11
- package/dist/hooks/error-recall.js +217 -10
- package/dist/hooks/ingest.js +217 -10
- package/dist/hooks/instructions-loaded.js +217 -10
- package/dist/hooks/notification.js +217 -10
- package/dist/hooks/post-compact.js +217 -10
- package/dist/hooks/post-tool-combined.js +217 -10
- package/dist/hooks/pre-compact.js +222 -11
- package/dist/hooks/pre-tool-use.js +217 -10
- package/dist/hooks/prompt-submit.js +222 -11
- package/dist/hooks/session-end.js +222 -11
- package/dist/hooks/session-start.js +217 -10
- package/dist/hooks/stop.js +217 -10
- package/dist/hooks/subagent-stop.js +217 -10
- package/dist/hooks/summary-worker.js +14 -1
- package/dist/index.js +222 -11
- package/dist/lib/cloud-sync.js +8 -0
- package/dist/lib/consolidation.js +3 -1
- package/dist/lib/database.js +8 -0
- package/dist/lib/db.js +8 -0
- package/dist/lib/device-registry.js +8 -0
- package/dist/lib/exe-daemon.js +1667 -1413
- package/dist/lib/hybrid-search.js +217 -10
- package/dist/lib/schedules.js +13 -2
- package/dist/lib/store.js +210 -10
- package/dist/lib/tasks.js +5 -1
- package/dist/lib/tmux-routing.js +5 -1
- package/dist/mcp/server.js +222 -11
- package/dist/mcp/tools/create-task.js +5 -1
- package/dist/mcp/tools/update-task.js +5 -1
- package/dist/runtime/index.js +222 -11
- package/dist/tui/App.js +222 -11
- package/package.json +1 -1
|
@@ -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);
|
|
@@ -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,87 @@ 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 (memoryIds.length === 0) return;
|
|
3470
|
+
const run = () => {
|
|
3471
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3472
|
+
};
|
|
3473
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3474
|
+
else setTimeout(run, 0);
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3388
3477
|
// src/lib/store.ts
|
|
3389
3478
|
var INIT_MAX_RETRIES = 3;
|
|
3390
3479
|
var INIT_RETRY_DELAY_MS = 1e3;
|
|
@@ -3584,6 +3673,7 @@ async function flushBatch() {
|
|
|
3584
3673
|
const globalClient = getClient();
|
|
3585
3674
|
const globalStmts = batch.map(buildStmt);
|
|
3586
3675
|
await globalClient.batch(globalStmts, "write");
|
|
3676
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
3587
3677
|
_pendingRecords.splice(0, batch.length);
|
|
3588
3678
|
try {
|
|
3589
3679
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
package/dist/bin/graph-export.js
CHANGED
|
@@ -2288,6 +2288,14 @@ async function ensureSchema() {
|
|
|
2288
2288
|
);
|
|
2289
2289
|
} catch {
|
|
2290
2290
|
}
|
|
2291
|
+
try {
|
|
2292
|
+
await client.execute(
|
|
2293
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2294
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2295
|
+
WHERE content_hash IS NOT NULL`
|
|
2296
|
+
);
|
|
2297
|
+
} catch {
|
|
2298
|
+
}
|
|
2291
2299
|
await client.executeMultiple(`
|
|
2292
2300
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2293
2301
|
id TEXT PRIMARY KEY,
|
|
@@ -3033,6 +3041,196 @@ var init_state_bus = __esm({
|
|
|
3033
3041
|
}
|
|
3034
3042
|
});
|
|
3035
3043
|
|
|
3044
|
+
// src/lib/memory-write-governor.ts
|
|
3045
|
+
import { createHash } from "crypto";
|
|
3046
|
+
function normalizeMemoryText(text) {
|
|
3047
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3048
|
+
}
|
|
3049
|
+
function classifyMemoryType(input) {
|
|
3050
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
3051
|
+
const tool = input.tool_name.toLowerCase();
|
|
3052
|
+
const text = input.raw_text.toLowerCase();
|
|
3053
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3054
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3055
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3056
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3057
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3058
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3059
|
+
return "raw";
|
|
3060
|
+
}
|
|
3061
|
+
function shouldDropMemory(text) {
|
|
3062
|
+
const normalized = normalizeMemoryText(text);
|
|
3063
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3064
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3065
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3066
|
+
}
|
|
3067
|
+
return { drop: false };
|
|
3068
|
+
}
|
|
3069
|
+
function shouldSkipEmbedding(input) {
|
|
3070
|
+
const type = classifyMemoryType(input);
|
|
3071
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3072
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
3073
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
3074
|
+
return false;
|
|
3075
|
+
}
|
|
3076
|
+
function hashMemoryContent(text) {
|
|
3077
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3078
|
+
}
|
|
3079
|
+
function scopedDedupArgs(input) {
|
|
3080
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
3081
|
+
}
|
|
3082
|
+
function governMemoryRecord(record) {
|
|
3083
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3084
|
+
const memoryType = classifyMemoryType({
|
|
3085
|
+
raw_text: normalized,
|
|
3086
|
+
agent_id: record.agent_id,
|
|
3087
|
+
project_name: record.project_name,
|
|
3088
|
+
tool_name: record.tool_name,
|
|
3089
|
+
memory_type: record.memory_type
|
|
3090
|
+
});
|
|
3091
|
+
const drop = shouldDropMemory(normalized);
|
|
3092
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3093
|
+
raw_text: normalized,
|
|
3094
|
+
agent_id: record.agent_id,
|
|
3095
|
+
project_name: record.project_name,
|
|
3096
|
+
tool_name: record.tool_name,
|
|
3097
|
+
memory_type: memoryType
|
|
3098
|
+
});
|
|
3099
|
+
return {
|
|
3100
|
+
record: {
|
|
3101
|
+
...record,
|
|
3102
|
+
raw_text: normalized,
|
|
3103
|
+
memory_type: memoryType,
|
|
3104
|
+
vector: skipEmbedding ? null : record.vector
|
|
3105
|
+
},
|
|
3106
|
+
contentHash: hashMemoryContent(normalized),
|
|
3107
|
+
shouldDrop: drop.drop,
|
|
3108
|
+
dropReason: drop.reason,
|
|
3109
|
+
skipEmbedding,
|
|
3110
|
+
hygiene: {
|
|
3111
|
+
dedup: true,
|
|
3112
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3113
|
+
}
|
|
3114
|
+
};
|
|
3115
|
+
}
|
|
3116
|
+
async function findScopedDuplicate(input) {
|
|
3117
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3118
|
+
const client = getClient2();
|
|
3119
|
+
const args = scopedDedupArgs(input);
|
|
3120
|
+
let sql = `SELECT id FROM memories
|
|
3121
|
+
WHERE content_hash = ?
|
|
3122
|
+
AND agent_id = ?
|
|
3123
|
+
AND project_name = ?
|
|
3124
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3125
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3126
|
+
if (input.excludeId) {
|
|
3127
|
+
sql += " AND id != ?";
|
|
3128
|
+
args.push(input.excludeId);
|
|
3129
|
+
}
|
|
3130
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3131
|
+
const result = await client.execute({ sql, args });
|
|
3132
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3133
|
+
}
|
|
3134
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3135
|
+
try {
|
|
3136
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3137
|
+
const client = getClient2();
|
|
3138
|
+
const current = await client.execute({
|
|
3139
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3140
|
+
importance, timestamp
|
|
3141
|
+
FROM memories
|
|
3142
|
+
WHERE id = ?
|
|
3143
|
+
LIMIT 1`,
|
|
3144
|
+
args: [memoryId]
|
|
3145
|
+
});
|
|
3146
|
+
const row = current.rows[0];
|
|
3147
|
+
if (!row) return;
|
|
3148
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3149
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
3150
|
+
const agentId = String(row.agent_id);
|
|
3151
|
+
const projectName = String(row.project_name);
|
|
3152
|
+
if (contentHash) {
|
|
3153
|
+
await client.execute({
|
|
3154
|
+
sql: `UPDATE memories
|
|
3155
|
+
SET status = 'deleted',
|
|
3156
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3157
|
+
WHERE id != ?
|
|
3158
|
+
AND content_hash = ?
|
|
3159
|
+
AND agent_id = ?
|
|
3160
|
+
AND project_name = ?
|
|
3161
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3162
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3163
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
3164
|
+
});
|
|
3165
|
+
}
|
|
3166
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3167
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3168
|
+
const old = await client.execute({
|
|
3169
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3170
|
+
args: [supersedesId]
|
|
3171
|
+
});
|
|
3172
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3173
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3174
|
+
await client.batch([
|
|
3175
|
+
{
|
|
3176
|
+
sql: `UPDATE memories
|
|
3177
|
+
SET status = 'archived',
|
|
3178
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3179
|
+
WHERE id = ?`,
|
|
3180
|
+
args: [supersedesId]
|
|
3181
|
+
},
|
|
3182
|
+
{
|
|
3183
|
+
sql: `UPDATE memories
|
|
3184
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3185
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3186
|
+
WHERE id = ?`,
|
|
3187
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3188
|
+
}
|
|
3189
|
+
], "write");
|
|
3190
|
+
}
|
|
3191
|
+
} catch (err) {
|
|
3192
|
+
process.stderr.write(
|
|
3193
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3194
|
+
`
|
|
3195
|
+
);
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3199
|
+
if (memoryIds.length === 0) return;
|
|
3200
|
+
const run = () => {
|
|
3201
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3202
|
+
};
|
|
3203
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3204
|
+
else setTimeout(run, 0);
|
|
3205
|
+
}
|
|
3206
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
3207
|
+
var init_memory_write_governor = __esm({
|
|
3208
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3209
|
+
"use strict";
|
|
3210
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3211
|
+
"decision",
|
|
3212
|
+
"adr",
|
|
3213
|
+
"behavior",
|
|
3214
|
+
"procedure"
|
|
3215
|
+
]);
|
|
3216
|
+
NOISE_DROP_PATTERNS = [
|
|
3217
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3218
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3219
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3220
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3221
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3222
|
+
];
|
|
3223
|
+
SKIP_EMBED_PATTERNS = [
|
|
3224
|
+
/tmux capture-pane\b/i,
|
|
3225
|
+
/docker ps\b/i,
|
|
3226
|
+
/docker images\b/i,
|
|
3227
|
+
/git status\b/i,
|
|
3228
|
+
/grep .*node_modules/i,
|
|
3229
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3230
|
+
];
|
|
3231
|
+
}
|
|
3232
|
+
});
|
|
3233
|
+
|
|
3036
3234
|
// src/lib/shard-manager.ts
|
|
3037
3235
|
var shard_manager_exports = {};
|
|
3038
3236
|
__export(shard_manager_exports, {
|
|
@@ -3197,7 +3395,8 @@ async function ensureShardSchema(client) {
|
|
|
3197
3395
|
}
|
|
3198
3396
|
for (const idx of [
|
|
3199
3397
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
3200
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
3398
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
3399
|
+
"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"
|
|
3201
3400
|
]) {
|
|
3202
3401
|
try {
|
|
3203
3402
|
await client.execute(idx);
|
|
@@ -3622,7 +3821,6 @@ __export(store_exports, {
|
|
|
3622
3821
|
vectorToBlob: () => vectorToBlob,
|
|
3623
3822
|
writeMemory: () => writeMemory
|
|
3624
3823
|
});
|
|
3625
|
-
import { createHash } from "crypto";
|
|
3626
3824
|
function isBusyError2(err) {
|
|
3627
3825
|
if (err instanceof Error) {
|
|
3628
3826
|
const msg = err.message.toLowerCase();
|
|
@@ -3736,17 +3934,24 @@ async function writeMemory(record) {
|
|
|
3736
3934
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
3737
3935
|
);
|
|
3738
3936
|
}
|
|
3739
|
-
const
|
|
3740
|
-
if (
|
|
3937
|
+
const governed = governMemoryRecord(record);
|
|
3938
|
+
if (governed.shouldDrop) return;
|
|
3939
|
+
record = governed.record;
|
|
3940
|
+
const contentHash = governed.contentHash;
|
|
3941
|
+
const memoryType = record.memory_type ?? "raw";
|
|
3942
|
+
if (_pendingRecords.some(
|
|
3943
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
3944
|
+
)) {
|
|
3741
3945
|
return;
|
|
3742
3946
|
}
|
|
3743
3947
|
try {
|
|
3744
|
-
const
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3948
|
+
const existing = await findScopedDuplicate({
|
|
3949
|
+
contentHash,
|
|
3950
|
+
agentId: record.agent_id,
|
|
3951
|
+
projectName: record.project_name,
|
|
3952
|
+
memoryType
|
|
3748
3953
|
});
|
|
3749
|
-
if (existing
|
|
3954
|
+
if (existing) return;
|
|
3750
3955
|
} catch {
|
|
3751
3956
|
}
|
|
3752
3957
|
const dbRow = {
|
|
@@ -3777,7 +3982,7 @@ async function writeMemory(record) {
|
|
|
3777
3982
|
tier: record.tier ?? classifyTier(record),
|
|
3778
3983
|
supersedes_id: record.supersedes_id ?? null,
|
|
3779
3984
|
draft: record.draft ? 1 : 0,
|
|
3780
|
-
memory_type:
|
|
3985
|
+
memory_type: memoryType,
|
|
3781
3986
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
3782
3987
|
content_hash: contentHash,
|
|
3783
3988
|
intent: record.intent ?? null,
|
|
@@ -3936,6 +4141,7 @@ async function flushBatch() {
|
|
|
3936
4141
|
const globalClient = getClient();
|
|
3937
4142
|
const globalStmts = batch.map(buildStmt);
|
|
3938
4143
|
await globalClient.batch(globalStmts, "write");
|
|
4144
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
3939
4145
|
_pendingRecords.splice(0, batch.length);
|
|
3940
4146
|
try {
|
|
3941
4147
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4194,6 +4400,7 @@ var init_store = __esm({
|
|
|
4194
4400
|
init_keychain();
|
|
4195
4401
|
init_config();
|
|
4196
4402
|
init_state_bus();
|
|
4403
|
+
init_memory_write_governor();
|
|
4197
4404
|
INIT_MAX_RETRIES = 3;
|
|
4198
4405
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
4199
4406
|
_pendingRecords = [];
|