create-walle 0.10.2 → 0.10.3
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.md +3 -1
- package/lib/release-schema.json +2 -2
- package/lib/runtime-closure-policy.json +8 -7
- package/package.json +1 -1
- package/template/coding-task-manager/api-prompts.js +45 -7
- package/template/coding-task-manager/bin/claude-hook.js +55 -1
- package/template/coding-task-manager/bin/ctm-relay-client.js +35 -12
- package/template/coding-task-manager/bin/land.js +2069 -0
- package/template/coding-task-manager/bin/memory-census.js +4 -2
- package/template/coding-task-manager/bin/memory-sync-verify.js +151 -0
- package/template/coding-task-manager/bin/probe-refusal-scope.js +530 -0
- package/template/coding-task-manager/db.js +156 -32
- package/template/coding-task-manager/lib/acp/acp-client.js +383 -0
- package/template/coding-task-manager/lib/acp/dsh-context-truth.js +176 -0
- package/template/coding-task-manager/lib/acp/dsh-launch-model.js +302 -0
- package/template/coding-task-manager/lib/acp/dsh-mcp-servers.js +194 -0
- package/template/coding-task-manager/lib/acp/dsh-prompt-lane.js +616 -0
- package/template/coding-task-manager/lib/acp/dsh-route-patch.js +308 -0
- package/template/coding-task-manager/lib/acp/dsh-session-runtime.js +522 -0
- package/template/coding-task-manager/lib/acp/dsh-transcript.js +395 -0
- package/template/coding-task-manager/lib/acp/dsh-usage-log.js +162 -0
- package/template/coding-task-manager/lib/acp/ndjson-stdio-transport.js +225 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +47 -11
- package/template/coding-task-manager/lib/adopted-launch-environment.js +123 -0
- package/template/coding-task-manager/lib/agent-auto-update-runtime.js +0 -3
- package/template/coding-task-manager/lib/agent-auto-update.js +26 -10
- package/template/coding-task-manager/lib/agent-bundle/build.js +657 -0
- package/template/coding-task-manager/lib/agent-bundle/codex-install.js +558 -0
- package/template/coding-task-manager/lib/agent-bundle/drift.js +120 -0
- package/template/coding-task-manager/lib/agent-bundle/gc.js +522 -0
- package/template/coding-task-manager/lib/agent-bundle/inventory.js +346 -0
- package/template/coding-task-manager/lib/agent-bundle/push.js +717 -0
- package/template/coding-task-manager/lib/agent-bundle/skill-transfer.js +724 -0
- package/template/coding-task-manager/lib/agent-bundle/spawn.js +119 -0
- package/template/coding-task-manager/lib/agent-bundle/store.js +568 -0
- package/template/coding-task-manager/lib/agent-capabilities.js +142 -12
- package/template/coding-task-manager/lib/agent-cli-cache.js +30 -5
- package/template/coding-task-manager/lib/agent-definitions.js +19 -0
- package/template/coding-task-manager/lib/agent-hooks-codex-toml.js +28 -16
- package/template/coding-task-manager/lib/agent-hooks-codex-workspace.js +9 -1
- package/template/coding-task-manager/lib/agent-hooks-installer.js +23 -8
- package/template/coding-task-manager/lib/agent-hooks-prune.js +37 -11
- package/template/coding-task-manager/lib/agent-hooks-shim.js +105 -0
- package/template/coding-task-manager/lib/agent-presets.js +84 -1
- package/template/coding-task-manager/lib/agent-upgrade-jobs.js +12 -1
- package/template/coding-task-manager/lib/agent-version-service.js +74 -11
- package/template/coding-task-manager/lib/all-sessions-query.js +6 -2
- package/template/coding-task-manager/lib/api/agent-bundles.js +436 -0
- package/template/coding-task-manager/lib/api/backup-retention.js +83 -0
- package/template/coding-task-manager/lib/api/conversation-sync-routes.js +124 -0
- package/template/coding-task-manager/lib/api/diagnostics.js +549 -69
- package/template/coding-task-manager/lib/api/fleet.js +118 -0
- package/template/coding-task-manager/lib/api/hub-bridge.js +243 -0
- package/template/coding-task-manager/lib/api/ingress.js +9 -1
- package/template/coding-task-manager/lib/api/landing.js +403 -0
- package/template/coding-task-manager/lib/api/machines.js +691 -2
- package/template/coding-task-manager/lib/api/memory-sync-routes.js +335 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +8 -3
- package/template/coding-task-manager/lib/api/remote-sessions.js +1326 -0
- package/template/coding-task-manager/lib/api/session-attach.js +623 -0
- package/template/coding-task-manager/lib/api/session-messages.js +1384 -0
- package/template/coding-task-manager/lib/api/sessions.js +77 -51
- package/template/coding-task-manager/lib/api/setup-network.js +544 -16
- package/template/coding-task-manager/lib/api/setup-wizard-handlers.js +884 -0
- package/template/coding-task-manager/lib/api/setup.js +829 -10
- package/template/coding-task-manager/lib/api/walle-bridge.js +9 -1
- package/template/coding-task-manager/lib/attachment-reconciler-wiring.js +5 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +23 -0
- package/template/coding-task-manager/lib/auth-rules.js +292 -21
- package/template/coding-task-manager/lib/background-stop.js +369 -0
- package/template/coding-task-manager/lib/best-of-attempts.js +4 -1
- package/template/coding-task-manager/lib/best-of-launch-plan.js +52 -0
- package/template/coding-task-manager/lib/box-keep-awake.js +89 -0
- package/template/coding-task-manager/lib/broadcast-reason-stats.js +152 -0
- package/template/coding-task-manager/lib/broadcast-serialize.js +5 -0
- package/template/coding-task-manager/lib/build-info.js +4 -2
- package/template/coding-task-manager/lib/claude-model-truth.js +13 -2
- package/template/coding-task-manager/lib/claude-transcript-terminal-renderer.js +17 -13
- package/template/coding-task-manager/lib/client-diag-handler.js +64 -2
- package/template/coding-task-manager/lib/codex-app-server-client.js +14 -16
- package/template/coding-task-manager/lib/codex-configuration-history.js +55 -0
- package/template/coding-task-manager/lib/codex-harness-qualification.js +43 -20
- package/template/coding-task-manager/lib/codex-rollout-history.js +743 -0
- package/template/coding-task-manager/lib/coding-agent-models.js +27 -12
- package/template/coding-task-manager/lib/coding-cli-skill-installer.js +44 -14
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +43 -2
- package/template/coding-task-manager/lib/coding-session-model-owner.js +1 -1
- package/template/coding-task-manager/lib/coding-session-model-public.js +7 -1
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +23 -4
- package/template/coding-task-manager/lib/coding-session-model-scan.js +31 -0
- package/template/coding-task-manager/lib/coding-session-model-state.js +7 -0
- package/template/coding-task-manager/lib/conversation-freshness-diagnostics.js +280 -0
- package/template/coding-task-manager/lib/conversation-item-clock.js +261 -0
- package/template/coding-task-manager/lib/conversation-source-registry.js +5 -0
- package/template/coding-task-manager/lib/conversation-store-v2.js +44 -0
- package/template/coding-task-manager/lib/conversation-sync.js +355 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +96 -12
- package/template/coding-task-manager/lib/create/worker-role-profile.js +4 -4
- package/template/coding-task-manager/lib/create-intent-lease.js +51 -0
- package/template/coding-task-manager/lib/ctm-session-context-api.js +97 -6
- package/template/coding-task-manager/lib/db-domain-tables.js +1 -0
- package/template/coding-task-manager/lib/db-domains.js +1 -0
- package/template/coding-task-manager/lib/db-owner-dispatch-probe.js +32 -0
- package/template/coding-task-manager/lib/db-owner-request-counts.js +178 -0
- package/template/coding-task-manager/lib/db-owner-worker-client.js +68 -14
- package/template/coding-task-manager/lib/db-schema-source-files.js +5 -0
- package/template/coding-task-manager/lib/deferred-restore-attempt.js +6 -2
- package/template/coding-task-manager/lib/feature-manifest.js +4 -0
- package/template/coding-task-manager/lib/fleet-conversation-route.js +97 -0
- package/template/coding-task-manager/lib/fleet-fanout.js +78 -0
- package/template/coding-task-manager/lib/fleet-hub.js +762 -0
- package/template/coding-task-manager/lib/fleet-origin-follower.js +252 -0
- package/template/coding-task-manager/lib/fleet-resolver-effects.js +147 -0
- package/template/coding-task-manager/lib/fleet-resolver-tick.js +148 -0
- package/template/coding-task-manager/lib/fleet-resolver.js +454 -0
- package/template/coding-task-manager/lib/fleet-session-list-routes.js +114 -0
- package/template/coding-task-manager/lib/fleet-session-lists.js +672 -0
- package/template/coding-task-manager/lib/fleet-update.js +798 -0
- package/template/coding-task-manager/lib/fs-watcher-root-watch.js +141 -0
- package/template/coding-task-manager/lib/fs-watcher.js +58 -42
- package/template/coding-task-manager/lib/harness-history-transition.js +50 -9
- package/template/coding-task-manager/lib/headless-term-service.js +84 -8
- package/template/coding-task-manager/lib/hermetic-agent-launch-guard.js +10 -0
- package/template/coding-task-manager/lib/history-transition-read-op.js +175 -8
- package/template/coding-task-manager/lib/host-cpu-categories.js +310 -0
- package/template/coding-task-manager/lib/host-fseventsd-sampler.js +399 -0
- package/template/coding-task-manager/lib/host-handoff.js +16 -19
- package/template/coding-task-manager/lib/host-stats.js +150 -3
- package/template/coding-task-manager/lib/hosted-sync-worker.js +43 -320
- package/template/coding-task-manager/lib/hub-bridge-access.js +798 -0
- package/template/coding-task-manager/lib/hub-bridge-box.js +409 -0
- package/template/coding-task-manager/lib/hub-bridge-mcp.js +380 -0
- package/template/coding-task-manager/lib/hub-bridge-mesh.js +313 -0
- package/template/coding-task-manager/lib/hub-bridge-ops.js +721 -0
- package/template/coding-task-manager/lib/hub-bridge.js +398 -0
- package/template/coding-task-manager/lib/idle-notify.js +491 -0
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +8 -0
- package/template/coding-task-manager/lib/instance-manifest.js +5 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +18 -8
- package/template/coding-task-manager/lib/landing/agent-rule.txt +1 -0
- package/template/coding-task-manager/lib/landing/batch-runner.js +366 -0
- package/template/coding-task-manager/lib/landing/config.js +536 -0
- package/template/coding-task-manager/lib/landing/ctm-view.js +256 -0
- package/template/coding-task-manager/lib/landing/gate.js +360 -0
- package/template/coding-task-manager/lib/landing/git.js +344 -0
- package/template/coding-task-manager/lib/landing/lease.js +247 -0
- package/template/coding-task-manager/lib/landing/merge-delta.js +380 -0
- package/template/coding-task-manager/lib/landing/proof.js +223 -0
- package/template/coding-task-manager/lib/landing/queue.js +998 -0
- package/template/coding-task-manager/lib/landing/radar.js +489 -0
- package/template/coding-task-manager/lib/landing/resolve-cli.js +424 -0
- package/template/coding-task-manager/lib/landing/state.js +263 -0
- package/template/coding-task-manager/lib/landing/stop.js +49 -0
- package/template/coding-task-manager/lib/landing/sync-cli.js +475 -0
- package/template/coding-task-manager/lib/landing/sync.js +456 -0
- package/template/coding-task-manager/lib/landing/train.js +885 -0
- package/template/coding-task-manager/lib/landing/window.js +57 -0
- package/template/coding-task-manager/lib/launch-environment.js +121 -0
- package/template/coding-task-manager/lib/launch-model-override.js +36 -10
- package/template/coding-task-manager/lib/launch-plan-pool.js +2 -1
- package/template/coding-task-manager/lib/launch-plan-warm-cache.js +6 -0
- package/template/coding-task-manager/lib/lead-model-observer.js +57 -1
- package/template/coding-task-manager/lib/lead-model-options.js +160 -3
- package/template/coding-task-manager/lib/lead-model-restore-reconciliation.js +106 -24
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +352 -68
- package/template/coding-task-manager/lib/lead-model-switch.js +114 -10
- package/template/coding-task-manager/lib/lead-model-transition-runtime.js +14 -2
- package/template/coding-task-manager/lib/lead-model-transition-store.js +24 -6
- package/template/coding-task-manager/lib/lead-route-preflight.js +179 -0
- package/template/coding-task-manager/lib/lead-switch-history-mode.js +110 -0
- package/template/coding-task-manager/lib/lead-wire-agent.js +7 -0
- package/template/coding-task-manager/lib/lifecycle-wake-experiment.js +9 -2
- package/template/coding-task-manager/lib/live-defer-announce.js +45 -0
- package/template/coding-task-manager/lib/machine-registry.js +750 -5
- package/template/coding-task-manager/lib/macos-capabilities.js +32 -15
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +433 -53
- package/template/coding-task-manager/lib/mainloop-observability.js +14 -9
- package/template/coding-task-manager/lib/media-draft-owner.js +16 -3
- package/template/coding-task-manager/lib/memory-join.js +337 -0
- package/template/coding-task-manager/lib/memory-sync-verify.js +393 -0
- package/template/coding-task-manager/lib/memory-sync.js +565 -0
- package/template/coding-task-manager/lib/migrations/v57-delegate-pref-mirror-opencode.js +68 -0
- package/template/coding-task-manager/lib/migrations/v58-subagent-launch-native-subagents.js +42 -0
- package/template/coding-task-manager/lib/migrations/v59-coding-session-model-state-dsh.js +73 -0
- package/template/coding-task-manager/lib/migrations/v60-delegate-pref-mirror-dsh.js +78 -0
- package/template/coding-task-manager/lib/migrations/v61-conversation-item-clock.js +71 -0
- package/template/coding-task-manager/lib/model-availability.js +727 -0
- package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +4 -6
- package/template/coding-task-manager/lib/model-host-receipt.js +6 -3
- package/template/coding-task-manager/lib/model-id-rule.js +19 -0
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/auto-mode-review.js +110 -23
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/generation-probe.js +60 -17
- package/template/coding-task-manager/lib/model-proxy/historical-tool-declarations.js +37 -0
- package/template/coding-task-manager/lib/model-proxy/lead-request-validation.js +1 -0
- package/template/coding-task-manager/lib/model-proxy/lead-token-admin.js +130 -0
- package/template/coding-task-manager/lib/model-proxy/refusal-scope.js +151 -0
- package/template/coding-task-manager/lib/model-proxy/request-budget-store.js +11 -2
- package/template/coding-task-manager/lib/model-proxy/tokens.js +69 -5
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-agent-model-args.js +25 -22
- package/template/coding-task-manager/lib/native-history-control.js +6 -4
- package/template/coding-task-manager/lib/native-lead-settings-client.js +44 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +173 -36
- package/template/coding-task-manager/lib/online-backup-worker-client.js +2 -0
- package/template/coding-task-manager/lib/opencode-cli.js +480 -0
- package/template/coding-task-manager/lib/opencode-launch-model.js +471 -0
- package/template/coding-task-manager/lib/opencode-v1-plugin/model-carrier.mjs +35 -0
- package/template/coding-task-manager/lib/opencode-v2-plugin/server.js +118 -0
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +1 -1
- package/template/coding-task-manager/lib/park-composer-draft.js +54 -0
- package/template/coding-task-manager/lib/park-fresh-relaunch.js +41 -10
- package/template/coding-task-manager/lib/perf-phase-trace.js +72 -0
- package/template/coding-task-manager/lib/perf-summary.js +7 -0
- package/template/coding-task-manager/lib/perf-tracker.js +63 -2
- package/template/coding-task-manager/lib/project-config.js +7 -0
- package/template/coding-task-manager/lib/prompt-purge-v2.js +52 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +72 -15
- package/template/coding-task-manager/lib/provider-login-tab.js +10 -2
- package/template/coding-task-manager/lib/read-pool-client.js +89 -2
- package/template/coding-task-manager/lib/read-pool-worker-handle.js +29 -4
- package/template/coding-task-manager/lib/recent-catalog-query.js +15 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +67 -10
- package/template/coding-task-manager/lib/recovery-evidence.js +26 -11
- package/template/coding-task-manager/lib/relay-client.js +57 -3
- package/template/coding-task-manager/lib/relink-audit.js +34 -5
- package/template/coding-task-manager/lib/remote-machine-catalog.js +321 -26
- package/template/coding-task-manager/lib/remote-machine-create.js +576 -36
- package/template/coding-task-manager/lib/remote-machine-link.js +546 -59
- package/template/coding-task-manager/lib/remote-machine-proxy.js +143 -9
- package/template/coding-task-manager/lib/remote-session-forward.js +65 -7
- package/template/coding-task-manager/lib/remote-terminal-target.js +9 -2
- package/template/coding-task-manager/lib/restart-guard.js +18 -6
- package/template/coding-task-manager/lib/restore-seed-modes.js +87 -0
- package/template/coding-task-manager/lib/restored-scrollback-hydration-runtime.js +22 -2
- package/template/coding-task-manager/lib/resume-admission.js +17 -3
- package/template/coding-task-manager/lib/review-repo-registry.js +58 -19
- package/template/coding-task-manager/lib/root-delivery-runtime.js +2 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +1 -1
- package/template/coding-task-manager/lib/runtime-contract.js +3 -1
- package/template/coding-task-manager/lib/schema-indexes.js +1 -0
- package/template/coding-task-manager/lib/session-context-locator.js +742 -0
- package/template/coding-task-manager/lib/session-create/attachment.js +2 -2
- package/template/coding-task-manager/lib/session-create/create-phases.js +118 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +86 -16
- package/template/coding-task-manager/lib/session-create/dsh-session.js +930 -0
- package/template/coding-task-manager/lib/session-create/lead-route-launch.js +186 -13
- package/template/coding-task-manager/lib/session-create/native-lead-lifetime.js +55 -3
- package/template/coding-task-manager/lib/session-create/opencode-lead-provider.js +50 -0
- package/template/coding-task-manager/lib/session-create/prepared.js +162 -38
- package/template/coding-task-manager/lib/session-create/provider-process.js +160 -28
- package/template/coding-task-manager/lib/session-create/response.js +7 -7
- package/template/coding-task-manager/lib/session-create/structured-session.js +27 -0
- package/template/coding-task-manager/lib/session-create/subagent-pick-table.js +3 -1
- package/template/coding-task-manager/lib/session-create/subagent-pick.js +458 -9
- package/template/coding-task-manager/lib/session-create/transcript.js +1 -1
- package/template/coding-task-manager/lib/session-create/worker-budget-setup.js +21 -2
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +7 -1
- package/template/coding-task-manager/lib/session-create/worker-launch-sandbox.js +39 -10
- package/template/coding-task-manager/lib/session-create/worker-observability.js +2 -2
- package/template/coding-task-manager/lib/session-empty.js +13 -10
- package/template/coding-task-manager/lib/session-host-manager.js +60 -0
- package/template/coding-task-manager/lib/session-jobs.js +3 -1
- package/template/coding-task-manager/lib/session-lifecycle.js +10 -4
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +6 -2
- package/template/coding-task-manager/lib/session-model-intent-contract.js +11 -8
- package/template/coding-task-manager/lib/session-park.js +738 -0
- package/template/coding-task-manager/lib/session-path-grant.js +13 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +106 -4
- package/template/coding-task-manager/lib/session-transport.js +17 -0
- package/template/coding-task-manager/lib/session-workspace-projection.js +54 -5
- package/template/coding-task-manager/lib/session-workspace-tracking-runtime.js +213 -1
- package/template/coding-task-manager/lib/skill-autocomplete-query.js +120 -3
- package/template/coding-task-manager/lib/skill-autocomplete.js +15 -1
- package/template/coding-task-manager/lib/sqlite-file-set.js +39 -0
- package/template/coding-task-manager/lib/standup-search-adapter.js +16 -2
- package/template/coding-task-manager/lib/state-sync/client-ledger.js +12 -0
- package/template/coding-task-manager/lib/state-sync/frame-emitter.js +319 -100
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +4 -1
- package/template/coding-task-manager/lib/storage/delegate-pref-mirror-store.js +32 -9
- package/template/coding-task-manager/lib/structured-session-boot-sweep.js +235 -0
- package/template/coding-task-manager/lib/submission-ack.js +90 -2
- package/template/coding-task-manager/lib/systemd-scope.js +115 -0
- package/template/coding-task-manager/lib/telemetry-receiver.js +39 -0
- package/template/coding-task-manager/lib/terminal-attach-geometry.js +985 -0
- package/template/coding-task-manager/lib/terminal-bootstrap.js +30 -0
- package/template/coding-task-manager/lib/terminal-draft-operation.js +357 -0
- package/template/coding-task-manager/lib/terminal-input-admission.js +17 -1
- package/template/coding-task-manager/lib/terminal-input-prepared.js +563 -0
- package/template/coding-task-manager/lib/transcript-cache-temps.js +171 -0
- package/template/coding-task-manager/lib/transcript-frame-cache.js +8 -3
- package/template/coding-task-manager/lib/transcript-source.js +36 -4
- package/template/coding-task-manager/lib/transcript-store.js +9 -0
- package/template/coding-task-manager/lib/typing-interaction-trace.js +106 -3
- package/template/coding-task-manager/lib/usage-ledger/backfill.js +40 -5
- package/template/coding-task-manager/lib/usage-ledger/client.js +4 -1
- package/template/coding-task-manager/lib/usage-ledger/dsh-parse.js +152 -0
- package/template/coding-task-manager/lib/usage-ledger/dsh-read.js +73 -0
- package/template/coding-task-manager/lib/usage-ledger/ingest.js +34 -6
- package/template/coding-task-manager/lib/usage-ledger/live.js +35 -8
- package/template/coding-task-manager/lib/usage-ledger/read.js +29 -20
- package/template/coding-task-manager/lib/usage-ledger/schema.js +61 -1
- package/template/coding-task-manager/lib/usage-ledger/task-coordinator.js +4 -2
- package/template/coding-task-manager/lib/wake-skip-reasons.js +1 -0
- package/template/coding-task-manager/lib/walle/turn.js +1 -1
- package/template/coding-task-manager/lib/walle-history-serve.js +838 -0
- package/template/coding-task-manager/lib/walle-kill-authority.js +2 -2
- package/template/coding-task-manager/lib/walle-log-rotation.js +164 -1
- package/template/coding-task-manager/lib/walle-mcp-auto-config.js +56 -2
- package/template/coding-task-manager/lib/walle-row-history.js +495 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +33 -14
- package/template/coding-task-manager/lib/watch-worker-client.js +203 -0
- package/template/coding-task-manager/lib/worker-terminal-output.js +5 -2
- package/template/coding-task-manager/lib/ws/hub-bridge.js +35 -0
- package/template/coding-task-manager/lib/ws/lifecycle.js +6 -11
- package/template/coding-task-manager/lib/ws/misc.js +1 -1
- package/template/coding-task-manager/lib/ws/state-sync.js +106 -4
- package/template/coding-task-manager/lib/ws/terminal-attach.js +91 -0
- package/template/coding-task-manager/oauth-proxy.js +112 -115
- package/template/coding-task-manager/package-lock.json +10 -94
- package/template/coding-task-manager/package.json +4 -3
- package/template/coding-task-manager/protocol/message-table.json +10 -0
- package/template/coding-task-manager/protocol/messages.js +10 -0
- package/template/coding-task-manager/protocol/ws-schema.json +20 -0
- package/template/coding-task-manager/protocol/ws-schema.md +2 -0
- package/template/coding-task-manager/public/css/app.css +170 -0
- package/template/coding-task-manager/public/css/walle-session.css +4 -0
- package/template/coding-task-manager/public/index.html +473 -243
- package/template/coding-task-manager/public/js/agent-command.js +86 -0
- package/template/coding-task-manager/public/js/app/backups-panel.js +111 -5
- package/template/coding-task-manager/public/js/app/coding-agent-upgrade.js +103 -4
- package/template/coding-task-manager/public/js/app/machines-page.js +1328 -8
- package/template/coding-task-manager/public/js/app/models-tab.js +113 -38
- package/template/coding-task-manager/public/js/app/restart-banner.js +53 -0
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +184 -2
- package/template/coding-task-manager/public/js/background-work.js +196 -27
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +138 -10
- package/template/coding-task-manager/public/js/core/active-session-groups.js +179 -0
- package/template/coding-task-manager/public/js/core/pending-create.js +238 -0
- package/template/coding-task-manager/public/js/core/recent-machine-source.js +228 -0
- package/template/coding-task-manager/public/js/core/session-commands.js +180 -14
- package/template/coding-task-manager/public/js/dashboard-client-function-order.json +8 -0
- package/template/coding-task-manager/public/js/document-review-links.js +9 -1
- package/template/coding-task-manager/public/js/file-resolution-client.js +52 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +22 -2
- package/template/coding-task-manager/public/js/machine-pool-shared.js +558 -3
- package/template/coding-task-manager/public/js/message-renderer.js +4 -3
- package/template/coding-task-manager/public/js/model-picker.js +3 -1
- package/template/coding-task-manager/public/js/native-subagent-review.js +15 -2
- package/template/coding-task-manager/public/js/new-session-agent-grid.js +346 -0
- package/template/coding-task-manager/public/js/pasted-content.js +236 -0
- package/template/coding-task-manager/public/js/pe-private-content-lifetime.js +39 -7
- package/template/coding-task-manager/public/js/private-model-lifetime.js +6 -2
- package/template/coding-task-manager/public/js/prompts.js +11 -10
- package/template/coding-task-manager/public/js/protocol.js +10 -0
- package/template/coding-task-manager/public/js/restart-banner-policy.js +29 -1
- package/template/coding-task-manager/public/js/session-model-picker.js +447 -57
- package/template/coding-task-manager/public/js/session-search-utils.js +18 -2
- package/template/coding-task-manager/public/js/session-usage-view.js +2 -1
- package/template/coding-task-manager/public/js/session-workspace-tracking.js +51 -1
- package/template/coding-task-manager/public/js/state-sync-client.js +10 -1
- package/template/coding-task-manager/public/js/stream-view.js +6 -5
- package/template/coding-task-manager/public/js/terminal/conv-only-session.js +287 -0
- package/template/coding-task-manager/public/js/terminal/runtime-09.js +2 -0
- package/template/coding-task-manager/public/js/terminal/runtime-10.js +5 -5
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +8 -1
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +1 -1
- package/template/coding-task-manager/public/js/terminal-attachment-draft.js +67 -13
- package/template/coding-task-manager/public/js/terminal-image-orchestration.js +52 -6
- package/template/coding-task-manager/public/js/terminal-wheel.js +23 -3
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +4 -4
- package/template/coding-task-manager/public/js/walle.js +6 -0
- package/template/coding-task-manager/public/js/ws/live-dispatch.js +10 -0
- package/template/coding-task-manager/public/m/app.css +140 -0
- package/template/coding-task-manager/public/m/app.js +507 -68
- package/template/coding-task-manager/public/m/index.html +17 -0
- package/template/coding-task-manager/public/m/machines.js +838 -4
- package/template/coding-task-manager/public/m/private-api.js +31 -1
- package/template/coding-task-manager/public/usage.html +1 -0
- package/template/coding-task-manager/scripts/dev-route-fixture/synthetic-route-upstream.js +104 -0
- package/template/coding-task-manager/scripts/dev-route-fixture.js +339 -0
- package/template/coding-task-manager/scripts/opencode-lead-route-probe.js +195 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe/fake-anthropic.js +168 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe/probe-plugin/server.js +95 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe.js +673 -0
- package/template/coding-task-manager/server.js +1950 -11679
- package/template/coding-task-manager/session-integrity.js +64 -4
- package/template/coding-task-manager/workers/db-owner-worker.js +19 -2
- package/template/coding-task-manager/workers/online-backup-worker.js +1 -0
- package/template/coding-task-manager/workers/read-pool-model-collector.js +51 -3
- package/template/coding-task-manager/workers/read-pool-worker.js +76 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +6 -6
- package/template/coding-task-manager/workers/session-host-process.js +5 -5
- package/template/coding-task-manager/workers/watch-worker.js +105 -0
- package/template/coding-task-manager/workers/worktree-worker.js +168 -33
- package/template/ctm-relay/lib/protocol.js +14 -1
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/shared/backup-retention.js +82 -0
- package/template/shared/conversation-admission.js +2 -0
- package/template/shared/conversation-provenance.js +3 -7
- package/template/shared/conversation-storage-v2-contract.js +5 -0
- package/template/shared/linked-worktree.js +51 -0
- package/template/shared/macos-fda-target.js +57 -0
- package/template/shared/orphan-parents.js +55 -0
- package/template/shared/release-schema.json +2 -2
- package/template/shared/storage/contract.js +3 -0
- package/template/wall-e/adapters/imessage.js +12 -0
- package/template/wall-e/agent.js +71 -4
- package/template/wall-e/api-walle.js +21 -1
- package/template/wall-e/bin/train-gemma-e4b-tooluse.js +2 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +5 -5
- package/template/wall-e/brain/brain-join.js +859 -0
- package/template/wall-e/brain/brain-sync-membership.js +20 -0
- package/template/wall-e/brain/brain-sync-store.js +131 -77
- package/template/wall-e/brain/brain-sync-v2-schema.js +203 -0
- package/template/wall-e/brain/brain-sync-v2.js +578 -0
- package/template/wall-e/brain/delegate-model-prefs-store.js +13 -4
- package/template/wall-e/brain/deterministic-id.js +51 -0
- package/template/wall-e/brain/memories.js +2 -2
- package/template/wall-e/brain/migrations.js +40 -6
- package/template/wall-e/brain/model-identity-migration.js +1 -1
- package/template/wall-e/brain/owner-call-whitelist.js +23 -7
- package/template/wall-e/brain/schema.js +45 -85
- package/template/wall-e/brain.js +171 -35
- package/template/wall-e/chat.js +3 -3
- package/template/wall-e/coding/agent-shell-env.js +7 -2
- package/template/wall-e/coding/prompt-bundle.js +66 -21
- package/template/wall-e/config/main-loop-exemptions.json +2 -2
- package/template/wall-e/http/admin-api.js +37 -0
- package/template/wall-e/http/gws-api.js +4 -0
- package/template/wall-e/http/helper-rules-api.js +7 -1
- package/template/wall-e/http/model-admin.js +8 -1
- package/template/wall-e/http/model-delegate-pref-admin.js +3 -3
- package/template/wall-e/http/model-proxy-providers.js +174 -1
- package/template/wall-e/http/model-route-health.js +157 -0
- package/template/wall-e/http/sync-api.js +278 -464
- package/template/wall-e/jobs/job-runner.js +28 -1
- package/template/wall-e/lib/brain-owner-op-priority.js +9 -1
- package/template/wall-e/lib/ctm-data-dir.js +26 -0
- package/template/wall-e/lib/derivation-home.js +147 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +50 -9
- package/template/wall-e/lib/helper-rules/grade.js +51 -8
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +38 -5
- package/template/wall-e/lib/helper-rules/store.js +4 -2
- package/template/wall-e/lib/landing-mcp-tools.js +170 -0
- package/template/wall-e/lib/mcp-client-config.js +133 -14
- package/template/wall-e/lib/mcp-gateway-migrate.js +28 -64
- package/template/wall-e/lib/mcp-integration.js +58 -13
- package/template/wall-e/lib/parent-death.js +7 -1
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -4
- package/template/wall-e/llm/delegate-lead-prefs.js +16 -1
- package/template/wall-e/llm/delegate-vendor-default.js +12 -5
- package/template/wall-e/llm/model-roles.js +1 -1
- package/template/wall-e/llm/native-delegate-selection.js +56 -8
- package/template/wall-e/llm/worker-delegate-args.js +72 -7
- package/template/wall-e/llm/worker-mcp-routing.js +66 -17
- package/template/wall-e/loops/brain-custom-writes.js +19 -0
- package/template/wall-e/loops/ingest.js +17 -1
- package/template/wall-e/loops/think.js +19 -4
- package/template/wall-e/mcp-contract.js +222 -6
- package/template/wall-e/mcp-protocol-contract.js +40 -5
- package/template/wall-e/mcp-server.js +128 -29
- package/template/wall-e/mcp-worker-schemas.js +5 -5
- package/template/wall-e/memory/ctm-context-client.js +85 -0
- package/template/wall-e/memory/ctm-session-context.js +9 -3
- package/template/wall-e/memory/hub-bridge-client.js +388 -0
- package/template/wall-e/memory/replica-origin.js +56 -0
- package/template/wall-e/memory/session-pool.js +135 -0
- package/template/wall-e/runtime/live-capabilities.js +8 -3
- package/template/wall-e/server.js +4 -2
- package/template/wall-e/shared/release-schema.json +2 -2
- package/template/wall-e/shared/sqlite-file-set.js +39 -0
- package/template/wall-e/shared/storage/contract.js +3 -0
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +7 -1
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +4 -4
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +6 -6
- package/template/wall-e/skills/_templates/fleet-sync/VERSION +1 -0
- package/template/wall-e/skills/_templates/fleet-sync/released-sha256.json +16 -0
- package/template/wall-e/skills/_templates/fleet-sync/templates/claude/SKILL.md +64 -0
- package/template/wall-e/skills/_templates/fleet-sync/templates/codex/SKILL.md +64 -0
- package/template/wall-e/tools/chrome-automation.js +6 -0
- package/template/wall-e/training/setup-cuda-train-env.sh +2 -2
- package/template/wall-e/workers/brain-owner-worker.js +18 -4
- package/template/wall-e/workers/mcp-gateway-process.js +5 -5
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// WP-0 (docs/local-landing-queue-multi-session-integration-2026-10-26.html §5 D-3/D-5/D-11,
|
|
3
|
+
// §6.2, §8 WP-0): the git plumbing the landing queue is built on. Zero runtime deps.
|
|
4
|
+
//
|
|
5
|
+
// Three hard rules this module exists to enforce:
|
|
6
|
+
//
|
|
7
|
+
// 1. Every git child runs with `--no-optional-locks` (D-11 / I-7): a `git status`-style
|
|
8
|
+
// probe must never leave `index.lock` in a session worktree.
|
|
9
|
+
// 2. Every git child env is `process.env` MINUS the §4 GIT_* list (same seven names as
|
|
10
|
+
// bin/git-test-env.js; the two lists are asserted equal by
|
|
11
|
+
// tests/landing-git-primitives.test.js). I-8 is the incident: a leaked GIT_DIR made a
|
|
12
|
+
// gate/test process operate on the wrong repository and wipe real refs.
|
|
13
|
+
// 3. Nothing here writes into a session worktree. The train commit is built from
|
|
14
|
+
// `merge-tree`/`commit-tree` objects only; the one exception is `snapshotCommit`, which
|
|
15
|
+
// uses a TEMP INDEX outside the worktree so the real index (and its lock) is untouched.
|
|
16
|
+
//
|
|
17
|
+
// This file is the lowest-level module of lib/landing/ (no local requires), so it also hosts
|
|
18
|
+
// the shared typed-error helper `landingError` used by state.js/lease.js/config.js — that
|
|
19
|
+
// keeps the directory to the four files WP-0 owns instead of adding a fifth just for 5 lines.
|
|
20
|
+
//
|
|
21
|
+
// Error contract: every throw is an Error with `.code` set to a typed string
|
|
22
|
+
// (`git_failed`, `cas_lost`, `target_dirty`, ...), per §6.2's exit-code/typed-error contract.
|
|
23
|
+
|
|
24
|
+
const { spawnSync } = require('child_process');
|
|
25
|
+
const fs = require('fs');
|
|
26
|
+
const os = require('os');
|
|
27
|
+
const crypto = require('crypto');
|
|
28
|
+
const path = require('path');
|
|
29
|
+
|
|
30
|
+
const MAX_BUFFER = 64 * 1024 * 1024;
|
|
31
|
+
|
|
32
|
+
// §4 / bin/git-test-env.js: GIT_CONTEXT_ENV_KEYS. Copied (not required: lib/ must not depend on
|
|
33
|
+
// bin/, whose files are pinned by bin/test-broker-protocol.manifest.json, I-6); a unit test
|
|
34
|
+
// asserts the two arrays stay equal so drift is caught.
|
|
35
|
+
const SCRUBBED_ENV = Object.freeze([
|
|
36
|
+
'GIT_DIR',
|
|
37
|
+
'GIT_WORK_TREE',
|
|
38
|
+
'GIT_INDEX_FILE',
|
|
39
|
+
'GIT_PREFIX',
|
|
40
|
+
'GIT_OBJECT_DIRECTORY',
|
|
41
|
+
'GIT_COMMON_DIR',
|
|
42
|
+
'GIT_ALTERNATE_OBJECT_DIRECTORIES',
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const OID_RE = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
|
46
|
+
|
|
47
|
+
// Git's own refusal wording when a fast-forward would clobber local state (§1.6 V-4).
|
|
48
|
+
const OVERWRITE_HEADERS = [
|
|
49
|
+
'error: Your local changes to the following files would be overwritten by merge:',
|
|
50
|
+
'error: The following untracked working tree files would be overwritten by merge:',
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
function landingError(code, message, extra) {
|
|
54
|
+
const err = new Error(message);
|
|
55
|
+
err.code = code;
|
|
56
|
+
if (extra) Object.assign(err, extra);
|
|
57
|
+
return err;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// process.env minus the §4 GIT_* list, plus `extra`. `extra` is applied AFTER the scrub, which
|
|
61
|
+
// is what lets snapshotCommit pass GIT_INDEX_FILE=<tmp> on purpose.
|
|
62
|
+
function childEnv(extra) {
|
|
63
|
+
const env = { ...process.env };
|
|
64
|
+
for (const key of SCRUBBED_ENV) delete env[key];
|
|
65
|
+
if (extra) Object.assign(env, extra);
|
|
66
|
+
return env;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Raw spawn: never throws on a non-zero exit (the wrappers below need to inspect it).
|
|
70
|
+
function runGitRaw(cwd, args, opts = {}) {
|
|
71
|
+
const res = spawnSync('git', ['--no-optional-locks', ...args], {
|
|
72
|
+
cwd,
|
|
73
|
+
env: childEnv(opts.env),
|
|
74
|
+
encoding: 'utf8',
|
|
75
|
+
maxBuffer: opts.maxBuffer || MAX_BUFFER,
|
|
76
|
+
input: opts.input === undefined ? undefined : opts.input,
|
|
77
|
+
});
|
|
78
|
+
if (res.error) {
|
|
79
|
+
throw landingError('git_failed', `git ${args.join(' ')}: ${res.error.message}`, { args, cwd, cause: res.error });
|
|
80
|
+
}
|
|
81
|
+
return { status: res.status, stdout: res.stdout || '', stderr: res.stderr || '' };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function gitFailed(cwd, args, res) {
|
|
85
|
+
const detail = String(res.stderr || res.stdout || '').trim();
|
|
86
|
+
return landingError('git_failed', `git ${args.join(' ')} exited ${res.status}${detail ? `: ${detail}` : ''}`, {
|
|
87
|
+
args, cwd, status: res.status, stderr: res.stderr, stdout: res.stdout,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Sync `git` that throws `git_failed` on any non-zero exit and returns stdout.
|
|
92
|
+
function git(cwd, args, opts = {}) {
|
|
93
|
+
const res = runGitRaw(cwd, args, opts);
|
|
94
|
+
if (res.status !== 0) throw gitFailed(cwd, args, res);
|
|
95
|
+
return res.stdout;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// --- read-only helpers ---------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
function revParseOrNull(cwd, rev, opts = {}) {
|
|
101
|
+
const res = runGitRaw(cwd, ['rev-parse', '--verify', '--quiet', rev], opts);
|
|
102
|
+
if (res.status !== 0) return null;
|
|
103
|
+
const value = res.stdout.trim();
|
|
104
|
+
return value || null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function revParse(cwd, rev, opts = {}) {
|
|
108
|
+
const value = revParseOrNull(cwd, rev, opts);
|
|
109
|
+
if (value === null) {
|
|
110
|
+
throw landingError('git_failed', `cannot resolve revision ${JSON.stringify(rev)} in ${cwd}`, { rev, cwd });
|
|
111
|
+
}
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Absolute path of the repository's common git dir (shared by every worktree of the repo).
|
|
116
|
+
// Memoized per resolved cwd: it cannot change while this process runs, and every state path
|
|
117
|
+
// (state.landingDir) and every radar cache read goes through it -- un-memoized, a plain
|
|
118
|
+
// `land status` on a 413-worktree repo spent 46 s of its 128 s spawning this one rev-parse.
|
|
119
|
+
// Only successes are kept, so a cwd that is not a repo yet still fails every time.
|
|
120
|
+
const COMMON_DIR_CACHE = new Map();
|
|
121
|
+
function commonDir(cwd) {
|
|
122
|
+
const key = path.resolve(cwd);
|
|
123
|
+
let value = COMMON_DIR_CACHE.get(key);
|
|
124
|
+
if (value === undefined) {
|
|
125
|
+
value = git(cwd, ['rev-parse', '--path-format=absolute', '--git-common-dir']).trim();
|
|
126
|
+
COMMON_DIR_CACHE.set(key, value);
|
|
127
|
+
}
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Absolute path of the git dir for THIS worktree (`.git/worktrees/<n>` for a linked one).
|
|
132
|
+
function gitDir(cwd) {
|
|
133
|
+
return git(cwd, ['rev-parse', '--path-format=absolute', '--git-dir']).trim();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function isAncestor(cwd, ancestor, descendant, opts = {}) {
|
|
137
|
+
const res = runGitRaw(cwd, ['merge-base', '--is-ancestor', ancestor, descendant], opts);
|
|
138
|
+
if (res.status === 0) return true;
|
|
139
|
+
if (res.status === 1) return false;
|
|
140
|
+
throw gitFailed(cwd, ['merge-base', '--is-ancestor', ancestor, descendant], res);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function isGitRepo(cwd) {
|
|
144
|
+
const res = runGitRaw(cwd, ['rev-parse', '--git-dir']);
|
|
145
|
+
return res.status === 0;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Absolute, symlink-resolved path of the worktree root (the directory the queue's `.ctm.json`
|
|
149
|
+
// may live in — a worktree's own root, not the common dir). Outside a repository there is no
|
|
150
|
+
// toplevel, and that is a typed refusal rather than a silent fallback (§6.1).
|
|
151
|
+
function toplevel(cwd) {
|
|
152
|
+
const res = runGitRaw(cwd, ['rev-parse', '--show-toplevel']);
|
|
153
|
+
if (res.status !== 0) {
|
|
154
|
+
throw landingError('not_a_repo', `not inside a git repository: ${cwd}`, {
|
|
155
|
+
cwd, status: res.status, stderr: String(res.stderr || '').trim(),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const top = res.stdout.trim();
|
|
159
|
+
if (!top) {
|
|
160
|
+
throw landingError('not_a_repo', `git reported no toplevel for ${cwd}`, { cwd, status: res.status });
|
|
161
|
+
}
|
|
162
|
+
return fs.realpathSync(top);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// --- D-3: worktree-free train commit -------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
// `git merge-tree --write-tree --name-only <base> <tip>` (observed §1.6 V-1/V-2).
|
|
168
|
+
// exit 0 -> { tree, conflicts: [] }
|
|
169
|
+
// exit 1 -> { tree, conflicts: [paths...] } (first line is the tree oid, then the conflicted
|
|
170
|
+
// paths up to the first blank line, then git's informational block)
|
|
171
|
+
// other -> throw git_failed
|
|
172
|
+
// A merge driver is free to print to stdout, so the tree oid is located by shape rather than by
|
|
173
|
+
// assuming it is line 1.
|
|
174
|
+
function mergeTree(cwd, base, tip, opts = {}) {
|
|
175
|
+
const args = ['merge-tree', '--write-tree', '--name-only', base, tip];
|
|
176
|
+
const res = runGitRaw(cwd, args, opts);
|
|
177
|
+
if (res.status !== 0 && res.status !== 1) throw gitFailed(cwd, args, res);
|
|
178
|
+
const lines = res.stdout.split('\n').map((line) => line.replace(/\r$/, ''));
|
|
179
|
+
let index = 0;
|
|
180
|
+
while (index < lines.length && !OID_RE.test(lines[index].trim())) index += 1;
|
|
181
|
+
if (index >= lines.length) {
|
|
182
|
+
throw landingError('git_failed', `git merge-tree produced no tree oid for ${base}..${tip}`, {
|
|
183
|
+
base, tip, cwd, status: res.status, stdout: res.stdout,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
const tree = lines[index].trim();
|
|
187
|
+
const conflicts = [];
|
|
188
|
+
for (let i = index + 1; i < lines.length; i += 1) {
|
|
189
|
+
if (lines[i] === '') break;
|
|
190
|
+
conflicts.push(lines[i]);
|
|
191
|
+
}
|
|
192
|
+
return { tree, conflicts };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function commitTree(cwd, tree, parents = [], message = '', opts = {}) {
|
|
196
|
+
const args = ['commit-tree', tree];
|
|
197
|
+
for (const parent of parents) args.push('-p', parent);
|
|
198
|
+
args.push('-m', message);
|
|
199
|
+
return git(cwd, args, opts).trim();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// --- D-5: landing the train ----------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
// `git update-ref <ref> <new> <old>` is a compare-and-swap (observed §1.6 V-3). On failure the
|
|
205
|
+
// ref is re-read: only a genuinely different current value is `cas_lost`; anything else is a
|
|
206
|
+
// real git failure.
|
|
207
|
+
function casUpdateRef(cwd, ref, newSha, oldSha, opts = {}) {
|
|
208
|
+
const args = ['update-ref', ref, newSha, oldSha];
|
|
209
|
+
const res = runGitRaw(cwd, args, opts);
|
|
210
|
+
if (res.status === 0) return true;
|
|
211
|
+
const current = revParseOrNull(cwd, ref);
|
|
212
|
+
if (current !== oldSha) {
|
|
213
|
+
throw landingError('cas_lost', `ref ${ref} is at ${current || '(absent)'}, expected ${oldSha}`, {
|
|
214
|
+
ref, expected: oldSha, current, cwd, stderr: res.stderr,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
throw gitFailed(cwd, args, res);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Paths git lists under an "…would be overwritten" header (tab-indented, one per line).
|
|
221
|
+
function parseOverwritePaths(stderr) {
|
|
222
|
+
const lines = String(stderr || '').split('\n');
|
|
223
|
+
const paths = [];
|
|
224
|
+
let collecting = false;
|
|
225
|
+
for (const line of lines) {
|
|
226
|
+
if (!collecting) {
|
|
227
|
+
if (OVERWRITE_HEADERS.includes(line.trim())) collecting = true;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (!line.startsWith('\t')) break;
|
|
231
|
+
let rel = line.slice(1).trim();
|
|
232
|
+
if (rel.startsWith('"') && rel.endsWith('"') && rel.length > 1) rel = rel.slice(1, -1);
|
|
233
|
+
if (rel) paths.push(rel);
|
|
234
|
+
}
|
|
235
|
+
return paths;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// `git -C <worktree> merge --ff-only <sha>` (observed §1.6 V-4): unrelated dirt is tolerated,
|
|
239
|
+
// an overlapping dirty file refuses WITHOUT modifying the worktree -> `target_dirty` + .paths.
|
|
240
|
+
function ffCheckedOut(worktree, sha, opts = {}) {
|
|
241
|
+
const args = ['merge', '--ff-only', sha];
|
|
242
|
+
const res = runGitRaw(worktree, args, opts);
|
|
243
|
+
if (res.status === 0) return { sha: revParseOrNull(worktree, 'HEAD'), stdout: res.stdout };
|
|
244
|
+
const paths = parseOverwritePaths(res.stderr);
|
|
245
|
+
if (paths.length) {
|
|
246
|
+
throw landingError('target_dirty', `fast-forward into ${worktree} would overwrite local changes: ${paths.join(', ')}`, {
|
|
247
|
+
paths, sha, worktree, stderr: res.stderr,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
throw gitFailed(worktree, args, res);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// WP-2 (D-7): the radar snapshots a dirty worktree on EVERY sweep, so the snapshot commit must be a
|
|
254
|
+
// pure function of (HEAD, content) — otherwise the pair cache key (`<snapshotSha>-<otherSha>.json`)
|
|
255
|
+
// would change on every run and never hit. With `deterministic: true` the identity and both dates are
|
|
256
|
+
// fixed (the date is HEAD's own committer date), so the commit object bytes — and therefore the sha —
|
|
257
|
+
// depend only on the tree, the parent and this message.
|
|
258
|
+
const SNAPSHOT_MESSAGE = 'land radar snapshot';
|
|
259
|
+
const SNAPSHOT_IDENTITY = Object.freeze({ name: 'ctm-landing-radar', email: 'radar@example.invalid' });
|
|
260
|
+
|
|
261
|
+
// Fixed author/committer identity + HEAD's committer date, as GIT_* env for commit-tree (which
|
|
262
|
+
// otherwise requires a configured identity it must not depend on).
|
|
263
|
+
function snapshotIdentityEnv(worktree, head) {
|
|
264
|
+
const env = {
|
|
265
|
+
GIT_AUTHOR_NAME: SNAPSHOT_IDENTITY.name,
|
|
266
|
+
GIT_AUTHOR_EMAIL: SNAPSHOT_IDENTITY.email,
|
|
267
|
+
GIT_COMMITTER_NAME: SNAPSHOT_IDENTITY.name,
|
|
268
|
+
GIT_COMMITTER_EMAIL: SNAPSHOT_IDENTITY.email,
|
|
269
|
+
};
|
|
270
|
+
const res = runGitRaw(worktree, ['show', '-s', '--format=%cI', head]);
|
|
271
|
+
const date = res.status === 0 ? res.stdout.trim() : '';
|
|
272
|
+
// No date means the commit could not be read, which cannot happen for a resolved HEAD; leaving the
|
|
273
|
+
// dates unset then makes the commit non-deterministic rather than silently wrong-dated.
|
|
274
|
+
if (date) {
|
|
275
|
+
env.GIT_AUTHOR_DATE = date;
|
|
276
|
+
env.GIT_COMMITTER_DATE = date;
|
|
277
|
+
}
|
|
278
|
+
return env;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Snapshot commit of a worktree's CURRENT state (tracked edits + untracked-not-ignored files),
|
|
282
|
+
// built through a temp index so the real index is never touched and no `index.lock` appears in
|
|
283
|
+
// the worktree (observed §1.6 V-5: 0.186 s on a 10k-file repo).
|
|
284
|
+
//
|
|
285
|
+
// `opts.deterministic` (WP-2) additionally pins the identity, the dates and the message, so the same
|
|
286
|
+
// HEAD and the same content always produce the same sha. Absent, behaviour is unchanged.
|
|
287
|
+
function snapshotCommit(worktree, opts = {}) {
|
|
288
|
+
const head = revParseOrNull(worktree, 'HEAD');
|
|
289
|
+
if (!head) {
|
|
290
|
+
throw landingError('git_failed', `snapshotCommit: ${worktree} has no HEAD commit`, { cwd: worktree });
|
|
291
|
+
}
|
|
292
|
+
const tmpIndex = path.join(os.tmpdir(), `ctm-landing-index-${process.pid}-${crypto.randomBytes(6).toString('hex')}`);
|
|
293
|
+
const env = { GIT_INDEX_FILE: tmpIndex };
|
|
294
|
+
if (opts.deterministic) Object.assign(env, snapshotIdentityEnv(worktree, head));
|
|
295
|
+
try {
|
|
296
|
+
const realIndex = git(worktree, ['rev-parse', '--path-format=absolute', '--git-path', 'index']).trim();
|
|
297
|
+
let seeded = false;
|
|
298
|
+
try {
|
|
299
|
+
fs.copyFileSync(realIndex, tmpIndex);
|
|
300
|
+
seeded = true;
|
|
301
|
+
} catch (error) {
|
|
302
|
+
/* expected: no index file yet (fresh/odd worktree) -> seed the temp index from HEAD instead */
|
|
303
|
+
}
|
|
304
|
+
if (!seeded) git(worktree, ['read-tree', head], { env });
|
|
305
|
+
git(worktree, ['add', '-A'], { env });
|
|
306
|
+
const tree = git(worktree, ['write-tree'], { env }).trim();
|
|
307
|
+
const message = opts.message || (opts.deterministic ? SNAPSHOT_MESSAGE : `snapshot ${new Date().toISOString()}`);
|
|
308
|
+
return commitTree(worktree, tree, [head], message, { env });
|
|
309
|
+
} finally {
|
|
310
|
+
for (const file of [tmpIndex, `${tmpIndex}.lock`]) {
|
|
311
|
+
try {
|
|
312
|
+
fs.rmSync(file, { force: true });
|
|
313
|
+
} catch (error) {
|
|
314
|
+
/* expected: temp index cleanup is best-effort; a leftover file under os.tmpdir() never
|
|
315
|
+
affects the repo (the real index and its lock are untouched by construction) */
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
module.exports = {
|
|
322
|
+
SCRUBBED_ENV,
|
|
323
|
+
MAX_BUFFER,
|
|
324
|
+
SNAPSHOT_MESSAGE,
|
|
325
|
+
SNAPSHOT_IDENTITY,
|
|
326
|
+
landingError,
|
|
327
|
+
childEnv,
|
|
328
|
+
runGitRaw,
|
|
329
|
+
git,
|
|
330
|
+
gitFailed,
|
|
331
|
+
revParse,
|
|
332
|
+
revParseOrNull,
|
|
333
|
+
commonDir,
|
|
334
|
+
gitDir,
|
|
335
|
+
isAncestor,
|
|
336
|
+
isGitRepo,
|
|
337
|
+
toplevel,
|
|
338
|
+
mergeTree,
|
|
339
|
+
commitTree,
|
|
340
|
+
casUpdateRef,
|
|
341
|
+
ffCheckedOut,
|
|
342
|
+
parseOverwritePaths,
|
|
343
|
+
snapshotCommit,
|
|
344
|
+
};
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// WP-0 (docs/local-landing-queue-multi-session-integration-2026-10-26.html §5 D-2, §4/§9.1, §8
|
|
3
|
+
// WP-0): the single per-repository runner lease — one writer, no daemon.
|
|
4
|
+
//
|
|
5
|
+
// Ported (copied with attribution, never imported — bin/ files are pinned by
|
|
6
|
+
// bin/test-broker-protocol.manifest.json, I-6) from bin/test-slot-broker.js:
|
|
7
|
+
// _claimDir (:600-620) mkdtemp stage + renameSync into place
|
|
8
|
+
// _verifiedRemove (:388-440) re-read the stamp, require record equality, rename to a private
|
|
9
|
+
// tombstone, then remove the tombstone (never rm -rf a live claim)
|
|
10
|
+
// _reapIfDead (:530-547) kill(pid, 0) -> ESRCH, plus a lease-age + registry check; an
|
|
11
|
+
// unreadable stamp is never reaped
|
|
12
|
+
//
|
|
13
|
+
// Layout: `landing/runner/lease/owner.json` (the DIRECTORY is what gets renamed). Use
|
|
14
|
+
// leaseDir()/leasePath() — nothing else should hardcode these paths.
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const os = require('os');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const crypto = require('crypto');
|
|
20
|
+
const { spawnSync } = require('child_process');
|
|
21
|
+
const { landingError } = require('./git');
|
|
22
|
+
const { readJsonSafe, writeJsonAtomic } = require('./state');
|
|
23
|
+
|
|
24
|
+
// D-2: heartbeat freshness window. A constant on purpose — the queue has no flags (D-1).
|
|
25
|
+
const LAND_HEARTBEAT_MS = 10000;
|
|
26
|
+
// D-2 pid-reuse clause: a stale lease whose pid is alive is only dead when that pid is not a
|
|
27
|
+
// live `land` process. Matches `land`, `land.js`, `node .../bin/land.js` — and nothing else.
|
|
28
|
+
const LAND_PROCESS_RE = /\bland(?:\.js)?\b/;
|
|
29
|
+
|
|
30
|
+
const RUNNER_DIRNAME = 'runner';
|
|
31
|
+
const LEASE_DIRNAME = 'lease';
|
|
32
|
+
const OWNER_FILENAME = 'owner.json';
|
|
33
|
+
|
|
34
|
+
function runnerDir(root) {
|
|
35
|
+
return path.join(root, RUNNER_DIRNAME);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function leaseDir(root) {
|
|
39
|
+
return path.join(runnerDir(root), LEASE_DIRNAME);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function leasePath(root) {
|
|
43
|
+
return path.join(leaseDir(root), OWNER_FILENAME);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function isLeaseRecord(record) {
|
|
47
|
+
return Boolean(record) && typeof record === 'object' && typeof record.pid === 'number' && typeof record.token === 'string';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// D-10: the runner advertises what it can do. A runner spawned from an older `land.js` has no
|
|
51
|
+
// `caps`, which is how `land cancel --force` (and, in WP-3, `urgent`) tells "this runner will
|
|
52
|
+
// honour a stop request" from "this runner will overwrite the state I am about to write".
|
|
53
|
+
function hasCap(record, cap) {
|
|
54
|
+
return Boolean(record) && Array.isArray(record.caps) && record.caps.includes(cap);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isProcessAlive(pid, kill) {
|
|
58
|
+
try {
|
|
59
|
+
kill(pid, 0);
|
|
60
|
+
return true;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
// ESRCH = gone; EPERM = exists but not ours, i.e. alive.
|
|
63
|
+
return !(error && error.code === 'ESRCH');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// `opts.now` is a number or a function, so a caller can freeze or advance the clock.
|
|
68
|
+
function nowValue(opts = {}) {
|
|
69
|
+
const now = opts.now;
|
|
70
|
+
if (typeof now === 'function') return now();
|
|
71
|
+
if (typeof now === 'number') return now;
|
|
72
|
+
return Date.now();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isStale(record, opts = {}) {
|
|
76
|
+
if (!isLeaseRecord(record)) return false;
|
|
77
|
+
const heartbeat = Date.parse(record.heartbeatAt);
|
|
78
|
+
if (!Number.isFinite(heartbeat)) return false;
|
|
79
|
+
return nowValue(opts) - heartbeat > 3 * LAND_HEARTBEAT_MS;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// D-2 pid-reuse probe: the command line of a live pid, or null when it cannot be read (the
|
|
83
|
+
// process exited between the liveness check and this call, ps is missing, ...). null is
|
|
84
|
+
// "unknown", which is never treated as dead.
|
|
85
|
+
function processCommand(pid) {
|
|
86
|
+
const res = spawnSync('ps', ['-o', 'command=', '-p', String(pid)], { encoding: 'utf8' });
|
|
87
|
+
if (!res || res.error || res.status !== 0) return null;
|
|
88
|
+
const command = String(res.stdout || '').trim();
|
|
89
|
+
return command === '' ? null : command;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// D-2 liveness. Dead iff `kill(pid, 0)` -> ESRCH, OR the heartbeat is older than
|
|
93
|
+
// 3 x LAND_HEARTBEAT_MS AND the pid is not a live `land` process (a pid the OS reused after the
|
|
94
|
+
// runner died, which is exactly what the ESRCH test alone cannot see). A live `land` process is
|
|
95
|
+
// never dead, however old its heartbeat. A missing/unreadable stamp is never dead: we cannot
|
|
96
|
+
// tell a dead owner from one we merely failed to read.
|
|
97
|
+
function isDead(record, opts = {}) {
|
|
98
|
+
if (!isLeaseRecord(record)) return false;
|
|
99
|
+
const kill = opts.kill || process.kill;
|
|
100
|
+
if (!isProcessAlive(record.pid, kill)) return true;
|
|
101
|
+
if (!isStale(record, opts)) return false;
|
|
102
|
+
const probe = opts.processCommand || processCommand;
|
|
103
|
+
const command = probe(record.pid);
|
|
104
|
+
if (typeof command !== 'string') return false;
|
|
105
|
+
return !LAND_PROCESS_RE.test(command);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function read(root) {
|
|
109
|
+
const record = readJsonSafe(leasePath(root));
|
|
110
|
+
return isLeaseRecord(record) ? record : null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Verified removal: re-read IMMEDIATELY before removing and require the stamp to still be the one
|
|
114
|
+
// the decision was made on. The removal itself renames the whole directory to a private
|
|
115
|
+
// tombstone FIRST (a single syscall, so the path is never briefly empty — rename onto an EMPTY
|
|
116
|
+
// directory would otherwise succeed and a concurrent claimant could slip in) and only then
|
|
117
|
+
// removes the tombstone.
|
|
118
|
+
function verifiedRemove(dir, expected) {
|
|
119
|
+
const current = readJsonSafe(path.join(dir, OWNER_FILENAME));
|
|
120
|
+
if (!isLeaseRecord(current) || !expected || current.token !== expected.token) return false;
|
|
121
|
+
const tombstone = `${dir}.dead-${process.pid}-${crypto.randomBytes(4).toString('hex')}`;
|
|
122
|
+
try {
|
|
123
|
+
fs.renameSync(dir, tombstone);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
/* expected: someone else already reaped or reclaimed this lease; there is nothing of ours to
|
|
126
|
+
remove, so report "not removed" rather than deleting a live claim */
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
fs.rmSync(tombstone, { recursive: true, force: true });
|
|
131
|
+
} catch (error) {
|
|
132
|
+
/* expected: the tombstone is private to this call, so a failed cleanup leaves only a stray
|
|
133
|
+
.dead-* directory; the live lease path is already free */
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function reapIfDead(root, opts = {}) {
|
|
139
|
+
const record = read(root);
|
|
140
|
+
if (!record) return false;
|
|
141
|
+
if (!isDead(record, opts)) return false;
|
|
142
|
+
return verifiedRemove(leaseDir(root), record);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Atomic claim (broker `_claimDir`): stage owner.json inside a private mkdtemp'd directory, then
|
|
146
|
+
// renameSync it into place. rename onto a non-empty directory fails atomically, so the lease path
|
|
147
|
+
// is either fully-formed-and-stamped or it was never claimed by this call.
|
|
148
|
+
// Returns the record on success, null when a live holder owns it.
|
|
149
|
+
function claim(root, opts = {}) {
|
|
150
|
+
const host = opts.host || os.hostname();
|
|
151
|
+
const jobId = opts.jobId === undefined ? null : opts.jobId;
|
|
152
|
+
const dir = leaseDir(root);
|
|
153
|
+
const staging = runnerDir(root);
|
|
154
|
+
fs.mkdirSync(staging, { recursive: true });
|
|
155
|
+
// Bounded retry: a reap that really removed a dead holder frees the path for THIS call, so the
|
|
156
|
+
// next submitter becomes the runner without an outer wait loop (D-2: "a dead runner's job
|
|
157
|
+
// returns to the head of the queue"). A live holder still yields null after the first attempt.
|
|
158
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
159
|
+
const token = crypto.randomBytes(16).toString('hex');
|
|
160
|
+
const stamp = new Date(nowValue(opts)).toISOString();
|
|
161
|
+
// D-10: `caps` rides along with the record. `heartbeat` spreads `{...current}`, so it survives
|
|
162
|
+
// every refresh without being re-stated there.
|
|
163
|
+
const record = { contract: 1, pid: process.pid, startedAt: stamp, heartbeatAt: stamp, token, jobId, host, caps: ['stop'] };
|
|
164
|
+
let tmp;
|
|
165
|
+
try {
|
|
166
|
+
tmp = fs.mkdtempSync(path.join(staging, '.claim-'));
|
|
167
|
+
} catch (error) {
|
|
168
|
+
throw landingError('lease_stage_failed', `cannot stage a claim under ${staging}: ${error.message}`, { root, cause: error });
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
fs.writeFileSync(path.join(tmp, OWNER_FILENAME), `${JSON.stringify(record)}\n`);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
rmrf(tmp);
|
|
174
|
+
throw landingError('lease_stage_failed', `cannot write the staged owner stamp in ${tmp}: ${error.message}`, { root, cause: error });
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
fs.renameSync(tmp, dir);
|
|
178
|
+
return record;
|
|
179
|
+
} catch (error) {
|
|
180
|
+
rmrf(tmp);
|
|
181
|
+
// Lost the race (or the path is a non-empty directory). Reap only a genuinely dead holder.
|
|
182
|
+
if (!reapIfDead(root, opts)) return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function rmrf(dir) {
|
|
189
|
+
try {
|
|
190
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
191
|
+
} catch (error) {
|
|
192
|
+
/* expected: best-effort cleanup of our own staging directory under landing/runner/ */
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Refresh heartbeatAt (and jobId, when given) only while the on-disk token is still ours.
|
|
197
|
+
function heartbeat(root, token, opts = {}) {
|
|
198
|
+
const file = leasePath(root);
|
|
199
|
+
const current = readJsonSafe(file);
|
|
200
|
+
if (!isLeaseRecord(current) || current.token !== token) {
|
|
201
|
+
throw landingError('lease_lost', `lease token ${token} is no longer held in ${root}`, { root, token });
|
|
202
|
+
}
|
|
203
|
+
const next = { ...current, heartbeatAt: new Date(nowValue(opts)).toISOString() };
|
|
204
|
+
if (opts.jobId !== undefined) next.jobId = opts.jobId;
|
|
205
|
+
// §9 S-6/D-6 (WP-1): the train in flight, so `land cancel` can tell a batch member from a singleton
|
|
206
|
+
// without reading a second file. Additive (R-3) — an older reader ignores it, and a lease written by
|
|
207
|
+
// an older runner has no `jobIds` at all, which `stop.isBatchMemberInFlight` reads as "not a member".
|
|
208
|
+
if (opts.jobIds !== undefined) next.jobIds = opts.jobIds;
|
|
209
|
+
writeJsonAtomic(file, next);
|
|
210
|
+
// The write is a rename into the same path; re-read to make sure we did not overwrite a holder
|
|
211
|
+
// that replaced the lease in between (the same "verified" discipline as removal).
|
|
212
|
+
const after = readJsonSafe(file);
|
|
213
|
+
if (!isLeaseRecord(after) || after.token !== token) {
|
|
214
|
+
throw landingError('lease_lost', `lease token ${token} was replaced while heartbeating ${root}`, { root, token });
|
|
215
|
+
}
|
|
216
|
+
return after;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Verified release: true only when this call removed OUR lease.
|
|
220
|
+
function release(root, token) {
|
|
221
|
+
const current = read(root);
|
|
222
|
+
if (!current || current.token !== token) return false;
|
|
223
|
+
return verifiedRemove(leaseDir(root), current);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
module.exports = {
|
|
227
|
+
LAND_HEARTBEAT_MS,
|
|
228
|
+
LAND_PROCESS_RE,
|
|
229
|
+
RUNNER_DIRNAME,
|
|
230
|
+
LEASE_DIRNAME,
|
|
231
|
+
OWNER_FILENAME,
|
|
232
|
+
runnerDir,
|
|
233
|
+
leaseDir,
|
|
234
|
+
leasePath,
|
|
235
|
+
hasCap,
|
|
236
|
+
claim,
|
|
237
|
+
heartbeat,
|
|
238
|
+
release,
|
|
239
|
+
read,
|
|
240
|
+
isDead,
|
|
241
|
+
isStale,
|
|
242
|
+
isProcessAlive,
|
|
243
|
+
processCommand,
|
|
244
|
+
nowValue,
|
|
245
|
+
reapIfDead,
|
|
246
|
+
verifiedRemove,
|
|
247
|
+
};
|