@askexenow/exe-os 0.9.16 → 0.9.18
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 +1242 -909
- package/dist/bin/backfill-responses.js +1245 -912
- package/dist/bin/backfill-vectors.js +1244 -906
- package/dist/bin/cleanup-stale-review-tasks.js +1870 -417
- package/dist/bin/cli.js +217 -107
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +62 -0
- package/dist/bin/exe-assign.js +346 -10
- package/dist/bin/exe-boot.js +387 -32
- package/dist/bin/exe-call.js +72 -2
- package/dist/bin/exe-cloud.js +8 -0
- package/dist/bin/exe-dispatch.js +1821 -225
- package/dist/bin/exe-doctor.js +720 -52
- package/dist/bin/exe-export-behaviors.js +1429 -148
- package/dist/bin/exe-forget.js +1408 -34
- package/dist/bin/exe-gateway.js +1629 -1295
- package/dist/bin/exe-heartbeat.js +1899 -448
- package/dist/bin/exe-kill.js +1624 -346
- package/dist/bin/exe-launch-agent.js +726 -90
- package/dist/bin/exe-link.js +27 -8
- package/dist/bin/exe-new-employee.js +75 -9
- package/dist/bin/exe-pending-messages.js +2769 -1316
- package/dist/bin/exe-pending-notifications.js +2829 -1376
- package/dist/bin/exe-pending-reviews.js +2847 -1392
- package/dist/bin/exe-rename.js +89 -8
- package/dist/bin/exe-review.js +1494 -312
- package/dist/bin/exe-search.js +1608 -1300
- package/dist/bin/exe-session-cleanup.js +194 -91
- package/dist/bin/exe-settings.js +10 -2
- package/dist/bin/exe-start-codex.js +769 -120
- package/dist/bin/exe-start-opencode.js +763 -108
- package/dist/bin/exe-status.js +1887 -434
- package/dist/bin/exe-team.js +1782 -324
- package/dist/bin/git-sweep.js +408 -33
- package/dist/bin/graph-backfill.js +681 -27
- package/dist/bin/graph-export.js +1419 -141
- package/dist/bin/install.js +4 -8
- package/dist/bin/intercom-check.js +8641 -0
- package/dist/bin/scan-tasks.js +553 -38
- package/dist/bin/setup.js +82 -10
- package/dist/bin/shard-migrate.js +682 -28
- package/dist/gateway/index.js +1629 -1295
- package/dist/hooks/bug-report-worker.js +1136 -183
- package/dist/hooks/codex-stop-task-finalizer.js +1060 -107
- package/dist/hooks/commit-complete.js +408 -33
- package/dist/hooks/error-recall.js +1608 -1300
- package/dist/hooks/ingest-worker.js +250 -7966
- package/dist/hooks/ingest.js +707 -119
- package/dist/hooks/instructions-loaded.js +383 -20
- package/dist/hooks/notification.js +383 -20
- package/dist/hooks/post-compact.js +384 -21
- package/dist/hooks/{response-ingest-worker.js → post-tool-combined.js} +4157 -1716
- package/dist/hooks/pre-compact.js +486 -45
- package/dist/hooks/pre-tool-use.js +385 -22
- package/dist/hooks/prompt-submit.js +291 -96
- package/dist/hooks/session-end.js +490 -48
- package/dist/hooks/session-start.js +236 -22
- package/dist/hooks/stop.js +192 -50
- package/dist/hooks/subagent-stop.js +95 -18
- package/dist/hooks/summary-worker.js +205 -361
- package/dist/index.js +221 -105
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +27 -8
- package/dist/lib/consolidation.js +437 -41
- package/dist/lib/database.js +20 -8
- package/dist/lib/db-daemon-client.js +2 -2
- package/dist/lib/db.js +20 -8
- package/dist/lib/device-registry.js +27 -8
- package/dist/lib/employee-templates.js +62 -0
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon.js +6703 -6259
- package/dist/lib/hybrid-search.js +1608 -1300
- package/dist/lib/identity.js +1 -1
- package/dist/lib/messaging.js +11 -3
- package/dist/lib/reminders.js +1 -1
- package/dist/lib/schedules.js +718 -26
- package/dist/lib/session-registry.js +11 -0
- package/dist/lib/skill-learning.js +639 -9
- package/dist/lib/store.js +676 -27
- package/dist/lib/tasks.js +665 -27
- package/dist/lib/tmux-routing.js +732 -94
- package/dist/lib/token-spend.js +1 -1
- package/dist/mcp/server.js +856 -383
- package/dist/mcp/tools/complete-reminder.js +1 -1
- package/dist/mcp/tools/create-reminder.js +1 -1
- package/dist/mcp/tools/create-task.js +616 -46
- package/dist/mcp/tools/deactivate-behavior.js +9 -1
- package/dist/mcp/tools/list-reminders.js +1 -1
- package/dist/mcp/tools/list-tasks.js +10 -2
- package/dist/mcp/tools/send-message.js +11 -3
- package/dist/mcp/tools/update-task.js +677 -39
- package/dist/runtime/index.js +425 -37
- package/dist/tui/App.js +365 -34
- package/package.json +5 -2
- package/src/commands/exe/intercom.md +6 -17
- package/dist/bin/wiki-sync.js +0 -2991
- package/dist/hooks/prompt-ingest-worker.js +0 -3979
|
@@ -83,9 +83,9 @@ var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
|
|
|
83
83
|
var init_db_retry = __esm({
|
|
84
84
|
"src/lib/db-retry.ts"() {
|
|
85
85
|
"use strict";
|
|
86
|
-
MAX_RETRIES =
|
|
87
|
-
BASE_DELAY_MS =
|
|
88
|
-
MAX_JITTER_MS =
|
|
86
|
+
MAX_RETRIES = 5;
|
|
87
|
+
BASE_DELAY_MS = 250;
|
|
88
|
+
MAX_JITTER_MS = 400;
|
|
89
89
|
}
|
|
90
90
|
});
|
|
91
91
|
|
|
@@ -1622,7 +1622,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
1622
1622
|
});
|
|
1623
1623
|
if (response.error) {
|
|
1624
1624
|
const errMsg = String(response.error);
|
|
1625
|
-
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
1625
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
|
|
1626
1626
|
process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
|
|
1627
1627
|
`);
|
|
1628
1628
|
return fallbackClient.execute(stmt);
|
|
@@ -1647,7 +1647,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
1647
1647
|
});
|
|
1648
1648
|
if (response.error) {
|
|
1649
1649
|
const errMsg = String(response.error);
|
|
1650
|
-
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed") {
|
|
1650
|
+
if (errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized") {
|
|
1651
1651
|
process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
|
|
1652
1652
|
`);
|
|
1653
1653
|
return fallbackClient.batch(stmts, mode);
|
|
@@ -1770,7 +1770,7 @@ async function initDatabase(config) {
|
|
|
1770
1770
|
});
|
|
1771
1771
|
}, 3e4);
|
|
1772
1772
|
_walCheckpointTimer.unref();
|
|
1773
|
-
if (process.env.DATABASE_URL) {
|
|
1773
|
+
if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
|
|
1774
1774
|
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
1775
1775
|
}
|
|
1776
1776
|
}
|
|
@@ -1781,7 +1781,7 @@ function getClient() {
|
|
|
1781
1781
|
if (!_adapterClient) {
|
|
1782
1782
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1783
1783
|
}
|
|
1784
|
-
if (process.env.DATABASE_URL) {
|
|
1784
|
+
if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") {
|
|
1785
1785
|
return _adapterClient;
|
|
1786
1786
|
}
|
|
1787
1787
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
@@ -1793,9 +1793,11 @@ function getClient() {
|
|
|
1793
1793
|
return _resilientClient;
|
|
1794
1794
|
}
|
|
1795
1795
|
async function initDaemonClient() {
|
|
1796
|
-
if (process.env.DATABASE_URL) return;
|
|
1796
|
+
if (process.env.DATABASE_URL && process.env.EXE_USE_POSTGRES === "1") return;
|
|
1797
1797
|
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
1798
|
+
if (process.env.VITEST) return;
|
|
1798
1799
|
if (!_resilientClient) return;
|
|
1800
|
+
if (_daemonClient) return;
|
|
1799
1801
|
try {
|
|
1800
1802
|
const { initDaemonDbClient: initDaemonDbClient2 } = await Promise.resolve().then(() => (init_db_daemon_client(), db_daemon_client_exports));
|
|
1801
1803
|
_daemonClient = await initDaemonDbClient2(_resilientClient);
|
|
@@ -1944,6 +1946,13 @@ async function ensureSchema() {
|
|
|
1944
1946
|
});
|
|
1945
1947
|
} catch {
|
|
1946
1948
|
}
|
|
1949
|
+
try {
|
|
1950
|
+
await client.execute({
|
|
1951
|
+
sql: `ALTER TABLE behaviors ADD COLUMN vector F32_BLOB(${EMBEDDING_DIM})`,
|
|
1952
|
+
args: []
|
|
1953
|
+
});
|
|
1954
|
+
} catch {
|
|
1955
|
+
}
|
|
1947
1956
|
try {
|
|
1948
1957
|
await client.execute({
|
|
1949
1958
|
sql: `ALTER TABLE tasks ADD COLUMN blocked_by TEXT`,
|
|
@@ -2814,6 +2823,7 @@ var init_database = __esm({
|
|
|
2814
2823
|
init_db_retry();
|
|
2815
2824
|
init_employees();
|
|
2816
2825
|
init_database_adapter();
|
|
2826
|
+
init_memory();
|
|
2817
2827
|
_client = null;
|
|
2818
2828
|
_resilientClient = null;
|
|
2819
2829
|
_walCheckpointTimer = null;
|
|
@@ -3432,6 +3442,68 @@ var init_platform_procedures = __esm({
|
|
|
3432
3442
|
domain: "architecture",
|
|
3433
3443
|
priority: "p0",
|
|
3434
3444
|
content: "Tasks live in the DB. Intercom (tmux send-keys) is fire-and-forget \u2014 it may fail, get garbled, or arrive mid-work. Never rely on intercom for task delivery. The UserPromptSubmit hook checks the DB for new tasks on every prompt. Your operating procedures step 7 says check for next work. The daemon nudges idle agents as a speedup. If you have no tasks, you found them all."
|
|
3445
|
+
},
|
|
3446
|
+
// --- MCP is the ONLY data interface ---
|
|
3447
|
+
{
|
|
3448
|
+
title: "MCP disconnect \u2014 ask the user, never work around it",
|
|
3449
|
+
domain: "workflow",
|
|
3450
|
+
priority: "p0",
|
|
3451
|
+
content: "If MCP tools are unavailable, disconnected, or returning connection errors: STOP. Tell the user clearly: 'MCP server is disconnected. Please run /mcp to reconnect.' Do NOT attempt workarounds \u2014 no raw Node imports, no direct DB access, no CLI hacks, no daemon socket calls. MCP is the ONLY data interface. Working around it wastes time, hits bundling issues, and bypasses the contract boundary. Ask once, wait, proceed when reconnected."
|
|
3452
|
+
},
|
|
3453
|
+
// --- MCP Tool Catalog (Layer 0 — every agent knows what tools exist) ---
|
|
3454
|
+
{
|
|
3455
|
+
title: "MCP tools \u2014 memory and search",
|
|
3456
|
+
domain: "tool-use",
|
|
3457
|
+
priority: "p1",
|
|
3458
|
+
content: "recall_my_memory: search your own memories (semantic + FTS). ask_team_memory: search a colleague's memories by agent name. store_memory: persist a memory (decisions, summaries, context). commit_memory: high-importance memory that survives consolidation. search_everything: unified search across memories, tasks, entities, conversations. get_session_context: temporal window of memories around a timestamp. consolidate_memories: merge duplicate/related memories into insights. get_memory_cardinality: count memories per agent (health check)."
|
|
3459
|
+
},
|
|
3460
|
+
{
|
|
3461
|
+
title: "MCP tools \u2014 task orchestration",
|
|
3462
|
+
domain: "tool-use",
|
|
3463
|
+
priority: "p1",
|
|
3464
|
+
content: "create_task: dispatch work to an employee (auto-spawns session). The ONLY dispatch path. list_tasks: query tasks by status, assignee, project. get_task: fetch full task details by ID. update_task: change status (in_progress, done, blocked, cancelled) + add result summary. close_task: finalize a reviewed task (COO only). checkpoint_task: save progress state for crash recovery. resume_employee: re-spawn an employee session for an existing task."
|
|
3465
|
+
},
|
|
3466
|
+
{
|
|
3467
|
+
title: "MCP tools \u2014 knowledge graph (GraphRAG)",
|
|
3468
|
+
domain: "tool-use",
|
|
3469
|
+
priority: "p1",
|
|
3470
|
+
content: "query_relationships: find connections between entities in the knowledge graph. get_entity_neighbors: explore an entity's direct connections. get_hot_entities: find most-referenced entities (trending topics). get_graph_stats: graph health \u2014 entity/relationship counts, density. export_graph: export graph data for visualization. merge_entities: deduplicate entities (alias resolution). find_similar_trajectories: match tool-call patterns to past task solutions."
|
|
3471
|
+
},
|
|
3472
|
+
{
|
|
3473
|
+
title: "MCP tools \u2014 identity, behavior, and decisions",
|
|
3474
|
+
domain: "tool-use",
|
|
3475
|
+
priority: "p1",
|
|
3476
|
+
content: "get_identity: read an agent's exe.md (Layer 1 identity). update_identity: write an agent's exe.md. Identity > behavior \u2014 use for permanent rules. store_behavior: record a correction or pattern for an agent (Layer 2 expertise). list_behaviors: view an agent's active behaviors. deactivate_behavior: soft-delete a stale or conflicting behavior. store_decision: record an ADR (architectural decision record). get_decision: retrieve a past decision by query."
|
|
3477
|
+
},
|
|
3478
|
+
{
|
|
3479
|
+
title: "MCP tools \u2014 communication and messaging",
|
|
3480
|
+
domain: "tool-use",
|
|
3481
|
+
priority: "p1",
|
|
3482
|
+
content: "send_message: send supplementary context to another agent (NOT for actionable work \u2014 use create_task). acknowledge_messages: mark messages as read. send_whatsapp: send WhatsApp message via gateway (customer-facing alerts). query_conversations: search ingested conversations across all channels (WhatsApp, email, etc.)."
|
|
3483
|
+
},
|
|
3484
|
+
{
|
|
3485
|
+
title: "MCP tools \u2014 wiki, documents, and content",
|
|
3486
|
+
domain: "tool-use",
|
|
3487
|
+
priority: "p1",
|
|
3488
|
+
content: "create_wiki_page: create a wiki page in exe-wiki. list_wiki_pages: browse wiki pages. get_wiki_page: read a wiki page. update_wiki_page: edit a wiki page. ingest_document: import a file (PDF, MD, etc.) into memory as chunks. list_documents: browse ingested documents by workspace. purge_document: remove a document and its memory chunks. set_document_importance: adjust chunk importance scores. rerank_documents: re-score document relevance for a query."
|
|
3489
|
+
},
|
|
3490
|
+
{
|
|
3491
|
+
title: "MCP tools \u2014 system, operations, and admin",
|
|
3492
|
+
domain: "tool-use",
|
|
3493
|
+
priority: "p1",
|
|
3494
|
+
content: "get_agent_spend: token usage per agent/session (cost tracking). list_agent_sessions: view agent session history. get_session_kills: audit log of killed sessions. get_daemon_health: check exed daemon status. get_auto_wake_status: daemon auto-wake configuration. get_worker_gate: check worker deployment gates. run_memory_audit: health check \u2014 duplicates, null vectors, orphaned rows. run_consolidation: trigger sleep-time memory consolidation. cloud_sync: force a cloud sync cycle. backup_vps: trigger VPS backup."
|
|
3495
|
+
},
|
|
3496
|
+
{
|
|
3497
|
+
title: "MCP tools \u2014 config, licensing, and team",
|
|
3498
|
+
domain: "tool-use",
|
|
3499
|
+
priority: "p1",
|
|
3500
|
+
content: "set_agent_config: view/change per-agent runtime and model settings. list_employees: view the employee roster. add_person: add a person to the CRM contacts roster. list_people: browse CRM contacts. get_person: fetch contact details. get_license_status: check license validity. create_license: generate a new license key (admin). list_licenses: view all issued licenses. activate_license: activate a license on a device."
|
|
3501
|
+
},
|
|
3502
|
+
{
|
|
3503
|
+
title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
|
|
3504
|
+
domain: "tool-use",
|
|
3505
|
+
priority: "p1",
|
|
3506
|
+
content: "create_trigger: set up a scheduled recurring agent job (cron). list_triggers: view active triggers. load_skill: load a slash-command skill dynamically. apply_starter_pack: import a pre-built behavior + identity pack for a role. export_orchestration: export full org state (tasks, behaviors, identities) as portable JSON. import_orchestration: import org state into a new instance. deploy_client: deploy a customer client instance. query_company_brain: unified RAG query across all company knowledge. create_reminder: set a text reminder (shown in boot brief). list_reminders: view pending reminders. complete_reminder: mark a reminder done. global_procedure: manage Layer 0 procedures (actions: store, list, deactivate). Legacy aliases: store_global_procedure, list_global_procedures, deactivate_global_procedure."
|
|
3435
3507
|
}
|
|
3436
3508
|
];
|
|
3437
3509
|
PLATFORM_PROCEDURE_TITLES = new Set(
|
|
@@ -3774,7 +3846,7 @@ var init_agent_config = __esm({
|
|
|
3774
3846
|
init_secure_files();
|
|
3775
3847
|
AGENT_CONFIG_PATH = path9.join(EXE_AI_DIR, "agent-config.json");
|
|
3776
3848
|
DEFAULT_MODELS = {
|
|
3777
|
-
claude: "claude-opus-4",
|
|
3849
|
+
claude: "claude-opus-4.6",
|
|
3778
3850
|
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
3779
3851
|
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
3780
3852
|
};
|
|
@@ -4056,8 +4128,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
4056
4128
|
}
|
|
4057
4129
|
function getCacheAgeMs() {
|
|
4058
4130
|
try {
|
|
4059
|
-
const { statSync:
|
|
4060
|
-
const s =
|
|
4131
|
+
const { statSync: statSync3 } = __require("fs");
|
|
4132
|
+
const s = statSync3(CACHE_PATH);
|
|
4061
4133
|
return Date.now() - s.mtimeMs;
|
|
4062
4134
|
} catch {
|
|
4063
4135
|
return Infinity;
|
|
@@ -4559,10 +4631,10 @@ async function disposeEmbedder() {
|
|
|
4559
4631
|
async function embedDirect(text) {
|
|
4560
4632
|
const llamaCpp = await import("node-llama-cpp");
|
|
4561
4633
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4562
|
-
const { existsSync:
|
|
4563
|
-
const
|
|
4564
|
-
const modelPath =
|
|
4565
|
-
if (!
|
|
4634
|
+
const { existsSync: existsSync19 } = await import("fs");
|
|
4635
|
+
const path20 = await import("path");
|
|
4636
|
+
const modelPath = path20.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
4637
|
+
if (!existsSync19(modelPath)) {
|
|
4566
4638
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
4567
4639
|
}
|
|
4568
4640
|
const llama = await llamaCpp.getLlama();
|
|
@@ -4600,13 +4672,13 @@ __export(worker_gate_exports, {
|
|
|
4600
4672
|
tryAcquireBackfillLock: () => tryAcquireBackfillLock,
|
|
4601
4673
|
tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
|
|
4602
4674
|
});
|
|
4603
|
-
import { readdirSync as readdirSync4, writeFileSync as writeFileSync7, unlinkSync as
|
|
4604
|
-
import
|
|
4675
|
+
import { readdirSync as readdirSync4, writeFileSync as writeFileSync7, unlinkSync as unlinkSync5, mkdirSync as mkdirSync6, existsSync as existsSync15 } from "fs";
|
|
4676
|
+
import path16 from "path";
|
|
4605
4677
|
function tryAcquireWorkerSlot() {
|
|
4606
4678
|
try {
|
|
4607
4679
|
mkdirSync6(WORKER_PID_DIR, { recursive: true });
|
|
4608
4680
|
const reservationId = `res-${process.pid}-${Date.now()}`;
|
|
4609
|
-
const reservationPath =
|
|
4681
|
+
const reservationPath = path16.join(WORKER_PID_DIR, `${reservationId}.pid`);
|
|
4610
4682
|
writeFileSync7(reservationPath, String(process.pid));
|
|
4611
4683
|
const files = readdirSync4(WORKER_PID_DIR);
|
|
4612
4684
|
let alive = 0;
|
|
@@ -4624,20 +4696,20 @@ function tryAcquireWorkerSlot() {
|
|
|
4624
4696
|
alive++;
|
|
4625
4697
|
} catch {
|
|
4626
4698
|
try {
|
|
4627
|
-
|
|
4699
|
+
unlinkSync5(path16.join(WORKER_PID_DIR, f));
|
|
4628
4700
|
} catch {
|
|
4629
4701
|
}
|
|
4630
4702
|
}
|
|
4631
4703
|
}
|
|
4632
4704
|
if (alive > MAX_CONCURRENT_WORKERS) {
|
|
4633
4705
|
try {
|
|
4634
|
-
|
|
4706
|
+
unlinkSync5(reservationPath);
|
|
4635
4707
|
} catch {
|
|
4636
4708
|
}
|
|
4637
4709
|
return false;
|
|
4638
4710
|
}
|
|
4639
4711
|
try {
|
|
4640
|
-
|
|
4712
|
+
unlinkSync5(reservationPath);
|
|
4641
4713
|
} catch {
|
|
4642
4714
|
}
|
|
4643
4715
|
return true;
|
|
@@ -4648,20 +4720,20 @@ function tryAcquireWorkerSlot() {
|
|
|
4648
4720
|
function registerWorkerPid(pid) {
|
|
4649
4721
|
try {
|
|
4650
4722
|
mkdirSync6(WORKER_PID_DIR, { recursive: true });
|
|
4651
|
-
writeFileSync7(
|
|
4723
|
+
writeFileSync7(path16.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
4652
4724
|
} catch {
|
|
4653
4725
|
}
|
|
4654
4726
|
}
|
|
4655
4727
|
function cleanupWorkerPid() {
|
|
4656
4728
|
try {
|
|
4657
|
-
|
|
4729
|
+
unlinkSync5(path16.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
|
|
4658
4730
|
} catch {
|
|
4659
4731
|
}
|
|
4660
4732
|
}
|
|
4661
4733
|
function tryAcquireBackfillLock() {
|
|
4662
4734
|
try {
|
|
4663
4735
|
mkdirSync6(WORKER_PID_DIR, { recursive: true });
|
|
4664
|
-
if (
|
|
4736
|
+
if (existsSync15(BACKFILL_LOCK)) {
|
|
4665
4737
|
try {
|
|
4666
4738
|
const pid = parseInt(
|
|
4667
4739
|
__require("fs").readFileSync(BACKFILL_LOCK, "utf8").trim(),
|
|
@@ -4685,7 +4757,7 @@ function tryAcquireBackfillLock() {
|
|
|
4685
4757
|
}
|
|
4686
4758
|
function releaseBackfillLock() {
|
|
4687
4759
|
try {
|
|
4688
|
-
|
|
4760
|
+
unlinkSync5(BACKFILL_LOCK);
|
|
4689
4761
|
} catch {
|
|
4690
4762
|
}
|
|
4691
4763
|
}
|
|
@@ -4694,9 +4766,9 @@ var init_worker_gate = __esm({
|
|
|
4694
4766
|
"src/lib/worker-gate.ts"() {
|
|
4695
4767
|
"use strict";
|
|
4696
4768
|
init_config();
|
|
4697
|
-
WORKER_PID_DIR =
|
|
4769
|
+
WORKER_PID_DIR = path16.join(EXE_AI_DIR, "worker-pids");
|
|
4698
4770
|
MAX_CONCURRENT_WORKERS = 3;
|
|
4699
|
-
BACKFILL_LOCK =
|
|
4771
|
+
BACKFILL_LOCK = path16.join(WORKER_PID_DIR, "backfill.lock");
|
|
4700
4772
|
}
|
|
4701
4773
|
});
|
|
4702
4774
|
|
|
@@ -4798,8 +4870,8 @@ __export(crdt_sync_exports, {
|
|
|
4798
4870
|
rebuildFromDb: () => rebuildFromDb
|
|
4799
4871
|
});
|
|
4800
4872
|
import * as Y from "yjs";
|
|
4801
|
-
import { readFileSync as
|
|
4802
|
-
import
|
|
4873
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as existsSync16, mkdirSync as mkdirSync7, unlinkSync as unlinkSync6 } from "fs";
|
|
4874
|
+
import path17 from "path";
|
|
4803
4875
|
import { homedir } from "os";
|
|
4804
4876
|
function getStatePath() {
|
|
4805
4877
|
return _statePathOverride ?? DEFAULT_STATE_PATH;
|
|
@@ -4811,14 +4883,14 @@ function initCrdtDoc() {
|
|
|
4811
4883
|
if (doc) return doc;
|
|
4812
4884
|
doc = new Y.Doc();
|
|
4813
4885
|
const sp = getStatePath();
|
|
4814
|
-
if (
|
|
4886
|
+
if (existsSync16(sp)) {
|
|
4815
4887
|
try {
|
|
4816
|
-
const state =
|
|
4888
|
+
const state = readFileSync12(sp);
|
|
4817
4889
|
Y.applyUpdate(doc, new Uint8Array(state));
|
|
4818
4890
|
} catch {
|
|
4819
4891
|
console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
|
|
4820
4892
|
try {
|
|
4821
|
-
|
|
4893
|
+
unlinkSync6(sp);
|
|
4822
4894
|
} catch {
|
|
4823
4895
|
}
|
|
4824
4896
|
rebuildFromDb().catch((err) => {
|
|
@@ -4955,8 +5027,8 @@ function persistState() {
|
|
|
4955
5027
|
if (!doc) return;
|
|
4956
5028
|
try {
|
|
4957
5029
|
const sp = getStatePath();
|
|
4958
|
-
const dir =
|
|
4959
|
-
if (!
|
|
5030
|
+
const dir = path17.dirname(sp);
|
|
5031
|
+
if (!existsSync16(dir)) mkdirSync7(dir, { recursive: true });
|
|
4960
5032
|
const state = Y.encodeStateAsUpdate(doc);
|
|
4961
5033
|
writeFileSync8(sp, Buffer.from(state));
|
|
4962
5034
|
} catch {
|
|
@@ -4999,7 +5071,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
|
4999
5071
|
var init_crdt_sync = __esm({
|
|
5000
5072
|
"src/lib/crdt-sync.ts"() {
|
|
5001
5073
|
"use strict";
|
|
5002
|
-
DEFAULT_STATE_PATH =
|
|
5074
|
+
DEFAULT_STATE_PATH = path17.join(homedir(), ".exe-os", "crdt-state.bin");
|
|
5003
5075
|
_statePathOverride = null;
|
|
5004
5076
|
doc = null;
|
|
5005
5077
|
}
|
|
@@ -5034,17 +5106,17 @@ __export(cloud_sync_exports, {
|
|
|
5034
5106
|
pushToPostgres: () => pushToPostgres,
|
|
5035
5107
|
recordRosterDeletion: () => recordRosterDeletion
|
|
5036
5108
|
});
|
|
5037
|
-
import { readFileSync as
|
|
5109
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, existsSync as existsSync17, readdirSync as readdirSync5, mkdirSync as mkdirSync8, appendFileSync as appendFileSync3, unlinkSync as unlinkSync7, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
5038
5110
|
import crypto4 from "crypto";
|
|
5039
|
-
import
|
|
5111
|
+
import path18 from "path";
|
|
5040
5112
|
import { homedir as homedir2 } from "os";
|
|
5041
5113
|
function sqlSafe(v) {
|
|
5042
5114
|
return v === void 0 ? null : v;
|
|
5043
5115
|
}
|
|
5044
5116
|
function logError(msg) {
|
|
5045
5117
|
try {
|
|
5046
|
-
const logPath =
|
|
5047
|
-
|
|
5118
|
+
const logPath = path18.join(homedir2(), ".exe-os", "workers.log");
|
|
5119
|
+
appendFileSync3(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
5048
5120
|
`);
|
|
5049
5121
|
} catch {
|
|
5050
5122
|
}
|
|
@@ -5052,11 +5124,11 @@ function logError(msg) {
|
|
|
5052
5124
|
function loadPgClient() {
|
|
5053
5125
|
if (_pgFailed) return null;
|
|
5054
5126
|
const postgresUrl = process.env.DATABASE_URL;
|
|
5055
|
-
const configPath =
|
|
5127
|
+
const configPath = path18.join(EXE_AI_DIR, "config.json");
|
|
5056
5128
|
let cloudPostgresUrl;
|
|
5057
5129
|
try {
|
|
5058
|
-
if (
|
|
5059
|
-
const cfg = JSON.parse(
|
|
5130
|
+
if (existsSync17(configPath)) {
|
|
5131
|
+
const cfg = JSON.parse(readFileSync13(configPath, "utf8"));
|
|
5060
5132
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
5061
5133
|
if (cfg.cloud?.syncToPostgres === false) {
|
|
5062
5134
|
_pgFailed = true;
|
|
@@ -5074,8 +5146,8 @@ function loadPgClient() {
|
|
|
5074
5146
|
_pgPromise = (async () => {
|
|
5075
5147
|
const { createRequire: createRequire3 } = await import("module");
|
|
5076
5148
|
const { pathToFileURL: pathToFileURL3 } = await import("url");
|
|
5077
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
5078
|
-
const req = createRequire3(
|
|
5149
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path18.join(homedir2(), "exe-db");
|
|
5150
|
+
const req = createRequire3(path18.join(exeDbRoot, "package.json"));
|
|
5079
5151
|
const entry = req.resolve("@prisma/client");
|
|
5080
5152
|
const mod = await import(pathToFileURL3(entry).href);
|
|
5081
5153
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -5124,11 +5196,11 @@ async function withRosterLock(fn) {
|
|
|
5124
5196
|
} catch (err) {
|
|
5125
5197
|
if (err.code === "EEXIST") {
|
|
5126
5198
|
try {
|
|
5127
|
-
const ts = parseInt(
|
|
5199
|
+
const ts = parseInt(readFileSync13(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
5128
5200
|
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
5129
5201
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
5130
5202
|
}
|
|
5131
|
-
|
|
5203
|
+
unlinkSync7(ROSTER_LOCK_PATH);
|
|
5132
5204
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
5133
5205
|
closeSync2(fd);
|
|
5134
5206
|
writeFileSync9(ROSTER_LOCK_PATH, String(Date.now()));
|
|
@@ -5144,7 +5216,7 @@ async function withRosterLock(fn) {
|
|
|
5144
5216
|
return await fn();
|
|
5145
5217
|
} finally {
|
|
5146
5218
|
try {
|
|
5147
|
-
|
|
5219
|
+
unlinkSync7(ROSTER_LOCK_PATH);
|
|
5148
5220
|
} catch {
|
|
5149
5221
|
}
|
|
5150
5222
|
}
|
|
@@ -5515,8 +5587,8 @@ async function cloudSync(config) {
|
|
|
5515
5587
|
try {
|
|
5516
5588
|
const employees = await loadEmployees();
|
|
5517
5589
|
rosterResult.employees = employees.length;
|
|
5518
|
-
const idDir =
|
|
5519
|
-
if (
|
|
5590
|
+
const idDir = path18.join(EXE_AI_DIR, "identity");
|
|
5591
|
+
if (existsSync17(idDir)) {
|
|
5520
5592
|
rosterResult.identities = readdirSync5(idDir).filter((f) => f.endsWith(".md")).length;
|
|
5521
5593
|
}
|
|
5522
5594
|
} catch {
|
|
@@ -5537,8 +5609,8 @@ async function cloudSync(config) {
|
|
|
5537
5609
|
function recordRosterDeletion(name) {
|
|
5538
5610
|
let deletions = [];
|
|
5539
5611
|
try {
|
|
5540
|
-
if (
|
|
5541
|
-
deletions = JSON.parse(
|
|
5612
|
+
if (existsSync17(ROSTER_DELETIONS_PATH)) {
|
|
5613
|
+
deletions = JSON.parse(readFileSync13(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
5542
5614
|
}
|
|
5543
5615
|
} catch {
|
|
5544
5616
|
}
|
|
@@ -5547,8 +5619,8 @@ function recordRosterDeletion(name) {
|
|
|
5547
5619
|
}
|
|
5548
5620
|
function consumeRosterDeletions() {
|
|
5549
5621
|
try {
|
|
5550
|
-
if (!
|
|
5551
|
-
const deletions = JSON.parse(
|
|
5622
|
+
if (!existsSync17(ROSTER_DELETIONS_PATH)) return [];
|
|
5623
|
+
const deletions = JSON.parse(readFileSync13(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
5552
5624
|
writeFileSync9(ROSTER_DELETIONS_PATH, "[]");
|
|
5553
5625
|
return deletions;
|
|
5554
5626
|
} catch {
|
|
@@ -5556,37 +5628,37 @@ function consumeRosterDeletions() {
|
|
|
5556
5628
|
}
|
|
5557
5629
|
}
|
|
5558
5630
|
function buildRosterBlob(paths) {
|
|
5559
|
-
const rosterPath = paths?.rosterPath ??
|
|
5560
|
-
const identityDir = paths?.identityDir ??
|
|
5561
|
-
const configPath = paths?.configPath ??
|
|
5631
|
+
const rosterPath = paths?.rosterPath ?? path18.join(EXE_AI_DIR, "exe-employees.json");
|
|
5632
|
+
const identityDir = paths?.identityDir ?? path18.join(EXE_AI_DIR, "identity");
|
|
5633
|
+
const configPath = paths?.configPath ?? path18.join(EXE_AI_DIR, "config.json");
|
|
5562
5634
|
let roster = [];
|
|
5563
|
-
if (
|
|
5635
|
+
if (existsSync17(rosterPath)) {
|
|
5564
5636
|
try {
|
|
5565
|
-
roster = JSON.parse(
|
|
5637
|
+
roster = JSON.parse(readFileSync13(rosterPath, "utf-8"));
|
|
5566
5638
|
} catch {
|
|
5567
5639
|
}
|
|
5568
5640
|
}
|
|
5569
5641
|
const identities = {};
|
|
5570
|
-
if (
|
|
5642
|
+
if (existsSync17(identityDir)) {
|
|
5571
5643
|
for (const file of readdirSync5(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
5572
5644
|
try {
|
|
5573
|
-
identities[file] =
|
|
5645
|
+
identities[file] = readFileSync13(path18.join(identityDir, file), "utf-8");
|
|
5574
5646
|
} catch {
|
|
5575
5647
|
}
|
|
5576
5648
|
}
|
|
5577
5649
|
}
|
|
5578
5650
|
let config;
|
|
5579
|
-
if (
|
|
5651
|
+
if (existsSync17(configPath)) {
|
|
5580
5652
|
try {
|
|
5581
|
-
config = JSON.parse(
|
|
5653
|
+
config = JSON.parse(readFileSync13(configPath, "utf-8"));
|
|
5582
5654
|
} catch {
|
|
5583
5655
|
}
|
|
5584
5656
|
}
|
|
5585
5657
|
let agentConfig;
|
|
5586
|
-
const agentConfigPath =
|
|
5587
|
-
if (
|
|
5658
|
+
const agentConfigPath = path18.join(EXE_AI_DIR, "agent-config.json");
|
|
5659
|
+
if (existsSync17(agentConfigPath)) {
|
|
5588
5660
|
try {
|
|
5589
|
-
agentConfig = JSON.parse(
|
|
5661
|
+
agentConfig = JSON.parse(readFileSync13(agentConfigPath, "utf-8"));
|
|
5590
5662
|
} catch {
|
|
5591
5663
|
}
|
|
5592
5664
|
}
|
|
@@ -5662,16 +5734,16 @@ async function cloudPullRoster(config) {
|
|
|
5662
5734
|
}
|
|
5663
5735
|
}
|
|
5664
5736
|
function mergeConfig(remoteConfig, configPath) {
|
|
5665
|
-
const cfgPath = configPath ??
|
|
5737
|
+
const cfgPath = configPath ?? path18.join(EXE_AI_DIR, "config.json");
|
|
5666
5738
|
let local = {};
|
|
5667
|
-
if (
|
|
5739
|
+
if (existsSync17(cfgPath)) {
|
|
5668
5740
|
try {
|
|
5669
|
-
local = JSON.parse(
|
|
5741
|
+
local = JSON.parse(readFileSync13(cfgPath, "utf-8"));
|
|
5670
5742
|
} catch {
|
|
5671
5743
|
}
|
|
5672
5744
|
}
|
|
5673
5745
|
const merged = { ...remoteConfig, ...local };
|
|
5674
|
-
const dir =
|
|
5746
|
+
const dir = path18.dirname(cfgPath);
|
|
5675
5747
|
ensurePrivateDirSync(dir);
|
|
5676
5748
|
writeFileSync9(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
5677
5749
|
enforcePrivateFileSync(cfgPath);
|
|
@@ -5679,7 +5751,7 @@ function mergeConfig(remoteConfig, configPath) {
|
|
|
5679
5751
|
async function mergeRosterFromRemote(remote, paths) {
|
|
5680
5752
|
return withRosterLock(async () => {
|
|
5681
5753
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
5682
|
-
const identityDir = paths?.identityDir ??
|
|
5754
|
+
const identityDir = paths?.identityDir ?? path18.join(EXE_AI_DIR, "identity");
|
|
5683
5755
|
const localEmployees = await loadEmployees(rosterPath);
|
|
5684
5756
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
5685
5757
|
let added = 0;
|
|
@@ -5700,11 +5772,11 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
5700
5772
|
) ?? lookupKey;
|
|
5701
5773
|
const remoteIdentity = remote.identities[matchedKey];
|
|
5702
5774
|
if (remoteIdentity) {
|
|
5703
|
-
if (!
|
|
5704
|
-
const idPath =
|
|
5775
|
+
if (!existsSync17(identityDir)) mkdirSync8(identityDir, { recursive: true });
|
|
5776
|
+
const idPath = path18.join(identityDir, `${remoteEmp.name}.md`);
|
|
5705
5777
|
let localIdentity = null;
|
|
5706
5778
|
try {
|
|
5707
|
-
localIdentity =
|
|
5779
|
+
localIdentity = existsSync17(idPath) ? readFileSync13(idPath, "utf-8") : null;
|
|
5708
5780
|
} catch {
|
|
5709
5781
|
}
|
|
5710
5782
|
if (localIdentity !== remoteIdentity) {
|
|
@@ -5734,16 +5806,16 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
5734
5806
|
}
|
|
5735
5807
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
5736
5808
|
try {
|
|
5737
|
-
const agentConfigPath =
|
|
5809
|
+
const agentConfigPath = path18.join(EXE_AI_DIR, "agent-config.json");
|
|
5738
5810
|
let local = {};
|
|
5739
|
-
if (
|
|
5811
|
+
if (existsSync17(agentConfigPath)) {
|
|
5740
5812
|
try {
|
|
5741
|
-
local = JSON.parse(
|
|
5813
|
+
local = JSON.parse(readFileSync13(agentConfigPath, "utf-8"));
|
|
5742
5814
|
} catch {
|
|
5743
5815
|
}
|
|
5744
5816
|
}
|
|
5745
5817
|
const merged = { ...remote.agentConfig, ...local };
|
|
5746
|
-
ensurePrivateDirSync(
|
|
5818
|
+
ensurePrivateDirSync(path18.dirname(agentConfigPath));
|
|
5747
5819
|
writeFileSync9(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
5748
5820
|
enforcePrivateFileSync(agentConfigPath);
|
|
5749
5821
|
} catch {
|
|
@@ -6184,11 +6256,11 @@ var init_cloud_sync = __esm({
|
|
|
6184
6256
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
6185
6257
|
FETCH_TIMEOUT_MS = 3e4;
|
|
6186
6258
|
PUSH_BATCH_SIZE = 5e3;
|
|
6187
|
-
ROSTER_LOCK_PATH =
|
|
6259
|
+
ROSTER_LOCK_PATH = path18.join(EXE_AI_DIR, "roster-merge.lock");
|
|
6188
6260
|
LOCK_STALE_MS = 3e4;
|
|
6189
6261
|
_pgPromise = null;
|
|
6190
6262
|
_pgFailed = false;
|
|
6191
|
-
ROSTER_DELETIONS_PATH =
|
|
6263
|
+
ROSTER_DELETIONS_PATH = path18.join(EXE_AI_DIR, "roster-deletions.json");
|
|
6192
6264
|
}
|
|
6193
6265
|
});
|
|
6194
6266
|
|
|
@@ -6258,6 +6330,11 @@ async function initStore(options) {
|
|
|
6258
6330
|
encryptionKey: hexKey
|
|
6259
6331
|
});
|
|
6260
6332
|
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
6333
|
+
try {
|
|
6334
|
+
const { initDaemonClient: initDaemonClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
6335
|
+
await initDaemonClient2();
|
|
6336
|
+
} catch {
|
|
6337
|
+
}
|
|
6261
6338
|
if (!options?.lightweight) {
|
|
6262
6339
|
try {
|
|
6263
6340
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
@@ -6277,288 +6354,59 @@ async function initStore(options) {
|
|
|
6277
6354
|
}
|
|
6278
6355
|
}
|
|
6279
6356
|
}
|
|
6280
|
-
function
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
return 3;
|
|
6284
|
-
}
|
|
6285
|
-
function inferFilePaths(record) {
|
|
6286
|
-
if (!["Read", "Write", "Edit"].includes(record.tool_name)) return null;
|
|
6287
|
-
const firstLine = record.raw_text.split("\n")[0] ?? "";
|
|
6288
|
-
const match = firstLine.match(/(\/[\w./-]+\.\w+)/);
|
|
6289
|
-
return match ? JSON.stringify([match[1]]) : null;
|
|
6290
|
-
}
|
|
6291
|
-
function inferCommitHash(record) {
|
|
6292
|
-
if (record.tool_name !== "Bash") return null;
|
|
6293
|
-
const match = record.raw_text.match(/\b([a-f0-9]{7,40})\b/);
|
|
6294
|
-
return match ? match[1] : null;
|
|
6295
|
-
}
|
|
6296
|
-
function inferLanguageType(record) {
|
|
6297
|
-
const text = record.raw_text;
|
|
6298
|
-
if (!text || text.length < 10) return null;
|
|
6299
|
-
const trimmed = text.trimStart();
|
|
6300
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return "json";
|
|
6301
|
-
if (/\b(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|ALTER TABLE)\b/i.test(text)) return "sql";
|
|
6302
|
-
if (/\b(function |const |import |export |class |def |async |=>)\b/.test(text)) return "code";
|
|
6303
|
-
if (trimmed.startsWith("#") || trimmed.startsWith("*")) return "prose";
|
|
6304
|
-
return "mixed";
|
|
6305
|
-
}
|
|
6306
|
-
function inferDomain(record) {
|
|
6307
|
-
const proj = (record.project_name ?? "").toLowerCase();
|
|
6308
|
-
if (proj.includes("marketing") || proj.includes("content")) return "marketing";
|
|
6309
|
-
if (proj.includes("crm") || proj.includes("customer")) return "customer";
|
|
6310
|
-
return null;
|
|
6357
|
+
function vectorToBlob(vector) {
|
|
6358
|
+
const f32 = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
6359
|
+
return JSON.stringify(Array.from(f32));
|
|
6311
6360
|
}
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6361
|
+
|
|
6362
|
+
// src/adapters/claude/hooks/summary-worker.ts
|
|
6363
|
+
init_database();
|
|
6364
|
+
init_notifications();
|
|
6365
|
+
|
|
6366
|
+
// src/lib/memory-queue-client.ts
|
|
6367
|
+
init_exe_daemon_client();
|
|
6368
|
+
|
|
6369
|
+
// src/lib/memory-queue.ts
|
|
6370
|
+
init_config();
|
|
6371
|
+
import { appendFileSync as appendFileSync2, readFileSync as readFileSync11, renameSync as renameSync4, unlinkSync as unlinkSync4, existsSync as existsSync14, statSync as statSync2 } from "fs";
|
|
6372
|
+
import path15 from "path";
|
|
6373
|
+
var QUEUE_PATH2 = path15.join(EXE_AI_DIR, "memory-queue.jsonl");
|
|
6374
|
+
var PROCESSING_PATH = QUEUE_PATH2 + ".processing";
|
|
6375
|
+
var TTL_MS2 = 24 * 60 * 60 * 1e3;
|
|
6376
|
+
function enqueueMemory(entry) {
|
|
6377
|
+
appendFileSync2(QUEUE_PATH2, JSON.stringify(entry) + "\n");
|
|
6378
|
+
}
|
|
6379
|
+
|
|
6380
|
+
// src/lib/memory-queue-client.ts
|
|
6381
|
+
async function writeMemoryViaDaemon(entry) {
|
|
6382
|
+
if (process.env.EXE_IS_DAEMON === "1") {
|
|
6383
|
+
enqueueMemory(entry);
|
|
6384
|
+
return false;
|
|
6317
6385
|
}
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
return;
|
|
6386
|
+
if (!isClientConnected()) {
|
|
6387
|
+
enqueueMemory(entry);
|
|
6388
|
+
return false;
|
|
6321
6389
|
}
|
|
6322
6390
|
try {
|
|
6323
|
-
const
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
args: [contentHash, record.agent_id]
|
|
6391
|
+
const response = await sendDaemonRequest({
|
|
6392
|
+
type: "write-memory",
|
|
6393
|
+
entry
|
|
6327
6394
|
});
|
|
6328
|
-
if (
|
|
6395
|
+
if (response.ok) return true;
|
|
6396
|
+
enqueueMemory(entry);
|
|
6397
|
+
return false;
|
|
6329
6398
|
} catch {
|
|
6399
|
+
enqueueMemory(entry);
|
|
6400
|
+
return false;
|
|
6330
6401
|
}
|
|
6331
|
-
const dbRow = {
|
|
6332
|
-
id: record.id,
|
|
6333
|
-
agent_id: record.agent_id,
|
|
6334
|
-
agent_role: record.agent_role,
|
|
6335
|
-
session_id: record.session_id,
|
|
6336
|
-
timestamp: record.timestamp,
|
|
6337
|
-
tool_name: record.tool_name,
|
|
6338
|
-
project_name: record.project_name,
|
|
6339
|
-
has_error: record.has_error ? 1 : 0,
|
|
6340
|
-
raw_text: record.raw_text,
|
|
6341
|
-
vector: record.vector,
|
|
6342
|
-
version: 0,
|
|
6343
|
-
// Placeholder — assigned atomically at flush time
|
|
6344
|
-
task_id: record.task_id ?? null,
|
|
6345
|
-
importance: record.importance ?? 5,
|
|
6346
|
-
status: record.status ?? "active",
|
|
6347
|
-
confidence: record.confidence ?? 0.7,
|
|
6348
|
-
last_accessed: record.last_accessed ?? record.timestamp,
|
|
6349
|
-
workspace_id: record.workspace_id ?? null,
|
|
6350
|
-
document_id: record.document_id ?? null,
|
|
6351
|
-
user_id: record.user_id ?? null,
|
|
6352
|
-
char_offset: record.char_offset ?? null,
|
|
6353
|
-
page_number: record.page_number ?? null,
|
|
6354
|
-
source_path: record.source_path ?? null,
|
|
6355
|
-
source_type: record.source_type ?? null,
|
|
6356
|
-
tier: record.tier ?? classifyTier(record),
|
|
6357
|
-
supersedes_id: record.supersedes_id ?? null,
|
|
6358
|
-
draft: record.draft ? 1 : 0,
|
|
6359
|
-
memory_type: record.memory_type ?? "raw",
|
|
6360
|
-
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
6361
|
-
content_hash: contentHash,
|
|
6362
|
-
intent: record.intent ?? null,
|
|
6363
|
-
outcome: record.outcome ?? null,
|
|
6364
|
-
domain: record.domain ?? inferDomain(record),
|
|
6365
|
-
referenced_entities: record.referenced_entities ?? null,
|
|
6366
|
-
retrieval_count: record.retrieval_count ?? 0,
|
|
6367
|
-
chain_position: record.chain_position ?? null,
|
|
6368
|
-
review_status: record.review_status ?? null,
|
|
6369
|
-
context_window_pct: record.context_window_pct ?? null,
|
|
6370
|
-
file_paths: record.file_paths ?? inferFilePaths(record),
|
|
6371
|
-
commit_hash: record.commit_hash ?? inferCommitHash(record),
|
|
6372
|
-
duration_ms: record.duration_ms ?? null,
|
|
6373
|
-
token_cost: record.token_cost ?? null,
|
|
6374
|
-
audience: record.audience ?? null,
|
|
6375
|
-
language_type: record.language_type ?? inferLanguageType(record),
|
|
6376
|
-
parent_memory_id: record.parent_memory_id ?? null
|
|
6377
|
-
};
|
|
6378
|
-
_pendingRecords.push(dbRow);
|
|
6379
|
-
orgBus.emit({
|
|
6380
|
-
type: "memory_stored",
|
|
6381
|
-
agentId: record.agent_id,
|
|
6382
|
-
project: record.project_name,
|
|
6383
|
-
timestamp: record.timestamp
|
|
6384
|
-
});
|
|
6385
|
-
const MAX_PENDING = 1e3;
|
|
6386
|
-
if (_pendingRecords.length > MAX_PENDING) {
|
|
6387
|
-
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
6388
|
-
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
6389
|
-
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
6390
|
-
}
|
|
6391
|
-
if (_flushTimer === null) {
|
|
6392
|
-
_flushTimer = setInterval(() => {
|
|
6393
|
-
void flushBatch();
|
|
6394
|
-
}, _flushIntervalMs);
|
|
6395
|
-
if (_flushTimer && typeof _flushTimer === "object" && "unref" in _flushTimer) {
|
|
6396
|
-
_flushTimer.unref();
|
|
6397
|
-
}
|
|
6398
|
-
}
|
|
6399
|
-
if (_pendingRecords.length >= _batchSize) {
|
|
6400
|
-
await flushBatch();
|
|
6401
|
-
}
|
|
6402
|
-
}
|
|
6403
|
-
async function flushBatch() {
|
|
6404
|
-
if (_flushing || _pendingRecords.length === 0) return 0;
|
|
6405
|
-
_flushing = true;
|
|
6406
|
-
try {
|
|
6407
|
-
const batch = _pendingRecords.slice(0);
|
|
6408
|
-
const client = getClient();
|
|
6409
|
-
const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
|
|
6410
|
-
let baseVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
6411
|
-
for (const row of batch) {
|
|
6412
|
-
row.version = baseVersion++;
|
|
6413
|
-
}
|
|
6414
|
-
_nextVersion = baseVersion;
|
|
6415
|
-
const buildStmt = (row) => {
|
|
6416
|
-
const hasVector = row.vector !== null;
|
|
6417
|
-
const taskId = row.task_id ?? null;
|
|
6418
|
-
const importance = row.importance ?? 5;
|
|
6419
|
-
const status = row.status ?? "active";
|
|
6420
|
-
const confidence = row.confidence ?? 0.7;
|
|
6421
|
-
const lastAccessed = row.last_accessed ?? row.timestamp;
|
|
6422
|
-
const workspaceId = row.workspace_id ?? null;
|
|
6423
|
-
const documentId = row.document_id ?? null;
|
|
6424
|
-
const userId = row.user_id ?? null;
|
|
6425
|
-
const charOffset = row.char_offset ?? null;
|
|
6426
|
-
const pageNumber = row.page_number ?? null;
|
|
6427
|
-
const sourcePath = row.source_path ?? null;
|
|
6428
|
-
const sourceType = row.source_type ?? null;
|
|
6429
|
-
const tier = row.tier ?? 3;
|
|
6430
|
-
const supersedesId = row.supersedes_id ?? null;
|
|
6431
|
-
const draft = row.draft ? 1 : 0;
|
|
6432
|
-
const memoryType = row.memory_type ?? "raw";
|
|
6433
|
-
const trajectory = row.trajectory ?? null;
|
|
6434
|
-
const contentHash = row.content_hash ?? null;
|
|
6435
|
-
const intent = row.intent ?? null;
|
|
6436
|
-
const outcome = row.outcome ?? null;
|
|
6437
|
-
const domain = row.domain ?? null;
|
|
6438
|
-
const referencedEntities = row.referenced_entities ?? null;
|
|
6439
|
-
const retrievalCount = row.retrieval_count ?? 0;
|
|
6440
|
-
const chainPosition = row.chain_position ?? null;
|
|
6441
|
-
const reviewStatus = row.review_status ?? null;
|
|
6442
|
-
const contextWindowPct = row.context_window_pct ?? null;
|
|
6443
|
-
const filePaths = row.file_paths ?? null;
|
|
6444
|
-
const commitHash = row.commit_hash ?? null;
|
|
6445
|
-
const durationMs = row.duration_ms ?? null;
|
|
6446
|
-
const tokenCost = row.token_cost ?? null;
|
|
6447
|
-
const audience = row.audience ?? null;
|
|
6448
|
-
const languageType = row.language_type ?? null;
|
|
6449
|
-
const parentMemoryId = row.parent_memory_id ?? null;
|
|
6450
|
-
const cols = `id, agent_id, agent_role, session_id, timestamp,
|
|
6451
|
-
tool_name, project_name,
|
|
6452
|
-
has_error, raw_text, vector, version, task_id, importance, status,
|
|
6453
|
-
confidence, last_accessed,
|
|
6454
|
-
workspace_id, document_id, user_id, char_offset, page_number,
|
|
6455
|
-
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
|
|
6456
|
-
intent, outcome, domain, referenced_entities, retrieval_count,
|
|
6457
|
-
chain_position, review_status, context_window_pct, file_paths, commit_hash,
|
|
6458
|
-
duration_ms, token_cost, audience, language_type, parent_memory_id`;
|
|
6459
|
-
const metaArgs = [
|
|
6460
|
-
intent,
|
|
6461
|
-
outcome,
|
|
6462
|
-
domain,
|
|
6463
|
-
referencedEntities,
|
|
6464
|
-
retrievalCount,
|
|
6465
|
-
chainPosition,
|
|
6466
|
-
reviewStatus,
|
|
6467
|
-
contextWindowPct,
|
|
6468
|
-
filePaths,
|
|
6469
|
-
commitHash,
|
|
6470
|
-
durationMs,
|
|
6471
|
-
tokenCost,
|
|
6472
|
-
audience,
|
|
6473
|
-
languageType,
|
|
6474
|
-
parentMemoryId
|
|
6475
|
-
];
|
|
6476
|
-
const baseArgs = [
|
|
6477
|
-
row.id,
|
|
6478
|
-
row.agent_id,
|
|
6479
|
-
row.agent_role,
|
|
6480
|
-
row.session_id,
|
|
6481
|
-
row.timestamp,
|
|
6482
|
-
row.tool_name,
|
|
6483
|
-
row.project_name,
|
|
6484
|
-
row.has_error,
|
|
6485
|
-
row.raw_text
|
|
6486
|
-
];
|
|
6487
|
-
const sharedArgs = [
|
|
6488
|
-
row.version,
|
|
6489
|
-
taskId,
|
|
6490
|
-
importance,
|
|
6491
|
-
status,
|
|
6492
|
-
confidence,
|
|
6493
|
-
lastAccessed,
|
|
6494
|
-
workspaceId,
|
|
6495
|
-
documentId,
|
|
6496
|
-
userId,
|
|
6497
|
-
charOffset,
|
|
6498
|
-
pageNumber,
|
|
6499
|
-
sourcePath,
|
|
6500
|
-
sourceType,
|
|
6501
|
-
tier,
|
|
6502
|
-
supersedesId,
|
|
6503
|
-
draft,
|
|
6504
|
-
memoryType,
|
|
6505
|
-
trajectory,
|
|
6506
|
-
contentHash
|
|
6507
|
-
];
|
|
6508
|
-
return {
|
|
6509
|
-
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
6510
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
6511
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
6512
|
-
args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
|
|
6513
|
-
};
|
|
6514
|
-
};
|
|
6515
|
-
const globalClient = getClient();
|
|
6516
|
-
const globalStmts = batch.map(buildStmt);
|
|
6517
|
-
await globalClient.batch(globalStmts, "write");
|
|
6518
|
-
_pendingRecords.splice(0, batch.length);
|
|
6519
|
-
try {
|
|
6520
|
-
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
6521
|
-
if (isShardingEnabled2()) {
|
|
6522
|
-
const byProject = /* @__PURE__ */ new Map();
|
|
6523
|
-
for (const row of batch) {
|
|
6524
|
-
const proj = row.project_name || "unknown";
|
|
6525
|
-
if (!byProject.has(proj)) byProject.set(proj, []);
|
|
6526
|
-
byProject.get(proj).push(row);
|
|
6527
|
-
}
|
|
6528
|
-
for (const [project, rows] of byProject) {
|
|
6529
|
-
try {
|
|
6530
|
-
const shardClient = await getReadyShardClient2(project);
|
|
6531
|
-
const shardStmts = rows.map(buildStmt);
|
|
6532
|
-
await shardClient.batch(shardStmts, "write");
|
|
6533
|
-
} catch (err) {
|
|
6534
|
-
process.stderr.write(
|
|
6535
|
-
`[store] Shard write failed for ${project}: ${err instanceof Error ? err.message : String(err)}
|
|
6536
|
-
`
|
|
6537
|
-
);
|
|
6538
|
-
}
|
|
6539
|
-
}
|
|
6540
|
-
}
|
|
6541
|
-
} catch {
|
|
6542
|
-
}
|
|
6543
|
-
return batch.length;
|
|
6544
|
-
} finally {
|
|
6545
|
-
_flushing = false;
|
|
6546
|
-
}
|
|
6547
|
-
}
|
|
6548
|
-
function vectorToBlob(vector) {
|
|
6549
|
-
const f32 = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
6550
|
-
return JSON.stringify(Array.from(f32));
|
|
6551
6402
|
}
|
|
6552
6403
|
|
|
6553
6404
|
// src/adapters/claude/hooks/summary-worker.ts
|
|
6554
|
-
init_database();
|
|
6555
|
-
init_notifications();
|
|
6556
6405
|
init_task_scope();
|
|
6557
6406
|
init_employees();
|
|
6558
|
-
import crypto5 from "crypto";
|
|
6559
6407
|
import { execSync as execSync4 } from "child_process";
|
|
6560
|
-
import { existsSync as
|
|
6561
|
-
import
|
|
6408
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync9, openSync as openSync3, closeSync as closeSync3 } from "fs";
|
|
6409
|
+
import path19 from "path";
|
|
6562
6410
|
async function main() {
|
|
6563
6411
|
const agentId = process.env.AGENT_ID ?? "default";
|
|
6564
6412
|
const agentRole = process.env.AGENT_ROLE ?? "employee";
|
|
@@ -6637,19 +6485,15 @@ async function main() {
|
|
|
6637
6485
|
}
|
|
6638
6486
|
if (limitReached) {
|
|
6639
6487
|
} else {
|
|
6640
|
-
await
|
|
6641
|
-
|
|
6488
|
+
await writeMemoryViaDaemon({
|
|
6489
|
+
raw_text: summaryText,
|
|
6642
6490
|
agent_id: agentId,
|
|
6643
6491
|
agent_role: agentRole,
|
|
6644
6492
|
session_id: `auto-summary-${Date.now()}`,
|
|
6645
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6646
6493
|
tool_name: "auto-summary",
|
|
6647
6494
|
project_name: primaryProject,
|
|
6648
|
-
|
|
6649
|
-
raw_text: summaryText,
|
|
6650
|
-
vector: null
|
|
6495
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6651
6496
|
});
|
|
6652
|
-
await flushBatch();
|
|
6653
6497
|
if (!canCoordinate(agentId, agentRole)) {
|
|
6654
6498
|
let totalErrors = 0;
|
|
6655
6499
|
for (const [, data] of projects) {
|
|
@@ -6693,8 +6537,8 @@ async function main() {
|
|
|
6693
6537
|
}
|
|
6694
6538
|
try {
|
|
6695
6539
|
const { EXE_AI_DIR: EXE_AI_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
6696
|
-
const flagPath =
|
|
6697
|
-
if (
|
|
6540
|
+
const flagPath = path19.join(EXE_AI_DIR2, "session-cache", "needs-backfill");
|
|
6541
|
+
if (existsSync18(flagPath)) {
|
|
6698
6542
|
const { tryAcquireWorkerSlot: tryAcquireWorkerSlot2, registerWorkerPid: registerWorkerPid2 } = await Promise.resolve().then(() => (init_worker_gate(), worker_gate_exports));
|
|
6699
6543
|
if (!tryAcquireWorkerSlot2()) {
|
|
6700
6544
|
process.stderr.write("[summary-worker] Backfill needed but worker gate full \u2014 skipping\n");
|
|
@@ -6702,11 +6546,11 @@ async function main() {
|
|
|
6702
6546
|
const { spawn: spawn2 } = await import("child_process");
|
|
6703
6547
|
const { fileURLToPath: fileURLToPath3 } = await import("url");
|
|
6704
6548
|
const thisFile = fileURLToPath3(import.meta.url);
|
|
6705
|
-
const backfillPath =
|
|
6706
|
-
if (
|
|
6549
|
+
const backfillPath = path19.resolve(path19.dirname(thisFile), "backfill-vectors.js");
|
|
6550
|
+
if (existsSync18(backfillPath)) {
|
|
6707
6551
|
const { EXE_AI_DIR: exeDir2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
6708
|
-
const bLogPath =
|
|
6709
|
-
mkdirSync9(
|
|
6552
|
+
const bLogPath = path19.join(exeDir2, "workers.log");
|
|
6553
|
+
mkdirSync9(path19.dirname(bLogPath), { recursive: true });
|
|
6710
6554
|
const bLogFd = openSync3(bLogPath, "a");
|
|
6711
6555
|
const child = spawn2(process.execPath, [backfillPath], {
|
|
6712
6556
|
detached: true,
|