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
|
@@ -282,6 +282,19 @@ function createMainloopObservability(deps) {
|
|
|
282
282
|
: _activeSyncSegment;
|
|
283
283
|
const threshold = _attributedOp ? _lagThreshold : _unknownLagThreshold;
|
|
284
284
|
const name = _attributedOp ? _attributedOp.name : '(unknown)';
|
|
285
|
+
// WP-23 (D-33): the watchdog worker's own measured suspension, read from shared memory.
|
|
286
|
+
// It is the only in-process observer that is frozen by a suspension but not by a
|
|
287
|
+
// main-thread block, so whenever it has ticked we decide sleep-vs-freeze from it and
|
|
288
|
+
// never from CPU or timed work. Absent (CTM_MAIN_WATCHDOG=0, or no tick yet) the legacy
|
|
289
|
+
// rule below applies unchanged.
|
|
290
|
+
//
|
|
291
|
+
// WP-2 (D-6): read it BEFORE the evidence build so the suspension is available as an
|
|
292
|
+
// input to the classifier — the ladder labels a mostly-suspended block `process-suspended`
|
|
293
|
+
// instead of the inferential `off-cpu-unattributed`/`main_descheduled`.
|
|
294
|
+
const _watchdog = _readWatchdogSuspension(lagIntervalMs);
|
|
295
|
+
const _suspendedMs = _watchdog
|
|
296
|
+
? Math.max(0, Math.min(_watchdog.suspendedTo, now) - Math.max(_watchdog.suspendedFrom, now - blockedMs))
|
|
297
|
+
: 0;
|
|
285
298
|
let _blockEvidence = null;
|
|
286
299
|
try {
|
|
287
300
|
if (blockedMs >= 200) {
|
|
@@ -293,17 +306,12 @@ function createMainloopObservability(deps) {
|
|
|
293
306
|
mainThreadCpuDeltaMs: _mainThreadCpuDeltaMs,
|
|
294
307
|
processCpuDeltaMs: _processCpuDeltaMs,
|
|
295
308
|
activeSyncEvidence: _activeSyncEvidence,
|
|
309
|
+
suspendedMs: _suspendedMs,
|
|
296
310
|
},
|
|
297
311
|
);
|
|
298
312
|
}
|
|
299
313
|
_lagEvidenceBaseline = currentEvidence;
|
|
300
314
|
} catch { /* expected: evidence collection must never break the detector */ }
|
|
301
|
-
// WP-23 (D-33): the watchdog worker's own measured suspension, read from shared memory.
|
|
302
|
-
// It is the only in-process observer that is frozen by a suspension but not by a
|
|
303
|
-
// main-thread block, so whenever it has ticked we decide sleep-vs-freeze from it and
|
|
304
|
-
// never from CPU or timed work. Absent (CTM_MAIN_WATCHDOG=0, or no tick yet) the legacy
|
|
305
|
-
// rule below applies unchanged.
|
|
306
|
-
const _watchdog = _readWatchdogSuspension(lagIntervalMs);
|
|
307
315
|
const _suspectedSleep = perfTracker.isSuspectedSleepBlock(blockedMs, {
|
|
308
316
|
idleDuringGap: _idleDuringGap,
|
|
309
317
|
recentSyncEvidence: _recentSyncEvidence,
|
|
@@ -313,9 +321,6 @@ function createMainloopObservability(deps) {
|
|
|
313
321
|
watchdog: _watchdog || undefined,
|
|
314
322
|
gapStartMs: now - blockedMs,
|
|
315
323
|
});
|
|
316
|
-
const _suspendedMs = _watchdog
|
|
317
|
-
? Math.max(0, Math.min(_watchdog.suspendedTo, now) - Math.max(_watchdog.suspendedFrom, now - blockedMs))
|
|
318
|
-
: 0;
|
|
319
324
|
let lagSample = null;
|
|
320
325
|
try {
|
|
321
326
|
lagSample = perfTracker.recordEventLoopLagSample(name, delta, {
|
|
@@ -498,7 +498,11 @@ function createMediaDraftOwner(deps) {
|
|
|
498
498
|
const next = stampDraftMutation(item, {
|
|
499
499
|
...item,
|
|
500
500
|
state: input.state,
|
|
501
|
-
|
|
501
|
+
// WP-2 (composer-image-chip-stuck-submission-recovery-2026-10-30.html §6): `''` still
|
|
502
|
+
// means "keep the current id" (unchanged default); the explicit clearSubmittedInputId
|
|
503
|
+
// flag is the ONLY way to drop a submittedInputId, and it exists for the stale-draft
|
|
504
|
+
// recovery that returns a frozen draft to attached.
|
|
505
|
+
submittedInputId: input.clearSubmittedInputId === true ? '' : String(input.submittedInputId || item.submittedInputId || ''),
|
|
502
506
|
deliveryAttemptId: String(input.attemptId || item.deliveryAttemptId || ''),
|
|
503
507
|
stateReason: String(input.reason || (input.state === 'ready' ? '' : item.stateReason || '')),
|
|
504
508
|
updatedAt: new Date().toISOString(),
|
|
@@ -694,12 +698,21 @@ function createMediaDraftOwner(deps) {
|
|
|
694
698
|
&& Date.parse(item.updatedAt || item.createdAt || 0) < before);
|
|
695
699
|
const recovered = [];
|
|
696
700
|
for (const candidate of candidates) {
|
|
701
|
+
// R-3 (WP-2): a `frozen` draft whose delivery was CONFIRMED was interrupted before Enter,
|
|
702
|
+
// so the image is still in the agent composer -- `failed` would lie about it (and would
|
|
703
|
+
// re-deliver a token that is already there). It returns to `attached` with the stale
|
|
704
|
+
// submittedInputId cleared, so the next send freezes it again. A `delivery_pending`
|
|
705
|
+
// draft, or a `frozen` one the provider never acknowledged, keeps today's failure.
|
|
706
|
+
const interruptedBeforeEnter = candidate.state === 'frozen' && Boolean(candidate.deliveryConfirmedAt);
|
|
697
707
|
const item = await setDraftState({
|
|
698
708
|
sessionId,
|
|
699
709
|
attachmentId: candidate.attachmentId,
|
|
700
710
|
expectedRevision: candidate.revision,
|
|
701
|
-
state: 'failed',
|
|
702
|
-
|
|
711
|
+
state: interruptedBeforeEnter ? 'attached' : 'failed',
|
|
712
|
+
clearSubmittedInputId: interruptedBeforeEnter,
|
|
713
|
+
reason: interruptedBeforeEnter
|
|
714
|
+
? 'Send was interrupted before Enter; image is still in the composer.'
|
|
715
|
+
: 'Image delivery was interrupted. Retry or remove it.',
|
|
703
716
|
});
|
|
704
717
|
recovered.push(item);
|
|
705
718
|
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// WP-4b (docs/shared-memory-every-machine-2026-10-31.html §5 D-6, §6.7): the HUB side of the join
|
|
4
|
+
// state machine — a member whose vector does not name the hub origin (WP-3's 'join_required') takes
|
|
5
|
+
// the hub's consistent snapshot in 4 MiB sha256-verified chunks and imports it, instead of idling.
|
|
6
|
+
//
|
|
7
|
+
// advanceMemberJoin(member, ctx) -> { state, detail }
|
|
8
|
+
// state ∈ 'seed_pending' | 'join_snapshot' | 'join_transfer' | 'join_import' | 'join_done'
|
|
9
|
+
// | 'join_failed'
|
|
10
|
+
//
|
|
11
|
+
// D-6: (1) the hub takes a consistent snapshot of its own brain, (2) reads the snapshot's own
|
|
12
|
+
// vector, (3) ships it in 4 MiB chunks, (4) the member imports the replicated tables, (5) the
|
|
13
|
+
// member's vector becomes the snapshot's, so hub changes written during the transfer arrive through
|
|
14
|
+
// the ordinary D-3 feed. P-1: the vector travels FROM THE SNAPSHOT FILE, never the live DB.
|
|
15
|
+
//
|
|
16
|
+
// The per-member progress Map is MODULE state by design, exactly like memory-sync.js's backoff
|
|
17
|
+
// bookkeeping: a hub restart loses it and the transfer RESUMES from the member's own `received[]`
|
|
18
|
+
// (P-3, checkpoints on both sides) — never from the hub's memory. A member restart mid-import is
|
|
19
|
+
// Wall-E's job (WP-4a): this side only polls /join/status until it reads 'done' or 'failed'.
|
|
20
|
+
|
|
21
|
+
const fsp = require('node:fs/promises');
|
|
22
|
+
|
|
23
|
+
// §6.7: the transfer chunk size. Shared with lib/api/memory-sync-routes.js — the sender writes at
|
|
24
|
+
// offset index*CHUNK_BYTES and the receiver reads at the same offset, so the two must never drift.
|
|
25
|
+
const CHUNK_BYTES = 4 * 1024 * 1024;
|
|
26
|
+
const DEFAULT_CHUNKS_PER_TICK = 32;
|
|
27
|
+
// §6.7/D-6: a failed join is retried from step 1 after this long, never on every tick.
|
|
28
|
+
const FAILED_RETRY_MS = 60 * 60 * 1000;
|
|
29
|
+
const JOIN_ID_RE = /^[A-Za-z0-9._:-]{1,200}$/;
|
|
30
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|
|
31
|
+
|
|
32
|
+
// The hub's LOCAL Wall-E join route (loopback + CTM token, like LOCAL_PATHS in memory-sync.js).
|
|
33
|
+
const SNAPSHOT_PATH = '/api/walle/sync/v2/join/snapshot';
|
|
34
|
+
// The member's CTM front routes (D-12): the hub dials the member's CTM, which forwards to its Wall-E.
|
|
35
|
+
const MEMBER_JOIN_PATHS = Object.freeze({
|
|
36
|
+
chunk: '/api/sync/brain/v2/join/chunk',
|
|
37
|
+
transfer: '/api/sync/brain/v2/join/transfer',
|
|
38
|
+
import: '/api/sync/brain/v2/join/import',
|
|
39
|
+
status: '/api/sync/brain/v2/join/status',
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// instanceId -> { joinId, snapshot, phase, memberPath, imported, restarted, error, nextAttemptAt }.
|
|
43
|
+
const _progress = new Map();
|
|
44
|
+
|
|
45
|
+
function _string(value, max = 200) {
|
|
46
|
+
if (typeof value === 'string') return value.trim().slice(0, max);
|
|
47
|
+
return value == null ? '' : String(value).trim().slice(0, max);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function _nowOf(ctx = {}) {
|
|
51
|
+
return typeof ctx.now === 'function' ? Number(ctx.now()) || Date.now() : Date.now();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function _chunkCount(bytes) {
|
|
55
|
+
const size = Math.max(0, Number(bytes) || 0);
|
|
56
|
+
return Math.max(1, Math.ceil(size / CHUNK_BYTES));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function _joinUrl(base, pathname) {
|
|
60
|
+
return `${String(base).replace(/\/+$/, '')}${pathname}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// One local Wall-E call. requestJson resolves { status, json } for any answer and rejects only on a
|
|
64
|
+
// transport fault — the caller maps both (memory-sync.js's _walleRequest shape).
|
|
65
|
+
async function _walleRequest(walle, pathname, { method = 'GET', body = null } = {}) {
|
|
66
|
+
try {
|
|
67
|
+
const res = await walle.requestJson(pathname, body == null ? { method } : { method, body });
|
|
68
|
+
return { status: Number(res && res.status) || 0, json: (res && res.json) || null };
|
|
69
|
+
} catch (err) {
|
|
70
|
+
return { status: 0, json: null, error: err?.message || String(err) };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// One member request, with the AbortController + unref'd timer shape memory-sync.js uses so a hung
|
|
75
|
+
// member can never hold the tick open past the timeout. Never throws: a transport fault is reported
|
|
76
|
+
// as `{ status: 0 }` and mapped by the caller.
|
|
77
|
+
async function _memberRequest(fetchImpl, url, pathname, { method = 'GET', body = null, headers = {} } = {}) {
|
|
78
|
+
const fetchFn = fetchImpl || global.fetch;
|
|
79
|
+
if (typeof fetchFn !== 'function') return { status: 0, json: null, error: 'fetch_unavailable' };
|
|
80
|
+
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
81
|
+
const timer = controller ? setTimeout(() => controller.abort(), DEFAULT_REQUEST_TIMEOUT_MS) : null;
|
|
82
|
+
if (timer && typeof timer.unref === 'function') timer.unref();
|
|
83
|
+
try {
|
|
84
|
+
const payload = body == null ? null : JSON.stringify(body);
|
|
85
|
+
const res = await fetchFn(_joinUrl(url, pathname), {
|
|
86
|
+
method,
|
|
87
|
+
headers: {
|
|
88
|
+
...headers,
|
|
89
|
+
...(payload ? { 'Content-Type': 'application/json' } : {}),
|
|
90
|
+
Accept: 'application/json',
|
|
91
|
+
},
|
|
92
|
+
...(payload ? { body: payload } : {}),
|
|
93
|
+
signal: controller ? controller.signal : undefined,
|
|
94
|
+
});
|
|
95
|
+
let json = null;
|
|
96
|
+
try { json = await res.json(); } catch { json = null; /* expected: a non-JSON body is degraded, mapped by the caller */ }
|
|
97
|
+
return { status: Number(res && res.status) || 0, json };
|
|
98
|
+
} catch (err) {
|
|
99
|
+
return { status: 0, json: null, error: err?.message || String(err) };
|
|
100
|
+
} finally {
|
|
101
|
+
if (timer) clearTimeout(timer);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// The production chunk reader (the `readChunk` seam): a bounded read at an absolute offset. A short
|
|
106
|
+
// read is a hard error — a truncated chunk would assemble to a wrong sha256 on the member, not to a
|
|
107
|
+
// short file.
|
|
108
|
+
async function _readChunkDefault(filePath, offset, length) {
|
|
109
|
+
const handle = await fsp.open(filePath, 'r');
|
|
110
|
+
try {
|
|
111
|
+
const buffer = Buffer.alloc(length);
|
|
112
|
+
const { bytesRead } = await handle.read(buffer, 0, length, offset);
|
|
113
|
+
if (bytesRead !== length) throw new Error(`short_read_${bytesRead}_of_${length}`);
|
|
114
|
+
return buffer;
|
|
115
|
+
} finally {
|
|
116
|
+
try { await handle.close(); } catch { /* expected: a close fault must not mask the read verdict */ }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// R-5 (§6.6): `freshSnapshot` rides on the failed record so the retry after the backoff asks the hub's
|
|
121
|
+
// own Wall-E for a NEW snapshot instead of reusing the 6 h window's file the member already refused.
|
|
122
|
+
function _fail(instanceId, nowMs, error, { freshSnapshot = false } = {}) {
|
|
123
|
+
_progress.set(instanceId, { phase: 'failed', error, nextAttemptAt: nowMs + FAILED_RETRY_MS, freshSnapshot });
|
|
124
|
+
return { state: 'join_failed', detail: { error } };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Advance one member's join by one tick. Called by memory-sync.js's `syncMemberBrainOnce` exactly
|
|
129
|
+
* where it used to answer the idle 'join_required' state.
|
|
130
|
+
*
|
|
131
|
+
* @param {{instanceId: string, urls?: string[], url?: string}} member
|
|
132
|
+
* @param {object} ctx { localInstanceId, walle, fetchImpl, headers, memberUrl, now, chunksPerTick, readChunk }
|
|
133
|
+
*/
|
|
134
|
+
async function advanceMemberJoin(member = {}, ctx = {}) {
|
|
135
|
+
const instanceId = _string(member.instanceId);
|
|
136
|
+
const walle = ctx.walle;
|
|
137
|
+
const fetchImpl = ctx.fetchImpl || global.fetch;
|
|
138
|
+
const headers = ctx.headers || {};
|
|
139
|
+
const memberUrl = _string(ctx.memberUrl, 1000);
|
|
140
|
+
const localInstanceId = _string(ctx.localInstanceId);
|
|
141
|
+
const chunksPerTick = Math.max(1, Number(ctx.chunksPerTick) || DEFAULT_CHUNKS_PER_TICK);
|
|
142
|
+
const readChunk = typeof ctx.readChunk === 'function' ? ctx.readChunk : _readChunkDefault;
|
|
143
|
+
const nowMs = _nowOf(ctx);
|
|
144
|
+
|
|
145
|
+
if (!instanceId) return { state: 'join_failed', detail: { error: 'member_instance_required' } };
|
|
146
|
+
if (!memberUrl) return { state: 'join_failed', detail: { error: 'member_has_no_url' } };
|
|
147
|
+
if (!walle || typeof walle.requestJson !== 'function') return { state: 'join_failed', detail: { error: 'walle_client_missing' } };
|
|
148
|
+
|
|
149
|
+
let p = _progress.get(instanceId) || null;
|
|
150
|
+
let fresh = false;
|
|
151
|
+
// A failed join is retried from step 1 only after the 1 h backoff (D-6/§6.7).
|
|
152
|
+
if (p && p.phase === 'failed') {
|
|
153
|
+
if (nowMs < p.nextAttemptAt) return { state: 'join_failed', detail: { error: p.error, retryAt: p.nextAttemptAt } };
|
|
154
|
+
// R-5: the member refused the previous snapshot — remember to ask for a fresh one (§6.6).
|
|
155
|
+
fresh = p.freshSnapshot === true;
|
|
156
|
+
_progress.delete(instanceId);
|
|
157
|
+
p = null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 1. snapshot — once per joinId. 409 clock_seed_pending (D-9: the hub's own clock walk is not
|
|
161
|
+
// done) parks the member for the next tick with no partial state. A retry after a refused import
|
|
162
|
+
// carries {fresh:true} so createJoinSnapshot skips the 6 h reuse instead of re-offering the same file.
|
|
163
|
+
if (!p) {
|
|
164
|
+
const snap = await _walleRequest(walle, SNAPSHOT_PATH, { method: 'POST', body: fresh ? { fresh: true } : {} });
|
|
165
|
+
if (snap.status === 409) return { state: 'seed_pending', detail: { error: 'clock_seed_pending' } };
|
|
166
|
+
if (snap.status === 0 || !snap.json || snap.status < 200 || snap.status >= 300) {
|
|
167
|
+
return { state: 'join_snapshot', detail: { error: snap.error || `snapshot_http_${snap.status}` } };
|
|
168
|
+
}
|
|
169
|
+
const joinId = _string(snap.json.joinId, 200);
|
|
170
|
+
const snapshotPath = _string(snap.json.path, 1000);
|
|
171
|
+
const bytes = Number(snap.json.bytes);
|
|
172
|
+
if (!JOIN_ID_RE.test(joinId) || !snapshotPath || !Number.isFinite(bytes) || bytes < 0) {
|
|
173
|
+
return { state: 'join_snapshot', detail: { error: 'snapshot_bad_reply' } };
|
|
174
|
+
}
|
|
175
|
+
p = {
|
|
176
|
+
joinId,
|
|
177
|
+
snapshot: { path: snapshotPath, bytes, sha256: _string(snap.json.sha256, 64), vector: (snap.json.vector && typeof snap.json.vector === 'object') ? snap.json.vector : {} },
|
|
178
|
+
phase: 'transfer',
|
|
179
|
+
memberPath: '',
|
|
180
|
+
imported: false,
|
|
181
|
+
restarted: false,
|
|
182
|
+
};
|
|
183
|
+
_progress.set(instanceId, p);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 2. transfer — ask the member what it already holds (P-3: resume after a hub restart), then send
|
|
187
|
+
// up to `chunksPerTick` missing chunks in index order.
|
|
188
|
+
if (p.phase === 'transfer') {
|
|
189
|
+
const transfer = await _memberRequest(fetchImpl, memberUrl, `${MEMBER_JOIN_PATHS.transfer}?joinId=${encodeURIComponent(p.joinId)}`, { method: 'GET', headers });
|
|
190
|
+
if (transfer.status === 0) return { state: 'join_transfer', detail: { error: transfer.error || 'member_unreachable' } };
|
|
191
|
+
if (transfer.status < 200 || transfer.status >= 300 || !transfer.json) {
|
|
192
|
+
return { state: 'join_transfer', detail: { error: `transfer_http_${transfer.status}` } };
|
|
193
|
+
}
|
|
194
|
+
const declared = Number(transfer.json.total);
|
|
195
|
+
const total = Number.isInteger(declared) && declared > 0 ? declared : _chunkCount(p.snapshot.bytes);
|
|
196
|
+
if (transfer.json.complete === true && _string(transfer.json.path, 1000)) {
|
|
197
|
+
p.memberPath = _string(transfer.json.path, 1000);
|
|
198
|
+
p.phase = 'import';
|
|
199
|
+
} else {
|
|
200
|
+
const received = new Set((Array.isArray(transfer.json.received) ? transfer.json.received : []).map(Number).filter((n) => Number.isInteger(n) && n >= 0));
|
|
201
|
+
let sent = 0;
|
|
202
|
+
for (let index = 0; index < total && sent < chunksPerTick; index += 1) {
|
|
203
|
+
if (received.has(index)) continue;
|
|
204
|
+
const offset = index * CHUNK_BYTES;
|
|
205
|
+
const length = Math.min(CHUNK_BYTES, p.snapshot.bytes - offset);
|
|
206
|
+
if (length <= 0) continue;
|
|
207
|
+
let data;
|
|
208
|
+
try {
|
|
209
|
+
data = await readChunk(p.snapshot.path, offset, length, ctx);
|
|
210
|
+
} catch (err) {
|
|
211
|
+
return { state: 'join_transfer', detail: { error: `snapshot_read_failed: ${err?.message || String(err)}` } };
|
|
212
|
+
}
|
|
213
|
+
if (!Buffer.isBuffer(data) || data.length !== length) {
|
|
214
|
+
return { state: 'join_transfer', detail: { error: `snapshot_chunk_short_${index}` } };
|
|
215
|
+
}
|
|
216
|
+
const res = await _memberRequest(fetchImpl, memberUrl, MEMBER_JOIN_PATHS.chunk, {
|
|
217
|
+
method: 'POST',
|
|
218
|
+
headers,
|
|
219
|
+
body: {
|
|
220
|
+
joinId: p.joinId,
|
|
221
|
+
index,
|
|
222
|
+
total,
|
|
223
|
+
chunkBytes: length,
|
|
224
|
+
fileBytes: p.snapshot.bytes,
|
|
225
|
+
fileSha256: p.snapshot.sha256,
|
|
226
|
+
dataBase64: data.toString('base64'),
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
sent += 1;
|
|
230
|
+
if (res.status === 507 || (res.json && res.json.error === 'insufficient_storage')) {
|
|
231
|
+
return _fail(instanceId, nowMs, 'insufficient_storage');
|
|
232
|
+
}
|
|
233
|
+
if (res.status === 422 || (res.json && res.json.error === 'sha256_mismatch')) {
|
|
234
|
+
// The member deleted its .part + sidecar; restart the transfer from 0 exactly once.
|
|
235
|
+
if (!p.restarted) {
|
|
236
|
+
p.restarted = true;
|
|
237
|
+
p.memberPath = '';
|
|
238
|
+
return { state: 'join_transfer', detail: { error: 'sha256_mismatch', restarted: true } };
|
|
239
|
+
}
|
|
240
|
+
return _fail(instanceId, nowMs, 'sha256_mismatch');
|
|
241
|
+
}
|
|
242
|
+
if (res.status === 0) return { state: 'join_transfer', detail: { error: res.error || 'member_unreachable' } };
|
|
243
|
+
if (res.status < 200 || res.status >= 300 || !res.json) {
|
|
244
|
+
return { state: 'join_transfer', detail: { error: `chunk_http_${res.status}` } };
|
|
245
|
+
}
|
|
246
|
+
if (res.json.complete === true && _string(res.json.path, 1000)) {
|
|
247
|
+
p.memberPath = _string(res.json.path, 1000);
|
|
248
|
+
p.phase = 'import';
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (p.phase !== 'import') return { state: 'join_transfer', detail: { sent, total } };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// 3. import + 4. poll — the member hands the file to its own brain owner (WP-4a); this side only
|
|
257
|
+
// drives and observes. The import POST is issued at most once per joinId.
|
|
258
|
+
if (p.phase === 'import') {
|
|
259
|
+
if (!p.imported) {
|
|
260
|
+
if (!p.memberPath) {
|
|
261
|
+
const again = await _memberRequest(fetchImpl, memberUrl, `${MEMBER_JOIN_PATHS.transfer}?joinId=${encodeURIComponent(p.joinId)}`, { method: 'GET', headers });
|
|
262
|
+
const path = _string(again.json && again.json.path, 1000);
|
|
263
|
+
if (again.status >= 200 && again.status < 300 && again.json && again.json.complete === true && path) {
|
|
264
|
+
p.memberPath = path;
|
|
265
|
+
} else {
|
|
266
|
+
p.phase = 'transfer';
|
|
267
|
+
return { state: 'join_transfer', detail: { error: 'member_path_missing' } };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const posted = await _memberRequest(fetchImpl, memberUrl, MEMBER_JOIN_PATHS.import, {
|
|
271
|
+
method: 'POST',
|
|
272
|
+
headers,
|
|
273
|
+
body: { joinId: p.joinId, path: p.memberPath, sha256: p.snapshot.sha256, homeInstanceId: localInstanceId },
|
|
274
|
+
});
|
|
275
|
+
if (posted.status === 0) return { state: 'join_import', detail: { error: posted.error || 'member_unreachable' } };
|
|
276
|
+
// 409 join_in_progress: a previous tick's import is already running — poll it, never re-post.
|
|
277
|
+
if (posted.status === 409) p.imported = true;
|
|
278
|
+
// R-9: a 4xx import reply is terminal for THIS attempt — fail with the status + the member's own
|
|
279
|
+
// error code instead of re-POSTing the same refused import on every round with no backoff.
|
|
280
|
+
else if (posted.status >= 400 && posted.status < 500) {
|
|
281
|
+
return _fail(instanceId, nowMs, `import_http_${posted.status}:${_string(posted.json && posted.json.error, 160)}`);
|
|
282
|
+
// 5xx / odd replies stay non-terminal — a member restart or a transient fault is retried next tick.
|
|
283
|
+
} else if (posted.status < 200 || posted.status >= 300 || !posted.json) {
|
|
284
|
+
return { state: 'join_import', detail: { error: `import_http_${posted.status}` } };
|
|
285
|
+
// R-4/R-5: a 2xx whose state is 'failed' means the member cannot resume THIS snapshot — ask for a
|
|
286
|
+
// fresh one on the retry instead of polling a file it has already refused.
|
|
287
|
+
} else if (_string(posted.json.state, 40) === 'failed') {
|
|
288
|
+
return _fail(instanceId, nowMs, 'member_join_not_resumable', { freshSnapshot: true });
|
|
289
|
+
} else p.imported = true;
|
|
290
|
+
}
|
|
291
|
+
const status = await _memberRequest(fetchImpl, memberUrl, MEMBER_JOIN_PATHS.status, { method: 'GET', headers });
|
|
292
|
+
if (status.status === 0) return { state: 'join_import', detail: { error: status.error || 'member_unreachable' } };
|
|
293
|
+
if (status.status < 200 || status.status >= 300 || !status.json) {
|
|
294
|
+
return { state: 'join_import', detail: { error: `status_http_${status.status}` } };
|
|
295
|
+
}
|
|
296
|
+
const memberState = _string(status.json.state, 40);
|
|
297
|
+
if (memberState === 'done') {
|
|
298
|
+
_progress.delete(instanceId);
|
|
299
|
+
return {
|
|
300
|
+
state: 'join_done',
|
|
301
|
+
detail: {
|
|
302
|
+
joinId: p.joinId,
|
|
303
|
+
memberPath: p.memberPath,
|
|
304
|
+
imported: Number(status.json.imported) || 0,
|
|
305
|
+
rekeyed: Number(status.json.rekeyed) || 0,
|
|
306
|
+
vector: p.snapshot.vector,
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
if (memberState === 'failed') return _fail(instanceId, nowMs, _string(status.json.error, 200) || 'join_import_failed');
|
|
311
|
+
return { state: 'join_import', detail: { joinId: p.joinId, memberState: memberState || 'none' } };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return { state: 'join_failed', detail: { error: 'join_phase_unknown' } };
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/** Test seam: forget every member's join progress (module state survives a process). */
|
|
318
|
+
function _resetMemberJoinStateForTests() {
|
|
319
|
+
_progress.clear();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Observability/test seam: the raw per-member progress record (never mutated by callers). */
|
|
323
|
+
function memberJoinProgress(instanceId) {
|
|
324
|
+
const p = _progress.get(_string(instanceId));
|
|
325
|
+
return p ? { ...p } : null;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
module.exports = {
|
|
329
|
+
advanceMemberJoin,
|
|
330
|
+
memberJoinProgress,
|
|
331
|
+
_resetMemberJoinStateForTests,
|
|
332
|
+
CHUNK_BYTES,
|
|
333
|
+
MEMBER_JOIN_PATHS,
|
|
334
|
+
SNAPSHOT_PATH,
|
|
335
|
+
FAILED_RETRY_MS,
|
|
336
|
+
JOIN_ID_RE,
|
|
337
|
+
};
|