@askexenow/exe-os 0.9.34 → 0.9.35
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 +210 -10
- package/dist/bin/backfill-responses.js +210 -10
- package/dist/bin/backfill-vectors.js +13 -2
- package/dist/bin/cleanup-stale-review-tasks.js +217 -10
- package/dist/bin/cli.js +222 -11
- package/dist/bin/exe-assign.js +210 -10
- package/dist/bin/exe-boot.js +24 -3
- package/dist/bin/exe-dispatch.js +222 -11
- package/dist/bin/exe-doctor.js +13 -2
- package/dist/bin/exe-export-behaviors.js +217 -10
- package/dist/bin/exe-forget.js +217 -10
- package/dist/bin/exe-gateway.js +222 -11
- package/dist/bin/exe-heartbeat.js +217 -10
- package/dist/bin/exe-kill.js +217 -10
- package/dist/bin/exe-launch-agent.js +92 -2
- package/dist/bin/exe-link.js +8 -0
- package/dist/bin/exe-pending-messages.js +217 -10
- package/dist/bin/exe-pending-notifications.js +217 -10
- package/dist/bin/exe-pending-reviews.js +217 -10
- package/dist/bin/exe-rename.js +8 -0
- package/dist/bin/exe-review.js +217 -10
- package/dist/bin/exe-search.js +217 -10
- package/dist/bin/exe-session-cleanup.js +222 -11
- package/dist/bin/exe-start-codex.js +92 -2
- package/dist/bin/exe-start-opencode.js +92 -2
- package/dist/bin/exe-status.js +217 -10
- package/dist/bin/exe-team.js +217 -10
- package/dist/bin/git-sweep.js +222 -11
- package/dist/bin/graph-backfill.js +92 -2
- package/dist/bin/graph-export.js +217 -10
- package/dist/bin/intercom-check.js +222 -11
- package/dist/bin/scan-tasks.js +222 -11
- package/dist/bin/setup.js +8 -0
- package/dist/bin/shard-migrate.js +92 -2
- package/dist/gateway/index.js +222 -11
- package/dist/hooks/bug-report-worker.js +222 -11
- package/dist/hooks/codex-stop-task-finalizer.js +217 -10
- package/dist/hooks/commit-complete.js +222 -11
- package/dist/hooks/error-recall.js +217 -10
- package/dist/hooks/ingest.js +217 -10
- package/dist/hooks/instructions-loaded.js +217 -10
- package/dist/hooks/notification.js +217 -10
- package/dist/hooks/post-compact.js +217 -10
- package/dist/hooks/post-tool-combined.js +217 -10
- package/dist/hooks/pre-compact.js +222 -11
- package/dist/hooks/pre-tool-use.js +217 -10
- package/dist/hooks/prompt-submit.js +222 -11
- package/dist/hooks/session-end.js +222 -11
- package/dist/hooks/session-start.js +217 -10
- package/dist/hooks/stop.js +217 -10
- package/dist/hooks/subagent-stop.js +217 -10
- package/dist/hooks/summary-worker.js +14 -1
- package/dist/index.js +222 -11
- 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/exe-daemon.js +1667 -1413
- package/dist/lib/hybrid-search.js +217 -10
- package/dist/lib/schedules.js +13 -2
- package/dist/lib/store.js +210 -10
- package/dist/lib/tasks.js +5 -1
- package/dist/lib/tmux-routing.js +5 -1
- package/dist/mcp/server.js +222 -11
- package/dist/mcp/tools/create-task.js +5 -1
- package/dist/mcp/tools/update-task.js +5 -1
- package/dist/runtime/index.js +222 -11
- package/dist/tui/App.js +222 -11
- package/package.json +1 -1
package/dist/tui/App.js
CHANGED
|
@@ -3098,6 +3098,14 @@ async function ensureSchema() {
|
|
|
3098
3098
|
);
|
|
3099
3099
|
} catch {
|
|
3100
3100
|
}
|
|
3101
|
+
try {
|
|
3102
|
+
await client.execute(
|
|
3103
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_scoped_content_hash
|
|
3104
|
+
ON memories(content_hash, agent_id, project_name, memory_type)
|
|
3105
|
+
WHERE content_hash IS NOT NULL`
|
|
3106
|
+
);
|
|
3107
|
+
} catch {
|
|
3108
|
+
}
|
|
3101
3109
|
await client.executeMultiple(`
|
|
3102
3110
|
CREATE TABLE IF NOT EXISTS entities (
|
|
3103
3111
|
id TEXT PRIMARY KEY,
|
|
@@ -7053,7 +7061,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
7053
7061
|
}
|
|
7054
7062
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
7055
7063
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
7056
|
-
|
|
7064
|
+
let ccModel = agentRtConfig.model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
7065
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
7066
|
+
ccModel += "[1m]";
|
|
7067
|
+
}
|
|
7068
|
+
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
7057
7069
|
}
|
|
7058
7070
|
}
|
|
7059
7071
|
let spawnCommand;
|
|
@@ -11072,6 +11084,196 @@ var init_wiki_client = __esm({
|
|
|
11072
11084
|
}
|
|
11073
11085
|
});
|
|
11074
11086
|
|
|
11087
|
+
// src/lib/memory-write-governor.ts
|
|
11088
|
+
import { createHash } from "crypto";
|
|
11089
|
+
function normalizeMemoryText(text) {
|
|
11090
|
+
return text.replace(/\r\n/g, "\n").replace(/[ \t]+$/gm, "").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
11091
|
+
}
|
|
11092
|
+
function classifyMemoryType(input) {
|
|
11093
|
+
if (input.memory_type && input.memory_type.trim()) return input.memory_type.trim();
|
|
11094
|
+
const tool = input.tool_name.toLowerCase();
|
|
11095
|
+
const text = input.raw_text.toLowerCase();
|
|
11096
|
+
if (tool.includes("store_decision") || tool.includes("decision")) return "decision";
|
|
11097
|
+
if (tool.includes("commit") || text.includes("adr-") || text.includes("architectural decision")) return "adr";
|
|
11098
|
+
if (tool.includes("store_behavior") || tool.includes("behavior")) return "behavior";
|
|
11099
|
+
if (tool.includes("global_procedure") || text.includes("organization-wide procedures")) return "procedure";
|
|
11100
|
+
if (tool.includes("send_whatsapp") || tool.includes("conversation")) return "conversation";
|
|
11101
|
+
if (tool === "store_memory" || tool === "manual") return "observation";
|
|
11102
|
+
return "raw";
|
|
11103
|
+
}
|
|
11104
|
+
function shouldDropMemory(text) {
|
|
11105
|
+
const normalized = normalizeMemoryText(text);
|
|
11106
|
+
if (normalized.length < 10) return { drop: true, reason: "too_short" };
|
|
11107
|
+
if (NOISE_DROP_PATTERNS.some((pattern) => pattern.test(normalized))) {
|
|
11108
|
+
return { drop: true, reason: "known_boilerplate_noise" };
|
|
11109
|
+
}
|
|
11110
|
+
return { drop: false };
|
|
11111
|
+
}
|
|
11112
|
+
function shouldSkipEmbedding(input) {
|
|
11113
|
+
const type = classifyMemoryType(input);
|
|
11114
|
+
if (HIGH_VALUE_SUPERSESSION_TYPES.has(type)) return false;
|
|
11115
|
+
if (type === "raw" && input.raw_text.length > 2e4) return true;
|
|
11116
|
+
if (SKIP_EMBED_PATTERNS.some((pattern) => pattern.test(input.raw_text))) return true;
|
|
11117
|
+
return false;
|
|
11118
|
+
}
|
|
11119
|
+
function hashMemoryContent(text) {
|
|
11120
|
+
return createHash("sha256").update(normalizeMemoryText(text)).digest("hex");
|
|
11121
|
+
}
|
|
11122
|
+
function scopedDedupArgs(input) {
|
|
11123
|
+
return [input.contentHash, input.agentId, input.projectName, input.memoryType];
|
|
11124
|
+
}
|
|
11125
|
+
function governMemoryRecord(record) {
|
|
11126
|
+
const normalized = normalizeMemoryText(record.raw_text);
|
|
11127
|
+
const memoryType = classifyMemoryType({
|
|
11128
|
+
raw_text: normalized,
|
|
11129
|
+
agent_id: record.agent_id,
|
|
11130
|
+
project_name: record.project_name,
|
|
11131
|
+
tool_name: record.tool_name,
|
|
11132
|
+
memory_type: record.memory_type
|
|
11133
|
+
});
|
|
11134
|
+
const drop = shouldDropMemory(normalized);
|
|
11135
|
+
const skipEmbedding = shouldSkipEmbedding({
|
|
11136
|
+
raw_text: normalized,
|
|
11137
|
+
agent_id: record.agent_id,
|
|
11138
|
+
project_name: record.project_name,
|
|
11139
|
+
tool_name: record.tool_name,
|
|
11140
|
+
memory_type: memoryType
|
|
11141
|
+
});
|
|
11142
|
+
return {
|
|
11143
|
+
record: {
|
|
11144
|
+
...record,
|
|
11145
|
+
raw_text: normalized,
|
|
11146
|
+
memory_type: memoryType,
|
|
11147
|
+
vector: skipEmbedding ? null : record.vector
|
|
11148
|
+
},
|
|
11149
|
+
contentHash: hashMemoryContent(normalized),
|
|
11150
|
+
shouldDrop: drop.drop,
|
|
11151
|
+
dropReason: drop.reason,
|
|
11152
|
+
skipEmbedding,
|
|
11153
|
+
hygiene: {
|
|
11154
|
+
dedup: true,
|
|
11155
|
+
supersession: HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)
|
|
11156
|
+
}
|
|
11157
|
+
};
|
|
11158
|
+
}
|
|
11159
|
+
async function findScopedDuplicate(input) {
|
|
11160
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
11161
|
+
const client = getClient2();
|
|
11162
|
+
const args = scopedDedupArgs(input);
|
|
11163
|
+
let sql = `SELECT id FROM memories
|
|
11164
|
+
WHERE content_hash = ?
|
|
11165
|
+
AND agent_id = ?
|
|
11166
|
+
AND project_name = ?
|
|
11167
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
11168
|
+
AND COALESCE(status, 'active') != 'deleted'`;
|
|
11169
|
+
if (input.excludeId) {
|
|
11170
|
+
sql += " AND id != ?";
|
|
11171
|
+
args.push(input.excludeId);
|
|
11172
|
+
}
|
|
11173
|
+
sql += " ORDER BY timestamp DESC LIMIT 1";
|
|
11174
|
+
const result = await client.execute({ sql, args });
|
|
11175
|
+
return result.rows[0]?.id ? String(result.rows[0].id) : null;
|
|
11176
|
+
}
|
|
11177
|
+
async function runPostWriteMemoryHygiene(memoryId) {
|
|
11178
|
+
try {
|
|
11179
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
11180
|
+
const client = getClient2();
|
|
11181
|
+
const current = await client.execute({
|
|
11182
|
+
sql: `SELECT id, agent_id, project_name, memory_type, content_hash, supersedes_id,
|
|
11183
|
+
importance, timestamp
|
|
11184
|
+
FROM memories
|
|
11185
|
+
WHERE id = ?
|
|
11186
|
+
LIMIT 1`,
|
|
11187
|
+
args: [memoryId]
|
|
11188
|
+
});
|
|
11189
|
+
const row = current.rows[0];
|
|
11190
|
+
if (!row) return;
|
|
11191
|
+
const memoryType = String(row.memory_type ?? "raw");
|
|
11192
|
+
const contentHash = row.content_hash ? String(row.content_hash) : null;
|
|
11193
|
+
const agentId = String(row.agent_id);
|
|
11194
|
+
const projectName = String(row.project_name);
|
|
11195
|
+
if (contentHash) {
|
|
11196
|
+
await client.execute({
|
|
11197
|
+
sql: `UPDATE memories
|
|
11198
|
+
SET status = 'deleted',
|
|
11199
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
11200
|
+
WHERE id != ?
|
|
11201
|
+
AND content_hash = ?
|
|
11202
|
+
AND agent_id = ?
|
|
11203
|
+
AND project_name = ?
|
|
11204
|
+
AND COALESCE(memory_type, 'raw') = ?
|
|
11205
|
+
AND COALESCE(status, 'active') = 'active'`,
|
|
11206
|
+
args: [memoryId, contentHash, agentId, projectName, memoryType]
|
|
11207
|
+
});
|
|
11208
|
+
}
|
|
11209
|
+
const supersedesId = row.supersedes_id ? String(row.supersedes_id) : null;
|
|
11210
|
+
if (supersedesId && HIGH_VALUE_SUPERSESSION_TYPES.has(memoryType)) {
|
|
11211
|
+
const old = await client.execute({
|
|
11212
|
+
sql: `SELECT importance FROM memories WHERE id = ? LIMIT 1`,
|
|
11213
|
+
args: [supersedesId]
|
|
11214
|
+
});
|
|
11215
|
+
const oldImportance = Number(old.rows[0]?.importance ?? 0);
|
|
11216
|
+
const newImportance = Number(row.importance ?? 0);
|
|
11217
|
+
await client.batch([
|
|
11218
|
+
{
|
|
11219
|
+
sql: `UPDATE memories
|
|
11220
|
+
SET status = 'archived',
|
|
11221
|
+
outcome = COALESCE(outcome, 'superseded')
|
|
11222
|
+
WHERE id = ?`,
|
|
11223
|
+
args: [supersedesId]
|
|
11224
|
+
},
|
|
11225
|
+
{
|
|
11226
|
+
sql: `UPDATE memories
|
|
11227
|
+
SET importance = MAX(COALESCE(importance, 5), ?),
|
|
11228
|
+
parent_memory_id = COALESCE(parent_memory_id, ?)
|
|
11229
|
+
WHERE id = ?`,
|
|
11230
|
+
args: [Math.max(oldImportance, newImportance), supersedesId, memoryId]
|
|
11231
|
+
}
|
|
11232
|
+
], "write");
|
|
11233
|
+
}
|
|
11234
|
+
} catch (err) {
|
|
11235
|
+
process.stderr.write(
|
|
11236
|
+
`[memory-governor] post-write hygiene failed for ${memoryId}: ${err instanceof Error ? err.message : String(err)}
|
|
11237
|
+
`
|
|
11238
|
+
);
|
|
11239
|
+
}
|
|
11240
|
+
}
|
|
11241
|
+
function schedulePostWriteMemoryHygiene(memoryIds) {
|
|
11242
|
+
if (memoryIds.length === 0) return;
|
|
11243
|
+
const run = () => {
|
|
11244
|
+
void Promise.all(memoryIds.map((id) => runPostWriteMemoryHygiene(id)));
|
|
11245
|
+
};
|
|
11246
|
+
if (typeof setImmediate === "function") setImmediate(run);
|
|
11247
|
+
else setTimeout(run, 0);
|
|
11248
|
+
}
|
|
11249
|
+
var HIGH_VALUE_SUPERSESSION_TYPES, NOISE_DROP_PATTERNS, SKIP_EMBED_PATTERNS;
|
|
11250
|
+
var init_memory_write_governor = __esm({
|
|
11251
|
+
"src/lib/memory-write-governor.ts"() {
|
|
11252
|
+
"use strict";
|
|
11253
|
+
HIGH_VALUE_SUPERSESSION_TYPES = /* @__PURE__ */ new Set([
|
|
11254
|
+
"decision",
|
|
11255
|
+
"adr",
|
|
11256
|
+
"behavior",
|
|
11257
|
+
"procedure"
|
|
11258
|
+
]);
|
|
11259
|
+
NOISE_DROP_PATTERNS = [
|
|
11260
|
+
/^\s*\[📋\s+\d+\s+reviews?\s+pending\b/im,
|
|
11261
|
+
/^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*$/im,
|
|
11262
|
+
/^\s*The UserPromptSubmit hook checks the DB for new tasks/im,
|
|
11263
|
+
/^\s*Intercom is a speedup, not delivery/im,
|
|
11264
|
+
/^\s*Context bar reads as USAGE not remaining/im
|
|
11265
|
+
];
|
|
11266
|
+
SKIP_EMBED_PATTERNS = [
|
|
11267
|
+
/tmux capture-pane\b/i,
|
|
11268
|
+
/docker ps\b/i,
|
|
11269
|
+
/docker images\b/i,
|
|
11270
|
+
/git status\b/i,
|
|
11271
|
+
/grep .*node_modules/i,
|
|
11272
|
+
/npm (install|ci)\b[\s\S]*(added \d+ packages|audited \d+ packages)/i
|
|
11273
|
+
];
|
|
11274
|
+
}
|
|
11275
|
+
});
|
|
11276
|
+
|
|
11075
11277
|
// src/lib/shard-manager.ts
|
|
11076
11278
|
var shard_manager_exports = {};
|
|
11077
11279
|
__export(shard_manager_exports, {
|
|
@@ -11236,7 +11438,8 @@ async function ensureShardSchema(client) {
|
|
|
11236
11438
|
}
|
|
11237
11439
|
for (const idx of [
|
|
11238
11440
|
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
11239
|
-
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
11441
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL",
|
|
11442
|
+
"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"
|
|
11240
11443
|
]) {
|
|
11241
11444
|
try {
|
|
11242
11445
|
await client.execute(idx);
|
|
@@ -11412,7 +11615,6 @@ __export(store_exports, {
|
|
|
11412
11615
|
vectorToBlob: () => vectorToBlob,
|
|
11413
11616
|
writeMemory: () => writeMemory
|
|
11414
11617
|
});
|
|
11415
|
-
import { createHash } from "crypto";
|
|
11416
11618
|
function isBusyError2(err) {
|
|
11417
11619
|
if (err instanceof Error) {
|
|
11418
11620
|
const msg = err.message.toLowerCase();
|
|
@@ -11526,17 +11728,24 @@ async function writeMemory(record) {
|
|
|
11526
11728
|
`Expected ${EMBEDDING_DIM}-dim vector, got ${record.vector.length}`
|
|
11527
11729
|
);
|
|
11528
11730
|
}
|
|
11529
|
-
const
|
|
11530
|
-
if (
|
|
11731
|
+
const governed = governMemoryRecord(record);
|
|
11732
|
+
if (governed.shouldDrop) return;
|
|
11733
|
+
record = governed.record;
|
|
11734
|
+
const contentHash = governed.contentHash;
|
|
11735
|
+
const memoryType = record.memory_type ?? "raw";
|
|
11736
|
+
if (_pendingRecords.some(
|
|
11737
|
+
(r) => r.content_hash === contentHash && r.agent_id === record.agent_id && r.project_name === record.project_name && (r.memory_type ?? "raw") === memoryType
|
|
11738
|
+
)) {
|
|
11531
11739
|
return;
|
|
11532
11740
|
}
|
|
11533
11741
|
try {
|
|
11534
|
-
const
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11742
|
+
const existing = await findScopedDuplicate({
|
|
11743
|
+
contentHash,
|
|
11744
|
+
agentId: record.agent_id,
|
|
11745
|
+
projectName: record.project_name,
|
|
11746
|
+
memoryType
|
|
11538
11747
|
});
|
|
11539
|
-
if (existing
|
|
11748
|
+
if (existing) return;
|
|
11540
11749
|
} catch {
|
|
11541
11750
|
}
|
|
11542
11751
|
const dbRow = {
|
|
@@ -11567,7 +11776,7 @@ async function writeMemory(record) {
|
|
|
11567
11776
|
tier: record.tier ?? classifyTier(record),
|
|
11568
11777
|
supersedes_id: record.supersedes_id ?? null,
|
|
11569
11778
|
draft: record.draft ? 1 : 0,
|
|
11570
|
-
memory_type:
|
|
11779
|
+
memory_type: memoryType,
|
|
11571
11780
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
11572
11781
|
content_hash: contentHash,
|
|
11573
11782
|
intent: record.intent ?? null,
|
|
@@ -11726,6 +11935,7 @@ async function flushBatch() {
|
|
|
11726
11935
|
const globalClient = getClient();
|
|
11727
11936
|
const globalStmts = batch.map(buildStmt);
|
|
11728
11937
|
await globalClient.batch(globalStmts, "write");
|
|
11938
|
+
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
11729
11939
|
_pendingRecords.splice(0, batch.length);
|
|
11730
11940
|
try {
|
|
11731
11941
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -11984,6 +12194,7 @@ var init_store = __esm({
|
|
|
11984
12194
|
init_keychain();
|
|
11985
12195
|
init_config();
|
|
11986
12196
|
init_state_bus();
|
|
12197
|
+
init_memory_write_governor();
|
|
11987
12198
|
INIT_MAX_RETRIES = 3;
|
|
11988
12199
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
11989
12200
|
_pendingRecords = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askexenow/exe-os",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.35",
|
|
4
4
|
"description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|