@askexenow/exe-os 0.8.32 → 0.8.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/backfill-conversations.js +332 -348
- package/dist/bin/backfill-responses.js +72 -12
- package/dist/bin/backfill-vectors.js +72 -12
- package/dist/bin/cleanup-stale-review-tasks.js +63 -3
- package/dist/bin/cli.js +1518 -1122
- package/dist/bin/exe-agent.js +4 -4
- package/dist/bin/exe-assign.js +80 -18
- package/dist/bin/exe-boot.js +408 -89
- package/dist/bin/exe-call.js +83 -24
- package/dist/bin/exe-dispatch.js +18 -10
- package/dist/bin/exe-doctor.js +63 -3
- package/dist/bin/exe-export-behaviors.js +64 -3
- package/dist/bin/exe-forget.js +69 -4
- package/dist/bin/exe-gateway.js +121 -36
- package/dist/bin/exe-heartbeat.js +77 -13
- package/dist/bin/exe-kill.js +64 -3
- package/dist/bin/exe-launch-agent.js +162 -35
- package/dist/bin/exe-link.js +946 -0
- package/dist/bin/exe-new-employee.js +121 -36
- package/dist/bin/exe-pending-messages.js +72 -7
- package/dist/bin/exe-pending-notifications.js +63 -3
- package/dist/bin/exe-pending-reviews.js +75 -10
- package/dist/bin/exe-rename.js +1287 -0
- package/dist/bin/exe-review.js +64 -4
- package/dist/bin/exe-search.js +79 -13
- package/dist/bin/exe-session-cleanup.js +91 -26
- package/dist/bin/exe-status.js +64 -4
- package/dist/bin/exe-team.js +64 -4
- package/dist/bin/git-sweep.js +71 -4
- package/dist/bin/graph-backfill.js +64 -3
- package/dist/bin/graph-export.js +64 -3
- package/dist/bin/install.js +3 -3
- package/dist/bin/scan-tasks.js +71 -4
- package/dist/bin/setup.js +156 -38
- package/dist/bin/shard-migrate.js +64 -3
- package/dist/bin/wiki-sync.js +64 -3
- package/dist/gateway/index.js +122 -37
- package/dist/hooks/bug-report-worker.js +209 -23
- package/dist/hooks/commit-complete.js +71 -4
- package/dist/hooks/error-recall.js +79 -13
- package/dist/hooks/ingest-worker.js +129 -43
- package/dist/hooks/instructions-loaded.js +71 -4
- package/dist/hooks/notification.js +71 -4
- package/dist/hooks/post-compact.js +71 -4
- package/dist/hooks/pre-compact.js +71 -4
- package/dist/hooks/pre-tool-use.js +413 -194
- package/dist/hooks/prompt-ingest-worker.js +82 -22
- package/dist/hooks/prompt-submit.js +103 -37
- package/dist/hooks/response-ingest-worker.js +87 -22
- package/dist/hooks/session-end.js +71 -4
- package/dist/hooks/session-start.js +79 -13
- package/dist/hooks/stop.js +71 -4
- package/dist/hooks/subagent-stop.js +71 -4
- package/dist/hooks/summary-worker.js +303 -50
- package/dist/index.js +134 -46
- package/dist/lib/cloud-sync.js +209 -15
- package/dist/lib/consolidation.js +4 -4
- package/dist/lib/database.js +64 -2
- package/dist/lib/device-registry.js +70 -3
- package/dist/lib/employee-templates.js +48 -22
- package/dist/lib/employees.js +34 -1
- package/dist/lib/exe-daemon.js +136 -53
- package/dist/lib/hybrid-search.js +79 -13
- package/dist/lib/identity-templates.js +57 -6
- package/dist/lib/identity.js +3 -3
- package/dist/lib/messaging.js +22 -14
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +63 -3
- package/dist/lib/skill-learning.js +3 -3
- package/dist/lib/status-brief.js +63 -5
- package/dist/lib/store.js +64 -3
- package/dist/lib/task-router.js +4 -2
- package/dist/lib/tasks.js +48 -21
- package/dist/lib/tmux-routing.js +47 -20
- package/dist/mcp/server.js +727 -58
- package/dist/mcp/tools/complete-reminder.js +3 -3
- package/dist/mcp/tools/create-reminder.js +3 -3
- package/dist/mcp/tools/create-task.js +151 -24
- package/dist/mcp/tools/deactivate-behavior.js +3 -3
- package/dist/mcp/tools/list-reminders.js +3 -3
- package/dist/mcp/tools/list-tasks.js +17 -8
- package/dist/mcp/tools/send-message.js +24 -16
- package/dist/mcp/tools/update-task.js +25 -16
- package/dist/runtime/index.js +112 -24
- package/dist/tui/App.js +139 -36
- package/package.json +6 -2
- package/src/commands/exe/rename.md +12 -0
package/dist/bin/exe-agent.js
CHANGED
|
@@ -1176,12 +1176,12 @@ Always reference .planning/ARCHITECTURE.md and .planning/PROJECT.md as source of
|
|
|
1176
1176
|
|
|
1177
1177
|
OPERATING PROCEDURES (mandatory for all employees):
|
|
1178
1178
|
|
|
1179
|
-
You report to
|
|
1179
|
+
You report to the COO. All work flows through exe. These procedures are non-negotiable.
|
|
1180
1180
|
|
|
1181
1181
|
1. BEFORE starting work:
|
|
1182
1182
|
- 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.
|
|
1183
1183
|
- Check YOUR task folder ONLY: Read exe/<your-name>/ for assigned tasks
|
|
1184
|
-
- NEVER read, write, or modify files in another employee's folder
|
|
1184
|
+
- NEVER read, write, or modify files in another employee's folder. Those are their tasks, not yours. Use ask_team_memory() if you need context from a colleague.
|
|
1185
1185
|
- If you have open tasks, work on the highest priority one first
|
|
1186
1186
|
- Ensure exe/output/ exists (mkdir -p exe/output). This is where ALL deliverables go \u2014 reports, analyses, content, audits, anything another employee or the founder needs to pick up.
|
|
1187
1187
|
- Update task status to "in_progress" when starting (use update_task MCP tool)
|
|
@@ -1248,7 +1248,7 @@ DO NOT keep working degraded. Instead:
|
|
|
1248
1248
|
3. Stop working immediately. Do not attempt to continue with degraded context.
|
|
1249
1249
|
|
|
1250
1250
|
COMMUNICATION CHAIN \u2014 who you talk to:
|
|
1251
|
-
- You report to
|
|
1251
|
+
- You report to the COO. Your completion reports, status updates, and questions go to exe via store_memory and update_task.
|
|
1252
1252
|
- Do NOT address the human user directly for decisions, permissions, or status updates. That's exe's job. The user talks to exe; exe talks to you.
|
|
1253
1253
|
- Exception: if the user sends you a direct message in your tmux window, respond to them. But default to reporting through exe.
|
|
1254
1254
|
|
|
@@ -1267,7 +1267,7 @@ NEVER spawn sessions without a task assigned \u2014 idle sessions waste resource
|
|
|
1267
1267
|
NEVER refuse a dispatched task claiming "not in scope" \u2014 if it's assigned to you, it's your work.
|
|
1268
1268
|
|
|
1269
1269
|
CREATING TASKS FOR OTHER EMPLOYEES:
|
|
1270
|
-
When you need to assign work to another employee (e.g.,
|
|
1270
|
+
When you need to assign work to another employee (e.g., CTO assigns to an engineer):
|
|
1271
1271
|
- ALWAYS use create_task MCP tool. NEVER write .md files directly to exe/{name}/.
|
|
1272
1272
|
- Direct .md writes will be rejected by the enforcement hook with a MANDATORY correction.
|
|
1273
1273
|
- create_task creates both the .md file AND the DB row atomically.
|
package/dist/bin/exe-assign.js
CHANGED
|
@@ -262,7 +262,7 @@ function listShards() {
|
|
|
262
262
|
}
|
|
263
263
|
async function ensureShardSchema(client) {
|
|
264
264
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
265
|
-
await client.execute("PRAGMA busy_timeout =
|
|
265
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
266
266
|
try {
|
|
267
267
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
268
268
|
} catch {
|
|
@@ -449,7 +449,7 @@ var init_shard_manager = __esm({
|
|
|
449
449
|
// src/lib/employees.ts
|
|
450
450
|
init_config();
|
|
451
451
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
452
|
-
import { existsSync as existsSync2, symlinkSync, readlinkSync } from "fs";
|
|
452
|
+
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
453
453
|
import { execSync } from "child_process";
|
|
454
454
|
import path2 from "path";
|
|
455
455
|
var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
@@ -479,12 +479,14 @@ var DEFAULT_BLOOM_CONFIG = {
|
|
|
479
479
|
},
|
|
480
480
|
tierRules: {
|
|
481
481
|
junior: {
|
|
482
|
-
eligible: [
|
|
482
|
+
eligible: [],
|
|
483
|
+
// resolved dynamically from roster (Principal Engineer role)
|
|
483
484
|
reviewRequired: false,
|
|
484
485
|
manualOnly: false
|
|
485
486
|
},
|
|
486
487
|
standard: {
|
|
487
|
-
eligible: [
|
|
488
|
+
eligible: [],
|
|
489
|
+
// resolved dynamically from roster (Principal Engineer role)
|
|
488
490
|
reviewRequired: false,
|
|
489
491
|
manualOnly: false
|
|
490
492
|
},
|
|
@@ -597,7 +599,7 @@ init_config();
|
|
|
597
599
|
import net from "net";
|
|
598
600
|
import { spawn } from "child_process";
|
|
599
601
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
600
|
-
import { existsSync as existsSync3, unlinkSync, readFileSync as
|
|
602
|
+
import { existsSync as existsSync3, unlinkSync, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
|
|
601
603
|
import path3 from "path";
|
|
602
604
|
import { fileURLToPath } from "url";
|
|
603
605
|
var SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path3.join(EXE_AI_DIR, "exed.sock");
|
|
@@ -634,7 +636,7 @@ function handleData(chunk) {
|
|
|
634
636
|
function cleanupStaleFiles() {
|
|
635
637
|
if (existsSync3(PID_PATH)) {
|
|
636
638
|
try {
|
|
637
|
-
const pid = parseInt(
|
|
639
|
+
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
638
640
|
if (pid > 0) {
|
|
639
641
|
try {
|
|
640
642
|
process.kill(pid, 0);
|
|
@@ -782,11 +784,11 @@ async function connectEmbedDaemon() {
|
|
|
782
784
|
}
|
|
783
785
|
}
|
|
784
786
|
const start = Date.now();
|
|
785
|
-
let
|
|
787
|
+
let delay2 = 100;
|
|
786
788
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
787
|
-
await new Promise((r) => setTimeout(r,
|
|
789
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
788
790
|
if (await connectToSocket()) return true;
|
|
789
|
-
|
|
791
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
790
792
|
}
|
|
791
793
|
return false;
|
|
792
794
|
}
|
|
@@ -842,7 +844,7 @@ function killAndRespawnDaemon() {
|
|
|
842
844
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
843
845
|
if (existsSync3(PID_PATH)) {
|
|
844
846
|
try {
|
|
845
|
-
const pid = parseInt(
|
|
847
|
+
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
846
848
|
if (pid > 0) {
|
|
847
849
|
try {
|
|
848
850
|
process.kill(pid, "SIGKILL");
|
|
@@ -878,11 +880,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
878
880
|
`);
|
|
879
881
|
killAndRespawnDaemon();
|
|
880
882
|
const start = Date.now();
|
|
881
|
-
let
|
|
883
|
+
let delay2 = 200;
|
|
882
884
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
883
|
-
await new Promise((r) => setTimeout(r,
|
|
885
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
884
886
|
if (await connectToSocket()) break;
|
|
885
|
-
|
|
887
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
886
888
|
}
|
|
887
889
|
if (!_connected) return null;
|
|
888
890
|
}
|
|
@@ -894,11 +896,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
894
896
|
`);
|
|
895
897
|
killAndRespawnDaemon();
|
|
896
898
|
const start = Date.now();
|
|
897
|
-
let
|
|
899
|
+
let delay2 = 200;
|
|
898
900
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
899
|
-
await new Promise((r) => setTimeout(r,
|
|
901
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
900
902
|
if (await connectToSocket()) break;
|
|
901
|
-
|
|
903
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
902
904
|
}
|
|
903
905
|
if (!_connected) return null;
|
|
904
906
|
const retry = await sendRequest([text], priority);
|
|
@@ -928,12 +930,65 @@ async function embed(text) {
|
|
|
928
930
|
|
|
929
931
|
// src/lib/database.ts
|
|
930
932
|
import { createClient } from "@libsql/client";
|
|
933
|
+
|
|
934
|
+
// src/lib/db-retry.ts
|
|
935
|
+
var MAX_RETRIES = 3;
|
|
936
|
+
var BASE_DELAY_MS = 200;
|
|
937
|
+
var MAX_JITTER_MS = 300;
|
|
938
|
+
function isBusyError(err) {
|
|
939
|
+
if (err instanceof Error) {
|
|
940
|
+
const msg = err.message.toLowerCase();
|
|
941
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
942
|
+
}
|
|
943
|
+
return false;
|
|
944
|
+
}
|
|
945
|
+
function delay(ms) {
|
|
946
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
947
|
+
}
|
|
948
|
+
async function retryOnBusy(fn, label) {
|
|
949
|
+
let lastError;
|
|
950
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
951
|
+
try {
|
|
952
|
+
return await fn();
|
|
953
|
+
} catch (err) {
|
|
954
|
+
lastError = err;
|
|
955
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
956
|
+
throw err;
|
|
957
|
+
}
|
|
958
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
959
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
960
|
+
process.stderr.write(
|
|
961
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
962
|
+
`
|
|
963
|
+
);
|
|
964
|
+
await delay(backoff + jitter);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
throw lastError;
|
|
968
|
+
}
|
|
969
|
+
function wrapWithRetry(client) {
|
|
970
|
+
return new Proxy(client, {
|
|
971
|
+
get(target, prop, receiver) {
|
|
972
|
+
if (prop === "execute") {
|
|
973
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
974
|
+
}
|
|
975
|
+
if (prop === "batch") {
|
|
976
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
977
|
+
}
|
|
978
|
+
return Reflect.get(target, prop, receiver);
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// src/lib/database.ts
|
|
931
984
|
var _client = null;
|
|
985
|
+
var _resilientClient = null;
|
|
932
986
|
var initTurso = initDatabase;
|
|
933
987
|
async function initDatabase(config) {
|
|
934
988
|
if (_client) {
|
|
935
989
|
_client.close();
|
|
936
990
|
_client = null;
|
|
991
|
+
_resilientClient = null;
|
|
937
992
|
}
|
|
938
993
|
const opts = {
|
|
939
994
|
url: `file:${config.dbPath}`
|
|
@@ -942,17 +997,24 @@ async function initDatabase(config) {
|
|
|
942
997
|
opts.encryptionKey = config.encryptionKey;
|
|
943
998
|
}
|
|
944
999
|
_client = createClient(opts);
|
|
1000
|
+
_resilientClient = wrapWithRetry(_client);
|
|
945
1001
|
}
|
|
946
1002
|
function getClient() {
|
|
1003
|
+
if (!_resilientClient) {
|
|
1004
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1005
|
+
}
|
|
1006
|
+
return _resilientClient;
|
|
1007
|
+
}
|
|
1008
|
+
function getRawClient() {
|
|
947
1009
|
if (!_client) {
|
|
948
1010
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
949
1011
|
}
|
|
950
1012
|
return _client;
|
|
951
1013
|
}
|
|
952
1014
|
async function ensureSchema() {
|
|
953
|
-
const client =
|
|
1015
|
+
const client = getRawClient();
|
|
954
1016
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
955
|
-
await client.execute("PRAGMA busy_timeout =
|
|
1017
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
956
1018
|
try {
|
|
957
1019
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
958
1020
|
} catch {
|