@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.
- package/dist/bin/backfill-conversations.js +212 -11
- package/dist/bin/backfill-responses.js +212 -11
- package/dist/bin/backfill-vectors.js +14 -3
- package/dist/bin/cleanup-stale-review-tasks.js +224 -12
- package/dist/bin/cli.js +265 -23
- package/dist/bin/exe-agent.js +1 -1
- package/dist/bin/exe-assign.js +217 -12
- package/dist/bin/exe-boot.js +25 -4
- package/dist/bin/exe-call.js +7 -5
- package/dist/bin/exe-dispatch.js +229 -13
- package/dist/bin/exe-doctor.js +14 -3
- package/dist/bin/exe-export-behaviors.js +301 -14
- package/dist/bin/exe-forget.js +245 -21
- package/dist/bin/exe-gateway.js +229 -13
- package/dist/bin/exe-heartbeat.js +224 -12
- package/dist/bin/exe-kill.js +224 -12
- package/dist/bin/exe-launch-agent.js +177 -9
- package/dist/bin/exe-link.js +8 -0
- package/dist/bin/exe-new-employee.js +26 -2
- package/dist/bin/exe-pending-messages.js +224 -12
- package/dist/bin/exe-pending-notifications.js +224 -12
- package/dist/bin/exe-pending-reviews.js +224 -12
- package/dist/bin/exe-rename.js +9 -1
- package/dist/bin/exe-review.js +224 -12
- package/dist/bin/exe-search.js +246 -21
- package/dist/bin/exe-session-cleanup.js +229 -13
- package/dist/bin/exe-start-codex.js +161 -5
- package/dist/bin/exe-start-opencode.js +172 -5
- package/dist/bin/exe-status.js +224 -12
- package/dist/bin/exe-team.js +224 -12
- package/dist/bin/git-sweep.js +229 -13
- package/dist/bin/graph-backfill.js +94 -3
- package/dist/bin/graph-export.js +224 -12
- package/dist/bin/install.js +25 -1
- package/dist/bin/intercom-check.js +229 -13
- package/dist/bin/scan-tasks.js +229 -13
- package/dist/bin/setup.js +15 -5
- package/dist/bin/shard-migrate.js +94 -3
- package/dist/gateway/index.js +229 -13
- package/dist/hooks/bug-report-worker.js +229 -13
- package/dist/hooks/codex-stop-task-finalizer.js +224 -12
- package/dist/hooks/commit-complete.js +229 -13
- package/dist/hooks/error-recall.js +246 -21
- package/dist/hooks/ingest.js +224 -12
- package/dist/hooks/instructions-loaded.js +224 -12
- package/dist/hooks/notification.js +224 -12
- package/dist/hooks/post-compact.js +224 -12
- package/dist/hooks/post-tool-combined.js +246 -21
- package/dist/hooks/pre-compact.js +229 -13
- package/dist/hooks/pre-tool-use.js +234 -18
- package/dist/hooks/prompt-submit.js +346 -23
- package/dist/hooks/session-end.js +229 -13
- package/dist/hooks/session-start.js +418 -42
- package/dist/hooks/stop.js +224 -12
- package/dist/hooks/subagent-stop.js +224 -12
- package/dist/hooks/summary-worker.js +15 -2
- package/dist/index.js +229 -13
- 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/employee-templates.js +7 -5
- package/dist/lib/exe-daemon.js +1776 -1433
- package/dist/lib/hybrid-search.js +246 -21
- package/dist/lib/schedules.js +14 -3
- package/dist/lib/store.js +217 -12
- package/dist/lib/tasks.js +5 -1
- package/dist/lib/tmux-routing.js +5 -1
- package/dist/mcp/server.js +331 -37
- package/dist/mcp/tools/create-task.js +5 -1
- package/dist/mcp/tools/update-task.js +5 -1
- package/dist/runtime/index.js +229 -13
- package/dist/tui/App.js +229 -13
- package/package.json +1 -1
- package/src/commands/exe/save.md +48 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
6
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
7
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
8
|
}) : x)(function(x) {
|
|
@@ -14,6 +16,15 @@ var __export = (target, all) => {
|
|
|
14
16
|
for (var name in all)
|
|
15
17
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
18
|
};
|
|
19
|
+
var __copyProps = (to, from, except, desc) => {
|
|
20
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
21
|
+
for (let key of __getOwnPropNames(from))
|
|
22
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
23
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
24
|
+
}
|
|
25
|
+
return to;
|
|
26
|
+
};
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
17
28
|
|
|
18
29
|
// src/types/memory.ts
|
|
19
30
|
var EMBEDDING_DIM;
|
|
@@ -118,6 +129,21 @@ var init_secure_files = __esm({
|
|
|
118
129
|
});
|
|
119
130
|
|
|
120
131
|
// src/lib/config.ts
|
|
132
|
+
var config_exports = {};
|
|
133
|
+
__export(config_exports, {
|
|
134
|
+
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
135
|
+
CONFIG_PATH: () => CONFIG_PATH,
|
|
136
|
+
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
137
|
+
DB_PATH: () => DB_PATH,
|
|
138
|
+
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
139
|
+
LEGACY_LANCE_PATH: () => LEGACY_LANCE_PATH,
|
|
140
|
+
MODELS_DIR: () => MODELS_DIR,
|
|
141
|
+
loadConfig: () => loadConfig,
|
|
142
|
+
loadConfigFrom: () => loadConfigFrom,
|
|
143
|
+
loadConfigSync: () => loadConfigSync,
|
|
144
|
+
migrateConfig: () => migrateConfig,
|
|
145
|
+
saveConfig: () => saveConfig
|
|
146
|
+
});
|
|
121
147
|
import { readFile, writeFile } from "fs/promises";
|
|
122
148
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
123
149
|
import path from "path";
|
|
@@ -221,6 +247,46 @@ async function loadConfig() {
|
|
|
221
247
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
222
248
|
}
|
|
223
249
|
}
|
|
250
|
+
function loadConfigSync() {
|
|
251
|
+
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
252
|
+
const configPath = path.join(dir, "config.json");
|
|
253
|
+
if (!existsSync2(configPath)) {
|
|
254
|
+
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
255
|
+
}
|
|
256
|
+
try {
|
|
257
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
258
|
+
let parsed = JSON.parse(raw);
|
|
259
|
+
parsed = migrateLegacyConfig(parsed);
|
|
260
|
+
const { config: migratedCfg } = migrateConfig(parsed);
|
|
261
|
+
normalizeScalingRoadmap(migratedCfg);
|
|
262
|
+
normalizeSessionLifecycle(migratedCfg);
|
|
263
|
+
normalizeAutoUpdate(migratedCfg);
|
|
264
|
+
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
265
|
+
} catch {
|
|
266
|
+
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async function saveConfig(config) {
|
|
270
|
+
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
271
|
+
await ensurePrivateDir(dir);
|
|
272
|
+
const configPath = path.join(dir, "config.json");
|
|
273
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
274
|
+
await enforcePrivateFile(configPath);
|
|
275
|
+
}
|
|
276
|
+
async function loadConfigFrom(configPath) {
|
|
277
|
+
const raw = await readFile(configPath, "utf-8");
|
|
278
|
+
try {
|
|
279
|
+
let parsed = JSON.parse(raw);
|
|
280
|
+
parsed = migrateLegacyConfig(parsed);
|
|
281
|
+
const { config: migratedCfg } = migrateConfig(parsed);
|
|
282
|
+
normalizeScalingRoadmap(migratedCfg);
|
|
283
|
+
normalizeSessionLifecycle(migratedCfg);
|
|
284
|
+
normalizeAutoUpdate(migratedCfg);
|
|
285
|
+
return { ...DEFAULT_CONFIG, ...migratedCfg };
|
|
286
|
+
} catch {
|
|
287
|
+
return { ...DEFAULT_CONFIG };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
224
290
|
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
225
291
|
var init_config = __esm({
|
|
226
292
|
"src/lib/config.ts"() {
|
|
@@ -2288,6 +2354,14 @@ async function ensureSchema() {
|
|
|
2288
2354
|
);
|
|
2289
2355
|
} catch {
|
|
2290
2356
|
}
|
|
2357
|
+
try {
|
|
2358
|
+
await client.execute(
|
|
2359
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2360
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2361
|
+
WHERE content_hash IS NOT NULL`
|
|
2362
|
+
);
|
|
2363
|
+
} catch {
|
|
2364
|
+
}
|
|
2291
2365
|
await client.executeMultiple(`
|
|
2292
2366
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2293
2367
|
id TEXT PRIMARY KEY,
|
|
@@ -3033,6 +3107,197 @@ var init_state_bus = __esm({
|
|
|
3033
3107
|
}
|
|
3034
3108
|
});
|
|
3035
3109
|
|
|
3110
|
+
// src/lib/memory-write-governor.ts
|
|
3111
|
+
import { createHash } from "crypto";
|
|
3112
|
+
function normalizeMemoryText(text) {
|
|
3113
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3114
|
+
}
|
|
3115
|
+
function classifyMemoryType(input) {
|
|
3116
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
3117
|
+
const tool = input.tool_name.toLowerCase();
|
|
3118
|
+
const text = input.raw_text.toLowerCase();
|
|
3119
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3120
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3121
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3122
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3123
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3124
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3125
|
+
return "raw";
|
|
3126
|
+
}
|
|
3127
|
+
function shouldDropMemory(text) {
|
|
3128
|
+
const normalized = normalizeMemoryText(text);
|
|
3129
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3130
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3131
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3132
|
+
}
|
|
3133
|
+
return { drop: false };
|
|
3134
|
+
}
|
|
3135
|
+
function shouldSkipEmbedding(input) {
|
|
3136
|
+
const type = classifyMemoryType(input);
|
|
3137
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3138
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
3139
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
3140
|
+
return false;
|
|
3141
|
+
}
|
|
3142
|
+
function hashMemoryContent(text) {
|
|
3143
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3144
|
+
}
|
|
3145
|
+
function scopedDedupArgs(input) {
|
|
3146
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
3147
|
+
}
|
|
3148
|
+
function governMemoryRecord(record) {
|
|
3149
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3150
|
+
const memoryType = classifyMemoryType({
|
|
3151
|
+
raw_text: normalized,
|
|
3152
|
+
agent_id: record.agent_id,
|
|
3153
|
+
project_name: record.project_name,
|
|
3154
|
+
tool_name: record.tool_name,
|
|
3155
|
+
memory_type: record.memory_type
|
|
3156
|
+
});
|
|
3157
|
+
const drop = shouldDropMemory(normalized);
|
|
3158
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3159
|
+
raw_text: normalized,
|
|
3160
|
+
agent_id: record.agent_id,
|
|
3161
|
+
project_name: record.project_name,
|
|
3162
|
+
tool_name: record.tool_name,
|
|
3163
|
+
memory_type: memoryType
|
|
3164
|
+
});
|
|
3165
|
+
return {
|
|
3166
|
+
record: {
|
|
3167
|
+
...record,
|
|
3168
|
+
raw_text: normalized,
|
|
3169
|
+
memory_type: memoryType,
|
|
3170
|
+
vector: skipEmbedding ? null : record.vector
|
|
3171
|
+
},
|
|
3172
|
+
contentHash: hashMemoryContent(normalized),
|
|
3173
|
+
shouldDrop: drop.drop,
|
|
3174
|
+
dropReason: drop.reason,
|
|
3175
|
+
skipEmbedding,
|
|
3176
|
+
hygiene: {
|
|
3177
|
+
dedup: true,
|
|
3178
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3179
|
+
}
|
|
3180
|
+
};
|
|
3181
|
+
}
|
|
3182
|
+
async function findScopedDuplicate(input) {
|
|
3183
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3184
|
+
const client = getClient2();
|
|
3185
|
+
const args = scopedDedupArgs(input);
|
|
3186
|
+
let sql = `SELECT id FROM memories
|
|
3187
|
+
WHERE content_hash = ?
|
|
3188
|
+
AND agent_id = ?
|
|
3189
|
+
AND project_name = ?
|
|
3190
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3191
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3192
|
+
if (input.excludeId) {
|
|
3193
|
+
sql += " AND id != ?";
|
|
3194
|
+
args.push(input.excludeId);
|
|
3195
|
+
}
|
|
3196
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3197
|
+
const result = await client.execute({ sql, args });
|
|
3198
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3199
|
+
}
|
|
3200
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3201
|
+
try {
|
|
3202
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3203
|
+
const client = getClient2();
|
|
3204
|
+
const current = await client.execute({
|
|
3205
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3206
|
+
importance, timestamp
|
|
3207
|
+
FROM memories
|
|
3208
|
+
WHERE id = ?
|
|
3209
|
+
LIMIT 1`,
|
|
3210
|
+
args: [memoryId]
|
|
3211
|
+
});
|
|
3212
|
+
const row = current.rows[0];
|
|
3213
|
+
if (!row) return;
|
|
3214
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3215
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
3216
|
+
const agentId2 = String(row.agent_id);
|
|
3217
|
+
const projectName2 = String(row.project_name);
|
|
3218
|
+
if (contentHash) {
|
|
3219
|
+
await client.execute({
|
|
3220
|
+
sql: `UPDATE memories
|
|
3221
|
+
SET status = 'deleted',
|
|
3222
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3223
|
+
WHERE id != ?
|
|
3224
|
+
AND content_hash = ?
|
|
3225
|
+
AND agent_id = ?
|
|
3226
|
+
AND project_name = ?
|
|
3227
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3228
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3229
|
+
args: [memoryId, contentHash, agentId2, projectName2, memoryType]
|
|
3230
|
+
});
|
|
3231
|
+
}
|
|
3232
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3233
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3234
|
+
const old = await client.execute({
|
|
3235
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3236
|
+
args: [supersedesId]
|
|
3237
|
+
});
|
|
3238
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3239
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3240
|
+
await client.batch([
|
|
3241
|
+
{
|
|
3242
|
+
sql: `UPDATE memories
|
|
3243
|
+
SET status = 'archived',
|
|
3244
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3245
|
+
WHERE id = ?`,
|
|
3246
|
+
args: [supersedesId]
|
|
3247
|
+
},
|
|
3248
|
+
{
|
|
3249
|
+
sql: `UPDATE memories
|
|
3250
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3251
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3252
|
+
WHERE id = ?`,
|
|
3253
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3254
|
+
}
|
|
3255
|
+
], "write");
|
|
3256
|
+
}
|
|
3257
|
+
} catch (err) {
|
|
3258
|
+
process.stderr.write(
|
|
3259
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3260
|
+
`
|
|
3261
|
+
);
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3265
|
+
if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
3266
|
+
if (memoryIds.length === 0) return;
|
|
3267
|
+
const run = () => {
|
|
3268
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3269
|
+
};
|
|
3270
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3271
|
+
else setTimeout(run, 0);
|
|
3272
|
+
}
|
|
3273
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
3274
|
+
var init_memory_write_governor = __esm({
|
|
3275
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3276
|
+
"use strict";
|
|
3277
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3278
|
+
"decision",
|
|
3279
|
+
"adr",
|
|
3280
|
+
"behavior",
|
|
3281
|
+
"procedure"
|
|
3282
|
+
]);
|
|
3283
|
+
NOISE_DROP_PATTERNS = [
|
|
3284
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3285
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3286
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3287
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3288
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3289
|
+
];
|
|
3290
|
+
SKIP_EMBED_PATTERNS = [
|
|
3291
|
+
/tmux capture-pane\b/i,
|
|
3292
|
+
/docker ps\b/i,
|
|
3293
|
+
/docker images\b/i,
|
|
3294
|
+
/git status\b/i,
|
|
3295
|
+
/grep .*node_modules/i,
|
|
3296
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3297
|
+
];
|
|
3298
|
+
}
|
|
3299
|
+
});
|
|
3300
|
+
|
|
3036
3301
|
// src/lib/shard-manager.ts
|
|
3037
3302
|
var shard_manager_exports = {};
|
|
3038
3303
|
__export(shard_manager_exports, {
|
|
@@ -3197,7 +3462,8 @@ async function ensureShardSchema(client) {
|
|
|
3197
3462
|
}
|
|
3198
3463
|
for (const idx of [
|
|
3199
3464
|
"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"
|
|
3465
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
3466
|
+
"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
3467
|
]) {
|
|
3202
3468
|
try {
|
|
3203
3469
|
await client.execute(idx);
|
|
@@ -3391,7 +3657,7 @@ var init_platform_procedures = __esm({
|
|
|
3391
3657
|
title: "Chain of command \u2014 who talks to whom",
|
|
3392
3658
|
domain: "workflow",
|
|
3393
3659
|
priority: "p0",
|
|
3394
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
3660
|
+
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."
|
|
3395
3661
|
},
|
|
3396
3662
|
{
|
|
3397
3663
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -3622,7 +3888,6 @@ __export(store_exports, {
|
|
|
3622
3888
|
vectorToBlob: () => vectorToBlob,
|
|
3623
3889
|
writeMemory: () => writeMemory
|
|
3624
3890
|
});
|
|
3625
|
-
import { createHash } from "crypto";
|
|
3626
3891
|
function isBusyError2(err) {
|
|
3627
3892
|
if (err instanceof Error) {
|
|
3628
3893
|
const msg = err.message.toLowerCase();
|
|
@@ -3736,17 +4001,24 @@ async function writeMemory(record) {
|
|
|
3736
4001
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
3737
4002
|
);
|
|
3738
4003
|
}
|
|
3739
|
-
const
|
|
3740
|
-
if (
|
|
4004
|
+
const governed = governMemoryRecord(record);
|
|
4005
|
+
if (governed.shouldDrop) return;
|
|
4006
|
+
record = governed.record;
|
|
4007
|
+
const contentHash = governed.contentHash;
|
|
4008
|
+
const memoryType = record.memory_type ?? "raw";
|
|
4009
|
+
if (_pendingRecords.some(
|
|
4010
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
4011
|
+
)) {
|
|
3741
4012
|
return;
|
|
3742
4013
|
}
|
|
3743
4014
|
try {
|
|
3744
|
-
const
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
4015
|
+
const existing = await findScopedDuplicate({
|
|
4016
|
+
contentHash,
|
|
4017
|
+
agentId: record.agent_id,
|
|
4018
|
+
projectName: record.project_name,
|
|
4019
|
+
memoryType
|
|
3748
4020
|
});
|
|
3749
|
-
if (existing
|
|
4021
|
+
if (existing) return;
|
|
3750
4022
|
} catch {
|
|
3751
4023
|
}
|
|
3752
4024
|
const dbRow = {
|
|
@@ -3777,7 +4049,7 @@ async function writeMemory(record) {
|
|
|
3777
4049
|
tier: record.tier ?? classifyTier(record),
|
|
3778
4050
|
supersedes_id: record.supersedes_id ?? null,
|
|
3779
4051
|
draft: record.draft ? 1 : 0,
|
|
3780
|
-
memory_type:
|
|
4052
|
+
memory_type: memoryType,
|
|
3781
4053
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
3782
4054
|
content_hash: contentHash,
|
|
3783
4055
|
intent: record.intent ?? null,
|
|
@@ -3936,6 +4208,7 @@ async function flushBatch() {
|
|
|
3936
4208
|
const globalClient = getClient();
|
|
3937
4209
|
const globalStmts = batch.map(buildStmt);
|
|
3938
4210
|
await globalClient.batch(globalStmts, "write");
|
|
4211
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
3939
4212
|
_pendingRecords.splice(0, batch.length);
|
|
3940
4213
|
try {
|
|
3941
4214
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4056,7 +4329,11 @@ async function searchMemories(queryVector, agentId2, options) {
|
|
|
4056
4329
|
sql += ` AND timestamp >= ?`;
|
|
4057
4330
|
args.push(options.since);
|
|
4058
4331
|
}
|
|
4059
|
-
if (options?.
|
|
4332
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
4333
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
4334
|
+
sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
4335
|
+
args.push(...uniqueTypes);
|
|
4336
|
+
} else if (options?.memoryType) {
|
|
4060
4337
|
sql += ` AND memory_type = ?`;
|
|
4061
4338
|
args.push(options.memoryType);
|
|
4062
4339
|
}
|
|
@@ -4194,6 +4471,7 @@ var init_store = __esm({
|
|
|
4194
4471
|
init_keychain();
|
|
4195
4472
|
init_config();
|
|
4196
4473
|
init_state_bus();
|
|
4474
|
+
init_memory_write_governor();
|
|
4197
4475
|
INIT_MAX_RETRIES = 3;
|
|
4198
4476
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
4199
4477
|
_pendingRecords = [];
|
|
@@ -4322,7 +4600,16 @@ var BEHAVIORS_EXPORT_DIR = path8.join(
|
|
|
4322
4600
|
"behaviors-export"
|
|
4323
4601
|
);
|
|
4324
4602
|
var STALE_EXPORT_AGE_MS = 60 * 60 * 1e3;
|
|
4325
|
-
var
|
|
4603
|
+
var DEFAULT_BEHAVIOR_LIMIT = 30;
|
|
4604
|
+
function getBehaviorLimit() {
|
|
4605
|
+
try {
|
|
4606
|
+
const { loadConfigSync: loadConfigSync2 } = (init_config(), __toCommonJS(config_exports));
|
|
4607
|
+
const cfg = loadConfigSync2();
|
|
4608
|
+
return cfg.behaviorExportLimit ?? DEFAULT_BEHAVIOR_LIMIT;
|
|
4609
|
+
} catch {
|
|
4610
|
+
return DEFAULT_BEHAVIOR_LIMIT;
|
|
4611
|
+
}
|
|
4612
|
+
}
|
|
4326
4613
|
function sweepStaleBehaviorExports(now = Date.now()) {
|
|
4327
4614
|
if (!existsSync8(BEHAVIORS_EXPORT_DIR)) return;
|
|
4328
4615
|
let entries;
|
|
@@ -4376,7 +4663,7 @@ function exportFilePath(agentId2, projectName2, sessionKey2) {
|
|
|
4376
4663
|
async function exportBehaviorsForAgent(agentId2, projectName2, sessionKey2) {
|
|
4377
4664
|
mkdirSync3(BEHAVIORS_EXPORT_DIR, { recursive: true });
|
|
4378
4665
|
sweepStaleBehaviorExports();
|
|
4379
|
-
const behaviors = await listBehaviors(agentId2, projectName2,
|
|
4666
|
+
const behaviors = await listBehaviors(agentId2, projectName2, getBehaviorLimit());
|
|
4380
4667
|
if (behaviors.length === 0) return null;
|
|
4381
4668
|
const body = renderBehaviorExport(behaviors);
|
|
4382
4669
|
const target = exportFilePath(agentId2, projectName2, sessionKey2);
|