@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
package/dist/bin/setup.js
CHANGED
|
@@ -20,7 +20,6 @@ var config_exports = {};
|
|
|
20
20
|
__export(config_exports, {
|
|
21
21
|
CONFIG_MIGRATIONS: () => CONFIG_MIGRATIONS,
|
|
22
22
|
CONFIG_PATH: () => CONFIG_PATH,
|
|
23
|
-
COO_AGENT_NAME: () => COO_AGENT_NAME,
|
|
24
23
|
CURRENT_CONFIG_VERSION: () => CURRENT_CONFIG_VERSION,
|
|
25
24
|
DB_PATH: () => DB_PATH,
|
|
26
25
|
EXE_AI_DIR: () => EXE_AI_DIR,
|
|
@@ -176,7 +175,7 @@ async function loadConfigFrom(configPath) {
|
|
|
176
175
|
return { ...DEFAULT_CONFIG };
|
|
177
176
|
}
|
|
178
177
|
}
|
|
179
|
-
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH,
|
|
178
|
+
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
180
179
|
var init_config = __esm({
|
|
181
180
|
"src/lib/config.ts"() {
|
|
182
181
|
"use strict";
|
|
@@ -184,7 +183,6 @@ var init_config = __esm({
|
|
|
184
183
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
185
184
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
186
185
|
CONFIG_PATH = path.join(EXE_AI_DIR, "config.json");
|
|
187
|
-
COO_AGENT_NAME = "exe";
|
|
188
186
|
LEGACY_LANCE_PATH = path.join(EXE_AI_DIR, "local.lance");
|
|
189
187
|
CURRENT_CONFIG_VERSION = 1;
|
|
190
188
|
DEFAULT_CONFIG = {
|
|
@@ -220,13 +218,7 @@ var init_config = __esm({
|
|
|
220
218
|
wikiUrl: "",
|
|
221
219
|
wikiApiKey: "",
|
|
222
220
|
wikiSyncIntervalMs: 30 * 60 * 1e3,
|
|
223
|
-
wikiWorkspaceMapping: {
|
|
224
|
-
exe: "Executive",
|
|
225
|
-
yoshi: "Engineering",
|
|
226
|
-
mari: "Marketing",
|
|
227
|
-
tom: "Engineering",
|
|
228
|
-
sasha: "Production"
|
|
229
|
-
},
|
|
221
|
+
wikiWorkspaceMapping: {},
|
|
230
222
|
wikiAutoUpdate: true,
|
|
231
223
|
wikiAutoUpdateThreshold: 0.5,
|
|
232
224
|
wikiAutoUpdateCreateNew: true,
|
|
@@ -475,6 +467,10 @@ function spawnDaemon() {
|
|
|
475
467
|
stdio: ["ignore", "ignore", stderrFd],
|
|
476
468
|
env: {
|
|
477
469
|
...process.env,
|
|
470
|
+
TMUX: void 0,
|
|
471
|
+
// Daemon is global — must not inherit session scope
|
|
472
|
+
TMUX_PANE: void 0,
|
|
473
|
+
// Prevents resolveExeSession() from scoping to one session
|
|
478
474
|
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
479
475
|
EXE_DAEMON_PID: PID_PATH
|
|
480
476
|
}
|
|
@@ -568,11 +564,11 @@ async function connectEmbedDaemon() {
|
|
|
568
564
|
}
|
|
569
565
|
}
|
|
570
566
|
const start = Date.now();
|
|
571
|
-
let
|
|
567
|
+
let delay2 = 100;
|
|
572
568
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
573
|
-
await new Promise((r) => setTimeout(r,
|
|
569
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
574
570
|
if (await connectToSocket()) return true;
|
|
575
|
-
|
|
571
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
576
572
|
}
|
|
577
573
|
return false;
|
|
578
574
|
}
|
|
@@ -664,11 +660,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
664
660
|
`);
|
|
665
661
|
killAndRespawnDaemon();
|
|
666
662
|
const start = Date.now();
|
|
667
|
-
let
|
|
663
|
+
let delay2 = 200;
|
|
668
664
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
669
|
-
await new Promise((r) => setTimeout(r,
|
|
665
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
670
666
|
if (await connectToSocket()) break;
|
|
671
|
-
|
|
667
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
672
668
|
}
|
|
673
669
|
if (!_connected) return null;
|
|
674
670
|
}
|
|
@@ -680,11 +676,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
680
676
|
`);
|
|
681
677
|
killAndRespawnDaemon();
|
|
682
678
|
const start = Date.now();
|
|
683
|
-
let
|
|
679
|
+
let delay2 = 200;
|
|
684
680
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
685
|
-
await new Promise((r) => setTimeout(r,
|
|
681
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
686
682
|
if (await connectToSocket()) break;
|
|
687
|
-
|
|
683
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
688
684
|
}
|
|
689
685
|
if (!_connected) return null;
|
|
690
686
|
const retry = await sendRequest([text], priority);
|
|
@@ -1243,61 +1239,80 @@ var init_crypto = __esm({
|
|
|
1243
1239
|
});
|
|
1244
1240
|
|
|
1245
1241
|
// src/lib/db-retry.ts
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
});
|
|
1251
|
-
|
|
1252
|
-
// src/lib/database.ts
|
|
1253
|
-
import { createClient } from "@libsql/client";
|
|
1254
|
-
function getClient() {
|
|
1255
|
-
if (!_resilientClient) {
|
|
1256
|
-
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1242
|
+
function isBusyError(err) {
|
|
1243
|
+
if (err instanceof Error) {
|
|
1244
|
+
const msg = err.message.toLowerCase();
|
|
1245
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1257
1246
|
}
|
|
1258
|
-
return
|
|
1247
|
+
return false;
|
|
1259
1248
|
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1249
|
+
function delay(ms) {
|
|
1250
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1251
|
+
}
|
|
1252
|
+
async function retryOnBusy(fn, label) {
|
|
1253
|
+
let lastError;
|
|
1254
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
1255
|
+
try {
|
|
1256
|
+
return await fn();
|
|
1257
|
+
} catch (err) {
|
|
1258
|
+
lastError = err;
|
|
1259
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
1260
|
+
throw err;
|
|
1261
|
+
}
|
|
1262
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
1263
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
1264
|
+
process.stderr.write(
|
|
1265
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
1266
|
+
`
|
|
1267
|
+
);
|
|
1268
|
+
await delay(backoff + jitter);
|
|
1269
|
+
}
|
|
1266
1270
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1271
|
+
throw lastError;
|
|
1272
|
+
}
|
|
1273
|
+
function wrapWithRetry(client) {
|
|
1274
|
+
return new Proxy(client, {
|
|
1275
|
+
get(target, prop, receiver) {
|
|
1276
|
+
if (prop === "execute") {
|
|
1277
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
1278
|
+
}
|
|
1279
|
+
if (prop === "batch") {
|
|
1280
|
+
return (stmts, mode) => retryOnBusy(() => target.batch(stmts, mode), "batch");
|
|
1281
|
+
}
|
|
1282
|
+
return Reflect.get(target, prop, receiver);
|
|
1276
1283
|
}
|
|
1277
1284
|
});
|
|
1278
1285
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
}
|
|
1283
|
-
var init_compress = __esm({
|
|
1284
|
-
"src/lib/compress.ts"() {
|
|
1286
|
+
var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
|
|
1287
|
+
var init_db_retry = __esm({
|
|
1288
|
+
"src/lib/db-retry.ts"() {
|
|
1285
1289
|
"use strict";
|
|
1290
|
+
MAX_RETRIES = 3;
|
|
1291
|
+
BASE_DELAY_MS = 200;
|
|
1292
|
+
MAX_JITTER_MS = 300;
|
|
1286
1293
|
}
|
|
1287
1294
|
});
|
|
1288
1295
|
|
|
1289
1296
|
// src/lib/employees.ts
|
|
1290
1297
|
var employees_exports = {};
|
|
1291
1298
|
__export(employees_exports, {
|
|
1299
|
+
COORDINATOR_ROLE: () => COORDINATOR_ROLE,
|
|
1300
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
1292
1301
|
EMPLOYEES_PATH: () => EMPLOYEES_PATH,
|
|
1293
1302
|
addEmployee: () => addEmployee,
|
|
1303
|
+
canCoordinate: () => canCoordinate,
|
|
1304
|
+
getCoordinatorEmployee: () => getCoordinatorEmployee,
|
|
1305
|
+
getCoordinatorName: () => getCoordinatorName,
|
|
1294
1306
|
getEmployee: () => getEmployee,
|
|
1295
1307
|
getEmployeeByRole: () => getEmployeeByRole,
|
|
1296
1308
|
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
1297
1309
|
hasRole: () => hasRole,
|
|
1310
|
+
isCoordinatorName: () => isCoordinatorName,
|
|
1311
|
+
isCoordinatorRole: () => isCoordinatorRole,
|
|
1298
1312
|
isMultiInstance: () => isMultiInstance,
|
|
1299
1313
|
loadEmployees: () => loadEmployees,
|
|
1300
1314
|
loadEmployeesSync: () => loadEmployeesSync,
|
|
1315
|
+
normalizeRole: () => normalizeRole,
|
|
1301
1316
|
normalizeRosterCase: () => normalizeRosterCase,
|
|
1302
1317
|
registerBinSymlinks: () => registerBinSymlinks,
|
|
1303
1318
|
saveEmployees: () => saveEmployees,
|
|
@@ -1308,6 +1323,25 @@ import { existsSync as existsSync6, symlinkSync, readlinkSync, readFileSync as r
|
|
|
1308
1323
|
import { execSync } from "child_process";
|
|
1309
1324
|
import path6 from "path";
|
|
1310
1325
|
import os3 from "os";
|
|
1326
|
+
function normalizeRole(role) {
|
|
1327
|
+
return (role ?? "").trim().toLowerCase();
|
|
1328
|
+
}
|
|
1329
|
+
function isCoordinatorRole(role) {
|
|
1330
|
+
return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
|
|
1331
|
+
}
|
|
1332
|
+
function getCoordinatorEmployee(employees) {
|
|
1333
|
+
return employees.find((e) => isCoordinatorRole(e.role));
|
|
1334
|
+
}
|
|
1335
|
+
function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
1336
|
+
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
1337
|
+
}
|
|
1338
|
+
function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
|
|
1339
|
+
if (!agentName) return false;
|
|
1340
|
+
return agentName.toLowerCase() === getCoordinatorName(employees).toLowerCase();
|
|
1341
|
+
}
|
|
1342
|
+
function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
|
|
1343
|
+
return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
|
|
1344
|
+
}
|
|
1311
1345
|
function validateEmployeeName(name) {
|
|
1312
1346
|
if (!name) {
|
|
1313
1347
|
return { valid: false, error: "Name is required" };
|
|
@@ -1445,16 +1479,948 @@ function registerBinSymlinks(name) {
|
|
|
1445
1479
|
}
|
|
1446
1480
|
return { created, skipped, errors };
|
|
1447
1481
|
}
|
|
1448
|
-
var EMPLOYEES_PATH, MULTI_INSTANCE_ROLES;
|
|
1482
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
|
|
1449
1483
|
var init_employees = __esm({
|
|
1450
1484
|
"src/lib/employees.ts"() {
|
|
1451
1485
|
"use strict";
|
|
1452
1486
|
init_config();
|
|
1453
1487
|
EMPLOYEES_PATH = path6.join(EXE_AI_DIR, "exe-employees.json");
|
|
1488
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
1489
|
+
COORDINATOR_ROLE = "COO";
|
|
1454
1490
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
1455
1491
|
}
|
|
1456
1492
|
});
|
|
1457
1493
|
|
|
1494
|
+
// src/lib/database.ts
|
|
1495
|
+
var database_exports = {};
|
|
1496
|
+
__export(database_exports, {
|
|
1497
|
+
disposeDatabase: () => disposeDatabase,
|
|
1498
|
+
disposeTurso: () => disposeTurso,
|
|
1499
|
+
ensureSchema: () => ensureSchema,
|
|
1500
|
+
getClient: () => getClient,
|
|
1501
|
+
getRawClient: () => getRawClient,
|
|
1502
|
+
initDatabase: () => initDatabase,
|
|
1503
|
+
initTurso: () => initTurso,
|
|
1504
|
+
isInitialized: () => isInitialized
|
|
1505
|
+
});
|
|
1506
|
+
import { createClient } from "@libsql/client";
|
|
1507
|
+
async function initDatabase(config) {
|
|
1508
|
+
if (_client) {
|
|
1509
|
+
_client.close();
|
|
1510
|
+
_client = null;
|
|
1511
|
+
_resilientClient = null;
|
|
1512
|
+
}
|
|
1513
|
+
const opts = {
|
|
1514
|
+
url: `file:${config.dbPath}`
|
|
1515
|
+
};
|
|
1516
|
+
if (config.encryptionKey) {
|
|
1517
|
+
opts.encryptionKey = config.encryptionKey;
|
|
1518
|
+
}
|
|
1519
|
+
_client = createClient(opts);
|
|
1520
|
+
_resilientClient = wrapWithRetry(_client);
|
|
1521
|
+
}
|
|
1522
|
+
function isInitialized() {
|
|
1523
|
+
return _client !== null;
|
|
1524
|
+
}
|
|
1525
|
+
function getClient() {
|
|
1526
|
+
if (!_resilientClient) {
|
|
1527
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1528
|
+
}
|
|
1529
|
+
return _resilientClient;
|
|
1530
|
+
}
|
|
1531
|
+
function getRawClient() {
|
|
1532
|
+
if (!_client) {
|
|
1533
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1534
|
+
}
|
|
1535
|
+
return _client;
|
|
1536
|
+
}
|
|
1537
|
+
async function ensureSchema() {
|
|
1538
|
+
const client = getRawClient();
|
|
1539
|
+
await client.execute("PRAGMA journal_mode = WAL");
|
|
1540
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
1541
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
1542
|
+
try {
|
|
1543
|
+
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
1544
|
+
} catch {
|
|
1545
|
+
}
|
|
1546
|
+
await client.executeMultiple(`
|
|
1547
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
1548
|
+
id TEXT PRIMARY KEY,
|
|
1549
|
+
agent_id TEXT NOT NULL,
|
|
1550
|
+
agent_role TEXT NOT NULL,
|
|
1551
|
+
session_id TEXT NOT NULL,
|
|
1552
|
+
timestamp TEXT NOT NULL,
|
|
1553
|
+
tool_name TEXT NOT NULL,
|
|
1554
|
+
project_name TEXT NOT NULL,
|
|
1555
|
+
has_error INTEGER NOT NULL DEFAULT 0,
|
|
1556
|
+
raw_text TEXT NOT NULL,
|
|
1557
|
+
vector F32_BLOB(1024),
|
|
1558
|
+
version INTEGER NOT NULL DEFAULT 0
|
|
1559
|
+
);
|
|
1560
|
+
|
|
1561
|
+
CREATE INDEX IF NOT EXISTS idx_memories_agent
|
|
1562
|
+
ON memories(agent_id);
|
|
1563
|
+
|
|
1564
|
+
CREATE INDEX IF NOT EXISTS idx_memories_timestamp
|
|
1565
|
+
ON memories(timestamp);
|
|
1566
|
+
|
|
1567
|
+
CREATE INDEX IF NOT EXISTS idx_memories_session
|
|
1568
|
+
ON memories(session_id);
|
|
1569
|
+
|
|
1570
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project
|
|
1571
|
+
ON memories(project_name);
|
|
1572
|
+
|
|
1573
|
+
CREATE INDEX IF NOT EXISTS idx_memories_tool
|
|
1574
|
+
ON memories(tool_name);
|
|
1575
|
+
|
|
1576
|
+
CREATE INDEX IF NOT EXISTS idx_memories_version
|
|
1577
|
+
ON memories(version);
|
|
1578
|
+
|
|
1579
|
+
CREATE INDEX IF NOT EXISTS idx_memories_agent_project
|
|
1580
|
+
ON memories(agent_id, project_name);
|
|
1581
|
+
`);
|
|
1582
|
+
await client.executeMultiple(`
|
|
1583
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
1584
|
+
raw_text,
|
|
1585
|
+
content='memories',
|
|
1586
|
+
content_rowid='rowid'
|
|
1587
|
+
);
|
|
1588
|
+
|
|
1589
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_ai AFTER INSERT ON memories BEGIN
|
|
1590
|
+
INSERT INTO memories_fts(rowid, raw_text) VALUES (new.rowid, new.raw_text);
|
|
1591
|
+
END;
|
|
1592
|
+
|
|
1593
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_ad AFTER DELETE ON memories BEGIN
|
|
1594
|
+
INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
|
|
1595
|
+
END;
|
|
1596
|
+
|
|
1597
|
+
CREATE TRIGGER IF NOT EXISTS memories_fts_au AFTER UPDATE ON memories BEGIN
|
|
1598
|
+
INSERT INTO memories_fts(memories_fts, rowid, raw_text) VALUES('delete', old.rowid, old.raw_text);
|
|
1599
|
+
INSERT INTO memories_fts(rowid, raw_text) VALUES (new.rowid, new.raw_text);
|
|
1600
|
+
END;
|
|
1601
|
+
`);
|
|
1602
|
+
await client.executeMultiple(`
|
|
1603
|
+
CREATE TABLE IF NOT EXISTS sync_meta (
|
|
1604
|
+
key TEXT PRIMARY KEY,
|
|
1605
|
+
value TEXT NOT NULL
|
|
1606
|
+
);
|
|
1607
|
+
`);
|
|
1608
|
+
await client.executeMultiple(`
|
|
1609
|
+
CREATE TABLE IF NOT EXISTS tasks (
|
|
1610
|
+
id TEXT PRIMARY KEY,
|
|
1611
|
+
title TEXT NOT NULL,
|
|
1612
|
+
assigned_to TEXT NOT NULL,
|
|
1613
|
+
assigned_by TEXT NOT NULL,
|
|
1614
|
+
project_name TEXT NOT NULL,
|
|
1615
|
+
priority TEXT NOT NULL DEFAULT 'p1',
|
|
1616
|
+
status TEXT NOT NULL DEFAULT 'open',
|
|
1617
|
+
task_file TEXT,
|
|
1618
|
+
created_at TEXT NOT NULL,
|
|
1619
|
+
updated_at TEXT NOT NULL
|
|
1620
|
+
);
|
|
1621
|
+
|
|
1622
|
+
CREATE INDEX IF NOT EXISTS idx_tasks_assignee_status
|
|
1623
|
+
ON tasks(assigned_to, status);
|
|
1624
|
+
`);
|
|
1625
|
+
await client.executeMultiple(`
|
|
1626
|
+
CREATE TABLE IF NOT EXISTS behaviors (
|
|
1627
|
+
id TEXT PRIMARY KEY,
|
|
1628
|
+
agent_id TEXT NOT NULL,
|
|
1629
|
+
project_name TEXT,
|
|
1630
|
+
domain TEXT,
|
|
1631
|
+
content TEXT NOT NULL,
|
|
1632
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
1633
|
+
created_at TEXT NOT NULL,
|
|
1634
|
+
updated_at TEXT NOT NULL
|
|
1635
|
+
);
|
|
1636
|
+
|
|
1637
|
+
CREATE INDEX IF NOT EXISTS idx_behaviors_agent
|
|
1638
|
+
ON behaviors(agent_id, active);
|
|
1639
|
+
`);
|
|
1640
|
+
try {
|
|
1641
|
+
const coordinatorName = getCoordinatorName();
|
|
1642
|
+
const existing = await client.execute({
|
|
1643
|
+
sql: "SELECT COUNT(*) as cnt FROM behaviors WHERE agent_id = ?",
|
|
1644
|
+
args: [coordinatorName]
|
|
1645
|
+
});
|
|
1646
|
+
if (Number(existing.rows[0]?.cnt) === 0) {
|
|
1647
|
+
const seededAt = "2026-03-25T00:00:00Z";
|
|
1648
|
+
for (const [domain, content] of [
|
|
1649
|
+
["workflow", `Don't ask "keep going?" \u2014 just keep executing phases/plans autonomously`],
|
|
1650
|
+
["tool-use", "Always use create_task MCP tool, never write .md files directly for task creation"],
|
|
1651
|
+
["workflow", "Auto-start reviewing when idle and reviews are pending \u2014 never ask founder for permission"]
|
|
1652
|
+
]) {
|
|
1653
|
+
await client.execute({
|
|
1654
|
+
sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, content, active, created_at, updated_at)
|
|
1655
|
+
VALUES (hex(randomblob(16)), ?, NULL, ?, ?, 1, ?, ?)`,
|
|
1656
|
+
args: [coordinatorName, domain, content, seededAt, seededAt]
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
} catch {
|
|
1661
|
+
}
|
|
1662
|
+
try {
|
|
1663
|
+
await client.execute({
|
|
1664
|
+
sql: `ALTER TABLE behaviors ADD COLUMN priority TEXT DEFAULT 'p1'`,
|
|
1665
|
+
args: []
|
|
1666
|
+
});
|
|
1667
|
+
} catch {
|
|
1668
|
+
}
|
|
1669
|
+
try {
|
|
1670
|
+
await client.execute({
|
|
1671
|
+
sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
|
|
1672
|
+
args: []
|
|
1673
|
+
});
|
|
1674
|
+
} catch {
|
|
1675
|
+
}
|
|
1676
|
+
try {
|
|
1677
|
+
await client.execute({
|
|
1678
|
+
sql: `ALTER TABLE tasks ADD COLUMN parent_task_id TEXT`,
|
|
1679
|
+
args: []
|
|
1680
|
+
});
|
|
1681
|
+
} catch {
|
|
1682
|
+
}
|
|
1683
|
+
try {
|
|
1684
|
+
await client.execute({
|
|
1685
|
+
sql: `CREATE INDEX IF NOT EXISTS idx_tasks_parent_task_id
|
|
1686
|
+
ON tasks(parent_task_id)
|
|
1687
|
+
WHERE parent_task_id IS NOT NULL`,
|
|
1688
|
+
args: []
|
|
1689
|
+
});
|
|
1690
|
+
} catch {
|
|
1691
|
+
}
|
|
1692
|
+
try {
|
|
1693
|
+
await client.execute({
|
|
1694
|
+
sql: `UPDATE tasks SET status = 'done' WHERE status = 'completed'`,
|
|
1695
|
+
args: []
|
|
1696
|
+
});
|
|
1697
|
+
} catch {
|
|
1698
|
+
}
|
|
1699
|
+
try {
|
|
1700
|
+
await client.execute({
|
|
1701
|
+
sql: `ALTER TABLE tasks ADD COLUMN reviewer TEXT`,
|
|
1702
|
+
args: []
|
|
1703
|
+
});
|
|
1704
|
+
} catch {
|
|
1705
|
+
}
|
|
1706
|
+
try {
|
|
1707
|
+
await client.execute({
|
|
1708
|
+
sql: `ALTER TABLE tasks ADD COLUMN context TEXT`,
|
|
1709
|
+
args: []
|
|
1710
|
+
});
|
|
1711
|
+
} catch {
|
|
1712
|
+
}
|
|
1713
|
+
try {
|
|
1714
|
+
await client.execute({
|
|
1715
|
+
sql: `ALTER TABLE tasks ADD COLUMN result TEXT`,
|
|
1716
|
+
args: []
|
|
1717
|
+
});
|
|
1718
|
+
} catch {
|
|
1719
|
+
}
|
|
1720
|
+
try {
|
|
1721
|
+
await client.execute({
|
|
1722
|
+
sql: `ALTER TABLE tasks ADD COLUMN assigned_tmux TEXT`,
|
|
1723
|
+
args: []
|
|
1724
|
+
});
|
|
1725
|
+
} catch {
|
|
1726
|
+
}
|
|
1727
|
+
try {
|
|
1728
|
+
await client.execute({
|
|
1729
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
|
|
1730
|
+
args: []
|
|
1731
|
+
});
|
|
1732
|
+
} catch {
|
|
1733
|
+
}
|
|
1734
|
+
try {
|
|
1735
|
+
await client.execute({
|
|
1736
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
|
|
1737
|
+
args: []
|
|
1738
|
+
});
|
|
1739
|
+
} catch {
|
|
1740
|
+
}
|
|
1741
|
+
try {
|
|
1742
|
+
await client.execute({
|
|
1743
|
+
sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
|
|
1744
|
+
args: []
|
|
1745
|
+
});
|
|
1746
|
+
} catch {
|
|
1747
|
+
}
|
|
1748
|
+
try {
|
|
1749
|
+
await client.execute({
|
|
1750
|
+
sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
|
|
1751
|
+
args: []
|
|
1752
|
+
});
|
|
1753
|
+
} catch {
|
|
1754
|
+
}
|
|
1755
|
+
try {
|
|
1756
|
+
await client.execute({
|
|
1757
|
+
sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
|
|
1758
|
+
args: []
|
|
1759
|
+
});
|
|
1760
|
+
} catch {
|
|
1761
|
+
}
|
|
1762
|
+
try {
|
|
1763
|
+
await client.execute({
|
|
1764
|
+
sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
|
|
1765
|
+
args: []
|
|
1766
|
+
});
|
|
1767
|
+
} catch {
|
|
1768
|
+
}
|
|
1769
|
+
try {
|
|
1770
|
+
await client.execute({
|
|
1771
|
+
sql: `ALTER TABLE memories ADD COLUMN author_device_id TEXT`,
|
|
1772
|
+
args: []
|
|
1773
|
+
});
|
|
1774
|
+
} catch {
|
|
1775
|
+
}
|
|
1776
|
+
try {
|
|
1777
|
+
await client.execute({
|
|
1778
|
+
sql: `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'`,
|
|
1779
|
+
args: []
|
|
1780
|
+
});
|
|
1781
|
+
} catch {
|
|
1782
|
+
}
|
|
1783
|
+
await client.executeMultiple(`
|
|
1784
|
+
CREATE TABLE IF NOT EXISTS consolidations (
|
|
1785
|
+
id TEXT PRIMARY KEY,
|
|
1786
|
+
consolidated_memory_id TEXT NOT NULL,
|
|
1787
|
+
source_memory_id TEXT NOT NULL,
|
|
1788
|
+
created_at TEXT NOT NULL
|
|
1789
|
+
);
|
|
1790
|
+
|
|
1791
|
+
CREATE INDEX IF NOT EXISTS idx_consolidations_source
|
|
1792
|
+
ON consolidations(source_memory_id);
|
|
1793
|
+
|
|
1794
|
+
CREATE INDEX IF NOT EXISTS idx_consolidations_consolidated
|
|
1795
|
+
ON consolidations(consolidated_memory_id);
|
|
1796
|
+
`);
|
|
1797
|
+
await client.executeMultiple(`
|
|
1798
|
+
CREATE TABLE IF NOT EXISTS reminders (
|
|
1799
|
+
id TEXT PRIMARY KEY,
|
|
1800
|
+
text TEXT NOT NULL,
|
|
1801
|
+
created_at TEXT NOT NULL,
|
|
1802
|
+
due_date TEXT,
|
|
1803
|
+
completed_at TEXT
|
|
1804
|
+
);
|
|
1805
|
+
`);
|
|
1806
|
+
await client.executeMultiple(`
|
|
1807
|
+
CREATE TABLE IF NOT EXISTS notifications (
|
|
1808
|
+
id TEXT PRIMARY KEY,
|
|
1809
|
+
agent_id TEXT NOT NULL,
|
|
1810
|
+
agent_role TEXT NOT NULL,
|
|
1811
|
+
event TEXT NOT NULL,
|
|
1812
|
+
project TEXT NOT NULL,
|
|
1813
|
+
summary TEXT NOT NULL,
|
|
1814
|
+
task_file TEXT,
|
|
1815
|
+
read INTEGER NOT NULL DEFAULT 0,
|
|
1816
|
+
created_at TEXT NOT NULL
|
|
1817
|
+
);
|
|
1818
|
+
|
|
1819
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_read
|
|
1820
|
+
ON notifications(read);
|
|
1821
|
+
|
|
1822
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_agent
|
|
1823
|
+
ON notifications(agent_id);
|
|
1824
|
+
|
|
1825
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_task_file
|
|
1826
|
+
ON notifications(task_file);
|
|
1827
|
+
`);
|
|
1828
|
+
await client.executeMultiple(`
|
|
1829
|
+
CREATE TABLE IF NOT EXISTS schedules (
|
|
1830
|
+
id TEXT PRIMARY KEY,
|
|
1831
|
+
cron TEXT NOT NULL,
|
|
1832
|
+
description TEXT NOT NULL,
|
|
1833
|
+
job_type TEXT NOT NULL DEFAULT 'report',
|
|
1834
|
+
prompt TEXT,
|
|
1835
|
+
assigned_to TEXT,
|
|
1836
|
+
project_name TEXT,
|
|
1837
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
1838
|
+
use_crontab INTEGER NOT NULL DEFAULT 0,
|
|
1839
|
+
created_at TEXT NOT NULL
|
|
1840
|
+
);
|
|
1841
|
+
`);
|
|
1842
|
+
await client.executeMultiple(`
|
|
1843
|
+
CREATE TABLE IF NOT EXISTS device_registry (
|
|
1844
|
+
device_id TEXT PRIMARY KEY,
|
|
1845
|
+
friendly_name TEXT NOT NULL,
|
|
1846
|
+
hostname TEXT NOT NULL,
|
|
1847
|
+
projects TEXT NOT NULL DEFAULT '[]',
|
|
1848
|
+
agents TEXT NOT NULL DEFAULT '[]',
|
|
1849
|
+
connected INTEGER DEFAULT 0,
|
|
1850
|
+
last_seen TEXT NOT NULL
|
|
1851
|
+
);
|
|
1852
|
+
`);
|
|
1853
|
+
await client.executeMultiple(`
|
|
1854
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
1855
|
+
id TEXT PRIMARY KEY,
|
|
1856
|
+
from_agent TEXT NOT NULL,
|
|
1857
|
+
from_device TEXT NOT NULL DEFAULT 'local',
|
|
1858
|
+
target_agent TEXT NOT NULL,
|
|
1859
|
+
target_project TEXT,
|
|
1860
|
+
target_device TEXT NOT NULL DEFAULT 'local',
|
|
1861
|
+
content TEXT NOT NULL,
|
|
1862
|
+
priority TEXT DEFAULT 'normal',
|
|
1863
|
+
status TEXT DEFAULT 'pending',
|
|
1864
|
+
server_seq INTEGER,
|
|
1865
|
+
retry_count INTEGER DEFAULT 0,
|
|
1866
|
+
created_at TEXT NOT NULL,
|
|
1867
|
+
delivered_at TEXT,
|
|
1868
|
+
processed_at TEXT,
|
|
1869
|
+
failed_at TEXT,
|
|
1870
|
+
failure_reason TEXT
|
|
1871
|
+
);
|
|
1872
|
+
|
|
1873
|
+
CREATE INDEX IF NOT EXISTS idx_messages_target
|
|
1874
|
+
ON messages(target_agent, status);
|
|
1875
|
+
|
|
1876
|
+
CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
|
|
1877
|
+
ON messages(target_agent, from_agent, server_seq);
|
|
1878
|
+
`);
|
|
1879
|
+
try {
|
|
1880
|
+
await client.execute({
|
|
1881
|
+
sql: `UPDATE memories SET project_name = 'exe-create' WHERE project_name = 'web'`,
|
|
1882
|
+
args: []
|
|
1883
|
+
});
|
|
1884
|
+
await client.execute({
|
|
1885
|
+
sql: `UPDATE memories SET project_name = 'exe-os' WHERE project_name = 'worker'`,
|
|
1886
|
+
args: []
|
|
1887
|
+
});
|
|
1888
|
+
await client.execute({
|
|
1889
|
+
sql: `UPDATE tasks SET project_name = 'exe-create' WHERE project_name = 'web'`,
|
|
1890
|
+
args: []
|
|
1891
|
+
});
|
|
1892
|
+
await client.execute({
|
|
1893
|
+
sql: `UPDATE tasks SET project_name = 'exe-os' WHERE project_name = 'worker'`,
|
|
1894
|
+
args: []
|
|
1895
|
+
});
|
|
1896
|
+
} catch {
|
|
1897
|
+
}
|
|
1898
|
+
await client.executeMultiple(`
|
|
1899
|
+
CREATE TABLE IF NOT EXISTS trajectories (
|
|
1900
|
+
id TEXT PRIMARY KEY,
|
|
1901
|
+
task_id TEXT NOT NULL,
|
|
1902
|
+
agent_id TEXT NOT NULL,
|
|
1903
|
+
project_name TEXT NOT NULL,
|
|
1904
|
+
task_title TEXT NOT NULL,
|
|
1905
|
+
signature TEXT NOT NULL,
|
|
1906
|
+
signature_hash TEXT NOT NULL,
|
|
1907
|
+
tool_count INTEGER NOT NULL,
|
|
1908
|
+
skill_id TEXT,
|
|
1909
|
+
created_at TEXT NOT NULL
|
|
1910
|
+
);
|
|
1911
|
+
|
|
1912
|
+
CREATE INDEX IF NOT EXISTS idx_trajectories_hash
|
|
1913
|
+
ON trajectories(signature_hash);
|
|
1914
|
+
|
|
1915
|
+
CREATE INDEX IF NOT EXISTS idx_trajectories_agent
|
|
1916
|
+
ON trajectories(agent_id);
|
|
1917
|
+
`);
|
|
1918
|
+
try {
|
|
1919
|
+
await client.execute("ALTER TABLE trajectories ADD COLUMN skill_id TEXT");
|
|
1920
|
+
} catch {
|
|
1921
|
+
}
|
|
1922
|
+
await client.executeMultiple(`
|
|
1923
|
+
CREATE TABLE IF NOT EXISTS consolidations (
|
|
1924
|
+
id TEXT PRIMARY KEY,
|
|
1925
|
+
consolidated_memory_id TEXT NOT NULL,
|
|
1926
|
+
source_memory_id TEXT NOT NULL,
|
|
1927
|
+
created_at TEXT NOT NULL
|
|
1928
|
+
);
|
|
1929
|
+
|
|
1930
|
+
CREATE INDEX IF NOT EXISTS idx_consolidations_source
|
|
1931
|
+
ON consolidations(source_memory_id);
|
|
1932
|
+
`);
|
|
1933
|
+
await client.executeMultiple(`
|
|
1934
|
+
CREATE TABLE IF NOT EXISTS audit_trail (
|
|
1935
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1936
|
+
timestamp TEXT NOT NULL,
|
|
1937
|
+
session_id TEXT NOT NULL,
|
|
1938
|
+
agent_id TEXT NOT NULL,
|
|
1939
|
+
tool TEXT NOT NULL,
|
|
1940
|
+
input TEXT,
|
|
1941
|
+
decision TEXT NOT NULL,
|
|
1942
|
+
reason TEXT,
|
|
1943
|
+
is_customer_facing INTEGER NOT NULL DEFAULT 0
|
|
1944
|
+
);
|
|
1945
|
+
|
|
1946
|
+
CREATE INDEX IF NOT EXISTS idx_audit_trail_agent
|
|
1947
|
+
ON audit_trail(agent_id, timestamp);
|
|
1948
|
+
|
|
1949
|
+
CREATE INDEX IF NOT EXISTS idx_audit_trail_session
|
|
1950
|
+
ON audit_trail(session_id);
|
|
1951
|
+
`);
|
|
1952
|
+
try {
|
|
1953
|
+
await client.execute({
|
|
1954
|
+
sql: `ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0`,
|
|
1955
|
+
args: []
|
|
1956
|
+
});
|
|
1957
|
+
} catch {
|
|
1958
|
+
}
|
|
1959
|
+
try {
|
|
1960
|
+
await client.execute({
|
|
1961
|
+
sql: `ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5`,
|
|
1962
|
+
args: []
|
|
1963
|
+
});
|
|
1964
|
+
} catch {
|
|
1965
|
+
}
|
|
1966
|
+
try {
|
|
1967
|
+
await client.execute({
|
|
1968
|
+
sql: `ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'`,
|
|
1969
|
+
args: []
|
|
1970
|
+
});
|
|
1971
|
+
} catch {
|
|
1972
|
+
}
|
|
1973
|
+
try {
|
|
1974
|
+
await client.execute({
|
|
1975
|
+
sql: `ALTER TABLE memories ADD COLUMN confidence REAL DEFAULT 0.7`,
|
|
1976
|
+
args: []
|
|
1977
|
+
});
|
|
1978
|
+
} catch {
|
|
1979
|
+
}
|
|
1980
|
+
try {
|
|
1981
|
+
await client.execute({
|
|
1982
|
+
sql: `ALTER TABLE memories ADD COLUMN last_accessed TEXT`,
|
|
1983
|
+
args: []
|
|
1984
|
+
});
|
|
1985
|
+
} catch {
|
|
1986
|
+
}
|
|
1987
|
+
try {
|
|
1988
|
+
await client.execute({
|
|
1989
|
+
sql: `UPDATE memories SET last_accessed = timestamp WHERE last_accessed IS NULL`,
|
|
1990
|
+
args: []
|
|
1991
|
+
});
|
|
1992
|
+
} catch {
|
|
1993
|
+
}
|
|
1994
|
+
try {
|
|
1995
|
+
await client.execute({
|
|
1996
|
+
sql: `ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0`,
|
|
1997
|
+
args: []
|
|
1998
|
+
});
|
|
1999
|
+
} catch {
|
|
2000
|
+
}
|
|
2001
|
+
try {
|
|
2002
|
+
await client.execute({
|
|
2003
|
+
sql: `ALTER TABLE memories ADD COLUMN graph_extracted INTEGER DEFAULT 0`,
|
|
2004
|
+
args: []
|
|
2005
|
+
});
|
|
2006
|
+
} catch {
|
|
2007
|
+
}
|
|
2008
|
+
for (const col of [
|
|
2009
|
+
"ALTER TABLE memories ADD COLUMN content_hash TEXT",
|
|
2010
|
+
"ALTER TABLE memories ADD COLUMN graph_extracted_hash TEXT"
|
|
2011
|
+
]) {
|
|
2012
|
+
try {
|
|
2013
|
+
await client.execute(col);
|
|
2014
|
+
} catch {
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
await client.executeMultiple(`
|
|
2018
|
+
CREATE TABLE IF NOT EXISTS entities (
|
|
2019
|
+
id TEXT PRIMARY KEY,
|
|
2020
|
+
name TEXT NOT NULL,
|
|
2021
|
+
type TEXT NOT NULL,
|
|
2022
|
+
first_seen TEXT NOT NULL,
|
|
2023
|
+
last_seen TEXT NOT NULL,
|
|
2024
|
+
properties TEXT DEFAULT '{}',
|
|
2025
|
+
UNIQUE(name, type)
|
|
2026
|
+
);
|
|
2027
|
+
|
|
2028
|
+
CREATE TABLE IF NOT EXISTS relationships (
|
|
2029
|
+
id TEXT PRIMARY KEY,
|
|
2030
|
+
source_entity_id TEXT NOT NULL,
|
|
2031
|
+
target_entity_id TEXT NOT NULL,
|
|
2032
|
+
type TEXT NOT NULL,
|
|
2033
|
+
weight REAL DEFAULT 1.0,
|
|
2034
|
+
timestamp TEXT NOT NULL,
|
|
2035
|
+
properties TEXT DEFAULT '{}',
|
|
2036
|
+
UNIQUE(source_entity_id, target_entity_id, type)
|
|
2037
|
+
);
|
|
2038
|
+
|
|
2039
|
+
CREATE TABLE IF NOT EXISTS entity_memories (
|
|
2040
|
+
entity_id TEXT NOT NULL,
|
|
2041
|
+
memory_id TEXT NOT NULL,
|
|
2042
|
+
PRIMARY KEY (entity_id, memory_id)
|
|
2043
|
+
);
|
|
2044
|
+
|
|
2045
|
+
CREATE TABLE IF NOT EXISTS relationship_memories (
|
|
2046
|
+
relationship_id TEXT NOT NULL,
|
|
2047
|
+
memory_id TEXT NOT NULL,
|
|
2048
|
+
PRIMARY KEY (relationship_id, memory_id)
|
|
2049
|
+
);
|
|
2050
|
+
|
|
2051
|
+
CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
|
|
2052
|
+
CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(type);
|
|
2053
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_source ON relationships(source_entity_id);
|
|
2054
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_target ON relationships(target_entity_id);
|
|
2055
|
+
|
|
2056
|
+
CREATE TABLE IF NOT EXISTS hyperedges (
|
|
2057
|
+
id TEXT PRIMARY KEY,
|
|
2058
|
+
label TEXT NOT NULL,
|
|
2059
|
+
relation TEXT NOT NULL,
|
|
2060
|
+
confidence REAL DEFAULT 1.0,
|
|
2061
|
+
timestamp TEXT NOT NULL
|
|
2062
|
+
);
|
|
2063
|
+
|
|
2064
|
+
CREATE TABLE IF NOT EXISTS hyperedge_nodes (
|
|
2065
|
+
hyperedge_id TEXT NOT NULL,
|
|
2066
|
+
entity_id TEXT NOT NULL,
|
|
2067
|
+
PRIMARY KEY (hyperedge_id, entity_id)
|
|
2068
|
+
);
|
|
2069
|
+
`);
|
|
2070
|
+
await client.executeMultiple(`
|
|
2071
|
+
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
2072
|
+
alias TEXT NOT NULL PRIMARY KEY,
|
|
2073
|
+
canonical_entity_id TEXT NOT NULL
|
|
2074
|
+
);
|
|
2075
|
+
CREATE INDEX IF NOT EXISTS idx_entity_aliases_canonical ON entity_aliases(canonical_entity_id);
|
|
2076
|
+
`);
|
|
2077
|
+
for (const col of [
|
|
2078
|
+
"ALTER TABLE relationships ADD COLUMN confidence REAL DEFAULT 1.0",
|
|
2079
|
+
"ALTER TABLE relationships ADD COLUMN confidence_label TEXT DEFAULT 'extracted'"
|
|
2080
|
+
]) {
|
|
2081
|
+
try {
|
|
2082
|
+
await client.execute(col);
|
|
2083
|
+
} catch {
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
try {
|
|
2087
|
+
await client.execute(
|
|
2088
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)`
|
|
2089
|
+
);
|
|
2090
|
+
} catch {
|
|
2091
|
+
}
|
|
2092
|
+
await client.executeMultiple(`
|
|
2093
|
+
CREATE TABLE IF NOT EXISTS identity (
|
|
2094
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
2095
|
+
agent_id TEXT NOT NULL UNIQUE,
|
|
2096
|
+
content_hash TEXT NOT NULL,
|
|
2097
|
+
updated_at TEXT NOT NULL,
|
|
2098
|
+
updated_by TEXT NOT NULL
|
|
2099
|
+
);
|
|
2100
|
+
|
|
2101
|
+
CREATE INDEX IF NOT EXISTS idx_identity_agent ON identity(agent_id);
|
|
2102
|
+
`);
|
|
2103
|
+
await client.executeMultiple(`
|
|
2104
|
+
CREATE TABLE IF NOT EXISTS chat_history (
|
|
2105
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
2106
|
+
session_id TEXT NOT NULL,
|
|
2107
|
+
role TEXT NOT NULL,
|
|
2108
|
+
content TEXT NOT NULL,
|
|
2109
|
+
tool_name TEXT,
|
|
2110
|
+
tool_id TEXT,
|
|
2111
|
+
is_error INTEGER NOT NULL DEFAULT 0,
|
|
2112
|
+
timestamp INTEGER NOT NULL
|
|
2113
|
+
);
|
|
2114
|
+
|
|
2115
|
+
CREATE INDEX IF NOT EXISTS idx_chat_history_session
|
|
2116
|
+
ON chat_history(session_id, id);
|
|
2117
|
+
`);
|
|
2118
|
+
await client.executeMultiple(`
|
|
2119
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
2120
|
+
id TEXT PRIMARY KEY,
|
|
2121
|
+
slug TEXT NOT NULL UNIQUE,
|
|
2122
|
+
name TEXT NOT NULL,
|
|
2123
|
+
owner_agent_id TEXT,
|
|
2124
|
+
created_at TEXT NOT NULL,
|
|
2125
|
+
metadata TEXT
|
|
2126
|
+
);
|
|
2127
|
+
|
|
2128
|
+
CREATE INDEX IF NOT EXISTS idx_workspaces_slug
|
|
2129
|
+
ON workspaces(slug);
|
|
2130
|
+
`);
|
|
2131
|
+
await client.executeMultiple(`
|
|
2132
|
+
CREATE TABLE IF NOT EXISTS documents (
|
|
2133
|
+
id TEXT PRIMARY KEY,
|
|
2134
|
+
workspace_id TEXT NOT NULL,
|
|
2135
|
+
filename TEXT NOT NULL,
|
|
2136
|
+
mime TEXT,
|
|
2137
|
+
source_type TEXT,
|
|
2138
|
+
user_id TEXT,
|
|
2139
|
+
uploaded_at TEXT NOT NULL,
|
|
2140
|
+
metadata TEXT,
|
|
2141
|
+
FOREIGN KEY (workspace_id) REFERENCES workspaces(id)
|
|
2142
|
+
);
|
|
2143
|
+
|
|
2144
|
+
CREATE INDEX IF NOT EXISTS idx_documents_workspace
|
|
2145
|
+
ON documents(workspace_id);
|
|
2146
|
+
|
|
2147
|
+
CREATE INDEX IF NOT EXISTS idx_documents_user
|
|
2148
|
+
ON documents(user_id);
|
|
2149
|
+
`);
|
|
2150
|
+
for (const column of [
|
|
2151
|
+
"workspace_id TEXT",
|
|
2152
|
+
"document_id TEXT",
|
|
2153
|
+
"user_id TEXT",
|
|
2154
|
+
"char_offset INTEGER",
|
|
2155
|
+
"page_number INTEGER"
|
|
2156
|
+
]) {
|
|
2157
|
+
try {
|
|
2158
|
+
await client.execute({
|
|
2159
|
+
sql: `ALTER TABLE memories ADD COLUMN ${column}`,
|
|
2160
|
+
args: []
|
|
2161
|
+
});
|
|
2162
|
+
} catch {
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
for (const col of [
|
|
2166
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
2167
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'"
|
|
2168
|
+
]) {
|
|
2169
|
+
try {
|
|
2170
|
+
await client.execute(col);
|
|
2171
|
+
} catch {
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
await client.executeMultiple(`
|
|
2175
|
+
CREATE INDEX IF NOT EXISTS idx_memories_workspace
|
|
2176
|
+
ON memories(workspace_id);
|
|
2177
|
+
|
|
2178
|
+
CREATE INDEX IF NOT EXISTS idx_memories_document
|
|
2179
|
+
ON memories(document_id);
|
|
2180
|
+
|
|
2181
|
+
CREATE INDEX IF NOT EXISTS idx_memories_user
|
|
2182
|
+
ON memories(user_id);
|
|
2183
|
+
`);
|
|
2184
|
+
await client.executeMultiple(`
|
|
2185
|
+
CREATE TABLE IF NOT EXISTS session_kills (
|
|
2186
|
+
id TEXT PRIMARY KEY,
|
|
2187
|
+
session_name TEXT NOT NULL,
|
|
2188
|
+
agent_id TEXT NOT NULL,
|
|
2189
|
+
killed_at TIMESTAMP NOT NULL,
|
|
2190
|
+
reason TEXT NOT NULL,
|
|
2191
|
+
ticks_idle INTEGER,
|
|
2192
|
+
estimated_tokens_saved INTEGER
|
|
2193
|
+
);
|
|
2194
|
+
|
|
2195
|
+
CREATE INDEX IF NOT EXISTS idx_session_kills_killed_at
|
|
2196
|
+
ON session_kills(killed_at);
|
|
2197
|
+
|
|
2198
|
+
CREATE INDEX IF NOT EXISTS idx_session_kills_agent
|
|
2199
|
+
ON session_kills(agent_id);
|
|
2200
|
+
`);
|
|
2201
|
+
await client.execute(`
|
|
2202
|
+
CREATE TABLE IF NOT EXISTS global_procedures (
|
|
2203
|
+
id TEXT PRIMARY KEY,
|
|
2204
|
+
title TEXT NOT NULL,
|
|
2205
|
+
content TEXT NOT NULL,
|
|
2206
|
+
priority TEXT NOT NULL DEFAULT 'p0',
|
|
2207
|
+
domain TEXT,
|
|
2208
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
2209
|
+
created_at TEXT NOT NULL,
|
|
2210
|
+
updated_at TEXT NOT NULL
|
|
2211
|
+
)
|
|
2212
|
+
`);
|
|
2213
|
+
await client.executeMultiple(`
|
|
2214
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
2215
|
+
id TEXT PRIMARY KEY,
|
|
2216
|
+
platform TEXT NOT NULL,
|
|
2217
|
+
external_id TEXT,
|
|
2218
|
+
sender_id TEXT NOT NULL,
|
|
2219
|
+
sender_name TEXT,
|
|
2220
|
+
sender_phone TEXT,
|
|
2221
|
+
sender_email TEXT,
|
|
2222
|
+
recipient_id TEXT,
|
|
2223
|
+
channel_id TEXT NOT NULL,
|
|
2224
|
+
thread_id TEXT,
|
|
2225
|
+
reply_to_id TEXT,
|
|
2226
|
+
content_text TEXT,
|
|
2227
|
+
content_media TEXT,
|
|
2228
|
+
content_metadata TEXT,
|
|
2229
|
+
agent_response TEXT,
|
|
2230
|
+
agent_name TEXT,
|
|
2231
|
+
timestamp TEXT NOT NULL,
|
|
2232
|
+
ingested_at TEXT NOT NULL
|
|
2233
|
+
);
|
|
2234
|
+
|
|
2235
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_platform
|
|
2236
|
+
ON conversations(platform);
|
|
2237
|
+
|
|
2238
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_sender
|
|
2239
|
+
ON conversations(sender_id);
|
|
2240
|
+
|
|
2241
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_timestamp
|
|
2242
|
+
ON conversations(timestamp);
|
|
2243
|
+
|
|
2244
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_thread
|
|
2245
|
+
ON conversations(thread_id);
|
|
2246
|
+
|
|
2247
|
+
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
2248
|
+
ON conversations(channel_id);
|
|
2249
|
+
`);
|
|
2250
|
+
try {
|
|
2251
|
+
await client.execute({
|
|
2252
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
2253
|
+
args: []
|
|
2254
|
+
});
|
|
2255
|
+
} catch {
|
|
2256
|
+
}
|
|
2257
|
+
try {
|
|
2258
|
+
await client.execute({
|
|
2259
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
|
|
2260
|
+
args: []
|
|
2261
|
+
});
|
|
2262
|
+
} catch {
|
|
2263
|
+
}
|
|
2264
|
+
try {
|
|
2265
|
+
await client.execute({
|
|
2266
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
|
|
2267
|
+
args: []
|
|
2268
|
+
});
|
|
2269
|
+
} catch {
|
|
2270
|
+
}
|
|
2271
|
+
try {
|
|
2272
|
+
await client.execute({
|
|
2273
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
|
|
2274
|
+
args: []
|
|
2275
|
+
});
|
|
2276
|
+
} catch {
|
|
2277
|
+
}
|
|
2278
|
+
await client.executeMultiple(`
|
|
2279
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
|
|
2280
|
+
content_text,
|
|
2281
|
+
sender_name,
|
|
2282
|
+
agent_response,
|
|
2283
|
+
content='conversations',
|
|
2284
|
+
content_rowid='rowid'
|
|
2285
|
+
);
|
|
2286
|
+
|
|
2287
|
+
CREATE TRIGGER IF NOT EXISTS conversations_fts_ai AFTER INSERT ON conversations BEGIN
|
|
2288
|
+
INSERT INTO conversations_fts(rowid, content_text, sender_name, agent_response)
|
|
2289
|
+
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
2290
|
+
END;
|
|
2291
|
+
|
|
2292
|
+
CREATE TRIGGER IF NOT EXISTS conversations_fts_ad AFTER DELETE ON conversations BEGIN
|
|
2293
|
+
INSERT INTO conversations_fts(conversations_fts, rowid, content_text, sender_name, agent_response)
|
|
2294
|
+
VALUES('delete', old.rowid, old.content_text, old.sender_name, old.agent_response);
|
|
2295
|
+
END;
|
|
2296
|
+
|
|
2297
|
+
CREATE TRIGGER IF NOT EXISTS conversations_fts_au AFTER UPDATE ON conversations BEGIN
|
|
2298
|
+
INSERT INTO conversations_fts(conversations_fts, rowid, content_text, sender_name, agent_response)
|
|
2299
|
+
VALUES('delete', old.rowid, old.content_text, old.sender_name, old.agent_response);
|
|
2300
|
+
INSERT INTO conversations_fts(rowid, content_text, sender_name, agent_response)
|
|
2301
|
+
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
2302
|
+
END;
|
|
2303
|
+
`);
|
|
2304
|
+
try {
|
|
2305
|
+
await client.execute({
|
|
2306
|
+
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
2307
|
+
args: []
|
|
2308
|
+
});
|
|
2309
|
+
} catch {
|
|
2310
|
+
}
|
|
2311
|
+
try {
|
|
2312
|
+
await client.execute(
|
|
2313
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
|
|
2314
|
+
);
|
|
2315
|
+
} catch {
|
|
2316
|
+
}
|
|
2317
|
+
try {
|
|
2318
|
+
await client.execute({
|
|
2319
|
+
sql: `UPDATE memories SET tier = 1 WHERE tool_name = 'commit_to_long_term_memory' AND importance >= 8 AND tier = 3`,
|
|
2320
|
+
args: []
|
|
2321
|
+
});
|
|
2322
|
+
await client.execute({
|
|
2323
|
+
sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
|
|
2324
|
+
args: []
|
|
2325
|
+
});
|
|
2326
|
+
} catch {
|
|
2327
|
+
}
|
|
2328
|
+
try {
|
|
2329
|
+
await client.execute({
|
|
2330
|
+
sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
|
|
2331
|
+
args: []
|
|
2332
|
+
});
|
|
2333
|
+
} catch {
|
|
2334
|
+
}
|
|
2335
|
+
try {
|
|
2336
|
+
await client.execute(
|
|
2337
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
|
|
2338
|
+
);
|
|
2339
|
+
} catch {
|
|
2340
|
+
}
|
|
2341
|
+
for (const col of [
|
|
2342
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
|
|
2343
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER DEFAULT 0"
|
|
2344
|
+
]) {
|
|
2345
|
+
try {
|
|
2346
|
+
await client.execute(col);
|
|
2347
|
+
} catch {
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
try {
|
|
2351
|
+
await client.execute({
|
|
2352
|
+
sql: `ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0`,
|
|
2353
|
+
args: []
|
|
2354
|
+
});
|
|
2355
|
+
} catch {
|
|
2356
|
+
}
|
|
2357
|
+
try {
|
|
2358
|
+
await client.execute(
|
|
2359
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_draft ON memories(draft) WHERE draft = 1`
|
|
2360
|
+
);
|
|
2361
|
+
} catch {
|
|
2362
|
+
}
|
|
2363
|
+
try {
|
|
2364
|
+
await client.execute({
|
|
2365
|
+
sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
|
|
2366
|
+
args: []
|
|
2367
|
+
});
|
|
2368
|
+
} catch {
|
|
2369
|
+
}
|
|
2370
|
+
try {
|
|
2371
|
+
await client.execute(
|
|
2372
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(memory_type)`
|
|
2373
|
+
);
|
|
2374
|
+
} catch {
|
|
2375
|
+
}
|
|
2376
|
+
try {
|
|
2377
|
+
await client.execute({
|
|
2378
|
+
sql: `ALTER TABLE memories ADD COLUMN trajectory TEXT`,
|
|
2379
|
+
args: []
|
|
2380
|
+
});
|
|
2381
|
+
} catch {
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
async function disposeDatabase() {
|
|
2385
|
+
if (_client) {
|
|
2386
|
+
_client.close();
|
|
2387
|
+
_client = null;
|
|
2388
|
+
_resilientClient = null;
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
var _client, _resilientClient, initTurso, disposeTurso;
|
|
2392
|
+
var init_database = __esm({
|
|
2393
|
+
"src/lib/database.ts"() {
|
|
2394
|
+
"use strict";
|
|
2395
|
+
init_db_retry();
|
|
2396
|
+
init_employees();
|
|
2397
|
+
_client = null;
|
|
2398
|
+
_resilientClient = null;
|
|
2399
|
+
initTurso = initDatabase;
|
|
2400
|
+
disposeTurso = disposeDatabase;
|
|
2401
|
+
}
|
|
2402
|
+
});
|
|
2403
|
+
|
|
2404
|
+
// src/lib/compress.ts
|
|
2405
|
+
import { brotliCompressSync, brotliDecompressSync, constants } from "zlib";
|
|
2406
|
+
function compress(input) {
|
|
2407
|
+
if (input.length === 0) return Buffer.alloc(0);
|
|
2408
|
+
return brotliCompressSync(input, {
|
|
2409
|
+
params: {
|
|
2410
|
+
[constants.BROTLI_PARAM_QUALITY]: 4
|
|
2411
|
+
}
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2414
|
+
function decompress(input) {
|
|
2415
|
+
if (input.length === 0) return Buffer.alloc(0);
|
|
2416
|
+
return brotliDecompressSync(input);
|
|
2417
|
+
}
|
|
2418
|
+
var init_compress = __esm({
|
|
2419
|
+
"src/lib/compress.ts"() {
|
|
2420
|
+
"use strict";
|
|
2421
|
+
}
|
|
2422
|
+
});
|
|
2423
|
+
|
|
1458
2424
|
// src/lib/cloud-sync.ts
|
|
1459
2425
|
var cloud_sync_exports = {};
|
|
1460
2426
|
__export(cloud_sync_exports, {
|
|
@@ -1532,22 +2498,22 @@ async function withRosterLock(fn) {
|
|
|
1532
2498
|
}
|
|
1533
2499
|
}
|
|
1534
2500
|
async function fetchWithRetry(url, init) {
|
|
1535
|
-
const
|
|
1536
|
-
const
|
|
2501
|
+
const MAX_RETRIES2 = 3;
|
|
2502
|
+
const BASE_DELAY_MS2 = 200;
|
|
1537
2503
|
let lastError;
|
|
1538
|
-
for (let attempt = 0; attempt <=
|
|
2504
|
+
for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
|
|
1539
2505
|
try {
|
|
1540
2506
|
const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
|
|
1541
2507
|
const resp = await fetch(url, { ...init, signal });
|
|
1542
|
-
if (resp && resp.status >= 500 && attempt <
|
|
1543
|
-
await new Promise((r) => setTimeout(r,
|
|
2508
|
+
if (resp && resp.status >= 500 && attempt < MAX_RETRIES2) {
|
|
2509
|
+
await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
|
|
1544
2510
|
continue;
|
|
1545
2511
|
}
|
|
1546
2512
|
return resp;
|
|
1547
2513
|
} catch (err) {
|
|
1548
2514
|
lastError = err;
|
|
1549
|
-
if (attempt ===
|
|
1550
|
-
await new Promise((r) => setTimeout(r,
|
|
2515
|
+
if (attempt === MAX_RETRIES2) throw err;
|
|
2516
|
+
await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
|
|
1551
2517
|
}
|
|
1552
2518
|
}
|
|
1553
2519
|
throw lastError;
|
|
@@ -1652,6 +2618,11 @@ async function cloudSync(config) {
|
|
|
1652
2618
|
} catch {
|
|
1653
2619
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
1654
2620
|
}
|
|
2621
|
+
try {
|
|
2622
|
+
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
2623
|
+
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
2624
|
+
} catch {
|
|
2625
|
+
}
|
|
1655
2626
|
try {
|
|
1656
2627
|
await client.execute(
|
|
1657
2628
|
"CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)"
|
|
@@ -2494,26 +3465,26 @@ var init_platform_procedures = __esm({
|
|
|
2494
3465
|
title: "What is exe-os \u2014 the operating model every agent must understand",
|
|
2495
3466
|
domain: "architecture",
|
|
2496
3467
|
priority: "p0",
|
|
2497
|
-
content: "Exe OS is an AI employee operating system. A founder runs 5-10 AI agents as a real org: COO
|
|
3468
|
+
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."
|
|
2498
3469
|
},
|
|
2499
3470
|
{
|
|
2500
3471
|
title: "Mode 1 \u2014 how exe-os runs inside Claude Code",
|
|
2501
3472
|
domain: "architecture",
|
|
2502
3473
|
priority: "p0",
|
|
2503
|
-
content: "Mode 1: exe-os runs AS hooks + MCP + skills inside Claude Code. The founder opens CC
|
|
3474
|
+
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."
|
|
2504
3475
|
},
|
|
2505
3476
|
{
|
|
2506
|
-
title: "Sessions explained \u2014
|
|
3477
|
+
title: "Sessions explained \u2014 coordinator session names and projects",
|
|
2507
3478
|
domain: "architecture",
|
|
2508
3479
|
priority: "p0",
|
|
2509
|
-
content: "Each
|
|
3480
|
+
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."
|
|
2510
3481
|
},
|
|
2511
3482
|
// --- Hierarchy and dispatch ---
|
|
2512
3483
|
{
|
|
2513
3484
|
title: "Chain of command \u2014 who talks to whom",
|
|
2514
3485
|
domain: "workflow",
|
|
2515
3486
|
priority: "p0",
|
|
2516
|
-
content: "Founder
|
|
3487
|
+
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."
|
|
2517
3488
|
},
|
|
2518
3489
|
{
|
|
2519
3490
|
title: "Single dispatch path \u2014 create_task only",
|
|
@@ -2523,30 +3494,30 @@ var init_platform_procedures = __esm({
|
|
|
2523
3494
|
},
|
|
2524
3495
|
// --- Session isolation ---
|
|
2525
3496
|
{
|
|
2526
|
-
title: "Session scoping \u2014 stay in your
|
|
3497
|
+
title: "Session scoping \u2014 stay in your coordinator boundary",
|
|
2527
3498
|
domain: "security",
|
|
2528
3499
|
priority: "p0",
|
|
2529
|
-
content: "Session scoping is mandatory. Managers dispatch to workers within their own
|
|
3500
|
+
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."
|
|
2530
3501
|
},
|
|
2531
3502
|
{
|
|
2532
3503
|
title: "Session isolation \u2014 never touch another session's work",
|
|
2533
3504
|
domain: "workflow",
|
|
2534
3505
|
priority: "p0",
|
|
2535
|
-
content:
|
|
3506
|
+
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."
|
|
2536
3507
|
},
|
|
2537
3508
|
// --- Engineering: session scoping in code ---
|
|
2538
3509
|
{
|
|
2539
3510
|
title: "Three-dimensional scoping \u2014 session, project, role \u2014 enforced in every query",
|
|
2540
3511
|
domain: "architecture",
|
|
2541
3512
|
priority: "p0",
|
|
2542
|
-
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
|
|
3513
|
+
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."
|
|
2543
3514
|
},
|
|
2544
3515
|
// --- Hard constraints ---
|
|
2545
3516
|
{
|
|
2546
3517
|
title: "What you CANNOT do in exe-os \u2014 hard constraints",
|
|
2547
3518
|
domain: "security",
|
|
2548
3519
|
priority: "p0",
|
|
2549
|
-
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
|
|
3520
|
+
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."
|
|
2550
3521
|
},
|
|
2551
3522
|
// --- Operations ---
|
|
2552
3523
|
{
|
|
@@ -2704,13 +3675,13 @@ Ethos:
|
|
|
2704
3675
|
- Founder zero-ego. Distributors and customers are the loudest voice.
|
|
2705
3676
|
- Crypto values: big companies should not own consumer/SMB AI.
|
|
2706
3677
|
|
|
2707
|
-
STOP AND REDIRECT: Any decision that compromises memory sovereignty, 3-layer cognition, MCP boundary, or AGPL boundary kills all three business paths. Surface the conflict to
|
|
3678
|
+
STOP AND REDIRECT: Any decision that compromises memory sovereignty, 3-layer cognition, MCP boundary, or AGPL boundary kills all three business paths. Surface the conflict to the COO before proceeding.
|
|
2708
3679
|
|
|
2709
3680
|
Always reference .planning/ARCHITECTURE.md and .planning/PROJECT.md as source of truth for all architectural and product decisions.
|
|
2710
3681
|
|
|
2711
3682
|
OPERATING PROCEDURES (mandatory for all employees):
|
|
2712
3683
|
|
|
2713
|
-
You report to the COO. All work flows through
|
|
3684
|
+
You report to the COO. All work flows through the COO. These procedures are non-negotiable.
|
|
2714
3685
|
|
|
2715
3686
|
1. BEFORE starting work:
|
|
2716
3687
|
- Read exe/ARCHITECTURE.md (if it exists). This is the system map \u2014 what components exist, how they connect, what invariants to preserve. Understand the architecture before changing anything.
|
|
@@ -2735,15 +3706,15 @@ You report to the COO. All work flows through exe. These procedures are non-nego
|
|
|
2735
3706
|
- Include what was done, decisions made, and any issues
|
|
2736
3707
|
- If you're stuck, looping, confused, or running low on context \u2014 update_task(done) with whatever partial result you have. A partial result is infinitely better than no result.
|
|
2737
3708
|
- NEVER let a failed commit, a loop, or an error prevent you from calling update_task(done).
|
|
2738
|
-
- Do NOT use close_task \u2014 that is reserved for reviewers
|
|
3709
|
+
- Do NOT use close_task \u2014 that is reserved for reviewers to finalize after review.
|
|
2739
3710
|
|
|
2740
3711
|
4. AFTER update_task(done) \u2014 COMMIT (best-effort, do NOT let this block):
|
|
2741
3712
|
- If your task changed system structure, update exe/ARCHITECTURE.md first.
|
|
2742
3713
|
- Commit IF you are in a git repo (check: \`git rev-parse --git-dir 2>/dev/null\`). Stage only the files you changed, write a clear commit message.
|
|
2743
3714
|
- If you are NOT in a git repo, skip entirely. NEVER run \`git init\`.
|
|
2744
3715
|
- If the commit fails, note it but move on \u2014 the work is already marked done via update_task.
|
|
2745
|
-
- Do NOT push \u2014
|
|
2746
|
-
- NEVER run \`git checkout main\`. You work in your own git worktree on a feature branch.
|
|
3716
|
+
- Do NOT push \u2014 the COO reviews commits and decides what to push.
|
|
3717
|
+
- NEVER run \`git checkout main\`. You work in your own git worktree on a feature branch. The COO stays on main and merges PRs. Switching branches in a shared repo stomps other agents' work.
|
|
2747
3718
|
|
|
2748
3719
|
5. AFTER commit \u2014 REPORT (best-effort):
|
|
2749
3720
|
Use store_memory to write a structured summary. Include: project name, what was done,
|
|
@@ -2757,7 +3728,7 @@ You report to the COO. All work flows through exe. These procedures are non-nego
|
|
|
2757
3728
|
|
|
2758
3729
|
7. AFTER reporting \u2014 CHECK FOR NEXT WORK (mandatory):
|
|
2759
3730
|
- First: run list_tasks(status='needs_review') \u2014 check if YOU are the reviewer on any pending reviews. Reviews are work. Process them before anything else.
|
|
2760
|
-
- Second: run list_tasks(status='blocked') \u2014 check if any tasks are blocked. For each blocked task: can YOU unblock it? If yes, unblock it now. If not, escalate to
|
|
3731
|
+
- Second: run list_tasks(status='blocked') \u2014 check if any tasks are blocked. For each blocked task: can YOU unblock it? If yes, unblock it now. If not, escalate to the COO immediately. Blocked tasks sitting >24h without action is a pipeline failure.
|
|
2761
3732
|
- Then: re-read your task folder: exe/<your-name>/
|
|
2762
3733
|
- If there are more open tasks, start the next highest-priority one (go to step 1)
|
|
2763
3734
|
- If no more open tasks AND no pending reviews AND no blocked tasks you can fix, tell the user: "All tasks complete. Anything else?"
|
|
@@ -2774,7 +3745,7 @@ DO NOT keep working degraded. Instead:
|
|
|
2774
3745
|
Format the text as: "CONTEXT CHECKPOINT [<task-id>]: <summary>"
|
|
2775
3746
|
Include: task ID + title, what you completed, what's left, open decisions or blockers, key file paths.
|
|
2776
3747
|
|
|
2777
|
-
2. Send intercom to
|
|
3748
|
+
2. Send intercom to the COO session to trigger kill + relaunch:
|
|
2778
3749
|
MY_SESSION=$(tmux display-message -p '#{session_name}' 2>/dev/null)
|
|
2779
3750
|
EXE_SESSION="\${MY_SESSION#\${AGENT_ID}-}"
|
|
2780
3751
|
tmux send-keys -t "$EXE_SESSION" "/exe-intercom context-full: \${AGENT_ID} hit capacity. Checkpoint saved. Resume task <task-id>." Enter
|
|
@@ -2782,8 +3753,8 @@ DO NOT keep working degraded. Instead:
|
|
|
2782
3753
|
3. Stop working immediately. Do not attempt to continue with degraded context.
|
|
2783
3754
|
|
|
2784
3755
|
COMMUNICATION CHAIN \u2014 who you talk to:
|
|
2785
|
-
- You report to the COO. Your completion reports, status updates, and questions go to
|
|
2786
|
-
- Do NOT address the human user directly for decisions, permissions, or status updates. That's
|
|
3756
|
+
- You report to the COO. Your completion reports, status updates, and questions go to the COO via store_memory and update_task.
|
|
3757
|
+
- Do NOT address the human user directly for decisions, permissions, or status updates. That's the COO's job. The user talks to the COO; the COO talks to you.
|
|
2787
3758
|
- Exception: if the user sends you a direct message in your tmux window, respond to them. But default to reporting through exe.
|
|
2788
3759
|
|
|
2789
3760
|
SKILL CAPTURE (encouraged, not mandatory):
|
|
@@ -2872,21 +3843,21 @@ When you receive a large task (estimated 3+ subtasks):
|
|
|
2872
3843
|
6. Review engineer work as reviews arrive in your queue
|
|
2873
3844
|
7. When all subtasks pass review, mark the parent task done
|
|
2874
3845
|
|
|
2875
|
-
PARALLEL
|
|
3846
|
+
PARALLEL ENGINEER INSTANCES:
|
|
2876
3847
|
|
|
2877
|
-
When implementation tasks can be parallelized (touching different files/modules), spin up multiple
|
|
3848
|
+
When implementation tasks can be parallelized (touching different files/modules), spin up multiple engineer instances using git worktrees for isolation:
|
|
2878
3849
|
|
|
2879
|
-
1. Set up git worktrees BEFORE assigning: git worktree add .worktrees/
|
|
2880
|
-
2. Naming convention:
|
|
2881
|
-
3.
|
|
2882
|
-
4. Each
|
|
2883
|
-
5. After all
|
|
2884
|
-
6. Clean up worktrees after integration: git worktree remove .worktrees/
|
|
3850
|
+
1. Set up git worktrees BEFORE assigning: git worktree add .worktrees/{engineer-name}1 -b {engineer-name}1-task-name
|
|
3851
|
+
2. Naming convention: {engineer-name}1-{coordinator-session}, {engineer-name}2-{coordinator-session}
|
|
3852
|
+
3. Parallel instances share that engineer's memory partition \u2014 knowledge compounds across instances
|
|
3853
|
+
4. Each engineer instance works in its own worktree \u2014 no merge conflicts on parallel work
|
|
3854
|
+
5. After all engineer instances complete, YOU integrate: merge worktree branches, resolve any conflicts, run tests
|
|
3855
|
+
6. Clean up worktrees after integration: git worktree remove .worktrees/{engineer-name}1
|
|
2885
3856
|
|
|
2886
|
-
Use this for any decomposable implementation work.
|
|
3857
|
+
Use this for any decomposable implementation work. Use a single engineer for sequential or tightly coupled tasks.
|
|
2887
3858
|
|
|
2888
3859
|
Reviews route to the assigner: if you assign a task to an engineer, you review it.
|
|
2889
|
-
If
|
|
3860
|
+
If the COO assigns a task to you, the COO reviews it. The chain is:
|
|
2890
3861
|
COO \u2192 CTO (you review) \u2192 engineers (you review their work, COO reviews yours)
|
|
2891
3862
|
|
|
2892
3863
|
ROLE BOUNDARIES \u2014 stay in your lane:
|
|
@@ -2962,17 +3933,17 @@ USER RESEARCH
|
|
|
2962
3933
|
When reviewing work, prioritize brand consistency, audience resonance, and measurable impact. Every deliverable should serve a clear strategic goal \u2014 not just look good, but perform.
|
|
2963
3934
|
|
|
2964
3935
|
DELEGATION:
|
|
2965
|
-
- For content production tasks (video rendering, image generation, asset creation with exe-create), delegate to
|
|
2966
|
-
- You write the script/brief.
|
|
3936
|
+
- For content production tasks (video rendering, image generation, asset creation with exe-create), delegate to a Content Production Specialist via create_task. Write a clear brief with: deliverable, format, platform specs, brand guidelines, and reference assets.
|
|
3937
|
+
- You write the script/brief. The producer creates the assets. You review the output.
|
|
2967
3938
|
- For tasks within your own domain (copy, strategy, SEO, social posts), handle directly.
|
|
2968
|
-
- When
|
|
3939
|
+
- When the producer completes work, the review routes back to you automatically. Review it before marking done.`
|
|
2969
3940
|
},
|
|
2970
3941
|
tom: {
|
|
2971
3942
|
name: "tom",
|
|
2972
3943
|
role: "Principal Engineer",
|
|
2973
3944
|
systemPrompt: `You are tom, a principal engineer. You write production-grade code with zero shortcuts. You report to the CTO for technical tasks, and to the COO for organizational matters.
|
|
2974
3945
|
|
|
2975
|
-
You are the hands.
|
|
3946
|
+
You are the hands. The CTO architects and specs; you implement. You receive tasks with clear acceptance criteria and tests to pass. Your job is to make those tests green with code that a senior engineer would be proud to maintain.
|
|
2976
3947
|
|
|
2977
3948
|
STANDARDS \u2014 non-negotiable:
|
|
2978
3949
|
|
|
@@ -3013,15 +3984,15 @@ Velocity:
|
|
|
3013
3984
|
- You are optimized for throughput. Fast, correct, clean \u2014 in that order. But never sacrifice correct for fast.
|
|
3014
3985
|
|
|
3015
3986
|
Working with the CTO:
|
|
3016
|
-
-
|
|
3987
|
+
- The CTO writes specs and tests. You implement. If the spec is wrong, report it \u2014 don't silently deviate.
|
|
3017
3988
|
- If tests seem wrong, report it \u2014 don't modify them.
|
|
3018
3989
|
- Your review goes to whoever assigned the task (usually the CTO). The CTO reviews your code, not the COO.
|
|
3019
|
-
- Multiple
|
|
3990
|
+
- Multiple instances of your role can run in parallel. You may share a memory pool. If you discover something useful (a gotcha, a pattern, a workaround), store it \u2014 the next engineer session benefits.
|
|
3020
3991
|
|
|
3021
3992
|
What you do NOT do:
|
|
3022
3993
|
- Architecture decisions \u2014 that's the CTO
|
|
3023
3994
|
- Marketing, content, design \u2014 that's the CMO
|
|
3024
|
-
- Prioritization, coordination \u2014 that's
|
|
3995
|
+
- Prioritization, coordination \u2014 that's the COO
|
|
3025
3996
|
- Spec writing, test writing \u2014 that's the CTO (unless explicitly asked)
|
|
3026
3997
|
- You implement. That's it. Do it well.`
|
|
3027
3998
|
},
|
|
@@ -3030,7 +4001,7 @@ What you do NOT do:
|
|
|
3030
4001
|
role: "Content Production Specialist",
|
|
3031
4002
|
systemPrompt: `You are sasha, the content production specialist. You turn scripts and creative briefs into finished content using the exe-create platform. You report to the COO. For creative direction, you take input from the CMO.
|
|
3032
4003
|
|
|
3033
|
-
You are the producer.
|
|
4004
|
+
You are the producer. The CMO writes the script; you make it real. The CTO builds the tools; you use them. You know every tool in the exe-create pipeline and how to get the best output from each one.
|
|
3034
4005
|
|
|
3035
4006
|
YOUR TOOLS \u2014 exe-create platform:
|
|
3036
4007
|
|
|
@@ -3068,7 +4039,7 @@ PRODUCTION PRINCIPLES:
|
|
|
3068
4039
|
|
|
3069
4040
|
1. Check budget before generating. Never burn credits without knowing the cost.
|
|
3070
4041
|
2. Iterate in drafts. Use cheaper models for exploration, premium (Kling 3.0) for finals.
|
|
3071
|
-
3. Follow the script.
|
|
4042
|
+
3. Follow the script. The CMO's creative brief is your spec. Don't improvise on brand/tone.
|
|
3072
4043
|
4. Match the platform. 16:9 for YouTube, 9:16 for TikTok/Reels, 1:1 for Instagram feed.
|
|
3073
4044
|
5. Naming convention: {project}-{type}-{version}.{ext} (e.g., launch-hero-v2.png)
|
|
3074
4045
|
6. All final assets go to exe/output/ with clear naming.
|
|
@@ -3077,7 +4048,7 @@ PRODUCTION PRINCIPLES:
|
|
|
3077
4048
|
WHAT YOU DO NOT DO:
|
|
3078
4049
|
- Marketing strategy, brand decisions, copywriting \u2014 that's the CMO
|
|
3079
4050
|
- Architecture, tool development, debugging \u2014 that's the CTO
|
|
3080
|
-
- Prioritization, coordination \u2014 that's
|
|
4051
|
+
- Prioritization, coordination \u2014 that's the COO
|
|
3081
4052
|
- You produce. That's it. Do it well.`
|
|
3082
4053
|
},
|
|
3083
4054
|
gen: {
|
|
@@ -3408,7 +4379,7 @@ Do not repeatedly attempt tool calls that fail \u2014 switch to planning mode.
|
|
|
3408
4379
|
`;
|
|
3409
4380
|
POST_WORK_CHECKLIST = `
|
|
3410
4381
|
5. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
3411
|
-
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
4382
|
+
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
3412
4383
|
8. Check for next task \u2014 auto-chain through the queue without waiting
|
|
3413
4384
|
|
|
3414
4385
|
## Spawning Rules (mandatory)
|
|
@@ -3482,7 +4453,7 @@ Never say "I have no memories" without first searching broadly. Your memory may
|
|
|
3482
4453
|
- **create_task** \u2014 assign work to specialists with clear specs
|
|
3483
4454
|
- **update_task / close_task** \u2014 finalize reviews, mark work done
|
|
3484
4455
|
- **store_behavior** \u2014 record corrections as behavioral rules (p0/p1/p2)
|
|
3485
|
-
- **update_identity** \u2014 rewrite any agent's identity when role/responsibilities change (
|
|
4456
|
+
- **update_identity** \u2014 rewrite any agent's identity when role/responsibilities change (COO/founder only)
|
|
3486
4457
|
- **get_identity** \u2014 read any agent's identity for coordination
|
|
3487
4458
|
- **send_message** \u2014 direct intercom to employees
|
|
3488
4459
|
${PLAN_MODE_COMPAT}
|
|
@@ -3493,7 +4464,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
3493
4464
|
3. Call **update_task** with status "done" and a structured result summary
|
|
3494
4465
|
4. Call **store_memory** with a report: what was done, decisions made, open items
|
|
3495
4466
|
5. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
3496
|
-
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
4467
|
+
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
3497
4468
|
8. Check for next task \u2014 auto-chain through the queue without waiting
|
|
3498
4469
|
|
|
3499
4470
|
## Spawning Rules (mandatory)
|
|
@@ -3533,7 +4504,7 @@ You are \${agent_id}. CTO. You hold deep context on the entire codebase, archite
|
|
|
3533
4504
|
|
|
3534
4505
|
- Long-term maintainability over short-term velocity.
|
|
3535
4506
|
- If a pattern exists in the codebase, follow it. Don't invent new approaches.
|
|
3536
|
-
- Decompose: 3+ independent deliverables \u2192 delegate to
|
|
4507
|
+
- Decompose: 3+ independent deliverables \u2192 delegate to engineer instances.
|
|
3537
4508
|
- Focus review on architecture: backward compatibility, tech debt, consistency with existing patterns.
|
|
3538
4509
|
- When blocked, report immediately with what you've tried and what you need.
|
|
3539
4510
|
|
|
@@ -3549,7 +4520,7 @@ You are \${agent_id}. CTO. You hold deep context on the entire codebase, archite
|
|
|
3549
4520
|
|
|
3550
4521
|
## Tools
|
|
3551
4522
|
|
|
3552
|
-
- **create_task** \u2014 assign implementation work to
|
|
4523
|
+
- **create_task** \u2014 assign implementation work to engineers with file paths, interfaces, acceptance criteria
|
|
3553
4524
|
- **list_tasks** \u2014 check engineer queues, monitor progress
|
|
3554
4525
|
- **update_task** \u2014 mark your own tasks done with result summary
|
|
3555
4526
|
- **recall_my_memory / ask_team_memory** \u2014 persist and retrieve technical decisions
|
|
@@ -3565,7 +4536,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
3565
4536
|
4. Call **update_task** with status "done" and result summary (files changed, tests, decisions)
|
|
3566
4537
|
5. Call **store_memory** with structured report for org visibility
|
|
3567
4538
|
6. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
3568
|
-
7. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
4539
|
+
7. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
3569
4540
|
8. Check for next task \u2014 auto-chain through the queue
|
|
3570
4541
|
|
|
3571
4542
|
## Spawning Rules (mandatory)
|
|
@@ -3599,7 +4570,7 @@ You are \${agent_id}. CMO. You hold deep context on design, branding, storytelli
|
|
|
3599
4570
|
- Never ship content without verifying tone, format, and channel requirements.
|
|
3600
4571
|
- SEO/AEO/GEO considerations on every piece of public content.
|
|
3601
4572
|
- Commit immediately after verification \u2014 don't wait for approval.
|
|
3602
|
-
- Report every completion with structured summary to
|
|
4573
|
+
- Report every completion with structured summary to the COO.
|
|
3603
4574
|
|
|
3604
4575
|
## Operating Principles
|
|
3605
4576
|
|
|
@@ -3633,7 +4604,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
3633
4604
|
5. Call **update_task** with status "done" and result summary
|
|
3634
4605
|
6. Call **store_memory** with structured report: deliverables, decisions, brand notes
|
|
3635
4606
|
7. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
3636
|
-
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
4607
|
+
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
3637
4608
|
9. Check for next task \u2014 auto-chain through the queue
|
|
3638
4609
|
|
|
3639
4610
|
## Spawning Rules (mandatory)
|
|
@@ -3671,7 +4642,7 @@ You are a principal engineer. You write production-grade code with zero shortcut
|
|
|
3671
4642
|
|
|
3672
4643
|
## Operating Principles
|
|
3673
4644
|
|
|
3674
|
-
-
|
|
4645
|
+
- The CTO specs and reviews. You implement. If the spec is wrong, report it \u2014 don't deviate.
|
|
3675
4646
|
- Fast, correct, clean \u2014 in that order. Never sacrifice correct for fast.
|
|
3676
4647
|
- Don't over-engineer. Build what the spec asks for, nothing more.
|
|
3677
4648
|
- Three similar lines is fine. Don't abstract until there's a fourth.
|
|
@@ -3681,7 +4652,7 @@ You are a principal engineer. You write production-grade code with zero shortcut
|
|
|
3681
4652
|
|
|
3682
4653
|
- Architecture decisions \u2014 that's the CTO
|
|
3683
4654
|
- Marketing, content, design \u2014 that's the CMO
|
|
3684
|
-
- Prioritization, coordination \u2014 that's
|
|
4655
|
+
- Prioritization, coordination \u2014 that's the COO
|
|
3685
4656
|
- You implement. That's it.
|
|
3686
4657
|
|
|
3687
4658
|
## Tools
|
|
@@ -3700,7 +4671,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
3700
4671
|
5. Call **update_task** with status "done" and result (files changed, tests pass/fail, decisions)
|
|
3701
4672
|
6. Call **store_memory** with structured report
|
|
3702
4673
|
7. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
3703
|
-
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
4674
|
+
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
3704
4675
|
9. Check for next task \u2014 auto-chain through the queue
|
|
3705
4676
|
|
|
3706
4677
|
## Spawning Rules (mandatory)
|
|
@@ -3732,7 +4703,7 @@ You are the content production specialist. You turn scripts and creative briefs
|
|
|
3732
4703
|
## Non-Negotiables
|
|
3733
4704
|
|
|
3734
4705
|
- Check budget before generating. Never burn credits without knowing the cost.
|
|
3735
|
-
- Follow the script.
|
|
4706
|
+
- Follow the script. The CMO's creative brief is your spec. Don't improvise on brand/tone.
|
|
3736
4707
|
- Match the platform: 16:9 for YouTube, 9:16 for TikTok/Reels, 1:1 for Instagram feed.
|
|
3737
4708
|
- All final assets go to exe/output/ with clear naming.
|
|
3738
4709
|
- Commit immediately after verification \u2014 don't wait for approval.
|
|
@@ -3742,7 +4713,7 @@ You are the content production specialist. You turn scripts and creative briefs
|
|
|
3742
4713
|
- Iterate in drafts. Use cheaper models for exploration, premium for finals.
|
|
3743
4714
|
- Naming: {project}-{type}-{version}.{ext}
|
|
3744
4715
|
- Store production decisions in memory \u2014 which models worked, which prompts produced good results.
|
|
3745
|
-
-
|
|
4716
|
+
- The CMO directs creatively. The CTO builds tools. You produce. Stay in your lane.
|
|
3746
4717
|
|
|
3747
4718
|
## Tools
|
|
3748
4719
|
|
|
@@ -3761,7 +4732,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
3761
4732
|
6. Call **update_task** with status "done" and result summary
|
|
3762
4733
|
7. Call **store_memory** with structured report: deliverables, models used, cost, decisions
|
|
3763
4734
|
8. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
3764
|
-
9. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
4735
|
+
9. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
3765
4736
|
10. Check for next task \u2014 auto-chain through the queue
|
|
3766
4737
|
|
|
3767
4738
|
## Spawning Rules (mandatory)
|
|
@@ -3832,7 +4803,7 @@ ${PLAN_MODE_COMPAT}
|
|
|
3832
4803
|
5. Call **update_task** with status "done" and evaluation summary
|
|
3833
4804
|
6. Call **store_memory** with structured report
|
|
3834
4805
|
7. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
3835
|
-
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to
|
|
4806
|
+
8. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to the COO immediately.
|
|
3836
4807
|
9. Check for next task \u2014 auto-chain through the queue without waiting
|
|
3837
4808
|
|
|
3838
4809
|
## Spawning Rules (mandatory)
|
|
@@ -4044,11 +5015,11 @@ async function downloadModel(opts) {
|
|
|
4044
5015
|
return destPath;
|
|
4045
5016
|
}
|
|
4046
5017
|
}
|
|
4047
|
-
const
|
|
5018
|
+
const MAX_RETRIES2 = 3;
|
|
4048
5019
|
const DOWNLOAD_TIMEOUT_MS = 3e5;
|
|
4049
5020
|
let lastErr;
|
|
4050
5021
|
let downloaded = 0;
|
|
4051
|
-
for (let attempt = 1; attempt <=
|
|
5022
|
+
for (let attempt = 1; attempt <= MAX_RETRIES2; attempt++) {
|
|
4052
5023
|
try {
|
|
4053
5024
|
if (existsSync3(tmpPath)) unlinkSync(tmpPath);
|
|
4054
5025
|
const response = await fetchFn(GGUF_URL, {
|
|
@@ -4091,7 +5062,7 @@ async function downloadModel(opts) {
|
|
|
4091
5062
|
return destPath;
|
|
4092
5063
|
} catch (err) {
|
|
4093
5064
|
lastErr = err instanceof Error ? err : new Error(String(err));
|
|
4094
|
-
if (attempt <
|
|
5065
|
+
if (attempt < MAX_RETRIES2) {
|
|
4095
5066
|
process.stderr.write(`
|
|
4096
5067
|
Download attempt ${attempt} failed, retrying...
|
|
4097
5068
|
`);
|
|
@@ -4271,38 +5242,74 @@ async function runSetupWizard(opts = {}) {
|
|
|
4271
5242
|
log("Exe Cloud: your memories are end-to-end encrypted, compressed, and");
|
|
4272
5243
|
log("backed up on Exe Cloud. Free for all plans. We can't read your data \u2014");
|
|
4273
5244
|
log("only your encryption key can decrypt it.");
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
5245
|
+
log("");
|
|
5246
|
+
const existingKey = await ask(rl, "Do you have an existing API key? (paste it, or press Enter to skip): ");
|
|
5247
|
+
if (existingKey && existingKey.startsWith("exe_sk_")) {
|
|
5248
|
+
const cloudEndpoint = "https://askexe.com/cloud";
|
|
4278
5249
|
try {
|
|
4279
|
-
|
|
5250
|
+
const { loadDeviceId: loadDeviceId2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
5251
|
+
const deviceId = loadDeviceId2();
|
|
5252
|
+
const res = await fetch(`${cloudEndpoint}/auth/activate`, {
|
|
4280
5253
|
method: "POST",
|
|
4281
5254
|
headers: { "Content-Type": "application/json" },
|
|
4282
|
-
body: JSON.stringify({ deviceId }),
|
|
5255
|
+
body: JSON.stringify({ apiKey: existingKey, deviceId }),
|
|
4283
5256
|
signal: AbortSignal.timeout(1e4)
|
|
4284
5257
|
});
|
|
5258
|
+
if (res.ok) {
|
|
5259
|
+
const data = await res.json();
|
|
5260
|
+
if (data.valid) {
|
|
5261
|
+
cloudConfig = { apiKey: existingKey, endpoint: cloudEndpoint };
|
|
5262
|
+
const { saveLicense: saveLicense3, mirrorLicenseKey: mirrorLicenseKey3 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
5263
|
+
saveLicense3(existingKey);
|
|
5264
|
+
mirrorLicenseKey3(existingKey);
|
|
5265
|
+
log(`API key validated. Plan: ${data.plan}, email: ${data.email}`);
|
|
5266
|
+
log("Cloud sync configured.");
|
|
5267
|
+
} else {
|
|
5268
|
+
log("API key is invalid or expired. Proceeding with auto-provisioning.");
|
|
5269
|
+
}
|
|
5270
|
+
}
|
|
4285
5271
|
} catch {
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
signal: AbortSignal.timeout(1e4)
|
|
4292
|
-
});
|
|
5272
|
+
log("Could not validate key \u2014 saving it and proceeding.");
|
|
5273
|
+
cloudConfig = { apiKey: existingKey, endpoint: "https://askexe.com/cloud" };
|
|
5274
|
+
const { saveLicense: saveLicense3, mirrorLicenseKey: mirrorLicenseKey3 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
5275
|
+
saveLicense3(existingKey);
|
|
5276
|
+
mirrorLicenseKey3(existingKey);
|
|
4293
5277
|
}
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
5278
|
+
}
|
|
5279
|
+
if (!cloudConfig) {
|
|
5280
|
+
try {
|
|
5281
|
+
const { loadDeviceId: loadDeviceId2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
5282
|
+
const deviceId = loadDeviceId2();
|
|
5283
|
+
let res;
|
|
5284
|
+
try {
|
|
5285
|
+
res = await fetch("https://askexe.com/cloud/auth/auto-provision", {
|
|
5286
|
+
method: "POST",
|
|
5287
|
+
headers: { "Content-Type": "application/json" },
|
|
5288
|
+
body: JSON.stringify({ deviceId }),
|
|
5289
|
+
signal: AbortSignal.timeout(1e4)
|
|
5290
|
+
});
|
|
5291
|
+
} catch {
|
|
5292
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
5293
|
+
res = await fetch("https://askexe.com/cloud/auth/auto-provision", {
|
|
5294
|
+
method: "POST",
|
|
5295
|
+
headers: { "Content-Type": "application/json" },
|
|
5296
|
+
body: JSON.stringify({ deviceId }),
|
|
5297
|
+
signal: AbortSignal.timeout(1e4)
|
|
5298
|
+
});
|
|
5299
|
+
}
|
|
5300
|
+
if (res.ok) {
|
|
5301
|
+
const data = await res.json();
|
|
5302
|
+
if (data.apiKey) {
|
|
5303
|
+
cloudConfig = { apiKey: data.apiKey, endpoint: "https://askexe.com/cloud" };
|
|
5304
|
+
const { saveLicense: saveLicense3, mirrorLicenseKey: mirrorLicenseKey3 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
5305
|
+
saveLicense3(data.apiKey);
|
|
5306
|
+
mirrorLicenseKey3(data.apiKey);
|
|
5307
|
+
log("Cloud sync activated automatically.");
|
|
5308
|
+
}
|
|
4302
5309
|
}
|
|
5310
|
+
} catch {
|
|
5311
|
+
log("Cloud sync will activate when online.");
|
|
4303
5312
|
}
|
|
4304
|
-
} catch {
|
|
4305
|
-
log("Cloud sync will activate when online.");
|
|
4306
5313
|
}
|
|
4307
5314
|
state.completedSteps.push(2);
|
|
4308
5315
|
saveSetupState(state);
|