@askexenow/exe-os 0.8.80 → 0.8.82
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 +359 -267
- package/dist/bin/backfill-responses.js +357 -265
- package/dist/bin/backfill-vectors.js +339 -264
- package/dist/bin/cleanup-stale-review-tasks.js +315 -256
- package/dist/bin/cli.js +494 -240
- package/dist/bin/exe-agent.js +141 -46
- package/dist/bin/exe-assign.js +151 -63
- package/dist/bin/exe-boot.js +294 -115
- package/dist/bin/exe-call.js +76 -51
- package/dist/bin/exe-cloud.js +58 -45
- package/dist/bin/exe-dispatch.js +434 -277
- package/dist/bin/exe-doctor.js +317 -246
- package/dist/bin/exe-export-behaviors.js +328 -248
- package/dist/bin/exe-forget.js +314 -231
- package/dist/bin/exe-gateway.js +2676 -1402
- package/dist/bin/exe-heartbeat.js +329 -264
- package/dist/bin/exe-kill.js +324 -244
- package/dist/bin/exe-launch-agent.js +574 -463
- package/dist/bin/exe-link.js +1055 -95
- package/dist/bin/exe-new-employee.js +49 -54
- package/dist/bin/exe-pending-messages.js +310 -253
- package/dist/bin/exe-pending-notifications.js +299 -228
- package/dist/bin/exe-pending-reviews.js +314 -245
- package/dist/bin/exe-rename.js +259 -195
- package/dist/bin/exe-review.js +140 -64
- package/dist/bin/exe-search.js +543 -356
- package/dist/bin/exe-session-cleanup.js +463 -382
- package/dist/bin/exe-settings.js +129 -99
- package/dist/bin/exe-start.sh +6 -6
- package/dist/bin/exe-status.js +95 -36
- package/dist/bin/exe-team.js +116 -51
- package/dist/bin/git-sweep.js +482 -307
- package/dist/bin/graph-backfill.js +357 -245
- package/dist/bin/graph-export.js +324 -244
- package/dist/bin/install.js +33 -10
- package/dist/bin/scan-tasks.js +481 -307
- package/dist/bin/setup.js +1147 -140
- package/dist/bin/shard-migrate.js +321 -241
- package/dist/bin/update.js +1 -7
- package/dist/bin/wiki-sync.js +318 -238
- package/dist/gateway/index.js +2656 -1383
- package/dist/hooks/bug-report-worker.js +641 -472
- package/dist/hooks/commit-complete.js +482 -307
- package/dist/hooks/error-recall.js +363 -135
- package/dist/hooks/exe-heartbeat-hook.js +97 -27
- package/dist/hooks/ingest-worker.js +584 -397
- package/dist/hooks/ingest.js +123 -58
- package/dist/hooks/instructions-loaded.js +212 -82
- package/dist/hooks/notification.js +200 -70
- package/dist/hooks/post-compact.js +199 -81
- package/dist/hooks/pre-compact.js +352 -140
- package/dist/hooks/pre-tool-use.js +416 -278
- package/dist/hooks/prompt-ingest-worker.js +376 -299
- package/dist/hooks/prompt-submit.js +414 -188
- package/dist/hooks/response-ingest-worker.js +408 -338
- package/dist/hooks/session-end.js +209 -83
- package/dist/hooks/session-start.js +382 -158
- package/dist/hooks/stop.js +209 -83
- package/dist/hooks/subagent-stop.js +209 -85
- package/dist/hooks/summary-worker.js +606 -510
- package/dist/index.js +2133 -855
- package/dist/lib/cloud-sync.js +1175 -184
- package/dist/lib/config.js +1 -9
- package/dist/lib/consolidation.js +71 -34
- package/dist/lib/database.js +166 -14
- package/dist/lib/device-registry.js +189 -117
- package/dist/lib/embedder.js +6 -10
- package/dist/lib/employee-templates.js +134 -39
- package/dist/lib/employees.js +30 -7
- package/dist/lib/exe-daemon-client.js +5 -7
- package/dist/lib/exe-daemon.js +514 -152
- package/dist/lib/hybrid-search.js +543 -356
- package/dist/lib/identity-templates.js +15 -15
- package/dist/lib/identity.js +19 -15
- package/dist/lib/license.js +1 -7
- package/dist/lib/messaging.js +157 -135
- package/dist/lib/reminders.js +97 -0
- package/dist/lib/schedules.js +302 -231
- package/dist/lib/skill-learning.js +33 -27
- package/dist/lib/status-brief.js +11 -14
- package/dist/lib/store.js +326 -237
- package/dist/lib/task-router.js +105 -1
- package/dist/lib/tasks.js +233 -116
- package/dist/lib/tmux-routing.js +173 -56
- package/dist/lib/ws-client.js +13 -3
- package/dist/mcp/server.js +2009 -1015
- package/dist/mcp/tools/complete-reminder.js +97 -0
- package/dist/mcp/tools/create-reminder.js +97 -0
- package/dist/mcp/tools/create-task.js +426 -262
- package/dist/mcp/tools/deactivate-behavior.js +119 -44
- package/dist/mcp/tools/list-reminders.js +97 -0
- package/dist/mcp/tools/list-tasks.js +56 -57
- package/dist/mcp/tools/send-message.js +206 -143
- package/dist/mcp/tools/update-task.js +259 -85
- package/dist/runtime/index.js +495 -316
- package/dist/tui/App.js +1128 -919
- package/package.json +2 -10
- package/src/commands/exe/afk.md +8 -8
- package/src/commands/exe/assign.md +1 -1
- package/src/commands/exe/build-adv.md +1 -1
- package/src/commands/exe/call.md +10 -10
- package/src/commands/exe/employee-heartbeat.md +9 -6
- package/src/commands/exe/heartbeat.md +5 -5
- package/src/commands/exe/intercom.md +26 -15
- package/src/commands/exe/launch.md +2 -2
- package/src/commands/exe/new-employee.md +1 -1
- package/src/commands/exe/review.md +2 -2
- package/src/commands/exe/schedule.md +1 -1
- package/src/commands/exe/sessions.md +2 -2
- package/src/commands/exe.md +22 -20
|
@@ -68,7 +68,7 @@ function wrapWithRetry(client) {
|
|
|
68
68
|
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
69
69
|
}
|
|
70
70
|
if (prop === "batch") {
|
|
71
|
-
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
71
|
+
return (stmts, mode) => retryOnBusy(() => target.batch(stmts, mode), "batch");
|
|
72
72
|
}
|
|
73
73
|
return Reflect.get(target, prop, receiver);
|
|
74
74
|
}
|
|
@@ -84,6 +84,301 @@ var init_db_retry = __esm({
|
|
|
84
84
|
}
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
+
// src/lib/config.ts
|
|
88
|
+
var config_exports = {};
|
|
89
|
+
__export(config_exports, {
|
|
90
|
+
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
91
|
+
CONFIG_PATH: () => CONFIG_PATH,
|
|
92
|
+
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
93
|
+
DB_PATH: () => DB_PATH,
|
|
94
|
+
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
95
|
+
LEGACY_LANCE_PATH: () => LEGACY_LANCE_PATH,
|
|
96
|
+
MODELS_DIR: () => MODELS_DIR,
|
|
97
|
+
loadConfig: () => loadConfig,
|
|
98
|
+
loadConfigFrom: () => loadConfigFrom,
|
|
99
|
+
loadConfigSync: () => loadConfigSync,
|
|
100
|
+
migrateConfig: () => migrateConfig,
|
|
101
|
+
saveConfig: () => saveConfig
|
|
102
|
+
});
|
|
103
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
104
|
+
import { readFileSync, existsSync, renameSync } from "fs";
|
|
105
|
+
import path from "path";
|
|
106
|
+
import os from "os";
|
|
107
|
+
function resolveDataDir() {
|
|
108
|
+
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
109
|
+
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
110
|
+
const newDir = path.join(os.homedir(), ".exe-os");
|
|
111
|
+
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
112
|
+
if (!existsSync(newDir) && existsSync(legacyDir)) {
|
|
113
|
+
try {
|
|
114
|
+
renameSync(legacyDir, newDir);
|
|
115
|
+
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
116
|
+
`);
|
|
117
|
+
} catch {
|
|
118
|
+
return legacyDir;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return newDir;
|
|
122
|
+
}
|
|
123
|
+
function migrateLegacyConfig(raw) {
|
|
124
|
+
if ("r2" in raw) {
|
|
125
|
+
process.stderr.write(
|
|
126
|
+
"[exe-os] Warning: config.json contains deprecated 'r2' field from v1.0. R2 sync has been replaced in v1.1. The 'r2' field will be ignored.\n"
|
|
127
|
+
);
|
|
128
|
+
delete raw.r2;
|
|
129
|
+
}
|
|
130
|
+
if ("syncIntervalMs" in raw) {
|
|
131
|
+
delete raw.syncIntervalMs;
|
|
132
|
+
}
|
|
133
|
+
return raw;
|
|
134
|
+
}
|
|
135
|
+
function migrateConfig(raw) {
|
|
136
|
+
const fromVersion = typeof raw.config_version === "number" ? raw.config_version : 0;
|
|
137
|
+
let currentVersion = fromVersion;
|
|
138
|
+
let migrated = false;
|
|
139
|
+
if (currentVersion > CURRENT_CONFIG_VERSION) {
|
|
140
|
+
return { config: raw, migrated: false, fromVersion };
|
|
141
|
+
}
|
|
142
|
+
for (const migration of CONFIG_MIGRATIONS) {
|
|
143
|
+
if (currentVersion === migration.from && migration.to <= CURRENT_CONFIG_VERSION) {
|
|
144
|
+
raw = migration.migrate(raw);
|
|
145
|
+
currentVersion = migration.to;
|
|
146
|
+
migrated = true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return { config: raw, migrated, fromVersion };
|
|
150
|
+
}
|
|
151
|
+
function normalizeScalingRoadmap(raw) {
|
|
152
|
+
const defaultAuto = DEFAULT_CONFIG.scalingRoadmap.rerankerAutoTrigger;
|
|
153
|
+
const userRoadmap = raw.scalingRoadmap ?? {};
|
|
154
|
+
const userAuto = userRoadmap.rerankerAutoTrigger ?? {};
|
|
155
|
+
if (userAuto.enabled === void 0 && raw.rerankerEnabled !== void 0) {
|
|
156
|
+
userAuto.enabled = raw.rerankerEnabled;
|
|
157
|
+
}
|
|
158
|
+
raw.scalingRoadmap = {
|
|
159
|
+
...userRoadmap,
|
|
160
|
+
rerankerAutoTrigger: { ...defaultAuto, ...userAuto }
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function normalizeSessionLifecycle(raw) {
|
|
164
|
+
const defaultSL = DEFAULT_CONFIG.sessionLifecycle;
|
|
165
|
+
const userSL = raw.sessionLifecycle ?? {};
|
|
166
|
+
raw.sessionLifecycle = { ...defaultSL, ...userSL };
|
|
167
|
+
}
|
|
168
|
+
function normalizeAutoUpdate(raw) {
|
|
169
|
+
const defaultAU = DEFAULT_CONFIG.autoUpdate;
|
|
170
|
+
const userAU = raw.autoUpdate ?? {};
|
|
171
|
+
raw.autoUpdate = { ...defaultAU, ...userAU };
|
|
172
|
+
}
|
|
173
|
+
async function loadConfig() {
|
|
174
|
+
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
175
|
+
await mkdir(dir, { recursive: true });
|
|
176
|
+
const configPath = path.join(dir, "config.json");
|
|
177
|
+
if (!existsSync(configPath)) {
|
|
178
|
+
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
179
|
+
}
|
|
180
|
+
const raw = await readFile(configPath, "utf-8");
|
|
181
|
+
try {
|
|
182
|
+
let parsed = JSON.parse(raw);
|
|
183
|
+
parsed = migrateLegacyConfig(parsed);
|
|
184
|
+
const { config: migratedCfg, migrated, fromVersion } = migrateConfig(parsed);
|
|
185
|
+
if (migrated) {
|
|
186
|
+
process.stderr.write(`[exe-os] Config migrated from v${fromVersion} to v${migratedCfg.config_version}
|
|
187
|
+
`);
|
|
188
|
+
try {
|
|
189
|
+
await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
190
|
+
} catch {
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
normalizeScalingRoadmap(migratedCfg);
|
|
194
|
+
normalizeSessionLifecycle(migratedCfg);
|
|
195
|
+
normalizeAutoUpdate(migratedCfg);
|
|
196
|
+
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
197
|
+
if (config.dbPath.startsWith("~")) {
|
|
198
|
+
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
199
|
+
}
|
|
200
|
+
return config;
|
|
201
|
+
} catch {
|
|
202
|
+
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function loadConfigSync() {
|
|
206
|
+
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
207
|
+
const configPath = path.join(dir, "config.json");
|
|
208
|
+
if (!existsSync(configPath)) {
|
|
209
|
+
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
213
|
+
let parsed = JSON.parse(raw);
|
|
214
|
+
parsed = migrateLegacyConfig(parsed);
|
|
215
|
+
const { config: migratedCfg } = migrateConfig(parsed);
|
|
216
|
+
normalizeScalingRoadmap(migratedCfg);
|
|
217
|
+
normalizeSessionLifecycle(migratedCfg);
|
|
218
|
+
normalizeAutoUpdate(migratedCfg);
|
|
219
|
+
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
220
|
+
} catch {
|
|
221
|
+
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async function saveConfig(config) {
|
|
225
|
+
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
226
|
+
await mkdir(dir, { recursive: true });
|
|
227
|
+
const configPath = path.join(dir, "config.json");
|
|
228
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
229
|
+
if (config.cloud?.apiKey) {
|
|
230
|
+
await chmod(configPath, 384);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async function loadConfigFrom(configPath) {
|
|
234
|
+
const raw = await readFile(configPath, "utf-8");
|
|
235
|
+
try {
|
|
236
|
+
let parsed = JSON.parse(raw);
|
|
237
|
+
parsed = migrateLegacyConfig(parsed);
|
|
238
|
+
const { config: migratedCfg } = migrateConfig(parsed);
|
|
239
|
+
normalizeScalingRoadmap(migratedCfg);
|
|
240
|
+
normalizeSessionLifecycle(migratedCfg);
|
|
241
|
+
normalizeAutoUpdate(migratedCfg);
|
|
242
|
+
return { ...DEFAULT_CONFIG, ...migratedCfg };
|
|
243
|
+
} catch {
|
|
244
|
+
return { ...DEFAULT_CONFIG };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
248
|
+
var init_config = __esm({
|
|
249
|
+
"src/lib/config.ts"() {
|
|
250
|
+
"use strict";
|
|
251
|
+
EXE_AI_DIR = resolveDataDir();
|
|
252
|
+
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
253
|
+
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
254
|
+
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
255
|
+
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
256
|
+
CURRENT_CONFIG_VERSION = 1;
|
|
257
|
+
DEFAULT_CONFIG = {
|
|
258
|
+
config_version: CURRENT_CONFIG_VERSION,
|
|
259
|
+
dbPath: DB_PATH,
|
|
260
|
+
modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
|
|
261
|
+
embeddingDim: 1024,
|
|
262
|
+
batchSize: 20,
|
|
263
|
+
flushIntervalMs: 1e4,
|
|
264
|
+
autoIngestion: true,
|
|
265
|
+
autoRetrieval: true,
|
|
266
|
+
searchMode: "hybrid",
|
|
267
|
+
hookSearchMode: "hybrid",
|
|
268
|
+
fileGrepEnabled: true,
|
|
269
|
+
splashEffect: true,
|
|
270
|
+
consolidationEnabled: true,
|
|
271
|
+
consolidationIntervalMs: 6 * 60 * 60 * 1e3,
|
|
272
|
+
consolidationModel: "claude-haiku-4-5-20251001",
|
|
273
|
+
consolidationMaxCallsPerRun: 20,
|
|
274
|
+
selfQueryRouter: true,
|
|
275
|
+
selfQueryModel: "claude-haiku-4-5-20251001",
|
|
276
|
+
rerankerEnabled: true,
|
|
277
|
+
scalingRoadmap: {
|
|
278
|
+
rerankerAutoTrigger: {
|
|
279
|
+
enabled: true,
|
|
280
|
+
broadQueryMinCardinality: 5e4,
|
|
281
|
+
fetchTopK: 150,
|
|
282
|
+
returnTopK: 5
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
graphRagEnabled: true,
|
|
286
|
+
wikiEnabled: false,
|
|
287
|
+
wikiUrl: "",
|
|
288
|
+
wikiApiKey: "",
|
|
289
|
+
wikiSyncIntervalMs: 30 * 60 * 1e3,
|
|
290
|
+
wikiWorkspaceMapping: {},
|
|
291
|
+
wikiAutoUpdate: true,
|
|
292
|
+
wikiAutoUpdateThreshold: 0.5,
|
|
293
|
+
wikiAutoUpdateCreateNew: true,
|
|
294
|
+
skillLearning: true,
|
|
295
|
+
skillThreshold: 3,
|
|
296
|
+
skillModel: "claude-haiku-4-5-20251001",
|
|
297
|
+
exeHeartbeat: {
|
|
298
|
+
enabled: true,
|
|
299
|
+
intervalSeconds: 60,
|
|
300
|
+
staleInProgressThresholdHours: 2
|
|
301
|
+
},
|
|
302
|
+
sessionLifecycle: {
|
|
303
|
+
idleKillEnabled: true,
|
|
304
|
+
idleKillTicksRequired: 3,
|
|
305
|
+
idleKillIntercomAckWindowMs: 1e4,
|
|
306
|
+
maxAutoInstances: 10
|
|
307
|
+
},
|
|
308
|
+
autoUpdate: {
|
|
309
|
+
checkOnBoot: true,
|
|
310
|
+
autoInstall: false,
|
|
311
|
+
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
CONFIG_MIGRATIONS = [
|
|
315
|
+
{
|
|
316
|
+
from: 0,
|
|
317
|
+
to: 1,
|
|
318
|
+
migrate: (cfg) => {
|
|
319
|
+
cfg.config_version = 1;
|
|
320
|
+
return cfg;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
];
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// src/lib/employees.ts
|
|
328
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
329
|
+
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
330
|
+
import { execSync } from "child_process";
|
|
331
|
+
import path2 from "path";
|
|
332
|
+
import os2 from "os";
|
|
333
|
+
function normalizeRole(role) {
|
|
334
|
+
return (role ?? "").trim().toLowerCase();
|
|
335
|
+
}
|
|
336
|
+
function isCoordinatorRole(role) {
|
|
337
|
+
return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
|
|
338
|
+
}
|
|
339
|
+
function getCoordinatorEmployee(employees) {
|
|
340
|
+
return employees.find((e) => isCoordinatorRole(e.role));
|
|
341
|
+
}
|
|
342
|
+
function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
343
|
+
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
344
|
+
}
|
|
345
|
+
function isCoordinatorName(agentName2, employees = loadEmployeesSync()) {
|
|
346
|
+
if (!agentName2) return false;
|
|
347
|
+
return agentName2.toLowerCase() === getCoordinatorName(employees).toLowerCase();
|
|
348
|
+
}
|
|
349
|
+
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
350
|
+
if (!existsSync2(employeesPath)) {
|
|
351
|
+
return [];
|
|
352
|
+
}
|
|
353
|
+
const raw = await readFile2(employeesPath, "utf-8");
|
|
354
|
+
try {
|
|
355
|
+
return JSON.parse(raw);
|
|
356
|
+
} catch {
|
|
357
|
+
return [];
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
361
|
+
if (!existsSync2(employeesPath)) return [];
|
|
362
|
+
try {
|
|
363
|
+
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
364
|
+
} catch {
|
|
365
|
+
return [];
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function getEmployee(employees, name) {
|
|
369
|
+
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
370
|
+
}
|
|
371
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
|
|
372
|
+
var init_employees = __esm({
|
|
373
|
+
"src/lib/employees.ts"() {
|
|
374
|
+
"use strict";
|
|
375
|
+
init_config();
|
|
376
|
+
EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
377
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
378
|
+
COORDINATOR_ROLE = "COO";
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
|
|
87
382
|
// src/lib/database.ts
|
|
88
383
|
import { createClient } from "@libsql/client";
|
|
89
384
|
async function initDatabase(config) {
|
|
@@ -217,22 +512,24 @@ async function ensureSchema() {
|
|
|
217
512
|
ON behaviors(agent_id, active);
|
|
218
513
|
`);
|
|
219
514
|
try {
|
|
515
|
+
const coordinatorName = getCoordinatorName();
|
|
220
516
|
const existing = await client.execute({
|
|
221
|
-
sql: "SELECT COUNT(*) as cnt FROM behaviors WHERE agent_id =
|
|
222
|
-
args: []
|
|
517
|
+
sql: "SELECT COUNT(*) as cnt FROM behaviors WHERE agent_id = ?",
|
|
518
|
+
args: [coordinatorName]
|
|
223
519
|
});
|
|
224
520
|
if (Number(existing.rows[0]?.cnt) === 0) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
521
|
+
const seededAt = "2026-03-25T00:00:00Z";
|
|
522
|
+
for (const [domain, content] of [
|
|
523
|
+
["workflow", `Don't ask "keep going?" \u2014 just keep executing phases/plans autonomously`],
|
|
524
|
+
["tool-use", "Always use create_task MCP tool, never write .md files directly for task creation"],
|
|
525
|
+
["workflow", "Auto-start reviewing when idle and reviews are pending \u2014 never ask founder for permission"]
|
|
526
|
+
]) {
|
|
527
|
+
await client.execute({
|
|
528
|
+
sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, content, active, created_at, updated_at)
|
|
529
|
+
VALUES (hex(randomblob(16)), ?, NULL, ?, ?, 1, ?, ?)`,
|
|
530
|
+
args: [coordinatorName, domain, content, seededAt, seededAt]
|
|
531
|
+
});
|
|
532
|
+
}
|
|
236
533
|
}
|
|
237
534
|
} catch {
|
|
238
535
|
}
|
|
@@ -881,306 +1178,92 @@ async function ensureSchema() {
|
|
|
881
1178
|
try {
|
|
882
1179
|
await client.execute({
|
|
883
1180
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
884
|
-
args: []
|
|
885
|
-
});
|
|
886
|
-
} catch {
|
|
887
|
-
}
|
|
888
|
-
try {
|
|
889
|
-
await client.execute(
|
|
890
|
-
`CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
|
|
891
|
-
);
|
|
892
|
-
} catch {
|
|
893
|
-
}
|
|
894
|
-
try {
|
|
895
|
-
await client.execute({
|
|
896
|
-
sql: `UPDATE memories SET tier = 1 WHERE tool_name = 'commit_to_long_term_memory' AND importance >= 8 AND tier = 3`,
|
|
897
|
-
args: []
|
|
898
|
-
});
|
|
899
|
-
await client.execute({
|
|
900
|
-
sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
|
|
901
|
-
args: []
|
|
902
|
-
});
|
|
903
|
-
} catch {
|
|
904
|
-
}
|
|
905
|
-
try {
|
|
906
|
-
await client.execute({
|
|
907
|
-
sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
|
|
908
|
-
args: []
|
|
909
|
-
});
|
|
910
|
-
} catch {
|
|
911
|
-
}
|
|
912
|
-
try {
|
|
913
|
-
await client.execute(
|
|
914
|
-
`CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
|
|
915
|
-
);
|
|
916
|
-
} catch {
|
|
917
|
-
}
|
|
918
|
-
for (const col of [
|
|
919
|
-
"ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
|
|
920
|
-
"ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER DEFAULT 0"
|
|
921
|
-
]) {
|
|
922
|
-
try {
|
|
923
|
-
await client.execute(col);
|
|
924
|
-
} catch {
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
var _client, _resilientClient, initTurso;
|
|
929
|
-
var init_database = __esm({
|
|
930
|
-
"src/lib/database.ts"() {
|
|
931
|
-
"use strict";
|
|
932
|
-
init_db_retry();
|
|
933
|
-
_client = null;
|
|
934
|
-
_resilientClient = null;
|
|
935
|
-
initTurso = initDatabase;
|
|
936
|
-
}
|
|
937
|
-
});
|
|
938
|
-
|
|
939
|
-
// src/lib/config.ts
|
|
940
|
-
var config_exports = {};
|
|
941
|
-
__export(config_exports, {
|
|
942
|
-
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
943
|
-
CONFIG_PATH: () => CONFIG_PATH,
|
|
944
|
-
COO_AGENT_NAME: () => COO_AGENT_NAME,
|
|
945
|
-
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
946
|
-
DB_PATH: () => DB_PATH,
|
|
947
|
-
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
948
|
-
LEGACY_LANCE_PATH: () => LEGACY_LANCE_PATH,
|
|
949
|
-
MODELS_DIR: () => MODELS_DIR,
|
|
950
|
-
loadConfig: () => loadConfig,
|
|
951
|
-
loadConfigFrom: () => loadConfigFrom,
|
|
952
|
-
loadConfigSync: () => loadConfigSync,
|
|
953
|
-
migrateConfig: () => migrateConfig,
|
|
954
|
-
saveConfig: () => saveConfig
|
|
955
|
-
});
|
|
956
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
957
|
-
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
958
|
-
import path2 from "path";
|
|
959
|
-
import os2 from "os";
|
|
960
|
-
function resolveDataDir() {
|
|
961
|
-
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
962
|
-
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
963
|
-
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
964
|
-
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
965
|
-
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
966
|
-
try {
|
|
967
|
-
renameSync(legacyDir, newDir);
|
|
968
|
-
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
969
|
-
`);
|
|
970
|
-
} catch {
|
|
971
|
-
return legacyDir;
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
return newDir;
|
|
975
|
-
}
|
|
976
|
-
function migrateLegacyConfig(raw) {
|
|
977
|
-
if ("r2" in raw) {
|
|
978
|
-
process.stderr.write(
|
|
979
|
-
"[exe-os] Warning: config.json contains deprecated 'r2' field from v1.0. R2 sync has been replaced in v1.1. The 'r2' field will be ignored.\n"
|
|
980
|
-
);
|
|
981
|
-
delete raw.r2;
|
|
1181
|
+
args: []
|
|
1182
|
+
});
|
|
1183
|
+
} catch {
|
|
982
1184
|
}
|
|
983
|
-
|
|
984
|
-
|
|
1185
|
+
try {
|
|
1186
|
+
await client.execute(
|
|
1187
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
|
|
1188
|
+
);
|
|
1189
|
+
} catch {
|
|
985
1190
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1191
|
+
try {
|
|
1192
|
+
await client.execute({
|
|
1193
|
+
sql: `UPDATE memories SET tier = 1 WHERE tool_name = 'commit_to_long_term_memory' AND importance >= 8 AND tier = 3`,
|
|
1194
|
+
args: []
|
|
1195
|
+
});
|
|
1196
|
+
await client.execute({
|
|
1197
|
+
sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
|
|
1198
|
+
args: []
|
|
1199
|
+
});
|
|
1200
|
+
} catch {
|
|
994
1201
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1202
|
+
try {
|
|
1203
|
+
await client.execute({
|
|
1204
|
+
sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
|
|
1205
|
+
args: []
|
|
1206
|
+
});
|
|
1207
|
+
} catch {
|
|
1001
1208
|
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
const userAuto = userRoadmap.rerankerAutoTrigger ?? {};
|
|
1008
|
-
if (userAuto.enabled === void 0 && raw.rerankerEnabled !== void 0) {
|
|
1009
|
-
userAuto.enabled = raw.rerankerEnabled;
|
|
1209
|
+
try {
|
|
1210
|
+
await client.execute(
|
|
1211
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
|
|
1212
|
+
);
|
|
1213
|
+
} catch {
|
|
1010
1214
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
raw.sessionLifecycle = { ...defaultSL, ...userSL };
|
|
1020
|
-
}
|
|
1021
|
-
function normalizeAutoUpdate(raw) {
|
|
1022
|
-
const defaultAU = DEFAULT_CONFIG.autoUpdate;
|
|
1023
|
-
const userAU = raw.autoUpdate ?? {};
|
|
1024
|
-
raw.autoUpdate = { ...defaultAU, ...userAU };
|
|
1025
|
-
}
|
|
1026
|
-
async function loadConfig() {
|
|
1027
|
-
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
1028
|
-
await mkdir2(dir, { recursive: true });
|
|
1029
|
-
const configPath = path2.join(dir, "config.json");
|
|
1030
|
-
if (!existsSync2(configPath)) {
|
|
1031
|
-
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
1215
|
+
for (const col of [
|
|
1216
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
|
|
1217
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER DEFAULT 0"
|
|
1218
|
+
]) {
|
|
1219
|
+
try {
|
|
1220
|
+
await client.execute(col);
|
|
1221
|
+
} catch {
|
|
1222
|
+
}
|
|
1032
1223
|
}
|
|
1033
|
-
const raw = await readFile2(configPath, "utf-8");
|
|
1034
1224
|
try {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
process.stderr.write(`[exe-os] Config migrated from v${fromVersion} to v${migratedCfg.config_version}
|
|
1040
|
-
`);
|
|
1041
|
-
try {
|
|
1042
|
-
await writeFile2(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
1043
|
-
} catch {
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
normalizeScalingRoadmap(migratedCfg);
|
|
1047
|
-
normalizeSessionLifecycle(migratedCfg);
|
|
1048
|
-
normalizeAutoUpdate(migratedCfg);
|
|
1049
|
-
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
1050
|
-
if (config.dbPath.startsWith("~")) {
|
|
1051
|
-
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1052
|
-
}
|
|
1053
|
-
return config;
|
|
1225
|
+
await client.execute({
|
|
1226
|
+
sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
|
|
1227
|
+
args: []
|
|
1228
|
+
});
|
|
1054
1229
|
} catch {
|
|
1055
|
-
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
1056
1230
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
1231
|
+
try {
|
|
1232
|
+
await client.execute(
|
|
1233
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
|
|
1234
|
+
);
|
|
1235
|
+
} catch {
|
|
1063
1236
|
}
|
|
1064
1237
|
try {
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
normalizeScalingRoadmap(migratedCfg);
|
|
1070
|
-
normalizeSessionLifecycle(migratedCfg);
|
|
1071
|
-
normalizeAutoUpdate(migratedCfg);
|
|
1072
|
-
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
1238
|
+
await client.execute({
|
|
1239
|
+
sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
|
|
1240
|
+
args: []
|
|
1241
|
+
});
|
|
1073
1242
|
} catch {
|
|
1074
|
-
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
1075
1243
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1082
|
-
if (config.cloud?.apiKey) {
|
|
1083
|
-
await chmod2(configPath, 384);
|
|
1244
|
+
try {
|
|
1245
|
+
await client.execute(
|
|
1246
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
|
|
1247
|
+
);
|
|
1248
|
+
} catch {
|
|
1084
1249
|
}
|
|
1085
|
-
}
|
|
1086
|
-
async function loadConfigFrom(configPath) {
|
|
1087
|
-
const raw = await readFile2(configPath, "utf-8");
|
|
1088
1250
|
try {
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
normalizeSessionLifecycle(migratedCfg);
|
|
1094
|
-
normalizeAutoUpdate(migratedCfg);
|
|
1095
|
-
return { ...DEFAULT_CONFIG, ...migratedCfg };
|
|
1251
|
+
await client.execute({
|
|
1252
|
+
sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
|
|
1253
|
+
args: []
|
|
1254
|
+
});
|
|
1096
1255
|
} catch {
|
|
1097
|
-
return { ...DEFAULT_CONFIG };
|
|
1098
1256
|
}
|
|
1099
1257
|
}
|
|
1100
|
-
var
|
|
1101
|
-
var
|
|
1102
|
-
"src/lib/
|
|
1258
|
+
var _client, _resilientClient, initTurso;
|
|
1259
|
+
var init_database = __esm({
|
|
1260
|
+
"src/lib/database.ts"() {
|
|
1103
1261
|
"use strict";
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
LEGACY_LANCE_PATH = path2.join(EXE_AI_DIR, "local.lance");
|
|
1110
|
-
CURRENT_CONFIG_VERSION = 1;
|
|
1111
|
-
DEFAULT_CONFIG = {
|
|
1112
|
-
config_version: CURRENT_CONFIG_VERSION,
|
|
1113
|
-
dbPath: DB_PATH,
|
|
1114
|
-
modelFile: "jina-embeddings-v5-small-q4_k_m.gguf",
|
|
1115
|
-
embeddingDim: 1024,
|
|
1116
|
-
batchSize: 20,
|
|
1117
|
-
flushIntervalMs: 1e4,
|
|
1118
|
-
autoIngestion: true,
|
|
1119
|
-
autoRetrieval: true,
|
|
1120
|
-
searchMode: "hybrid",
|
|
1121
|
-
hookSearchMode: "hybrid",
|
|
1122
|
-
fileGrepEnabled: true,
|
|
1123
|
-
splashEffect: true,
|
|
1124
|
-
consolidationEnabled: true,
|
|
1125
|
-
consolidationIntervalMs: 6 * 60 * 60 * 1e3,
|
|
1126
|
-
consolidationModel: "claude-haiku-4-5-20251001",
|
|
1127
|
-
consolidationMaxCallsPerRun: 20,
|
|
1128
|
-
selfQueryRouter: true,
|
|
1129
|
-
selfQueryModel: "claude-haiku-4-5-20251001",
|
|
1130
|
-
rerankerEnabled: true,
|
|
1131
|
-
scalingRoadmap: {
|
|
1132
|
-
rerankerAutoTrigger: {
|
|
1133
|
-
enabled: true,
|
|
1134
|
-
broadQueryMinCardinality: 5e4,
|
|
1135
|
-
fetchTopK: 150,
|
|
1136
|
-
returnTopK: 5
|
|
1137
|
-
}
|
|
1138
|
-
},
|
|
1139
|
-
graphRagEnabled: true,
|
|
1140
|
-
wikiEnabled: false,
|
|
1141
|
-
wikiUrl: "",
|
|
1142
|
-
wikiApiKey: "",
|
|
1143
|
-
wikiSyncIntervalMs: 30 * 60 * 1e3,
|
|
1144
|
-
wikiWorkspaceMapping: {
|
|
1145
|
-
exe: "Executive",
|
|
1146
|
-
yoshi: "Engineering",
|
|
1147
|
-
mari: "Marketing",
|
|
1148
|
-
tom: "Engineering",
|
|
1149
|
-
sasha: "Production"
|
|
1150
|
-
},
|
|
1151
|
-
wikiAutoUpdate: true,
|
|
1152
|
-
wikiAutoUpdateThreshold: 0.5,
|
|
1153
|
-
wikiAutoUpdateCreateNew: true,
|
|
1154
|
-
skillLearning: true,
|
|
1155
|
-
skillThreshold: 3,
|
|
1156
|
-
skillModel: "claude-haiku-4-5-20251001",
|
|
1157
|
-
exeHeartbeat: {
|
|
1158
|
-
enabled: true,
|
|
1159
|
-
intervalSeconds: 60,
|
|
1160
|
-
staleInProgressThresholdHours: 2
|
|
1161
|
-
},
|
|
1162
|
-
sessionLifecycle: {
|
|
1163
|
-
idleKillEnabled: true,
|
|
1164
|
-
idleKillTicksRequired: 3,
|
|
1165
|
-
idleKillIntercomAckWindowMs: 1e4,
|
|
1166
|
-
maxAutoInstances: 10
|
|
1167
|
-
},
|
|
1168
|
-
autoUpdate: {
|
|
1169
|
-
checkOnBoot: true,
|
|
1170
|
-
autoInstall: false,
|
|
1171
|
-
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
1172
|
-
}
|
|
1173
|
-
};
|
|
1174
|
-
CONFIG_MIGRATIONS = [
|
|
1175
|
-
{
|
|
1176
|
-
from: 0,
|
|
1177
|
-
to: 1,
|
|
1178
|
-
migrate: (cfg) => {
|
|
1179
|
-
cfg.config_version = 1;
|
|
1180
|
-
return cfg;
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
];
|
|
1262
|
+
init_db_retry();
|
|
1263
|
+
init_employees();
|
|
1264
|
+
_client = null;
|
|
1265
|
+
_resilientClient = null;
|
|
1266
|
+
initTurso = initDatabase;
|
|
1184
1267
|
}
|
|
1185
1268
|
});
|
|
1186
1269
|
|
|
@@ -1252,12 +1335,12 @@ __export(shard_manager_exports, {
|
|
|
1252
1335
|
listShards: () => listShards,
|
|
1253
1336
|
shardExists: () => shardExists
|
|
1254
1337
|
});
|
|
1255
|
-
import
|
|
1256
|
-
import { existsSync as
|
|
1338
|
+
import path4 from "path";
|
|
1339
|
+
import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
|
|
1257
1340
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1258
1341
|
function initShardManager(encryptionKey) {
|
|
1259
1342
|
_encryptionKey = encryptionKey;
|
|
1260
|
-
if (!
|
|
1343
|
+
if (!existsSync4(SHARDS_DIR)) {
|
|
1261
1344
|
mkdirSync(SHARDS_DIR, { recursive: true });
|
|
1262
1345
|
}
|
|
1263
1346
|
_shardingEnabled = true;
|
|
@@ -1278,7 +1361,7 @@ function getShardClient(projectName) {
|
|
|
1278
1361
|
}
|
|
1279
1362
|
const cached = _shards.get(safeName);
|
|
1280
1363
|
if (cached) return cached;
|
|
1281
|
-
const dbPath =
|
|
1364
|
+
const dbPath = path4.join(SHARDS_DIR, `${safeName}.db`);
|
|
1282
1365
|
const client = createClient2({
|
|
1283
1366
|
url: `file:${dbPath}`,
|
|
1284
1367
|
encryptionKey: _encryptionKey
|
|
@@ -1288,10 +1371,10 @@ function getShardClient(projectName) {
|
|
|
1288
1371
|
}
|
|
1289
1372
|
function shardExists(projectName) {
|
|
1290
1373
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1291
|
-
return
|
|
1374
|
+
return existsSync4(path4.join(SHARDS_DIR, `${safeName}.db`));
|
|
1292
1375
|
}
|
|
1293
1376
|
function listShards() {
|
|
1294
|
-
if (!
|
|
1377
|
+
if (!existsSync4(SHARDS_DIR)) return [];
|
|
1295
1378
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1296
1379
|
}
|
|
1297
1380
|
async function ensureShardSchema(client) {
|
|
@@ -1361,7 +1444,11 @@ async function ensureShardSchema(client) {
|
|
|
1361
1444
|
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
1362
1445
|
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'",
|
|
1363
1446
|
"ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3",
|
|
1364
|
-
"ALTER TABLE memories ADD COLUMN supersedes_id TEXT"
|
|
1447
|
+
"ALTER TABLE memories ADD COLUMN supersedes_id TEXT",
|
|
1448
|
+
// MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
|
|
1449
|
+
"ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
|
|
1450
|
+
"ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
|
|
1451
|
+
"ALTER TABLE memories ADD COLUMN trajectory TEXT"
|
|
1365
1452
|
]) {
|
|
1366
1453
|
try {
|
|
1367
1454
|
await client.execute(col);
|
|
@@ -1473,7 +1560,7 @@ var init_shard_manager = __esm({
|
|
|
1473
1560
|
"src/lib/shard-manager.ts"() {
|
|
1474
1561
|
"use strict";
|
|
1475
1562
|
init_config();
|
|
1476
|
-
SHARDS_DIR =
|
|
1563
|
+
SHARDS_DIR = path4.join(EXE_AI_DIR, "shards");
|
|
1477
1564
|
_shards = /* @__PURE__ */ new Map();
|
|
1478
1565
|
_encryptionKey = null;
|
|
1479
1566
|
_shardingEnabled = false;
|
|
@@ -1491,26 +1578,26 @@ var init_platform_procedures = __esm({
|
|
|
1491
1578
|
title: "What is exe-os \u2014 the operating model every agent must understand",
|
|
1492
1579
|
domain: "architecture",
|
|
1493
1580
|
priority: "p0",
|
|
1494
|
-
content: "Exe OS is an AI employee operating system. A founder runs 5-10 AI agents as a real org: COO
|
|
1581
|
+
content: "Exe OS is an AI employee operating system. A founder runs 5-10 AI agents as a real org: COO, CTO, CMO, engineers, and content production specialists. Each agent has identity, expertise, and experience layers \u2014 persistent memory that makes them better over time. All data is local-first, E2EE, owned by the user. The MCP server is the ONLY data interface \u2014 never access the DB directly."
|
|
1495
1582
|
},
|
|
1496
1583
|
{
|
|
1497
1584
|
title: "Mode 1 \u2014 how exe-os runs inside Claude Code",
|
|
1498
1585
|
domain: "architecture",
|
|
1499
1586
|
priority: "p0",
|
|
1500
|
-
content: "Mode 1: exe-os runs AS hooks + MCP + skills inside Claude Code. The founder opens CC
|
|
1587
|
+
content: "Mode 1: exe-os runs AS hooks + MCP + skills inside Claude Code. The founder opens CC and boots the COO. The COO manages employees in tmux sessions. Each coordinator session is a separate CC window/project. Employees run in their own tmux panes via create_task auto-spawn. The founder talks to the COO; the COO orchestrates the team. CC is the shell, exe-os is the brain."
|
|
1501
1588
|
},
|
|
1502
1589
|
{
|
|
1503
|
-
title: "Sessions explained \u2014
|
|
1590
|
+
title: "Sessions explained \u2014 coordinator session names and projects",
|
|
1504
1591
|
domain: "architecture",
|
|
1505
1592
|
priority: "p0",
|
|
1506
|
-
content: "Each
|
|
1593
|
+
content: "Each coordinator session is an isolated project session. One might be exe-os development, another might be exe-wiki. Each session spawns its own employees using {employee}-{coordinatorSession}. Sessions share the same memory DB but tasks are scoped to the session that created them. A founder can run multiple projects simultaneously. Sessions never interfere with each other."
|
|
1507
1594
|
},
|
|
1508
1595
|
// --- Hierarchy and dispatch ---
|
|
1509
1596
|
{
|
|
1510
1597
|
title: "Chain of command \u2014 who talks to whom",
|
|
1511
1598
|
domain: "workflow",
|
|
1512
1599
|
priority: "p0",
|
|
1513
|
-
content: "Founder
|
|
1600
|
+
content: "Founder -> COO -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the COO 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."
|
|
1514
1601
|
},
|
|
1515
1602
|
{
|
|
1516
1603
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -1520,30 +1607,30 @@ var init_platform_procedures = __esm({
|
|
|
1520
1607
|
},
|
|
1521
1608
|
// --- Session isolation ---
|
|
1522
1609
|
{
|
|
1523
|
-
title: "Session scoping \u2014 stay in your
|
|
1610
|
+
title: "Session scoping \u2014 stay in your coordinator boundary",
|
|
1524
1611
|
domain: "security",
|
|
1525
1612
|
priority: "p0",
|
|
1526
|
-
content: "Session scoping is mandatory. Managers dispatch to workers within their own
|
|
1613
|
+
content: "Session scoping is mandatory. Managers dispatch to workers within their own coordinator session ONLY. Employee sessions use {employee}-{coordinatorSession}. Cross-session dispatch is blocked by the system. Verify session names before dispatch. Tasks are scoped to the creating coordinator session."
|
|
1527
1614
|
},
|
|
1528
1615
|
{
|
|
1529
1616
|
title: "Session isolation \u2014 never touch another session's work",
|
|
1530
1617
|
domain: "workflow",
|
|
1531
1618
|
priority: "p0",
|
|
1532
|
-
content:
|
|
1619
|
+
content: "Sessions are isolated. A coordinator session owns ONLY tasks it dispatched. (1) Never close/update/cancel tasks from another coordinator session. (2) Never review work from a different session \u2014 report that it belongs to another session and skip. (3) Ignore other sessions' items in list_tasks results. (4) Employees inherit session: employee sessions work ONLY on their parent coordinator session's tasks. Cross-session work is a system violation."
|
|
1533
1620
|
},
|
|
1534
1621
|
// --- Engineering: session scoping in code ---
|
|
1535
1622
|
{
|
|
1536
1623
|
title: "Three-dimensional scoping \u2014 session, project, role \u2014 enforced in every query",
|
|
1537
1624
|
domain: "architecture",
|
|
1538
1625
|
priority: "p0",
|
|
1539
|
-
content: "Every DB query, notification, review count, and task operation MUST be scoped on 3 dimensions: (1) Session \u2014 filter by session_scope matching current
|
|
1626
|
+
content: "Every DB query, notification, review count, and task operation MUST be scoped on 3 dimensions: (1) Session \u2014 filter by session_scope matching the current coordinator session. (2) Project \u2014 filter by project_name. (3) Role \u2014 agents only see data at their hierarchy level. When writing ANY function that touches tasks, reviews, messages, or notifications: always accept a sessionScope parameter and pass it to the SQL WHERE clause. Unscoped queries are bugs. Test by running 2+ coordinator sessions simultaneously."
|
|
1540
1627
|
},
|
|
1541
1628
|
// --- Hard constraints ---
|
|
1542
1629
|
{
|
|
1543
1630
|
title: "What you CANNOT do in exe-os \u2014 hard constraints",
|
|
1544
1631
|
domain: "security",
|
|
1545
1632
|
priority: "p0",
|
|
1546
|
-
content: "NEVER: (1) Access the database directly \u2014 it's SQLCipher encrypted, always fails. Use MCP tools only. (2) Manually spawn tmux sessions \u2014 create_task handles it. (3) Run git checkout main \u2014 agents work in worktrees. (4) Modify another agent's in-progress task. (5) Push to remote \u2014
|
|
1633
|
+
content: "NEVER: (1) Access the database directly \u2014 it's SQLCipher encrypted, always fails. Use MCP tools only. (2) Manually spawn tmux sessions \u2014 create_task handles it. (3) Run git checkout main \u2014 agents work in worktrees. (4) Modify another agent's in-progress task. (5) Push to remote \u2014 the COO reviews and pushes. (6) Skip update_task(done) \u2014 it's the ONLY way your work gets reviewed. (7) Run git init."
|
|
1547
1634
|
},
|
|
1548
1635
|
// --- Operations ---
|
|
1549
1636
|
{
|
|
@@ -1662,24 +1749,24 @@ ${p.content}`).join("\n\n");
|
|
|
1662
1749
|
});
|
|
1663
1750
|
|
|
1664
1751
|
// src/lib/session-registry.ts
|
|
1665
|
-
import
|
|
1666
|
-
import
|
|
1752
|
+
import path5 from "path";
|
|
1753
|
+
import os4 from "os";
|
|
1667
1754
|
var REGISTRY_PATH;
|
|
1668
1755
|
var init_session_registry = __esm({
|
|
1669
1756
|
"src/lib/session-registry.ts"() {
|
|
1670
1757
|
"use strict";
|
|
1671
|
-
REGISTRY_PATH =
|
|
1758
|
+
REGISTRY_PATH = path5.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
1672
1759
|
}
|
|
1673
1760
|
});
|
|
1674
1761
|
|
|
1675
1762
|
// src/lib/session-key.ts
|
|
1676
|
-
import { execSync } from "child_process";
|
|
1763
|
+
import { execSync as execSync2 } from "child_process";
|
|
1677
1764
|
function getSessionKey() {
|
|
1678
1765
|
if (_cached) return _cached;
|
|
1679
1766
|
let pid = process.ppid;
|
|
1680
1767
|
for (let i = 0; i < 10; i++) {
|
|
1681
1768
|
try {
|
|
1682
|
-
const info =
|
|
1769
|
+
const info = execSync2(`ps -p ${pid} -o ppid=,comm=`, {
|
|
1683
1770
|
encoding: "utf8",
|
|
1684
1771
|
timeout: 2e3
|
|
1685
1772
|
}).trim();
|
|
@@ -1815,7 +1902,7 @@ var init_transport = __esm({
|
|
|
1815
1902
|
});
|
|
1816
1903
|
|
|
1817
1904
|
// src/lib/cc-agent-support.ts
|
|
1818
|
-
import { execSync as
|
|
1905
|
+
import { execSync as execSync3 } from "child_process";
|
|
1819
1906
|
var init_cc_agent_support = __esm({
|
|
1820
1907
|
"src/lib/cc-agent-support.ts"() {
|
|
1821
1908
|
"use strict";
|
|
@@ -1844,17 +1931,17 @@ var init_provider_table = __esm({
|
|
|
1844
1931
|
});
|
|
1845
1932
|
|
|
1846
1933
|
// src/lib/intercom-queue.ts
|
|
1847
|
-
import { readFileSync as
|
|
1848
|
-
import
|
|
1849
|
-
import
|
|
1934
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
1935
|
+
import path6 from "path";
|
|
1936
|
+
import os5 from "os";
|
|
1850
1937
|
function ensureDir() {
|
|
1851
|
-
const dir =
|
|
1852
|
-
if (!
|
|
1938
|
+
const dir = path6.dirname(QUEUE_PATH);
|
|
1939
|
+
if (!existsSync5(dir)) mkdirSync2(dir, { recursive: true });
|
|
1853
1940
|
}
|
|
1854
1941
|
function readQueue() {
|
|
1855
1942
|
try {
|
|
1856
|
-
if (!
|
|
1857
|
-
return JSON.parse(
|
|
1943
|
+
if (!existsSync5(QUEUE_PATH)) return [];
|
|
1944
|
+
return JSON.parse(readFileSync3(QUEUE_PATH, "utf8"));
|
|
1858
1945
|
} catch {
|
|
1859
1946
|
return [];
|
|
1860
1947
|
}
|
|
@@ -1862,8 +1949,8 @@ function readQueue() {
|
|
|
1862
1949
|
function writeQueue(queue) {
|
|
1863
1950
|
ensureDir();
|
|
1864
1951
|
const tmp = `${QUEUE_PATH}.tmp`;
|
|
1865
|
-
|
|
1866
|
-
|
|
1952
|
+
writeFileSync2(tmp, JSON.stringify(queue, null, 2));
|
|
1953
|
+
renameSync3(tmp, QUEUE_PATH);
|
|
1867
1954
|
}
|
|
1868
1955
|
function queueIntercom(targetSession, reason) {
|
|
1869
1956
|
const queue = readQueue();
|
|
@@ -1886,38 +1973,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
1886
1973
|
var init_intercom_queue = __esm({
|
|
1887
1974
|
"src/lib/intercom-queue.ts"() {
|
|
1888
1975
|
"use strict";
|
|
1889
|
-
QUEUE_PATH =
|
|
1976
|
+
QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
1890
1977
|
TTL_MS = 60 * 60 * 1e3;
|
|
1891
|
-
INTERCOM_LOG =
|
|
1892
|
-
}
|
|
1893
|
-
});
|
|
1894
|
-
|
|
1895
|
-
// src/lib/employees.ts
|
|
1896
|
-
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
1897
|
-
import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1898
|
-
import { execSync as execSync3 } from "child_process";
|
|
1899
|
-
import path6 from "path";
|
|
1900
|
-
import os5 from "os";
|
|
1901
|
-
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
1902
|
-
if (!existsSync5(employeesPath)) {
|
|
1903
|
-
return [];
|
|
1904
|
-
}
|
|
1905
|
-
const raw = await readFile3(employeesPath, "utf-8");
|
|
1906
|
-
try {
|
|
1907
|
-
return JSON.parse(raw);
|
|
1908
|
-
} catch {
|
|
1909
|
-
return [];
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
function getEmployee(employees, name) {
|
|
1913
|
-
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
1914
|
-
}
|
|
1915
|
-
var EMPLOYEES_PATH;
|
|
1916
|
-
var init_employees = __esm({
|
|
1917
|
-
"src/lib/employees.ts"() {
|
|
1918
|
-
"use strict";
|
|
1919
|
-
init_config();
|
|
1920
|
-
EMPLOYEES_PATH = path6.join(EXE_AI_DIR, "exe-employees.json");
|
|
1978
|
+
INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
1921
1979
|
}
|
|
1922
1980
|
});
|
|
1923
1981
|
|
|
@@ -1961,8 +2019,10 @@ function getMySession() {
|
|
|
1961
2019
|
return getTransport().getMySession();
|
|
1962
2020
|
}
|
|
1963
2021
|
function extractRootExe(name) {
|
|
1964
|
-
|
|
1965
|
-
|
|
2022
|
+
if (!name) return null;
|
|
2023
|
+
if (!name.includes("-")) return name;
|
|
2024
|
+
const parts = name.split("-").filter(Boolean);
|
|
2025
|
+
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
1966
2026
|
}
|
|
1967
2027
|
function getParentExe(sessionKey) {
|
|
1968
2028
|
try {
|
|
@@ -2042,12 +2102,14 @@ function getSessionState(sessionName) {
|
|
|
2042
2102
|
}
|
|
2043
2103
|
}
|
|
2044
2104
|
function isExeSession(sessionName) {
|
|
2045
|
-
|
|
2105
|
+
const matchesBaseWithInstance = (baseName) => sessionName === baseName || sessionName.startsWith(baseName) && /^\d+$/.test(sessionName.slice(baseName.length));
|
|
2106
|
+
const coordinatorName = getCoordinatorName();
|
|
2107
|
+
return matchesBaseWithInstance(coordinatorName) || matchesBaseWithInstance("exe");
|
|
2046
2108
|
}
|
|
2047
2109
|
function sendIntercom(targetSession) {
|
|
2048
2110
|
const transport = getTransport();
|
|
2049
2111
|
if (isExeSession(targetSession)) {
|
|
2050
|
-
logIntercom(`
|
|
2112
|
+
logIntercom(`SKIP_COORDINATOR \u2192 ${targetSession} (coordinator sessions use prompt-submit hook)`);
|
|
2051
2113
|
return "skipped_exe";
|
|
2052
2114
|
}
|
|
2053
2115
|
if (isDebounced(targetSession)) {
|
|
@@ -2098,6 +2160,7 @@ var init_tmux_routing = __esm({
|
|
|
2098
2160
|
init_provider_table();
|
|
2099
2161
|
init_intercom_queue();
|
|
2100
2162
|
init_plan_limits();
|
|
2163
|
+
init_employees();
|
|
2101
2164
|
SPAWN_LOCK_DIR = path9.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
2102
2165
|
SESSION_CACHE = path9.join(os6.homedir(), ".exe-os", "session-cache");
|
|
2103
2166
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
@@ -2262,6 +2325,10 @@ function spawnDaemon() {
|
|
|
2262
2325
|
stdio: ["ignore", "ignore", stderrFd],
|
|
2263
2326
|
env: {
|
|
2264
2327
|
...process.env,
|
|
2328
|
+
TMUX: void 0,
|
|
2329
|
+
// Daemon is global — must not inherit session scope
|
|
2330
|
+
TMUX_PANE: void 0,
|
|
2331
|
+
// Prevents resolveExeSession() from scoping to one session
|
|
2265
2332
|
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
2266
2333
|
EXE_DAEMON_PID: PID_PATH
|
|
2267
2334
|
}
|
|
@@ -2776,21 +2843,23 @@ function getReviewChecklist(role, agent, taskSlug) {
|
|
|
2776
2843
|
}
|
|
2777
2844
|
async function createReviewForCompletedTask(row, result, _baseDir, now) {
|
|
2778
2845
|
const taskFile = String(row.task_file);
|
|
2779
|
-
|
|
2846
|
+
const employees = await loadEmployees();
|
|
2847
|
+
const coordinatorName = getCoordinatorName(employees);
|
|
2848
|
+
if (String(row.assigned_to) === "exe" || isCoordinatorName(String(row.assigned_to), employees)) return;
|
|
2780
2849
|
if (String(row.title).startsWith("Review:")) return;
|
|
2781
2850
|
const fileName = taskFile.split("/").pop() ?? "";
|
|
2782
2851
|
if (fileName.startsWith("review-") && String(row.assigned_by) === "system") return;
|
|
2783
2852
|
if (fileName.startsWith("review-") && String(row.assigned_to) === "system") return;
|
|
2784
2853
|
const client = getClient();
|
|
2785
2854
|
const agent = String(row.assigned_to);
|
|
2786
|
-
const
|
|
2855
|
+
const rawReviewer = row.reviewer || row.assigned_by;
|
|
2856
|
+
const reviewer = rawReviewer ? String(rawReviewer) : coordinatorName;
|
|
2787
2857
|
const currentStatus = String(row.status ?? "");
|
|
2788
2858
|
if (currentStatus === "done") return;
|
|
2789
2859
|
const existingResult = String(row.result ?? "");
|
|
2790
2860
|
if (existingResult.includes("## Review notes")) return;
|
|
2791
2861
|
let reviewerRole = "unknown";
|
|
2792
2862
|
try {
|
|
2793
|
-
const employees = await loadEmployees();
|
|
2794
2863
|
const emp = getEmployee(employees, reviewer);
|
|
2795
2864
|
if (emp) reviewerRole = emp.role;
|
|
2796
2865
|
} catch {
|
|
@@ -2835,7 +2904,7 @@ async function createReviewForCompletedTask(row, result, _baseDir, now) {
|
|
|
2835
2904
|
agentRole: String(row.assigned_to),
|
|
2836
2905
|
event: "task_complete",
|
|
2837
2906
|
project: String(row.project_name),
|
|
2838
|
-
summary: `completed "${taskTitle}" \u2014
|
|
2907
|
+
summary: `completed "${taskTitle}" \u2014 ready for review`,
|
|
2839
2908
|
taskFile
|
|
2840
2909
|
});
|
|
2841
2910
|
const originalPriority = String(row.priority).toLowerCase();
|
|
@@ -3149,17 +3218,17 @@ init_memory();
|
|
|
3149
3218
|
init_database();
|
|
3150
3219
|
|
|
3151
3220
|
// src/lib/keychain.ts
|
|
3152
|
-
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
3153
|
-
import { existsSync } from "fs";
|
|
3154
|
-
import
|
|
3155
|
-
import
|
|
3221
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3222
|
+
import { existsSync as existsSync3 } from "fs";
|
|
3223
|
+
import path3 from "path";
|
|
3224
|
+
import os3 from "os";
|
|
3156
3225
|
var SERVICE = "exe-mem";
|
|
3157
3226
|
var ACCOUNT = "master-key";
|
|
3158
3227
|
function getKeyDir() {
|
|
3159
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
3228
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os3.homedir(), ".exe-os");
|
|
3160
3229
|
}
|
|
3161
3230
|
function getKeyPath() {
|
|
3162
|
-
return
|
|
3231
|
+
return path3.join(getKeyDir(), "master.key");
|
|
3163
3232
|
}
|
|
3164
3233
|
async function tryKeytar() {
|
|
3165
3234
|
try {
|
|
@@ -3180,11 +3249,11 @@ async function getMasterKey() {
|
|
|
3180
3249
|
}
|
|
3181
3250
|
}
|
|
3182
3251
|
const keyPath = getKeyPath();
|
|
3183
|
-
if (!
|
|
3252
|
+
if (!existsSync3(keyPath)) {
|
|
3184
3253
|
return null;
|
|
3185
3254
|
}
|
|
3186
3255
|
try {
|
|
3187
|
-
const content = await
|
|
3256
|
+
const content = await readFile3(keyPath, "utf-8");
|
|
3188
3257
|
return Buffer.from(content.trim(), "base64");
|
|
3189
3258
|
} catch {
|
|
3190
3259
|
return null;
|
|
@@ -3307,7 +3376,10 @@ async function writeMemory(record) {
|
|
|
3307
3376
|
source_path: record.source_path ?? null,
|
|
3308
3377
|
source_type: record.source_type ?? null,
|
|
3309
3378
|
tier: record.tier ?? classifyTier(record),
|
|
3310
|
-
supersedes_id: record.supersedes_id ?? null
|
|
3379
|
+
supersedes_id: record.supersedes_id ?? null,
|
|
3380
|
+
draft: record.draft ? 1 : 0,
|
|
3381
|
+
memory_type: record.memory_type ?? "raw",
|
|
3382
|
+
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null
|
|
3311
3383
|
};
|
|
3312
3384
|
_pendingRecords.push(dbRow);
|
|
3313
3385
|
orgBus.emit({
|
|
@@ -3362,6 +3434,9 @@ async function flushBatch() {
|
|
|
3362
3434
|
const sourceType = row.source_type ?? null;
|
|
3363
3435
|
const tier = row.tier ?? 3;
|
|
3364
3436
|
const supersedesId = row.supersedes_id ?? null;
|
|
3437
|
+
const draft = row.draft ? 1 : 0;
|
|
3438
|
+
const memoryType = row.memory_type ?? "raw";
|
|
3439
|
+
const trajectory = row.trajectory ?? null;
|
|
3365
3440
|
return {
|
|
3366
3441
|
sql: hasVector ? `INSERT OR IGNORE INTO memories
|
|
3367
3442
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
@@ -3369,15 +3444,15 @@ async function flushBatch() {
|
|
|
3369
3444
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
3370
3445
|
confidence, last_accessed,
|
|
3371
3446
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
3372
|
-
source_path, source_type, tier, supersedes_id)
|
|
3373
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
|
|
3447
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
|
|
3448
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
|
|
3374
3449
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
3375
3450
|
tool_name, project_name,
|
|
3376
3451
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
3377
3452
|
confidence, last_accessed,
|
|
3378
3453
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
3379
|
-
source_path, source_type, tier, supersedes_id)
|
|
3380
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3454
|
+
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory)
|
|
3455
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3381
3456
|
args: hasVector ? [
|
|
3382
3457
|
row.id,
|
|
3383
3458
|
row.agent_id,
|
|
@@ -3403,7 +3478,10 @@ async function flushBatch() {
|
|
|
3403
3478
|
sourcePath,
|
|
3404
3479
|
sourceType,
|
|
3405
3480
|
tier,
|
|
3406
|
-
supersedesId
|
|
3481
|
+
supersedesId,
|
|
3482
|
+
draft,
|
|
3483
|
+
memoryType,
|
|
3484
|
+
trajectory
|
|
3407
3485
|
] : [
|
|
3408
3486
|
row.id,
|
|
3409
3487
|
row.agent_id,
|
|
@@ -3428,7 +3506,10 @@ async function flushBatch() {
|
|
|
3428
3506
|
sourcePath,
|
|
3429
3507
|
sourceType,
|
|
3430
3508
|
tier,
|
|
3431
|
-
supersedesId
|
|
3509
|
+
supersedesId,
|
|
3510
|
+
draft,
|
|
3511
|
+
memoryType,
|
|
3512
|
+
trajectory
|
|
3432
3513
|
]
|
|
3433
3514
|
};
|
|
3434
3515
|
};
|