@reticlehq/server 3.7.0 → 3.8.1
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/SKILL.md +59 -68
- package/bin/reticle.js +9 -2
- package/dist/command/cli/adhoc-suite.js +1 -1
- package/dist/command/cli/adhoc-verdict.d.ts +12 -0
- package/dist/command/cli/adhoc-verdict.js +62 -4
- package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
- package/dist/command/cli/answers/gate-hook-message.js +5 -1
- package/dist/command/cli/auth/cloud-session.d.ts +11 -19
- package/dist/command/cli/auth/cloud-session.js +23 -0
- package/dist/command/cli/auth/device-flow.d.ts +3 -37
- package/dist/command/cli/cli-doctor.js +66 -21
- package/dist/command/cli/cli-flow-commands.js +53 -11
- package/dist/command/cli/cli-kill.d.ts +8 -0
- package/dist/command/cli/cli-kill.js +43 -3
- package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
- package/dist/command/cli/cli-parse-feedback.js +13 -1
- package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
- package/dist/command/cli/cli-parse-grammar.js +1 -6
- package/dist/command/cli/cli-parse-serve.d.ts +24 -0
- package/dist/command/cli/cli-parse-serve.js +124 -0
- package/dist/command/cli/cli-parse.d.ts +12 -11
- package/dist/command/cli/cli-parse.js +100 -123
- package/dist/command/cli/cli-usage.d.ts +0 -11
- package/dist/command/cli/cli-usage.js +43 -16
- package/dist/command/cli/cli-verify.d.ts +1 -1
- package/dist/command/cli/cli-verify.js +29 -14
- package/dist/command/cli/cloud-cli.js +27 -9
- package/dist/command/cli/cloud-kit.js +3 -3
- package/dist/command/cli/cloud-link.d.ts +1 -20
- package/dist/command/cli/cloud-link.js +2 -0
- package/dist/command/cli/cloud-login.d.ts +6 -2
- package/dist/command/cli/cloud-login.js +13 -41
- package/dist/command/cli/config/checkout.d.ts +10 -0
- package/dist/command/cli/config/checkout.js +78 -0
- package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
- package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
- package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
- package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
- package/dist/command/cli/doctor/doctor-rows.js +4 -0
- package/dist/command/cli/drive/drive-attach.d.ts +5 -0
- package/dist/command/cli/drive/drive-attach.js +21 -1
- package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
- package/dist/command/cli/hook/codex-transcript.js +224 -0
- package/dist/command/cli/hook/episode-structure.d.ts +24 -0
- package/dist/command/cli/hook/episode-structure.js +138 -0
- package/dist/command/cli/hook/hook-command.d.ts +9 -0
- package/dist/command/cli/hook/hook-command.js +211 -0
- package/dist/command/cli/hook/hook-fast.d.ts +31 -0
- package/dist/command/cli/hook/hook-fast.js +136 -0
- package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
- package/dist/command/cli/hook/prompt-hook.js +199 -0
- package/dist/command/cli/hook/tool-hook.d.ts +21 -0
- package/dist/command/cli/hook/tool-hook.js +259 -0
- package/dist/command/cli/launch/cli-launch.d.ts +2 -0
- package/dist/command/cli/launch/cli-launch.js +22 -2
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
- package/dist/command/cli/mcp-command.d.ts +9 -0
- package/dist/command/cli/mcp-command.js +127 -41
- package/dist/command/cli/open-navigate.d.ts +43 -0
- package/dist/command/cli/open-navigate.js +85 -0
- package/dist/command/cli/ports/port-holder.d.ts +16 -4
- package/dist/command/cli/ports/port-holder.js +58 -12
- package/dist/command/cli/ports/resolve/cli-port.js +18 -2
- package/dist/command/cli/project-name.d.ts +1 -7
- package/dist/command/cli/project-name.js +1 -0
- package/dist/command/cli/report-command.d.ts +8 -2
- package/dist/command/cli/report-command.js +95 -18
- package/dist/command/cli/status-fields.d.ts +9 -2
- package/dist/command/cli/status-fields.js +148 -4
- package/dist/command/cli/try-command.d.ts +3 -4
- package/dist/command/cli/try-command.js +6 -11
- package/dist/command/cli/verify-results.d.ts +4 -1
- package/dist/command/cli/verify-results.js +3 -1
- package/dist/command/cli.d.ts +1 -7
- package/dist/command/cli.js +79 -160
- package/dist/command/daemon/daemon-resilience.d.ts +6 -1
- package/dist/command/daemon/daemon-resilience.js +31 -18
- package/dist/command/daemon/daemon.d.ts +11 -0
- package/dist/command/daemon/daemon.js +70 -2
- package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
- package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
- package/dist/command/daemon/wake-decision.js +4 -2
- package/dist/command/daemon/win32-escape.d.ts +32 -0
- package/dist/command/daemon/win32-escape.js +119 -0
- package/dist/command/setup/agent-configs.d.ts +9 -0
- package/dist/command/setup/agent-configs.js +9 -0
- package/dist/command/setup/auto-approve.d.ts +10 -3
- package/dist/command/setup/auto-approve.js +51 -3
- package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
- package/dist/command/setup/bringup/dev-server-wait.js +5 -1
- package/dist/command/setup/bringup/ensure-daemon.js +4 -7
- package/dist/command/setup/init/init-host.js +6 -0
- package/dist/command/setup/init/init-port.js +5 -4
- package/dist/command/setup/init/init-runtime.js +7 -1
- package/dist/command/setup/node-effects.d.ts +8 -0
- package/dist/command/setup/node-effects.js +36 -4
- package/dist/command/setup/probe/dev-port.d.ts +26 -0
- package/dist/command/setup/probe/dev-port.js +117 -0
- package/dist/command/setup/probe/page-probe.d.ts +1 -1
- package/dist/command/setup/probe/page-probe.js +11 -3
- package/dist/command/setup/remaining-steps.d.ts +0 -7
- package/dist/command/setup/remaining-steps.js +3 -2
- package/dist/command/setup/run-setup.d.ts +11 -0
- package/dist/command/setup/run-setup.js +33 -5
- package/dist/command/setup/setup-command.d.ts +2 -0
- package/dist/command/setup/setup-command.js +22 -4
- package/dist/command/update/updater.d.ts +1 -6
- package/dist/command/update/updater.js +4 -5
- package/dist/command/update/version-seen.d.ts +24 -0
- package/dist/command/update/version-seen.js +65 -0
- package/dist/command/version/peer-announce.d.ts +9 -1
- package/dist/command/version/peer-announce.js +25 -2
- package/dist/command/version/sdk-fix.d.ts +5 -6
- package/dist/command/version/sdk-fix.js +17 -32
- package/dist/command/version/version-skew.d.ts +16 -1
- package/dist/command/version/version-skew.js +84 -10
- package/dist/features/crawl/crawl-tools.js +2 -2
- package/dist/features/crawl/crawl.js +2 -0
- package/dist/features/exhaust/ledger.d.ts +15 -96
- package/dist/features/exhaust/ledger.js +3 -3
- package/dist/features/harness/drive-runs.d.ts +28 -4
- package/dist/features/harness/drive-runs.js +99 -7
- package/dist/features/harness/drivers.d.ts +1 -1
- package/dist/features/harness/drivers.js +1 -1
- package/dist/features/harness/harness.d.ts +5 -0
- package/dist/features/harness/harness.js +24 -12
- package/dist/features/harness/platform/platform-drives.d.ts +7 -1
- package/dist/features/harness/platform/platform-drives.js +12 -7
- package/dist/features/harness/platform/refusal.d.ts +1 -1
- package/dist/features/harness/platform/refusal.js +4 -4
- package/dist/features/harness/platform/remote-drive.js +70 -28
- package/dist/features/harness/platform/server-driver.js +22 -1
- package/dist/features/harness/platform-config.d.ts +1 -10
- package/dist/features/harness/platform-config.js +0 -20
- package/dist/features/license/license.d.ts +2 -14
- package/dist/features/visual/step-shots.d.ts +33 -1
- package/dist/features/visual/step-shots.js +155 -1
- package/dist/features/visual/visual-tools.js +12 -4
- package/dist/hooks/coding-agents.d.ts +6 -0
- package/dist/hooks/coding-agents.js +24 -3
- package/dist/hooks/episode-stamp.d.ts +32 -0
- package/dist/hooks/episode-stamp.js +61 -0
- package/dist/hooks/hook-commands.js +19 -9
- package/dist/index.d.ts +5 -1
- package/dist/index.js +66 -24
- package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
- package/dist/judgement/app-graph/journal-steps.js +92 -0
- package/dist/judgement/capsule/capsule-store.d.ts +2 -39
- package/dist/judgement/domain/domain-model.js +1 -10
- package/dist/judgement/domain/domain-tools.js +4 -2
- package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
- package/dist/judgement/runs/artifact/run-store.js +153 -28
- package/dist/judgement/runs/default-run-id.d.ts +3 -1
- package/dist/judgement/runs/default-run-id.js +15 -3
- package/dist/judgement/runs/drive-run.d.ts +3 -3
- package/dist/judgement/runs/drive-run.js +11 -7
- package/dist/judgement/runs/run-ledger.d.ts +21 -0
- package/dist/judgement/runs/run-ledger.js +143 -0
- package/dist/judgement/runs/runner-port.d.ts +1 -1
- package/dist/judgement/runs/runner-port.js +8 -2
- package/dist/judgement/runs/verification-sync.d.ts +4 -3
- package/dist/judgement/runs/verification-sync.js +27 -5
- package/dist/language/flows/affected-tools.js +2 -1
- package/dist/language/flows/annotate-notes/annotate.js +8 -3
- package/dist/language/flows/annotate-tools.js +1 -1
- package/dist/language/flows/change/affected.d.ts +8 -0
- package/dist/language/flows/change/affected.js +20 -7
- package/dist/language/flows/decision.js +19 -4
- package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
- package/dist/language/flows/fields/flow-secret-field.js +67 -5
- package/dist/language/flows/flow-anchor.d.ts +5 -0
- package/dist/language/flows/flow-anchor.js +4 -0
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +9 -0
- package/dist/language/flows/flow-expect-grammar.js +15 -10
- package/dist/language/flows/flow-intent.js +6 -1
- package/dist/language/flows/flow-journey.d.ts +8 -0
- package/dist/language/flows/flow-journey.js +13 -0
- package/dist/language/flows/flow-lease.d.ts +27 -0
- package/dist/language/flows/flow-lease.js +59 -0
- package/dist/language/flows/flow-replay-run.d.ts +1 -87
- package/dist/language/flows/flow-replay-run.js +111 -310
- package/dist/language/flows/flow-replay.js +21 -19
- package/dist/language/flows/flow-replayable.d.ts +38 -0
- package/dist/language/flows/flow-replayable.js +179 -0
- package/dist/language/flows/flow-start-path.d.ts +108 -0
- package/dist/language/flows/flow-start-path.js +313 -0
- package/dist/language/flows/flow-step-runners.d.ts +23 -2
- package/dist/language/flows/flow-step-runners.js +191 -32
- package/dist/language/flows/flow-store-for-session.d.ts +8 -1
- package/dist/language/flows/flow-store-for-session.js +6 -0
- package/dist/language/flows/flow-tools.d.ts +2 -23
- package/dist/language/flows/flow-tools.js +63 -113
- package/dist/language/flows/flows.d.ts +4 -6
- package/dist/language/flows/flows.js +90 -15
- package/dist/language/flows/heal-run.d.ts +10 -4
- package/dist/language/flows/heal-run.js +26 -9
- package/dist/language/flows/recording/flake.d.ts +3 -27
- package/dist/language/flows/recording/flake.js +1 -1
- package/dist/language/flows/recording/recording-backtrack.js +1 -4
- package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
- package/dist/language/flows/recording/tape/recordings.js +9 -3
- package/dist/language/flows/replay.d.ts +25 -5
- package/dist/language/flows/replay.js +83 -16
- package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
- package/dist/language/flows/suite/coverage.d.ts +9 -0
- package/dist/language/flows/suite/coverage.js +12 -1
- package/dist/language/flows/suite-selection.d.ts +25 -0
- package/dist/language/flows/suite-selection.js +41 -9
- package/dist/machine/git-tracks.d.ts +6 -0
- package/dist/machine/git-tracks.js +36 -0
- package/dist/memory/cloud/background-sync.d.ts +25 -0
- package/dist/memory/cloud/background-sync.js +79 -0
- package/dist/memory/cloud/cloud-config.d.ts +12 -1
- package/dist/memory/cloud/cloud-config.js +39 -13
- package/dist/memory/cloud/cloud-sync.d.ts +3 -24
- package/dist/memory/cloud/cloud-sync.js +5 -2
- package/dist/memory/cloud/harness-config.d.ts +0 -7
- package/dist/memory/cloud/memory-scope.d.ts +19 -0
- package/dist/memory/cloud/memory-scope.js +48 -0
- package/dist/memory/cloud/sync-answer.d.ts +43 -0
- package/dist/memory/cloud/sync-answer.js +42 -0
- package/dist/memory/cloud/sync-cycle.d.ts +40 -10
- package/dist/memory/cloud/sync-cycle.js +97 -144
- package/dist/memory/cloud/sync-daemon.d.ts +50 -3
- package/dist/memory/cloud/sync-daemon.js +473 -83
- package/dist/memory/cloud/sync-describe.d.ts +28 -0
- package/dist/memory/cloud/sync-describe.js +92 -0
- package/dist/memory/cloud/sync-disk.d.ts +9 -1
- package/dist/memory/cloud/sync-disk.js +137 -33
- package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
- package/dist/memory/cloud/sync-flow-versions.js +42 -0
- package/dist/memory/impact/impact-store.js +32 -15
- package/dist/memory/intent/intent-shard.d.ts +41 -266
- package/dist/memory/intent/intent-tools.js +20 -61
- package/dist/memory/intent/record-request.d.ts +27 -0
- package/dist/memory/intent/record-request.js +88 -0
- package/dist/memory/intent/settled-words.js +9 -1
- package/dist/memory/journal/drive-flow.d.ts +3 -0
- package/dist/memory/journal/drive-flow.js +11 -41
- package/dist/memory/journal/envelope-store.js +1 -1
- package/dist/memory/journal/envelope.d.ts +6 -154
- package/dist/memory/journal/episode-log.d.ts +107 -0
- package/dist/memory/journal/episode-log.js +302 -0
- package/dist/memory/journal/journal-recorder.d.ts +7 -0
- package/dist/memory/journal/journal-recorder.js +22 -9
- package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
- package/dist/memory/journal/on-disk/ambient-file.js +1 -1
- package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
- package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
- package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
- package/dist/memory/journal/self-observation.js +3 -1
- package/dist/memory/journal/session-end.js +23 -9
- package/dist/memory/journal/session-journal.js +39 -20
- package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
- package/dist/memory/project/artifact-root-resolver.js +68 -23
- package/dist/memory/project/artifact-root.d.ts +17 -3
- package/dist/memory/project/artifact-root.js +47 -9
- package/dist/memory/project/fs/fs-port.d.ts +5 -0
- package/dist/memory/project/fs/fs-port.js +13 -0
- package/dist/memory/project/learned-routes.d.ts +3 -4
- package/dist/memory/project/learned-routes.js +3 -11
- package/dist/memory/project/link-directory.js +5 -2
- package/dist/memory/project/root-claims.d.ts +3 -1
- package/dist/memory/project/root-claims.js +41 -7
- package/dist/memory/project/session-root.d.ts +1 -1
- package/dist/memory/project/session-root.js +1 -15
- package/dist/memory/project/sync-status.js +5 -6
- package/dist/memory/recall/memory-tools.js +2 -2
- package/dist/memory/recall/platform-memory.d.ts +3 -1
- package/dist/memory/recall/platform-memory.js +9 -1
- package/dist/memory/recall/project-memory.js +15 -19
- package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
- package/dist/portal/bridge/auth-failure-reason.js +19 -0
- package/dist/portal/bridge/bridge.d.ts +19 -4
- package/dist/portal/bridge/bridge.js +150 -177
- package/dist/portal/bridge/harness-request.d.ts +15 -0
- package/dist/portal/bridge/harness-request.js +19 -0
- package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
- package/dist/portal/bridge/origin/origin-follow.js +110 -0
- package/dist/portal/bridge/pairing-token.d.ts +6 -0
- package/dist/portal/bridge/pairing-token.js +47 -16
- package/dist/portal/bridge/protocol-skew.d.ts +27 -2
- package/dist/portal/bridge/protocol-skew.js +66 -2
- package/dist/portal/bridge/session-nonces.d.ts +46 -0
- package/dist/portal/bridge/session-nonces.js +72 -0
- package/dist/portal/input/viewport-tools.d.ts +31 -0
- package/dist/portal/input/viewport-tools.js +106 -15
- package/dist/portal/pool/bounded-close.d.ts +23 -0
- package/dist/portal/pool/bounded-close.js +38 -0
- package/dist/portal/pool/browser-pool.d.ts +44 -39
- package/dist/portal/pool/browser-pool.js +247 -95
- package/dist/portal/pool/context-permissions.d.ts +9 -1
- package/dist/portal/pool/context-permissions.js +26 -0
- package/dist/portal/pool/lease-emulation.d.ts +37 -0
- package/dist/portal/pool/lease-emulation.js +29 -0
- package/dist/portal/pool/playwright-launcher.d.ts +6 -0
- package/dist/portal/pool/playwright-launcher.js +74 -7
- package/dist/portal/pool/pool-contract.d.ts +23 -1
- package/dist/portal/pool/pool-lease.d.ts +128 -0
- package/dist/portal/pool/pool-lease.js +49 -0
- package/dist/portal/pool/zero-install.d.ts +8 -1
- package/dist/portal/pool/zero-install.js +24 -2
- package/dist/portal/production/production-activation.d.ts +136 -0
- package/dist/portal/production/production-activation.js +173 -0
- package/dist/portal/production/production-drive.d.ts +52 -0
- package/dist/portal/production/production-drive.js +301 -0
- package/dist/portal/production/production-hello.d.ts +23 -0
- package/dist/portal/production/production-hello.js +23 -0
- package/dist/portal/realm/web-realm.js +42 -15
- package/dist/portal/session/control-envelope.d.ts +1 -1
- package/dist/portal/session/dev-server/served-document.d.ts +0 -5
- package/dist/portal/session/dev-server/served-document.js +6 -8
- package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
- package/dist/portal/session/first-run-wiring.d.ts +3 -36
- package/dist/portal/session/first-run-wiring.js +10 -103
- package/dist/portal/session/live-control-tools.js +61 -19
- package/dist/portal/session/no-session-next-action.d.ts +11 -0
- package/dist/portal/session/no-session-next-action.js +40 -15
- package/dist/portal/session/no-session-watch.d.ts +7 -0
- package/dist/portal/session/no-session-watch.js +67 -23
- package/dist/portal/session/output-budget.d.ts +10 -0
- package/dist/portal/session/output-budget.js +16 -0
- package/dist/portal/session/presence/session-lease.d.ts +2 -0
- package/dist/portal/session/presence/session-lease.js +8 -0
- package/dist/portal/session/recorded-gaps.d.ts +15 -11
- package/dist/portal/session/recorded-gaps.js +39 -18
- package/dist/portal/session/serving-directory.d.ts +24 -2
- package/dist/portal/session/serving-directory.js +93 -5
- package/dist/portal/session/session-info.d.ts +26 -0
- package/dist/portal/session/session-info.js +20 -0
- package/dist/portal/session/session-manager.d.ts +35 -3
- package/dist/portal/session/session-manager.js +69 -14
- package/dist/portal/session/session-successor.js +1 -9
- package/dist/portal/session/session-tools.js +22 -4
- package/dist/portal/session/session.d.ts +10 -10
- package/dist/portal/session/session.js +37 -29
- package/dist/portal/session/zero-install-first-call.d.ts +7 -2
- package/dist/portal/session/zero-install-first-call.js +43 -20
- package/dist/start-wiring.d.ts +2 -2
- package/dist/start-wiring.js +17 -3
- package/dist/status-payload.d.ts +11 -1
- package/dist/status-payload.js +7 -1
- package/dist/surface/agent-presence-grace.d.ts +11 -0
- package/dist/surface/agent-presence-grace.js +34 -0
- package/dist/surface/http-server.d.ts +12 -1
- package/dist/surface/http-server.js +64 -15
- package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
- package/dist/surface/mcp/faults/mcp-outage.js +19 -1
- package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
- package/dist/surface/mcp/mcp-proxy.js +194 -267
- package/dist/surface/mcp/mcp.d.ts +20 -3
- package/dist/surface/mcp/mcp.js +88 -25
- package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
- package/dist/surface/mcp/proxy/drive-calls.js +114 -5
- package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
- package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
- package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
- package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
- package/dist/surface/mcp/server-instructions.js +35 -16
- package/dist/surface/mcp/shared-params.d.ts +8 -0
- package/dist/surface/mcp/shared-params.js +15 -1
- package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
- package/dist/surface/mcp/sse-frame-parser.js +18 -0
- package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
- package/dist/surface/mcp/surface-vocabulary.js +13 -0
- package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
- package/dist/surface/mcp/tool-catalog-cache.js +14 -4
- package/dist/surface/tools/account-tool.d.ts +4 -3
- package/dist/surface/tools/account-tool.js +20 -31
- package/dist/surface/tools/act/act-danger.d.ts +2 -0
- package/dist/surface/tools/act/act-danger.js +41 -14
- package/dist/surface/tools/act/act-observation.d.ts +11 -0
- package/dist/surface/tools/act/act-observation.js +33 -0
- package/dist/surface/tools/act/act-preflight.js +10 -3
- package/dist/surface/tools/act/act-sequence-retry.js +2 -1
- package/dist/surface/tools/act/act-target.js +19 -5
- package/dist/surface/tools/act/durable.js +1 -1
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
- package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
- package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
- package/dist/surface/tools/act/unsettled-find.js +71 -0
- package/dist/surface/tools/act-sequence-tool.js +53 -24
- package/dist/surface/tools/act-tools.d.ts +2 -3
- package/dist/surface/tools/act-tools.js +49 -47
- package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
- package/dist/surface/tools/agent/for-the-agent.js +41 -3
- package/dist/surface/tools/assert/assert-grade.js +8 -3
- package/dist/surface/tools/assert/assert-verdict.js +4 -2
- package/dist/surface/tools/browser-tools.js +7 -4
- package/dist/surface/tools/chat-drives.js +50 -25
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.d.ts +8 -0
- package/dist/surface/tools/dynamic-tools.js +89 -34
- package/dist/surface/tools/empty-session-list.d.ts +18 -25
- package/dist/surface/tools/empty-session-list.js +67 -38
- package/dist/surface/tools/error-recovery.d.ts +17 -7
- package/dist/surface/tools/error-recovery.js +53 -20
- package/dist/surface/tools/explore-tools.d.ts +10 -0
- package/dist/surface/tools/explore-tools.js +72 -19
- package/dist/surface/tools/feedback-tools.js +23 -2
- package/dist/surface/tools/gap-novelty.d.ts +6 -0
- package/dist/surface/tools/gap-novelty.js +9 -0
- package/dist/surface/tools/gaps/capability-absences.js +4 -3
- package/dist/surface/tools/harness-explore.d.ts +1 -1
- package/dist/surface/tools/harness-explore.js +6 -4
- package/dist/surface/tools/harness-gate.d.ts +43 -21
- package/dist/surface/tools/harness-gate.js +55 -81
- package/dist/surface/tools/harness-script.d.ts +2 -0
- package/dist/surface/tools/harness-script.js +11 -6
- package/dist/surface/tools/harness-toolset.js +3 -4
- package/dist/surface/tools/invoke-tool.d.ts +0 -8
- package/dist/surface/tools/invoke-tool.js +164 -178
- package/dist/surface/tools/lease-hint.d.ts +9 -0
- package/dist/surface/tools/lease-hint.js +22 -3
- package/dist/surface/tools/lease-permissions.d.ts +1 -1
- package/dist/surface/tools/lease-readiness.d.ts +55 -0
- package/dist/surface/tools/lease-readiness.js +150 -2
- package/dist/surface/tools/lease-tools.d.ts +3 -75
- package/dist/surface/tools/lease-tools.js +124 -188
- package/dist/surface/tools/map-tools.d.ts +20 -0
- package/dist/surface/tools/map-tools.js +145 -0
- package/dist/surface/tools/merge-tools.js +11 -7
- package/dist/surface/tools/next-step.js +6 -3
- package/dist/surface/tools/observe-tools.js +46 -35
- package/dist/surface/tools/platform-moment.d.ts +3 -12
- package/dist/surface/tools/platform-moment.js +12 -24
- package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
- package/dist/surface/tools/read/complete-snapshot.js +13 -2
- package/dist/surface/tools/read/query-paginate.js +6 -0
- package/dist/surface/tools/read/query-shape.d.ts +9 -0
- package/dist/surface/tools/read/query-shape.js +15 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
- package/dist/surface/tools/read-tools.js +5 -5
- package/dist/surface/tools/real-input-attempt.d.ts +11 -0
- package/dist/surface/tools/real-input-attempt.js +206 -38
- package/dist/surface/tools/reconcile-tools.js +21 -8
- package/dist/surface/tools/reticle-result.d.ts +3 -0
- package/dist/surface/tools/reticle-result.js +8 -1
- package/dist/surface/tools/run-report.d.ts +22 -0
- package/dist/surface/tools/run-report.js +141 -0
- package/dist/surface/tools/session-ports.d.ts +57 -0
- package/dist/surface/tools/session-ports.js +102 -0
- package/dist/surface/tools/tool-kit.d.ts +58 -4
- package/dist/surface/tools/tool-kit.js +140 -6
- package/dist/surface/tools/tool-surface.d.ts +2 -0
- package/dist/surface/tools/tool-surface.js +45 -0
- package/dist/surface/tools/tools.js +49 -87
- package/dist/telemetry/automation-hint.d.ts +5 -0
- package/dist/telemetry/automation-hint.js +7 -0
- package/dist/telemetry/cli-telemetry.d.ts +22 -0
- package/dist/telemetry/cli-telemetry.js +80 -11
- package/dist/telemetry/daemon-telemetry.d.ts +3 -1
- package/dist/telemetry/daemon-telemetry.js +9 -2
- package/dist/telemetry/feedback-cli.d.ts +1 -1
- package/dist/telemetry/feedback-cli.js +8 -3
- package/dist/telemetry/feedback.d.ts +1 -1
- package/dist/telemetry/feedback.js +51 -4
- package/dist/telemetry/harness-run.d.ts +3 -3
- package/dist/telemetry/harness-run.js +18 -7
- package/dist/telemetry/hud-events.d.ts +1 -1
- package/dist/telemetry/hud-metrics.d.ts +6 -3
- package/dist/telemetry/hud-metrics.js +20 -8
- package/dist/telemetry/install-source.js +1 -1
- package/dist/telemetry/mcp-connection.d.ts +1 -1
- package/dist/telemetry/mcp-connection.js +21 -2
- package/dist/telemetry/onboarding-firsts.d.ts +6 -1
- package/dist/telemetry/onboarding-firsts.js +41 -1
- package/dist/telemetry/proxy-telemetry.d.ts +42 -0
- package/dist/telemetry/proxy-telemetry.js +70 -1
- package/dist/telemetry/session-metrics.d.ts +1 -3
- package/dist/telemetry/session-metrics.js +16 -12
- package/dist/telemetry/telemetry.d.ts +9 -1
- package/dist/telemetry/telemetry.js +16 -1
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +7 -1
- package/dist/wire-journal.js +12 -2
- package/docs/README.md +4 -2
- package/docs/actions.mdx +7 -6
- package/docs/adapters.md +2 -1
- package/docs/agent-cheatsheet.md +19 -5
- package/docs/architecture.md +13 -10
- package/docs/autodrive.md +6 -5
- package/docs/benchmarks.md +2 -2
- package/docs/capabilities.mdx +1 -1
- package/docs/cli/affected.mdx +1 -1
- package/docs/cli/cloud.mdx +6 -6
- package/docs/cli/doctor.mdx +3 -1
- package/docs/cli/feedback.mdx +11 -7
- package/docs/cli/gate.mdx +1 -1
- package/docs/cli/help.mdx +1 -1
- package/docs/cli/init.mdx +20 -16
- package/docs/cli/mcp.mdx +5 -2
- package/docs/cli/open.mdx +5 -2
- package/docs/cli/report.mdx +1 -1
- package/docs/cli/restart.mdx +1 -1
- package/docs/cli/rollback.mdx +4 -4
- package/docs/cli/serve.mdx +7 -5
- package/docs/cli/setup.mdx +1 -1
- package/docs/cli/status.mdx +6 -2
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/telemetry.mdx +5 -1
- package/docs/cli/try.mdx +8 -8
- package/docs/cli/update.mdx +8 -5
- package/docs/cli/verify.mdx +12 -5
- package/docs/cli/version.mdx +1 -1
- package/docs/cli.mdx +10 -6
- package/docs/debugging.md +1 -1
- package/docs/deploy-checks.md +8 -6
- package/docs/desktop.mdx +14 -18
- package/docs/enterprise.md +6 -6
- package/docs/environment.mdx +5 -3
- package/docs/faq.mdx +9 -6
- package/docs/first-drive.md +19 -9
- package/docs/flows.md +3 -4
- package/docs/for-agents.md +1 -1
- package/docs/frameworks.mdx +34 -11
- package/docs/getting-started.md +46 -29
- package/docs/http-transport.md +2 -2
- package/docs/human-control.md +8 -8
- package/docs/index.mdx +2 -2
- package/docs/install-agentic.mdx +18 -19
- package/docs/install-manual.mdx +8 -4
- package/docs/integration-patterns.md +5 -5
- package/docs/multi-agent-testing.md +7 -5
- package/docs/packages/browser.mdx +34 -2
- package/docs/packages/core.mdx +2 -1
- package/docs/packages/electron.mdx +15 -3
- package/docs/packages/eslint-plugin.mdx +1 -1
- package/docs/packages/next.mdx +17 -5
- package/docs/packages/react.mdx +8 -1
- package/docs/packages/server.mdx +3 -3
- package/docs/packages/tauri.mdx +3 -3
- package/docs/packages/vite-plugin.mdx +1 -1
- package/docs/packages.mdx +19 -6
- package/docs/platform-integration.md +12 -4
- package/docs/predicates.mdx +18 -7
- package/docs/production-mode.md +108 -0
- package/docs/prompt-capture.md +99 -0
- package/docs/quickstart.mdx +14 -12
- package/docs/recipes.mdx +9 -8
- package/docs/required-checks.md +3 -2
- package/docs/skill-file.mdx +4 -3
- package/docs/skill-setup.md +2 -2
- package/docs/skill.md +62 -70
- package/docs/state-files.md +1 -0
- package/docs/state-management.mdx +11 -9
- package/docs/system-map.md +14 -13
- package/docs/telemetry.md +32 -24
- package/docs/testing.md +9 -5
- package/docs/tools/act-and-wait.mdx +17 -13
- package/docs/tools/act-sequence.mdx +40 -66
- package/docs/tools/act.mdx +7 -5
- package/docs/tools/assert.mdx +1 -1
- package/docs/tools/look.mdx +1 -1
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/network.mdx +13 -11
- package/docs/tools/overview.mdx +3 -3
- package/docs/tools/query.mdx +3 -3
- package/docs/tools/session-and-feedback.mdx +9 -6
- package/docs/tools/sessions.mdx +7 -0
- package/docs/tools/snapshot.mdx +9 -7
- package/docs/tools/tools-and-run.mdx +11 -10
- package/docs/tools/verify.mdx +1 -1
- package/docs/troubleshooting.mdx +21 -9
- package/docs/usage.md +58 -43
- package/docs/use-cases.mdx +2 -2
- package/docs/vs-chrome-devtools-mcp.mdx +5 -5
- package/docs/vs-playwright-mcp.mdx +5 -4
- package/docs/what-is-recorded.md +12 -7
- package/docs/what-is-reticle.mdx +2 -2
- package/docs/why-reticle.mdx +1 -1
- package/package.json +9 -12
- package/dist/command/dev/stale-issue-guard.d.ts +0 -34
- package/dist/command/dev/stale-issue-guard.js +0 -69
|
@@ -19,12 +19,19 @@ import { CONTRACT_FINGERPRINT } from '@reticlehq/core';
|
|
|
19
19
|
import { CspBasis, diagnoseDesktop, diagnoseObservedWebCsp, diagnoseWebCsp, isDesktopProject, resolveWebCspFindings, webCspOptionsFor, } from '@reticlehq/init';
|
|
20
20
|
import { RETICLE_CONFIG_BASENAME, diagnosePortMismatch, readProjectFramework, readProjectId, readProjectPort, } from './ports/resolve/cli-port.js';
|
|
21
21
|
import { DoctorRow, doctorRow } from './doctor/doctor-rows.js';
|
|
22
|
+
import { ReticleDir } from '@reticlehq/core';
|
|
23
|
+
import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
|
|
24
|
+
import { BackgroundSyncState, backgroundSyncGate } from '../../memory/cloud/background-sync.js';
|
|
25
|
+
import { readCloudState } from '../../memory/cloud/sync-disk.js';
|
|
26
|
+
import { signedInTo } from './auth/cloud-session.js';
|
|
27
|
+
import { claudeCliHere, projectDirOf, promptCaptureRows } from './hook/hook-command.js';
|
|
22
28
|
import { coverageLines } from './doctor/doctor-coverage-line.js';
|
|
23
29
|
import { homedir } from 'node:os';
|
|
24
30
|
import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
|
|
25
31
|
import { describeUnsynced } from '../../memory/cloud/unsynced-roots.js';
|
|
26
32
|
import { machineUnsyncedRoots } from '../../memory/project/sync-status.js';
|
|
27
33
|
import { attachState, describeAttachState } from '../../surface/mcp/attach-memory.js';
|
|
34
|
+
import { agentLinkText } from './doctor/doctor-agent-link.js';
|
|
28
35
|
import { findOccupiedSiblings, siblingListenerNote } from './ports/sibling-ports.js';
|
|
29
36
|
import { daemonsServingProjectElsewhere, resolveDaemonForProject, splitBrainNote, wrongDaemonNote, } from '../daemon/daemon-resolve.js';
|
|
30
37
|
import { isAlive } from '../daemon/daemon.js';
|
|
@@ -37,8 +44,9 @@ import { hasConnectedDocument, observeWebDocument, } from '../../portal/session/
|
|
|
37
44
|
*/
|
|
38
45
|
/** Narrow the `/status` payload to the two fields the daemon line reads. */
|
|
39
46
|
function asIdentity(payload) {
|
|
40
|
-
if (typeof payload !== 'object' || null === payload)
|
|
47
|
+
if (typeof payload !== 'object' || null === payload) {
|
|
41
48
|
return {};
|
|
49
|
+
}
|
|
42
50
|
const record = payload;
|
|
43
51
|
const pick = (key) => {
|
|
44
52
|
const value = record[key];
|
|
@@ -93,8 +101,9 @@ export async function handleDoctor(port) {
|
|
|
93
101
|
contract: CONTRACT_FINGERPRINT,
|
|
94
102
|
});
|
|
95
103
|
line(built.text);
|
|
96
|
-
if (built.skew !== undefined)
|
|
104
|
+
if (built.skew !== undefined) {
|
|
97
105
|
line(doctorRow(DoctorRow.VERSION, `✗ ${built.skew}`));
|
|
106
|
+
}
|
|
98
107
|
// The same payload already carries whether anything has CONNECTED, and doctor was reading
|
|
99
108
|
// `version` off it and dropping the rest. Without this the command is silent on the one step the
|
|
100
109
|
// funnel stalls on: wired correctly, daemon up, and no page has ever dialled in.
|
|
@@ -122,18 +131,22 @@ export async function handleDoctor(port) {
|
|
|
122
131
|
else {
|
|
123
132
|
line(doctorRow(DoctorRow.DAEMON, `✗ not running on :${port} — your agent runs \`reticle mcp\` (or \`reticle serve\`)`));
|
|
124
133
|
}
|
|
125
|
-
if (sessions !== undefined)
|
|
134
|
+
if (sessions !== undefined) {
|
|
126
135
|
line(sessions.text);
|
|
127
|
-
|
|
136
|
+
}
|
|
137
|
+
for (const row of coverageLines(daemonStatus)) {
|
|
128
138
|
line(row);
|
|
139
|
+
}
|
|
129
140
|
// Runs nothing will send, named by folder with the one command that sends them.
|
|
130
|
-
for (const entry of await machineUnsyncedRoots(createNodeFileSystem(), homedir(), process.env))
|
|
141
|
+
for (const entry of await machineUnsyncedRoots(createNodeFileSystem(), homedir(), process.env)) {
|
|
131
142
|
line(doctorRow(DoctorRow.UNSYNCED, `✗ ${describeUnsynced(entry, process.cwd())}`));
|
|
143
|
+
}
|
|
132
144
|
line(doctorRow(DoctorRow.BRIDGE_PORT, `${port} (your app must dial THIS port, not your dev-server port)`));
|
|
133
145
|
const projectPort = readProjectPort(process.cwd());
|
|
134
146
|
const mismatch = diagnosePortMismatch(port, projectPort);
|
|
135
|
-
if (mismatch !== undefined)
|
|
147
|
+
if (mismatch !== undefined) {
|
|
136
148
|
line(doctorRow(DoctorRow.PORT_CHECK, `✗ ${mismatch}`));
|
|
149
|
+
}
|
|
137
150
|
const projectId = readProjectId(process.cwd());
|
|
138
151
|
// The hop between the agent and this daemon, stated as its own row rather than inferred from the
|
|
139
152
|
// ones above it. `sessions` says the BROWSER reached the daemon; nothing said whether the AGENT
|
|
@@ -145,26 +158,23 @@ export async function handleDoctor(port) {
|
|
|
145
158
|
// attached here" and sends the reader to re-register a server that is registered and running —
|
|
146
159
|
// the confident wrong answer for a link that is not missing but misaimed.
|
|
147
160
|
const split = splitBrainLine(port, projectId);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
// answers "did this ever work" while looking like "does this work" is the wrong
|
|
158
|
-
// shape here even though every word of it is true.
|
|
159
|
-
'✓ an MCP client attached here and called tools before (a record, not a live check)'
|
|
160
|
-
: `✗ ${attachAction}`));
|
|
161
|
+
// The record alone cannot answer whether the link works NOW (#1710): when the port is held
|
|
162
|
+
// but `/status` does not answer, the record below would still read healthy or blame the
|
|
163
|
+
// client, while the daemon row above already names the one fix for the held port. So in that
|
|
164
|
+
// state the agent link row only points back at the daemon row instead of repeating the
|
|
165
|
+
// record or adding a second command. No probe runs here: `/status` and `/mcp/sse` share one
|
|
166
|
+
// HTTP server, so silence on `/status` already answers the MCP question, and an SSE connect
|
|
167
|
+
// would flip agent presence on a daemon with no agents attached.
|
|
168
|
+
const foreign = presence === PortPresence.FOREIGN;
|
|
169
|
+
line(doctorRow(DoctorRow.AGENT_LINK, agentLinkText({ split, attachAction, foreign })));
|
|
161
170
|
// Remaining half of #261. The SDK dialling a port we are not on is invisible as a refused inbound,
|
|
162
171
|
// but a listener on a well-known Reticle port is visible. Report the observation; do not conclude
|
|
163
172
|
// it is the daemon this app wants — somebody else's daemon looks the same from here.
|
|
164
173
|
const occupiedSiblings = await findOccupiedSiblings(port, probeDaemon);
|
|
165
174
|
const siblingNote = siblingListenerNote(port, occupiedSiblings);
|
|
166
|
-
if (siblingNote !== undefined)
|
|
175
|
+
if (siblingNote !== undefined) {
|
|
167
176
|
line(doctorRow(DoctorRow.SIBLING, siblingNote));
|
|
177
|
+
}
|
|
168
178
|
// The check this checklist was missing: is the APP wired, not just the tools. Everything above can
|
|
169
179
|
// be green in a project that has never been through `init`, and that combination is precisely the
|
|
170
180
|
// one `doctor` gets run to explain.
|
|
@@ -175,6 +185,10 @@ export async function handleDoctor(port) {
|
|
|
175
185
|
// and telling somebody a file is missing while it sits in front of them is its own dead end.
|
|
176
186
|
configPresent: existsSync(join(process.cwd(), RETICLE_CONFIG_BASENAME)),
|
|
177
187
|
}));
|
|
188
|
+
// Are prompts reaching `.reticle/`, and is the work reaching the user's own workspace.
|
|
189
|
+
for (const row of await captureAndSyncLines(process.cwd(), process.env)) {
|
|
190
|
+
line(row);
|
|
191
|
+
}
|
|
178
192
|
// Where to LOOK when something is wrong. The daemon has always written a structured log here and
|
|
179
193
|
// nothing ever said so, so the first move in every investigation was reading source instead of
|
|
180
194
|
// reading the log. `RETICLE_TRACE=1` turns the same stream into a per-stage trace — see
|
|
@@ -246,6 +260,37 @@ export async function handleDoctor(port) {
|
|
|
246
260
|
line(doctorRow(DoctorRow.DESKTOP, '✓ desktop wiring looks right'));
|
|
247
261
|
}
|
|
248
262
|
const keychain = keychainNoteFor({ read: readProjectFile });
|
|
249
|
-
if (keychain !== undefined)
|
|
263
|
+
if (keychain !== undefined) {
|
|
250
264
|
line(doctorRow(DoctorRow.DESKTOP, `⚠ ${keychain}`));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Two rows: does each agent hand its prompts to Reticle, and does the daemon send this
|
|
269
|
+
* project's work in the background, and if not, why.
|
|
270
|
+
*
|
|
271
|
+
* Both answers come from the disk, the same files the hook and the daemon read, so `doctor` needs
|
|
272
|
+
* no daemon to give them. A sync the platform refused shows as the last error the cycle recorded.
|
|
273
|
+
*/
|
|
274
|
+
async function captureAndSyncLines(cwd, env) {
|
|
275
|
+
const home = homedir();
|
|
276
|
+
const projectDir = projectDirOf(cwd);
|
|
277
|
+
const lines = promptCaptureRows(projectDir, env, claudeCliHere()).map((row) => doctorRow(DoctorRow.PROMPTS, row));
|
|
278
|
+
const reticleRoot = join(projectDir, ReticleDir.ROOT);
|
|
279
|
+
const cloud = await resolveProjectCloud(createNodeFileSystem(), reticleRoot, home, env);
|
|
280
|
+
const gate = backgroundSyncGate({
|
|
281
|
+
reticleRoot,
|
|
282
|
+
cloud,
|
|
283
|
+
env,
|
|
284
|
+
signedIn: (url) => signedInTo(join(home, ReticleDir.ROOT), url),
|
|
285
|
+
});
|
|
286
|
+
const state = readCloudState(reticleRoot);
|
|
287
|
+
const on = BackgroundSyncState.ON === gate.state;
|
|
288
|
+
const last = state.lastPushAt === undefined
|
|
289
|
+
? 'no push yet'
|
|
290
|
+
: `last push ${new Date(state.lastPushAt).toISOString()}`;
|
|
291
|
+
lines.push(doctorRow(DoctorRow.SYNC, `${on ? '✓ on' : '✗ off'}: ${gate.why}; ${last}`));
|
|
292
|
+
if (state.lastError !== undefined) {
|
|
293
|
+
lines.push(doctorRow(DoctorRow.SYNC, `✗ last error: ${state.lastError}`));
|
|
294
|
+
}
|
|
295
|
+
return lines;
|
|
251
296
|
}
|
|
@@ -10,13 +10,13 @@ import { knownRegression } from './known-regression.js';
|
|
|
10
10
|
import { gateHookMessage, GATE_SKIP_ENV } from './answers/gate-hook-message.js';
|
|
11
11
|
import { readProjectId } from './ports/resolve/cli-port.js';
|
|
12
12
|
import { changedFilesSince } from '../../language/flows/change/git-changed.js';
|
|
13
|
-
import { join } from 'node:path';
|
|
13
|
+
import { isAbsolute, join, sep } from 'node:path';
|
|
14
14
|
import { ReticleDir } from '@reticlehq/core';
|
|
15
15
|
import { FlowStore } from '../../language/flows/flows.js';
|
|
16
16
|
import { RunStore } from '../../judgement/runs/artifact/run-store.js';
|
|
17
17
|
import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
|
|
18
18
|
import { affectedSavedFlows, toFlowSources, } from '../../language/flows/change/flow-sources.js';
|
|
19
|
-
import { isInteractiveSource, unflowedFiles } from '../../language/flows/change/affected.js';
|
|
19
|
+
import { isInteractiveSource, sourceMatchesChange, unflowedFiles, } from '../../language/flows/change/affected.js';
|
|
20
20
|
import { LedgerStore, regressions, staleChanged, unexecutedChanged, } from '../../features/exhaust/ledger.js';
|
|
21
21
|
import { gateDecision, passingFlowNames } from '../../language/flows/change/gate.js';
|
|
22
22
|
import { FlakeStore } from '../../language/flows/stores/flake-store.js';
|
|
@@ -68,18 +68,31 @@ export async function loadNamedFlows(fs, reticleRoot, projectId) {
|
|
|
68
68
|
*/
|
|
69
69
|
/**
|
|
70
70
|
* A changed file's text, or '' when it is gone. `git diff --name-only` answers from the repository
|
|
71
|
-
* root while the gate may run in a package below it, so leading
|
|
72
|
-
*
|
|
71
|
+
* root while the gate may run in a package below it, so a leading segment is dropped only when it is
|
|
72
|
+
* the directory the gate runs in (or a chain of them ending at `cwd`). An absolute path is read as is.
|
|
73
|
+
* Never fall through to a shorter suffix that merely happens to exist: that is another file.
|
|
73
74
|
*/
|
|
74
75
|
function atChangedPath(cwd, file, read) {
|
|
75
|
-
const
|
|
76
|
-
for (let i = 0; i < parts.length; i += 1) {
|
|
76
|
+
const attempt = (path) => {
|
|
77
77
|
try {
|
|
78
|
-
return read(
|
|
78
|
+
return read(path);
|
|
79
79
|
}
|
|
80
80
|
catch {
|
|
81
|
-
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
if (isAbsolute(file))
|
|
85
|
+
return attempt(file);
|
|
86
|
+
const parts = file.split('/');
|
|
87
|
+
const cwdParts = cwd.split(sep);
|
|
88
|
+
for (let i = 0; i < parts.length; i += 1) {
|
|
89
|
+
if (i > 0 &&
|
|
90
|
+
(i > cwdParts.length || cwdParts.slice(-i).join('/') !== parts.slice(0, i).join('/'))) {
|
|
91
|
+
continue;
|
|
82
92
|
}
|
|
93
|
+
const found = attempt(join(cwd, ...parts.slice(i)));
|
|
94
|
+
if (found !== undefined)
|
|
95
|
+
return found;
|
|
83
96
|
}
|
|
84
97
|
return undefined;
|
|
85
98
|
}
|
|
@@ -90,6 +103,30 @@ function readChangedFile(cwd, file) {
|
|
|
90
103
|
function changedFileModifiedAt(cwd, file) {
|
|
91
104
|
return atChangedPath(cwd, file, (path) => statSync(path).mtimeMs);
|
|
92
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* The flows that still count as passing for the gate.
|
|
108
|
+
*
|
|
109
|
+
* A flow's newest pass counts only if its run is later than the newest mtime of the changed files
|
|
110
|
+
* that belong to THAT flow: the changed files that match its sources (the same suffix rule as
|
|
111
|
+
* `affectedFlows`, so a repo-root path, a package-relative stamp and an absolute stamp all agree).
|
|
112
|
+
* Edits outside its sources never invalidate it. A flow with no recorded sources cannot be
|
|
113
|
+
* attributed, so every changed file counts for it. A changed file that is gone fails closed. Only
|
|
114
|
+
* `affected` flows are judged; any other flow's newest pass stands.
|
|
115
|
+
*/
|
|
116
|
+
async function currentPassing(fs, root, flows, affected, changed) {
|
|
117
|
+
const sourcesOf = new Map(toFlowSources(flows).map((f) => [f.name, f.sources ?? []]));
|
|
118
|
+
const passing = [];
|
|
119
|
+
const cwd = process.cwd();
|
|
120
|
+
for (const [name, at] of await new RunStore(fs, root).passingFlowTimes(passingFlowNames)) {
|
|
121
|
+
const sources = sourcesOf.get(name) ?? [];
|
|
122
|
+
const own = 0 === sources.length ? changed : changed.filter((f) => sourceMatchesChange(f, sources));
|
|
123
|
+
const stale = affected.includes(name) &&
|
|
124
|
+
own.some((f) => !((changedFileModifiedAt(cwd, f) ?? Infinity) < at));
|
|
125
|
+
if (!stale)
|
|
126
|
+
passing.push(name);
|
|
127
|
+
}
|
|
128
|
+
return passing;
|
|
129
|
+
}
|
|
93
130
|
export async function handleGate(files, since,
|
|
94
131
|
/** Hook mode: prose for a human, and silence when there was simply nothing to check. */
|
|
95
132
|
hook = false,
|
|
@@ -102,8 +139,7 @@ acceptCoverage = false) {
|
|
|
102
139
|
const changed = (await resolveChangedFiles(files, since, process.cwd())).files;
|
|
103
140
|
const allFlows = await loadNamedFlows(fs, reticleRoot, readProjectId(process.cwd()));
|
|
104
141
|
const affected = affectedSavedFlows(allFlows, changed).affected;
|
|
105
|
-
const
|
|
106
|
-
const passing = passingFlowNames(latest?.flows ?? []);
|
|
142
|
+
const passing = await currentPassing(fs, reticleRoot, allFlows, affected, changed);
|
|
107
143
|
const flaky = await new FlakeStore(fs, reticleRoot).flakyFlows();
|
|
108
144
|
// Anti-reward-hacking: diff each flow's CURRENT assertions against what it asserted the last
|
|
109
145
|
// time it passed. A mustHold that dropped from a real consequence to a fakeable presence check is a
|
|
@@ -133,9 +169,13 @@ acceptCoverage = false) {
|
|
|
133
169
|
.map(([name]) => name);
|
|
134
170
|
// Only against a suite that exists: a project with no flows yet is NOTHING_TO_CHECK, and
|
|
135
171
|
// demanding a flow per edited component on its first day would block every stop.
|
|
172
|
+
const flowSourcesAll = toFlowSources(allFlows);
|
|
136
173
|
const unflowed = 0 === allFlows.length
|
|
137
174
|
? []
|
|
138
|
-
: unflowedFiles(
|
|
175
|
+
: unflowedFiles(flowSourcesAll, changed, (file) => isInteractiveSource(readChangedFile(process.cwd(), file)));
|
|
176
|
+
// Flows exist but none carries a source stamp (a stack without source stamping, or flows saved before stamping was added): `unflowed`
|
|
177
|
+
// then names every changed component, which would read as "nothing drove it" when a flow did.
|
|
178
|
+
const flowsWithoutSources = allFlows.length > 0 && flowSourcesAll.every((f) => 0 === (f.sources ?? []).length);
|
|
139
179
|
// The coverage ledger, when one exists: a level that fell below its best, and changed code the
|
|
140
180
|
// browser loaded and never ran. A project that never folded coverage has an empty ledger and
|
|
141
181
|
// neither can fire.
|
|
@@ -181,6 +221,7 @@ acceptCoverage = false) {
|
|
|
181
221
|
...(result.downgraded.length > 0 ? { downgraded: result.downgraded } : {}),
|
|
182
222
|
...(result.deleted.length > 0 ? { deletedCoverage: result.deleted } : {}),
|
|
183
223
|
...(result.unflowed.length > 0 ? { unflowed: result.unflowed } : {}),
|
|
224
|
+
...(result.unflowed.length > 0 && flowsWithoutSources ? { flowsWithoutSources } : {}),
|
|
184
225
|
...(result.coverageRegressed.length > 0
|
|
185
226
|
? { coverageRegressed: result.coverageRegressed }
|
|
186
227
|
: {}),
|
|
@@ -221,6 +262,7 @@ acceptCoverage = false) {
|
|
|
221
262
|
downgraded: result.downgraded.map((d) => d.flow),
|
|
222
263
|
deleted: result.deleted,
|
|
223
264
|
unflowed: result.unflowed,
|
|
265
|
+
flowsWithoutSources,
|
|
224
266
|
coverageRegressed: result.coverageRegressed.map((r) => `${r.level} ${String(r.was)}% -> ${String(r.now)}%`),
|
|
225
267
|
unexecuted: result.unexecuted,
|
|
226
268
|
regressed: regressed?.length ?? 0,
|
|
@@ -54,6 +54,14 @@ export declare function planKill(input: {
|
|
|
54
54
|
answersStatus: boolean;
|
|
55
55
|
force: boolean;
|
|
56
56
|
}): KillPlan;
|
|
57
|
+
/**
|
|
58
|
+
* Ask the daemon on `port` to run its own shutdown path. True when it accepted.
|
|
59
|
+
*
|
|
60
|
+
* Asked before any signal, on every OS. On Windows a signal ends the process at once, so the daemon
|
|
61
|
+
* did not close its browser or send its stop event. False for an older daemon without the route, a
|
|
62
|
+
* wrong token, or no answer: the caller then sends the signal as before.
|
|
63
|
+
*/
|
|
64
|
+
export declare function requestShutdown(port: number, token?: string | undefined): Promise<boolean>;
|
|
57
65
|
/** `reticle kill` — free the port. Resolves to whether the port is now free. */
|
|
58
66
|
export declare function runKill(port: number, force: boolean): Promise<boolean>;
|
|
59
67
|
export {};
|
|
@@ -23,6 +23,9 @@ import { probeDaemon } from '../../surface/mcp/mcp-proxy.js';
|
|
|
23
23
|
import { log } from '../../log.js';
|
|
24
24
|
import { fetchStatus } from '../daemon/binding/daemon-status-probe.js';
|
|
25
25
|
import { captureLookup, findPortHolder } from './ports/port-holder.js';
|
|
26
|
+
import * as http from 'node:http';
|
|
27
|
+
import { LOOPBACK_HOST, SHUTDOWN_PATH } from '@reticlehq/core';
|
|
28
|
+
import { storedPairingToken } from '../../portal/bridge/pairing-token.js';
|
|
26
29
|
/** What the plan says to do with the port. */
|
|
27
30
|
export const KillAction = {
|
|
28
31
|
NOTHING: 'nothing',
|
|
@@ -74,14 +77,48 @@ const GRACEFUL_KILL_MS = 5_000;
|
|
|
74
77
|
/** How long after SIGKILL before we accept the process is not ours to kill and say so. */
|
|
75
78
|
const FORCED_KILL_MS = 2_000;
|
|
76
79
|
const KILL_POLL_MS = 100;
|
|
80
|
+
/** A loopback call: a daemon that does not answer in this time gets the signal instead. */
|
|
81
|
+
const SHUTDOWN_REQUEST_TIMEOUT_MS = 1_000;
|
|
82
|
+
/**
|
|
83
|
+
* Ask the daemon on `port` to run its own shutdown path. True when it accepted.
|
|
84
|
+
*
|
|
85
|
+
* Asked before any signal, on every OS. On Windows a signal ends the process at once, so the daemon
|
|
86
|
+
* did not close its browser or send its stop event. False for an older daemon without the route, a
|
|
87
|
+
* wrong token, or no answer: the caller then sends the signal as before.
|
|
88
|
+
*/
|
|
89
|
+
export function requestShutdown(port, token = storedPairingToken()) {
|
|
90
|
+
if (token === undefined) {
|
|
91
|
+
return Promise.resolve(false);
|
|
92
|
+
}
|
|
93
|
+
return new Promise((resolve) => {
|
|
94
|
+
const req = http.request({
|
|
95
|
+
host: LOOPBACK_HOST,
|
|
96
|
+
port,
|
|
97
|
+
path: SHUTDOWN_PATH,
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: { authorization: `Bearer ${token}` },
|
|
100
|
+
timeout: SHUTDOWN_REQUEST_TIMEOUT_MS,
|
|
101
|
+
}, (res) => {
|
|
102
|
+
res.resume();
|
|
103
|
+
resolve(202 === res.statusCode);
|
|
104
|
+
});
|
|
105
|
+
req.on('error', () => resolve(false));
|
|
106
|
+
req.on('timeout', () => {
|
|
107
|
+
req.destroy();
|
|
108
|
+
resolve(false);
|
|
109
|
+
});
|
|
110
|
+
req.end();
|
|
111
|
+
});
|
|
112
|
+
}
|
|
77
113
|
/**
|
|
78
114
|
* Signal ONE pid and wait for it to go: SIGTERM, then SIGKILL, then give up and say it survived.
|
|
115
|
+
* `asked`: the daemon already accepted a shutdown request, so the SIGTERM is not sent.
|
|
79
116
|
*
|
|
80
117
|
* The escalation is the reason this exists rather than a bare SIGTERM — there is a field report of a
|
|
81
118
|
* daemon that ignored SIGTERM until a human ran `kill -9` by hand, which is the moment the `lsof -ti`
|
|
82
119
|
* pipeline gets typed and the agent's proxy dies with the daemon.
|
|
83
120
|
*/
|
|
84
|
-
async function terminate(pid) {
|
|
121
|
+
async function terminate(pid, asked = false) {
|
|
85
122
|
const signal = (name) => {
|
|
86
123
|
try {
|
|
87
124
|
process.kill(pid, name);
|
|
@@ -90,7 +127,9 @@ async function terminate(pid) {
|
|
|
90
127
|
// Gone between the liveness check and here. The next poll reports it as gone.
|
|
91
128
|
}
|
|
92
129
|
};
|
|
93
|
-
|
|
130
|
+
if (!asked) {
|
|
131
|
+
signal('SIGTERM');
|
|
132
|
+
}
|
|
94
133
|
const started = Date.now();
|
|
95
134
|
let escalated = false;
|
|
96
135
|
for (;;) {
|
|
@@ -143,7 +182,8 @@ export async function runKill(port, force) {
|
|
|
143
182
|
log('reticle_kill_nothing_to_do', { port, presence });
|
|
144
183
|
return true;
|
|
145
184
|
}
|
|
146
|
-
const
|
|
185
|
+
const asked = PortPresence.DAEMON === presence && (await requestShutdown(port));
|
|
186
|
+
const { gone, escalated } = await terminate(pid, asked);
|
|
147
187
|
if (gone)
|
|
148
188
|
removePid(port);
|
|
149
189
|
log(gone ? 'reticle_killed' : 'reticle_kill_survived', {
|
|
@@ -11,6 +11,8 @@ export declare const BUG_FLAG = "--bug";
|
|
|
11
11
|
*/
|
|
12
12
|
export declare const KIND_FLAG = "--kind";
|
|
13
13
|
export declare const AGENT_FLAG = "--agent";
|
|
14
|
+
/** `--contact <email>`: a reply address, sent only when the person gives it. */
|
|
15
|
+
export declare const CONTACT_FLAG = "--contact";
|
|
14
16
|
/** Accepted `--kind` values, from core's enum — never a second hand-written list to drift from it. */
|
|
15
17
|
export declare const FEEDBACK_KINDS: readonly string[];
|
|
16
18
|
/** What `parseFeedbackArgs` yields: the parsed command, or a usage error to print. */
|
|
@@ -23,6 +25,8 @@ export type ParsedFeedback = {
|
|
|
23
25
|
bug: boolean;
|
|
24
26
|
/** `--agent`: file as the agent, so agent reports never dilute the human rating signal. */
|
|
25
27
|
agent: boolean;
|
|
28
|
+
/** `--contact`: a reply address the person gave. */
|
|
29
|
+
contact?: string;
|
|
26
30
|
} | {
|
|
27
31
|
kind: 'error';
|
|
28
32
|
message: string;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* is the one command whose arguments are free text, so it is the only place in the grammar where
|
|
6
6
|
* "everything that is not a flag" is a rule with edge cases rather than a one-liner.
|
|
7
7
|
*/
|
|
8
|
-
import { FeedbackKind } from '@reticlehq/core/telemetry';
|
|
8
|
+
import { FEEDBACK_CONTACT_MAX, FeedbackKind, isFeedbackContact } from '@reticlehq/core/telemetry';
|
|
9
9
|
/** `reticle feedback --rating 4 "the words"` — the human half of the channel. */
|
|
10
10
|
export const RATING_FLAG = '--rating';
|
|
11
11
|
export const BUG_FLAG = '--bug';
|
|
@@ -19,6 +19,8 @@ export const BUG_FLAG = '--bug';
|
|
|
19
19
|
*/
|
|
20
20
|
export const KIND_FLAG = '--kind';
|
|
21
21
|
export const AGENT_FLAG = '--agent';
|
|
22
|
+
/** `--contact <email>`: a reply address, sent only when the person gives it. */
|
|
23
|
+
export const CONTACT_FLAG = '--contact';
|
|
22
24
|
/** Accepted `--kind` values, from core's enum — never a second hand-written list to drift from it. */
|
|
23
25
|
export const FEEDBACK_KINDS = Object.values(FeedbackKind);
|
|
24
26
|
/** Parse everything after `reticle feedback`. */
|
|
@@ -33,6 +35,14 @@ export function parseFeedbackArgs(rest) {
|
|
|
33
35
|
if (feedbackKind !== undefined && !FEEDBACK_KINDS.includes(feedbackKind)) {
|
|
34
36
|
return { kind: 'error', message: `${KIND_FLAG} takes one of: ${FEEDBACK_KINDS.join(', ')}` };
|
|
35
37
|
}
|
|
38
|
+
const contactAt = rest.indexOf(CONTACT_FLAG);
|
|
39
|
+
const contact = -1 === contactAt ? undefined : (rest[contactAt + 1] ?? '');
|
|
40
|
+
if (contact !== undefined && !isFeedbackContact(contact)) {
|
|
41
|
+
return {
|
|
42
|
+
kind: 'error',
|
|
43
|
+
message: `${CONTACT_FLAG} takes one email address of at most ${String(FEEDBACK_CONTACT_MAX)} characters, such as you@example.com`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
36
46
|
// Everything that is not a flag or a flag's VALUE is the message. Quoting is the user's job for
|
|
37
47
|
// shell reasons, but joining the remainder means an unquoted sentence still works. Both value
|
|
38
48
|
// positions have to be consumed: without that, `--kind bug "..."` filed a report whose text began
|
|
@@ -40,6 +50,7 @@ export function parseFeedbackArgs(rest) {
|
|
|
40
50
|
const consumed = new Set([
|
|
41
51
|
...(-1 === ratingAt ? [] : [ratingAt, ratingAt + 1]),
|
|
42
52
|
...(-1 === kindAt ? [] : [kindAt, kindAt + 1]),
|
|
53
|
+
...(-1 === contactAt ? [] : [contactAt, contactAt + 1]),
|
|
43
54
|
]);
|
|
44
55
|
const text = rest
|
|
45
56
|
.filter((arg, i) => !consumed.has(i) && !arg.startsWith('--'))
|
|
@@ -52,5 +63,6 @@ export function parseFeedbackArgs(rest) {
|
|
|
52
63
|
...(feedbackKind !== undefined ? { feedbackKind } : {}),
|
|
53
64
|
bug: rest.includes(BUG_FLAG),
|
|
54
65
|
agent: rest.includes(AGENT_FLAG),
|
|
66
|
+
...(contact !== undefined ? { contact } : {}),
|
|
55
67
|
};
|
|
56
68
|
}
|
|
@@ -46,8 +46,7 @@ export declare const CLOUD_COMMANDS: readonly string[];
|
|
|
46
46
|
export declare const RENAMED_COMMANDS: ReadonlyMap<string, string>;
|
|
47
47
|
/**
|
|
48
48
|
* The command an old name now goes by, when the note saying so should print; otherwise undefined.
|
|
49
|
-
* Not for a request for help (that answer names the new command itself)
|
|
50
|
-
* `login --email`, which `connect --help` documents as the sign-in for CI and agents.
|
|
49
|
+
* Not for a request for help (that answer names the new command itself).
|
|
51
50
|
*/
|
|
52
51
|
export declare function renamedCommandFor(argv: readonly string[]): string | undefined;
|
|
53
52
|
/**
|
|
@@ -82,19 +82,14 @@ export const RENAMED_COMMANDS = new Map([
|
|
|
82
82
|
['memory', 'runs memory'],
|
|
83
83
|
]);
|
|
84
84
|
const HELP_FLAGS = new Set(['--help', '-h']);
|
|
85
|
-
/** `login --email` is the documented sign-in without a browser, so it is not a renamed `connect`. */
|
|
86
|
-
const BROWSERLESS_LOGIN = { command: 'login', flag: '--email' };
|
|
87
85
|
/**
|
|
88
86
|
* The command an old name now goes by, when the note saying so should print; otherwise undefined.
|
|
89
|
-
* Not for a request for help (that answer names the new command itself)
|
|
90
|
-
* `login --email`, which `connect --help` documents as the sign-in for CI and agents.
|
|
87
|
+
* Not for a request for help (that answer names the new command itself).
|
|
91
88
|
*/
|
|
92
89
|
export function renamedCommandFor(argv) {
|
|
93
90
|
const name = argv[0];
|
|
94
91
|
if (name === undefined || argv.some((arg) => HELP_FLAGS.has(arg)))
|
|
95
92
|
return undefined;
|
|
96
|
-
if (BROWSERLESS_LOGIN.command === name && argv.includes(BROWSERLESS_LOGIN.flag))
|
|
97
|
-
return undefined;
|
|
98
93
|
return RENAMED_COMMANDS.get(name);
|
|
99
94
|
}
|
|
100
95
|
/**
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Force a hidden browser. The default is now HEADED: a run nobody can see is a run nobody trusts,
|
|
3
|
+
* and every "did it actually do anything?" question cost a round-trip. CI passes this (or just sets
|
|
4
|
+
* CI, which flips the default) because there is no display there to be headed on.
|
|
5
|
+
*/
|
|
6
|
+
export declare const HEADLESS_FLAG = "--headless";
|
|
7
|
+
export declare const DRIVE_FLAG = "--drive";
|
|
8
|
+
export declare const HTTP_FLAG = "--http";
|
|
9
|
+
export declare const HTTP_PORT_FLAG = "--http-port";
|
|
10
|
+
export declare const HTTP_TOKEN_FLAG = "--http-token";
|
|
11
|
+
type ServeFlags = {
|
|
12
|
+
kind: 'ok';
|
|
13
|
+
port: number;
|
|
14
|
+
driveUrl?: string;
|
|
15
|
+
headless: boolean;
|
|
16
|
+
http: boolean;
|
|
17
|
+
httpPort?: number;
|
|
18
|
+
httpToken?: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'error';
|
|
21
|
+
message: string;
|
|
22
|
+
};
|
|
23
|
+
export declare function parseServeFlags(args: string[], defaultPort: number, defaultHeadless: boolean): ServeFlags;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The serve / mcp / `_daemon` flag grammar, including the verify HTTP endpoint.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `cli-parse.ts` when that file crossed the line cap. These three commands share one
|
|
5
|
+
* flag set: the bridge port, a drive URL, headless, and the verify endpoint `--http` starts.
|
|
6
|
+
*/
|
|
7
|
+
import { HEADED_FLAG, PORT_FLAG, missingValue, notANumber, unknownArgument, } from './cli-parse-grammar.js';
|
|
8
|
+
/**
|
|
9
|
+
* Force a hidden browser. The default is now HEADED: a run nobody can see is a run nobody trusts,
|
|
10
|
+
* and every "did it actually do anything?" question cost a round-trip. CI passes this (or just sets
|
|
11
|
+
* CI, which flips the default) because there is no display there to be headed on.
|
|
12
|
+
*/
|
|
13
|
+
export const HEADLESS_FLAG = '--headless';
|
|
14
|
+
export const DRIVE_FLAG = '--drive';
|
|
15
|
+
export const HTTP_FLAG = '--http';
|
|
16
|
+
export const HTTP_PORT_FLAG = '--http-port';
|
|
17
|
+
export const HTTP_TOKEN_FLAG = '--http-token';
|
|
18
|
+
const requiresHttp = (flag) => ({
|
|
19
|
+
kind: 'error',
|
|
20
|
+
message: `${flag} requires ${HTTP_FLAG} — it configures the verify endpoint ${HTTP_FLAG} starts`,
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* The verify endpoint cannot use the bridge port.
|
|
24
|
+
*
|
|
25
|
+
* `reticle serve --http --http-port 4400` reached `listen` and died with a raw
|
|
26
|
+
* `EADDRINUSE 127.0.0.1:4400`. That number is this daemon's bridge port, and MCP is already
|
|
27
|
+
* served there. Name both ports and stop before anything listens (#1786).
|
|
28
|
+
*/
|
|
29
|
+
const httpPortIsBridge = (httpPort, bridgePort) => ({
|
|
30
|
+
kind: 'error',
|
|
31
|
+
message: `${HTTP_PORT_FLAG} ${String(httpPort)} is the bridge port ${String(bridgePort)}. ` +
|
|
32
|
+
'Pick another port. MCP is already served on the bridge port.',
|
|
33
|
+
});
|
|
34
|
+
export function parseServeFlags(args, defaultPort, defaultHeadless) {
|
|
35
|
+
let port = defaultPort;
|
|
36
|
+
let driveUrl;
|
|
37
|
+
let headless = defaultHeadless;
|
|
38
|
+
let http = false;
|
|
39
|
+
let httpPort;
|
|
40
|
+
let httpToken;
|
|
41
|
+
let i = 0;
|
|
42
|
+
while (i < args.length) {
|
|
43
|
+
const arg = args[i];
|
|
44
|
+
// `i < args.length` already guarantees this, but the index signature does not say so and the
|
|
45
|
+
// unknown-argument error needs a real string to name.
|
|
46
|
+
if (arg === undefined) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
if (arg === PORT_FLAG) {
|
|
50
|
+
i++;
|
|
51
|
+
const n = args[i];
|
|
52
|
+
if (n === undefined) {
|
|
53
|
+
return missingValue(PORT_FLAG);
|
|
54
|
+
}
|
|
55
|
+
const parsed = parseInt(n, 10);
|
|
56
|
+
if (isNaN(parsed)) {
|
|
57
|
+
return notANumber(PORT_FLAG, n);
|
|
58
|
+
}
|
|
59
|
+
port = parsed;
|
|
60
|
+
}
|
|
61
|
+
else if (arg === DRIVE_FLAG) {
|
|
62
|
+
i++;
|
|
63
|
+
driveUrl = args[i];
|
|
64
|
+
if (driveUrl === undefined) {
|
|
65
|
+
return missingValue(DRIVE_FLAG);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (arg === HEADED_FLAG) {
|
|
69
|
+
headless = false;
|
|
70
|
+
}
|
|
71
|
+
else if (arg === HEADLESS_FLAG) {
|
|
72
|
+
headless = true;
|
|
73
|
+
}
|
|
74
|
+
else if (arg === HTTP_FLAG) {
|
|
75
|
+
http = true;
|
|
76
|
+
}
|
|
77
|
+
else if (arg === HTTP_PORT_FLAG) {
|
|
78
|
+
i++;
|
|
79
|
+
const n = args[i];
|
|
80
|
+
if (n === undefined) {
|
|
81
|
+
return missingValue(HTTP_PORT_FLAG);
|
|
82
|
+
}
|
|
83
|
+
const parsed = parseInt(n, 10);
|
|
84
|
+
if (isNaN(parsed)) {
|
|
85
|
+
return notANumber(HTTP_PORT_FLAG, n);
|
|
86
|
+
}
|
|
87
|
+
httpPort = parsed;
|
|
88
|
+
}
|
|
89
|
+
else if (arg === HTTP_TOKEN_FLAG) {
|
|
90
|
+
i++;
|
|
91
|
+
httpToken = args[i];
|
|
92
|
+
if (httpToken === undefined) {
|
|
93
|
+
return missingValue(HTTP_TOKEN_FLAG);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
return unknownArgument(arg);
|
|
98
|
+
}
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
// Without `--http` these flags configure an endpoint nothing starts, and they were accepted and
|
|
102
|
+
// silently ignored — worse than being rejected, because the whole reason to pass them is to be
|
|
103
|
+
// honoured (#687).
|
|
104
|
+
if (!http && httpPort !== undefined) {
|
|
105
|
+
return requiresHttp(HTTP_PORT_FLAG);
|
|
106
|
+
}
|
|
107
|
+
if (!http && httpToken !== undefined) {
|
|
108
|
+
return requiresHttp(HTTP_TOKEN_FLAG);
|
|
109
|
+
}
|
|
110
|
+
// `port` is the bridge port this command will bind. The caller passes the resolved default
|
|
111
|
+
// (RETICLE_PORT, the project port, this project's daemon, or 4400). `--port` replaces it.
|
|
112
|
+
if (httpPort !== undefined && httpPort === port) {
|
|
113
|
+
return httpPortIsBridge(httpPort, port);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
kind: 'ok',
|
|
117
|
+
port,
|
|
118
|
+
headless,
|
|
119
|
+
http,
|
|
120
|
+
...(driveUrl !== undefined ? { driveUrl } : {}),
|
|
121
|
+
...(httpPort !== undefined ? { httpPort } : {}),
|
|
122
|
+
...(httpToken !== undefined ? { httpToken } : {}),
|
|
123
|
+
};
|
|
124
|
+
}
|