@askexenow/exe-os 0.9.299 → 0.9.300
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/.env.customer.example +1 -1
- package/deploy/compose/.env.example +1 -1
- package/deploy/compose/docker-compose.yml +31 -5
- package/deploy/compose/generate-env.ts +1 -1
- package/deploy/compose/observability/otel-collector-config.yaml +10 -1
- package/deploy/compose/setup.sh +1 -1
- package/dist/active-agent-56J56WW5.js +27 -0
- package/dist/active-agent-VDWK7TES.js +28 -0
- package/dist/agentic-ontology-MZ4WHFDE.js +25 -0
- package/dist/assets/com.askexe.exed.plist +6 -5
- package/dist/backfill-metadata-IHKI5GXV.js +600 -0
- package/dist/backfill-metadata-ZU3SZNBD.js +600 -0
- package/dist/behaviors-G4KWGS24.js +46 -0
- package/dist/behaviors-WO67R6C4.js +46 -0
- package/dist/bin/agentic-ontology-backfill.js +5 -5
- package/dist/bin/agentic-reflection-backfill.js +6 -6
- package/dist/bin/agentic-semantic-label.js +5 -5
- package/dist/bin/backfill-conversations.js +6 -6
- package/dist/bin/backfill-responses.js +6 -6
- package/dist/bin/backfill-vectors.js +8 -8
- package/dist/bin/bulk-sync-postgres.js +13 -7
- package/dist/bin/cc-doctor.js +5 -5
- package/dist/bin/cleanup-stale-review-tasks.js +10 -10
- package/dist/bin/cli.js +16 -16
- package/dist/bin/deferred-daemon-restart.js +1 -1
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +10 -10
- package/dist/bin/exe-assign.js +8 -8
- package/dist/bin/exe-boot.js +30 -20
- package/dist/bin/exe-call.js +4 -4
- package/dist/bin/exe-cloud.js +13 -7
- package/dist/bin/exe-dispatch.js +10 -10
- package/dist/bin/exe-doctor.js +2 -2
- package/dist/bin/exe-export-behaviors.js +7 -7
- package/dist/bin/exe-forget.js +6 -6
- package/dist/bin/exe-gateway.js +7 -7
- package/dist/bin/exe-healthcheck.js +5 -5
- package/dist/bin/exe-heartbeat.js +10 -10
- package/dist/bin/exe-kill.js +13 -13
- package/dist/bin/exe-launch-agent.js +29 -19
- package/dist/bin/exe-new-employee.js +6 -6
- package/dist/bin/exe-pending-messages.js +11 -11
- package/dist/bin/exe-pending-notifications.js +10 -10
- package/dist/bin/exe-pending-reviews.js +10 -10
- package/dist/bin/exe-rename.js +4 -4
- package/dist/bin/exe-review.js +12 -12
- package/dist/bin/exe-search.js +5 -5
- package/dist/bin/exe-session-cleanup.js +15 -15
- package/dist/bin/exe-settings.js +13 -7
- package/dist/bin/exe-start-codex.js +11 -11
- package/dist/bin/exe-start-opencode.js +8 -8
- package/dist/bin/exe-status.js +11 -11
- package/dist/bin/exe-team.js +3 -3
- package/dist/bin/git-sweep.js +11 -11
- package/dist/bin/graph-backfill.js +6 -6
- package/dist/bin/graph-export.js +5 -5
- package/dist/bin/import-history.js +9 -9
- package/dist/bin/install-launchd.js +7 -3
- package/dist/bin/install.js +19 -15
- package/dist/bin/intercom-check.js +4 -4
- package/dist/bin/mcp-sessions.js +2 -2
- package/dist/bin/orchestration-metrics.js +4 -4
- package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
- package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
- package/dist/bin/pre-publish.js +24 -1
- package/dist/bin/scan-tasks.js +10 -10
- package/dist/bin/setup.js +1 -1
- package/dist/bin/shard-migrate.js +4 -4
- package/dist/bin/stack-update.js +123 -3
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/capability-cards-XAQSL26B.js +89 -0
- package/dist/capacity-monitor-6MQLFFQT.js +51 -0
- package/dist/capacity-monitor-BB3LKJLE.js +51 -0
- package/dist/catchup-brief-BQSL5M5S.js +175 -0
- package/dist/catchup-brief-COALBX6L.js +175 -0
- package/dist/cc-binary-detect-B5JDCJ5J.js +19 -0
- package/dist/chunk-22LDUTY7.js +14597 -0
- package/dist/chunk-24M4AJPG.js +128 -0
- package/dist/chunk-2B7RCTPT.js +85 -0
- package/dist/chunk-2QBA6YE6.js +127 -0
- package/dist/chunk-2RGDEBZC.js +731 -0
- package/dist/chunk-32DBQWR5.js +333 -0
- package/dist/chunk-3EOPMTG2.js +128 -0
- package/dist/chunk-3NS4V4JW.js +382 -0
- package/dist/chunk-3NYY2NZ3.js +836 -0
- package/dist/chunk-3ROUD5WA.js +97 -0
- package/dist/chunk-3RY2ARDN.js +129 -0
- package/dist/chunk-3Y5IRIRU.js +290 -0
- package/dist/chunk-3ZWWUKBI.js +210 -0
- package/dist/chunk-463G3VAH.js +122 -0
- package/dist/chunk-4LC7BFI2.js +76 -0
- package/dist/chunk-4Z3FWLOE.js +836 -0
- package/dist/chunk-5BAU4T5G.js +208 -0
- package/dist/chunk-5FP7YHCG.js +1158 -0
- package/dist/chunk-5U3JZP62.js +1352 -0
- package/dist/chunk-5VNFXIGF.js +85 -0
- package/dist/chunk-6UVUJNLY.js +1186 -0
- package/dist/chunk-7KPWYWYL.js +290 -0
- package/dist/chunk-7URNGDEY.js +2145 -0
- package/dist/chunk-ADZQBZOX.js +122 -0
- package/dist/chunk-APSZAEDO.js +1186 -0
- package/dist/chunk-ASHF6VO4.js +2265 -0
- package/dist/chunk-BT2LEHIW.js +448 -0
- package/dist/chunk-BTS5QUWB.js +50 -0
- package/dist/chunk-BWJDJ3BS.js +604 -0
- package/dist/chunk-CME46VWP.js +150 -0
- package/dist/chunk-D3ICCKXY.js +54 -0
- package/dist/chunk-D3IOU3NO.js +377 -0
- package/dist/chunk-DFGXRKI2.js +221 -0
- package/dist/chunk-DO65VHQZ.js +128 -0
- package/dist/chunk-E2OMUBXQ.js +567 -0
- package/dist/chunk-ECMXIV6N.js +97 -0
- package/dist/chunk-EDMVA3PT.js +727 -0
- package/dist/chunk-F5OSXH4A.js +4388 -0
- package/dist/chunk-F5OWHPRG.js +236 -0
- package/dist/chunk-F7MZA3QP.js +199 -0
- package/dist/chunk-FRNXQSB4.js +134 -0
- package/dist/chunk-FTAASABV.js +362 -0
- package/dist/chunk-GBL5QSTM.js +197 -0
- package/dist/chunk-GRXWINOW.js +244 -0
- package/dist/chunk-GUPNVUG5.js +348 -0
- package/dist/chunk-GY66UPMX.js +167 -0
- package/dist/chunk-HCCG67BY.js +43 -0
- package/dist/chunk-HCSZZXZZ.js +197 -0
- package/dist/chunk-HNGNZU62.js +240 -0
- package/dist/chunk-HP2D5LIE.js +214 -0
- package/dist/chunk-HUABQHDC.js +1352 -0
- package/dist/chunk-HYKO2LNW.js +157 -0
- package/dist/chunk-IFL6DG2K.js +181 -0
- package/dist/chunk-IKPQRHVQ.js +304 -0
- package/dist/chunk-JCWA3X6A.js +402 -0
- package/dist/chunk-JHPK33IP.js +2162 -0
- package/dist/chunk-JWGDH5I2.js +127 -0
- package/dist/chunk-KBXQFXYM.js +567 -0
- package/dist/chunk-KGY5QIOJ.js +1350 -0
- package/dist/chunk-KLES22FB.js +1094 -0
- package/dist/chunk-KY43UELJ.js +331 -0
- package/dist/chunk-L32V4O5Z.js +58 -0
- package/dist/chunk-LC7ETNTJ.js +1350 -0
- package/dist/chunk-LEJ5FKIK.js +55 -0
- package/dist/chunk-LNLLCAI4.js +377 -0
- package/dist/chunk-LQWZYMNU.js +448 -0
- package/dist/chunk-LY3SOO73.js +76 -0
- package/dist/chunk-M6CIHXXB.js +159 -0
- package/dist/chunk-MJOQ35DX.js +427 -0
- package/dist/chunk-MO5HER5Y.js +345 -0
- package/dist/chunk-MY4TGLT6.js +284 -0
- package/dist/chunk-N3ARGCVG.js +345 -0
- package/dist/chunk-N4XG2M2U.js +735 -0
- package/dist/chunk-N72JNFJ4.js +535 -0
- package/dist/chunk-NM3AUMFE.js +2145 -0
- package/dist/chunk-NPPQ3TR4.js +735 -0
- package/dist/chunk-NTWF4DAF.js +581 -0
- package/dist/chunk-NXL3VKXM.js +331 -0
- package/dist/chunk-OMSLHEEF.js +456 -0
- package/dist/chunk-OYIP3QVN.js +167 -0
- package/dist/chunk-P2IOW54H.js +668 -0
- package/dist/chunk-P5KXQ3RN.js +731 -0
- package/dist/chunk-P5UXP53T.js +81 -0
- package/dist/chunk-PH6VRRFR.js +395 -0
- package/dist/chunk-Q3GKOF7Z.js +85 -0
- package/dist/chunk-QKBN3CY2.js +381 -0
- package/dist/chunk-QNNAVMQH.js +1094 -0
- package/dist/chunk-QODDW4YI.js +171 -0
- package/dist/chunk-QPAYPTSH.js +2162 -0
- package/dist/chunk-QRWDJ5RI.js +381 -0
- package/dist/chunk-RBFZCHVB.js +105 -0
- package/dist/chunk-RCEULTPF.js +185 -0
- package/dist/chunk-RCGHXBCX.js +630 -0
- package/dist/chunk-ROSCLRTH.js +204 -0
- package/dist/chunk-RYAOSGUW.js +227 -0
- package/dist/chunk-S2SPGHPY.js +38 -0
- package/dist/chunk-SBPEWD7Z.js +171 -0
- package/dist/chunk-SDPUWZP5.js +333 -0
- package/dist/chunk-SVLSHDNL.js +54 -0
- package/dist/chunk-SVUYBT5N.js +262 -0
- package/dist/chunk-T7PTLVJV.js +284 -0
- package/dist/chunk-TGUSLO4B.js +50 -0
- package/dist/chunk-TPJH6PE6.js +1158 -0
- package/dist/chunk-TVW7EDOJ.js +382 -0
- package/dist/chunk-TYRUIE6P.js +58 -0
- package/dist/chunk-UN5EPVBN.js +14597 -0
- package/dist/chunk-URLH7ZVR.js +70 -0
- package/dist/chunk-USYRTGR7.js +402 -0
- package/dist/chunk-V4ABCEHM.js +30 -0
- package/dist/chunk-VKCNXOQ6.js +214 -0
- package/dist/chunk-WB2B25UM.js +230 -0
- package/dist/chunk-WCUZX7F7.js +204 -0
- package/dist/chunk-WL5RMOZQ.js +362 -0
- package/dist/chunk-WPAXAOHD.js +1079 -0
- package/dist/chunk-XABJRAUW.js +3346 -0
- package/dist/chunk-YDFY6YCH.js +280 -0
- package/dist/chunk-YGUMRYCN.js +33 -0
- package/dist/chunk-YJSP5PPG.js +128 -0
- package/dist/chunk-YOMETWOJ.js +4388 -0
- package/dist/chunk-Z4FVFSE3.js +81 -0
- package/dist/chunk-Z4TLSNUW.js +244 -0
- package/dist/chunk-ZP6T5K6I.js +535 -0
- package/dist/chunk-ZR6ZJT32.js +123 -0
- package/dist/co-activation-JGF5YIDU.js +74 -0
- package/dist/co-occurrence-HLLC6GT2.js +95 -0
- package/dist/co-occurrence-W2LIAPHI.js +95 -0
- package/dist/code-context-index-FCL47WKE.js +30 -0
- package/dist/conversation-entity-extractor-WC2RU6RS.js +114 -0
- package/dist/core-memory-CRSR2PSL.js +110 -0
- package/dist/core-memory-VSKFRMEV.js +110 -0
- package/dist/crdt-sync-6VH2YDVY.js +33 -0
- package/dist/crm-webhook-RXFPZJXP.js +10 -0
- package/dist/crm-webhook-Z26LEFKG.js +10 -0
- package/dist/cto-delegation-gate-45IBLPTK.js +280 -0
- package/dist/cto-delegation-gate-SF4EUB2Q.js +280 -0
- package/dist/daemon-orchestration-VB3BLYIT.js +143 -0
- package/dist/daemon-orchestration-W66UYGUD.js +143 -0
- package/dist/db-backup-NVUTS7L5.js +43 -0
- package/dist/doc-graph-extractor-MLYQYT4B.js +133 -0
- package/dist/doc-graph-extractor-SVFSXKL6.js +133 -0
- package/dist/dreaming-AZYRAGKA.js +34 -0
- package/dist/dreaming-WG5CDUHX.js +34 -0
- package/dist/entity-boost-XAFCDDB6.js +375 -0
- package/dist/exe-drift-3SGA53CL.js +70 -0
- package/dist/exe-export-APUNLKWF.js +77 -0
- package/dist/exe-export-NM4SXB3P.js +77 -0
- package/dist/exe-import-6GLNCP62.js +80 -0
- package/dist/exe-import-U4H4ES3Z.js +80 -0
- package/dist/exe-key-FIPXUTMF.js +673 -0
- package/dist/exe-key-WTLCMOYJ.js +673 -0
- package/dist/exe-snapshot-ILO3WSEC.js +338 -0
- package/dist/exe-snapshot-IODRQLBX.js +338 -0
- package/dist/fast-db-init-7LYYUCSJ.js +7 -0
- package/dist/fast-db-init-IU7GYFWB.js +7 -0
- package/dist/gateway/index.js +11 -11
- package/dist/git-staleness-GGCFPHQ5.js +112 -0
- package/dist/git-task-sweep-M3SWXFKJ.js +42 -0
- package/dist/git-task-sweep-Y6KNWB67.js +42 -0
- package/dist/global-procedures-626WAU3I.js +22 -0
- package/dist/graph-auto-extract-TKHQ4OR3.js +183 -0
- package/dist/graph-auto-extract-VGFEWFZX.js +183 -0
- package/dist/graph-rag-KECA5TE4.js +35 -0
- package/dist/hooks/bug-report-worker.js +12 -12
- package/dist/hooks/codex-stop-task-finalizer.js +12 -12
- package/dist/hooks/commit-complete.js +12 -12
- package/dist/hooks/error-recall.js +6 -6
- package/dist/hooks/exe-heartbeat-hook.js +3 -3
- package/dist/hooks/ingest-worker.js +3 -3
- package/dist/hooks/ingest.js +6 -6
- package/dist/hooks/instructions-loaded.js +4 -4
- package/dist/hooks/manifest.json +20 -20
- package/dist/hooks/notification.js +4 -4
- package/dist/hooks/post-compact.js +11 -11
- package/dist/hooks/post-tool-combined.js +6 -6
- package/dist/hooks/pre-compact.js +15 -15
- package/dist/hooks/pre-tool-use.js +15 -15
- package/dist/hooks/prompt-submit.js +23 -23
- package/dist/hooks/session-end.js +20 -20
- package/dist/hooks/session-start.js +12 -12
- package/dist/hooks/stop.js +18 -18
- package/dist/hooks/subagent-stop.js +11 -11
- package/dist/hooks/summary-worker.js +18 -18
- package/dist/index.js +20 -20
- package/dist/installer-3FB5EMPB.js +40 -0
- package/dist/installer-BRQ42CPB.js +344 -0
- package/dist/installer-PXZJG256.js +298 -0
- package/dist/lib/cloud-sync.js +13 -7
- package/dist/lib/consolidation.js +7 -7
- package/dist/lib/database.js +6 -4
- package/dist/lib/db-daemon-client.js +11 -202
- package/dist/lib/db.js +6 -4
- package/dist/lib/embedder.js +3 -3
- package/dist/lib/employee-templates.js +4 -4
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon-client.js +2 -2
- package/dist/lib/exe-daemon.js +53 -51
- package/dist/lib/hybrid-search.js +5 -5
- package/dist/lib/identity.js +2 -2
- package/dist/lib/messaging.js +10 -10
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +5 -5
- package/dist/lib/session-registry.js +4 -4
- package/dist/lib/skill-learning.js +6 -6
- package/dist/lib/store.js +4 -4
- package/dist/lib/task-router.js +3 -3
- package/dist/lib/tasks.js +11 -11
- package/dist/lib/tmux-routing.js +9 -9
- package/dist/lib/token-spend.js +3 -3
- package/dist/mcp/register-tools.js +65 -63
- package/dist/mcp/server.js +66 -64
- package/dist/mcp/tools/complete-reminder.js +4 -4
- package/dist/mcp/tools/create-reminder.js +4 -4
- package/dist/mcp/tools/create-task.js +13 -13
- package/dist/mcp/tools/deactivate-behavior.js +7 -7
- package/dist/mcp/tools/list-reminders.js +4 -4
- package/dist/mcp/tools/list-tasks.js +13 -13
- package/dist/mcp/tools/send-message.js +12 -12
- package/dist/mcp/tools/update-task.js +12 -12
- package/dist/mcp-http-config-OF3MB7M5.js +31 -0
- package/dist/memory-cards-CPIZVXWI.js +180 -0
- package/dist/memory-graph-extractor-JIYWLBFF.js +22 -0
- package/dist/memory-graph-extractor-MDPSLZDM.js +22 -0
- package/dist/memory-poisoning-defense-5UZT3WWA.js +224 -0
- package/dist/memory-queue-client-WKWRFERJ.js +16 -0
- package/dist/memory-reflection-TA2VQYPH.js +244 -0
- package/dist/message-queue-client-IFQQ2HI7.js +92 -0
- package/dist/notifications-CZBQ3H5T.js +47 -0
- package/dist/notifications-EIIL2EQV.js +47 -0
- package/dist/orchestration-events-VUYR6MXE.js +27 -0
- package/dist/orchestrator-MAMR4C37.js +35 -0
- package/dist/orchestrator-VE5WHEJH.js +35 -0
- package/dist/pipeline-router-DKXD6DJO.js +15 -0
- package/dist/pipeline-router-YNW63BY5.js +15 -0
- package/dist/plan-limits-ZM4MNZKY.js +28 -0
- package/dist/project-boot-E2TWYTAC.js +299 -0
- package/dist/projection-worker-WFPRM4AI.js +1084 -0
- package/dist/projection-worker-YKV3PFCV.js +1084 -0
- package/dist/prospective-memory-OAFZUODU.js +232 -0
- package/dist/reranker-AFU75HEX.js +19 -0
- package/dist/reranker-RYNSJNDF.js +19 -0
- package/dist/retrieval-health-RSQEIYIB.js +12 -0
- package/dist/review-polling-LGX7DUNT.js +126 -0
- package/dist/review-polling-MJBCYV4I.js +126 -0
- package/dist/runtime/index.js +16 -16
- package/dist/services/codex-reviewd/index.js +855 -0
- package/dist/session-events-5N47BRFK.js +38 -0
- package/dist/session-events-PT6SVS2P.js +38 -0
- package/dist/session-kill-telemetry-HKL2NQMR.js +31 -0
- package/dist/session-scope-GQNCM6UQ.js +88 -0
- package/dist/session-scope-MMGM232A.js +88 -0
- package/dist/setup-wizard-SELXXVLD.js +12 -0
- package/dist/setup-wizard-X7YSRDNQ.js +12 -0
- package/dist/skill-refinement-CCP4ULZ3.js +159 -0
- package/dist/skill-refinement-WCPDNHZ5.js +159 -0
- package/dist/stack-update-5VSGG36W.js +84 -0
- package/dist/steward-gate-PIXNK4BK.js +15 -0
- package/dist/task-enforcement-LEBWCYZT.js +506 -0
- package/dist/task-enforcement-VOSQRAQB.js +506 -0
- package/dist/task-scope-CQZ33PRU.js +37 -0
- package/dist/task-scope-JTTEZKDU.js +37 -0
- package/dist/tasks-crud-DC4GCXQQ.js +79 -0
- package/dist/tasks-crud-T32IRPXF.js +79 -0
- package/dist/tasks-notify-OBFVHJDP.js +40 -0
- package/dist/tasks-notify-OUQWUM6W.js +40 -0
- package/dist/tasks-review-N33MTHWJ.js +49 -0
- package/dist/tasks-review-OSBG2YN2.js +49 -0
- package/dist/telemetry-upload-EYHEWTKG.js +741 -0
- package/dist/telemetry-upload-XLBW4DRP.js +741 -0
- package/dist/token-budget-I6FMMDFX.js +86 -0
- package/dist/tool-capability-index-IWQBQKM7.js +10 -0
- package/dist/tool-telemetry-2E3Z7CRV.js +17 -0
- package/dist/tui/App.js +17 -17
- package/dist/tui-data-VWT4Q5UT.js +260 -0
- package/dist/tui-data-XFBFBSBE.js +260 -0
- package/dist/wiki-acl-EUOPNUIQ.js +111 -0
- package/dist/worker-gate-OQMKAMP7.js +21 -0
- package/dist/worker-gate-ZPP3SZK6.js +21 -0
- package/dist/workflow-engine-P7WYJP2B.js +28 -0
- package/dist/workflow-engine-UYNB5RTB.js +28 -0
- package/dist/worktree-H5C4LMQR.js +28 -0
- package/dist/worktree-sweep-KFWF3XZD.js +21 -0
- package/package.json +1 -1
- package/release-notes.json +30 -104
- package/src/commands/exe.md +18 -1
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deserializeResultSet,
|
|
3
|
+
serializeValue
|
|
4
|
+
} from "./chunk-QGGH7LOU.js";
|
|
5
|
+
import {
|
|
6
|
+
connectEmbedDaemon,
|
|
7
|
+
isClientConnected,
|
|
8
|
+
sendDaemonRequest
|
|
9
|
+
} from "./chunk-NTWF4DAF.js";
|
|
10
|
+
|
|
11
|
+
// src/lib/db-daemon-client.ts
|
|
12
|
+
function normalizeStatement(stmt) {
|
|
13
|
+
if (typeof stmt === "string") {
|
|
14
|
+
return { sql: stmt, args: [] };
|
|
15
|
+
}
|
|
16
|
+
const sql = stmt.sql;
|
|
17
|
+
let args = [];
|
|
18
|
+
if (Array.isArray(stmt.args)) {
|
|
19
|
+
args = stmt.args.map((v) => serializeValue(v));
|
|
20
|
+
} else if (stmt.args && typeof stmt.args === "object") {
|
|
21
|
+
const named = {};
|
|
22
|
+
for (const [key, val] of Object.entries(stmt.args)) {
|
|
23
|
+
named[key] = serializeValue(val);
|
|
24
|
+
}
|
|
25
|
+
return { sql, args: named };
|
|
26
|
+
}
|
|
27
|
+
return { sql, args };
|
|
28
|
+
}
|
|
29
|
+
function isReadOnlySql(sql) {
|
|
30
|
+
const normalized = sql.replace(/^\s*--.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").trim().toLowerCase();
|
|
31
|
+
return /^(select|pragma\s+(?!wal_checkpoint|journal_mode|synchronous|user_version)|with\b.*\bselect\b)/s.test(normalized);
|
|
32
|
+
}
|
|
33
|
+
var TRANSIENT_TRANSPORT_ERRORS = [
|
|
34
|
+
"Not connected",
|
|
35
|
+
"Connection closed",
|
|
36
|
+
"Request timeout",
|
|
37
|
+
"DB not initialized",
|
|
38
|
+
"Server shutting down",
|
|
39
|
+
"Daemon transport error"
|
|
40
|
+
];
|
|
41
|
+
function isTransientDaemonTransportError(err) {
|
|
42
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
43
|
+
return TRANSIENT_TRANSPORT_ERRORS.some((s) => msg.includes(s));
|
|
44
|
+
}
|
|
45
|
+
async function retryOnDaemonTransportError(fn, opts = {}) {
|
|
46
|
+
const attempts = Math.max(1, opts.attempts ?? 4);
|
|
47
|
+
const baseDelayMs = opts.baseDelayMs ?? 150;
|
|
48
|
+
let lastErr;
|
|
49
|
+
for (let i = 0; i < attempts; i++) {
|
|
50
|
+
try {
|
|
51
|
+
return await fn();
|
|
52
|
+
} catch (err) {
|
|
53
|
+
lastErr = err;
|
|
54
|
+
if (i === attempts - 1 || !isTransientDaemonTransportError(err)) throw err;
|
|
55
|
+
await connectEmbedDaemon().catch(() => false);
|
|
56
|
+
await new Promise((r) => setTimeout(r, baseDelayMs * (i + 1)));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
throw lastErr;
|
|
60
|
+
}
|
|
61
|
+
function createDaemonDbClient(fallbackClient) {
|
|
62
|
+
let _useDaemon = false;
|
|
63
|
+
const isMcpProcess = () => process.env.EXE_MCP_MODE === "1";
|
|
64
|
+
const isTransportError = (errMsg) => errMsg === "Not connected" || errMsg === "Request timeout" || errMsg === "Write failed" || errMsg === "DB not initialized" || errMsg === "Connection closed" || errMsg === "Server shutting down";
|
|
65
|
+
async function ensureDaemonRoute() {
|
|
66
|
+
if (_useDaemon && isClientConnected()) return true;
|
|
67
|
+
const connected = await connectEmbedDaemon().catch(() => false);
|
|
68
|
+
if (connected) {
|
|
69
|
+
_useDaemon = true;
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
function unavailableForMcp(errMsg) {
|
|
75
|
+
const suffix = errMsg ? ` Last transport error: ${errMsg}.` : "";
|
|
76
|
+
return new Error(
|
|
77
|
+
"Daemon unavailable for MCP DB operation. Refusing direct SQLite fallback from MCP process to preserve the single-writer gate and prevent FTS5 corruption." + suffix
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const client = {
|
|
81
|
+
// Daemon-routed clients cannot span a transaction across requests —
|
|
82
|
+
// BEGIN/COMMIT via execute() is rejected by the daemon SQL guard.
|
|
83
|
+
// Callers that need atomic multi-statement writes must use batch()
|
|
84
|
+
// (executed atomically daemon-side). See store.ts flushBatch.
|
|
85
|
+
// @ts-expect-error -- capability marker consumed by flushBatch
|
|
86
|
+
interactiveTransactions: false,
|
|
87
|
+
async execute(stmt) {
|
|
88
|
+
const daemonReady = await ensureDaemonRoute();
|
|
89
|
+
if (!daemonReady) {
|
|
90
|
+
if (isMcpProcess()) throw unavailableForMcp();
|
|
91
|
+
return fallbackClient.execute(stmt);
|
|
92
|
+
}
|
|
93
|
+
const { sql, args } = normalizeStatement(stmt);
|
|
94
|
+
let response = await sendDaemonRequest({
|
|
95
|
+
type: "db-execute",
|
|
96
|
+
sql,
|
|
97
|
+
args
|
|
98
|
+
});
|
|
99
|
+
if (response.error) {
|
|
100
|
+
const errMsg = String(response.error);
|
|
101
|
+
if (isTransportError(errMsg) && isReadOnlySql(sql)) {
|
|
102
|
+
_useDaemon = false;
|
|
103
|
+
if (await ensureDaemonRoute()) {
|
|
104
|
+
response = await sendDaemonRequest({ type: "db-execute", sql, args });
|
|
105
|
+
if (!response.error && response.db) {
|
|
106
|
+
return deserializeResultSet(response.db);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (isMcpProcess()) throw unavailableForMcp(errMsg);
|
|
110
|
+
process.stderr.write(`[db-daemon] Transport error (${errMsg}), falling back to direct
|
|
111
|
+
`);
|
|
112
|
+
return fallbackClient.execute(stmt);
|
|
113
|
+
}
|
|
114
|
+
if (isTransportError(errMsg)) {
|
|
115
|
+
_useDaemon = false;
|
|
116
|
+
throw new Error(`Daemon transport error after write request; refusing unsafe retry: ${errMsg}`);
|
|
117
|
+
}
|
|
118
|
+
throw new Error(errMsg);
|
|
119
|
+
}
|
|
120
|
+
if (response.db) {
|
|
121
|
+
return deserializeResultSet(response.db);
|
|
122
|
+
}
|
|
123
|
+
if (isMcpProcess()) throw unavailableForMcp("Unexpected daemon response shape");
|
|
124
|
+
if (!isReadOnlySql(sql)) {
|
|
125
|
+
throw new Error("Unexpected daemon response after write request; refusing unsafe direct fallback");
|
|
126
|
+
}
|
|
127
|
+
process.stderr.write("[db-daemon] Unexpected response shape, falling back to direct\n");
|
|
128
|
+
return fallbackClient.execute(stmt);
|
|
129
|
+
},
|
|
130
|
+
async batch(stmts, mode) {
|
|
131
|
+
const daemonReady = await ensureDaemonRoute();
|
|
132
|
+
if (!daemonReady) {
|
|
133
|
+
if (isMcpProcess()) throw unavailableForMcp();
|
|
134
|
+
return fallbackClient.batch(stmts, mode);
|
|
135
|
+
}
|
|
136
|
+
const statements = stmts.map(normalizeStatement);
|
|
137
|
+
let response = await sendDaemonRequest({
|
|
138
|
+
type: "db-batch",
|
|
139
|
+
statements,
|
|
140
|
+
mode: mode ?? "deferred"
|
|
141
|
+
});
|
|
142
|
+
if (response.error) {
|
|
143
|
+
const errMsg = String(response.error);
|
|
144
|
+
const readOnlyBatch = statements.every((s) => isReadOnlySql(s.sql));
|
|
145
|
+
if (isTransportError(errMsg) && readOnlyBatch) {
|
|
146
|
+
_useDaemon = false;
|
|
147
|
+
if (await ensureDaemonRoute()) {
|
|
148
|
+
response = await sendDaemonRequest({
|
|
149
|
+
type: "db-batch",
|
|
150
|
+
statements,
|
|
151
|
+
mode: mode ?? "deferred"
|
|
152
|
+
});
|
|
153
|
+
const retriedResults = response["db-batch"];
|
|
154
|
+
if (!response.error && retriedResults) {
|
|
155
|
+
return retriedResults.map(deserializeResultSet);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (isMcpProcess()) throw unavailableForMcp(errMsg);
|
|
159
|
+
process.stderr.write(`[db-daemon] Batch transport error (${errMsg}), falling back to direct
|
|
160
|
+
`);
|
|
161
|
+
return fallbackClient.batch(stmts, mode);
|
|
162
|
+
}
|
|
163
|
+
if (isTransportError(errMsg)) {
|
|
164
|
+
_useDaemon = false;
|
|
165
|
+
throw new Error(`Daemon transport error after write batch; refusing unsafe retry: ${errMsg}`);
|
|
166
|
+
}
|
|
167
|
+
throw new Error(errMsg);
|
|
168
|
+
}
|
|
169
|
+
const batchResults = response["db-batch"];
|
|
170
|
+
if (batchResults) {
|
|
171
|
+
return batchResults.map(deserializeResultSet);
|
|
172
|
+
}
|
|
173
|
+
if (isMcpProcess()) throw unavailableForMcp("Unexpected daemon batch response shape");
|
|
174
|
+
if (!statements.every((s) => isReadOnlySql(s.sql))) {
|
|
175
|
+
throw new Error("Unexpected daemon response after write batch; refusing unsafe direct fallback");
|
|
176
|
+
}
|
|
177
|
+
process.stderr.write("[db-daemon] Unexpected batch response shape, falling back to direct\n");
|
|
178
|
+
return fallbackClient.batch(stmts, mode);
|
|
179
|
+
},
|
|
180
|
+
// Transaction support — delegate to fallback (transactions need direct connection)
|
|
181
|
+
async transaction(mode) {
|
|
182
|
+
return fallbackClient.transaction(mode);
|
|
183
|
+
},
|
|
184
|
+
// executeMultiple — delegate to fallback (used only for schema migrations)
|
|
185
|
+
async executeMultiple(sql) {
|
|
186
|
+
return fallbackClient.executeMultiple(sql);
|
|
187
|
+
},
|
|
188
|
+
// migrate — delegate to fallback
|
|
189
|
+
async migrate(stmts) {
|
|
190
|
+
return fallbackClient.migrate(stmts);
|
|
191
|
+
},
|
|
192
|
+
// Sync mode — delegate to fallback
|
|
193
|
+
sync() {
|
|
194
|
+
return fallbackClient.sync();
|
|
195
|
+
},
|
|
196
|
+
close() {
|
|
197
|
+
_useDaemon = false;
|
|
198
|
+
},
|
|
199
|
+
get closed() {
|
|
200
|
+
return fallbackClient.closed;
|
|
201
|
+
},
|
|
202
|
+
get protocol() {
|
|
203
|
+
return fallbackClient.protocol;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
...client,
|
|
208
|
+
/** Enable daemon routing (call after confirming daemon is connected) */
|
|
209
|
+
_enableDaemon() {
|
|
210
|
+
_useDaemon = true;
|
|
211
|
+
},
|
|
212
|
+
/** Check if daemon routing is active */
|
|
213
|
+
_isDaemonActive() {
|
|
214
|
+
return _useDaemon && isClientConnected();
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
async function initDaemonDbClient(fallbackClient) {
|
|
219
|
+
if (process.env.EXE_IS_DAEMON === "1") return null;
|
|
220
|
+
const connected = await connectEmbedDaemon();
|
|
221
|
+
const client = createDaemonDbClient(fallbackClient);
|
|
222
|
+
if (connected) {
|
|
223
|
+
client._enableDaemon();
|
|
224
|
+
process.stderr.write("[db-daemon] DB routing through daemon (single-writer)\n");
|
|
225
|
+
} else {
|
|
226
|
+
process.stderr.write("[db-daemon] Daemon unavailable at init \u2014 will retry lazily\n");
|
|
227
|
+
}
|
|
228
|
+
return client;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export {
|
|
232
|
+
isTransientDaemonTransportError,
|
|
233
|
+
retryOnDaemonTransportError,
|
|
234
|
+
createDaemonDbClient,
|
|
235
|
+
initDaemonDbClient
|
|
236
|
+
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveAnthropicAuth
|
|
3
|
+
} from "./chunk-EJIF4FNT.js";
|
|
4
|
+
|
|
5
|
+
// src/lib/retrieval-health.ts
|
|
6
|
+
async function getRetrievalHealth() {
|
|
7
|
+
let embedDaemon = "unavailable";
|
|
8
|
+
try {
|
|
9
|
+
const { isDaemonAlive } = await import("./mcp-health-WDOB6XUB.js");
|
|
10
|
+
const { alive } = isDaemonAlive();
|
|
11
|
+
if (alive) {
|
|
12
|
+
try {
|
|
13
|
+
const { pingDaemon } = await import("./lib/exe-daemon-client.js");
|
|
14
|
+
const health = await pingDaemon();
|
|
15
|
+
if (health) {
|
|
16
|
+
const worker = health.embedWorker;
|
|
17
|
+
const embeddingField = health.embedding;
|
|
18
|
+
if (worker?.disabledByDesign || embeddingField === "disabled") {
|
|
19
|
+
embedDaemon = "disabled";
|
|
20
|
+
} else if (worker) {
|
|
21
|
+
embedDaemon = worker.forked && worker.ready && worker.pid != null ? "running" : "stopped";
|
|
22
|
+
} else if (embeddingField === "ok") {
|
|
23
|
+
embedDaemon = "running";
|
|
24
|
+
} else {
|
|
25
|
+
embedDaemon = "stopped";
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
embedDaemon = "stopped";
|
|
29
|
+
}
|
|
30
|
+
} catch {
|
|
31
|
+
embedDaemon = "stopped";
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
embedDaemon = "unavailable";
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
embedDaemon = "unavailable";
|
|
38
|
+
}
|
|
39
|
+
let configuredSearchMode = "hybrid";
|
|
40
|
+
let selfQueryRouterEnabled = true;
|
|
41
|
+
try {
|
|
42
|
+
const { loadConfigSync } = await import("./lib/config.js");
|
|
43
|
+
const cfg = loadConfigSync();
|
|
44
|
+
configuredSearchMode = cfg.searchMode ?? "hybrid";
|
|
45
|
+
selfQueryRouterEnabled = cfg.selfQueryRouter ?? true;
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
let actualSearchMode;
|
|
49
|
+
if (configuredSearchMode === "fts") {
|
|
50
|
+
actualSearchMode = "fts+graph";
|
|
51
|
+
} else if (embedDaemon === "running") {
|
|
52
|
+
actualSearchMode = "hybrid (vector+fts+graph)";
|
|
53
|
+
} else {
|
|
54
|
+
actualSearchMode = "fts+graph (degraded from hybrid)";
|
|
55
|
+
}
|
|
56
|
+
let queryRouter;
|
|
57
|
+
if (!selfQueryRouterEnabled) {
|
|
58
|
+
queryRouter = "disabled";
|
|
59
|
+
} else if (embedDaemon === "running" || embedDaemon === "disabled") {
|
|
60
|
+
queryRouter = resolveAnthropicAuth() ? "active" : "fallback";
|
|
61
|
+
} else {
|
|
62
|
+
queryRouter = "fallback";
|
|
63
|
+
}
|
|
64
|
+
let totalMemories = 0;
|
|
65
|
+
let memoriesWithVectors = 0;
|
|
66
|
+
let entities = 0;
|
|
67
|
+
let relationships = 0;
|
|
68
|
+
try {
|
|
69
|
+
const { getClient } = await import("./lib/database.js");
|
|
70
|
+
const client = getClient();
|
|
71
|
+
const [totalRes, vectorRes] = await Promise.all([
|
|
72
|
+
client.execute("SELECT COUNT(*) as cnt FROM memories WHERE status IS NULL OR status != 'deleted'"),
|
|
73
|
+
client.execute("SELECT COUNT(*) as cnt FROM memories WHERE vector IS NOT NULL AND (status IS NULL OR status != 'deleted')")
|
|
74
|
+
]);
|
|
75
|
+
totalMemories = Number(totalRes.rows[0]?.cnt ?? 0);
|
|
76
|
+
memoriesWithVectors = Number(vectorRes.rows[0]?.cnt ?? 0);
|
|
77
|
+
try {
|
|
78
|
+
const { getGraphStats } = await import("./graph-query-AP5R6ZHO.js");
|
|
79
|
+
const stats = await getGraphStats(client);
|
|
80
|
+
entities = stats.entities;
|
|
81
|
+
relationships = stats.relationships;
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
const staleCount = totalMemories - memoriesWithVectors;
|
|
87
|
+
const coveragePct = totalMemories > 0 ? Math.round(memoriesWithVectors / totalMemories * 100) : null;
|
|
88
|
+
let dbRestore = { hasEvents: false, count: 0, last: null, quarantineFiles: 0 };
|
|
89
|
+
try {
|
|
90
|
+
const { getDbRestoreHealth } = await import("./db-restore-events-GNZS42YO.js");
|
|
91
|
+
dbRestore = getDbRestoreHealth();
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
const summary = {
|
|
95
|
+
embedDaemon,
|
|
96
|
+
searchMode: {
|
|
97
|
+
configured: configuredSearchMode,
|
|
98
|
+
actual: actualSearchMode
|
|
99
|
+
},
|
|
100
|
+
queryRouter,
|
|
101
|
+
vectorBackfill: {
|
|
102
|
+
totalMemories,
|
|
103
|
+
memoriesWithVectors,
|
|
104
|
+
staleCount,
|
|
105
|
+
coveragePct
|
|
106
|
+
},
|
|
107
|
+
graph: {
|
|
108
|
+
entities,
|
|
109
|
+
relationships
|
|
110
|
+
},
|
|
111
|
+
dbRestore
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
...summary,
|
|
115
|
+
degradations: computeDegradations(summary)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function computeDegradations(h) {
|
|
119
|
+
const out = [];
|
|
120
|
+
const isRuntimeDowngrade = h.searchMode.actual.includes("degraded");
|
|
121
|
+
if (isRuntimeDowngrade) {
|
|
122
|
+
out.push({
|
|
123
|
+
code: "retrieval_downgraded",
|
|
124
|
+
severity: "warn",
|
|
125
|
+
message: `Retrieval running as "${h.searchMode.actual}" (configured: "${h.searchMode.configured}")`,
|
|
126
|
+
remediation: h.embedDaemon === "disabled" ? "Embeddings are disabled. Enable them in settings if you want vector retrieval." : "Embed daemon is not running. Start the daemon / embed worker to restore hybrid retrieval."
|
|
127
|
+
});
|
|
128
|
+
} else if (h.searchMode.configured === "fts") {
|
|
129
|
+
out.push({
|
|
130
|
+
code: "embeddings_off",
|
|
131
|
+
severity: "info",
|
|
132
|
+
message: "Search mode is FTS-only by configuration (keyword + graph; no vector retrieval)",
|
|
133
|
+
remediation: 'Switch searchMode to "hybrid" in settings to enable vector retrieval.'
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (h.queryRouter === "fallback") {
|
|
137
|
+
out.push({
|
|
138
|
+
code: "query_router_fallback",
|
|
139
|
+
severity: "info",
|
|
140
|
+
message: "Self-query-router using rule-based fallback (LLM routing is an optional enrichment; keyword + graph retrieval unaffected)",
|
|
141
|
+
remediation: "To enable LLM-based query routing, provide an Anthropic credential: set ANTHROPIC_API_KEY, or ANTHROPIC_AUTH_TOKEN if you use Claude Code / OpenCode / a subscription-OAuth host."
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (h.dbRestore.hasEvents) {
|
|
145
|
+
const last = h.dbRestore.last;
|
|
146
|
+
if (last && (last.kind === "restore-failed" || last.kind === "zeroed-no-wal")) {
|
|
147
|
+
out.push({
|
|
148
|
+
code: "db_corruption_unrecovered",
|
|
149
|
+
severity: "critical",
|
|
150
|
+
message: `DB corruption could not be auto-recovered: ${last.detail ?? last.kind} (${last.at})`,
|
|
151
|
+
remediation: "Restore from a known-good backup (`exe-os cloud reupload` or restore a backup); preserved corrupt DB is in ~/.exe-os/."
|
|
152
|
+
});
|
|
153
|
+
} else if (last && (last.kind === "auto-restore" || last.kind === "wal-recovery")) {
|
|
154
|
+
out.push({
|
|
155
|
+
code: "db_auto_restored",
|
|
156
|
+
severity: "warn",
|
|
157
|
+
message: last.kind === "auto-restore" ? `DB was auto-restored from backup${last.restoredFrom ? ` (${last.restoredFrom})` : ""}${typeof last.hoursLost === "number" ? `, ~${last.hoursLost}h data-loss window` : ""} at ${last.at}` : `DB was reconstructed from WAL after a 0-byte corruption at ${last.at}`,
|
|
158
|
+
remediation: "Recent memories may be missing. Run a cloud sync to reconcile and verify recent data."
|
|
159
|
+
});
|
|
160
|
+
} else if (h.dbRestore.quarantineFiles > 0) {
|
|
161
|
+
out.push({
|
|
162
|
+
code: "db_corruption_quarantine",
|
|
163
|
+
severity: "warn",
|
|
164
|
+
message: `${h.dbRestore.quarantineFiles} quarantined corrupt DB file(s) present in ~/.exe-os/ (prior corruption event)`,
|
|
165
|
+
remediation: "Verify data integrity; remove quarantined .corrupt-*/.zeroed-* files once you've confirmed no data is needed."
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
var SEVERITY_ICON = {
|
|
172
|
+
info: "\u2139\uFE0F",
|
|
173
|
+
// ℹ️
|
|
174
|
+
warn: "\u{1F7E0}",
|
|
175
|
+
// 🟠
|
|
176
|
+
critical: "\u{1F534}"
|
|
177
|
+
// 🔴
|
|
178
|
+
};
|
|
179
|
+
function formatDegradations(degradations, heading = "Degradations") {
|
|
180
|
+
const lines = [];
|
|
181
|
+
lines.push(`### ${heading}`);
|
|
182
|
+
if (degradations.length === 0) {
|
|
183
|
+
lines.push("\u{1F7E2} None \u2014 all retrieval and storage subsystems nominal.");
|
|
184
|
+
return lines.join("\n");
|
|
185
|
+
}
|
|
186
|
+
const order = { critical: 0, warn: 1, info: 2 };
|
|
187
|
+
const sorted = [...degradations].sort((a, b) => order[a.severity] - order[b.severity]);
|
|
188
|
+
for (const d of sorted) {
|
|
189
|
+
lines.push(`${SEVERITY_ICON[d.severity]} ${d.message}`);
|
|
190
|
+
if (d.remediation) lines.push(` \u2192 ${d.remediation}`);
|
|
191
|
+
}
|
|
192
|
+
return lines.join("\n");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export {
|
|
196
|
+
getRetrievalHealth,
|
|
197
|
+
computeDegradations,
|
|
198
|
+
formatDegradations
|
|
199
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// src/lib/cc-binary-detect.ts
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
var CC_NATIVE_ONLY_CUTOFF = "2.1.119";
|
|
6
|
+
var CC_SAFE_PINNED_VERSION = "2.1.98";
|
|
7
|
+
function detectAutoupdaterVar(varName, homeDir = process.env.HOME ?? process.env.USERPROFILE ?? "", env = process.env) {
|
|
8
|
+
if (env[varName] === "1") {
|
|
9
|
+
return { source: "env" };
|
|
10
|
+
}
|
|
11
|
+
if (homeDir.length === 0) return null;
|
|
12
|
+
const profiles = [
|
|
13
|
+
".zshrc",
|
|
14
|
+
".zprofile",
|
|
15
|
+
".bashrc",
|
|
16
|
+
".bash_profile",
|
|
17
|
+
".profile"
|
|
18
|
+
];
|
|
19
|
+
const pattern = new RegExp(
|
|
20
|
+
`^\\s*(?:export\\s+)?${varName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=["']?1["']?\\s*$`,
|
|
21
|
+
"m"
|
|
22
|
+
);
|
|
23
|
+
for (const name of profiles) {
|
|
24
|
+
const file = path.join(homeDir, name);
|
|
25
|
+
if (!existsSync(file)) continue;
|
|
26
|
+
try {
|
|
27
|
+
const content = readFileSync(file, "utf8");
|
|
28
|
+
const uncommented = content.split("\n").filter((line) => !/^\s*#/.test(line)).join("\n");
|
|
29
|
+
if (pattern.test(uncommented)) {
|
|
30
|
+
return { source: "profile", profile: name };
|
|
31
|
+
}
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
function isAutoupdaterDisabled(env = process.env, homeDir = env.HOME ?? env.USERPROFILE ?? "") {
|
|
38
|
+
return detectAutoupdaterVar("DISABLE_AUTOUPDATER", homeDir, env) !== null || detectAutoupdaterVar("CLAUDE_CODE_AUTOUPDATER_DISABLED", homeDir, env) !== null;
|
|
39
|
+
}
|
|
40
|
+
function compareSemver(a, b) {
|
|
41
|
+
const pa = a.split(".").map((n) => Number.parseInt(n, 10));
|
|
42
|
+
const pb = b.split(".").map((n) => Number.parseInt(n, 10));
|
|
43
|
+
const len = Math.max(pa.length, pb.length);
|
|
44
|
+
for (let i = 0; i < len; i++) {
|
|
45
|
+
const x = Number.isFinite(pa[i]) ? pa[i] : 0;
|
|
46
|
+
const y = Number.isFinite(pb[i]) ? pb[i] : 0;
|
|
47
|
+
if (x !== y) return x - y;
|
|
48
|
+
}
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
function looksNative(p) {
|
|
52
|
+
return p.includes("bin/claude.exe") || p.includes("bin/claude-native") || p.includes("claude.exe") || p.includes("claude-native") || p.includes("claude/versions/");
|
|
53
|
+
}
|
|
54
|
+
function detectCcNativeBinary(env = process.env) {
|
|
55
|
+
const reasons = [];
|
|
56
|
+
let resolvedPath;
|
|
57
|
+
let version;
|
|
58
|
+
const execPath = (env.CLAUDE_CODE_EXECPATH ?? "").trim();
|
|
59
|
+
if (execPath.length > 0 && looksNative(execPath)) {
|
|
60
|
+
reasons.push(`CLAUDE_CODE_EXECPATH points to native binary: ${execPath}`);
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const claudePath = execSync("which claude 2>/dev/null || true", {
|
|
64
|
+
encoding: "utf8",
|
|
65
|
+
timeout: 5e3
|
|
66
|
+
}).trim();
|
|
67
|
+
if (claudePath) {
|
|
68
|
+
let resolved = claudePath;
|
|
69
|
+
try {
|
|
70
|
+
resolved = execSync(
|
|
71
|
+
`readlink -f "${claudePath}" 2>/dev/null || readlink "${claudePath}" 2>/dev/null || echo "${claudePath}"`,
|
|
72
|
+
{ encoding: "utf8", timeout: 5e3 }
|
|
73
|
+
).trim();
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
resolvedPath = resolved;
|
|
77
|
+
if (looksNative(resolved)) {
|
|
78
|
+
reasons.push(`claude resolves to native binary: ${resolved}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const versionsDir = path.join(
|
|
85
|
+
env.HOME ?? env.USERPROFILE ?? "",
|
|
86
|
+
".local",
|
|
87
|
+
"share",
|
|
88
|
+
"claude",
|
|
89
|
+
"versions"
|
|
90
|
+
);
|
|
91
|
+
if (versionsDir && existsSync(versionsDir)) {
|
|
92
|
+
const entries = readdirSync(versionsDir);
|
|
93
|
+
if (entries.length > 0) {
|
|
94
|
+
reasons.push(
|
|
95
|
+
`${entries.length} cached native CC version(s) in ${versionsDir}`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const out = execSync("claude --version 2>/dev/null || echo unknown", {
|
|
103
|
+
encoding: "utf8",
|
|
104
|
+
timeout: 5e3
|
|
105
|
+
}).trim();
|
|
106
|
+
const m = out.match(/(\d+\.\d+\.\d+)/);
|
|
107
|
+
if (m) {
|
|
108
|
+
version = m[1];
|
|
109
|
+
if (compareSemver(version, CC_NATIVE_ONLY_CUTOFF) >= 0) {
|
|
110
|
+
reasons.push(
|
|
111
|
+
`CC version ${version} is \u2265${CC_NATIVE_ONLY_CUTOFF} (native-binary build)`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
return { detected: reasons.length > 0, reasons, resolvedPath, version };
|
|
118
|
+
}
|
|
119
|
+
function ccNativeBinaryWarningLine(status = detectCcNativeBinary(), env = process.env) {
|
|
120
|
+
if (!status.detected) return null;
|
|
121
|
+
if (isAutoupdaterDisabled(env)) return null;
|
|
122
|
+
const ver = status.version ? ` (v${status.version})` : "";
|
|
123
|
+
return `\u{1F534} Claude Code native binary detected${ver} \u2014 phantom-billing risk. exe-os is tested against cli.js. Mitigate: disable the auto-updater (export DISABLE_AUTOUPDATER=1 and CLAUDE_CODE_AUTOUPDATER_DISABLED=1 in your shell profile) (run \`exe-os healthcheck\` for details). Advisory only.`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
CC_NATIVE_ONLY_CUTOFF,
|
|
128
|
+
CC_SAFE_PINNED_VERSION,
|
|
129
|
+
detectAutoupdaterVar,
|
|
130
|
+
isAutoupdaterDisabled,
|
|
131
|
+
compareSemver,
|
|
132
|
+
detectCcNativeBinary,
|
|
133
|
+
ccNativeBinaryWarningLine
|
|
134
|
+
};
|