@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
|
@@ -2321,6 +2321,14 @@ async function ensureSchema() {
|
|
|
2321
2321
|
);
|
|
2322
2322
|
} catch {
|
|
2323
2323
|
}
|
|
2324
|
+
try {
|
|
2325
|
+
await client.execute(
|
|
2326
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2327
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2328
|
+
WHERE content_hash IS NOT NULL`
|
|
2329
|
+
);
|
|
2330
|
+
} catch {
|
|
2331
|
+
}
|
|
2324
2332
|
await client.executeMultiple(`
|
|
2325
2333
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2326
2334
|
id TEXT PRIMARY KEY,
|
|
@@ -3066,6 +3074,197 @@ var init_state_bus = __esm({
|
|
|
3066
3074
|
}
|
|
3067
3075
|
});
|
|
3068
3076
|
|
|
3077
|
+
// src/lib/memory-write-governor.ts
|
|
3078
|
+
import { createHash } from "crypto";
|
|
3079
|
+
function normalizeMemoryText(text) {
|
|
3080
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3081
|
+
}
|
|
3082
|
+
function classifyMemoryType(input) {
|
|
3083
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
3084
|
+
const tool = input.tool_name.toLowerCase();
|
|
3085
|
+
const text = input.raw_text.toLowerCase();
|
|
3086
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3087
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3088
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3089
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3090
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3091
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3092
|
+
return "raw";
|
|
3093
|
+
}
|
|
3094
|
+
function shouldDropMemory(text) {
|
|
3095
|
+
const normalized = normalizeMemoryText(text);
|
|
3096
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3097
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3098
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3099
|
+
}
|
|
3100
|
+
return { drop: false };
|
|
3101
|
+
}
|
|
3102
|
+
function shouldSkipEmbedding(input) {
|
|
3103
|
+
const type = classifyMemoryType(input);
|
|
3104
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3105
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
3106
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
3107
|
+
return false;
|
|
3108
|
+
}
|
|
3109
|
+
function hashMemoryContent(text) {
|
|
3110
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3111
|
+
}
|
|
3112
|
+
function scopedDedupArgs(input) {
|
|
3113
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
3114
|
+
}
|
|
3115
|
+
function governMemoryRecord(record) {
|
|
3116
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3117
|
+
const memoryType = classifyMemoryType({
|
|
3118
|
+
raw_text: normalized,
|
|
3119
|
+
agent_id: record.agent_id,
|
|
3120
|
+
project_name: record.project_name,
|
|
3121
|
+
tool_name: record.tool_name,
|
|
3122
|
+
memory_type: record.memory_type
|
|
3123
|
+
});
|
|
3124
|
+
const drop = shouldDropMemory(normalized);
|
|
3125
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3126
|
+
raw_text: normalized,
|
|
3127
|
+
agent_id: record.agent_id,
|
|
3128
|
+
project_name: record.project_name,
|
|
3129
|
+
tool_name: record.tool_name,
|
|
3130
|
+
memory_type: memoryType
|
|
3131
|
+
});
|
|
3132
|
+
return {
|
|
3133
|
+
record: {
|
|
3134
|
+
...record,
|
|
3135
|
+
raw_text: normalized,
|
|
3136
|
+
memory_type: memoryType,
|
|
3137
|
+
vector: skipEmbedding ? null : record.vector
|
|
3138
|
+
},
|
|
3139
|
+
contentHash: hashMemoryContent(normalized),
|
|
3140
|
+
shouldDrop: drop.drop,
|
|
3141
|
+
dropReason: drop.reason,
|
|
3142
|
+
skipEmbedding,
|
|
3143
|
+
hygiene: {
|
|
3144
|
+
dedup: true,
|
|
3145
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3146
|
+
}
|
|
3147
|
+
};
|
|
3148
|
+
}
|
|
3149
|
+
async function findScopedDuplicate(input) {
|
|
3150
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3151
|
+
const client = getClient2();
|
|
3152
|
+
const args = scopedDedupArgs(input);
|
|
3153
|
+
let sql = `SELECT id FROM memories
|
|
3154
|
+
WHERE content_hash = ?
|
|
3155
|
+
AND agent_id = ?
|
|
3156
|
+
AND project_name = ?
|
|
3157
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3158
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3159
|
+
if (input.excludeId) {
|
|
3160
|
+
sql += " AND id != ?";
|
|
3161
|
+
args.push(input.excludeId);
|
|
3162
|
+
}
|
|
3163
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3164
|
+
const result = await client.execute({ sql, args });
|
|
3165
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3166
|
+
}
|
|
3167
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3168
|
+
try {
|
|
3169
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3170
|
+
const client = getClient2();
|
|
3171
|
+
const current = await client.execute({
|
|
3172
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3173
|
+
importance, timestamp
|
|
3174
|
+
FROM memories
|
|
3175
|
+
WHERE id = ?
|
|
3176
|
+
LIMIT 1`,
|
|
3177
|
+
args: [memoryId]
|
|
3178
|
+
});
|
|
3179
|
+
const row = current.rows[0];
|
|
3180
|
+
if (!row) return;
|
|
3181
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3182
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
3183
|
+
const agentId = String(row.agent_id);
|
|
3184
|
+
const projectName = String(row.project_name);
|
|
3185
|
+
if (contentHash) {
|
|
3186
|
+
await client.execute({
|
|
3187
|
+
sql: `UPDATE memories
|
|
3188
|
+
SET status = 'deleted',
|
|
3189
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3190
|
+
WHERE id != ?
|
|
3191
|
+
AND content_hash = ?
|
|
3192
|
+
AND agent_id = ?
|
|
3193
|
+
AND project_name = ?
|
|
3194
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3195
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3196
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
3197
|
+
});
|
|
3198
|
+
}
|
|
3199
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3200
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3201
|
+
const old = await client.execute({
|
|
3202
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3203
|
+
args: [supersedesId]
|
|
3204
|
+
});
|
|
3205
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3206
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3207
|
+
await client.batch([
|
|
3208
|
+
{
|
|
3209
|
+
sql: `UPDATE memories
|
|
3210
|
+
SET status = 'archived',
|
|
3211
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3212
|
+
WHERE id = ?`,
|
|
3213
|
+
args: [supersedesId]
|
|
3214
|
+
},
|
|
3215
|
+
{
|
|
3216
|
+
sql: `UPDATE memories
|
|
3217
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3218
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3219
|
+
WHERE id = ?`,
|
|
3220
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3221
|
+
}
|
|
3222
|
+
], "write");
|
|
3223
|
+
}
|
|
3224
|
+
} catch (err) {
|
|
3225
|
+
process.stderr.write(
|
|
3226
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3227
|
+
`
|
|
3228
|
+
);
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3232
|
+
if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
3233
|
+
if (memoryIds.length === 0) return;
|
|
3234
|
+
const run = () => {
|
|
3235
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3236
|
+
};
|
|
3237
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3238
|
+
else setTimeout(run, 0);
|
|
3239
|
+
}
|
|
3240
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
3241
|
+
var init_memory_write_governor = __esm({
|
|
3242
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3243
|
+
"use strict";
|
|
3244
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3245
|
+
"decision",
|
|
3246
|
+
"adr",
|
|
3247
|
+
"behavior",
|
|
3248
|
+
"procedure"
|
|
3249
|
+
]);
|
|
3250
|
+
NOISE_DROP_PATTERNS = [
|
|
3251
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3252
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3253
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3254
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3255
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3256
|
+
];
|
|
3257
|
+
SKIP_EMBED_PATTERNS = [
|
|
3258
|
+
/tmux capture-pane\b/i,
|
|
3259
|
+
/docker ps\b/i,
|
|
3260
|
+
/docker images\b/i,
|
|
3261
|
+
/git status\b/i,
|
|
3262
|
+
/grep .*node_modules/i,
|
|
3263
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3264
|
+
];
|
|
3265
|
+
}
|
|
3266
|
+
});
|
|
3267
|
+
|
|
3069
3268
|
// src/lib/shard-manager.ts
|
|
3070
3269
|
var shard_manager_exports = {};
|
|
3071
3270
|
__export(shard_manager_exports, {
|
|
@@ -3230,7 +3429,8 @@ async function ensureShardSchema(client) {
|
|
|
3230
3429
|
}
|
|
3231
3430
|
for (const idx of [
|
|
3232
3431
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
3233
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
3432
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
3433
|
+
"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"
|
|
3234
3434
|
]) {
|
|
3235
3435
|
try {
|
|
3236
3436
|
await client.execute(idx);
|
|
@@ -3424,7 +3624,7 @@ var init_platform_procedures = __esm({
|
|
|
3424
3624
|
title: "Chain of command \u2014 who talks to whom",
|
|
3425
3625
|
domain: "workflow",
|
|
3426
3626
|
priority: "p0",
|
|
3427
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
3627
|
+
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."
|
|
3428
3628
|
},
|
|
3429
3629
|
{
|
|
3430
3630
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -3655,7 +3855,6 @@ __export(store_exports, {
|
|
|
3655
3855
|
vectorToBlob: () => vectorToBlob,
|
|
3656
3856
|
writeMemory: () => writeMemory
|
|
3657
3857
|
});
|
|
3658
|
-
import { createHash } from "crypto";
|
|
3659
3858
|
function isBusyError2(err) {
|
|
3660
3859
|
if (err instanceof Error) {
|
|
3661
3860
|
const msg = err.message.toLowerCase();
|
|
@@ -3769,17 +3968,24 @@ async function writeMemory(record) {
|
|
|
3769
3968
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
3770
3969
|
);
|
|
3771
3970
|
}
|
|
3772
|
-
const
|
|
3773
|
-
if (
|
|
3971
|
+
const governed = governMemoryRecord(record);
|
|
3972
|
+
if (governed.shouldDrop) return;
|
|
3973
|
+
record = governed.record;
|
|
3974
|
+
const contentHash = governed.contentHash;
|
|
3975
|
+
const memoryType = record.memory_type ?? "raw";
|
|
3976
|
+
if (_pendingRecords.some(
|
|
3977
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
3978
|
+
)) {
|
|
3774
3979
|
return;
|
|
3775
3980
|
}
|
|
3776
3981
|
try {
|
|
3777
|
-
const
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3982
|
+
const existing = await findScopedDuplicate({
|
|
3983
|
+
contentHash,
|
|
3984
|
+
agentId: record.agent_id,
|
|
3985
|
+
projectName: record.project_name,
|
|
3986
|
+
memoryType
|
|
3781
3987
|
});
|
|
3782
|
-
if (existing
|
|
3988
|
+
if (existing) return;
|
|
3783
3989
|
} catch {
|
|
3784
3990
|
}
|
|
3785
3991
|
const dbRow = {
|
|
@@ -3810,7 +4016,7 @@ async function writeMemory(record) {
|
|
|
3810
4016
|
tier: record.tier ?? classifyTier(record),
|
|
3811
4017
|
supersedes_id: record.supersedes_id ?? null,
|
|
3812
4018
|
draft: record.draft ? 1 : 0,
|
|
3813
|
-
memory_type:
|
|
4019
|
+
memory_type: memoryType,
|
|
3814
4020
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
3815
4021
|
content_hash: contentHash,
|
|
3816
4022
|
intent: record.intent ?? null,
|
|
@@ -3969,6 +4175,7 @@ async function flushBatch() {
|
|
|
3969
4175
|
const globalClient = getClient();
|
|
3970
4176
|
const globalStmts = batch.map(buildStmt);
|
|
3971
4177
|
await globalClient.batch(globalStmts, "write");
|
|
4178
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
3972
4179
|
_pendingRecords.splice(0, batch.length);
|
|
3973
4180
|
try {
|
|
3974
4181
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4089,7 +4296,11 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
4089
4296
|
sql += ` AND timestamp >= ?`;
|
|
4090
4297
|
args.push(options.since);
|
|
4091
4298
|
}
|
|
4092
|
-
if (options?.
|
|
4299
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
4300
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
4301
|
+
sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
4302
|
+
args.push(...uniqueTypes);
|
|
4303
|
+
} else if (options?.memoryType) {
|
|
4093
4304
|
sql += ` AND memory_type = ?`;
|
|
4094
4305
|
args.push(options.memoryType);
|
|
4095
4306
|
}
|
|
@@ -4227,6 +4438,7 @@ var init_store = __esm({
|
|
|
4227
4438
|
init_keychain();
|
|
4228
4439
|
init_config();
|
|
4229
4440
|
init_state_bus();
|
|
4441
|
+
init_memory_write_governor();
|
|
4230
4442
|
INIT_MAX_RETRIES = 3;
|
|
4231
4443
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
4232
4444
|
_pendingRecords = [];
|
|
@@ -7673,7 +7885,11 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
|
|
|
7673
7885
|
}
|
|
7674
7886
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
7675
7887
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
7676
|
-
|
|
7888
|
+
let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
7889
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
7890
|
+
ccModel += "[1m]";
|
|
7891
|
+
}
|
|
7892
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
7677
7893
|
}
|
|
7678
7894
|
}
|
|
7679
7895
|
let spawnCommand;
|
|
@@ -129,6 +129,21 @@ var init_secure_files = __esm({
|
|
|
129
129
|
});
|
|
130
130
|
|
|
131
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
|
+
});
|
|
132
147
|
import { readFile, writeFile } from "fs/promises";
|
|
133
148
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
134
149
|
import path from "path";
|
|
@@ -232,6 +247,46 @@ async function loadConfig() {
|
|
|
232
247
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
233
248
|
}
|
|
234
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
|
+
}
|
|
235
290
|
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
236
291
|
var init_config = __esm({
|
|
237
292
|
"src/lib/config.ts"() {
|
|
@@ -2095,6 +2150,14 @@ async function ensureSchema() {
|
|
|
2095
2150
|
);
|
|
2096
2151
|
} catch {
|
|
2097
2152
|
}
|
|
2153
|
+
try {
|
|
2154
|
+
await client.execute(
|
|
2155
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2156
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2157
|
+
WHERE content_hash IS NOT NULL`
|
|
2158
|
+
);
|
|
2159
|
+
} catch {
|
|
2160
|
+
}
|
|
2098
2161
|
await client.executeMultiple(`
|
|
2099
2162
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2100
2163
|
id TEXT PRIMARY KEY,
|
|
@@ -2764,7 +2827,8 @@ async function ensureShardSchema(client) {
|
|
|
2764
2827
|
}
|
|
2765
2828
|
for (const idx of [
|
|
2766
2829
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
2767
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
2830
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
2831
|
+
"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"
|
|
2768
2832
|
]) {
|
|
2769
2833
|
try {
|
|
2770
2834
|
await client.execute(idx);
|
|
@@ -2958,7 +3022,7 @@ var init_platform_procedures = __esm({
|
|
|
2958
3022
|
title: "Chain of command \u2014 who talks to whom",
|
|
2959
3023
|
domain: "workflow",
|
|
2960
3024
|
priority: "p0",
|
|
2961
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
3025
|
+
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."
|
|
2962
3026
|
},
|
|
2963
3027
|
{
|
|
2964
3028
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -3512,6 +3576,7 @@ var init_preferences = __esm({
|
|
|
3512
3576
|
// src/adapters/claude/installer.ts
|
|
3513
3577
|
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir } from "fs/promises";
|
|
3514
3578
|
import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync6, copyFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
3579
|
+
import { createHash as createHash2 } from "crypto";
|
|
3515
3580
|
import path12 from "path";
|
|
3516
3581
|
import os9 from "os";
|
|
3517
3582
|
import { execSync as execSync5 } from "child_process";
|
|
@@ -3973,7 +4038,6 @@ import { spawnSync } from "child_process";
|
|
|
3973
4038
|
// src/lib/store.ts
|
|
3974
4039
|
init_memory();
|
|
3975
4040
|
init_database();
|
|
3976
|
-
import { createHash } from "crypto";
|
|
3977
4041
|
|
|
3978
4042
|
// src/lib/keychain.ts
|
|
3979
4043
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
@@ -4206,6 +4270,88 @@ var StateBus = class {
|
|
|
4206
4270
|
};
|
|
4207
4271
|
var orgBus = new StateBus();
|
|
4208
4272
|
|
|
4273
|
+
// src/lib/memory-write-governor.ts
|
|
4274
|
+
import { createHash } from "crypto";
|
|
4275
|
+
var HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
4276
|
+
"decision",
|
|
4277
|
+
"adr",
|
|
4278
|
+
"behavior",
|
|
4279
|
+
"procedure"
|
|
4280
|
+
]);
|
|
4281
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
4282
|
+
try {
|
|
4283
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4284
|
+
const client = getClient2();
|
|
4285
|
+
const current = await client.execute({
|
|
4286
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
4287
|
+
importance, timestamp
|
|
4288
|
+
FROM memories
|
|
4289
|
+
WHERE id = ?
|
|
4290
|
+
LIMIT 1`,
|
|
4291
|
+
args: [memoryId]
|
|
4292
|
+
});
|
|
4293
|
+
const row = current.rows[0];
|
|
4294
|
+
if (!row) return;
|
|
4295
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
4296
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
4297
|
+
const agentId = String(row.agent_id);
|
|
4298
|
+
const projectName = String(row.project_name);
|
|
4299
|
+
if (contentHash) {
|
|
4300
|
+
await client.execute({
|
|
4301
|
+
sql: `UPDATE memories
|
|
4302
|
+
SET status = 'deleted',
|
|
4303
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
4304
|
+
WHERE id != ?
|
|
4305
|
+
AND content_hash = ?
|
|
4306
|
+
AND agent_id = ?
|
|
4307
|
+
AND project_name = ?
|
|
4308
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
4309
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
4310
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
4311
|
+
});
|
|
4312
|
+
}
|
|
4313
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
4314
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
4315
|
+
const old = await client.execute({
|
|
4316
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
4317
|
+
args: [supersedesId]
|
|
4318
|
+
});
|
|
4319
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
4320
|
+
const newImportance = Number(row.importance ?? 0);
|
|
4321
|
+
await client.batch([
|
|
4322
|
+
{
|
|
4323
|
+
sql: `UPDATE memories
|
|
4324
|
+
SET status = 'archived',
|
|
4325
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
4326
|
+
WHERE id = ?`,
|
|
4327
|
+
args: [supersedesId]
|
|
4328
|
+
},
|
|
4329
|
+
{
|
|
4330
|
+
sql: `UPDATE memories
|
|
4331
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
4332
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
4333
|
+
WHERE id = ?`,
|
|
4334
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
4335
|
+
}
|
|
4336
|
+
], "write");
|
|
4337
|
+
}
|
|
4338
|
+
} catch (err) {
|
|
4339
|
+
process.stderr.write(
|
|
4340
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
4341
|
+
`
|
|
4342
|
+
);
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
4346
|
+
if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
4347
|
+
if (memoryIds.length === 0) return;
|
|
4348
|
+
const run = () => {
|
|
4349
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
4350
|
+
};
|
|
4351
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
4352
|
+
else setTimeout(run, 0);
|
|
4353
|
+
}
|
|
4354
|
+
|
|
4209
4355
|
// src/lib/store.ts
|
|
4210
4356
|
var INIT_MAX_RETRIES = 3;
|
|
4211
4357
|
var INIT_RETRY_DELAY_MS = 1e3;
|
|
@@ -4405,6 +4551,7 @@ async function flushBatch() {
|
|
|
4405
4551
|
const globalClient = getClient();
|
|
4406
4552
|
const globalStmts = batch.map(buildStmt);
|
|
4407
4553
|
await globalClient.batch(globalStmts, "write");
|
|
4554
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4408
4555
|
_pendingRecords.splice(0, batch.length);
|
|
4409
4556
|
try {
|
|
4410
4557
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4516,7 +4663,16 @@ var BEHAVIORS_EXPORT_DIR = path8.join(
|
|
|
4516
4663
|
"behaviors-export"
|
|
4517
4664
|
);
|
|
4518
4665
|
var STALE_EXPORT_AGE_MS = 60 * 60 * 1e3;
|
|
4519
|
-
var
|
|
4666
|
+
var DEFAULT_BEHAVIOR_LIMIT = 30;
|
|
4667
|
+
function getBehaviorLimit() {
|
|
4668
|
+
try {
|
|
4669
|
+
const { loadConfigSync: loadConfigSync2 } = (init_config(), __toCommonJS(config_exports));
|
|
4670
|
+
const cfg = loadConfigSync2();
|
|
4671
|
+
return cfg.behaviorExportLimit ?? DEFAULT_BEHAVIOR_LIMIT;
|
|
4672
|
+
} catch {
|
|
4673
|
+
return DEFAULT_BEHAVIOR_LIMIT;
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4520
4676
|
function sweepStaleBehaviorExports(now = Date.now()) {
|
|
4521
4677
|
if (!existsSync8(BEHAVIORS_EXPORT_DIR)) return;
|
|
4522
4678
|
let entries;
|
|
@@ -4570,7 +4726,7 @@ function exportFilePath(agentId, projectName, sessionKey) {
|
|
|
4570
4726
|
async function exportBehaviorsForAgent(agentId, projectName, sessionKey) {
|
|
4571
4727
|
mkdirSync3(BEHAVIORS_EXPORT_DIR, { recursive: true });
|
|
4572
4728
|
sweepStaleBehaviorExports();
|
|
4573
|
-
const behaviors = await listBehaviors(agentId, projectName,
|
|
4729
|
+
const behaviors = await listBehaviors(agentId, projectName, getBehaviorLimit());
|
|
4574
4730
|
if (behaviors.length === 0) return null;
|
|
4575
4731
|
const body = renderBehaviorExport(behaviors);
|
|
4576
4732
|
const target = exportFilePath(agentId, projectName, sessionKey);
|