@askexenow/exe-os 0.9.92 → 0.9.94
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/deploy/compose/docker-compose.yml +1 -0
- package/dist/bin/agentic-ontology-backfill.js +65 -8
- package/dist/bin/agentic-reflection-backfill.js +54 -3
- package/dist/bin/agentic-semantic-label.js +54 -3
- package/dist/bin/backfill-conversations.js +69 -9
- package/dist/bin/backfill-responses.js +69 -9
- package/dist/bin/backfill-vectors.js +54 -3
- package/dist/bin/bulk-sync-postgres.js +66 -8
- package/dist/bin/cleanup-stale-review-tasks.js +118 -13
- package/dist/bin/cli.js +1605 -456
- package/dist/bin/customer-readiness.js +51 -0
- package/dist/bin/exe-agent.js +17 -3
- package/dist/bin/exe-assign.js +75 -9
- package/dist/bin/exe-boot.js +111 -12
- package/dist/bin/exe-call.js +17 -3
- package/dist/bin/exe-cloud.js +76 -10
- package/dist/bin/exe-dispatch.js +133 -18
- package/dist/bin/exe-doctor.js +75 -9
- package/dist/bin/exe-export-behaviors.js +75 -9
- package/dist/bin/exe-forget.js +94 -9
- package/dist/bin/exe-gateway.js +132 -18
- package/dist/bin/exe-heartbeat.js +118 -13
- package/dist/bin/exe-kill.js +75 -9
- package/dist/bin/exe-launch-agent.js +75 -9
- package/dist/bin/exe-new-employee.js +18 -4
- package/dist/bin/exe-pending-messages.js +118 -13
- package/dist/bin/exe-pending-notifications.js +118 -13
- package/dist/bin/exe-pending-reviews.js +118 -13
- package/dist/bin/exe-rename.js +75 -9
- package/dist/bin/exe-review.js +75 -9
- package/dist/bin/exe-search.js +100 -9
- package/dist/bin/exe-session-cleanup.js +133 -18
- package/dist/bin/exe-settings.js +1 -0
- package/dist/bin/exe-start-codex.js +65 -8
- package/dist/bin/exe-start-opencode.js +65 -8
- package/dist/bin/exe-status.js +118 -13
- package/dist/bin/exe-support.js +1 -0
- package/dist/bin/exe-team.js +75 -9
- package/dist/bin/git-sweep.js +133 -18
- package/dist/bin/graph-backfill.js +65 -8
- package/dist/bin/graph-export.js +75 -9
- package/dist/bin/intercom-check.js +133 -18
- package/dist/bin/scan-tasks.js +133 -18
- package/dist/bin/setup.js +55 -4
- package/dist/bin/shard-migrate.js +65 -8
- package/dist/bin/stack-update.js +57 -1
- package/dist/bin/update.js +1 -1
- package/dist/gateway/index.js +133 -18
- package/dist/hooks/bug-report-worker.js +133 -18
- package/dist/hooks/codex-stop-task-finalizer.js +123 -14
- package/dist/hooks/commit-complete.js +133 -18
- package/dist/hooks/error-recall.js +100 -9
- package/dist/hooks/ingest.js +75 -9
- package/dist/hooks/instructions-loaded.js +75 -9
- package/dist/hooks/notification.js +75 -9
- package/dist/hooks/post-compact.js +310 -50
- package/dist/hooks/post-tool-combined.js +433 -13
- package/dist/hooks/pre-compact.js +133 -18
- package/dist/hooks/pre-tool-use.js +118 -13
- package/dist/hooks/prompt-submit.js +191 -19
- package/dist/hooks/session-end.js +133 -18
- package/dist/hooks/session-start.js +143 -13
- package/dist/hooks/stop.js +118 -13
- package/dist/hooks/subagent-stop.js +118 -13
- package/dist/hooks/summary-worker.js +96 -7
- package/dist/index.js +133 -18
- package/dist/lib/cloud-sync.js +38 -0
- package/dist/lib/consolidation.js +3 -1
- package/dist/lib/database.js +37 -0
- package/dist/lib/db.js +37 -0
- package/dist/lib/device-registry.js +37 -0
- package/dist/lib/employee-templates.js +17 -3
- package/dist/lib/exe-daemon.js +913 -42
- package/dist/lib/hybrid-search.js +100 -9
- package/dist/lib/license.js +1 -1
- package/dist/lib/messaging.js +40 -4
- package/dist/lib/schedules.js +54 -3
- package/dist/lib/store.js +75 -9
- package/dist/lib/tasks.js +58 -9
- package/dist/lib/tmux-routing.js +58 -9
- package/dist/mcp/server.js +875 -42
- package/dist/mcp/tools/create-task.js +67 -12
- package/dist/mcp/tools/list-tasks.js +46 -5
- package/dist/mcp/tools/send-message.js +40 -4
- package/dist/mcp/tools/update-task.js +58 -9
- package/dist/runtime/index.js +133 -18
- package/dist/tui/App.js +132 -18
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -2660,8 +2660,8 @@ function deriveMachineKey() {
|
|
|
2660
2660
|
}
|
|
2661
2661
|
function readMachineId() {
|
|
2662
2662
|
try {
|
|
2663
|
-
const { readFileSync:
|
|
2664
|
-
return
|
|
2663
|
+
const { readFileSync: readFileSync39 } = __require("fs");
|
|
2664
|
+
return readFileSync39("/etc/machine-id", "utf-8").trim();
|
|
2665
2665
|
} catch {
|
|
2666
2666
|
return "";
|
|
2667
2667
|
}
|
|
@@ -3751,8 +3751,8 @@ function findPackageRoot() {
|
|
|
3751
3751
|
function getAvailableMemoryGB() {
|
|
3752
3752
|
if (process.platform === "darwin") {
|
|
3753
3753
|
try {
|
|
3754
|
-
const { execSync:
|
|
3755
|
-
const vmstat =
|
|
3754
|
+
const { execSync: execSync20 } = __require("child_process");
|
|
3755
|
+
const vmstat = execSync20("vm_stat", { encoding: "utf8" });
|
|
3756
3756
|
const pageSize = 16384;
|
|
3757
3757
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
3758
3758
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -5412,6 +5412,20 @@ async function ensureSchema() {
|
|
|
5412
5412
|
});
|
|
5413
5413
|
} catch {
|
|
5414
5414
|
}
|
|
5415
|
+
try {
|
|
5416
|
+
await client.execute({
|
|
5417
|
+
sql: `ALTER TABLE tasks ADD COLUMN spawn_runtime TEXT`,
|
|
5418
|
+
args: []
|
|
5419
|
+
});
|
|
5420
|
+
} catch {
|
|
5421
|
+
}
|
|
5422
|
+
try {
|
|
5423
|
+
await client.execute({
|
|
5424
|
+
sql: `ALTER TABLE tasks ADD COLUMN spawn_model TEXT`,
|
|
5425
|
+
args: []
|
|
5426
|
+
});
|
|
5427
|
+
} catch {
|
|
5428
|
+
}
|
|
5415
5429
|
await client.executeMultiple(`
|
|
5416
5430
|
CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
|
|
5417
5431
|
content_text,
|
|
@@ -5663,6 +5677,22 @@ async function ensureSchema() {
|
|
|
5663
5677
|
);
|
|
5664
5678
|
} catch {
|
|
5665
5679
|
}
|
|
5680
|
+
for (const col of [
|
|
5681
|
+
"ALTER TABLE memories ADD COLUMN valid_from TEXT",
|
|
5682
|
+
"ALTER TABLE memories ADD COLUMN invalid_at TEXT"
|
|
5683
|
+
]) {
|
|
5684
|
+
try {
|
|
5685
|
+
await client.execute(col);
|
|
5686
|
+
} catch {
|
|
5687
|
+
}
|
|
5688
|
+
}
|
|
5689
|
+
try {
|
|
5690
|
+
await client.execute({
|
|
5691
|
+
sql: `UPDATE memories SET valid_from = timestamp WHERE valid_from IS NULL`,
|
|
5692
|
+
args: []
|
|
5693
|
+
});
|
|
5694
|
+
} catch {
|
|
5695
|
+
}
|
|
5666
5696
|
try {
|
|
5667
5697
|
await client.execute({
|
|
5668
5698
|
sql: `ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'`,
|
|
@@ -5705,6 +5735,13 @@ async function ensureSchema() {
|
|
|
5705
5735
|
} catch {
|
|
5706
5736
|
}
|
|
5707
5737
|
}
|
|
5738
|
+
try {
|
|
5739
|
+
await client.execute({
|
|
5740
|
+
sql: `ALTER TABLE memories ADD COLUMN procedure_for TEXT`,
|
|
5741
|
+
args: []
|
|
5742
|
+
});
|
|
5743
|
+
} catch {
|
|
5744
|
+
}
|
|
5708
5745
|
try {
|
|
5709
5746
|
await client.execute({
|
|
5710
5747
|
sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
|
|
@@ -6146,8 +6183,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
6146
6183
|
}
|
|
6147
6184
|
function getCacheAgeMs() {
|
|
6148
6185
|
try {
|
|
6149
|
-
const { statSync:
|
|
6150
|
-
const s =
|
|
6186
|
+
const { statSync: statSync9 } = __require("fs");
|
|
6187
|
+
const s = statSync9(CACHE_PATH);
|
|
6151
6188
|
return Date.now() - s.mtimeMs;
|
|
6152
6189
|
} catch {
|
|
6153
6190
|
return Infinity;
|
|
@@ -6321,7 +6358,7 @@ var init_license = __esm({
|
|
|
6321
6358
|
LICENSE_PATH = path13.join(EXE_AI_DIR, "license.key");
|
|
6322
6359
|
CACHE_PATH = path13.join(EXE_AI_DIR, "license-cache.json");
|
|
6323
6360
|
DEVICE_ID_PATH = path13.join(EXE_AI_DIR, "device-id");
|
|
6324
|
-
API_BASE = "https://askexe.com/cloud";
|
|
6361
|
+
API_BASE = process.env.EXE_CLOUD_ENDPOINT ?? "https://askexe.com/cloud";
|
|
6325
6362
|
RETRY_DELAY_MS = 500;
|
|
6326
6363
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
6327
6364
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
@@ -8894,6 +8931,20 @@ var init_platform_procedures = __esm({
|
|
|
8894
8931
|
priority: "p1",
|
|
8895
8932
|
content: "Once per session (COO boot only, never repeat), call list_my_feature_requests to check if any previously filed feature requests have been shipped by AskExe. If any request has status 'shipped' with a shipped_version, surface it to the founder immediately: '\u{1F680} N feature(s) shipped \u2014 run exe-os update to get version X.Y.Z'. This is a one-time check at boot, not a recurring poll. If no requests exist or none are shipped, skip silently. If the MCP tool is unavailable or the network call fails, skip silently \u2014 this is informational, not blocking."
|
|
8896
8933
|
},
|
|
8934
|
+
// --- Tool guidance ---
|
|
8935
|
+
{
|
|
8936
|
+
title: "How to use company_actions \u2014 execute business actions through gateway connectors",
|
|
8937
|
+
domain: "tools",
|
|
8938
|
+
priority: "p2",
|
|
8939
|
+
content: "The company_actions tool executes business actions through gateway connectors (e.g. send WhatsApp, trigger workflows, update CRM). It routes through the exe-gateway on the VPS. Actions are defined by the customer's gateway configuration \u2014 each connector (WhatsApp, Shopify, email, etc.) exposes specific actions. Use query_company_brain to find available data first, then company_actions to act on it. Requires gateway auth token. Read-only founders should NOT use this \u2014 it mutates external state."
|
|
8940
|
+
},
|
|
8941
|
+
// --- Release awareness ---
|
|
8942
|
+
{
|
|
8943
|
+
title: "What's New check \u2014 surface new features after update",
|
|
8944
|
+
domain: "support",
|
|
8945
|
+
priority: "p1",
|
|
8946
|
+
content: "Once per session (COO boot only, never repeat), check if the installed exe-os version is newer than the last session. If it is, read the bundled release-notes.json (at the package root) and surface a brief summary to the founder: 'Updated to exe-os vX.Y.Z \u2014 N new features, M fixes.' List the top 3 features by name. This helps the founder know what they got from the update. If release-notes.json doesn't exist or the version hasn't changed, skip silently. Never repeat this check in the same session."
|
|
8947
|
+
},
|
|
8897
8948
|
// --- Platform vs Customer ownership ---
|
|
8898
8949
|
{
|
|
8899
8950
|
title: "What the platform provides vs what you customize",
|
|
@@ -8982,13 +9033,13 @@ var init_platform_procedures = __esm({
|
|
|
8982
9033
|
title: "MCP tools \u2014 memory, decision, and search",
|
|
8983
9034
|
domain: "tool-use",
|
|
8984
9035
|
priority: "p1",
|
|
8985
|
-
content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
|
|
9036
|
+
content: `memory(action="recall") / recall_my_memory: search your own memories (semantic + FTS). Supports as_of param for bi-temporal queries (what did I know at time X?), kind param to filter by memory type (decision, procedure, observation, raw, conversation, behavior). memory(action="ask_team") / ask_team_memory: search a colleague's memories by agent name. memory(action="store") / store_memory: persist a memory. Supports kind param and procedure_for domain tag for procedure-type memories. memory(action="commit") / commit_memory: high-importance memory that survives consolidation. Requires summary. memory(action="search") / search_everything: unified search across memories, tasks, entities, conversations. memory(action="session_context") / get_session_context: temporal memory window. Requires session_id + target_timestamp. memory(action="consolidate") / consolidate_memories: merge duplicate/related memories. memory(action="cardinality") / get_memory_cardinality: count memories per agent. memory(action="supersede") / supersede: replace an old memory with a new version (old_id + new text). decision(action="store") / store_decision: record an architectural decision (domain, decision, rationale). decision(action="get") / get_decision: retrieve a past decision by domain or query.`
|
|
8986
9037
|
},
|
|
8987
9038
|
{
|
|
8988
9039
|
title: "MCP tools \u2014 task orchestration",
|
|
8989
9040
|
domain: "tool-use",
|
|
8990
9041
|
priority: "p1",
|
|
8991
|
-
content:
|
|
9042
|
+
content: `task(action="create") / create_task: dispatch work (title, assigned_to, context). The ONLY dispatch path. Auto-spawns session. Supports spawn_runtime and spawn_model params to override the agent's default runtime/model for a specific task. task(action="list") / list_tasks: query tasks by status, assignee, project. task(action="get") / get_task: fetch full task details by task_id. task(action="update") / update_task: change status (in_progress, done, blocked, cancelled) + result summary. task(action="close") / close_task: finalize a reviewed task (COO only). task(action="checkpoint") / checkpoint_task: save progress state for crash recovery. task(action="resume") / resume_employee: re-spawn an employee session for an existing task.`
|
|
8992
9043
|
},
|
|
8993
9044
|
{
|
|
8994
9045
|
title: "MCP tools \u2014 knowledge graph (GraphRAG)",
|
|
@@ -9018,7 +9069,7 @@ var init_platform_procedures = __esm({
|
|
|
9018
9069
|
title: "MCP tools \u2014 admin, config, and operations",
|
|
9019
9070
|
domain: "tool-use",
|
|
9020
9071
|
priority: "p1",
|
|
9021
|
-
content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. mcp_ping(): daemon health + license status + tool usage stats.'
|
|
9072
|
+
content: 'config(action="list_employees"): view roster. config(action="agent_spend"): token usage per agent. config(action="daemon_health"): check exed status. config(action="license_status"): check license. config(action="cloud_sync"): force sync. config(action="memory_audit"): health check (dupes, null vectors). config(action="run_consolidation"): trigger memory consolidation. config(action="company_procedure", subaction="store|list|deactivate"): manage company procedures. config(action="global_procedure"): list all procedures (platform + company). config(action="create_trigger|list_triggers"): scheduled agent jobs. config(action="export_orchestration|import_orchestration"): portable org state. diagnostics(action="healthcheck|doctor|status_brief|check_update|cloud_status"): system diagnostics. diagnostics(action="tool_search"): semantic tool discovery \u2014 find relevant MCP tools by natural language query. Returns top-K tools ranked by relevance. diagnostics(action="drift"): identity drift detection \u2014 score how far an agent has drifted from its role identity. Returns drift score + recommendations. mcp_ping(): daemon health + license status + tool usage stats.'
|
|
9022
9073
|
}
|
|
9023
9074
|
];
|
|
9024
9075
|
PLATFORM_PROCEDURE_TITLES = new Set(
|
|
@@ -9702,6 +9753,8 @@ async function writeMemory(record) {
|
|
|
9702
9753
|
source_type: record.source_type ?? null,
|
|
9703
9754
|
tier: record.tier ?? classifyTier(record),
|
|
9704
9755
|
supersedes_id: record.supersedes_id ?? null,
|
|
9756
|
+
valid_from: record.valid_from ?? record.timestamp,
|
|
9757
|
+
invalid_at: record.invalid_at ?? null,
|
|
9705
9758
|
draft: record.draft ? 1 : 0,
|
|
9706
9759
|
memory_type: memoryType,
|
|
9707
9760
|
trajectory: record.trajectory ? JSON.stringify(record.trajectory) : null,
|
|
@@ -9720,7 +9773,8 @@ async function writeMemory(record) {
|
|
|
9720
9773
|
token_cost: record.token_cost ?? null,
|
|
9721
9774
|
audience: record.audience ?? null,
|
|
9722
9775
|
language_type: record.language_type ?? inferLanguageType(record),
|
|
9723
|
-
parent_memory_id: record.parent_memory_id ?? null
|
|
9776
|
+
parent_memory_id: record.parent_memory_id ?? null,
|
|
9777
|
+
procedure_for: record.procedure_for ?? null
|
|
9724
9778
|
};
|
|
9725
9779
|
_pendingRecords.push(dbRow);
|
|
9726
9780
|
orgBus.emit({
|
|
@@ -9775,6 +9829,8 @@ async function flushBatch() {
|
|
|
9775
9829
|
const sourceType = row.source_type ?? null;
|
|
9776
9830
|
const tier = row.tier ?? 3;
|
|
9777
9831
|
const supersedesId = row.supersedes_id ?? null;
|
|
9832
|
+
const validFrom = row.valid_from ?? row.timestamp;
|
|
9833
|
+
const invalidAt = row.invalid_at ?? null;
|
|
9778
9834
|
const draft = row.draft ? 1 : 0;
|
|
9779
9835
|
const memoryType = row.memory_type ?? "raw";
|
|
9780
9836
|
const trajectory = row.trajectory ?? null;
|
|
@@ -9794,15 +9850,16 @@ async function flushBatch() {
|
|
|
9794
9850
|
const audience = row.audience ?? null;
|
|
9795
9851
|
const languageType = row.language_type ?? null;
|
|
9796
9852
|
const parentMemoryId = row.parent_memory_id ?? null;
|
|
9853
|
+
const procedureFor = row.procedure_for ?? null;
|
|
9797
9854
|
const cols = `id, agent_id, agent_role, session_id, timestamp,
|
|
9798
9855
|
tool_name, project_name,
|
|
9799
9856
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
9800
9857
|
confidence, last_accessed,
|
|
9801
9858
|
workspace_id, document_id, user_id, char_offset, page_number,
|
|
9802
|
-
source_path, source_type, tier, supersedes_id, draft, memory_type, trajectory, content_hash,
|
|
9859
|
+
source_path, source_type, tier, supersedes_id, valid_from, invalid_at, draft, memory_type, trajectory, content_hash,
|
|
9803
9860
|
intent, outcome, domain, referenced_entities, retrieval_count,
|
|
9804
9861
|
chain_position, review_status, context_window_pct, file_paths, commit_hash,
|
|
9805
|
-
duration_ms, token_cost, audience, language_type, parent_memory_id`;
|
|
9862
|
+
duration_ms, token_cost, audience, language_type, parent_memory_id, procedure_for`;
|
|
9806
9863
|
const metaArgs = [
|
|
9807
9864
|
intent,
|
|
9808
9865
|
outcome,
|
|
@@ -9818,7 +9875,8 @@ async function flushBatch() {
|
|
|
9818
9875
|
tokenCost,
|
|
9819
9876
|
audience,
|
|
9820
9877
|
languageType,
|
|
9821
|
-
parentMemoryId
|
|
9878
|
+
parentMemoryId,
|
|
9879
|
+
procedureFor
|
|
9822
9880
|
];
|
|
9823
9881
|
const baseArgs = [
|
|
9824
9882
|
row.id,
|
|
@@ -9847,6 +9905,8 @@ async function flushBatch() {
|
|
|
9847
9905
|
sourceType,
|
|
9848
9906
|
tier,
|
|
9849
9907
|
supersedesId,
|
|
9908
|
+
validFrom,
|
|
9909
|
+
invalidAt,
|
|
9850
9910
|
draft,
|
|
9851
9911
|
memoryType,
|
|
9852
9912
|
trajectory,
|
|
@@ -9854,8 +9914,8 @@ async function flushBatch() {
|
|
|
9854
9914
|
];
|
|
9855
9915
|
return {
|
|
9856
9916
|
sql: hasVector ? `INSERT OR IGNORE INTO memories (${cols})
|
|
9857
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
9858
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
9917
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories (${cols})
|
|
9918
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
9859
9919
|
args: hasVector ? [...baseArgs, vectorToBlob(row.vector), ...sharedArgs, ...metaArgs] : [...baseArgs, ...sharedArgs, ...metaArgs]
|
|
9860
9920
|
};
|
|
9861
9921
|
};
|
|
@@ -9971,6 +10031,12 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
9971
10031
|
AND vector IS NOT NULL${statusFilter}${draftFilter}
|
|
9972
10032
|
AND COALESCE(confidence, 0.7) >= 0.3`;
|
|
9973
10033
|
const args2 = [agentId];
|
|
10034
|
+
if (options?.asOf) {
|
|
10035
|
+
sql += ` AND (valid_from IS NULL OR valid_from <= ?) AND (invalid_at IS NULL OR invalid_at > ?)`;
|
|
10036
|
+
args2.push(options.asOf, options.asOf);
|
|
10037
|
+
} else {
|
|
10038
|
+
sql += ` AND invalid_at IS NULL`;
|
|
10039
|
+
}
|
|
9974
10040
|
const scope = buildWikiScopeFilter(options, "");
|
|
9975
10041
|
sql += scope.clause;
|
|
9976
10042
|
args2.push(...scope.args);
|
|
@@ -12351,9 +12417,9 @@ Unclassified: ${unclassified}
|
|
|
12351
12417
|
}
|
|
12352
12418
|
async function exportBatches(options) {
|
|
12353
12419
|
const fs8 = await import("fs");
|
|
12354
|
-
const
|
|
12420
|
+
const path58 = await import("path");
|
|
12355
12421
|
const client = getClient();
|
|
12356
|
-
const outDir =
|
|
12422
|
+
const outDir = path58.join(process.cwd(), "exe/output/classifications/input");
|
|
12357
12423
|
fs8.mkdirSync(outDir, { recursive: true });
|
|
12358
12424
|
const countResult = await client.execute({
|
|
12359
12425
|
sql: "SELECT COUNT(*) as cnt FROM memories WHERE intent IS NULL AND outcome IS NULL AND domain IS NULL",
|
|
@@ -12377,7 +12443,7 @@ async function exportBatches(options) {
|
|
|
12377
12443
|
const text = String(row.text || "").replace(/\n/g, " ");
|
|
12378
12444
|
return JSON.stringify({ id: row.id, text });
|
|
12379
12445
|
});
|
|
12380
|
-
const batchFile =
|
|
12446
|
+
const batchFile = path58.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
|
|
12381
12447
|
fs8.writeFileSync(batchFile, lines.join("\n") + "\n");
|
|
12382
12448
|
exported += batch.rows.length;
|
|
12383
12449
|
offset += options.batchSize;
|
|
@@ -12393,7 +12459,7 @@ async function exportBatches(options) {
|
|
|
12393
12459
|
}
|
|
12394
12460
|
async function importClassifications(importDir) {
|
|
12395
12461
|
const fs8 = await import("fs");
|
|
12396
|
-
const
|
|
12462
|
+
const path58 = await import("path");
|
|
12397
12463
|
const client = getClient();
|
|
12398
12464
|
const files = fs8.readdirSync(importDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
12399
12465
|
process.stderr.write(`[backfill-metadata] Found ${files.length} JSONL files to import from ${importDir}
|
|
@@ -12401,7 +12467,7 @@ async function importClassifications(importDir) {
|
|
|
12401
12467
|
let imported = 0;
|
|
12402
12468
|
let invalid = 0;
|
|
12403
12469
|
for (const file of files) {
|
|
12404
|
-
const lines = fs8.readFileSync(
|
|
12470
|
+
const lines = fs8.readFileSync(path58.join(importDir, file), "utf-8").split("\n").filter(Boolean);
|
|
12405
12471
|
for (const line of lines) {
|
|
12406
12472
|
try {
|
|
12407
12473
|
const rec = JSON.parse(line);
|
|
@@ -13572,8 +13638,8 @@ function logQueue(msg) {
|
|
|
13572
13638
|
process.stderr.write(`[intercom-queue] ${msg}
|
|
13573
13639
|
`);
|
|
13574
13640
|
try {
|
|
13575
|
-
const { appendFileSync:
|
|
13576
|
-
|
|
13641
|
+
const { appendFileSync: appendFileSync4 } = __require("fs");
|
|
13642
|
+
appendFileSync4(INTERCOM_LOG, line);
|
|
13577
13643
|
} catch {
|
|
13578
13644
|
}
|
|
13579
13645
|
}
|
|
@@ -14131,8 +14197,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
14131
14197
|
const complexity = input.complexity ?? "standard";
|
|
14132
14198
|
const sessionScope = earlySessionScope;
|
|
14133
14199
|
await client.execute({
|
|
14134
|
-
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
|
|
14135
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
14200
|
+
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, spawn_runtime, spawn_model, created_at, updated_at)
|
|
14201
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
14136
14202
|
args: [
|
|
14137
14203
|
id,
|
|
14138
14204
|
input.title,
|
|
@@ -14152,6 +14218,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
14152
14218
|
0,
|
|
14153
14219
|
null,
|
|
14154
14220
|
sessionScope,
|
|
14221
|
+
input.spawnRuntime ?? null,
|
|
14222
|
+
input.spawnModel ?? null,
|
|
14155
14223
|
now2,
|
|
14156
14224
|
now2
|
|
14157
14225
|
]
|
|
@@ -14208,7 +14276,9 @@ ${input.context}
|
|
|
14208
14276
|
budgetTokens: input.budgetTokens ?? null,
|
|
14209
14277
|
budgetFallbackModel: input.budgetFallbackModel ?? null,
|
|
14210
14278
|
tokensUsed: 0,
|
|
14211
|
-
tokensWarnedAt: null
|
|
14279
|
+
tokensWarnedAt: null,
|
|
14280
|
+
spawnRuntime: input.spawnRuntime ?? null,
|
|
14281
|
+
spawnModel: input.spawnModel ?? null
|
|
14212
14282
|
};
|
|
14213
14283
|
}
|
|
14214
14284
|
async function listTasks(input) {
|
|
@@ -14258,7 +14328,9 @@ async function listTasks(input) {
|
|
|
14258
14328
|
budgetTokens: r.budget_tokens !== null ? Number(r.budget_tokens) : null,
|
|
14259
14329
|
budgetFallbackModel: r.budget_fallback_model !== null ? String(r.budget_fallback_model) : null,
|
|
14260
14330
|
tokensUsed: Number(r.tokens_used ?? 0),
|
|
14261
|
-
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
|
|
14331
|
+
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null,
|
|
14332
|
+
spawnRuntime: r.spawn_runtime !== null && r.spawn_runtime !== void 0 ? String(r.spawn_runtime) : null,
|
|
14333
|
+
spawnModel: r.spawn_model !== null && r.spawn_model !== void 0 ? String(r.spawn_model) : null
|
|
14262
14334
|
}));
|
|
14263
14335
|
}
|
|
14264
14336
|
function isTmuxSessionAlive(identifier) {
|
|
@@ -15039,10 +15111,10 @@ async function disposeEmbedder() {
|
|
|
15039
15111
|
async function embedDirect(text) {
|
|
15040
15112
|
const llamaCpp = await import("node-llama-cpp");
|
|
15041
15113
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
15042
|
-
const { existsSync:
|
|
15043
|
-
const
|
|
15044
|
-
const modelPath =
|
|
15045
|
-
if (!
|
|
15114
|
+
const { existsSync: existsSync43 } = await import("fs");
|
|
15115
|
+
const path58 = await import("path");
|
|
15116
|
+
const modelPath = path58.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
15117
|
+
if (!existsSync43(modelPath)) {
|
|
15046
15118
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
15047
15119
|
}
|
|
15048
15120
|
const llama = await llamaCpp.getLlama();
|
|
@@ -15555,6 +15627,8 @@ async function updateTask(input) {
|
|
|
15555
15627
|
budgetFallbackModel: row.budget_fallback_model !== void 0 && row.budget_fallback_model !== null ? String(row.budget_fallback_model) : null,
|
|
15556
15628
|
tokensUsed: Number(row.tokens_used ?? 0),
|
|
15557
15629
|
tokensWarnedAt: row.tokens_warned_at !== void 0 && row.tokens_warned_at !== null ? Number(row.tokens_warned_at) : null,
|
|
15630
|
+
spawnRuntime: row.spawn_runtime !== void 0 && row.spawn_runtime !== null ? String(row.spawn_runtime) : null,
|
|
15631
|
+
spawnModel: row.spawn_model !== void 0 && row.spawn_model !== null ? String(row.spawn_model) : null,
|
|
15558
15632
|
nextTask
|
|
15559
15633
|
};
|
|
15560
15634
|
}
|
|
@@ -16050,6 +16124,7 @@ function resolveExeSession() {
|
|
|
16050
16124
|
const mySession = getMySession();
|
|
16051
16125
|
if (!mySession) return null;
|
|
16052
16126
|
const fromSessionName = extractRootExe(mySession);
|
|
16127
|
+
let candidate = null;
|
|
16053
16128
|
try {
|
|
16054
16129
|
const key = getSessionKey();
|
|
16055
16130
|
const parentExe = getParentExe(key);
|
|
@@ -16060,13 +16135,47 @@ function resolveExeSession() {
|
|
|
16060
16135
|
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
16061
16136
|
`
|
|
16062
16137
|
);
|
|
16063
|
-
|
|
16138
|
+
candidate = fromSessionName;
|
|
16139
|
+
} else {
|
|
16140
|
+
candidate = fromCache;
|
|
16064
16141
|
}
|
|
16065
|
-
return fromCache;
|
|
16066
16142
|
}
|
|
16067
16143
|
} catch {
|
|
16068
16144
|
}
|
|
16069
|
-
|
|
16145
|
+
if (!candidate) {
|
|
16146
|
+
candidate = fromSessionName ?? mySession;
|
|
16147
|
+
}
|
|
16148
|
+
if (candidate && isRootSession(candidate)) {
|
|
16149
|
+
try {
|
|
16150
|
+
const transport = getTransport();
|
|
16151
|
+
const liveSessions = transport.listSessions();
|
|
16152
|
+
if (!liveSessions.includes(candidate)) {
|
|
16153
|
+
const liveRoots = liveSessions.filter((s) => isRootSession(s));
|
|
16154
|
+
if (liveRoots.length === 1) {
|
|
16155
|
+
process.stderr.write(
|
|
16156
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. Using live coordinator "${liveRoots[0]}".
|
|
16157
|
+
`
|
|
16158
|
+
);
|
|
16159
|
+
return liveRoots[0];
|
|
16160
|
+
} else if (liveRoots.length > 1) {
|
|
16161
|
+
const base = candidate.replace(/\d+$/, "");
|
|
16162
|
+
const match = liveRoots.find((s) => s.startsWith(base));
|
|
16163
|
+
const chosen = match ?? liveRoots[0];
|
|
16164
|
+
process.stderr.write(
|
|
16165
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead. ${liveRoots.length} live roots found, using "${chosen}".
|
|
16166
|
+
`
|
|
16167
|
+
);
|
|
16168
|
+
return chosen;
|
|
16169
|
+
}
|
|
16170
|
+
process.stderr.write(
|
|
16171
|
+
`[tmux-routing] WARN: resolved session "${candidate}" is dead and no live coordinator found.
|
|
16172
|
+
`
|
|
16173
|
+
);
|
|
16174
|
+
}
|
|
16175
|
+
} catch {
|
|
16176
|
+
}
|
|
16177
|
+
}
|
|
16178
|
+
return candidate;
|
|
16070
16179
|
}
|
|
16071
16180
|
function isEmployeeAlive(sessionName) {
|
|
16072
16181
|
return getTransport().isAlive(sessionName);
|
|
@@ -16468,7 +16577,12 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
16468
16577
|
}
|
|
16469
16578
|
const spawnCwd = opts?.cwd ?? projectDir;
|
|
16470
16579
|
const useExeAgent = !!(opts?.model && opts?.provider);
|
|
16471
|
-
const
|
|
16580
|
+
const baseRtConfig = getAgentRuntime(employeeName);
|
|
16581
|
+
const agentRtConfig = {
|
|
16582
|
+
...baseRtConfig,
|
|
16583
|
+
...opts?.runtimeOverride ? { runtime: opts.runtimeOverride } : {},
|
|
16584
|
+
...opts?.modelOverride ? { model: opts.modelOverride } : {}
|
|
16585
|
+
};
|
|
16472
16586
|
const useCodex = !useExeAgent && agentRtConfig.runtime === "codex";
|
|
16473
16587
|
const useOpencode = !useExeAgent && !useCodex && agentRtConfig.runtime === "opencode";
|
|
16474
16588
|
const ccProvider = useExeAgent || useCodex || useOpencode ? DEFAULT_PROVIDER : detectActiveProvider();
|
|
@@ -18012,17 +18126,980 @@ var init_exe_rename = __esm({
|
|
|
18012
18126
|
}
|
|
18013
18127
|
});
|
|
18014
18128
|
|
|
18129
|
+
// src/lib/drift-probes.ts
|
|
18130
|
+
async function getRecentMemories(agentId, limit) {
|
|
18131
|
+
try {
|
|
18132
|
+
const { getClient: getClient2, isInitialized: isInitialized2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
18133
|
+
if (!isInitialized2()) return { count: 0, texts: [] };
|
|
18134
|
+
const client = getClient2();
|
|
18135
|
+
const result = await client.execute({
|
|
18136
|
+
sql: `SELECT text FROM memories WHERE agent_id = ? ORDER BY created_at DESC LIMIT ?`,
|
|
18137
|
+
args: [agentId, limit]
|
|
18138
|
+
});
|
|
18139
|
+
const texts = result.rows.map((r) => String(r.text ?? ""));
|
|
18140
|
+
return { count: texts.length, texts };
|
|
18141
|
+
} catch {
|
|
18142
|
+
return { count: 0, texts: [] };
|
|
18143
|
+
}
|
|
18144
|
+
}
|
|
18145
|
+
async function getDecisionCount(agentId) {
|
|
18146
|
+
try {
|
|
18147
|
+
const { getClient: getClient2, isInitialized: isInitialized2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
18148
|
+
if (!isInitialized2()) return 0;
|
|
18149
|
+
const client = getClient2();
|
|
18150
|
+
const result = await client.execute({
|
|
18151
|
+
sql: `SELECT COUNT(*) as cnt FROM memories WHERE agent_id = ? AND memory_type = 'decision'`,
|
|
18152
|
+
args: [agentId]
|
|
18153
|
+
});
|
|
18154
|
+
return Number(result.rows[0]?.cnt ?? 0);
|
|
18155
|
+
} catch {
|
|
18156
|
+
return 0;
|
|
18157
|
+
}
|
|
18158
|
+
}
|
|
18159
|
+
function probeContinuity(ctx) {
|
|
18160
|
+
const memCount = ctx.recentMemoryCount;
|
|
18161
|
+
let score;
|
|
18162
|
+
let detail;
|
|
18163
|
+
if (memCount >= 20) {
|
|
18164
|
+
score = 95;
|
|
18165
|
+
detail = `${memCount} recent memories \u2014 strong continuity`;
|
|
18166
|
+
} else if (memCount >= 10) {
|
|
18167
|
+
score = 85;
|
|
18168
|
+
detail = `${memCount} recent memories \u2014 adequate continuity`;
|
|
18169
|
+
} else if (memCount >= 3) {
|
|
18170
|
+
score = 70;
|
|
18171
|
+
detail = `${memCount} recent memories \u2014 limited continuity`;
|
|
18172
|
+
} else if (memCount >= 1) {
|
|
18173
|
+
score = 50;
|
|
18174
|
+
detail = `${memCount} recent memories \u2014 weak continuity`;
|
|
18175
|
+
} else {
|
|
18176
|
+
score = 30;
|
|
18177
|
+
detail = "No recent memories \u2014 agent may lack session context";
|
|
18178
|
+
}
|
|
18179
|
+
if (ctx.storedDecisionCount > 0) {
|
|
18180
|
+
score = Math.min(100, score + 5);
|
|
18181
|
+
detail += ` (+${ctx.storedDecisionCount} decisions)`;
|
|
18182
|
+
}
|
|
18183
|
+
return { axis: "continuity", score, detail };
|
|
18184
|
+
}
|
|
18185
|
+
function probeConsistency(ctx) {
|
|
18186
|
+
if (!ctx.identityBody || ctx.recentMemoryTexts.length === 0) {
|
|
18187
|
+
return {
|
|
18188
|
+
axis: "consistency",
|
|
18189
|
+
score: ctx.identityBody ? 80 : 50,
|
|
18190
|
+
detail: ctx.identityBody ? "No memories to check against identity" : "No identity file \u2014 cannot assess consistency"
|
|
18191
|
+
};
|
|
18192
|
+
}
|
|
18193
|
+
const identityTerms = extractKeyTerms(ctx.identityBody);
|
|
18194
|
+
if (identityTerms.length === 0) {
|
|
18195
|
+
return { axis: "consistency", score: 75, detail: "Identity has no extractable key terms" };
|
|
18196
|
+
}
|
|
18197
|
+
const memoryText = ctx.recentMemoryTexts.join(" ").toLowerCase();
|
|
18198
|
+
let matched = 0;
|
|
18199
|
+
for (const term of identityTerms) {
|
|
18200
|
+
if (memoryText.includes(term.toLowerCase())) matched++;
|
|
18201
|
+
}
|
|
18202
|
+
const ratio = matched / identityTerms.length;
|
|
18203
|
+
const score = Math.round(50 + ratio * 50);
|
|
18204
|
+
const detail = `${matched}/${identityTerms.length} identity terms found in recent memories`;
|
|
18205
|
+
return { axis: "consistency", score, detail };
|
|
18206
|
+
}
|
|
18207
|
+
function probeRoleFidelity(ctx) {
|
|
18208
|
+
const flags = [];
|
|
18209
|
+
if (!ctx.identityBody) {
|
|
18210
|
+
return {
|
|
18211
|
+
axis: "role-fidelity",
|
|
18212
|
+
score: 40,
|
|
18213
|
+
detail: `No identity file for ${ctx.agent.name}`
|
|
18214
|
+
};
|
|
18215
|
+
}
|
|
18216
|
+
let score = 100;
|
|
18217
|
+
const identityLower = ctx.identityBody.toLowerCase();
|
|
18218
|
+
const rosterRole = ctx.agent.role.toLowerCase();
|
|
18219
|
+
if (!identityLower.includes(rosterRole)) {
|
|
18220
|
+
score -= 15;
|
|
18221
|
+
flags.push(`Identity does not mention role "${ctx.agent.role}"`);
|
|
18222
|
+
}
|
|
18223
|
+
if (!identityLower.includes(ctx.agent.name.toLowerCase())) {
|
|
18224
|
+
score -= 10;
|
|
18225
|
+
flags.push(`Identity does not mention agent name "${ctx.agent.name}"`);
|
|
18226
|
+
}
|
|
18227
|
+
const hasScopeBoundary = identityLower.includes("do not") || identityLower.includes("don't") || identityLower.includes("not your") || identityLower.includes("outside your") || identityLower.includes("you do not");
|
|
18228
|
+
if (!hasScopeBoundary) {
|
|
18229
|
+
score -= 10;
|
|
18230
|
+
flags.push("Identity lacks explicit scope boundaries (what NOT to do)");
|
|
18231
|
+
}
|
|
18232
|
+
if (ctx.agent.systemPrompt) {
|
|
18233
|
+
const promptTerms = extractKeyTerms(ctx.agent.systemPrompt);
|
|
18234
|
+
const identityText = ctx.identityBody.toLowerCase();
|
|
18235
|
+
let promptMatched = 0;
|
|
18236
|
+
for (const term of promptTerms.slice(0, 20)) {
|
|
18237
|
+
if (identityText.includes(term.toLowerCase())) promptMatched++;
|
|
18238
|
+
}
|
|
18239
|
+
const promptRatio = promptTerms.length > 0 ? promptMatched / Math.min(promptTerms.length, 20) : 1;
|
|
18240
|
+
if (promptRatio < 0.3) {
|
|
18241
|
+
score -= 15;
|
|
18242
|
+
flags.push("Identity content diverges significantly from roster systemPrompt");
|
|
18243
|
+
}
|
|
18244
|
+
}
|
|
18245
|
+
if (ctx.recentMemoryTexts.length > 5) {
|
|
18246
|
+
const roleKeywords = extractRoleKeywords(ctx.agent.role);
|
|
18247
|
+
const memoryText = ctx.recentMemoryTexts.join(" ").toLowerCase();
|
|
18248
|
+
let domainHits = 0;
|
|
18249
|
+
for (const kw of roleKeywords) {
|
|
18250
|
+
if (memoryText.includes(kw)) domainHits++;
|
|
18251
|
+
}
|
|
18252
|
+
const domainRatio = roleKeywords.length > 0 ? domainHits / roleKeywords.length : 1;
|
|
18253
|
+
if (domainRatio < 0.2) {
|
|
18254
|
+
score -= 10;
|
|
18255
|
+
flags.push(`Recent work shows little overlap with ${ctx.agent.role} domain keywords`);
|
|
18256
|
+
}
|
|
18257
|
+
}
|
|
18258
|
+
score = Math.max(0, Math.min(100, score));
|
|
18259
|
+
const detail = flags.length > 0 ? flags.join("; ") : "Identity aligns with roster definition";
|
|
18260
|
+
return { axis: "role-fidelity", score, detail };
|
|
18261
|
+
}
|
|
18262
|
+
function probeWorldModel(ctx) {
|
|
18263
|
+
if (!ctx.identityBody) {
|
|
18264
|
+
return {
|
|
18265
|
+
axis: "world-model",
|
|
18266
|
+
score: 50,
|
|
18267
|
+
detail: "No identity file \u2014 cannot assess org awareness"
|
|
18268
|
+
};
|
|
18269
|
+
}
|
|
18270
|
+
const identityLower = ctx.identityBody.toLowerCase();
|
|
18271
|
+
const flags = [];
|
|
18272
|
+
let score = 100;
|
|
18273
|
+
const otherAgents = ctx.allEmployees.filter((e) => e.name !== ctx.agent.name);
|
|
18274
|
+
let mentionedAgents = 0;
|
|
18275
|
+
for (const other of otherAgents) {
|
|
18276
|
+
if (identityLower.includes(other.name.toLowerCase())) mentionedAgents++;
|
|
18277
|
+
}
|
|
18278
|
+
if (otherAgents.length > 0) {
|
|
18279
|
+
const mentionRatio = mentionedAgents / otherAgents.length;
|
|
18280
|
+
if (mentionRatio < 0.3) {
|
|
18281
|
+
score -= 15;
|
|
18282
|
+
flags.push(`Identity mentions ${mentionedAgents}/${otherAgents.length} team members`);
|
|
18283
|
+
}
|
|
18284
|
+
}
|
|
18285
|
+
const hasReportingChain = identityLower.includes("report") || identityLower.includes("manager") || identityLower.includes("coo") || identityLower.includes("coordinator");
|
|
18286
|
+
if (!hasReportingChain) {
|
|
18287
|
+
score -= 10;
|
|
18288
|
+
flags.push("Identity does not reference reporting chain");
|
|
18289
|
+
}
|
|
18290
|
+
const orgTerms = ["exe-os", "exe-wiki", "exe-crm", "askexe"];
|
|
18291
|
+
let orgMentions = 0;
|
|
18292
|
+
for (const term of orgTerms) {
|
|
18293
|
+
if (identityLower.includes(term)) orgMentions++;
|
|
18294
|
+
}
|
|
18295
|
+
if (orgMentions === 0) {
|
|
18296
|
+
score -= 5;
|
|
18297
|
+
flags.push("Identity does not reference any org products");
|
|
18298
|
+
}
|
|
18299
|
+
score = Math.max(0, Math.min(100, score));
|
|
18300
|
+
const detail = flags.length > 0 ? flags.join("; ") : "Identity reflects org structure";
|
|
18301
|
+
return { axis: "world-model", score, detail };
|
|
18302
|
+
}
|
|
18303
|
+
function extractKeyTerms(text) {
|
|
18304
|
+
const stopwords = /* @__PURE__ */ new Set([
|
|
18305
|
+
"the",
|
|
18306
|
+
"and",
|
|
18307
|
+
"for",
|
|
18308
|
+
"are",
|
|
18309
|
+
"but",
|
|
18310
|
+
"not",
|
|
18311
|
+
"you",
|
|
18312
|
+
"all",
|
|
18313
|
+
"any",
|
|
18314
|
+
"can",
|
|
18315
|
+
"had",
|
|
18316
|
+
"her",
|
|
18317
|
+
"was",
|
|
18318
|
+
"one",
|
|
18319
|
+
"our",
|
|
18320
|
+
"out",
|
|
18321
|
+
"has",
|
|
18322
|
+
"his",
|
|
18323
|
+
"how",
|
|
18324
|
+
"its",
|
|
18325
|
+
"may",
|
|
18326
|
+
"new",
|
|
18327
|
+
"now",
|
|
18328
|
+
"old",
|
|
18329
|
+
"see",
|
|
18330
|
+
"way",
|
|
18331
|
+
"who",
|
|
18332
|
+
"did",
|
|
18333
|
+
"get",
|
|
18334
|
+
"got",
|
|
18335
|
+
"let",
|
|
18336
|
+
"say",
|
|
18337
|
+
"she",
|
|
18338
|
+
"too",
|
|
18339
|
+
"use",
|
|
18340
|
+
"with",
|
|
18341
|
+
"this",
|
|
18342
|
+
"that",
|
|
18343
|
+
"from",
|
|
18344
|
+
"they",
|
|
18345
|
+
"been",
|
|
18346
|
+
"have",
|
|
18347
|
+
"will",
|
|
18348
|
+
"your",
|
|
18349
|
+
"what",
|
|
18350
|
+
"when",
|
|
18351
|
+
"make",
|
|
18352
|
+
"like",
|
|
18353
|
+
"just",
|
|
18354
|
+
"over",
|
|
18355
|
+
"such",
|
|
18356
|
+
"take",
|
|
18357
|
+
"than",
|
|
18358
|
+
"them",
|
|
18359
|
+
"very",
|
|
18360
|
+
"some",
|
|
18361
|
+
"could",
|
|
18362
|
+
"into",
|
|
18363
|
+
"then",
|
|
18364
|
+
"more",
|
|
18365
|
+
"also",
|
|
18366
|
+
"after",
|
|
18367
|
+
"should",
|
|
18368
|
+
"would",
|
|
18369
|
+
"about",
|
|
18370
|
+
"their",
|
|
18371
|
+
"which",
|
|
18372
|
+
"these",
|
|
18373
|
+
"other",
|
|
18374
|
+
"every",
|
|
18375
|
+
"does",
|
|
18376
|
+
"being",
|
|
18377
|
+
"those",
|
|
18378
|
+
"never",
|
|
18379
|
+
"before",
|
|
18380
|
+
"through"
|
|
18381
|
+
]);
|
|
18382
|
+
const words = text.replace(/[^\w\s-]/g, " ").split(/\s+/).filter((w) => w.length > 3 && !stopwords.has(w.toLowerCase()));
|
|
18383
|
+
return [...new Set(words.map((w) => w.toLowerCase()))].slice(0, 50);
|
|
18384
|
+
}
|
|
18385
|
+
function extractRoleKeywords(role) {
|
|
18386
|
+
const roleKeywordMap = {
|
|
18387
|
+
"coo": ["coordinate", "review", "status", "team", "task", "priority", "dispatch"],
|
|
18388
|
+
"cto": ["architecture", "code", "technical", "system", "design", "review", "security"],
|
|
18389
|
+
"cmo": ["marketing", "brand", "content", "design", "seo", "social", "campaign"],
|
|
18390
|
+
"principal engineer": ["code", "implement", "test", "fix", "feature", "refactor", "build"],
|
|
18391
|
+
"staff code reviewer": ["review", "code", "quality", "issue", "fix", "pattern"],
|
|
18392
|
+
"content production specialist": ["video", "image", "render", "content", "produce", "media"],
|
|
18393
|
+
"ai product lead": ["competitive", "analysis", "feature", "product", "research", "repo"]
|
|
18394
|
+
};
|
|
18395
|
+
const normalized = role.toLowerCase();
|
|
18396
|
+
return roleKeywordMap[normalized] ?? normalized.split(/\s+/).filter((w) => w.length > 2);
|
|
18397
|
+
}
|
|
18398
|
+
async function runDriftProbes(options = {}) {
|
|
18399
|
+
const employees = loadEmployeesSync();
|
|
18400
|
+
const targetAgents = options.agentId ? employees.filter((e) => e.name === options.agentId) : employees;
|
|
18401
|
+
if (targetAgents.length === 0) {
|
|
18402
|
+
return [];
|
|
18403
|
+
}
|
|
18404
|
+
const axes = options.axes ?? ["continuity", "consistency", "role-fidelity", "world-model"];
|
|
18405
|
+
const results = [];
|
|
18406
|
+
for (const agent of targetAgents) {
|
|
18407
|
+
const identity = getIdentity(agent.name);
|
|
18408
|
+
const { count: memCount, texts: memTexts } = await getRecentMemories(agent.name, 50);
|
|
18409
|
+
const decisionCount = await getDecisionCount(agent.name);
|
|
18410
|
+
const ctx = {
|
|
18411
|
+
agent,
|
|
18412
|
+
identityBody: identity?.body ?? null,
|
|
18413
|
+
identityRole: identity?.frontmatter.role ?? null,
|
|
18414
|
+
recentMemoryCount: memCount,
|
|
18415
|
+
recentMemoryTexts: memTexts,
|
|
18416
|
+
storedDecisionCount: decisionCount,
|
|
18417
|
+
allEmployees: employees
|
|
18418
|
+
};
|
|
18419
|
+
const probes = [];
|
|
18420
|
+
const probeFns = {
|
|
18421
|
+
continuity: probeContinuity,
|
|
18422
|
+
consistency: probeConsistency,
|
|
18423
|
+
"role-fidelity": probeRoleFidelity,
|
|
18424
|
+
"world-model": probeWorldModel
|
|
18425
|
+
};
|
|
18426
|
+
for (const axis of axes) {
|
|
18427
|
+
probes.push(probeFns[axis](ctx));
|
|
18428
|
+
}
|
|
18429
|
+
const scores = {
|
|
18430
|
+
continuity: 0,
|
|
18431
|
+
consistency: 0,
|
|
18432
|
+
"role-fidelity": 0,
|
|
18433
|
+
"world-model": 0
|
|
18434
|
+
};
|
|
18435
|
+
for (const probe of probes) {
|
|
18436
|
+
scores[probe.axis] = probe.score;
|
|
18437
|
+
}
|
|
18438
|
+
const weights = {
|
|
18439
|
+
continuity: 0.2,
|
|
18440
|
+
consistency: 0.2,
|
|
18441
|
+
"role-fidelity": 0.35,
|
|
18442
|
+
"world-model": 0.25
|
|
18443
|
+
};
|
|
18444
|
+
let weightedSum = 0;
|
|
18445
|
+
let weightTotal = 0;
|
|
18446
|
+
for (const axis of axes) {
|
|
18447
|
+
weightedSum += scores[axis] * weights[axis];
|
|
18448
|
+
weightTotal += weights[axis];
|
|
18449
|
+
}
|
|
18450
|
+
const overall = Math.round(weightTotal > 0 ? weightedSum / weightTotal : 0);
|
|
18451
|
+
const flags = [];
|
|
18452
|
+
for (const probe of probes) {
|
|
18453
|
+
if (probe.score < DRIFT_THRESHOLD) {
|
|
18454
|
+
flags.push(`${probe.axis} at ${probe.score}% \u2014 ${probe.detail}`);
|
|
18455
|
+
}
|
|
18456
|
+
}
|
|
18457
|
+
results.push({
|
|
18458
|
+
agent: agent.name,
|
|
18459
|
+
scores,
|
|
18460
|
+
overall,
|
|
18461
|
+
drifting: flags.length > 0,
|
|
18462
|
+
flags
|
|
18463
|
+
});
|
|
18464
|
+
}
|
|
18465
|
+
return results;
|
|
18466
|
+
}
|
|
18467
|
+
var DRIFT_THRESHOLD;
|
|
18468
|
+
var init_drift_probes = __esm({
|
|
18469
|
+
"src/lib/drift-probes.ts"() {
|
|
18470
|
+
"use strict";
|
|
18471
|
+
init_identity();
|
|
18472
|
+
init_employees();
|
|
18473
|
+
DRIFT_THRESHOLD = 80;
|
|
18474
|
+
}
|
|
18475
|
+
});
|
|
18476
|
+
|
|
18477
|
+
// src/bin/exe-drift.ts
|
|
18478
|
+
var exe_drift_exports = {};
|
|
18479
|
+
__export(exe_drift_exports, {
|
|
18480
|
+
runDrift: () => runDrift
|
|
18481
|
+
});
|
|
18482
|
+
function statusIcon(overall) {
|
|
18483
|
+
if (overall >= 80) return "\x1B[32m\u{1F7E2} OK\x1B[0m";
|
|
18484
|
+
if (overall >= 60) return "\x1B[33m\u{1F7E0} WARN\x1B[0m";
|
|
18485
|
+
return "\x1B[31m\u{1F534} DRIFTING\x1B[0m";
|
|
18486
|
+
}
|
|
18487
|
+
function padRight(str, len) {
|
|
18488
|
+
return str.length >= len ? str.slice(0, len) : str + " ".repeat(len - str.length);
|
|
18489
|
+
}
|
|
18490
|
+
function padLeft(str, len) {
|
|
18491
|
+
return str.length >= len ? str : " ".repeat(len - str.length) + str;
|
|
18492
|
+
}
|
|
18493
|
+
function formatTable(results) {
|
|
18494
|
+
const lines = [];
|
|
18495
|
+
const header = padRight("Agent", 10) + AXES.map((a) => padLeft(AXIS_HEADERS[a], 9)).join("") + padLeft("Overall", 9) + " Status";
|
|
18496
|
+
lines.push(header);
|
|
18497
|
+
lines.push("-".repeat(header.length + 10));
|
|
18498
|
+
for (const r of results) {
|
|
18499
|
+
const line = padRight(r.agent, 10) + AXES.map((a) => padLeft(String(r.scores[a]), 9)).join("") + padLeft(String(r.overall), 9) + " " + statusIcon(r.overall);
|
|
18500
|
+
lines.push(line);
|
|
18501
|
+
}
|
|
18502
|
+
return lines.join("\n");
|
|
18503
|
+
}
|
|
18504
|
+
async function runDrift(args2) {
|
|
18505
|
+
const agentIdx = args2.indexOf("--agent");
|
|
18506
|
+
const agentId = agentIdx >= 0 ? args2[agentIdx + 1] : void 0;
|
|
18507
|
+
console.log("\nexe-os doctor --drift\n");
|
|
18508
|
+
const results = await runDriftProbes({ agentId });
|
|
18509
|
+
if (results.length === 0) {
|
|
18510
|
+
console.log("No agents found. Run /exe-team to see available employees.");
|
|
18511
|
+
return;
|
|
18512
|
+
}
|
|
18513
|
+
console.log(formatTable(results));
|
|
18514
|
+
console.log();
|
|
18515
|
+
const flagged = results.filter((r) => r.flags.length > 0);
|
|
18516
|
+
if (flagged.length > 0) {
|
|
18517
|
+
for (const r of flagged) {
|
|
18518
|
+
for (const flag of r.flags) {
|
|
18519
|
+
console.log(`\u26A0 ${r.agent}: ${flag}`);
|
|
18520
|
+
}
|
|
18521
|
+
}
|
|
18522
|
+
console.log();
|
|
18523
|
+
} else {
|
|
18524
|
+
console.log("All agents within role-fidelity thresholds.\n");
|
|
18525
|
+
}
|
|
18526
|
+
}
|
|
18527
|
+
var AXES, AXIS_HEADERS;
|
|
18528
|
+
var init_exe_drift = __esm({
|
|
18529
|
+
"src/bin/exe-drift.ts"() {
|
|
18530
|
+
"use strict";
|
|
18531
|
+
init_drift_probes();
|
|
18532
|
+
AXES = ["continuity", "consistency", "role-fidelity", "world-model"];
|
|
18533
|
+
AXIS_HEADERS = {
|
|
18534
|
+
continuity: "Cont.",
|
|
18535
|
+
consistency: "Consist.",
|
|
18536
|
+
"role-fidelity": "Role",
|
|
18537
|
+
"world-model": "World"
|
|
18538
|
+
};
|
|
18539
|
+
}
|
|
18540
|
+
});
|
|
18541
|
+
|
|
18542
|
+
// src/lib/mcp-transport-health.ts
|
|
18543
|
+
import { appendFileSync as appendFileSync3, closeSync as closeSync3, existsSync as existsSync30, mkdirSync as mkdirSync22, openSync as openSync3, readFileSync as readFileSync26, readSync, statSync as statSync7, writeFileSync as writeFileSync23 } from "fs";
|
|
18544
|
+
import path37 from "path";
|
|
18545
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
18546
|
+
function parsePositiveInt(value, fallback) {
|
|
18547
|
+
if (!value) return fallback;
|
|
18548
|
+
const parsed = Number.parseInt(value, 10);
|
|
18549
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
18550
|
+
}
|
|
18551
|
+
function readTailText(filePath, maxBytes) {
|
|
18552
|
+
const stats = statSync7(filePath);
|
|
18553
|
+
if (stats.size <= maxBytes) return readFileSync26(filePath, "utf8");
|
|
18554
|
+
const fd = openSync3(filePath, "r");
|
|
18555
|
+
try {
|
|
18556
|
+
const buffer = Buffer.allocUnsafe(maxBytes);
|
|
18557
|
+
readSync(fd, buffer, 0, maxBytes, stats.size - maxBytes);
|
|
18558
|
+
const text = buffer.toString("utf8");
|
|
18559
|
+
const firstNewline = text.indexOf("\n");
|
|
18560
|
+
return firstNewline >= 0 ? text.slice(firstNewline + 1) : text;
|
|
18561
|
+
} finally {
|
|
18562
|
+
closeSync3(fd);
|
|
18563
|
+
}
|
|
18564
|
+
}
|
|
18565
|
+
function readPackageVersion2() {
|
|
18566
|
+
let dir = path37.dirname(fileURLToPath5(import.meta.url));
|
|
18567
|
+
const { root } = path37.parse(dir);
|
|
18568
|
+
while (dir !== root) {
|
|
18569
|
+
const pkgPath = path37.join(dir, "package.json");
|
|
18570
|
+
if (existsSync30(pkgPath)) {
|
|
18571
|
+
try {
|
|
18572
|
+
const parsed = JSON.parse(readFileSync26(pkgPath, "utf8"));
|
|
18573
|
+
return parsed.version ?? "unknown";
|
|
18574
|
+
} catch {
|
|
18575
|
+
return "unknown";
|
|
18576
|
+
}
|
|
18577
|
+
}
|
|
18578
|
+
dir = path37.dirname(dir);
|
|
18579
|
+
}
|
|
18580
|
+
return "unknown";
|
|
18581
|
+
}
|
|
18582
|
+
function parseMcpHttpEventLines(raw, limit = 200) {
|
|
18583
|
+
const lines = raw.trim().split("\n").filter(Boolean).slice(-limit);
|
|
18584
|
+
const events = [];
|
|
18585
|
+
for (const line of lines) {
|
|
18586
|
+
try {
|
|
18587
|
+
events.push(JSON.parse(line));
|
|
18588
|
+
} catch {
|
|
18589
|
+
}
|
|
18590
|
+
}
|
|
18591
|
+
return events;
|
|
18592
|
+
}
|
|
18593
|
+
function readMcpHttpEvents(limit = 200) {
|
|
18594
|
+
if (!existsSync30(MCP_HTTP_EVENTS_PATH)) return [];
|
|
18595
|
+
const raw = readTailText(MCP_HTTP_EVENTS_PATH, EVENT_READ_BYTES);
|
|
18596
|
+
return parseMcpHttpEventLines(raw, limit);
|
|
18597
|
+
}
|
|
18598
|
+
function summarizeMcpTransport(events = readMcpHttpEvents()) {
|
|
18599
|
+
const lastServerStartIndex = events.map((event) => event.message).lastIndexOf("server_started");
|
|
18600
|
+
const scopedEvents = lastServerStartIndex >= 0 ? events.slice(lastServerStartIndex) : events;
|
|
18601
|
+
const activeSessionEvent = [...scopedEvents].reverse().find((event) => typeof event.activeSessions === "number");
|
|
18602
|
+
const successfulToolCalls = scopedEvents.filter((event) => event.message === "tool_call_ok");
|
|
18603
|
+
const lastSuccessfulToolCall = successfulToolCalls.at(-1) ?? null;
|
|
18604
|
+
const summary = {
|
|
18605
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18606
|
+
version: readPackageVersion2(),
|
|
18607
|
+
scope: "local",
|
|
18608
|
+
privacy: "metadata_only",
|
|
18609
|
+
eventLogPath: MCP_HTTP_EVENTS_PATH,
|
|
18610
|
+
activeSessions: activeSessionEvent?.activeSessions ?? null,
|
|
18611
|
+
sessionsCreated: scopedEvents.filter((event) => event.message === "session_initialized").length,
|
|
18612
|
+
sessionsClosed: scopedEvents.filter((event) => event.message === "session_closed").length,
|
|
18613
|
+
missingSessionErrors: scopedEvents.filter((event) => event.message?.includes("missing MCP session")).length,
|
|
18614
|
+
staleSessionErrors: scopedEvents.filter((event) => event.message?.includes("stale or unknown")).length,
|
|
18615
|
+
transportErrors: scopedEvents.filter((event) => event.level === "warn" || event.level === "error").length,
|
|
18616
|
+
lastSuccessfulHandshake: scopedEvents.filter((event) => event.message === "session_initialized").at(-1)?.timestamp ?? null,
|
|
18617
|
+
lastSuccessfulToolCall: lastSuccessfulToolCall?.timestamp ?? null,
|
|
18618
|
+
lastSuccessfulToolCallByRuntime: {},
|
|
18619
|
+
lastSuccessfulToolCallByAgent: {},
|
|
18620
|
+
lastSuccessfulToolCallByFamily: {},
|
|
18621
|
+
activeSessionsByRuntime: {},
|
|
18622
|
+
recentWarnings: scopedEvents.filter((event) => event.level === "warn" || event.level === "error").slice(-10),
|
|
18623
|
+
remediation: [
|
|
18624
|
+
"If MCP tools fail with missing/stale session, reconnect the MCP client (/mcp or restart the runtime).",
|
|
18625
|
+
"Do not access the database directly; MCP is the only data interface.",
|
|
18626
|
+
"Check get_daemon_health or exe-healthcheck for daemon/MCP endpoint status before retrying work."
|
|
18627
|
+
]
|
|
18628
|
+
};
|
|
18629
|
+
const createdBySession = /* @__PURE__ */ new Map();
|
|
18630
|
+
for (const event of scopedEvents) {
|
|
18631
|
+
if (event.message === "session_initialized" && event.sessionId) createdBySession.set(event.sessionId, event);
|
|
18632
|
+
if ((event.message === "session_closed" || event.message === "session_expired") && event.sessionId) {
|
|
18633
|
+
createdBySession.delete(event.sessionId);
|
|
18634
|
+
}
|
|
18635
|
+
}
|
|
18636
|
+
for (const event of createdBySession.values()) {
|
|
18637
|
+
const runtime = event.runtime ?? "Unknown";
|
|
18638
|
+
summary.activeSessionsByRuntime[runtime] = (summary.activeSessionsByRuntime[runtime] ?? 0) + 1;
|
|
18639
|
+
}
|
|
18640
|
+
for (const event of successfulToolCalls) {
|
|
18641
|
+
if (event.runtime) summary.lastSuccessfulToolCallByRuntime[event.runtime] = event.timestamp ?? "";
|
|
18642
|
+
if (event.agentId) summary.lastSuccessfulToolCallByAgent[event.agentId] = event.timestamp ?? "";
|
|
18643
|
+
if (event.toolFamily) summary.lastSuccessfulToolCallByFamily[event.toolFamily] = event.timestamp ?? "";
|
|
18644
|
+
}
|
|
18645
|
+
return summary;
|
|
18646
|
+
}
|
|
18647
|
+
var MCP_HTTP_EVENTS_PATH, MCP_MONITOR_DIR, MCP_TRANSPORT_SUMMARY_PATH, DEFAULT_EVENT_READ_BYTES, DEFAULT_EVENT_MAX_BYTES, EVENT_READ_BYTES, EVENT_MAX_BYTES;
|
|
18648
|
+
var init_mcp_transport_health = __esm({
|
|
18649
|
+
"src/lib/mcp-transport-health.ts"() {
|
|
18650
|
+
"use strict";
|
|
18651
|
+
init_config();
|
|
18652
|
+
MCP_HTTP_EVENTS_PATH = path37.join(EXE_AI_DIR, "mcp-http-events.jsonl");
|
|
18653
|
+
MCP_MONITOR_DIR = path37.join(EXE_AI_DIR, "monitor");
|
|
18654
|
+
MCP_TRANSPORT_SUMMARY_PATH = path37.join(MCP_MONITOR_DIR, "mcp-transport-summary.json");
|
|
18655
|
+
DEFAULT_EVENT_READ_BYTES = 256 * 1024;
|
|
18656
|
+
DEFAULT_EVENT_MAX_BYTES = 1024 * 1024;
|
|
18657
|
+
EVENT_READ_BYTES = parsePositiveInt(process.env.EXE_MCP_HTTP_EVENT_READ_BYTES, DEFAULT_EVENT_READ_BYTES);
|
|
18658
|
+
EVENT_MAX_BYTES = parsePositiveInt(process.env.EXE_MCP_HTTP_EVENT_MAX_BYTES, DEFAULT_EVENT_MAX_BYTES);
|
|
18659
|
+
}
|
|
18660
|
+
});
|
|
18661
|
+
|
|
18662
|
+
// src/bin/exe-healthcheck.ts
|
|
18663
|
+
import { existsSync as existsSync31, readFileSync as readFileSync27, readdirSync as readdirSync9 } from "fs";
|
|
18664
|
+
import path38 from "path";
|
|
18665
|
+
import { execSync as execSync14 } from "child_process";
|
|
18666
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
18667
|
+
function findPackageRoot2() {
|
|
18668
|
+
let dir = path38.dirname(fileURLToPath6(import.meta.url));
|
|
18669
|
+
const { root } = path38.parse(dir);
|
|
18670
|
+
while (dir !== root) {
|
|
18671
|
+
if (existsSync31(path38.join(dir, "package.json"))) return dir;
|
|
18672
|
+
dir = path38.dirname(dir);
|
|
18673
|
+
}
|
|
18674
|
+
throw new Error("Cannot find package root");
|
|
18675
|
+
}
|
|
18676
|
+
function checkBuildIntegrity(pkgRoot) {
|
|
18677
|
+
const results = [];
|
|
18678
|
+
const tsupConfig = path38.join(pkgRoot, "tsup.config.ts");
|
|
18679
|
+
if (!existsSync31(tsupConfig)) {
|
|
18680
|
+
return [{ name: "build/tsup-config", pass: false, detail: "tsup.config.ts not found" }];
|
|
18681
|
+
}
|
|
18682
|
+
const configContent = readFileSync27(tsupConfig, "utf-8");
|
|
18683
|
+
const entryMatches = configContent.matchAll(/"([^"]+)":\s*"src\//g);
|
|
18684
|
+
const missing = [];
|
|
18685
|
+
let total = 0;
|
|
18686
|
+
for (const match of entryMatches) {
|
|
18687
|
+
const outputKey = match[1];
|
|
18688
|
+
const expectedPath = path38.join(pkgRoot, "dist", `${outputKey}.js`);
|
|
18689
|
+
total++;
|
|
18690
|
+
if (!existsSync31(expectedPath)) {
|
|
18691
|
+
missing.push(`dist/${outputKey}.js`);
|
|
18692
|
+
}
|
|
18693
|
+
}
|
|
18694
|
+
if (missing.length > 0) {
|
|
18695
|
+
results.push({
|
|
18696
|
+
name: "build/entry-points",
|
|
18697
|
+
pass: false,
|
|
18698
|
+
detail: `${missing.length}/${total} entry points missing:
|
|
18699
|
+
${missing.join("\n ")}`
|
|
18700
|
+
});
|
|
18701
|
+
} else {
|
|
18702
|
+
results.push({
|
|
18703
|
+
name: "build/entry-points",
|
|
18704
|
+
pass: true,
|
|
18705
|
+
detail: `${total} entry points verified`
|
|
18706
|
+
});
|
|
18707
|
+
}
|
|
18708
|
+
return results;
|
|
18709
|
+
}
|
|
18710
|
+
function checkEmbedPipeline(pkgRoot) {
|
|
18711
|
+
const results = [];
|
|
18712
|
+
const daemonPath = path38.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
18713
|
+
if (!existsSync31(daemonPath)) {
|
|
18714
|
+
results.push({
|
|
18715
|
+
name: "exed/daemon-exists",
|
|
18716
|
+
pass: false,
|
|
18717
|
+
detail: `exe-daemon.js not found at ${daemonPath}`
|
|
18718
|
+
});
|
|
18719
|
+
return results;
|
|
18720
|
+
}
|
|
18721
|
+
results.push({ name: "exed/daemon-exists", pass: true, detail: "dist/lib/exe-daemon.js exists" });
|
|
18722
|
+
const entryDirs = ["dist/hooks", "dist/bin", "dist/mcp"];
|
|
18723
|
+
for (const dir of entryDirs) {
|
|
18724
|
+
const fullDir = path38.join(pkgRoot, dir);
|
|
18725
|
+
if (!existsSync31(fullDir)) continue;
|
|
18726
|
+
let walkDir2 = fullDir;
|
|
18727
|
+
const { root } = path38.parse(walkDir2);
|
|
18728
|
+
let foundRoot = null;
|
|
18729
|
+
while (walkDir2 !== root) {
|
|
18730
|
+
if (existsSync31(path38.join(walkDir2, "package.json"))) {
|
|
18731
|
+
foundRoot = walkDir2;
|
|
18732
|
+
break;
|
|
18733
|
+
}
|
|
18734
|
+
walkDir2 = path38.dirname(walkDir2);
|
|
18735
|
+
}
|
|
18736
|
+
if (!foundRoot) {
|
|
18737
|
+
results.push({
|
|
18738
|
+
name: `exed/reachable-from-${dir}`,
|
|
18739
|
+
pass: false,
|
|
18740
|
+
detail: `Cannot find package root from ${dir}`
|
|
18741
|
+
});
|
|
18742
|
+
continue;
|
|
18743
|
+
}
|
|
18744
|
+
const resolvedDaemon = path38.join(foundRoot, "dist", "lib", "exe-daemon.js");
|
|
18745
|
+
const reachable = existsSync31(resolvedDaemon);
|
|
18746
|
+
results.push({
|
|
18747
|
+
name: `exed/reachable-from-${dir}`,
|
|
18748
|
+
pass: reachable,
|
|
18749
|
+
detail: reachable ? `Resolves to ${resolvedDaemon}` : `NOT FOUND: ${resolvedDaemon}`
|
|
18750
|
+
});
|
|
18751
|
+
}
|
|
18752
|
+
return results;
|
|
18753
|
+
}
|
|
18754
|
+
function checkTaskSystem(pkgRoot) {
|
|
18755
|
+
const results = [];
|
|
18756
|
+
const scannerPath = path38.join(pkgRoot, "dist", "bin", "scan-tasks.js");
|
|
18757
|
+
if (!existsSync31(scannerPath)) {
|
|
18758
|
+
results.push({ name: "tasks/scanner", pass: false, detail: "scan-tasks.js not found" });
|
|
18759
|
+
return results;
|
|
18760
|
+
}
|
|
18761
|
+
try {
|
|
18762
|
+
execSync14(`node "${scannerPath}" /tmp/nonexistent-healthcheck-test --format=json 2>/dev/null`, {
|
|
18763
|
+
timeout: 1e4,
|
|
18764
|
+
encoding: "utf-8"
|
|
18765
|
+
});
|
|
18766
|
+
results.push({ name: "tasks/scanner", pass: true, detail: "scan-tasks.js runs without import errors" });
|
|
18767
|
+
} catch (err) {
|
|
18768
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
18769
|
+
if (msg.includes("Cannot find module") || msg.includes("ERR_MODULE_NOT_FOUND") || msg.includes("SyntaxError")) {
|
|
18770
|
+
results.push({ name: "tasks/scanner", pass: false, detail: `Import error: ${msg.slice(0, 200)}` });
|
|
18771
|
+
} else {
|
|
18772
|
+
results.push({ name: "tasks/scanner", pass: true, detail: "scan-tasks.js runs (no import errors)" });
|
|
18773
|
+
}
|
|
18774
|
+
}
|
|
18775
|
+
return results;
|
|
18776
|
+
}
|
|
18777
|
+
function checkWorkerSpawning(pkgRoot) {
|
|
18778
|
+
const results = [];
|
|
18779
|
+
const workerPath = path38.join(pkgRoot, "dist", "hooks", "ingest-worker.js");
|
|
18780
|
+
if (!existsSync31(workerPath)) {
|
|
18781
|
+
results.push({ name: "workers/ingest-worker", pass: false, detail: "ingest-worker.js not found" });
|
|
18782
|
+
return results;
|
|
18783
|
+
}
|
|
18784
|
+
try {
|
|
18785
|
+
execSync14(`node --check "${workerPath}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
|
|
18786
|
+
results.push({ name: "workers/ingest-worker", pass: true, detail: "ingest-worker.js parses OK" });
|
|
18787
|
+
} catch (err) {
|
|
18788
|
+
results.push({
|
|
18789
|
+
name: "workers/ingest-worker",
|
|
18790
|
+
pass: false,
|
|
18791
|
+
detail: `Parse error: ${err instanceof Error ? err.message.slice(0, 200) : String(err)}`
|
|
18792
|
+
});
|
|
18793
|
+
}
|
|
18794
|
+
const hooksDir = path38.join(pkgRoot, "dist", "hooks");
|
|
18795
|
+
if (existsSync31(hooksDir)) {
|
|
18796
|
+
const hookFiles = readdirSync9(hooksDir).filter((f) => f.endsWith(".js") && !f.endsWith(".js.map"));
|
|
18797
|
+
let hooksPassed = 0;
|
|
18798
|
+
const hooksFailed = [];
|
|
18799
|
+
for (const hook of hookFiles) {
|
|
18800
|
+
try {
|
|
18801
|
+
execSync14(`node --check "${path38.join(hooksDir, hook)}" 2>&1`, { timeout: 1e4, encoding: "utf-8" });
|
|
18802
|
+
hooksPassed++;
|
|
18803
|
+
} catch {
|
|
18804
|
+
hooksFailed.push(hook);
|
|
18805
|
+
}
|
|
18806
|
+
}
|
|
18807
|
+
if (hooksFailed.length > 0) {
|
|
18808
|
+
results.push({
|
|
18809
|
+
name: "workers/hooks-parse",
|
|
18810
|
+
pass: false,
|
|
18811
|
+
detail: `${hooksFailed.length}/${hookFiles.length} hooks fail to parse: ${hooksFailed.join(", ")}`
|
|
18812
|
+
});
|
|
18813
|
+
} else {
|
|
18814
|
+
results.push({
|
|
18815
|
+
name: "workers/hooks-parse",
|
|
18816
|
+
pass: true,
|
|
18817
|
+
detail: `${hooksPassed} hook entry points parse OK`
|
|
18818
|
+
});
|
|
18819
|
+
}
|
|
18820
|
+
}
|
|
18821
|
+
return results;
|
|
18822
|
+
}
|
|
18823
|
+
function checkMcpTransport() {
|
|
18824
|
+
const results = [];
|
|
18825
|
+
const pidPath = path38.join(EXE_AI_DIR, "exed.pid");
|
|
18826
|
+
const tokenPath = path38.join(EXE_AI_DIR, "exed.token");
|
|
18827
|
+
let daemonAlive = false;
|
|
18828
|
+
if (existsSync31(pidPath)) {
|
|
18829
|
+
try {
|
|
18830
|
+
const pid = parseInt(readFileSync27(pidPath, "utf8").trim(), 10);
|
|
18831
|
+
process.kill(pid, 0);
|
|
18832
|
+
daemonAlive = true;
|
|
18833
|
+
results.push({ name: "mcp/daemon-process", pass: true, detail: `exed process alive (pid ${pid})` });
|
|
18834
|
+
} catch {
|
|
18835
|
+
results.push({ name: "mcp/daemon-process", pass: false, detail: "exed.pid exists but process is not alive; restart exe-os/exed" });
|
|
18836
|
+
}
|
|
18837
|
+
} else {
|
|
18838
|
+
results.push({ name: "mcp/daemon-process", pass: false, detail: "No exed.pid found; daemon is not running" });
|
|
18839
|
+
}
|
|
18840
|
+
if (daemonAlive && existsSync31(tokenPath)) {
|
|
18841
|
+
try {
|
|
18842
|
+
const token = readFileSync27(tokenPath, "utf8").trim();
|
|
18843
|
+
const response = execSync14(
|
|
18844
|
+
`curl -sS -i -m 2 -H "Authorization: Bearer ${token}" -H 'Accept: application/json, text/event-stream' http://127.0.0.1:48739/mcp`,
|
|
18845
|
+
{ encoding: "utf8", timeout: 3e3 }
|
|
18846
|
+
);
|
|
18847
|
+
const jsonRpcError = response.includes("Content-Type: application/json") && response.includes("missing MCP session");
|
|
18848
|
+
results.push({
|
|
18849
|
+
name: "mcp/http-endpoint",
|
|
18850
|
+
pass: jsonRpcError,
|
|
18851
|
+
detail: jsonRpcError ? "MCP HTTP endpoint reachable; missing-session probe returns JSON-RPC (expected)" : "MCP HTTP endpoint reachable but did not return expected JSON-RPC missing-session response"
|
|
18852
|
+
});
|
|
18853
|
+
} catch (err) {
|
|
18854
|
+
results.push({
|
|
18855
|
+
name: "mcp/http-endpoint",
|
|
18856
|
+
pass: false,
|
|
18857
|
+
detail: `MCP HTTP endpoint not reachable: ${err instanceof Error ? err.message.slice(0, 180) : String(err)}`
|
|
18858
|
+
});
|
|
18859
|
+
}
|
|
18860
|
+
} else if (daemonAlive) {
|
|
18861
|
+
results.push({ name: "mcp/http-endpoint", pass: false, detail: "Daemon is alive but exed.token is missing; cannot probe MCP HTTP" });
|
|
18862
|
+
}
|
|
18863
|
+
const events = readMcpHttpEvents(200);
|
|
18864
|
+
const summary = summarizeMcpTransport(events);
|
|
18865
|
+
results.push({
|
|
18866
|
+
name: "mcp/local-event-log",
|
|
18867
|
+
pass: true,
|
|
18868
|
+
detail: `${events.length} recent event(s); activeSessions=${summary.activeSessions ?? "unknown"}; lastHandshake=${summary.lastSuccessfulHandshake ?? "none"}; lastTool=${summary.lastSuccessfulToolCall ?? "none"}`
|
|
18869
|
+
});
|
|
18870
|
+
results.push({
|
|
18871
|
+
name: "mcp/monitor-summary",
|
|
18872
|
+
pass: true,
|
|
18873
|
+
detail: `Privacy-safe local monitor summary: ${path38.join(EXE_AI_DIR, "monitor", "mcp-transport-summary.json")}`
|
|
18874
|
+
});
|
|
18875
|
+
return results;
|
|
18876
|
+
}
|
|
18877
|
+
function checkClaudeCodeInstall() {
|
|
18878
|
+
const results = [];
|
|
18879
|
+
const execPath = process.env.CLAUDE_CODE_EXECPATH ?? "";
|
|
18880
|
+
if (execPath.length > 0 && (execPath.includes("claude/versions/") || execPath.includes("claude.exe") || execPath.includes("claude-native"))) {
|
|
18881
|
+
results.push({
|
|
18882
|
+
name: "cc/execpath-clean",
|
|
18883
|
+
pass: false,
|
|
18884
|
+
detail: `CLAUDE_CODE_EXECPATH points to native binary: "${execPath}" \u2014 20K phantom billing risk. Unset it: unset CLAUDE_CODE_EXECPATH`
|
|
18885
|
+
});
|
|
18886
|
+
} else {
|
|
18887
|
+
results.push({
|
|
18888
|
+
name: "cc/execpath-clean",
|
|
18889
|
+
pass: true,
|
|
18890
|
+
detail: execPath ? `CLAUDE_CODE_EXECPATH=${execPath} (node runtime, OK)` : "CLAUDE_CODE_EXECPATH is unset"
|
|
18891
|
+
});
|
|
18892
|
+
}
|
|
18893
|
+
try {
|
|
18894
|
+
const claudePath = execSync14("which claude 2>/dev/null || true", { encoding: "utf8", timeout: 5e3 }).trim();
|
|
18895
|
+
if (!claudePath) {
|
|
18896
|
+
results.push({
|
|
18897
|
+
name: "cc/cli-binary",
|
|
18898
|
+
pass: false,
|
|
18899
|
+
detail: "claude not found in PATH"
|
|
18900
|
+
});
|
|
18901
|
+
} else {
|
|
18902
|
+
let resolved = claudePath;
|
|
18903
|
+
try {
|
|
18904
|
+
resolved = execSync14(`readlink -f "${claudePath}" 2>/dev/null || readlink "${claudePath}" 2>/dev/null || echo "${claudePath}"`, {
|
|
18905
|
+
encoding: "utf8",
|
|
18906
|
+
timeout: 5e3
|
|
18907
|
+
}).trim();
|
|
18908
|
+
} catch {
|
|
18909
|
+
}
|
|
18910
|
+
if (resolved.includes("bin/claude.exe") || resolved.includes("bin/claude-native")) {
|
|
18911
|
+
results.push({
|
|
18912
|
+
name: "cc/cli-binary",
|
|
18913
|
+
pass: false,
|
|
18914
|
+
detail: `claude resolves to native binary: ${resolved}. Should be cli.js. Run: npm install -g @anthropic-ai/claude-code@2.1.98`
|
|
18915
|
+
});
|
|
18916
|
+
} else {
|
|
18917
|
+
results.push({
|
|
18918
|
+
name: "cc/cli-binary",
|
|
18919
|
+
pass: true,
|
|
18920
|
+
detail: `claude resolves to: ${resolved}`
|
|
18921
|
+
});
|
|
18922
|
+
}
|
|
18923
|
+
}
|
|
18924
|
+
} catch {
|
|
18925
|
+
results.push({
|
|
18926
|
+
name: "cc/cli-binary",
|
|
18927
|
+
pass: false,
|
|
18928
|
+
detail: "Failed to check claude binary path"
|
|
18929
|
+
});
|
|
18930
|
+
}
|
|
18931
|
+
const versionsDir = path38.join(
|
|
18932
|
+
process.env.HOME ?? process.env.USERPROFILE ?? "",
|
|
18933
|
+
".local",
|
|
18934
|
+
"share",
|
|
18935
|
+
"claude",
|
|
18936
|
+
"versions"
|
|
18937
|
+
);
|
|
18938
|
+
if (existsSync31(versionsDir)) {
|
|
18939
|
+
try {
|
|
18940
|
+
const entries = readdirSync9(versionsDir);
|
|
18941
|
+
if (entries.length > 0) {
|
|
18942
|
+
results.push({
|
|
18943
|
+
name: "cc/native-cache-clean",
|
|
18944
|
+
pass: false,
|
|
18945
|
+
detail: `${entries.length} cached native version(s) found in ${versionsDir}: ${entries.slice(0, 3).join(", ")}${entries.length > 3 ? "..." : ""}. Remove: rm -rf "${versionsDir}"`
|
|
18946
|
+
});
|
|
18947
|
+
} else {
|
|
18948
|
+
results.push({
|
|
18949
|
+
name: "cc/native-cache-clean",
|
|
18950
|
+
pass: true,
|
|
18951
|
+
detail: `${versionsDir} is empty`
|
|
18952
|
+
});
|
|
18953
|
+
}
|
|
18954
|
+
} catch {
|
|
18955
|
+
results.push({
|
|
18956
|
+
name: "cc/native-cache-clean",
|
|
18957
|
+
pass: true,
|
|
18958
|
+
detail: `${versionsDir} not readable (OK)`
|
|
18959
|
+
});
|
|
18960
|
+
}
|
|
18961
|
+
} else {
|
|
18962
|
+
results.push({
|
|
18963
|
+
name: "cc/native-cache-clean",
|
|
18964
|
+
pass: true,
|
|
18965
|
+
detail: `${versionsDir} does not exist`
|
|
18966
|
+
});
|
|
18967
|
+
}
|
|
18968
|
+
const disableOld = process.env.DISABLE_AUTOUPDATER === "1";
|
|
18969
|
+
const disableNew = process.env.CLAUDE_CODE_AUTOUPDATER_DISABLED === "1";
|
|
18970
|
+
if (!disableOld && !disableNew) {
|
|
18971
|
+
results.push({
|
|
18972
|
+
name: "cc/autoupdater-disabled",
|
|
18973
|
+
pass: false,
|
|
18974
|
+
detail: "Neither DISABLE_AUTOUPDATER=1 nor CLAUDE_CODE_AUTOUPDATER_DISABLED=1 is set. Auto-updater may install infected native binary. Export both in your shell profile."
|
|
18975
|
+
});
|
|
18976
|
+
} else {
|
|
18977
|
+
const which = [
|
|
18978
|
+
disableOld ? "DISABLE_AUTOUPDATER=1" : null,
|
|
18979
|
+
disableNew ? "CLAUDE_CODE_AUTOUPDATER_DISABLED=1" : null
|
|
18980
|
+
].filter(Boolean).join(" + ");
|
|
18981
|
+
results.push({
|
|
18982
|
+
name: "cc/autoupdater-disabled",
|
|
18983
|
+
pass: true,
|
|
18984
|
+
detail: `Auto-updater disabled via ${which}`
|
|
18985
|
+
});
|
|
18986
|
+
}
|
|
18987
|
+
try {
|
|
18988
|
+
const ccVersion = execSync14("claude --version 2>/dev/null || echo unknown", {
|
|
18989
|
+
encoding: "utf8",
|
|
18990
|
+
timeout: 5e3
|
|
18991
|
+
}).trim();
|
|
18992
|
+
const versionMatch = ccVersion.match(/(\d+\.\d+\.\d+)/);
|
|
18993
|
+
if (versionMatch) {
|
|
18994
|
+
const ver = versionMatch[1];
|
|
18995
|
+
const [, minor] = ver.split(".").map(Number);
|
|
18996
|
+
const isRisky = minor !== void 0 && minor >= 1 && parseInt(ver.split(".")[2] ?? "0") >= 119;
|
|
18997
|
+
results.push({
|
|
18998
|
+
name: "cc/version",
|
|
18999
|
+
pass: !isRisky,
|
|
19000
|
+
detail: isRisky ? `CC version ${ver} \u2014 \u22652.1.119 ships native binary only. Pin: npm install -g @anthropic-ai/claude-code@2.1.98` : `CC version ${ver}`
|
|
19001
|
+
});
|
|
19002
|
+
}
|
|
19003
|
+
} catch {
|
|
19004
|
+
}
|
|
19005
|
+
return results;
|
|
19006
|
+
}
|
|
19007
|
+
function runHealthCheck() {
|
|
19008
|
+
const pkgRoot = findPackageRoot2();
|
|
19009
|
+
const results = [
|
|
19010
|
+
...checkBuildIntegrity(pkgRoot),
|
|
19011
|
+
...checkEmbedPipeline(pkgRoot),
|
|
19012
|
+
...checkTaskSystem(pkgRoot),
|
|
19013
|
+
...checkWorkerSpawning(pkgRoot),
|
|
19014
|
+
...checkMcpTransport(),
|
|
19015
|
+
...checkClaudeCodeInstall()
|
|
19016
|
+
];
|
|
19017
|
+
const passed = results.filter((r) => r.pass).length;
|
|
19018
|
+
const failed = results.filter((r) => !r.pass).length;
|
|
19019
|
+
return { results, passed, failed };
|
|
19020
|
+
}
|
|
19021
|
+
var init_exe_healthcheck = __esm({
|
|
19022
|
+
"src/bin/exe-healthcheck.ts"() {
|
|
19023
|
+
"use strict";
|
|
19024
|
+
init_is_main();
|
|
19025
|
+
init_config();
|
|
19026
|
+
init_mcp_transport_health();
|
|
19027
|
+
if (isMainModule(import.meta.url) && (process.argv[1] ?? "").includes("exe-healthcheck")) {
|
|
19028
|
+
const { results, passed, failed } = runHealthCheck();
|
|
19029
|
+
console.log("\n exe-os Health Check\n");
|
|
19030
|
+
for (const r of results) {
|
|
19031
|
+
const icon = r.pass ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
|
|
19032
|
+
console.log(` ${icon} ${r.name}`);
|
|
19033
|
+
console.log(` ${r.detail}`);
|
|
19034
|
+
}
|
|
19035
|
+
console.log(`
|
|
19036
|
+
${passed} passed, ${failed} failed
|
|
19037
|
+
`);
|
|
19038
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
19039
|
+
}
|
|
19040
|
+
}
|
|
19041
|
+
});
|
|
19042
|
+
|
|
19043
|
+
// src/bin/cc-doctor.ts
|
|
19044
|
+
var cc_doctor_exports = {};
|
|
19045
|
+
__export(cc_doctor_exports, {
|
|
19046
|
+
runCcDoctor: () => runCcDoctor
|
|
19047
|
+
});
|
|
19048
|
+
function formatResult(r) {
|
|
19049
|
+
const icon = r.pass ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
|
|
19050
|
+
const label = LABELS[r.name] ?? r.name;
|
|
19051
|
+
return `${icon} ${label}: ${r.detail}`;
|
|
19052
|
+
}
|
|
19053
|
+
function runCcDoctor() {
|
|
19054
|
+
const results = checkClaudeCodeInstall();
|
|
19055
|
+
const passed = results.filter((r) => r.pass).length;
|
|
19056
|
+
const failed = results.filter((r) => !r.pass).length;
|
|
19057
|
+
return { results, passed, failed };
|
|
19058
|
+
}
|
|
19059
|
+
var LABELS;
|
|
19060
|
+
var init_cc_doctor = __esm({
|
|
19061
|
+
"src/bin/cc-doctor.ts"() {
|
|
19062
|
+
"use strict";
|
|
19063
|
+
init_exe_healthcheck();
|
|
19064
|
+
init_is_main();
|
|
19065
|
+
LABELS = {
|
|
19066
|
+
"cc/execpath-clean": "EXECPATH",
|
|
19067
|
+
"cc/cli-binary": "Symlink",
|
|
19068
|
+
"cc/native-cache-clean": "Native cache",
|
|
19069
|
+
"cc/autoupdater-disabled": "Auto-updater",
|
|
19070
|
+
"cc/version": "Version"
|
|
19071
|
+
};
|
|
19072
|
+
if (isMainModule(import.meta.url) && (process.argv[1] ?? "").includes("cc-doctor")) {
|
|
19073
|
+
const { results, passed, failed } = runCcDoctor();
|
|
19074
|
+
console.log("\n CC Install Health Check\n");
|
|
19075
|
+
for (const r of results) {
|
|
19076
|
+
console.log(` ${formatResult(r)}`);
|
|
19077
|
+
}
|
|
19078
|
+
if (failed === 0) {
|
|
19079
|
+
console.log(`
|
|
19080
|
+
\x1B[32mStatus: CLEAN\x1B[0m \u2014 no 20K billing risk (${passed} checks passed)
|
|
19081
|
+
`);
|
|
19082
|
+
} else {
|
|
19083
|
+
console.log(`
|
|
19084
|
+
\x1B[31mStatus: ${failed} ISSUE${failed > 1 ? "S" : ""} FOUND\x1B[0m \u2014 ${passed} passed, ${failed} failed`);
|
|
19085
|
+
console.log(" Fix: npm install -g @anthropic-ai/claude-code@2.1.98\n");
|
|
19086
|
+
}
|
|
19087
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
19088
|
+
}
|
|
19089
|
+
}
|
|
19090
|
+
});
|
|
19091
|
+
|
|
18015
19092
|
// src/lib/model-downloader.ts
|
|
18016
|
-
import { createWriteStream, createReadStream as createReadStream2, existsSync as
|
|
19093
|
+
import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync32, unlinkSync as unlinkSync14, renameSync as renameSync7 } from "fs";
|
|
18017
19094
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
18018
19095
|
import { createHash as createHash6 } from "crypto";
|
|
18019
|
-
import
|
|
19096
|
+
import path39 from "path";
|
|
18020
19097
|
async function downloadModel(opts) {
|
|
18021
19098
|
const { destDir, onProgress, fetchFn = globalThis.fetch } = opts;
|
|
18022
|
-
const destPath =
|
|
19099
|
+
const destPath = path39.join(destDir, LOCAL_FILENAME);
|
|
18023
19100
|
const tmpPath = destPath + ".tmp";
|
|
18024
19101
|
await mkdir6(destDir, { recursive: true });
|
|
18025
|
-
if (
|
|
19102
|
+
if (existsSync32(destPath)) {
|
|
18026
19103
|
const hash = await fileHash(destPath);
|
|
18027
19104
|
if (hash === EXPECTED_SHA256) {
|
|
18028
19105
|
return destPath;
|
|
@@ -18034,7 +19111,7 @@ async function downloadModel(opts) {
|
|
|
18034
19111
|
let downloaded = 0;
|
|
18035
19112
|
for (let attempt = 1; attempt <= MAX_RETRIES4; attempt++) {
|
|
18036
19113
|
try {
|
|
18037
|
-
if (
|
|
19114
|
+
if (existsSync32(tmpPath)) unlinkSync14(tmpPath);
|
|
18038
19115
|
const response = await fetchFn(GGUF_URL, {
|
|
18039
19116
|
redirect: "follow",
|
|
18040
19117
|
signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
|
|
@@ -18079,7 +19156,7 @@ async function downloadModel(opts) {
|
|
|
18079
19156
|
process.stderr.write(`
|
|
18080
19157
|
Download attempt ${attempt} failed, retrying...
|
|
18081
19158
|
`);
|
|
18082
|
-
if (
|
|
19159
|
+
if (existsSync32(tmpPath)) unlinkSync14(tmpPath);
|
|
18083
19160
|
}
|
|
18084
19161
|
}
|
|
18085
19162
|
}
|
|
@@ -18656,38 +19733,38 @@ __export(session_wrappers_exports, {
|
|
|
18656
19733
|
generateSessionWrappers: () => generateSessionWrappers
|
|
18657
19734
|
});
|
|
18658
19735
|
import {
|
|
18659
|
-
existsSync as
|
|
18660
|
-
readFileSync as
|
|
18661
|
-
writeFileSync as
|
|
18662
|
-
mkdirSync as
|
|
19736
|
+
existsSync as existsSync33,
|
|
19737
|
+
readFileSync as readFileSync28,
|
|
19738
|
+
writeFileSync as writeFileSync24,
|
|
19739
|
+
mkdirSync as mkdirSync23,
|
|
18663
19740
|
chmodSync as chmodSync4,
|
|
18664
|
-
readdirSync as
|
|
19741
|
+
readdirSync as readdirSync10,
|
|
18665
19742
|
unlinkSync as unlinkSync15
|
|
18666
19743
|
} from "fs";
|
|
18667
|
-
import { execSync as
|
|
18668
|
-
import
|
|
19744
|
+
import { execSync as execSync15 } from "child_process";
|
|
19745
|
+
import path40 from "path";
|
|
18669
19746
|
import { homedir as homedir5 } from "os";
|
|
18670
19747
|
function generateSessionWrappers(packageRoot, homeDir) {
|
|
18671
19748
|
const home = homeDir ?? homedir5();
|
|
18672
|
-
const binDir =
|
|
18673
|
-
const rosterPath =
|
|
19749
|
+
const binDir = path40.join(home, ".exe-os", "bin");
|
|
19750
|
+
const rosterPath = path40.join(home, ".exe-os", "exe-employees.json");
|
|
18674
19751
|
const shouldMirrorToGlobalBin = homeDir === void 0;
|
|
18675
|
-
|
|
18676
|
-
const exeStartDst =
|
|
19752
|
+
mkdirSync23(binDir, { recursive: true });
|
|
19753
|
+
const exeStartDst = path40.join(binDir, "exe-start");
|
|
18677
19754
|
const candidates = [
|
|
18678
|
-
|
|
18679
|
-
|
|
19755
|
+
path40.join(packageRoot, "dist", "bin", "exe-start.sh"),
|
|
19756
|
+
path40.join(packageRoot, "src", "bin", "exe-start.sh")
|
|
18680
19757
|
];
|
|
18681
19758
|
for (const src of candidates) {
|
|
18682
|
-
if (
|
|
18683
|
-
|
|
19759
|
+
if (existsSync33(src)) {
|
|
19760
|
+
writeFileSync24(exeStartDst, readFileSync28(src));
|
|
18684
19761
|
chmodSync4(exeStartDst, 493);
|
|
18685
19762
|
break;
|
|
18686
19763
|
}
|
|
18687
19764
|
}
|
|
18688
19765
|
let employees = [];
|
|
18689
19766
|
try {
|
|
18690
|
-
employees = JSON.parse(
|
|
19767
|
+
employees = JSON.parse(readFileSync28(rosterPath, "utf8"));
|
|
18691
19768
|
} catch {
|
|
18692
19769
|
return { created: 0, pathConfigured: false };
|
|
18693
19770
|
}
|
|
@@ -18695,11 +19772,11 @@ function generateSessionWrappers(packageRoot, homeDir) {
|
|
|
18695
19772
|
return { created: 0, pathConfigured: false };
|
|
18696
19773
|
}
|
|
18697
19774
|
try {
|
|
18698
|
-
for (const f of
|
|
19775
|
+
for (const f of readdirSync10(binDir)) {
|
|
18699
19776
|
if (f === "exe-start") continue;
|
|
18700
|
-
const fPath =
|
|
19777
|
+
const fPath = path40.join(binDir, f);
|
|
18701
19778
|
try {
|
|
18702
|
-
const content =
|
|
19779
|
+
const content = readFileSync28(fPath, "utf8");
|
|
18703
19780
|
if (content.includes("exe-start")) {
|
|
18704
19781
|
unlinkSync15(fPath);
|
|
18705
19782
|
}
|
|
@@ -18715,36 +19792,36 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
18715
19792
|
const globalBinDir = shouldMirrorToGlobalBin ? resolveGlobalBinDir() : null;
|
|
18716
19793
|
for (const emp of employees) {
|
|
18717
19794
|
for (let n = 1; n <= MAX_N; n++) {
|
|
18718
|
-
writeWrapper(
|
|
19795
|
+
writeWrapper(path40.join(binDir, `${emp.name}${n}`), wrapperContent);
|
|
18719
19796
|
if (globalBinDir) {
|
|
18720
|
-
writeWrapper(
|
|
19797
|
+
writeWrapper(path40.join(globalBinDir, `${emp.name}${n}`), wrapperContent);
|
|
18721
19798
|
}
|
|
18722
19799
|
created++;
|
|
18723
|
-
writeWrapper(
|
|
19800
|
+
writeWrapper(path40.join(binDir, `${emp.name}${n}-codex`), wrapperContent);
|
|
18724
19801
|
if (globalBinDir) {
|
|
18725
|
-
writeWrapper(
|
|
19802
|
+
writeWrapper(path40.join(globalBinDir, `${emp.name}${n}-codex`), wrapperContent);
|
|
18726
19803
|
}
|
|
18727
19804
|
created++;
|
|
18728
19805
|
}
|
|
18729
19806
|
}
|
|
18730
19807
|
const codexLauncherCandidates = [
|
|
18731
|
-
|
|
18732
|
-
|
|
19808
|
+
path40.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
|
|
19809
|
+
path40.join(packageRoot, "src", "bin", "exe-start-codex.ts")
|
|
18733
19810
|
];
|
|
18734
19811
|
let codexLauncher = null;
|
|
18735
19812
|
for (const c of codexLauncherCandidates) {
|
|
18736
|
-
if (
|
|
19813
|
+
if (existsSync33(c)) {
|
|
18737
19814
|
codexLauncher = c;
|
|
18738
19815
|
break;
|
|
18739
19816
|
}
|
|
18740
19817
|
}
|
|
18741
19818
|
if (codexLauncher) {
|
|
18742
19819
|
for (const emp of employees) {
|
|
18743
|
-
const wrapperPath =
|
|
19820
|
+
const wrapperPath = path40.join(binDir, `${emp.name}-codex`);
|
|
18744
19821
|
const content = `#!/bin/bash
|
|
18745
19822
|
exec node "${codexLauncher}" --agent ${emp.name} "$@"
|
|
18746
19823
|
`;
|
|
18747
|
-
|
|
19824
|
+
writeFileSync24(wrapperPath, content);
|
|
18748
19825
|
chmodSync4(wrapperPath, 493);
|
|
18749
19826
|
created++;
|
|
18750
19827
|
}
|
|
@@ -18754,20 +19831,20 @@ exec node "${codexLauncher}" --agent ${emp.name} "$@"
|
|
|
18754
19831
|
}
|
|
18755
19832
|
function writeWrapper(wrapperPath, content) {
|
|
18756
19833
|
try {
|
|
18757
|
-
|
|
19834
|
+
writeFileSync24(wrapperPath, content);
|
|
18758
19835
|
chmodSync4(wrapperPath, 493);
|
|
18759
19836
|
} catch {
|
|
18760
19837
|
}
|
|
18761
19838
|
}
|
|
18762
19839
|
function resolveGlobalBinDir() {
|
|
18763
19840
|
try {
|
|
18764
|
-
const exeOsPath =
|
|
18765
|
-
if (exeOsPath) return
|
|
19841
|
+
const exeOsPath = execSync15("command -v exe-os", { encoding: "utf8", timeout: 3e3 }).trim().split("\n")[0];
|
|
19842
|
+
if (exeOsPath) return path40.dirname(exeOsPath);
|
|
18766
19843
|
} catch {
|
|
18767
19844
|
}
|
|
18768
19845
|
try {
|
|
18769
|
-
const prefix =
|
|
18770
|
-
if (prefix) return
|
|
19846
|
+
const prefix = execSync15("npm prefix -g", { encoding: "utf8", timeout: 3e3 }).trim();
|
|
19847
|
+
if (prefix) return path40.join(prefix, "bin");
|
|
18771
19848
|
} catch {
|
|
18772
19849
|
}
|
|
18773
19850
|
return null;
|
|
@@ -18783,24 +19860,24 @@ export PATH="${binDir}:$PATH"
|
|
|
18783
19860
|
const shell = process.env.SHELL ?? "/bin/bash";
|
|
18784
19861
|
const profilePaths = [];
|
|
18785
19862
|
if (shell.includes("zsh")) {
|
|
18786
|
-
profilePaths.push(
|
|
19863
|
+
profilePaths.push(path40.join(home, ".zshrc"));
|
|
18787
19864
|
} else if (shell.includes("bash")) {
|
|
18788
|
-
profilePaths.push(
|
|
18789
|
-
profilePaths.push(
|
|
19865
|
+
profilePaths.push(path40.join(home, ".bashrc"));
|
|
19866
|
+
profilePaths.push(path40.join(home, ".bash_profile"));
|
|
18790
19867
|
} else {
|
|
18791
|
-
profilePaths.push(
|
|
19868
|
+
profilePaths.push(path40.join(home, ".profile"));
|
|
18792
19869
|
}
|
|
18793
19870
|
for (const profilePath of profilePaths) {
|
|
18794
19871
|
try {
|
|
18795
19872
|
let content = "";
|
|
18796
19873
|
try {
|
|
18797
|
-
content =
|
|
19874
|
+
content = readFileSync28(profilePath, "utf8");
|
|
18798
19875
|
} catch {
|
|
18799
19876
|
}
|
|
18800
19877
|
if (content.includes(".exe-os/bin")) {
|
|
18801
19878
|
return false;
|
|
18802
19879
|
}
|
|
18803
|
-
|
|
19880
|
+
writeFileSync24(profilePath, content + exportLine);
|
|
18804
19881
|
return true;
|
|
18805
19882
|
} catch {
|
|
18806
19883
|
continue;
|
|
@@ -18823,36 +19900,36 @@ __export(setup_wizard_exports, {
|
|
|
18823
19900
|
validateModel: () => validateModel
|
|
18824
19901
|
});
|
|
18825
19902
|
import crypto13 from "crypto";
|
|
18826
|
-
import { existsSync as
|
|
19903
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync24, readFileSync as readFileSync29, writeFileSync as writeFileSync25, unlinkSync as unlinkSync16 } from "fs";
|
|
18827
19904
|
import os19 from "os";
|
|
18828
|
-
import
|
|
19905
|
+
import path41 from "path";
|
|
18829
19906
|
import { createInterface as createInterface4 } from "readline";
|
|
18830
|
-
function
|
|
18831
|
-
let dir =
|
|
18832
|
-
const root =
|
|
19907
|
+
function findPackageRoot3() {
|
|
19908
|
+
let dir = path41.dirname(new URL(import.meta.url).pathname);
|
|
19909
|
+
const root = path41.parse(dir).root;
|
|
18833
19910
|
while (dir !== root) {
|
|
18834
|
-
const pkgPath =
|
|
18835
|
-
if (
|
|
19911
|
+
const pkgPath = path41.join(dir, "package.json");
|
|
19912
|
+
if (existsSync34(pkgPath)) {
|
|
18836
19913
|
try {
|
|
18837
|
-
const pkg = JSON.parse(
|
|
19914
|
+
const pkg = JSON.parse(readFileSync29(pkgPath, "utf-8"));
|
|
18838
19915
|
if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
|
|
18839
19916
|
} catch {
|
|
18840
19917
|
}
|
|
18841
19918
|
}
|
|
18842
|
-
dir =
|
|
19919
|
+
dir = path41.dirname(dir);
|
|
18843
19920
|
}
|
|
18844
19921
|
return null;
|
|
18845
19922
|
}
|
|
18846
19923
|
function loadSetupState() {
|
|
18847
19924
|
try {
|
|
18848
|
-
return JSON.parse(
|
|
19925
|
+
return JSON.parse(readFileSync29(SETUP_STATE_PATH, "utf8"));
|
|
18849
19926
|
} catch {
|
|
18850
19927
|
return { completedSteps: [], startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
18851
19928
|
}
|
|
18852
19929
|
}
|
|
18853
19930
|
function saveSetupState(state) {
|
|
18854
|
-
|
|
18855
|
-
|
|
19931
|
+
mkdirSync24(path41.dirname(SETUP_STATE_PATH), { recursive: true });
|
|
19932
|
+
writeFileSync25(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
|
|
18856
19933
|
}
|
|
18857
19934
|
function clearSetupState() {
|
|
18858
19935
|
try {
|
|
@@ -18873,8 +19950,8 @@ function ask3(rl, prompt) {
|
|
|
18873
19950
|
function getAvailableMemoryGB2() {
|
|
18874
19951
|
if (process.platform === "darwin") {
|
|
18875
19952
|
try {
|
|
18876
|
-
const { execSync:
|
|
18877
|
-
const vmstat =
|
|
19953
|
+
const { execSync: execSync20 } = __require("child_process");
|
|
19954
|
+
const vmstat = execSync20("vm_stat", { encoding: "utf8" });
|
|
18878
19955
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
18879
19956
|
const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : 16384;
|
|
18880
19957
|
const free = vmstat.match(/Pages free:\s+(\d+)/);
|
|
@@ -18902,10 +19979,10 @@ async function validateModel(log) {
|
|
|
18902
19979
|
if (totalGB <= 8 || isLowMemory()) {
|
|
18903
19980
|
log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
|
|
18904
19981
|
log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
|
|
18905
|
-
const modelPath =
|
|
18906
|
-
if (
|
|
18907
|
-
const { statSync:
|
|
18908
|
-
const size =
|
|
19982
|
+
const modelPath = path41.join(MODELS_DIR, LOCAL_FILENAME);
|
|
19983
|
+
if (existsSync34(modelPath)) {
|
|
19984
|
+
const { statSync: statSync9 } = await import("fs");
|
|
19985
|
+
const size = statSync9(modelPath).size;
|
|
18909
19986
|
if (size > 300 * 1e6) {
|
|
18910
19987
|
log(`Model file verified (${(size / 1e6).toFixed(0)} MB).`);
|
|
18911
19988
|
return;
|
|
@@ -18998,7 +20075,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
18998
20075
|
if (state.completedSteps.length > 0) {
|
|
18999
20076
|
log(`Resuming setup from step ${Math.max(...state.completedSteps) + 1}...`);
|
|
19000
20077
|
}
|
|
19001
|
-
if (
|
|
20078
|
+
if (existsSync34(LEGACY_LANCE_PATH)) {
|
|
19002
20079
|
log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
|
|
19003
20080
|
log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
|
|
19004
20081
|
log(" The old directory will not be modified or deleted.");
|
|
@@ -19189,10 +20266,10 @@ async function runSetupWizard(opts = {}) {
|
|
|
19189
20266
|
await saveConfig(config);
|
|
19190
20267
|
log("");
|
|
19191
20268
|
try {
|
|
19192
|
-
const claudeJsonPath =
|
|
20269
|
+
const claudeJsonPath = path41.join(os19.homedir(), ".claude.json");
|
|
19193
20270
|
let claudeJson = {};
|
|
19194
20271
|
try {
|
|
19195
|
-
claudeJson = JSON.parse(
|
|
20272
|
+
claudeJson = JSON.parse(readFileSync29(claudeJsonPath, "utf8"));
|
|
19196
20273
|
} catch {
|
|
19197
20274
|
}
|
|
19198
20275
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -19201,7 +20278,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
19201
20278
|
if (!projects[dir]) projects[dir] = {};
|
|
19202
20279
|
projects[dir].hasTrustDialogAccepted = true;
|
|
19203
20280
|
}
|
|
19204
|
-
|
|
20281
|
+
writeFileSync25(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
19205
20282
|
} catch {
|
|
19206
20283
|
}
|
|
19207
20284
|
state.completedSteps.push(5);
|
|
@@ -19215,7 +20292,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
19215
20292
|
const prefs = { ...existingPrefs };
|
|
19216
20293
|
log("=== Config Defaults ===");
|
|
19217
20294
|
log("");
|
|
19218
|
-
const ghosttyDetected =
|
|
20295
|
+
const ghosttyDetected = existsSync34(path41.join(os19.homedir(), ".config", "ghostty")) || existsSync34(path41.join(os19.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
|
|
19219
20296
|
if (ghosttyDetected) {
|
|
19220
20297
|
const ghosttyAnswer = await ask3(rl, "Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ");
|
|
19221
20298
|
prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
|
|
@@ -19262,7 +20339,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
19262
20339
|
let missingIdentities = [];
|
|
19263
20340
|
for (const emp of roster) {
|
|
19264
20341
|
const idPath = identityPath2(emp.name);
|
|
19265
|
-
if (!
|
|
20342
|
+
if (!existsSync34(idPath)) {
|
|
19266
20343
|
missingIdentities.push(emp.name);
|
|
19267
20344
|
}
|
|
19268
20345
|
}
|
|
@@ -19294,7 +20371,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
19294
20371
|
}
|
|
19295
20372
|
missingIdentities = [];
|
|
19296
20373
|
for (const emp of roster) {
|
|
19297
|
-
if (!
|
|
20374
|
+
if (!existsSync34(identityPath2(emp.name))) {
|
|
19298
20375
|
missingIdentities.push(emp.name);
|
|
19299
20376
|
}
|
|
19300
20377
|
}
|
|
@@ -19312,7 +20389,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
19312
20389
|
}
|
|
19313
20390
|
try {
|
|
19314
20391
|
const { generateSessionWrappers: generateSessionWrappers2 } = await Promise.resolve().then(() => (init_session_wrappers(), session_wrappers_exports));
|
|
19315
|
-
const pkgRoot =
|
|
20392
|
+
const pkgRoot = findPackageRoot3();
|
|
19316
20393
|
if (pkgRoot) {
|
|
19317
20394
|
const wrapResult = generateSessionWrappers2(pkgRoot);
|
|
19318
20395
|
if (wrapResult.created > 0) {
|
|
@@ -19353,9 +20430,9 @@ async function runSetupWizard(opts = {}) {
|
|
|
19353
20430
|
const cooIdentityContent = getIdentityTemplate("coo");
|
|
19354
20431
|
if (cooIdentityContent) {
|
|
19355
20432
|
const cooIdPath = identityPath2(cooName);
|
|
19356
|
-
|
|
20433
|
+
mkdirSync24(path41.dirname(cooIdPath), { recursive: true });
|
|
19357
20434
|
const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
|
|
19358
|
-
|
|
20435
|
+
writeFileSync25(cooIdPath, replaced, "utf-8");
|
|
19359
20436
|
}
|
|
19360
20437
|
registerBinSymlinks2(cooName);
|
|
19361
20438
|
createdEmployees.push({ name: cooName, role: "COO" });
|
|
@@ -19471,9 +20548,9 @@ async function runSetupWizard(opts = {}) {
|
|
|
19471
20548
|
const ctoIdentityContent = getIdentityTemplate("cto");
|
|
19472
20549
|
if (ctoIdentityContent) {
|
|
19473
20550
|
const ctoIdPath = identityPath2(ctoName);
|
|
19474
|
-
|
|
20551
|
+
mkdirSync24(path41.dirname(ctoIdPath), { recursive: true });
|
|
19475
20552
|
const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
|
|
19476
|
-
|
|
20553
|
+
writeFileSync25(ctoIdPath, replaced, "utf-8");
|
|
19477
20554
|
}
|
|
19478
20555
|
registerBinSymlinks2(ctoName);
|
|
19479
20556
|
createdEmployees.push({ name: ctoName, role: "CTO" });
|
|
@@ -19494,9 +20571,9 @@ async function runSetupWizard(opts = {}) {
|
|
|
19494
20571
|
const cmoIdentityContent = getIdentityTemplate("cmo");
|
|
19495
20572
|
if (cmoIdentityContent) {
|
|
19496
20573
|
const cmoIdPath = identityPath2(cmoName);
|
|
19497
|
-
|
|
20574
|
+
mkdirSync24(path41.dirname(cmoIdPath), { recursive: true });
|
|
19498
20575
|
const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
|
|
19499
|
-
|
|
20576
|
+
writeFileSync25(cmoIdPath, replaced, "utf-8");
|
|
19500
20577
|
}
|
|
19501
20578
|
registerBinSymlinks2(cmoName);
|
|
19502
20579
|
createdEmployees.push({ name: cmoName, role: "CMO" });
|
|
@@ -19512,14 +20589,14 @@ async function runSetupWizard(opts = {}) {
|
|
|
19512
20589
|
if (!pairingRosterPulled) {
|
|
19513
20590
|
try {
|
|
19514
20591
|
const { generateSessionWrappers: generateSessionWrappers2 } = await Promise.resolve().then(() => (init_session_wrappers(), session_wrappers_exports));
|
|
19515
|
-
const pkgRoot =
|
|
20592
|
+
const pkgRoot = findPackageRoot3();
|
|
19516
20593
|
if (pkgRoot) {
|
|
19517
20594
|
const wrapResult = generateSessionWrappers2(pkgRoot);
|
|
19518
20595
|
if (wrapResult.created > 0) {
|
|
19519
20596
|
log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
|
|
19520
20597
|
}
|
|
19521
20598
|
if (wrapResult.pathConfigured) {
|
|
19522
|
-
const binDir =
|
|
20599
|
+
const binDir = path41.join(os19.homedir(), ".exe-os", "bin");
|
|
19523
20600
|
process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
|
|
19524
20601
|
pathJustConfigured = true;
|
|
19525
20602
|
}
|
|
@@ -19559,10 +20636,10 @@ async function runSetupWizard(opts = {}) {
|
|
|
19559
20636
|
log("Team: " + createdEmployees.map((e) => `${e.name} (${e.role})`).join(", "));
|
|
19560
20637
|
}
|
|
19561
20638
|
let version = "";
|
|
19562
|
-
const pkgRoot2 =
|
|
20639
|
+
const pkgRoot2 = findPackageRoot3();
|
|
19563
20640
|
if (pkgRoot2) {
|
|
19564
20641
|
try {
|
|
19565
|
-
version = JSON.parse(
|
|
20642
|
+
version = JSON.parse(readFileSync29(path41.join(pkgRoot2, "package.json"), "utf-8")).version;
|
|
19566
20643
|
} catch {
|
|
19567
20644
|
}
|
|
19568
20645
|
}
|
|
@@ -19601,46 +20678,46 @@ var init_setup_wizard = __esm({
|
|
|
19601
20678
|
init_config();
|
|
19602
20679
|
init_keychain();
|
|
19603
20680
|
init_model_downloader();
|
|
19604
|
-
SETUP_STATE_PATH =
|
|
20681
|
+
SETUP_STATE_PATH = path41.join(os19.homedir(), ".exe-os", "setup-state.json");
|
|
19605
20682
|
}
|
|
19606
20683
|
});
|
|
19607
20684
|
|
|
19608
20685
|
// src/lib/update-backup.ts
|
|
19609
20686
|
import { copyFile, readFile as readFile6, readdir as readdir3, writeFile as writeFile7, rm as rm2, mkdir as mkdir7, cp } from "fs/promises";
|
|
19610
|
-
import { existsSync as
|
|
19611
|
-
import
|
|
20687
|
+
import { existsSync as existsSync35 } from "fs";
|
|
20688
|
+
import path42 from "path";
|
|
19612
20689
|
import os20 from "os";
|
|
19613
20690
|
function resolveDataDir2() {
|
|
19614
20691
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
19615
20692
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
19616
|
-
return
|
|
20693
|
+
return path42.join(os20.homedir(), ".exe-os");
|
|
19617
20694
|
}
|
|
19618
20695
|
function externalBackupTargets(homeDir) {
|
|
19619
20696
|
return [
|
|
19620
|
-
{ name: "claude.json", path:
|
|
19621
|
-
{ name: "claude-settings.json", path:
|
|
19622
|
-
{ name: "claude-CLAUDE.md", path:
|
|
19623
|
-
{ name: "tmux.conf", path:
|
|
19624
|
-
{ name: "zshrc", path:
|
|
19625
|
-
{ name: "bashrc", path:
|
|
19626
|
-
{ name: "ghostty-config", path:
|
|
19627
|
-
{ name: "codex-config.toml", path:
|
|
19628
|
-
{ name: "codex-hooks.json", path:
|
|
19629
|
-
{ name: "opencode-config.json", path:
|
|
20697
|
+
{ name: "claude.json", path: path42.join(homeDir, ".claude.json") },
|
|
20698
|
+
{ name: "claude-settings.json", path: path42.join(homeDir, ".claude", "settings.json") },
|
|
20699
|
+
{ name: "claude-CLAUDE.md", path: path42.join(homeDir, ".claude", "CLAUDE.md") },
|
|
20700
|
+
{ name: "tmux.conf", path: path42.join(homeDir, ".tmux.conf") },
|
|
20701
|
+
{ name: "zshrc", path: path42.join(homeDir, ".zshrc") },
|
|
20702
|
+
{ name: "bashrc", path: path42.join(homeDir, ".bashrc") },
|
|
20703
|
+
{ name: "ghostty-config", path: path42.join(homeDir, ".config", "ghostty", "config") },
|
|
20704
|
+
{ name: "codex-config.toml", path: path42.join(homeDir, ".codex", "config.toml") },
|
|
20705
|
+
{ name: "codex-hooks.json", path: path42.join(homeDir, ".codex", "hooks.json") },
|
|
20706
|
+
{ name: "opencode-config.json", path: path42.join(homeDir, ".config", "opencode", "opencode.json") }
|
|
19630
20707
|
];
|
|
19631
20708
|
}
|
|
19632
20709
|
async function createUpdateBackup(currentVersion, dataDir2, homeDir = os20.homedir()) {
|
|
19633
20710
|
const dir = dataDir2 ?? resolveDataDir2();
|
|
19634
|
-
const backupDir =
|
|
19635
|
-
if (
|
|
20711
|
+
const backupDir = path42.join(dir, BACKUP_DIR_NAME);
|
|
20712
|
+
if (existsSync35(backupDir)) {
|
|
19636
20713
|
await rm2(backupDir, { recursive: true, force: true });
|
|
19637
20714
|
}
|
|
19638
20715
|
await mkdir7(backupDir, { recursive: true });
|
|
19639
20716
|
const backedUpFiles = [];
|
|
19640
20717
|
for (const target of BACKUP_TARGETS) {
|
|
19641
|
-
const src =
|
|
19642
|
-
if (!
|
|
19643
|
-
const dest =
|
|
20718
|
+
const src = path42.join(dir, target.name);
|
|
20719
|
+
if (!existsSync35(src)) continue;
|
|
20720
|
+
const dest = path42.join(backupDir, target.name);
|
|
19644
20721
|
if (target.type === "file") {
|
|
19645
20722
|
await copyFile(src, dest);
|
|
19646
20723
|
} else {
|
|
@@ -19651,18 +20728,18 @@ async function createUpdateBackup(currentVersion, dataDir2, homeDir = os20.homed
|
|
|
19651
20728
|
const entries = await readdir3(dir, { withFileTypes: true });
|
|
19652
20729
|
for (const entry of entries) {
|
|
19653
20730
|
if (entry.isFile() && entry.name.endsWith(".db") && entry.name !== BACKUP_DIR_NAME) {
|
|
19654
|
-
const src =
|
|
19655
|
-
const dest =
|
|
20731
|
+
const src = path42.join(dir, entry.name);
|
|
20732
|
+
const dest = path42.join(backupDir, entry.name);
|
|
19656
20733
|
await copyFile(src, dest);
|
|
19657
20734
|
backedUpFiles.push(entry.name);
|
|
19658
20735
|
}
|
|
19659
20736
|
}
|
|
19660
20737
|
const externalFiles = [];
|
|
19661
|
-
const externalDir =
|
|
20738
|
+
const externalDir = path42.join(backupDir, "external");
|
|
19662
20739
|
for (const target of externalBackupTargets(homeDir)) {
|
|
19663
|
-
if (!
|
|
20740
|
+
if (!existsSync35(target.path)) continue;
|
|
19664
20741
|
await mkdir7(externalDir, { recursive: true });
|
|
19665
|
-
await copyFile(target.path,
|
|
20742
|
+
await copyFile(target.path, path42.join(externalDir, target.name));
|
|
19666
20743
|
externalFiles.push(target);
|
|
19667
20744
|
}
|
|
19668
20745
|
const manifest = {
|
|
@@ -19672,16 +20749,16 @@ async function createUpdateBackup(currentVersion, dataDir2, homeDir = os20.homed
|
|
|
19672
20749
|
...externalFiles.length > 0 ? { externalFiles } : {}
|
|
19673
20750
|
};
|
|
19674
20751
|
await writeFile7(
|
|
19675
|
-
|
|
20752
|
+
path42.join(backupDir, "manifest.json"),
|
|
19676
20753
|
JSON.stringify(manifest, null, 2) + "\n"
|
|
19677
20754
|
);
|
|
19678
20755
|
return manifest;
|
|
19679
20756
|
}
|
|
19680
20757
|
async function restoreFromBackup(dataDir2) {
|
|
19681
20758
|
const dir = dataDir2 ?? resolveDataDir2();
|
|
19682
|
-
const backupDir =
|
|
19683
|
-
const manifestPath =
|
|
19684
|
-
if (!
|
|
20759
|
+
const backupDir = path42.join(dir, BACKUP_DIR_NAME);
|
|
20760
|
+
const manifestPath = path42.join(backupDir, "manifest.json");
|
|
20761
|
+
if (!existsSync35(manifestPath)) {
|
|
19685
20762
|
throw new Error(
|
|
19686
20763
|
`No backup found at ${backupDir}. Nothing to restore.`
|
|
19687
20764
|
);
|
|
@@ -19690,9 +20767,9 @@ async function restoreFromBackup(dataDir2) {
|
|
|
19690
20767
|
await readFile6(manifestPath, "utf-8")
|
|
19691
20768
|
);
|
|
19692
20769
|
for (const fileName of manifest.files) {
|
|
19693
|
-
const src =
|
|
19694
|
-
const dest =
|
|
19695
|
-
if (!
|
|
20770
|
+
const src = path42.join(backupDir, fileName);
|
|
20771
|
+
const dest = path42.join(dir, fileName);
|
|
20772
|
+
if (!existsSync35(src)) continue;
|
|
19696
20773
|
const stat2 = await import("fs/promises").then((m) => m.stat(src));
|
|
19697
20774
|
if (stat2.isDirectory()) {
|
|
19698
20775
|
await cp(src, dest, { recursive: true, force: true });
|
|
@@ -19701,17 +20778,17 @@ async function restoreFromBackup(dataDir2) {
|
|
|
19701
20778
|
}
|
|
19702
20779
|
}
|
|
19703
20780
|
for (const external of manifest.externalFiles ?? []) {
|
|
19704
|
-
const src =
|
|
19705
|
-
if (!
|
|
19706
|
-
await mkdir7(
|
|
20781
|
+
const src = path42.join(backupDir, "external", external.name);
|
|
20782
|
+
if (!existsSync35(src)) continue;
|
|
20783
|
+
await mkdir7(path42.dirname(external.path), { recursive: true });
|
|
19707
20784
|
await copyFile(src, external.path);
|
|
19708
20785
|
}
|
|
19709
20786
|
return manifest;
|
|
19710
20787
|
}
|
|
19711
20788
|
async function deleteBackup(dataDir2) {
|
|
19712
20789
|
const dir = dataDir2 ?? resolveDataDir2();
|
|
19713
|
-
const backupDir =
|
|
19714
|
-
if (
|
|
20790
|
+
const backupDir = path42.join(dir, BACKUP_DIR_NAME);
|
|
20791
|
+
if (existsSync35(backupDir)) {
|
|
19715
20792
|
await rm2(backupDir, { recursive: true, force: true });
|
|
19716
20793
|
}
|
|
19717
20794
|
}
|
|
@@ -19735,17 +20812,17 @@ var init_update_backup = __esm({
|
|
|
19735
20812
|
});
|
|
19736
20813
|
|
|
19737
20814
|
// src/lib/update-check.ts
|
|
19738
|
-
import { execSync as
|
|
19739
|
-
import { readFileSync as
|
|
19740
|
-
import
|
|
20815
|
+
import { execSync as execSync16 } from "child_process";
|
|
20816
|
+
import { readFileSync as readFileSync30 } from "fs";
|
|
20817
|
+
import path43 from "path";
|
|
19741
20818
|
function getLocalVersion(packageRoot) {
|
|
19742
|
-
const pkgPath =
|
|
19743
|
-
const pkg = JSON.parse(
|
|
20819
|
+
const pkgPath = path43.join(packageRoot, "package.json");
|
|
20820
|
+
const pkg = JSON.parse(readFileSync30(pkgPath, "utf-8"));
|
|
19744
20821
|
return pkg.version;
|
|
19745
20822
|
}
|
|
19746
20823
|
function getRemoteVersion() {
|
|
19747
20824
|
try {
|
|
19748
|
-
const output2 =
|
|
20825
|
+
const output2 = execSync16("npm view @askexenow/exe-os version", {
|
|
19749
20826
|
encoding: "utf-8",
|
|
19750
20827
|
timeout: 15e3,
|
|
19751
20828
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -19784,7 +20861,7 @@ __export(update_exports, {
|
|
|
19784
20861
|
getRemoteVersion: () => getRemoteVersion,
|
|
19785
20862
|
runUpdate: () => runUpdate
|
|
19786
20863
|
});
|
|
19787
|
-
import { execSync as
|
|
20864
|
+
import { execSync as execSync17 } from "child_process";
|
|
19788
20865
|
import { createInterface as createInterface5 } from "readline";
|
|
19789
20866
|
async function runRestore() {
|
|
19790
20867
|
console.log("\n\u{1F504} Restoring from update backup...");
|
|
@@ -19795,7 +20872,7 @@ async function runRestore() {
|
|
|
19795
20872
|
console.log(`
|
|
19796
20873
|
\u{1F4E5} Reinstalling @askexenow/exe-os@${manifest.version}...`);
|
|
19797
20874
|
try {
|
|
19798
|
-
|
|
20875
|
+
execSync17(`npm install -g @askexenow/exe-os@${manifest.version}`, {
|
|
19799
20876
|
stdio: ["pipe", "pipe", "inherit"],
|
|
19800
20877
|
timeout: 3e5
|
|
19801
20878
|
});
|
|
@@ -19876,7 +20953,7 @@ async function runUpdate(cliArgs) {
|
|
|
19876
20953
|
}
|
|
19877
20954
|
console.log("\u{1F9F9} Clearing npm cache...");
|
|
19878
20955
|
try {
|
|
19879
|
-
|
|
20956
|
+
execSync17("npm cache clean --force", { stdio: "pipe" });
|
|
19880
20957
|
console.log(" Done");
|
|
19881
20958
|
} catch {
|
|
19882
20959
|
console.log(" Skipped (non-critical)");
|
|
@@ -19884,7 +20961,7 @@ async function runUpdate(cliArgs) {
|
|
|
19884
20961
|
console.log("\u{1F4E5} Installing @askexenow/exe-os@latest...");
|
|
19885
20962
|
console.log(" This may take a minute...\n");
|
|
19886
20963
|
try {
|
|
19887
|
-
|
|
20964
|
+
execSync17("npm install -g @askexenow/exe-os@latest", {
|
|
19888
20965
|
stdio: ["pipe", "pipe", "inherit"],
|
|
19889
20966
|
timeout: 3e5
|
|
19890
20967
|
});
|
|
@@ -19902,7 +20979,7 @@ async function runUpdate(cliArgs) {
|
|
|
19902
20979
|
newVersion = getLocalVersion(packageRoot);
|
|
19903
20980
|
} catch {
|
|
19904
20981
|
try {
|
|
19905
|
-
const out =
|
|
20982
|
+
const out = execSync17("npm list -g @askexenow/exe-os --depth=0 2>/dev/null", { encoding: "utf8" });
|
|
19906
20983
|
const match = out.match(/@askexenow\/exe-os@(\S+)/);
|
|
19907
20984
|
newVersion = match?.[1] ?? "unknown";
|
|
19908
20985
|
} catch {
|
|
@@ -19931,7 +21008,7 @@ async function runUpdate(cliArgs) {
|
|
|
19931
21008
|
}
|
|
19932
21009
|
console.log("\u{1F527} Re-registering MCP, hooks, wrappers, and daemon...");
|
|
19933
21010
|
try {
|
|
19934
|
-
|
|
21011
|
+
execSync17("exe-os-install --global", {
|
|
19935
21012
|
stdio: ["pipe", "inherit", "inherit"],
|
|
19936
21013
|
timeout: 3e5
|
|
19937
21014
|
});
|
|
@@ -19966,7 +21043,7 @@ async function runUpdate(cliArgs) {
|
|
|
19966
21043
|
}
|
|
19967
21044
|
try {
|
|
19968
21045
|
console.log("\u{1FA7A} Checking AskExe support intake...");
|
|
19969
|
-
|
|
21046
|
+
execSync17("exe-os support health", {
|
|
19970
21047
|
stdio: ["pipe", "inherit", "inherit"],
|
|
19971
21048
|
timeout: 3e4
|
|
19972
21049
|
});
|
|
@@ -19994,11 +21071,11 @@ var init_update = __esm({
|
|
|
19994
21071
|
// src/lib/stack-update.ts
|
|
19995
21072
|
import { execFileSync as execFileSync4, spawnSync } from "child_process";
|
|
19996
21073
|
import { createVerify, randomBytes as randomBytes2, verify as verifySignature } from "crypto";
|
|
19997
|
-
import { copyFileSync as copyFileSync5, existsSync as
|
|
21074
|
+
import { copyFileSync as copyFileSync5, existsSync as existsSync36, mkdirSync as mkdirSync25, readdirSync as readdirSync11, readFileSync as readFileSync31, renameSync as renameSync8, writeFileSync as writeFileSync26 } from "fs";
|
|
19998
21075
|
import http from "http";
|
|
19999
21076
|
import https from "https";
|
|
20000
|
-
import
|
|
20001
|
-
import { fileURLToPath as
|
|
21077
|
+
import path44 from "path";
|
|
21078
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
20002
21079
|
function isSignedEnvelope(value) {
|
|
20003
21080
|
return !!value && typeof value === "object" && "manifest" in value && "signature" in value;
|
|
20004
21081
|
}
|
|
@@ -20032,21 +21109,21 @@ function stableJson(value) {
|
|
|
20032
21109
|
return `{${Object.keys(obj).sort().map((key) => `${JSON.stringify(key)}:${stableJson(obj[key])}`).join(",")}}`;
|
|
20033
21110
|
}
|
|
20034
21111
|
function findLatestBackupEnvFile(envFile) {
|
|
20035
|
-
const backupDir =
|
|
20036
|
-
if (!
|
|
20037
|
-
const backups =
|
|
21112
|
+
const backupDir = path44.join(path44.dirname(envFile), ".exe-stack-backups");
|
|
21113
|
+
if (!existsSync36(backupDir)) return null;
|
|
21114
|
+
const backups = readdirSync11(backupDir).filter((name) => name.startsWith("env-") && name.endsWith(".bak")).sort();
|
|
20038
21115
|
const latest = backups.at(-1);
|
|
20039
|
-
return latest ?
|
|
21116
|
+
return latest ? path44.join(backupDir, latest) : null;
|
|
20040
21117
|
}
|
|
20041
21118
|
async function rollbackStackUpdate(options) {
|
|
20042
21119
|
const exec2 = options.exec ?? defaultExec;
|
|
20043
|
-
const backupEnvFile = options.lockFile &&
|
|
20044
|
-
const rollbackEnv = backupEnvFile &&
|
|
21120
|
+
const backupEnvFile = options.lockFile && existsSync36(options.lockFile) ? JSON.parse(readFileSync31(options.lockFile, "utf8")).backupEnvFile : void 0;
|
|
21121
|
+
const rollbackEnv = backupEnvFile && existsSync36(backupEnvFile) ? backupEnvFile : findLatestBackupEnvFile(options.envFile);
|
|
20045
21122
|
if (!rollbackEnv) throw new Error(`No stack backup env found beside ${options.envFile}`);
|
|
20046
|
-
|
|
21123
|
+
writeFileSync26(options.envFile, readFileSync31(rollbackEnv), { mode: 384 });
|
|
20047
21124
|
const composeArgs = ["compose", "--file", options.composeFile, "--env-file", options.envFile];
|
|
20048
21125
|
exec2("docker", [...composeArgs, "up", "-d"]);
|
|
20049
|
-
return { status: "rolled_back", targetVersion: "previous", changes: [], backupEnvFile: rollbackEnv, lockFile: options.lockFile ??
|
|
21126
|
+
return { status: "rolled_back", targetVersion: "previous", changes: [], backupEnvFile: rollbackEnv, lockFile: options.lockFile ?? path44.join(path44.dirname(options.envFile), ".exe-stack-lock.json") };
|
|
20050
21127
|
}
|
|
20051
21128
|
function parseStackManifest(raw, publicKey) {
|
|
20052
21129
|
const parsedRaw = JSON.parse(raw);
|
|
@@ -20071,7 +21148,7 @@ function parseStackManifest(raw, publicKey) {
|
|
|
20071
21148
|
}
|
|
20072
21149
|
async function loadStackManifest(ref, fetchText = defaultFetchText, publicKey, authToken) {
|
|
20073
21150
|
if (/^https?:\/\//.test(ref)) return parseStackManifest(await fetchTextWithAuth(ref, fetchText, authToken), publicKey);
|
|
20074
|
-
return parseStackManifest(
|
|
21151
|
+
return parseStackManifest(readFileSync31(ref, "utf8"), publicKey);
|
|
20075
21152
|
}
|
|
20076
21153
|
async function fetchTextWithAuth(ref, fetchText, authToken) {
|
|
20077
21154
|
if (!authToken || fetchText !== defaultFetchText) return fetchText(ref);
|
|
@@ -20200,9 +21277,9 @@ Emergency override requires --break-glass <reason> and writes an audit file.`
|
|
|
20200
21277
|
function writeBreakGlassAudit(plan, issues, options) {
|
|
20201
21278
|
const now2 = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
20202
21279
|
const stamp = now2().toISOString().replace(/[:.]/g, "-");
|
|
20203
|
-
const defaultDir =
|
|
20204
|
-
const auditFile = options.breakGlassAuditFile ??
|
|
20205
|
-
|
|
21280
|
+
const defaultDir = existsSync36("exe/output") ? "exe/output" : path44.dirname(options.envFile ?? ".");
|
|
21281
|
+
const auditFile = options.breakGlassAuditFile ?? path44.join(defaultDir, `stack-update-break-glass-${stamp}.md`);
|
|
21282
|
+
mkdirSync25(path44.dirname(auditFile), { recursive: true });
|
|
20206
21283
|
const body = [
|
|
20207
21284
|
`# Stack Update Break-Glass Audit \u2014 ${now2().toISOString()}`,
|
|
20208
21285
|
"",
|
|
@@ -20216,7 +21293,7 @@ function writeBreakGlassAudit(plan, issues, options) {
|
|
|
20216
21293
|
"Return this deployment to the standard pinned GHCR image path immediately after the emergency is resolved.",
|
|
20217
21294
|
""
|
|
20218
21295
|
].join("\n");
|
|
20219
|
-
|
|
21296
|
+
writeFileSync26(auditFile, body, { mode: 384 });
|
|
20220
21297
|
console.warn(`[stack-update] BREAK-GLASS deploy override recorded: ${auditFile}`);
|
|
20221
21298
|
}
|
|
20222
21299
|
function assertBreakingChangesAllowed(plan, allowedIds) {
|
|
@@ -20242,26 +21319,26 @@ function shellSucceeds(command) {
|
|
|
20242
21319
|
return res.status === 0;
|
|
20243
21320
|
}
|
|
20244
21321
|
function resolvePackageRoot2() {
|
|
20245
|
-
const here =
|
|
21322
|
+
const here = path44.dirname(fileURLToPath7(import.meta.url));
|
|
20246
21323
|
const candidates = [
|
|
20247
|
-
|
|
20248
|
-
|
|
21324
|
+
path44.resolve(here, "..", ".."),
|
|
21325
|
+
path44.resolve(here, ".."),
|
|
20249
21326
|
process.cwd()
|
|
20250
21327
|
];
|
|
20251
21328
|
for (const c of candidates) {
|
|
20252
|
-
if (
|
|
21329
|
+
if (existsSync36(path44.join(c, "package.json")) && existsSync36(path44.join(c, "deploy", "compose", "docker-compose.yml"))) return c;
|
|
20253
21330
|
}
|
|
20254
21331
|
return process.cwd();
|
|
20255
21332
|
}
|
|
20256
21333
|
function copyTemplateIfMissing(srcRel, dest, created) {
|
|
20257
|
-
if (
|
|
20258
|
-
const src =
|
|
20259
|
-
if (!
|
|
21334
|
+
if (existsSync36(dest)) return;
|
|
21335
|
+
const src = path44.join(resolvePackageRoot2(), srcRel);
|
|
21336
|
+
if (!existsSync36(src)) throw new Error(`Missing packaged stack template: ${srcRel}. Reinstall/update exe-os and retry.`);
|
|
20260
21337
|
try {
|
|
20261
|
-
|
|
21338
|
+
mkdirSync25(path44.dirname(dest), { recursive: true });
|
|
20262
21339
|
} catch (err) {
|
|
20263
21340
|
if (err.code === "EACCES") {
|
|
20264
|
-
const dir =
|
|
21341
|
+
const dir = path44.dirname(dest);
|
|
20265
21342
|
throw new Error(
|
|
20266
21343
|
`Permission denied creating ${dir}. Run this first:
|
|
20267
21344
|
|
|
@@ -20277,8 +21354,8 @@ Then re-run stack-update.`
|
|
|
20277
21354
|
}
|
|
20278
21355
|
function installDockerUbuntu(exec2) {
|
|
20279
21356
|
if (process.platform !== "linux") throw new Error("Docker auto-install is only supported on Linux. Install Docker manually, then retry.");
|
|
20280
|
-
if (!
|
|
20281
|
-
const osRelease =
|
|
21357
|
+
if (!existsSync36("/etc/os-release")) throw new Error("Cannot detect Linux distro; install Docker manually, then retry.");
|
|
21358
|
+
const osRelease = readFileSync31("/etc/os-release", "utf8");
|
|
20282
21359
|
if (!/ID=(ubuntu|debian)|ID_LIKE=.*debian/.test(osRelease)) {
|
|
20283
21360
|
throw new Error("Docker auto-install currently supports Ubuntu/Debian only. Install Docker manually, then retry.");
|
|
20284
21361
|
}
|
|
@@ -20315,7 +21392,7 @@ function hydrateEnv(raw, opts) {
|
|
|
20315
21392
|
for (const [key, value] of env.entries()) {
|
|
20316
21393
|
if (!/CHANGEME/.test(value)) continue;
|
|
20317
21394
|
if (key === "EXE_LICENSE_KEY" && license) replacements[key] = license;
|
|
20318
|
-
else if (key === "MONITOR_AGENT_KEY") continue;
|
|
21395
|
+
else if (key === "MONITOR_AGENT_TOKEN" || key === "MONITOR_AGENT_KEY") continue;
|
|
20319
21396
|
else if (key === "EXE_GATEWAY_WS_RELAY_AUTH_TOKEN") replacements[key] = randomHexSecret(24);
|
|
20320
21397
|
else if (key.endsWith("_PASSWORD")) replacements[key] = randomSecret(24);
|
|
20321
21398
|
else if (key.endsWith("_TOKEN")) replacements[key] = randomHexSecret(32);
|
|
@@ -20327,6 +21404,45 @@ function hydrateEnv(raw, opts) {
|
|
|
20327
21404
|
const remaining = [...parseEnv(next).entries()].filter(([, value]) => /CHANGEME/.test(value)).map(([key, value]) => `${key}=${value}`);
|
|
20328
21405
|
return { raw: next, hadPlaceholders: /CHANGEME/.test(raw), remaining: [...new Set(remaining)] };
|
|
20329
21406
|
}
|
|
21407
|
+
async function pairMonitorAgent(hubUrl, licenseKey, domain, envFile) {
|
|
21408
|
+
if (!hubUrl || !licenseKey || !domain) {
|
|
21409
|
+
return { paired: false, error: "Missing hubUrl, licenseKey, or domain for monitor pairing" };
|
|
21410
|
+
}
|
|
21411
|
+
const registrationUrl = `${hubUrl.replace(/\/+$/, "")}/api/register-agent`;
|
|
21412
|
+
try {
|
|
21413
|
+
const res = await fetch(registrationUrl, {
|
|
21414
|
+
method: "POST",
|
|
21415
|
+
headers: {
|
|
21416
|
+
"content-type": "application/json",
|
|
21417
|
+
authorization: `Bearer ${licenseKey}`
|
|
21418
|
+
},
|
|
21419
|
+
body: JSON.stringify({ name: domain, host: domain, port: 45876 }),
|
|
21420
|
+
signal: AbortSignal.timeout(15e3)
|
|
21421
|
+
});
|
|
21422
|
+
if (!res.ok) {
|
|
21423
|
+
const body = await res.text().catch(() => "");
|
|
21424
|
+
return { paired: false, error: `Monitor hub returned HTTP ${res.status}: ${body}` };
|
|
21425
|
+
}
|
|
21426
|
+
const data = await res.json();
|
|
21427
|
+
if (!data.token || !data.key) {
|
|
21428
|
+
return { paired: false, error: "Monitor hub response missing token or key" };
|
|
21429
|
+
}
|
|
21430
|
+
if (existsSync36(envFile)) {
|
|
21431
|
+
const envRaw = readFileSync31(envFile, "utf8");
|
|
21432
|
+
const patched = patchEnv(envRaw, {
|
|
21433
|
+
MONITOR_AGENT_TOKEN: data.token,
|
|
21434
|
+
MONITOR_AGENT_KEY: data.key
|
|
21435
|
+
});
|
|
21436
|
+
if (patched !== envRaw) {
|
|
21437
|
+
writeFileSync26(envFile, patched, { mode: 384 });
|
|
21438
|
+
}
|
|
21439
|
+
}
|
|
21440
|
+
return { paired: true, systemName: data.name ?? domain };
|
|
21441
|
+
} catch (err) {
|
|
21442
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
21443
|
+
return { paired: false, error: `Monitor hub unreachable: ${reason}` };
|
|
21444
|
+
}
|
|
21445
|
+
}
|
|
20330
21446
|
function bootstrapStackHost(options) {
|
|
20331
21447
|
const exec2 = options.exec ?? defaultExec;
|
|
20332
21448
|
const createdFiles = [];
|
|
@@ -20341,26 +21457,26 @@ function bootstrapStackHost(options) {
|
|
|
20341
21457
|
}
|
|
20342
21458
|
copyTemplateIfMissing("deploy/compose/docker-compose.yml", options.composeFile, createdFiles);
|
|
20343
21459
|
copyTemplateIfMissing("deploy/compose/.env.customer.example", options.envFile, createdFiles);
|
|
20344
|
-
const brandingDest =
|
|
20345
|
-
copyTemplateIfMissing("deploy/compose/gateway.json",
|
|
20346
|
-
if (!
|
|
21460
|
+
const brandingDest = path44.join(path44.dirname(options.envFile), "branding.json");
|
|
21461
|
+
copyTemplateIfMissing("deploy/compose/gateway.json", path44.join(path44.dirname(options.envFile), "gateway.json"), createdFiles);
|
|
21462
|
+
if (!existsSync36(brandingDest)) writeFileSync26(brandingDest, JSON.stringify({ brandName: "Hygo", productName: "Hygo OS" }, null, 2) + "\n", { mode: 384 });
|
|
20347
21463
|
let envHadPlaceholders = false;
|
|
20348
21464
|
let envRemainingPlaceholders = [];
|
|
20349
|
-
if (
|
|
20350
|
-
const envRaw =
|
|
21465
|
+
if (existsSync36(options.envFile)) {
|
|
21466
|
+
const envRaw = readFileSync31(options.envFile, "utf8");
|
|
20351
21467
|
const hydrated = hydrateEnv(envRaw, options);
|
|
20352
21468
|
envHadPlaceholders = hydrated.hadPlaceholders;
|
|
20353
21469
|
envRemainingPlaceholders = hydrated.remaining;
|
|
20354
21470
|
if (hydrated.raw !== envRaw) {
|
|
20355
|
-
|
|
21471
|
+
writeFileSync26(options.envFile, hydrated.raw, { mode: 384 });
|
|
20356
21472
|
actions.push("hydrate_env_secrets");
|
|
20357
21473
|
}
|
|
20358
21474
|
}
|
|
20359
21475
|
return {
|
|
20360
21476
|
dockerInstalled,
|
|
20361
21477
|
dockerComposeInstalled,
|
|
20362
|
-
composeFileExists:
|
|
20363
|
-
envFileExists:
|
|
21478
|
+
composeFileExists: existsSync36(options.composeFile),
|
|
21479
|
+
envFileExists: existsSync36(options.envFile),
|
|
20364
21480
|
envHadPlaceholders,
|
|
20365
21481
|
envRemainingPlaceholders,
|
|
20366
21482
|
licensePresent: !!(options.licenseKey || process.env.EXE_LICENSE_KEY || loadLicense()),
|
|
@@ -20399,35 +21515,51 @@ async function runStackUpdate(options) {
|
|
|
20399
21515
|
const report = bootstrapStackHost({ ...options, installDocker: options.installDocker ?? !!options.yes });
|
|
20400
21516
|
if (!options.dryRun) assertHostReadyForApply(report);
|
|
20401
21517
|
}
|
|
21518
|
+
const hubUrl = options.monitorHubUrl || parseEnv(readFileSync31(options.envFile, "utf8")).get("MONITOR_HUB_URL") || "";
|
|
21519
|
+
const pairLicense = options.licenseKey || process.env.EXE_LICENSE_KEY || loadLicense() || "";
|
|
21520
|
+
const pairDomain = options.domain || process.env.EXE_STACK_DOMAIN || process.env.CUSTOMER_DOMAIN || "";
|
|
21521
|
+
if (hubUrl && pairLicense && pairDomain) {
|
|
21522
|
+
const envBefore = readFileSync31(options.envFile, "utf8");
|
|
21523
|
+
const hasPlaceholder = /CHANGEME/.test(parseEnv(envBefore).get("MONITOR_AGENT_TOKEN") ?? "");
|
|
21524
|
+
if (hasPlaceholder) {
|
|
21525
|
+
const pair = options.pairMonitor ? options.pairMonitor(hubUrl, pairLicense, pairDomain, options.envFile) : pairMonitorAgent(hubUrl, pairLicense, pairDomain, options.envFile);
|
|
21526
|
+
const result = await pair;
|
|
21527
|
+
if (result.paired) {
|
|
21528
|
+
console.log(`[stack-update] Monitor agent paired: ${result.systemName}`);
|
|
21529
|
+
} else {
|
|
21530
|
+
console.warn(`[stack-update] Monitor pairing skipped: ${result.error}`);
|
|
21531
|
+
}
|
|
21532
|
+
}
|
|
21533
|
+
}
|
|
20402
21534
|
const manifest = await loadStackManifest(options.manifestRef, options.fetchText, options.manifestPublicKey, options.manifestAuthToken);
|
|
20403
|
-
const envRaw =
|
|
21535
|
+
const envRaw = readFileSync31(options.envFile, "utf8");
|
|
20404
21536
|
const plan = createStackUpdatePlan(manifest, envRaw, options.targetVersion);
|
|
20405
21537
|
assertBreakingChangesAllowed(plan, options.allowedBreakingChangeIds ?? []);
|
|
20406
21538
|
assertDeploymentScopeAllowed(plan, options.deploymentPersona ?? "customer");
|
|
20407
21539
|
const plannedEnvRaw = patchEnv(envRaw, Object.fromEntries(plan.changes.map((c) => [c.key, c.after])));
|
|
20408
|
-
const composeRaw =
|
|
21540
|
+
const composeRaw = readFileSync31(options.composeFile, "utf8");
|
|
20409
21541
|
assertProductionDeployGate(plan, plannedEnvRaw, composeRaw, {
|
|
20410
21542
|
breakGlassReason: options.breakGlassReason,
|
|
20411
21543
|
breakGlassAuditFile: options.breakGlassAuditFile,
|
|
20412
21544
|
now: now2,
|
|
20413
21545
|
envFile: options.envFile
|
|
20414
21546
|
});
|
|
20415
|
-
const lockFile = options.lockFile ??
|
|
21547
|
+
const lockFile = options.lockFile ?? path44.join(path44.dirname(options.envFile), ".exe-stack-lock.json");
|
|
20416
21548
|
const previousVersion = readCurrentStackVersion(lockFile);
|
|
20417
21549
|
const containersRunning = plan.changes.length === 0 ? areStackContainersRunning(options.composeFile, options.envFile) : true;
|
|
20418
21550
|
if (options.dryRun || plan.changes.length === 0 && containersRunning) {
|
|
20419
21551
|
return { status: "planned", targetVersion: plan.targetVersion, changes: plan.changes, lockFile };
|
|
20420
21552
|
}
|
|
20421
21553
|
await postDeployAudit(options, "started", plan.targetVersion, previousVersion);
|
|
20422
|
-
const backupDir =
|
|
20423
|
-
|
|
21554
|
+
const backupDir = path44.join(path44.dirname(options.envFile), ".exe-stack-backups");
|
|
21555
|
+
mkdirSync25(backupDir, { recursive: true });
|
|
20424
21556
|
const stamp = now2().toISOString().replace(/[:.]/g, "-");
|
|
20425
|
-
const backupEnvFile =
|
|
20426
|
-
|
|
21557
|
+
const backupEnvFile = path44.join(backupDir, `env-${stamp}.bak`);
|
|
21558
|
+
writeFileSync26(backupEnvFile, envRaw, { mode: 384 });
|
|
20427
21559
|
const updates = Object.fromEntries(plan.changes.map((c) => [c.key, c.after]));
|
|
20428
21560
|
const patched = patchEnv(envRaw, updates);
|
|
20429
21561
|
const tmp = `${options.envFile}.tmp-${process.pid}`;
|
|
20430
|
-
|
|
21562
|
+
writeFileSync26(tmp, patched, { mode: 384 });
|
|
20431
21563
|
renameSync8(tmp, options.envFile);
|
|
20432
21564
|
const composeArgs = ["compose", "--file", options.composeFile, "--env-file", options.envFile];
|
|
20433
21565
|
let registryForLogout;
|
|
@@ -20440,11 +21572,11 @@ async function runStackUpdate(options) {
|
|
|
20440
21572
|
exec2("docker", [...composeArgs, "pull"]);
|
|
20441
21573
|
exec2("docker", [...composeArgs, "up", "-d"]);
|
|
20442
21574
|
await verifyReleaseHealth(plan.release, options.healthRetries ?? 12, options.healthDelayMs ?? 5e3);
|
|
20443
|
-
|
|
21575
|
+
writeFileSync26(lockFile, JSON.stringify({ stackVersion: plan.targetVersion, updatedAt: now2().toISOString(), backupEnvFile, services: plan.release.services }, null, 2) + "\n");
|
|
20444
21576
|
await postDeployAudit(options, "success", plan.targetVersion, previousVersion, void 0, { changes: plan.changes.length });
|
|
20445
21577
|
return { status: "updated", targetVersion: plan.targetVersion, changes: plan.changes, backupEnvFile, lockFile };
|
|
20446
21578
|
} catch (err) {
|
|
20447
|
-
|
|
21579
|
+
writeFileSync26(options.envFile, envRaw, { mode: 384 });
|
|
20448
21580
|
try {
|
|
20449
21581
|
exec2("docker", [...composeArgs, "up", "-d"]);
|
|
20450
21582
|
} catch {
|
|
@@ -20475,9 +21607,9 @@ async function fetchImageCredentials(options) {
|
|
|
20475
21607
|
return await res.json();
|
|
20476
21608
|
}
|
|
20477
21609
|
function readCurrentStackVersion(lockFile) {
|
|
20478
|
-
if (!
|
|
21610
|
+
if (!existsSync36(lockFile)) return void 0;
|
|
20479
21611
|
try {
|
|
20480
|
-
const parsed = JSON.parse(
|
|
21612
|
+
const parsed = JSON.parse(readFileSync31(lockFile, "utf8"));
|
|
20481
21613
|
return parsed.stackVersion;
|
|
20482
21614
|
} catch {
|
|
20483
21615
|
return void 0;
|
|
@@ -20565,13 +21697,13 @@ async function defaultPostJson(url, body, authToken) {
|
|
|
20565
21697
|
if (!res.ok) throw new Error(`Failed to POST ${url}: HTTP ${res.status}`);
|
|
20566
21698
|
}
|
|
20567
21699
|
function defaultStackPaths() {
|
|
20568
|
-
const cwdCompose =
|
|
20569
|
-
const cwdEnv =
|
|
20570
|
-
const packagedManifest =
|
|
20571
|
-
const manifestRef = process.env.EXE_STACK_MANIFEST || (
|
|
21700
|
+
const cwdCompose = path44.resolve("docker-compose.yml");
|
|
21701
|
+
const cwdEnv = path44.resolve(".env");
|
|
21702
|
+
const packagedManifest = path44.join(resolvePackageRoot2(), "deploy", "stack-manifests", "v0.9.json");
|
|
21703
|
+
const manifestRef = process.env.EXE_STACK_MANIFEST || (existsSync36(packagedManifest) ? packagedManifest : "https://update.askexe.com/stack-manifest.json");
|
|
20572
21704
|
return {
|
|
20573
|
-
composeFile: process.env.EXE_STACK_COMPOSE_FILE || (
|
|
20574
|
-
envFile: process.env.EXE_STACK_ENV_FILE || (
|
|
21705
|
+
composeFile: process.env.EXE_STACK_COMPOSE_FILE || (existsSync36(cwdCompose) ? cwdCompose : "/opt/exe-stack/docker-compose.yml"),
|
|
21706
|
+
envFile: process.env.EXE_STACK_ENV_FILE || (existsSync36(cwdEnv) ? cwdEnv : "/opt/exe-stack/.env"),
|
|
20575
21707
|
manifestRef,
|
|
20576
21708
|
// Only call update.askexe.com if explicitly configured or if a remote manifest was requested.
|
|
20577
21709
|
// Packaged manifests keep cold-start installs unblocked even before update-service entitlements are provisioned.
|
|
@@ -20585,8 +21717,8 @@ function defaultStackPaths() {
|
|
|
20585
21717
|
}
|
|
20586
21718
|
function loadDefaultPublicKey() {
|
|
20587
21719
|
if (process.env.EXE_STACK_PUBLIC_KEY) return process.env.EXE_STACK_PUBLIC_KEY;
|
|
20588
|
-
if (process.env.EXE_STACK_PUBLIC_KEY_FILE &&
|
|
20589
|
-
return
|
|
21720
|
+
if (process.env.EXE_STACK_PUBLIC_KEY_FILE && existsSync36(process.env.EXE_STACK_PUBLIC_KEY_FILE)) {
|
|
21721
|
+
return readFileSync31(process.env.EXE_STACK_PUBLIC_KEY_FILE, "utf8");
|
|
20590
21722
|
}
|
|
20591
21723
|
return void 0;
|
|
20592
21724
|
}
|
|
@@ -20604,7 +21736,7 @@ var stack_update_exports = {};
|
|
|
20604
21736
|
__export(stack_update_exports, {
|
|
20605
21737
|
runStackUpdateCli: () => main7
|
|
20606
21738
|
});
|
|
20607
|
-
import { readFileSync as
|
|
21739
|
+
import { readFileSync as readFileSync32 } from "fs";
|
|
20608
21740
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
20609
21741
|
function parseArgs4(args2) {
|
|
20610
21742
|
const defaults = defaultStackPaths();
|
|
@@ -20638,8 +21770,8 @@ function parseArgs4(args2) {
|
|
|
20638
21770
|
else if (arg === "--env-file" || arg === "--stack-env-file") opts.envFile = next();
|
|
20639
21771
|
else if (arg.startsWith("--env-file=") || arg.startsWith("--stack-env-file=")) opts.envFile = arg.split("=").slice(1).join("=");
|
|
20640
21772
|
else if (arg === "--lock-file") opts.lockFile = next();
|
|
20641
|
-
else if (arg === "--public-key") opts.manifestPublicKey =
|
|
20642
|
-
else if (arg.startsWith("--public-key=")) opts.manifestPublicKey =
|
|
21773
|
+
else if (arg === "--public-key") opts.manifestPublicKey = readFileSync32(next(), "utf8");
|
|
21774
|
+
else if (arg.startsWith("--public-key=")) opts.manifestPublicKey = readFileSync32(arg.split("=").slice(1).join("="), "utf8");
|
|
20643
21775
|
else if (arg === "--auth-token") opts.manifestAuthToken = next();
|
|
20644
21776
|
else if (arg.startsWith("--auth-token=")) opts.manifestAuthToken = arg.split("=").slice(1).join("=");
|
|
20645
21777
|
else if (arg === "--auth-token-env") opts.manifestAuthToken = process.env[next()] ?? "";
|
|
@@ -20844,11 +21976,11 @@ async function main7(args2 = process.argv.slice(2)) {
|
|
|
20844
21976
|
if (!opts.check && !opts.dryRun) assertHostReadyForApply(hostReport);
|
|
20845
21977
|
}
|
|
20846
21978
|
const manifest = await loadStackManifest(opts.manifestRef, void 0, opts.manifestPublicKey, opts.manifestAuthToken);
|
|
20847
|
-
const envRaw =
|
|
21979
|
+
const envRaw = readFileSync32(opts.envFile, "utf8");
|
|
20848
21980
|
const plan = createStackUpdatePlan(manifest, envRaw, opts.targetVersion);
|
|
20849
21981
|
assertDeploymentScopeAllowed(plan, opts.deploymentPersona);
|
|
20850
21982
|
const plannedEnvRaw = patchEnv(envRaw, Object.fromEntries(plan.changes.map((c) => [c.key, c.after])));
|
|
20851
|
-
assertProductionDeployGate(plan, plannedEnvRaw,
|
|
21983
|
+
assertProductionDeployGate(plan, plannedEnvRaw, readFileSync32(opts.composeFile, "utf8"), {
|
|
20852
21984
|
breakGlassReason: opts.breakGlassReason,
|
|
20853
21985
|
breakGlassAuditFile: opts.breakGlassAuditFile,
|
|
20854
21986
|
envFile: opts.envFile
|
|
@@ -25450,8 +26582,8 @@ var init_ErrorOverview = __esm({
|
|
|
25450
26582
|
"use strict";
|
|
25451
26583
|
init_Box();
|
|
25452
26584
|
init_Text();
|
|
25453
|
-
cleanupPath = (
|
|
25454
|
-
return
|
|
26585
|
+
cleanupPath = (path58) => {
|
|
26586
|
+
return path58?.replace(`file://${cwd()}/`, "");
|
|
25455
26587
|
};
|
|
25456
26588
|
stackUtils = new StackUtils({
|
|
25457
26589
|
cwd: cwd(),
|
|
@@ -27555,13 +28687,13 @@ __export(tmux_status_exports, {
|
|
|
27555
28687
|
parseActivity: () => parseActivity,
|
|
27556
28688
|
parseContextPercentage: () => parseContextPercentage
|
|
27557
28689
|
});
|
|
27558
|
-
import { execSync as
|
|
28690
|
+
import { execSync as execSync18 } from "child_process";
|
|
27559
28691
|
function inTmux() {
|
|
27560
28692
|
if (process.env.TMUX || process.env.TMUX_PANE) return true;
|
|
27561
28693
|
const term = process.env.TERM ?? "";
|
|
27562
28694
|
if (term.startsWith("tmux") || term.startsWith("screen")) return true;
|
|
27563
28695
|
try {
|
|
27564
|
-
|
|
28696
|
+
execSync18("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
27565
28697
|
encoding: "utf8",
|
|
27566
28698
|
timeout: 2e3
|
|
27567
28699
|
});
|
|
@@ -27571,12 +28703,12 @@ function inTmux() {
|
|
|
27571
28703
|
try {
|
|
27572
28704
|
let pid = process.ppid;
|
|
27573
28705
|
for (let depth = 0; depth < 8 && pid > 1; depth++) {
|
|
27574
|
-
const comm =
|
|
28706
|
+
const comm = execSync18(`ps -p ${pid} -o comm= 2>/dev/null`, {
|
|
27575
28707
|
encoding: "utf8",
|
|
27576
28708
|
timeout: 1e3
|
|
27577
28709
|
}).trim();
|
|
27578
28710
|
if (/tmux/.test(comm)) return true;
|
|
27579
|
-
const ppid =
|
|
28711
|
+
const ppid = execSync18(`ps -p ${pid} -o ppid= 2>/dev/null`, {
|
|
27580
28712
|
encoding: "utf8",
|
|
27581
28713
|
timeout: 1e3
|
|
27582
28714
|
}).trim();
|
|
@@ -27589,7 +28721,7 @@ function inTmux() {
|
|
|
27589
28721
|
}
|
|
27590
28722
|
function listTmuxSessions() {
|
|
27591
28723
|
try {
|
|
27592
|
-
const out =
|
|
28724
|
+
const out = execSync18("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
27593
28725
|
encoding: "utf8",
|
|
27594
28726
|
timeout: 3e3
|
|
27595
28727
|
});
|
|
@@ -27600,7 +28732,7 @@ function listTmuxSessions() {
|
|
|
27600
28732
|
}
|
|
27601
28733
|
function capturePaneLines(windowName, lines = 10) {
|
|
27602
28734
|
try {
|
|
27603
|
-
const out =
|
|
28735
|
+
const out = execSync18(
|
|
27604
28736
|
`tmux capture-pane -t ${JSON.stringify(windowName)} -p 2>/dev/null | tail -${lines}`,
|
|
27605
28737
|
{ encoding: "utf8", timeout: 3e3 }
|
|
27606
28738
|
);
|
|
@@ -27611,7 +28743,7 @@ function capturePaneLines(windowName, lines = 10) {
|
|
|
27611
28743
|
}
|
|
27612
28744
|
function getPaneCwd(windowName) {
|
|
27613
28745
|
try {
|
|
27614
|
-
const out =
|
|
28746
|
+
const out = execSync18(
|
|
27615
28747
|
`tmux display-message -t ${JSON.stringify(windowName)} -p '#{pane_current_path}' 2>/dev/null`,
|
|
27616
28748
|
{ encoding: "utf8", timeout: 3e3 }
|
|
27617
28749
|
);
|
|
@@ -27622,7 +28754,7 @@ function getPaneCwd(windowName) {
|
|
|
27622
28754
|
}
|
|
27623
28755
|
function projectFromPath(dir) {
|
|
27624
28756
|
try {
|
|
27625
|
-
const root =
|
|
28757
|
+
const root = execSync18("git -C " + JSON.stringify(dir) + " rev-parse --show-toplevel 2>/dev/null", {
|
|
27626
28758
|
encoding: "utf8",
|
|
27627
28759
|
timeout: 3e3
|
|
27628
28760
|
}).trim();
|
|
@@ -27691,7 +28823,7 @@ function getEmployeeStatuses(employeeNames) {
|
|
|
27691
28823
|
}
|
|
27692
28824
|
let paneAlive = true;
|
|
27693
28825
|
try {
|
|
27694
|
-
const paneStatus =
|
|
28826
|
+
const paneStatus = execSync18(
|
|
27695
28827
|
`tmux list-panes -t ${JSON.stringify(sessionName)} -F '#{pane_dead}' 2>/dev/null`,
|
|
27696
28828
|
{ encoding: "utf8", timeout: 3e3 }
|
|
27697
28829
|
).trim();
|
|
@@ -27859,11 +28991,11 @@ function Footer() {
|
|
|
27859
28991
|
} catch {
|
|
27860
28992
|
}
|
|
27861
28993
|
try {
|
|
27862
|
-
const { existsSync:
|
|
28994
|
+
const { existsSync: existsSync43 } = await import("fs");
|
|
27863
28995
|
const { join } = await import("path");
|
|
27864
28996
|
const home = process.env.HOME ?? "";
|
|
27865
28997
|
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
27866
|
-
setDaemon(
|
|
28998
|
+
setDaemon(existsSync43(pidPath) ? "running" : "stopped");
|
|
27867
28999
|
} catch {
|
|
27868
29000
|
setDaemon("unknown");
|
|
27869
29001
|
}
|
|
@@ -27881,8 +29013,8 @@ function Footer() {
|
|
|
27881
29013
|
setSessions(allSessions.length);
|
|
27882
29014
|
if (!currentSession) {
|
|
27883
29015
|
try {
|
|
27884
|
-
const { execSync:
|
|
27885
|
-
const name =
|
|
29016
|
+
const { execSync: execSync20 } = await import("child_process");
|
|
29017
|
+
const name = execSync20("tmux display-message -p '#{session_name}' 2>/dev/null", {
|
|
27886
29018
|
encoding: "utf8",
|
|
27887
29019
|
timeout: 2e3
|
|
27888
29020
|
}).trim();
|
|
@@ -29914,10 +31046,10 @@ var init_hooks = __esm({
|
|
|
29914
31046
|
});
|
|
29915
31047
|
|
|
29916
31048
|
// src/runtime/safety-checks.ts
|
|
29917
|
-
import
|
|
31049
|
+
import path45 from "path";
|
|
29918
31050
|
import os21 from "os";
|
|
29919
31051
|
function checkPathSafety(filePath) {
|
|
29920
|
-
const resolved =
|
|
31052
|
+
const resolved = path45.resolve(filePath);
|
|
29921
31053
|
for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
|
|
29922
31054
|
const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
|
|
29923
31055
|
if (matches) {
|
|
@@ -29927,7 +31059,7 @@ function checkPathSafety(filePath) {
|
|
|
29927
31059
|
return { safe: true, bypassImmune: true };
|
|
29928
31060
|
}
|
|
29929
31061
|
function checkReadPathSafety(filePath) {
|
|
29930
|
-
const resolved =
|
|
31062
|
+
const resolved = path45.resolve(filePath);
|
|
29931
31063
|
const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
|
|
29932
31064
|
(p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
|
|
29933
31065
|
);
|
|
@@ -29953,11 +31085,11 @@ var init_safety_checks = __esm({
|
|
|
29953
31085
|
reason: "Git config can set hooks and command execution"
|
|
29954
31086
|
},
|
|
29955
31087
|
{
|
|
29956
|
-
pattern: (p) => p.startsWith(
|
|
31088
|
+
pattern: (p) => p.startsWith(path45.join(HOME, ".claude")),
|
|
29957
31089
|
reason: "Claude configuration files are protected"
|
|
29958
31090
|
},
|
|
29959
31091
|
{
|
|
29960
|
-
pattern: (p) => p.startsWith(
|
|
31092
|
+
pattern: (p) => p.startsWith(path45.join(HOME, ".exe-os")),
|
|
29961
31093
|
reason: "exe-os configuration files are protected"
|
|
29962
31094
|
},
|
|
29963
31095
|
{
|
|
@@ -29974,7 +31106,7 @@ var init_safety_checks = __esm({
|
|
|
29974
31106
|
},
|
|
29975
31107
|
{
|
|
29976
31108
|
pattern: (p) => {
|
|
29977
|
-
const name =
|
|
31109
|
+
const name = path45.basename(p);
|
|
29978
31110
|
return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
|
|
29979
31111
|
},
|
|
29980
31112
|
reason: "Shell configuration files can execute arbitrary code on login"
|
|
@@ -30001,7 +31133,7 @@ __export(file_read_exports, {
|
|
|
30001
31133
|
FileReadTool: () => FileReadTool
|
|
30002
31134
|
});
|
|
30003
31135
|
import fs3 from "fs/promises";
|
|
30004
|
-
import
|
|
31136
|
+
import path46 from "path";
|
|
30005
31137
|
import { z } from "zod";
|
|
30006
31138
|
function isBinary(buf) {
|
|
30007
31139
|
for (let i = 0; i < buf.length; i++) {
|
|
@@ -30037,7 +31169,7 @@ var init_file_read = __esm({
|
|
|
30037
31169
|
return { behavior: "allow" };
|
|
30038
31170
|
},
|
|
30039
31171
|
async call(input, context) {
|
|
30040
|
-
const filePath =
|
|
31172
|
+
const filePath = path46.isAbsolute(input.file_path) ? input.file_path : path46.resolve(context.cwd, input.file_path);
|
|
30041
31173
|
let stat2;
|
|
30042
31174
|
try {
|
|
30043
31175
|
stat2 = await fs3.stat(filePath);
|
|
@@ -30077,7 +31209,7 @@ __export(glob_exports, {
|
|
|
30077
31209
|
GlobTool: () => GlobTool
|
|
30078
31210
|
});
|
|
30079
31211
|
import fs4 from "fs/promises";
|
|
30080
|
-
import
|
|
31212
|
+
import path47 from "path";
|
|
30081
31213
|
import { z as z2 } from "zod";
|
|
30082
31214
|
async function walkDir(dir, maxDepth = 10) {
|
|
30083
31215
|
const results = [];
|
|
@@ -30093,7 +31225,7 @@ async function walkDir(dir, maxDepth = 10) {
|
|
|
30093
31225
|
if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
|
|
30094
31226
|
continue;
|
|
30095
31227
|
}
|
|
30096
|
-
const fullPath =
|
|
31228
|
+
const fullPath = path47.join(current, entry.name);
|
|
30097
31229
|
if (entry.isDirectory()) {
|
|
30098
31230
|
await walk(fullPath, depth + 1);
|
|
30099
31231
|
} else {
|
|
@@ -30127,11 +31259,11 @@ var init_glob = __esm({
|
|
|
30127
31259
|
inputSchema: inputSchema2,
|
|
30128
31260
|
isReadOnly: true,
|
|
30129
31261
|
async call(input, context) {
|
|
30130
|
-
const baseDir = input.path ?
|
|
31262
|
+
const baseDir = input.path ? path47.isAbsolute(input.path) ? input.path : path47.resolve(context.cwd, input.path) : context.cwd;
|
|
30131
31263
|
try {
|
|
30132
31264
|
const entries = await walkDir(baseDir);
|
|
30133
31265
|
const matched = entries.filter(
|
|
30134
|
-
(e) => simpleGlobMatch(
|
|
31266
|
+
(e) => simpleGlobMatch(path47.relative(baseDir, e.path), input.pattern)
|
|
30135
31267
|
);
|
|
30136
31268
|
matched.sort((a, b) => b.mtime - a.mtime);
|
|
30137
31269
|
if (matched.length === 0) {
|
|
@@ -30157,7 +31289,7 @@ __export(grep_exports, {
|
|
|
30157
31289
|
});
|
|
30158
31290
|
import { spawn as spawn2 } from "child_process";
|
|
30159
31291
|
import fs5 from "fs/promises";
|
|
30160
|
-
import
|
|
31292
|
+
import path48 from "path";
|
|
30161
31293
|
import { z as z3 } from "zod";
|
|
30162
31294
|
function runRipgrep(input, searchPath, context) {
|
|
30163
31295
|
return new Promise((resolve, reject) => {
|
|
@@ -30211,7 +31343,7 @@ async function nodeGrep(input, searchPath) {
|
|
|
30211
31343
|
}
|
|
30212
31344
|
for (const entry of entries) {
|
|
30213
31345
|
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
30214
|
-
const fullPath =
|
|
31346
|
+
const fullPath = path48.join(dir, entry.name);
|
|
30215
31347
|
if (entry.isDirectory()) {
|
|
30216
31348
|
await walk(fullPath);
|
|
30217
31349
|
} else {
|
|
@@ -30257,7 +31389,7 @@ var init_grep = __esm({
|
|
|
30257
31389
|
inputSchema: inputSchema3,
|
|
30258
31390
|
isReadOnly: true,
|
|
30259
31391
|
async call(input, context) {
|
|
30260
|
-
const searchPath = input.path ?
|
|
31392
|
+
const searchPath = input.path ? path48.isAbsolute(input.path) ? input.path : path48.resolve(context.cwd, input.path) : context.cwd;
|
|
30261
31393
|
try {
|
|
30262
31394
|
const result = await runRipgrep(input, searchPath, context);
|
|
30263
31395
|
return result;
|
|
@@ -30282,7 +31414,7 @@ __export(file_write_exports, {
|
|
|
30282
31414
|
FileWriteTool: () => FileWriteTool
|
|
30283
31415
|
});
|
|
30284
31416
|
import fs6 from "fs/promises";
|
|
30285
|
-
import
|
|
31417
|
+
import path49 from "path";
|
|
30286
31418
|
import { z as z4 } from "zod";
|
|
30287
31419
|
var inputSchema4, FileWriteTool;
|
|
30288
31420
|
var init_file_write = __esm({
|
|
@@ -30310,8 +31442,8 @@ var init_file_write = __esm({
|
|
|
30310
31442
|
return { behavior: "allow" };
|
|
30311
31443
|
},
|
|
30312
31444
|
async call(input, context) {
|
|
30313
|
-
const filePath =
|
|
30314
|
-
const dir =
|
|
31445
|
+
const filePath = path49.isAbsolute(input.file_path) ? input.file_path : path49.resolve(context.cwd, input.file_path);
|
|
31446
|
+
const dir = path49.dirname(filePath);
|
|
30315
31447
|
await fs6.mkdir(dir, { recursive: true });
|
|
30316
31448
|
await fs6.writeFile(filePath, input.content, "utf-8");
|
|
30317
31449
|
return {
|
|
@@ -30329,7 +31461,7 @@ __export(file_edit_exports, {
|
|
|
30329
31461
|
FileEditTool: () => FileEditTool
|
|
30330
31462
|
});
|
|
30331
31463
|
import fs7 from "fs/promises";
|
|
30332
|
-
import
|
|
31464
|
+
import path50 from "path";
|
|
30333
31465
|
import { z as z5 } from "zod";
|
|
30334
31466
|
function countOccurrences(haystack, needle) {
|
|
30335
31467
|
let count = 0;
|
|
@@ -30370,7 +31502,7 @@ var init_file_edit = __esm({
|
|
|
30370
31502
|
return { behavior: "allow" };
|
|
30371
31503
|
},
|
|
30372
31504
|
async call(input, context) {
|
|
30373
|
-
const filePath =
|
|
31505
|
+
const filePath = path50.isAbsolute(input.file_path) ? input.file_path : path50.resolve(context.cwd, input.file_path);
|
|
30374
31506
|
let content;
|
|
30375
31507
|
try {
|
|
30376
31508
|
content = await fs7.readFile(filePath, "utf-8");
|
|
@@ -30612,7 +31744,7 @@ var init_bash = __esm({
|
|
|
30612
31744
|
// src/tui/views/CommandCenter.tsx
|
|
30613
31745
|
import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
|
|
30614
31746
|
import TextInput from "ink-text-input";
|
|
30615
|
-
import
|
|
31747
|
+
import path51 from "path";
|
|
30616
31748
|
import { homedir as homedir6 } from "os";
|
|
30617
31749
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
30618
31750
|
function CommandCenterView({
|
|
@@ -30647,15 +31779,15 @@ function CommandCenterView({
|
|
|
30647
31779
|
const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
|
|
30648
31780
|
const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
|
|
30649
31781
|
const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
|
|
30650
|
-
const { readFileSync:
|
|
31782
|
+
const { readFileSync: readFileSync39, existsSync: existsSync43 } = await import("fs");
|
|
30651
31783
|
const { join } = await import("path");
|
|
30652
31784
|
const { homedir: homedir8 } = await import("os");
|
|
30653
31785
|
const configPath = join(homedir8(), ".exe-os", "config.json");
|
|
30654
31786
|
let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
|
|
30655
31787
|
let providerConfigs = {};
|
|
30656
|
-
if (
|
|
31788
|
+
if (existsSync43(configPath)) {
|
|
30657
31789
|
try {
|
|
30658
|
-
const raw = JSON.parse(
|
|
31790
|
+
const raw = JSON.parse(readFileSync39(configPath, "utf8"));
|
|
30659
31791
|
if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
|
|
30660
31792
|
if (raw.providers && typeof raw.providers === "object") {
|
|
30661
31793
|
providerConfigs = raw.providers;
|
|
@@ -30716,7 +31848,7 @@ function CommandCenterView({
|
|
|
30716
31848
|
const markerDir = join(homedir8(), ".exe-os", "session-cache");
|
|
30717
31849
|
const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
|
|
30718
31850
|
for (const f of agentFiles) {
|
|
30719
|
-
const data = JSON.parse(
|
|
31851
|
+
const data = JSON.parse(readFileSync39(join(markerDir, f), "utf8"));
|
|
30720
31852
|
if (data.agentRole) {
|
|
30721
31853
|
agentRole = data.agentRole;
|
|
30722
31854
|
break;
|
|
@@ -30861,7 +31993,7 @@ function CommandCenterView({
|
|
|
30861
31993
|
const demoEntries = DEMO_PROJECTS.map((p) => ({
|
|
30862
31994
|
projectName: p.projectName,
|
|
30863
31995
|
exeSession: p.exeSession,
|
|
30864
|
-
projectDir:
|
|
31996
|
+
projectDir: path51.join(homedir6(), p.projectName),
|
|
30865
31997
|
employeeCount: p.employees.length,
|
|
30866
31998
|
activeCount: p.employees.filter((e) => e.status === "active").length,
|
|
30867
31999
|
memoryCount: p.employees.length * 4e3,
|
|
@@ -30899,7 +32031,7 @@ function CommandCenterView({
|
|
|
30899
32031
|
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
30900
32032
|
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
30901
32033
|
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
30902
|
-
const { existsSync:
|
|
32034
|
+
const { existsSync: existsSync43 } = await import("fs");
|
|
30903
32035
|
const { join } = await import("path");
|
|
30904
32036
|
const client = getClient2();
|
|
30905
32037
|
if (!client) {
|
|
@@ -30970,7 +32102,7 @@ function CommandCenterView({
|
|
|
30970
32102
|
}
|
|
30971
32103
|
const memoryCount = memoryCounts.get(name) ?? 0;
|
|
30972
32104
|
const openTaskCount = openTaskCounts.get(name) ?? 0;
|
|
30973
|
-
const hasGit = projectDir ?
|
|
32105
|
+
const hasGit = projectDir ? existsSync43(join(projectDir, ".git")) : false;
|
|
30974
32106
|
const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
|
|
30975
32107
|
projectList.push({
|
|
30976
32108
|
projectName: name,
|
|
@@ -30995,7 +32127,7 @@ function CommandCenterView({
|
|
|
30995
32127
|
setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
|
|
30996
32128
|
try {
|
|
30997
32129
|
const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
|
|
30998
|
-
setHealth((h) => ({ ...h, daemon:
|
|
32130
|
+
setHealth((h) => ({ ...h, daemon: existsSync43(pidPath) ? "running" : "stopped" }));
|
|
30999
32131
|
} catch {
|
|
31000
32132
|
}
|
|
31001
32133
|
const activityResult = await client.execute(
|
|
@@ -31236,8 +32368,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
|
|
|
31236
32368
|
}
|
|
31237
32369
|
const capture = () => {
|
|
31238
32370
|
try {
|
|
31239
|
-
const { execSync:
|
|
31240
|
-
const output2 =
|
|
32371
|
+
const { execSync: execSync20 } = __require("child_process");
|
|
32372
|
+
const output2 = execSync20(
|
|
31241
32373
|
`tmux capture-pane -t ${JSON.stringify(sessionName)} -p -e 2>/dev/null | tail -${CAPTURE_LINES}`,
|
|
31242
32374
|
{ encoding: "utf8", timeout: 3e3 }
|
|
31243
32375
|
);
|
|
@@ -31261,8 +32393,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
|
|
|
31261
32393
|
if (key.return) {
|
|
31262
32394
|
if (!demo && inputBuffer.trim()) {
|
|
31263
32395
|
try {
|
|
31264
|
-
const { execSync:
|
|
31265
|
-
|
|
32396
|
+
const { execSync: execSync20 } = __require("child_process");
|
|
32397
|
+
execSync20(
|
|
31266
32398
|
`tmux send-keys -t ${JSON.stringify(sessionName)} ${JSON.stringify(inputBuffer)} Enter`,
|
|
31267
32399
|
{ timeout: 2e3 }
|
|
31268
32400
|
);
|
|
@@ -31270,8 +32402,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
|
|
|
31270
32402
|
}
|
|
31271
32403
|
} else if (!demo) {
|
|
31272
32404
|
try {
|
|
31273
|
-
const { execSync:
|
|
31274
|
-
|
|
32405
|
+
const { execSync: execSync20 } = __require("child_process");
|
|
32406
|
+
execSync20(`tmux send-keys -t ${JSON.stringify(sessionName)} Enter`, { timeout: 2e3 });
|
|
31275
32407
|
} catch {
|
|
31276
32408
|
}
|
|
31277
32409
|
}
|
|
@@ -31751,12 +32883,12 @@ function useOrchestrator(enabled = true) {
|
|
|
31751
32883
|
searchFn: async () => [],
|
|
31752
32884
|
autoApproveP2: true
|
|
31753
32885
|
});
|
|
31754
|
-
await
|
|
32886
|
+
await runHealthCheck2();
|
|
31755
32887
|
} catch {
|
|
31756
32888
|
setIsLoading(false);
|
|
31757
32889
|
}
|
|
31758
32890
|
}
|
|
31759
|
-
async function
|
|
32891
|
+
async function runHealthCheck2() {
|
|
31760
32892
|
if (cancelled || !orchestratorRef.current) return;
|
|
31761
32893
|
try {
|
|
31762
32894
|
const health = await orchestratorRef.current.healthCheck();
|
|
@@ -31785,7 +32917,7 @@ function useOrchestrator(enabled = true) {
|
|
|
31785
32917
|
setIsLoading(false);
|
|
31786
32918
|
}
|
|
31787
32919
|
init();
|
|
31788
|
-
const timer = setInterval(
|
|
32920
|
+
const timer = setInterval(runHealthCheck2, TICK_INTERVAL_MS);
|
|
31789
32921
|
return () => {
|
|
31790
32922
|
cancelled = true;
|
|
31791
32923
|
clearInterval(timer);
|
|
@@ -31865,7 +32997,7 @@ var init_useOrchestrator = __esm({
|
|
|
31865
32997
|
|
|
31866
32998
|
// src/tui/views/Sessions.tsx
|
|
31867
32999
|
import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
|
|
31868
|
-
import
|
|
33000
|
+
import path52 from "path";
|
|
31869
33001
|
import { homedir as homedir7 } from "os";
|
|
31870
33002
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
31871
33003
|
function isCoordinatorEntry(entry) {
|
|
@@ -31903,7 +33035,7 @@ function SessionsView({
|
|
|
31903
33035
|
if (demo) {
|
|
31904
33036
|
setProjects(DEMO_PROJECTS.map((p) => ({
|
|
31905
33037
|
...p,
|
|
31906
|
-
projectDir:
|
|
33038
|
+
projectDir: path52.join(homedir7(), p.projectName),
|
|
31907
33039
|
employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
|
|
31908
33040
|
})));
|
|
31909
33041
|
return;
|
|
@@ -31958,12 +33090,12 @@ function SessionsView({
|
|
|
31958
33090
|
return;
|
|
31959
33091
|
}
|
|
31960
33092
|
} else {
|
|
31961
|
-
const { execSync:
|
|
33093
|
+
const { execSync: execSync20 } = await import("child_process");
|
|
31962
33094
|
const dir = projectDir || process.cwd();
|
|
31963
|
-
|
|
31964
|
-
|
|
33095
|
+
execSync20(`tmux new-session -d -s ${JSON.stringify(entry.sessionName)} -c ${JSON.stringify(dir)}`, { timeout: 5e3 });
|
|
33096
|
+
execSync20(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "claude --dangerously-skip-permissions" Enter`, { timeout: 3e3 });
|
|
31965
33097
|
await new Promise((r) => setTimeout(r, 3e3));
|
|
31966
|
-
|
|
33098
|
+
execSync20(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "/exe" Enter`, { timeout: 3e3 });
|
|
31967
33099
|
}
|
|
31968
33100
|
const updated = { ...entry, status: "active", activity: "Starting...", attached: false };
|
|
31969
33101
|
setViewingEmployee(updated);
|
|
@@ -32066,7 +33198,7 @@ function SessionsView({
|
|
|
32066
33198
|
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2, capturePaneLines: capturePaneLines2, parseActivity: parseActivity2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
32067
33199
|
const { getCoordinatorName: getCoordinatorName2, isCoordinatorRole: isCoordinatorRole2, loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
32068
33200
|
const { isExeSession: isExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
32069
|
-
const { execSync:
|
|
33201
|
+
const { execSync: execSync20 } = await import("child_process");
|
|
32070
33202
|
if (!inTmux2()) {
|
|
32071
33203
|
setTmuxAvailable(false);
|
|
32072
33204
|
setProjects([]);
|
|
@@ -32075,7 +33207,7 @@ function SessionsView({
|
|
|
32075
33207
|
setTmuxAvailable(true);
|
|
32076
33208
|
const attachedMap = /* @__PURE__ */ new Map();
|
|
32077
33209
|
try {
|
|
32078
|
-
const out =
|
|
33210
|
+
const out = execSync20("tmux list-sessions -F '#{session_name}:#{session_attached}' 2>/dev/null", {
|
|
32079
33211
|
encoding: "utf8",
|
|
32080
33212
|
timeout: 3e3
|
|
32081
33213
|
});
|
|
@@ -33111,19 +34243,19 @@ function upsertConversation(conversations, platform, senderId, message) {
|
|
|
33111
34243
|
async function loadGatewayConfig() {
|
|
33112
34244
|
const state = { running: false, port: 3100, adapters: [], agents: [], gatewayUrl: "" };
|
|
33113
34245
|
try {
|
|
33114
|
-
const { execSync:
|
|
33115
|
-
const ps =
|
|
34246
|
+
const { execSync: execSync20 } = await import("child_process");
|
|
34247
|
+
const ps = execSync20("pgrep -f exe-gateway 2>/dev/null", { encoding: "utf8", timeout: 3e3 });
|
|
33116
34248
|
state.running = ps.trim().length > 0;
|
|
33117
34249
|
} catch {
|
|
33118
34250
|
state.running = false;
|
|
33119
34251
|
}
|
|
33120
34252
|
try {
|
|
33121
|
-
const { existsSync:
|
|
34253
|
+
const { existsSync: existsSync43, readFileSync: readFileSync39 } = await import("fs");
|
|
33122
34254
|
const { join } = await import("path");
|
|
33123
34255
|
const home = process.env.HOME ?? "";
|
|
33124
34256
|
const configPath = join(home, ".exe-os", "gateway.json");
|
|
33125
|
-
if (
|
|
33126
|
-
const raw = JSON.parse(
|
|
34257
|
+
if (existsSync43(configPath)) {
|
|
34258
|
+
const raw = JSON.parse(readFileSync39(configPath, "utf8"));
|
|
33127
34259
|
state.port = raw.port ?? 3100;
|
|
33128
34260
|
state.gatewayUrl = raw.gatewayUrl ?? "";
|
|
33129
34261
|
if (raw.adapters) {
|
|
@@ -33589,10 +34721,10 @@ var init_Gateway = __esm({
|
|
|
33589
34721
|
});
|
|
33590
34722
|
|
|
33591
34723
|
// src/tui/utils/agent-status.ts
|
|
33592
|
-
import { execSync as
|
|
34724
|
+
import { execSync as execSync19 } from "child_process";
|
|
33593
34725
|
function getAgentStatus(agentId) {
|
|
33594
34726
|
try {
|
|
33595
|
-
const sessions =
|
|
34727
|
+
const sessions = execSync19("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
|
|
33596
34728
|
encoding: "utf8",
|
|
33597
34729
|
timeout: 2e3
|
|
33598
34730
|
}).trim().split("\n");
|
|
@@ -33603,7 +34735,7 @@ function getAgentStatus(agentId) {
|
|
|
33603
34735
|
return /^\d?-/.test(suffix) || /^\d+$/.test(suffix);
|
|
33604
34736
|
});
|
|
33605
34737
|
if (!agentSession) return { label: "offline", color: "gray" };
|
|
33606
|
-
const pane =
|
|
34738
|
+
const pane = execSync19(`tmux capture-pane -t "${agentSession}" -p 2>/dev/null | tail -3`, {
|
|
33607
34739
|
encoding: "utf8",
|
|
33608
34740
|
timeout: 2e3
|
|
33609
34741
|
});
|
|
@@ -33721,12 +34853,12 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
33721
34853
|
setMembers(teamData);
|
|
33722
34854
|
setDbError(null);
|
|
33723
34855
|
try {
|
|
33724
|
-
const { existsSync:
|
|
34856
|
+
const { existsSync: existsSync43, readFileSync: readFileSync39 } = await import("fs");
|
|
33725
34857
|
const { join } = await import("path");
|
|
33726
34858
|
const home = process.env.HOME ?? "";
|
|
33727
34859
|
const gatewayConfig = join(home, ".exe-os", "gateway.json");
|
|
33728
|
-
if (
|
|
33729
|
-
const raw = JSON.parse(
|
|
34860
|
+
if (existsSync43(gatewayConfig)) {
|
|
34861
|
+
const raw = JSON.parse(readFileSync39(gatewayConfig, "utf8"));
|
|
33730
34862
|
if (raw.agents && raw.agents.length > 0) {
|
|
33731
34863
|
setExternals(raw.agents.map((a) => ({
|
|
33732
34864
|
name: a.name,
|
|
@@ -33906,8 +35038,8 @@ __export(wiki_client_exports, {
|
|
|
33906
35038
|
listDocuments: () => listDocuments,
|
|
33907
35039
|
listWorkspaces: () => listWorkspaces
|
|
33908
35040
|
});
|
|
33909
|
-
async function wikiFetch(config,
|
|
33910
|
-
const url = `${config.baseUrl}/api/v1${
|
|
35041
|
+
async function wikiFetch(config, path58, method = "GET", body) {
|
|
35042
|
+
const url = `${config.baseUrl}/api/v1${path58}`;
|
|
33911
35043
|
const headers = {
|
|
33912
35044
|
Authorization: `Bearer ${config.apiKey}`,
|
|
33913
35045
|
"Content-Type": "application/json"
|
|
@@ -33940,7 +35072,7 @@ async function wikiFetch(config, path56, method = "GET", body) {
|
|
|
33940
35072
|
}
|
|
33941
35073
|
}
|
|
33942
35074
|
if (!response.ok) {
|
|
33943
|
-
throw new Error(`Wiki API ${method} ${
|
|
35075
|
+
throw new Error(`Wiki API ${method} ${path58}: ${response.status} ${response.statusText}`);
|
|
33944
35076
|
}
|
|
33945
35077
|
return response.json();
|
|
33946
35078
|
} finally {
|
|
@@ -34526,20 +35658,20 @@ function SettingsView({ onBack }) {
|
|
|
34526
35658
|
};
|
|
34527
35659
|
});
|
|
34528
35660
|
try {
|
|
34529
|
-
const { execSync:
|
|
34530
|
-
|
|
35661
|
+
const { execSync: execSync20 } = await import("child_process");
|
|
35662
|
+
execSync20("curl -s --max-time 1 http://localhost:11434/api/tags", { timeout: 2e3 });
|
|
34531
35663
|
providerList.push({ name: "Ollama", configured: true, detail: "localhost:11434" });
|
|
34532
35664
|
} catch {
|
|
34533
35665
|
providerList.push({ name: "Ollama", configured: false, detail: "not running" });
|
|
34534
35666
|
}
|
|
34535
35667
|
setProviders(providerList);
|
|
34536
35668
|
try {
|
|
34537
|
-
const { existsSync:
|
|
35669
|
+
const { existsSync: existsSync43 } = await import("fs");
|
|
34538
35670
|
const { join } = await import("path");
|
|
34539
35671
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
34540
35672
|
const cfg = await loadConfig2();
|
|
34541
35673
|
const home = process.env.HOME ?? "";
|
|
34542
|
-
const hasKey =
|
|
35674
|
+
const hasKey = existsSync43(join(home, ".exe-os", "master.key"));
|
|
34543
35675
|
if (cfg.cloud) {
|
|
34544
35676
|
setCloud({
|
|
34545
35677
|
configured: true,
|
|
@@ -34552,22 +35684,22 @@ function SettingsView({ onBack }) {
|
|
|
34552
35684
|
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
34553
35685
|
let daemon = "unknown";
|
|
34554
35686
|
try {
|
|
34555
|
-
daemon =
|
|
35687
|
+
daemon = existsSync43(pidPath) ? "running" : "stopped";
|
|
34556
35688
|
} catch {
|
|
34557
35689
|
}
|
|
34558
35690
|
let version = "unknown";
|
|
34559
35691
|
try {
|
|
34560
|
-
const { readFileSync:
|
|
35692
|
+
const { readFileSync: readFileSync39 } = await import("fs");
|
|
34561
35693
|
const { createRequire: createRequire3 } = await import("module");
|
|
34562
35694
|
const require2 = createRequire3(import.meta.url);
|
|
34563
35695
|
const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
|
|
34564
|
-
const pkg = JSON.parse(
|
|
35696
|
+
const pkg = JSON.parse(readFileSync39(pkgPath, "utf8"));
|
|
34565
35697
|
version = pkg.version;
|
|
34566
35698
|
} catch {
|
|
34567
35699
|
try {
|
|
34568
|
-
const { readFileSync:
|
|
35700
|
+
const { readFileSync: readFileSync39 } = await import("fs");
|
|
34569
35701
|
const { join: joinPath } = await import("path");
|
|
34570
|
-
const pkg = JSON.parse(
|
|
35702
|
+
const pkg = JSON.parse(readFileSync39(joinPath(process.cwd(), "package.json"), "utf8"));
|
|
34571
35703
|
version = pkg.version;
|
|
34572
35704
|
} catch {
|
|
34573
35705
|
}
|
|
@@ -35426,18 +36558,18 @@ __export(code_context_index_exports, {
|
|
|
35426
36558
|
traceCodeSymbol: () => traceCodeSymbol
|
|
35427
36559
|
});
|
|
35428
36560
|
import crypto14 from "crypto";
|
|
35429
|
-
import
|
|
35430
|
-
import { existsSync as
|
|
36561
|
+
import path53 from "path";
|
|
36562
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync26, readFileSync as readFileSync34, readdirSync as readdirSync12, statSync as statSync8, writeFileSync as writeFileSync27 } from "fs";
|
|
35431
36563
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
35432
36564
|
function vectorStorePath(projectRoot) {
|
|
35433
36565
|
const rootHash = hashText(projectRoot).slice(0, 16);
|
|
35434
|
-
return
|
|
36566
|
+
return path53.join(indexDir(), `${rootHash}.vectors.json`);
|
|
35435
36567
|
}
|
|
35436
36568
|
function loadVectorStore(projectRoot) {
|
|
35437
36569
|
const file = vectorStorePath(projectRoot);
|
|
35438
|
-
if (!
|
|
36570
|
+
if (!existsSync38(file)) return null;
|
|
35439
36571
|
try {
|
|
35440
|
-
const parsed = JSON.parse(
|
|
36572
|
+
const parsed = JSON.parse(readFileSync34(file, "utf8"));
|
|
35441
36573
|
if (parsed.version !== VECTOR_STORE_VERSION) return null;
|
|
35442
36574
|
return parsed;
|
|
35443
36575
|
} catch {
|
|
@@ -35445,7 +36577,7 @@ function loadVectorStore(projectRoot) {
|
|
|
35445
36577
|
}
|
|
35446
36578
|
}
|
|
35447
36579
|
function saveVectorStore(projectRoot, store) {
|
|
35448
|
-
|
|
36580
|
+
writeFileSync27(vectorStorePath(projectRoot), JSON.stringify(store));
|
|
35449
36581
|
}
|
|
35450
36582
|
function cosineSimilarity(a, b) {
|
|
35451
36583
|
let dot = 0, normA = 0, normB = 0;
|
|
@@ -35501,20 +36633,20 @@ async function embedSymbols(index) {
|
|
|
35501
36633
|
return store;
|
|
35502
36634
|
}
|
|
35503
36635
|
function normalizeProjectRoot(projectRoot) {
|
|
35504
|
-
return
|
|
36636
|
+
return path53.resolve(projectRoot || process.cwd());
|
|
35505
36637
|
}
|
|
35506
36638
|
function hashText(text) {
|
|
35507
36639
|
return crypto14.createHash("sha256").update(text).digest("hex");
|
|
35508
36640
|
}
|
|
35509
36641
|
function indexDir() {
|
|
35510
|
-
const dir =
|
|
35511
|
-
|
|
36642
|
+
const dir = path53.join(EXE_AI_DIR, "code-context");
|
|
36643
|
+
mkdirSync26(dir, { recursive: true });
|
|
35512
36644
|
return dir;
|
|
35513
36645
|
}
|
|
35514
36646
|
function getCodeContextIndexPath(projectRoot) {
|
|
35515
36647
|
const root = normalizeProjectRoot(projectRoot);
|
|
35516
36648
|
const rootHash = hashText(root).slice(0, 16);
|
|
35517
|
-
return
|
|
36649
|
+
return path53.join(indexDir(), `${rootHash}.json`);
|
|
35518
36650
|
}
|
|
35519
36651
|
function currentBranch(projectRoot) {
|
|
35520
36652
|
const result = spawnSync3("git", ["branch", "--show-current"], { cwd: projectRoot, encoding: "utf8", timeout: 2e3 });
|
|
@@ -35526,9 +36658,9 @@ function shouldIgnore(relPath) {
|
|
|
35526
36658
|
return parts.some((part) => IGNORE_SEGMENTS.has(part));
|
|
35527
36659
|
}
|
|
35528
36660
|
function listRecursive(projectRoot, dir = projectRoot, out = []) {
|
|
35529
|
-
for (const entry of
|
|
35530
|
-
const abs =
|
|
35531
|
-
const rel =
|
|
36661
|
+
for (const entry of readdirSync12(dir, { withFileTypes: true })) {
|
|
36662
|
+
const abs = path53.join(dir, entry.name);
|
|
36663
|
+
const rel = path53.relative(projectRoot, abs).replaceAll(path53.sep, "/");
|
|
35532
36664
|
if (shouldIgnore(rel)) continue;
|
|
35533
36665
|
if (entry.isDirectory()) listRecursive(projectRoot, abs, out);
|
|
35534
36666
|
else if (entry.isFile()) out.push(rel);
|
|
@@ -35544,7 +36676,7 @@ function listCodeFiles(projectRoot, maxFiles) {
|
|
|
35544
36676
|
const rg = spawnSync3("rg", ["--files"], { cwd: projectRoot, encoding: "utf8", timeout: 5e3, maxBuffer: 1024 * 1024 * 16 });
|
|
35545
36677
|
files = rg.status === 0 && rg.stdout.trim() ? rg.stdout.split("\n").map((s) => s.trim()).filter(Boolean) : listRecursive(projectRoot);
|
|
35546
36678
|
}
|
|
35547
|
-
return files.map((file) => file.replaceAll(
|
|
36679
|
+
return files.map((file) => file.replaceAll(path53.sep, "/")).filter((file) => isChunkable(file) && !shouldIgnore(file)).slice(0, maxFiles).sort();
|
|
35548
36680
|
}
|
|
35549
36681
|
function parseImportPaths(importText) {
|
|
35550
36682
|
const paths = [];
|
|
@@ -35557,13 +36689,13 @@ function parseImportPaths(importText) {
|
|
|
35557
36689
|
}
|
|
35558
36690
|
function resolveImport(fromFile, importPath, allFiles) {
|
|
35559
36691
|
if (!importPath.startsWith(".")) return null;
|
|
35560
|
-
const base =
|
|
36692
|
+
const base = path53.posix.normalize(path53.posix.join(path53.posix.dirname(fromFile.replaceAll(path53.sep, "/")), importPath));
|
|
35561
36693
|
const withoutKnownExt = base.replace(/\.(?:[a-z0-9]+)$/i, "");
|
|
35562
36694
|
const candidates = [base];
|
|
35563
36695
|
for (const ext of ["ts", "tsx", "js", "jsx", "py", "rs", "go", "java", "cs", "cpp", "c", "rb", "php", "swift", "kt", "scala", "sql", "md", "json", "yaml", "yml"]) {
|
|
35564
36696
|
candidates.push(`${withoutKnownExt}.${ext}`, `${base}.${ext}`);
|
|
35565
36697
|
}
|
|
35566
|
-
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(
|
|
36698
|
+
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(path53.posix.join(base, indexName));
|
|
35567
36699
|
return candidates.find((candidate) => allFiles.has(candidate)) ?? null;
|
|
35568
36700
|
}
|
|
35569
36701
|
function symbolId(filePath, chunk) {
|
|
@@ -35571,9 +36703,9 @@ function symbolId(filePath, chunk) {
|
|
|
35571
36703
|
}
|
|
35572
36704
|
function loadIndex(projectRoot) {
|
|
35573
36705
|
const file = getCodeContextIndexPath(projectRoot);
|
|
35574
|
-
if (!
|
|
36706
|
+
if (!existsSync38(file)) return null;
|
|
35575
36707
|
try {
|
|
35576
|
-
const parsed = JSON.parse(
|
|
36708
|
+
const parsed = JSON.parse(readFileSync34(file, "utf8"));
|
|
35577
36709
|
if (parsed.version !== INDEX_VERSION || parsed.projectRoot !== projectRoot) return null;
|
|
35578
36710
|
return parsed;
|
|
35579
36711
|
} catch {
|
|
@@ -35581,20 +36713,20 @@ function loadIndex(projectRoot) {
|
|
|
35581
36713
|
}
|
|
35582
36714
|
}
|
|
35583
36715
|
function saveIndex(index) {
|
|
35584
|
-
|
|
36716
|
+
writeFileSync27(getCodeContextIndexPath(index.projectRoot), JSON.stringify(index, null, 2));
|
|
35585
36717
|
}
|
|
35586
36718
|
function buildFileRecord(projectRoot, relPath, allFiles, previous) {
|
|
35587
|
-
const absPath =
|
|
36719
|
+
const absPath = path53.join(projectRoot, relPath);
|
|
35588
36720
|
let stat2;
|
|
35589
36721
|
try {
|
|
35590
|
-
stat2 =
|
|
36722
|
+
stat2 = statSync8(absPath);
|
|
35591
36723
|
} catch {
|
|
35592
36724
|
return { record: null, reused: false };
|
|
35593
36725
|
}
|
|
35594
36726
|
if (!stat2.isFile()) return { record: null, reused: false };
|
|
35595
36727
|
const language = languageForFile(relPath);
|
|
35596
36728
|
if (!language || !isChunkable(relPath)) return { record: null, reused: false };
|
|
35597
|
-
const source =
|
|
36729
|
+
const source = readFileSync34(absPath, "utf8");
|
|
35598
36730
|
const hash = hashText(source);
|
|
35599
36731
|
if (previous && previous.hash === hash && previous.mtimeMs === stat2.mtimeMs && previous.size === stat2.size && previous.language === language) {
|
|
35600
36732
|
return { record: previous, reused: true };
|
|
@@ -35622,13 +36754,13 @@ function buildCodeContextIndex(options = {}) {
|
|
|
35622
36754
|
const branch = currentBranch(projectRoot);
|
|
35623
36755
|
const previous = options.force ? null : loadIndex(projectRoot);
|
|
35624
36756
|
const files = listCodeFiles(projectRoot, maxFiles);
|
|
35625
|
-
const allFiles = new Set(files.map((file) => file.replaceAll(
|
|
36757
|
+
const allFiles = new Set(files.map((file) => file.replaceAll(path53.sep, "/")));
|
|
35626
36758
|
const fileRecords = {};
|
|
35627
36759
|
let rebuiltFiles = 0;
|
|
35628
36760
|
let reusedFiles = 0;
|
|
35629
36761
|
let skippedFiles = 0;
|
|
35630
36762
|
for (const rel of files) {
|
|
35631
|
-
const normalized = rel.replaceAll(
|
|
36763
|
+
const normalized = rel.replaceAll(path53.sep, "/");
|
|
35632
36764
|
const { record, reused } = buildFileRecord(projectRoot, normalized, allFiles, previous?.files[normalized]);
|
|
35633
36765
|
if (record) {
|
|
35634
36766
|
fileRecords[normalized] = record;
|
|
@@ -35657,11 +36789,11 @@ function loadOrBuildCodeContextIndex(options = {}) {
|
|
|
35657
36789
|
if (loaded) {
|
|
35658
36790
|
const currentFiles = listCodeFiles(projectRoot, options.maxFiles ?? DEFAULT_MAX_FILES);
|
|
35659
36791
|
const unchanged = currentFiles.every((rel) => {
|
|
35660
|
-
const normalized = rel.replaceAll(
|
|
36792
|
+
const normalized = rel.replaceAll(path53.sep, "/");
|
|
35661
36793
|
const existing = loaded.files[normalized];
|
|
35662
36794
|
if (!existing) return false;
|
|
35663
36795
|
try {
|
|
35664
|
-
const stat2 =
|
|
36796
|
+
const stat2 = statSync8(path53.join(projectRoot, normalized));
|
|
35665
36797
|
return stat2.mtimeMs === existing.mtimeMs && stat2.size === existing.size;
|
|
35666
36798
|
} catch {
|
|
35667
36799
|
return false;
|
|
@@ -35714,9 +36846,9 @@ function globToRegex(pattern) {
|
|
|
35714
36846
|
}
|
|
35715
36847
|
function matchesPath(filePath, patterns) {
|
|
35716
36848
|
if (!patterns || patterns.length === 0) return true;
|
|
35717
|
-
const normalized = filePath.replaceAll(
|
|
36849
|
+
const normalized = filePath.replaceAll(path53.sep, "/");
|
|
35718
36850
|
return patterns.some((pattern) => {
|
|
35719
|
-
const p = pattern.replaceAll(
|
|
36851
|
+
const p = pattern.replaceAll(path53.sep, "/").replace(/^\.\//, "");
|
|
35720
36852
|
return normalized === p || normalized.startsWith(`${p}/`) || normalized.endsWith(p) || globToRegex(p).test(normalized);
|
|
35721
36853
|
});
|
|
35722
36854
|
}
|
|
@@ -35909,7 +37041,7 @@ function traceCodeSymbol(symbolName, options = {}) {
|
|
|
35909
37041
|
}
|
|
35910
37042
|
function resolveTargetFile(index, input) {
|
|
35911
37043
|
if (input.filePath) {
|
|
35912
|
-
const normalized = input.filePath.replaceAll(
|
|
37044
|
+
const normalized = input.filePath.replaceAll(path53.sep, "/").replace(/^\.\//, "");
|
|
35913
37045
|
if (index.files[normalized]) return { filePath: normalized, target: normalized };
|
|
35914
37046
|
const suffix = Object.keys(index.files).find((file) => file.endsWith(normalized));
|
|
35915
37047
|
if (suffix) return { filePath: suffix, target: input.filePath };
|
|
@@ -35939,7 +37071,7 @@ function analyzeBlastRadius(input) {
|
|
|
35939
37071
|
}
|
|
35940
37072
|
}
|
|
35941
37073
|
}
|
|
35942
|
-
const targetBase =
|
|
37074
|
+
const targetBase = path53.basename(target.filePath).replace(/\.[^.]+$/, "").toLowerCase();
|
|
35943
37075
|
const symbolLower = input.symbol?.toLowerCase();
|
|
35944
37076
|
const tests = Object.keys(index.files).filter((file) => {
|
|
35945
37077
|
const lower = file.toLowerCase();
|
|
@@ -36176,16 +37308,16 @@ __export(installer_exports2, {
|
|
|
36176
37308
|
verifyOpenCodeHooks: () => verifyOpenCodeHooks
|
|
36177
37309
|
});
|
|
36178
37310
|
import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
|
|
36179
|
-
import { existsSync as
|
|
36180
|
-
import
|
|
37311
|
+
import { existsSync as existsSync39, readFileSync as readFileSync35 } from "fs";
|
|
37312
|
+
import path54 from "path";
|
|
36181
37313
|
import os22 from "os";
|
|
36182
37314
|
async function registerOpenCodeMcp(packageRoot, homeDir = os22.homedir()) {
|
|
36183
37315
|
void packageRoot;
|
|
36184
|
-
const configDir =
|
|
36185
|
-
const configPath =
|
|
37316
|
+
const configDir = path54.join(homeDir, ".config", "opencode");
|
|
37317
|
+
const configPath = path54.join(configDir, "opencode.json");
|
|
36186
37318
|
await mkdir8(configDir, { recursive: true });
|
|
36187
37319
|
let config = {};
|
|
36188
|
-
if (
|
|
37320
|
+
if (existsSync39(configPath)) {
|
|
36189
37321
|
try {
|
|
36190
37322
|
config = JSON.parse(await readFile7(configPath, "utf-8"));
|
|
36191
37323
|
} catch {
|
|
@@ -36213,14 +37345,14 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os22.homedir()) {
|
|
|
36213
37345
|
return true;
|
|
36214
37346
|
}
|
|
36215
37347
|
async function installOpenCodePlugin(packageRoot, homeDir = os22.homedir()) {
|
|
36216
|
-
const pluginDir =
|
|
36217
|
-
const pluginPath =
|
|
37348
|
+
const pluginDir = path54.join(homeDir, ".config", "opencode", "plugins");
|
|
37349
|
+
const pluginPath = path54.join(pluginDir, "exe-os.mjs");
|
|
36218
37350
|
await mkdir8(pluginDir, { recursive: true });
|
|
36219
37351
|
const pluginContent = PLUGIN_TEMPLATE.replace(
|
|
36220
37352
|
/__PACKAGE_ROOT__/g,
|
|
36221
37353
|
packageRoot.replace(/\\/g, "\\\\")
|
|
36222
37354
|
);
|
|
36223
|
-
if (
|
|
37355
|
+
if (existsSync39(pluginPath)) {
|
|
36224
37356
|
const existing = await readFile7(pluginPath, "utf-8");
|
|
36225
37357
|
if (existing === pluginContent) {
|
|
36226
37358
|
return false;
|
|
@@ -36230,18 +37362,18 @@ async function installOpenCodePlugin(packageRoot, homeDir = os22.homedir()) {
|
|
|
36230
37362
|
return true;
|
|
36231
37363
|
}
|
|
36232
37364
|
function verifyOpenCodeHooks(homeDir = os22.homedir()) {
|
|
36233
|
-
const configPath =
|
|
36234
|
-
const pluginPath =
|
|
36235
|
-
if (!
|
|
37365
|
+
const configPath = path54.join(homeDir, ".config", "opencode", "opencode.json");
|
|
37366
|
+
const pluginPath = path54.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
|
|
37367
|
+
if (!existsSync39(configPath)) return false;
|
|
36236
37368
|
try {
|
|
36237
|
-
const config = JSON.parse(
|
|
37369
|
+
const config = JSON.parse(readFileSync35(configPath, "utf-8"));
|
|
36238
37370
|
if (!config.mcp?.["exe-os"]?.enabled) return false;
|
|
36239
37371
|
} catch {
|
|
36240
37372
|
return false;
|
|
36241
37373
|
}
|
|
36242
|
-
if (!
|
|
37374
|
+
if (!existsSync39(pluginPath)) return false;
|
|
36243
37375
|
try {
|
|
36244
|
-
const plugin =
|
|
37376
|
+
const plugin = readFileSync35(pluginPath, "utf-8");
|
|
36245
37377
|
if (!plugin.includes(EXE_HOOK_FILES.postToolCombined)) return false;
|
|
36246
37378
|
if (textHasLegacySplitPostToolHook(plugin)) return false;
|
|
36247
37379
|
} catch {
|
|
@@ -36283,19 +37415,19 @@ __export(installer_exports3, {
|
|
|
36283
37415
|
verifyCodexHooks: () => verifyCodexHooks
|
|
36284
37416
|
});
|
|
36285
37417
|
import { readFile as readFile8, writeFile as writeFile9, mkdir as mkdir9 } from "fs/promises";
|
|
36286
|
-
import { existsSync as
|
|
36287
|
-
import
|
|
37418
|
+
import { existsSync as existsSync40, readFileSync as readFileSync36 } from "fs";
|
|
37419
|
+
import path55 from "path";
|
|
36288
37420
|
import os23 from "os";
|
|
36289
37421
|
async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
|
|
36290
|
-
const codexDir =
|
|
36291
|
-
const hooksPath =
|
|
36292
|
-
const logsDir =
|
|
36293
|
-
const hookLogPath =
|
|
37422
|
+
const codexDir = path55.join(homeDir, ".codex");
|
|
37423
|
+
const hooksPath = path55.join(codexDir, "hooks.json");
|
|
37424
|
+
const logsDir = path55.join(homeDir, ".exe-os", "logs");
|
|
37425
|
+
const hookLogPath = path55.join(logsDir, "hooks.log");
|
|
36294
37426
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
36295
37427
|
await mkdir9(codexDir, { recursive: true });
|
|
36296
37428
|
await mkdir9(logsDir, { recursive: true });
|
|
36297
37429
|
let hooksJson = {};
|
|
36298
|
-
if (
|
|
37430
|
+
if (existsSync40(hooksPath)) {
|
|
36299
37431
|
try {
|
|
36300
37432
|
hooksJson = JSON.parse(await readFile8(hooksPath, "utf-8"));
|
|
36301
37433
|
} catch {
|
|
@@ -36315,7 +37447,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
|
|
|
36315
37447
|
// Combined hook: runs ingest + error-recall in one Node process.
|
|
36316
37448
|
// Eliminates a cold-start cycle per tool call (~3-6s savings on Codex).
|
|
36317
37449
|
type: "command",
|
|
36318
|
-
command: `node "${
|
|
37450
|
+
command: `node "${path55.join(packageRoot, "dist", "hooks", "post-tool-combined.js")}"${logSuffix}`
|
|
36319
37451
|
}
|
|
36320
37452
|
]
|
|
36321
37453
|
},
|
|
@@ -36329,7 +37461,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
|
|
|
36329
37461
|
// Single hook: prompt-submit handles memory retrieval + entity boost.
|
|
36330
37462
|
// exe-heartbeat-hook is CC-specific (intercom) — omitted on Codex.
|
|
36331
37463
|
type: "command",
|
|
36332
|
-
command: `node "${
|
|
37464
|
+
command: `node "${path55.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
|
|
36333
37465
|
}
|
|
36334
37466
|
]
|
|
36335
37467
|
},
|
|
@@ -36341,7 +37473,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
|
|
|
36341
37473
|
hooks: [
|
|
36342
37474
|
{
|
|
36343
37475
|
type: "command",
|
|
36344
|
-
command: `node "${
|
|
37476
|
+
command: `node "${path55.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
|
|
36345
37477
|
}
|
|
36346
37478
|
]
|
|
36347
37479
|
},
|
|
@@ -36354,7 +37486,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
|
|
|
36354
37486
|
hooks: [
|
|
36355
37487
|
{
|
|
36356
37488
|
type: "command",
|
|
36357
|
-
command: `node "${
|
|
37489
|
+
command: `node "${path55.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
|
|
36358
37490
|
}
|
|
36359
37491
|
]
|
|
36360
37492
|
},
|
|
@@ -36403,10 +37535,10 @@ async function mergeCodexHooks(packageRoot, homeDir = os23.homedir()) {
|
|
|
36403
37535
|
return { added, skipped };
|
|
36404
37536
|
}
|
|
36405
37537
|
function verifyCodexHooks(homeDir = os23.homedir()) {
|
|
36406
|
-
const hooksPath =
|
|
36407
|
-
if (!
|
|
37538
|
+
const hooksPath = path55.join(homeDir, ".codex", "hooks.json");
|
|
37539
|
+
if (!existsSync40(hooksPath)) return false;
|
|
36408
37540
|
try {
|
|
36409
|
-
const hooksJson = JSON.parse(
|
|
37541
|
+
const hooksJson = JSON.parse(readFileSync36(hooksPath, "utf-8"));
|
|
36410
37542
|
if (!hooksJson.hooks) return false;
|
|
36411
37543
|
const required = ["PostToolUse", "UserPromptSubmit", "Stop", "PreToolUse"];
|
|
36412
37544
|
for (const event of required) {
|
|
@@ -36438,11 +37570,11 @@ function verifyCodexHooks(homeDir = os23.homedir()) {
|
|
|
36438
37570
|
async function installCodexStatusLine(homeDir = os23.homedir()) {
|
|
36439
37571
|
const prefs = loadPreferences(homeDir);
|
|
36440
37572
|
if (prefs.codexStatusLine === false) return "opted-out";
|
|
36441
|
-
const codexDir =
|
|
36442
|
-
const configPath =
|
|
37573
|
+
const codexDir = path55.join(homeDir, ".codex");
|
|
37574
|
+
const configPath = path55.join(codexDir, "config.toml");
|
|
36443
37575
|
await mkdir9(codexDir, { recursive: true });
|
|
36444
37576
|
let content = "";
|
|
36445
|
-
if (
|
|
37577
|
+
if (existsSync40(configPath)) {
|
|
36446
37578
|
content = await readFile8(configPath, "utf-8");
|
|
36447
37579
|
if (/\[tui\][\s\S]*?status_line\s*=/.test(content)) {
|
|
36448
37580
|
return "already-configured";
|
|
@@ -36494,12 +37626,12 @@ ${line}
|
|
|
36494
37626
|
return { content: next, changed: next !== sectionContent };
|
|
36495
37627
|
}
|
|
36496
37628
|
async function registerCodexMcpServer(packageRoot, homeDir = os23.homedir()) {
|
|
36497
|
-
const codexDir =
|
|
36498
|
-
const configPath =
|
|
37629
|
+
const codexDir = path55.join(homeDir, ".codex");
|
|
37630
|
+
const configPath = path55.join(codexDir, "config.toml");
|
|
36499
37631
|
void packageRoot;
|
|
36500
37632
|
await mkdir9(codexDir, { recursive: true });
|
|
36501
37633
|
let content = "";
|
|
36502
|
-
if (
|
|
37634
|
+
if (existsSync40(configPath)) {
|
|
36503
37635
|
content = await readFile8(configPath, "utf-8");
|
|
36504
37636
|
}
|
|
36505
37637
|
const sectionHeader = "[mcp_servers.exe-os]";
|
|
@@ -36524,10 +37656,10 @@ async function registerCodexMcpServer(packageRoot, homeDir = os23.homedir()) {
|
|
|
36524
37656
|
return "registered";
|
|
36525
37657
|
}
|
|
36526
37658
|
async function ensureCodexHooksFeature(homeDir = os23.homedir()) {
|
|
36527
|
-
const configPath =
|
|
36528
|
-
await mkdir9(
|
|
37659
|
+
const configPath = path55.join(homeDir, ".codex", "config.toml");
|
|
37660
|
+
await mkdir9(path55.join(homeDir, ".codex"), { recursive: true });
|
|
36529
37661
|
let content = "";
|
|
36530
|
-
if (
|
|
37662
|
+
if (existsSync40(configPath)) {
|
|
36531
37663
|
content = await readFile8(configPath, "utf-8");
|
|
36532
37664
|
}
|
|
36533
37665
|
if (/\[features\][\s\S]*?codex_hooks\s*=\s*true/.test(content)) {
|
|
@@ -36602,32 +37734,32 @@ __export(mcp_diagnostics_exports, {
|
|
|
36602
37734
|
diagnoseClaudeMcpConfig: () => diagnoseClaudeMcpConfig,
|
|
36603
37735
|
formatMcpDiagnosticReport: () => formatMcpDiagnosticReport
|
|
36604
37736
|
});
|
|
36605
|
-
import { existsSync as
|
|
36606
|
-
import
|
|
37737
|
+
import { existsSync as existsSync41, readFileSync as readFileSync37 } from "fs";
|
|
37738
|
+
import path56 from "path";
|
|
36607
37739
|
import os24 from "os";
|
|
36608
37740
|
function readJson(filePath) {
|
|
36609
|
-
if (!
|
|
37741
|
+
if (!existsSync41(filePath)) return null;
|
|
36610
37742
|
try {
|
|
36611
|
-
return JSON.parse(
|
|
37743
|
+
return JSON.parse(readFileSync37(filePath, "utf8"));
|
|
36612
37744
|
} catch {
|
|
36613
37745
|
return null;
|
|
36614
37746
|
}
|
|
36615
37747
|
}
|
|
36616
37748
|
function pathApplies2(projectPath, cwd2) {
|
|
36617
|
-
const project =
|
|
36618
|
-
const current =
|
|
36619
|
-
return current === project || current.startsWith(project +
|
|
37749
|
+
const project = path56.resolve(projectPath);
|
|
37750
|
+
const current = path56.resolve(cwd2);
|
|
37751
|
+
return current === project || current.startsWith(project + path56.sep);
|
|
36620
37752
|
}
|
|
36621
37753
|
function findAncestorMcpJsons2(cwd2, homeDir) {
|
|
36622
37754
|
const files = [];
|
|
36623
|
-
let dir =
|
|
36624
|
-
const root =
|
|
36625
|
-
const stop =
|
|
37755
|
+
let dir = path56.resolve(cwd2);
|
|
37756
|
+
const root = path56.parse(dir).root;
|
|
37757
|
+
const stop = path56.resolve(homeDir);
|
|
36626
37758
|
while (dir !== root) {
|
|
36627
|
-
const candidate =
|
|
36628
|
-
if (
|
|
37759
|
+
const candidate = path56.join(dir, ".mcp.json");
|
|
37760
|
+
if (existsSync41(candidate)) files.push(candidate);
|
|
36629
37761
|
if (dir === stop) break;
|
|
36630
|
-
dir =
|
|
37762
|
+
dir = path56.dirname(dir);
|
|
36631
37763
|
}
|
|
36632
37764
|
return files;
|
|
36633
37765
|
}
|
|
@@ -36644,8 +37776,8 @@ function serverAllowedByPermissions(serverName, prefixes) {
|
|
|
36644
37776
|
return prefixes.has(serverName) || prefixes.has(serverName.replace(/-/g, "_"));
|
|
36645
37777
|
}
|
|
36646
37778
|
function diagnoseClaudeMcpConfig(homeDir = os24.homedir(), cwd2 = process.cwd(), env = process.env) {
|
|
36647
|
-
const claudeJsonPath =
|
|
36648
|
-
const settingsPath =
|
|
37779
|
+
const claudeJsonPath = path56.join(homeDir, ".claude.json");
|
|
37780
|
+
const settingsPath = path56.join(homeDir, ".claude", "settings.json");
|
|
36649
37781
|
const claudeJson = readJson(claudeJsonPath);
|
|
36650
37782
|
const settings = readJson(settingsPath);
|
|
36651
37783
|
const issues = [];
|
|
@@ -36765,7 +37897,7 @@ function diagnoseClaudeMcpConfig(homeDir = os24.homedir(), cwd2 = process.cwd(),
|
|
|
36765
37897
|
});
|
|
36766
37898
|
}
|
|
36767
37899
|
return {
|
|
36768
|
-
cwd:
|
|
37900
|
+
cwd: path56.resolve(cwd2),
|
|
36769
37901
|
globalServers,
|
|
36770
37902
|
projectServers: projectServers.sort((a, b) => a.name.localeCompare(b.name)),
|
|
36771
37903
|
mcpJsonServers: mcpJsonServers.sort((a, b) => a.name.localeCompare(b.name)),
|
|
@@ -36802,14 +37934,14 @@ var init_mcp_diagnostics = __esm({
|
|
|
36802
37934
|
});
|
|
36803
37935
|
|
|
36804
37936
|
// src/bin/cli.ts
|
|
36805
|
-
import { existsSync as
|
|
36806
|
-
import
|
|
37937
|
+
import { existsSync as existsSync42, readFileSync as readFileSync38, writeFileSync as writeFileSync28, readdirSync as readdirSync13, rmSync as rmSync2 } from "fs";
|
|
37938
|
+
import path57 from "path";
|
|
36807
37939
|
import os25 from "os";
|
|
36808
37940
|
var args = process.argv.slice(2);
|
|
36809
37941
|
if (args.includes("--version") || args.includes("-v")) {
|
|
36810
37942
|
try {
|
|
36811
|
-
const pkgPath =
|
|
36812
|
-
const pkg = JSON.parse(
|
|
37943
|
+
const pkgPath = path57.join(path57.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
|
|
37944
|
+
const pkg = JSON.parse(readFileSync38(pkgPath, "utf8"));
|
|
36813
37945
|
console.log(pkg.version);
|
|
36814
37946
|
} catch {
|
|
36815
37947
|
console.log("unknown");
|
|
@@ -37020,6 +38152,23 @@ ID: ${result.id}`);
|
|
|
37020
38152
|
await runRename();
|
|
37021
38153
|
} else if (args[0] === "--activate" || args[0] === "activate") {
|
|
37022
38154
|
await runActivate(args[1]);
|
|
38155
|
+
} else if (args[0] === "doctor") {
|
|
38156
|
+
if (args.includes("--drift")) {
|
|
38157
|
+
const { runDrift: runDrift2 } = await Promise.resolve().then(() => (init_exe_drift(), exe_drift_exports));
|
|
38158
|
+
await runDrift2(args.slice(1));
|
|
38159
|
+
} else {
|
|
38160
|
+
const { runCcDoctor: runCcDoctor2 } = await Promise.resolve().then(() => (init_cc_doctor(), cc_doctor_exports));
|
|
38161
|
+
const { results, failed } = runCcDoctor2();
|
|
38162
|
+
console.log("\n exe-os doctor\n");
|
|
38163
|
+
for (const r of results) {
|
|
38164
|
+
const icon = r.pass ? "\x1B[32m\u2713\x1B[0m" : "\x1B[31m\u2717\x1B[0m";
|
|
38165
|
+
console.log(` ${icon} ${r.name}: ${r.detail}`);
|
|
38166
|
+
}
|
|
38167
|
+
console.log(failed === 0 ? "\n \x1B[32mAll checks passed\x1B[0m\n" : `
|
|
38168
|
+
\x1B[31m${failed} issue(s) found\x1B[0m
|
|
38169
|
+
`);
|
|
38170
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
38171
|
+
}
|
|
37023
38172
|
} else if (args[0] === "setup" || args[0] === "-setup" || args[0] === "--setup") {
|
|
37024
38173
|
const { runSetupWizard: runSetupWizard2 } = await Promise.resolve().then(() => (init_setup_wizard(), setup_wizard_exports));
|
|
37025
38174
|
await runSetupWizard2({ skipModel: args.includes("--skip-model") });
|
|
@@ -37037,11 +38186,11 @@ ID: ${result.id}`);
|
|
|
37037
38186
|
});
|
|
37038
38187
|
await init_App2().then(() => App_exports);
|
|
37039
38188
|
} else {
|
|
37040
|
-
const claudeDir =
|
|
37041
|
-
const settingsPath =
|
|
37042
|
-
const hasClaudeCode =
|
|
38189
|
+
const claudeDir = path57.join(os25.homedir(), ".claude");
|
|
38190
|
+
const settingsPath = path57.join(claudeDir, "settings.json");
|
|
38191
|
+
const hasClaudeCode = existsSync42(settingsPath) && (() => {
|
|
37043
38192
|
try {
|
|
37044
|
-
const raw =
|
|
38193
|
+
const raw = readFileSync38(settingsPath, "utf8");
|
|
37045
38194
|
return raw.includes("exe-os") || raw.includes("exe-mem");
|
|
37046
38195
|
} catch {
|
|
37047
38196
|
return false;
|
|
@@ -37051,9 +38200,9 @@ ID: ${result.id}`);
|
|
|
37051
38200
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
37052
38201
|
let cooName = DEFAULT_COORDINATOR_TEMPLATE_NAME2;
|
|
37053
38202
|
try {
|
|
37054
|
-
const rosterPath =
|
|
37055
|
-
if (
|
|
37056
|
-
const roster = JSON.parse(
|
|
38203
|
+
const rosterPath = path57.join(os25.homedir(), ".exe-os", "exe-employees.json");
|
|
38204
|
+
if (existsSync42(rosterPath)) {
|
|
38205
|
+
const roster = JSON.parse(readFileSync38(rosterPath, "utf8"));
|
|
37057
38206
|
const coo = roster.find((e) => e.role === "COO");
|
|
37058
38207
|
if (coo) cooName = coo.name;
|
|
37059
38208
|
}
|
|
@@ -37206,14 +38355,14 @@ async function runCodexInstall() {
|
|
|
37206
38355
|
}
|
|
37207
38356
|
async function runClaudeCheck() {
|
|
37208
38357
|
const { detectMcpNameCollisions: detectMcpNameCollisions2 } = await Promise.resolve().then(() => (init_installer(), installer_exports));
|
|
37209
|
-
const claudeDir =
|
|
37210
|
-
const settingsPath =
|
|
37211
|
-
const claudeJsonPath =
|
|
38358
|
+
const claudeDir = path57.join(os25.homedir(), ".claude");
|
|
38359
|
+
const settingsPath = path57.join(claudeDir, "settings.json");
|
|
38360
|
+
const claudeJsonPath = path57.join(os25.homedir(), ".claude.json");
|
|
37212
38361
|
let ok = true;
|
|
37213
|
-
if (
|
|
38362
|
+
if (existsSync42(settingsPath)) {
|
|
37214
38363
|
let settings;
|
|
37215
38364
|
try {
|
|
37216
|
-
settings = JSON.parse(
|
|
38365
|
+
settings = JSON.parse(readFileSync38(settingsPath, "utf8"));
|
|
37217
38366
|
} catch {
|
|
37218
38367
|
console.log("\x1B[31m\u2717\x1B[0m settings.json is malformed (invalid JSON)");
|
|
37219
38368
|
ok = false;
|
|
@@ -37239,10 +38388,10 @@ async function runClaudeCheck() {
|
|
|
37239
38388
|
console.log("\x1B[31m\u2717\x1B[0m settings.json not found");
|
|
37240
38389
|
ok = false;
|
|
37241
38390
|
}
|
|
37242
|
-
if (
|
|
38391
|
+
if (existsSync42(claudeJsonPath)) {
|
|
37243
38392
|
let claudeJson;
|
|
37244
38393
|
try {
|
|
37245
|
-
claudeJson = JSON.parse(
|
|
38394
|
+
claudeJson = JSON.parse(readFileSync38(claudeJsonPath, "utf8"));
|
|
37246
38395
|
} catch {
|
|
37247
38396
|
console.log("\x1B[31m\u2717\x1B[0m claude.json is malformed (invalid JSON)");
|
|
37248
38397
|
ok = false;
|
|
@@ -37275,8 +38424,8 @@ async function runClaudeCheck() {
|
|
|
37275
38424
|
} else {
|
|
37276
38425
|
console.log("\x1B[32m\u2713\x1B[0m No .mcp.json/project MCP name collisions detected");
|
|
37277
38426
|
}
|
|
37278
|
-
const skillsDir =
|
|
37279
|
-
if (
|
|
38427
|
+
const skillsDir = path57.join(claudeDir, "skills");
|
|
38428
|
+
if (existsSync42(skillsDir)) {
|
|
37280
38429
|
console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
|
|
37281
38430
|
} else {
|
|
37282
38431
|
console.log("\x1B[31m\u2717\x1B[0m Slash skills directory missing");
|
|
@@ -37300,16 +38449,16 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37300
38449
|
const dryRun = flags.includes("--dry-run");
|
|
37301
38450
|
const purge = flags.includes("--purge");
|
|
37302
38451
|
const homeDir = os25.homedir();
|
|
37303
|
-
const claudeDir =
|
|
37304
|
-
const settingsPath =
|
|
37305
|
-
const claudeJsonPath =
|
|
37306
|
-
const exeOsDir =
|
|
38452
|
+
const claudeDir = path57.join(homeDir, ".claude");
|
|
38453
|
+
const settingsPath = path57.join(claudeDir, "settings.json");
|
|
38454
|
+
const claudeJsonPath = path57.join(homeDir, ".claude.json");
|
|
38455
|
+
const exeOsDir = path57.join(homeDir, ".exe-os");
|
|
37307
38456
|
let removed = 0;
|
|
37308
38457
|
const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
|
|
37309
38458
|
let settings = {};
|
|
37310
|
-
if (
|
|
38459
|
+
if (existsSync42(settingsPath)) {
|
|
37311
38460
|
try {
|
|
37312
|
-
settings = JSON.parse(
|
|
38461
|
+
settings = JSON.parse(readFileSync38(settingsPath, "utf8"));
|
|
37313
38462
|
} catch {
|
|
37314
38463
|
console.error("Your ~/.claude/settings.json appears malformed.");
|
|
37315
38464
|
if (purge) {
|
|
@@ -37347,15 +38496,15 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37347
38496
|
permCount = before - settings.permissions.allow.length;
|
|
37348
38497
|
}
|
|
37349
38498
|
if (!dryRun) {
|
|
37350
|
-
|
|
38499
|
+
writeFileSync28(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
37351
38500
|
}
|
|
37352
38501
|
log("\u2713 Removed exe-os hooks from settings.json");
|
|
37353
38502
|
if (permCount > 0) log(`\u2713 Removed ${permCount} MCP permission entries`);
|
|
37354
38503
|
removed++;
|
|
37355
38504
|
}
|
|
37356
38505
|
}
|
|
37357
|
-
if (
|
|
37358
|
-
const raw =
|
|
38506
|
+
if (existsSync42(claudeJsonPath)) {
|
|
38507
|
+
const raw = readFileSync38(claudeJsonPath, "utf8");
|
|
37359
38508
|
if (raw.length > 1e6) {
|
|
37360
38509
|
console.error("claude.json exceeds 1 MB \u2014 skipping parse.");
|
|
37361
38510
|
} else {
|
|
@@ -37376,7 +38525,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37376
38525
|
}
|
|
37377
38526
|
if (removedMcp) {
|
|
37378
38527
|
if (!dryRun) {
|
|
37379
|
-
|
|
38528
|
+
writeFileSync28(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
37380
38529
|
}
|
|
37381
38530
|
log("\u2713 Removed exe-os MCP server from claude.json");
|
|
37382
38531
|
removed++;
|
|
@@ -37384,14 +38533,14 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37384
38533
|
}
|
|
37385
38534
|
}
|
|
37386
38535
|
}
|
|
37387
|
-
const skillsDir =
|
|
37388
|
-
if (
|
|
38536
|
+
const skillsDir = path57.join(claudeDir, "skills");
|
|
38537
|
+
if (existsSync42(skillsDir)) {
|
|
37389
38538
|
let skillCount = 0;
|
|
37390
38539
|
try {
|
|
37391
|
-
const entries =
|
|
38540
|
+
const entries = readdirSync13(skillsDir);
|
|
37392
38541
|
for (const entry of entries) {
|
|
37393
38542
|
if (entry.startsWith("exe")) {
|
|
37394
|
-
const fullPath =
|
|
38543
|
+
const fullPath = path57.join(skillsDir, entry);
|
|
37395
38544
|
if (!dryRun) rmSync2(fullPath, { recursive: true, force: true });
|
|
37396
38545
|
skillCount++;
|
|
37397
38546
|
}
|
|
@@ -37403,30 +38552,30 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37403
38552
|
removed++;
|
|
37404
38553
|
}
|
|
37405
38554
|
}
|
|
37406
|
-
const claudeMdPath =
|
|
37407
|
-
if (
|
|
37408
|
-
const content =
|
|
38555
|
+
const claudeMdPath = path57.join(claudeDir, "CLAUDE.md");
|
|
38556
|
+
if (existsSync42(claudeMdPath)) {
|
|
38557
|
+
const content = readFileSync38(claudeMdPath, "utf8");
|
|
37409
38558
|
const startMarker = "<!-- exe-os:orchestration-start -->";
|
|
37410
38559
|
const endMarker = "<!-- exe-os:orchestration-end -->";
|
|
37411
38560
|
const startIdx = content.indexOf(startMarker);
|
|
37412
38561
|
const endIdx = content.indexOf(endMarker);
|
|
37413
38562
|
if (startIdx !== -1 && endIdx !== -1) {
|
|
37414
38563
|
const cleaned = (content.slice(0, startIdx) + content.slice(endIdx + endMarker.length)).replace(/\n{3,}/g, "\n\n").trim() + "\n";
|
|
37415
|
-
if (!dryRun)
|
|
38564
|
+
if (!dryRun) writeFileSync28(claudeMdPath, cleaned);
|
|
37416
38565
|
log("\u2713 Removed orchestration block from CLAUDE.md");
|
|
37417
38566
|
removed++;
|
|
37418
38567
|
}
|
|
37419
38568
|
}
|
|
37420
|
-
const agentsDir =
|
|
37421
|
-
if (
|
|
38569
|
+
const agentsDir = path57.join(claudeDir, "agents");
|
|
38570
|
+
if (existsSync42(agentsDir)) {
|
|
37422
38571
|
let agentCount = 0;
|
|
37423
38572
|
try {
|
|
37424
|
-
const entries =
|
|
38573
|
+
const entries = readdirSync13(agentsDir).filter((f) => f.endsWith(".md"));
|
|
37425
38574
|
let knownNames = /* @__PURE__ */ new Set();
|
|
37426
|
-
const rosterPath =
|
|
37427
|
-
if (
|
|
38575
|
+
const rosterPath = path57.join(exeOsDir, "exe-employees.json");
|
|
38576
|
+
if (existsSync42(rosterPath)) {
|
|
37428
38577
|
try {
|
|
37429
|
-
const roster = JSON.parse(
|
|
38578
|
+
const roster = JSON.parse(readFileSync38(rosterPath, "utf8"));
|
|
37430
38579
|
knownNames = new Set(roster.map((e) => e.name));
|
|
37431
38580
|
} catch {
|
|
37432
38581
|
}
|
|
@@ -37434,7 +38583,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37434
38583
|
for (const entry of entries) {
|
|
37435
38584
|
const name = entry.replace(/\.md$/, "");
|
|
37436
38585
|
if (knownNames.has(name)) {
|
|
37437
|
-
if (!dryRun) rmSync2(
|
|
38586
|
+
if (!dryRun) rmSync2(path57.join(agentsDir, entry), { force: true });
|
|
37438
38587
|
agentCount++;
|
|
37439
38588
|
}
|
|
37440
38589
|
}
|
|
@@ -37445,16 +38594,16 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37445
38594
|
removed++;
|
|
37446
38595
|
}
|
|
37447
38596
|
}
|
|
37448
|
-
const projectsDir =
|
|
37449
|
-
if (
|
|
38597
|
+
const projectsDir = path57.join(claudeDir, "projects");
|
|
38598
|
+
if (existsSync42(projectsDir)) {
|
|
37450
38599
|
let projectCount = 0;
|
|
37451
38600
|
try {
|
|
37452
|
-
const projects =
|
|
38601
|
+
const projects = readdirSync13(projectsDir);
|
|
37453
38602
|
for (const proj of projects) {
|
|
37454
|
-
const projSettings =
|
|
37455
|
-
if (!
|
|
38603
|
+
const projSettings = path57.join(projectsDir, proj, "settings.json");
|
|
38604
|
+
if (!existsSync42(projSettings)) continue;
|
|
37456
38605
|
try {
|
|
37457
|
-
const pSettings = JSON.parse(
|
|
38606
|
+
const pSettings = JSON.parse(readFileSync38(projSettings, "utf8"));
|
|
37458
38607
|
let changed = false;
|
|
37459
38608
|
if (Array.isArray(pSettings.permissions?.allow)) {
|
|
37460
38609
|
const before = pSettings.permissions.allow.length;
|
|
@@ -37464,7 +38613,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37464
38613
|
if (pSettings.permissions.allow.length < before) changed = true;
|
|
37465
38614
|
}
|
|
37466
38615
|
if (changed && !dryRun) {
|
|
37467
|
-
|
|
38616
|
+
writeFileSync28(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
|
|
37468
38617
|
}
|
|
37469
38618
|
if (changed) projectCount++;
|
|
37470
38619
|
} catch {
|
|
@@ -37478,28 +38627,28 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37478
38627
|
}
|
|
37479
38628
|
}
|
|
37480
38629
|
try {
|
|
37481
|
-
const { execSync:
|
|
38630
|
+
const { execSync: execSync20 } = await import("child_process");
|
|
37482
38631
|
const findExeBin3 = () => {
|
|
37483
38632
|
try {
|
|
37484
|
-
return
|
|
38633
|
+
return execSync20(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
37485
38634
|
} catch {
|
|
37486
38635
|
return null;
|
|
37487
38636
|
}
|
|
37488
38637
|
};
|
|
37489
38638
|
const exeBinPath = findExeBin3();
|
|
37490
38639
|
if (!exeBinPath) throw new Error("exe-os not found in PATH");
|
|
37491
|
-
const binDir =
|
|
38640
|
+
const binDir = path57.dirname(exeBinPath);
|
|
37492
38641
|
let symlinkCount = 0;
|
|
37493
|
-
const rosterPath =
|
|
37494
|
-
if (
|
|
37495
|
-
const roster = JSON.parse(
|
|
38642
|
+
const rosterPath = path57.join(exeOsDir, "exe-employees.json");
|
|
38643
|
+
if (existsSync42(rosterPath)) {
|
|
38644
|
+
const roster = JSON.parse(readFileSync38(rosterPath, "utf8"));
|
|
37496
38645
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
37497
38646
|
const coordinatorName = roster.find((e) => e.role?.toLowerCase() === "coo")?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME2;
|
|
37498
38647
|
for (const emp of roster) {
|
|
37499
38648
|
if (emp.name === coordinatorName) continue;
|
|
37500
38649
|
for (const suffix of ["", "-opencode"]) {
|
|
37501
|
-
const linkPath =
|
|
37502
|
-
if (
|
|
38650
|
+
const linkPath = path57.join(binDir, `${emp.name}${suffix}`);
|
|
38651
|
+
if (existsSync42(linkPath)) {
|
|
37503
38652
|
if (!dryRun) rmSync2(linkPath, { force: true });
|
|
37504
38653
|
symlinkCount++;
|
|
37505
38654
|
}
|
|
@@ -37512,7 +38661,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
37512
38661
|
}
|
|
37513
38662
|
} catch {
|
|
37514
38663
|
}
|
|
37515
|
-
if (purge &&
|
|
38664
|
+
if (purge && existsSync42(exeOsDir)) {
|
|
37516
38665
|
if (!dryRun) {
|
|
37517
38666
|
process.stdout.write("\x1B[33m\u26A0 This will delete all memories, identities, and agent data.\x1B[0m\n");
|
|
37518
38667
|
process.stdout.write(" Removing ~/.exe-os...\n");
|
|
@@ -37537,7 +38686,7 @@ async function checkForUpdateOnBoot() {
|
|
|
37537
38686
|
const config = await loadConfig2();
|
|
37538
38687
|
if (!config.autoUpdate.checkOnBoot) return;
|
|
37539
38688
|
const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
37540
|
-
const packageRoot =
|
|
38689
|
+
const packageRoot = path57.resolve(
|
|
37541
38690
|
new URL("../..", import.meta.url).pathname
|
|
37542
38691
|
);
|
|
37543
38692
|
const result = checkForUpdate2(packageRoot);
|
|
@@ -37598,7 +38747,7 @@ async function runActivate(key) {
|
|
|
37598
38747
|
const idTemplate = getIdentityTemplate(identityKey);
|
|
37599
38748
|
if (idTemplate) {
|
|
37600
38749
|
const idPath = identityPath2(name);
|
|
37601
|
-
const dir =
|
|
38750
|
+
const dir = path57.dirname(idPath);
|
|
37602
38751
|
if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
|
|
37603
38752
|
fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
|
|
37604
38753
|
}
|