@askexenow/exe-os 0.9.35 → 0.9.37
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 +5 -1
- package/dist/bin/backfill-responses.js +5 -1
- package/dist/bin/backfill-vectors.js +1 -1
- package/dist/bin/cleanup-stale-review-tasks.js +10 -2
- package/dist/bin/cli.js +48 -14
- package/dist/bin/exe-agent.js +1 -1
- package/dist/bin/exe-assign.js +10 -2
- package/dist/bin/exe-boot.js +1 -1
- package/dist/bin/exe-call.js +7 -5
- package/dist/bin/exe-dispatch.js +10 -2
- package/dist/bin/exe-doctor.js +1 -1
- package/dist/bin/exe-export-behaviors.js +87 -4
- package/dist/bin/exe-forget.js +31 -11
- package/dist/bin/exe-gateway.js +10 -2
- package/dist/bin/exe-heartbeat.js +10 -2
- package/dist/bin/exe-kill.js +10 -2
- package/dist/bin/exe-launch-agent.js +85 -7
- package/dist/bin/exe-new-employee.js +26 -2
- package/dist/bin/exe-pending-messages.js +10 -2
- package/dist/bin/exe-pending-notifications.js +10 -2
- package/dist/bin/exe-pending-reviews.js +10 -2
- package/dist/bin/exe-rename.js +1 -1
- package/dist/bin/exe-review.js +10 -2
- package/dist/bin/exe-search.js +38 -19
- package/dist/bin/exe-session-cleanup.js +14 -3
- package/dist/bin/exe-start-codex.js +69 -3
- package/dist/bin/exe-start-opencode.js +80 -3
- package/dist/bin/exe-status.js +10 -2
- package/dist/bin/exe-team.js +10 -2
- package/dist/bin/git-sweep.js +10 -2
- package/dist/bin/graph-backfill.js +2 -1
- package/dist/bin/graph-export.js +10 -2
- package/dist/bin/install.js +25 -1
- package/dist/bin/intercom-check.js +10 -2
- package/dist/bin/scan-tasks.js +10 -2
- package/dist/bin/setup.js +7 -5
- package/dist/bin/shard-migrate.js +2 -1
- package/dist/gateway/index.js +10 -2
- package/dist/hooks/bug-report-worker.js +10 -2
- package/dist/hooks/codex-stop-task-finalizer.js +10 -2
- package/dist/hooks/commit-complete.js +10 -2
- package/dist/hooks/error-recall.js +38 -19
- package/dist/hooks/ingest-worker.js +9 -2
- package/dist/hooks/ingest.js +10 -2
- package/dist/hooks/instructions-loaded.js +10 -2
- package/dist/hooks/notification.js +10 -2
- package/dist/hooks/post-compact.js +10 -2
- package/dist/hooks/post-tool-combined.js +47 -21
- package/dist/hooks/pre-compact.js +12 -3
- package/dist/hooks/pre-tool-use.js +20 -8
- package/dist/hooks/prompt-submit.js +133 -20
- package/dist/hooks/session-end.js +138 -5
- package/dist/hooks/session-start.js +216 -46
- package/dist/hooks/stop.js +14 -4
- package/dist/hooks/subagent-stop.js +10 -2
- package/dist/hooks/summary-worker.js +121 -19
- package/dist/index.js +32 -16
- package/dist/lib/employee-templates.js +7 -5
- package/dist/lib/exe-daemon.js +124 -34
- package/dist/lib/hybrid-search.js +38 -19
- package/dist/lib/schedules.js +1 -1
- package/dist/lib/store.js +10 -2
- package/dist/mcp/server.js +118 -34
- package/dist/runtime/index.js +32 -16
- package/dist/tui/App.js +10 -2
- package/package.json +1 -1
- package/src/commands/exe/save.md +52 -0
|
@@ -6946,6 +6946,9 @@ function classifyMemoryType(input2) {
|
|
|
6946
6946
|
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
6947
6947
|
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
6948
6948
|
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
6949
|
+
if (tool.includes("checkpoint") || text.startsWith("context checkpoint")) return "checkpoint";
|
|
6950
|
+
if (tool.includes("sessionsummary") || tool.includes("session-summary")) return "summary";
|
|
6951
|
+
if (tool.includes("sessionend") || text.startsWith("session ended")) return "summary";
|
|
6949
6952
|
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
6950
6953
|
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
6951
6954
|
return "raw";
|
|
@@ -7088,6 +7091,7 @@ async function runPostWriteMemoryHygiene(memoryId) {
|
|
|
7088
7091
|
}
|
|
7089
7092
|
}
|
|
7090
7093
|
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
7094
|
+
if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
7091
7095
|
if (memoryIds.length === 0) return;
|
|
7092
7096
|
const run = () => {
|
|
7093
7097
|
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
@@ -7482,7 +7486,7 @@ var init_platform_procedures = __esm({
|
|
|
7482
7486
|
title: "Chain of command \u2014 who talks to whom",
|
|
7483
7487
|
domain: "workflow",
|
|
7484
7488
|
priority: "p0",
|
|
7485
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
7489
|
+
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."
|
|
7486
7490
|
},
|
|
7487
7491
|
{
|
|
7488
7492
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -8154,7 +8158,11 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
8154
8158
|
sql += ` AND timestamp >= ?`;
|
|
8155
8159
|
args.push(options.since);
|
|
8156
8160
|
}
|
|
8157
|
-
if (options?.
|
|
8161
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
8162
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
8163
|
+
sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
8164
|
+
args.push(...uniqueTypes);
|
|
8165
|
+
} else if (options?.memoryType) {
|
|
8158
8166
|
sql += ` AND memory_type = ?`;
|
|
8159
8167
|
args.push(options.memoryType);
|
|
8160
8168
|
}
|
|
@@ -8914,6 +8922,88 @@ function clearCacheState(sessionKey) {
|
|
|
8914
8922
|
// src/adapters/claude/hooks/session-end.ts
|
|
8915
8923
|
init_task_scope();
|
|
8916
8924
|
init_employees();
|
|
8925
|
+
|
|
8926
|
+
// src/lib/auto-checkpoint.ts
|
|
8927
|
+
var FILE_RE = /(?:^|\s)([\w./-]+\.(?:ts|tsx|js|jsx|json|md|yml|yaml|sql|go|py|css|scss|html|sh))(?:\b|$)/g;
|
|
8928
|
+
var DECISION_RE = /\b(decision:|decided:|we decided|founder directive|captured in .*architecture|source of truth)\b/i;
|
|
8929
|
+
function asString(value, fallback = "") {
|
|
8930
|
+
if (value == null) return fallback;
|
|
8931
|
+
return String(value);
|
|
8932
|
+
}
|
|
8933
|
+
function compactLine(text, max = 220) {
|
|
8934
|
+
return text.replace(/\s+/g, " ").trim().slice(0, max);
|
|
8935
|
+
}
|
|
8936
|
+
function topEntries(counts, limit) {
|
|
8937
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, limit).map(([name, count]) => `${name}(${count})`);
|
|
8938
|
+
}
|
|
8939
|
+
function buildAutoCheckpoint(input2) {
|
|
8940
|
+
const maxSamples = input2.maxSamples ?? 8;
|
|
8941
|
+
const projectCounts = /* @__PURE__ */ new Map();
|
|
8942
|
+
const toolCounts = /* @__PURE__ */ new Map();
|
|
8943
|
+
const files = /* @__PURE__ */ new Set();
|
|
8944
|
+
const errors = [];
|
|
8945
|
+
const samples = [];
|
|
8946
|
+
const decisionTexts = [];
|
|
8947
|
+
for (const row of input2.memories) {
|
|
8948
|
+
const tool = asString(row.tool_name, "unknown");
|
|
8949
|
+
const project = asString(row.project_name, input2.projectName || "unknown");
|
|
8950
|
+
const raw = asString(row.raw_text);
|
|
8951
|
+
const hasError = row.has_error === 1 || row.has_error === true;
|
|
8952
|
+
toolCounts.set(tool, (toolCounts.get(tool) ?? 0) + 1);
|
|
8953
|
+
projectCounts.set(project, (projectCounts.get(project) ?? 0) + 1);
|
|
8954
|
+
if (hasError && errors.length < 5) errors.push(compactLine(raw, 180));
|
|
8955
|
+
if (samples.length < maxSamples && raw.length > 30) {
|
|
8956
|
+
samples.push(`[${tool}] ${compactLine(raw)}`);
|
|
8957
|
+
}
|
|
8958
|
+
if (DECISION_RE.test(raw) && decisionTexts.length < 5) {
|
|
8959
|
+
decisionTexts.push(`AUTO DECISION CANDIDATE [${input2.agentId}]: ${compactLine(raw, 500)}`);
|
|
8960
|
+
}
|
|
8961
|
+
for (const match of raw.matchAll(FILE_RE)) {
|
|
8962
|
+
if (match[1]) files.add(match[1]);
|
|
8963
|
+
if (files.size >= 20) break;
|
|
8964
|
+
}
|
|
8965
|
+
}
|
|
8966
|
+
const taskLines = (input2.tasks ?? []).slice(0, 10).map((task) => {
|
|
8967
|
+
const status = asString(task.status, "unknown");
|
|
8968
|
+
const priority = asString(task.priority, "?").toUpperCase();
|
|
8969
|
+
const title = asString(task.title, "untitled");
|
|
8970
|
+
const taskFile = asString(task.task_file);
|
|
8971
|
+
return `- [${status}/${priority}] ${title}${taskFile ? ` (${taskFile})` : ""}`;
|
|
8972
|
+
});
|
|
8973
|
+
const parts = [
|
|
8974
|
+
`CONTEXT CHECKPOINT [auto:${input2.reason}]`,
|
|
8975
|
+
`Agent: ${input2.agentId} (${input2.agentRole})`,
|
|
8976
|
+
`Session: ${input2.sessionId}`,
|
|
8977
|
+
`Project: ${input2.projectName}`,
|
|
8978
|
+
`Time: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
8979
|
+
"",
|
|
8980
|
+
"## Recent Activity",
|
|
8981
|
+
`- Memories scanned: ${input2.memories.length}`,
|
|
8982
|
+
`- Projects: ${topEntries(projectCounts, 5).join(", ") || input2.projectName}`,
|
|
8983
|
+
`- Tools: ${topEntries(toolCounts, 8).join(", ") || "none"}`
|
|
8984
|
+
];
|
|
8985
|
+
if (taskLines.length > 0) {
|
|
8986
|
+
parts.push("", "## Open / Active Tasks", ...taskLines);
|
|
8987
|
+
}
|
|
8988
|
+
if (files.size > 0) {
|
|
8989
|
+
parts.push("", "## Files Mentioned", ...[...files].slice(0, 20).map((f) => `- ${f}`));
|
|
8990
|
+
}
|
|
8991
|
+
if (samples.length > 0) {
|
|
8992
|
+
parts.push("", "## Important Recent Traces", ...samples.map((s) => `- ${s}`));
|
|
8993
|
+
}
|
|
8994
|
+
if (errors.length > 0) {
|
|
8995
|
+
parts.push("", "## Errors / Risks", ...errors.map((e) => `- ${e}`));
|
|
8996
|
+
}
|
|
8997
|
+
if (decisionTexts.length > 0) {
|
|
8998
|
+
parts.push("", "## Decision Candidates", ...decisionTexts.map((d) => `- ${d.replace(/^AUTO DECISION CANDIDATE \\[[^\\]]+\\]: /, "")}`));
|
|
8999
|
+
}
|
|
9000
|
+
return {
|
|
9001
|
+
checkpointText: parts.join("\n"),
|
|
9002
|
+
decisionTexts
|
|
9003
|
+
};
|
|
9004
|
+
}
|
|
9005
|
+
|
|
9006
|
+
// src/adapters/claude/hooks/session-end.ts
|
|
8917
9007
|
if (!process.env.AGENT_ID) {
|
|
8918
9008
|
process.env.AGENT_ID = "default";
|
|
8919
9009
|
process.env.AGENT_ROLE = "employee";
|
|
@@ -8946,16 +9036,59 @@ process.stdin.on("end", async () => {
|
|
|
8946
9036
|
});
|
|
8947
9037
|
const orphanInfo = orphanResult.rows.length > 0 ? `
|
|
8948
9038
|
Orphaned tasks at session end: ${orphanResult.rows.map((r) => `"${String(r.title)}" (${String(r.status)})`).join(", ")}` : "";
|
|
9039
|
+
const projectName = process.env.EXE_PROJECT_NAME ?? process.cwd().split("/").pop() ?? "unknown";
|
|
9040
|
+
const recent = await client.execute({
|
|
9041
|
+
sql: `SELECT tool_name, project_name, raw_text, has_error, timestamp
|
|
9042
|
+
FROM memories
|
|
9043
|
+
WHERE agent_id = ?
|
|
9044
|
+
ORDER BY timestamp DESC
|
|
9045
|
+
LIMIT 75`,
|
|
9046
|
+
args: [agent.agentId]
|
|
9047
|
+
});
|
|
9048
|
+
const taskRows = await client.execute({
|
|
9049
|
+
sql: `SELECT title, status, task_file, priority
|
|
9050
|
+
FROM tasks
|
|
9051
|
+
WHERE assigned_to = ? AND status IN ('open', 'in_progress')${seScope.sql}
|
|
9052
|
+
ORDER BY priority ASC, updated_at DESC LIMIT 10`,
|
|
9053
|
+
args: [agent.agentId, ...seScope.args]
|
|
9054
|
+
});
|
|
9055
|
+
const { checkpointText, decisionTexts } = buildAutoCheckpoint({
|
|
9056
|
+
agentId: agent.agentId,
|
|
9057
|
+
agentRole: agent.agentRole,
|
|
9058
|
+
sessionId: data.session_id,
|
|
9059
|
+
projectName,
|
|
9060
|
+
reason: "session-end",
|
|
9061
|
+
memories: recent.rows,
|
|
9062
|
+
tasks: taskRows.rows,
|
|
9063
|
+
maxSamples: 12
|
|
9064
|
+
});
|
|
8949
9065
|
const { writeMemoryViaDaemon: writeMemoryViaDaemon2 } = await Promise.resolve().then(() => (init_memory_queue_client(), memory_queue_client_exports));
|
|
8950
9066
|
await writeMemoryViaDaemon2({
|
|
8951
|
-
raw_text:
|
|
9067
|
+
raw_text: `${checkpointText}${orphanInfo ? `
|
|
9068
|
+
|
|
9069
|
+
## Session-End Warnings${orphanInfo}` : ""}`,
|
|
8952
9070
|
agent_id: agent.agentId,
|
|
8953
9071
|
agent_role: agent.agentRole,
|
|
8954
9072
|
session_id: data.session_id,
|
|
8955
9073
|
tool_name: "SessionEnd",
|
|
8956
|
-
project_name:
|
|
8957
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
9074
|
+
project_name: projectName,
|
|
9075
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9076
|
+
importance: 8,
|
|
9077
|
+
memory_type: "checkpoint"
|
|
8958
9078
|
});
|
|
9079
|
+
for (const decisionText of decisionTexts.slice(0, 5)) {
|
|
9080
|
+
await writeMemoryViaDaemon2({
|
|
9081
|
+
raw_text: decisionText,
|
|
9082
|
+
agent_id: agent.agentId,
|
|
9083
|
+
agent_role: agent.agentRole,
|
|
9084
|
+
session_id: data.session_id,
|
|
9085
|
+
tool_name: "auto-decision",
|
|
9086
|
+
project_name: projectName,
|
|
9087
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9088
|
+
importance: 8,
|
|
9089
|
+
memory_type: "decision"
|
|
9090
|
+
});
|
|
9091
|
+
}
|
|
8959
9092
|
try {
|
|
8960
9093
|
const { clearSessionFileReads: clearSessionFileReads2 } = await Promise.resolve().then(() => (init_git_staleness(), git_staleness_exports));
|
|
8961
9094
|
await clearSessionFileReads2(data.session_id);
|
|
@@ -3290,8 +3290,8 @@ function deriveMachineKey() {
|
|
|
3290
3290
|
}
|
|
3291
3291
|
function readMachineId() {
|
|
3292
3292
|
try {
|
|
3293
|
-
const { readFileSync:
|
|
3294
|
-
return
|
|
3293
|
+
const { readFileSync: readFileSync14 } = __require("fs");
|
|
3294
|
+
return readFileSync14("/etc/machine-id", "utf-8").trim();
|
|
3295
3295
|
} catch {
|
|
3296
3296
|
return "";
|
|
3297
3297
|
}
|
|
@@ -3453,6 +3453,9 @@ function classifyMemoryType(input2) {
|
|
|
3453
3453
|
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3454
3454
|
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3455
3455
|
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3456
|
+
if (tool.includes("checkpoint") || text.startsWith("context checkpoint")) return "checkpoint";
|
|
3457
|
+
if (tool.includes("sessionsummary") || tool.includes("session-summary")) return "summary";
|
|
3458
|
+
if (tool.includes("sessionend") || text.startsWith("session ended")) return "summary";
|
|
3456
3459
|
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3457
3460
|
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3458
3461
|
return "raw";
|
|
@@ -3545,10 +3548,10 @@ async function runPostWriteMemoryHygiene(memoryId) {
|
|
|
3545
3548
|
const row = current.rows[0];
|
|
3546
3549
|
if (!row) return;
|
|
3547
3550
|
const memoryType = String(row.memory_type ?? "raw");
|
|
3548
|
-
const
|
|
3551
|
+
const contentHash2 = row.content_hash ? String(row.content_hash) : null;
|
|
3549
3552
|
const agentId = String(row.agent_id);
|
|
3550
3553
|
const projectName = String(row.project_name);
|
|
3551
|
-
if (
|
|
3554
|
+
if (contentHash2) {
|
|
3552
3555
|
await client.execute({
|
|
3553
3556
|
sql: `UPDATE memories
|
|
3554
3557
|
SET status = 'deleted',
|
|
@@ -3559,7 +3562,7 @@ async function runPostWriteMemoryHygiene(memoryId) {
|
|
|
3559
3562
|
AND project_name = ?
|
|
3560
3563
|
AND COALESCE(memory_type, 'raw') = ?
|
|
3561
3564
|
AND COALESCE(status, 'active') = 'active'`,
|
|
3562
|
-
args: [memoryId,
|
|
3565
|
+
args: [memoryId, contentHash2, agentId, projectName, memoryType]
|
|
3563
3566
|
});
|
|
3564
3567
|
}
|
|
3565
3568
|
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
@@ -3595,6 +3598,7 @@ async function runPostWriteMemoryHygiene(memoryId) {
|
|
|
3595
3598
|
}
|
|
3596
3599
|
}
|
|
3597
3600
|
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3601
|
+
if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
3598
3602
|
if (memoryIds.length === 0) return;
|
|
3599
3603
|
const run = () => {
|
|
3600
3604
|
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
@@ -3989,7 +3993,7 @@ var init_platform_procedures = __esm({
|
|
|
3989
3993
|
title: "Chain of command \u2014 who talks to whom",
|
|
3990
3994
|
domain: "workflow",
|
|
3991
3995
|
priority: "p0",
|
|
3992
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
3996
|
+
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."
|
|
3993
3997
|
},
|
|
3994
3998
|
{
|
|
3995
3999
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -4336,16 +4340,16 @@ async function writeMemory(record) {
|
|
|
4336
4340
|
const governed = governMemoryRecord(record);
|
|
4337
4341
|
if (governed.shouldDrop) return;
|
|
4338
4342
|
record = governed.record;
|
|
4339
|
-
const
|
|
4343
|
+
const contentHash2 = governed.contentHash;
|
|
4340
4344
|
const memoryType = record.memory_type ?? "raw";
|
|
4341
4345
|
if (_pendingRecords.some(
|
|
4342
|
-
(r) => r.content_hash ===
|
|
4346
|
+
(r) => r.content_hash === contentHash2 && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
4343
4347
|
)) {
|
|
4344
4348
|
return;
|
|
4345
4349
|
}
|
|
4346
4350
|
try {
|
|
4347
4351
|
const existing = await findScopedDuplicate({
|
|
4348
|
-
contentHash,
|
|
4352
|
+
contentHash: contentHash2,
|
|
4349
4353
|
agentId: record.agent_id,
|
|
4350
4354
|
projectName: record.project_name,
|
|
4351
4355
|
memoryType
|
|
@@ -4383,7 +4387,7 @@ async function writeMemory(record) {
|
|
|
4383
4387
|
draft: record.draft ? 1 : 0,
|
|
4384
4388
|
memory_type: memoryType,
|
|
4385
4389
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
4386
|
-
content_hash:
|
|
4390
|
+
content_hash: contentHash2,
|
|
4387
4391
|
intent: record.intent ?? null,
|
|
4388
4392
|
outcome: record.outcome ?? null,
|
|
4389
4393
|
domain: record.domain ?? inferDomain(record),
|
|
@@ -4456,7 +4460,7 @@ async function flushBatch() {
|
|
|
4456
4460
|
const draft = row.draft ? 1 : 0;
|
|
4457
4461
|
const memoryType = row.memory_type ?? "raw";
|
|
4458
4462
|
const trajectory = row.trajectory ?? null;
|
|
4459
|
-
const
|
|
4463
|
+
const contentHash2 = row.content_hash ?? null;
|
|
4460
4464
|
const intent = row.intent ?? null;
|
|
4461
4465
|
const outcome = row.outcome ?? null;
|
|
4462
4466
|
const domain = row.domain ?? null;
|
|
@@ -4528,7 +4532,7 @@ async function flushBatch() {
|
|
|
4528
4532
|
draft,
|
|
4529
4533
|
memoryType,
|
|
4530
4534
|
trajectory,
|
|
4531
|
-
|
|
4535
|
+
contentHash2
|
|
4532
4536
|
];
|
|
4533
4537
|
return {
|
|
4534
4538
|
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
@@ -4661,7 +4665,11 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
4661
4665
|
sql += ` AND timestamp >= ?`;
|
|
4662
4666
|
args.push(options.since);
|
|
4663
4667
|
}
|
|
4664
|
-
if (options?.
|
|
4668
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
4669
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
4670
|
+
sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
4671
|
+
args.push(...uniqueTypes);
|
|
4672
|
+
} else if (options?.memoryType) {
|
|
4665
4673
|
sql += ` AND memory_type = ?`;
|
|
4666
4674
|
args.push(options.memoryType);
|
|
4667
4675
|
}
|
|
@@ -5066,10 +5074,10 @@ async function disposeEmbedder() {
|
|
|
5066
5074
|
async function embedDirect(text) {
|
|
5067
5075
|
const llamaCpp = await import("node-llama-cpp");
|
|
5068
5076
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
5069
|
-
const { existsSync:
|
|
5070
|
-
const
|
|
5071
|
-
const modelPath =
|
|
5072
|
-
if (!
|
|
5077
|
+
const { existsSync: existsSync17 } = await import("fs");
|
|
5078
|
+
const path21 = await import("path");
|
|
5079
|
+
const modelPath = path21.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
5080
|
+
if (!existsSync17(modelPath)) {
|
|
5073
5081
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
5074
5082
|
}
|
|
5075
5083
|
const llama = await llamaCpp.getLlama();
|
|
@@ -5959,6 +5967,17 @@ __export(hybrid_search_exports, {
|
|
|
5959
5967
|
rrfMerge: () => rrfMerge,
|
|
5960
5968
|
rrfMergeMulti: () => rrfMergeMulti
|
|
5961
5969
|
});
|
|
5970
|
+
function appendMemoryTypeFilter(sql, args, column, options) {
|
|
5971
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
5972
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
5973
|
+
sql += ` AND ${column} IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
5974
|
+
args.push(...uniqueTypes);
|
|
5975
|
+
} else if (options?.memoryType) {
|
|
5976
|
+
sql += ` AND ${column} = ?`;
|
|
5977
|
+
args.push(options.memoryType);
|
|
5978
|
+
}
|
|
5979
|
+
return sql;
|
|
5980
|
+
}
|
|
5962
5981
|
async function hybridSearch(queryText, agentId, options) {
|
|
5963
5982
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
5964
5983
|
const config = await loadConfig2();
|
|
@@ -6054,7 +6073,7 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
6054
6073
|
}
|
|
6055
6074
|
if (lists.length === 0) return [];
|
|
6056
6075
|
if (lists.length === 1 && !effectiveIsBroad) return lists[0].slice(0, limit);
|
|
6057
|
-
const rrfLimit = effectiveIsBroad ? Math.max(limit * 5,
|
|
6076
|
+
const rrfLimit = effectiveIsBroad ? Math.max(limit * 5, broadFetchTopK) : limit;
|
|
6058
6077
|
let merged = lists.length === 1 ? lists[0].slice(0, rrfLimit) : rrfMergeMulti(lists, rrfLimit, RRF_K, weights);
|
|
6059
6078
|
let graphContextMap = /* @__PURE__ */ new Map();
|
|
6060
6079
|
let entityBoostRan = false;
|
|
@@ -6075,6 +6094,7 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
6075
6094
|
returnTopK: 5
|
|
6076
6095
|
};
|
|
6077
6096
|
let rerankedAndBlended = null;
|
|
6097
|
+
const rerankReturnLimit = Math.max(limit, auto.returnTopK ?? 5);
|
|
6078
6098
|
if (effectiveIsBroad && auto.enabled && rerankerAvailable) {
|
|
6079
6099
|
const cardinality2 = await estimateCardinality(agentId, effectiveOptions);
|
|
6080
6100
|
if (cardinality2 > auto.broadQueryMinCardinality) {
|
|
@@ -6086,16 +6106,16 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
6086
6106
|
text: m.raw_text,
|
|
6087
6107
|
context: graphContextMap.get(m.id)
|
|
6088
6108
|
}));
|
|
6089
|
-
const scored = await rerankWithContext2(effectiveQuery, candidates,
|
|
6109
|
+
const scored = await rerankWithContext2(effectiveQuery, candidates, rerankReturnLimit);
|
|
6090
6110
|
rerankedRecords = scored.map((s) => merged[s.index]);
|
|
6091
6111
|
} else {
|
|
6092
6112
|
const { rerank: rerank2 } = await Promise.resolve().then(() => (init_reranker(), reranker_exports));
|
|
6093
|
-
rerankedRecords = await rerank2(effectiveQuery, merged,
|
|
6113
|
+
rerankedRecords = await rerank2(effectiveQuery, merged, rerankReturnLimit);
|
|
6094
6114
|
}
|
|
6095
6115
|
if (rerankedRecords.length > 0) {
|
|
6096
6116
|
rerankedAndBlended = rrfMergeMulti(
|
|
6097
6117
|
[rerankedRecords],
|
|
6098
|
-
|
|
6118
|
+
rerankReturnLimit,
|
|
6099
6119
|
RRF_K
|
|
6100
6120
|
);
|
|
6101
6121
|
}
|
|
@@ -6103,10 +6123,7 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
6103
6123
|
}
|
|
6104
6124
|
}
|
|
6105
6125
|
}
|
|
6106
|
-
const finalResults = (rerankedAndBlended ?? merged).slice(
|
|
6107
|
-
0,
|
|
6108
|
-
rerankedAndBlended ? auto.returnTopK : limit
|
|
6109
|
-
);
|
|
6126
|
+
const finalResults = (rerankedAndBlended ?? merged).slice(0, limit);
|
|
6110
6127
|
if (options?.includeSource && finalResults.length > 0) {
|
|
6111
6128
|
await attachDocumentMetadata(finalResults);
|
|
6112
6129
|
}
|
|
@@ -6137,10 +6154,10 @@ async function hybridSearch(queryText, agentId, options) {
|
|
|
6137
6154
|
};
|
|
6138
6155
|
try {
|
|
6139
6156
|
const fs = await import("fs");
|
|
6140
|
-
const
|
|
6157
|
+
const path21 = await import("path");
|
|
6141
6158
|
const os10 = await import("os");
|
|
6142
|
-
const logPath =
|
|
6143
|
-
fs.mkdirSync(
|
|
6159
|
+
const logPath = path21.join(os10.homedir(), ".exe-os", "search-quality.jsonl");
|
|
6160
|
+
fs.mkdirSync(path21.dirname(logPath), { recursive: true });
|
|
6144
6161
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
6145
6162
|
} catch {
|
|
6146
6163
|
}
|
|
@@ -6187,6 +6204,7 @@ async function estimateCardinality(agentId, options) {
|
|
|
6187
6204
|
sql += ` AND timestamp >= ?`;
|
|
6188
6205
|
args.push(options.since);
|
|
6189
6206
|
}
|
|
6207
|
+
sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
|
|
6190
6208
|
try {
|
|
6191
6209
|
const result = await client.execute({ sql, args });
|
|
6192
6210
|
return Number(result.rows[0]?.cnt) || 0;
|
|
@@ -6308,10 +6326,7 @@ async function ftsQuery(client, matchExpr, agentId, options, limit) {
|
|
|
6308
6326
|
sql += ` AND m.timestamp >= ?`;
|
|
6309
6327
|
args.push(options.since);
|
|
6310
6328
|
}
|
|
6311
|
-
|
|
6312
|
-
sql += ` AND m.memory_type = ?`;
|
|
6313
|
-
args.push(options.memoryType);
|
|
6314
|
-
}
|
|
6329
|
+
sql = appendMemoryTypeFilter(sql, args, "m.memory_type", options);
|
|
6315
6330
|
sql += ` ORDER BY rank LIMIT ?`;
|
|
6316
6331
|
args.push(limit);
|
|
6317
6332
|
const result = await client.execute({ sql, args });
|
|
@@ -6368,9 +6383,16 @@ async function recentRecords(agentId, options, limit, textFilter) {
|
|
|
6368
6383
|
AND timestamp >= ? AND timestamp <= ?
|
|
6369
6384
|
AND COALESCE(status, 'active') = 'active'
|
|
6370
6385
|
AND ${options?.includeRaw === false ? "COALESCE(memory_type, 'raw') != 'raw'" : "1 = 1"}
|
|
6386
|
+
${options?.memoryTypes?.length ? `AND memory_type IN (${options.memoryTypes.map(() => "?").join(",")})` : options?.memoryType ? "AND memory_type = ?" : ""}
|
|
6371
6387
|
AND COALESCE(confidence, 0.7) >= 0.3
|
|
6372
6388
|
ORDER BY timestamp DESC LIMIT ?`,
|
|
6373
|
-
args: [
|
|
6389
|
+
args: [
|
|
6390
|
+
agentId,
|
|
6391
|
+
windowStart,
|
|
6392
|
+
killedAt,
|
|
6393
|
+
...options?.memoryTypes?.length ? [...new Set(options.memoryTypes)] : options?.memoryType ? [options.memoryType] : [],
|
|
6394
|
+
boundarySlots
|
|
6395
|
+
]
|
|
6374
6396
|
});
|
|
6375
6397
|
for (const row of boundaryResult.rows) {
|
|
6376
6398
|
sessionBoundaryMemories.push(rowToMemoryRecord(row));
|
|
@@ -6416,10 +6438,7 @@ async function recentRecords(agentId, options, limit, textFilter) {
|
|
|
6416
6438
|
sql += ` AND timestamp >= ?`;
|
|
6417
6439
|
args.push(options.since);
|
|
6418
6440
|
}
|
|
6419
|
-
|
|
6420
|
-
sql += ` AND memory_type = ?`;
|
|
6421
|
-
args.push(options.memoryType);
|
|
6422
|
-
}
|
|
6441
|
+
sql = appendMemoryTypeFilter(sql, args, "memory_type", options);
|
|
6423
6442
|
if (textFilter) {
|
|
6424
6443
|
sql += ` AND raw_text LIKE '%' || ? || '%'`;
|
|
6425
6444
|
args.push(textFilter);
|
|
@@ -7443,10 +7462,145 @@ var init_git_staleness = __esm({
|
|
|
7443
7462
|
}
|
|
7444
7463
|
});
|
|
7445
7464
|
|
|
7465
|
+
// src/lib/identity.ts
|
|
7466
|
+
var identity_exports = {};
|
|
7467
|
+
__export(identity_exports, {
|
|
7468
|
+
getIdentity: () => getIdentity,
|
|
7469
|
+
getIdentityInjection: () => getIdentityInjection,
|
|
7470
|
+
identityPath: () => identityPath,
|
|
7471
|
+
listIdentities: () => listIdentities,
|
|
7472
|
+
updateIdentity: () => updateIdentity
|
|
7473
|
+
});
|
|
7474
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "fs";
|
|
7475
|
+
import { readdirSync as readdirSync5 } from "fs";
|
|
7476
|
+
import path19 from "path";
|
|
7477
|
+
import { createHash as createHash2 } from "crypto";
|
|
7478
|
+
function ensureDir() {
|
|
7479
|
+
if (!existsSync15(IDENTITY_DIR2)) {
|
|
7480
|
+
mkdirSync7(IDENTITY_DIR2, { recursive: true });
|
|
7481
|
+
}
|
|
7482
|
+
}
|
|
7483
|
+
function identityPath(agentId) {
|
|
7484
|
+
return path19.join(IDENTITY_DIR2, `${agentId}.md`);
|
|
7485
|
+
}
|
|
7486
|
+
function parseFrontmatter(raw) {
|
|
7487
|
+
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
7488
|
+
if (!match) {
|
|
7489
|
+
return {
|
|
7490
|
+
frontmatter: {
|
|
7491
|
+
role: "unknown",
|
|
7492
|
+
title: "Unknown",
|
|
7493
|
+
agent_id: "unknown",
|
|
7494
|
+
org_level: "specialist",
|
|
7495
|
+
created_by: "system",
|
|
7496
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
7497
|
+
},
|
|
7498
|
+
body: raw
|
|
7499
|
+
};
|
|
7500
|
+
}
|
|
7501
|
+
const yamlStr = match[1];
|
|
7502
|
+
const body = match[2].trim();
|
|
7503
|
+
const fm = {};
|
|
7504
|
+
for (const line of yamlStr.split("\n")) {
|
|
7505
|
+
const kv = line.match(/^(\w+):\s*(.+)$/);
|
|
7506
|
+
if (kv) fm[kv[1]] = kv[2].trim();
|
|
7507
|
+
}
|
|
7508
|
+
return {
|
|
7509
|
+
frontmatter: {
|
|
7510
|
+
role: fm.role ?? "unknown",
|
|
7511
|
+
title: fm.title ?? "Unknown",
|
|
7512
|
+
agent_id: fm.agent_id ?? "unknown",
|
|
7513
|
+
org_level: fm.org_level ?? "specialist",
|
|
7514
|
+
created_by: fm.created_by ?? "system",
|
|
7515
|
+
updated_at: fm.updated_at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
7516
|
+
},
|
|
7517
|
+
body
|
|
7518
|
+
};
|
|
7519
|
+
}
|
|
7520
|
+
function contentHash(content) {
|
|
7521
|
+
return createHash2("sha256").update(content).digest("hex").slice(0, 16);
|
|
7522
|
+
}
|
|
7523
|
+
function getIdentity(agentId) {
|
|
7524
|
+
const filePath = identityPath(agentId);
|
|
7525
|
+
if (!existsSync15(filePath)) return null;
|
|
7526
|
+
const raw = readFileSync12(filePath, "utf-8");
|
|
7527
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
7528
|
+
return {
|
|
7529
|
+
agentId,
|
|
7530
|
+
frontmatter,
|
|
7531
|
+
body,
|
|
7532
|
+
raw,
|
|
7533
|
+
contentHash: contentHash(raw)
|
|
7534
|
+
};
|
|
7535
|
+
}
|
|
7536
|
+
async function updateIdentity(agentId, content, updatedBy) {
|
|
7537
|
+
ensureDir();
|
|
7538
|
+
const filePath = identityPath(agentId);
|
|
7539
|
+
const hash = contentHash(content);
|
|
7540
|
+
writeFileSync8(filePath, content, "utf-8");
|
|
7541
|
+
try {
|
|
7542
|
+
const client = getClient();
|
|
7543
|
+
await client.execute({
|
|
7544
|
+
sql: `INSERT INTO identity (agent_id, content_hash, updated_at, updated_by)
|
|
7545
|
+
VALUES (?, ?, ?, ?)
|
|
7546
|
+
ON CONFLICT(agent_id) DO UPDATE SET
|
|
7547
|
+
content_hash = excluded.content_hash,
|
|
7548
|
+
updated_at = excluded.updated_at,
|
|
7549
|
+
updated_by = excluded.updated_by`,
|
|
7550
|
+
args: [agentId, hash, (/* @__PURE__ */ new Date()).toISOString(), updatedBy]
|
|
7551
|
+
});
|
|
7552
|
+
} catch {
|
|
7553
|
+
}
|
|
7554
|
+
}
|
|
7555
|
+
function listIdentities() {
|
|
7556
|
+
ensureDir();
|
|
7557
|
+
const files = readdirSync5(IDENTITY_DIR2).filter((f) => f.endsWith(".md"));
|
|
7558
|
+
const results = [];
|
|
7559
|
+
for (const file of files) {
|
|
7560
|
+
const agentId = file.replace(".md", "");
|
|
7561
|
+
const identity = getIdentity(agentId);
|
|
7562
|
+
if (!identity) continue;
|
|
7563
|
+
const lines = identity.body.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
|
|
7564
|
+
const summary = lines[0]?.trim().slice(0, 120) ?? identity.frontmatter.title;
|
|
7565
|
+
results.push({
|
|
7566
|
+
agentId,
|
|
7567
|
+
title: `${identity.frontmatter.title} (${identity.frontmatter.role.toUpperCase()})`,
|
|
7568
|
+
summary
|
|
7569
|
+
});
|
|
7570
|
+
}
|
|
7571
|
+
return results;
|
|
7572
|
+
}
|
|
7573
|
+
function getIdentityInjection(agentId) {
|
|
7574
|
+
const own = getIdentity(agentId);
|
|
7575
|
+
const all = listIdentities();
|
|
7576
|
+
const parts = [];
|
|
7577
|
+
if (own) {
|
|
7578
|
+
parts.push(`## Your Identity (exe.md)
|
|
7579
|
+
These define WHO YOU ARE. Non-negotiable. Permanent.
|
|
7580
|
+
|
|
7581
|
+
${own.body}`);
|
|
7582
|
+
}
|
|
7583
|
+
const teamLines = all.filter((a) => a.agentId !== agentId).map((a) => `- ${a.agentId} (${a.title}): ${a.summary}`);
|
|
7584
|
+
if (teamLines.length > 0) {
|
|
7585
|
+
parts.push(`## Team Identities
|
|
7586
|
+
${teamLines.join("\n")}`);
|
|
7587
|
+
}
|
|
7588
|
+
return parts.join("\n\n");
|
|
7589
|
+
}
|
|
7590
|
+
var IDENTITY_DIR2;
|
|
7591
|
+
var init_identity = __esm({
|
|
7592
|
+
"src/lib/identity.ts"() {
|
|
7593
|
+
"use strict";
|
|
7594
|
+
init_config();
|
|
7595
|
+
init_database();
|
|
7596
|
+
IDENTITY_DIR2 = path19.join(EXE_AI_DIR, "identity");
|
|
7597
|
+
}
|
|
7598
|
+
});
|
|
7599
|
+
|
|
7446
7600
|
// src/adapters/claude/hooks/session-start.ts
|
|
7447
7601
|
init_config();
|
|
7448
|
-
import
|
|
7449
|
-
import { unlinkSync as unlinkSync4, existsSync as
|
|
7602
|
+
import path20 from "path";
|
|
7603
|
+
import { unlinkSync as unlinkSync4, existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
|
|
7450
7604
|
if (!process.env.AGENT_ID) {
|
|
7451
7605
|
process.env.AGENT_ID = "default";
|
|
7452
7606
|
process.env.AGENT_ROLE = "employee";
|
|
@@ -7479,8 +7633,8 @@ process.stdin.on("end", async () => {
|
|
|
7479
7633
|
const sessionScope = getCurrentSessionScope2();
|
|
7480
7634
|
if (source === "startup") {
|
|
7481
7635
|
try {
|
|
7482
|
-
const undefinedPath =
|
|
7483
|
-
process.env.EXE_OS_DIR ??
|
|
7636
|
+
const undefinedPath = path20.join(
|
|
7637
|
+
process.env.EXE_OS_DIR ?? path20.join(process.env.HOME ?? "", ".exe-os"),
|
|
7484
7638
|
"session-cache",
|
|
7485
7639
|
"active-agent-undefined.json"
|
|
7486
7640
|
);
|
|
@@ -7494,13 +7648,13 @@ process.stdin.on("end", async () => {
|
|
|
7494
7648
|
const agentId = agent.agentId;
|
|
7495
7649
|
if (agentId !== "default") {
|
|
7496
7650
|
try {
|
|
7497
|
-
const cacheDir =
|
|
7498
|
-
process.env.EXE_OS_DIR ??
|
|
7651
|
+
const cacheDir = path20.join(
|
|
7652
|
+
process.env.EXE_OS_DIR ?? path20.join(process.env.HOME ?? "", ".exe-os"),
|
|
7499
7653
|
"session-cache"
|
|
7500
7654
|
);
|
|
7501
|
-
const markerPath =
|
|
7502
|
-
if (
|
|
7503
|
-
const marker = JSON.parse(
|
|
7655
|
+
const markerPath = path20.join(cacheDir, `current-task-${agentId}.json`);
|
|
7656
|
+
if (existsSync16(markerPath)) {
|
|
7657
|
+
const marker = JSON.parse(readFileSync13(markerPath, "utf-8"));
|
|
7504
7658
|
if (marker.taskId) {
|
|
7505
7659
|
const client = getClient2();
|
|
7506
7660
|
const markerScope = sessionScopeFilter2(sessionScope);
|
|
@@ -7608,6 +7762,22 @@ flow, so bug fixes are fast.`;
|
|
|
7608
7762
|
} catch {
|
|
7609
7763
|
}
|
|
7610
7764
|
let additionalContext = "";
|
|
7765
|
+
if (agentId !== "default") {
|
|
7766
|
+
try {
|
|
7767
|
+
const { getIdentity: getIdentity2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
7768
|
+
const identity = getIdentity2(agentId);
|
|
7769
|
+
if (identity) {
|
|
7770
|
+
const title = identity.frontmatter.title ?? identity.frontmatter.role ?? agentId;
|
|
7771
|
+
const role = identity.frontmatter.role ?? "";
|
|
7772
|
+
const firstLine = identity.body.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
7773
|
+
additionalContext += `## Your Identity
|
|
7774
|
+
You are **${title}**${role ? ` (${role})` : ""}. ${firstLine}
|
|
7775
|
+
|
|
7776
|
+
`;
|
|
7777
|
+
}
|
|
7778
|
+
} catch {
|
|
7779
|
+
}
|
|
7780
|
+
}
|
|
7611
7781
|
if (memories.length > 0) {
|
|
7612
7782
|
const brief = memories.map(
|
|
7613
7783
|
(m) => `[${m.timestamp}] ${m.tool_name}: ${m.raw_text.slice(0, 200)}`
|