@askexenow/exe-os 0.8.33 → 0.8.37
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 +341 -349
- package/dist/bin/backfill-responses.js +81 -13
- package/dist/bin/backfill-vectors.js +72 -12
- package/dist/bin/cleanup-stale-review-tasks.js +63 -3
- package/dist/bin/cli.js +1737 -1117
- package/dist/bin/exe-assign.js +89 -19
- package/dist/bin/exe-boot.js +951 -101
- package/dist/bin/exe-call.js +61 -2
- package/dist/bin/exe-dispatch.js +61 -13
- package/dist/bin/exe-doctor.js +63 -3
- package/dist/bin/exe-export-behaviors.js +71 -3
- package/dist/bin/exe-forget.js +69 -4
- package/dist/bin/exe-gateway.js +178 -45
- package/dist/bin/exe-heartbeat.js +79 -14
- package/dist/bin/exe-kill.js +71 -3
- package/dist/bin/exe-launch-agent.js +148 -14
- package/dist/bin/exe-link.js +1437 -0
- package/dist/bin/exe-new-employee.js +98 -13
- package/dist/bin/exe-pending-messages.js +74 -8
- package/dist/bin/exe-pending-notifications.js +63 -3
- package/dist/bin/exe-pending-reviews.js +77 -11
- package/dist/bin/exe-rename.js +1287 -0
- package/dist/bin/exe-review.js +73 -5
- package/dist/bin/exe-search.js +88 -14
- package/dist/bin/exe-session-cleanup.js +102 -28
- package/dist/bin/exe-status.js +64 -4
- package/dist/bin/exe-team.js +64 -4
- package/dist/bin/git-sweep.js +80 -5
- package/dist/bin/graph-backfill.js +71 -3
- package/dist/bin/graph-export.js +71 -3
- package/dist/bin/install.js +38 -8
- package/dist/bin/scan-tasks.js +80 -5
- package/dist/bin/setup.js +128 -10
- package/dist/bin/shard-migrate.js +71 -3
- package/dist/bin/wiki-sync.js +71 -3
- package/dist/gateway/index.js +179 -46
- package/dist/hooks/bug-report-worker.js +254 -28
- package/dist/hooks/commit-complete.js +80 -5
- package/dist/hooks/error-recall.js +89 -15
- package/dist/hooks/exe-heartbeat-hook.js +1 -1
- package/dist/hooks/ingest-worker.js +185 -51
- package/dist/hooks/ingest.js +1 -1
- package/dist/hooks/instructions-loaded.js +81 -6
- package/dist/hooks/notification.js +81 -6
- package/dist/hooks/post-compact.js +81 -6
- package/dist/hooks/pre-compact.js +81 -6
- package/dist/hooks/pre-tool-use.js +423 -196
- package/dist/hooks/prompt-ingest-worker.js +91 -23
- package/dist/hooks/prompt-submit.js +159 -45
- package/dist/hooks/response-ingest-worker.js +96 -23
- package/dist/hooks/session-end.js +81 -6
- package/dist/hooks/session-start.js +89 -15
- package/dist/hooks/stop.js +81 -6
- package/dist/hooks/subagent-stop.js +81 -6
- package/dist/hooks/summary-worker.js +807 -55
- package/dist/index.js +198 -60
- package/dist/lib/cloud-sync.js +703 -18
- 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 +26 -0
- package/dist/lib/employees.js +34 -1
- package/dist/lib/exe-daemon.js +207 -74
- package/dist/lib/hybrid-search.js +88 -14
- package/dist/lib/identity-templates.js +51 -0
- package/dist/lib/identity.js +3 -3
- package/dist/lib/messaging.js +65 -17
- 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 +73 -4
- package/dist/lib/task-router.js +4 -2
- package/dist/lib/tasks.js +95 -28
- package/dist/lib/tmux-routing.js +92 -23
- package/dist/mcp/server.js +800 -74
- 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 +198 -31
- package/dist/mcp/tools/deactivate-behavior.js +4 -4
- package/dist/mcp/tools/list-reminders.js +3 -3
- package/dist/mcp/tools/list-tasks.js +19 -9
- package/dist/mcp/tools/send-message.js +69 -21
- package/dist/mcp/tools/update-task.js +28 -18
- package/dist/runtime/index.js +166 -28
- package/dist/tui/App.js +193 -40
- package/package.json +7 -3
- package/src/commands/exe/afk.md +116 -0
- package/src/commands/exe/rename.md +12 -0
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 {
|
|
@@ -1853,7 +1915,8 @@ async function writeMemory(record) {
|
|
|
1853
1915
|
has_error: record.has_error ? 1 : 0,
|
|
1854
1916
|
raw_text: record.raw_text,
|
|
1855
1917
|
vector: record.vector,
|
|
1856
|
-
version:
|
|
1918
|
+
version: 0,
|
|
1919
|
+
// Placeholder — assigned atomically at flush time
|
|
1857
1920
|
task_id: record.task_id ?? null,
|
|
1858
1921
|
importance: record.importance ?? 5,
|
|
1859
1922
|
status: record.status ?? "active",
|
|
@@ -1887,6 +1950,13 @@ async function flushBatch() {
|
|
|
1887
1950
|
_flushing = true;
|
|
1888
1951
|
try {
|
|
1889
1952
|
const batch = _pendingRecords.slice(0);
|
|
1953
|
+
const client = getClient();
|
|
1954
|
+
const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
|
|
1955
|
+
let baseVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1956
|
+
for (const row of batch) {
|
|
1957
|
+
row.version = baseVersion++;
|
|
1958
|
+
}
|
|
1959
|
+
_nextVersion = baseVersion;
|
|
1890
1960
|
const buildStmt = (row) => {
|
|
1891
1961
|
const hasVector = row.vector !== null;
|
|
1892
1962
|
const taskId = row.task_id ?? null;
|