@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
|
@@ -5,22 +5,37 @@
|
|
|
5
5
|
* `credentials.json` (per-project api keys from `reticle link`). The non-secret repo binding + sync policy
|
|
6
6
|
* is `<repo>/.reticle/cloud.json`. Auth for a command = `RETICLE_API_KEY` env (agent) OR the login token.
|
|
7
7
|
*/
|
|
8
|
+
import { CreatedProjectSchema } from './project-name.js';
|
|
9
|
+
import { keyRefusalAtLastSync } from '../../memory/project/sync-status.js';
|
|
8
10
|
import { apiKeyFrom } from '@reticlehq/core';
|
|
9
|
-
import {
|
|
11
|
+
import { PlatformLinkVia } from '@reticlehq/core/telemetry';
|
|
12
|
+
import { existsSync } from 'node:fs';
|
|
13
|
+
import { writeFile } from 'node:fs/promises';
|
|
10
14
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
11
15
|
import { homedir } from 'node:os';
|
|
12
|
-
import {
|
|
16
|
+
import { join } from 'node:path';
|
|
13
17
|
import { z } from 'zod';
|
|
14
18
|
import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
|
|
15
19
|
import { CLOUD_LINK_FILE, resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
20
|
+
import { memoryReadUrl, MemoryResponseScope, scopeMemoryResponse, scopeOfMemoryResponse, } from '../../memory/cloud/memory-scope.js';
|
|
21
|
+
import { linkDirectoryFrom } from '../../memory/project/link-directory.js';
|
|
18
22
|
import { RETICLE_CONFIG_BASENAME } from './ports/resolve/cli-port.js';
|
|
23
|
+
import { cmdLink, validateKey } from './cloud-link.js';
|
|
24
|
+
// `link` moved to its own module; the CLI entry still imports it from here.
|
|
25
|
+
export { cmdLink } from './cloud-link.js';
|
|
19
26
|
import { normalizeUrl } from './auth/cloud-session.js';
|
|
20
|
-
import { cmdLogin, cmdLogout } from './cloud-login.js';
|
|
21
|
-
import {
|
|
27
|
+
import { chooseWorkspace, cmdLogin, cmdLogout } from './cloud-login.js';
|
|
28
|
+
import { cmdTry } from './try-command.js';
|
|
29
|
+
import { CLOUD_COMMANDS } from './cli-parse-grammar.js';
|
|
30
|
+
import { api, baseUrl, bearer, emit, err, flags, hint, readJson, readSession, readSessionFor, RETICLE_DIR, } from './cloud-kit.js';
|
|
31
|
+
import { syncRequest } from '../../memory/cloud/cloud-sync.js';
|
|
32
|
+
import { GateExit, gateExitWith } from './answers/gate-exit.js';
|
|
33
|
+
import { brokenOf } from './known-regression.js';
|
|
34
|
+
import { describeUnsyncedBriefly } from '../../memory/cloud/unsynced-roots.js';
|
|
35
|
+
import { machineUnsyncedRoots } from '../../memory/project/sync-status.js';
|
|
22
36
|
import { describeSync, runSyncCycle } from '../../memory/cloud/sync-cycle.js';
|
|
23
37
|
import { diskSink, diskSource, readCloudIssues, readCloudState } from '../../memory/cloud/sync-disk.js';
|
|
38
|
+
import { fetchPlatformRun } from '../../features/harness/platform/platform-drives.js';
|
|
24
39
|
/**
|
|
25
40
|
* Where `reticle login` dials when nothing says otherwise: the hosted service.
|
|
26
41
|
*
|
|
@@ -40,25 +55,11 @@ import { diskSink, diskSource, readCloudIssues, readCloudState } from '../../mem
|
|
|
40
55
|
* override resolves through. This directory is what makes staging and production hold at the same
|
|
41
56
|
* time instead of clobbering each other, which is the whole reason a single file was not enough.
|
|
42
57
|
*/
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
'connect',
|
|
46
|
-
'logout',
|
|
47
|
-
'whoami',
|
|
48
|
-
'link',
|
|
49
|
-
'project',
|
|
50
|
-
'config',
|
|
51
|
-
'issues',
|
|
52
|
-
'memory',
|
|
53
|
-
'push',
|
|
54
|
-
'sync',
|
|
55
|
-
'runs',
|
|
56
|
-
'regression',
|
|
57
|
-
'share',
|
|
58
|
-
]);
|
|
59
|
-
export const isCloudCommand = (cmd) => cmd !== undefined && CLOUD_COMMANDS.has(cmd);
|
|
58
|
+
const CLOUD_COMMAND_SET = new Set(CLOUD_COMMANDS);
|
|
59
|
+
export const isCloudCommand = (cmd) => cmd !== undefined && CLOUD_COMMAND_SET.has(cmd);
|
|
60
60
|
/** `reticle sync --watch` — keep cycling instead of exiting. */
|
|
61
61
|
const WATCH_FLAG = '--watch';
|
|
62
|
+
const MOVE_HISTORY_FLAG = '--move-history';
|
|
62
63
|
/**
|
|
63
64
|
* How often `--watch` cycles.
|
|
64
65
|
*
|
|
@@ -68,78 +69,15 @@ const WATCH_FLAG = '--watch';
|
|
|
68
69
|
*/
|
|
69
70
|
const DEFAULT_SYNC_INTERVAL_MS = 60_000;
|
|
70
71
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* at a glance which row this repo is using.
|
|
75
|
-
*/
|
|
76
|
-
const KEY_HINT_CHARS = 16;
|
|
77
|
-
const keyHint = (key) => key.length <= KEY_HINT_CHARS ? key : `${key.slice(0, KEY_HINT_CHARS)}…`;
|
|
78
|
-
/**
|
|
79
|
-
* The api key this machine already holds for a project ON THIS CLOUD, if any.
|
|
80
|
-
*
|
|
81
|
-
* Two shapes, matching the resolver: `{ key, url }` is what `link` writes now and is only returned
|
|
82
|
-
* when the URL matches, and a bare string is the legacy shape with no URL to check. Without the URL
|
|
83
|
-
* check this would happily reuse a production key for a self-hosted link, because `link` names
|
|
84
|
-
* every project "default" and the two collide in one slot.
|
|
85
|
-
*/
|
|
86
|
-
const storedCredential = async (projectId, url, orgId) => findCredential(await readJson(join(home(), CREDENTIALS_FILE)), projectId, url, orgId);
|
|
87
|
-
/**
|
|
88
|
-
* What a key is good for, or undefined when the cloud will not accept it.
|
|
89
|
-
*
|
|
90
|
-
* Never throws: a revoked key, a rotated one and an unreachable cloud are all "cannot reuse this",
|
|
91
|
-
* and the caller's answer to every one of them is the same — mint a fresh one.
|
|
72
|
+
* The `.reticle` this folder's commands read and write: the project `link` binds (see
|
|
73
|
+
* `linkDirectoryFor`), so `sync` from a monorepo root reaches the app it linked — unless only this
|
|
74
|
+
* folder holds a link, made before `link` followed the project, which keeps working.
|
|
92
75
|
*/
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
const KeySchema = z.object({ projectId: z.string(), projectName: z.string(), key: z.string() });
|
|
102
|
-
const WhoamiSchema = z.object({
|
|
103
|
-
projectId: z.string(),
|
|
104
|
-
projectName: z.string(),
|
|
105
|
-
/**
|
|
106
|
-
* Which tenant the key belongs to. Optional for the same reason `dashboardUrl` is — an older
|
|
107
|
-
* cloud does not send it — and when it is missing a stored key cannot be proved to be ours, which
|
|
108
|
-
* is why the reuse path below mints instead of guessing.
|
|
109
|
-
*/
|
|
110
|
-
orgId: z.string().optional(),
|
|
111
|
-
/**
|
|
112
|
-
* Where this project's dashboard lives. Optional because an older cloud does not send it, and a
|
|
113
|
-
* CLI that refused to link against one would break the thing it is supposed to connect.
|
|
114
|
-
*/
|
|
115
|
-
dashboardUrl: z.string().optional(),
|
|
116
|
-
});
|
|
117
|
-
const CreatedProjectSchema = z.object({ projectId: z.string(), name: z.string() });
|
|
118
|
-
const ProjectsListSchema = z.object({
|
|
119
|
-
projects: z.array(z.object({ projectId: z.string(), name: z.string() })),
|
|
120
|
-
});
|
|
121
|
-
/** Resolve a --project value that may be a slug id OR a display name into the canonical projectId. */
|
|
122
|
-
/**
|
|
123
|
-
* The id for the project the caller named, creating it if it does not exist yet.
|
|
124
|
-
*
|
|
125
|
-
* It used to refuse — "create it with `reticle project create`" — which made naming a project a
|
|
126
|
-
* two-command bookkeeping ritual for the COMMON case: a first repo, whose project has of course not
|
|
127
|
-
* been created yet. That refusal is also the only reason the magic path existed: bare `link` binds
|
|
128
|
-
* to a project called `Default` precisely so nobody has to meet this error.
|
|
129
|
-
*
|
|
130
|
-
* Creating is announced rather than silent. A tool that quietly invents a durable, billable object
|
|
131
|
-
* is its own surprise, and the whole point of this change is that the automatic path SAYS what it
|
|
132
|
-
* did.
|
|
133
|
-
*/
|
|
134
|
-
const resolveProjectId = async (url, token, wanted) => {
|
|
135
|
-
const { projects } = ProjectsListSchema.parse(await api('GET', `${url}/v1/projects`, token));
|
|
136
|
-
const lc = wanted.toLowerCase();
|
|
137
|
-
const match = projects.find((p) => p.projectId === wanted || p.name.toLowerCase() === lc);
|
|
138
|
-
if (match !== undefined)
|
|
139
|
-
return match.projectId;
|
|
140
|
-
const created = CreatedProjectSchema.parse(await api('POST', `${url}/v1/projects`, token, { name: wanted }));
|
|
141
|
-
hint(`created project "${wanted}" (${created.projectId}) — it did not exist yet`);
|
|
142
|
-
return created.projectId;
|
|
76
|
+
const linkedRoot = () => {
|
|
77
|
+
const project = join(linkDirectoryFrom(process.cwd()), RETICLE_DIR);
|
|
78
|
+
const here = join(process.cwd(), RETICLE_DIR);
|
|
79
|
+
const onlyHere = !existsSync(join(project, CLOUD_LINK_FILE)) && existsSync(join(here, CLOUD_LINK_FILE));
|
|
80
|
+
return onlyHere ? here : project;
|
|
143
81
|
};
|
|
144
82
|
/**
|
|
145
83
|
* `reticle whoami` — the one call an agent (or a confused human) makes to know its state: who am I logged
|
|
@@ -148,13 +86,13 @@ const resolveProjectId = async (url, token, wanted) => {
|
|
|
148
86
|
const cmdWhoami = async () => {
|
|
149
87
|
const session = await readSession();
|
|
150
88
|
const fs = createNodeFileSystem();
|
|
151
|
-
const cloud = await resolveProjectCloud(fs,
|
|
89
|
+
const cloud = await resolveProjectCloud(fs, linkedRoot(), homedir(), process.env);
|
|
152
90
|
/*
|
|
153
91
|
* The sync half of "what is my state". Without it the honest answer to "why does the dashboard
|
|
154
92
|
* look old?" was to go and read a JSON file — and the two failure modes a person actually hits
|
|
155
93
|
* (nothing has synced yet, and the last attempt errored) looked identical from out here.
|
|
156
94
|
*/
|
|
157
|
-
const reticleRoot =
|
|
95
|
+
const reticleRoot = linkedRoot();
|
|
158
96
|
const state = readCloudState(reticleRoot);
|
|
159
97
|
const decisions = Object.keys(readCloudIssues(reticleRoot).triage).length;
|
|
160
98
|
emit({
|
|
@@ -176,10 +114,35 @@ const cmdWhoami = async () => {
|
|
|
176
114
|
verify: cloud.verify,
|
|
177
115
|
},
|
|
178
116
|
});
|
|
117
|
+
// Signed out, `link` refuses with "run reticle login first"; `connect` does both in one go.
|
|
179
118
|
if (null === cloud.config)
|
|
180
|
-
hint(
|
|
119
|
+
hint(null === session
|
|
120
|
+
? 'this repo is not attached — run `reticle connect` (signs in and links in one step)'
|
|
121
|
+
: 'this repo is not attached — run `reticle connect`');
|
|
181
122
|
return 0;
|
|
182
123
|
};
|
|
124
|
+
/**
|
|
125
|
+
* Who is signed in and which project this repo is linked to, for `reticle status`. Local files
|
|
126
|
+
* only: status must answer with no network.
|
|
127
|
+
*/
|
|
128
|
+
export const accountStatusFields = async () => {
|
|
129
|
+
const session = await readSession();
|
|
130
|
+
const cloud = await resolveProjectCloud(createNodeFileSystem(), linkedRoot(), homedir(), process.env);
|
|
131
|
+
// What the last sync heard, from local state, in the platform's words when it named the reason.
|
|
132
|
+
const refused = keyRefusalAtLastSync(linkedRoot());
|
|
133
|
+
const link = await readJson(join(linkedRoot(), CLOUD_LINK_FILE));
|
|
134
|
+
const workspace = 'object' === typeof link && null !== link
|
|
135
|
+
? link['workspace']
|
|
136
|
+
: undefined;
|
|
137
|
+
return {
|
|
138
|
+
signedInAs: session?.orgName ?? null,
|
|
139
|
+
linkedProject: null === cloud.config ? null : cloud.projectId,
|
|
140
|
+
...(null !== cloud.config && 'string' === typeof workspace && 0 < workspace.length
|
|
141
|
+
? { linkedWorkspace: workspace }
|
|
142
|
+
: {}),
|
|
143
|
+
...(refused === undefined ? {} : { keyRefused: refused }),
|
|
144
|
+
};
|
|
145
|
+
};
|
|
183
146
|
/** `reticle project ls` / `reticle project create <name>` — key- or session-authed. */
|
|
184
147
|
const cmdProject = async (argv) => {
|
|
185
148
|
const active = await readSession();
|
|
@@ -190,8 +153,8 @@ const cmdProject = async (argv) => {
|
|
|
190
153
|
// Name BOTH hosts when there is a session for a different one. "Run reticle login" on its own is
|
|
191
154
|
// baffling to somebody who just did — the useful fact is that they logged in somewhere else.
|
|
192
155
|
err(null !== active && normalizeUrl(active.url) !== url
|
|
193
|
-
? `signed in to ${normalizeUrl(active.url)}, but this command targets ${url} — run \`reticle
|
|
194
|
-
: `not signed in to ${url} — run \`reticle
|
|
156
|
+
? `signed in to ${normalizeUrl(active.url)}, but this command targets ${url} — run \`reticle connect --url ${url}\`, or set RETICLE_API_KEY`
|
|
157
|
+
: `not signed in to ${url} — run \`reticle connect --url ${url}\`, or set RETICLE_API_KEY`);
|
|
195
158
|
return 2;
|
|
196
159
|
}
|
|
197
160
|
const sub = argv[0];
|
|
@@ -207,7 +170,7 @@ const cmdProject = async (argv) => {
|
|
|
207
170
|
}
|
|
208
171
|
const created = CreatedProjectSchema.parse(await api('POST', `${url}/v1/projects`, token, { name }));
|
|
209
172
|
emit(created);
|
|
210
|
-
hint(`next: \`reticle
|
|
173
|
+
hint(`next: \`reticle connect --project ${created.projectId}\` to bind this repo`);
|
|
211
174
|
return 0;
|
|
212
175
|
}
|
|
213
176
|
if ('rename' === sub) {
|
|
@@ -232,228 +195,24 @@ const cmdProject = async (argv) => {
|
|
|
232
195
|
err('usage: reticle project <ls|create <name>|rename <id> <name>|rm <id>>');
|
|
233
196
|
return 2;
|
|
234
197
|
};
|
|
198
|
+
const NO_INSTALL = '--no-install';
|
|
199
|
+
/** Whether `reticle connect`'s init half installs the packages: not under `--no-install`. */
|
|
200
|
+
export const connectInstalls = (argv) => !argv.includes(NO_INSTALL);
|
|
235
201
|
/**
|
|
236
|
-
* `reticle
|
|
237
|
-
*
|
|
238
|
-
* whoami. Writes the non-secret binding to <repo>/.reticle/cloud.json and the secret key to
|
|
239
|
-
* ~/.reticle/credentials.json (keyed by projectId).
|
|
202
|
+
* `reticle connect`: the cloud half of first-run setup in one go. A saved login is checked against
|
|
203
|
+
* this host first; it links once, in the workspace chosen, then sends local history.
|
|
240
204
|
*/
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
const
|
|
244
|
-
// Same rule as every other authed verb: the token is looked up by the host it will be sent to.
|
|
245
|
-
const session = await readSessionFor(url);
|
|
246
|
-
const envKey = apiKeyFrom(process.env);
|
|
247
|
-
/*
|
|
248
|
-
* Read the existing binding FIRST, because it decides which project a bare `link` targets.
|
|
249
|
-
* Re-running `link` is ordinary — rotating a key, repointing an environment — and it must land in
|
|
250
|
-
* the project this repo already reports to, or its history splits in two without saying so.
|
|
251
|
-
*/
|
|
252
|
-
const priorLink = await readJson(join(process.cwd(), RETICLE_DIR, CLOUD_LINK_FILE));
|
|
253
|
-
const priorProjectId = 'object' === typeof priorLink && priorLink !== null
|
|
254
|
-
? priorLink['projectId']
|
|
255
|
-
: undefined;
|
|
256
|
-
let projectId;
|
|
257
|
-
let projectName;
|
|
258
|
-
let key;
|
|
259
|
-
/**
|
|
260
|
-
* The tenant this binding belongs to, recorded so the credential can be filed and found per-org.
|
|
261
|
-
* Undefined against an older cloud, where the slot stays cloud+project as it always was.
|
|
262
|
-
*/
|
|
263
|
-
let orgId;
|
|
264
|
-
/** The key this machine already had for the slot, and whether it provably belongs to another tenant. */
|
|
265
|
-
let priorKey;
|
|
266
|
-
let priorIsForeign = false;
|
|
267
|
-
/*
|
|
268
|
-
* Where this project's dashboard lives. Asked of the cloud rather than derived from `url`: the API
|
|
269
|
-
* origin and the console origin are different hosts in every deployment that is not a laptop, so a
|
|
270
|
-
* link the CLI guessed would be wrong exactly where it matters.
|
|
271
|
-
*/
|
|
272
|
-
let dashboardUrl;
|
|
273
|
-
/** Whether the key was already on this machine — so the report can say so instead of "minted". */
|
|
274
|
-
let reusedKey = false;
|
|
275
|
-
// Tracked separately from the value: an OLDER cloud answers whoami without a dashboardUrl, and
|
|
276
|
-
// keying the fallback off the value would ask the same question twice every time.
|
|
277
|
-
let askedWhoami = false;
|
|
278
|
-
if (envKey !== undefined && envKey.length > 0) {
|
|
279
|
-
const who = WhoamiSchema.parse(await api('GET', `${url}/v1/cloud/whoami`, envKey));
|
|
280
|
-
projectId = who.projectId;
|
|
281
|
-
projectName = who.projectName;
|
|
282
|
-
dashboardUrl = who.dashboardUrl;
|
|
283
|
-
orgId = who.orgId;
|
|
284
|
-
askedWhoami = true;
|
|
285
|
-
key = envKey;
|
|
286
|
-
}
|
|
287
|
-
else if (session !== null) {
|
|
288
|
-
// --project accepts a slug id OR a display name; default when omitted. Resolve to the canonical id.
|
|
289
|
-
const wanted = f['project'];
|
|
290
|
-
/*
|
|
291
|
-
* A repo is named after itself, not "Default".
|
|
292
|
-
*
|
|
293
|
-
* When every repo binds to one project called "Default", two unrelated checkouts on one account
|
|
294
|
-
* merge their runs, issues and impact into a single bucket and the per-project view describes
|
|
295
|
-
* nothing. It is also what lets two TENANTS collide, since a credential slot built from a
|
|
296
|
-
* project id is only as distinct as the ids are.
|
|
297
|
-
*/
|
|
298
|
-
const fallback = defaultProjectFor(basename(process.cwd()), 'string' === typeof priorProjectId ? priorProjectId : undefined);
|
|
299
|
-
const targetId = wanted === undefined
|
|
300
|
-
? await resolveProjectId(url, session.token, fallback)
|
|
301
|
-
: await resolveProjectId(url, session.token, wanted);
|
|
302
|
-
/*
|
|
303
|
-
* Reuse the key this machine already holds for the project, rather than minting another.
|
|
304
|
-
*
|
|
305
|
-
* `link` was idempotent about the BINDING and not about the KEY: two runs against one project
|
|
306
|
-
* left two live `reticle-cli` keys on the account, each valid, neither identifiable to a repo.
|
|
307
|
-
* Agents retry — that is what agents do — so it accumulates silently until somebody has a key
|
|
308
|
-
* list they cannot reason about and revokes the wrong one.
|
|
309
|
-
*
|
|
310
|
-
* Validated before trusting, because a stored key can have been revoked or rotated from the
|
|
311
|
-
* dashboard and a stale credential must not strand the repo. The check is the whoami call the
|
|
312
|
-
* mint path already makes for `dashboardUrl`, so the common path costs no extra round trip —
|
|
313
|
-
* and a key that fails it is replaced rather than reported.
|
|
314
|
-
*/
|
|
315
|
-
const existing = await storedCredential(targetId, url, session.orgId);
|
|
316
|
-
const validated = existing === undefined ? undefined : await validateKey(url, existing);
|
|
317
|
-
/*
|
|
318
|
-
* A valid key is not the same as OUR key.
|
|
319
|
-
*
|
|
320
|
-
* `validateKey` only asks whether the cloud still accepts it, and a key belonging to another
|
|
321
|
-
* organisation on the same cloud passes that question perfectly. With every project named
|
|
322
|
-
* "default", the slot `<url>::default` was shared across tenants — so a brand-new workspace
|
|
323
|
-
* signing in on a machine that had linked a different account reused that account's key and
|
|
324
|
-
* would have pushed its runs into a stranger's dashboard. Measured, not hypothesised.
|
|
325
|
-
*
|
|
326
|
-
* So reuse now requires PROOF of a tenant match, and treats anything less as no match: an older
|
|
327
|
-
* cloud that omits `orgId`, or a session file written before we recorded one, both fall through
|
|
328
|
-
* to minting. Minting a second key is a tidiness problem; pushing to the wrong tenant is a
|
|
329
|
-
* disclosure, and only one of those is worth defaulting to.
|
|
330
|
-
*/
|
|
331
|
-
const sameTenant = validated !== undefined &&
|
|
332
|
-
session.orgId !== undefined &&
|
|
333
|
-
validated.orgId !== undefined &&
|
|
334
|
-
validated.orgId === session.orgId;
|
|
335
|
-
const reusable = sameTenant ? validated : undefined;
|
|
336
|
-
priorKey = existing;
|
|
337
|
-
// Provably somebody else's: it still works on this cloud AND whoami names a different org. A key
|
|
338
|
-
// that merely FAILED validation is our own revoked one, and overwriting that is the point.
|
|
339
|
-
priorIsForeign =
|
|
340
|
-
validated !== undefined &&
|
|
341
|
-
validated.orgId !== undefined &&
|
|
342
|
-
session.orgId !== undefined &&
|
|
343
|
-
validated.orgId !== session.orgId;
|
|
344
|
-
if (existing !== undefined && reusable !== undefined) {
|
|
345
|
-
projectId = reusable.projectId;
|
|
346
|
-
projectName = reusable.projectName;
|
|
347
|
-
dashboardUrl = reusable.dashboardUrl;
|
|
348
|
-
orgId = reusable.orgId;
|
|
349
|
-
askedWhoami = true;
|
|
350
|
-
key = existing;
|
|
351
|
-
reusedKey = true;
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
const minted = KeySchema.parse(await api('POST', `${url}/v1/keys`, session.token, {
|
|
355
|
-
name: 'reticle-cli',
|
|
356
|
-
projectId: targetId,
|
|
357
|
-
}));
|
|
358
|
-
projectId = minted.projectId;
|
|
359
|
-
projectName = minted.projectName;
|
|
360
|
-
key = minted.key;
|
|
361
|
-
// The key was minted WITH this session, so its tenant is this session's by construction.
|
|
362
|
-
orgId = session.orgId;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
err('run `reticle login` first, or set RETICLE_API_KEY to link with an existing key');
|
|
367
|
-
return 2;
|
|
368
|
-
}
|
|
369
|
-
const reticleDir = join(process.cwd(), RETICLE_DIR);
|
|
370
|
-
await mkdir(reticleDir, { recursive: true });
|
|
371
|
-
const linkPath = join(reticleDir, CLOUD_LINK_FILE);
|
|
372
|
-
const prev = await readJson(linkPath);
|
|
373
|
-
const prevObj = 'object' === typeof prev && prev !== null ? prev : {};
|
|
374
|
-
// The minted-key path has not asked yet. Best-effort: a link that works is worth more than a link
|
|
375
|
-
// that also has a link in it, and an older cloud simply does not send one.
|
|
376
|
-
if (!askedWhoami) {
|
|
377
|
-
try {
|
|
378
|
-
const who = WhoamiSchema.parse(await api('GET', `${url}/v1/cloud/whoami`, key));
|
|
379
|
-
dashboardUrl = who.dashboardUrl;
|
|
380
|
-
// Only FILL IN a tenant we do not have. The session we minted with is the authority on which
|
|
381
|
-
// org this key belongs to; letting a later lookup overwrite it is how the answer drifts.
|
|
382
|
-
orgId = orgId ?? who.orgId;
|
|
383
|
-
}
|
|
384
|
-
catch {
|
|
385
|
-
// Older cloud, or a transient failure. The HUD shows its list without a link.
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
const cloudJson = {
|
|
389
|
-
projectId,
|
|
390
|
-
projectName,
|
|
391
|
-
// Recorded so the daemon resolves the credential in the ORG slot rather than the ambiguous
|
|
392
|
-
// cloud+project one, which two tenants on one cloud both answer to.
|
|
393
|
-
...(orgId === undefined ? {} : { orgId }),
|
|
394
|
-
url,
|
|
395
|
-
...(dashboardUrl === undefined ? {} : { dashboardUrl }),
|
|
396
|
-
sync: prevObj['sync'] ?? { runs: true, memory: true, flows: true },
|
|
397
|
-
verify: prevObj['verify'] ?? 'local',
|
|
398
|
-
};
|
|
399
|
-
await writeFile(linkPath, `${JSON.stringify(cloudJson, null, 2)}\n`);
|
|
400
|
-
await mkdir(home(), { recursive: true });
|
|
401
|
-
const credPath = join(home(), CREDENTIALS_FILE);
|
|
402
|
-
const creds = (await readJson(credPath)) ?? {};
|
|
403
|
-
const credObj = applyCredential('object' === typeof creds && creds !== null ? creds : {}, { projectId, url, key, orgId, priorKey, priorIsForeign });
|
|
404
|
-
await writeFile(credPath, `${JSON.stringify(credObj, null, 2)}\n`);
|
|
405
|
-
emit({ linked: projectName, projectId, cloudJson: linkPath, credentials: credPath });
|
|
406
|
-
/*
|
|
407
|
-
* Say what just happened, in the vocabulary of somebody who has used other tools.
|
|
408
|
-
*
|
|
409
|
-
* `link` mints the key and stores it for you, which is the product's whole edge — and it is
|
|
410
|
-
* invisible, which is its whole cost. A real report: somebody pasted a masked placeholder key
|
|
411
|
-
* into a `.env` because their mental model said "I must make a key and put it somewhere". One had
|
|
412
|
-
* already been minted and filed outside the repo. They did not need another step; they needed to
|
|
413
|
-
* be told the step had happened.
|
|
414
|
-
*
|
|
415
|
-
* The key is identified the way the dashboard identifies it — a prefix, never the secret — so
|
|
416
|
-
* this can be read aloud, pasted into an issue, or left in a terminal without leaking anything.
|
|
417
|
-
*/
|
|
418
|
-
hint(`bound this repo to project "${projectName}"`);
|
|
419
|
-
hint(reusedKey
|
|
420
|
-
? `reusing key ${keyHint(key)} — already stored in ${credPath}, not in your repo`
|
|
421
|
-
: `minted key ${keyHint(key)} — stored in ${credPath}, not in your repo`);
|
|
422
|
-
hint('to change it: `reticle link --project <other>`; to inspect: `reticle whoami`');
|
|
423
|
-
hint('linked ✓ runs auto-push on `reticle verify`; `reticle push` sends existing local runs; `reticle whoami` shows state');
|
|
424
|
-
/*
|
|
425
|
-
* A binding is not a connection.
|
|
426
|
-
*
|
|
427
|
-
* Without `.reticle.json` the app's bundle carries no projectId, so the daemon cannot attribute a
|
|
428
|
-
* session to this repo: its runs pool into whichever root the daemon itself was started in, and
|
|
429
|
-
* `sync` here reports "nothing to send" however much was actually recorded. Measured on this
|
|
430
|
-
* repo's bench app — two verdicts driven, then a sync that claimed there was nothing.
|
|
431
|
-
*
|
|
432
|
-
* Said AFTER the success line rather than refusing: the binding really was written and really is
|
|
433
|
-
* correct, and the missing half is one command away. Refusing would strand somebody who links
|
|
434
|
-
* before they install, which is a legitimate order to work in.
|
|
435
|
-
*/
|
|
436
|
-
if (!(await createNodeFileSystem().exists(join(process.cwd(), RETICLE_CONFIG_BASENAME)))) {
|
|
437
|
-
hint(`no ${RETICLE_CONFIG_BASENAME} here, so this app announces no project — its runs will not be ` +
|
|
438
|
-
'attributed to this binding. Run `reticle init` in the app, then restart the dev server.');
|
|
439
|
-
}
|
|
440
|
-
return 0;
|
|
441
|
-
};
|
|
442
|
-
/**
|
|
443
|
-
* `reticle connect` finishes the cloud half of first-run setup in one invocation. The CLI entry
|
|
444
|
-
* initializes an unwired app before calling this verb. A saved login is checked against this exact
|
|
445
|
-
* host before reuse; an expired one opens the normal browser approval flow. Login does not auto-link
|
|
446
|
-
* here because this command links once, to the project the caller named, then sends local history.
|
|
447
|
-
*/
|
|
448
|
-
const cmdConnect = async (argv) => {
|
|
205
|
+
const cmdConnect = async (given) => {
|
|
206
|
+
// `--no-install` is the init half's (see `connectInstalls`); the cloud half takes it and moves on.
|
|
207
|
+
const argv = given.filter((arg) => NO_INSTALL !== arg);
|
|
449
208
|
for (let i = 0; i < argv.length; i += 2) {
|
|
450
209
|
const flag = argv[i];
|
|
451
210
|
const value = argv[i + 1];
|
|
452
|
-
if ((flag !== '--project' && flag !== '--url') ||
|
|
211
|
+
if ((flag !== '--project' && flag !== '--url' && flag !== '--workspace') ||
|
|
453
212
|
value === undefined ||
|
|
454
213
|
0 === value.length ||
|
|
455
214
|
value.startsWith('--')) {
|
|
456
|
-
err('usage: reticle connect [--project <name|id>] [--url <
|
|
215
|
+
err('usage: reticle connect [--project <name|id>] [--workspace <name|id>] [--url <origin>] [--no-install]');
|
|
457
216
|
return 2;
|
|
458
217
|
}
|
|
459
218
|
}
|
|
@@ -481,12 +240,15 @@ const cmdConnect = async (argv) => {
|
|
|
481
240
|
return code;
|
|
482
241
|
}
|
|
483
242
|
}
|
|
243
|
+
const chosen = await chooseWorkspace(url, f['workspace']);
|
|
244
|
+
if (chosen !== 0)
|
|
245
|
+
return chosen;
|
|
484
246
|
const linkArgs = [
|
|
485
247
|
'--url',
|
|
486
248
|
url,
|
|
487
249
|
...(f['project'] === undefined ? [] : ['--project', f['project']]),
|
|
488
250
|
];
|
|
489
|
-
const linked = await cmdLink(linkArgs);
|
|
251
|
+
const linked = await cmdLink(linkArgs, process.cwd(), PlatformLinkVia.CONNECT);
|
|
490
252
|
if (linked !== 0)
|
|
491
253
|
return linked;
|
|
492
254
|
const pushed = await cmdPush();
|
|
@@ -498,10 +260,10 @@ const cmdConnect = async (argv) => {
|
|
|
498
260
|
/** `reticle config [--runs on|off] [--memory on|off] [--flows on|off] [--verify local|server]`. */
|
|
499
261
|
const cmdConfig = async (argv) => {
|
|
500
262
|
const f = flags(argv);
|
|
501
|
-
const linkPath = join(
|
|
263
|
+
const linkPath = join(linkedRoot(), CLOUD_LINK_FILE);
|
|
502
264
|
const raw = await readJson(linkPath);
|
|
503
265
|
if (null === raw || typeof raw !== 'object') {
|
|
504
|
-
err('no .reticle/cloud.json here — run `reticle
|
|
266
|
+
err('no .reticle/cloud.json here — run `reticle connect` first');
|
|
505
267
|
return 2;
|
|
506
268
|
}
|
|
507
269
|
const cfg = raw;
|
|
@@ -532,7 +294,7 @@ const cmdConfig = async (argv) => {
|
|
|
532
294
|
return 0;
|
|
533
295
|
};
|
|
534
296
|
/**
|
|
535
|
-
* `reticle sync [--watch]` — one full cycle: send the difference, collect what came back.
|
|
297
|
+
* `reticle sync [--watch] [--move-history]` — one full cycle: send the difference, collect what came back.
|
|
536
298
|
*
|
|
537
299
|
* This replaced a `push` that re-uploaded every run artifact on every invocation. That was fine with
|
|
538
300
|
* three runs and absurd with three hundred, and it only ever went one way — so a bug somebody
|
|
@@ -543,12 +305,15 @@ const cmdConfig = async (argv) => {
|
|
|
543
305
|
*/
|
|
544
306
|
const cmdSync = async (argv) => {
|
|
545
307
|
const fs = createNodeFileSystem();
|
|
546
|
-
const reticleRoot =
|
|
308
|
+
const reticleRoot = linkedRoot();
|
|
547
309
|
const cloud = await resolveProjectCloud(fs, reticleRoot, homedir(), process.env);
|
|
548
310
|
if (null === cloud.config) {
|
|
549
|
-
err(cloud.reason ?? 'cloud not attached here: run `reticle
|
|
311
|
+
err(cloud.reason ?? 'cloud not attached here: run `reticle connect`, or set RETICLE_API_KEY');
|
|
312
|
+
await reportUnsynced(fs);
|
|
550
313
|
return 1;
|
|
551
314
|
}
|
|
315
|
+
if (cloud.note !== undefined)
|
|
316
|
+
err(cloud.note);
|
|
552
317
|
const config = cloud.config;
|
|
553
318
|
const full = diskSource(reticleRoot);
|
|
554
319
|
const source = {
|
|
@@ -557,18 +322,21 @@ const cmdSync = async (argv) => {
|
|
|
557
322
|
capsules: () => (cloud.policy.capsules ? full.capsules() : []),
|
|
558
323
|
// `memory` is the project's cross-run history and the derived records that summarise it.
|
|
559
324
|
derived: (kind) => cloud.policy.memory ? full.derived(kind) : undefined,
|
|
325
|
+
...(cloud.policy.screenshots && full.screenshot !== undefined
|
|
326
|
+
? { screenshot: full.screenshot }
|
|
327
|
+
: {}),
|
|
560
328
|
};
|
|
561
329
|
const once = async () => {
|
|
562
330
|
const report = await runSyncCycle({
|
|
563
331
|
config,
|
|
332
|
+
...(cloud.link === undefined ? {} : { link: cloud.link }),
|
|
333
|
+
// Runs made under a folder's previous link go only when the person says so.
|
|
334
|
+
...(argv.includes(MOVE_HISTORY_FLAG) ? { moveHistory: true } : {}),
|
|
564
335
|
source,
|
|
565
336
|
sink: diskSink(reticleRoot),
|
|
566
337
|
state: readCloudState(reticleRoot),
|
|
567
338
|
now: () => Date.now(),
|
|
568
|
-
request:
|
|
569
|
-
const res = await fetch(url, init);
|
|
570
|
-
return { status: res.status, text: await res.text() };
|
|
571
|
-
},
|
|
339
|
+
request: (url, init) => syncRequest(url, init),
|
|
572
340
|
});
|
|
573
341
|
emit({
|
|
574
342
|
ok: report.ok,
|
|
@@ -587,6 +355,7 @@ const cmdSync = async (argv) => {
|
|
|
587
355
|
...(report.error === undefined ? {} : { error: report.error }),
|
|
588
356
|
});
|
|
589
357
|
hint(describeSync(report));
|
|
358
|
+
await reportUnsynced(fs);
|
|
590
359
|
return report.ok ? 0 : 1;
|
|
591
360
|
};
|
|
592
361
|
const watch = argv.includes(WATCH_FLAG);
|
|
@@ -599,20 +368,57 @@ const cmdSync = async (argv) => {
|
|
|
599
368
|
await sleep(everyMs);
|
|
600
369
|
}
|
|
601
370
|
};
|
|
371
|
+
/**
|
|
372
|
+
* Every other folder on this machine holding runs the platform never got, one line each. `sync` only
|
|
373
|
+
* ever sends the folder it runs in, so a monorepo app's unlinked `.reticle` was invisible from here.
|
|
374
|
+
*/
|
|
375
|
+
const reportUnsynced = async (fs) => {
|
|
376
|
+
for (const line of describeUnsyncedBriefly(await machineUnsyncedRoots(fs, homedir(), process.env), process.cwd()))
|
|
377
|
+
hint(line);
|
|
378
|
+
};
|
|
602
379
|
/** `reticle push` — the name people already type. One cycle, same as `reticle sync`. */
|
|
603
380
|
const cmdPush = async () => cmdSync([]);
|
|
604
|
-
/**
|
|
381
|
+
/**
|
|
382
|
+
* The linked project: its cloud, and the ID the link declares. Throws a friendly error when not
|
|
383
|
+
* attached.
|
|
384
|
+
*
|
|
385
|
+
* The id rides along for `reticle memory`, whose entire job is "what does THIS project know" and
|
|
386
|
+
* which was asking with nothing but the API key. A key covers a workspace, not a repo, so on a
|
|
387
|
+
* workspace with two repos it could print a sibling's established knowledge under this project's
|
|
388
|
+
* heading with no way for the reader to tell. See `memory-scope.ts`.
|
|
389
|
+
*
|
|
390
|
+
* The other `repoCloud()` callers below still read with the key alone. That is not an oversight
|
|
391
|
+
* being papered over: this change is scoped to the memory read, and the rest each need their own
|
|
392
|
+
* look at what the platform filters on.
|
|
393
|
+
*/
|
|
605
394
|
const repoCloud = async () => {
|
|
606
395
|
const fs = createNodeFileSystem();
|
|
607
|
-
const cloud = await resolveProjectCloud(fs,
|
|
396
|
+
const cloud = await resolveProjectCloud(fs, linkedRoot(), homedir(), process.env);
|
|
608
397
|
if (null === cloud.config)
|
|
609
|
-
throw new Error(cloud.reason ?? 'cloud not attached here: run `reticle
|
|
610
|
-
return cloud.config;
|
|
398
|
+
throw new Error(cloud.reason ?? 'cloud not attached here: run `reticle connect`, or set RETICLE_API_KEY');
|
|
399
|
+
return { ...cloud.config, projectId: cloud.projectId };
|
|
611
400
|
};
|
|
612
401
|
/** `reticle runs` — the linked project's recent run artifacts (the key scopes it server-side). */
|
|
613
|
-
|
|
402
|
+
/**
|
|
403
|
+
* `reticle runs [<id>]` — the project's runs, or one of them by id.
|
|
404
|
+
*
|
|
405
|
+
* With an id it is the way back to a Harness drive whose local record is gone (another machine, a
|
|
406
|
+
* cleaned checkout): the platform keeps the run. A 404 is "not synced yet, or not found", never a
|
|
407
|
+
* crash, since a run written a minute ago may simply not have been pushed.
|
|
408
|
+
*/
|
|
409
|
+
const cmdRuns = async (argv) => {
|
|
614
410
|
const { url, apiKey } = await repoCloud();
|
|
615
|
-
|
|
411
|
+
const id = argv[0];
|
|
412
|
+
if (id === undefined) {
|
|
413
|
+
emit(await api('GET', `${url}/v1/runs`, apiKey));
|
|
414
|
+
return 0;
|
|
415
|
+
}
|
|
416
|
+
const got = await fetchPlatformRun({ url, apiKey }, id);
|
|
417
|
+
if ('error' in got) {
|
|
418
|
+
err(got.error);
|
|
419
|
+
return 1;
|
|
420
|
+
}
|
|
421
|
+
emit(got.run);
|
|
616
422
|
return 0;
|
|
617
423
|
};
|
|
618
424
|
/**
|
|
@@ -633,7 +439,7 @@ const cmdIssues = async (argv) => {
|
|
|
633
439
|
const fixAt = argv.indexOf('--fix');
|
|
634
440
|
const wanted = -1 === fixAt ? undefined : argv[fixAt + 1];
|
|
635
441
|
if (fixAt !== -1 && wanted === undefined) {
|
|
636
|
-
err('usage: reticle issues --fix <fingerprint>');
|
|
442
|
+
err('usage: reticle runs issues --fix <fingerprint>');
|
|
637
443
|
return 2;
|
|
638
444
|
}
|
|
639
445
|
const body = await api('GET', `${url}/v1/issues`, apiKey);
|
|
@@ -652,7 +458,7 @@ const cmdIssues = async (argv) => {
|
|
|
652
458
|
}
|
|
653
459
|
const found = parsed.data.issues.find((i) => i.fingerprint === wanted);
|
|
654
460
|
if (found === undefined) {
|
|
655
|
-
err(`no issue with fingerprint '${wanted}' — run \`reticle issues\` to list them`);
|
|
461
|
+
err(`no issue with fingerprint '${wanted}' — run \`reticle runs issues\` to list them`);
|
|
656
462
|
return 2;
|
|
657
463
|
}
|
|
658
464
|
const prompt = found.fixPrompt;
|
|
@@ -679,15 +485,39 @@ const cmdIssues = async (argv) => {
|
|
|
679
485
|
* whole corpus to answer one question is the cost the sharded store was built to avoid.
|
|
680
486
|
*/
|
|
681
487
|
const cmdMemory = async (argv) => {
|
|
682
|
-
const { url, apiKey } = await repoCloud();
|
|
488
|
+
const { url, apiKey, projectId } = await repoCloud();
|
|
683
489
|
const at = argv.indexOf('--subject');
|
|
684
490
|
const subject = -1 === at ? undefined : argv[at + 1];
|
|
685
491
|
if (-1 !== at && subject === undefined) {
|
|
686
|
-
err('usage: reticle memory [--subject <name>]');
|
|
492
|
+
err('usage: reticle runs memory [--subject <name>]');
|
|
687
493
|
return 2;
|
|
688
494
|
}
|
|
689
|
-
|
|
690
|
-
|
|
495
|
+
// Scoped to the LINKED project, on the way out AND on the way back. Without the parameter
|
|
496
|
+
// this printed whatever the key covered; without checking the response it still would, for as long
|
|
497
|
+
// as the platform ignores a parameter it does not know yet — which is exactly the window this ships
|
|
498
|
+
// in. This is the command whose whole job is "what does THIS project know", so a sibling's answer
|
|
499
|
+
// arriving under this heading is the one output nobody can tell from a correct one.
|
|
500
|
+
//
|
|
501
|
+
// The check is on the ENVELOPE and it REFUSES rather than printing. Printing an empty list would
|
|
502
|
+
// report "this project knows nothing", which is a different fact from "this response could not be
|
|
503
|
+
// shown to be about this project" and the one a person is likelier to act on. Nothing goes to
|
|
504
|
+
// stdout in that case: a caller piping this into an agent gets an error on stderr and a non-zero
|
|
505
|
+
// exit, never a plausible-looking empty answer.
|
|
506
|
+
//
|
|
507
|
+
// The refusal is the PRINTER's own, not a second check here: `scopeMemoryResponse` answers
|
|
508
|
+
// `undefined` for anything it cannot show to be this project's, so there is no ordering a future
|
|
509
|
+
// edit can get wrong — the body it must not print is one it was never handed. The verdict is read
|
|
510
|
+
// only to say WHICH refusal this is.
|
|
511
|
+
const scope = { projectId, subject };
|
|
512
|
+
const body = await api('GET', memoryReadUrl(url, scope), apiKey);
|
|
513
|
+
const printable = scopeMemoryResponse(body, projectId);
|
|
514
|
+
if (printable === undefined) {
|
|
515
|
+
err(MemoryResponseScope.OTHER === scopeOfMemoryResponse(body, projectId)
|
|
516
|
+
? `the server answered about a different project than this repo is linked to — refusing to print another project's knowledge as this one's. Check the link with \`reticle status\`.`
|
|
517
|
+
: `the server's response does not say which project it is about, so there is no way to tell whether this is this project's knowledge. Refusing to print it; check the link with \`reticle status\`.`);
|
|
518
|
+
return 1;
|
|
519
|
+
}
|
|
520
|
+
emit(printable);
|
|
691
521
|
return 0;
|
|
692
522
|
};
|
|
693
523
|
/** `reticle regression` — the CI gate: broken flows vs before. Exit 3 if any regressed (pipeline-friendly). */
|
|
@@ -695,20 +525,35 @@ const cmdRegression = async () => {
|
|
|
695
525
|
const { url, apiKey } = await repoCloud();
|
|
696
526
|
const report = await api('GET', `${url}/v1/project/regression`, apiKey);
|
|
697
527
|
emit(report);
|
|
698
|
-
|
|
699
|
-
return parsed.success && parsed.data.broken.length > 0 ? 3 : 0;
|
|
528
|
+
return gateExitWith(GateExit.PASS, brokenOf(report)?.length);
|
|
700
529
|
};
|
|
701
530
|
/** `reticle share <runId>` — mint a public proof link for one run. */
|
|
702
531
|
const cmdShare = async (argv) => {
|
|
703
532
|
const runId = argv[0];
|
|
704
533
|
if (runId === undefined) {
|
|
705
|
-
err('usage: reticle share <runId>');
|
|
534
|
+
err('usage: reticle runs share <runId>');
|
|
706
535
|
return 2;
|
|
707
536
|
}
|
|
708
537
|
const { url, apiKey } = await repoCloud();
|
|
709
538
|
emit(await api('POST', `${url}/v1/runs/${encodeURIComponent(runId)}/share`, apiKey));
|
|
710
539
|
return 0;
|
|
711
540
|
};
|
|
541
|
+
/** `reticle runs <regression|share|issues|memory>`, and `reticle runs [<runId>]` otherwise. */
|
|
542
|
+
const cmdRunsFamily = async (argv) => {
|
|
543
|
+
const [sub, ...rest] = argv;
|
|
544
|
+
switch (sub) {
|
|
545
|
+
case 'regression':
|
|
546
|
+
return cmdRegression();
|
|
547
|
+
case 'share':
|
|
548
|
+
return cmdShare(rest);
|
|
549
|
+
case 'issues':
|
|
550
|
+
return cmdIssues(rest);
|
|
551
|
+
case 'memory':
|
|
552
|
+
return cmdMemory(rest);
|
|
553
|
+
default:
|
|
554
|
+
return cmdRuns(argv);
|
|
555
|
+
}
|
|
556
|
+
};
|
|
712
557
|
/** Dispatch a cloud subcommand. Returns the process exit code. */
|
|
713
558
|
export const runCloudCommand = async (argv) => {
|
|
714
559
|
const [cmd, ...rest] = argv;
|
|
@@ -720,6 +565,11 @@ export const runCloudCommand = async (argv) => {
|
|
|
720
565
|
return await cmdLogin(rest, cmdLink);
|
|
721
566
|
case 'connect':
|
|
722
567
|
return await cmdConnect(rest);
|
|
568
|
+
case 'try':
|
|
569
|
+
return await cmdTry(rest, {
|
|
570
|
+
push: () => cmdSync([]),
|
|
571
|
+
dashboardUrl: async (c) => (await validateKey(c.url, c.apiKey))?.dashboardUrl,
|
|
572
|
+
});
|
|
723
573
|
case 'logout':
|
|
724
574
|
return await cmdLogout(rest);
|
|
725
575
|
case 'whoami':
|
|
@@ -730,12 +580,13 @@ export const runCloudCommand = async (argv) => {
|
|
|
730
580
|
return await cmdLink(rest);
|
|
731
581
|
case 'config':
|
|
732
582
|
return await cmdConfig(rest);
|
|
583
|
+
// `push` is the name people type, so it takes `--watch` too: the help and the README say so.
|
|
733
584
|
case 'push':
|
|
734
|
-
return await
|
|
585
|
+
return await cmdSync(rest);
|
|
735
586
|
case 'sync':
|
|
736
587
|
return await cmdSync(rest);
|
|
737
588
|
case 'runs':
|
|
738
|
-
return await
|
|
589
|
+
return await cmdRunsFamily(rest);
|
|
739
590
|
case 'issues':
|
|
740
591
|
return await cmdIssues(rest);
|
|
741
592
|
case 'memory':
|