@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
|
@@ -2299,6 +2299,14 @@ async function ensureSchema() {
|
|
|
2299
2299
|
);
|
|
2300
2300
|
} catch {
|
|
2301
2301
|
}
|
|
2302
|
+
try {
|
|
2303
|
+
await client.execute(
|
|
2304
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
2305
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
2306
|
+
WHERE content_hash IS NOT NULL`
|
|
2307
|
+
);
|
|
2308
|
+
} catch {
|
|
2309
|
+
}
|
|
2302
2310
|
await client.executeMultiple(`
|
|
2303
2311
|
CREATE TABLE IF NOT EXISTS entities (
|
|
2304
2312
|
id TEXT PRIMARY KEY,
|
|
@@ -3044,6 +3052,197 @@ var init_state_bus = __esm({
|
|
|
3044
3052
|
}
|
|
3045
3053
|
});
|
|
3046
3054
|
|
|
3055
|
+
// src/lib/memory-write-governor.ts
|
|
3056
|
+
import { createHash } from "crypto";
|
|
3057
|
+
function normalizeMemoryText(text) {
|
|
3058
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
3059
|
+
}
|
|
3060
|
+
function classifyMemoryType(input) {
|
|
3061
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
3062
|
+
const tool = input.tool_name.toLowerCase();
|
|
3063
|
+
const text = input.raw_text.toLowerCase();
|
|
3064
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
3065
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
3066
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
3067
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
3068
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
3069
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
3070
|
+
return "raw";
|
|
3071
|
+
}
|
|
3072
|
+
function shouldDropMemory(text) {
|
|
3073
|
+
const normalized = normalizeMemoryText(text);
|
|
3074
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
3075
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
3076
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
3077
|
+
}
|
|
3078
|
+
return { drop: false };
|
|
3079
|
+
}
|
|
3080
|
+
function shouldSkipEmbedding(input) {
|
|
3081
|
+
const type = classifyMemoryType(input);
|
|
3082
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
3083
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
3084
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
3085
|
+
return false;
|
|
3086
|
+
}
|
|
3087
|
+
function hashMemoryContent(text) {
|
|
3088
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
3089
|
+
}
|
|
3090
|
+
function scopedDedupArgs(input) {
|
|
3091
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
3092
|
+
}
|
|
3093
|
+
function governMemoryRecord(record) {
|
|
3094
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
3095
|
+
const memoryType = classifyMemoryType({
|
|
3096
|
+
raw_text: normalized,
|
|
3097
|
+
agent_id: record.agent_id,
|
|
3098
|
+
project_name: record.project_name,
|
|
3099
|
+
tool_name: record.tool_name,
|
|
3100
|
+
memory_type: record.memory_type
|
|
3101
|
+
});
|
|
3102
|
+
const drop = shouldDropMemory(normalized);
|
|
3103
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
3104
|
+
raw_text: normalized,
|
|
3105
|
+
agent_id: record.agent_id,
|
|
3106
|
+
project_name: record.project_name,
|
|
3107
|
+
tool_name: record.tool_name,
|
|
3108
|
+
memory_type: memoryType
|
|
3109
|
+
});
|
|
3110
|
+
return {
|
|
3111
|
+
record: {
|
|
3112
|
+
...record,
|
|
3113
|
+
raw_text: normalized,
|
|
3114
|
+
memory_type: memoryType,
|
|
3115
|
+
vector: skipEmbedding ? null : record.vector
|
|
3116
|
+
},
|
|
3117
|
+
contentHash: hashMemoryContent(normalized),
|
|
3118
|
+
shouldDrop: drop.drop,
|
|
3119
|
+
dropReason: drop.reason,
|
|
3120
|
+
skipEmbedding,
|
|
3121
|
+
hygiene: {
|
|
3122
|
+
dedup: true,
|
|
3123
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
3124
|
+
}
|
|
3125
|
+
};
|
|
3126
|
+
}
|
|
3127
|
+
async function findScopedDuplicate(input) {
|
|
3128
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3129
|
+
const client = getClient2();
|
|
3130
|
+
const args = scopedDedupArgs(input);
|
|
3131
|
+
let sql = `SELECT id FROM memories
|
|
3132
|
+
WHERE content_hash = ?
|
|
3133
|
+
AND agent_id = ?
|
|
3134
|
+
AND project_name = ?
|
|
3135
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3136
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
3137
|
+
if (input.excludeId) {
|
|
3138
|
+
sql += " AND id != ?";
|
|
3139
|
+
args.push(input.excludeId);
|
|
3140
|
+
}
|
|
3141
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
3142
|
+
const result = await client.execute({ sql, args });
|
|
3143
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
3144
|
+
}
|
|
3145
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
3146
|
+
try {
|
|
3147
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3148
|
+
const client = getClient2();
|
|
3149
|
+
const current = await client.execute({
|
|
3150
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
3151
|
+
importance, timestamp
|
|
3152
|
+
FROM memories
|
|
3153
|
+
WHERE id = ?
|
|
3154
|
+
LIMIT 1`,
|
|
3155
|
+
args: [memoryId]
|
|
3156
|
+
});
|
|
3157
|
+
const row = current.rows[0];
|
|
3158
|
+
if (!row) return;
|
|
3159
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
3160
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
3161
|
+
const agentId = String(row.agent_id);
|
|
3162
|
+
const projectName = String(row.project_name);
|
|
3163
|
+
if (contentHash) {
|
|
3164
|
+
await client.execute({
|
|
3165
|
+
sql: `UPDATE memories
|
|
3166
|
+
SET status = 'deleted',
|
|
3167
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3168
|
+
WHERE id != ?
|
|
3169
|
+
AND content_hash = ?
|
|
3170
|
+
AND agent_id = ?
|
|
3171
|
+
AND project_name = ?
|
|
3172
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
3173
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
3174
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
3175
|
+
});
|
|
3176
|
+
}
|
|
3177
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
3178
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
3179
|
+
const old = await client.execute({
|
|
3180
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
3181
|
+
args: [supersedesId]
|
|
3182
|
+
});
|
|
3183
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
3184
|
+
const newImportance = Number(row.importance ?? 0);
|
|
3185
|
+
await client.batch([
|
|
3186
|
+
{
|
|
3187
|
+
sql: `UPDATE memories
|
|
3188
|
+
SET status = 'archived',
|
|
3189
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
3190
|
+
WHERE id = ?`,
|
|
3191
|
+
args: [supersedesId]
|
|
3192
|
+
},
|
|
3193
|
+
{
|
|
3194
|
+
sql: `UPDATE memories
|
|
3195
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
3196
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
3197
|
+
WHERE id = ?`,
|
|
3198
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
3199
|
+
}
|
|
3200
|
+
], "write");
|
|
3201
|
+
}
|
|
3202
|
+
} catch (err) {
|
|
3203
|
+
process.stderr.write(
|
|
3204
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
3205
|
+
`
|
|
3206
|
+
);
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
3210
|
+
if (process.env.EXE_SKIP_MEMORY_HYGIENE === "1") return;
|
|
3211
|
+
if (memoryIds.length === 0) return;
|
|
3212
|
+
const run = () => {
|
|
3213
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
3214
|
+
};
|
|
3215
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
3216
|
+
else setTimeout(run, 0);
|
|
3217
|
+
}
|
|
3218
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
3219
|
+
var init_memory_write_governor = __esm({
|
|
3220
|
+
"src/lib/memory-write-governor.ts"() {
|
|
3221
|
+
"use strict";
|
|
3222
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
3223
|
+
"decision",
|
|
3224
|
+
"adr",
|
|
3225
|
+
"behavior",
|
|
3226
|
+
"procedure"
|
|
3227
|
+
]);
|
|
3228
|
+
NOISE_DROP_PATTERNS = [
|
|
3229
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
3230
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
3231
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
3232
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
3233
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
3234
|
+
];
|
|
3235
|
+
SKIP_EMBED_PATTERNS = [
|
|
3236
|
+
/tmux capture-pane\b/i,
|
|
3237
|
+
/docker ps\b/i,
|
|
3238
|
+
/docker images\b/i,
|
|
3239
|
+
/git status\b/i,
|
|
3240
|
+
/grep .*node_modules/i,
|
|
3241
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
3242
|
+
];
|
|
3243
|
+
}
|
|
3244
|
+
});
|
|
3245
|
+
|
|
3047
3246
|
// src/lib/shard-manager.ts
|
|
3048
3247
|
var shard_manager_exports = {};
|
|
3049
3248
|
__export(shard_manager_exports, {
|
|
@@ -3208,7 +3407,8 @@ async function ensureShardSchema(client) {
|
|
|
3208
3407
|
}
|
|
3209
3408
|
for (const idx of [
|
|
3210
3409
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
3211
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
3410
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
3411
|
+
"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"
|
|
3212
3412
|
]) {
|
|
3213
3413
|
try {
|
|
3214
3414
|
await client.execute(idx);
|
|
@@ -3402,7 +3602,7 @@ var init_platform_procedures = __esm({
|
|
|
3402
3602
|
title: "Chain of command \u2014 who talks to whom",
|
|
3403
3603
|
domain: "workflow",
|
|
3404
3604
|
priority: "p0",
|
|
3405
|
-
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the
|
|
3605
|
+
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."
|
|
3406
3606
|
},
|
|
3407
3607
|
{
|
|
3408
3608
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -3633,7 +3833,6 @@ __export(store_exports, {
|
|
|
3633
3833
|
vectorToBlob: () => vectorToBlob,
|
|
3634
3834
|
writeMemory: () => writeMemory
|
|
3635
3835
|
});
|
|
3636
|
-
import { createHash } from "crypto";
|
|
3637
3836
|
function isBusyError2(err) {
|
|
3638
3837
|
if (err instanceof Error) {
|
|
3639
3838
|
const msg = err.message.toLowerCase();
|
|
@@ -3747,17 +3946,24 @@ async function writeMemory(record) {
|
|
|
3747
3946
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
3748
3947
|
);
|
|
3749
3948
|
}
|
|
3750
|
-
const
|
|
3751
|
-
if (
|
|
3949
|
+
const governed = governMemoryRecord(record);
|
|
3950
|
+
if (governed.shouldDrop) return;
|
|
3951
|
+
record = governed.record;
|
|
3952
|
+
const contentHash = governed.contentHash;
|
|
3953
|
+
const memoryType = record.memory_type ?? "raw";
|
|
3954
|
+
if (_pendingRecords.some(
|
|
3955
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
3956
|
+
)) {
|
|
3752
3957
|
return;
|
|
3753
3958
|
}
|
|
3754
3959
|
try {
|
|
3755
|
-
const
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3960
|
+
const existing = await findScopedDuplicate({
|
|
3961
|
+
contentHash,
|
|
3962
|
+
agentId: record.agent_id,
|
|
3963
|
+
projectName: record.project_name,
|
|
3964
|
+
memoryType
|
|
3759
3965
|
});
|
|
3760
|
-
if (existing
|
|
3966
|
+
if (existing) return;
|
|
3761
3967
|
} catch {
|
|
3762
3968
|
}
|
|
3763
3969
|
const dbRow = {
|
|
@@ -3788,7 +3994,7 @@ async function writeMemory(record) {
|
|
|
3788
3994
|
tier: record.tier ?? classifyTier(record),
|
|
3789
3995
|
supersedes_id: record.supersedes_id ?? null,
|
|
3790
3996
|
draft: record.draft ? 1 : 0,
|
|
3791
|
-
memory_type:
|
|
3997
|
+
memory_type: memoryType,
|
|
3792
3998
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
3793
3999
|
content_hash: contentHash,
|
|
3794
4000
|
intent: record.intent ?? null,
|
|
@@ -3947,6 +4153,7 @@ async function flushBatch() {
|
|
|
3947
4153
|
const globalClient = getClient();
|
|
3948
4154
|
const globalStmts = batch.map(buildStmt);
|
|
3949
4155
|
await globalClient.batch(globalStmts, "write");
|
|
4156
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
3950
4157
|
_pendingRecords.splice(0, batch.length);
|
|
3951
4158
|
try {
|
|
3952
4159
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -4067,7 +4274,11 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
4067
4274
|
sql += ` AND timestamp >= ?`;
|
|
4068
4275
|
args.push(options.since);
|
|
4069
4276
|
}
|
|
4070
|
-
if (options?.
|
|
4277
|
+
if (options?.memoryTypes && options.memoryTypes.length > 0) {
|
|
4278
|
+
const uniqueTypes = [...new Set(options.memoryTypes)];
|
|
4279
|
+
sql += ` AND memory_type IN (${uniqueTypes.map(() => "?").join(",")})`;
|
|
4280
|
+
args.push(...uniqueTypes);
|
|
4281
|
+
} else if (options?.memoryType) {
|
|
4071
4282
|
sql += ` AND memory_type = ?`;
|
|
4072
4283
|
args.push(options.memoryType);
|
|
4073
4284
|
}
|
|
@@ -4205,6 +4416,7 @@ var init_store = __esm({
|
|
|
4205
4416
|
init_keychain();
|
|
4206
4417
|
init_config();
|
|
4207
4418
|
init_state_bus();
|
|
4419
|
+
init_memory_write_governor();
|
|
4208
4420
|
INIT_MAX_RETRIES = 3;
|
|
4209
4421
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
4210
4422
|
_pendingRecords = [];
|