@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
|
@@ -2687,6 +2687,14 @@ async function ensureSchema() {
|
|
|
2687
2687
|
);
|
|
2688
2688
|
} catch {
|
|
2689
2689
|
}
|
|
2690
|
+
try {
|
|
2691
|
+
await client.execute(
|
|
2692
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2693
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2694
|
+
WHERE content_hash IS NOT NULL`
|
|
2695
|
+
);
|
|
2696
|
+
} catch {
|
|
2697
|
+
}
|
|
2690
2698
|
await client.executeMultiple(`
|
|
2691
2699
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2692
2700
|
id TEXT PRIMARY KEY,
|
|
@@ -3282,8 +3290,8 @@ function deriveMachineKey() {
|
|
|
3282
3290
|
}
|
|
3283
3291
|
function readMachineId() {
|
|
3284
3292
|
try {
|
|
3285
|
-
const { readFileSync:
|
|
3286
|
-
return
|
|
3293
|
+
const { readFileSync: readFileSync14 } = __require("fs");
|
|
3294
|
+
return readFileSync14("/etc/machine-id", "utf-8").trim();
|
|
3287
3295
|
} catch {
|
|
3288
3296
|
return "";
|
|
3289
3297
|
}
|
|
@@ -3432,6 +3440,197 @@ var init_state_bus = __esm({
|
|
|
3432
3440
|
}
|
|
3433
3441
|
});
|
|
3434
3442
|
|
|
3443
|
+
// src/lib/memory-write-governor.ts
|
|
3444
|
+
import { createHash } from "crypto";
|
|
3445
|
+
function normalizeMemoryText(text) {
|
|
3446
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3447
|
+
}
|
|
3448
|
+
function classifyMemoryType(input2) {
|
|
3449
|
+
if (input2.memory_type && input2.memory_type.trim()) return input2.memory_type.trim();
|
|
3450
|
+
const tool = input2.tool_name.toLowerCase();
|
|
3451
|
+
const text = input2.raw_text.toLowerCase();
|
|
3452
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3453
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3454
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3455
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3456
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3457
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3458
|
+
return "raw";
|
|
3459
|
+
}
|
|
3460
|
+
function shouldDropMemory(text) {
|
|
3461
|
+
const normalized = normalizeMemoryText(text);
|
|
3462
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3463
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3464
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3465
|
+
}
|
|
3466
|
+
return { drop: false };
|
|
3467
|
+
}
|
|
3468
|
+
function shouldSkipEmbedding(input2) {
|
|
3469
|
+
const type = classifyMemoryType(input2);
|
|
3470
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3471
|
+
if (type === "raw" && input2.raw_text.length > 2e4) return true;
|
|
3472
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input2.raw_text))) return true;
|
|
3473
|
+
return false;
|
|
3474
|
+
}
|
|
3475
|
+
function hashMemoryContent(text) {
|
|
3476
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3477
|
+
}
|
|
3478
|
+
function scopedDedupArgs(input2) {
|
|
3479
|
+
return [input2.contentHash, input2.agentId, input2.projectName, input2.memoryType];
|
|
3480
|
+
}
|
|
3481
|
+
function governMemoryRecord(record) {
|
|
3482
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3483
|
+
const memoryType = classifyMemoryType({
|
|
3484
|
+
raw_text: normalized,
|
|
3485
|
+
agent_id: record.agent_id,
|
|
3486
|
+
project_name: record.project_name,
|
|
3487
|
+
tool_name: record.tool_name,
|
|
3488
|
+
memory_type: record.memory_type
|
|
3489
|
+
});
|
|
3490
|
+
const drop = shouldDropMemory(normalized);
|
|
3491
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3492
|
+
raw_text: normalized,
|
|
3493
|
+
agent_id: record.agent_id,
|
|
3494
|
+
project_name: record.project_name,
|
|
3495
|
+
tool_name: record.tool_name,
|
|
3496
|
+
memory_type: memoryType
|
|
3497
|
+
});
|
|
3498
|
+
return {
|
|
3499
|
+
record: {
|
|
3500
|
+
...record,
|
|
3501
|
+
raw_text: normalized,
|
|
3502
|
+
memory_type: memoryType,
|
|
3503
|
+
vector: skipEmbedding ? null : record.vector
|
|
3504
|
+
},
|
|
3505
|
+
contentHash: hashMemoryContent(normalized),
|
|
3506
|
+
shouldDrop: drop.drop,
|
|
3507
|
+
dropReason: drop.reason,
|
|
3508
|
+
skipEmbedding,
|
|
3509
|
+
hygiene: {
|
|
3510
|
+
dedup: true,
|
|
3511
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3512
|
+
}
|
|
3513
|
+
};
|
|
3514
|
+
}
|
|
3515
|
+
async function findScopedDuplicate(input2) {
|
|
3516
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3517
|
+
const client = getClient2();
|
|
3518
|
+
const args = scopedDedupArgs(input2);
|
|
3519
|
+
let sql = `SELECT id FROM memories
|
|
3520
|
+
WHERE content_hash = ?
|
|
3521
|
+
AND agent_id = ?
|
|
3522
|
+
AND project_name = ?
|
|
3523
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3524
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3525
|
+
if (input2.excludeId) {
|
|
3526
|
+
sql += " AND id != ?";
|
|
3527
|
+
args.push(input2.excludeId);
|
|
3528
|
+
}
|
|
3529
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3530
|
+
const result = await client.execute({ sql, args });
|
|
3531
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3532
|
+
}
|
|
3533
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3534
|
+
try {
|
|
3535
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3536
|
+
const client = getClient2();
|
|
3537
|
+
const current = await client.execute({
|
|
3538
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3539
|
+
importance, timestamp
|
|
3540
|
+
FROM memories
|
|
3541
|
+
WHERE id = ?
|
|
3542
|
+
LIMIT 1`,
|
|
3543
|
+
args: [memoryId]
|
|
3544
|
+
});
|
|
3545
|
+
const row = current.rows[0];
|
|
3546
|
+
if (!row) return;
|
|
3547
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3548
|
+
const contentHash2 = row.content_hash ? String(row.content_hash) : null;
|
|
3549
|
+
const agentId = String(row.agent_id);
|
|
3550
|
+
const projectName = String(row.project_name);
|
|
3551
|
+
if (contentHash2) {
|
|
3552
|
+
await client.execute({
|
|
3553
|
+
sql: `UPDATE memories
|
|
3554
|
+
SET status = 'deleted',
|
|
3555
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3556
|
+
WHERE id != ?
|
|
3557
|
+
AND content_hash = ?
|
|
3558
|
+
AND agent_id = ?
|
|
3559
|
+
AND project_name = ?
|
|
3560
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3561
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3562
|
+
args: [memoryId, contentHash2, agentId, projectName, memoryType]
|
|
3563
|
+
});
|
|
3564
|
+
}
|
|
3565
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3566
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3567
|
+
const old = await client.execute({
|
|
3568
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3569
|
+
args: [supersedesId]
|
|
3570
|
+
});
|
|
3571
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3572
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3573
|
+
await client.batch([
|
|
3574
|
+
{
|
|
3575
|
+
sql: `UPDATE memories
|
|
3576
|
+
SET status = 'archived',
|
|
3577
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3578
|
+
WHERE id = ?`,
|
|
3579
|
+
args: [supersedesId]
|
|
3580
|
+
},
|
|
3581
|
+
{
|
|
3582
|
+
sql: `UPDATE memories
|
|
3583
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3584
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3585
|
+
WHERE id = ?`,
|
|
3586
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3587
|
+
}
|
|
3588
|
+
], "write");
|
|
3589
|
+
}
|
|
3590
|
+
} catch (err) {
|
|
3591
|
+
process.stderr.write(
|
|
3592
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3593
|
+
`
|
|
3594
|
+
);
|
|
3595
|
+
}
|
|
3596
|
+
}
|
|
3597
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3598
|
+
if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
3599
|
+
if (memoryIds.length === 0) return;
|
|
3600
|
+
const run = () => {
|
|
3601
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3602
|
+
};
|
|
3603
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3604
|
+
else setTimeout(run, 0);
|
|
3605
|
+
}
|
|
3606
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
3607
|
+
var init_memory_write_governor = __esm({
|
|
3608
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3609
|
+
"use strict";
|
|
3610
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3611
|
+
"decision",
|
|
3612
|
+
"adr",
|
|
3613
|
+
"behavior",
|
|
3614
|
+
"procedure"
|
|
3615
|
+
]);
|
|
3616
|
+
NOISE_DROP_PATTERNS = [
|
|
3617
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3618
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3619
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3620
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3621
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3622
|
+
];
|
|
3623
|
+
SKIP_EMBED_PATTERNS = [
|
|
3624
|
+
/tmux capture-pane\b/i,
|
|
3625
|
+
/docker ps\b/i,
|
|
3626
|
+
/docker images\b/i,
|
|
3627
|
+
/git status\b/i,
|
|
3628
|
+
/grep .*node_modules/i,
|
|
3629
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3630
|
+
];
|
|
3631
|
+
}
|
|
3632
|
+
});
|
|
3633
|
+
|
|
3435
3634
|
// src/lib/shard-manager.ts
|
|
3436
3635
|
var shard_manager_exports = {};
|
|
3437
3636
|
__export(shard_manager_exports, {
|
|
@@ -3596,7 +3795,8 @@ async function ensureShardSchema(client) {
|
|
|
3596
3795
|
}
|
|
3597
3796
|
for (const idx of [
|
|
3598
3797
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
3599
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
3798
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
3799
|
+
"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"
|
|
3600
3800
|
]) {
|
|
3601
3801
|
try {
|
|
3602
3802
|
await client.execute(idx);
|
|
@@ -3790,7 +3990,7 @@ var init_platform_procedures = __esm({
|
|
|
3790
3990
|
title: "Chain of command \u2014 who talks to whom",
|
|
3791
3991
|
domain: "workflow",
|
|
3792
3992
|
priority: "p0",
|
|
3793
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
3993
|
+
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."
|
|
3794
3994
|
},
|
|
3795
3995
|
{
|
|
3796
3996
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -4021,7 +4221,6 @@ __export(store_exports, {
|
|
|
4021
4221
|
vectorToBlob: () => vectorToBlob,
|
|
4022
4222
|
writeMemory: () => writeMemory
|
|
4023
4223
|
});
|
|
4024
|
-
import { createHash } from "crypto";
|
|
4025
4224
|
function isBusyError2(err) {
|
|
4026
4225
|
if (err instanceof Error) {
|
|
4027
4226
|
const msg = err.message.toLowerCase();
|
|
@@ -4135,17 +4334,24 @@ async function writeMemory(record) {
|
|
|
4135
4334
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
4136
4335
|
);
|
|
4137
4336
|
}
|
|
4138
|
-
const
|
|
4139
|
-
if (
|
|
4337
|
+
const governed = governMemoryRecord(record);
|
|
4338
|
+
if (governed.shouldDrop) return;
|
|
4339
|
+
record = governed.record;
|
|
4340
|
+
const contentHash2 = governed.contentHash;
|
|
4341
|
+
const memoryType = record.memory_type ?? "raw";
|
|
4342
|
+
if (_pendingRecords.some(
|
|
4343
|
+
(r) => r.content_hash === contentHash2 && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
4344
|
+
)) {
|
|
4140
4345
|
return;
|
|
4141
4346
|
}
|
|
4142
4347
|
try {
|
|
4143
|
-
const
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4348
|
+
const existing = await findScopedDuplicate({
|
|
4349
|
+
contentHash: contentHash2,
|
|
4350
|
+
agentId: record.agent_id,
|
|
4351
|
+
projectName: record.project_name,
|
|
4352
|
+
memoryType
|
|
4147
4353
|
});
|
|
4148
|
-
if (existing
|
|
4354
|
+
if (existing) return;
|
|
4149
4355
|
} catch {
|
|
4150
4356
|
}
|
|
4151
4357
|
const dbRow = {
|
|
@@ -4176,9 +4382,9 @@ async function writeMemory(record) {
|
|
|
4176
4382
|
tier: record.tier ?? classifyTier(record),
|
|
4177
4383
|
supersedes_id: record.supersedes_id ?? null,
|
|
4178
4384
|
draft: record.draft ? 1 : 0,
|
|
4179
|
-
memory_type:
|
|
4385
|
+
memory_type: memoryType,
|
|
4180
4386
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
4181
|
-
content_hash:
|
|
4387
|
+
content_hash: contentHash2,
|
|
4182
4388
|
intent: record.intent ?? null,
|
|
4183
4389
|
outcome: record.outcome ?? null,
|
|
4184
4390
|
domain: record.domain ?? inferDomain(record),
|
|
@@ -4251,7 +4457,7 @@ async function flushBatch() {
|
|
|
4251
4457
|
const draft = row.draft ? 1 : 0;
|
|
4252
4458
|
const memoryType = row.memory_type ?? "raw";
|
|
4253
4459
|
const trajectory = row.trajectory ?? null;
|
|
4254
|
-
const
|
|
4460
|
+
const contentHash2 = row.content_hash ?? null;
|
|
4255
4461
|
const intent = row.intent ?? null;
|
|
4256
4462
|
const outcome = row.outcome ?? null;
|
|
4257
4463
|
const domain = row.domain ?? null;
|
|
@@ -4323,7 +4529,7 @@ async function flushBatch() {
|
|
|
4323
4529
|
draft,
|
|
4324
4530
|
memoryType,
|
|
4325
4531
|
trajectory,
|
|
4326
|
-
|
|
4532
|
+
contentHash2
|
|
4327
4533
|
];
|
|
4328
4534
|
return {
|
|
4329
4535
|
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
@@ -4335,6 +4541,7 @@ async function flushBatch() {
|
|
|
4335
4541
|
const globalClient = getClient();
|
|
4336
4542
|
const globalStmts = batch.map(buildStmt);
|
|
4337
4543
|
await globalClient.batch(globalStmts, "write");
|
|
4544
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
4338
4545
|
_pendingRecords.splice(0, batch.length);
|
|
4339
4546
|
try {
|
|
4340
4547
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4455,7 +4662,11 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
4455
4662
|
sql += ` AND timestamp >= ?`;
|
|
4456
4663
|
args.push(options.since);
|
|
4457
4664
|
}
|
|
4458
|
-
if (options?.
|
|
4665
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
4666
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
4667
|
+
sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
4668
|
+
args.push(...uniqueTypes);
|
|
4669
|
+
} else if (options?.memoryType) {
|
|
4459
4670
|
sql += ` AND memory_type = ?`;
|
|
4460
4671
|
args.push(options.memoryType);
|
|
4461
4672
|
}
|
|
@@ -4593,6 +4804,7 @@ var init_store = __esm({
|
|
|
4593
4804
|
init_keychain();
|
|
4594
4805
|
init_config();
|
|
4595
4806
|
init_state_bus();
|
|
4807
|
+
init_memory_write_governor();
|
|
4596
4808
|
INIT_MAX_RETRIES = 3;
|
|
4597
4809
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
4598
4810
|
_pendingRecords = [];
|
|
@@ -4859,10 +5071,10 @@ async function disposeEmbedder() {
|
|
|
4859
5071
|
async function embedDirect(text) {
|
|
4860
5072
|
const llamaCpp = await import("node-llama-cpp");
|
|
4861
5073
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4862
|
-
const { existsSync:
|
|
4863
|
-
const
|
|
4864
|
-
const modelPath =
|
|
4865
|
-
if (!
|
|
5074
|
+
const { existsSync: existsSync17 } = await import("fs");
|
|
5075
|
+
const path21 = await import("path");
|
|
5076
|
+
const modelPath = path21.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
5077
|
+
if (!existsSync17(modelPath)) {
|
|
4866
5078
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
4867
5079
|
}
|
|
4868
5080
|
const llama = await llamaCpp.getLlama();
|
|
@@ -5752,6 +5964,17 @@ __export(hybrid_search_exports, {
|
|
|
5752
5964
|
rrfMerge: () => rrfMerge,
|
|
5753
5965
|
rrfMergeMulti: () => rrfMergeMulti
|
|
5754
5966
|
});
|
|
5967
|
+
function appendMemoryTypeFilter(sql, args, column, options) {
|
|
5968
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
5969
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
5970
|
+
sql += ` AND ${column} IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
5971
|
+
args.push(...uniqueTypes);
|
|
5972
|
+
} else if (options?.memoryType) {
|
|
5973
|
+
sql += ` AND ${column} = ?`;
|
|
5974
|
+
args.push(options.memoryType);
|
|
5975
|
+
}
|
|
5976
|
+
return sql;
|
|
5977
|
+
}
|
|
5755
5978
|
async function hybridSearch(queryText, agentId, options) {
|
|
5756
5979
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
5757
5980
|
const config = await loadConfig2();
|
|
@@ -5930,10 +6153,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
5930
6153
|
};
|
|
5931
6154
|
try {
|
|
5932
6155
|
const fs = await import("fs");
|
|
5933
|
-
const
|
|
6156
|
+
const path21 = await import("path");
|
|
5934
6157
|
const os10 = await import("os");
|
|
5935
|
-
const logPath =
|
|
5936
|
-
fs.mkdirSync(
|
|
6158
|
+
const logPath = path21.join(os10.homedir(), ".exe-os", "search-quality.jsonl");
|
|
6159
|
+
fs.mkdirSync(path21.dirname(logPath), { recursive: true });
|
|
5937
6160
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
5938
6161
|
} catch {
|
|
5939
6162
|
}
|
|
@@ -5980,6 +6203,7 @@ async function estimateCardinality(agentId, options) {
|
|
|
5980
6203
|
sql += ` AND timestamp >= ?`;
|
|
5981
6204
|
args.push(options.since);
|
|
5982
6205
|
}
|
|
6206
|
+
sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
|
|
5983
6207
|
try {
|
|
5984
6208
|
const result = await client.execute({ sql, args });
|
|
5985
6209
|
return Number(result.rows[0]?.cnt) || 0;
|
|
@@ -6101,10 +6325,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
|
|
|
6101
6325
|
sql += ` AND m.timestamp >= ?`;
|
|
6102
6326
|
args.push(options.since);
|
|
6103
6327
|
}
|
|
6104
|
-
|
|
6105
|
-
sql += ` AND m.memory_type = ?`;
|
|
6106
|
-
args.push(options.memoryType);
|
|
6107
|
-
}
|
|
6328
|
+
sql = appendMemoryTypeFilter(sql, args, "m.memory_type", options);
|
|
6108
6329
|
sql += ` ORDER BY rank LIMIT ?`;
|
|
6109
6330
|
args.push(limit);
|
|
6110
6331
|
const result = await client.execute({ sql, args });
|
|
@@ -6161,9 +6382,16 @@ async function recentRecords(agentId, options, limit, textFilter) {
|
|
|
6161
6382
|
AND timestamp >= ? AND timestamp <= ?
|
|
6162
6383
|
AND COALESCE(status, 'active') = 'active'
|
|
6163
6384
|
AND ${options?.includeRaw === false ? "COALESCE(memory_type, 'raw') != 'raw'" : "1 = 1"}
|
|
6385
|
+
${options?.memoryTypes?.length ? `AND memory_type IN (${options.memoryTypes.map(() => "?").join(",")})` : options?.memoryType ? "AND memory_type = ?" : ""}
|
|
6164
6386
|
AND COALESCE(confidence, 0.7) >= 0.3
|
|
6165
6387
|
ORDER BY timestamp DESC LIMIT ?`,
|
|
6166
|
-
args: [
|
|
6388
|
+
args: [
|
|
6389
|
+
agentId,
|
|
6390
|
+
windowStart,
|
|
6391
|
+
killedAt,
|
|
6392
|
+
...options?.memoryTypes?.length ? [...new Set(options.memoryTypes)] : options?.memoryType ? [options.memoryType] : [],
|
|
6393
|
+
boundarySlots
|
|
6394
|
+
]
|
|
6167
6395
|
});
|
|
6168
6396
|
for (const row of boundaryResult.rows) {
|
|
6169
6397
|
sessionBoundaryMemories.push(rowToMemoryRecord(row));
|
|
@@ -6209,10 +6437,7 @@ async function recentRecords(agentId, options, limit, textFilter) {
|
|
|
6209
6437
|
sql += ` AND timestamp >= ?`;
|
|
6210
6438
|
args.push(options.since);
|
|
6211
6439
|
}
|
|
6212
|
-
|
|
6213
|
-
sql += ` AND memory_type = ?`;
|
|
6214
|
-
args.push(options.memoryType);
|
|
6215
|
-
}
|
|
6440
|
+
sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
|
|
6216
6441
|
if (textFilter) {
|
|
6217
6442
|
sql += ` AND raw_text LIKE '%' || ? || '%'`;
|
|
6218
6443
|
args.push(textFilter);
|
|
@@ -7236,10 +7461,145 @@ var init_git_staleness = __esm({
|
|
|
7236
7461
|
}
|
|
7237
7462
|
});
|
|
7238
7463
|
|
|
7464
|
+
// src/lib/identity.ts
|
|
7465
|
+
var identity_exports = {};
|
|
7466
|
+
__export(identity_exports, {
|
|
7467
|
+
getIdentity: () => getIdentity,
|
|
7468
|
+
getIdentityInjection: () => getIdentityInjection,
|
|
7469
|
+
identityPath: () => identityPath,
|
|
7470
|
+
listIdentities: () => listIdentities,
|
|
7471
|
+
updateIdentity: () => updateIdentity
|
|
7472
|
+
});
|
|
7473
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "fs";
|
|
7474
|
+
import { readdirSync as readdirSync5 } from "fs";
|
|
7475
|
+
import path19 from "path";
|
|
7476
|
+
import { createHash as createHash2 } from "crypto";
|
|
7477
|
+
function ensureDir() {
|
|
7478
|
+
if (!existsSync15(IDENTITY_DIR2)) {
|
|
7479
|
+
mkdirSync7(IDENTITY_DIR2, { recursive: true });
|
|
7480
|
+
}
|
|
7481
|
+
}
|
|
7482
|
+
function identityPath(agentId) {
|
|
7483
|
+
return path19.join(IDENTITY_DIR2, `${agentId}.md`);
|
|
7484
|
+
}
|
|
7485
|
+
function parseFrontmatter(raw) {
|
|
7486
|
+
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
7487
|
+
if (!match) {
|
|
7488
|
+
return {
|
|
7489
|
+
frontmatter: {
|
|
7490
|
+
role: "unknown",
|
|
7491
|
+
title: "Unknown",
|
|
7492
|
+
agent_id: "unknown",
|
|
7493
|
+
org_level: "specialist",
|
|
7494
|
+
created_by: "system",
|
|
7495
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
7496
|
+
},
|
|
7497
|
+
body: raw
|
|
7498
|
+
};
|
|
7499
|
+
}
|
|
7500
|
+
const yamlStr = match[1];
|
|
7501
|
+
const body = match[2].trim();
|
|
7502
|
+
const fm = {};
|
|
7503
|
+
for (const line of yamlStr.split("\n")) {
|
|
7504
|
+
const kv = line.match(/^(\w+):\s*(.+)$/);
|
|
7505
|
+
if (kv) fm[kv[1]] = kv[2].trim();
|
|
7506
|
+
}
|
|
7507
|
+
return {
|
|
7508
|
+
frontmatter: {
|
|
7509
|
+
role: fm.role ?? "unknown",
|
|
7510
|
+
title: fm.title ?? "Unknown",
|
|
7511
|
+
agent_id: fm.agent_id ?? "unknown",
|
|
7512
|
+
org_level: fm.org_level ?? "specialist",
|
|
7513
|
+
created_by: fm.created_by ?? "system",
|
|
7514
|
+
updated_at: fm.updated_at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
7515
|
+
},
|
|
7516
|
+
body
|
|
7517
|
+
};
|
|
7518
|
+
}
|
|
7519
|
+
function contentHash(content) {
|
|
7520
|
+
return createHash2("sha256").update(content).digest("hex").slice(0, 16);
|
|
7521
|
+
}
|
|
7522
|
+
function getIdentity(agentId) {
|
|
7523
|
+
const filePath = identityPath(agentId);
|
|
7524
|
+
if (!existsSync15(filePath)) return null;
|
|
7525
|
+
const raw = readFileSync12(filePath, "utf-8");
|
|
7526
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
7527
|
+
return {
|
|
7528
|
+
agentId,
|
|
7529
|
+
frontmatter,
|
|
7530
|
+
body,
|
|
7531
|
+
raw,
|
|
7532
|
+
contentHash: contentHash(raw)
|
|
7533
|
+
};
|
|
7534
|
+
}
|
|
7535
|
+
async function updateIdentity(agentId, content, updatedBy) {
|
|
7536
|
+
ensureDir();
|
|
7537
|
+
const filePath = identityPath(agentId);
|
|
7538
|
+
const hash = contentHash(content);
|
|
7539
|
+
writeFileSync8(filePath, content, "utf-8");
|
|
7540
|
+
try {
|
|
7541
|
+
const client = getClient();
|
|
7542
|
+
await client.execute({
|
|
7543
|
+
sql: `INSERT INTO identity (agent_id, content_hash, updated_at, updated_by)
|
|
7544
|
+
VALUES (?, ?, ?, ?)
|
|
7545
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
7546
|
+
content_hash = excluded.content_hash,
|
|
7547
|
+
updated_at = excluded.updated_at,
|
|
7548
|
+
updated_by = excluded.updated_by`,
|
|
7549
|
+
args: [agentId, hash, (/* @__PURE__ */ new Date()).toISOString(), updatedBy]
|
|
7550
|
+
});
|
|
7551
|
+
} catch {
|
|
7552
|
+
}
|
|
7553
|
+
}
|
|
7554
|
+
function listIdentities() {
|
|
7555
|
+
ensureDir();
|
|
7556
|
+
const files = readdirSync5(IDENTITY_DIR2).filter((f) => f.endsWith(".md"));
|
|
7557
|
+
const results = [];
|
|
7558
|
+
for (const file of files) {
|
|
7559
|
+
const agentId = file.replace(".md", "");
|
|
7560
|
+
const identity = getIdentity(agentId);
|
|
7561
|
+
if (!identity) continue;
|
|
7562
|
+
const lines = identity.body.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
|
|
7563
|
+
const summary = lines[0]?.trim().slice(0, 120) ?? identity.frontmatter.title;
|
|
7564
|
+
results.push({
|
|
7565
|
+
agentId,
|
|
7566
|
+
title: `${identity.frontmatter.title} (${identity.frontmatter.role.toUpperCase()})`,
|
|
7567
|
+
summary
|
|
7568
|
+
});
|
|
7569
|
+
}
|
|
7570
|
+
return results;
|
|
7571
|
+
}
|
|
7572
|
+
function getIdentityInjection(agentId) {
|
|
7573
|
+
const own = getIdentity(agentId);
|
|
7574
|
+
const all = listIdentities();
|
|
7575
|
+
const parts = [];
|
|
7576
|
+
if (own) {
|
|
7577
|
+
parts.push(`## Your Identity (exe.md)
|
|
7578
|
+
These define WHO YOU ARE. Non-negotiable. Permanent.
|
|
7579
|
+
|
|
7580
|
+
${own.body}`);
|
|
7581
|
+
}
|
|
7582
|
+
const teamLines = all.filter((a) => a.agentId !== agentId).map((a) => `- ${a.agentId} (${a.title}): ${a.summary}`);
|
|
7583
|
+
if (teamLines.length > 0) {
|
|
7584
|
+
parts.push(`## Team Identities
|
|
7585
|
+
${teamLines.join("\n")}`);
|
|
7586
|
+
}
|
|
7587
|
+
return parts.join("\n\n");
|
|
7588
|
+
}
|
|
7589
|
+
var IDENTITY_DIR2;
|
|
7590
|
+
var init_identity = __esm({
|
|
7591
|
+
"src/lib/identity.ts"() {
|
|
7592
|
+
"use strict";
|
|
7593
|
+
init_config();
|
|
7594
|
+
init_database();
|
|
7595
|
+
IDENTITY_DIR2 = path19.join(EXE_AI_DIR, "identity");
|
|
7596
|
+
}
|
|
7597
|
+
});
|
|
7598
|
+
|
|
7239
7599
|
// src/adapters/claude/hooks/session-start.ts
|
|
7240
7600
|
init_config();
|
|
7241
|
-
import
|
|
7242
|
-
import { unlinkSync as unlinkSync4, existsSync as
|
|
7601
|
+
import path20 from "path";
|
|
7602
|
+
import { unlinkSync as unlinkSync4, existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
|
|
7243
7603
|
if (!process.env.AGENT_ID) {
|
|
7244
7604
|
process.env.AGENT_ID = "default";
|
|
7245
7605
|
process.env.AGENT_ROLE = "employee";
|
|
@@ -7272,8 +7632,8 @@ process.stdin.on("end", async () => {
|
|
|
7272
7632
|
const sessionScope = getCurrentSessionScope2();
|
|
7273
7633
|
if (source === "startup") {
|
|
7274
7634
|
try {
|
|
7275
|
-
const undefinedPath =
|
|
7276
|
-
process.env.EXE_OS_DIR ??
|
|
7635
|
+
const undefinedPath = path20.join(
|
|
7636
|
+
process.env.EXE_OS_DIR ?? path20.join(process.env.HOME ?? "", ".exe-os"),
|
|
7277
7637
|
"session-cache",
|
|
7278
7638
|
"active-agent-undefined.json"
|
|
7279
7639
|
);
|
|
@@ -7287,13 +7647,13 @@ process.stdin.on("end", async () => {
|
|
|
7287
7647
|
const agentId = agent.agentId;
|
|
7288
7648
|
if (agentId !== "default") {
|
|
7289
7649
|
try {
|
|
7290
|
-
const cacheDir =
|
|
7291
|
-
process.env.EXE_OS_DIR ??
|
|
7650
|
+
const cacheDir = path20.join(
|
|
7651
|
+
process.env.EXE_OS_DIR ?? path20.join(process.env.HOME ?? "", ".exe-os"),
|
|
7292
7652
|
"session-cache"
|
|
7293
7653
|
);
|
|
7294
|
-
const markerPath =
|
|
7295
|
-
if (
|
|
7296
|
-
const marker = JSON.parse(
|
|
7654
|
+
const markerPath = path20.join(cacheDir, `current-task-${agentId}.json`);
|
|
7655
|
+
if (existsSync16(markerPath)) {
|
|
7656
|
+
const marker = JSON.parse(readFileSync13(markerPath, "utf-8"));
|
|
7297
7657
|
if (marker.taskId) {
|
|
7298
7658
|
const client = getClient2();
|
|
7299
7659
|
const markerScope = sessionScopeFilter2(sessionScope);
|
|
@@ -7401,6 +7761,22 @@ flow, so bug fixes are fast.`;
|
|
|
7401
7761
|
} catch {
|
|
7402
7762
|
}
|
|
7403
7763
|
let additionalContext = "";
|
|
7764
|
+
if (agentId !== "default") {
|
|
7765
|
+
try {
|
|
7766
|
+
const { getIdentity: getIdentity2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
7767
|
+
const identity = getIdentity2(agentId);
|
|
7768
|
+
if (identity) {
|
|
7769
|
+
const title = identity.frontmatter.title ?? identity.frontmatter.role ?? agentId;
|
|
7770
|
+
const role = identity.frontmatter.role ?? "";
|
|
7771
|
+
const firstLine = identity.body.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
7772
|
+
additionalContext += `## Your Identity
|
|
7773
|
+
You are **${title}**${role ? ` (${role})` : ""}. ${firstLine}
|
|
7774
|
+
|
|
7775
|
+
`;
|
|
7776
|
+
}
|
|
7777
|
+
} catch {
|
|
7778
|
+
}
|
|
7779
|
+
}
|
|
7404
7780
|
if (memories.length > 0) {
|
|
7405
7781
|
const brief = memories.map(
|
|
7406
7782
|
(m) => `[${m.timestamp}] ${m.tool_name}: ${m.raw_text.slice(0, 200)}`
|