@askexenow/exe-os 0.9.256 → 0.9.259
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 +13 -13
- package/deploy/compose/.env.example +8 -8
- package/deploy/compose/docker-compose.yml +18 -18
- package/deploy/compose/generate-env.ts +22 -18
- package/deploy/compose/init-db.sql +221 -20
- package/deploy/stack-manifests/v0.9.json +1207 -1136
- package/dist/{active-agent-DTZ6VJIR.js → active-agent-IGZXTTV4.js} +3 -3
- package/dist/{active-agent-7QNK5CJZ.js → active-agent-OYUXMTHS.js} +3 -3
- package/dist/{agentic-ontology-UZK33N6I.js → agentic-ontology-5WT23SLZ.js} +1 -1
- package/dist/{backfill-metadata-R7PNZ5TX.js → backfill-metadata-EG52U3GF.js} +4 -4
- package/dist/{behaviors-G6QHSQBN.js → behaviors-2TZCFJLU.js} +3 -3
- package/dist/bin/age-ontology-load.js +2 -2
- 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 -5
- package/dist/bin/backfill-responses.js +6 -5
- package/dist/bin/backfill-vectors.js +7 -6
- package/dist/bin/bulk-sync-postgres.js +6 -6
- package/dist/bin/cleanup-stale-review-tasks.js +9 -9
- package/dist/bin/cli.js +17 -17
- package/dist/bin/deferred-daemon-restart.js +4 -1
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +4 -4
- package/dist/bin/exe-assign.js +8 -7
- package/dist/bin/exe-boot.js +16 -16
- package/dist/bin/exe-call.js +4 -4
- package/dist/bin/exe-cloud.js +4 -4
- package/dist/bin/exe-dispatch.js +9 -9
- package/dist/bin/exe-doctor.js +1 -1
- package/dist/bin/exe-export-behaviors.js +7 -7
- package/dist/bin/exe-forget.js +6 -6
- package/dist/bin/exe-gateway.js +9 -9
- package/dist/bin/exe-heartbeat.js +9 -9
- package/dist/bin/exe-kill.js +12 -12
- package/dist/bin/exe-launch-agent.js +16 -16
- package/dist/bin/exe-new-employee.js +6 -6
- package/dist/bin/exe-pending-messages.js +11 -10
- package/dist/bin/exe-pending-notifications.js +9 -9
- package/dist/bin/exe-pending-reviews.js +11 -9
- package/dist/bin/exe-rename.js +4 -4
- package/dist/bin/exe-review.js +11 -11
- package/dist/bin/exe-search.js +5 -5
- package/dist/bin/exe-session-cleanup.js +14 -14
- package/dist/bin/exe-settings.js +4 -4
- package/dist/bin/exe-start-codex.js +11 -11
- package/dist/bin/exe-start-opencode.js +8 -8
- package/dist/bin/exe-status.js +10 -10
- package/dist/bin/exe-support.js +3 -1
- package/dist/bin/exe-team.js +3 -3
- package/dist/bin/git-sweep.js +71 -11
- package/dist/bin/graph-backfill.js +4 -4
- package/dist/bin/graph-export.js +5 -5
- package/dist/bin/graph-layer-benchmark.js +7 -7
- package/dist/bin/import-history.js +7 -7
- package/dist/bin/install.js +12 -9
- 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 +7 -7
- package/dist/bin/postgres-agentic-semantic-backfill.js +7 -7
- package/dist/bin/scan-tasks.js +9 -9
- package/dist/bin/setup.js +1 -1
- package/dist/bin/shard-migrate.js +4 -4
- package/dist/bin/stack-update.js +20 -3
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/{capacity-monitor-QMKII67L.js → capacity-monitor-CTFWWTCR.js} +10 -10
- package/dist/{catchup-brief-CNISNLV7.js → catchup-brief-UML47LXI.js} +11 -11
- package/dist/{chunk-QP4FHME2.js → chunk-235ZCOYB.js} +18 -6
- package/dist/{chunk-2NEQQCRC.js → chunk-25JAXHON.js} +1 -1
- package/dist/{chunk-MU6ESLYL.js → chunk-2PFNATXD.js} +1 -1
- package/dist/chunk-2XZ6X3PJ.js +13 -0
- package/dist/chunk-3XX3CDKF.js +9 -0
- package/dist/{chunk-ZTB6E2ZL.js → chunk-4FGTT26Q.js} +1 -1
- package/dist/{chunk-YYSQAM4W.js → chunk-4TYAHVDI.js} +8 -8
- package/dist/{chunk-2QKNXGII.js → chunk-4VECWOUO.js} +2 -2
- package/dist/{chunk-YXMXP45V.js → chunk-57C3MZPQ.js} +2 -2
- package/dist/{chunk-FTNNNAMH.js → chunk-5JYCTIQD.js} +1 -1
- package/dist/{chunk-CS267UMH.js → chunk-5LDTCWYX.js} +79 -19
- package/dist/{chunk-FQVITYVF.js → chunk-6D2IZ5MB.js} +2 -2
- package/dist/{chunk-ZG3HADWE.js → chunk-7UJRF4WF.js} +1 -1
- package/dist/{chunk-JFVITKXI.js → chunk-A2UPDE3J.js} +1 -1
- package/dist/{chunk-KOCQAMAM.js → chunk-ANYOAZCZ.js} +238 -5
- package/dist/{chunk-PSQNT5DS.js → chunk-AQS2B3HC.js} +8 -8
- package/dist/{chunk-ABNALOLM.js → chunk-BGEXTWGR.js} +3 -3
- package/dist/{chunk-LPK5JPME.js → chunk-BPZL5YOM.js} +1 -1
- package/dist/{chunk-RLDOG7DI.js → chunk-C6SSCNOC.js} +2516 -2289
- package/dist/{chunk-JGEGEOVP.js → chunk-COKTAJUZ.js} +1 -1
- package/dist/{chunk-MRZE5IOP.js → chunk-CXOX7TRG.js} +1 -1
- package/dist/{chunk-6LFFIEDM.js → chunk-DU64OESH.js} +1 -1
- package/dist/{chunk-LYIUESG2.js → chunk-DYURFBPS.js} +10 -10
- package/dist/{chunk-X3SS45PO.js → chunk-FPXZY3FY.js} +1 -1
- package/dist/{chunk-TVTRMINO.js → chunk-FUGZF7VR.js} +1 -1
- package/dist/{chunk-O7SFCX5B.js → chunk-GB4FI66P.js} +2 -2
- package/dist/{chunk-VGWQBI76.js → chunk-GBR4MAAK.js} +1 -1
- package/dist/chunk-GH4LVBQM.js +371 -0
- package/dist/{chunk-AIXZ5O7U.js → chunk-GIHMDOSK.js} +1 -1
- package/dist/{chunk-RDCE652I.js → chunk-HDWVXSGO.js} +1 -1
- package/dist/{chunk-RF54NGPJ.js → chunk-IJ7R3MXE.js} +3 -5
- package/dist/{chunk-R7FBOZT5.js → chunk-ISL3NSVX.js} +1 -1
- package/dist/{chunk-5B2AEXVA.js → chunk-IVSRRIRG.js} +1 -1
- package/dist/{chunk-SD2R3SEA.js → chunk-J3YNCJ4A.js} +1 -1
- package/dist/{chunk-5IZYSS3M.js → chunk-JE4C74EE.js} +4 -4
- package/dist/{chunk-VRVHIVUE.js → chunk-KSR2PNRW.js} +2 -2
- package/dist/{chunk-LL2ARYTZ.js → chunk-L3PY4NFQ.js} +1 -1
- package/dist/{chunk-VFATLVRX.js → chunk-L5VPUOB6.js} +1 -1
- package/dist/{chunk-3VLFVOM7.js → chunk-LRKJGSNH.js} +2 -2
- package/dist/{chunk-4FT3SQAS.js → chunk-LVY74L2J.js} +2 -2
- package/dist/{chunk-X4T7LR2X.js → chunk-M7PZFYHE.js} +2 -2
- package/dist/{chunk-CIX64N7D.js → chunk-MGTVPIEZ.js} +1 -1
- package/dist/{chunk-MXCBORCC.js → chunk-MKTEGZ37.js} +3 -3
- package/dist/chunk-MMRUBN3I.js +36 -0
- package/dist/{chunk-4MONXPWR.js → chunk-MPXLF7TA.js} +1 -1
- package/dist/{chunk-6QMXKKFD.js → chunk-N27CTUFU.js} +1 -1
- package/dist/{chunk-YDHPC4PX.js → chunk-N4ES27RI.js} +3 -3
- package/dist/{chunk-WIRJ574R.js → chunk-NGQQRGLP.js} +2 -2
- package/dist/{chunk-AQOCHSIR.js → chunk-OCJ5GZKV.js} +4 -4
- package/dist/{chunk-O477L4LV.js → chunk-OSPS5N2I.js} +1 -1
- package/dist/{chunk-5WEH43HH.js → chunk-PQHA6X6Y.js} +1 -1
- package/dist/{chunk-DJYIBHN5.js → chunk-PQQTSNXS.js} +3 -3
- package/dist/{chunk-LGFB67MY.js → chunk-Q3GLQDZI.js} +1 -1
- package/dist/{chunk-7GR7VBBW.js → chunk-QUC27OCW.js} +1 -1
- package/dist/{chunk-5NBOFYJG.js → chunk-QYNFWFFH.js} +4 -4
- package/dist/{chunk-X7I6NLIA.js → chunk-T2EUNNUX.js} +5 -5
- package/dist/{chunk-VRWOLLKN.js → chunk-T4NFOOPB.js} +2 -2
- package/dist/{chunk-2YJSDJEH.js → chunk-TZPHTI5Q.js} +1 -1
- package/dist/{chunk-CQSFIQGN.js → chunk-UOZ5KUNN.js} +1 -1
- package/dist/{chunk-5R4R743Q.js → chunk-V2UVWYHO.js} +17 -15
- package/dist/{chunk-VKCZ3OGM.js → chunk-VD676VIC.js} +4 -4
- package/dist/{chunk-USLVSLQ5.js → chunk-VDCPKJUQ.js} +1 -1
- package/dist/{chunk-Y7NMPQXZ.js → chunk-VLX6AHTD.js} +8 -8
- package/dist/{chunk-ITPIBVSG.js → chunk-WMZTSHNX.js} +83 -1
- package/dist/{chunk-5U7WB4YG.js → chunk-WVBZ3QBR.js} +2 -2
- package/dist/{chunk-3EMZZZNU.js → chunk-X2RKYKTP.js} +1 -1
- package/dist/{chunk-XTIHYH64.js → chunk-YY2BCIAP.js} +2 -2
- package/dist/{chunk-Z6GHDYQI.js → chunk-Z2AEOVEZ.js} +30 -6
- package/dist/{chunk-PHTRZQR4.js → chunk-ZBDAFYDD.js} +4 -4
- package/dist/{chunk-E4CCKWZN.js → chunk-ZKFTDL4M.js} +1 -1
- package/dist/{co-activation-AIVMI5U2.js → co-activation-UNVL5JCP.js} +2 -2
- package/dist/{co-occurrence-L6QOQTJB.js → co-occurrence-ETAVWYVE.js} +2 -2
- package/dist/{code-context-index-DYHYVJHX.js → code-context-index-DCQYAYA2.js} +3 -2
- package/dist/{crdt-sync-YBMDPFNT.js → crdt-sync-AH7N6QOE.js} +1 -1
- package/dist/{crm-webhook-QO3ZESKR.js → crm-webhook-R6546T3Y.js} +2 -2
- package/dist/{cto-delegation-gate-UFPVFLIW.js → cto-delegation-gate-VB4TMZ3I.js} +8 -8
- package/dist/{daemon-orchestration-6XAISQ7B.js → daemon-orchestration-YAJKIL6Q.js} +12 -12
- package/dist/{db-backup-7UMCTS44.js → db-backup-2RG6VHT7.js} +11 -3
- package/dist/{dreaming-FJ75QVGZ.js → dreaming-WMBTSXGD.js} +9 -9
- package/dist/{exe-drift-OH3WV2ZQ.js → exe-drift-MQZGYHEN.js} +3 -3
- package/dist/{exe-export-UYKYNVBU.js → exe-export-E4BDIHOC.js} +5 -5
- package/dist/{exe-import-Q4FNSMLJ.js → exe-import-IWAD4HN6.js} +5 -5
- package/dist/{exe-key-22LOIIUX.js → exe-key-L2RV7XJX.js} +2 -2
- package/dist/{exe-snapshot-J7CL6QEL.js → exe-snapshot-IOGN4ARV.js} +12 -12
- package/dist/{fast-db-init-QXGL2PKQ.js → fast-db-init-GCY3F74H.js} +1 -1
- package/dist/gateway/index.js +8 -8
- package/dist/{git-staleness-YVWDCFIE.js → git-staleness-BQIFNZIU.js} +2 -2
- package/dist/{git-task-sweep-RRCOTTIS.js → git-task-sweep-GSKS6WKR.js} +9 -9
- package/dist/{global-procedures-FCGWAFES.js → global-procedures-3DJUA5OX.js} +3 -3
- package/dist/{graph-auto-extract-RUQC5IIS.js → graph-auto-extract-2I44WRDY.js} +2 -2
- package/dist/hooks/bug-report-worker.js +11 -11
- package/dist/hooks/codex-stop-task-finalizer.js +11 -11
- package/dist/hooks/commit-complete.js +11 -11
- package/dist/hooks/error-recall.js +6 -6
- package/dist/hooks/exe-heartbeat-hook.js +3 -3
- package/dist/hooks/ingest-worker.js +3 -2
- 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 +10 -10
- package/dist/hooks/post-tool-combined.js +6 -6
- package/dist/hooks/pre-compact.js +14 -13
- package/dist/hooks/pre-tool-use.js +14 -14
- package/dist/hooks/prompt-submit.js +22 -22
- package/dist/hooks/session-end.js +19 -18
- package/dist/hooks/session-start.js +11 -11
- package/dist/hooks/stop.js +70 -17
- package/dist/hooks/subagent-stop.js +10 -10
- package/dist/hooks/summary-worker.js +17 -16
- package/dist/index.js +17 -17
- package/dist/{installer-7SMJC3SX.js → installer-6MQCAHUG.js} +5 -5
- package/dist/{installer-GFZVC43I.js → installer-TCMPFSSP.js} +5 -5
- package/dist/{installer-34DCTB5B.js → installer-ZY2BKTEO.js} +5 -5
- package/dist/lib/cloud-sync.js +4 -4
- package/dist/lib/consolidation.js +5 -5
- package/dist/lib/database.js +2 -2
- package/dist/lib/db-daemon-client.js +58 -13
- package/dist/lib/db.js +2 -2
- package/dist/lib/embedder.js +3 -2
- package/dist/lib/employee-templates.js +4 -4
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon-client.js +2 -1
- package/dist/lib/exe-daemon.js +255 -104
- package/dist/lib/hybrid-search.js +5 -5
- package/dist/lib/identity.js +2 -2
- package/dist/lib/messaging.js +9 -9
- 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 +4 -4
- package/dist/lib/store.js +4 -4
- package/dist/lib/task-router.js +3 -3
- package/dist/lib/tasks.js +10 -10
- package/dist/lib/tmux-routing.js +8 -8
- package/dist/lib/token-spend.js +3 -3
- package/dist/mcp/register-tools.js +59 -56
- package/dist/mcp/server.js +60 -57
- 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 +12 -12
- package/dist/mcp/tools/deactivate-behavior.js +5 -5
- package/dist/mcp/tools/list-reminders.js +4 -4
- package/dist/mcp/tools/list-tasks.js +12 -12
- package/dist/mcp/tools/send-message.js +11 -11
- package/dist/mcp/tools/update-task.js +11 -11
- package/dist/{mcp-http-config-MZMHKMJC.js → mcp-http-config-VUDZ3D5D.js} +3 -3
- package/dist/{memory-cards-3SFXU6IP.js → memory-cards-ZOOPC2WF.js} +2 -2
- package/dist/{memory-graph-extractor-T57YQQCW.js → memory-graph-extractor-RRQMUBMI.js} +3 -3
- package/dist/{memory-poisoning-defense-O53AHMTZ.js → memory-poisoning-defense-UQMNLG6H.js} +2 -2
- package/dist/{memory-queue-client-ITWQIFSD.js → memory-queue-client-TPQDAA4D.js} +3 -2
- package/dist/{memory-reflection-YPP2JC2S.js → memory-reflection-GSGXAGXV.js} +2 -2
- package/dist/{notifications-BETWD6EK.js → notifications-ZKGLZVCU.js} +8 -8
- package/dist/{orchestration-events-A5D52NXX.js → orchestration-events-7RMWC5SS.js} +3 -3
- package/dist/{orchestrator-X564XCWC.js → orchestrator-A6MX2OHA.js} +10 -10
- package/dist/{pipeline-router-RVHLL7UA.js → pipeline-router-6ZBYJD2U.js} +3 -3
- package/dist/{plan-limits-ANAVC6PM.js → plan-limits-4XH4A7IA.js} +3 -3
- package/dist/{project-boot-ENMCAL7G.js → project-boot-7ZEIDWUG.js} +3 -2
- package/dist/{projection-worker-O3HBG5QK.js → projection-worker-YKKBNQZT.js} +130 -51
- package/dist/{reranker-SRJL4IWB.js → reranker-DN2A3H6O.js} +1 -1
- package/dist/{review-polling-5JTTHHEO.js → review-polling-PK3CY4NI.js} +9 -9
- package/dist/runtime/index.js +11 -11
- package/dist/{session-events-RCSYHQQ2.js → session-events-IYU6FYHH.js} +9 -9
- package/dist/{session-kill-telemetry-AL3H4ELS.js → session-kill-telemetry-G2VV4CAH.js} +3 -3
- package/dist/{session-scope-ZB4SR3AX.js → session-scope-DHTVH3D4.js} +8 -8
- package/dist/{setup-wizard-HXTADFXI.js → setup-wizard-IA5ISHQ2.js} +1 -1
- package/dist/{skill-refinement-TT4VDYYW.js → skill-refinement-6PBAFLWP.js} +2 -2
- package/dist/{stack-release-7WDKQOCO.js → stack-release-NW7MV3WV.js} +41 -11
- package/dist/{stack-update-F4CQWMGV.js → stack-update-5SM62R3O.js} +3 -1
- package/dist/{steward-gate-HSV67KLF.js → steward-gate-EQV6CZKY.js} +3 -3
- package/dist/support-outbox-SZVLHHZG.js +295 -0
- package/dist/{task-enforcement-A6AZTYAN.js → task-enforcement-2LS5DOXK.js} +8 -8
- package/dist/{task-scope-XKNAY5S7.js → task-scope-AKF3CSWO.js} +8 -8
- package/dist/{tasks-crud-F732BVOE.js → tasks-crud-KOIA5SAH.js} +8 -8
- package/dist/{tasks-notify-LJ65U7DF.js → tasks-notify-7ZTE4ZQM.js} +9 -9
- package/dist/{tasks-review-Y5F4HRAR.js → tasks-review-VMMMAK2Y.js} +8 -8
- package/dist/{telemetry-upload-HVYO6FL3.js → telemetry-upload-YLW4NAUF.js} +15 -8
- package/dist/{token-budget-VODGJYKX.js → token-budget-NA4OLFNP.js} +2 -2
- package/dist/{tool-capability-index-PZWWVABO.js → tool-capability-index-C73KVY5O.js} +1 -1
- package/dist/{tool-telemetry-5BSTF3P6.js → tool-telemetry-OVI5KL4S.js} +1 -1
- package/dist/tui/App.js +16 -16
- package/dist/{tui-data-EHJWRNRZ.js → tui-data-5NT24CC5.js} +8 -8
- package/dist/{worker-gate-4AS4K7G4.js → worker-gate-AQLJUQ5G.js} +1 -1
- package/dist/{workflow-engine-BXGNFNUW.js → workflow-engine-TRGGUNIZ.js} +2 -2
- package/dist/{worktree-3N5BPITS.js → worktree-NK7GZNEA.js} +4 -4
- package/dist/worktree-sweep-5XVZCH6A.js +18 -0
- package/package.json +3 -2
- package/release-notes.json +28 -27
- package/stack.release.json +48 -48
- package/dist/prediction-log-DOEOHDHS.js +0 -120
- package/dist/support-outbox-KEJ73I3F.js +0 -206
- /package/dist/{chunk-AWVDA2FL.js → chunk-2H3FVAN3.js} +0 -0
- /package/dist/{chunk-VPHOOQLR.js → chunk-3GHTBVZO.js} +0 -0
- /package/dist/{chunk-CCPCIW4Z.js → chunk-BBPRL2MP.js} +0 -0
- /package/dist/{chunk-X2E6W3DB.js → chunk-BRSI3FD6.js} +0 -0
- /package/dist/{chunk-Y2FVN7CX.js → chunk-EYLQRPHF.js} +0 -0
- /package/dist/{chunk-4S5TEBXD.js → chunk-H6QJT5O5.js} +0 -0
- /package/dist/{chunk-FCII2MMI.js → chunk-J5CAYOJU.js} +0 -0
- /package/dist/{chunk-LY2DYTDL.js → chunk-RFJESVEL.js} +0 -0
- /package/dist/{chunk-GBHQ5TXO.js → chunk-UOOCGJUE.js} +0 -0
- /package/dist/{core-memory-WFP2L52F.js → core-memory-VZFTGOFE.js} +0 -0
- /package/dist/{entity-boost-RTYXAOWV.js → entity-boost-OAB2PZQP.js} +0 -0
- /package/dist/{message-queue-client-2CACBUA4.js → message-queue-client-YTKTHAYO.js} +0 -0
- /package/dist/{wiki-acl-MS7QLQCR.js → wiki-acl-UCPOROPR.js} +0 -0
|
@@ -3,30 +3,30 @@ import {
|
|
|
3
3
|
} from "./chunk-MLXJ5EZG.js";
|
|
4
4
|
import {
|
|
5
5
|
createTask
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-V2UVWYHO.js";
|
|
7
7
|
import {
|
|
8
8
|
getActiveAgent
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-GBR4MAAK.js";
|
|
10
10
|
import {
|
|
11
11
|
ensureEmployee,
|
|
12
12
|
logTaskDispatch,
|
|
13
13
|
resolveExeSession
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-5LDTCWYX.js";
|
|
15
15
|
import {
|
|
16
16
|
recordOrchestrationEventBestEffort
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-VDCPKJUQ.js";
|
|
18
18
|
import {
|
|
19
19
|
getAgentRuntime
|
|
20
20
|
} from "./chunk-XJUUWHVN.js";
|
|
21
21
|
import {
|
|
22
22
|
getLicenseSync
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-L5VPUOB6.js";
|
|
24
24
|
import {
|
|
25
25
|
getAgentContext
|
|
26
26
|
} from "./chunk-GJV3WDWM.js";
|
|
27
27
|
import {
|
|
28
28
|
isCoordinatorName
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-WVBZ3QBR.js";
|
|
30
30
|
|
|
31
31
|
// src/mcp/tools/create-task.ts
|
|
32
32
|
import { z } from "zod";
|
|
@@ -275,7 +275,7 @@ function registerCreateTask(server) {
|
|
|
275
275
|
session_scope: sessionScope,
|
|
276
276
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
277
277
|
}), "utf-8");
|
|
278
|
-
const { recordOrchestrationEventBestEffort: recordOE } = await import("./orchestration-events-
|
|
278
|
+
const { recordOrchestrationEventBestEffort: recordOE } = await import("./orchestration-events-7RMWC5SS.js");
|
|
279
279
|
recordOE({
|
|
280
280
|
eventType: "signal.created",
|
|
281
281
|
source: "create-task.mcp",
|
|
@@ -307,7 +307,7 @@ function registerCreateTask(server) {
|
|
|
307
307
|
let projectConflictOpts = {};
|
|
308
308
|
try {
|
|
309
309
|
const { getClient } = await import("./lib/database.js");
|
|
310
|
-
const { sessionScopeFilter } = await import("./task-scope-
|
|
310
|
+
const { sessionScopeFilter } = await import("./task-scope-AKF3CSWO.js");
|
|
311
311
|
const client = getClient();
|
|
312
312
|
const scope = sessionScopeFilter(task.sessionScope || callerRoot || exeSession || null);
|
|
313
313
|
const existing = await client.execute({
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
listWorkflowDefinitions,
|
|
3
3
|
runWorkflow,
|
|
4
4
|
startWorkflow
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2PFNATXD.js";
|
|
6
6
|
import {
|
|
7
7
|
ingest
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-X2RKYKTP.js";
|
|
9
9
|
import {
|
|
10
10
|
initCRMBridge
|
|
11
11
|
} from "./chunk-ONKIWA3R.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
vectorToBlob
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-AQS2B3HC.js";
|
|
4
4
|
import {
|
|
5
5
|
extractKeywords,
|
|
6
6
|
keywordsToString
|
|
7
7
|
} from "./chunk-CHCA3ZM2.js";
|
|
8
8
|
import {
|
|
9
9
|
isCoordinatorName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-WVBZ3QBR.js";
|
|
11
11
|
|
|
12
12
|
// src/lib/consolidation.ts
|
|
13
13
|
import { randomUUID } from "crypto";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureWorktree
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DU64OESH.js";
|
|
4
4
|
import {
|
|
5
5
|
queueIntercom
|
|
6
6
|
} from "./chunk-5CHYEKMH.js";
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./chunk-4JERP7NT.js";
|
|
11
11
|
import {
|
|
12
12
|
registerSession
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-J3YNCJ4A.js";
|
|
14
14
|
import {
|
|
15
15
|
getTransport
|
|
16
16
|
} from "./chunk-MVW62NIZ.js";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
} from "./chunk-CX6GL3ZJ.js";
|
|
20
20
|
import {
|
|
21
21
|
recordOrchestrationEventBestEffort
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-VDCPKJUQ.js";
|
|
23
23
|
import {
|
|
24
24
|
getAgentRuntime,
|
|
25
25
|
normalizeCcModelName
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
import {
|
|
31
31
|
PlanLimitError,
|
|
32
32
|
assertEmployeeLimitSync
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-L5VPUOB6.js";
|
|
34
34
|
import {
|
|
35
35
|
getSessionKey
|
|
36
36
|
} from "./chunk-CVYC6DUW.js";
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
} from "./chunk-MP2AFCGL.js";
|
|
46
46
|
import {
|
|
47
47
|
ensureAgentSymlink
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-ISL3NSVX.js";
|
|
49
49
|
import {
|
|
50
50
|
expandDualPrefixTools
|
|
51
51
|
} from "./chunk-HYZV25LY.js";
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
isCoordinatorName,
|
|
58
58
|
loadEmployees,
|
|
59
59
|
loadEmployeesSync
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-WVBZ3QBR.js";
|
|
61
61
|
import {
|
|
62
62
|
loadDeviceId
|
|
63
63
|
} from "./chunk-MOZ2YQ54.js";
|
|
@@ -398,6 +398,52 @@ function checkLaneAffinity(title, context, assigneeName) {
|
|
|
398
398
|
}
|
|
399
399
|
async function resolveTask(client, identifier, scopeSession) {
|
|
400
400
|
const scope = sessionScopeFilter(scopeSession);
|
|
401
|
+
const currentScope = typeof scope.args[0] === "string" ? String(scope.args[0]) : null;
|
|
402
|
+
const crossSessionError = (rows) => {
|
|
403
|
+
if (!currentScope || rows.length === 0) return null;
|
|
404
|
+
const unique = /* @__PURE__ */ new Map();
|
|
405
|
+
for (const row of rows) unique.set(String(row.id), row);
|
|
406
|
+
const crossSessionRows = [...unique.values()].filter((row) => {
|
|
407
|
+
const rowScope = row.session_scope === null || row.session_scope === void 0 ? null : String(row.session_scope);
|
|
408
|
+
return rowScope !== null && rowScope !== currentScope;
|
|
409
|
+
});
|
|
410
|
+
if (crossSessionRows.length === 0) return null;
|
|
411
|
+
const matches = crossSessionRows.slice(0, 5).map((row) => `${String(row.id).slice(0, 8)} "${String(row.title)}" [session:${String(row.session_scope)}]`).join(", ");
|
|
412
|
+
return new Error(
|
|
413
|
+
`Cross-session task mutation blocked: "${identifier}" belongs to another coordinator session. Current session: ${currentScope}. Matching task(s): ${matches}. Use task(action="list", cross_session=true) for read-only diagnostics, or switch to the owning session to update/close.`
|
|
414
|
+
);
|
|
415
|
+
};
|
|
416
|
+
const findUnscopedMatches = async () => {
|
|
417
|
+
const matches = [];
|
|
418
|
+
const pushRows = (rows) => {
|
|
419
|
+
for (const row of rows) {
|
|
420
|
+
if (!matches.some((m) => String(m.id) === String(row.id))) matches.push(row);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
let result2 = await client.execute({
|
|
424
|
+
sql: "SELECT * FROM tasks WHERE id = ? LIMIT 10",
|
|
425
|
+
args: [identifier]
|
|
426
|
+
});
|
|
427
|
+
pushRows(result2.rows);
|
|
428
|
+
if (/^[a-f0-9]{7,12}$/i.test(identifier)) {
|
|
429
|
+
result2 = await client.execute({
|
|
430
|
+
sql: "SELECT * FROM tasks WHERE id LIKE ? LIMIT 10",
|
|
431
|
+
args: [`${identifier}%`]
|
|
432
|
+
});
|
|
433
|
+
pushRows(result2.rows);
|
|
434
|
+
}
|
|
435
|
+
result2 = await client.execute({
|
|
436
|
+
sql: "SELECT * FROM tasks WHERE task_file LIKE ? LIMIT 10",
|
|
437
|
+
args: [`%${identifier}%`]
|
|
438
|
+
});
|
|
439
|
+
pushRows(result2.rows);
|
|
440
|
+
result2 = await client.execute({
|
|
441
|
+
sql: "SELECT * FROM tasks WHERE title LIKE ? LIMIT 10",
|
|
442
|
+
args: [`%${identifier}%`]
|
|
443
|
+
});
|
|
444
|
+
pushRows(result2.rows);
|
|
445
|
+
return matches;
|
|
446
|
+
};
|
|
401
447
|
let result = await client.execute({
|
|
402
448
|
sql: `SELECT * FROM tasks WHERE id = ?${scope.sql}`,
|
|
403
449
|
args: [identifier, ...scope.args]
|
|
@@ -409,10 +455,19 @@ async function resolveTask(client, identifier, scopeSession) {
|
|
|
409
455
|
args: [`${identifier}%`, ...scope.args]
|
|
410
456
|
});
|
|
411
457
|
if (result.rows.length === 0) {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
458
|
+
if (currentScope) {
|
|
459
|
+
const unscoped = await client.execute({
|
|
460
|
+
sql: `SELECT * FROM tasks WHERE id LIKE ?`,
|
|
461
|
+
args: [`${identifier}%`]
|
|
462
|
+
});
|
|
463
|
+
const err2 = crossSessionError(unscoped.rows);
|
|
464
|
+
if (err2) throw err2;
|
|
465
|
+
} else {
|
|
466
|
+
result = await client.execute({
|
|
467
|
+
sql: `SELECT * FROM tasks WHERE id LIKE ?`,
|
|
468
|
+
args: [`${identifier}%`]
|
|
469
|
+
});
|
|
470
|
+
}
|
|
416
471
|
}
|
|
417
472
|
if (result.rows.length === 1) return result.rows[0];
|
|
418
473
|
if (result.rows.length > 1) {
|
|
@@ -457,7 +512,10 @@ async function resolveTask(client, identifier, scopeSession) {
|
|
|
457
512
|
`Multiple tasks match "${identifier}": ${matches}. Use a UUID to disambiguate.`
|
|
458
513
|
);
|
|
459
514
|
}
|
|
460
|
-
|
|
515
|
+
const unscopedMatches = await findUnscopedMatches();
|
|
516
|
+
const err = crossSessionError(unscopedMatches);
|
|
517
|
+
if (err) throw err;
|
|
518
|
+
throw new Error(`Task not found in current session: ${identifier}`);
|
|
461
519
|
}
|
|
462
520
|
function renderTaskMarkdown(f) {
|
|
463
521
|
return `# ${f.title}
|
|
@@ -527,7 +585,7 @@ async function createTaskCore(input) {
|
|
|
527
585
|
if (isCoordinatorSession) {
|
|
528
586
|
earlySessionScope = resolved;
|
|
529
587
|
} else {
|
|
530
|
-
const { getSessionProject } = await import("./session-scope-
|
|
588
|
+
const { getSessionProject } = await import("./session-scope-DHTVH3D4.js");
|
|
531
589
|
const sessionProject = getSessionProject(resolved);
|
|
532
590
|
if (sessionProject && sessionProject !== input.projectName) {
|
|
533
591
|
scopeMismatchWarning = `session/project mismatch: session "${resolved}" owns "${sessionProject}" but task targets "${input.projectName}". Routed to default scope.`;
|
|
@@ -994,7 +1052,7 @@ async function updateTaskStatus(input) {
|
|
|
994
1052
|
} catch {
|
|
995
1053
|
}
|
|
996
1054
|
try {
|
|
997
|
-
const { writeNotification: writeNotification2 } = await import("./notifications-
|
|
1055
|
+
const { writeNotification: writeNotification2 } = await import("./notifications-ZKGLZVCU.js");
|
|
998
1056
|
await writeNotification2({
|
|
999
1057
|
agentId: reviewer,
|
|
1000
1058
|
agentRole: isCoordinatorName(reviewer) ? "COO" : "manager",
|
|
@@ -1332,7 +1390,7 @@ ${input.result ?? ""}`;
|
|
|
1332
1390
|
sql: "SELECT assertions FROM tasks WHERE id = ?",
|
|
1333
1391
|
args: [taskId]
|
|
1334
1392
|
});
|
|
1335
|
-
|
|
1393
|
+
const merged = { assertions: [], resolved: [] };
|
|
1336
1394
|
if (existing.rows.length > 0 && existing.rows[0]?.assertions) {
|
|
1337
1395
|
try {
|
|
1338
1396
|
const prev = JSON.parse(String(existing.rows[0].assertions));
|
|
@@ -1409,7 +1467,7 @@ ${input.result ?? ""}`;
|
|
|
1409
1467
|
}
|
|
1410
1468
|
if (shouldWriteCompletionMemory && input.result) {
|
|
1411
1469
|
try {
|
|
1412
|
-
const { writeMemoryViaDaemon } = await import("./memory-queue-client-
|
|
1470
|
+
const { writeMemoryViaDaemon } = await import("./memory-queue-client-TPQDAA4D.js");
|
|
1413
1471
|
await writeMemoryViaDaemon({
|
|
1414
1472
|
raw_text: input.result,
|
|
1415
1473
|
agent_id: String(row.assigned_to),
|
|
@@ -1512,7 +1570,7 @@ ${input.result ?? ""}`;
|
|
|
1512
1570
|
}
|
|
1513
1571
|
if (input.status === "done" || input.status === "needs_review") {
|
|
1514
1572
|
try {
|
|
1515
|
-
const { incrementSkillSuccess } = await import("./skill-refinement-
|
|
1573
|
+
const { incrementSkillSuccess } = await import("./skill-refinement-6PBAFLWP.js");
|
|
1516
1574
|
await incrementSkillSuccess(
|
|
1517
1575
|
String(row.assigned_to),
|
|
1518
1576
|
row.project_name ? String(row.project_name) : null
|
|
@@ -2997,7 +3055,7 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
2997
3055
|
reason: `capture-pane failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2998
3056
|
};
|
|
2999
3057
|
}
|
|
3000
|
-
const { isAtCapacity } = await import("./capacity-monitor-
|
|
3058
|
+
const { isAtCapacity } = await import("./capacity-monitor-CTFWWTCR.js");
|
|
3001
3059
|
if (!isAtCapacity(pane)) {
|
|
3002
3060
|
return {
|
|
3003
3061
|
atCapacity: false,
|
|
@@ -3264,7 +3322,8 @@ function notifyCoordinatorTaskCompletion(coordinatorSession, agentName, taskTitl
|
|
|
3264
3322
|
if (pending instanceof Promise) {
|
|
3265
3323
|
pending.then((count) => {
|
|
3266
3324
|
if (count > 0) {
|
|
3267
|
-
logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}", ${count} reviews pending \u2014
|
|
3325
|
+
logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}", ${count} reviews pending \u2014 sending intercom)`);
|
|
3326
|
+
sendIntercom(coordinatorSession, { force: true, reason: "completion" });
|
|
3268
3327
|
}
|
|
3269
3328
|
}).catch(() => {
|
|
3270
3329
|
});
|
|
@@ -3272,7 +3331,8 @@ function notifyCoordinatorTaskCompletion(coordinatorSession, agentName, taskTitl
|
|
|
3272
3331
|
}
|
|
3273
3332
|
} catch {
|
|
3274
3333
|
}
|
|
3275
|
-
logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}") \u2014 review count unavailable,
|
|
3334
|
+
logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}") \u2014 review count unavailable, sending intercom as fallback`);
|
|
3335
|
+
sendIntercom(coordinatorSession, { force: true, reason: "completion" });
|
|
3276
3336
|
return true;
|
|
3277
3337
|
} catch (e) {
|
|
3278
3338
|
process.stderr.write("[tmux-routing] notifyCoordinatorTaskCompletion for " + coordinatorSession + ": " + (e instanceof Error ? e.message : String(e)) + "\n");
|
|
@@ -204,7 +204,7 @@ async function main(args) {
|
|
|
204
204
|
console.log("[health-gate] Starting rollback...");
|
|
205
205
|
restorePreDeployBackup();
|
|
206
206
|
try {
|
|
207
|
-
const { rollbackStackUpdate, defaultStackPaths } = await import("./stack-update-
|
|
207
|
+
const { rollbackStackUpdate, defaultStackPaths } = await import("./stack-update-5SM62R3O.js");
|
|
208
208
|
const paths = defaultStackPaths();
|
|
209
209
|
await rollbackStackUpdate({
|
|
210
210
|
manifestRef: paths.manifestRef,
|
|
@@ -142,13 +142,14 @@ function createStackUpdatePlan(manifest, envRaw, targetVersion) {
|
|
|
142
142
|
}
|
|
143
143
|
var ASKEXE_GHCR_IMAGE = /^(?:ghcr\.io\/askexe|update\.askexe\.com\/askexe)\/[a-z0-9._/-]+(?:(?::[^:@$/{]+)(?:@sha256:[a-f0-9]{64})?|@sha256:[a-f0-9]{64})$/i;
|
|
144
144
|
var OFFICIAL_COMPOSE_IMAGE = /^(?:postgres|pgvector\/pgvector|clickhouse\/clickhouse-server|redis|nginx|postgrest\/postgrest|supabase\/gotrue|cloudflare\/cloudflared):[^:@$/{]+(?:@sha256:[a-f0-9]{64})?$/i;
|
|
145
|
-
function validatePinnedGhcrImage(image, label) {
|
|
145
|
+
function validatePinnedGhcrImage(image, label, requireDigest = false) {
|
|
146
146
|
const trimmed = image.trim().replace(/^['"]|['"]$/g, "");
|
|
147
147
|
if (!trimmed) return `${label} is empty`;
|
|
148
148
|
if (trimmed.includes("${")) return null;
|
|
149
149
|
if (!trimmed.startsWith("ghcr.io/askexe/") && !trimmed.startsWith("update.askexe.com/askexe/")) return `${label} must use ghcr.io/askexe/* or update.askexe.com/askexe/*, got ${trimmed}`;
|
|
150
150
|
if (/:latest(?:$|[\s#])/.test(trimmed)) return `${label} must not use :latest (${trimmed})`;
|
|
151
151
|
if (!ASKEXE_GHCR_IMAGE.test(trimmed)) return `${label} must be pinned with an explicit tag or sha256 digest from ghcr.io/askexe or update.askexe.com/askexe, got ${trimmed}`;
|
|
152
|
+
if (requireDigest && !/@sha256:[a-f0-9]{64}/.test(trimmed)) return `${label} must include @sha256: digest for supply-chain integrity, got ${trimmed}`;
|
|
152
153
|
return null;
|
|
153
154
|
}
|
|
154
155
|
function validateComposeImageLiteral(image, label) {
|
|
@@ -427,7 +428,7 @@ function bootstrapStackHost(options) {
|
|
|
427
428
|
);
|
|
428
429
|
const brandingDest = path.join(path.dirname(options.envFile), "branding.json");
|
|
429
430
|
copyTemplateIfMissing("deploy/compose/gateway.json", path.join(path.dirname(options.envFile), "gateway.json"), createdFiles);
|
|
430
|
-
if (!existsSync(brandingDest)) writeFileSync(brandingDest, JSON.stringify({ brandName: "
|
|
431
|
+
if (!existsSync(brandingDest)) writeFileSync(brandingDest, JSON.stringify({ brandName: "Exe", productName: "Exe OS" }, null, 2) + "\n", { mode: 384 });
|
|
431
432
|
copyTemplateIfMissing(
|
|
432
433
|
"deploy/compose/cloudflared/config.yml.example",
|
|
433
434
|
path.join(path.dirname(options.composeFile), "cloudflared", "config.yml.example"),
|
|
@@ -474,6 +475,199 @@ function assertHostReadyForApply(report) {
|
|
|
474
475
|
if (blockers.length > 0) throw new Error(`Stack host is not ready:
|
|
475
476
|
- ${blockers.join("\n- ")}`);
|
|
476
477
|
}
|
|
478
|
+
function hardenHost(exec) {
|
|
479
|
+
const run = exec ?? defaultExec;
|
|
480
|
+
const result = {
|
|
481
|
+
skipped: false,
|
|
482
|
+
ufw: { changed: false, actions: [] },
|
|
483
|
+
ssh: { changed: false, actions: [] }
|
|
484
|
+
};
|
|
485
|
+
if (process.platform !== "linux") {
|
|
486
|
+
result.skipped = true;
|
|
487
|
+
result.reason = "Host hardening only runs on Linux (skipped on " + process.platform + ")";
|
|
488
|
+
console.log(`[stack-update] ${result.reason}`);
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
hardenUfw(run, result);
|
|
492
|
+
hardenSsh(run, result);
|
|
493
|
+
return result;
|
|
494
|
+
}
|
|
495
|
+
function hardenUfw(exec, result) {
|
|
496
|
+
const whichUfw = spawnSync("which", ["ufw"], { stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 });
|
|
497
|
+
const ufwInstalled = whichUfw.status === 0;
|
|
498
|
+
if (!ufwInstalled) {
|
|
499
|
+
if (!existsSync("/etc/os-release")) {
|
|
500
|
+
result.ufw.actions.push("ufw_not_installed_unknown_distro");
|
|
501
|
+
console.warn("[stack-update] UFW not installed and OS not detected \u2014 skipping firewall hardening");
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
const osRelease = readFileSync("/etc/os-release", "utf8");
|
|
505
|
+
if (!/ID=(ubuntu|debian)|ID_LIKE=.*debian/.test(osRelease)) {
|
|
506
|
+
result.ufw.actions.push("ufw_not_installed_unsupported_distro");
|
|
507
|
+
console.warn("[stack-update] UFW not installed on non-Debian OS \u2014 skipping firewall hardening");
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
console.log("[stack-update] Installing UFW...");
|
|
511
|
+
try {
|
|
512
|
+
exec("apt-get", ["install", "-y", "ufw"]);
|
|
513
|
+
result.ufw.actions.push("installed_ufw");
|
|
514
|
+
} catch (err) {
|
|
515
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
516
|
+
console.warn(`[stack-update] Failed to install UFW: ${reason}`);
|
|
517
|
+
result.ufw.actions.push("install_failed");
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const statusResult = spawnSync("ufw", ["status", "verbose"], {
|
|
522
|
+
encoding: "utf8",
|
|
523
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
524
|
+
timeout: 1e4
|
|
525
|
+
});
|
|
526
|
+
const statusOutput = statusResult.stdout ?? "";
|
|
527
|
+
const isActive = /Status:\s*active/i.test(statusOutput);
|
|
528
|
+
const has22 = /22\/tcp\s+ALLOW/i.test(statusOutput);
|
|
529
|
+
const has80 = /80\/tcp\s+ALLOW/i.test(statusOutput);
|
|
530
|
+
const has443 = /443\/tcp\s+ALLOW/i.test(statusOutput);
|
|
531
|
+
const defaultDeny = /Default:\s*deny\s*\(incoming\)/i.test(statusOutput);
|
|
532
|
+
if (isActive && has22 && has80 && has443 && defaultDeny) {
|
|
533
|
+
result.ufw.actions.push("already_hardened");
|
|
534
|
+
console.log("[stack-update] UFW already active with correct rules \u2014 skipping");
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
console.log("[stack-update] Configuring UFW firewall...");
|
|
538
|
+
try {
|
|
539
|
+
if (!defaultDeny) {
|
|
540
|
+
exec("ufw", ["default", "deny", "incoming"]);
|
|
541
|
+
result.ufw.actions.push("set_default_deny_incoming");
|
|
542
|
+
}
|
|
543
|
+
exec("ufw", ["default", "allow", "outgoing"]);
|
|
544
|
+
result.ufw.actions.push("set_default_allow_outgoing");
|
|
545
|
+
if (!has22) {
|
|
546
|
+
exec("ufw", ["allow", "22/tcp"]);
|
|
547
|
+
result.ufw.actions.push("allow_22_tcp");
|
|
548
|
+
}
|
|
549
|
+
if (!has80) {
|
|
550
|
+
exec("ufw", ["allow", "80/tcp"]);
|
|
551
|
+
result.ufw.actions.push("allow_80_tcp");
|
|
552
|
+
}
|
|
553
|
+
if (!has443) {
|
|
554
|
+
exec("ufw", ["allow", "443/tcp"]);
|
|
555
|
+
result.ufw.actions.push("allow_443_tcp");
|
|
556
|
+
}
|
|
557
|
+
if (!isActive) {
|
|
558
|
+
exec("ufw", ["--force", "enable"]);
|
|
559
|
+
result.ufw.actions.push("enabled_ufw");
|
|
560
|
+
}
|
|
561
|
+
result.ufw.changed = true;
|
|
562
|
+
console.log("[stack-update] \u2713 UFW firewall configured: deny incoming, allow 22/80/443");
|
|
563
|
+
} catch (err) {
|
|
564
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
565
|
+
console.warn(`[stack-update] UFW configuration failed (non-fatal): ${reason}`);
|
|
566
|
+
result.ufw.actions.push("configuration_failed");
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
function hardenSsh(exec, result) {
|
|
570
|
+
const sshdConfig = "/etc/ssh/sshd_config";
|
|
571
|
+
if (!existsSync(sshdConfig)) {
|
|
572
|
+
result.ssh.actions.push("sshd_config_not_found");
|
|
573
|
+
console.warn("[stack-update] /etc/ssh/sshd_config not found \u2014 skipping SSH hardening");
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
let configRaw;
|
|
577
|
+
try {
|
|
578
|
+
configRaw = readFileSync(sshdConfig, "utf8");
|
|
579
|
+
} catch (err) {
|
|
580
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
581
|
+
result.ssh.actions.push("sshd_config_unreadable");
|
|
582
|
+
console.warn(`[stack-update] Cannot read sshd_config: ${reason}`);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
let modified = configRaw;
|
|
586
|
+
let needsReload = false;
|
|
587
|
+
const passwordAuthMatch = modified.match(/^\s*PasswordAuthentication\s+(yes|no)\s*$/m);
|
|
588
|
+
const passwordAuthCurrently = passwordAuthMatch?.[1]?.toLowerCase();
|
|
589
|
+
if (passwordAuthCurrently === "yes") {
|
|
590
|
+
modified = modified.replace(
|
|
591
|
+
/^\s*PasswordAuthentication\s+yes\s*$/m,
|
|
592
|
+
"PasswordAuthentication no"
|
|
593
|
+
);
|
|
594
|
+
result.ssh.actions.push("set_password_auth_no");
|
|
595
|
+
needsReload = true;
|
|
596
|
+
} else if (!passwordAuthMatch) {
|
|
597
|
+
if (/^#\s*PasswordAuthentication\s/m.test(modified)) {
|
|
598
|
+
modified = modified.replace(
|
|
599
|
+
/^#\s*PasswordAuthentication\s.*$/m,
|
|
600
|
+
"PasswordAuthentication no"
|
|
601
|
+
);
|
|
602
|
+
} else {
|
|
603
|
+
modified += "\nPasswordAuthentication no\n";
|
|
604
|
+
}
|
|
605
|
+
result.ssh.actions.push("set_password_auth_no");
|
|
606
|
+
needsReload = true;
|
|
607
|
+
} else {
|
|
608
|
+
result.ssh.actions.push("password_auth_already_no");
|
|
609
|
+
}
|
|
610
|
+
const rootLoginMatch = modified.match(/^\s*PermitRootLogin\s+(\S+)\s*$/m);
|
|
611
|
+
const rootLoginCurrently = rootLoginMatch?.[1]?.toLowerCase();
|
|
612
|
+
if (rootLoginCurrently === "yes") {
|
|
613
|
+
modified = modified.replace(
|
|
614
|
+
/^\s*PermitRootLogin\s+yes\s*$/m,
|
|
615
|
+
"PermitRootLogin prohibit-password"
|
|
616
|
+
);
|
|
617
|
+
result.ssh.actions.push("set_root_login_prohibit_password");
|
|
618
|
+
needsReload = true;
|
|
619
|
+
} else if (!rootLoginMatch) {
|
|
620
|
+
if (/^#\s*PermitRootLogin\s/m.test(modified)) {
|
|
621
|
+
modified = modified.replace(
|
|
622
|
+
/^#\s*PermitRootLogin\s.*$/m,
|
|
623
|
+
"PermitRootLogin prohibit-password"
|
|
624
|
+
);
|
|
625
|
+
} else {
|
|
626
|
+
modified += "\nPermitRootLogin prohibit-password\n";
|
|
627
|
+
}
|
|
628
|
+
result.ssh.actions.push("set_root_login_prohibit_password");
|
|
629
|
+
needsReload = true;
|
|
630
|
+
} else if (rootLoginCurrently === "prohibit-password" || rootLoginCurrently === "without-password" || rootLoginCurrently === "no") {
|
|
631
|
+
result.ssh.actions.push("root_login_already_restricted");
|
|
632
|
+
} else {
|
|
633
|
+
modified = modified.replace(
|
|
634
|
+
/^\s*PermitRootLogin\s+\S+\s*$/m,
|
|
635
|
+
"PermitRootLogin prohibit-password"
|
|
636
|
+
);
|
|
637
|
+
result.ssh.actions.push("set_root_login_prohibit_password");
|
|
638
|
+
needsReload = true;
|
|
639
|
+
}
|
|
640
|
+
if (!needsReload) {
|
|
641
|
+
console.log("[stack-update] SSH already hardened \u2014 skipping");
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
try {
|
|
645
|
+
writeFileSync(sshdConfig, modified, { mode: 384 });
|
|
646
|
+
result.ssh.changed = true;
|
|
647
|
+
} catch (err) {
|
|
648
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
649
|
+
console.warn(`[stack-update] Failed to write sshd_config: ${reason}`);
|
|
650
|
+
result.ssh.actions.push("write_failed");
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
try {
|
|
654
|
+
exec("systemctl", ["reload", "ssh"]);
|
|
655
|
+
result.ssh.actions.push("reloaded_ssh");
|
|
656
|
+
} catch {
|
|
657
|
+
try {
|
|
658
|
+
exec("systemctl", ["reload", "sshd"]);
|
|
659
|
+
result.ssh.actions.push("reloaded_sshd");
|
|
660
|
+
} catch (err) {
|
|
661
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
662
|
+
console.warn(`[stack-update] SSH reload failed (changes will apply on next restart): ${reason}`);
|
|
663
|
+
result.ssh.actions.push("reload_failed");
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
const sshSummary = result.ssh.actions.filter((a) => a.startsWith("set_")).map((a) => a.replace("set_", "").replaceAll("_", " ")).join(", ");
|
|
667
|
+
if (sshSummary) {
|
|
668
|
+
console.log(`[stack-update] \u2713 SSH hardened: ${sshSummary}`);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
477
671
|
function areStackContainersRunning(composeFile, envFile) {
|
|
478
672
|
try {
|
|
479
673
|
const result = spawnSync("docker", ["compose", "--file", composeFile, "--env-file", envFile, "ps", "-q"], {
|
|
@@ -493,8 +687,15 @@ var CRITICAL_BIND_MOUNTS = [
|
|
|
493
687
|
var CRITICAL_VOLUMES = [
|
|
494
688
|
"postgres_data",
|
|
495
689
|
"gateway_data",
|
|
690
|
+
"gateway_whatsapp_auth",
|
|
496
691
|
"wiki_data",
|
|
497
|
-
"exe_os_data"
|
|
692
|
+
"exe_os_data",
|
|
693
|
+
"crm_data",
|
|
694
|
+
"monitor_hub_data",
|
|
695
|
+
"monitor_agent_data",
|
|
696
|
+
"redis_data",
|
|
697
|
+
"clickhouse_data",
|
|
698
|
+
"erp_sites"
|
|
498
699
|
];
|
|
499
700
|
function assertBindMountsExist(stackDir) {
|
|
500
701
|
const missing = [];
|
|
@@ -862,10 +1063,41 @@ async function runStackUpdate(options) {
|
|
|
862
1063
|
throw new Error("verifyStack hook not provided");
|
|
863
1064
|
}
|
|
864
1065
|
const verifyReport = await options.verifyStack({ composeFile: options.composeFile, envFile: options.envFile });
|
|
1066
|
+
const securityFailures = [];
|
|
865
1067
|
for (const r of verifyReport.results) {
|
|
866
|
-
if (r.status === "fail")
|
|
1068
|
+
if (r.status === "fail") {
|
|
1069
|
+
console.warn(`[verify-stack] FAIL: ${r.check}: ${r.message}`);
|
|
1070
|
+
if (/security|auth|signup|password|ssl|tls|bind|exposed/i.test(r.check)) {
|
|
1071
|
+
securityFailures.push(`${r.check}: ${r.message}`);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
867
1074
|
}
|
|
868
|
-
|
|
1075
|
+
if (securityFailures.length > 0) {
|
|
1076
|
+
throw new Error(`Security verification failed:
|
|
1077
|
+
- ${securityFailures.join("\n - ")}
|
|
1078
|
+
Fix these before the stack is safe to operate.`);
|
|
1079
|
+
}
|
|
1080
|
+
} catch (verifyErr) {
|
|
1081
|
+
if (verifyErr instanceof Error && verifyErr.message.startsWith("Security verification failed")) {
|
|
1082
|
+
throw verifyErr;
|
|
1083
|
+
}
|
|
1084
|
+
console.warn("[stack-update] Post-deploy verification skipped (module not available)");
|
|
1085
|
+
}
|
|
1086
|
+
if (!options.skipHardening) {
|
|
1087
|
+
try {
|
|
1088
|
+
const hardenResult = hardenHost(exec);
|
|
1089
|
+
if (!hardenResult.skipped) {
|
|
1090
|
+
const actions = [...hardenResult.ufw.actions, ...hardenResult.ssh.actions].filter(Boolean);
|
|
1091
|
+
if (actions.length > 0) {
|
|
1092
|
+
console.log(`[stack-update] Host hardening: ${actions.join(", ")}`);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
} catch (hardenErr) {
|
|
1096
|
+
const reason = hardenErr instanceof Error ? hardenErr.message : String(hardenErr);
|
|
1097
|
+
console.warn(`[stack-update] Host hardening failed (non-fatal): ${reason}`);
|
|
1098
|
+
}
|
|
1099
|
+
} else {
|
|
1100
|
+
console.log("[stack-update] Host hardening skipped (--skip-hardening)");
|
|
869
1101
|
}
|
|
870
1102
|
writeFileSync(lockFile, JSON.stringify({ stackVersion: plan.targetVersion, previousVersion, updatedAt: now().toISOString(), backupEnvFile, services: plan.release.services }, null, 2) + "\n");
|
|
871
1103
|
await postDeployAudit(options, "success", plan.targetVersion, previousVersion, void 0, { changes: plan.changes.length });
|
|
@@ -1078,6 +1310,7 @@ export {
|
|
|
1078
1310
|
pairMonitorAgent,
|
|
1079
1311
|
bootstrapStackHost,
|
|
1080
1312
|
assertHostReadyForApply,
|
|
1313
|
+
hardenHost,
|
|
1081
1314
|
runStackUpdate,
|
|
1082
1315
|
readCurrentStackVersion,
|
|
1083
1316
|
listAvailableVersions,
|