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
|
@@ -123,11 +123,40 @@
|
|
|
123
123
|
}).join('');
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
|
|
127
|
+
// ── WP-3 models helpers, hoisted to module scope (box-owned sessions WP-3, docs/remote-session-
|
|
128
|
+
// child-transcript-model-truth-and-restart-2026-10-27.html §5 D-7): pure functions of the registry
|
|
129
|
+
// row, used by the card/sheet below AND exported as `modelsDelegateWarnings` so the shared
|
|
130
|
+
// Delegate pane (public/js/session-model-picker.js) words a box's reach verdict with THIS page's
|
|
131
|
+
// copy on the phone, exactly as it uses machinesPageModelsDelegateWarnings on the desktop.
|
|
132
|
+
function modelsBlock(machine) {
|
|
133
|
+
var block = machine && machine.models;
|
|
134
|
+
return block && typeof block === 'object' ? block : null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function modelsDelegate(machine) {
|
|
138
|
+
var block = modelsBlock(machine);
|
|
139
|
+
return block && Array.isArray(block.delegate) ? block.delegate : [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function modelsDelegateWarnings(machine) {
|
|
143
|
+
return modelsDelegate(machine).filter(function (entry) {
|
|
144
|
+
var reach = String((entry && entry.reach) || '');
|
|
145
|
+
return reach === 'unreachable' || reach === 'no_server';
|
|
146
|
+
}).map(function (entry) {
|
|
147
|
+
return '/delegate on ' + machineName(machine) + ' uses ' + String((entry && entry.model) || '')
|
|
148
|
+
+ ' through a route ' + machineName(machine) + " can't reach.";
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
126
152
|
function create(deps) {
|
|
127
153
|
var d = deps || {};
|
|
128
154
|
var $ = d.$ || function () { return null; };
|
|
129
155
|
var esc = d.esc || defaultEsc;
|
|
130
156
|
var api = d.api || function () { return Promise.reject(new Error('no api')); };
|
|
157
|
+
// hub bridge (R-13/AC-4d): the host re-mounts its per-card Access block after EVERY paint, because
|
|
158
|
+
// render() rebuilds the card markup (a load/refresh would otherwise wipe it).
|
|
159
|
+
var afterRender = typeof d.afterRender === 'function' ? d.afterRender : null;
|
|
131
160
|
var toast = d.toast || function () {};
|
|
132
161
|
var host = d.document || (typeof document !== 'undefined' ? document : null);
|
|
133
162
|
var openNewSession = d.openNewSessionSheet || function () {};
|
|
@@ -209,14 +238,15 @@
|
|
|
209
238
|
+ '</div>';
|
|
210
239
|
}
|
|
211
240
|
|
|
212
|
-
function machineFactsHtml(sample, agents) {
|
|
241
|
+
function machineFactsHtml(sample, agents, history, presence) {
|
|
213
242
|
return ''
|
|
214
243
|
+ factRow('Load', sample && sample.load1 != null ? esc(Number(sample.load1).toFixed(2)) : '')
|
|
215
244
|
+ factRow('Cores', sample && sample.cores != null ? esc(String(sample.cores)) : '')
|
|
216
245
|
+ factRow('Disk free', sample ? esc(machineFormatBytes(sample.diskFreeBytes)) : '')
|
|
217
246
|
+ factRow('GPU', esc(machineGpuText(sample && sample.gpu)))
|
|
247
|
+
+ factRow('Power', esc(machinePowerText(sample, machineHistoryRows(history), at())))
|
|
218
248
|
+ factRow('Tasks', esc(machineTaskLine(sample && sample.tasks)))
|
|
219
|
-
+ factRow('Agents', esc(machineAgentText(agents)));
|
|
249
|
+
+ factRow('Agents', esc(machineAgentText(agents, presence)));
|
|
220
250
|
}
|
|
221
251
|
|
|
222
252
|
// ── WP-3 sign-in: a coding agent ON a pooled machine, signed in from this phone ───────────────
|
|
@@ -642,6 +672,15 @@
|
|
|
642
672
|
});
|
|
643
673
|
}
|
|
644
674
|
|
|
675
|
+
// WP-3 (§8, docs/fleet-auto-update-pooled-machines-2026-10-26.html): the box's update status line
|
|
676
|
+
// — the phone twin of the desktop card's "mpc-fleet". The rule is the shared machineFleetLine;
|
|
677
|
+
// this is only its markup, so PHONE = DESKTOP PARITY holds byte for byte.
|
|
678
|
+
function fleetHtml(machine) {
|
|
679
|
+
var fleet = machineFleetLine(machine);
|
|
680
|
+
if (!fleet) return '';
|
|
681
|
+
return '<div class="mp-fleet" data-fleet-tone="' + esc(fleet.tone) + '" title="' + esc(fleet.title) + '">' + esc(fleet.text) + '</div>';
|
|
682
|
+
}
|
|
683
|
+
|
|
645
684
|
function machineCardHtml(machine, history) {
|
|
646
685
|
var m = machine || {};
|
|
647
686
|
var id = normId(m.instanceId);
|
|
@@ -668,9 +707,12 @@
|
|
|
668
707
|
+ '<span class="mp-cred" data-cred="' + esc(badge.cred) + '" title="' + esc(badge.title) + '">' + esc(badge.text) + '</span>'
|
|
669
708
|
+ '</div>'
|
|
670
709
|
+ '<div class="mp-meta">' + esc(meta) + ' ' + staleNote + '</div>'
|
|
710
|
+
+ fleetHtml(m)
|
|
671
711
|
+ sparkBlock(cpuSeries, memSeries, cpuNow, memNow)
|
|
672
|
-
+ '<div class="mp-facts">' + machineFactsHtml(sample, m.agents) + '</div>'
|
|
712
|
+
+ '<div class="mp-facts">' + machineFactsHtml(sample, m.agents, history, m.agentPresence) + '</div>'
|
|
673
713
|
+ signInBlockHtml(m)
|
|
714
|
+
+ skillsRowHtml(m)
|
|
715
|
+
+ modelsRowHtml(m)
|
|
674
716
|
+ '<div class="mp-actions">'
|
|
675
717
|
+ '<button type="button" class="mp-btn mp-fav" aria-pressed="' + (m.favorite ? 'true' : 'false') + '"'
|
|
676
718
|
+ ' title="Favorite — shown first in the picker"'
|
|
@@ -704,7 +746,7 @@
|
|
|
704
746
|
var poolNote = state.machines.length
|
|
705
747
|
? 'In a pool with ' + state.machines.length + ' other machine' + (state.machines.length === 1 ? '' : 's')
|
|
706
748
|
: 'Not in a pool yet';
|
|
707
|
-
var facts = machineFactsHtml(latest, null)
|
|
749
|
+
var facts = machineFactsHtml(latest, null, history)
|
|
708
750
|
+ factRow('Memory', latest ? esc(machineFormatBytes(latest.memUsedBytes) + ' / ' + machineFormatBytes(latest.memTotalBytes)) : '');
|
|
709
751
|
return '<article class="mp-card mp-self" data-machine-id="' + esc(id) + '" data-health="reachable">'
|
|
710
752
|
+ '<div class="mp-head">'
|
|
@@ -780,6 +822,9 @@
|
|
|
780
822
|
// the old card away) has only state.signInDrafts to be painted from.
|
|
781
823
|
restoreSignInDraftsFromState(card, adoptedKeys);
|
|
782
824
|
bind(card);
|
|
825
|
+
if (afterRender) {
|
|
826
|
+
try { afterRender(card); } catch (error) { if (typeof console !== 'undefined') console.warn('[phone-machines] afterRender failed', error); }
|
|
827
|
+
}
|
|
783
828
|
return card;
|
|
784
829
|
}
|
|
785
830
|
|
|
@@ -1127,6 +1172,715 @@
|
|
|
1127
1172
|
});
|
|
1128
1173
|
}
|
|
1129
1174
|
|
|
1175
|
+
// ── WP-9 (§9 S-9, AC-9a..AC-9d): the row's one Skills line and its Review sheet ─────────────
|
|
1176
|
+
// PHONE = DESKTOP PARITY: the same line, the same three sections, the same actions and the same
|
|
1177
|
+
// wording public/js/app/machines-page.js renders. AC-9c: a row with `skills: null` renders exactly
|
|
1178
|
+
// the card it rendered before this work — the line builder returns '' and nothing else moved.
|
|
1179
|
+
var SKILL_REASONS = {
|
|
1180
|
+
platform: 'macOS-only',
|
|
1181
|
+
hub_home_path: 'points at a path that exists only on this laptop',
|
|
1182
|
+
too_large: 'too large to send',
|
|
1183
|
+
unreadable: 'could not be read',
|
|
1184
|
+
};
|
|
1185
|
+
var SKILL_STATES = {
|
|
1186
|
+
new_on_box: 'new on this machine',
|
|
1187
|
+
same: 'same as the hub',
|
|
1188
|
+
shadows_hub: 'this machine’s copy wins',
|
|
1189
|
+
changed_on_box: 'changed on this machine',
|
|
1190
|
+
conflict: 'both sides changed',
|
|
1191
|
+
};
|
|
1192
|
+
var BOX_LOCAL_STATES = ['new_on_box', 'changed_on_box', 'conflict', 'shadows_hub'];
|
|
1193
|
+
var DIFF_LINE_CAP = 400;
|
|
1194
|
+
var review = { instanceId: '', skipped: {}, fromHub: null };
|
|
1195
|
+
|
|
1196
|
+
function skillsBlock(machine) {
|
|
1197
|
+
var block = machine && machine.skills;
|
|
1198
|
+
return block && typeof block === 'object' ? block : null;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
function skillReasonLabel(reason) {
|
|
1202
|
+
var key = String(reason || '');
|
|
1203
|
+
return SKILL_REASONS[key] || key || 'held back';
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
function skillStateLabel(value) {
|
|
1207
|
+
var key = String(value || '');
|
|
1208
|
+
return SKILL_STATES[key] || key || 'differs';
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
function skillsHeldBack(machine) {
|
|
1212
|
+
var block = skillsBlock(machine);
|
|
1213
|
+
return block && Array.isArray(block.heldBack) ? block.heldBack : [];
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
function skillsOnBox(machine) {
|
|
1217
|
+
var block = skillsBlock(machine);
|
|
1218
|
+
return block && Array.isArray(block.onBox) ? block.onBox : [];
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
function skillsPlugins(machine) {
|
|
1222
|
+
var block = skillsBlock(machine);
|
|
1223
|
+
return block && Array.isArray(block.plugins) ? block.plugins : [];
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
function skillsExcluded(machine) {
|
|
1227
|
+
var block = skillsBlock(machine);
|
|
1228
|
+
return block && Array.isArray(block.excludePlugins) ? block.excludePlugins : [];
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
function skillsBoxLocalCount(machine) {
|
|
1232
|
+
return skillsOnBox(machine).filter(function (item) {
|
|
1233
|
+
return item && BOX_LOCAL_STATES.indexOf(String(item.state)) !== -1;
|
|
1234
|
+
}).length;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
function skillsLineText(machine) {
|
|
1238
|
+
var block = skillsBlock(machine);
|
|
1239
|
+
if (!block) return '';
|
|
1240
|
+
var parts = [(Number(block.sentCount) || 0) + ' sent'];
|
|
1241
|
+
var heldBack = skillsHeldBack(machine).length;
|
|
1242
|
+
if (heldBack) parts.push(heldBack + ' held back');
|
|
1243
|
+
var local = skillsBoxLocalCount(machine);
|
|
1244
|
+
if (local) parts.push(local + ' new on ' + machineName(machine));
|
|
1245
|
+
var text = 'Skills: ' + parts.join(' · ');
|
|
1246
|
+
var error = block.pushError;
|
|
1247
|
+
if (error && (error.message || error.code)) text += ' · last push failed: ' + String(error.message || error.code);
|
|
1248
|
+
return text;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
function skillsNeedsReview(machine) {
|
|
1252
|
+
if (!skillsBlock(machine)) return false;
|
|
1253
|
+
if (skillsHeldBack(machine).length) return true;
|
|
1254
|
+
if (skillsBoxLocalCount(machine)) return true;
|
|
1255
|
+
var excluded = skillsExcluded(machine);
|
|
1256
|
+
return skillsPlugins(machine).some(function (plugin) { return excluded.indexOf(plugin) === -1; });
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
function skillsRowHtml(machine) {
|
|
1260
|
+
if (!skillsBlock(machine)) return ''; // AC-9c: no block, no bytes
|
|
1261
|
+
var id = normId(machine && machine.instanceId);
|
|
1262
|
+
return '<div class="mp-skills"><span class="mp-skills-line">' + esc(skillsLineText(machine)) + '</span>'
|
|
1263
|
+
+ (skillsNeedsReview(machine)
|
|
1264
|
+
? '<button type="button" class="mp-btn mp-skills-review" data-machine-review="' + esc(id) + '">Review</button>'
|
|
1265
|
+
: '')
|
|
1266
|
+
+ '</div>';
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
// ── WP-3: the Models line + the Review sheet's Models section (§6.2, §8 WP-3) ────────────────
|
|
1270
|
+
// The phone twin of public/js/app/machines-page.js: the same states, the same strings, from the
|
|
1271
|
+
// same row block (lib/machine-registry.js `_modelsBlockFrom`, read on the 60 s probe tick).
|
|
1272
|
+
// `null` = never read, or a box that predates WP-1 — then this card renders exactly the bytes it
|
|
1273
|
+
// rendered before this work (AC-3a), so every builder below returns '' for null.
|
|
1274
|
+
|
|
1275
|
+
function modelsUnreachable(machine) {
|
|
1276
|
+
var block = modelsBlock(machine);
|
|
1277
|
+
return block && Array.isArray(block.unreachable) ? block.unreachable : [];
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
function modelsUnreachableLabel(machine, item) {
|
|
1281
|
+
if (String((item && item.type) || '').toLowerCase() === 'ollama') return 'nothing is running there';
|
|
1282
|
+
return "can't be reached from " + machineName(machine);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
function modelsReachLabel(machine, reach) {
|
|
1286
|
+
return (String(reach || '') === 'reachable' ? 'can be reached from ' : "can't be reached from ")
|
|
1287
|
+
+ machineName(machine);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
function modelsLineText(machine) {
|
|
1291
|
+
var block = modelsBlock(machine);
|
|
1292
|
+
if (!block) return '';
|
|
1293
|
+
var parts = [(Number(block.usable) || 0) + ' usable'];
|
|
1294
|
+
var unreachable = modelsUnreachable(machine).length;
|
|
1295
|
+
if (unreachable) parts.push(unreachable + " can't be reached from " + machineName(machine));
|
|
1296
|
+
return 'Models: ' + parts.join(' · ');
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
function modelsNeedsReview(machine) {
|
|
1300
|
+
if (!modelsBlock(machine)) return false;
|
|
1301
|
+
if (modelsUnreachable(machine).length) return true;
|
|
1302
|
+
return modelsDelegateWarnings(machine).length > 0;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
function modelsRowHtml(machine) {
|
|
1306
|
+
if (!modelsBlock(machine)) return ''; // AC-3a: no block, no bytes
|
|
1307
|
+
var id = normId(machine && machine.instanceId);
|
|
1308
|
+
return '<div class="mp-models"><span class="mp-models-line">' + esc(modelsLineText(machine)) + '</span>'
|
|
1309
|
+
+ (modelsNeedsReview(machine)
|
|
1310
|
+
? '<span class="mp-models-sep">—</span>'
|
|
1311
|
+
+ '<button type="button" class="mp-btn mp-models-review" data-machine-review="' + esc(id) + '">Review</button>'
|
|
1312
|
+
: '')
|
|
1313
|
+
+ modelsDelegateWarnings(machine).map(function (text) {
|
|
1314
|
+
return '<span class="mp-models-warn">' + esc(text) + '</span>';
|
|
1315
|
+
}).join('')
|
|
1316
|
+
+ '</div>';
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/** WP-9 title, extended by WP-3: the sheet names whichever of the two blocks the row has. */
|
|
1320
|
+
function reviewTitle(machine) {
|
|
1321
|
+
var name = machineName(machine);
|
|
1322
|
+
var hasSkills = !!skillsBlock(machine);
|
|
1323
|
+
var hasModels = !!modelsBlock(machine);
|
|
1324
|
+
if (hasSkills && hasModels) return 'Skills and models on ' + name;
|
|
1325
|
+
if (hasModels) return 'Models on ' + name;
|
|
1326
|
+
return 'Skills on ' + name;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
/** WP-3: a row is reviewable while EITHER block has something to show; an absent block renders
|
|
1330
|
+
* no section, so a models-only row opens a Models-only sheet. */
|
|
1331
|
+
function reviewOpenable(machine) {
|
|
1332
|
+
return !!skillsBlock(machine) || modelsNeedsReview(machine);
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/** WP-3 + WP-4 (desktop parity): the sheet's Models section. WP-4 puts ONE control on the
|
|
1336
|
+
* unreachable rows — a checkbox, because the route ids are the box's own — and the matching
|
|
1337
|
+
* "Remove from <name>" button under the list; never on the /delegate rows. Nothing unreachable →
|
|
1338
|
+
* no control at all, and the button stays disabled until a row is ticked. */
|
|
1339
|
+
function reviewModelsHtml(machine) {
|
|
1340
|
+
if (!modelsBlock(machine)) return ''; // no block, no section
|
|
1341
|
+
var name = machineName(machine);
|
|
1342
|
+
var unreachable = modelsUnreachable(machine);
|
|
1343
|
+
var rows = unreachable.map(function (item) {
|
|
1344
|
+
var id = String((item && item.id) || '');
|
|
1345
|
+
return '<li class="mp-review-item" data-route="' + esc(id) + '">'
|
|
1346
|
+
+ '<label class="mp-review-pick"><input type="checkbox" data-role="models-pick" value="' + esc(id) + '"'
|
|
1347
|
+
+ ' aria-label="' + esc('Remove ' + id + ' from ' + name) + '">'
|
|
1348
|
+
+ '<span class="mp-review-name">' + esc(id) + '</span></label>'
|
|
1349
|
+
+ '<span class="mp-review-meta">'
|
|
1350
|
+
+ esc([String((item && item.type) || ''), String((item && item.origin) || '')].filter(Boolean).join(' · '))
|
|
1351
|
+
+ '</span>'
|
|
1352
|
+
+ '<span class="mp-review-where">' + esc(modelsUnreachableLabel(machine, item)) + '</span></li>';
|
|
1353
|
+
});
|
|
1354
|
+
if (!rows.length) rows.push('<li class="mp-review-empty">Every route on this machine can be reached.</li>');
|
|
1355
|
+
modelsDelegate(machine).forEach(function (entry) {
|
|
1356
|
+
var route = String((entry && entry.routeId) || '');
|
|
1357
|
+
var meta = [String((entry && entry.model) || ''), route ? 'route ' + route : ''].filter(Boolean).join(' · ');
|
|
1358
|
+
rows.push('<li class="mp-review-item" data-agent="' + esc(String((entry && entry.agent) || '')) + '">'
|
|
1359
|
+
+ '<span class="mp-review-name">' + esc(String((entry && entry.agent) || '')) + '</span>'
|
|
1360
|
+
+ '<span class="mp-review-meta">' + esc(meta) + '</span>'
|
|
1361
|
+
+ '<span class="mp-review-where">' + esc(modelsReachLabel(machine, entry && entry.reach)) + '</span></li>');
|
|
1362
|
+
});
|
|
1363
|
+
var remove = unreachable.length
|
|
1364
|
+
? '<div class="mp-review-models-remove"><button type="button" class="mp-btn mp-danger" data-role="models-remove"'
|
|
1365
|
+
+ ' disabled>Remove from ' + esc(name) + '</button></div>'
|
|
1366
|
+
: '';
|
|
1367
|
+
return '<section class="mp-review-section" data-section="models"><h4>Models on ' + esc(name)
|
|
1368
|
+
+ '</h4><ul>' + rows.join('') + '</ul>' + remove + fromHubHtml(machine) + '</section>';
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
/** WP-5 (desktop parity): the "From this hub" subsection — the routes THIS hub holds that the
|
|
1372
|
+
* machine does not, one row each, each row with its OWN "Use on <name>" button. No checkbox and
|
|
1373
|
+
* no bulk control (AC-5c: nothing here can copy more than one route). The list is read ONCE per
|
|
1374
|
+
* open and read again after a copy or a remove. */
|
|
1375
|
+
function fromHubState(machine) {
|
|
1376
|
+
var id = normId(machine && machine.instanceId);
|
|
1377
|
+
var store = review && review.fromHub;
|
|
1378
|
+
if (!store || normId(store.instanceId) !== id) return { status: 'loading' };
|
|
1379
|
+
if (store.error) return { status: 'error', error: String(store.error) };
|
|
1380
|
+
return { status: 'ready', routes: Array.isArray(store.routes) ? store.routes : [] };
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
function fromHubItemsHtml(machine) {
|
|
1384
|
+
if (!modelsBlock(machine)) return ''; // no block, no subsection
|
|
1385
|
+
var name = machineName(machine);
|
|
1386
|
+
var id = normId(machine && machine.instanceId);
|
|
1387
|
+
var view = fromHubState(machine);
|
|
1388
|
+
if (view.status === 'loading') {
|
|
1389
|
+
return '<li class="mp-review-empty">' + esc('Looking for routes this hub has that ' + name + ' lacks…') + '</li>';
|
|
1390
|
+
}
|
|
1391
|
+
if (view.status === 'error') return '<li class="mp-review-note">' + esc(view.error) + '</li>';
|
|
1392
|
+
if (!view.routes.length) {
|
|
1393
|
+
return '<li class="mp-review-empty">' + esc('This hub has no other routes ' + name + ' could use.') + '</li>';
|
|
1394
|
+
}
|
|
1395
|
+
return view.routes.map(function (route) {
|
|
1396
|
+
var routeId = String((route && route.id) || '');
|
|
1397
|
+
var label = String((route && route.name) || '') || routeId;
|
|
1398
|
+
var origin = String((route && route.origin) || '');
|
|
1399
|
+
var meta = [String((route && route.type) || ''), origin].filter(Boolean).join(' · ');
|
|
1400
|
+
return '<li class="mp-review-item" data-hub-route="' + esc(routeId) + '">'
|
|
1401
|
+
+ '<span class="mp-review-name">' + esc(label) + '</span>'
|
|
1402
|
+
+ '<span class="mp-review-meta">' + esc(meta) + '</span>'
|
|
1403
|
+
+ '<span class="mp-review-actions"><button type="button" class="mp-btn mp-primary" data-role="models-copy"'
|
|
1404
|
+
+ ' data-route-id="' + esc(routeId) + '" data-origin="' + esc(origin) + '">'
|
|
1405
|
+
+ 'Use on ' + esc(name) + '</button></span></li>';
|
|
1406
|
+
}).join('');
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
function fromHubHtml(machine) {
|
|
1410
|
+
if (!modelsBlock(machine)) return '';
|
|
1411
|
+
return '<div class="mp-review-from-hub" data-section="from-hub"><h5>From this hub</h5>'
|
|
1412
|
+
+ '<ul class="mp-review-list" data-role="from-hub">' + fromHubItemsHtml(machine) + '</ul></div>';
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
/** Repaint ONLY the list: the rest of the open sheet (and the note an action just wrote) stays. */
|
|
1416
|
+
function fromHubPaint() {
|
|
1417
|
+
var overlay = dialog && dialog.overlay;
|
|
1418
|
+
var machine = reviewMachine();
|
|
1419
|
+
if (!overlay || typeof overlay.querySelector !== 'function' || !modelsBlock(machine)) return false;
|
|
1420
|
+
var node = overlay.querySelector('[data-role="from-hub"]');
|
|
1421
|
+
if (!node) return false;
|
|
1422
|
+
node.innerHTML = fromHubItemsHtml(machine);
|
|
1423
|
+
return true;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
/** WP-5: ONE read of `models/copyable` per open, stored on the open sheet's own state. A refusal
|
|
1427
|
+
* is the server's own code and is shown, never retried — there is no timer here. */
|
|
1428
|
+
function fetchFromHub(instanceId) {
|
|
1429
|
+
var id = normId(instanceId);
|
|
1430
|
+
if (!id) return Promise.resolve(false);
|
|
1431
|
+
review.fromHub = { instanceId: id, loading: true };
|
|
1432
|
+
fromHubPaint();
|
|
1433
|
+
return api('/api/machines/' + encodeURIComponent(id) + '/models/copyable')
|
|
1434
|
+
.then(function (payload) {
|
|
1435
|
+
if (normId(review.instanceId) !== id) return false; // the sheet moved on meanwhile
|
|
1436
|
+
review.fromHub = {
|
|
1437
|
+
instanceId: id,
|
|
1438
|
+
routes: (payload && Array.isArray(payload.routes)) ? payload.routes : [],
|
|
1439
|
+
};
|
|
1440
|
+
fromHubPaint();
|
|
1441
|
+
return true;
|
|
1442
|
+
})
|
|
1443
|
+
.catch(function (error) {
|
|
1444
|
+
// REPORT: the subsection says why it is empty; the sheet stays open and nothing is retried.
|
|
1445
|
+
if (normId(review.instanceId) !== id) return false;
|
|
1446
|
+
review.fromHub = { instanceId: id, error: serverError(error) };
|
|
1447
|
+
fromHubPaint();
|
|
1448
|
+
return false;
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/** The name a row was painted with — the success note says what travelled, in the user's words. */
|
|
1453
|
+
function fromHubRouteName(routeId) {
|
|
1454
|
+
var routes = (review && review.fromHub && Array.isArray(review.fromHub.routes)) ? review.fromHub.routes : [];
|
|
1455
|
+
var match = routes.filter(function (route) {
|
|
1456
|
+
return String((route && route.id) || '') === String(routeId == null ? '' : routeId);
|
|
1457
|
+
})[0];
|
|
1458
|
+
return String((match && match.name) || '') || String(routeId == null ? '' : routeId);
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
/** WP-5: after a copy or a remove, re-read BOTH the list and what this hub could still offer. */
|
|
1462
|
+
function reloadReview() {
|
|
1463
|
+
var id = normId(review && review.instanceId);
|
|
1464
|
+
return reviewRefresh().then(function () {
|
|
1465
|
+
return fetchFromHub(id);
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
/** WP-5 / AC-5c (desktop parity): "Use on <name>" — ONE route and its key, and nothing else; the
|
|
1470
|
+
* confirm says so before anything is sent, and `expectOrigin` is the origin the row was painted
|
|
1471
|
+
* with, so a route that moved on the hub is refused instead of copied. */
|
|
1472
|
+
function copyModel(instanceId, button) {
|
|
1473
|
+
var id = normId(instanceId);
|
|
1474
|
+
var name = machineName(reviewMachine() || { instanceId: id });
|
|
1475
|
+
var attr = function (key) {
|
|
1476
|
+
return button && typeof button.getAttribute === 'function' ? String(button.getAttribute(key) || '') : '';
|
|
1477
|
+
};
|
|
1478
|
+
var routeId = attr('data-route-id');
|
|
1479
|
+
var origin = attr('data-origin');
|
|
1480
|
+
if (!id || !routeId) return Promise.resolve(false);
|
|
1481
|
+
var label = fromHubRouteName(routeId);
|
|
1482
|
+
if (confirmImpl && !confirmImpl('Copies this route and its key to ' + name + '. Only this route is copied.')) {
|
|
1483
|
+
return Promise.resolve(false);
|
|
1484
|
+
}
|
|
1485
|
+
busy(button, true);
|
|
1486
|
+
return api('/api/machines/' + encodeURIComponent(id) + '/models/copy', {
|
|
1487
|
+
method: 'POST',
|
|
1488
|
+
body: { routeId: routeId, expectOrigin: origin },
|
|
1489
|
+
}).then(function () {
|
|
1490
|
+
busy(button, false);
|
|
1491
|
+
// After the reload, which repaints the sheet (a note set first would be wiped).
|
|
1492
|
+
return reloadReview().then(function (reloaded) {
|
|
1493
|
+
reviewNote('Copied ' + label + ' to ' + name, 'ok');
|
|
1494
|
+
return reloaded;
|
|
1495
|
+
});
|
|
1496
|
+
}).catch(function (error) {
|
|
1497
|
+
// REPORT: the refusal (or the transport fault) stays on the sheet, which is still open.
|
|
1498
|
+
busy(button, false);
|
|
1499
|
+
reviewNote(serverError(error), 'bad');
|
|
1500
|
+
return false;
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
function reviewItemKey(agent, name) {
|
|
1505
|
+
return String(agent || '') + ':' + String(name || '');
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
function reviewHeldBackHtml(machine) {
|
|
1509
|
+
if (!skillsBlock(machine)) return ''; // no block, no section (§8 WP-3)
|
|
1510
|
+
var items = skillsHeldBack(machine);
|
|
1511
|
+
var body = items.length
|
|
1512
|
+
? items.map(function (item) {
|
|
1513
|
+
var where = item && item.file
|
|
1514
|
+
? '<span class="mp-review-where">' + esc(String(item.file) + (item.line ? ':' + item.line : '')) + '</span>'
|
|
1515
|
+
: '';
|
|
1516
|
+
return '<li class="mp-review-item" data-key="' + esc(reviewItemKey(item && item.agent, item && item.name)) + '">'
|
|
1517
|
+
+ '<span class="mp-review-name">' + esc(String((item && item.name) || '')) + '</span>'
|
|
1518
|
+
+ '<span class="mp-review-meta">' + esc([String((item && item.agent) || ''), skillReasonLabel(item && item.reason)].filter(Boolean).join(' · ')) + '</span>'
|
|
1519
|
+
+ where + '</li>';
|
|
1520
|
+
}).join('')
|
|
1521
|
+
: '<li class="mp-review-empty">Nothing was held back.</li>';
|
|
1522
|
+
return '<section class="mp-review-section" data-section="held-back"><h4>Held back</h4><ul>' + body + '</ul></section>';
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
function reviewItemActionsHtml(instanceId, item) {
|
|
1526
|
+
var state = String((item && item.state) || '');
|
|
1527
|
+
var agent = String((item && item.agent) || '');
|
|
1528
|
+
var name = String((item && item.name) || '');
|
|
1529
|
+
var attrs = ' data-review-action data-review-id="' + esc(instanceId) + '" data-review-agent="' + esc(agent)
|
|
1530
|
+
+ '" data-review-name="' + esc(name) + '" data-review-box-hash="' + esc(String((item && item.boxHash) || '')) + '"';
|
|
1531
|
+
var out = '';
|
|
1532
|
+
if (state !== 'shadows_hub') out += '<button type="button" class="mp-btn mp-primary"' + attrs + ' data-review-verb="import">Import</button>';
|
|
1533
|
+
if (state !== 'new_on_box') out += '<button type="button" class="mp-btn"' + attrs + ' data-review-verb="retire">Use the laptop’s copy</button>';
|
|
1534
|
+
out += '<button type="button" class="mp-btn"' + attrs + ' data-review-skip>Skip</button>';
|
|
1535
|
+
return out;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
function reviewOnBoxHtml(machine) {
|
|
1539
|
+
if (!skillsBlock(machine)) return ''; // no block, no section (§8 WP-3)
|
|
1540
|
+
var id = normId(machine && machine.instanceId);
|
|
1541
|
+
var items = skillsOnBox(machine).filter(function (item) { return item && String(item.state) !== 'same'; });
|
|
1542
|
+
var body = items.length
|
|
1543
|
+
? items.map(function (item) {
|
|
1544
|
+
var name = String((item && item.name) || '');
|
|
1545
|
+
var key = reviewItemKey(item && item.agent, name);
|
|
1546
|
+
return '<li class="mp-review-item" data-key="' + esc(key) + '">'
|
|
1547
|
+
+ '<span class="mp-review-name">' + esc(name) + '</span>'
|
|
1548
|
+
+ '<span class="mp-review-meta">' + esc([String((item && item.agent) || ''), skillStateLabel(item && item.state)].filter(Boolean).join(' · ')) + '</span>'
|
|
1549
|
+
+ '<span class="mp-review-actions">' + reviewItemActionsHtml(id, item)
|
|
1550
|
+
+ '<button type="button" class="mp-btn" data-review-diff data-review-id="' + esc(id) + '"'
|
|
1551
|
+
+ ' data-review-agent="' + esc(String((item && item.agent) || '')) + '" data-review-name="' + esc(name) + '">Show diff</button>'
|
|
1552
|
+
+ '</span><div class="mp-review-diff" hidden></div></li>';
|
|
1553
|
+
}).join('')
|
|
1554
|
+
: '<li class="mp-review-empty">This machine has no skills of its own.</li>';
|
|
1555
|
+
return '<section class="mp-review-section" data-section="on-box"><h4>On ' + esc(machineName(machine)) + '</h4><ul>' + body + '</ul></section>';
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
function reviewPluginsHtml(machine) {
|
|
1559
|
+
if (!skillsBlock(machine)) return ''; // no block, no section (§8 WP-3)
|
|
1560
|
+
var plugins = skillsPlugins(machine);
|
|
1561
|
+
var excluded = skillsExcluded(machine);
|
|
1562
|
+
var body = plugins.length
|
|
1563
|
+
? plugins.map(function (plugin) {
|
|
1564
|
+
var id = String(plugin);
|
|
1565
|
+
return '<label class="mp-review-plugin"><input type="checkbox" value="' + esc(id) + '"'
|
|
1566
|
+
+ (excluded.indexOf(id) !== -1 ? ' checked' : '') + '> ' + esc(id) + '</label>';
|
|
1567
|
+
}).join('')
|
|
1568
|
+
: '<p class="mp-review-empty">The hub sends no plugins to this machine.</p>';
|
|
1569
|
+
return '<section class="mp-review-section" data-section="plugins"><h4>Plugins</h4>'
|
|
1570
|
+
+ '<p class="mp-review-note">Checked plugins are not sent to this machine.</p>'
|
|
1571
|
+
+ '<div class="mp-review-plugins">' + body + '</div>'
|
|
1572
|
+
+ '<div class="mp-review-actions"><button type="button" class="mp-btn mp-primary" data-review-save-plugins'
|
|
1573
|
+
+ ' data-review-id="' + esc(normId(machine && machine.instanceId)) + '">Save</button></div></section>';
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
function reviewSheetHtml(machine) {
|
|
1577
|
+
return '<section class="model-picker-sheet mp-modal mp-review-sheet" role="dialog" aria-modal="true" aria-labelledby="mp-review-title">'
|
|
1578
|
+
+ '<div class="model-picker-head"><div><h2 id="mp-review-title">' + esc(reviewTitle(machine)) + '</h2>'
|
|
1579
|
+
+ '<p>' + esc(skillsLineText(machine) || modelsLineText(machine)) + '</p></div>'
|
|
1580
|
+
+ '<button type="button" class="model-picker-close" id="mp-review-close" aria-label="Close">×</button></div>'
|
|
1581
|
+
+ '<p class="mp-review-note" data-role="review-note" role="status" aria-live="polite"></p>'
|
|
1582
|
+
+ reviewHeldBackHtml(machine) + reviewOnBoxHtml(machine) + reviewPluginsHtml(machine)
|
|
1583
|
+
+ reviewModelsHtml(machine)
|
|
1584
|
+
+ '<div class="mp-modal-actions"><button type="button" class="mp-btn" id="mp-review-done">Close</button></div>'
|
|
1585
|
+
+ '</section>';
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
function reviewMachine() {
|
|
1589
|
+
var id = normId(review.instanceId);
|
|
1590
|
+
return state.machines.filter(function (m) { return normId(m && m.instanceId) === id; })[0] || null;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
function reviewNote(text, kind) {
|
|
1594
|
+
var node = (dialog && dialog.overlay && typeof dialog.overlay.querySelector === 'function')
|
|
1595
|
+
? dialog.overlay.querySelector('[data-role="review-note"]') : null;
|
|
1596
|
+
if (!node) return;
|
|
1597
|
+
node.textContent = String(text || '');
|
|
1598
|
+
node.className = 'mp-review-note' + (kind === 'bad' ? ' bad' : '');
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
/** Client-only Skip: the item leaves this sheet and stays gone across a repaint — no server call. */
|
|
1602
|
+
function reviewSkip(button) {
|
|
1603
|
+
if (!button || typeof button.getAttribute !== 'function') return false;
|
|
1604
|
+
review.skipped[reviewItemKey(button.getAttribute('data-review-agent'), button.getAttribute('data-review-name'))] = true;
|
|
1605
|
+
var item = typeof button.closest === 'function' ? button.closest('.mp-review-item') : null;
|
|
1606
|
+
if (item) item.hidden = true;
|
|
1607
|
+
return true;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
function applySkips() {
|
|
1611
|
+
var overlay = dialog && dialog.overlay;
|
|
1612
|
+
if (!overlay || typeof overlay.querySelectorAll !== 'function') return;
|
|
1613
|
+
Array.prototype.slice.call(overlay.querySelectorAll('.mp-review-item[data-key]') || []).forEach(function (item) {
|
|
1614
|
+
var key = typeof item.getAttribute === 'function' ? item.getAttribute('data-key') : null;
|
|
1615
|
+
if (key && review.skipped[key]) item.hidden = true;
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
/** AC-9a: re-read the list and repaint the OPEN sheet — never a page reload. */
|
|
1620
|
+
function reviewRefresh() {
|
|
1621
|
+
return load({ silent: true }).then(function () {
|
|
1622
|
+
var machine = reviewMachine();
|
|
1623
|
+
if (!(dialog && dialog.overlay && dialog.review)) return true; // the sheet was closed or replaced meanwhile
|
|
1624
|
+
if (machine && reviewOpenable(machine)) {
|
|
1625
|
+
dialog.overlay.innerHTML = reviewSheetHtml(machine);
|
|
1626
|
+
bindSheet();
|
|
1627
|
+
applySkips();
|
|
1628
|
+
} else {
|
|
1629
|
+
closeDialog(); // same as desktop machinesPageReviewPaint: nothing left to review → close
|
|
1630
|
+
}
|
|
1631
|
+
return true;
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
function openReviewSheet(instanceId) {
|
|
1636
|
+
var id = normId(instanceId);
|
|
1637
|
+
var machine = state.machines.filter(function (m) { return normId(m && m.instanceId) === id; })[0] || null;
|
|
1638
|
+
if (!reviewOpenable(machine)) return null;
|
|
1639
|
+
closeDialog();
|
|
1640
|
+
review = { instanceId: id, skipped: {}, fromHub: null };
|
|
1641
|
+
var overlay = mountDialog(reviewSheetHtml(machine));
|
|
1642
|
+
if (!overlay) return null;
|
|
1643
|
+
dialog = { overlay: overlay, review: true };
|
|
1644
|
+
bindSheet();
|
|
1645
|
+
// WP-5: one read of the hub's copyable routes per open — the sheet is already painted, so the
|
|
1646
|
+
// subsection shows "Looking for…" until this lands.
|
|
1647
|
+
fetchFromHub(id);
|
|
1648
|
+
return dialog;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
function bindSheet() {
|
|
1652
|
+
var close = $('mp-review-close');
|
|
1653
|
+
if (close && typeof close.addEventListener === 'function') close.addEventListener('click', closeDialog);
|
|
1654
|
+
var done = $('mp-review-done');
|
|
1655
|
+
if (done && typeof done.addEventListener === 'function') done.addEventListener('click', closeDialog);
|
|
1656
|
+
// The sheet mounts on document.body (mountDialog), OUTSIDE the card whose delegated click/change
|
|
1657
|
+
// listeners dispatch every data-review-* control — so a tap inside it never reached them.
|
|
1658
|
+
// Binding the overlay to the same dispatcher (bind() is idempotent per scope) makes the sheet's
|
|
1659
|
+
// Import / Use-the-laptop's-copy / Save / Remove-from-<box> controls work on the phone.
|
|
1660
|
+
if (dialog && dialog.overlay && dialog.overlay.dataset) bind(dialog.overlay);
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
function busy(node, state_) {
|
|
1664
|
+
if (!node || typeof node !== 'object') return;
|
|
1665
|
+
node.disabled = !!state_;
|
|
1666
|
+
if (typeof node.setAttribute === 'function') node.setAttribute('aria-busy', state_ ? 'true' : 'false');
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
function reviewActionFailed(error) {
|
|
1670
|
+
var payload = (error && error.payload) || null;
|
|
1671
|
+
var code = String((payload && (payload.error || payload.code)) || (error && (error.code || error.message)) || '');
|
|
1672
|
+
if (Number(error && error.status) === 409 || code.indexOf('agent_skill_changed') !== -1) {
|
|
1673
|
+
reviewNote('This skill changed on the box since you opened Review — reopen to see the new version.', 'bad');
|
|
1674
|
+
return reviewRefresh();
|
|
1675
|
+
}
|
|
1676
|
+
reviewNote(serverError(error), 'bad');
|
|
1677
|
+
return false;
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
function reviewAction(instanceId, agent, name, boxHash, verb, button) {
|
|
1681
|
+
var action = String(verb) === 'retire' ? 'retire' : 'import';
|
|
1682
|
+
var body = { agent: String(agent || ''), name: String(name || '') };
|
|
1683
|
+
if (boxHash) body.expectBoxHash = String(boxHash);
|
|
1684
|
+
busy(button, true);
|
|
1685
|
+
return api('/api/machines/' + encodeURIComponent(normId(instanceId)) + '/skills/' + action, { method: 'POST', body: body })
|
|
1686
|
+
.then(function () {
|
|
1687
|
+
busy(button, false);
|
|
1688
|
+
setStatus(action === 'import'
|
|
1689
|
+
? 'Imported ' + String(name || '') + ' from this machine.'
|
|
1690
|
+
: 'This machine now uses the laptop’s copy of ' + String(name || '') + '.');
|
|
1691
|
+
delete review.skipped[reviewItemKey(agent, name)];
|
|
1692
|
+
return reviewRefresh();
|
|
1693
|
+
})
|
|
1694
|
+
.catch(function (error) {
|
|
1695
|
+
// REPORT: the refusal (or the transport fault) stays on the sheet, which is still open.
|
|
1696
|
+
busy(button, false);
|
|
1697
|
+
return reviewActionFailed(error);
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
function savePlugins(instanceId, button) {
|
|
1702
|
+
var overlay = dialog && dialog.overlay;
|
|
1703
|
+
var excluded = [];
|
|
1704
|
+
if (overlay && typeof overlay.querySelectorAll === 'function') {
|
|
1705
|
+
Array.prototype.slice.call(overlay.querySelectorAll('.mp-review-plugins input') || []).forEach(function (box) {
|
|
1706
|
+
if (box && box.checked) excluded.push(String(box.value == null ? '' : box.value));
|
|
1707
|
+
});
|
|
1708
|
+
}
|
|
1709
|
+
busy(button, true);
|
|
1710
|
+
return api('/api/machines/' + encodeURIComponent(normId(instanceId)) + '/skills/exclude-plugins', {
|
|
1711
|
+
method: 'PUT',
|
|
1712
|
+
body: { plugins: excluded },
|
|
1713
|
+
}).then(function () {
|
|
1714
|
+
busy(button, false);
|
|
1715
|
+
setStatus(excluded.length
|
|
1716
|
+
? 'Plugins saved — ' + excluded.length + ' not sent to this machine.'
|
|
1717
|
+
: 'Plugins saved — every plugin is sent to this machine.');
|
|
1718
|
+
return reviewRefresh();
|
|
1719
|
+
}).catch(function (error) {
|
|
1720
|
+
busy(button, false);
|
|
1721
|
+
reviewNote(serverError(error), 'bad');
|
|
1722
|
+
return false;
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
/** WP-4: the route ids ticked in the open sheet — the only truth a Remove POST may be built from. */
|
|
1727
|
+
function modelsChecked() {
|
|
1728
|
+
var overlay = dialog && dialog.overlay;
|
|
1729
|
+
var picked = [];
|
|
1730
|
+
if (overlay && typeof overlay.querySelectorAll === 'function') {
|
|
1731
|
+
Array.prototype.slice.call(overlay.querySelectorAll('[data-role="models-pick"]') || []).forEach(function (box) {
|
|
1732
|
+
if (box && box.checked) picked.push(String(box.value == null ? '' : box.value));
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1735
|
+
return picked;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
/** WP-4: one tick or untick → the button is live exactly while something is ticked. Returns the count. */
|
|
1739
|
+
function modelsPicked() {
|
|
1740
|
+
var overlay = dialog && dialog.overlay;
|
|
1741
|
+
var count = modelsChecked().length;
|
|
1742
|
+
var node = overlay && typeof overlay.querySelector === 'function'
|
|
1743
|
+
? overlay.querySelector('[data-role="models-remove"]') : null;
|
|
1744
|
+
if (node) node.disabled = count === 0;
|
|
1745
|
+
return count;
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
/** WP-4: "Remove from <name>" — the box deletes these routes and the keys it holds for them; the
|
|
1749
|
+
* hub keeps its own copies, which is what the confirm says before anything is sent. A cancelled
|
|
1750
|
+
* confirm is not a request, only the TICKED ids travel, and the sheet is re-read after. */
|
|
1751
|
+
function removeModels(instanceId, button) {
|
|
1752
|
+
var id = normId(instanceId);
|
|
1753
|
+
var name = machineName(reviewMachine() || { instanceId: id });
|
|
1754
|
+
if (!modelsChecked().length) return Promise.resolve(false);
|
|
1755
|
+
if (confirmImpl && !confirmImpl('Deletes these routes and their keys from ' + name + '. This hub keeps its own copies.')) {
|
|
1756
|
+
return Promise.resolve(false);
|
|
1757
|
+
}
|
|
1758
|
+
var routeIds = modelsChecked();
|
|
1759
|
+
busy(button, true);
|
|
1760
|
+
return api('/api/machines/' + encodeURIComponent(id) + '/models/remove', {
|
|
1761
|
+
method: 'POST',
|
|
1762
|
+
body: { routeIds: routeIds },
|
|
1763
|
+
}).then(function (result) {
|
|
1764
|
+
busy(button, false);
|
|
1765
|
+
var data = (result && typeof result === 'object') ? result : {};
|
|
1766
|
+
var removed = Array.isArray(data.removed) ? data.removed.length : routeIds.length;
|
|
1767
|
+
var missing = Array.isArray(data.missing) ? data.missing.length : 0;
|
|
1768
|
+
// The note goes AFTER the reload, which repaints the sheet. WP-5: the removals also change
|
|
1769
|
+
// what this hub can offer, hence the reload of both lists.
|
|
1770
|
+
return reloadReview().then(function (reloaded) {
|
|
1771
|
+
reviewNote('Removed ' + removed + ' from ' + name + (missing ? ' · ' + missing + ' already gone' : ''), 'ok');
|
|
1772
|
+
return reloaded;
|
|
1773
|
+
});
|
|
1774
|
+
}).catch(function (error) {
|
|
1775
|
+
// REPORT: the refusal (or the transport fault) stays on the sheet, which is still open.
|
|
1776
|
+
busy(button, false);
|
|
1777
|
+
reviewNote(serverError(error), 'bad');
|
|
1778
|
+
return false;
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
// The diff ALGORITHM is public/js/prompt-diff.js — the same module the desktop page loads in
|
|
1783
|
+
// index.html and the phone does not, so the phone pulls the one copy in on first use (never a
|
|
1784
|
+
// second implementation of the LCS).
|
|
1785
|
+
var promptDiffPromise = null;
|
|
1786
|
+
|
|
1787
|
+
function promptDiffModule() {
|
|
1788
|
+
if (root.PromptDiff && typeof root.PromptDiff.diffLines === 'function') return Promise.resolve(root.PromptDiff);
|
|
1789
|
+
if (d.promptDiff && typeof d.promptDiff.diffLines === 'function') return Promise.resolve(d.promptDiff);
|
|
1790
|
+
if (promptDiffPromise) return promptDiffPromise;
|
|
1791
|
+
var doc = host || (typeof document !== 'undefined' ? document : null);
|
|
1792
|
+
if (!doc || typeof doc.createElement !== 'function') return Promise.resolve(null);
|
|
1793
|
+
var src = typeof d.promptDiffSrc === 'string' ? d.promptDiffSrc : '/js/prompt-diff.js';
|
|
1794
|
+
promptDiffPromise = new Promise(function (resolve) {
|
|
1795
|
+
var script = doc.createElement('script');
|
|
1796
|
+
script.src = src;
|
|
1797
|
+
script.onload = function () {
|
|
1798
|
+
resolve(root.PromptDiff && typeof root.PromptDiff.diffLines === 'function' ? root.PromptDiff : null);
|
|
1799
|
+
};
|
|
1800
|
+
script.onerror = function () { resolve(null); };
|
|
1801
|
+
var parent = doc.head || doc.body || doc.documentElement;
|
|
1802
|
+
if (parent && typeof parent.appendChild === 'function') parent.appendChild(script);
|
|
1803
|
+
else resolve(null);
|
|
1804
|
+
});
|
|
1805
|
+
return promptDiffPromise;
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
function diffFileHtml(module, boxFile, hubFile) {
|
|
1809
|
+
var filePath = String((boxFile && boxFile.path) || (hubFile && hubFile.path) || '');
|
|
1810
|
+
var size = Number((boxFile && boxFile.size) || (hubFile && hubFile.size) || 0);
|
|
1811
|
+
var head = '<p class="mp-diff-file">' + esc(filePath) + '</p>';
|
|
1812
|
+
if ((boxFile && boxFile.binary) || (hubFile && hubFile.binary)) {
|
|
1813
|
+
return head + '<p class="mp-diff-binary">' + esc('binary file, ' + machineFormatBytes(size)) + '</p>';
|
|
1814
|
+
}
|
|
1815
|
+
var ops = module ? module.diffLines(hubFile ? String(hubFile.text || '') : '', boxFile ? String(boxFile.text || '') : '') : null;
|
|
1816
|
+
if (!Array.isArray(ops)) return head + '<p class="mp-diff-binary">' + esc('binary file, ' + machineFormatBytes(size)) + '</p>';
|
|
1817
|
+
var shown = ops.slice(0, DIFF_LINE_CAP);
|
|
1818
|
+
return head + '<div class="mp-diff">' + shown.map(function (op) {
|
|
1819
|
+
var cls = op.type === 'add' ? 'mp-diff-add' : (op.type === 'del' ? 'mp-diff-del' : 'mp-diff-eq');
|
|
1820
|
+
var sign = op.type === 'add' ? '+' : (op.type === 'del' ? '-' : ' ');
|
|
1821
|
+
return '<span class="' + cls + '">' + esc(sign + ' ' + op.text) + '</span>';
|
|
1822
|
+
}).join('') + '</div>'
|
|
1823
|
+
+ (ops.length > shown.length ? '<p class="mp-review-note">' + esc('… ' + (ops.length - shown.length) + ' more lines') + '</p>' : '');
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
/** A preview payload + a diff module → the per-file markup. Pure, so the sheet is provable. */
|
|
1827
|
+
function diffHtml(module, preview) {
|
|
1828
|
+
var boxFiles = (preview && preview.box && Array.isArray(preview.box.files)) ? preview.box.files : [];
|
|
1829
|
+
var hubFiles = (preview && preview.hub && Array.isArray(preview.hub.files)) ? preview.hub.files : [];
|
|
1830
|
+
var hubByName = {};
|
|
1831
|
+
hubFiles.forEach(function (file) { if (file && file.path) hubByName[String(file.path)] = file; });
|
|
1832
|
+
var seen = {};
|
|
1833
|
+
var out = boxFiles.map(function (file) {
|
|
1834
|
+
var key = String((file && file.path) || '');
|
|
1835
|
+
seen[key] = true;
|
|
1836
|
+
return diffFileHtml(module, file, hubByName[key] || null);
|
|
1837
|
+
});
|
|
1838
|
+
hubFiles.forEach(function (file) {
|
|
1839
|
+
var key = String((file && file.path) || '');
|
|
1840
|
+
if (seen[key]) return;
|
|
1841
|
+
out.push('<p class="mp-diff-file">' + esc(key) + '</p><p class="mp-diff-binary">'
|
|
1842
|
+
+ esc('only on this hub — importing replaces it (a backup is kept)') + '</p>');
|
|
1843
|
+
});
|
|
1844
|
+
return out.join('') || '<p class="mp-review-empty">No files on either side.</p>';
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
function diffNode(agent, name) {
|
|
1848
|
+
var overlay = dialog && dialog.overlay;
|
|
1849
|
+
if (!overlay || typeof overlay.querySelector !== 'function') return null;
|
|
1850
|
+
var key = reviewItemKey(agent, name).replace(/"/g, '\\"');
|
|
1851
|
+
var item = overlay.querySelector('.mp-review-item[data-key="' + key + '"]');
|
|
1852
|
+
return item && typeof item.querySelector === 'function' ? item.querySelector('.mp-review-diff') : null;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
/** AC-9b: the hub's copy vs the box's, through the ONE diff module (lazily loaded on the phone). */
|
|
1856
|
+
function showDiff(instanceId, agent, name, button) {
|
|
1857
|
+
var node = diffNode(agent, name);
|
|
1858
|
+
if (node && !node.hidden) { node.hidden = true; return Promise.resolve(true); }
|
|
1859
|
+
busy(button, true);
|
|
1860
|
+
return api('/api/machines/' + encodeURIComponent(normId(instanceId)) + '/skills/preview?agent='
|
|
1861
|
+
+ encodeURIComponent(String(agent || '')) + '&name=' + encodeURIComponent(String(name || '')))
|
|
1862
|
+
.then(function (payload) {
|
|
1863
|
+
return promptDiffModule().then(function (module) {
|
|
1864
|
+
busy(button, false);
|
|
1865
|
+
node = diffNode(agent, name);
|
|
1866
|
+
if (!node) return false;
|
|
1867
|
+
node.hidden = false;
|
|
1868
|
+
node.innerHTML = diffHtml(module, payload);
|
|
1869
|
+
if (!module) node.innerHTML += '<p class="mp-review-note">' + esc('The diff module did not load — the file list above is still the truth.') + '</p>';
|
|
1870
|
+
return true;
|
|
1871
|
+
});
|
|
1872
|
+
})
|
|
1873
|
+
.catch(function (error) {
|
|
1874
|
+
busy(button, false);
|
|
1875
|
+
node = diffNode(agent, name);
|
|
1876
|
+
if (node) {
|
|
1877
|
+
node.hidden = false;
|
|
1878
|
+
node.innerHTML = '<p class="mp-review-note">' + esc(serverError(error)) + '</p>';
|
|
1879
|
+
}
|
|
1880
|
+
return false;
|
|
1881
|
+
});
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1130
1884
|
// ── wiring ─────────────────────────────────────────────────────────────────────────────────
|
|
1131
1885
|
// ONE delegated click listener plus one change listener on the page, so a re-render never loses a
|
|
1132
1886
|
// binding and a rename input only writes on commit (desktop parity: rename on `change`).
|
|
@@ -1196,6 +1950,51 @@
|
|
|
1196
1950
|
if (join) { event.preventDefault(); openAddDialog({ url: join.getAttribute('data-machine-url') || '' }); return; }
|
|
1197
1951
|
var signIn = closest('[data-machine-signin]');
|
|
1198
1952
|
if (signIn) { event.preventDefault(); signInToo(signIn.getAttribute('data-machine-signin')); return; }
|
|
1953
|
+
// WP-9: the Review sheet's own actions (same verbs, same wording as the desktop dialog).
|
|
1954
|
+
var reviewOpen = closest('[data-machine-review]');
|
|
1955
|
+
if (reviewOpen) { event.preventDefault(); openReviewSheet(reviewOpen.getAttribute('data-machine-review')); return; }
|
|
1956
|
+
var skip = closest('[data-review-skip]');
|
|
1957
|
+
if (skip) { event.preventDefault(); reviewSkip(skip); return; }
|
|
1958
|
+
var diff = closest('[data-review-diff]');
|
|
1959
|
+
if (diff) {
|
|
1960
|
+
event.preventDefault();
|
|
1961
|
+
showDiff(diff.getAttribute('data-review-id'), diff.getAttribute('data-review-agent'), diff.getAttribute('data-review-name'), diff);
|
|
1962
|
+
return;
|
|
1963
|
+
}
|
|
1964
|
+
var savePluginsNode = closest('[data-review-save-plugins]');
|
|
1965
|
+
if (savePluginsNode) {
|
|
1966
|
+
event.preventDefault();
|
|
1967
|
+
savePlugins(savePluginsNode.getAttribute('data-review-id'), savePluginsNode);
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
// WP-4: "Remove from <name>" — the instance id is the sheet's own (review.instanceId), never
|
|
1971
|
+
// read back out of the markup.
|
|
1972
|
+
var removeModelsNode = closest('[data-role="models-remove"]');
|
|
1973
|
+
if (removeModelsNode) {
|
|
1974
|
+
event.preventDefault();
|
|
1975
|
+
removeModels(review.instanceId, removeModelsNode);
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
// WP-5: "Use on <name>" — one route per tap, the sheet's own id, the row's own route/origin.
|
|
1979
|
+
var copyModelNode = closest('[data-role="models-copy"]');
|
|
1980
|
+
if (copyModelNode) {
|
|
1981
|
+
event.preventDefault();
|
|
1982
|
+
copyModel(review.instanceId, copyModelNode);
|
|
1983
|
+
return;
|
|
1984
|
+
}
|
|
1985
|
+
var action = closest('[data-review-action]');
|
|
1986
|
+
if (action) {
|
|
1987
|
+
event.preventDefault();
|
|
1988
|
+
reviewAction(
|
|
1989
|
+
action.getAttribute('data-review-id'),
|
|
1990
|
+
action.getAttribute('data-review-agent'),
|
|
1991
|
+
action.getAttribute('data-review-name'),
|
|
1992
|
+
action.getAttribute('data-review-box-hash'),
|
|
1993
|
+
action.getAttribute('data-review-verb'),
|
|
1994
|
+
action,
|
|
1995
|
+
);
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1199
1998
|
// WP-3: sign a coding agent in ON another machine (the passkey row above is the CTM LOGIN).
|
|
1200
1999
|
var agentSignIn = closest('[data-machine-sign-in]');
|
|
1201
2000
|
if (agentSignIn) {
|
|
@@ -1228,6 +2027,9 @@
|
|
|
1228
2027
|
scope.addEventListener('change', function (event) {
|
|
1229
2028
|
var target = event.target;
|
|
1230
2029
|
var closest = target && typeof target.closest === 'function' ? target.closest.bind(target) : null;
|
|
2030
|
+
// WP-4: a tick on a route row is the only thing that arms "Remove from <name>".
|
|
2031
|
+
var pick = closest ? closest('[data-role="models-pick"]') : null;
|
|
2032
|
+
if (pick) { modelsPicked(); return; }
|
|
1231
2033
|
var input = closest ? closest('[data-machine-rename]') : null;
|
|
1232
2034
|
if (!input) return;
|
|
1233
2035
|
rename(input.getAttribute('data-machine-rename'), input.value);
|
|
@@ -1286,6 +2088,35 @@
|
|
|
1286
2088
|
registerLegacy: registerLegacy,
|
|
1287
2089
|
openShowCodeDialog: openShowCodeDialog,
|
|
1288
2090
|
closeDialog: closeDialog,
|
|
2091
|
+
// WP-9 (§9 S-9): the row line + Review sheet, exposed like every other presenter here.
|
|
2092
|
+
skillsRowHtml: skillsRowHtml,
|
|
2093
|
+
skillsLineText: skillsLineText,
|
|
2094
|
+
skillsNeedsReview: skillsNeedsReview,
|
|
2095
|
+
// WP-3 (§8 WP-3): the row line + Review sheet's Models half, exposed like the skills twins.
|
|
2096
|
+
modelsRowHtml: modelsRowHtml,
|
|
2097
|
+
modelsLineText: modelsLineText,
|
|
2098
|
+
modelsNeedsReview: modelsNeedsReview,
|
|
2099
|
+
reviewModelsHtml: reviewModelsHtml,
|
|
2100
|
+
reviewSheetHtml: reviewSheetHtml,
|
|
2101
|
+
reviewHeldBackHtml: reviewHeldBackHtml,
|
|
2102
|
+
reviewOnBoxHtml: reviewOnBoxHtml,
|
|
2103
|
+
reviewPluginsHtml: reviewPluginsHtml,
|
|
2104
|
+
openReviewSheet: openReviewSheet,
|
|
2105
|
+
reviewRefresh: reviewRefresh,
|
|
2106
|
+
reviewAction: reviewAction,
|
|
2107
|
+
reviewSkip: reviewSkip,
|
|
2108
|
+
savePlugins: savePlugins,
|
|
2109
|
+
// WP-4 (§8 WP-4): the Models section's one control — the ids, the arming, and the write.
|
|
2110
|
+
modelsChecked: modelsChecked,
|
|
2111
|
+
modelsPicked: modelsPicked,
|
|
2112
|
+
removeModels: removeModels,
|
|
2113
|
+
// WP-5 (§8 WP-5): the "From this hub" subsection — the rows, the one read, and the write.
|
|
2114
|
+
fromHubHtml: fromHubHtml,
|
|
2115
|
+
fromHubItemsHtml: fromHubItemsHtml,
|
|
2116
|
+
fetchFromHub: fetchFromHub,
|
|
2117
|
+
copyModel: copyModel,
|
|
2118
|
+
showDiff: showDiff,
|
|
2119
|
+
diffHtml: diffHtml,
|
|
1289
2120
|
preview: function () { return dialog ? previewFields() : null; },
|
|
1290
2121
|
dialog: function () { return dialog; },
|
|
1291
2122
|
readOrigins: poolOrigins,
|
|
@@ -1307,6 +2138,9 @@
|
|
|
1307
2138
|
sheetRowHtml: sheetRowHtml,
|
|
1308
2139
|
sheetListHtml: sheetListHtml,
|
|
1309
2140
|
credentialBadge: credentialBadge,
|
|
2141
|
+
// WP-3 (box-owned sessions): the one sentence for a /delegate pick the box cannot reach, read by
|
|
2142
|
+
// the shared Delegate pane on the phone (PHONE = DESKTOP PARITY).
|
|
2143
|
+
modelsDelegateWarnings: modelsDelegateWarnings,
|
|
1310
2144
|
};
|
|
1311
2145
|
if (typeof module === 'object' && module.exports) module.exports = out;
|
|
1312
2146
|
else root.CtmPhoneMachines = out;
|