@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
|
@@ -6,20 +6,29 @@
|
|
|
6
6
|
* app, and keeping them together is what stops a drive attached to one app landing in another that
|
|
7
7
|
* happens to be on the same port. See `local-apps.ts` and `remote-drive.ts` for each half.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { isUnmatchedRoot } from '../../memory/project/dir/reticle-dir.js';
|
|
10
|
+
import { readProjectId } from '../../command/cli/ports/resolve/cli-port.js';
|
|
11
|
+
import { basename, dirname, join } from 'node:path';
|
|
10
12
|
import { homedir, hostname } from 'node:os';
|
|
11
|
-
import { LinkCapability, ReticleTool, asRecord } from '@reticlehq/core';
|
|
13
|
+
import { LinkCapability, ReticleDir, ReticleTool, asRecord, } from '@reticlehq/core';
|
|
12
14
|
import { prepareDrive } from '../../features/harness/platform/drive-target.js';
|
|
13
15
|
import { reticleToolset } from './harness-toolset.js';
|
|
14
|
-
import { projectDirFor } from '../../memory/project/session-root.js';
|
|
16
|
+
import { projectDirFor, sessionRoot } from '../../memory/project/session-root.js';
|
|
17
|
+
import { readDashboardUrl } from '../../memory/project/sync-status.js';
|
|
15
18
|
import { driveFrame } from '../../features/visual/visual-tools.js';
|
|
16
19
|
import { LEASE_ACQUIRE_TOOL } from './lease-tools.js';
|
|
17
20
|
import { REMOTE_DRIVE_JPEG_QUALITY, endDrivenTab, pickOwnDriveSession, startRemoteDrives, } from '../../features/harness/platform/remote-drive.js';
|
|
18
|
-
import { appKeyOf, appsByPlatform, machineOf, mayOpen, NOT_AN_APP_ADDRESS, nameFromProjectId, pickAppTab, startAppReports, } from '../../features/harness/platform/local-apps.js';
|
|
21
|
+
import { appKeyOf, appsByPlatform, homeRelative, machineOf, mayOpen, NOT_AN_APP_ADDRESS, nameFromProjectId, pickAppTab, startAppReports, withoutMarks, } from '../../features/harness/platform/local-apps.js';
|
|
19
22
|
import { serverOptionsFromEnv } from '../../features/harness/platform/server-driver.js';
|
|
20
|
-
import { driveForChat } from './explore-tools.js';
|
|
21
|
-
import { withLinkedCredential } from './harness-explore.js';
|
|
23
|
+
import { EXPLORE_TOOLS, driveForChat } from './explore-tools.js';
|
|
24
|
+
import { MSG_NO_HARNESS_KEY, harnessLockRefusal, withLinkedCredential } from './harness-explore.js';
|
|
22
25
|
import { runTool } from './invoke-tool.js';
|
|
26
|
+
import { announcedChannels, probeMarkers, notApplicableOf, recordedGaps, } from '../../portal/session/recorded-gaps.js';
|
|
27
|
+
import { probeDevServers } from '../../portal/session/dev-server/dev-server-probe.js';
|
|
28
|
+
import { DriveOrigin, onDriveChange, onDriveStep, runningDrive, stopDrive, } from '../../features/harness/drive-runs.js';
|
|
29
|
+
import { FreeDriveKind, planUrl, requestFreeDrive, } from '../../features/harness/platform/platform-drives.js';
|
|
30
|
+
import { HumanControlKind } from '@reticlehq/core';
|
|
31
|
+
import { onAgentsChange } from '../../hooks/coding-agents.js';
|
|
23
32
|
/** Why a platform drive with no tab of its own runs no tool. */
|
|
24
33
|
const NO_DRIVEN_TAB = 'No tab was picked for this drive, so no tool runs.';
|
|
25
34
|
/** What this daemon does for the platform's chat. Each one is listed only once it is built. */
|
|
@@ -48,6 +57,31 @@ const nameOf = async (fs, dir, projectId) => {
|
|
|
48
57
|
return nameFromProjectId(projectId);
|
|
49
58
|
return basename(dir) || dir;
|
|
50
59
|
};
|
|
60
|
+
/** How often the localhost dev-server scan may run: never more than this, however often we report. */
|
|
61
|
+
const DEV_SERVER_SCAN_EVERY_MS = 30_000;
|
|
62
|
+
/**
|
|
63
|
+
* Dev servers listening on localhost with no connected Reticle page — an app that is up and not
|
|
64
|
+
* instrumented, or not dialling. The same probe `doctor` and the no-session diagnosis use, cached.
|
|
65
|
+
*/
|
|
66
|
+
function devServerScan(connectedUrls, now) {
|
|
67
|
+
let last;
|
|
68
|
+
return async () => {
|
|
69
|
+
if (last === undefined || now() - last.at >= DEV_SERVER_SCAN_EVERY_MS)
|
|
70
|
+
last = { at: now(), ports: await probeDevServers() };
|
|
71
|
+
const connected = new Set(connectedUrls().map((url) => {
|
|
72
|
+
try {
|
|
73
|
+
return Number(new URL(url).port);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
}));
|
|
79
|
+
return last.ports
|
|
80
|
+
.filter((port) => !connected.has(port))
|
|
81
|
+
.map((port) => ({ url: `http://${LOCALHOST_HOST}:${String(port)}`, port }));
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const LOCALHOST_HOST = 'localhost';
|
|
51
85
|
export function startChatDrives(deps, sessions, fs, cloud, log) {
|
|
52
86
|
const env = process.env;
|
|
53
87
|
const machine = machineOf(hostname(), homedir());
|
|
@@ -69,13 +103,36 @@ export function startChatDrives(deps, sessions, fs, cloud, log) {
|
|
|
69
103
|
if (!mayOpen(url, sessions.list().map((tab) => tab.url)))
|
|
70
104
|
throw new Error(NOT_AN_APP_ADDRESS);
|
|
71
105
|
};
|
|
72
|
-
|
|
106
|
+
/**
|
|
107
|
+
* The `.reticle` each reported app writes into, learned from its tabs. A tab the chat opens for an
|
|
108
|
+
* app is leased into that root: resolved from the page alone, an app with no project id would land
|
|
109
|
+
* in `unmatched/`, which nothing syncs.
|
|
110
|
+
*/
|
|
111
|
+
const rootByApp = new Map();
|
|
112
|
+
/**
|
|
113
|
+
* The root AND the project a tab the daemon opens for an app is stamped with. Stamped with the
|
|
114
|
+
* root alone, a page that reports no project of its own opened as nobody's: its run fell to
|
|
115
|
+
* `unmatched/` and the drive answered a linked project "run reticle connect".
|
|
116
|
+
*/
|
|
117
|
+
const claimFor = (appKey) => (appKey === undefined ? undefined : rootByApp.get(appKey)) ?? {};
|
|
118
|
+
/** Where each credential's project was last open on this machine, from the reports. */
|
|
119
|
+
const lastUrlByKey = new Map();
|
|
120
|
+
/** Lease the app a credential's project was last open at, for a drive no tab of it can take. */
|
|
121
|
+
const reopenFor = async (key) => {
|
|
122
|
+
const last = lastUrlByKey.get(key);
|
|
123
|
+
if (last === undefined)
|
|
124
|
+
return undefined;
|
|
125
|
+
openable(last.url);
|
|
126
|
+
const id = asRecord(await runTool(LEASE_ACQUIRE_TOOL, deps, { ...last }))['sessionId'];
|
|
127
|
+
return 'string' === typeof id ? id : undefined;
|
|
128
|
+
};
|
|
129
|
+
const open = async (url, appKey) => {
|
|
73
130
|
openable(url);
|
|
74
|
-
await runTool(LEASE_ACQUIRE_TOOL, deps, { url });
|
|
131
|
+
await runTool(LEASE_ACQUIRE_TOOL, deps, { url, ...claimFor(appKey) });
|
|
75
132
|
};
|
|
76
133
|
const pick = (goal, key, app) => undefined === app
|
|
77
|
-
? pickOwnDriveSession(sessions.list(), goal, key, sessionKey)
|
|
78
|
-
: pickAppTab(app, goal, () => sessions.list(), appOf, open).then(async (id) =>
|
|
134
|
+
? pickOwnDriveSession(sessions.list(), goal, key, sessionKey, () => reopenFor(key))
|
|
135
|
+
: pickAppTab(app, goal, () => sessions.list(), appOf, (url) => open(url, app.key)).then(async (id) =>
|
|
79
136
|
// The app the platform named must be one this credential's project owns.
|
|
80
137
|
'string' === typeof id && (await sessionKey(id)) !== key ? null : id);
|
|
81
138
|
const drives = startRemoteDrives({
|
|
@@ -91,6 +148,7 @@ export function startChatDrives(deps, sessions, fs, cloud, log) {
|
|
|
91
148
|
url,
|
|
92
149
|
...(headed ? { headed } : {}),
|
|
93
150
|
...(hud === undefined ? {} : { hud }),
|
|
151
|
+
...claimFor(app?.key),
|
|
94
152
|
}));
|
|
95
153
|
const id = lease['sessionId'];
|
|
96
154
|
if ('string' !== typeof id)
|
|
@@ -110,9 +168,9 @@ export function startChatDrives(deps, sessions, fs, cloud, log) {
|
|
|
110
168
|
const tools = reticleToolset(deps, { sessionId, locked: true });
|
|
111
169
|
return { tools: tools.tools, invoke: (tool, args) => tools.invoke(tool, args) };
|
|
112
170
|
},
|
|
113
|
-
drive: async (goal, sessionId) => {
|
|
171
|
+
drive: async (goal, sessionId, spec) => {
|
|
114
172
|
const url = sessions.list().find((tab) => tab.sessionId === sessionId)?.url;
|
|
115
|
-
const outcome = await driveForChat(deps, goal, sessionId);
|
|
173
|
+
const outcome = await driveForChat(deps, goal, sessionId, spec?.plan, spec?.confirmDangerous);
|
|
116
174
|
return url === undefined ? outcome : { ...outcome, url };
|
|
117
175
|
},
|
|
118
176
|
// The leased tab, or a desktop window's own capture. A web tab only the SDK reaches has no camera.
|
|
@@ -122,22 +180,80 @@ export function startChatDrives(deps, sessions, fs, cloud, log) {
|
|
|
122
180
|
settle: (id, outcome) => endDrivenTab(id === undefined ? undefined : sessions.get(id), outcome),
|
|
123
181
|
log,
|
|
124
182
|
});
|
|
183
|
+
const scanDevServers = devServerScan(() => sessions.list().map((tab) => tab.url), () => Date.now());
|
|
125
184
|
const reports = startAppReports({
|
|
126
185
|
machine,
|
|
127
186
|
version: cloud.version,
|
|
128
187
|
capabilities: CHAT_CAPABILITIES,
|
|
129
|
-
apps: async () =>
|
|
130
|
-
|
|
131
|
-
|
|
188
|
+
apps: async () => {
|
|
189
|
+
// The setup score the dashboard shows is what the app's pages carry, asked of each page
|
|
190
|
+
// until its app has shown both markers: never only what an act happened to reach.
|
|
191
|
+
await probeMarkers(sessions.list().flatMap((tab) => {
|
|
192
|
+
const live = sessions.get(tab.sessionId);
|
|
193
|
+
const command = live?.command?.bind(live);
|
|
194
|
+
return command === undefined
|
|
195
|
+
? []
|
|
196
|
+
: [{ id: tab.sessionId, url: tab.url, projectId: tab.projectId, command }];
|
|
197
|
+
}));
|
|
198
|
+
return appsByPlatform(sessions.list().map((tab) => {
|
|
199
|
+
const live = sessions.get(tab.sessionId);
|
|
200
|
+
const sdkVersion = live?.sdkVersion;
|
|
201
|
+
// What the page announced plus the gaps its verdicts paid for: what the dashboard's
|
|
202
|
+
// coverage line and coding-agent prompt are built from.
|
|
203
|
+
const channels = announcedChannels({
|
|
204
|
+
id: tab.sessionId,
|
|
205
|
+
url: tab.url,
|
|
206
|
+
projectId: tab.projectId,
|
|
207
|
+
channels: live?.channels,
|
|
208
|
+
sourceMapping: live?.sourceMapping,
|
|
209
|
+
});
|
|
210
|
+
const gaps = recordedGaps(tab.sessionId).map(({ kind, missing, fix, seenAt }) => ({
|
|
211
|
+
kind,
|
|
212
|
+
missing,
|
|
213
|
+
fix,
|
|
214
|
+
seenAt,
|
|
215
|
+
}));
|
|
216
|
+
return {
|
|
217
|
+
...tab,
|
|
218
|
+
...(sdkVersion === undefined ? {} : { sdkVersion }),
|
|
219
|
+
...(0 === channels.length ? {} : { channels }),
|
|
220
|
+
gaps,
|
|
221
|
+
notApplicable: notApplicableOf({
|
|
222
|
+
id: tab.sessionId,
|
|
223
|
+
url: tab.url,
|
|
224
|
+
projectId: tab.projectId,
|
|
225
|
+
}),
|
|
226
|
+
};
|
|
227
|
+
}), serverOptionsFromEnv(await withLinkedCredential(deps, env)), machine.id, async (tab) => {
|
|
228
|
+
const root = sessionRoot(deps, tab.sessionId);
|
|
229
|
+
const dir = dirname(root);
|
|
230
|
+
const projectId = tab.projectId ?? readProjectId(dir);
|
|
231
|
+
const stamp = { root, ...(projectId === undefined ? {} : { projectId }) };
|
|
232
|
+
rootByApp.set(appKeyOf(machine.id, dir, tab.projectId), stamp);
|
|
233
|
+
const platform = await sessionCloud(tab.sessionId);
|
|
234
|
+
if (undefined !== platform)
|
|
235
|
+
lastUrlByKey.set(platform.apiKey, { url: withoutMarks(tab.url), ...stamp });
|
|
236
|
+
return {
|
|
237
|
+
dir,
|
|
238
|
+
name: await nameOf(fs, dir, tab.projectId),
|
|
239
|
+
...(undefined === platform
|
|
240
|
+
? {}
|
|
241
|
+
: { platform: { url: platform.url.replace(/\/+$/, ''), apiKey: platform.apiKey } }),
|
|
242
|
+
};
|
|
243
|
+
});
|
|
244
|
+
},
|
|
245
|
+
open,
|
|
246
|
+
extras: async () => {
|
|
247
|
+
const closure = sessions.lastClosure?.();
|
|
248
|
+
const unsynced = cloud.unsynced?.();
|
|
132
249
|
return {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
...(undefined === platform
|
|
250
|
+
devServers: await scanDevServers(),
|
|
251
|
+
...(closure === undefined
|
|
136
252
|
? {}
|
|
137
|
-
: {
|
|
253
|
+
: { helloFailure: { reason: closure.reason, at: closure.at } }),
|
|
254
|
+
...unsyncedReport(unsynced, homedir()),
|
|
138
255
|
};
|
|
139
|
-
}
|
|
140
|
-
open,
|
|
256
|
+
},
|
|
141
257
|
drivePending: (platform) => void drives.tick(platform),
|
|
142
258
|
// What the platform wants the person told: in the daemon's log, and on the HUD of each open tab
|
|
143
259
|
// of that project, so somebody who never reads the log still sees "update Reticle".
|
|
@@ -163,3 +279,131 @@ export function startChatDrives(deps, sessions, fs, cloud, log) {
|
|
|
163
279
|
},
|
|
164
280
|
};
|
|
165
281
|
}
|
|
282
|
+
/** The dashboard the tab's project is linked to, when its link names one. */
|
|
283
|
+
function dashboardOf(deps, sessionId) {
|
|
284
|
+
try {
|
|
285
|
+
return readDashboardUrl(sessionRoot(deps, sessionId));
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/** Said on the HUD when Link this project ends. */
|
|
292
|
+
const MSG_LINKED = 'Linked. This project now reports to your dashboard.';
|
|
293
|
+
const MSG_LINK_FAILED = 'Could not link this project. Run `reticle connect` in its folder.';
|
|
294
|
+
/** A page with no projectId: linking it would bind a hash-named project nothing here reads. */
|
|
295
|
+
const MSG_LINK_NEEDS_PROJECT = 'This page did not say which project it is, so there is nothing to link yet. Run `npx @reticlehq/server init` in your app (or pass `projectId` to `connect()`), then Link.';
|
|
296
|
+
const MSG_LINK_UNAVAILABLE = 'This Reticle cannot link from the panel. Run `reticle connect` in the project folder.';
|
|
297
|
+
/** Said on the HUD when Stop finds nothing to stop. */
|
|
298
|
+
const MSG_NOTHING_DRIVING = 'No Harness drive is running in this tab.';
|
|
299
|
+
const msgStartTrial = (url) => `Start your trial: ${url}`;
|
|
300
|
+
/**
|
|
301
|
+
* The panel's Harness controls. The switch is the platform's autonomous mode, unchanged. Run Harness
|
|
302
|
+
* and Stop drive. A run asks the platform for the drive's grant, then starts it
|
|
303
|
+
* through the same explore an agent calls (counted, recorded, polled the same way); its lines and
|
|
304
|
+
* steps reach the HUD log as the drive narrates them. A refused grant says why, and where to start
|
|
305
|
+
* a trial when it wants a card.
|
|
306
|
+
*/
|
|
307
|
+
export async function hudDrive(deps, sessionId,
|
|
308
|
+
/** The panel's control, as the bridge narrowed it (`harness-request.ts`). */
|
|
309
|
+
request,
|
|
310
|
+
/** The autonomous switch: written through to the platform, which the daemon owns. */
|
|
311
|
+
applySwitch, grant = (platform) => requestFreeDrive(platform, FreeDriveKind.EXPLORE)) {
|
|
312
|
+
if (HumanControlKind.HARNESS === request.kind)
|
|
313
|
+
return applySwitch(request.enabled);
|
|
314
|
+
// What the panel's Run and Stop answer belongs in the Harness log, and in the Agent Log as a summary.
|
|
315
|
+
const say = (text) => deps.sessions.get?.(sessionId)?.pushNarration(text, true, { harness: true, summary: true });
|
|
316
|
+
if (HumanControlKind.HARNESS_STOP === request.kind) {
|
|
317
|
+
const running = runningDrive(sessionId);
|
|
318
|
+
if (running === undefined || !stopDrive(running.harnessRun))
|
|
319
|
+
say(MSG_NOTHING_DRIVING);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
// Before the grant: a drive the gate refuses must not take one. The panel shows the prompt.
|
|
323
|
+
const env = await withLinkedCredential(deps, process.env, { sessionId });
|
|
324
|
+
const locked = await harnessLockRefusal(deps, sessionId, env);
|
|
325
|
+
if (locked !== undefined)
|
|
326
|
+
return say(locked.split('\n')[0] ?? locked);
|
|
327
|
+
const platform = serverOptionsFromEnv(env);
|
|
328
|
+
if (platform === undefined)
|
|
329
|
+
return say(MSG_NO_HARNESS_KEY);
|
|
330
|
+
const granted = await grant(platform);
|
|
331
|
+
if (!granted.granted) {
|
|
332
|
+
say(granted.message);
|
|
333
|
+
// At the console's origin (the tab's link names it), never the API's, which 404s when split.
|
|
334
|
+
if (granted.needsCard)
|
|
335
|
+
say(msgStartTrial(planUrl(dashboardOf(deps, sessionId) ?? platform.url)));
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const explore = EXPLORE_TOOLS.find((tool) => ReticleTool.VERIFY_EXPLORE === tool.name);
|
|
339
|
+
if (explore === undefined)
|
|
340
|
+
return;
|
|
341
|
+
try {
|
|
342
|
+
await runTool(explore, deps, {
|
|
343
|
+
sessionId,
|
|
344
|
+
driveId: granted.driveId,
|
|
345
|
+
origin: DriveOrigin.HUD,
|
|
346
|
+
wait: 0,
|
|
347
|
+
...(request.persona === undefined ? {} : { persona: request.persona }),
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
say(error instanceof Error ? error.message : String(error));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* The link a panel sign-in makes once it lands: the tab's project, never a page that did not say
|
|
356
|
+
* which project it is (that would bind a hash-named project nothing here reads).
|
|
357
|
+
*/
|
|
358
|
+
export function projectLinkOnly(link) {
|
|
359
|
+
return link === undefined
|
|
360
|
+
? undefined
|
|
361
|
+
: (root) => (isUnmatchedRoot(root) ? Promise.resolve(0) : link(root));
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* The panel's Harness controls on a bridge: the switch writes through to the platform, so console
|
|
365
|
+
* and panel cannot disagree; Run and Stop drive, in the project of the tab that asked.
|
|
366
|
+
*/
|
|
367
|
+
export function attachHudHarness(bridge, daemon, applySwitch,
|
|
368
|
+
/** Link this project: what `reticle connect` does from that folder. Absent: the button says so. */
|
|
369
|
+
link) {
|
|
370
|
+
bridge.attachHarnessRequest((request, s) => {
|
|
371
|
+
const root = s.artifactRoot ?? daemon.root;
|
|
372
|
+
if (HumanControlKind.HARNESS_LINK === request.kind) {
|
|
373
|
+
const say = (text) => daemon.deps().sessions.get?.(s.id)?.pushNarration(text);
|
|
374
|
+
if (link === undefined)
|
|
375
|
+
return say(MSG_LINK_UNAVAILABLE);
|
|
376
|
+
if (isUnmatchedRoot(root))
|
|
377
|
+
return say(MSG_LINK_NEEDS_PROJECT);
|
|
378
|
+
void link(root)
|
|
379
|
+
.then((code) => say(0 === code ? MSG_LINKED : MSG_LINK_FAILED))
|
|
380
|
+
.catch(() => say(MSG_LINK_FAILED))
|
|
381
|
+
.finally(daemon.repaint);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
void hudDrive(daemon.deps(), s.id, request, (on) => applySwitch(root, on));
|
|
385
|
+
});
|
|
386
|
+
onDriveChange(daemon.repaint);
|
|
387
|
+
// Each step too, so the panel's "N steps so far" counts up instead of sitting at zero.
|
|
388
|
+
onDriveStep(daemon.repaint);
|
|
389
|
+
// And "Connected: Claude Code" follows an agent attaching or leaving.
|
|
390
|
+
onAgentsChange(daemon.repaint);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* The `unsynced` field of a report. Sent empty too, once this daemon has counted: the platform reads
|
|
394
|
+
* an absent list as "no news" and kept a "never sent" banner for runs that had long been sent.
|
|
395
|
+
*/
|
|
396
|
+
export function unsyncedReport(unsynced, home) {
|
|
397
|
+
if (unsynced === undefined)
|
|
398
|
+
return {};
|
|
399
|
+
return {
|
|
400
|
+
// A folder no project claimed cannot be connected, so no board should tell anyone to.
|
|
401
|
+
unsynced: unsynced
|
|
402
|
+
.filter((u) => !isUnmatchedRoot(u.root))
|
|
403
|
+
.map((u) => ({
|
|
404
|
+
...u,
|
|
405
|
+
// The project, not its `.reticle`: the dashboard tells the person to run a command there.
|
|
406
|
+
root: homeRelative(ReticleDir.ROOT === basename(u.root) ? dirname(u.root) : u.root, home),
|
|
407
|
+
})),
|
|
408
|
+
};
|
|
409
|
+
}
|
|
@@ -5,14 +5,6 @@ interface Control {
|
|
|
5
5
|
}
|
|
6
6
|
/** Parse the interactive snapshot into {ref,label} controls, preserving document order. */
|
|
7
7
|
export declare function parseControls(tree: string): Control[];
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
* The table arrives as a thunk rather than an import: `tools.ts` assembles it FROM this module, so
|
|
12
|
-
* importing it back would close a cycle whose failure mode is a load-order-dependent crash rather
|
|
13
|
-
* than an error anyone sees while writing it. The thunk is called inside the handler, long after the
|
|
14
|
-
* table exists. It carries the merged names — the ones `reticle_run` will actually accept — because
|
|
15
|
-
* a tool that merged into a parent is not something an agent can call or a maintainer can cut.
|
|
16
|
-
*/
|
|
17
|
-
export declare function buildCoverageTools(toolNames: () => readonly string[]): ToolDef[];
|
|
8
|
+
/** Build the coverage tool. */
|
|
9
|
+
export declare function buildCoverageTools(): ToolDef[];
|
|
18
10
|
export {};
|
|
@@ -2,9 +2,6 @@ import { z } from 'zod';
|
|
|
2
2
|
import { sessionRoot } from '../../memory/project/session-root.js';
|
|
3
3
|
import { projectForRoot } from '../../memory/project/project-for-root.js';
|
|
4
4
|
import { coverageRegressed, observabilityOf } from '@reticlehq/engine/evidence/observability.js';
|
|
5
|
-
import { foldFeatureCapture } from './feature-capture.js';
|
|
6
|
-
import { foldToolHitRate } from './tool-hit-rate.js';
|
|
7
|
-
import { allSessionIntents } from '../../memory/intent/open-intents.js';
|
|
8
5
|
import { ReticleCommand, SnapshotMode } from '@reticlehq/core';
|
|
9
6
|
import { ReticleTool } from '@reticlehq/core';
|
|
10
7
|
import { asString } from '@reticlehq/core';
|
|
@@ -55,16 +52,8 @@ export function parseControls(tree) {
|
|
|
55
52
|
}
|
|
56
53
|
return controls;
|
|
57
54
|
}
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
*
|
|
61
|
-
* The table arrives as a thunk rather than an import: `tools.ts` assembles it FROM this module, so
|
|
62
|
-
* importing it back would close a cycle whose failure mode is a load-order-dependent crash rather
|
|
63
|
-
* than an error anyone sees while writing it. The thunk is called inside the handler, long after the
|
|
64
|
-
* table exists. It carries the merged names — the ones `reticle_run` will actually accept — because
|
|
65
|
-
* a tool that merged into a parent is not something an agent can call or a maintainer can cut.
|
|
66
|
-
*/
|
|
67
|
-
export function buildCoverageTools(toolNames) {
|
|
55
|
+
/** Build the coverage tool. */
|
|
56
|
+
export function buildCoverageTools() {
|
|
68
57
|
return [
|
|
69
58
|
{
|
|
70
59
|
name: ReticleTool.COVERAGE,
|
|
@@ -100,25 +89,6 @@ export function buildCoverageTools(toolNames) {
|
|
|
100
89
|
.object({ driven: z.number(), observable: z.number(), percent: z.number().optional() })
|
|
101
90
|
.optional()
|
|
102
91
|
.describe('Of the controls you DROVE, how many Reticle could fully observe. `untouched` above is work left for you; this is work left in the APP, and driving more controls does not move it. `percent` is OMITTED when nothing was driven, because 0/0 is not 100%.'),
|
|
103
|
-
featureUse: z
|
|
104
|
-
.object({
|
|
105
|
-
observed: z.boolean(),
|
|
106
|
-
truncated: z.boolean().optional(),
|
|
107
|
-
context: z.unknown().optional(),
|
|
108
|
-
intents: z.unknown().optional(),
|
|
109
|
-
missed: z.unknown().optional(),
|
|
110
|
-
})
|
|
111
|
-
.optional()
|
|
112
|
-
.describe('Whether this session used `reticle_context` and `reticle_intent` at all, and what it cost when it did not: `context` counts the calls and what followed each one, `intents` the ledger, `missed` the verdicts drawn against an empty ledger and the reads that re-fetched a fact already established. `observed:false` means nothing was recorded for this session — NOT that nothing was used. An instrument for deciding whether those two features earn their place; nothing here is a fault of yours.'),
|
|
113
|
-
toolHitRate: z
|
|
114
|
-
.object({
|
|
115
|
-
observed: z.boolean(),
|
|
116
|
-
cells: z.unknown().optional(),
|
|
117
|
-
called: z.unknown().optional(),
|
|
118
|
-
neverCalled: z.unknown().optional(),
|
|
119
|
-
})
|
|
120
|
-
.optional()
|
|
121
|
-
.describe('Which Reticle tools THIS session called, and how reachable each one was: `called` lists every tool with its call count, `neverCalled` the rest of the table, and both carry a `tier` — `default` (advertised to every agent), `extended` (advertised only on the full surface) or `run-only` (reachable solely by naming it to reticle_run). `cells` counts each tier on both sides. `observed:false` means nothing was recorded for this session, NOT that nothing was called. THREE LIMITS, all load-bearing: this is ONE session, so it is evidence about this run and is not a hit rate — a hit rate is a distribution over many sessions. A never-called tool is not a useless tool; one used once a month in an emergency looks identical here to one nobody has ever called, so frequency alone cannot decide a cut. And the counts describe how this run went, never how it should have gone — nothing here is a fault of yours.'),
|
|
122
92
|
observabilityRegressed: z
|
|
123
93
|
.object({ was: z.number(), now: z.number() })
|
|
124
94
|
.optional()
|
|
@@ -143,25 +113,6 @@ export function buildCoverageTools(toolNames) {
|
|
|
143
113
|
// first without the second is how an agent finishes a pass believing it verified something the
|
|
144
114
|
// app was never able to confirm.
|
|
145
115
|
const gaps = session.gaps?.open() ?? [];
|
|
146
|
-
// Folded here rather than given a tool of its own: this is already the "am I done, and what is
|
|
147
|
-
// this verdict worth" read, and a number nobody has a reason to ask for separately is one
|
|
148
|
-
// nobody ever sees. It is a fold over the journal and the intent ledger plus the one thing
|
|
149
|
-
// neither records — see surface/tools/feature-capture.ts.
|
|
150
|
-
const featureUse = foldFeatureCapture({
|
|
151
|
-
calls: session.capture.calls(),
|
|
152
|
-
dropped: session.capture.dropped,
|
|
153
|
-
actions: await session.readJournalActions(),
|
|
154
|
-
intents: await allSessionIntents(deps, sessionId),
|
|
155
|
-
finalActions: session.actionCount,
|
|
156
|
-
});
|
|
157
|
-
// Same fold, same reason, one level out: which of the whole tool table this session reached
|
|
158
|
-
// for, crossed with how reachable each name was. See surface/tools/tool-hit-rate.ts for what it can
|
|
159
|
-
// and cannot establish — the limits matter more than usual, because this is the number a
|
|
160
|
-
// decision to DELETE tools would be made on.
|
|
161
|
-
const toolHitRate = foldToolHitRate({
|
|
162
|
-
calls: session.capture?.toolCalls(),
|
|
163
|
-
allTools: toolNames(),
|
|
164
|
-
});
|
|
165
116
|
// The number, and the floor under it, together. A coverage figure that can only ever be
|
|
166
117
|
// reported and never contradicted is one an agent learns to satisfy rather than to earn.
|
|
167
118
|
const observability = observabilityOf(session.actedRefs(), gaps);
|
|
@@ -179,8 +130,6 @@ export function buildCoverageTools(toolNames) {
|
|
|
179
130
|
...(gaps.length > 0 ? { instrumentationGaps: gaps, unproven: true } : {}),
|
|
180
131
|
observability,
|
|
181
132
|
...(regressed === undefined ? {} : { observabilityRegressed: regressed }),
|
|
182
|
-
featureUse,
|
|
183
|
-
toolHitRate,
|
|
184
133
|
...(true === args['app']
|
|
185
134
|
? {
|
|
186
135
|
app: await foldAppCoverage({
|
|
@@ -8,13 +8,41 @@ import { ReticleTool } from '@reticlehq/core';
|
|
|
8
8
|
import { ADVERTISE_ALL_ENV } from './tool-surface.js';
|
|
9
9
|
import { getSessionMetrics } from '../../telemetry/session-metrics.js';
|
|
10
10
|
import { isPredicateParam, predicateGrammar, } from '@reticlehq/engine/question/predicate/predicate-eval.js';
|
|
11
|
+
/**
|
|
12
|
+
* A numeric parameter's enforced bounds, read off the schema that enforces them (#1537).
|
|
13
|
+
*
|
|
14
|
+
* The descriptions name a default and rarely a ceiling, so `timeout_ms: 60000` on act_and_wait was
|
|
15
|
+
* refused and the agent learned the 55000 cap from the error. Read here rather than written into
|
|
16
|
+
* prose, so the number shown is the number checked and cannot drift from it.
|
|
17
|
+
*/
|
|
18
|
+
function boundsOf(schema) {
|
|
19
|
+
let inner = schema;
|
|
20
|
+
for (;;) {
|
|
21
|
+
if (inner instanceof z.ZodOptional || inner instanceof z.ZodNullable) {
|
|
22
|
+
inner = inner.unwrap();
|
|
23
|
+
}
|
|
24
|
+
else if (inner instanceof z.ZodDefault) {
|
|
25
|
+
inner = inner.removeDefault();
|
|
26
|
+
}
|
|
27
|
+
else if (inner instanceof z.ZodEffects) {
|
|
28
|
+
inner = inner.innerType();
|
|
29
|
+
}
|
|
30
|
+
else
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
if (!(inner instanceof z.ZodNumber))
|
|
34
|
+
return {};
|
|
35
|
+
const { minValue: min, maxValue: max } = inner;
|
|
36
|
+
return { ...(null === min ? {} : { min }), ...(null === max ? {} : { max }) };
|
|
37
|
+
}
|
|
11
38
|
/** Compact param list from a tool's zod shape — name/required/description (the description already
|
|
12
|
-
* carries the type and any enum hints, so no JSON-Schema machinery is needed). */
|
|
39
|
+
* carries the type and any enum hints, so no JSON-Schema machinery is needed), plus numeric bounds. */
|
|
13
40
|
function paramInfo(shape) {
|
|
14
41
|
return Object.entries(shape).map(([name, schema]) => ({
|
|
15
42
|
name,
|
|
16
43
|
required: !schema.isOptional(),
|
|
17
44
|
description: schema.description ?? '',
|
|
45
|
+
...boundsOf(schema),
|
|
18
46
|
}));
|
|
19
47
|
}
|
|
20
48
|
/**
|
|
@@ -38,4 +38,14 @@ export declare const EMPTY_SESSION_LIST_OUTPUT: {
|
|
|
38
38
|
url: string;
|
|
39
39
|
}>>;
|
|
40
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Wire the calling project when another project's tab is the one currently connected.
|
|
43
|
+
*
|
|
44
|
+
* The list handler only used to reach {@link emptySessionList} when the daemon's whole list was
|
|
45
|
+
* empty. A live tab in project A then answered project B's first call with A's sessions, and B
|
|
46
|
+
* was never wired.
|
|
47
|
+
*/
|
|
48
|
+
export declare function wireCallerBesideLiveSessions(deps: ToolDeps, sessions: readonly {
|
|
49
|
+
projectId?: string;
|
|
50
|
+
}[]): Promise<unknown>;
|
|
41
51
|
export declare function emptySessionList(deps: ToolDeps, sessions: unknown[]): Promise<Record<string, unknown>>;
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
import { dirname } from 'node:path';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { DiscoveryInvite, NoSessionAction } from '@reticlehq/core';
|
|
12
|
+
import { readProjectId } from '../../command/cli/ports/resolve/cli-port.js';
|
|
13
|
+
import { callingClientDirectory } from '../../hooks/client-directory.js';
|
|
12
14
|
/** The answers that mean "this app is not set up yet", which a first run can settle by wiring it. */
|
|
13
15
|
const FIRST_RUN_ACTIONS = new Set([
|
|
14
16
|
NoSessionAction.RUN_INIT,
|
|
@@ -46,18 +48,56 @@ export const EMPTY_SESSION_LIST_OUTPUT = {
|
|
|
46
48
|
.optional()
|
|
47
49
|
.describe('Present ONLY when `sessions` is empty AND a tab was connected to this daemon earlier: the last sessionId and URL that tab was on when it disappeared. A route that 500s tears the page down and the SDK never reconnects — this is the last thing we knew, not a route-500 verdict. An empty list with no lastKnown is a tab that never arrived.'),
|
|
48
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Wire the calling project when another project's tab is the one currently connected.
|
|
53
|
+
*
|
|
54
|
+
* The list handler only used to reach {@link emptySessionList} when the daemon's whole list was
|
|
55
|
+
* empty. A live tab in project A then answered project B's first call with A's sessions, and B
|
|
56
|
+
* was never wired.
|
|
57
|
+
*/
|
|
58
|
+
export async function wireCallerBesideLiveSessions(deps, sessions) {
|
|
59
|
+
const dir = callingClientDirectory();
|
|
60
|
+
if (dir === undefined)
|
|
61
|
+
return undefined;
|
|
62
|
+
const projectId = readProjectId(dir);
|
|
63
|
+
if (projectId !== undefined && sessions.some((session) => session.projectId === projectId)) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const next = deps.sessions.noSessionNextAction();
|
|
67
|
+
const target = next !== undefined && FIRST_RUN_ACTIONS.has(next.action)
|
|
68
|
+
? deps.firstRun?.projectDirectory(dir)
|
|
69
|
+
: undefined;
|
|
70
|
+
if (target === undefined || deps.firstRun === undefined)
|
|
71
|
+
return undefined;
|
|
72
|
+
return deps.firstRun.wire(target);
|
|
73
|
+
}
|
|
74
|
+
/** The departed tab for this call: the caller's own project when it named one, else the daemon's newest. */
|
|
75
|
+
function departedForCaller(deps) {
|
|
76
|
+
const dir = callingClientDirectory();
|
|
77
|
+
if (dir === undefined)
|
|
78
|
+
return deps.sessions.lastKnown?.();
|
|
79
|
+
const projectId = readProjectId(dir);
|
|
80
|
+
if (projectId === undefined)
|
|
81
|
+
return undefined;
|
|
82
|
+
return deps.sessions.lastKnownFor?.(projectId);
|
|
83
|
+
}
|
|
49
84
|
export async function emptySessionList(deps, sessions) {
|
|
50
|
-
|
|
85
|
+
// The lead and its next action: the full differential (~3 KB of ranked causes) read as
|
|
86
|
+
// speculation on the call an agent makes first. Optional-call: test stubs predate the lead.
|
|
87
|
+
const why = deps.sessions.noSessionLead?.() ?? deps.sessions.noSessionHint();
|
|
51
88
|
// The executable half. `why` is for the human reading the transcript; this is the one the
|
|
52
89
|
// agent acts on, so it never has to parse a paragraph to find a command inside it.
|
|
53
90
|
const next = deps.sessions.noSessionNextAction();
|
|
54
|
-
// The first run wires the app, not the
|
|
55
|
-
//
|
|
91
|
+
// The first run wires the app the client is in, not the directory the daemon was started in.
|
|
92
|
+
// One daemon serves every project; the proxy names its cwd on the call. With no caller (an
|
|
93
|
+
// embed, a test) it is still the daemon's own project. A daemon outside any project asks instead.
|
|
94
|
+
// ponytail: cwd, not an MCP roots/list round trip. A proxy started outside the project still
|
|
95
|
+
// answers run_init; roots are the upgrade when a client launches there but names the project.
|
|
56
96
|
// Not only on `run_init`: an unwired app whose dev server is not running yet answers
|
|
57
97
|
// `start_dev_server`, which is the commonest first run of all, and init starts that server itself.
|
|
58
98
|
// `projectDirectory` refuses a project that is already wired, so a wired app is never re-run.
|
|
59
99
|
const dir = next !== undefined && FIRST_RUN_ACTIONS.has(next.action)
|
|
60
|
-
? deps.firstRun?.projectDirectory(dirname(deps.reticleRoot))
|
|
100
|
+
? deps.firstRun?.projectDirectory(callingClientDirectory() ?? dirname(deps.reticleRoot))
|
|
61
101
|
: undefined;
|
|
62
102
|
if (dir !== undefined && deps.firstRun !== undefined) {
|
|
63
103
|
const wired = await deps.firstRun.wire(dir);
|
|
@@ -67,7 +107,7 @@ export async function emptySessionList(deps, sessions) {
|
|
|
67
107
|
return { sessions, wired, ...(why === undefined ? {} : { why }) };
|
|
68
108
|
}
|
|
69
109
|
// The last tab, when one was here. Optional-call: test stubs of SessionManager predate it.
|
|
70
|
-
const known = deps
|
|
110
|
+
const known = departedForCaller(deps);
|
|
71
111
|
const lastKnown = undefined === known ? undefined : { sessionId: known.id, url: known.url };
|
|
72
112
|
return {
|
|
73
113
|
sessions,
|
|
@@ -18,6 +18,7 @@ export declare const RECOVERY: {
|
|
|
18
18
|
readonly MISSING_BASELINE: string;
|
|
19
19
|
readonly MISSING_RECORDING: string;
|
|
20
20
|
readonly STALE_REF: string;
|
|
21
|
+
readonly UNISSUED_REF: string;
|
|
21
22
|
readonly STALE_REF_AFTER_EDIT: string;
|
|
22
23
|
readonly INVALID_NAME: string;
|
|
23
24
|
/**
|
|
@@ -78,6 +79,13 @@ export declare const RECOVERY: {
|
|
|
78
79
|
* who deliberately switched the harness off gets a bug report filed about their own decision.
|
|
79
80
|
*/
|
|
80
81
|
readonly HARNESS_OFF: string;
|
|
82
|
+
/**
|
|
83
|
+
* The Harness asked for on a project that is not linked to the platform. The call was valid, and
|
|
84
|
+
* the refusal names reticle_act_and_wait as the alternative, which the catch-all below read as an
|
|
85
|
+
* agent's malformed call: it was then told to fix arguments that were never wrong.
|
|
86
|
+
*/
|
|
87
|
+
readonly HARNESS_LOCKED: string;
|
|
88
|
+
readonly HARNESS_NOT_LINKED: string;
|
|
81
89
|
};
|
|
82
90
|
/**
|
|
83
91
|
* The actionable next move for a known error message, or undefined when none is recognized.
|