@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
package/dist/bin/setup.js
CHANGED
|
@@ -3504,6 +3504,14 @@ async function ensureSchema() {
|
|
|
3504
3504
|
);
|
|
3505
3505
|
} catch {
|
|
3506
3506
|
}
|
|
3507
|
+
try {
|
|
3508
|
+
await client.execute(
|
|
3509
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
3510
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
3511
|
+
WHERE content_hash IS NOT NULL`
|
|
3512
|
+
);
|
|
3513
|
+
} catch {
|
|
3514
|
+
}
|
|
3507
3515
|
await client.executeMultiple(`
|
|
3508
3516
|
CREATE TABLE IF NOT EXISTS entities (
|
|
3509
3517
|
id TEXT PRIMARY KEY,
|
|
@@ -5651,7 +5659,7 @@ var init_platform_procedures = __esm({
|
|
|
5651
5659
|
title: "Chain of command \u2014 who talks to whom",
|
|
5652
5660
|
domain: "workflow",
|
|
5653
5661
|
priority: "p0",
|
|
5654
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
5662
|
+
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."
|
|
5655
5663
|
},
|
|
5656
5664
|
{
|
|
5657
5665
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -5856,8 +5864,9 @@ function personalizePrompt(prompt, templateName, actualName) {
|
|
|
5856
5864
|
return prompt.replace(new RegExp(`\\bYou are ${escaped}\\b`, "g"), `You are ${actualName}`);
|
|
5857
5865
|
}
|
|
5858
5866
|
function renderClientCOOTemplate(vars) {
|
|
5867
|
+
const resolved = { ...vars, title: vars.title || "Chief Operating Officer" };
|
|
5859
5868
|
for (const key of CLIENT_COO_PLACEHOLDERS) {
|
|
5860
|
-
const value =
|
|
5869
|
+
const value = resolved[key];
|
|
5861
5870
|
if (typeof value !== "string" || value.length === 0) {
|
|
5862
5871
|
throw new Error(
|
|
5863
5872
|
`renderClientCOOTemplate: missing required variable "${key}"`
|
|
@@ -5866,7 +5875,7 @@ function renderClientCOOTemplate(vars) {
|
|
|
5866
5875
|
}
|
|
5867
5876
|
let out = CLIENT_COO_TEMPLATE;
|
|
5868
5877
|
for (const key of CLIENT_COO_PLACEHOLDERS) {
|
|
5869
|
-
out = out.split(`{{${key}}}`).join(
|
|
5878
|
+
out = out.split(`{{${key}}}`).join(resolved[key]);
|
|
5870
5879
|
}
|
|
5871
5880
|
if (vars.industry_context) {
|
|
5872
5881
|
out += "\n" + vars.industry_context;
|
|
@@ -6343,7 +6352,7 @@ created_by: system
|
|
|
6343
6352
|
---
|
|
6344
6353
|
## Identity
|
|
6345
6354
|
|
|
6346
|
-
You are {{agent_name}}, the
|
|
6355
|
+
You are {{agent_name}}, the {{title}} at {{company_name}}.
|
|
6347
6356
|
|
|
6348
6357
|
You are {{founder_name}}'s most reliable teammate in business \u2014 the knowledgeable older sibling who has been through it all. You have seen projects succeed and fail. You know what matters and what is noise. You do not get anxious about problems; you see them coming, stay calm, and handle them.
|
|
6349
6358
|
|
|
@@ -6430,7 +6439,8 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
|
|
|
6430
6439
|
CLIENT_COO_PLACEHOLDERS = [
|
|
6431
6440
|
"agent_name",
|
|
6432
6441
|
"company_name",
|
|
6433
|
-
"founder_name"
|
|
6442
|
+
"founder_name",
|
|
6443
|
+
"title"
|
|
6434
6444
|
];
|
|
6435
6445
|
}
|
|
6436
6446
|
});
|
|
@@ -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);
|
|
@@ -2936,7 +2945,7 @@ var init_platform_procedures = __esm({
|
|
|
2936
2945
|
title: "Chain of command \u2014 who talks to whom",
|
|
2937
2946
|
domain: "workflow",
|
|
2938
2947
|
priority: "p0",
|
|
2939
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
2948
|
+
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."
|
|
2940
2949
|
},
|
|
2941
2950
|
{
|
|
2942
2951
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -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,88 @@ 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 (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
3470
|
+
if (memoryIds.length === 0) return;
|
|
3471
|
+
const run = () => {
|
|
3472
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3473
|
+
};
|
|
3474
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3475
|
+
else setTimeout(run, 0);
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3388
3478
|
// src/lib/store.ts
|
|
3389
3479
|
var INIT_MAX_RETRIES = 3;
|
|
3390
3480
|
var INIT_RETRY_DELAY_MS = 1e3;
|
|
@@ -3584,6 +3674,7 @@ async function flushBatch() {
|
|
|
3584
3674
|
const globalClient = getClient();
|
|
3585
3675
|
const globalStmts = batch.map(buildStmt);
|
|
3586
3676
|
await globalClient.batch(globalStmts, "write");
|
|
3677
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
3587
3678
|
_pendingRecords.splice(0, batch.length);
|
|
3588
3679
|
try {
|
|
3589
3680
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
package/dist/gateway/index.js
CHANGED
|
@@ -2932,6 +2932,14 @@ async function ensureSchema() {
|
|
|
2932
2932
|
);
|
|
2933
2933
|
} catch {
|
|
2934
2934
|
}
|
|
2935
|
+
try {
|
|
2936
|
+
await client.execute(
|
|
2937
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2938
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2939
|
+
WHERE content_hash IS NOT NULL`
|
|
2940
|
+
);
|
|
2941
|
+
} catch {
|
|
2942
|
+
}
|
|
2935
2943
|
await client.executeMultiple(`
|
|
2936
2944
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2937
2945
|
id TEXT PRIMARY KEY,
|
|
@@ -3690,6 +3698,197 @@ var init_keychain = __esm({
|
|
|
3690
3698
|
}
|
|
3691
3699
|
});
|
|
3692
3700
|
|
|
3701
|
+
// src/lib/memory-write-governor.ts
|
|
3702
|
+
import { createHash } from "crypto";
|
|
3703
|
+
function normalizeMemoryText(text) {
|
|
3704
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3705
|
+
}
|
|
3706
|
+
function classifyMemoryType(input) {
|
|
3707
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
3708
|
+
const tool = input.tool_name.toLowerCase();
|
|
3709
|
+
const text = input.raw_text.toLowerCase();
|
|
3710
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3711
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3712
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3713
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3714
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3715
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3716
|
+
return "raw";
|
|
3717
|
+
}
|
|
3718
|
+
function shouldDropMemory(text) {
|
|
3719
|
+
const normalized = normalizeMemoryText(text);
|
|
3720
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3721
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3722
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3723
|
+
}
|
|
3724
|
+
return { drop: false };
|
|
3725
|
+
}
|
|
3726
|
+
function shouldSkipEmbedding(input) {
|
|
3727
|
+
const type = classifyMemoryType(input);
|
|
3728
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3729
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
3730
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
3731
|
+
return false;
|
|
3732
|
+
}
|
|
3733
|
+
function hashMemoryContent(text) {
|
|
3734
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3735
|
+
}
|
|
3736
|
+
function scopedDedupArgs(input) {
|
|
3737
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
3738
|
+
}
|
|
3739
|
+
function governMemoryRecord(record) {
|
|
3740
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3741
|
+
const memoryType = classifyMemoryType({
|
|
3742
|
+
raw_text: normalized,
|
|
3743
|
+
agent_id: record.agent_id,
|
|
3744
|
+
project_name: record.project_name,
|
|
3745
|
+
tool_name: record.tool_name,
|
|
3746
|
+
memory_type: record.memory_type
|
|
3747
|
+
});
|
|
3748
|
+
const drop = shouldDropMemory(normalized);
|
|
3749
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3750
|
+
raw_text: normalized,
|
|
3751
|
+
agent_id: record.agent_id,
|
|
3752
|
+
project_name: record.project_name,
|
|
3753
|
+
tool_name: record.tool_name,
|
|
3754
|
+
memory_type: memoryType
|
|
3755
|
+
});
|
|
3756
|
+
return {
|
|
3757
|
+
record: {
|
|
3758
|
+
...record,
|
|
3759
|
+
raw_text: normalized,
|
|
3760
|
+
memory_type: memoryType,
|
|
3761
|
+
vector: skipEmbedding ? null : record.vector
|
|
3762
|
+
},
|
|
3763
|
+
contentHash: hashMemoryContent(normalized),
|
|
3764
|
+
shouldDrop: drop.drop,
|
|
3765
|
+
dropReason: drop.reason,
|
|
3766
|
+
skipEmbedding,
|
|
3767
|
+
hygiene: {
|
|
3768
|
+
dedup: true,
|
|
3769
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3770
|
+
}
|
|
3771
|
+
};
|
|
3772
|
+
}
|
|
3773
|
+
async function findScopedDuplicate(input) {
|
|
3774
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3775
|
+
const client = getClient2();
|
|
3776
|
+
const args = scopedDedupArgs(input);
|
|
3777
|
+
let sql = `SELECT id FROM memories
|
|
3778
|
+
WHERE content_hash = ?
|
|
3779
|
+
AND agent_id = ?
|
|
3780
|
+
AND project_name = ?
|
|
3781
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3782
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3783
|
+
if (input.excludeId) {
|
|
3784
|
+
sql += " AND id != ?";
|
|
3785
|
+
args.push(input.excludeId);
|
|
3786
|
+
}
|
|
3787
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3788
|
+
const result = await client.execute({ sql, args });
|
|
3789
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3790
|
+
}
|
|
3791
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3792
|
+
try {
|
|
3793
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3794
|
+
const client = getClient2();
|
|
3795
|
+
const current = await client.execute({
|
|
3796
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3797
|
+
importance, timestamp
|
|
3798
|
+
FROM memories
|
|
3799
|
+
WHERE id = ?
|
|
3800
|
+
LIMIT 1`,
|
|
3801
|
+
args: [memoryId]
|
|
3802
|
+
});
|
|
3803
|
+
const row = current.rows[0];
|
|
3804
|
+
if (!row) return;
|
|
3805
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3806
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
3807
|
+
const agentId = String(row.agent_id);
|
|
3808
|
+
const projectName = String(row.project_name);
|
|
3809
|
+
if (contentHash) {
|
|
3810
|
+
await client.execute({
|
|
3811
|
+
sql: `UPDATE memories
|
|
3812
|
+
SET status = 'deleted',
|
|
3813
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3814
|
+
WHERE id != ?
|
|
3815
|
+
AND content_hash = ?
|
|
3816
|
+
AND agent_id = ?
|
|
3817
|
+
AND project_name = ?
|
|
3818
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3819
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3820
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
3821
|
+
});
|
|
3822
|
+
}
|
|
3823
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3824
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3825
|
+
const old = await client.execute({
|
|
3826
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3827
|
+
args: [supersedesId]
|
|
3828
|
+
});
|
|
3829
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3830
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3831
|
+
await client.batch([
|
|
3832
|
+
{
|
|
3833
|
+
sql: `UPDATE memories
|
|
3834
|
+
SET status = 'archived',
|
|
3835
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3836
|
+
WHERE id = ?`,
|
|
3837
|
+
args: [supersedesId]
|
|
3838
|
+
},
|
|
3839
|
+
{
|
|
3840
|
+
sql: `UPDATE memories
|
|
3841
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3842
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3843
|
+
WHERE id = ?`,
|
|
3844
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3845
|
+
}
|
|
3846
|
+
], "write");
|
|
3847
|
+
}
|
|
3848
|
+
} catch (err) {
|
|
3849
|
+
process.stderr.write(
|
|
3850
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3851
|
+
`
|
|
3852
|
+
);
|
|
3853
|
+
}
|
|
3854
|
+
}
|
|
3855
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3856
|
+
if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
3857
|
+
if (memoryIds.length === 0) return;
|
|
3858
|
+
const run = () => {
|
|
3859
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3860
|
+
};
|
|
3861
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3862
|
+
else setTimeout(run, 0);
|
|
3863
|
+
}
|
|
3864
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
3865
|
+
var init_memory_write_governor = __esm({
|
|
3866
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3867
|
+
"use strict";
|
|
3868
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3869
|
+
"decision",
|
|
3870
|
+
"adr",
|
|
3871
|
+
"behavior",
|
|
3872
|
+
"procedure"
|
|
3873
|
+
]);
|
|
3874
|
+
NOISE_DROP_PATTERNS = [
|
|
3875
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3876
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3877
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3878
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3879
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3880
|
+
];
|
|
3881
|
+
SKIP_EMBED_PATTERNS = [
|
|
3882
|
+
/tmux capture-pane\b/i,
|
|
3883
|
+
/docker ps\b/i,
|
|
3884
|
+
/docker images\b/i,
|
|
3885
|
+
/git status\b/i,
|
|
3886
|
+
/grep .*node_modules/i,
|
|
3887
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3888
|
+
];
|
|
3889
|
+
}
|
|
3890
|
+
});
|
|
3891
|
+
|
|
3693
3892
|
// src/lib/shard-manager.ts
|
|
3694
3893
|
var shard_manager_exports = {};
|
|
3695
3894
|
__export(shard_manager_exports, {
|
|
@@ -3854,7 +4053,8 @@ async function ensureShardSchema(client) {
|
|
|
3854
4053
|
}
|
|
3855
4054
|
for (const idx of [
|
|
3856
4055
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
3857
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
4056
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
4057
|
+
"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"
|
|
3858
4058
|
]) {
|
|
3859
4059
|
try {
|
|
3860
4060
|
await client.execute(idx);
|
|
@@ -4048,7 +4248,7 @@ var init_platform_procedures = __esm({
|
|
|
4048
4248
|
title: "Chain of command \u2014 who talks to whom",
|
|
4049
4249
|
domain: "workflow",
|
|
4050
4250
|
priority: "p0",
|
|
4051
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
4251
|
+
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."
|
|
4052
4252
|
},
|
|
4053
4253
|
{
|
|
4054
4254
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -4279,7 +4479,6 @@ __export(store_exports, {
|
|
|
4279
4479
|
vectorToBlob: () => vectorToBlob,
|
|
4280
4480
|
writeMemory: () => writeMemory
|
|
4281
4481
|
});
|
|
4282
|
-
import { createHash } from "crypto";
|
|
4283
4482
|
function isBusyError2(err) {
|
|
4284
4483
|
if (err instanceof Error) {
|
|
4285
4484
|
const msg = err.message.toLowerCase();
|
|
@@ -4393,17 +4592,24 @@ async function writeMemory(record) {
|
|
|
4393
4592
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
4394
4593
|
);
|
|
4395
4594
|
}
|
|
4396
|
-
const
|
|
4397
|
-
if (
|
|
4595
|
+
const governed = governMemoryRecord(record);
|
|
4596
|
+
if (governed.shouldDrop) return;
|
|
4597
|
+
record = governed.record;
|
|
4598
|
+
const contentHash = governed.contentHash;
|
|
4599
|
+
const memoryType = record.memory_type ?? "raw";
|
|
4600
|
+
if (_pendingRecords.some(
|
|
4601
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
4602
|
+
)) {
|
|
4398
4603
|
return;
|
|
4399
4604
|
}
|
|
4400
4605
|
try {
|
|
4401
|
-
const
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4606
|
+
const existing = await findScopedDuplicate({
|
|
4607
|
+
contentHash,
|
|
4608
|
+
agentId: record.agent_id,
|
|
4609
|
+
projectName: record.project_name,
|
|
4610
|
+
memoryType
|
|
4405
4611
|
});
|
|
4406
|
-
if (existing
|
|
4612
|
+
if (existing) return;
|
|
4407
4613
|
} catch {
|
|
4408
4614
|
}
|
|
4409
4615
|
const dbRow = {
|
|
@@ -4434,7 +4640,7 @@ async function writeMemory(record) {
|
|
|
4434
4640
|
tier: record.tier ?? classifyTier(record),
|
|
4435
4641
|
supersedes_id: record.supersedes_id ?? null,
|
|
4436
4642
|
draft: record.draft ? 1 : 0,
|
|
4437
|
-
memory_type:
|
|
4643
|
+
memory_type: memoryType,
|
|
4438
4644
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
4439
4645
|
content_hash: contentHash,
|
|
4440
4646
|
intent: record.intent ?? null,
|
|
@@ -4593,6 +4799,7 @@ async function flushBatch() {
|
|
|
4593
4799
|
const globalClient = getClient();
|
|
4594
4800
|
const globalStmts = batch.map(buildStmt);
|
|
4595
4801
|
await globalClient.batch(globalStmts, "write");
|
|
4802
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4596
4803
|
_pendingRecords.splice(0, batch.length);
|
|
4597
4804
|
try {
|
|
4598
4805
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4713,7 +4920,11 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
4713
4920
|
sql += ` AND timestamp >= ?`;
|
|
4714
4921
|
args.push(options.since);
|
|
4715
4922
|
}
|
|
4716
|
-
if (options?.
|
|
4923
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
4924
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
4925
|
+
sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
4926
|
+
args.push(...uniqueTypes);
|
|
4927
|
+
} else if (options?.memoryType) {
|
|
4717
4928
|
sql += ` AND memory_type = ?`;
|
|
4718
4929
|
args.push(options.memoryType);
|
|
4719
4930
|
}
|
|
@@ -4851,6 +5062,7 @@ var init_store = __esm({
|
|
|
4851
5062
|
init_keychain();
|
|
4852
5063
|
init_config();
|
|
4853
5064
|
init_state_bus();
|
|
5065
|
+
init_memory_write_governor();
|
|
4854
5066
|
INIT_MAX_RETRIES = 3;
|
|
4855
5067
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
4856
5068
|
_pendingRecords = [];
|
|
@@ -9293,7 +9505,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9293
9505
|
}
|
|
9294
9506
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
9295
9507
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
9296
|
-
|
|
9508
|
+
let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
9509
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
9510
|
+
ccModel += "[1m]";
|
|
9511
|
+
}
|
|
9512
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
9297
9513
|
}
|
|
9298
9514
|
}
|
|
9299
9515
|
let spawnCommand;
|