@reticlehq/server 3.5.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/README.md +1 -1
- package/SKILL.md +123 -116
- package/dist/chromium-launch-options.d.ts +3 -1
- package/dist/chromium-launch-options.js +2 -1
- 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 +19 -2
- package/dist/command/cli/adhoc-verdict.js +76 -9
- 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/answers/open-note.d.ts +2 -0
- package/dist/command/cli/answers/open-note.js +22 -0
- 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 +31 -112
- 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 +35 -5
- package/dist/command/cli/cli-verify.js +114 -35
- package/dist/command/cli/cloud-cli.d.ts +13 -0
- package/dist/command/cli/cloud-cli.js +192 -341
- 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 +22 -0
- package/dist/command/cli/cloud-login.js +96 -8
- 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/browser/chromium-hint.d.ts +46 -0
- package/dist/command/cli/doctor/browser/chromium-hint.js +99 -1
- 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/drive/drive-attach.d.ts +27 -2
- package/dist/command/cli/drive/drive-attach.js +71 -4
- package/dist/command/cli/drive/drive-command.d.ts +2 -1
- package/dist/command/cli/drive/drive-command.js +13 -7
- 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 +15 -3
- 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.d.ts +10 -0
- package/dist/command/cli/ports/port-holder.js +25 -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 +35 -12
- 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 -181
- 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 +20 -0
- package/dist/command/cli.js +130 -104
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
- package/dist/command/daemon/binding/daemon-status-probe.js +1 -0
- package/dist/command/daemon/daemon-resilience.js +4 -4
- package/dist/command/daemon/daemon-resolve.d.ts +23 -1
- package/dist/command/daemon/daemon-resolve.js +79 -9
- package/dist/command/setup/agent-writer.d.ts +1 -1
- package/dist/command/setup/agent-writer.js +3 -2
- 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/connect-lease.d.ts +1 -0
- package/dist/command/setup/bringup/connect-lease.js +1 -0
- package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
- package/dist/command/setup/bringup/dev-server-wait.d.ts +8 -0
- package/dist/command/setup/bringup/dev-server-wait.js +19 -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 +14 -1
- package/dist/command/setup/init/init-port.js +32 -2
- package/dist/command/setup/init/init-runtime.d.ts +22 -2
- package/dist/command/setup/init/init-runtime.js +114 -38
- package/dist/command/setup/node-effects.d.ts +2 -0
- package/dist/command/setup/node-effects.js +38 -9
- 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 +2 -1
- package/dist/command/setup/run-setup.d.ts +34 -9
- package/dist/command/setup/run-setup.js +65 -51
- package/dist/command/setup/setup-command.d.ts +25 -1
- package/dist/command/setup/setup-command.js +59 -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 +49 -4
- package/dist/features/crawl/crawl-tools.js +4 -0
- package/dist/features/crawl/crawl.d.ts +6 -0
- package/dist/features/crawl/crawl.js +23 -2
- package/dist/features/exhaust/ledger.d.ts +21 -14
- package/dist/features/exhaust/ledger.js +35 -9
- package/dist/features/harness/app-findings.d.ts +2 -0
- package/dist/features/harness/app-findings.js +52 -0
- package/dist/features/harness/drive-report.d.ts +61 -1
- package/dist/features/harness/drive-report.js +394 -26
- 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 +10 -14
- package/dist/features/harness/drivers.js +10 -14
- 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/fill-values.d.ts +3 -73
- package/dist/features/harness/fill-values.js +3 -169
- package/dist/features/harness/goals.d.ts +82 -0
- package/dist/features/harness/goals.js +330 -0
- package/dist/features/harness/harness.d.ts +51 -1
- package/dist/features/harness/harness.js +207 -6
- package/dist/features/harness/platform/drive-target.d.ts +30 -0
- package/dist/features/harness/platform/drive-target.js +81 -0
- package/dist/features/harness/platform/local-apps.d.ts +127 -0
- package/dist/features/harness/platform/local-apps.js +280 -0
- 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 +186 -0
- package/dist/features/harness/platform/remote-drive.js +378 -0
- package/dist/features/harness/platform/script.d.ts +94 -0
- package/dist/features/harness/platform/script.js +260 -0
- package/dist/features/harness/platform/server-driver.d.ts +54 -0
- package/dist/features/harness/platform/server-driver.js +182 -0
- package/dist/features/harness/platform-config.d.ts +41 -1
- package/dist/features/harness/platform-config.js +106 -9
- package/dist/features/harness/route-guess.d.ts +13 -0
- package/dist/features/harness/route-guess.js +49 -0
- package/dist/features/harness/script/app-controls.d.ts +5 -0
- package/dist/features/harness/script/app-controls.js +40 -0
- package/dist/features/harness/script/lane-ids.d.ts +14 -0
- package/dist/features/harness/script/lane-ids.js +16 -0
- package/dist/features/harness/script/script-run.d.ts +70 -0
- package/dist/features/harness/script/script-run.js +606 -0
- 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.d.ts +10 -1
- package/dist/features/visual/visual-tools.js +62 -17
- 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 +23 -0
- package/dist/hooks/driven-by.js +56 -0
- package/dist/hooks/hook-bus.d.ts +4 -0
- package/dist/hooks/hook-bus.js +18 -0
- package/dist/hooks/hook-commands.js +15 -4
- package/dist/hooks/tool-log.d.ts +9 -0
- package/dist/hooks/tool-log.js +29 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +80 -243
- 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 +25 -3
- 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.d.ts +1 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +37 -11
- package/dist/judgement/runs/artifact/run-store.d.ts +14 -2
- package/dist/judgement/runs/artifact/run-store.js +195 -3
- 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 +71 -1
- package/dist/judgement/runs/drive-run.js +317 -5
- package/dist/judgement/runs/repair-prompt.js +1 -1
- package/dist/judgement/runs/resume.d.ts +44 -0
- package/dist/judgement/runs/resume.js +137 -0
- package/dist/judgement/runs/reticle-runner.js +13 -3
- 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 +5 -2
- package/dist/judgement/runs/verification-sync.js +40 -18
- package/dist/language/flows/change/gate.d.ts +10 -0
- package/dist/language/flows/change/gate.js +22 -0
- package/dist/language/flows/decision.js +36 -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 +61 -10
- package/dist/language/flows/flow-anchor.js +98 -6
- package/dist/language/flows/flow-cross-step.d.ts +15 -0
- package/dist/language/flows/flow-cross-step.js +21 -0
- 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 +45 -14
- package/dist/language/flows/flow-mutate-tools.js +5 -3
- package/dist/language/flows/flow-replay-run.d.ts +23 -9
- package/dist/language/flows/flow-replay-run.js +115 -110
- package/dist/language/flows/flow-replay-types.d.ts +1 -1
- package/dist/language/flows/flow-replay.d.ts +40 -1
- package/dist/language/flows/flow-replay.js +110 -22
- package/dist/language/flows/flow-result.d.ts +22 -1
- package/dist/language/flows/flow-result.js +47 -2
- package/dist/language/flows/flow-scope.js +5 -1
- package/dist/language/flows/flow-step-runners.d.ts +22 -2
- package/dist/language/flows/flow-step-runners.js +247 -47
- package/dist/language/flows/flow-store-for-session.d.ts +2 -2
- package/dist/language/flows/flow-store-for-session.js +7 -3
- package/dist/language/flows/flow-tools.d.ts +10 -0
- package/dist/language/flows/flow-tools.js +112 -89
- package/dist/language/flows/flows.d.ts +16 -1
- package/dist/language/flows/flows.js +74 -12
- package/dist/language/flows/heal-run.js +6 -4
- package/dist/language/flows/narrow-write.d.ts +7 -0
- package/dist/language/flows/narrow-write.js +36 -1
- package/dist/language/flows/recording/flake.d.ts +2 -2
- package/dist/language/flows/recording/recording-backtrack.js +14 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +58 -4
- package/dist/language/flows/recording/tape/recordings.js +95 -13
- package/dist/language/flows/replay-from-hud.d.ts +20 -0
- package/dist/language/flows/replay-from-hud.js +51 -0
- package/dist/language/flows/replay.d.ts +9 -5
- package/dist/language/flows/replay.js +56 -15
- package/dist/language/flows/single-replay.d.ts +7 -0
- package/dist/language/flows/single-replay.js +26 -0
- package/dist/language/flows/suite/suite-flakes.js +2 -0
- package/dist/language/flows/suite-selection.d.ts +2 -15
- package/dist/language/flows/suite-selection.js +4 -3
- package/dist/language/flows/verify-change-tools.d.ts +1 -0
- package/dist/language/flows/verify-change-tools.js +202 -191
- package/dist/launch-chromium.d.ts +27 -5
- package/dist/launch-chromium.js +38 -8
- package/dist/memory/cloud/cloud-config.d.ts +22 -1
- package/dist/memory/cloud/cloud-config.js +34 -5
- package/dist/memory/cloud/cloud-sync.d.ts +17 -14
- package/dist/memory/cloud/cloud-sync.js +15 -4
- package/dist/memory/cloud/harness-config.d.ts +75 -1
- package/dist/memory/cloud/harness-config.js +115 -24
- package/dist/memory/cloud/hud-notices-source.d.ts +21 -0
- package/dist/memory/cloud/hud-notices-source.js +128 -0
- package/dist/memory/cloud/memory-scope.d.ts +161 -0
- package/dist/memory/cloud/memory-scope.js +227 -0
- package/dist/memory/cloud/sync-cycle.d.ts +44 -7
- package/dist/memory/cloud/sync-cycle.js +129 -15
- package/dist/memory/cloud/sync-daemon.d.ts +11 -0
- package/dist/memory/cloud/sync-daemon.js +121 -9
- package/dist/memory/cloud/sync-disk.d.ts +1 -1
- package/dist/memory/cloud/sync-disk.js +31 -10
- 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 +34 -0
- package/dist/memory/impact/account-watch.js +59 -0
- package/dist/memory/impact/impact-recorder.d.ts +8 -0
- package/dist/memory/impact/impact-recorder.js +12 -2
- package/dist/memory/impact/impact-store.d.ts +17 -4
- package/dist/memory/impact/impact-store.js +169 -63
- 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 +14 -2
- package/dist/memory/intent/intent-store.d.ts +1 -0
- package/dist/memory/intent/intent-tools.js +122 -4
- 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/envelope.d.ts +8 -8
- package/dist/memory/journal/journal-recorder.js +52 -3
- package/dist/memory/journal/on-disk/retention.d.ts +8 -0
- package/dist/memory/journal/on-disk/retention.js +32 -2
- package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
- package/dist/memory/journal/on-disk/workspace-tiers.js +9 -4
- package/dist/memory/journal/session-end.d.ts +15 -1
- package/dist/memory/journal/session-end.js +42 -9
- package/dist/memory/project/artifact-root-resolver.d.ts +26 -1
- package/dist/memory/project/artifact-root-resolver.js +125 -16
- package/dist/memory/project/artifact-root.d.ts +46 -8
- package/dist/memory/project/artifact-root.js +89 -10
- package/dist/memory/project/dir/reticle-dir.d.ts +18 -2
- package/dist/memory/project/dir/reticle-dir.js +26 -3
- package/dist/memory/project/link-directory.d.ts +15 -0
- package/dist/memory/project/link-directory.js +44 -0
- package/dist/memory/project/project-tools.js +22 -3
- 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 +26 -1
- package/dist/memory/project/session-root.js +49 -5
- package/dist/memory/project/sync-status.d.ts +85 -0
- package/dist/memory/project/sync-status.js +224 -0
- package/dist/memory/recall/memory-tools.js +47 -2
- 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.d.ts +19 -0
- package/dist/memory/recall/project-memory.js +80 -13
- package/dist/portal/bridge/bridge.d.ts +9 -3
- package/dist/portal/bridge/bridge.js +82 -22
- package/dist/portal/bridge/harness-request.d.ts +23 -0
- package/dist/portal/bridge/harness-request.js +27 -0
- package/dist/portal/bridge/pairing-token.d.ts +9 -0
- package/dist/portal/bridge/pairing-token.js +17 -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 +83 -10
- package/dist/portal/input/real-input.js +218 -30
- package/dist/portal/input/viewport-tools.js +3 -3
- package/dist/portal/pool/browser-pool.d.ts +70 -9
- package/dist/portal/pool/browser-pool.js +190 -37
- 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 +35 -0
- package/dist/portal/pool/playwright-launcher.js +64 -3
- package/dist/portal/pool/pool-contract.d.ts +28 -5
- 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.d.ts +8 -0
- package/dist/portal/session/command-payload.js +24 -0
- 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 +21 -0
- package/dist/portal/session/dev-server/dev-command.js +87 -12
- package/dist/portal/session/facts/departure-note.d.ts +22 -0
- package/dist/portal/session/facts/departure-note.js +47 -0
- 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/facts/session-replaced.d.ts +5 -0
- package/dist/portal/session/facts/session-replaced.js +5 -0
- package/dist/portal/session/first-run-wiring.d.ts +42 -0
- package/dist/portal/session/first-run-wiring.js +132 -0
- 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/human/notes-ledger.d.ts +20 -0
- package/dist/portal/session/human/notes-ledger.js +55 -0
- package/dist/portal/session/human/review-store.d.ts +12 -0
- package/dist/portal/session/human/review-store.js +18 -10
- package/dist/portal/session/live-control-tools.d.ts +0 -13
- package/dist/portal/session/live-control-tools.js +107 -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 +8 -1
- package/dist/portal/session/no-session-diagnosis.js +46 -9
- package/dist/portal/session/no-session-next-action.d.ts +31 -0
- package/dist/portal/session/no-session-next-action.js +159 -60
- package/dist/portal/session/no-session-watch.d.ts +14 -1
- package/dist/portal/session/no-session-watch.js +227 -17
- package/dist/portal/session/presence/session-lease.js +1 -1
- package/dist/portal/session/presence/session-mirror.js +3 -0
- package/dist/portal/session/recorded-gaps.d.ts +97 -0
- package/dist/portal/session/recorded-gaps.js +251 -0
- package/dist/portal/session/serving-directory.d.ts +27 -0
- package/dist/portal/session/serving-directory.js +45 -0
- package/dist/portal/session/session-health.d.ts +18 -0
- package/dist/portal/session/session-health.js +9 -1
- package/dist/portal/session/session-info.d.ts +8 -1
- package/dist/portal/session/session-info.js +8 -1
- package/dist/portal/session/session-manager.d.ts +39 -0
- package/dist/portal/session/session-manager.js +98 -11
- package/dist/portal/session/session-reaper.js +4 -1
- package/dist/portal/session/session-successor.d.ts +13 -0
- package/dist/portal/session/session-successor.js +1 -1
- package/dist/portal/session/session-tools.js +26 -3
- package/dist/portal/session/session.d.ts +22 -30
- package/dist/portal/session/session.js +81 -79
- 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 +12 -0
- package/dist/start-wiring.d.ts +63 -0
- package/dist/start-wiring.js +169 -0
- package/dist/status-payload.d.ts +23 -1
- package/dist/status-payload.js +36 -1
- package/dist/surface/http-server.js +18 -2
- 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 +9 -0
- package/dist/surface/mcp/mcp-proxy.js +65 -13
- package/dist/surface/mcp/mcp.d.ts +34 -6
- package/dist/surface/mcp/mcp.js +61 -17
- 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.d.ts +4 -2
- package/dist/surface/mcp/server-instructions.js +32 -14
- package/dist/surface/mcp/shared-params.js +2 -2
- 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/navigation/navigate-arrival.d.ts +8 -0
- package/dist/surface/tools/act/navigation/navigate-arrival.js +56 -2
- 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/settle-in-flight.js +25 -3
- package/dist/surface/tools/act-sequence-tool.js +138 -29
- package/dist/surface/tools/act-tools.d.ts +0 -9
- package/dist/surface/tools/act-tools.js +71 -41
- 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.d.ts +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +42 -17
- package/dist/surface/tools/browser-tools.js +51 -2
- package/dist/surface/tools/chat-drives.d.ts +101 -0
- package/dist/surface/tools/chat-drives.js +409 -0
- 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 +51 -0
- package/dist/surface/tools/empty-session-list.js +120 -0
- package/dist/surface/tools/error-recovery.d.ts +14 -0
- package/dist/surface/tools/error-recovery.js +105 -8
- package/dist/surface/tools/explore-tools.d.ts +31 -1
- package/dist/surface/tools/explore-tools.js +438 -66
- package/dist/surface/tools/feedback-tools.d.ts +2 -3
- package/dist/surface/tools/feedback-tools.js +18 -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 +118 -57
- package/dist/surface/tools/harness-explore.js +344 -292
- 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 +17 -0
- package/dist/surface/tools/harness-plan.js +38 -0
- package/dist/surface/tools/harness-script.d.ts +30 -0
- package/dist/surface/tools/harness-script.js +560 -0
- 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 +22 -1
- package/dist/surface/tools/harness-toolset.js +101 -7
- 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 +263 -85
- 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 +49 -0
- package/dist/surface/tools/lease-seed.js +167 -0
- package/dist/surface/tools/lease-tools.d.ts +13 -24
- package/dist/surface/tools/lease-tools.js +146 -197
- package/dist/surface/tools/live-call-text.js +4 -4
- 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 +29 -0
- package/dist/surface/tools/next-step.js +214 -0
- package/dist/surface/tools/observe-tools.js +45 -9
- package/dist/surface/tools/platform-moment.d.ts +72 -0
- package/dist/surface/tools/platform-moment.js +296 -0
- package/dist/surface/tools/query-hint-schema.d.ts +7 -0
- package/dist/surface/tools/query-hint-schema.js +10 -0
- package/dist/surface/tools/read-tools.js +71 -14
- package/dist/surface/tools/real-input-attempt.js +96 -13
- 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 +83 -3
- package/dist/surface/tools/tool-kit.js +77 -7
- package/dist/surface/tools/tools.js +43 -59
- 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 +29 -6
- package/dist/telemetry/hud-metrics.js +116 -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 +38 -2
- package/dist/telemetry/telemetry.js +144 -34
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +13 -4
- package/dist/wire-journal.d.ts +2 -2
- package/dist/wire-journal.js +20 -6
- package/docs/README.md +3 -3
- package/docs/actions.mdx +6 -3
- package/docs/adapters.md +1 -1
- package/docs/agent-cheatsheet.md +25 -28
- package/docs/architecture.md +5 -5
- package/docs/autodrive.md +33 -28
- 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 +14 -3
- package/docs/cli/drive.mdx +20 -14
- 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 +43 -28
- 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 +18 -5
- 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 +5 -4
- package/docs/cli.mdx +111 -42
- package/docs/debugging.md +3 -3
- package/docs/deploy-checks.md +1 -1
- package/docs/desktop.mdx +9 -3
- package/docs/enterprise.md +11 -10
- package/docs/environment.mdx +7 -8
- 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 +65 -61
- package/docs/human-control.md +16 -16
- package/docs/index.mdx +15 -42
- package/docs/install-agentic.mdx +22 -37
- package/docs/install-manual.mdx +23 -13
- 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 +9 -9
- package/docs/packages/test.mdx +4 -10
- package/docs/packages/vite-plugin.mdx +32 -4
- package/docs/packages.mdx +11 -15
- package/docs/platform-integration.md +6 -5
- package/docs/predicates.mdx +40 -24
- package/docs/quickstart.mdx +69 -30
- 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 +23 -25
- 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 +22 -13
- 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 +55 -46
- 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 +17 -5
- package/docs/what-is-reticle.mdx +5 -3
- package/docs/why-reticle.mdx +1 -1
- package/package.json +9 -12
- package/dist/command/cli/demo/demo-page.d.ts +0 -78
- package/dist/command/cli/demo/demo-page.js +0 -241
- package/dist/command/cli/demo/demo-run.d.ts +0 -38
- package/dist/command/cli/demo/demo-run.js +0 -138
- package/dist/features/harness/driver.d.ts +0 -50
- package/dist/features/harness/driver.js +0 -236
- package/dist/features/harness/jev-driver.d.ts +0 -188
- package/dist/features/harness/jev-driver.js +0 -678
- package/dist/features/harness/openai-driver.d.ts +0 -58
- package/dist/features/harness/openai-driver.js +0 -206
- 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/memory/project/dir/fill-value-store.d.ts +0 -32
- package/dist/memory/project/dir/fill-value-store.js +0 -88
- 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
- package/docs/local-registry.md +0 -143
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
import * as http from 'node:http';
|
|
32
32
|
import { DRIVE_PATH, LOOPBACK_HOST } from '@reticlehq/core';
|
|
33
33
|
import { PortPresence } from '../../daemon/binding/port-presence.js';
|
|
34
|
+
import { summarizeStatus } from '../../daemon/binding/daemon-status-probe.js';
|
|
34
35
|
/** What `drive` should do about the port, given what is on it. */
|
|
35
36
|
export const DriveMode = {
|
|
36
37
|
/** Nothing is listening: bind it and run the foreground engine. */
|
|
@@ -134,18 +135,84 @@ export async function requestDriveSession(port, url, post = postJson) {
|
|
|
134
135
|
}
|
|
135
136
|
return readAttachResponse(port, url, res);
|
|
136
137
|
}
|
|
138
|
+
/** Nothing known about the app, as for a page that never connected. */
|
|
139
|
+
export const NO_ATTACHED_APP = { fields: {}, mismatch: false };
|
|
140
|
+
/**
|
|
141
|
+
* Control characters, and the 0x80 to 0x9f range some terminals also obey. Built with
|
|
142
|
+
* `fromCharCode` to keep them out of a regex literal (no-control-regex).
|
|
143
|
+
*/
|
|
144
|
+
const TERMINAL_CONTROLS = new RegExp(`[${String.fromCharCode(0)}-${String.fromCharCode(0x1f)}${String.fromCharCode(0x7f)}-${String.fromCharCode(0x9f)}]`, 'g');
|
|
145
|
+
/**
|
|
146
|
+
* A value safe to print. The project id and title come from the page, and the expected project id
|
|
147
|
+
* from a `.reticle.json` anyone can commit. All three are written straight to the terminal (and into
|
|
148
|
+
* the JSON line beside it), so they could otherwise move the cursor or retitle the window. Each
|
|
149
|
+
* control character becomes U+FFFD, so the reader can still see that something was there.
|
|
150
|
+
*/
|
|
151
|
+
function printable(value) {
|
|
152
|
+
return value.replace(TERMINAL_CONTROLS, '\uFFFD');
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Pick the attached session out of a `/status` payload. Pure.
|
|
156
|
+
*
|
|
157
|
+
* The drive answer is a lease result, which carries no project: the page reports that itself when
|
|
158
|
+
* it connects, and `/status` is where it is already listed.
|
|
159
|
+
*/
|
|
160
|
+
export function attachedApp(status, sessionId, expectedProjectId) {
|
|
161
|
+
const row = summarizeStatus(status).sessions.find((s) => s.sessionId === sessionId);
|
|
162
|
+
return {
|
|
163
|
+
fields: {
|
|
164
|
+
...(row?.projectId === undefined ? {} : { projectId: printable(row.projectId) }),
|
|
165
|
+
...(row?.title === undefined ? {} : { title: printable(row.title) }),
|
|
166
|
+
...(expectedProjectId === undefined
|
|
167
|
+
? {}
|
|
168
|
+
: { expectedProjectId: printable(expectedProjectId) }),
|
|
169
|
+
},
|
|
170
|
+
// Only warned when both sides are known: a page with no project id proves nothing, and neither
|
|
171
|
+
// does a directory without a `.reticle.json`.
|
|
172
|
+
mismatch: row?.projectId !== undefined &&
|
|
173
|
+
expectedProjectId !== undefined &&
|
|
174
|
+
row.projectId !== expectedProjectId,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/** The fallback when the daemon sent no hint for a page that did not connect. */
|
|
178
|
+
const MSG_NOT_READY_HINT = 'Check that the app embeds @reticlehq/browser.';
|
|
179
|
+
/** How the attach line names the page's project. */
|
|
180
|
+
const PROJECT_LABEL = (projectId) => `project ${JSON.stringify(projectId)}`;
|
|
181
|
+
/** The page is a different project from the one this directory's `.reticle.json` names. */
|
|
182
|
+
const MSG_PROJECT_MISMATCH = (url, expected, actual) => `Warning: this directory's .reticle.json is ${PROJECT_LABEL(expected)}, but the page at ${url} ` +
|
|
183
|
+
`is ${PROJECT_LABEL(actual)}, so another app is probably serving that port. Check which dev ` +
|
|
184
|
+
'server is on it before trusting anything this session reports.';
|
|
185
|
+
/**
|
|
186
|
+
* The project and title, and a warning when this directory names a different project.
|
|
187
|
+
*
|
|
188
|
+
* In a monorepo the port you meant for one app is easily held by another, and the port, url and
|
|
189
|
+
* session id read the same either way.
|
|
190
|
+
*/
|
|
191
|
+
function describeApp(url, app) {
|
|
192
|
+
const { projectId, title, expectedProjectId } = app.fields;
|
|
193
|
+
const named = [
|
|
194
|
+
...(projectId === undefined ? [] : [PROJECT_LABEL(projectId)]),
|
|
195
|
+
...(title === undefined ? [] : [JSON.stringify(title)]),
|
|
196
|
+
];
|
|
197
|
+
const label = 0 === named.length ? '' : ` (${named.join(', ')})`;
|
|
198
|
+
const warning = app.mismatch && projectId !== undefined && expectedProjectId !== undefined
|
|
199
|
+
? ` ${MSG_PROJECT_MISMATCH(url, expectedProjectId, projectId)}`
|
|
200
|
+
: '';
|
|
201
|
+
return { label, warning };
|
|
202
|
+
}
|
|
137
203
|
/** The success line. Names the session, because that is the handle everything downstream needs. */
|
|
138
|
-
export function describeAttached(port, url, session) {
|
|
204
|
+
export function describeAttached(port, url, session, app = NO_ATTACHED_APP) {
|
|
139
205
|
const life = session.expiresInMs === undefined
|
|
140
206
|
? ''
|
|
141
207
|
: ` It is released after ${String(Math.round(session.expiresInMs / 1000))}s untouched; any ` +
|
|
142
208
|
'tool call against it resets that.';
|
|
143
209
|
if (!session.ready) {
|
|
144
210
|
return (`the Reticle daemon on :${String(port)} opened ${url} as session ${session.sessionId}, but ` +
|
|
145
|
-
`the page did not connect to the bridge. ${session.hint ??
|
|
211
|
+
`the page did not connect to the bridge. ${session.hint ?? MSG_NOT_READY_HINT}`);
|
|
146
212
|
}
|
|
147
|
-
|
|
148
|
-
|
|
213
|
+
const { label, warning } = describeApp(url, app);
|
|
214
|
+
return (`attached to the Reticle daemon on :${String(port)} — it is driving ${url}${label} as session ` +
|
|
215
|
+
`${session.sessionId}, which every Reticle tool can address.${life}${warning}`);
|
|
149
216
|
}
|
|
150
217
|
/**
|
|
151
218
|
* What an attach cannot honour: the window.
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* place. The pure parts (which mode, and every sentence a user reads) live next door in
|
|
7
7
|
* drive-attach.ts, which is where the reasoning for attaching is written down.
|
|
8
8
|
*/
|
|
9
|
+
/** `projectId` is the one in this directory's `.reticle.json`, read by the caller. */
|
|
9
10
|
export declare function handleDrive(parsed: {
|
|
10
11
|
port: number;
|
|
11
12
|
driveUrl: string;
|
|
12
13
|
headless: boolean;
|
|
13
|
-
}): void;
|
|
14
|
+
}, projectId?: string): void;
|
|
@@ -13,9 +13,10 @@ import { probeDaemon } from '../../../surface/mcp/mcp-proxy.js';
|
|
|
13
13
|
import { readPid } from '../../daemon/daemon.js';
|
|
14
14
|
import { fetchStatus } from '../../daemon/binding/daemon-status-probe.js';
|
|
15
15
|
import { captureLookup, findPortHolder } from '../ports/port-holder.js';
|
|
16
|
-
import { DriveMode, decideDriveMode, describeAttached, driveForeignHolder, driveHeadlessOnAttach, driveRaceLost, requestDriveSession, } from './drive-attach.js';
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
import { DriveMode, NO_ATTACHED_APP, attachedApp, decideDriveMode, describeAttached, driveForeignHolder, driveHeadlessOnAttach, driveRaceLost, requestDriveSession, } from './drive-attach.js';
|
|
17
|
+
/** `projectId` is the one in this directory's `.reticle.json`, read by the caller. */
|
|
18
|
+
export function handleDrive(parsed, projectId) {
|
|
19
|
+
void driveWithHonestConflict(parsed, projectId);
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* Decide who gets the port BEFORE binding it — and when the answer is "the daemon", ask it instead.
|
|
@@ -29,7 +30,7 @@ export function handleDrive(parsed) {
|
|
|
29
30
|
* because the MCP proxy respawns a daemon into the gap. So a healthy daemon is now ATTACHED to —
|
|
30
31
|
* see cli/drive/drive-attach.ts.
|
|
31
32
|
*/
|
|
32
|
-
async function driveWithHonestConflict(parsed) {
|
|
33
|
+
async function driveWithHonestConflict(parsed, projectId) {
|
|
33
34
|
const presence = await probePresence(parsed.port, { tcpOpen: probeDaemon, status: fetchStatus });
|
|
34
35
|
const mode = decideDriveMode(presence);
|
|
35
36
|
if (DriveMode.REFUSE === mode) {
|
|
@@ -43,7 +44,7 @@ async function driveWithHonestConflict(parsed) {
|
|
|
43
44
|
return;
|
|
44
45
|
}
|
|
45
46
|
if (DriveMode.ATTACH === mode) {
|
|
46
|
-
await attachToRunningDaemon(parsed.port, parsed.driveUrl, parsed.headless);
|
|
47
|
+
await attachToRunningDaemon(parsed.port, parsed.driveUrl, parsed.headless, projectId);
|
|
47
48
|
return;
|
|
48
49
|
}
|
|
49
50
|
// The probe cannot close the race: something can take the port between here and the bind, and the
|
|
@@ -81,7 +82,7 @@ async function driveWithHonestConflict(parsed) {
|
|
|
81
82
|
* against it renews its lease), and a foreground hold here could only keep it alive by faking tool
|
|
82
83
|
* calls at it.
|
|
83
84
|
*/
|
|
84
|
-
async function attachToRunningDaemon(port, url, headless) {
|
|
85
|
+
async function attachToRunningDaemon(port, url, headless, projectId) {
|
|
85
86
|
const result = await requestDriveSession(port, url);
|
|
86
87
|
if (!result.ok) {
|
|
87
88
|
log('reticle_drive_attach_failed', { port, url, reason: result.reason });
|
|
@@ -89,13 +90,18 @@ async function attachToRunningDaemon(port, url, headless) {
|
|
|
89
90
|
process.exit(1);
|
|
90
91
|
return;
|
|
91
92
|
}
|
|
93
|
+
// Only a page that connected has reported its project; one that never dialled in is not listed.
|
|
94
|
+
const app = result.session.ready
|
|
95
|
+
? attachedApp(await fetchStatus(port), result.session.sessionId, projectId)
|
|
96
|
+
: NO_ATTACHED_APP;
|
|
92
97
|
log('reticle_drive_attached', {
|
|
93
98
|
port,
|
|
94
99
|
url,
|
|
95
100
|
sessionId: result.session.sessionId,
|
|
96
101
|
ready: result.session.ready,
|
|
102
|
+
...app.fields,
|
|
97
103
|
});
|
|
98
|
-
process.stderr.write(`${describeAttached(port, url, result.session)}\n`);
|
|
104
|
+
process.stderr.write(`${describeAttached(port, url, result.session, app)}\n`);
|
|
99
105
|
// The command's own default is headed, and this path cannot deliver that. Said out loud rather
|
|
100
106
|
// than left for the user to discover by watching a window that never opens.
|
|
101
107
|
if (!headless)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** The `broken` list of a regression report, or undefined when the report has none. */
|
|
2
|
+
export declare function brokenOf(report: unknown): unknown[] | undefined;
|
|
3
|
+
/** What the platform said about regressions: the broken list, or that it refused the credential. */
|
|
4
|
+
export interface KnownRegression {
|
|
5
|
+
broken?: unknown[];
|
|
6
|
+
/** The platform refused this project's key: said, and the gate fails closed on it. */
|
|
7
|
+
refused?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Nothing when `reticleRoot` is not linked or the platform did not answer (offline is not a failure);
|
|
11
|
+
* `refused` when it answered and refused the key — a revoked key left CI green and silent.
|
|
12
|
+
*/
|
|
13
|
+
export declare function knownRegression(reticleRoot: string): Promise<KnownRegression>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flows the linked project's platform says passed before and are broken now — what
|
|
3
|
+
* `reticle runs regression` prints, read here so `reticle gate` can fail on it too.
|
|
4
|
+
*
|
|
5
|
+
* Its own module, not a call into `cloud-cli.ts`: the gate is on the library's import path, and the
|
|
6
|
+
* cloud CLI reaches the install-time surface the library must never load.
|
|
7
|
+
*/
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
|
|
11
|
+
import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
|
|
12
|
+
import { CredentialRefusedError, api } from './cloud-kit.js';
|
|
13
|
+
const REGRESSION_PATH = '/v1/project/regression';
|
|
14
|
+
/** The `broken` list of a regression report, or undefined when the report has none. */
|
|
15
|
+
export function brokenOf(report) {
|
|
16
|
+
const parsed = z.object({ broken: z.array(z.unknown()) }).safeParse(report);
|
|
17
|
+
return parsed.success ? parsed.data.broken : undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Nothing when `reticleRoot` is not linked or the platform did not answer (offline is not a failure);
|
|
21
|
+
* `refused` when it answered and refused the key — a revoked key left CI green and silent.
|
|
22
|
+
*/
|
|
23
|
+
export async function knownRegression(reticleRoot) {
|
|
24
|
+
try {
|
|
25
|
+
const cloud = await resolveProjectCloud(createNodeFileSystem(), reticleRoot, homedir(), process.env);
|
|
26
|
+
if (null === cloud.config)
|
|
27
|
+
return {};
|
|
28
|
+
const broken = brokenOf(await api('GET', `${cloud.config.url}${REGRESSION_PATH}`, cloud.config.apiKey));
|
|
29
|
+
return broken === undefined ? {} : { broken };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return error instanceof CredentialRefusedError ? { refused: error.message } : {};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -36,6 +36,12 @@ export declare function installedSdkVersion(projectDir: string, readFile: (path:
|
|
|
36
36
|
export declare function readTextFile(path: string): string | undefined;
|
|
37
37
|
/** The one line a person sees on stderr when the CLI hands over — stdout belongs to the protocol. */
|
|
38
38
|
export declare function versionMatchNote(sdkVersion: string, cliVersion: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* The line `--help` opens with when the command it describes would run at another version (#1378).
|
|
41
|
+
* Help stays on this binary, so without it the flags listed are this release's, and the re-run
|
|
42
|
+
* rejected the ones its older release never had, as an unknown parameter.
|
|
43
|
+
*/
|
|
44
|
+
export declare function helpVersionNote(sdkVersion: string, cliVersion: string): string;
|
|
39
45
|
export interface VersionMatchInput {
|
|
40
46
|
argv: readonly string[];
|
|
41
47
|
cliVersion: string;
|
|
@@ -48,6 +54,12 @@ export interface VersionMatchInput {
|
|
|
48
54
|
* environment are handed in.
|
|
49
55
|
*/
|
|
50
56
|
export declare function versionToMatch(input: VersionMatchInput): string | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* The version the command asked about with `--help`, or `help <command>`, would actually run at.
|
|
59
|
+
* Undefined when help was not asked for, or when that command runs on this binary. Pure, like
|
|
60
|
+
* `versionToMatch`: it asks that same question about the command with the help request removed.
|
|
61
|
+
*/
|
|
62
|
+
export declare function helpRunsAt(input: VersionMatchInput): string | undefined;
|
|
51
63
|
/** How to launch `npx --yes @reticlehq/server@<version> <args>` on this platform. */
|
|
52
64
|
export declare function npxInvocation(version: string, args: readonly string[], on: string): {
|
|
53
65
|
file: string;
|
|
@@ -58,6 +58,8 @@ const KEEP_COMMANDS = new Set([
|
|
|
58
58
|
'_daemon',
|
|
59
59
|
]);
|
|
60
60
|
const KEEP_FLAGS = new Set(['--version', '-v', '--help', '-h']);
|
|
61
|
+
const HELP_COMMAND = 'help';
|
|
62
|
+
const HELP_FLAGS = new Set(['--help', '-h']);
|
|
61
63
|
const SETUP_COMMAND = 'setup';
|
|
62
64
|
const SETUP_INSTALL = 'install';
|
|
63
65
|
/** A published release — not `workspace:*`, a link, or a tag npx could not pin. */
|
|
@@ -105,6 +107,17 @@ export function versionMatchNote(sdkVersion, cliVersion) {
|
|
|
105
107
|
return (`This project's Reticle SDK is ${sdkVersion}; running ${SERVER_PACKAGE}@${sdkVersion} to match ` +
|
|
106
108
|
`(this CLI is ${cliVersion}, a different major). Set ${VersionMatchEnv.OPT_OUT}=1 to keep this one.`);
|
|
107
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* The line `--help` opens with when the command it describes would run at another version (#1378).
|
|
112
|
+
* Help stays on this binary, so without it the flags listed are this release's, and the re-run
|
|
113
|
+
* rejected the ones its older release never had, as an unknown parameter.
|
|
114
|
+
*/
|
|
115
|
+
export function helpVersionNote(sdkVersion, cliVersion) {
|
|
116
|
+
return (`This help describes ${SERVER_PACKAGE} ${cliVersion}, but in this project the command runs at ` +
|
|
117
|
+
`${SERVER_PACKAGE}@${sdkVersion} to match its SDK, which may not take every flag listed here. ` +
|
|
118
|
+
`Run npx ${SERVER_PACKAGE}@${sdkVersion} <command> --help for that version's help, or set ` +
|
|
119
|
+
`${VersionMatchEnv.OPT_OUT}=1 to run this one.`);
|
|
120
|
+
}
|
|
108
121
|
/** Did the person name a version on the npx line (`npx @reticlehq/server@<version> …`)? */
|
|
109
122
|
function pinnedOnNpxLine(spec) {
|
|
110
123
|
if (spec === undefined || !spec.startsWith(`${SERVER_PACKAGE}@`))
|
|
@@ -141,6 +154,18 @@ export function versionToMatch(input) {
|
|
|
141
154
|
return undefined;
|
|
142
155
|
return sdkMajor === majorOf(input.cliVersion) ? undefined : sdk;
|
|
143
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* The version the command asked about with `--help`, or `help <command>`, would actually run at.
|
|
159
|
+
* Undefined when help was not asked for, or when that command runs on this binary. Pure, like
|
|
160
|
+
* `versionToMatch`: it asks that same question about the command with the help request removed.
|
|
161
|
+
*/
|
|
162
|
+
export function helpRunsAt(input) {
|
|
163
|
+
const viaCommand = HELP_COMMAND === input.argv[0];
|
|
164
|
+
if (!viaCommand && !input.argv.some((arg) => HELP_FLAGS.has(arg)))
|
|
165
|
+
return undefined;
|
|
166
|
+
const asked = (viaCommand ? input.argv.slice(1) : input.argv).filter((arg) => !HELP_FLAGS.has(arg));
|
|
167
|
+
return versionToMatch({ ...input, argv: asked });
|
|
168
|
+
}
|
|
144
169
|
/** How to launch `npx --yes @reticlehq/server@<version> <args>` on this platform. */
|
|
145
170
|
export function npxInvocation(version, args, on) {
|
|
146
171
|
const argv = [NPX_YES, `${SERVER_PACKAGE}@${version}`, ...args];
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { log } from '../../../log.js';
|
|
18
18
|
import { RETICLE_VERIFY_DEFAULT_PORT } from '../../../index.js';
|
|
19
|
-
import { verifyEndpointMismatch } from '../../../status-payload.js';
|
|
19
|
+
import { strandedClientsNote, verifyEndpointMismatch } from '../../../status-payload.js';
|
|
20
20
|
import { probeDaemon, waitForDaemonBind } from '../../../surface/mcp/mcp-proxy.js';
|
|
21
21
|
import { stateDirProblem } from '../../daemon/state-dir.js';
|
|
22
22
|
import { readPid, isAlive, removePid, spawnDaemon, logPath, reticleStateHome, } from '../../daemon/daemon.js';
|
|
@@ -121,8 +121,17 @@ export function handleStop(port, quiet) {
|
|
|
121
121
|
const pid = readPid(port);
|
|
122
122
|
if (null === pid || !isAlive(pid)) {
|
|
123
123
|
removePid(port);
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
// No pid on record is not "not running": a daemon whose pid file vanished still answers its
|
|
125
|
+
// port, and `kill` finds the listener and confirms it is Reticle's before signalling it.
|
|
126
|
+
void fetchStatus(port).then(async (status) => {
|
|
127
|
+
if (status !== undefined) {
|
|
128
|
+
if (!(await runKill(port, false)))
|
|
129
|
+
process.exit(1);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (!quiet)
|
|
133
|
+
log('reticle_daemon_not_running', { port });
|
|
134
|
+
});
|
|
126
135
|
return;
|
|
127
136
|
}
|
|
128
137
|
process.kill(pid, 'SIGTERM');
|
|
@@ -168,6 +177,9 @@ export function handleStop(port, quiet) {
|
|
|
168
177
|
* anything at all, and a single `ok: false` cannot tell them which happened.
|
|
169
178
|
*/
|
|
170
179
|
export async function handleRestart(port, force) {
|
|
180
|
+
const stranded = strandedClientsNote(await fetchStatus(port));
|
|
181
|
+
if (stranded !== undefined)
|
|
182
|
+
process.stderr.write(`${stranded}\n`);
|
|
171
183
|
const freed = await runKill(port, force);
|
|
172
184
|
if (!freed) {
|
|
173
185
|
log('reticle_restart_aborted', {
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
* talks to for the rest of its life — and the port resolution at the top is the fix for agents on
|
|
8
8
|
* different projects silently sharing one daemon, one identity and one blast radius.
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* Whether the daemon this proxy starts hides its browser. A daemon on a port nobody chose — the
|
|
12
|
+
* requested one served another project, so this one was moved — was opening a visible browser the
|
|
13
|
+
* person never asked for, on a port nothing records. Only the requested port gets the default.
|
|
14
|
+
*/
|
|
15
|
+
export declare function spawnsHeadless(headless: boolean, requested: number, resolved: number): boolean;
|
|
10
16
|
/**
|
|
11
17
|
* MCP proxy mode: ensures the daemon is running, then bridges Claude Code's
|
|
12
18
|
* stdin/stdout to the daemon's SSE endpoint. This is the recommended way to
|
|
@@ -12,8 +12,8 @@ import { isAlive, spawnDaemon, reticleStateHome } from '../daemon/daemon.js';
|
|
|
12
12
|
import { PortPresence, probePresence, presenceIsUsable, describePresence, } from '../daemon/binding/port-presence.js';
|
|
13
13
|
import { waitForDaemon, startMcpProxy, probeDaemon, proxyLog, setProxyLogPort, } from '../../surface/mcp/mcp-proxy.js';
|
|
14
14
|
import { installProxyResilience } from '../daemon/daemon-resilience.js';
|
|
15
|
-
import { readProjectId } from './ports/resolve/cli-port.js';
|
|
16
|
-
import { resolveMcpPort, daemonProjectAt } from '../daemon/daemon-resolve.js';
|
|
15
|
+
import { readProjectId, readProjectPort } from './ports/resolve/cli-port.js';
|
|
16
|
+
import { resolveMcpPort, daemonProjectAt, relocationReason, } from '../daemon/daemon-resolve.js';
|
|
17
17
|
import { daemonSpawnArgs } from './daemon-start-options.js';
|
|
18
18
|
import { WakeAction, decideWake } from '../daemon/wake-decision.js';
|
|
19
19
|
import { pickDaemonPortToBind } from '../daemon/binding/free-port.js';
|
|
@@ -23,6 +23,14 @@ import { ReticleEnv } from '@reticlehq/core';
|
|
|
23
23
|
import { agentIo } from '../setup/agent-io.js';
|
|
24
24
|
import { SERVER_VERSION } from '../version/identity/server-version.js';
|
|
25
25
|
import { homedir } from 'node:os';
|
|
26
|
+
/**
|
|
27
|
+
* Whether the daemon this proxy starts hides its browser. A daemon on a port nobody chose — the
|
|
28
|
+
* requested one served another project, so this one was moved — was opening a visible browser the
|
|
29
|
+
* person never asked for, on a port nothing records. Only the requested port gets the default.
|
|
30
|
+
*/
|
|
31
|
+
export function spawnsHeadless(headless, requested, resolved) {
|
|
32
|
+
return headless || requested !== resolved;
|
|
33
|
+
}
|
|
26
34
|
/**
|
|
27
35
|
* MCP proxy mode: ensures the daemon is running, then bridges Claude Code's
|
|
28
36
|
* stdin/stdout to the daemon's SSE endpoint. This is the recommended way to
|
|
@@ -64,12 +72,12 @@ export async function handleMcp(opts) {
|
|
|
64
72
|
alive: isAlive,
|
|
65
73
|
daemonPresent: async (p) => presenceIsUsable(await probePresence(p, { tcpOpen: probeDaemon, status: fetchStatus })),
|
|
66
74
|
pickPort: (p) => pickDaemonPortToBind(p),
|
|
67
|
-
});
|
|
75
|
+
}, readProjectPort(process.cwd()));
|
|
68
76
|
if (port !== opts.port) {
|
|
69
77
|
log('reticle_mcp_port_relocated', {
|
|
70
78
|
requested: opts.port,
|
|
71
79
|
port,
|
|
72
|
-
reason:
|
|
80
|
+
reason: relocationReason(opts.port, port, projectId, reticleStateHome(), isAlive),
|
|
73
81
|
});
|
|
74
82
|
}
|
|
75
83
|
// The proxy IS the MCP server the editor launched. Nothing respawns it, so an uncaught throw here
|
|
@@ -119,7 +127,7 @@ export async function handleMcp(opts) {
|
|
|
119
127
|
}
|
|
120
128
|
const daemonArgs = daemonSpawnArgs({
|
|
121
129
|
port,
|
|
122
|
-
headless,
|
|
130
|
+
headless: spawnsHeadless(headless, opts.port, port),
|
|
123
131
|
http,
|
|
124
132
|
...(driveUrl !== undefined ? { driveUrl } : {}),
|
|
125
133
|
...(httpPort !== undefined ? { httpPort } : {}),
|
|
@@ -51,3 +51,13 @@ export declare function describeForeignHolder(port: number, holder: PortHolder |
|
|
|
51
51
|
ourPid?: number | null): string;
|
|
52
52
|
/** The lookup itself. `exec` is injected so the shelling out never runs in a unit test. */
|
|
53
53
|
export declare function findPortHolder(port: number, exec: (command: string, args: readonly string[]) => string | null): PortHolder | null;
|
|
54
|
+
/** The path in `lsof -a -p <pid> -d cwd -Fn` output, or null when it printed none. */
|
|
55
|
+
export declare function parseProcessCwd(stdout: string): string | null;
|
|
56
|
+
/**
|
|
57
|
+
* The working directory of whatever LISTENS on `port`, or null.
|
|
58
|
+
*
|
|
59
|
+
* How the daemon tells which checkout served a page when every git worktree declares the same
|
|
60
|
+
* projectId: the dev server runs inside exactly one of them. Null wherever `lsof` cannot answer —
|
|
61
|
+
* Windows, a slim container — and the caller then keeps the answer it had without this.
|
|
62
|
+
*/
|
|
63
|
+
export declare function findListenerCwd(port: number, exec: (command: string, args: readonly string[]) => string | null): string | null;
|
|
@@ -83,7 +83,7 @@ ourPid) {
|
|
|
83
83
|
// Naming the command matters more than naming the process. "Stop that process" describes an
|
|
84
84
|
// outcome and leaves the reader to invent a route to it, and the route they invent is the `-ti`
|
|
85
85
|
// pipeline that takes their agent's proxy down with the holder.
|
|
86
|
-
const tail = 'a daemon cannot bind it. Free it with `reticle
|
|
86
|
+
const tail = 'a daemon cannot bind it. Free it with `reticle restart --force` (it signals the listener only, ' +
|
|
87
87
|
"never the agent's mcp proxy), or run Reticle on a different port (`--port`), then retry.";
|
|
88
88
|
if (null === holder) {
|
|
89
89
|
/**
|
|
@@ -121,3 +121,27 @@ export function findPortHolder(port, exec) {
|
|
|
121
121
|
const out = exec('lsof', ['-nP', `-iTCP:${String(port)}`, '-sTCP:LISTEN', '-F', 'pc']);
|
|
122
122
|
return null === out ? null : parsePortHolder(out);
|
|
123
123
|
}
|
|
124
|
+
/** `lsof -Fn` emits the file name on its own line, prefixed `n`. */
|
|
125
|
+
const NAME_FIELD = 'n';
|
|
126
|
+
/** The path in `lsof -a -p <pid> -d cwd -Fn` output, or null when it printed none. */
|
|
127
|
+
export function parseProcessCwd(stdout) {
|
|
128
|
+
for (const raw of stdout.split('\n')) {
|
|
129
|
+
if (raw.startsWith(NAME_FIELD) && raw.length > NAME_FIELD.length)
|
|
130
|
+
return raw.slice(1);
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The working directory of whatever LISTENS on `port`, or null.
|
|
136
|
+
*
|
|
137
|
+
* How the daemon tells which checkout served a page when every git worktree declares the same
|
|
138
|
+
* projectId: the dev server runs inside exactly one of them. Null wherever `lsof` cannot answer —
|
|
139
|
+
* Windows, a slim container — and the caller then keeps the answer it had without this.
|
|
140
|
+
*/
|
|
141
|
+
export function findListenerCwd(port, exec) {
|
|
142
|
+
const holder = findPortHolder(port, exec);
|
|
143
|
+
if (null === holder)
|
|
144
|
+
return null;
|
|
145
|
+
const out = exec('lsof', ['-a', '-p', String(holder.pid), '-d', 'cwd', '-Fn']);
|
|
146
|
+
return null === out ? null : parseProcessCwd(out);
|
|
147
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* A repo already knows its name: the directory it lives in. That is not a guess, it is the name its
|
|
12
12
|
* owner chose and the one they will look for in a project list.
|
|
13
13
|
*/
|
|
14
|
+
import { z } from 'zod';
|
|
14
15
|
/** The id used when a directory name yields nothing usable — the historical behaviour, unchanged. */
|
|
15
16
|
export declare const DEFAULT_PROJECT_ID = "default";
|
|
16
17
|
/**
|
|
@@ -27,4 +28,31 @@ export declare const slugifyProjectName: (raw: string) => string;
|
|
|
27
28
|
* do to rotate a key or repoint an environment — must land in that same project or the history
|
|
28
29
|
* silently splits in two, which is worse than the shared-bucket problem this fixes.
|
|
29
30
|
*/
|
|
30
|
-
export declare const defaultProjectFor: (cwdBasename: string, existingProjectId: string | undefined
|
|
31
|
+
export declare const defaultProjectFor: (cwdBasename: string, existingProjectId: string | undefined,
|
|
32
|
+
/** The `projectId` `init` wrote into `.reticle.json`, when there is one. */
|
|
33
|
+
localProjectId?: string) => string;
|
|
34
|
+
export declare const CreatedProjectSchema: z.ZodObject<{
|
|
35
|
+
projectId: z.ZodString;
|
|
36
|
+
name: z.ZodString;
|
|
37
|
+
}, "strip", z.ZodTypeAny, {
|
|
38
|
+
name: string;
|
|
39
|
+
projectId: string;
|
|
40
|
+
}, {
|
|
41
|
+
name: string;
|
|
42
|
+
projectId: string;
|
|
43
|
+
}>;
|
|
44
|
+
/** ` in workspace "<name>"`, or nothing when no name is known. */
|
|
45
|
+
export declare const inWorkspace: (name: string | undefined) => string;
|
|
46
|
+
/**
|
|
47
|
+
* Which repository, and which folder in it, a project folder is: a hash of the `origin` remote and
|
|
48
|
+
* the folder's path inside the checkout, so every clone of one app agrees and two different apps
|
|
49
|
+
* both named `web` do not. Undefined outside git or with no remote. Neither leaves the machine.
|
|
50
|
+
*/
|
|
51
|
+
export declare function repoIdentity(dir: string): string | undefined;
|
|
52
|
+
export declare function resolveProjectId(url: string, token: string, wanted: string, workspace?: string, repo?: string,
|
|
53
|
+
/**
|
|
54
|
+
* The id `init` wrote into `.reticle.json`, for a project created by default: the platform is
|
|
55
|
+
* asked to keep it, so the folder and the dashboard name one project by one id. A platform that
|
|
56
|
+
* does not know the field ignores it and answers with its own, which is what gets linked.
|
|
57
|
+
*/
|
|
58
|
+
localId?: string): Promise<string>;
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
* A repo already knows its name: the directory it lives in. That is not a guess, it is the name its
|
|
12
12
|
* owner chose and the one they will look for in a project list.
|
|
13
13
|
*/
|
|
14
|
+
import { createHash } from 'node:crypto';
|
|
15
|
+
import { execFileSync } from 'node:child_process';
|
|
16
|
+
import { relative } from 'node:path';
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
import { PROJECT_ID_HASH_LENGTH } from '@reticlehq/core';
|
|
19
|
+
import { CredentialRefusedError, api, hint } from './cloud-kit.js';
|
|
14
20
|
/** Cap the slug so a deep or oddly-named checkout cannot produce an unreadable project id. */
|
|
15
21
|
const MAX_SLUG = 48;
|
|
16
22
|
/** The id used when a directory name yields nothing usable — the historical behaviour, unchanged. */
|
|
@@ -37,8 +43,107 @@ export const slugifyProjectName = (raw) => {
|
|
|
37
43
|
* do to rotate a key or repoint an environment — must land in that same project or the history
|
|
38
44
|
* silently splits in two, which is worse than the shared-bucket problem this fixes.
|
|
39
45
|
*/
|
|
40
|
-
export const defaultProjectFor = (cwdBasename, existingProjectId
|
|
46
|
+
export const defaultProjectFor = (cwdBasename, existingProjectId,
|
|
47
|
+
/** The `projectId` `init` wrote into `.reticle.json`, when there is one. */
|
|
48
|
+
localProjectId) => {
|
|
41
49
|
if (existingProjectId !== undefined && existingProjectId.length > 0)
|
|
42
50
|
return existingProjectId;
|
|
43
|
-
|
|
51
|
+
// The name part of `init`'s `<name>-<hash>`, else the id as written: a name the owner chose.
|
|
52
|
+
const named = localProjectId === undefined || 0 === localProjectId.length
|
|
53
|
+
? undefined
|
|
54
|
+
: (nameOfLocalId(localProjectId) ?? localProjectId);
|
|
55
|
+
return slugifyProjectName(named ?? cwdBasename);
|
|
44
56
|
};
|
|
57
|
+
/** `init`'s id is the app's name and a short hash of where it lives: `nina-todo-f96721e8`. */
|
|
58
|
+
const LOCAL_ID = new RegExp(`^(.+)-[0-9a-f]{${String(PROJECT_ID_HASH_LENGTH)}}$`);
|
|
59
|
+
/**
|
|
60
|
+
* The name part of the id `init` wrote. One project carried two names: `.reticle.json` said
|
|
61
|
+
* `nina-todo-f96721e8` (from the package) while the dashboard said `app` (the folder), so the person
|
|
62
|
+
* looked for one and the list showed the other. The dashboard now takes the name `init` wrote.
|
|
63
|
+
*/
|
|
64
|
+
function nameOfLocalId(localProjectId) {
|
|
65
|
+
return LOCAL_ID.exec(localProjectId)?.[1];
|
|
66
|
+
}
|
|
67
|
+
export const CreatedProjectSchema = z.object({ projectId: z.string(), name: z.string() });
|
|
68
|
+
const ProjectsListSchema = z.object({
|
|
69
|
+
projects: z.array(z.object({ projectId: z.string(), name: z.string(), repo: z.string().optional() })),
|
|
70
|
+
});
|
|
71
|
+
/** ` in workspace "<name>"`, or nothing when no name is known. */
|
|
72
|
+
export const inWorkspace = (name) => name === undefined || 0 === name.length ? '' : ` in workspace "${name}"`;
|
|
73
|
+
/** Characters of the repository identity: enough to tell repositories apart, nothing to read. */
|
|
74
|
+
const REPO_ID_CHARS = 16;
|
|
75
|
+
/**
|
|
76
|
+
* Which repository, and which folder in it, a project folder is: a hash of the `origin` remote and
|
|
77
|
+
* the folder's path inside the checkout, so every clone of one app agrees and two different apps
|
|
78
|
+
* both named `web` do not. Undefined outside git or with no remote. Neither leaves the machine.
|
|
79
|
+
*/
|
|
80
|
+
export function repoIdentity(dir) {
|
|
81
|
+
try {
|
|
82
|
+
const git = (...args) => execFileSync('git', args, {
|
|
83
|
+
cwd: dir,
|
|
84
|
+
encoding: 'utf8',
|
|
85
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
86
|
+
}).trim();
|
|
87
|
+
const remote = git('config', '--get', 'remote.origin.url')
|
|
88
|
+
.replace(/\.git$/, '')
|
|
89
|
+
.replace(/^[a-z+]+:\/\/|^[^@]+@/i, '')
|
|
90
|
+
.replace(':', '/')
|
|
91
|
+
.toLowerCase();
|
|
92
|
+
if (0 === remote.length)
|
|
93
|
+
return undefined;
|
|
94
|
+
const inside = relative(git('rev-parse', '--show-toplevel'), dir).split('\\').join('/');
|
|
95
|
+
return createHash('sha256')
|
|
96
|
+
.update(`${remote}\u0000${inside}`)
|
|
97
|
+
.digest('hex')
|
|
98
|
+
.slice(0, REPO_ID_CHARS);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The id for the project the caller named, creating it if it does not exist yet — and saying so,
|
|
106
|
+
* in which workspace. A project of that NAME made for another repository is not reused: two apps
|
|
107
|
+
* whose package is `web` shared one dashboard project. A project with no recorded repository, or an
|
|
108
|
+
* id named outright, is reused as before.
|
|
109
|
+
*/
|
|
110
|
+
/** Projects named when creating one was refused. */
|
|
111
|
+
const MAX_NAMED = 5;
|
|
112
|
+
export async function resolveProjectId(url, token, wanted, workspace, repo,
|
|
113
|
+
/**
|
|
114
|
+
* The id `init` wrote into `.reticle.json`, for a project created by default: the platform is
|
|
115
|
+
* asked to keep it, so the folder and the dashboard name one project by one id. A platform that
|
|
116
|
+
* does not know the field ignores it and answers with its own, which is what gets linked.
|
|
117
|
+
*/
|
|
118
|
+
localId) {
|
|
119
|
+
const { projects } = ProjectsListSchema.parse(await api('GET', `${url}/v1/projects`, token));
|
|
120
|
+
const lc = wanted.toLowerCase();
|
|
121
|
+
const holding = localId === undefined ? undefined : projects.find((p) => p.projectId === localId);
|
|
122
|
+
if (holding !== undefined)
|
|
123
|
+
return holding.projectId;
|
|
124
|
+
const match = projects.find((p) => p.projectId === wanted ||
|
|
125
|
+
(p.name.toLowerCase() === lc &&
|
|
126
|
+
(repo === undefined || p.repo === undefined || p.repo === repo)));
|
|
127
|
+
if (match !== undefined)
|
|
128
|
+
return match.projectId;
|
|
129
|
+
let answer;
|
|
130
|
+
try {
|
|
131
|
+
answer = await api('POST', `${url}/v1/projects`, token, {
|
|
132
|
+
name: wanted,
|
|
133
|
+
...(repo === undefined ? {} : { repo }),
|
|
134
|
+
...(localId === undefined ? {} : { projectId: localId }),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
// Refused to create one (a contributor): the platform's words, then the step that works.
|
|
139
|
+
if (error instanceof CredentialRefusedError ||
|
|
140
|
+
!(error instanceof Error) ||
|
|
141
|
+
0 === projects.length)
|
|
142
|
+
throw error;
|
|
143
|
+
const names = projects.map((p) => p.name).slice(0, MAX_NAMED);
|
|
144
|
+
throw new Error(`${error.message}\nTo link one that exists: ${names.map((n) => `\`reticle connect --project ${n}\``).join(', ')}`);
|
|
145
|
+
}
|
|
146
|
+
const created = CreatedProjectSchema.parse(answer);
|
|
147
|
+
hint(`created project "${wanted}" (${created.projectId})${inWorkspace(workspace)} — it did not exist yet`);
|
|
148
|
+
return created.projectId;
|
|
149
|
+
}
|
|
@@ -14,7 +14,23 @@ import type { OnboardingStep } from '@reticlehq/core/telemetry';
|
|
|
14
14
|
* so the entry point supplies it and every layer below stays a function of its arguments.
|
|
15
15
|
*/
|
|
16
16
|
export type StepReporter = (step: OnboardingStep) => void;
|
|
17
|
-
|
|
17
|
+
/** How many coding agents on this machine have Reticle's tools after this run. */
|
|
18
|
+
export declare function handleSetupMcp(reportStep: StepReporter, standalone?: boolean): number;
|
|
19
|
+
/**
|
|
20
|
+
* The one line the launchers read and strip: what they cannot know and the next steps depend on.
|
|
21
|
+
*
|
|
22
|
+
* The launchers own the closing words (served from main, so wording changes on merge) and used to
|
|
23
|
+
* print "restart your coding agent" to a machine with none, and "cd your-app" to somebody already
|
|
24
|
+
* standing in it. An older launcher shows this line as is; a launcher reading an older CLI finds no
|
|
25
|
+
* line and keeps its generic wording, so neither half has to ship first.
|
|
26
|
+
*/
|
|
27
|
+
export declare const INSTALL_RESULT_PREFIX = "RETICLE_INSTALL";
|
|
28
|
+
/** Whether the folder the installer ran in is an app: `init` runs here, or after a `cd`. */
|
|
29
|
+
export declare const InstallAppHere: {
|
|
30
|
+
readonly HERE: "here";
|
|
31
|
+
readonly NONE: "none";
|
|
32
|
+
};
|
|
33
|
+
export declare function installResultLine(agents: number, cwd: string): string;
|
|
18
34
|
/**
|
|
19
35
|
* `reticle setup install` — the Node half of the one-line installer.
|
|
20
36
|
*
|