@reticlehq/server 3.6.0 → 3.7.0
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 +122 -123
- package/dist/command/cli/adhoc-suite.d.ts +14 -0
- package/dist/command/cli/adhoc-suite.js +42 -7
- package/dist/command/cli/adhoc-verdict.d.ts +18 -2
- package/dist/command/cli/adhoc-verdict.js +70 -6
- package/dist/command/cli/answers/gate-exit.d.ts +23 -0
- package/dist/command/cli/answers/gate-exit.js +45 -0
- package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
- package/dist/command/cli/answers/gate-hook-message.js +3 -1
- package/dist/command/cli/auth/device-flow.d.ts +13 -2
- package/dist/command/cli/auth/device-flow.js +17 -0
- package/dist/command/cli/cli-doctor.js +14 -0
- package/dist/command/cli/cli-flow-commands.d.ts +0 -11
- package/dist/command/cli/cli-flow-commands.js +28 -105
- package/dist/command/cli/cli-kill.js +3 -2
- package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
- package/dist/command/cli/cli-parse-grammar.js +75 -0
- package/dist/command/cli/cli-parse-verify.d.ts +2 -0
- package/dist/command/cli/cli-parse-verify.js +18 -0
- package/dist/command/cli/cli-parse.d.ts +19 -28
- package/dist/command/cli/cli-parse.js +82 -182
- package/dist/command/cli/cli-update-commands.d.ts +1 -1
- package/dist/command/cli/cli-update-commands.js +61 -9
- package/dist/command/cli/cli-usage.d.ts +33 -0
- package/dist/command/cli/cli-usage.js +287 -0
- package/dist/command/cli/cli-verify.d.ts +34 -4
- package/dist/command/cli/cli-verify.js +81 -12
- package/dist/command/cli/cloud-cli.d.ts +13 -0
- package/dist/command/cli/cloud-cli.js +145 -333
- package/dist/command/cli/cloud-kit.d.ts +12 -0
- package/dist/command/cli/cloud-kit.js +41 -2
- package/dist/command/cli/cloud-link.d.ts +57 -0
- package/dist/command/cli/cloud-link.js +308 -0
- package/dist/command/cli/cloud-login.d.ts +15 -1
- package/dist/command/cli/cloud-login.js +67 -13
- package/dist/command/cli/context-command.d.ts +1 -0
- package/dist/command/cli/context-command.js +33 -0
- package/dist/command/cli/daemon-start-options.d.ts +3 -0
- package/dist/command/cli/daemon-start-options.js +24 -3
- package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
- package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
- package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
- package/dist/command/cli/doctor/doctor-project-line.js +5 -4
- package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
- package/dist/command/cli/doctor/doctor-rows.js +6 -0
- package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
- package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
- package/dist/command/cli/known-regression.d.ts +13 -0
- package/dist/command/cli/known-regression.js +34 -0
- package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
- package/dist/command/cli/launch/sdk-version-match.js +25 -0
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +11 -2
- package/dist/command/cli/mcp-command.d.ts +6 -0
- package/dist/command/cli/mcp-command.js +13 -5
- package/dist/command/cli/ports/port-holder.js +1 -1
- package/dist/command/cli/project-name.d.ts +29 -1
- package/dist/command/cli/project-name.js +107 -2
- package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
- package/dist/command/cli/setup-mcp-cli.js +29 -8
- package/dist/command/cli/status/status-lines.d.ts +1 -0
- package/dist/command/cli/status/status-lines.js +47 -2
- package/dist/command/cli/status/workspace-links.d.ts +10 -0
- package/dist/command/cli/status/workspace-links.js +29 -0
- package/dist/command/cli/try-command.d.ts +96 -0
- package/dist/command/cli/try-command.js +362 -0
- package/dist/command/cli/tutorial.d.ts +0 -100
- package/dist/command/cli/tutorial.js +0 -178
- package/dist/command/cli/verify-results.d.ts +19 -0
- package/dist/command/cli/verify-results.js +29 -0
- package/dist/command/cli-onboarding.d.ts +0 -11
- package/dist/command/cli-onboarding.js +0 -15
- package/dist/command/cli.d.ts +14 -0
- package/dist/command/cli.js +103 -83
- package/dist/command/daemon/daemon-resilience.js +4 -4
- package/dist/command/daemon/daemon-resolve.d.ts +9 -1
- package/dist/command/daemon/daemon-resolve.js +49 -10
- package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
- package/dist/command/setup/bringup/bridge-port.js +13 -3
- package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
- package/dist/command/setup/bringup/ensure-daemon.js +9 -2
- package/dist/command/setup/init/agent-restart.d.ts +23 -0
- package/dist/command/setup/init/agent-restart.js +28 -0
- package/dist/command/setup/init/init-port.d.ts +10 -1
- package/dist/command/setup/init/init-port.js +22 -2
- package/dist/command/setup/init/init-runtime.d.ts +12 -2
- package/dist/command/setup/init/init-runtime.js +96 -37
- package/dist/command/setup/node-effects.d.ts +2 -0
- package/dist/command/setup/node-effects.js +36 -8
- package/dist/command/setup/probe/existing-app.d.ts +12 -0
- package/dist/command/setup/probe/existing-app.js +14 -0
- package/dist/command/setup/remaining-steps.js +1 -1
- package/dist/command/setup/run-setup.d.ts +29 -9
- package/dist/command/setup/run-setup.js +34 -28
- package/dist/command/setup/setup-command.d.ts +23 -0
- package/dist/command/setup/setup-command.js +57 -4
- package/dist/command/setup/setup-mcp.js +25 -2
- package/dist/command/setup/tauri-signing.d.ts +19 -0
- package/dist/command/setup/tauri-signing.js +79 -0
- package/dist/command/setup/terminal/listeners.d.ts +10 -1
- package/dist/command/setup/terminal/listeners.js +37 -6
- package/dist/command/update/update-nudge.d.ts +9 -0
- package/dist/command/update/update-nudge.js +1 -1
- package/dist/command/update/updater.js +11 -15
- package/dist/command/version/version-nudge.js +3 -0
- package/dist/command/version/version-skew.d.ts +20 -1
- package/dist/command/version/version-skew.js +38 -2
- package/dist/features/crawl/crawl.js +14 -1
- package/dist/features/exhaust/ledger.d.ts +14 -14
- package/dist/features/harness/drive-report.d.ts +39 -5
- package/dist/features/harness/drive-report.js +271 -54
- package/dist/features/harness/drive-runs.d.ts +120 -0
- package/dist/features/harness/drive-runs.js +289 -0
- package/dist/features/harness/drivers.d.ts +1 -1
- package/dist/features/harness/drivers.js +1 -1
- package/dist/features/harness/explore/console-pages.d.ts +15 -0
- package/dist/features/harness/explore/console-pages.js +146 -0
- package/dist/features/harness/explore/disparity.d.ts +19 -0
- package/dist/features/harness/explore/disparity.js +71 -0
- package/dist/features/harness/explore/fake-app.d.ts +16 -0
- package/dist/features/harness/explore/fake-app.js +49 -0
- package/dist/features/harness/explore/goal-search.d.ts +26 -0
- package/dist/features/harness/explore/goal-search.js +144 -0
- package/dist/features/harness/explore/page-tree.d.ts +49 -0
- package/dist/features/harness/explore/page-tree.js +148 -0
- package/dist/features/harness/explore/site-map.d.ts +34 -0
- package/dist/features/harness/explore/site-map.js +150 -0
- package/dist/features/harness/goals.d.ts +68 -7
- package/dist/features/harness/goals.js +289 -36
- package/dist/features/harness/harness.d.ts +30 -1
- package/dist/features/harness/harness.js +141 -7
- package/dist/features/harness/platform/local-apps.d.ts +36 -3
- package/dist/features/harness/platform/local-apps.js +81 -5
- package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
- package/dist/features/harness/platform/persona-credentials.js +69 -0
- package/dist/features/harness/platform/platform-drives.d.ts +61 -0
- package/dist/features/harness/platform/platform-drives.js +114 -0
- package/dist/features/harness/platform/refusal.d.ts +52 -0
- package/dist/features/harness/platform/refusal.js +71 -0
- package/dist/features/harness/platform/remote-drive.d.ts +8 -2
- package/dist/features/harness/platform/remote-drive.js +22 -9
- package/dist/features/harness/platform/script.d.ts +57 -11
- package/dist/features/harness/platform/script.js +144 -12
- package/dist/features/harness/platform/server-driver.d.ts +17 -4
- package/dist/features/harness/platform/server-driver.js +29 -26
- package/dist/features/harness/platform-config.d.ts +38 -5
- package/dist/features/harness/platform-config.js +93 -8
- package/dist/features/harness/route-guess.d.ts +13 -0
- package/dist/features/harness/route-guess.js +49 -0
- package/dist/features/harness/script/script-run.d.ts +30 -1
- package/dist/features/harness/script/script-run.js +355 -48
- package/dist/features/license/license.d.ts +2 -2
- package/dist/features/visual/step-shots.d.ts +31 -0
- package/dist/features/visual/step-shots.js +231 -0
- package/dist/features/visual/visual-tools.js +22 -14
- package/dist/hooks/client-directory.d.ts +18 -0
- package/dist/hooks/client-directory.js +57 -0
- package/dist/hooks/coding-agents.d.ts +34 -0
- package/dist/hooks/coding-agents.js +117 -0
- package/dist/hooks/driven-by.d.ts +21 -2
- package/dist/hooks/driven-by.js +42 -2
- package/dist/hooks/hook-bus.d.ts +4 -0
- package/dist/hooks/hook-bus.js +18 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +26 -183
- package/dist/judgement/capsule/capsule-store.d.ts +2 -2
- package/dist/judgement/capsule/causal-summary.d.ts +15 -1
- package/dist/judgement/capsule/causal-summary.js +33 -0
- package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
- package/dist/judgement/runs/artifact/build-verification-run.js +20 -4
- package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
- package/dist/judgement/runs/artifact/gap-summary.js +12 -3
- package/dist/judgement/runs/artifact/replay-mapping.js +25 -9
- package/dist/judgement/runs/artifact/run-store.d.ts +13 -1
- package/dist/judgement/runs/artifact/run-store.js +175 -8
- package/dist/judgement/runs/context-tools.js +59 -1
- package/dist/judgement/runs/default-run-id.d.ts +3 -0
- package/dist/judgement/runs/default-run-id.js +16 -0
- package/dist/judgement/runs/drive-run.d.ts +53 -5
- package/dist/judgement/runs/drive-run.js +234 -20
- package/dist/judgement/runs/resume.d.ts +44 -0
- package/dist/judgement/runs/resume.js +137 -0
- package/dist/judgement/runs/reticle-runner.js +5 -2
- package/dist/judgement/runs/runner-port.d.ts +5 -1
- package/dist/judgement/runs/runner-port.js +8 -2
- package/dist/judgement/runs/verification-sync.d.ts +2 -0
- package/dist/judgement/runs/verification-sync.js +36 -15
- package/dist/language/flows/decision.js +2 -1
- package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
- package/dist/language/flows/fields/flow-secret-field.js +25 -2
- package/dist/language/flows/flow-anchor.d.ts +7 -2
- package/dist/language/flows/flow-anchor.js +10 -3
- package/dist/language/flows/flow-intent.d.ts +1 -0
- package/dist/language/flows/flow-journey.d.ts +6 -0
- package/dist/language/flows/flow-journey.js +20 -0
- package/dist/language/flows/flow-learning.d.ts +4 -0
- package/dist/language/flows/flow-learning.js +37 -3
- package/dist/language/flows/flow-replay-run.js +16 -18
- package/dist/language/flows/flow-replay-types.d.ts +1 -1
- package/dist/language/flows/flow-replay.d.ts +18 -1
- package/dist/language/flows/flow-replay.js +22 -7
- package/dist/language/flows/flow-result.d.ts +22 -1
- package/dist/language/flows/flow-result.js +47 -2
- package/dist/language/flows/flow-step-runners.d.ts +2 -0
- package/dist/language/flows/flow-step-runners.js +12 -6
- package/dist/language/flows/flow-store-for-session.js +5 -1
- package/dist/language/flows/flow-tools.d.ts +10 -0
- package/dist/language/flows/flow-tools.js +61 -62
- package/dist/language/flows/flows.d.ts +16 -1
- package/dist/language/flows/flows.js +69 -10
- package/dist/language/flows/narrow-write.d.ts +7 -0
- package/dist/language/flows/narrow-write.js +36 -1
- package/dist/language/flows/recording/recording-backtrack.js +14 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +29 -1
- package/dist/language/flows/recording/tape/recordings.js +60 -10
- package/dist/language/flows/replay.js +29 -6
- package/dist/language/flows/single-replay.d.ts +7 -0
- package/dist/language/flows/single-replay.js +26 -0
- package/dist/language/flows/verify-change-tools.d.ts +1 -0
- package/dist/language/flows/verify-change-tools.js +200 -193
- package/dist/memory/cloud/cloud-config.d.ts +10 -1
- package/dist/memory/cloud/cloud-config.js +19 -5
- package/dist/memory/cloud/cloud-sync.js +3 -3
- package/dist/memory/cloud/harness-config.d.ts +49 -0
- package/dist/memory/cloud/harness-config.js +16 -20
- package/dist/memory/cloud/memory-scope.d.ts +17 -0
- package/dist/memory/cloud/memory-scope.js +22 -0
- package/dist/memory/cloud/sync-cycle.d.ts +32 -4
- package/dist/memory/cloud/sync-cycle.js +113 -12
- package/dist/memory/cloud/sync-daemon.d.ts +11 -0
- package/dist/memory/cloud/sync-daemon.js +114 -4
- package/dist/memory/cloud/sync-disk.js +26 -2
- package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
- package/dist/memory/cloud/sync-screenshots.js +105 -0
- package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
- package/dist/memory/cloud/unsynced-roots.js +166 -0
- package/dist/memory/impact/account-watch.d.ts +16 -1
- package/dist/memory/impact/account-watch.js +26 -1
- package/dist/memory/impact/impact-store.d.ts +1 -4
- package/dist/memory/impact/impact-store.js +32 -42
- package/dist/memory/intent/inline-intent.d.ts +1 -0
- package/dist/memory/intent/intent-shard-store.js +16 -4
- package/dist/memory/intent/intent-shard.d.ts +12 -0
- package/dist/memory/intent/intent-store.d.ts +1 -0
- package/dist/memory/intent/intent-tools.js +42 -2
- package/dist/memory/intent/open-intents.d.ts +6 -0
- package/dist/memory/intent/open-intents.js +10 -1
- package/dist/memory/intent/settled-words.d.ts +24 -0
- package/dist/memory/intent/settled-words.js +130 -0
- package/dist/memory/journal/drive-flow.d.ts +16 -0
- package/dist/memory/journal/drive-flow.js +34 -2
- package/dist/memory/journal/drive-run-flush.d.ts +2 -0
- package/dist/memory/journal/drive-run-flush.js +20 -5
- package/dist/memory/journal/journal-recorder.js +46 -3
- package/dist/memory/journal/on-disk/retention.d.ts +5 -0
- package/dist/memory/journal/on-disk/retention.js +27 -2
- package/dist/memory/journal/on-disk/workspace-tiers.js +2 -0
- package/dist/memory/journal/session-end.d.ts +15 -1
- package/dist/memory/journal/session-end.js +38 -7
- package/dist/memory/project/artifact-root-resolver.js +33 -5
- package/dist/memory/project/artifact-root.d.ts +4 -3
- package/dist/memory/project/artifact-root.js +2 -2
- package/dist/memory/project/dir/reticle-dir.d.ts +14 -0
- package/dist/memory/project/dir/reticle-dir.js +23 -2
- package/dist/memory/project/link-directory.d.ts +15 -0
- package/dist/memory/project/link-directory.js +44 -0
- package/dist/memory/project/root-claims.d.ts +6 -0
- package/dist/memory/project/root-claims.js +39 -0
- package/dist/memory/project/session-root.d.ts +2 -0
- package/dist/memory/project/session-root.js +9 -1
- package/dist/memory/project/sync-status.d.ts +46 -0
- package/dist/memory/project/sync-status.js +135 -1
- package/dist/memory/recall/memory-tools.js +46 -3
- package/dist/memory/recall/platform-memory.d.ts +34 -0
- package/dist/memory/recall/platform-memory.js +139 -0
- package/dist/memory/recall/project-memory.js +36 -8
- package/dist/portal/bridge/bridge.d.ts +9 -5
- package/dist/portal/bridge/bridge.js +66 -23
- package/dist/portal/bridge/harness-request.d.ts +23 -0
- package/dist/portal/bridge/harness-request.js +27 -0
- package/dist/portal/bridge/wrong-path.d.ts +17 -0
- package/dist/portal/bridge/wrong-path.js +35 -0
- package/dist/portal/input/network-mock-tools.js +11 -2
- package/dist/portal/input/real-input.d.ts +2 -0
- package/dist/portal/input/real-input.js +13 -10
- package/dist/portal/pool/browser-pool.d.ts +48 -0
- package/dist/portal/pool/browser-pool.js +120 -2
- package/dist/portal/pool/context-permissions.d.ts +33 -0
- package/dist/portal/pool/context-permissions.js +33 -0
- package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
- package/dist/portal/pool/lease-marker-stamp.js +49 -0
- package/dist/portal/pool/playwright-launcher.d.ts +27 -5
- package/dist/portal/pool/playwright-launcher.js +59 -14
- package/dist/portal/pool/pool-contract.d.ts +21 -1
- package/dist/portal/session/agent-link.d.ts +8 -0
- package/dist/portal/session/agent-link.js +17 -0
- package/dist/portal/session/command-payload.js +6 -1
- package/dist/portal/session/daemon-answers.d.ts +3 -3
- package/dist/portal/session/daemon-answers.js +4 -2
- package/dist/portal/session/dev-server/dev-command.d.ts +9 -0
- package/dist/portal/session/dev-server/dev-command.js +27 -1
- package/dist/portal/session/facts/observed-state.d.ts +16 -18
- package/dist/portal/session/facts/observed-state.js +46 -3
- package/dist/portal/session/human/live-control.d.ts +9 -2
- package/dist/portal/session/human/live-control.js +12 -3
- package/dist/portal/session/live-control-tools.js +82 -13
- package/dist/portal/session/narration-args.d.ts +5 -0
- package/dist/portal/session/narration-args.js +17 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +1 -1
- package/dist/portal/session/no-session-diagnosis.js +31 -9
- package/dist/portal/session/no-session-next-action.d.ts +20 -0
- package/dist/portal/session/no-session-next-action.js +134 -61
- package/dist/portal/session/no-session-watch.js +179 -22
- package/dist/portal/session/presence/session-lease.js +1 -1
- package/dist/portal/session/recorded-gaps.d.ts +97 -0
- package/dist/portal/session/recorded-gaps.js +251 -0
- package/dist/portal/session/session-health.d.ts +11 -0
- package/dist/portal/session/session-health.js +3 -1
- package/dist/portal/session/session-info.js +2 -1
- package/dist/portal/session/session-manager.d.ts +18 -0
- package/dist/portal/session/session-manager.js +54 -3
- package/dist/portal/session/session-successor.d.ts +8 -0
- package/dist/portal/session/session-successor.js +1 -1
- package/dist/portal/session/session.d.ts +15 -28
- package/dist/portal/session/session.js +60 -61
- package/dist/portal/session/timing/command-timeout.js +25 -1
- package/dist/portal/session/timing/wall-clock.d.ts +1 -1
- package/dist/portal/session/timing/wall-clock.js +1 -1
- package/dist/portal/session/zero-install-first-call.d.ts +31 -0
- package/dist/portal/session/zero-install-first-call.js +88 -0
- package/dist/start-options.d.ts +7 -1
- package/dist/start-wiring.d.ts +63 -0
- package/dist/start-wiring.js +169 -0
- package/dist/status-payload.d.ts +13 -1
- package/dist/status-payload.js +13 -1
- package/dist/surface/http-server.js +7 -1
- package/dist/surface/mcp/attach-memory.d.ts +1 -0
- package/dist/surface/mcp/attach-memory.js +12 -1
- package/dist/surface/mcp/mcp-proxy.d.ts +4 -0
- package/dist/surface/mcp/mcp-proxy.js +29 -8
- package/dist/surface/mcp/mcp.d.ts +23 -0
- package/dist/surface/mcp/mcp.js +34 -4
- package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
- package/dist/surface/mcp/proxy/drive-calls.js +27 -0
- package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
- package/dist/surface/mcp/server-instructions.js +22 -14
- package/dist/surface/mcp/shared-params.js +1 -1
- package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
- package/dist/surface/mcp/surface-vocabulary.js +1 -0
- package/dist/surface/tools/account-tool.d.ts +22 -0
- package/dist/surface/tools/account-tool.js +157 -0
- package/dist/surface/tools/act/act-danger.d.ts +11 -0
- package/dist/surface/tools/act/act-danger.js +38 -1
- package/dist/surface/tools/act/act-observation.d.ts +33 -0
- package/dist/surface/tools/act/act-observation.js +57 -0
- package/dist/surface/tools/act/act-preflight.js +25 -2
- package/dist/surface/tools/act/act-target.js +8 -3
- package/dist/surface/tools/act/resolve-target.d.ts +1 -1
- package/dist/surface/tools/act/resolve-target.js +18 -3
- package/dist/surface/tools/act/screen-request.d.ts +34 -0
- package/dist/surface/tools/act/screen-request.js +113 -0
- package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
- package/dist/surface/tools/act/sequence-grade.js +13 -2
- package/dist/surface/tools/act-sequence-tool.js +136 -27
- package/dist/surface/tools/act-tools.d.ts +0 -9
- package/dist/surface/tools/act-tools.js +48 -34
- package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
- package/dist/surface/tools/agent/app-notes-learning.js +80 -0
- package/dist/surface/tools/agent/app-notes.d.ts +4 -0
- package/dist/surface/tools/agent/app-notes.js +48 -0
- package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
- package/dist/surface/tools/agent/build-staleness.js +62 -0
- package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
- package/dist/surface/tools/agent/compact-envelope.js +374 -0
- package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
- package/dist/surface/tools/agent/for-the-agent.js +44 -0
- package/dist/surface/tools/agent/notices.d.ts +50 -0
- package/dist/surface/tools/agent/notices.js +152 -0
- package/dist/surface/tools/agent/reteach.d.ts +11 -0
- package/dist/surface/tools/agent/reteach.js +50 -0
- package/dist/surface/tools/args/alias-args.d.ts +5 -0
- package/dist/surface/tools/args/alias-args.js +10 -0
- package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
- package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
- package/dist/surface/tools/assert/assert-source.d.ts +15 -0
- package/dist/surface/tools/assert/assert-source.js +40 -0
- package/dist/surface/tools/assert/assert-verdict.js +25 -15
- package/dist/surface/tools/browser-tools.js +43 -1
- package/dist/surface/tools/chat-drives.d.ts +75 -0
- package/dist/surface/tools/chat-drives.js +265 -21
- package/dist/surface/tools/coverage-tools.d.ts +2 -10
- package/dist/surface/tools/coverage-tools.js +2 -53
- package/dist/surface/tools/dynamic-tools.js +29 -1
- package/dist/surface/tools/empty-session-list.d.ts +10 -0
- package/dist/surface/tools/empty-session-list.js +45 -5
- package/dist/surface/tools/error-recovery.d.ts +8 -0
- package/dist/surface/tools/error-recovery.js +69 -5
- package/dist/surface/tools/explore-tools.d.ts +23 -2
- package/dist/surface/tools/explore-tools.js +377 -74
- package/dist/surface/tools/feedback-tools.d.ts +2 -3
- package/dist/surface/tools/feedback-tools.js +4 -3
- package/dist/surface/tools/gap-novelty.d.ts +3 -1
- package/dist/surface/tools/gap-novelty.js +8 -1
- package/dist/surface/tools/harness-explore.d.ts +52 -73
- package/dist/surface/tools/harness-explore.js +177 -146
- package/dist/surface/tools/harness-gate.d.ts +88 -0
- package/dist/surface/tools/harness-gate.js +235 -0
- package/dist/surface/tools/harness-hunt.d.ts +43 -0
- package/dist/surface/tools/harness-hunt.js +215 -0
- package/dist/surface/tools/harness-plan.d.ts +5 -0
- package/dist/surface/tools/harness-plan.js +7 -0
- package/dist/surface/tools/harness-script.d.ts +22 -0
- package/dist/surface/tools/harness-script.js +256 -38
- package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
- package/dist/surface/tools/harness-tab-guard.js +27 -0
- package/dist/surface/tools/harness-toolset.d.ts +8 -0
- package/dist/surface/tools/harness-toolset.js +27 -4
- package/dist/surface/tools/human-notes.d.ts +16 -0
- package/dist/surface/tools/human-notes.js +27 -0
- package/dist/surface/tools/invoke-tool.d.ts +5 -2
- package/dist/surface/tools/invoke-tool.js +220 -93
- package/dist/surface/tools/lease-hint.js +26 -5
- package/dist/surface/tools/lease-permissions.d.ts +33 -0
- package/dist/surface/tools/lease-permissions.js +73 -0
- package/dist/surface/tools/lease-readiness.d.ts +38 -0
- package/dist/surface/tools/lease-readiness.js +57 -0
- package/dist/surface/tools/lease-seed.d.ts +20 -0
- package/dist/surface/tools/lease-seed.js +45 -1
- package/dist/surface/tools/lease-tools.d.ts +10 -1
- package/dist/surface/tools/lease-tools.js +119 -69
- package/dist/surface/tools/live-call-text.js +2 -2
- package/dist/surface/tools/merge-tools.js +42 -2
- package/dist/surface/tools/merged-name-redirect.js +4 -0
- package/dist/surface/tools/next-step.d.ts +11 -1
- package/dist/surface/tools/next-step.js +73 -18
- package/dist/surface/tools/observe-tools.js +43 -5
- package/dist/surface/tools/platform-moment.d.ts +60 -0
- package/dist/surface/tools/platform-moment.js +132 -4
- package/dist/surface/tools/read-tools.js +65 -14
- package/dist/surface/tools/reticle-result.d.ts +120 -0
- package/dist/surface/tools/reticle-result.js +364 -0
- package/dist/surface/tools/tool-kit.d.ts +68 -2
- package/dist/surface/tools/tool-kit.js +73 -1
- package/dist/surface/tools/tools.js +25 -13
- package/dist/telemetry/account-envelope.d.ts +7 -0
- package/dist/telemetry/account-envelope.js +61 -0
- package/dist/telemetry/agent-client.d.ts +15 -0
- package/dist/telemetry/agent-client.js +57 -0
- package/dist/telemetry/app-instrumented.js +9 -2
- package/dist/telemetry/argument-shape.d.ts +7 -0
- package/dist/telemetry/argument-shape.js +86 -1
- package/dist/telemetry/automation-hint.d.ts +2 -3
- package/dist/telemetry/automation-hint.js +33 -8
- package/dist/telemetry/cli-telemetry.js +7 -2
- package/dist/telemetry/daemon-telemetry.js +3 -0
- package/dist/telemetry/error-fingerprint.d.ts +10 -1
- package/dist/telemetry/error-fingerprint.js +61 -5
- package/dist/telemetry/feedback-cli.d.ts +0 -13
- package/dist/telemetry/feedback-cli.js +0 -77
- package/dist/telemetry/feedback.d.ts +13 -0
- package/dist/telemetry/feedback.js +183 -17
- package/dist/telemetry/harness-run.d.ts +18 -0
- package/dist/telemetry/harness-run.js +80 -0
- package/dist/telemetry/hud-events.d.ts +16 -0
- package/dist/telemetry/hud-events.js +27 -0
- package/dist/telemetry/hud-metrics.d.ts +27 -6
- package/dist/telemetry/hud-metrics.js +99 -25
- package/dist/telemetry/init-telemetry.js +2 -2
- package/dist/telemetry/install-source.d.ts +13 -25
- package/dist/telemetry/install-source.js +44 -3
- package/dist/telemetry/mcp-connection.d.ts +0 -14
- package/dist/telemetry/mcp-connection.js +5 -1
- package/dist/telemetry/onboarding-firsts.d.ts +32 -0
- package/dist/telemetry/onboarding-firsts.js +81 -6
- package/dist/telemetry/platform-linked.d.ts +5 -0
- package/dist/telemetry/platform-linked.js +32 -0
- package/dist/telemetry/project-profile.js +5 -3
- package/dist/telemetry/proxy-telemetry.js +4 -1
- package/dist/telemetry/session-metrics.d.ts +15 -4
- package/dist/telemetry/session-metrics.js +88 -52
- package/dist/telemetry/telemetry.d.ts +26 -2
- package/dist/telemetry/telemetry.js +102 -21
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +12 -4
- package/dist/wire-journal.d.ts +2 -2
- package/dist/wire-journal.js +16 -5
- package/docs/README.md +2 -2
- package/docs/actions.mdx +6 -3
- package/docs/adapters.md +1 -1
- package/docs/agent-cheatsheet.md +24 -27
- package/docs/architecture.md +5 -5
- package/docs/autodrive.md +13 -12
- package/docs/benchmarks.md +5 -5
- package/docs/best-practices.mdx +27 -9
- package/docs/capabilities.mdx +14 -16
- package/docs/cli/affected.mdx +1 -1
- package/docs/cli/cloud.mdx +54 -75
- package/docs/cli/doctor.mdx +8 -3
- package/docs/cli/drive.mdx +12 -12
- package/docs/cli/feedback.mdx +3 -3
- package/docs/cli/gate.mdx +7 -2
- package/docs/cli/help.mdx +50 -55
- package/docs/cli/init.mdx +32 -15
- package/docs/cli/license.mdx +12 -8
- package/docs/cli/mcp.mdx +4 -4
- package/docs/cli/open.mdx +3 -3
- package/docs/cli/report.mdx +4 -2
- package/docs/cli/restart.mdx +2 -2
- package/docs/cli/rollback.mdx +14 -8
- package/docs/cli/serve.mdx +4 -4
- package/docs/cli/setup.mdx +23 -0
- package/docs/cli/status.mdx +13 -4
- package/docs/cli/stop.mdx +67 -8
- package/docs/cli/try.mdx +62 -0
- package/docs/cli/update.mdx +4 -3
- package/docs/cli/verify.mdx +17 -6
- package/docs/cli/version.mdx +3 -2
- package/docs/cli.mdx +110 -41
- package/docs/debugging.md +3 -3
- package/docs/deploy-checks.md +1 -1
- package/docs/desktop.mdx +5 -3
- package/docs/enterprise.md +11 -10
- package/docs/environment.mdx +5 -2
- package/docs/faq.mdx +3 -3
- package/docs/first-drive.md +5 -4
- package/docs/flows.md +35 -27
- package/docs/for-agents.md +4 -5
- package/docs/frameworks.mdx +32 -21
- package/docs/getting-started.md +66 -64
- package/docs/human-control.md +15 -14
- package/docs/index.mdx +15 -43
- package/docs/install-agentic.mdx +22 -37
- package/docs/install-manual.mdx +22 -12
- package/docs/instrumentation.mdx +5 -3
- package/docs/integration-patterns.md +7 -7
- package/docs/license-activation.mdx +1 -1
- package/docs/multi-agent-testing.md +24 -6
- package/docs/packages/babel-plugin.mdx +4 -2
- package/docs/packages/browser.mdx +16 -10
- package/docs/packages/core.mdx +12 -5
- package/docs/packages/electron.mdx +3 -2
- package/docs/packages/engine.mdx +1 -1
- package/docs/packages/eslint-plugin.mdx +18 -12
- package/docs/packages/next.mdx +8 -7
- package/docs/packages/open-verification.mdx +1 -1
- package/docs/packages/server.mdx +5 -5
- package/docs/packages/tauri.mdx +8 -8
- package/docs/packages/test.mdx +4 -10
- package/docs/packages/vite-plugin.mdx +11 -4
- package/docs/packages.mdx +11 -15
- package/docs/platform-integration.md +6 -5
- package/docs/predicates.mdx +40 -24
- package/docs/quickstart.mdx +58 -29
- package/docs/required-checks.md +8 -7
- package/docs/reticle-manual.md +15 -5
- package/docs/skill-file.mdx +17 -79
- package/docs/skill-setup.md +9 -9
- package/docs/skill.md +200 -0
- package/docs/system-map.md +7 -7
- package/docs/telemetry.md +22 -24
- package/docs/testing.md +4 -4
- package/docs/token-efficiency.md +12 -12
- package/docs/tools/act-and-wait.mdx +9 -2
- package/docs/tools/act-sequence.mdx +6 -7
- package/docs/tools/act.mdx +2 -2
- package/docs/tools/assert.mdx +18 -17
- package/docs/tools/console.mdx +9 -9
- package/docs/tools/inspect.mdx +16 -7
- package/docs/tools/look.mdx +24 -0
- package/docs/tools/navigate.mdx +5 -3
- package/docs/tools/network.mdx +2 -2
- package/docs/tools/observe.mdx +6 -6
- package/docs/tools/overview.mdx +34 -33
- package/docs/tools/query.mdx +5 -5
- package/docs/tools/session-and-feedback.mdx +13 -4
- package/docs/tools/sessions.mdx +8 -8
- package/docs/tools/snapshot.mdx +6 -5
- package/docs/tools/state.mdx +9 -9
- package/docs/tools/tools-and-run.mdx +26 -24
- package/docs/tools/verify.mdx +28 -0
- package/docs/tools/wait-for.mdx +8 -4
- package/docs/troubleshooting.mdx +21 -6
- package/docs/usage.md +51 -45
- package/docs/use-cases.mdx +3 -3
- package/docs/vs-chrome-devtools-mcp.mdx +9 -6
- package/docs/vs-playwright-mcp.mdx +3 -1
- package/docs/what-is-recorded.md +7 -5
- package/docs/what-is-reticle.mdx +2 -2
- package/docs/why-reticle.mdx +1 -1
- package/package.json +6 -5
- package/dist/command/cli/demo/demo-page.d.ts +0 -78
- package/dist/command/cli/demo/demo-page.js +0 -249
- package/dist/command/cli/demo/demo-run.d.ts +0 -38
- package/dist/command/cli/demo/demo-run.js +0 -138
- package/dist/judgement/hunt/hunt-report.d.ts +0 -49
- package/dist/judgement/hunt/hunt-report.js +0 -84
- package/dist/language/flows/buddy-status.d.ts +0 -25
- package/dist/language/flows/buddy-status.js +0 -32
- package/dist/language/flows/change/watch-batcher.d.ts +0 -18
- package/dist/language/flows/change/watch-batcher.js +0 -19
- package/dist/memory/cloud/harness-offer.d.ts +0 -44
- package/dist/memory/cloud/harness-offer.js +0 -145
- package/dist/surface/tools/feature-capture.d.ts +0 -151
- package/dist/surface/tools/feature-capture.js +0 -235
- package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
- package/dist/surface/tools/tool-hit-rate.js +0 -90
- package/dist/telemetry/harness-drive.d.ts +0 -4
- package/dist/telemetry/harness-drive.js +0 -35
- package/dist/telemetry/identify.d.ts +0 -22
- package/dist/telemetry/identify.js +0 -73
- package/docs/cli/capsules.mdx +0 -70
- package/docs/cli/hunt.mdx +0 -73
- package/docs/cli/identify.mdx +0 -76
- package/docs/cli/kill.mdx +0 -91
- package/docs/cli/watch.mdx +0 -62
|
@@ -14,6 +14,31 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { NoSessionAction, RETICLE_URL_PARAM, ReticleEnv, redactUrl } from '@reticlehq/core';
|
|
16
16
|
import { detectNonJsEcosystem, noPackageJsonMessage } from '@reticlehq/init';
|
|
17
|
+
/** The port a tombstone URL names, when it names one — anything unparseable names no port. */
|
|
18
|
+
export function portOfUrl(url) {
|
|
19
|
+
try {
|
|
20
|
+
const raw = new URL(url).port;
|
|
21
|
+
if ('' === raw)
|
|
22
|
+
return undefined;
|
|
23
|
+
const port = Number(raw);
|
|
24
|
+
return Number.isSafeInteger(port) && port > 0 ? port : undefined;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The departed session's own port no longer answers. Direct evidence, because the scan always
|
|
32
|
+
* covers that port — unlike an empty scan, which proves nothing the moment another project
|
|
33
|
+
* happens to be listening (#1421). A slow listener is up, not gone, and a url with no explicit
|
|
34
|
+
* port was never scanned, so neither counts.
|
|
35
|
+
*/
|
|
36
|
+
export function departedPortGone(facts) {
|
|
37
|
+
const port = facts.lastKnownUrl === undefined ? undefined : portOfUrl(facts.lastKnownUrl);
|
|
38
|
+
return (port !== undefined &&
|
|
39
|
+
!facts.listening.includes(port) &&
|
|
40
|
+
!(facts.slowListeners ?? []).includes(port));
|
|
41
|
+
}
|
|
17
42
|
/**
|
|
18
43
|
* The departed session's url as a human would type it: the params a Reticle launcher stamps on a
|
|
19
44
|
* lease are stripped, because reopening WITH them would adopt the dead lease's identity. Undefined
|
|
@@ -36,10 +61,29 @@ function reopenableUrl(raw) {
|
|
|
36
61
|
const port = '' === url.port ? ('https:' === url.protocol ? 443 : 80) : Number(url.port);
|
|
37
62
|
return { url: url.toString(), port };
|
|
38
63
|
}
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Reticle's own commands, the only ones here that cannot be wrong. Spelled through `npx`, like the
|
|
66
|
+
* CLI's own messages: the default MCP registration runs Reticle through `npx` and puts no `reticle`
|
|
67
|
+
* bin on PATH, so a bare `reticle init` fails with "command not found" exactly where it is handed out.
|
|
68
|
+
*/
|
|
69
|
+
const CLI = 'npx @reticlehq/server';
|
|
70
|
+
const INIT_COMMAND = `${CLI} init`;
|
|
71
|
+
const OPEN_COMMAND = `${CLI} open`;
|
|
42
72
|
const LOCALHOST = 'http://localhost';
|
|
73
|
+
/**
|
|
74
|
+
* What a lease on an app with no SDK can see. The lease supplies the SDK itself (the zero-install
|
|
75
|
+
* reader), so an unwired app still gets a verdict — on what the page does, not on its source.
|
|
76
|
+
*/
|
|
77
|
+
const ZERO_INSTALL_SEES = 'the lease supplies the SDK itself: DOM, network, console and routes, but no component state ' +
|
|
78
|
+
'or source file:line until the app is wired';
|
|
79
|
+
/** The zero-install call, with the URL only when it can be named without guessing. */
|
|
80
|
+
function zeroInstallLease(url) {
|
|
81
|
+
return `reticle_lease {action:"acquire", url:"${url ?? "<the app's URL>"}"}`;
|
|
82
|
+
}
|
|
83
|
+
/** Nothing here says this project was ever wired: no config, no recorded connection, no session. */
|
|
84
|
+
function neverWired(facts) {
|
|
85
|
+
return !facts.initialized && true !== facts.previouslyConnected && !facts.everConnected;
|
|
86
|
+
}
|
|
43
87
|
export function nextActionFor(facts) {
|
|
44
88
|
// FIRST, above every other cause, because it is the only one supported by positive evidence about
|
|
45
89
|
// a daemon rather than by an absence. This project's own connection record names a live daemon
|
|
@@ -71,7 +115,11 @@ export function nextActionFor(facts) {
|
|
|
71
115
|
// (`connectedSinceLastClosure` in the manager). Read as the weaker "a refusal was recorded at
|
|
72
116
|
// some point", the flip trades this bug for its mirror image and blames the token for a tab the
|
|
73
117
|
// human closed. The ordering belongs to the fact; what this branch does with it is then obvious.
|
|
74
|
-
|
|
118
|
+
// A departed session whose port is ALSO gone is the one shape where "reopen that" points at a
|
|
119
|
+
// dead socket and forbids the restart that fixes it (#1421). Keyed on that port itself, not on
|
|
120
|
+
// an empty scan: another project listening elsewhere says nothing about this one.
|
|
121
|
+
const departedPortIsGone = facts.everConnected && true !== facts.authRefused && departedPortGone(facts);
|
|
122
|
+
if (facts.everConnected && true !== facts.authRefused && !departedPortIsGone) {
|
|
75
123
|
const listening = facts.listening;
|
|
76
124
|
const only = 1 === listening.length ? listening[0] : undefined;
|
|
77
125
|
// The departed session's own url first: it is where this project's app demonstrably was, while
|
|
@@ -82,8 +130,8 @@ export function nextActionFor(facts) {
|
|
|
82
130
|
: 0 === listening.length
|
|
83
131
|
? ''
|
|
84
132
|
: only === undefined
|
|
85
|
-
? `
|
|
86
|
-
: `
|
|
133
|
+
? ` Something is serving a page on ${listening.map((p) => `:${String(p)}`).join(', ')}; it may not be this app — open the URL the human names rather than starting a second stack.`
|
|
134
|
+
: ` Something is serving a page on :${String(only)}; it may not be this app — just open ${LOCALHOST}:${String(only)} rather than starting a second stack.`;
|
|
87
135
|
const target = known !== undefined
|
|
88
136
|
? { command: `${OPEN_COMMAND} ${known.url}`, port: known.port }
|
|
89
137
|
: only === undefined
|
|
@@ -124,8 +172,64 @@ export function nextActionFor(facts) {
|
|
|
124
172
|
`point it there), then open the app.${leaseAlternative}`,
|
|
125
173
|
};
|
|
126
174
|
}
|
|
127
|
-
|
|
175
|
+
// A current pairing-token refusal is positive evidence that the app is running and instrumented.
|
|
176
|
+
// It must outrank an empty port scan, which only says the app is outside this daemon's scan set.
|
|
177
|
+
const ports = facts.listening.join(', ');
|
|
178
|
+
const only = 1 === facts.listening.length ? facts.listening[0] : undefined;
|
|
179
|
+
const where = '' === ports ? 'on a port this daemon did not scan' : `${ports} listening`;
|
|
180
|
+
// A refusal against a project that IS initialised here. The daemon has the config, so this is not
|
|
181
|
+
// a scope problem — the page reached the right daemon and presented a credential it would not
|
|
182
|
+
// accept. The usual cause is a dev server that shares no filesystem with the daemon (Docker, a
|
|
183
|
+
// devcontainer, WSL): the build plugin reads-or-mints the pairing token from `$HOME/.reticle`,
|
|
184
|
+
// which over there is a different file, so it mints its own and every page is refused. The daemon
|
|
185
|
+
// holds every fact needed to say so, which is why the reason below says it rather than repeating
|
|
186
|
+
// `authentication failed`.
|
|
187
|
+
if (true === facts.initialized && true === facts.authRefused) {
|
|
188
|
+
return {
|
|
189
|
+
action: NoSessionAction.OPEN_APP,
|
|
190
|
+
...(only === undefined ? {} : { port: only }),
|
|
191
|
+
reason: `a page dialled this daemon and was refused on the pairing token (${where}), so ` +
|
|
192
|
+
'the app IS running and instrumented and this project IS wired — the page simply presented ' +
|
|
193
|
+
'a token this daemon does not own. The usual cause is a dev server that does not share a ' +
|
|
194
|
+
'filesystem with the daemon (Docker, a devcontainer, WSL): the build plugin reads the token ' +
|
|
195
|
+
'from `$HOME/.reticle/pairing-token`, which over there is a different file, so it mints its ' +
|
|
196
|
+
"own. Point the plugin at the daemon's copy — mount `~/.reticle/pairing-token` into the " +
|
|
197
|
+
`container read-only and set \`${ReticleEnv.PAIRING_TOKEN_DIR}\` to the directory holding ` +
|
|
198
|
+
'it — then ' +
|
|
199
|
+
'restart the dev server, because the token is inlined when Vite resolves its config and ' +
|
|
200
|
+
'kept in the prebundled module. Reloading the page serves that same token, whether the ' +
|
|
201
|
+
'dev server is on this machine or in a container.',
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// A refused dial outranks the absence of a local config, for the same reason `previouslyConnected`
|
|
205
|
+
// does: it is positive evidence about the app, and `initialized` only ever answers "is there a
|
|
206
|
+
// `.reticle.json` in the ONE directory this daemon stands in". A globally-registered daemon stands
|
|
207
|
+
// in `/` or `$HOME`, so that answer is no for every project it serves -- and every page it turns
|
|
208
|
+
// away is proof that the project it turned away is wired.
|
|
209
|
+
if (!facts.initialized && true === facts.authRefused) {
|
|
210
|
+
return {
|
|
211
|
+
action: NoSessionAction.OPEN_APP,
|
|
212
|
+
...(only === undefined ? {} : { port: only }),
|
|
213
|
+
reason: `a page dialled this daemon and was refused on the pairing token, so the app IS running ` +
|
|
214
|
+
`and instrumented (${where}) — this is a SCOPE problem, not an install problem. ` +
|
|
215
|
+
'This daemon was started outside the project (an IDE that registers the MCP server ' +
|
|
216
|
+
'globally starts it in `/` or your home directory), so it has no `.reticle.json` to match ' +
|
|
217
|
+
'the page against. Do NOT run `reticle init`: the config it would write is already correct ' +
|
|
218
|
+
'somewhere else. Take a context you own instead with reticle_lease {action:"acquire", url, ' +
|
|
219
|
+
"projectId}, or restart the daemon from the app's own directory.",
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (0 === facts.listening.length || departedPortIsGone) {
|
|
128
223
|
const dev = facts.dev;
|
|
224
|
+
// The start advice below follows a departed session whose port is gone. Name it, so the restart
|
|
225
|
+
// does not read as if nothing had ever run here (#1421).
|
|
226
|
+
const stopped = departedPortIsGone ? reopenableUrl(facts.lastKnownUrl) : undefined;
|
|
227
|
+
const stoppedNote = stopped === undefined
|
|
228
|
+
? ''
|
|
229
|
+
: ` The session that was on ${redactUrl(stopped.url)} is gone and nothing listens there now.`;
|
|
230
|
+
const notRunning = departedPortIsGone
|
|
231
|
+
? "nothing answers on the port this project's app was last on, so the app is probably not running — "
|
|
232
|
+
: 'nothing is listening on the ports Reticle scans, so the app is probably not running — ';
|
|
129
233
|
if (dev === undefined) {
|
|
130
234
|
if (facts.exists !== undefined && !facts.exists('package.json')) {
|
|
131
235
|
const ecosystem = detectNonJsEcosystem(facts.exists);
|
|
@@ -143,10 +247,11 @@ export function nextActionFor(facts) {
|
|
|
143
247
|
}
|
|
144
248
|
return {
|
|
145
249
|
action: NoSessionAction.START_DEV_SERVER,
|
|
146
|
-
reason:
|
|
250
|
+
reason: notRunning +
|
|
147
251
|
'but this project declares no dev script (no `dev`, `develop` or `start` in its ' +
|
|
148
252
|
'package.json), so there is no command to hand you. Ask the human how their app is ' +
|
|
149
|
-
'started, and for the URL it serves on.'
|
|
253
|
+
'started, and for the URL it serves on.' +
|
|
254
|
+
stoppedNote,
|
|
150
255
|
};
|
|
151
256
|
}
|
|
152
257
|
// The app can live one directory down; the command has to be runnable from where the daemon
|
|
@@ -168,69 +273,37 @@ export function nextActionFor(facts) {
|
|
|
168
273
|
// server on any other port is invisible to it, and that a running app should be checked for
|
|
169
274
|
// rather than assumed away. Measured on a machine with three dev servers up on ports the scan
|
|
170
275
|
// does not cover, it reported the app was not running.
|
|
171
|
-
reason:
|
|
276
|
+
reason: notRunning +
|
|
172
277
|
'though that scan is narrow, so if it IS up on another port, ask for its URL instead of ' +
|
|
173
278
|
`starting a second one. This is the project's own ` +
|
|
174
279
|
(undefined === dev.script ? 'launcher' : `\`${dev.script}\` script`) +
|
|
175
280
|
(dev.directory === undefined ? '' : `, in \`${dev.directory}\``) +
|
|
176
281
|
` — run it in the ` +
|
|
177
|
-
'background, tell the human it is running, then call reticle_sessions again.'
|
|
282
|
+
'background, tell the human it is running, then call reticle_sessions again.' +
|
|
283
|
+
stoppedNote +
|
|
284
|
+
(neverWired(facts)
|
|
285
|
+
? ` Once it is up, ${zeroInstallLease(dev.port === undefined ? undefined : `${LOCALHOST}:${String(dev.port)}`)} ` +
|
|
286
|
+
`gets a verdict with nothing installed (${ZERO_INSTALL_SEES}); ` +
|
|
287
|
+
`\`${facts.init ?? INIT_COMMAND}\` wires it for good — then restart the dev server and reload.`
|
|
288
|
+
: ''),
|
|
178
289
|
};
|
|
179
290
|
}
|
|
180
291
|
// Something IS up. Whatever else is true, do NOT hand back a start command: a second dev server on
|
|
181
292
|
// a second port is the exact confusion the probe exists to prevent.
|
|
182
|
-
const ports = facts.listening.join(', ');
|
|
183
|
-
const only = 1 === facts.listening.length ? facts.listening[0] : undefined;
|
|
184
|
-
// A refused dial outranks the absence of a local config, for the same reason `previouslyConnected`
|
|
185
|
-
// does: it is positive evidence about the app, and `initialized` only ever answers "is there a
|
|
186
|
-
// `.reticle.json` in the ONE directory this daemon stands in". A globally-registered daemon stands
|
|
187
|
-
// in `/` or `$HOME`, so that answer is no for every project it serves -- and every page it turns
|
|
188
|
-
// away is proof that the project it turned away is wired.
|
|
189
|
-
// A refusal against a project that IS initialised here. The daemon has the config, so this is not
|
|
190
|
-
// a scope problem — the page reached the right daemon and presented a credential it would not
|
|
191
|
-
// accept. The usual cause is a dev server that shares no filesystem with the daemon (Docker, a
|
|
192
|
-
// devcontainer, WSL): the build plugin reads-or-mints the pairing token from `$HOME/.reticle`,
|
|
193
|
-
// which over there is a different file, so it mints its own and every page is refused. The daemon
|
|
194
|
-
// holds every fact needed to say so, which is why the reason below says it rather than repeating
|
|
195
|
-
// `authentication failed`.
|
|
196
|
-
if (true === facts.initialized && true === facts.authRefused) {
|
|
197
|
-
return {
|
|
198
|
-
action: NoSessionAction.OPEN_APP,
|
|
199
|
-
...(only === undefined ? {} : { port: only }),
|
|
200
|
-
reason: `a page dialled this daemon and was refused on the pairing token (${ports} listening), so ` +
|
|
201
|
-
'the app IS running and instrumented and this project IS wired — the page simply presented ' +
|
|
202
|
-
'a token this daemon does not own. The usual cause is a dev server that does not share a ' +
|
|
203
|
-
'filesystem with the daemon (Docker, a devcontainer, WSL): the build plugin reads the token ' +
|
|
204
|
-
'from `$HOME/.reticle/pairing-token`, which over there is a different file, so it mints its ' +
|
|
205
|
-
"own. Point the plugin at the daemon's copy — mount `~/.reticle/pairing-token` into the " +
|
|
206
|
-
`container read-only and set \`${ReticleEnv.PAIRING_TOKEN_DIR}\` to the directory holding ` +
|
|
207
|
-
'it — then ' +
|
|
208
|
-
'restart the dev server, because the token is inlined when Vite resolves its config and ' +
|
|
209
|
-
'kept in the prebundled module. Reloading the page serves that same token, whether the ' +
|
|
210
|
-
'dev server is on this machine or in a container.',
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
if (!facts.initialized && true === facts.authRefused) {
|
|
214
|
-
return {
|
|
215
|
-
action: NoSessionAction.OPEN_APP,
|
|
216
|
-
...(only === undefined ? {} : { port: only }),
|
|
217
|
-
reason: `a page dialled this daemon and was refused on the pairing token, so the app IS running ` +
|
|
218
|
-
`and instrumented (${ports} listening) — this is a SCOPE problem, not an install problem. ` +
|
|
219
|
-
'This daemon was started outside the project (an IDE that registers the MCP server ' +
|
|
220
|
-
'globally starts it in `/` or your home directory), so it has no `.reticle.json` to match ' +
|
|
221
|
-
'the page against. Do NOT run `reticle init`: the config it would write is already correct ' +
|
|
222
|
-
'somewhere else. Take a context you own instead with reticle_lease {action:"acquire", url, ' +
|
|
223
|
-
"projectId}, or restart the daemon from the app's own directory.",
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
293
|
if (!facts.initialized && true !== facts.previouslyConnected) {
|
|
294
|
+
// The port the project's own dev script pins outranks a lone listener: the scan is machine-wide.
|
|
295
|
+
const pinned = facts.dev?.port;
|
|
296
|
+
const target = pinned !== undefined && facts.listening.includes(pinned) ? pinned : only;
|
|
227
297
|
return {
|
|
228
298
|
action: NoSessionAction.RUN_INIT,
|
|
229
|
-
command: INIT_COMMAND,
|
|
230
|
-
...(
|
|
299
|
+
command: facts.init ?? INIT_COMMAND,
|
|
300
|
+
...(target === undefined ? {} : { port: target }),
|
|
231
301
|
reason: `something is listening (${ports}) but no \`.reticle.json\` was found, so the app may ` +
|
|
232
|
-
|
|
233
|
-
|
|
302
|
+
'carry no Reticle SDK. For a verdict NOW with nothing installed: ' +
|
|
303
|
+
`${zeroInstallLease(target === undefined ? undefined : `${LOCALHOST}:${String(target)}`)} — ` +
|
|
304
|
+
`${ZERO_INSTALL_SEES}. To wire it for good, run this command yourself (it runs in the ` +
|
|
305
|
+
"APP's own folder, not where this daemon stands), then restart the dev server and reload " +
|
|
306
|
+
'the page.',
|
|
234
307
|
};
|
|
235
308
|
}
|
|
236
309
|
if (only === undefined) {
|
|
@@ -258,12 +331,12 @@ export function nextActionFor(facts) {
|
|
|
258
331
|
command: `${OPEN_COMMAND} ${LOCALHOST}:${String(only)}`,
|
|
259
332
|
port: only,
|
|
260
333
|
reason: neverConnected
|
|
261
|
-
? 'this project is wired and
|
|
334
|
+
? 'this project is wired and something is listening on that port (it may not be this app), but no app has ever connected to ' +
|
|
262
335
|
'this daemon — Reticle only ever sees a page a browser has LOADED, and nothing has loaded ' +
|
|
263
336
|
'one. If opening it does not produce a session, the dev server is older than the Reticle ' +
|
|
264
337
|
'plugin and its bundle carries no SDK: restart the dev server (do not rely on HMR) and ' +
|
|
265
338
|
'load the page again.'
|
|
266
|
-
: 'this project is wired and
|
|
339
|
+
: 'this project is wired and something is listening on that port (it may not be this app) — Reticle only ever sees a page a ' +
|
|
267
340
|
'browser has LOADED, and nothing has loaded one.',
|
|
268
341
|
};
|
|
269
342
|
}
|
|
@@ -13,11 +13,12 @@ import { probeRouteStatus } from './dev-server/route-status-probe.js';
|
|
|
13
13
|
import { probeDevServerStates } from './dev-server/dev-server-probe.js';
|
|
14
14
|
import { existsSync } from 'node:fs';
|
|
15
15
|
import { homedir } from 'node:os';
|
|
16
|
-
import { join } from 'node:path';
|
|
16
|
+
import { join, resolve } from 'node:path';
|
|
17
|
+
import { callingClientDirectory } from '../../hooks/client-directory.js';
|
|
17
18
|
import { registeredElsewhere } from '../../memory/recall/registered-projects.js';
|
|
18
19
|
import { explainNoSession } from './no-session-diagnosis.js';
|
|
19
|
-
import { detectDevCommandInProject } from './dev-server/dev-command.js';
|
|
20
|
-
import { nextActionFor, renderNextAction } from './no-session-next-action.js';
|
|
20
|
+
import { detectDevCommandInProject, initCommandIn } from './dev-server/dev-command.js';
|
|
21
|
+
import { nextActionFor, portOfUrl, renderNextAction } from './no-session-next-action.js';
|
|
21
22
|
import { DEV_SERVER_PORTS, readProjectFramework, readProjectId, readProjectIsDesktop, readProjectPort, } from '../../command/cli/ports/resolve/cli-port.js';
|
|
22
23
|
import { discoverProjectConfigs } from '../../command/cli/config/config-discovery.js';
|
|
23
24
|
import { hasProjectConnectedBefore, rememberConnected, } from '../../memory/recall/prior/connection-memory.js';
|
|
@@ -49,19 +50,6 @@ function attachFailureClause(port, reason) {
|
|
|
49
50
|
'rather than treating this as a problem with the app.'
|
|
50
51
|
: ''));
|
|
51
52
|
}
|
|
52
|
-
/** The port a tombstone URL names, when it names one — anything unparseable names no port. */
|
|
53
|
-
function portOfUrl(url) {
|
|
54
|
-
try {
|
|
55
|
-
const raw = new URL(url).port;
|
|
56
|
-
if ('' === raw)
|
|
57
|
-
return undefined;
|
|
58
|
-
const port = Number(raw);
|
|
59
|
-
return Number.isSafeInteger(port) && port > 0 ? port : undefined;
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return undefined;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
53
|
/**
|
|
66
54
|
* Start the watch. Returns a stop function; the timer is unref'd so it never holds the daemon up.
|
|
67
55
|
*
|
|
@@ -70,6 +58,8 @@ function portOfUrl(url) {
|
|
|
70
58
|
*/
|
|
71
59
|
export function startNoSessionWatch(options) {
|
|
72
60
|
let listening = [];
|
|
61
|
+
/** Ports the last scan was asked about. A port absent from this set was not observed, so it is not "down". */
|
|
62
|
+
let probed = new Set();
|
|
73
63
|
/**
|
|
74
64
|
* Ports that accepted a connection and then answered nothing in time.
|
|
75
65
|
*
|
|
@@ -159,8 +149,8 @@ export function startNoSessionWatch(options) {
|
|
|
159
149
|
* this one starts, which is precisely the window the agent then spends being told to start a dev
|
|
160
150
|
* server that is already running.
|
|
161
151
|
*/
|
|
162
|
-
const splitBrain = () => {
|
|
163
|
-
const projectId = readProjectId(
|
|
152
|
+
const splitBrain = (dir = directory) => {
|
|
153
|
+
const projectId = readProjectId(dir);
|
|
164
154
|
if (projectId === undefined) {
|
|
165
155
|
return projectlessNote(options.port, projectDaemonsElsewhere(options.port, stateDir, isAlive));
|
|
166
156
|
}
|
|
@@ -211,6 +201,13 @@ export function startNoSessionWatch(options) {
|
|
|
211
201
|
const knownPort = known === undefined ? undefined : portOfUrl(known.url);
|
|
212
202
|
if (knownPort !== undefined)
|
|
213
203
|
ports.add(knownPort);
|
|
204
|
+
// Every departed project, not only the newest. B can still be serving on :3005 after A leaves
|
|
205
|
+
// on :5173, and a scan that never asked :3005 would report B's app as stopped.
|
|
206
|
+
for (const url of options.sessions.tombstoneUrls?.() ?? []) {
|
|
207
|
+
const port = portOfUrl(url);
|
|
208
|
+
if (port !== undefined)
|
|
209
|
+
ports.add(port);
|
|
210
|
+
}
|
|
214
211
|
return [...ports];
|
|
215
212
|
};
|
|
216
213
|
/**
|
|
@@ -255,7 +252,10 @@ export function startNoSessionWatch(options) {
|
|
|
255
252
|
}
|
|
256
253
|
};
|
|
257
254
|
const refresh = () => {
|
|
258
|
-
// Nothing to diagnose while a session is live, and no reason to scan.
|
|
255
|
+
// Nothing to diagnose while a session is live, and no reason to scan. What the last scan saw
|
|
256
|
+
// predates this session, so it is no observation of where the session goes on to depart from.
|
|
257
|
+
if (options.sessions.count() > 0)
|
|
258
|
+
probed = new Set();
|
|
259
259
|
if (running || options.sessions.count() > 0)
|
|
260
260
|
return;
|
|
261
261
|
running = true;
|
|
@@ -267,6 +267,7 @@ export function startNoSessionWatch(options) {
|
|
|
267
267
|
})
|
|
268
268
|
: options.probe(candidates))
|
|
269
269
|
.then(async (ports) => {
|
|
270
|
+
probed = new Set(candidates);
|
|
270
271
|
listening = ports;
|
|
271
272
|
siblingListeners =
|
|
272
273
|
options.occupiedSiblings !== undefined
|
|
@@ -329,6 +330,143 @@ export function startNoSessionWatch(options) {
|
|
|
329
330
|
return undefined;
|
|
330
331
|
return { reason: closure.reason, ...closure.page };
|
|
331
332
|
};
|
|
333
|
+
/**
|
|
334
|
+
* The diagnosis for a client standing in a different project than this daemon.
|
|
335
|
+
*
|
|
336
|
+
* `everConnected` and the newest tombstone are facts about the process. Spent on a second
|
|
337
|
+
* project they say that project's wiring is done and name the first project's URL. A directory
|
|
338
|
+
* that has never had a session of its own has never connected, whatever else this daemon has seen.
|
|
339
|
+
* Ports count only when this project announced them or its own last session was on them, so the
|
|
340
|
+
* reopen command cannot fall through to somebody else's dev server.
|
|
341
|
+
*/
|
|
342
|
+
const diagnosisFor = (dir) => {
|
|
343
|
+
const projectId = readProjectId(dir);
|
|
344
|
+
const initialized = projectId !== undefined;
|
|
345
|
+
// A tab that reported no project cannot be another project's: it is the daemon's own last tab,
|
|
346
|
+
// never "this daemon has never seen one" beside a refusal that names where it last saw it. A
|
|
347
|
+
// tab that named another project stays that project's (a second app is not told to reopen it).
|
|
348
|
+
const newest = options.sessions.lastKnown?.();
|
|
349
|
+
const unclaimed = newest !== undefined && newest.projectId === undefined ? newest : undefined;
|
|
350
|
+
const known = (projectId === undefined ? undefined : options.sessions.lastKnownFor?.(projectId)) ??
|
|
351
|
+
unclaimed;
|
|
352
|
+
const everConnected = (projectId !== undefined && true === options.sessions.everConnectedTo?.(projectId)) ||
|
|
353
|
+
unclaimed !== undefined;
|
|
354
|
+
const ownPorts = new Set(devServersForProject(readDevServers(stateDir), { projectId, root: dir }).map((entry) => entry.port));
|
|
355
|
+
if (known !== undefined) {
|
|
356
|
+
const port = portOfUrl(known.url);
|
|
357
|
+
if (port !== undefined)
|
|
358
|
+
ownPorts.add(port);
|
|
359
|
+
}
|
|
360
|
+
const heard = listening.filter((port) => ownPorts.has(port));
|
|
361
|
+
// Not in the last scan means we have not looked, not that the server stopped. Treating the
|
|
362
|
+
// gap as "down" is what tells a still-running app to start a second one.
|
|
363
|
+
for (const port of ownPorts) {
|
|
364
|
+
if (!probed.has(port) && !heard.includes(port))
|
|
365
|
+
heard.push(port);
|
|
366
|
+
}
|
|
367
|
+
const slow = slowListeners.filter((port) => ownPorts.has(port));
|
|
368
|
+
const closure = options.sessions.lastClosure?.();
|
|
369
|
+
const refusalIsThisProject = closure !== undefined &&
|
|
370
|
+
true !== options.sessions.connectedSinceLastClosure?.() &&
|
|
371
|
+
projectId !== undefined &&
|
|
372
|
+
closure.page?.projectId === projectId;
|
|
373
|
+
const helloRefused = refusalIsThisProject &&
|
|
374
|
+
closure !== undefined &&
|
|
375
|
+
closure.page !== undefined &&
|
|
376
|
+
!isAuthRefusalReason(closure.reason)
|
|
377
|
+
? { reason: closure.reason, ...closure.page }
|
|
378
|
+
: undefined;
|
|
379
|
+
const discovery = initialized ? undefined : discoverProjectConfigs(dir);
|
|
380
|
+
const found = discovery === undefined ? [] : discovery.found.filter((config) => config.directory !== dir);
|
|
381
|
+
const registered = 0 < found.length ? [] : registeredElsewhere(homedir(), dir);
|
|
382
|
+
const configsElsewhere = 0 < found.length
|
|
383
|
+
? found.map((config) => ({
|
|
384
|
+
directory: config.directory,
|
|
385
|
+
...(config.projectId === undefined ? {} : { projectId: config.projectId }),
|
|
386
|
+
}))
|
|
387
|
+
: 0 < registered.length
|
|
388
|
+
? registered.map((project) => ({
|
|
389
|
+
directory: project.directory,
|
|
390
|
+
...(project.projectId === undefined ? {} : { projectId: project.projectId }),
|
|
391
|
+
}))
|
|
392
|
+
: undefined;
|
|
393
|
+
const framework = readProjectFramework(dir);
|
|
394
|
+
const configured = readProjectPort(dir);
|
|
395
|
+
const previouslyConnected = hasProjectConnectedBefore(stateDir, options.port, projectId);
|
|
396
|
+
const authRefused = refusalIsThisProject && closure !== undefined && isAuthRefusalReason(closure.reason);
|
|
397
|
+
const status = known !== undefined && lastKnownStatus !== undefined && lastKnownStatus.url === known.url
|
|
398
|
+
? { lastKnownStatus: lastKnownStatus.status }
|
|
399
|
+
: {};
|
|
400
|
+
const departedTo = known?.departedTo;
|
|
401
|
+
const departed = departedTo === undefined || '' === departedTo ? {} : { departedTo };
|
|
402
|
+
const upMs = stallUptime(Date.now());
|
|
403
|
+
const facts = {
|
|
404
|
+
everConnected,
|
|
405
|
+
initialized,
|
|
406
|
+
...(configsElsewhere === undefined ? {} : { configsElsewhere }),
|
|
407
|
+
...(discovery !== undefined && configsElsewhere === undefined
|
|
408
|
+
? { searchedDirectories: discovery.searched }
|
|
409
|
+
: {}),
|
|
410
|
+
listening: heard,
|
|
411
|
+
slowListeners: slow,
|
|
412
|
+
port: options.port,
|
|
413
|
+
directory: dir,
|
|
414
|
+
previouslyConnected,
|
|
415
|
+
authRefused,
|
|
416
|
+
...(helloRefused === undefined ? {} : { helloRefused }),
|
|
417
|
+
...(framework === undefined ? {} : { framework }),
|
|
418
|
+
...(readProjectIsDesktop(dir) ? { desktop: true } : {}),
|
|
419
|
+
leaseExpired: known !== undefined && (options.wasReapedLease?.(known.id) ?? false),
|
|
420
|
+
...(known === undefined ? {} : { lastKnownUrl: known.url, ...status, ...departed }),
|
|
421
|
+
...(upMs === undefined ? {} : { daemonUpMs: upMs }),
|
|
422
|
+
...(configured === undefined ? {} : { projectPort: configured }),
|
|
423
|
+
...(0 === siblingListeners.length ? {} : { siblingListeners }),
|
|
424
|
+
};
|
|
425
|
+
const split = splitBrain(dir);
|
|
426
|
+
const next = nextActionFor({
|
|
427
|
+
everConnected,
|
|
428
|
+
initialized,
|
|
429
|
+
...(configsElsewhere === undefined ? {} : { configsElsewhere }),
|
|
430
|
+
previouslyConnected,
|
|
431
|
+
exists: (file) => existsSync(join(dir, file)),
|
|
432
|
+
authRefused,
|
|
433
|
+
...(helloRefused === undefined ? {} : { helloRefused: helloRefused.reason }),
|
|
434
|
+
...(split === undefined ? {} : { splitBrain: split }),
|
|
435
|
+
listening: heard,
|
|
436
|
+
slowListeners: slow,
|
|
437
|
+
...(known === undefined
|
|
438
|
+
? {}
|
|
439
|
+
: {
|
|
440
|
+
lastKnownUrl: known.url,
|
|
441
|
+
...(known.departedTo === undefined ? {} : { departedTo: known.departedTo }),
|
|
442
|
+
}),
|
|
443
|
+
dev: detectDevCommandInProject(dir),
|
|
444
|
+
init: initCommandIn(dir),
|
|
445
|
+
});
|
|
446
|
+
return { facts, next };
|
|
447
|
+
};
|
|
448
|
+
/**
|
|
449
|
+
* A call that named the client's project. Undefined means nobody named one (an embed, a test, a
|
|
450
|
+
* daemon answering itself), and the path below stays the one this watch was started with.
|
|
451
|
+
*/
|
|
452
|
+
const callerAnswer = () => {
|
|
453
|
+
const caller = callingClientDirectory();
|
|
454
|
+
if (caller === undefined)
|
|
455
|
+
return undefined;
|
|
456
|
+
return diagnosisFor(caller);
|
|
457
|
+
};
|
|
458
|
+
/**
|
|
459
|
+
* `listening`, plus the departed session's port when no scan has looked at it since: not looked
|
|
460
|
+
* at is not stopped. Without it `reticle status` called a running Vite stopped because the only
|
|
461
|
+
* scan ran before the app was started.
|
|
462
|
+
*/
|
|
463
|
+
const observedListening = () => {
|
|
464
|
+
const known = options.sessions.lastKnown?.();
|
|
465
|
+
const port = known === undefined ? undefined : portOfUrl(known.url);
|
|
466
|
+
return port === undefined || probed.has(port) || listening.includes(port)
|
|
467
|
+
? listening
|
|
468
|
+
: [...listening, port];
|
|
469
|
+
};
|
|
332
470
|
const nextAction = (scope) => {
|
|
333
471
|
const split = splitBrain();
|
|
334
472
|
return nextActionFor({
|
|
@@ -345,7 +483,8 @@ export function startNoSessionWatch(options) {
|
|
|
345
483
|
return refused === undefined ? {} : { helloRefused: refused.reason };
|
|
346
484
|
})(),
|
|
347
485
|
...(split === undefined ? {} : { splitBrain: split }),
|
|
348
|
-
listening,
|
|
486
|
+
listening: observedListening(),
|
|
487
|
+
slowListeners,
|
|
349
488
|
// The url the departed tab was on — the same tombstone the prose diagnosis quotes, so the
|
|
350
489
|
// command and the sentence beside it name the same page.
|
|
351
490
|
...(() => {
|
|
@@ -360,13 +499,21 @@ export function startNoSessionWatch(options) {
|
|
|
360
499
|
// Read when asked, like everything else here: a `package.json` can gain a dev script, and a
|
|
361
500
|
// daemon that cached "there is none" at boot would keep saying so for the rest of the day.
|
|
362
501
|
dev: detectDevCommandInProject(directory),
|
|
502
|
+
// This project's own runner and app folder, so the agent can wire it itself.
|
|
503
|
+
init: initCommandIn(directory),
|
|
363
504
|
});
|
|
364
505
|
};
|
|
365
|
-
options.sessions.setNoSessionNextAction(() =>
|
|
506
|
+
options.sessions.setNoSessionNextAction(() => {
|
|
507
|
+
const caller = callerAnswer();
|
|
508
|
+
return caller === undefined ? nextAction(projectScopeFacts()) : caller.next;
|
|
509
|
+
});
|
|
366
510
|
// ONE call for both registrations below. The prose and the branch code have to come from the
|
|
367
511
|
// same evaluation or they can describe different branches - the facts are read when asked, so two
|
|
368
512
|
// calls a moment apart can genuinely disagree (#615).
|
|
369
513
|
const explain = () => {
|
|
514
|
+
const caller = callerAnswer();
|
|
515
|
+
if (caller !== undefined)
|
|
516
|
+
return explainNoSession(caller.facts);
|
|
370
517
|
const scope = projectScopeFacts();
|
|
371
518
|
return explainNoSession({
|
|
372
519
|
everConnected: options.sessions.everConnected(),
|
|
@@ -377,7 +524,7 @@ export function startNoSessionWatch(options) {
|
|
|
377
524
|
// framework and its projectId, and whose real problem was a dev server older than the plugin.
|
|
378
525
|
// The boot value still counts: it is the one the daemon scoped its sessions with.
|
|
379
526
|
...scope,
|
|
380
|
-
listening,
|
|
527
|
+
listening: observedListening(),
|
|
381
528
|
slowListeners,
|
|
382
529
|
port: options.port,
|
|
383
530
|
// The directory `initialized` was decided in. Named in the message because "there is no
|
|
@@ -450,6 +597,16 @@ export function startNoSessionWatch(options) {
|
|
|
450
597
|
// scope facts so a discovered workspace config cannot become an `init` recommendation below it,
|
|
451
598
|
// and both come from ONE `explain()` call so they cannot describe different branches.
|
|
452
599
|
const rendered = () => {
|
|
600
|
+
const caller = callerAnswer();
|
|
601
|
+
if (caller !== undefined) {
|
|
602
|
+
const { message, detail } = explainNoSession(caller.facts);
|
|
603
|
+
// The attach failure is about the daemon's own project. A call from that project still hears
|
|
604
|
+
// it. A call from another project must not be told that opening this one failed.
|
|
605
|
+
const callerDir = callingClientDirectory();
|
|
606
|
+
const ownProject = callerDir !== undefined && resolve(callerDir) === resolve(directory);
|
|
607
|
+
const lead = `${message} ${renderNextAction(caller.next)}${ownProject ? (attachFailure ?? '') : ''}`;
|
|
608
|
+
return { lead, full: undefined === detail ? lead : `${lead} ${detail}` };
|
|
609
|
+
}
|
|
453
610
|
const scope = projectScopeFacts();
|
|
454
611
|
const { message, detail } = explain();
|
|
455
612
|
const lead = `${message} ${renderNextAction(nextAction(scope))}${attachFailure ?? ''}`;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Any edit here is a per-session tax on every user: say it in as few words as still work.
|
|
10
10
|
*/
|
|
11
|
-
const SESSION_LEASE_NOTICE = 'When you stop driving, call reticle_session {action:"yield", mode:"waiting"|"ask"}. The panel reads "live" until you do. {action:"end"} when the task is done
|
|
11
|
+
const SESSION_LEASE_NOTICE = 'When you stop driving, call reticle_session {action:"yield", mode:"waiting"|"ask"}. The panel reads "live" until you do. {action:"end"} only when the task is done: it is final.';
|
|
12
12
|
export function buildSessionLease(sessionId, openedAt) {
|
|
13
13
|
return { sessionId, opened_at: openedAt, IMPORTANT: SESSION_LEASE_NOTICE };
|
|
14
14
|
}
|