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
|
@@ -136,6 +136,10 @@
|
|
|
136
136
|
health: null,
|
|
137
137
|
healthTest: null,
|
|
138
138
|
},
|
|
139
|
+
// WP-2 (docs/external-causality-kill-session-loss-2026-10-27.html §5 D-5, §6, §8 WP-2): the
|
|
140
|
+
// last `host-dead` frame, or null. Mirrors the desktop banner's fact shape so both surfaces
|
|
141
|
+
// render the same policy text/actions.
|
|
142
|
+
hostDead: null,
|
|
139
143
|
detailScrollLock: {
|
|
140
144
|
locked: false,
|
|
141
145
|
scrollY: 0,
|
|
@@ -159,7 +163,7 @@
|
|
|
159
163
|
itemsContext: null,
|
|
160
164
|
itemElements: [],
|
|
161
165
|
},
|
|
162
|
-
projects: [],
|
|
166
|
+
projects: [], projectsError: false, // projectsError (D-6): this device's /api/projects read FAILED — never "no projects"
|
|
163
167
|
// WP-5 (S-16/AC-5c): the machine registry, mirrored field for field from the desktop client —
|
|
164
168
|
// same GET /api/machines rows, same reachable/unknown/unhealthy card states, same chip facts.
|
|
165
169
|
// Empty until the hub answers; with zero machines nothing machine-shaped renders at all.
|
|
@@ -805,6 +809,70 @@
|
|
|
805
809
|
banner.hidden = false;
|
|
806
810
|
}
|
|
807
811
|
|
|
812
|
+
// WP-2 (docs/external-causality-kill-session-loss-2026-10-27.html §5 D-5, §6, §8 WP-2, AC-2a/2e):
|
|
813
|
+
// the phone half of the dead-adopted-host notice. Text and button come from the SAME policy module
|
|
814
|
+
// the desktop banner uses (public/js/restart-banner-policy.js), so the two surfaces can never
|
|
815
|
+
// disagree; the notice reuses the app-reload-banner styling rather than a second system.
|
|
816
|
+
function hostDeadCopy(fact) {
|
|
817
|
+
const policy = window.RestartBannerPolicy;
|
|
818
|
+
if (policy && typeof policy.decideRestartBanner === 'function') {
|
|
819
|
+
const decision = policy.decideRestartBanner({ hostDead: fact });
|
|
820
|
+
return { text: decision.text, showButton: decision.actions.includes('resume') };
|
|
821
|
+
}
|
|
822
|
+
// Fail soft to the same strings if the policy script did not load (offline shell).
|
|
823
|
+
const total = Math.max(0, Number(fact.sessionCount) || 0);
|
|
824
|
+
const remaining = Math.max(0, Number(fact.remaining) || 0);
|
|
825
|
+
return {
|
|
826
|
+
text: remaining > 0
|
|
827
|
+
? `${total} sessions lost with their host. Resume ${remaining} sessions`
|
|
828
|
+
: `${total} sessions lost with their host, ${total} resumed`,
|
|
829
|
+
showButton: remaining > 0,
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function renderHostDeadBanner() {
|
|
834
|
+
const banner = $('host-dead-banner');
|
|
835
|
+
if (!banner) return null;
|
|
836
|
+
const fact = state.hostDead;
|
|
837
|
+
if (!fact || !fact.hostId) { banner.hidden = true; return null; }
|
|
838
|
+
const copy = hostDeadCopy(fact);
|
|
839
|
+
const msg = $('host-dead-msg');
|
|
840
|
+
if (msg) { msg.textContent = copy.text; msg.title = copy.text; }
|
|
841
|
+
const btn = $('host-dead-resume-btn');
|
|
842
|
+
if (btn) btn.hidden = !copy.showButton;
|
|
843
|
+
banner.hidden = false;
|
|
844
|
+
return copy;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
function applyHostDead(msg) {
|
|
848
|
+
const hostId = String((msg && msg.hostId) || '');
|
|
849
|
+
if (!hostId) { state.hostDead = null; renderHostDeadBanner(); return null; }
|
|
850
|
+
const sessionCount = Math.max(0, Number(msg.sessionCount) || 0);
|
|
851
|
+
const resumedCount = Array.isArray(msg.resumed) ? msg.resumed.length : 0;
|
|
852
|
+
state.hostDead = {
|
|
853
|
+
hostId,
|
|
854
|
+
at: Number(msg.at) || 0,
|
|
855
|
+
reason: String((msg && msg.reason) || ''),
|
|
856
|
+
sessionCount,
|
|
857
|
+
remaining: Math.max(0, sessionCount - resumedCount),
|
|
858
|
+
fingerprint: `${hostId}|${Number(msg.at) || 0}`,
|
|
859
|
+
};
|
|
860
|
+
renderHostDeadBanner();
|
|
861
|
+
return state.hostDead;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
function resumeHostDeadSessions() {
|
|
865
|
+
const fact = state.hostDead;
|
|
866
|
+
if (!fact || !fact.hostId) return Promise.resolve(null);
|
|
867
|
+
return api('/api/sessions/resume-deferred', { method: 'POST', body: { hostId: fact.hostId } })
|
|
868
|
+
.then((data) => {
|
|
869
|
+
// The server re-broadcasts `host-dead` to every viewer after the drain; applyHostDead
|
|
870
|
+
// renders that frame, so nothing is cleared locally (phone = desktop parity).
|
|
871
|
+
return data;
|
|
872
|
+
})
|
|
873
|
+
.catch((err) => { toast(err?.message || 'Could not resume the lost sessions.', 'error'); return null; });
|
|
874
|
+
}
|
|
875
|
+
|
|
808
876
|
function requestInstalledUpdateReload(opts = {}) {
|
|
809
877
|
const server = normalizeAppVersionInfo(opts.server) || state.appRuntime.latest;
|
|
810
878
|
state.appRuntime.latest = server || state.appRuntime.latest;
|
|
@@ -1305,9 +1373,21 @@
|
|
|
1305
1373
|
handleMobileAuthError: (err, lease) => { if (lease && !privateLeaseCurrent(lease)) throw privateScopeChangedError(); handleMobileAuthError(err); },
|
|
1306
1374
|
privateScopeChangedError,
|
|
1307
1375
|
});
|
|
1308
|
-
|
|
1376
|
+
try {
|
|
1377
|
+
return await mobilePrivateApi.request(path, options);
|
|
1378
|
+
} catch (err) {
|
|
1379
|
+
// WP-1b (§8 step 3): a failed api() already carries `status` and a body-derived `code`, but the
|
|
1380
|
+
// parsed JSON is named `payload`; the child viewer's safeErrorText reads `body`. Attach the ONE
|
|
1381
|
+
// parsed object under that name too, and change nothing else about the error.
|
|
1382
|
+
if (err && typeof err === 'object' && err.body === undefined && err.payload !== undefined) err.body = err.payload;
|
|
1383
|
+
throw err;
|
|
1384
|
+
}
|
|
1309
1385
|
}
|
|
1310
1386
|
|
|
1387
|
+
// §6.4 operator stop (phone half): the shared module owns the sheet and the per-task Stop control; this
|
|
1388
|
+
// app supplies the detail view's own card and its ONE authenticated request path (never a raw fetch).
|
|
1389
|
+
window.BackgroundWork?.installPhoneStop?.({ request: (path, options) => api(path, options), currentCard: () => (state.activeSession ? displayStatusCard(state.activeSession) : null) });
|
|
1390
|
+
|
|
1311
1391
|
function privateScopeChangedError() {
|
|
1312
1392
|
return Object.assign(new Error('Private phone data is paused. Verify this phone and CTM identity, then retry.'), { code: 'private_scope_changed' });
|
|
1313
1393
|
}
|
|
@@ -1791,6 +1871,18 @@
|
|
|
1791
1871
|
.trim();
|
|
1792
1872
|
}
|
|
1793
1873
|
|
|
1874
|
+
// WP-3 (codex-native-subagent-pick-enforcement-2026-10-28.html §5 D-6, §6, §9 S-8): the phone half of
|
|
1875
|
+
// the PASSIVE native-subagents-off chip — the SAME shared pure rule the desktop lead row reads,
|
|
1876
|
+
// gated to Codex cards. Static label: no click handler, no new WS message.
|
|
1877
|
+
function nativeSubagentChipHtml(card) {
|
|
1878
|
+
const shared = window.CTMCodingModelPresentation;
|
|
1879
|
+
if (!shared || typeof shared.nativeSubagentChip !== 'function') return '';
|
|
1880
|
+
if (workflowRoutingAgent(card) !== 'codex') return '';
|
|
1881
|
+
const pick = (card && (card.subagent_pick || (card.meta && card.meta.subagent_pick))) || null;
|
|
1882
|
+
const chip = shared.nativeSubagentChip(pick);
|
|
1883
|
+
return chip ? `<span class="model-chip model-chip-native-off" title="${esc(chip.title)}">${esc(chip.text)}</span>` : '';
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1794
1886
|
// WP1C: a generic card's model chip is the SHARED owner/ledger-qualified label (the same presenter
|
|
1795
1887
|
// the header and the sheet read) — never the raw card.model. Without the shared resolver a carrier
|
|
1796
1888
|
// declaring ANY authority field fails closed; a legacy card keeps its raw label.
|
|
@@ -1799,12 +1891,12 @@
|
|
|
1799
1891
|
const shared = window.CTMCodingModelPresentation;
|
|
1800
1892
|
if (shared && typeof shared.cardModelLabel === 'function') {
|
|
1801
1893
|
const qualified = shared.cardModelLabel(card, raw, modelDisplayLabel);
|
|
1802
|
-
return qualified ? `<span class="model-chip">${esc(qualified)}</span>` : '';
|
|
1894
|
+
return (qualified ? `<span class="model-chip">${esc(qualified)}</span>` : '') + nativeSubagentChipHtml(card);
|
|
1803
1895
|
}
|
|
1804
1896
|
const declares = (source) => !!source
|
|
1805
1897
|
&& ['model_owner', 'model_observation_health', 'model_switch_event'].some((key) => Object.hasOwn(source, key));
|
|
1806
|
-
if (declares(card) || declares(card && card.meta)) return
|
|
1807
|
-
return raw ? `<span class="model-chip">${esc(raw)}</span>` : '';
|
|
1898
|
+
if (declares(card) || declares(card && card.meta)) return nativeSubagentChipHtml(card);
|
|
1899
|
+
return (raw ? `<span class="model-chip">${esc(raw)}</span>` : '') + nativeSubagentChipHtml(card);
|
|
1808
1900
|
}
|
|
1809
1901
|
|
|
1810
1902
|
function modelProviderLabel(provider) {
|
|
@@ -2058,13 +2150,37 @@
|
|
|
2058
2150
|
.join('');
|
|
2059
2151
|
}
|
|
2060
2152
|
|
|
2153
|
+
// WP-3b (§8 WP-3): the landing queue's chip TEXT for the phone. This must produce byte-identical
|
|
2154
|
+
// strings to public/index.html's landingChipText for the same input — that is the phone parity
|
|
2155
|
+
// rule — so the two formatters change together. Nothing here is HTML; the callers escape.
|
|
2156
|
+
function landingEtaText(etaSeconds) {
|
|
2157
|
+
return typeof etaSeconds === 'number' && Number.isFinite(etaSeconds)
|
|
2158
|
+
? `${Math.round(etaSeconds / 60)}m` : '';
|
|
2159
|
+
}
|
|
2160
|
+
function landingQueueText(landing) {
|
|
2161
|
+
if (!landing || typeof landing !== 'object') return '';
|
|
2162
|
+
if (typeof landing.position === 'number' && Number.isFinite(landing.position)) {
|
|
2163
|
+
const total = Number.isFinite(Number(landing.total)) ? Number(landing.total) : 0;
|
|
2164
|
+
const eta = landingEtaText(landing.eta_s);
|
|
2165
|
+
return `⇡#${landing.position}/${total}${eta ? ` · ${eta}` : ''}`;
|
|
2166
|
+
}
|
|
2167
|
+
const state = typeof landing.state === 'string' ? landing.state.trim() : '';
|
|
2168
|
+
return state ? `⇡${state}` : '';
|
|
2169
|
+
}
|
|
2170
|
+
// The conflict radar is not on the row, same as desktop: it lives in the details Radar row.
|
|
2171
|
+
function landingChipText(card) {
|
|
2172
|
+
return landingQueueText(card && card.workspaceTracking ? card.workspaceTracking.landing : null);
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2061
2175
|
function sessionDiffTags(card, opts = {}) {
|
|
2062
2176
|
const diff = sessionWorktreeDiff(card);
|
|
2063
|
-
|
|
2177
|
+
const landingText = landingChipText(card);
|
|
2178
|
+
if (!diff && !landingText) return '';
|
|
2064
2179
|
const chips = [];
|
|
2065
2180
|
const interactive = !!opts.interactive;
|
|
2066
|
-
|
|
2067
|
-
|
|
2181
|
+
// A landing-only chip has no worktree diff to finish, so every `diff.` read below is guarded.
|
|
2182
|
+
const actionTarget = interactive && diff ? worktreeFinishTarget(card, diff) : null;
|
|
2183
|
+
if (diff && diff.dirtyFiles > 0) {
|
|
2068
2184
|
const label = pluralize(diff.dirtyFiles, 'file');
|
|
2069
2185
|
const title = diff.isMain
|
|
2070
2186
|
? `${diff.branch}: ${pluralize(diff.dirtyFiles, 'uncommitted file')} on main`
|
|
@@ -2074,7 +2190,7 @@
|
|
|
2074
2190
|
? `<button class="session-diff-chip session-diff-chip-action files" type="button"${worktreeFinishDataset(actionTarget)} title="${esc(actionTitle)}" aria-label="${esc(actionTitle)}">${esc(label)}</button>`
|
|
2075
2191
|
: `<span class="session-diff-chip files" title="${esc(title)}" aria-label="${esc(title)}">${esc(label)}</span>`);
|
|
2076
2192
|
}
|
|
2077
|
-
if (diff.unmergedCommits > 0) {
|
|
2193
|
+
if (diff && diff.unmergedCommits > 0) {
|
|
2078
2194
|
const label = pluralize(diff.unmergedCommits, 'commit');
|
|
2079
2195
|
// netContentDiffers === false → commits exist but merging changes nothing (integrated/
|
|
2080
2196
|
// superseded). Dim the chip + clarify the title so it's distinct from real unmerged work.
|
|
@@ -2090,7 +2206,13 @@
|
|
|
2090
2206
|
? `<button class="session-diff-chip session-diff-chip-action ${commitsCls}" type="button"${worktreeFinishDataset(actionTarget)} title="${esc(actionTitle)}" aria-label="${esc(actionTitle)}">${esc(label)}</button>`
|
|
2091
2207
|
: `<span class="session-diff-chip ${commitsCls}" title="${esc(title)}" aria-label="${esc(title)}">${esc(label)}</span>`);
|
|
2092
2208
|
}
|
|
2093
|
-
|
|
2209
|
+
if (landingText) {
|
|
2210
|
+
// Same text as the desktop queue part.
|
|
2211
|
+
chips.push(`<span class="session-diff-chip landing" title="${esc(landingText)}" aria-label="${esc(landingText)}">${esc(landingText)}</span>`);
|
|
2212
|
+
}
|
|
2213
|
+
const label = diff
|
|
2214
|
+
? (diff.isMain ? `Main branch changes for ${diff.branch}` : `Branch diff for ${diff.branch}`)
|
|
2215
|
+
: `Landing queue${landingText ? `: ${landingText}` : ''}`;
|
|
2094
2216
|
return `<span class="session-diff-tags" aria-label="${esc(label)}">${chips.join('')}</span>`;
|
|
2095
2217
|
}
|
|
2096
2218
|
|
|
@@ -2233,7 +2355,18 @@
|
|
|
2233
2355
|
async function retireWorkers(body) {
|
|
2234
2356
|
const calls = [api('/api/sessions/workers/retire', { method: 'POST', body })];
|
|
2235
2357
|
if (body && body.lead) calls.push(api('/api/sessions/' + encodeURIComponent(body.lead) + '/native-subagents/clear', { method: 'POST' }));
|
|
2236
|
-
|
|
2358
|
+
try {
|
|
2359
|
+
await Promise.all(calls);
|
|
2360
|
+
} catch (err) {
|
|
2361
|
+
// WP-1b (§8 step 5): a box-owned lead's clear is forwarded by the hub; an unreachable box names
|
|
2362
|
+
// itself through the phone's existing transient-message toast. Any other failure is rethrown
|
|
2363
|
+
// unchanged for the caller's own .catch.
|
|
2364
|
+
if (err?.code === 'machine_unreachable' || err?.body?.code === 'machine_unreachable') {
|
|
2365
|
+
toast(`${err?.body?.machineName || 'The machine that owns this session'} is unreachable. Retry when ready.`);
|
|
2366
|
+
return;
|
|
2367
|
+
}
|
|
2368
|
+
throw err;
|
|
2369
|
+
}
|
|
2237
2370
|
scheduleRefresh(0);
|
|
2238
2371
|
}
|
|
2239
2372
|
|
|
@@ -2433,6 +2566,15 @@
|
|
|
2433
2566
|
return `<span class="row-diff-mark ${cls}" title="${esc(titles.join('; '))}">${esc(sessionDiffCountText(diff))}</span>`;
|
|
2434
2567
|
}
|
|
2435
2568
|
|
|
2569
|
+
// WP-3b phone parity: the landing queue also rides the SESSION ROW mark, not just the worktree
|
|
2570
|
+
// sheet chip, matching the desktop badge on the session list row. Text is byte-identical to
|
|
2571
|
+
// `landingChipText` (and therefore to the desktop `landingChipText`).
|
|
2572
|
+
function sessionLandingMark(card) {
|
|
2573
|
+
const landingText = landingChipText(card);
|
|
2574
|
+
if (!landingText) return '';
|
|
2575
|
+
return `<span class="row-diff-mark landing" title="${esc(landingText)}">${esc(landingText)}</span>`;
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2436
2578
|
// A session row (home + Agents): title and ONE pill, one meta line, at most one button (Wake, parked/deferred only).
|
|
2437
2579
|
function sessionRow(card, opts = {}) {
|
|
2438
2580
|
const bucket = cardBucket(card);
|
|
@@ -2464,11 +2606,11 @@
|
|
|
2464
2606
|
<span class="session-main">
|
|
2465
2607
|
<span class="session-title-line">
|
|
2466
2608
|
<span class="session-title">${esc(card.title || card.id || 'Session')}</span>
|
|
2467
|
-
${opts.worker === true ? cardModelChip(card) :
|
|
2609
|
+
${opts.worker === true ? cardModelChip(card) : nativeSubagentChipHtml(card)}
|
|
2468
2610
|
${phoneMachineChip(card)}
|
|
2469
2611
|
${pill}
|
|
2470
2612
|
</span>
|
|
2471
|
-
<span class="session-meta"><span class="session-meta-text">${esc(meta)}</span>${sessionDiffMark(card)}</span>
|
|
2613
|
+
<span class="session-meta"><span class="session-meta-text">${esc(meta)}</span>${sessionDiffMark(card)}${sessionLandingMark(card)}</span>
|
|
2472
2614
|
${searchMatch}
|
|
2473
2615
|
</span>
|
|
2474
2616
|
${action ? `<span class="row-actions">${action}</span>` : ''}
|
|
@@ -4961,8 +5103,8 @@
|
|
|
4961
5103
|
|
|
4962
5104
|
async function loadProjects() {
|
|
4963
5105
|
const lease = mobilePrivateLease; if (!mobilePrivateReady || !privateLeaseCurrent(lease)) return;
|
|
4964
|
-
try { const data = await api('/api/projects'); if (privateLeaseCurrent(lease)) state.projects = Array.isArray(data) ? data : (Array.isArray(data.projects) ? data.projects : []); }
|
|
4965
|
-
catch { if (privateLeaseCurrent(lease)) state.projects = []; }
|
|
5106
|
+
try { const data = await api('/api/projects'); if (privateLeaseCurrent(lease)) { state.projects = Array.isArray(data) ? data : (Array.isArray(data.projects) ? data.projects : []); state.projectsError = false; } }
|
|
5107
|
+
catch { if (privateLeaseCurrent(lease)) { state.projects = []; state.projectsError = true; } }
|
|
4966
5108
|
}
|
|
4967
5109
|
|
|
4968
5110
|
function pushSupported() {
|
|
@@ -5641,6 +5783,10 @@
|
|
|
5641
5783
|
}
|
|
5642
5784
|
|
|
5643
5785
|
function dispatchMobileWsMessage(msg) {
|
|
5786
|
+
// WP-2 (docs/external-causality-kill-session-loss-2026-10-27.html §5 D-5, §6, §8 WP-2, AC-2a):
|
|
5787
|
+
// an adopted host died with sessions still attached — the phone shows the SAME notice and the
|
|
5788
|
+
// SAME Resume button as the desktop banner (PHONE = DESKTOP parity).
|
|
5789
|
+
if (msg.type === 'host-dead') { applyHostDead(msg); return; }
|
|
5644
5790
|
if (msg.type === 'error') {
|
|
5645
5791
|
// A machine create refused at the hub names the box and the page that fixes it; show it and
|
|
5646
5792
|
// stop. 'hello'/'pong'/… are unaffected, and no other frame type is touched.
|
|
@@ -5727,6 +5873,12 @@
|
|
|
5727
5873
|
phoneModelPicker?.delegatePrefsChanged();
|
|
5728
5874
|
return;
|
|
5729
5875
|
}
|
|
5876
|
+
// WP-4 (R-5/R-13, AC-2g): a box session's gated op was refused, or its ask was answered. The
|
|
5877
|
+
// phone shows the same banner the desktop shows (phone = desktop parity), in the session detail.
|
|
5878
|
+
if (msg.type === 'hub-bridge-pending' || msg.type === 'hub-bridge-pending-cleared') {
|
|
5879
|
+
phoneAccessOnFrame(msg);
|
|
5880
|
+
return;
|
|
5881
|
+
}
|
|
5730
5882
|
if (msg.type === 'remote-submission-status') {
|
|
5731
5883
|
applyRemoteSubmissionStatus(msg);
|
|
5732
5884
|
return;
|
|
@@ -7094,6 +7246,8 @@
|
|
|
7094
7246
|
setDetailSessionChromeVisible(true);
|
|
7095
7247
|
state.activeSession = card;
|
|
7096
7248
|
state.activeStreamSessionId = card.id;
|
|
7249
|
+
// WP-4 AC-2g: an ask already open for this session is shown before any frame arrives.
|
|
7250
|
+
phoneAccessSeedBanners().catch(() => {});
|
|
7097
7251
|
phonePresence.onDetailOpened(); // D-9: a new detail view starts its own idle clock
|
|
7098
7252
|
render();
|
|
7099
7253
|
resetDetailTimeline(card.id);
|
|
@@ -7145,6 +7299,7 @@
|
|
|
7145
7299
|
if (state.approvalSheet && state.approvalSheet.sessionId !== '') closeApprovalRequestSheet();
|
|
7146
7300
|
state.activeSession = null;
|
|
7147
7301
|
state.activeStreamSessionId = null;
|
|
7302
|
+
phoneAccessPaintBanner(); // AC-2g: an ask's banner belongs to the session the detail view showed
|
|
7148
7303
|
setDetailSessionChromeVisible(true);
|
|
7149
7304
|
resetDetailTimeline(null);
|
|
7150
7305
|
clearChoiceStillWaitingTimer();
|
|
@@ -7571,6 +7726,11 @@
|
|
|
7571
7726
|
return card?.agentCapabilities || card?.capabilities || {};
|
|
7572
7727
|
}
|
|
7573
7728
|
|
|
7729
|
+
// WP-11 phone parity (AC-15c): an image attach is a CAPABILITY gate — a dsh card whose live child
|
|
7730
|
+
// did not advertise image prompt support refuses; a card with no capability record is unchanged.
|
|
7731
|
+
const MOBILE_IMAGE_ATTACH_UNAVAILABLE = 'Images are unavailable: this DeepSeek Harness agent did not advertise image prompt support.';
|
|
7732
|
+
function sessionImageAttachAllowed(card) { return cardCapabilities(card).input?.attachments !== false; }
|
|
7733
|
+
|
|
7574
7734
|
function walleIdentityText(card) {
|
|
7575
7735
|
return [
|
|
7576
7736
|
card?.agent,
|
|
@@ -7722,6 +7882,8 @@
|
|
|
7722
7882
|
if (/codex|openai|gpt-|o[1345]/.test(value)) return 'codex';
|
|
7723
7883
|
if (/gemini|google/.test(value)) return 'gemini';
|
|
7724
7884
|
if (/cursor/.test(value)) return 'cursor';
|
|
7885
|
+
// WP-7 (S-59): DeepSeek Harness (dsh) — the phone chip must read the same agent as desktop.
|
|
7886
|
+
if (/deepseek|(^|[-_/])dsh($|[-_/\s])/.test(value)) return 'dsh';
|
|
7725
7887
|
}
|
|
7726
7888
|
return '';
|
|
7727
7889
|
}
|
|
@@ -7885,34 +8047,6 @@
|
|
|
7885
8047
|
`;
|
|
7886
8048
|
}
|
|
7887
8049
|
|
|
7888
|
-
function normalizeSessionMessagesPayload(data) {
|
|
7889
|
-
if (Array.isArray(data)) {
|
|
7890
|
-
return {
|
|
7891
|
-
messages: data,
|
|
7892
|
-
hasMore: false,
|
|
7893
|
-
nextOffset: data.length,
|
|
7894
|
-
total: data.length,
|
|
7895
|
-
pageKind: 'messages',
|
|
7896
|
-
conversationBudget: null,
|
|
7897
|
-
};
|
|
7898
|
-
}
|
|
7899
|
-
const messages = Array.isArray(data?.messages)
|
|
7900
|
-
? data.messages
|
|
7901
|
-
: (Array.isArray(data?.data) ? data.data : (Array.isArray(data?.items) ? data.items : []));
|
|
7902
|
-
return {
|
|
7903
|
-
messages,
|
|
7904
|
-
hasMore: !!(data?.has_more || data?.hasMore),
|
|
7905
|
-
nextOffset: Number.isFinite(Number(data?.next_offset ?? data?.nextOffset))
|
|
7906
|
-
? Number(data?.next_offset ?? data?.nextOffset)
|
|
7907
|
-
: messages.length,
|
|
7908
|
-
total: Number.isFinite(Number(data?.total)) ? Number(data.total) : messages.length,
|
|
7909
|
-
pageKind: String(data?.page_kind || data?.pageKind || ''),
|
|
7910
|
-
conversationBudget: data?.conversationBudget && typeof data.conversationBudget === 'object'
|
|
7911
|
-
? data.conversationBudget
|
|
7912
|
-
: null,
|
|
7913
|
-
};
|
|
7914
|
-
}
|
|
7915
|
-
|
|
7916
8050
|
function stripToolTokensForClassification(text) {
|
|
7917
8051
|
return String(text || '').replace(/\[Tool(?: result)?:\s*[^\]]+\]/g, '').trim();
|
|
7918
8052
|
}
|
|
@@ -7970,7 +8104,7 @@
|
|
|
7970
8104
|
timeoutMs: MOBILE_DETAIL_REQUEST_TIMEOUT_MS,
|
|
7971
8105
|
});
|
|
7972
8106
|
if (!privateLeaseCurrent(lease)) throw privateScopeChangedError();
|
|
7973
|
-
return normalizeSessionMessagesPayload(data);
|
|
8107
|
+
return window.CTMMobilePrivateApi.normalizeSessionMessagesPayload(data);
|
|
7974
8108
|
}
|
|
7975
8109
|
|
|
7976
8110
|
async function loadSessionMessagesWindow(card, opts = {}) {
|
|
@@ -11311,6 +11445,7 @@
|
|
|
11311
11445
|
agentOf: phoneModelAgent,
|
|
11312
11446
|
currentModelOf: (card) => (card ? String(card.model_id || card.model || '') : ''),
|
|
11313
11447
|
modelSourceOf: (card) => String(card?.model_source || ''),
|
|
11448
|
+
modelProviderOf: (card) => String(card?.model_provider || card?.meta?.model_provider || ''),
|
|
11314
11449
|
leadEffortOf: (card) => String(card?.model_effort || card?.meta?.model_effort || ''),
|
|
11315
11450
|
modelStateOf: (card) => card?.model_state || card?.modelState || card?.meta?.model_state || null,
|
|
11316
11451
|
isOnScreen: (id) => state.activeSession?.id === id,
|
|
@@ -11780,21 +11915,23 @@
|
|
|
11780
11915
|
if (!mobilePrivateReady || !privateLeaseCurrent(lease)) return;
|
|
11781
11916
|
const list = Array.from(files || []).filter(Boolean);
|
|
11782
11917
|
if (!list.length) return;
|
|
11918
|
+
// WP-11 phone parity (AC-15c): refuse the image attach BEFORE any upload, and say why.
|
|
11919
|
+
if (requestedKind === 'image' && !sessionImageAttachAllowed(state.activeSession)) {
|
|
11920
|
+
setAttachmentComposerStatus(MOBILE_IMAGE_ATTACH_UNAVAILABLE, 'error', composerElement('input'));
|
|
11921
|
+
return;
|
|
11922
|
+
}
|
|
11783
11923
|
const sessionId = state.activeSession?.id || '';
|
|
11784
11924
|
const statusInput = composerElement('input');
|
|
11785
11925
|
setAttachmentComposerStatus(`Attaching ${list.length} item${list.length === 1 ? '' : 's'}...`, '', statusInput);
|
|
11786
11926
|
const pending = list.map((file) => ({
|
|
11787
11927
|
id: `att-${++state.attachmentSeq}`,
|
|
11788
11928
|
kind: attachmentKindForFile(file, requestedKind),
|
|
11789
|
-
originalName: sanitizeAttachmentFilename(file.name,
|
|
11790
|
-
requestedKind === 'image' ? 'phone-image.png' : 'phone-attachment.bin'),
|
|
11929
|
+
originalName: sanitizeAttachmentFilename(file.name, requestedKind === 'image' ? 'phone-image.png' : 'phone-attachment.bin'),
|
|
11791
11930
|
size: file.size || 0,
|
|
11792
11931
|
status: 'queued',
|
|
11793
11932
|
progress: 0,
|
|
11794
11933
|
error: '',
|
|
11795
|
-
requestId: globalThis.crypto && typeof globalThis.crypto.randomUUID === 'function'
|
|
11796
|
-
? globalThis.crypto.randomUUID()
|
|
11797
|
-
: `mobile-upload-${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
|
11934
|
+
requestId: globalThis.crypto && typeof globalThis.crypto.randomUUID === 'function' ? globalThis.crypto.randomUUID() : `mobile-upload-${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
|
11798
11935
|
_uploadFile: file,
|
|
11799
11936
|
previewUrl: attachmentKindForFile(file, requestedKind) === 'image' ? URL.createObjectURL(file) : '',
|
|
11800
11937
|
}));
|
|
@@ -11817,23 +11954,15 @@
|
|
|
11817
11954
|
}));
|
|
11818
11955
|
if (!privateLeaseCurrent(lease)) return;
|
|
11819
11956
|
if (state.activeSession?.id !== sessionId) {
|
|
11820
|
-
const staleIds = new Set(pending.map((item) => item.id));
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
if (item.previewUrl) {
|
|
11824
|
-
try { URL.revokeObjectURL(item.previewUrl); } catch { /* expected: preview URLs may already be revoked */ }
|
|
11825
|
-
}
|
|
11826
|
-
}
|
|
11827
|
-
renderComposerAttachments();
|
|
11828
|
-
updateComposerState();
|
|
11829
|
-
setComposerStatus('', '', statusInput);
|
|
11957
|
+
const staleIds = new Set(pending.map((item) => item.id)); state.composerAttachments = state.composerAttachments.filter((item) => !staleIds.has(item.id));
|
|
11958
|
+
for (const item of pending) if (item.previewUrl) { try { URL.revokeObjectURL(item.previewUrl); } catch { /* expected: preview URLs may already be revoked */ } }
|
|
11959
|
+
renderComposerAttachments(); updateComposerState(); setComposerStatus('', '', statusInput);
|
|
11830
11960
|
return;
|
|
11831
11961
|
}
|
|
11832
11962
|
renderComposerAttachments();
|
|
11833
11963
|
updateComposerState();
|
|
11834
|
-
if (failures.length)
|
|
11835
|
-
|
|
11836
|
-
} else {
|
|
11964
|
+
if (failures.length) setAttachmentComposerStatus(failures[0], 'error', statusInput);
|
|
11965
|
+
else {
|
|
11837
11966
|
const names = pending.map((item) => item.originalName).join(', ');
|
|
11838
11967
|
setAttachmentComposerStatus(`Attached ${names}.`, 'ok', statusInput);
|
|
11839
11968
|
}
|
|
@@ -11978,7 +12107,8 @@
|
|
|
11978
12107
|
option.disabled = state.composerSending || !state.activeSession;
|
|
11979
12108
|
});
|
|
11980
12109
|
document.querySelectorAll('[data-send-menu-attach]').forEach((option) => {
|
|
11981
|
-
|
|
12110
|
+
const attachAllowed = option.dataset.sendMenuAttach !== 'image' || sessionImageAttachAllowed(state.activeSession); // WP-11/AC-15c: the image option is capability-gated
|
|
12111
|
+
option.disabled = state.composerSending || !state.activeSession || !attachAllowed; if (option.dataset.sendMenuAttach === 'image') option.title = attachAllowed ? 'Attach image' : MOBILE_IMAGE_ATTACH_UNAVAILABLE;
|
|
11982
12112
|
});
|
|
11983
12113
|
document.querySelectorAll('[data-walle-attach]').forEach((option) => {
|
|
11984
12114
|
option.disabled = state.composerSending || !state.activeSession;
|
|
@@ -11992,6 +12122,8 @@
|
|
|
11992
12122
|
if (/codex/.test(text)) return 'codex';
|
|
11993
12123
|
if (/gemini/.test(text)) return 'gemini';
|
|
11994
12124
|
if (/opencode|open-code/.test(text)) return 'opencode';
|
|
12125
|
+
// WP-7 (S-59): D-3 command word (never a substring such as `/x/dshell`).
|
|
12126
|
+
if (/^(?:\S*\/)?dsh(?:\s|$)/.test(text) || /deepseek/.test(text)) return 'dsh';
|
|
11995
12127
|
if (/wall[- ]?e|walle/.test(text)) return 'walle';
|
|
11996
12128
|
return text.trim();
|
|
11997
12129
|
}
|
|
@@ -12046,6 +12178,8 @@
|
|
|
12046
12178
|
const cwd = card.cwd || card.project || card.projectPath || '';
|
|
12047
12179
|
if (agent) params.set('agent', agent);
|
|
12048
12180
|
if (cwd) params.set('cwd', cwd);
|
|
12181
|
+
// remote-agent-skills WP-9 (S-9): a session on another machine gets that machine's skill list.
|
|
12182
|
+
if (card.id) params.set('sessionId', String(card.id));
|
|
12049
12183
|
return `/api/skills/autocomplete?${params.toString()}`;
|
|
12050
12184
|
}
|
|
12051
12185
|
|
|
@@ -13453,6 +13587,7 @@
|
|
|
13453
13587
|
api,
|
|
13454
13588
|
toast,
|
|
13455
13589
|
loadMachines: (options) => loadMachines(options),
|
|
13590
|
+
afterRender: () => { phoneAccessMount(); phoneAccessTrustAllMount(); },
|
|
13456
13591
|
openNewSessionSheet: (instanceId) => openNewSessionMachine(instanceId),
|
|
13457
13592
|
confirm: (message) => window.confirm(message),
|
|
13458
13593
|
now: () => Date.now(),
|
|
@@ -13463,7 +13598,305 @@
|
|
|
13463
13598
|
// Renders (or re-renders) the Machines section inside #more-content. more.js owns that container and
|
|
13464
13599
|
// rewrites it wholesale, so this runs again after each of its renders and the section node is reused.
|
|
13465
13600
|
function renderPhoneMachinesCard() {
|
|
13466
|
-
|
|
13601
|
+
const node = phoneMachines()?.render($('more-content')) || null;
|
|
13602
|
+
// WP-4 (AC-4d): PHONE = DESKTOP PARITY — the same Access block the desktop card renders (trust
|
|
13603
|
+
// select, active grants + Revoke, open asks + the 4-way grant card / Deny, the last 20 audit lines). The card
|
|
13604
|
+
// markup itself is public/m/machines.js's; this mounts the access section into each rendered card.
|
|
13605
|
+
phoneAccessBind();
|
|
13606
|
+
phoneAccessTrustAllMount();
|
|
13607
|
+
loadPhoneAccess(state.machines).then(() => { phoneAccessMount(); phoneAccessTrustAllMount(); }).catch(() => {});
|
|
13608
|
+
return node;
|
|
13609
|
+
}
|
|
13610
|
+
|
|
13611
|
+
// ── WP-4 phone access block (R-11 trust, R-4 grants, R-5 pending, R-9 audit, R-13/AC-4d) ───────
|
|
13612
|
+
// The phone twin of the desktop Machines page's Access block: the SAME shared markup, texts and
|
|
13613
|
+
// request bodies (public/js/machine-pool-shared.js — loaded by public/m/index.html before this
|
|
13614
|
+
// file), driven through the same routes, so a phone card and a desktop card can never disagree
|
|
13615
|
+
// about who may use this Mac. Only the class prefix and the delegated wiring are the phone's own.
|
|
13616
|
+
const PHONE_ACCESS_OPTS = { esc, classes: MACHINE_ACCESS_CLASSES_PHONE };
|
|
13617
|
+
const phoneAccessState = { trust: null, grants: [], pending: [], audit: {}, pendingIndex: {} };
|
|
13618
|
+
|
|
13619
|
+
/** R-11: a machine's effective policy — its own row, else the file default (shared rule). */
|
|
13620
|
+
function phoneAccessTrustValueFor(instanceId) {
|
|
13621
|
+
return machineEffectiveTrust(phoneAccessState.trust, instanceId);
|
|
13622
|
+
}
|
|
13623
|
+
|
|
13624
|
+
function phoneAccessGrantsFor(instanceId) {
|
|
13625
|
+
return machineAccessRowsFor(phoneAccessState.grants, instanceId);
|
|
13626
|
+
}
|
|
13627
|
+
|
|
13628
|
+
function phoneAccessPendingFor(instanceId) {
|
|
13629
|
+
return machineAccessRowsFor(phoneAccessState.pending, instanceId);
|
|
13630
|
+
}
|
|
13631
|
+
|
|
13632
|
+
function phoneAccessApply(trust, grants) {
|
|
13633
|
+
phoneAccessState.trust = trust && typeof trust === 'object'
|
|
13634
|
+
? {
|
|
13635
|
+
v: 1,
|
|
13636
|
+
default: MACHINES_PAGE_TRUST_VALUES.indexOf(String(trust.default || '')) !== -1 ? String(trust.default) : MACHINES_PAGE_TRUST_DEFAULT,
|
|
13637
|
+
machines: (trust.machines && typeof trust.machines === 'object') ? trust.machines : {},
|
|
13638
|
+
}
|
|
13639
|
+
: null;
|
|
13640
|
+
const rows = (grants && Array.isArray(grants.grants)) ? grants.grants : [];
|
|
13641
|
+
const pending = (grants && Array.isArray(grants.pending)) ? grants.pending : [];
|
|
13642
|
+
phoneAccessState.grants = rows;
|
|
13643
|
+
phoneAccessState.pending = pending;
|
|
13644
|
+
phoneAccessState.pendingIndex = {};
|
|
13645
|
+
for (const row of pending) {
|
|
13646
|
+
if (row && row.id) phoneAccessState.pendingIndex[String(row.id)] = row;
|
|
13647
|
+
}
|
|
13648
|
+
return true;
|
|
13649
|
+
}
|
|
13650
|
+
|
|
13651
|
+
/** Trust + grants + one audit read per member. A hub without the routes leaves the block empty. */
|
|
13652
|
+
async function loadPhoneAccess(machines) {
|
|
13653
|
+
try {
|
|
13654
|
+
const [trust, grants] = await Promise.all([api('/api/hub-bridge/trust'), api('/api/hub-bridge/grants')]);
|
|
13655
|
+
phoneAccessApply(trust, grants);
|
|
13656
|
+
} catch {
|
|
13657
|
+
phoneAccessApply(null, null);
|
|
13658
|
+
}
|
|
13659
|
+
const list = Array.isArray(machines) ? machines : (Array.isArray(state.machines) ? state.machines : []);
|
|
13660
|
+
await Promise.all(list.filter((m) => m && m.instanceId).map(async (machine) => {
|
|
13661
|
+
const id = String(machine.instanceId);
|
|
13662
|
+
try {
|
|
13663
|
+
const out = await api(`/api/hub-bridge/audit?machineId=${encodeURIComponent(id)}&limit=${MACHINES_PAGE_AUDIT_LIMIT}`);
|
|
13664
|
+
phoneAccessState.audit[id] = (out && Array.isArray(out.entries)) ? out.entries : [];
|
|
13665
|
+
} catch {
|
|
13666
|
+
phoneAccessState.audit[id] = [];
|
|
13667
|
+
}
|
|
13668
|
+
}));
|
|
13669
|
+
return phoneAccessState;
|
|
13670
|
+
}
|
|
13671
|
+
|
|
13672
|
+
function phoneAccessTrustAllHtml() {
|
|
13673
|
+
return machineTrustAllHtml(phoneAccessState.trust, PHONE_ACCESS_OPTS);
|
|
13674
|
+
}
|
|
13675
|
+
|
|
13676
|
+
function phoneAccessBlockHtml(machine) {
|
|
13677
|
+
const id = String((machine && machine.instanceId) || '');
|
|
13678
|
+
if (!id) return '';
|
|
13679
|
+
return machineAccessBlockHtml(id, {
|
|
13680
|
+
trust: phoneAccessState.trust,
|
|
13681
|
+
grants: phoneAccessGrantsFor(id),
|
|
13682
|
+
pending: phoneAccessPendingFor(id),
|
|
13683
|
+
audit: Array.isArray(phoneAccessState.audit[id]) ? phoneAccessState.audit[id] : [],
|
|
13684
|
+
now: phoneMachinesNow(),
|
|
13685
|
+
}, PHONE_ACCESS_OPTS);
|
|
13686
|
+
}
|
|
13687
|
+
|
|
13688
|
+
function phoneAccessPendingRow(pendingId) {
|
|
13689
|
+
return phoneAccessState.pendingIndex[String(pendingId || '')] || null;
|
|
13690
|
+
}
|
|
13691
|
+
|
|
13692
|
+
/** Answer the ask: POST the grant its data-grant key names — the ask's own tier, scope and duration. */
|
|
13693
|
+
async function phoneAccessAllow(instanceId, pendingId, grant) {
|
|
13694
|
+
const row = phoneAccessPendingRow(pendingId);
|
|
13695
|
+
if (!row) { toast('That request is gone.'); return false; }
|
|
13696
|
+
try {
|
|
13697
|
+
await api(...hubBridgeAnswerCall(row, instanceId, grant));
|
|
13698
|
+
} catch {
|
|
13699
|
+
toast('Could not allow that request.');
|
|
13700
|
+
return false;
|
|
13701
|
+
}
|
|
13702
|
+
await phoneAccessRefresh();
|
|
13703
|
+
return true;
|
|
13704
|
+
}
|
|
13705
|
+
|
|
13706
|
+
async function phoneAccessDeny(pendingId) {
|
|
13707
|
+
const key = String(pendingId || '');
|
|
13708
|
+
if (!key) return false;
|
|
13709
|
+
try {
|
|
13710
|
+
await api(hubBridgeDenyPath(key), { method: 'POST', body: {} });
|
|
13711
|
+
} catch {
|
|
13712
|
+
toast('Could not deny that request.');
|
|
13713
|
+
return false;
|
|
13714
|
+
}
|
|
13715
|
+
await phoneAccessRefresh();
|
|
13716
|
+
return true;
|
|
13717
|
+
}
|
|
13718
|
+
|
|
13719
|
+
async function phoneAccessRevoke(instanceId, callerSessionId, tier) {
|
|
13720
|
+
try {
|
|
13721
|
+
await api('/api/hub-bridge/grants', { method: 'DELETE', body: hubBridgeRevokeBody(instanceId, callerSessionId, tier) });
|
|
13722
|
+
} catch {
|
|
13723
|
+
toast('Could not revoke that grant.');
|
|
13724
|
+
return false;
|
|
13725
|
+
}
|
|
13726
|
+
await phoneAccessRefresh();
|
|
13727
|
+
return true;
|
|
13728
|
+
}
|
|
13729
|
+
|
|
13730
|
+
async function phoneAccessTrustChange(instanceId, value) {
|
|
13731
|
+
try {
|
|
13732
|
+
await api('/api/hub-bridge/trust', { method: 'PUT', body: hubBridgeTrustBody(instanceId, value) });
|
|
13733
|
+
} catch {
|
|
13734
|
+
toast('Could not save that setting.');
|
|
13735
|
+
return false;
|
|
13736
|
+
}
|
|
13737
|
+
await phoneAccessRefresh();
|
|
13738
|
+
return true;
|
|
13739
|
+
}
|
|
13740
|
+
|
|
13741
|
+
async function phoneAccessTrustAll(on) {
|
|
13742
|
+
try {
|
|
13743
|
+
await api('/api/hub-bridge/trust', { method: 'PUT', body: hubBridgeTrustAllBody(on) });
|
|
13744
|
+
} catch {
|
|
13745
|
+
toast('Could not save that setting.');
|
|
13746
|
+
return false;
|
|
13747
|
+
}
|
|
13748
|
+
await phoneAccessRefresh();
|
|
13749
|
+
return true;
|
|
13750
|
+
}
|
|
13751
|
+
|
|
13752
|
+
async function phoneAccessRefresh() {
|
|
13753
|
+
await loadPhoneAccess(state.machines);
|
|
13754
|
+
phoneAccessMount();
|
|
13755
|
+
return true;
|
|
13756
|
+
}
|
|
13757
|
+
|
|
13758
|
+
/** Mount (or repaint) the access section on every member card the phone Machines page rendered. */
|
|
13759
|
+
function phoneAccessMount() {
|
|
13760
|
+
const content = $('more-content');
|
|
13761
|
+
if (!content || typeof content.querySelectorAll !== 'function') return 0;
|
|
13762
|
+
const cards = content.querySelectorAll('.mp-card[data-machine-id]') || [];
|
|
13763
|
+
let mounted = 0;
|
|
13764
|
+
for (let i = 0; i < cards.length; i += 1) {
|
|
13765
|
+
const card = cards[i];
|
|
13766
|
+
// This Mac is not a pool member: R-11's policy is per OTHER machine. The phone's self card
|
|
13767
|
+
// (`mp-self`, public/m/machines.js) DOES carry an instance id, so the skip is by class — the
|
|
13768
|
+
// same rule as the desktop page, whose self card has no trust select at all.
|
|
13769
|
+
if (String(card.className || '').split(/\s+/).includes('mp-self')) continue;
|
|
13770
|
+
const id = String((card.getAttribute && card.getAttribute('data-machine-id')) || card.dataset?.machineId || '');
|
|
13771
|
+
if (!id) continue;
|
|
13772
|
+
// The shared template IS the `.mp-access` element (machineAccessBlockHtml), so it goes inside a
|
|
13773
|
+
// plain mount node that a repaint rewrites — never inside another `.mp-access`.
|
|
13774
|
+
let node = typeof card.querySelector === 'function' ? card.querySelector('.mp-access-mount') : null;
|
|
13775
|
+
if (!node) {
|
|
13776
|
+
node = document.createElement('div');
|
|
13777
|
+
node.className = 'mp-access-mount';
|
|
13778
|
+
card.appendChild(node);
|
|
13779
|
+
}
|
|
13780
|
+
node.innerHTML = phoneAccessBlockHtml({ instanceId: id });
|
|
13781
|
+
mounted += 1;
|
|
13782
|
+
}
|
|
13783
|
+
return mounted;
|
|
13784
|
+
}
|
|
13785
|
+
|
|
13786
|
+
// ONE delegated pair of listeners for the whole phone surface: the More container is rewritten
|
|
13787
|
+
// wholesale and the session detail is a different subtree, so per-node listeners would be lost. The
|
|
13788
|
+
// hooks are the shared ones (public/js/machine-pool-shared.js), so the phone and the desktop bind
|
|
13789
|
+
// the same markup. Capture phase, so a control inside a card never also opens the card.
|
|
13790
|
+
function phoneAccessBind() {
|
|
13791
|
+
if (typeof document === 'undefined' || typeof document.addEventListener !== 'function') return false;
|
|
13792
|
+
if (document.__ctmPhoneAccessBound) return false;
|
|
13793
|
+
document.__ctmPhoneAccessBound = true;
|
|
13794
|
+
document.addEventListener('change', (event) => {
|
|
13795
|
+
const node = event.target && typeof event.target.closest === 'function'
|
|
13796
|
+
? event.target.closest(HUB_BRIDGE_TRUST_HOOK) : null;
|
|
13797
|
+
if (!node || typeof node.getAttribute !== 'function') return;
|
|
13798
|
+
if (node.hasAttribute && node.hasAttribute('data-hub-bridge-trust-all')) { phoneAccessTrustAll(!!event.target.checked); return; }
|
|
13799
|
+
phoneAccessTrustChange(node.getAttribute('data-hub-bridge-trust'), event.target.value);
|
|
13800
|
+
}, true);
|
|
13801
|
+
document.addEventListener('click', (event) => {
|
|
13802
|
+
const node = event.target && typeof event.target.closest === 'function'
|
|
13803
|
+
? event.target.closest(HUB_BRIDGE_ACTION_HOOK) : null;
|
|
13804
|
+
if (!node || typeof node.getAttribute !== 'function') return;
|
|
13805
|
+
if (typeof event.stopPropagation === 'function') event.stopPropagation();
|
|
13806
|
+
const action = node.getAttribute('data-hub-bridge');
|
|
13807
|
+
if (action === 'allow') phoneAccessAllow(node.getAttribute('data-machine-id'), node.getAttribute('data-pending-id'), node.getAttribute('data-grant'));
|
|
13808
|
+
else if (action === 'deny') phoneAccessDeny(node.getAttribute('data-pending-id'));
|
|
13809
|
+
else if (action === 'revoke') phoneAccessRevoke(node.getAttribute('data-machine-id'), node.getAttribute('data-session-id'), node.getAttribute('data-tier'));
|
|
13810
|
+
}, true);
|
|
13811
|
+
return true;
|
|
13812
|
+
}
|
|
13813
|
+
|
|
13814
|
+
// ── AC-2g on the phone: the same banner sentence, in the session detail ─────────────────────────
|
|
13815
|
+
/** The open ask that belongs to the session the detail view is showing, if there is one. */
|
|
13816
|
+
function phoneAccessBannerRow() {
|
|
13817
|
+
const sid = String(state.activeSession?.id || '');
|
|
13818
|
+
if (!sid) return null;
|
|
13819
|
+
for (const key of Object.keys(phoneAccessState.pendingIndex)) {
|
|
13820
|
+
const row = phoneAccessState.pendingIndex[key];
|
|
13821
|
+
if (row && String(row.callerSessionId || '') === sid) return row;
|
|
13822
|
+
}
|
|
13823
|
+
return null;
|
|
13824
|
+
}
|
|
13825
|
+
|
|
13826
|
+
/** The detail view's banner slot: beside #detail-alert, above the message list. */
|
|
13827
|
+
function phoneAccessBannerHost() {
|
|
13828
|
+
const alert = $('detail-alert');
|
|
13829
|
+
const messages = $('detail-messages');
|
|
13830
|
+
const host = (alert && alert.parentNode) || (messages && messages.parentNode) || null;
|
|
13831
|
+
return { host, before: (messages && messages.parentNode === host) ? messages : null };
|
|
13832
|
+
}
|
|
13833
|
+
|
|
13834
|
+
function phoneAccessPaintBanner() {
|
|
13835
|
+
const slot = phoneAccessBannerHost();
|
|
13836
|
+
if (!slot.host || typeof document === 'undefined' || typeof document.createElement !== 'function') return 0;
|
|
13837
|
+
const row = phoneAccessBannerRow();
|
|
13838
|
+
const existing = typeof slot.host.querySelector === 'function' ? slot.host.querySelector('.mp-approval-banner') : null;
|
|
13839
|
+
if (!row) {
|
|
13840
|
+
if (existing && existing.parentNode) existing.parentNode.removeChild(existing);
|
|
13841
|
+
return 0;
|
|
13842
|
+
}
|
|
13843
|
+
let node = existing;
|
|
13844
|
+
if (!node) {
|
|
13845
|
+
node = document.createElement('section');
|
|
13846
|
+
node.className = 'detail-alert mp-approval-banner';
|
|
13847
|
+
if (typeof slot.host.insertBefore === 'function' && slot.before) slot.host.insertBefore(node, slot.before);
|
|
13848
|
+
else if (typeof slot.host.appendChild === 'function') slot.host.appendChild(node);
|
|
13849
|
+
}
|
|
13850
|
+
node.hidden = false;
|
|
13851
|
+
node.setAttribute('data-pending-id', String(row.id || ''));
|
|
13852
|
+
node.innerHTML = hubBridgeBannerHtml(row, PHONE_ACCESS_OPTS);
|
|
13853
|
+
return 1;
|
|
13854
|
+
}
|
|
13855
|
+
|
|
13856
|
+
/** Re-read the open asks when the detail view opens, so a banner is there before any frame. */
|
|
13857
|
+
async function phoneAccessSeedBanners() {
|
|
13858
|
+
try {
|
|
13859
|
+
const grants = await api('/api/hub-bridge/grants');
|
|
13860
|
+
phoneAccessApply(phoneAccessState.trust, grants);
|
|
13861
|
+
} catch {
|
|
13862
|
+
// HANDLE: an unreadable hub seeds nothing; the next frame or card open re-reads.
|
|
13863
|
+
}
|
|
13864
|
+
phoneAccessPaintBanner();
|
|
13865
|
+
return true;
|
|
13866
|
+
}
|
|
13867
|
+
|
|
13868
|
+
/** The phone's half of the R-5 fan-out: repaint the banner, and the Access block when it is on screen. */
|
|
13869
|
+
function phoneAccessOnFrame(msg) {
|
|
13870
|
+
const type = String((msg && msg.type) || '');
|
|
13871
|
+
if (type === 'hub-bridge-pending') {
|
|
13872
|
+
const row = msg && msg.pending;
|
|
13873
|
+
if (row && row.id) phoneAccessState.pendingIndex[String(row.id)] = row;
|
|
13874
|
+
} else if (type === 'hub-bridge-pending-cleared') {
|
|
13875
|
+
for (const id of ((msg && Array.isArray(msg.ids)) ? msg.ids : [])) delete phoneAccessState.pendingIndex[String(id || '')];
|
|
13876
|
+
} else {
|
|
13877
|
+
return false;
|
|
13878
|
+
}
|
|
13879
|
+
phoneAccessPaintBanner();
|
|
13880
|
+
const content = $('more-content');
|
|
13881
|
+
if (content && typeof content.querySelectorAll === 'function' && content.querySelectorAll('.mp-card').length) {
|
|
13882
|
+
phoneAccessRefresh().catch(() => {});
|
|
13883
|
+
}
|
|
13884
|
+
return true;
|
|
13885
|
+
}
|
|
13886
|
+
|
|
13887
|
+
// The page-level "Trust all my machines" switch lives in the Machines header, which m/machines.js
|
|
13888
|
+
// renders; app.js has no header hook, so the switch is mounted beside the section card. Kept in the
|
|
13889
|
+
// module scope so the phone twin of the desktop header control has ONE home.
|
|
13890
|
+
function phoneAccessTrustAllMount() {
|
|
13891
|
+
const card = $('phone-machines-card');
|
|
13892
|
+
if (!card || typeof card.appendChild !== 'function') return false;
|
|
13893
|
+
if (typeof card.querySelector === 'function' && card.querySelector('.mp-access-trust-all')) return true;
|
|
13894
|
+
if (typeof document === 'undefined' || typeof document.createElement !== 'function') return false;
|
|
13895
|
+
const wrap = document.createElement('div');
|
|
13896
|
+
wrap.className = 'mp-toolbar';
|
|
13897
|
+
wrap.innerHTML = phoneAccessTrustAllHtml();
|
|
13898
|
+
card.appendChild(wrap);
|
|
13899
|
+
return true;
|
|
13467
13900
|
}
|
|
13468
13901
|
|
|
13469
13902
|
// ── WP-6 item 3: the picker — <select> at N <= 4, the search sheet above it ─────────────────────
|
|
@@ -13684,7 +14117,7 @@
|
|
|
13684
14117
|
return;
|
|
13685
14118
|
}
|
|
13686
14119
|
if (String($('new-session-machine')?.value || '').trim() !== machine) return;
|
|
13687
|
-
select.innerHTML = phoneProjectOptionsHtml(rows);
|
|
14120
|
+
select.innerHTML = phoneProjectOptionsHtml(rows); if (state.projectsError && (await loadProjects(), state.projectsError)) return phoneMachineSetHint(`Couldn't read the project lists right now — pick the folder on ${name}.`, true); // D-6: retry this device's list; a failed read is UNKNOWN, never "no checkout"
|
|
13688
14121
|
const match = phoneSameRepoProject(state.projects, state.newSessionLocalCwd, rows);
|
|
13689
14122
|
if (match) {
|
|
13690
14123
|
select.value = match;
|
|
@@ -13704,6 +14137,9 @@
|
|
|
13704
14137
|
const agentLabel = agentSelect.selectedOptions?.[0]?.textContent?.trim() || agent;
|
|
13705
14138
|
const prompt = $('new-session-prompt').value.trim();
|
|
13706
14139
|
const isWalle = agent === 'walle';
|
|
14140
|
+
// WP-7 (S-60): the DeepSeek Harness is a conv-only ACP agent — same create frame as desktop
|
|
14141
|
+
// (`cmd:'dsh'`, `agentType:'dsh'`, no CLI args). Its first turn is typed in the composer.
|
|
14142
|
+
const isDsh = agent === 'dsh';
|
|
13707
14143
|
const cmd = agent === 'codex'
|
|
13708
14144
|
? 'codex'
|
|
13709
14145
|
: agent === 'gemini'
|
|
@@ -13712,12 +14148,12 @@
|
|
|
13712
14148
|
? undefined
|
|
13713
14149
|
: isWalle
|
|
13714
14150
|
? 'walle'
|
|
13715
|
-
: 'claude';
|
|
13716
|
-
const args = prompt && !isWalle ? [prompt] : [];
|
|
14151
|
+
: isDsh ? 'dsh' : 'claude';
|
|
14152
|
+
const args = prompt && !isWalle && !isDsh ? [prompt] : [];
|
|
13717
14153
|
// WP-5 (S-12/S-16): the machine chosen in the sheet travels with the create frame as `machine`;
|
|
13718
14154
|
// '' is this Mac and the field is omitted, so a local create frame is unchanged.
|
|
13719
14155
|
const machine = ($('new-session-machine')?.value || '').trim();
|
|
13720
|
-
const request = Object.freeze({ cwd, agent, agentLabel, prompt, isWalle, cmd, args: Object.freeze(args.slice()), machine });
|
|
14156
|
+
const request = Object.freeze({ cwd, agent, agentLabel, prompt, isWalle, isDsh, cmd, args: Object.freeze(args.slice()), machine });
|
|
13721
14157
|
const action = async () => {
|
|
13722
14158
|
if (!privateLeaseCurrent(lease) || state.pendingStepUp?.action !== action) throw privateScopeChangedError();
|
|
13723
14159
|
const id = randomId();
|
|
@@ -13730,6 +14166,7 @@
|
|
|
13730
14166
|
});
|
|
13731
14167
|
if (request.prompt) payload.initialMessage = request.prompt;
|
|
13732
14168
|
}
|
|
14169
|
+
if (request.isDsh) Object.assign(payload, { label: request.agentLabel || 'DeepSeek Harness', agentType: 'dsh' });
|
|
13733
14170
|
await sendWs(payload);
|
|
13734
14171
|
if (!privateLeaseCurrent(lease) || state.pendingStepUp?.action !== action) throw privateScopeChangedError();
|
|
13735
14172
|
$('new-session-sheet').hidden = true;
|
|
@@ -13892,6 +14329,8 @@
|
|
|
13892
14329
|
});
|
|
13893
14330
|
$('refresh-btn').addEventListener('click', refresh);
|
|
13894
14331
|
$('app-reload-now-btn')?.addEventListener('click', () => reloadForInstalledUpdate('banner'));
|
|
14332
|
+
// WP-2 (AC-2b): the same one action the desktop banner's Resume button posts.
|
|
14333
|
+
$('host-dead-resume-btn')?.addEventListener('click', () => { void resumeHostDeadSessions(); });
|
|
13895
14334
|
$('detail-back').addEventListener('click', (event) => {
|
|
13896
14335
|
event.preventDefault();
|
|
13897
14336
|
event.stopPropagation();
|