botmux 3.9.2 → 3.10.0
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/README.en.md +1 -1
- package/README.md +1 -1
- package/dist/.runtime-build-id +1 -1
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +6 -0
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/opencode.d.ts.map +1 -1
- package/dist/adapters/cli/opencode.js +7 -1
- package/dist/adapters/cli/opencode.js.map +1 -1
- package/dist/adapters/cli/reasonix.d.ts +35 -0
- package/dist/adapters/cli/reasonix.d.ts.map +1 -0
- package/dist/adapters/cli/reasonix.js +236 -0
- package/dist/adapters/cli/reasonix.js.map +1 -0
- package/dist/adapters/cli/registry.d.ts +2 -1
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +4 -1
- package/dist/adapters/cli/registry.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +5 -1
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +168 -62
- package/dist/cli.js.map +1 -1
- package/dist/core/command-handler.d.ts +18 -4
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +234 -26
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts +1 -0
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +27 -3
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dispatch.d.ts +54 -24
- package/dist/core/dispatch.d.ts.map +1 -1
- package/dist/core/dispatch.js +81 -27
- package/dist/core/dispatch.js.map +1 -1
- package/dist/core/input-turn-dedupe.d.ts +20 -0
- package/dist/core/input-turn-dedupe.d.ts.map +1 -0
- package/dist/core/input-turn-dedupe.js +57 -0
- package/dist/core/input-turn-dedupe.js.map +1 -0
- package/dist/core/local-terminal-opener.d.ts.map +1 -1
- package/dist/core/local-terminal-opener.js +10 -1
- package/dist/core/local-terminal-opener.js.map +1 -1
- package/dist/core/passthrough-commands.d.ts.map +1 -1
- package/dist/core/passthrough-commands.js +1 -1
- package/dist/core/passthrough-commands.js.map +1 -1
- package/dist/core/plugins/pm2.d.ts.map +1 -1
- package/dist/core/plugins/pm2.js +7 -1
- package/dist/core/plugins/pm2.js.map +1 -1
- package/dist/core/resource-monitor/attribution.d.ts.map +1 -1
- package/dist/core/resource-monitor/attribution.js +17 -1
- package/dist/core/resource-monitor/attribution.js.map +1 -1
- package/dist/core/resource-monitor/darwin.d.ts +145 -0
- package/dist/core/resource-monitor/darwin.d.ts.map +1 -0
- package/dist/core/resource-monitor/darwin.js +360 -0
- package/dist/core/resource-monitor/darwin.js.map +1 -0
- package/dist/core/resource-monitor/procfs.d.ts.map +1 -1
- package/dist/core/resource-monitor/procfs.js +6 -0
- package/dist/core/resource-monitor/procfs.js.map +1 -1
- package/dist/core/resource-monitor/types.d.ts +1 -1
- package/dist/core/resource-monitor/types.d.ts.map +1 -1
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +5 -2
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +3 -0
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/session-manager.d.ts +3 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +46 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-marker.d.ts +1 -8
- package/dist/core/session-marker.d.ts.map +1 -1
- package/dist/core/session-marker.js +2 -50
- package/dist/core/session-marker.js.map +1 -1
- package/dist/core/types.d.ts +3 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +17 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +292 -9
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +27 -12
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/daemon-internal-api.d.ts.map +1 -1
- package/dist/dashboard/daemon-internal-api.js +11 -2
- package/dist/dashboard/daemon-internal-api.js.map +1 -1
- package/dist/dashboard/groups-action-helpers.d.ts +2 -0
- package/dist/dashboard/groups-action-helpers.d.ts.map +1 -1
- package/dist/dashboard/groups-action-helpers.js +9 -0
- package/dist/dashboard/groups-action-helpers.js.map +1 -1
- package/dist/dashboard/groups-matrix-snapshot.d.ts +56 -0
- package/dist/dashboard/groups-matrix-snapshot.d.ts.map +1 -0
- package/dist/dashboard/groups-matrix-snapshot.js +127 -0
- package/dist/dashboard/groups-matrix-snapshot.js.map +1 -0
- package/dist/dashboard/resource-monitor-service.d.ts.map +1 -1
- package/dist/dashboard/resource-monitor-service.js +18 -2
- package/dist/dashboard/resource-monitor-service.js.map +1 -1
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +45 -4
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/groups-api.js +1 -1
- package/dist/dashboard/web/groups-api.js.map +1 -1
- package/dist/dashboard/web/i18n.js +10 -10
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/roles-page.d.ts.map +1 -1
- package/dist/dashboard/web/roles-page.js +26 -11
- package/dist/dashboard/web/roles-page.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard-web/chunks/{bot-defaults-page-BHTQEWCH.js → bot-defaults-page-LTVOUDIS.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-KLZCQAHF.js → chunk-3UE7S77S.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-W77TPKZH.js → chunk-DCS35UMD.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-E3HZZXK5.js → chunk-MFQPCVHY.js} +4 -4
- package/dist/dashboard-web/chunks/{chunk-EZH56JCI.js → chunk-ZU3UUKAR.js} +1 -1
- package/dist/dashboard-web/chunks/{connectors-page-BP255CAX.js → connectors-page-5KWDIMKC.js} +1 -1
- package/dist/dashboard-web/chunks/{groups-page-CDHVXBUT.js → groups-page-FHOKYXMW.js} +1 -1
- package/dist/dashboard-web/chunks/{insights-page-57BFE6GT.js → insights-page-T2ZX2RWL.js} +1 -1
- package/dist/dashboard-web/chunks/{monitor-room-UTOYGQVF.js → monitor-room-YNVBAGR6.js} +1 -1
- package/dist/dashboard-web/chunks/{monitoring-page-WTHYAIUM.js → monitoring-page-LHM55YWN.js} +1 -1
- package/dist/dashboard-web/chunks/{office-page-JSMIB353.js → office-page-ATXVP7PW.js} +1 -1
- package/dist/dashboard-web/chunks/{overview-page-3VDBOH7L.js → overview-page-QYI3KBDD.js} +1 -1
- package/dist/dashboard-web/chunks/roles-page-56VWM6CD.js +1 -0
- package/dist/dashboard-web/chunks/{schedules-page-HHN736H6.js → schedules-page-S5K6U4EO.js} +1 -1
- package/dist/dashboard-web/chunks/{sessions-page-EIWOZD7A.js → sessions-page-WBP4N7D2.js} +1 -1
- package/dist/dashboard-web/chunks/{settings-page-2IUT5LS4.js → settings-page-QUZDQARR.js} +1 -1
- package/dist/dashboard-web/chunks/{skills-page-JKFKMUEM.js → skills-page-IFY7AEND.js} +1 -1
- package/dist/dashboard-web/chunks/{team-federation-page-Q2PXC3UY.js → team-federation-page-C7FJQPFZ.js} +1 -1
- package/dist/dashboard-web/chunks/{v3-page-EBQCD4AO.js → v3-page-2LMF3WWR.js} +1 -1
- package/dist/dashboard-web/chunks/{whiteboards-page-QZRMVNZN.js → whiteboards-page-3XC6QRMY.js} +1 -1
- package/dist/dashboard-web/style.css +2 -4
- package/dist/dashboard.js +65 -9
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +33 -7
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +31 -7
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +7 -0
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +56 -0
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +42 -19
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +10 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +79 -0
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +14 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +171 -15
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/lark-hosts.d.ts +5 -0
- package/dist/im/lark/lark-hosts.d.ts.map +1 -1
- package/dist/im/lark/lark-hosts.js +10 -0
- package/dist/im/lark/lark-hosts.js.map +1 -1
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +24 -7
- package/dist/im/lark/message-parser.js.map +1 -1
- package/dist/pm2-graceful-exit.d.ts +28 -0
- package/dist/pm2-graceful-exit.d.ts.map +1 -0
- package/dist/pm2-graceful-exit.js +39 -0
- package/dist/pm2-graceful-exit.js.map +1 -0
- package/dist/services/bridge-fallback-gate.d.ts +9 -2
- package/dist/services/bridge-fallback-gate.d.ts.map +1 -1
- package/dist/services/bridge-fallback-gate.js +31 -19
- package/dist/services/bridge-fallback-gate.js.map +1 -1
- package/dist/services/message-listener-store.d.ts +18 -0
- package/dist/services/message-listener-store.d.ts.map +1 -1
- package/dist/services/message-listener-store.js +35 -10
- package/dist/services/message-listener-store.js.map +1 -1
- package/dist/services/message-listener.d.ts +17 -0
- package/dist/services/message-listener.d.ts.map +1 -1
- package/dist/services/message-listener.js +26 -0
- package/dist/services/message-listener.js.map +1 -1
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +2 -0
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/lark-scopes.json +1 -0
- package/dist/setup/verify-permissions.d.ts.map +1 -1
- package/dist/setup/verify-permissions.js +8 -0
- package/dist/setup/verify-permissions.js.map +1 -1
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/child-env.d.ts +1 -1
- package/dist/utils/child-env.d.ts.map +1 -1
- package/dist/utils/child-env.js +13 -0
- package/dist/utils/child-env.js.map +1 -1
- package/dist/utils/file-lock.d.ts.map +1 -1
- package/dist/utils/file-lock.js +1 -1
- package/dist/utils/file-lock.js.map +1 -1
- package/dist/utils/global-install.d.ts.map +1 -1
- package/dist/utils/global-install.js +56 -10
- package/dist/utils/global-install.js.map +1 -1
- package/dist/utils/idle-detector.d.ts +4 -0
- package/dist/utils/idle-detector.d.ts.map +1 -1
- package/dist/utils/idle-detector.js +25 -0
- package/dist/utils/idle-detector.js.map +1 -1
- package/dist/utils/process-identity.d.ts +7 -0
- package/dist/utils/process-identity.d.ts.map +1 -0
- package/dist/utils/process-identity.js +62 -0
- package/dist/utils/process-identity.js.map +1 -0
- package/dist/worker.js +123 -9
- package/dist/worker.js.map +1 -1
- package/dist/workflows/events/payloads.d.ts +10 -10
- package/dist/workflows/events/schema.d.ts +28 -28
- package/dist/workflows/hostExecutors/registry.d.ts +2 -7
- package/dist/workflows/hostExecutors/registry.d.ts.map +1 -1
- package/dist/workflows/hostExecutors/registry.js.map +1 -1
- package/dist/workflows/shared/provider-reconciler.d.ts +1 -30
- package/dist/workflows/shared/provider-reconciler.d.ts.map +1 -1
- package/dist/workflows/shared/provider-reconciler.js.map +1 -1
- package/dist/workflows/v3/artifact-contract.d.ts +41 -0
- package/dist/workflows/v3/artifact-contract.d.ts.map +1 -0
- package/dist/workflows/v3/artifact-contract.js +20 -0
- package/dist/workflows/v3/artifact-contract.js.map +1 -0
- package/dist/workflows/v3/botmux-attempt-lease.d.ts +7 -0
- package/dist/workflows/v3/botmux-attempt-lease.d.ts.map +1 -0
- package/dist/workflows/v3/botmux-attempt-lease.js +189 -0
- package/dist/workflows/v3/botmux-attempt-lease.js.map +1 -0
- package/dist/workflows/v3/botmux-host-policy.d.ts +7 -0
- package/dist/workflows/v3/botmux-host-policy.d.ts.map +1 -0
- package/dist/workflows/v3/botmux-host-policy.js +34 -0
- package/dist/workflows/v3/botmux-host-policy.js.map +1 -0
- package/dist/workflows/v3/cli-run.d.ts +1 -1
- package/dist/workflows/v3/cli-run.d.ts.map +1 -1
- package/dist/workflows/v3/cli-run.js +1 -1
- package/dist/workflows/v3/cli-run.js.map +1 -1
- package/dist/workflows/v3/contract.d.ts +8 -89
- package/dist/workflows/v3/contract.d.ts.map +1 -1
- package/dist/workflows/v3/contract.js +2 -8
- package/dist/workflows/v3/contract.js.map +1 -1
- package/dist/workflows/v3/core-control.d.ts +16 -0
- package/dist/workflows/v3/core-control.d.ts.map +1 -0
- package/dist/workflows/v3/core-control.js +60 -0
- package/dist/workflows/v3/core-control.js.map +1 -0
- package/dist/workflows/v3/daemon-run.d.ts.map +1 -1
- package/dist/workflows/v3/daemon-run.js +2 -1
- package/dist/workflows/v3/daemon-run.js.map +1 -1
- package/dist/workflows/v3/dag-loader.d.ts +5 -0
- package/dist/workflows/v3/dag-loader.d.ts.map +1 -0
- package/dist/workflows/v3/dag-loader.js +22 -0
- package/dist/workflows/v3/dag-loader.js.map +1 -0
- package/dist/workflows/v3/dag.d.ts +2 -6
- package/dist/workflows/v3/dag.d.ts.map +1 -1
- package/dist/workflows/v3/dag.js +2 -24
- package/dist/workflows/v3/dag.js.map +1 -1
- package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -1
- package/dist/workflows/v3/ephemeral-pool.js +22 -12
- package/dist/workflows/v3/ephemeral-pool.js.map +1 -1
- package/dist/workflows/v3/event-contract.d.ts +273 -0
- package/dist/workflows/v3/event-contract.d.ts.map +1 -0
- package/dist/workflows/v3/event-contract.js +8 -0
- package/dist/workflows/v3/event-contract.js.map +1 -0
- package/dist/workflows/v3/gate-policy.d.ts +12 -0
- package/dist/workflows/v3/gate-policy.d.ts.map +1 -0
- package/dist/workflows/v3/gate-policy.js +20 -0
- package/dist/workflows/v3/gate-policy.js.map +1 -0
- package/dist/workflows/v3/gate-wait-store.d.ts +99 -0
- package/dist/workflows/v3/gate-wait-store.d.ts.map +1 -0
- package/dist/workflows/v3/gate-wait-store.js +263 -0
- package/dist/workflows/v3/gate-wait-store.js.map +1 -0
- package/dist/workflows/v3/host.js +1 -1
- package/dist/workflows/v3/host.js.map +1 -1
- package/dist/workflows/v3/human-gate.d.ts +4 -99
- package/dist/workflows/v3/human-gate.d.ts.map +1 -1
- package/dist/workflows/v3/human-gate.js +4 -275
- package/dist/workflows/v3/human-gate.js.map +1 -1
- package/dist/workflows/v3/in-process-attempt-lease.d.ts +10 -0
- package/dist/workflows/v3/in-process-attempt-lease.d.ts.map +1 -0
- package/dist/workflows/v3/in-process-attempt-lease.js +47 -0
- package/dist/workflows/v3/in-process-attempt-lease.js.map +1 -0
- package/dist/workflows/v3/journal.d.ts +2 -275
- package/dist/workflows/v3/journal.d.ts.map +1 -1
- package/dist/workflows/v3/journal.js.map +1 -1
- package/dist/workflows/v3/library-service.js +1 -1
- package/dist/workflows/v3/library-service.js.map +1 -1
- package/dist/workflows/v3/orchestrator.d.ts +1 -2
- package/dist/workflows/v3/orchestrator.d.ts.map +1 -1
- package/dist/workflows/v3/orchestrator.js.map +1 -1
- package/dist/workflows/v3/portable-artifact-snapshot.d.ts +15 -0
- package/dist/workflows/v3/portable-artifact-snapshot.d.ts.map +1 -0
- package/dist/workflows/v3/portable-artifact-snapshot.js +76 -0
- package/dist/workflows/v3/portable-artifact-snapshot.js.map +1 -0
- package/dist/workflows/v3/portable-final-outputs.d.ts +37 -0
- package/dist/workflows/v3/portable-final-outputs.d.ts.map +1 -0
- package/dist/workflows/v3/portable-final-outputs.js +137 -0
- package/dist/workflows/v3/portable-final-outputs.js.map +1 -0
- package/dist/workflows/v3/portable-run-snapshot.d.ts +14 -0
- package/dist/workflows/v3/portable-run-snapshot.d.ts.map +1 -0
- package/dist/workflows/v3/portable-run-snapshot.js +176 -0
- package/dist/workflows/v3/portable-run-snapshot.js.map +1 -0
- package/dist/workflows/v3/portable-runtime.d.ts +83 -0
- package/dist/workflows/v3/portable-runtime.d.ts.map +1 -0
- package/dist/workflows/v3/portable-runtime.js +135 -0
- package/dist/workflows/v3/portable-runtime.js.map +1 -0
- package/dist/workflows/v3/runtime-host-contract.d.ts +182 -0
- package/dist/workflows/v3/runtime-host-contract.d.ts.map +1 -0
- package/dist/workflows/v3/runtime-host-contract.js +9 -0
- package/dist/workflows/v3/runtime-host-contract.js.map +1 -0
- package/dist/workflows/v3/runtime.d.ts +12 -226
- package/dist/workflows/v3/runtime.d.ts.map +1 -1
- package/dist/workflows/v3/runtime.js +14 -3173
- package/dist/workflows/v3/runtime.js.map +1 -1
- package/dist/workflows/v3/shared-node-runtime.d.ts +203 -0
- package/dist/workflows/v3/shared-node-runtime.d.ts.map +1 -0
- package/dist/workflows/v3/shared-node-runtime.js +2978 -0
- package/dist/workflows/v3/shared-node-runtime.js.map +1 -0
- package/dist/workflows/v3/shared-runtime.d.ts +17 -0
- package/dist/workflows/v3/shared-runtime.d.ts.map +1 -0
- package/dist/workflows/v3/shared-runtime.js +12 -0
- package/dist/workflows/v3/shared-runtime.js.map +1 -0
- package/package.json +4 -1
- package/dist/dashboard-web/chunks/roles-page-LHVAU2BI.js +0 -1
|
@@ -1,279 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Compatibility facade for the host-neutral gate wait store.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* so a daemon restart doesn't lose a pending approval. The journal already
|
|
7
|
-
* records `gateDispatched` / `gateResolved` (audit truth); this module owns the
|
|
8
|
-
* materialized, mutable wait files under `runDir/waits/<waitId>.json` — the
|
|
9
|
-
* active state the Lark card layer keys off and the restart-recovery scan reads.
|
|
10
|
-
*
|
|
11
|
-
* Split of concerns:
|
|
12
|
-
* - THIS file: the file-wait store + a gate resolver that persists
|
|
13
|
-
* pending → resolved around an injected decision source. Pure file IO,
|
|
14
|
-
* bot-agnostic, testable without the daemon.
|
|
15
|
-
* - daemon (later): supplies `awaitDecision` — posts the Lark approval card
|
|
16
|
-
* (reusing v0.2's card-builder / card-handler UX) and resolves when the
|
|
17
|
-
* button is clicked; on restart it re-arms pending waits via
|
|
18
|
-
* `listPendingWaits`.
|
|
19
|
-
*
|
|
20
|
-
* The wait shape mirrors v0.2's `waitKind: 'human-gate'` lineage but is
|
|
21
|
-
* deliberately scoped to v3's gate needs: no deadline, but options /
|
|
22
|
-
* approveOptions / approvers are persisted for crash-safe card recovery.
|
|
23
|
-
*/
|
|
24
|
-
import { randomBytes } from 'node:crypto';
|
|
25
|
-
import { chmodSync, closeSync, constants, writeFileSync, readFileSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, renameSync, readdirSync, unlinkSync, } from 'node:fs';
|
|
26
|
-
import { dirname, join } from 'node:path';
|
|
27
|
-
import { withFileLockSync } from '../../utils/file-lock.js';
|
|
28
|
-
import { fsyncDirectorySyncPortable, fsyncRegularFileSync } from '../../utils/fs-durability.js';
|
|
29
|
-
import { DEFAULT_HUMAN_GATE_OPTIONS } from './dag.js';
|
|
30
|
-
// ─── File-wait store ────────────────────────────────────────────────────────
|
|
31
|
-
export function waitsDir(runDir) {
|
|
32
|
-
return join(runDir, 'waits');
|
|
33
|
-
}
|
|
34
|
-
export function waitPath(runDir, waitId) {
|
|
35
|
-
return join(waitsDir(runDir), `${waitId}.json`);
|
|
36
|
-
}
|
|
37
|
-
/** Host approvals are per frozen attempt, while ordinary gates remain per
|
|
38
|
-
* runtime instance. Including the attempt number prevents a safe pre-intent
|
|
39
|
-
* retry from reusing an already-resolved approval file. */
|
|
40
|
-
export function v3GateWaitId(nodeId, instanceId, hostApproval) {
|
|
41
|
-
const base = instanceId ?? nodeId;
|
|
42
|
-
if (!hostApproval)
|
|
43
|
-
return `${base}-gate`;
|
|
44
|
-
const attempt = hostApproval.attemptId.slice(hostApproval.attemptId.lastIndexOf('/') + 1);
|
|
45
|
-
if (!/^\d{3}$/.test(attempt)) {
|
|
46
|
-
throw new Error(`v3 human-gate: invalid host attempt id ${JSON.stringify(hostApproval.attemptId)}`);
|
|
47
|
-
}
|
|
48
|
-
return `${base}-host-${attempt}-gate`;
|
|
49
|
-
}
|
|
50
|
-
/** Atomic JSON write (tmp + rename) so a crash never leaves a torn wait file. */
|
|
51
|
-
function atomicWriteJson(path, value) {
|
|
52
|
-
const dir = dirname(path);
|
|
53
|
-
const runDir = dirname(dir);
|
|
54
|
-
assertRealDirectory(runDir, 'run directory');
|
|
55
|
-
if (!existsSync(dir)) {
|
|
56
|
-
try {
|
|
57
|
-
mkdirSync(dir, { mode: 0o700 });
|
|
58
|
-
}
|
|
59
|
-
catch { /* race: assert below */ }
|
|
60
|
-
}
|
|
61
|
-
assertRealDirectory(dir, 'waits directory');
|
|
62
|
-
chmodSync(dir, 0o700);
|
|
63
|
-
if (existsSync(path))
|
|
64
|
-
assertPrivateRegularWaitFile(path, false);
|
|
65
|
-
const tmp = `${path}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
|
|
66
|
-
let fd;
|
|
67
|
-
try {
|
|
68
|
-
fd = openSync(tmp, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 0o600);
|
|
69
|
-
writeFileSync(fd, JSON.stringify(value, null, 2), 'utf-8');
|
|
70
|
-
fsyncSync(fd);
|
|
71
|
-
closeSync(fd);
|
|
72
|
-
fd = undefined;
|
|
73
|
-
// Rename replaces a raced final symlink rather than following it, but an
|
|
74
|
-
// already-present one is an integrity signal and was rejected above.
|
|
75
|
-
renameSync(tmp, path);
|
|
76
|
-
}
|
|
77
|
-
catch (err) {
|
|
78
|
-
if (fd !== undefined) {
|
|
79
|
-
try {
|
|
80
|
-
closeSync(fd);
|
|
81
|
-
}
|
|
82
|
-
catch { /* tolerate */ }
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
unlinkSync(tmp);
|
|
86
|
-
}
|
|
87
|
-
catch { /* tolerate */ }
|
|
88
|
-
throw err;
|
|
89
|
-
}
|
|
90
|
-
chmodSync(path, 0o600);
|
|
91
|
-
fsyncRegularFileSync(path);
|
|
92
|
-
fsyncDirectorySyncPortable(dir);
|
|
93
|
-
}
|
|
94
|
-
function assertRealDirectory(path, label) {
|
|
95
|
-
const stat = lstatSync(path);
|
|
96
|
-
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
97
|
-
throw new Error(`v3 human-gate: ${label} must be a real directory`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function assertPrivateRegularWaitFile(path, requirePrivate = true) {
|
|
101
|
-
const stat = lstatSync(path);
|
|
102
|
-
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
103
|
-
throw new Error('v3 human-gate: wait file must be a regular file');
|
|
104
|
-
}
|
|
105
|
-
if (requirePrivate && (stat.mode & 0o077) !== 0) {
|
|
106
|
-
throw new Error('v3 human-gate: host wait file must not be group/world accessible');
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/** Write the initial `pending` wait file for a gate. Overwrites any stale
|
|
110
|
-
* file at the same waitId (a re-dispatched gate). */
|
|
111
|
-
export function writePendingWait(runDir, input) {
|
|
112
|
-
const options = input.options ?? [...DEFAULT_HUMAN_GATE_OPTIONS];
|
|
113
|
-
const approveOptions = input.approveOptions ?? (options.includes('approve') ? ['approve'] : [options[0]]);
|
|
114
|
-
const wait = {
|
|
115
|
-
waitId: input.waitId,
|
|
116
|
-
nodeId: input.nodeId,
|
|
117
|
-
...(input.instanceId ? { instanceId: input.instanceId } : {}),
|
|
118
|
-
prompt: input.prompt,
|
|
119
|
-
options,
|
|
120
|
-
approveOptions,
|
|
121
|
-
approvers: input.approvers ?? [],
|
|
122
|
-
...(input.hostApproval ? { hostApproval: input.hostApproval } : {}),
|
|
123
|
-
status: 'pending',
|
|
124
|
-
createdAt: Date.now(),
|
|
125
|
-
};
|
|
126
|
-
atomicWriteJson(waitPath(runDir, input.waitId), wait);
|
|
127
|
-
return wait;
|
|
128
|
-
}
|
|
129
|
-
/** Read a single wait file, or `undefined` if it doesn't exist. */
|
|
130
|
-
export function readWait(runDir, waitId) {
|
|
131
|
-
const path = waitPath(runDir, waitId);
|
|
132
|
-
if (existsSync(waitsDir(runDir)))
|
|
133
|
-
assertRealDirectory(waitsDir(runDir), 'waits directory');
|
|
134
|
-
if (!existsSync(path))
|
|
135
|
-
return undefined;
|
|
136
|
-
const pathStat = lstatSync(path);
|
|
137
|
-
if (!pathStat.isFile() || pathStat.isSymbolicLink()) {
|
|
138
|
-
throw new Error('v3 human-gate: wait file must be a regular file');
|
|
139
|
-
}
|
|
140
|
-
const wait = normalizeWaitFile(JSON.parse(readFileSync(path, 'utf-8')));
|
|
141
|
-
if (wait.hostApproval && (pathStat.mode & 0o077) !== 0) {
|
|
142
|
-
throw new Error('v3 human-gate: host wait file must not be group/world accessible');
|
|
143
|
-
}
|
|
144
|
-
return wait;
|
|
145
|
-
}
|
|
146
|
-
/** Transition a wait to approved / rejected. Throws if the wait is missing
|
|
147
|
-
* (a resolution for an unknown gate is a programming error, not a no-op). */
|
|
148
|
-
export function resolveWait(runDir, waitId, resolution, by, selected) {
|
|
149
|
-
const outcome = resolveWaitOnce(runDir, waitId, resolution, by, selected);
|
|
150
|
-
if (!outcome.changed) {
|
|
151
|
-
throw new Error(`v3 human-gate: wait "${waitId}" is already ${outcome.wait.status}; first resolution wins`);
|
|
152
|
-
}
|
|
153
|
-
return outcome.wait;
|
|
154
|
-
}
|
|
155
|
-
/** Cross-process compare-and-set for a pending wait. Exactly one resolver may
|
|
156
|
-
* transition it; every later contradictory click observes the first result. */
|
|
157
|
-
export function resolveWaitOnce(runDir, waitId, resolution, by, selected) {
|
|
158
|
-
const path = waitPath(runDir, waitId);
|
|
159
|
-
if (existsSync(waitsDir(runDir)))
|
|
160
|
-
assertRealDirectory(waitsDir(runDir), 'waits directory');
|
|
161
|
-
if (!existsSync(path)) {
|
|
162
|
-
throw new Error(`v3 human-gate: no pending wait "${waitId}" in ${runDir}`);
|
|
163
|
-
}
|
|
164
|
-
return withFileLockSync(path, () => {
|
|
165
|
-
const existing = readWait(runDir, waitId);
|
|
166
|
-
if (!existing)
|
|
167
|
-
throw new Error(`v3 human-gate: no pending wait "${waitId}" in ${runDir}`);
|
|
168
|
-
if (existing.status !== 'pending')
|
|
169
|
-
return { wait: existing, changed: false };
|
|
170
|
-
const resolved = {
|
|
171
|
-
...existing,
|
|
172
|
-
status: resolution,
|
|
173
|
-
resolvedAt: Date.now(),
|
|
174
|
-
by,
|
|
175
|
-
selected,
|
|
176
|
-
};
|
|
177
|
-
atomicWriteJson(path, resolved);
|
|
178
|
-
return { wait: resolved, changed: true };
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
export function normalizeGateWaitInput(gate) {
|
|
182
|
-
const options = gate.options ?? [...DEFAULT_HUMAN_GATE_OPTIONS];
|
|
183
|
-
return {
|
|
184
|
-
prompt: gate.prompt,
|
|
185
|
-
options,
|
|
186
|
-
approveOptions: gate.approveOptions ?? (options.includes('approve') ? ['approve'] : [options[0]]),
|
|
187
|
-
approvers: gate.approvers ?? [],
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
export function selectedResolution(wait, selected) {
|
|
191
|
-
if (!wait.options.includes(selected))
|
|
192
|
-
return undefined;
|
|
193
|
-
return wait.approveOptions.includes(selected) ? 'approved' : 'rejected';
|
|
194
|
-
}
|
|
195
|
-
export function canResolveGateWait(wait, by) {
|
|
196
|
-
return wait.approvers.length === 0 || (!!by && wait.approvers.includes(by));
|
|
197
|
-
}
|
|
198
|
-
/** All still-pending waits in the runDir — the daemon's restart-recovery scan
|
|
199
|
-
* uses this to re-post / re-arm approval cards after a crash. */
|
|
200
|
-
export function listPendingWaits(runDir) {
|
|
201
|
-
const dir = waitsDir(runDir);
|
|
202
|
-
if (!existsSync(dir))
|
|
203
|
-
return [];
|
|
204
|
-
const out = [];
|
|
205
|
-
for (const name of readdirSync(dir)) {
|
|
206
|
-
if (!name.endsWith('.json') || name.endsWith('.tmp'))
|
|
207
|
-
continue;
|
|
208
|
-
try {
|
|
209
|
-
const wait = readWait(runDir, name.slice(0, -'.json'.length));
|
|
210
|
-
if (!wait)
|
|
211
|
-
continue;
|
|
212
|
-
if (wait.status === 'pending')
|
|
213
|
-
out.push(wait);
|
|
214
|
-
}
|
|
215
|
-
catch {
|
|
216
|
-
// skip a torn / unparseable wait file (mid-write crash)
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return out;
|
|
220
|
-
}
|
|
221
|
-
function normalizeWaitFile(raw) {
|
|
222
|
-
const options = raw.options ?? [...DEFAULT_HUMAN_GATE_OPTIONS];
|
|
223
|
-
let hostApproval;
|
|
224
|
-
if (raw.hostApproval !== undefined) {
|
|
225
|
-
const approval = raw.hostApproval;
|
|
226
|
-
if (!approval ||
|
|
227
|
-
typeof approval !== 'object' ||
|
|
228
|
-
Array.isArray(approval) ||
|
|
229
|
-
Object.keys(approval).sort().join(',') !== 'approvalDigest,attemptId,inputHash' ||
|
|
230
|
-
typeof approval.attemptId !== 'string' ||
|
|
231
|
-
!/\/attempts\/\d{3}$/.test(approval.attemptId) ||
|
|
232
|
-
typeof approval.approvalDigest !== 'string' ||
|
|
233
|
-
!/^sha256:[0-9a-f]{64}$/.test(approval.approvalDigest) ||
|
|
234
|
-
typeof approval.inputHash !== 'string' ||
|
|
235
|
-
!/^sha256:[0-9a-f]{64}$/.test(approval.inputHash)) {
|
|
236
|
-
throw new Error('v3 human-gate: malformed hostApproval in wait file');
|
|
237
|
-
}
|
|
238
|
-
hostApproval = approval;
|
|
239
|
-
}
|
|
240
|
-
return {
|
|
241
|
-
waitId: raw.waitId ?? '',
|
|
242
|
-
nodeId: raw.nodeId ?? '',
|
|
243
|
-
...(raw.instanceId ? { instanceId: raw.instanceId } : {}),
|
|
244
|
-
prompt: raw.prompt ?? '',
|
|
245
|
-
options,
|
|
246
|
-
approveOptions: raw.approveOptions ?? (options.includes('approve') ? ['approve'] : [options[0]]),
|
|
247
|
-
approvers: raw.approvers ?? [],
|
|
248
|
-
status: raw.status ?? 'pending',
|
|
249
|
-
createdAt: raw.createdAt ?? 0,
|
|
250
|
-
resolvedAt: raw.resolvedAt,
|
|
251
|
-
by: raw.by,
|
|
252
|
-
selected: raw.selected,
|
|
253
|
-
...(hostApproval ? { hostApproval } : {}),
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
// ─── Gate resolver (injected into the runtime) ──────────────────────────────
|
|
257
|
-
/**
|
|
258
|
-
* Build the `resolveGate` the runtime injects. Persists the wait as `pending`,
|
|
259
|
-
* delegates to the daemon-supplied `awaitDecision` (post card + await the
|
|
260
|
-
* click), then persists the resolution — so the file store is authoritative
|
|
261
|
-
* for pending/resolved regardless of whether the in-memory decision promise
|
|
262
|
-
* survives a restart (the daemon re-arms via `listPendingWaits`).
|
|
263
|
-
*
|
|
264
|
-
* `awaitDecision` is the only daemon-coupled seam; everything else here is file
|
|
265
|
-
* IO, which is why this factory is unit-testable with a fake decision source.
|
|
4
|
+
* Daemon and CLI callers retain the historical module path while embedders
|
|
5
|
+
* can depend directly on gate-wait-store without importing a Botmux adapter.
|
|
266
6
|
*/
|
|
267
|
-
export
|
|
268
|
-
return async ({ nodeId, prompt, waitId, runDir, hostApproval }) => {
|
|
269
|
-
const wait = writePendingWait(runDir, { waitId, nodeId, prompt, ...(hostApproval ? { hostApproval } : {}) });
|
|
270
|
-
const { resolution, by, selected } = await deps.awaitDecision(wait);
|
|
271
|
-
const settled = resolveWaitOnce(runDir, waitId, resolution, by, selected);
|
|
272
|
-
return {
|
|
273
|
-
resolution: settled.wait.status === 'approved' ? 'approved' : 'rejected',
|
|
274
|
-
by: settled.wait.by ?? by,
|
|
275
|
-
selected: settled.wait.selected,
|
|
276
|
-
};
|
|
277
|
-
};
|
|
278
|
-
}
|
|
7
|
+
export * from './gate-wait-store.js';
|
|
279
8
|
//# sourceMappingURL=human-gate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"human-gate.js","sourceRoot":"","sources":["../../../src/workflows/v3/human-gate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"human-gate.js","sourceRoot":"","sources":["../../../src/workflows/v3/human-gate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AttemptLeaseProvider } from './runtime-host-contract.js';
|
|
2
|
+
/**
|
|
3
|
+
* Lease provider for fresh, process-local executions.
|
|
4
|
+
*
|
|
5
|
+
* It can prove only closures observed by this exact provider instance. An
|
|
6
|
+
* attempt absent from the local ledger may belong to another live process, so
|
|
7
|
+
* restart recovery stays fail-closed instead of inventing a close proof.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createInProcessAttemptLeaseProvider(): AttemptLeaseProvider;
|
|
10
|
+
//# sourceMappingURL=in-process-attempt-lease.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-process-attempt-lease.d.ts","sourceRoot":"","sources":["../../../src/workflows/v3/in-process-attempt-lease.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EACrB,MAAM,4BAA4B,CAAC;AAEpC;;;;;;GAMG;AACH,wBAAgB,mCAAmC,IAAI,oBAAoB,CAwC1E"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lease provider for fresh, process-local executions.
|
|
3
|
+
*
|
|
4
|
+
* It can prove only closures observed by this exact provider instance. An
|
|
5
|
+
* attempt absent from the local ledger may belong to another live process, so
|
|
6
|
+
* restart recovery stays fail-closed instead of inventing a close proof.
|
|
7
|
+
*/
|
|
8
|
+
export function createInProcessAttemptLeaseProvider() {
|
|
9
|
+
const leases = new Map();
|
|
10
|
+
const keyFor = (binding) => `${binding.runId}\0${binding.attemptId}\0${binding.attemptDir}`;
|
|
11
|
+
return {
|
|
12
|
+
acquire: (binding) => {
|
|
13
|
+
const key = keyFor(binding);
|
|
14
|
+
if (leases.has(key)) {
|
|
15
|
+
throw new Error(`in-process attempt lease already acquired: ${binding.attemptId}`);
|
|
16
|
+
}
|
|
17
|
+
leases.set(key, 'active');
|
|
18
|
+
return { auditKind: 'attemptLease' };
|
|
19
|
+
},
|
|
20
|
+
closeBeforeExecution: (binding) => {
|
|
21
|
+
const key = keyFor(binding);
|
|
22
|
+
if (leases.get(key) !== 'active') {
|
|
23
|
+
throw new Error(`in-process attempt lease is not active: ${binding.attemptId}`);
|
|
24
|
+
}
|
|
25
|
+
leases.set(key, 'closed');
|
|
26
|
+
},
|
|
27
|
+
drainExternallyOwned: (binding) => {
|
|
28
|
+
const key = keyFor(binding);
|
|
29
|
+
const state = leases.get(key);
|
|
30
|
+
if (state === 'active')
|
|
31
|
+
return { status: 'pending' };
|
|
32
|
+
if (state !== 'closed')
|
|
33
|
+
return { status: 'unknown' };
|
|
34
|
+
return {
|
|
35
|
+
status: 'closed',
|
|
36
|
+
finalizeAfterProof: () => {
|
|
37
|
+
if (leases.get(key) === 'closed')
|
|
38
|
+
leases.delete(key);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
cleanupSettled: (binding) => {
|
|
43
|
+
leases.delete(keyFor(binding));
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=in-process-attempt-lease.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-process-attempt-lease.js","sourceRoot":"","sources":["../../../src/workflows/v3/in-process-attempt-lease.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,MAAM,UAAU,mCAAmC;IACjD,MAAM,MAAM,GAAG,IAAI,GAAG,EAA+B,CAAC;IACtD,MAAM,MAAM,GAAG,CAAC,OAIf,EAAU,EAAE,CAAC,GAAG,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,SAAS,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC;IAE9E,OAAO;QACL,OAAO,EAAE,CAAC,OAAO,EAA2B,EAAE;YAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;YAC5B,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,8CAA8C,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;YACrF,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC1B,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;QACvC,CAAC;QACD,oBAAoB,EAAE,CAAC,OAAO,EAAE,EAAE;YAChC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;YAC5B,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACjC,MAAM,IAAI,KAAK,CAAC,2CAA2C,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;YAClF,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC5B,CAAC;QACD,oBAAoB,EAAE,CAAC,OAAO,EAAE,EAAE;YAChC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;YAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,KAAK,KAAK,QAAQ;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACrD,IAAI,KAAK,KAAK,QAAQ;gBAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;YACrD,OAAO;gBACL,MAAM,EAAE,QAAQ;gBAChB,kBAAkB,EAAE,GAAG,EAAE;oBACvB,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,QAAQ;wBAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvD,CAAC;aACF,CAAC;QACJ,CAAC;QACD,cAAc,EAAE,CAAC,OAAO,EAAE,EAAE;YAC1B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACjC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -14,281 +14,8 @@
|
|
|
14
14
|
* cross-process journal lock and repairs an unterminated tail before writing
|
|
15
15
|
* the next event.
|
|
16
16
|
*/
|
|
17
|
-
import type {
|
|
18
|
-
|
|
19
|
-
* (`classifyTerminal` maps each class to `blocked` or `failed`).
|
|
20
|
-
* `gateRejected` / `cancelled` are user-driven; the rest are faults. */
|
|
21
|
-
export type V3ErrorClass = 'workerError' | 'manifestInvalid' | 'resultInvalid' | 'timeout' | 'gateRejected' | 'cancelled';
|
|
22
|
-
export type V3RunFailureReason = 'allSinksSkipped';
|
|
23
|
-
/** Bounded, privacy-safe identity for an external effect whose final provider
|
|
24
|
-
* outcome cannot be proved. Full inputs/errors stay in the protected attempt
|
|
25
|
-
* artifacts and logs; terminal cards only need this machine-readable tuple. */
|
|
26
|
-
export interface V3UncertainHostEffect {
|
|
27
|
-
nodeId: string;
|
|
28
|
-
instanceId: string;
|
|
29
|
-
attemptId: string;
|
|
30
|
-
executor: string;
|
|
31
|
-
errorCode: string;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* The MVP event union. Static DAG + fail-fast, so the lifecycle is small:
|
|
35
|
-
* run boundaries, per-node dispatch/settle, and gate dispatch/resolve. Retry
|
|
36
|
-
* (`attempts/NNN`) is modeled by `attemptId` on dispatch/settle events — a new
|
|
37
|
-
* attempt is just another `nodeDispatched` with a fresh `attemptId`.
|
|
38
|
-
*/
|
|
39
|
-
/**
|
|
40
|
-
* Structured loop reference carried on body-instance dispatches. The expanded
|
|
41
|
-
* nodeId (`repairLoop.i001.code`) is an OPAQUE key — projections/dashboards
|
|
42
|
-
* group by THIS field and never parse the id string (body ids may themselves
|
|
43
|
-
* contain dots).
|
|
44
|
-
*/
|
|
45
|
-
export interface V3LoopRef {
|
|
46
|
-
loopId: string;
|
|
47
|
-
iteration: number;
|
|
48
|
-
bodyNodeId: string;
|
|
49
|
-
}
|
|
50
|
-
export type V3Event = {
|
|
51
|
-
type: 'runStarted';
|
|
52
|
-
runId: string;
|
|
53
|
-
} | {
|
|
54
|
-
type: 'nodeDispatched';
|
|
55
|
-
nodeId: string;
|
|
56
|
-
instanceId?: string;
|
|
57
|
-
attemptId: string;
|
|
58
|
-
loop?: V3LoopRef;
|
|
59
|
-
} | {
|
|
60
|
-
type: 'hostInputPrepared';
|
|
61
|
-
nodeId: string;
|
|
62
|
-
instanceId: string;
|
|
63
|
-
attemptId: string;
|
|
64
|
-
executor: string;
|
|
65
|
-
provider: string;
|
|
66
|
-
inputRef: {
|
|
67
|
-
path: string;
|
|
68
|
-
sha256: string;
|
|
69
|
-
bytes: number;
|
|
70
|
-
};
|
|
71
|
-
inputHash: string;
|
|
72
|
-
idempotencyKey: string;
|
|
73
|
-
idempotencyTtlMs: number;
|
|
74
|
-
approvalDigest: string;
|
|
75
|
-
} | {
|
|
76
|
-
type: 'hostEffectIntent';
|
|
77
|
-
nodeId: string;
|
|
78
|
-
instanceId: string;
|
|
79
|
-
attemptId: string;
|
|
80
|
-
executor: string;
|
|
81
|
-
provider: string;
|
|
82
|
-
inputRef: {
|
|
83
|
-
path: string;
|
|
84
|
-
sha256: string;
|
|
85
|
-
bytes: number;
|
|
86
|
-
};
|
|
87
|
-
inputHash: string;
|
|
88
|
-
idempotencyKey: string;
|
|
89
|
-
idempotencyTtlMs: number;
|
|
90
|
-
approvalDigest: string;
|
|
91
|
-
} | {
|
|
92
|
-
type: 'hostEffectUncertain';
|
|
93
|
-
nodeId: string;
|
|
94
|
-
instanceId: string;
|
|
95
|
-
attemptId: string;
|
|
96
|
-
executor: string;
|
|
97
|
-
reason: 'ttlExpired' | 'inputUnrecoverable' | 'outputUnrecoverable' | 'definitionMismatch' | 'unknownProvider' | 'inputHashMismatch' | 'providerUncertain';
|
|
98
|
-
errorCode: string;
|
|
99
|
-
} | {
|
|
100
|
-
type: 'hostEffectRetryDeferred';
|
|
101
|
-
nodeId: string;
|
|
102
|
-
instanceId: string;
|
|
103
|
-
attemptId: string;
|
|
104
|
-
retryCount: number;
|
|
105
|
-
nextRetryAt: number;
|
|
106
|
-
errorCode: string;
|
|
107
|
-
} | {
|
|
108
|
-
type: 'nodeWorkerFenceArmed';
|
|
109
|
-
nodeId: string;
|
|
110
|
-
instanceId?: string;
|
|
111
|
-
attemptId: string;
|
|
112
|
-
} | {
|
|
113
|
-
type: 'nodeSessionReady';
|
|
114
|
-
nodeId: string;
|
|
115
|
-
instanceId?: string;
|
|
116
|
-
attemptId: string;
|
|
117
|
-
sessionInfo: {
|
|
118
|
-
sessionId: string;
|
|
119
|
-
webPort?: number;
|
|
120
|
-
};
|
|
121
|
-
ptyLogPath?: string;
|
|
122
|
-
} | {
|
|
123
|
-
type: 'nodeSucceeded';
|
|
124
|
-
nodeId: string;
|
|
125
|
-
instanceId?: string;
|
|
126
|
-
attemptId: string;
|
|
127
|
-
manifestPath: string;
|
|
128
|
-
} | {
|
|
129
|
-
type: 'nodeFailed';
|
|
130
|
-
nodeId: string;
|
|
131
|
-
instanceId?: string;
|
|
132
|
-
attemptId: string;
|
|
133
|
-
errorClass: V3ErrorClass;
|
|
134
|
-
errorCode?: string;
|
|
135
|
-
message?: string;
|
|
136
|
-
} | {
|
|
137
|
-
type: 'nodeBlocked';
|
|
138
|
-
nodeId: string;
|
|
139
|
-
instanceId?: string;
|
|
140
|
-
attemptId: string;
|
|
141
|
-
errorClass: V3ErrorClass;
|
|
142
|
-
errorCode?: string;
|
|
143
|
-
message?: string;
|
|
144
|
-
ask?: GoalAsk;
|
|
145
|
-
revisitTo?: string;
|
|
146
|
-
} | {
|
|
147
|
-
type: 'nodeRetryRequested';
|
|
148
|
-
nodeId: string;
|
|
149
|
-
instanceId?: string;
|
|
150
|
-
previousAttemptId: string;
|
|
151
|
-
nextAttemptId: string;
|
|
152
|
-
reason: 'blockedRetry';
|
|
153
|
-
previousErrorClass?: V3ErrorClass;
|
|
154
|
-
previousErrorCode?: string;
|
|
155
|
-
/** Host pre-intent retry must approve the newly frozen attempt again. */
|
|
156
|
-
resetGate?: boolean;
|
|
157
|
-
answer?: {
|
|
158
|
-
path: string;
|
|
159
|
-
preview: string;
|
|
160
|
-
by: string;
|
|
161
|
-
};
|
|
162
|
-
} | {
|
|
163
|
-
type: 'gateDispatched';
|
|
164
|
-
nodeId: string;
|
|
165
|
-
instanceId?: string;
|
|
166
|
-
waitId: string;
|
|
167
|
-
hostApproval?: {
|
|
168
|
-
attemptId: string;
|
|
169
|
-
approvalDigest: string;
|
|
170
|
-
inputHash: string;
|
|
171
|
-
};
|
|
172
|
-
} | {
|
|
173
|
-
type: 'gateResolved';
|
|
174
|
-
nodeId: string;
|
|
175
|
-
instanceId?: string;
|
|
176
|
-
waitId: string;
|
|
177
|
-
resolution: 'approved' | 'rejected';
|
|
178
|
-
by: string;
|
|
179
|
-
selected?: string;
|
|
180
|
-
hostApproval?: {
|
|
181
|
-
attemptId: string;
|
|
182
|
-
approvalDigest: string;
|
|
183
|
-
inputHash: string;
|
|
184
|
-
};
|
|
185
|
-
} | {
|
|
186
|
-
type: 'edgeResolved';
|
|
187
|
-
from: string;
|
|
188
|
-
to: string;
|
|
189
|
-
fromInstanceId?: string;
|
|
190
|
-
toInstanceId?: string;
|
|
191
|
-
sourceAttemptId: string;
|
|
192
|
-
active: boolean;
|
|
193
|
-
detail?: string;
|
|
194
|
-
} | {
|
|
195
|
-
type: 'nodeSkipped';
|
|
196
|
-
nodeId: string;
|
|
197
|
-
reason: 'triggerRuleUnsatisfied';
|
|
198
|
-
detail?: string;
|
|
199
|
-
} | ({
|
|
200
|
-
type: 'nodeCancelled';
|
|
201
|
-
nodeId: string;
|
|
202
|
-
instanceId?: string;
|
|
203
|
-
attemptId?: string;
|
|
204
|
-
detail?: string;
|
|
205
|
-
} & ({
|
|
206
|
-
reason: 'earlyReleaseLoser';
|
|
207
|
-
byNodeId: string;
|
|
208
|
-
} | {
|
|
209
|
-
reason: 'runCancelled';
|
|
210
|
-
cancelRequestId: string;
|
|
211
|
-
})) | {
|
|
212
|
-
type: 'nodeAttemptDrained';
|
|
213
|
-
nodeId: string;
|
|
214
|
-
instanceId?: string;
|
|
215
|
-
attemptId: string;
|
|
216
|
-
reason: 'terminalPeer' | 'obsoleteAttempt' | 'orphanRecovery' | 'runCancellation';
|
|
217
|
-
} | {
|
|
218
|
-
type: 'nodeRevisitRequested';
|
|
219
|
-
nodeId: string;
|
|
220
|
-
instanceId: string;
|
|
221
|
-
attemptId: string;
|
|
222
|
-
toNodeId: string;
|
|
223
|
-
reason?: string;
|
|
224
|
-
reasonPath?: string;
|
|
225
|
-
sourceManifestPath?: string;
|
|
226
|
-
targetPreviousManifestPath?: string;
|
|
227
|
-
} | {
|
|
228
|
-
type: 'nodeInstanceSuperseded';
|
|
229
|
-
nodeId: string;
|
|
230
|
-
instanceId: string;
|
|
231
|
-
byNodeId: string;
|
|
232
|
-
reason: 'refresh';
|
|
233
|
-
} | {
|
|
234
|
-
type: 'revisitBudgetGranted';
|
|
235
|
-
sourceNodeId?: string;
|
|
236
|
-
toNodeId?: string;
|
|
237
|
-
by: string;
|
|
238
|
-
reason?: string;
|
|
239
|
-
} | {
|
|
240
|
-
type: 'loopStarted';
|
|
241
|
-
loopId: string;
|
|
242
|
-
} | {
|
|
243
|
-
type: 'loopIterationStarted';
|
|
244
|
-
loopId: string;
|
|
245
|
-
iteration: number;
|
|
246
|
-
} | {
|
|
247
|
-
type: 'loopIterationDecision';
|
|
248
|
-
loopId: string;
|
|
249
|
-
iteration: number;
|
|
250
|
-
decision: 'exit' | 'continue' | 'exhausted';
|
|
251
|
-
/** Human-readable why (e.g. `result.passed=false (2/3 iterations used)`). */
|
|
252
|
-
detail?: string;
|
|
253
|
-
} | {
|
|
254
|
-
type: 'loopIterationGranted';
|
|
255
|
-
loopId: string;
|
|
256
|
-
fromIteration: number;
|
|
257
|
-
by?: string;
|
|
258
|
-
} | {
|
|
259
|
-
type: 'runCancelRequested';
|
|
260
|
-
cancelRequestId: string;
|
|
261
|
-
by: string;
|
|
262
|
-
reason?: string;
|
|
263
|
-
} | {
|
|
264
|
-
type: 'runCancelled';
|
|
265
|
-
cancelRequestId: string;
|
|
266
|
-
by: string;
|
|
267
|
-
uncertainHostEffects?: V3UncertainHostEffect[];
|
|
268
|
-
} | {
|
|
269
|
-
type: 'runSucceeded';
|
|
270
|
-
} | {
|
|
271
|
-
type: 'runFailed';
|
|
272
|
-
failedNodeId?: string;
|
|
273
|
-
reason?: V3RunFailureReason;
|
|
274
|
-
detail?: string;
|
|
275
|
-
} | {
|
|
276
|
-
type: 'runBlocked';
|
|
277
|
-
blockedNodeId: string;
|
|
278
|
-
};
|
|
279
|
-
/** A journal line: the event flattened with its append timestamp (flattened —
|
|
280
|
-
* not `{ts, event}` — so `grep nodeFailed journal.ndjson` just works). */
|
|
281
|
-
export type StoredEvent = V3Event & {
|
|
282
|
-
ts: number;
|
|
283
|
-
};
|
|
284
|
-
export interface JournalMutation {
|
|
285
|
-
/** Lazy snapshot; access it before calling append when doing read/check/write. */
|
|
286
|
-
readonly events: readonly StoredEvent[];
|
|
287
|
-
/** Append while retaining the mutation's already-held cross-process lock. */
|
|
288
|
-
append(event: V3Event, options?: {
|
|
289
|
-
durable?: boolean;
|
|
290
|
-
}): StoredEvent;
|
|
291
|
-
}
|
|
17
|
+
import type { JournalMutation, StoredEvent, V3Event } from './event-contract.js';
|
|
18
|
+
export type { GoalAsk, GoalAnswer, JournalMutation, StoredEvent, V3ErrorClass, V3Event, V3LoopRef, V3RunFailureReason, V3UncertainHostEffect, } from './event-contract.js';
|
|
292
19
|
/**
|
|
293
20
|
* Run one read/check/append mutation under the journal's sole lock. Callers
|
|
294
21
|
* such as start-intent use this instead of nesting a file lock around
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../../../src/workflows/v3/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAiBH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../../../src/workflows/v3/journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAiBH,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACjF,YAAY,EACV,OAAO,EACP,UAAU,EACV,eAAe,EACf,WAAW,EACX,YAAY,EACZ,OAAO,EACP,SAAS,EACT,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AA+F7B;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,CAAC,GACnC,CAAC,CAgCH;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAE5E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAEnF;AAID;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,EAAE,CAG9D"}
|