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,489 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// WP-2 (docs/local-landing-queue-multi-session-integration-2026-10-26.html §5 D-7, D-8, D-9 Tier B,
|
|
3
|
+
// §6.3 `radar/` + `claims/`, §8 WP-2, §10 T-5): the ADVISORY pairwise conflict radar for the CLI.
|
|
4
|
+
//
|
|
5
|
+
// Three properties, in order of importance:
|
|
6
|
+
//
|
|
7
|
+
// 1. The radar never blocks. No verb here refuses a job, edits a file, or takes a lock. It returns
|
|
8
|
+
// levels; the caller decides nothing on their basis.
|
|
9
|
+
// 2. The radar never writes into a session worktree. Every git child is `--no-optional-locks`
|
|
10
|
+
// (git.js), pair results go to `$(git-common-dir)/landing/radar/`, and the only worktree-side
|
|
11
|
+
// operation at all is the D-7 dirty-worktree snapshot, which goes through a TEMP index
|
|
12
|
+
// (`git.js#snapshotCommit`) so the real index and its lock are untouched.
|
|
13
|
+
// 3. The radar is incremental. A pair's level is a pure function of (tipA, tipB, configHash), so it
|
|
14
|
+
// is cached per sha pair; a sweep recomputes only the pairs whose tips moved. Snapshot commits
|
|
15
|
+
// are deterministic for the same reason (D-7: "a sweep recomputes only pairs whose tip changed").
|
|
16
|
+
//
|
|
17
|
+
// Levels (§5 D-7 / §8 AC-2b):
|
|
18
|
+
// L3 `git merge-tree` reports a textual conflict
|
|
19
|
+
// L2 a file changed on both sides has the SAME non-empty -U0 hunk header context on both sides
|
|
20
|
+
// (git's own funcname, so `diff.*.xfuncname` drivers apply — language-independent, D-9 Tier B),
|
|
21
|
+
// or a common file matches a `landing.registries` glob (D-9 Tier B class)
|
|
22
|
+
// L1 the two sides changed at least one file in common
|
|
23
|
+
// L0 nothing in common
|
|
24
|
+
// `L1*` is L0 plus a live soft claim (§5 D-7): advisory, transient, never cached.
|
|
25
|
+
// `unknown` — `cacheOnly` asked about a pair that has never been computed.
|
|
26
|
+
//
|
|
27
|
+
// The `ledger` flag on an L3 pair says the conflict is machine-mergeable in principle: every
|
|
28
|
+
// conflicted path is either driver-backed (`.gitattributes` `merge=<driver>`) or owned by a
|
|
29
|
+
// `landing.regenerate[]` entry. It is a label, never an action — D-8 is what acts on it, and this
|
|
30
|
+
// module never runs a driver or a regenerate command.
|
|
31
|
+
//
|
|
32
|
+
// Sync by design (§11 Risks): the `land` CLI is a synchronous, one-shot process, so every probe here
|
|
33
|
+
// is synchronous and nothing is left running when the verb returns.
|
|
34
|
+
|
|
35
|
+
const fs = require('fs');
|
|
36
|
+
const path = require('path');
|
|
37
|
+
const crypto = require('crypto');
|
|
38
|
+
|
|
39
|
+
const { CONTRACT, landingDir, readJsonSafe, writeJsonAtomic } = require('./state');
|
|
40
|
+
const { globMatch, worktreeList, mergeBase, changedFilesBetween, hunkHeaders } = require('./train');
|
|
41
|
+
const { landingError, runGitRaw, mergeTree, revParseOrNull, snapshotCommit } = require('./git');
|
|
42
|
+
|
|
43
|
+
// §5 D-7: the CLI scope is "all named-branch worktrees, capped at 64 by recency of tip commit".
|
|
44
|
+
const MAX_BRANCHES = 64;
|
|
45
|
+
// Levels, ordered. `unknown` is not a level — it is "this sweep did not look".
|
|
46
|
+
const LEVELS = Object.freeze(['L0', 'L1', 'L1*', 'L2', 'L3']);
|
|
47
|
+
const CLAIM_DEFAULT_TTL_HOURS = 4;
|
|
48
|
+
|
|
49
|
+
function levelRank(level) {
|
|
50
|
+
if (level === 'unknown') return -1;
|
|
51
|
+
const index = LEVELS.indexOf(level);
|
|
52
|
+
return index === -1 ? 0 : index;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// --- config ------------------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
function registryPatterns(config) {
|
|
58
|
+
return config && Array.isArray(config.registries) ? config.registries : [];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function regenerateEntries(config) {
|
|
62
|
+
return config && Array.isArray(config.regenerate) ? config.regenerate : [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// The pair cache key's second half (§5 D-7): a cached level is reusable only while the policy that
|
|
66
|
+
// produced it is unchanged. Only the two keys the radar reads are hashed, so an unrelated policy
|
|
67
|
+
// edit (a gate, the target) does not invalidate every pair.
|
|
68
|
+
function configHash(config) {
|
|
69
|
+
return crypto.createHash('sha256').update(JSON.stringify({
|
|
70
|
+
registries: registryPatterns(config),
|
|
71
|
+
regenerate: regenerateEntries(config),
|
|
72
|
+
})).digest('hex');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// `landing.regenerate[].paths` (D-8) and `landing.registries[]` (D-9 Tier B) are both git-style
|
|
76
|
+
// globs; `globMatch` is train.js's one implementation of them.
|
|
77
|
+
function matchesAny(patterns, file) {
|
|
78
|
+
return patterns.some((pattern) => globMatch(pattern, file));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function ownedByRegenerate(config, file) {
|
|
82
|
+
return regenerateEntries(config).some((entry) => Array.isArray(entry.paths) && entry.paths.some((pattern) => globMatch(pattern, file)));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// `.gitattributes` `merge=<driver>`: `git check-attr` reports `unspecified` when nothing is set and
|
|
86
|
+
// `unset` for a negative pattern. Anything else names a driver, so git — not the queue — owns the
|
|
87
|
+
// merge of that path (D-8).
|
|
88
|
+
function driverBacked(cwd, file) {
|
|
89
|
+
const res = runGitRaw(cwd, ['check-attr', 'merge', '--', file]);
|
|
90
|
+
if (res.status !== 0) return false;
|
|
91
|
+
const match = /merge:\s*(.*)$/m.exec(res.stdout);
|
|
92
|
+
if (!match) return false;
|
|
93
|
+
const value = match[1].trim();
|
|
94
|
+
return value !== '' && value !== 'unspecified' && value !== 'unset';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// --- levels ------------------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
// "the text after the second `@@`" of a `git diff -U0` hunk header — git's funcname context. An
|
|
100
|
+
// empty one carries no information and is never a match (`@@ -1 +1 @@`).
|
|
101
|
+
function hunkContext(header) {
|
|
102
|
+
const parts = String(header).split('@@');
|
|
103
|
+
if (parts.length < 3) return null;
|
|
104
|
+
const context = parts[2].trim();
|
|
105
|
+
return context || null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// D-9 Tier B: both sides moved a hunk inside the SAME funcname context, which is git's own,
|
|
109
|
+
// language-independent "same region" signal (it honours `diff.*.xfuncname`).
|
|
110
|
+
function sharesHunkContext(cwd, base, a, b, files) {
|
|
111
|
+
for (const file of files) {
|
|
112
|
+
const left = new Set();
|
|
113
|
+
for (const header of hunkHeaders(cwd, base, a, file)) {
|
|
114
|
+
const context = hunkContext(header);
|
|
115
|
+
if (context) left.add(context);
|
|
116
|
+
}
|
|
117
|
+
if (!left.size) continue;
|
|
118
|
+
for (const header of hunkHeaders(cwd, base, b, file)) {
|
|
119
|
+
const context = hunkContext(header);
|
|
120
|
+
if (context && left.has(context)) return true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// `{ level, files, conflicts, ledger, registry }` for two commits (§5 D-7). Exactly ONE merge-tree
|
|
127
|
+
// spawn (and one merge-base spawn) — the sweep counts them, so this must stay a single call each.
|
|
128
|
+
function pairLevel(cwd, a, b, opts = {}) {
|
|
129
|
+
const config = opts.config || {};
|
|
130
|
+
const base = mergeBase(cwd, a, b);
|
|
131
|
+
// No merge base (unrelated histories) means no common ancestor to diff from; `files` stays empty
|
|
132
|
+
// and the merge-tree probe below still decides the level.
|
|
133
|
+
const files = base === null ? [] : intersection(changedFilesBetween(cwd, base, a), changedFilesBetween(cwd, base, b)).sort();
|
|
134
|
+
|
|
135
|
+
const merged = mergeTree(cwd, a, b);
|
|
136
|
+
let level;
|
|
137
|
+
let conflicts = [];
|
|
138
|
+
let ledger = false;
|
|
139
|
+
if (merged.conflicts.length) {
|
|
140
|
+
level = 'L3';
|
|
141
|
+
conflicts = merged.conflicts.slice().sort();
|
|
142
|
+
// Machine-mergeable in principle: a `.gitattributes` driver, or a `landing.regenerate[]` owner.
|
|
143
|
+
// (A driver attribute is set but its `merge.<driver>.driver` command may be missing or failing —
|
|
144
|
+
// that is exactly the case merge-tree still reports, and exactly what the flag is for.)
|
|
145
|
+
ledger = conflicts.every((file) => driverBacked(cwd, file) || ownedByRegenerate(config, file));
|
|
146
|
+
} else if (sharesHunkContext(cwd, base, a, b, files)) {
|
|
147
|
+
level = 'L2';
|
|
148
|
+
} else if (files.length) {
|
|
149
|
+
level = 'L1';
|
|
150
|
+
} else {
|
|
151
|
+
level = 'L0';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// `matchesAny` takes ONE path, so it must be applied per file: passing the array would coerce it to
|
|
155
|
+
// the comma-joined string and miss every registry path but the accidental whole-string match.
|
|
156
|
+
const registry = files.some((file) => matchesAny(registryPatterns(config), file));
|
|
157
|
+
// §5 D-9 Tier B: a shared registry path (routes, migrations, flags, protocol tables) is a
|
|
158
|
+
// collision class of its own and is flagged at least L2 even when the hunks do not line up.
|
|
159
|
+
if (registry && levelRank(level) < levelRank('L2')) level = 'L2';
|
|
160
|
+
|
|
161
|
+
return { level, files, conflicts, ledger, registry };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function intersection(left, right) {
|
|
165
|
+
const set = new Set(right);
|
|
166
|
+
return left.filter((file) => set.has(file));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// --- cache (§6.3 `radar/<tipA>-<tipB>.json`) ---------------------------------------------------
|
|
170
|
+
|
|
171
|
+
function radarDir(cwd) {
|
|
172
|
+
return path.join(landingDir(cwd), 'radar');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function cacheFileFor(cwd, tipA, tipB) {
|
|
176
|
+
const [low, high] = tipA < tipB ? [tipA, tipB] : [tipB, tipA];
|
|
177
|
+
return path.join(radarDir(cwd), `${low}-${high}.json`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// A record is reusable only when it was written by this contract, for these two tips, under this
|
|
181
|
+
// exact policy. Anything else is a miss, never a guess.
|
|
182
|
+
function readCachedPair(cwd, tipA, tipB, hash) {
|
|
183
|
+
const record = readJsonSafe(cacheFileFor(cwd, tipA, tipB));
|
|
184
|
+
if (!record || typeof record !== 'object') return null;
|
|
185
|
+
if (record.contract !== CONTRACT || record.configHash !== hash) return null;
|
|
186
|
+
if (typeof record.level !== 'string') return null;
|
|
187
|
+
return {
|
|
188
|
+
level: record.level,
|
|
189
|
+
files: Array.isArray(record.files) ? record.files : [],
|
|
190
|
+
conflicts: Array.isArray(record.conflicts) ? record.conflicts : [],
|
|
191
|
+
ledger: record.ledger === true,
|
|
192
|
+
registry: record.registry === true,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function writeCachedPair(cwd, tipA, tipB, hash, result) {
|
|
197
|
+
const [low, high] = tipA < tipB ? [tipA, tipB] : [tipB, tipA];
|
|
198
|
+
writeJsonAtomic(cacheFileFor(cwd, tipA, tipB), {
|
|
199
|
+
contract: CONTRACT,
|
|
200
|
+
a: low,
|
|
201
|
+
b: high,
|
|
202
|
+
level: result.level,
|
|
203
|
+
files: result.files,
|
|
204
|
+
conflicts: result.conflicts,
|
|
205
|
+
ledger: result.ledger,
|
|
206
|
+
registry: result.registry,
|
|
207
|
+
configHash: hash,
|
|
208
|
+
at: new Date().toISOString(),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// --- claims (§6.3 `claims/<session>.json`, §5 D-7 soft claims) ----------------------------------
|
|
213
|
+
|
|
214
|
+
function claimsDir(cwd) {
|
|
215
|
+
return path.join(landingDir(cwd), 'claims');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Live claims only. `until <= now` is expired; an unparseable `until` is expired too (a claim with
|
|
219
|
+
// no readable expiry must never warn forever). A claim never blocks anything — it only ever adds an
|
|
220
|
+
// `L1*` warning to a pair that is otherwise clean.
|
|
221
|
+
function loadClaims(cwd, nowIso) {
|
|
222
|
+
let names;
|
|
223
|
+
try {
|
|
224
|
+
names = fs.readdirSync(claimsDir(cwd));
|
|
225
|
+
} catch (error) {
|
|
226
|
+
/* expected: no claim has ever been recorded in this repository (or the directory was pruned) —
|
|
227
|
+
"no claims" is exactly the empty list */
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
const now = Date.parse(nowIso);
|
|
231
|
+
const claims = [];
|
|
232
|
+
for (const name of names.slice().sort()) {
|
|
233
|
+
if (!name.endsWith('.json')) continue;
|
|
234
|
+
const record = readJsonSafe(path.join(claimsDir(cwd), name));
|
|
235
|
+
if (!record || typeof record !== 'object' || record.contract !== CONTRACT) continue;
|
|
236
|
+
if (typeof record.session !== 'string' || !record.session) continue;
|
|
237
|
+
if (typeof record.branch !== 'string' || !record.branch) continue;
|
|
238
|
+
if (!Array.isArray(record.paths) || !record.paths.length || !record.paths.every((entry) => typeof entry === 'string')) continue;
|
|
239
|
+
const until = Date.parse(record.until);
|
|
240
|
+
if (!Number.isFinite(until) || until <= now) continue;
|
|
241
|
+
claims.push({ session: record.session, branch: record.branch, paths: record.paths.slice(), until: record.until });
|
|
242
|
+
}
|
|
243
|
+
return claims;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// §5 D-7: a claim by the session owning one side warns the other side when it names a path that side
|
|
247
|
+
// changed since the merge base. `claims` entries are `{ session, paths }`.
|
|
248
|
+
function claimsForPair(cwd, base, pair, claims) {
|
|
249
|
+
const found = [];
|
|
250
|
+
// One changed-file list per side, computed at most once per pair and only if a claim names it.
|
|
251
|
+
const changed = new Map();
|
|
252
|
+
const changedOn = (side) => {
|
|
253
|
+
if (!changed.has(side.branch)) changed.set(side.branch, changedFilesBetween(cwd, base, side.tip));
|
|
254
|
+
return changed.get(side.branch);
|
|
255
|
+
};
|
|
256
|
+
for (const claim of claims) {
|
|
257
|
+
const other = claim.branch === pair.a.branch ? pair.b : (claim.branch === pair.b.branch ? pair.a : null);
|
|
258
|
+
if (!other) continue;
|
|
259
|
+
const files = changedOn(other);
|
|
260
|
+
if (!files.length) continue;
|
|
261
|
+
const matched = claim.paths.filter((pattern) => files.some((file) => globMatch(pattern, file)));
|
|
262
|
+
if (!matched.length) continue;
|
|
263
|
+
found.push({ session: claim.session, paths: matched });
|
|
264
|
+
}
|
|
265
|
+
return found;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// --- scope (§5 D-7: every worktree on a named branch other than the target) ---------------------
|
|
269
|
+
|
|
270
|
+
// `git --no-optional-locks status --porcelain`: tracked changes or untracked-not-ignored files. A
|
|
271
|
+
// worktree with uncommitted work is probed as a snapshot commit, so the radar sees it as it is now.
|
|
272
|
+
function worktreeDirty(worktree) {
|
|
273
|
+
if (!worktree) return false;
|
|
274
|
+
let res;
|
|
275
|
+
try {
|
|
276
|
+
res = runGitRaw(worktree, ['status', '--porcelain']);
|
|
277
|
+
} catch (error) {
|
|
278
|
+
/* expected: the worktree directory vanished between `worktree list --porcelain` and this probe
|
|
279
|
+
(a session removed its worktree) — a directory that is gone holds no uncommitted work, so it
|
|
280
|
+
is not dirty and the branch's committed tip is used */
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
return res.status === 0 && res.stdout.trim() !== '';
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// One entry per named-branch worktree other than the target, most recent tip first, capped at
|
|
287
|
+
// MAX_BRANCHES. Bare and prunable worktrees are skipped: neither has a directory the dirty probe
|
|
288
|
+
// could read, and a prunable path is by definition gone. Returns `{ branches, truncated }` where
|
|
289
|
+
// `truncated` is how many worktrees the cap dropped, so a caller can say the scope was cut.
|
|
290
|
+
//
|
|
291
|
+
// `onlyBranches` (§8 WP-3, `land status --radar-for`) is applied HERE, before the dirty probe and
|
|
292
|
+
// therefore before any snapshot commit: a worktree the caller did not name is never even read, so a
|
|
293
|
+
// CTM sweep restricted to live sessions' branches cannot spend a snapshot on a stranger's checkout.
|
|
294
|
+
function scopeBranches(cwd, target, onlyBranches = null) {
|
|
295
|
+
const entries = worktreeList(cwd);
|
|
296
|
+
const branches = [];
|
|
297
|
+
for (const entry of entries) {
|
|
298
|
+
if (!entry.branch || !entry.branch.startsWith('refs/heads/')) continue;
|
|
299
|
+
if (entry.bare || entry.prunable) continue;
|
|
300
|
+
const branch = entry.branch.slice('refs/heads/'.length);
|
|
301
|
+
if (branch === target) continue;
|
|
302
|
+
if (onlyBranches && !onlyBranches.has(branch)) continue;
|
|
303
|
+
const tip = revParseOrNull(cwd, entry.branch);
|
|
304
|
+
if (!tip) continue;
|
|
305
|
+
const dirty = worktreeDirty(entry.path);
|
|
306
|
+
branches.push({
|
|
307
|
+
branch,
|
|
308
|
+
worktree: entry.path,
|
|
309
|
+
tip,
|
|
310
|
+
dirty,
|
|
311
|
+
snapshot: false,
|
|
312
|
+
committerDate: commitCommitterDate(cwd, tip),
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
branches.sort((left, right) => (left.committerDate < right.committerDate ? 1 : left.committerDate > right.committerDate ? -1 : left.branch.localeCompare(right.branch)));
|
|
316
|
+
const scoped = branches.slice(0, MAX_BRANCHES);
|
|
317
|
+
for (const entry of scoped) {
|
|
318
|
+
if (!entry.dirty) continue;
|
|
319
|
+
// Deterministic by construction (git.js#snapshotCommit), so an unchanged dirty worktree keeps
|
|
320
|
+
// its cache key across sweeps (D-7).
|
|
321
|
+
entry.tip = snapshotCommit(entry.worktree, { deterministic: true });
|
|
322
|
+
entry.snapshot = true;
|
|
323
|
+
}
|
|
324
|
+
return { branches: scoped, truncated: branches.length - scoped.length };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function commitCommitterDate(cwd, tip) {
|
|
328
|
+
const res = runGitRaw(cwd, ['show', '-s', '--format=%cI', tip]);
|
|
329
|
+
return res.status === 0 ? res.stdout.trim() : '';
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Every unordered branch pair, plus every branch against the target (§5 D-7). A cross pair is laid
|
|
333
|
+
// out in branch-name order so `a`/`b` do not depend on the tips' committer dates; a target pair is
|
|
334
|
+
// always `<branch> × <target>`, which is how the CLI line reads.
|
|
335
|
+
function buildPairs(branches, targetTip, targetName) {
|
|
336
|
+
const pairs = [];
|
|
337
|
+
for (let index = 0; index < branches.length; index += 1) {
|
|
338
|
+
for (let other = index + 1; other < branches.length; other += 1) {
|
|
339
|
+
const [a, b] = branches[index].branch < branches[other].branch
|
|
340
|
+
? [branches[index], branches[other]]
|
|
341
|
+
: [branches[other], branches[index]];
|
|
342
|
+
pairs.push({ a, b });
|
|
343
|
+
}
|
|
344
|
+
pairs.push({
|
|
345
|
+
a: branches[index],
|
|
346
|
+
b: { branch: targetName, worktree: null, tip: targetTip, dirty: false, snapshot: false },
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
return pairs;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// --- sweep (§5 D-7, §8 AC-2a/AC-2d) ------------------------------------------------------------
|
|
353
|
+
|
|
354
|
+
// The whole radar in one call: scope, pair levels (cached / computed / unknown), soft claims and the
|
|
355
|
+
// spawn counters the tests assert on. `cacheOnly` is what makes `land status` cheap: uncached pairs
|
|
356
|
+
// come back `level: 'unknown'` and no merge-tree (or diff, or merge-base) is spawned for them.
|
|
357
|
+
//
|
|
358
|
+
// Claims are applied to pairs whose level is KNOWN, only when `cacheOnly` is false, and only when a
|
|
359
|
+
// live claim names one of the pair's two branches — judging a claim needs the changed-file list of the
|
|
360
|
+
// warned side, which costs a merge-base and a diff, and `cacheOnly` promises no such spawn. A cached
|
|
361
|
+
// pair therefore reports the level it was computed with, never an `L1*` derived on the fly; and a
|
|
362
|
+
// sweep with no claims spawns no merge base for any cached pair (`stats.mergeBaseSpawns` stays 0).
|
|
363
|
+
function sweep(cwd, opts = {}) {
|
|
364
|
+
const config = opts.config || {};
|
|
365
|
+
const target = config.target;
|
|
366
|
+
if (typeof target !== 'string' || !target) {
|
|
367
|
+
throw landingError('config_invalid', 'radar.sweep needs config.target (the branch work lands on)', { cwd });
|
|
368
|
+
}
|
|
369
|
+
const targetTip = revParseOrNull(cwd, `refs/heads/${target}`);
|
|
370
|
+
if (!targetTip) {
|
|
371
|
+
throw landingError('target_missing', `target branch ${JSON.stringify(target)} does not exist`, { target, cwd });
|
|
372
|
+
}
|
|
373
|
+
const hash = configHash(config);
|
|
374
|
+
// §8 WP-3: `opts.onlyBranches` (the CTM probe / `land status --radar-for`) restricts the swept
|
|
375
|
+
// branches to the listed names. The filter is applied in scopeBranches BEFORE any dirty probe, so
|
|
376
|
+
// an un-listed worktree is not snapshotted at all; every listed branch still gets its target pair.
|
|
377
|
+
// An EMPTY list is a real restriction ("sweep no branch"), never "no restriction": a caller that
|
|
378
|
+
// wants every branch simply omits the option. Getting this backwards would turn a probe with no
|
|
379
|
+
// live branches into a full-repo snapshot sweep.
|
|
380
|
+
const only = Array.isArray(opts.onlyBranches)
|
|
381
|
+
? new Set(opts.onlyBranches.filter((branch) => typeof branch === 'string' && branch))
|
|
382
|
+
: null;
|
|
383
|
+
const scope = scopeBranches(cwd, target, only);
|
|
384
|
+
const branches = scope.branches;
|
|
385
|
+
let pairs = buildPairs(branches, targetTip, target);
|
|
386
|
+
if (typeof opts.withBranch === 'string' && opts.withBranch) {
|
|
387
|
+
pairs = pairs.filter((pair) => pair.a.branch === opts.withBranch || pair.b.branch === opts.withBranch);
|
|
388
|
+
}
|
|
389
|
+
const claims = opts.cacheOnly ? [] : loadClaims(cwd, typeof opts.claimsNow === 'string' && opts.claimsNow ? opts.claimsNow : new Date().toISOString());
|
|
390
|
+
// Claims are keyed by branch, so a pair can only be affected when a claim names one of its two
|
|
391
|
+
// branches. Precomputed once: with no claims at all (the common case) no pair ever needs a merge
|
|
392
|
+
// base, which is what keeps a fully cached sweep at ZERO merge-base spawns (D-7 incrementality).
|
|
393
|
+
const claimBranches = new Set(claims.map((claim) => claim.branch));
|
|
394
|
+
|
|
395
|
+
const stats = { pairs: pairs.length, computed: 0, cached: 0, mergeTreeSpawns: 0, mergeBaseSpawns: 0, truncated: scope.truncated };
|
|
396
|
+
const results = [];
|
|
397
|
+
for (const pair of pairs) {
|
|
398
|
+
let result;
|
|
399
|
+
let cached = false;
|
|
400
|
+
const hit = readCachedPair(cwd, pair.a.tip, pair.b.tip, hash);
|
|
401
|
+
if (hit) {
|
|
402
|
+
result = hit;
|
|
403
|
+
cached = true;
|
|
404
|
+
stats.cached += 1;
|
|
405
|
+
} else if (opts.cacheOnly) {
|
|
406
|
+
result = { level: 'unknown', files: [], conflicts: [], ledger: false, registry: false };
|
|
407
|
+
} else {
|
|
408
|
+
result = pairLevel(cwd, pair.a.tip, pair.b.tip, { config });
|
|
409
|
+
// pairLevel spawns exactly one merge-base and exactly one merge-tree; the counters are what the
|
|
410
|
+
// incremental-recompute acceptance criteria assert on (never seconds: §10 T-5).
|
|
411
|
+
stats.mergeBaseSpawns += 1;
|
|
412
|
+
stats.mergeTreeSpawns += 1;
|
|
413
|
+
stats.computed += 1;
|
|
414
|
+
writeCachedPair(cwd, pair.a.tip, pair.b.tip, hash, result);
|
|
415
|
+
}
|
|
416
|
+
let level = result.level;
|
|
417
|
+
let pairClaims = [];
|
|
418
|
+
// A claim can only name this pair when one of the pair's branches owns it; with no claim on
|
|
419
|
+
// either side there is nothing to compare, so neither the merge base nor the diff is spawned. On a
|
|
420
|
+
// fully cached sweep with no claims this is what keeps `mergeBaseSpawns` at 0 (D-7 incrementality).
|
|
421
|
+
if (!opts.cacheOnly && level !== 'unknown' && (claimBranches.has(pair.a.branch) || claimBranches.has(pair.b.branch))) {
|
|
422
|
+
stats.mergeBaseSpawns += 1;
|
|
423
|
+
const base = mergeBase(cwd, pair.a.tip, pair.b.tip);
|
|
424
|
+
// No merge base means the two sides share nothing, so no claim can name their disagreement.
|
|
425
|
+
pairClaims = base === null ? [] : claimsForPair(cwd, base, pair, claims);
|
|
426
|
+
// §5 D-7: claims only ever lift a clean pair to `L1*` — never above, never below.
|
|
427
|
+
if (pairClaims.length && level === 'L0') level = 'L1*';
|
|
428
|
+
}
|
|
429
|
+
results.push({
|
|
430
|
+
a: pair.a.branch,
|
|
431
|
+
b: pair.b.branch,
|
|
432
|
+
level,
|
|
433
|
+
files: result.files,
|
|
434
|
+
conflicts: result.conflicts,
|
|
435
|
+
ledger: result.ledger,
|
|
436
|
+
registry: result.registry,
|
|
437
|
+
claims: pairClaims,
|
|
438
|
+
cached,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return {
|
|
443
|
+
contract: CONTRACT,
|
|
444
|
+
target,
|
|
445
|
+
targetTip,
|
|
446
|
+
branches: branches.map((entry) => ({
|
|
447
|
+
branch: entry.branch,
|
|
448
|
+
worktree: entry.worktree,
|
|
449
|
+
tip: entry.tip,
|
|
450
|
+
dirty: entry.dirty,
|
|
451
|
+
snapshot: entry.snapshot,
|
|
452
|
+
})),
|
|
453
|
+
pairs: results,
|
|
454
|
+
stats,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// The `land status` / `land conflicts` one-line summaries: the worst known level, how many pairs are
|
|
459
|
+
// at or above L2, and how many were never computed.
|
|
460
|
+
function summarize(pairs) {
|
|
461
|
+
let max = null;
|
|
462
|
+
let atLeastL2 = 0;
|
|
463
|
+
let unknown = 0;
|
|
464
|
+
for (const pair of pairs) {
|
|
465
|
+
if (pair.level === 'unknown') {
|
|
466
|
+
unknown += 1;
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
if (levelRank(pair.level) >= levelRank('L2')) atLeastL2 += 1;
|
|
470
|
+
if (max === null || levelRank(pair.level) > levelRank(max)) max = pair.level;
|
|
471
|
+
}
|
|
472
|
+
return { max: max === null ? (unknown ? 'unknown' : 'L0') : max, atLeastL2, unknown };
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
module.exports = {
|
|
476
|
+
MAX_BRANCHES,
|
|
477
|
+
LEVELS,
|
|
478
|
+
CLAIM_DEFAULT_TTL_HOURS,
|
|
479
|
+
levelRank,
|
|
480
|
+
configHash,
|
|
481
|
+
hunkContext,
|
|
482
|
+
pairLevel,
|
|
483
|
+
radarDir,
|
|
484
|
+
claimsDir,
|
|
485
|
+
cacheFileFor,
|
|
486
|
+
loadClaims,
|
|
487
|
+
summarize,
|
|
488
|
+
sweep,
|
|
489
|
+
};
|