@reticlehq/server 2.13.1 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +8 -18
- package/bin/reticle.js +3 -0
- package/dist/bridge/auth-failure-reason.js +12 -1
- package/dist/bridge/bridge-security.d.ts +8 -0
- package/dist/bridge/bridge-security.js +6 -1
- package/dist/bridge/bridge.d.ts +3 -0
- package/dist/bridge/bridge.js +23 -1
- package/dist/bridge/bridge.test-harness.d.ts +10 -1
- package/dist/bridge/bridge.test-harness.js +7 -1
- package/dist/bridge/pairing-token.d.ts +17 -0
- package/dist/bridge/pairing-token.js +26 -0
- package/dist/bridge/token-auth.d.ts +7 -0
- package/dist/bridge/token-auth.js +7 -1
- package/dist/capsule/capsule-store.d.ts +4 -4
- package/dist/capsule/capsule.d.ts +1 -1
- package/dist/capsule/capsule.js +3 -3
- package/dist/capsule/causal-summary.d.ts +21 -1
- package/dist/capsule/causal-summary.js +8 -6
- package/dist/capsule/divergence.d.ts +1 -1
- package/dist/capsule/divergence.js +26 -10
- package/dist/chromium-launch-options.d.ts +2 -1
- package/dist/cli/adhoc-verdict.d.ts +58 -0
- package/dist/cli/adhoc-verdict.js +115 -0
- package/dist/cli/chromium-hint.d.ts +18 -4
- package/dist/cli/chromium-hint.js +54 -6
- package/dist/cli/cli-doctor.js +1 -2
- package/dist/cli/cli-flow-commands.d.ts +16 -2
- package/dist/cli/cli-flow-commands.js +28 -9
- package/dist/cli/cli-parse-feedback.js +1 -1
- package/dist/cli/cli-parse.d.ts +2 -1
- package/dist/cli/cli-parse.js +38 -0
- package/dist/cli/cli-port.d.ts +5 -13
- package/dist/cli/cli-port.js +5 -38
- package/dist/cli/cli-update-commands.js +4 -4
- package/dist/cli/cli-verify.d.ts +24 -7
- package/dist/cli/cli-verify.js +87 -13
- package/dist/cli/cloud-keystore.d.ts +2 -1
- package/dist/cli/cloud-login.d.ts +2 -1
- package/dist/cli/cloud-session.d.ts +2 -1
- package/dist/cli/cloud-session.js +1 -1
- package/dist/cli/daemon-start-options.d.ts +2 -1
- package/dist/cli/device-flow.d.ts +2 -2
- package/dist/cli/doctor-daemon-line.d.ts +2 -1
- package/dist/cli/doctor-project-line.d.ts +2 -1
- package/dist/cli/doctor-rows.d.ts +2 -1
- package/dist/cli/drive-attach.d.ts +4 -3
- package/dist/cli/gate-hook-message.d.ts +2 -1
- package/dist/cli/status-next-action.js +10 -11
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +21 -9
- package/dist/cloud/account-state.d.ts +20 -0
- package/dist/cloud/account-state.js +65 -0
- package/dist/cloud/cloud-sync.d.ts +46 -3
- package/dist/cloud/cloud-sync.js +116 -0
- package/dist/cloud/sync-cycle.d.ts +5 -4
- package/dist/cloud/sync-cycle.js +1 -1
- package/dist/cloud/sync-daemon.d.ts +3 -19
- package/dist/cloud/sync-daemon.js +2 -2
- package/dist/crawl/crawl-tools.js +1 -1
- package/dist/crawl/crawl.d.ts +5 -5
- package/dist/crawl/crawl.js +138 -4
- package/dist/daemon/daemon-resilience.d.ts +3 -2
- package/dist/daemon/daemon-resilience.js +43 -4
- package/dist/daemon/daemon-resolve.d.ts +0 -9
- package/dist/daemon/daemon-resolve.js +2 -2
- package/dist/daemon/dev-servers.d.ts +1 -1
- package/dist/daemon/dev-servers.js +1 -1
- package/dist/daemon/loopback-alias.d.ts +2 -1
- package/dist/daemon/startup-failure.d.ts +11 -0
- package/dist/daemon/startup-failure.js +46 -0
- package/dist/events/contradictions.d.ts +10 -16
- package/dist/events/contradictions.js +149 -17
- package/dist/events/declared.d.ts +13 -1
- package/dist/events/declared.js +59 -3
- package/dist/events/echo-mismatch.js +75 -6
- package/dist/events/lineage.d.ts +52 -0
- package/dist/events/lineage.js +122 -0
- package/dist/events/net-evidence.d.ts +21 -0
- package/dist/events/net-evidence.js +81 -0
- package/dist/events/predicate-console.d.ts +13 -0
- package/dist/events/predicate-console.js +138 -0
- package/dist/events/predicate-element.d.ts +13 -0
- package/dist/events/predicate-element.js +214 -0
- package/dist/events/predicate-eval.d.ts +15 -3
- package/dist/events/predicate-eval.js +128 -110
- package/dist/events/predicate-parse.js +34 -1
- package/dist/events/predicate-request-body.d.ts +50 -0
- package/dist/events/predicate-request-body.js +120 -0
- package/dist/events/predicate-route.d.ts +21 -1
- package/dist/events/predicate-route.js +149 -21
- package/dist/events/predicate-schema.d.ts +8 -1
- package/dist/events/predicate-schema.js +34 -0
- package/dist/events/predicate.d.ts +2 -0
- package/dist/events/predicate.js +52 -159
- package/dist/events/split-text-miss.d.ts +6 -4
- package/dist/events/split-text-miss.js +12 -5
- package/dist/flows/affected-tools.js +22 -9
- package/dist/flows/annotate.d.ts +2 -1
- package/dist/flows/annotate.js +19 -1
- package/dist/flows/coverage.d.ts +2 -2
- package/dist/flows/flake.d.ts +3 -3
- package/dist/flows/flow-expect-grammar.d.ts +33 -0
- package/dist/flows/flow-expect-grammar.js +155 -0
- package/dist/flows/flow-replay-run.d.ts +1 -1
- package/dist/flows/flow-replay-run.js +28 -15
- package/dist/flows/flow-replay.d.ts +10 -0
- package/dist/flows/flow-replay.js +57 -22
- package/dist/flows/flow-secret-field.d.ts +14 -0
- package/dist/flows/flow-secret-field.js +22 -0
- package/dist/flows/flow-step-runners.d.ts +1 -0
- package/dist/flows/flow-step-runners.js +91 -34
- package/dist/flows/flow-success.js +22 -0
- package/dist/flows/flow-tools.js +27 -8
- package/dist/flows/flow-upload-resolve.d.ts +23 -0
- package/dist/flows/flow-upload-resolve.js +46 -0
- package/dist/flows/flows.d.ts +15 -0
- package/dist/flows/flows.js +17 -14
- package/dist/flows/git-changed.d.ts +23 -4
- package/dist/flows/git-changed.js +32 -6
- package/dist/flows/heal-run.js +2 -2
- package/dist/flows/predicate-to-expect.d.ts +3 -2
- package/dist/flows/predicate-to-expect.js +11 -5
- package/dist/flows/recording-backtrack.d.ts +24 -0
- package/dist/flows/recording-backtrack.js +73 -0
- package/dist/flows/recordings.d.ts +6 -0
- package/dist/flows/replay-halt.d.ts +26 -0
- package/dist/flows/replay-halt.js +30 -0
- package/dist/flows/replay.d.ts +0 -8
- package/dist/flows/replay.js +15 -3
- package/dist/flows/suite-flakes.d.ts +2 -1
- package/dist/flows/verify-change-tools.js +16 -4
- package/dist/honesty/already-true.d.ts +14 -0
- package/dist/honesty/already-true.js +47 -4
- package/dist/honesty/blind-spots.d.ts +3 -1
- package/dist/honesty/blind-spots.js +24 -1
- package/dist/honesty/body-capture-remedy.d.ts +42 -0
- package/dist/honesty/body-capture-remedy.js +95 -0
- package/dist/honesty/feature-capture.d.ts +3 -2
- package/dist/honesty/feature-capture.js +1 -1
- package/dist/honesty/gap-ledger.d.ts +1 -1
- package/dist/honesty/gap-ledger.js +1 -1
- package/dist/honesty/instrumentation-gaps.d.ts +8 -1
- package/dist/honesty/instrumentation-gaps.js +12 -2
- package/dist/honesty/observability.d.ts +4 -3
- package/dist/honesty/tool-hit-rate.d.ts +3 -2
- package/dist/honesty/uncaptured-bodies.d.ts +3 -1
- package/dist/honesty/uncaptured-bodies.js +6 -2
- package/dist/honesty/unsettled.d.ts +9 -0
- package/dist/honesty/unsettled.js +45 -0
- package/dist/honesty/verified.d.ts +32 -1
- package/dist/honesty/verified.js +37 -10
- package/dist/impact/impact-store.d.ts +5 -14
- package/dist/impact/impact-store.js +49 -6
- package/dist/index.js +1 -1
- package/dist/input/network-detail.d.ts +26 -1
- package/dist/input/network-detail.js +44 -12
- package/dist/input/network-mock-tools.js +24 -17
- package/dist/input/real-input.js +1 -1
- package/dist/input/viewport-tools.js +25 -13
- package/dist/intent/inline-intent.d.ts +0 -10
- package/dist/intent/inline-intent.js +1 -1
- package/dist/intent/intent-shard-store.d.ts +3 -2
- package/dist/intent/intent-shard-store.js +1 -1
- package/dist/intent/intent-shard.d.ts +14 -14
- package/dist/intent/intent-shard.js +4 -4
- package/dist/intent/intent-store.d.ts +1 -1
- package/dist/intent/intent-store.js +1 -1
- package/dist/intent/intent-subject.d.ts +2 -1
- package/dist/intent/open-intents.d.ts +3 -2
- package/dist/license/license.d.ts +4 -4
- package/dist/license/license.js +1 -1
- package/dist/mcp/attach-memory.d.ts +2 -1
- package/dist/mcp/client-identity.d.ts +2 -1
- package/dist/mcp/mcp-outage.d.ts +1 -1
- package/dist/mcp/mcp-outage.js +1 -1
- package/dist/mcp/mcp-proxy.d.ts +3 -1
- package/dist/mcp/mcp-proxy.js +32 -7
- package/dist/mcp/mcp.js +3 -1
- package/dist/mcp/proxy-handshake.d.ts +2 -1
- package/dist/mcp/proxy-idle-exit.d.ts +45 -0
- package/dist/mcp/proxy-idle-exit.js +94 -0
- package/dist/mcp/server-instructions.d.ts +2 -1
- package/dist/memory/project-memory.d.ts +2 -3
- package/dist/memory/project-memory.js +1 -1
- package/dist/oracles/propose-consequences.js +5 -5
- package/dist/oracles/self-instrument.d.ts +2 -2
- package/dist/oracles/self-instrument.js +1 -1
- package/dist/platform.d.ts +3 -5
- package/dist/platform.js +3 -5
- package/dist/pool/browser-pool.d.ts +92 -0
- package/dist/pool/browser-pool.js +119 -5
- package/dist/pool/playwright-launcher.js +29 -2
- package/dist/pool/storage-seed.d.ts +23 -0
- package/dist/pool/storage-seed.js +198 -0
- package/dist/project/artifact-root.d.ts +2 -1
- package/dist/project/memory-fs.d.ts +2 -1
- package/dist/project/reticle-dir.js +1 -1
- package/dist/project/session-root.d.ts +8 -0
- package/dist/project/session-root.js +9 -2
- package/dist/runs/reticle-runner.d.ts +14 -1
- package/dist/runs/reticle-runner.js +39 -2
- package/dist/session/attachment-history.d.ts +2 -1
- package/dist/session/fake-session.d.ts +37 -0
- package/dist/session/fake-session.js +81 -0
- package/dist/session/lease-visibility.d.ts +2 -1
- package/dist/session/live-control-tools.js +6 -0
- package/dist/session/no-session-diagnosis.d.ts +17 -1
- package/dist/session/no-session-diagnosis.js +32 -6
- package/dist/session/no-session-next-action.d.ts +14 -0
- package/dist/session/no-session-next-action.js +18 -0
- package/dist/session/no-session-watch.js +46 -3
- package/dist/session/registered-projects.d.ts +54 -0
- package/dist/session/registered-projects.js +73 -0
- package/dist/session/review-store.d.ts +2 -1
- package/dist/session/session-health.d.ts +62 -1
- package/dist/session/session-health.js +82 -2
- package/dist/session/session-manager.d.ts +11 -1
- package/dist/session/session-manager.js +18 -3
- package/dist/session/session-replaced.d.ts +24 -0
- package/dist/session/session-replaced.js +29 -0
- package/dist/session/session-successor.js +20 -4
- package/dist/session/session.d.ts +13 -5
- package/dist/session/session.js +31 -23
- package/dist/setup/agent-configs.d.ts +3 -2
- package/dist/setup/agent-writer.d.ts +3 -2
- package/dist/setup/approval-migration.d.ts +2 -1
- package/dist/setup/approval-migration.js +1 -1
- package/dist/setup/auto-approve.d.ts +11 -19
- package/dist/setup/auto-approve.js +15 -12
- package/dist/{init → setup}/confirm.js +1 -1
- package/dist/setup/desktop-shape.d.ts +3 -2
- package/dist/setup/drive-agent.d.ts +2 -3
- package/dist/setup/drive-agent.js +1 -1
- package/dist/setup/drive-plan.d.ts +3 -2
- package/dist/setup/ensure-daemon.d.ts +2 -1
- package/dist/setup/existing-app.d.ts +12 -0
- package/dist/setup/existing-app.js +13 -0
- package/dist/setup/init-host.d.ts +11 -0
- package/dist/setup/init-host.js +26 -0
- package/dist/setup/init-runtime.d.ts +4 -10
- package/dist/setup/init-runtime.js +23 -16
- package/dist/setup/license-key.d.ts +2 -1
- package/dist/setup/listeners.d.ts +2 -1
- package/dist/setup/loopback-probe-urls.d.ts +18 -0
- package/dist/setup/loopback-probe-urls.js +52 -0
- package/dist/setup/node-effects.d.ts +3 -0
- package/dist/setup/node-effects.js +26 -11
- package/dist/setup/page-probe.d.ts +5 -0
- package/dist/setup/relaunch.d.ts +2 -1
- package/dist/setup/run-setup.d.ts +5 -1
- package/dist/setup/run-setup.js +141 -50
- package/dist/setup/setup-command.d.ts +3 -2
- package/dist/setup/setup-command.js +8 -0
- package/dist/setup/setup-options.d.ts +5 -3
- package/dist/setup/setup-options.js +3 -2
- package/dist/setup/wait-progress.d.ts +28 -0
- package/dist/setup/wait-progress.js +43 -0
- package/dist/telemetry/app-instrumented.d.ts +2 -1
- package/dist/telemetry/app-instrumented.js +1 -1
- package/dist/telemetry/automation-hint.d.ts +1 -1
- package/dist/telemetry/automation-hint.js +1 -1
- package/dist/telemetry/cli-telemetry.js +1 -1
- package/dist/telemetry/connect-failure.d.ts +1 -1
- package/dist/telemetry/connect-failure.js +1 -1
- package/dist/telemetry/crash-cause.d.ts +3 -2
- package/dist/telemetry/crash-cause.js +1 -1
- package/dist/telemetry/daemon-telemetry.d.ts +3 -2
- package/dist/telemetry/daemon-telemetry.js +1 -1
- package/dist/telemetry/error-class.d.ts +3 -2
- package/dist/telemetry/error-class.js +1 -1
- package/dist/telemetry/feedback-cli.js +1 -1
- package/dist/telemetry/feedback-context.d.ts +3 -2
- package/dist/telemetry/feedback-context.js +5 -4
- package/dist/telemetry/feedback-local.d.ts +3 -2
- package/dist/telemetry/feedback.d.ts +4 -3
- package/dist/telemetry/feedback.js +1 -1
- package/dist/telemetry/git-facts.d.ts +2 -2
- package/dist/telemetry/git-facts.js +1 -1
- package/dist/telemetry/identify.d.ts +1 -1
- package/dist/telemetry/identify.js +1 -1
- package/dist/telemetry/init-telemetry.d.ts +2 -14
- package/dist/telemetry/init-telemetry.js +4 -13
- package/dist/telemetry/install-source.d.ts +7 -13
- package/dist/telemetry/install-source.js +7 -29
- package/dist/telemetry/license-activation.d.ts +3 -2
- package/dist/telemetry/license-activation.js +1 -1
- package/dist/telemetry/machine-snapshot.d.ts +1 -1
- package/dist/telemetry/mcp-connection.js +1 -1
- package/dist/telemetry/project-profile.d.ts +0 -14
- package/dist/telemetry/project-profile.js +1 -1
- package/dist/telemetry/proxy-telemetry.js +1 -1
- package/dist/telemetry/session-metrics.d.ts +1 -1
- package/dist/telemetry/session-metrics.js +1 -1
- package/dist/telemetry/telemetry.d.ts +1 -17
- package/dist/telemetry/telemetry.js +4 -4
- package/dist/telemetry/tool-refused.d.ts +1 -1
- package/dist/telemetry/tool-refused.js +1 -1
- package/dist/tools/act-observation.d.ts +3 -2
- package/dist/tools/act-preflight.js +8 -3
- package/dist/tools/act-target.d.ts +4 -0
- package/dist/tools/act-target.js +14 -5
- package/dist/tools/act-tools.d.ts +0 -2
- package/dist/tools/act-tools.js +45 -15
- package/dist/tools/assert-source.d.ts +30 -0
- package/dist/tools/assert-source.js +21 -0
- package/dist/tools/assert-verdict.d.ts +1 -1
- package/dist/tools/assert-verdict.js +14 -4
- package/dist/tools/browser-tools.js +28 -8
- package/dist/tools/complete-snapshot.d.ts +3 -2
- package/dist/tools/dynamic-tools.js +8 -0
- package/dist/tools/error-recovery.d.ts +10 -0
- package/dist/tools/error-recovery.js +23 -0
- package/dist/tools/feedback-tools.js +1 -1
- package/dist/tools/invoke-tool.js +2 -0
- package/dist/tools/lease-tools.d.ts +48 -20
- package/dist/tools/lease-tools.js +311 -76
- package/dist/tools/lineage-tools.d.ts +14 -0
- package/dist/tools/lineage-tools.js +64 -0
- package/dist/tools/merge-tools.js +1 -3
- package/dist/tools/navigate-arrival.d.ts +45 -1
- package/dist/tools/navigate-arrival.js +39 -6
- package/dist/tools/navigate-result.d.ts +8 -1
- package/dist/tools/navigate-result.js +14 -4
- package/dist/tools/numeric-bounds.d.ts +0 -11
- package/dist/tools/numeric-bounds.js +4 -4
- package/dist/tools/observe-tools.js +22 -26
- package/dist/tools/observed-nothing.d.ts +9 -0
- package/dist/tools/observed-nothing.js +2 -1
- package/dist/tools/read-tools.js +12 -17
- package/dist/tools/real-input-attempt.d.ts +14 -6
- package/dist/tools/real-input-attempt.js +75 -18
- package/dist/tools/reconcile-tools.js +2 -1
- package/dist/tools/reload-result.d.ts +6 -1
- package/dist/tools/reload-result.js +7 -2
- package/dist/tools/resolve-target.d.ts +7 -1
- package/dist/tools/resolve-target.js +72 -9
- package/dist/tools/settle-in-flight.d.ts +1 -1
- package/dist/tools/settle-in-flight.js +9 -2
- package/dist/tools/snapshot-delta.d.ts +24 -1
- package/dist/tools/snapshot-delta.js +66 -7
- package/dist/tools/tool-names.d.ts +1 -0
- package/dist/tools/tool-names.js +1 -0
- package/dist/tools/tool-surface.js +20 -2
- package/dist/tools/tools.js +120 -11
- package/dist/tools/verify-next-baton.d.ts +2 -1
- package/dist/update/sdk-sync.d.ts +1 -1
- package/dist/update/sdk-sync.js +1 -1
- package/dist/update/updater.js +1 -1
- package/dist/version/sdk-fix.d.ts +2 -1
- package/dist/version/version-skew.d.ts +0 -8
- package/dist/version/version-skew.js +1 -1
- package/docs/README.md +8 -6
- package/docs/actions.mdx +1 -1
- package/docs/agent-cheatsheet.md +4 -2
- package/docs/architecture.md +1 -1
- package/docs/cli/mcp.mdx +3 -1
- package/docs/cli/watch.mdx +1 -1
- package/docs/cli.mdx +1 -1
- package/docs/desktop.mdx +1 -1
- package/docs/docs.json +8 -3
- package/docs/faq.mdx +9 -0
- package/docs/first-drive.md +136 -0
- package/docs/frameworks.mdx +29 -7
- package/docs/gate-plan.md +2 -2
- package/docs/gates.md +19 -11
- package/docs/getting-started.md +7 -1
- package/docs/http-transport.md +164 -0
- package/docs/index.mdx +5 -3
- package/docs/install-manual.mdx +1 -1
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages.mdx +15 -3
- package/docs/platform-integration.md +1 -1
- package/docs/predicates.mdx +2 -0
- package/docs/system-map.md +2 -2
- package/docs/telemetry-contract.md +4 -4
- package/docs/telemetry-events.mdx +1 -1
- package/docs/telemetry.md +3 -3
- package/docs/tools-navigate.mdx +14 -6
- package/docs/usage.md +4 -4
- package/package.json +7 -4
- package/dist/init/agent-rules.d.ts +0 -116
- package/dist/init/agent-rules.js +0 -279
- package/dist/init/app-choice.d.ts +0 -20
- package/dist/init/app-choice.js +0 -25
- package/dist/init/astro-host.d.ts +0 -21
- package/dist/init/astro-host.js +0 -27
- package/dist/init/astro-patch.d.ts +0 -33
- package/dist/init/astro-patch.js +0 -300
- package/dist/init/capabilities.d.ts +0 -40
- package/dist/init/capabilities.js +0 -150
- package/dist/init/closing-hint.d.ts +0 -36
- package/dist/init/closing-hint.js +0 -120
- package/dist/init/connect-steps.d.ts +0 -2
- package/dist/init/connect-steps.js +0 -50
- package/dist/init/cra.d.ts +0 -79
- package/dist/init/cra.js +0 -178
- package/dist/init/csp-check.d.ts +0 -38
- package/dist/init/csp-check.js +0 -107
- package/dist/init/csp-doctor.d.ts +0 -32
- package/dist/init/csp-doctor.js +0 -54
- package/dist/init/desktop-doctor.d.ts +0 -41
- package/dist/init/desktop-doctor.js +0 -198
- package/dist/init/detect.d.ts +0 -96
- package/dist/init/detect.js +0 -209
- package/dist/init/dev-script.d.ts +0 -50
- package/dist/init/dev-script.js +0 -66
- package/dist/init/format-generated.d.ts +0 -18
- package/dist/init/format-generated.js +0 -39
- package/dist/init/install-hint.d.ts +0 -9
- package/dist/init/install-hint.js +0 -29
- package/dist/init/mcp-clients.d.ts +0 -89
- package/dist/init/mcp-clients.js +0 -299
- package/dist/init/mcp-registered.d.ts +0 -12
- package/dist/init/mcp-registered.js +0 -14
- package/dist/init/mcp.d.ts +0 -89
- package/dist/init/mcp.js +0 -129
- package/dist/init/next-patch.d.ts +0 -39
- package/dist/init/next-patch.js +0 -196
- package/dist/init/node-io.d.ts +0 -7
- package/dist/init/node-io.js +0 -117
- package/dist/init/non-js-project.d.ts +0 -27
- package/dist/init/non-js-project.js +0 -84
- package/dist/init/patch-kind.d.ts +0 -20
- package/dist/init/patch-kind.js +0 -10
- package/dist/init/plan-framework.d.ts +0 -64
- package/dist/init/plan-framework.js +0 -565
- package/dist/init/plan.d.ts +0 -242
- package/dist/init/plan.js +0 -703
- package/dist/init/preflight.d.ts +0 -28
- package/dist/init/preflight.js +0 -38
- package/dist/init/project-id.d.ts +0 -12
- package/dist/init/project-id.js +0 -25
- package/dist/init/refresh-rules.d.ts +0 -39
- package/dist/init/refresh-rules.js +0 -51
- package/dist/init/run.d.ts +0 -117
- package/dist/init/run.js +0 -806
- package/dist/init/slash-command.d.ts +0 -27
- package/dist/init/slash-command.js +0 -132
- package/dist/init/snippets.d.ts +0 -134
- package/dist/init/snippets.js +0 -572
- package/dist/init/vite-config.d.ts +0 -18
- package/dist/init/vite-config.js +0 -114
- package/dist/init/windows-quote.d.ts +0 -38
- package/dist/init/windows-quote.js +0 -70
- package/dist/init/workspace-apps.d.ts +0 -30
- package/dist/init/workspace-apps.js +0 -178
- package/dist/project/remember-project.d.ts +0 -24
- package/dist/project/remember-project.js +0 -40
- /package/dist/{init → setup}/confirm.d.ts +0 -0
package/dist/cli/cli-verify.d.ts
CHANGED
|
@@ -10,12 +10,17 @@
|
|
|
10
10
|
* — is unit-tested without launching a real browser.
|
|
11
11
|
*/
|
|
12
12
|
import { type ReticleVerificationRun } from '@reticlehq/core';
|
|
13
|
+
import { type VerifyProgressListener } from '../runs/reticle-runner.js';
|
|
13
14
|
/** The live capabilities runVerify needs — faked in tests so the logic runs without a browser. */
|
|
14
15
|
export interface VerifyConnection {
|
|
15
16
|
/** Resolve true once a browser session has connected, or false at timeout. */
|
|
16
17
|
sessionReady(timeoutMs: number): Promise<boolean>;
|
|
17
18
|
listFlows(): Promise<string[]>;
|
|
18
|
-
|
|
19
|
+
/**
|
|
20
|
+
* `onProgress` is narration for a run in flight — see `verify-progress.ts` in core. Optional at
|
|
21
|
+
* every layer: a connection that ignores it behaves exactly as it did before.
|
|
22
|
+
*/
|
|
23
|
+
verify(onProgress?: VerifyProgressListener): Promise<ReticleVerificationRun>;
|
|
19
24
|
close(): Promise<void>;
|
|
20
25
|
}
|
|
21
26
|
export interface VerifyPorts {
|
|
@@ -48,17 +53,29 @@ export declare function urlParts(url: string): {
|
|
|
48
53
|
* worst answer available, and reached most often by the people with the fewest other options, since
|
|
49
54
|
* the skill offers this command as the way to a verdict with no MCP at all.
|
|
50
55
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* second port works when the app is configured for it.
|
|
56
|
+
* The message says every way out rather than picking one, and it says FIRST that a busy port is the
|
|
57
|
+
* normal state rather than a fault — an install that worked leaves a daemon on it, so a reader who
|
|
58
|
+
* arrives here has done nothing wrong and should not go looking for what they broke (#689).
|
|
55
59
|
*
|
|
56
|
-
*
|
|
57
|
-
* this
|
|
60
|
+
* `reticle drive` leads, because it is the only option that works in the state most people are in
|
|
61
|
+
* when they reach this message: the client exposes no `reticle_*` tools (Codex, Cursor Cloud,
|
|
62
|
+
* Antigravity, a session whose MCP link dropped), which is exactly when the CLI is reached for. It
|
|
63
|
+
* ATTACHES to the running daemon rather than binding — see cli/drive-attach.ts — so there is nothing
|
|
64
|
+
* to stop, nothing to race, and it hands back a sessionId the daemon owns. The advice that used to
|
|
65
|
+
* lead, "ask the daemon through the tools", is the one thing that reader by construction cannot do.
|
|
66
|
+
*
|
|
67
|
+
* Stopping the daemon stays on the list and stays LAST of the working options, with the reason: the
|
|
68
|
+
* MCP proxy respawns one into the gap, so `stop` is a race the caller usually loses, and it kills
|
|
69
|
+
* the agent's own link on the way past.
|
|
70
|
+
*
|
|
71
|
+
* `verify` itself attaching, rather than needing the port at all, is the real fix and is #689's
|
|
72
|
+
* first bullet — not this change.
|
|
58
73
|
*/
|
|
59
74
|
export declare function portBusyMessage(port: number): string;
|
|
60
75
|
export declare function handleVerify(parsed: {
|
|
61
76
|
url: string;
|
|
77
|
+
/** A parsed predicate for a flow-free, one-shot verdict against the running daemon. */
|
|
78
|
+
expect?: unknown;
|
|
62
79
|
headless: boolean;
|
|
63
80
|
timeoutMs?: number;
|
|
64
81
|
storageState?: string;
|
package/dist/cli/cli-verify.js
CHANGED
|
@@ -10,13 +10,15 @@
|
|
|
10
10
|
* — is unit-tested without launching a real browser.
|
|
11
11
|
*/
|
|
12
12
|
import { join, basename } from 'node:path';
|
|
13
|
+
import { runAdhocVerdict } from './adhoc-verdict.js';
|
|
14
|
+
import { readOrCreatePairingTokenSync, defaultPairingTokenDir } from '../bridge/pairing-token.js';
|
|
13
15
|
import { randomUUID } from 'node:crypto';
|
|
14
|
-
import { RETICLE_DEFAULT_PORT, ReticleEnv, bridgeWsUrl, isLoopbackHostname, ReticleDir, RunAgentKind, RunFramework, RunProfile, RunTrigger, VerdictStatus, } from '@reticlehq/core';
|
|
16
|
+
import { RETICLE_DEFAULT_PORT, ReticleEnv, bridgeWsUrl, isLoopbackHostname, ReticleDir, RunAgentKind, RunFramework, RunProfile, RunTrigger, VerdictStatus, VerifyPhase, } from '@reticlehq/core';
|
|
15
17
|
import { start } from '../index.js';
|
|
16
18
|
import { probePresence, PortPresence } from '../daemon/port-presence.js';
|
|
17
19
|
import { probeDaemon } from '../mcp/mcp-proxy.js';
|
|
18
20
|
import { fetchStatus } from './cli-launch.js';
|
|
19
|
-
import { cloudFetch, resolveCloudConfig, syncRunToCloud, SyncOutcome, } from '../cloud/cloud-sync.js';
|
|
21
|
+
import { cloudFetch, createProgressReporter, resolveCloudConfig, syncProgressToCloud, syncRunToCloud, SyncOutcome, } from '../cloud/cloud-sync.js';
|
|
20
22
|
import { ReticleRunner } from '../runs/reticle-runner.js';
|
|
21
23
|
import { createRunnerPort } from '../runs/runner-port.js';
|
|
22
24
|
import { RunStore } from '../runs/run-store.js';
|
|
@@ -71,8 +73,44 @@ export async function runVerify(args, ports) {
|
|
|
71
73
|
ports.exit(EXIT_FAIL);
|
|
72
74
|
return;
|
|
73
75
|
}
|
|
74
|
-
|
|
76
|
+
/*
|
|
77
|
+
* Narrate the run while it happens.
|
|
78
|
+
*
|
|
79
|
+
* Everything else the CLI reports is a finished artifact, which is the right shape for evidence
|
|
80
|
+
* and the wrong shape for the minutes a verification actually takes. Without this the dashboard
|
|
81
|
+
* has nothing to show between "linked" and "done", and a run that is working looks exactly like
|
|
82
|
+
* one that has died — the ambiguity somebody spent fifteen minutes inside.
|
|
83
|
+
*
|
|
84
|
+
* Opt-in and best-effort: no cloud credentials means nothing is buffered and nothing is sent.
|
|
85
|
+
*/
|
|
86
|
+
/*
|
|
87
|
+
* A correlation id for the STREAM, minted before the run exists.
|
|
88
|
+
*
|
|
89
|
+
* The artifact's own `runId` is only assigned once verification finishes, and these events have
|
|
90
|
+
* to be attributable from the first one — so the stream gets its own id, and the dashboard keys
|
|
91
|
+
* live progress by it until the finished run replaces the whole picture.
|
|
92
|
+
*/
|
|
93
|
+
const streamId = randomUUID();
|
|
94
|
+
const cloud = resolveCloudConfig(process.env);
|
|
95
|
+
const progress = createProgressReporter(streamId, cloud, cloudFetch);
|
|
96
|
+
let run;
|
|
97
|
+
try {
|
|
98
|
+
run = await conn.verify(progress.onProgress);
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
// Stopped before the last flush so the timer cannot fire mid-send, and flushed after it so the
|
|
102
|
+
// events from the final flow are not thrown away with the interval that would have sent them.
|
|
103
|
+
progress.stop();
|
|
104
|
+
await progress.flush().catch(() => undefined);
|
|
105
|
+
}
|
|
75
106
|
await pushRunToCloud(run, ports); // best-effort; opt-in; never changes the verdict or exit code
|
|
107
|
+
/*
|
|
108
|
+
* The last event anybody watching is waiting for, sent after the artifact has actually landed —
|
|
109
|
+
* so "pushed" on a dashboard means the run is really there, not that we were about to try.
|
|
110
|
+
*/
|
|
111
|
+
await syncProgressToCloud(streamId,
|
|
112
|
+
// The run's OWN injected timestamp — no wall clock is read in this path (rule 7).
|
|
113
|
+
[{ phase: VerifyPhase.PUSHED, at: run.createdAt }], cloud, cloudFetch).catch(() => undefined);
|
|
76
114
|
ports.out(renderRunReport(run));
|
|
77
115
|
ports.exit(run.verdict.status === VerdictStatus.PASS ? EXIT_PASS : EXIT_FAIL);
|
|
78
116
|
}
|
|
@@ -179,12 +217,13 @@ async function openLiveConnection(opts) {
|
|
|
179
217
|
return {
|
|
180
218
|
sessionReady: (timeoutMs) => waitForSession(deps.sessions, timeoutMs, opts.now),
|
|
181
219
|
listFlows: () => deps.flows.list(),
|
|
182
|
-
verify: async () => {
|
|
220
|
+
verify: async (onProgress) => {
|
|
183
221
|
const run = await runner.verify({
|
|
184
222
|
project: { name: opts.projectName, framework: RunFramework.OTHER, previewUrl: opts.url },
|
|
185
223
|
agent: { id: VERIFY_AGENT_ID, kind: RunAgentKind.OEM_PIPELINE },
|
|
186
224
|
trigger: { kind: RunTrigger.OEM },
|
|
187
225
|
profile: RunProfile.PROD_PREVIEW,
|
|
226
|
+
...(onProgress === undefined ? {} : { onProgress }),
|
|
188
227
|
});
|
|
189
228
|
// Persist the artifact. `reticle gate` decides from RunStore.latest, so without this the
|
|
190
229
|
// documented CI loop is broken end to end: `reticle verify` could pass and the gate would still
|
|
@@ -214,22 +253,38 @@ async function openLiveConnection(opts) {
|
|
|
214
253
|
* worst answer available, and reached most often by the people with the fewest other options, since
|
|
215
254
|
* the skill offers this command as the way to a verdict with no MCP at all.
|
|
216
255
|
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
256
|
+
* The message says every way out rather than picking one, and it says FIRST that a busy port is the
|
|
257
|
+
* normal state rather than a fault — an install that worked leaves a daemon on it, so a reader who
|
|
258
|
+
* arrives here has done nothing wrong and should not go looking for what they broke (#689).
|
|
259
|
+
*
|
|
260
|
+
* `reticle drive` leads, because it is the only option that works in the state most people are in
|
|
261
|
+
* when they reach this message: the client exposes no `reticle_*` tools (Codex, Cursor Cloud,
|
|
262
|
+
* Antigravity, a session whose MCP link dropped), which is exactly when the CLI is reached for. It
|
|
263
|
+
* ATTACHES to the running daemon rather than binding — see cli/drive-attach.ts — so there is nothing
|
|
264
|
+
* to stop, nothing to race, and it hands back a sessionId the daemon owns. The advice that used to
|
|
265
|
+
* lead, "ask the daemon through the tools", is the one thing that reader by construction cannot do.
|
|
221
266
|
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
267
|
+
* Stopping the daemon stays on the list and stays LAST of the working options, with the reason: the
|
|
268
|
+
* MCP proxy respawns one into the gap, so `stop` is a race the caller usually loses, and it kills
|
|
269
|
+
* the agent's own link on the way past.
|
|
270
|
+
*
|
|
271
|
+
* `verify` itself attaching, rather than needing the port at all, is the real fix and is #689's
|
|
272
|
+
* first bullet — not this change.
|
|
224
273
|
*/
|
|
225
274
|
export function portBusyMessage(port) {
|
|
226
275
|
return (`reticle verify needs port ${String(port)} — the port your app dials — and a Reticle daemon is ` +
|
|
227
276
|
'already listening on it. It did not start a second one.\n\n' +
|
|
228
|
-
'
|
|
277
|
+
' This is the NORMAL state after a working install, not a fault: the daemon your MCP client ' +
|
|
278
|
+
'started owns that port.\n\n' +
|
|
279
|
+
` • Drive the app through the daemon that is already there — this needs no tools and stops ` +
|
|
280
|
+
`nothing: npx @reticlehq/server drive <url>\n` +
|
|
281
|
+
' • If your client HAS the Reticle tools, ask that daemon directly: ' +
|
|
229
282
|
'reticle_run { tool: "reticle_verify", args: { action: "change", files: ["..."] } }\n' +
|
|
230
|
-
` • Or stop it and re-run: npx @reticlehq/server stop --port ${String(port)}\n` +
|
|
231
283
|
` • Or run both on another port, if your app is configured for it: RETICLE_PORT=<port> ` +
|
|
232
|
-
'npx @reticlehq/server verify <url
|
|
284
|
+
'npx @reticlehq/server verify <url>\n' +
|
|
285
|
+
` • Stopping the daemon (npx @reticlehq/server stop --port ${String(port)}) works, but it cuts ` +
|
|
286
|
+
"your agent's MCP link and the proxy usually respawns a daemon into the gap before verify can " +
|
|
287
|
+
'bind — prefer one of the above.');
|
|
233
288
|
}
|
|
234
289
|
export function handleVerify(parsed) {
|
|
235
290
|
const now = () => Date.now();
|
|
@@ -257,6 +312,25 @@ export function handleVerify(parsed) {
|
|
|
257
312
|
const port = parsed.port ?? RETICLE_DEFAULT_PORT;
|
|
258
313
|
if ((await probePresence(port, { tcpOpen: probeDaemon, status: fetchStatus })) ===
|
|
259
314
|
PortPresence.DAEMON) {
|
|
315
|
+
// A daemon owning the port is the NORMAL state after a working install, and it used to be the
|
|
316
|
+
// end of the road: `verify` refused, the other verdict paths need saved flows a first-install
|
|
317
|
+
// project does not have, and stopping the daemon cuts the agent's own MCP link. An agent could
|
|
318
|
+
// hold a live, correctly-wired app and have no way to reach a verdict at all.
|
|
319
|
+
//
|
|
320
|
+
// With `--expect` there is now a way, and it does not need the port: ask the daemon that
|
|
321
|
+
// already owns it. See runAdhocVerdict.
|
|
322
|
+
if (parsed.expect !== undefined) {
|
|
323
|
+
const verdict = await runAdhocVerdict({
|
|
324
|
+
port,
|
|
325
|
+
...(parsed.url !== undefined && '' !== parsed.url ? { url: parsed.url } : {}),
|
|
326
|
+
predicate: parsed.expect,
|
|
327
|
+
...((t) => (t === undefined || 0 === t.length ? {} : { token: t }))(readOrCreatePairingTokenSync(defaultPairingTokenDir())),
|
|
328
|
+
});
|
|
329
|
+
for (const line of verdict.lines)
|
|
330
|
+
ports.out(line);
|
|
331
|
+
ports.exit(verdict.code);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
260
334
|
ports.fail(portBusyMessage(port));
|
|
261
335
|
ports.exit(1);
|
|
262
336
|
return;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* caller is expected to establish the tenant before trusting what comes back.
|
|
6
6
|
*/
|
|
7
7
|
export declare const findCredential: (raw: unknown, projectId: string, url: string, orgId: string | undefined) => string | undefined;
|
|
8
|
-
|
|
8
|
+
interface CredentialWrite {
|
|
9
9
|
projectId: string;
|
|
10
10
|
url: string;
|
|
11
11
|
key: string;
|
|
@@ -35,3 +35,4 @@ export interface CredentialWrite {
|
|
|
35
35
|
export declare const applyCredential: (store: Record<string, unknown>, write: CredentialWrite) => Record<string, unknown>;
|
|
36
36
|
/** Where the store lives, given the reticle home directory. */
|
|
37
37
|
export declare const credentialsPath: (homeDir: string, file: string) => string;
|
|
38
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Run `reticle link` with these arguments. Injected; see the note at the top of this file. */
|
|
2
|
-
|
|
2
|
+
type Linker = (argv: readonly string[]) => Promise<number>;
|
|
3
3
|
/**
|
|
4
4
|
* `reticle login` — browser device flow by default; `--email <e>` (or a positional email) keeps the
|
|
5
5
|
* headless two-step code path for CI/servers where opening a browser makes no sense.
|
|
@@ -15,3 +15,4 @@ export declare const cmdLogin: (argv: readonly string[], link: Linker) => Promis
|
|
|
15
15
|
* one you did not mean.
|
|
16
16
|
*/
|
|
17
17
|
export declare const cmdLogout: (argv?: readonly string[]) => Promise<number>;
|
|
18
|
+
export {};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
/** Where per-host sessions live under the reticle home directory. */
|
|
10
10
|
export declare const SESSIONS_DIR = "sessions";
|
|
11
|
-
|
|
11
|
+
declare const SessionSchema: z.ZodObject<{
|
|
12
12
|
url: z.ZodString;
|
|
13
13
|
token: z.ZodString;
|
|
14
14
|
orgName: z.ZodString;
|
|
@@ -46,3 +46,4 @@ export declare const readSessionFrom: (raw: Promise<unknown>) => Promise<Session
|
|
|
46
46
|
* sessions existed keeps working and is not silently signed out by an upgrade.
|
|
47
47
|
*/
|
|
48
48
|
export declare const resolveSessionFor: (url: string, perHost: Session | null, active: Session | null) => Session | null;
|
|
49
|
+
export {};
|
|
@@ -9,7 +9,7 @@ import { z } from 'zod';
|
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
/** Where per-host sessions live under the reticle home directory. */
|
|
11
11
|
export const SESSIONS_DIR = 'sessions';
|
|
12
|
-
|
|
12
|
+
const SessionSchema = z.object({
|
|
13
13
|
url: z.string(),
|
|
14
14
|
token: z.string(),
|
|
15
15
|
orgName: z.string(),
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* replay, the spec runner), which exists whether or not a drive URL was named.
|
|
13
13
|
*/
|
|
14
14
|
import type { StartOptions } from '../index.js';
|
|
15
|
-
|
|
15
|
+
type DaemonFlags = {
|
|
16
16
|
port: number;
|
|
17
17
|
driveUrl?: string;
|
|
18
18
|
headless: boolean;
|
|
@@ -30,3 +30,4 @@ export declare function daemonStartOptions(parsed: DaemonFlags): StartOptions;
|
|
|
30
30
|
* idea: that headless belongs to the drive URL. It belongs to the pool, which exists either way.
|
|
31
31
|
*/
|
|
32
32
|
export declare function daemonSpawnArgs(parsed: DaemonFlags): string[];
|
|
33
|
+
export {};
|
|
@@ -53,18 +53,18 @@ export declare const DevicePollSchema: z.ZodObject<{
|
|
|
53
53
|
}>>;
|
|
54
54
|
}, "strip", z.ZodTypeAny, {
|
|
55
55
|
status: string;
|
|
56
|
+
token?: string | undefined;
|
|
56
57
|
org?: {
|
|
57
58
|
name: string;
|
|
58
59
|
id?: string | undefined;
|
|
59
60
|
} | undefined;
|
|
60
|
-
token?: string | undefined;
|
|
61
61
|
}, {
|
|
62
62
|
status: string;
|
|
63
|
+
token?: string | undefined;
|
|
63
64
|
org?: {
|
|
64
65
|
name: string;
|
|
65
66
|
id?: string | undefined;
|
|
66
67
|
} | undefined;
|
|
67
|
-
token?: string | undefined;
|
|
68
68
|
}>;
|
|
69
69
|
/**
|
|
70
70
|
* Best-effort open the approval page in the default browser.
|
|
@@ -18,7 +18,7 @@ export interface DaemonIdentity {
|
|
|
18
18
|
version?: string;
|
|
19
19
|
contract?: string;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
interface DaemonLine {
|
|
22
22
|
/** The `daemon ✓ …` line itself. */
|
|
23
23
|
text: string;
|
|
24
24
|
/** A skew sentence to print underneath, when this CLI and that daemon disagree. */
|
|
@@ -35,3 +35,4 @@ export declare function daemonLine(port: number, pid: number | null, peer: Daemo
|
|
|
35
35
|
version: string;
|
|
36
36
|
contract: string;
|
|
37
37
|
}): DaemonLine;
|
|
38
|
+
export {};
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Registering the MCP server and instrumenting the app are two different halves of the install, and
|
|
11
11
|
* more than one route does the first without the second.
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
interface ProjectWiringFacts {
|
|
14
14
|
/** The id from `.reticle.json`, or undefined when there is no config here. */
|
|
15
15
|
projectId: string | undefined;
|
|
16
16
|
/** Has an app for this project ever connected on this port? Durable across daemon restarts. */
|
|
@@ -35,3 +35,4 @@ export interface ProjectWiringFacts {
|
|
|
35
35
|
* other way — and `init` is the one action that can overwrite a setup that already works.
|
|
36
36
|
*/
|
|
37
37
|
export declare function projectWiringLine(facts: ProjectWiringFacts): string;
|
|
38
|
+
export {};
|
|
@@ -47,7 +47,7 @@ export declare const DoctorRow: {
|
|
|
47
47
|
readonly TRACING: "tracing";
|
|
48
48
|
readonly DESKTOP: "desktop";
|
|
49
49
|
};
|
|
50
|
-
|
|
50
|
+
type DoctorRowLabel = (typeof DoctorRow)[keyof typeof DoctorRow];
|
|
51
51
|
export declare const DOCTOR_ROW_LABELS: readonly DoctorRowLabel[];
|
|
52
52
|
/**
|
|
53
53
|
* Width the label column pads to.
|
|
@@ -60,3 +60,4 @@ export declare const DOCTOR_ROW_LABELS: readonly DoctorRowLabel[];
|
|
|
60
60
|
export declare const LABEL_COLUMN: number;
|
|
61
61
|
/** Build one `doctor` row: the standard indent, the label padded to the column, then `rest`. */
|
|
62
62
|
export declare function doctorRow(label: DoctorRowLabel, rest: string): string;
|
|
63
|
+
export {};
|
|
@@ -42,7 +42,7 @@ export type DriveMode = (typeof DriveMode)[keyof typeof DriveMode];
|
|
|
42
42
|
/** Pure. Exhaustive by switch, so a fourth presence has to decide what driving means for it. */
|
|
43
43
|
export declare function decideDriveMode(presence: PortPresence): DriveMode;
|
|
44
44
|
/** A driveable session the daemon opened on our behalf. */
|
|
45
|
-
|
|
45
|
+
interface DriveSession {
|
|
46
46
|
sessionId: string;
|
|
47
47
|
/** Whether the tab's SDK actually registered — false ⇒ the app may not embed @reticlehq/core. */
|
|
48
48
|
ready: boolean;
|
|
@@ -51,7 +51,7 @@ export interface DriveSession {
|
|
|
51
51
|
/** The daemon's own diagnosis when the tab did not connect. */
|
|
52
52
|
hint?: string;
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
type DriveAttachResult = {
|
|
55
55
|
ok: true;
|
|
56
56
|
session: DriveSession;
|
|
57
57
|
} | {
|
|
@@ -59,7 +59,7 @@ export type DriveAttachResult = {
|
|
|
59
59
|
reason: string;
|
|
60
60
|
};
|
|
61
61
|
/** POST the drive request. Injected so the decision logic is tested without a socket. */
|
|
62
|
-
|
|
62
|
+
type DrivePost = (port: number, path: string, body: string) => Promise<{
|
|
63
63
|
status: number;
|
|
64
64
|
body: string;
|
|
65
65
|
}>;
|
|
@@ -110,3 +110,4 @@ export declare function driveForeignHolder(description: string): string;
|
|
|
110
110
|
* and that sentence is "run it again", because the second run attaches instead of binding.
|
|
111
111
|
*/
|
|
112
112
|
export declare function driveRaceLost(port: number, url: string): string;
|
|
113
|
+
export {};
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
/** Named so a reader of the hook output knows the flag is real and not a suggestion. */
|
|
14
14
|
export declare const GATE_SKIP_ENV = "RETICLE_SKIP_GATE";
|
|
15
|
-
|
|
15
|
+
interface GateHookInput {
|
|
16
16
|
/** Flows the changed files touch that have no passing artifact. */
|
|
17
17
|
uncovered: readonly string[];
|
|
18
18
|
/** Flows held back as flaky — reported, never counted as a pass. */
|
|
@@ -31,3 +31,4 @@ export interface GateHookInput {
|
|
|
31
31
|
* interrupted.
|
|
32
32
|
*/
|
|
33
33
|
export declare function gateHookMessage(exit: number, input: GateHookInput): string | undefined;
|
|
34
|
+
export {};
|
|
@@ -21,17 +21,6 @@ import { nextActionFor } from '../session/no-session-next-action.js';
|
|
|
21
21
|
export function statusNextAction(facts) {
|
|
22
22
|
if (facts.sessionCount > 0)
|
|
23
23
|
return undefined;
|
|
24
|
-
// Ahead of everything else, because it dominates: an app that was never wired cannot connect, and
|
|
25
|
-
// no advice about dev servers or ports applies until it is. `previouslyConnected` overrides it —
|
|
26
|
-
// an app CAN be wired by the Vite or Babel plugin with no `.reticle.json` at all, so a project
|
|
27
|
-
// that has connected here before is wired whatever this file says, and sending it back to `init`
|
|
28
|
-
// would be the same wrong answer in the other direction.
|
|
29
|
-
if (!facts.initialized && !facts.previouslyConnected) {
|
|
30
|
-
return ('no app has ever connected for this project, and there is no Reticle config here — so the ' +
|
|
31
|
-
'tools are registered and the app itself is not instrumented. Those are two different halves ' +
|
|
32
|
-
'of the install. Run `npx @reticlehq/server init` in the app directory, then start the dev ' +
|
|
33
|
-
'server and load the page.');
|
|
34
|
-
}
|
|
35
24
|
if (!facts.running) {
|
|
36
25
|
// `running: false` reads as "Reticle is broken", and it usually means the opposite: the daemon is
|
|
37
26
|
// started by an agent, on demand, and idles out when nobody is driving. A user who has not
|
|
@@ -43,6 +32,16 @@ export function statusNextAction(facts) {
|
|
|
43
32
|
`Reticle tool, and it exits again when idle. ${wiring} Ask your agent to verify something, then ` +
|
|
44
33
|
`run status again.`).replace(/\s+/g, ' ');
|
|
45
34
|
}
|
|
35
|
+
// Only diagnose instrumentation after a live daemon makes that diagnosis possible. When the
|
|
36
|
+
// daemon is absent, claiming the app is unwired confuses missing evidence with evidence of a
|
|
37
|
+
// missing install. `previouslyConnected` overrides this branch because plugin-based wiring may
|
|
38
|
+
// connect without creating `.reticle.json`.
|
|
39
|
+
if (!facts.initialized && !facts.previouslyConnected) {
|
|
40
|
+
return ('no app has ever connected for this project, and there is no Reticle config here — so the ' +
|
|
41
|
+
'tools are registered and the app itself is not instrumented. Those are two different halves ' +
|
|
42
|
+
'of the install. Run `npx @reticlehq/server init` in the app directory, then start the dev ' +
|
|
43
|
+
'server and load the page.');
|
|
44
|
+
}
|
|
46
45
|
// The daemon is up and no page has connected. `nextActionFor` owns the ranking; this passes what
|
|
47
46
|
// it has and lets that function say what is missing rather than guessing at it. It CAN see
|
|
48
47
|
// listening ports now — the announced ones — which is what the empty list here used to cost.
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -33,15 +33,16 @@ import { installDaemonResilience, recordExitReason, DaemonExitReason, } from './
|
|
|
33
33
|
import { IdleShutdown, resolveIdleShutdownMs, resolveIdleCheckMs } from './daemon/idle-shutdown.js';
|
|
34
34
|
import { DaemonHeartbeat, resolveHeartbeatMs } from './daemon/heartbeat.js';
|
|
35
35
|
import { everServedToolCall } from './daemon/daemon-usefulness.js';
|
|
36
|
+
import { DAEMON_START_FAILED_EVENT, readDaemonStartupCause } from './daemon/startup-failure.js';
|
|
36
37
|
import { fetchStatus, summarizeStatus, warnOnDaemonSkew, decideOpen, openInBrowser, openCommand, } from './cli/cli-launch.js';
|
|
37
38
|
import { handleDrive } from './cli/drive-command.js';
|
|
38
39
|
import { handleVerify } from './cli/cli-verify.js';
|
|
39
40
|
import { runKill } from './cli/cli-kill.js';
|
|
40
41
|
import { summarizeHunt } from './hunt/hunt-report.js';
|
|
41
|
-
import { runInit } from '
|
|
42
|
+
import { runInit, buildNodeIo } from '@reticlehq/init';
|
|
42
43
|
import { continueAfterInit } from './setup/init-runtime.js';
|
|
43
44
|
import { handleDoctor } from './cli/cli-doctor.js';
|
|
44
|
-
import {
|
|
45
|
+
import { serverInitHost } from './setup/init-host.js';
|
|
45
46
|
import { describeLicense } from './license/license.js';
|
|
46
47
|
import { isLikelyDevServerPort, devServerPortWarning, readProjectPort, readProjectId, } from './cli/cli-port.js';
|
|
47
48
|
import { DAEMON_INNER_COMMAND, PORT_FLAG, parseCliArgs, CLI_USAGE } from './cli/cli-parse.js';
|
|
@@ -52,7 +53,7 @@ import { reportCliRun } from './telemetry/cli-telemetry.js';
|
|
|
52
53
|
export { parseCliArgs, CLI_USAGE };
|
|
53
54
|
function handleInit(parsed) {
|
|
54
55
|
const cwd = process.cwd();
|
|
55
|
-
const io = buildNodeIo(cwd);
|
|
56
|
+
const io = buildNodeIo(cwd, serverInitHost());
|
|
56
57
|
const result = runInit({
|
|
57
58
|
cwd,
|
|
58
59
|
port: parsed.port,
|
|
@@ -60,6 +61,9 @@ function handleInit(parsed) {
|
|
|
60
61
|
dryRun: parsed.dryRun,
|
|
61
62
|
install: parsed.install,
|
|
62
63
|
...(parsed.app === undefined ? {} : { app: parsed.app }),
|
|
64
|
+
// Handed to init, not only to the drive phase below: the preflight names `--url` as the way
|
|
65
|
+
// past a missing package manager, and could not honour that while never being told about it.
|
|
66
|
+
...(parsed.url === undefined ? {} : { url: parsed.url }),
|
|
63
67
|
captureBodies: true === parsed.captureBodies,
|
|
64
68
|
// The outcome is reported by confirmInstall instead, once it knows whether an app connected —
|
|
65
69
|
// `init` writing files was never the same thing as `init` working (#269).
|
|
@@ -122,6 +126,7 @@ async function serveWithHonestExit(parsed) {
|
|
|
122
126
|
return;
|
|
123
127
|
}
|
|
124
128
|
const daemonArgs = daemonSpawnArgs(parsed);
|
|
129
|
+
const startupStartedAt = Date.now();
|
|
125
130
|
spawnDaemon(process.execPath, scriptPath, daemonArgs, parsed.port);
|
|
126
131
|
// The child binds asynchronously and, when it cannot, exits 1 long after this process would have
|
|
127
132
|
// reported success. Wait for it to ANSWER — `/status` responding is the only evidence a daemon
|
|
@@ -129,12 +134,14 @@ async function serveWithHonestExit(parsed) {
|
|
|
129
134
|
const bound = await waitForPresence(parsed.port, PortPresence.DAEMON, SERVE_BIND_TIMEOUT_MS);
|
|
130
135
|
if (!bound) {
|
|
131
136
|
const settled = await probePresence(parsed.port, { tcpOpen: probeDaemon, status: fetchStatus });
|
|
137
|
+
const startupCause = readDaemonStartupCause(logPath(parsed.port), startupStartedAt);
|
|
132
138
|
log('reticle_daemon_start_failed_parent', {
|
|
133
139
|
port: parsed.port,
|
|
134
140
|
presence: settled,
|
|
135
141
|
reason: describePresence(settled, parsed.port),
|
|
136
142
|
log: logPath(parsed.port),
|
|
137
143
|
stateDir: stateDirProblem(reticleStateHome()) === undefined ? 'writable' : 'unwritable',
|
|
144
|
+
...(startupCause === undefined ? {} : { cause: startupCause }),
|
|
138
145
|
});
|
|
139
146
|
// Name the CAUSE when we can see it. An unwritable state directory is a first-run failure mode
|
|
140
147
|
// (locked-down home, read-only container mount, managed profile) that produced only "nothing is
|
|
@@ -142,8 +149,11 @@ async function serveWithHonestExit(parsed) {
|
|
|
142
149
|
// cannot exist. Found by stress-testing 2.6.0 with `chmod 555 ~/.reticle`.
|
|
143
150
|
const dirProblem = stateDirProblem(reticleStateHome());
|
|
144
151
|
process.stderr.write(dirProblem === undefined
|
|
145
|
-
?
|
|
146
|
-
`
|
|
152
|
+
? startupCause === undefined
|
|
153
|
+
? `the daemon did not come up on :${String(parsed.port)} — ${describePresence(settled, parsed.port)}\n` +
|
|
154
|
+
`see ${logPath(parsed.port)}\n`
|
|
155
|
+
: `the daemon did not come up on :${String(parsed.port)}.\n${startupCause}\n` +
|
|
156
|
+
`see ${logPath(parsed.port)}\n`
|
|
147
157
|
: `the daemon did not come up on :${String(parsed.port)}.\n${dirProblem}\n`);
|
|
148
158
|
process.exit(1);
|
|
149
159
|
return;
|
|
@@ -367,8 +377,10 @@ async function handleAffected(files, since) {
|
|
|
367
377
|
try {
|
|
368
378
|
const fs = createNodeFileSystem();
|
|
369
379
|
const reticleRoot = join(process.cwd(), ReticleDir.ROOT);
|
|
370
|
-
|
|
371
|
-
|
|
380
|
+
// The CLI gate still degrades to "no changes" rather than crash CI over a bad ref — the
|
|
381
|
+
// original reasoning, now opted into explicitly instead of handed a clean-looking empty list.
|
|
382
|
+
const changed = (await resolveChangedFiles(files, since, process.cwd())).files;
|
|
383
|
+
const result = affectedSavedFlows(await loadNamedFlows(fs, reticleRoot, readProjectId(process.cwd())), changed);
|
|
372
384
|
log('reticle_affected', {
|
|
373
385
|
changedFiles: changed,
|
|
374
386
|
affected: result.affected,
|
|
@@ -644,12 +656,12 @@ function handleDaemonInner(parsed) {
|
|
|
644
656
|
})
|
|
645
657
|
.catch((error) => {
|
|
646
658
|
const message = error instanceof Error ? error.message : String(error);
|
|
647
|
-
log(
|
|
659
|
+
log(DAEMON_START_FAILED_EVENT, { error: message });
|
|
648
660
|
removePid(parsed.port);
|
|
649
661
|
process.exit(1);
|
|
650
662
|
});
|
|
651
663
|
}
|
|
652
|
-
function main() {
|
|
664
|
+
export function main() {
|
|
653
665
|
// Before anything reads process.env — notably the telemetry gate and the bridge's security
|
|
654
666
|
// options — fold in a project-local `.env`. Values already in the environment always win.
|
|
655
667
|
loadDotEnv(process.cwd());
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is this machine signed in to a Reticle workspace?
|
|
3
|
+
*
|
|
4
|
+
* Asked by the HUD, and there are two sources that must not be reimplemented per caller: the session
|
|
5
|
+
* file `reticle login` writes to `~/.reticle/session.json`, and `RETICLE_CLOUD_KEY` for an agent that
|
|
6
|
+
* was handed a key instead. Everything that gates on login — the defect sync button, the prompt to sign
|
|
7
|
+
* in — resolves through here.
|
|
8
|
+
*
|
|
9
|
+
* Node-only by design: it reads the filesystem and the environment, so it lives in the server and
|
|
10
|
+
* only the SHAPE (`AccountState`) is in core, where the contract belongs.
|
|
11
|
+
*/
|
|
12
|
+
import { type AccountState } from '@reticlehq/core';
|
|
13
|
+
/**
|
|
14
|
+
* Read the account state for this machine.
|
|
15
|
+
*
|
|
16
|
+
* The env key WINS over the session file: an agent handed a key is authenticating as that key,
|
|
17
|
+
* whatever a human left on disk, and reporting the human's org there would be a lie about who is
|
|
18
|
+
* acting.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readAccountState(home: string, env: NodeJS.ProcessEnv): AccountState;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is this machine signed in to a Reticle workspace?
|
|
3
|
+
*
|
|
4
|
+
* Asked by the HUD, and there are two sources that must not be reimplemented per caller: the session
|
|
5
|
+
* file `reticle login` writes to `~/.reticle/session.json`, and `RETICLE_CLOUD_KEY` for an agent that
|
|
6
|
+
* was handed a key instead. Everything that gates on login — the defect sync button, the prompt to sign
|
|
7
|
+
* in — resolves through here.
|
|
8
|
+
*
|
|
9
|
+
* Node-only by design: it reads the filesystem and the environment, so it lives in the server and
|
|
10
|
+
* only the SHAPE (`AccountState`) is in core, where the contract belongs.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { ReticleDir } from '@reticlehq/core';
|
|
15
|
+
import { CloudEnv } from './cloud-sync.js';
|
|
16
|
+
import { SESSION_FILE } from '../cli/cloud-kit.js';
|
|
17
|
+
/** Signed OUT is the safe answer: it shows the way in, where a wrong "signed in" hides it. */
|
|
18
|
+
const SIGNED_OUT = { signedIn: false };
|
|
19
|
+
/**
|
|
20
|
+
* The fields we read off the session file, and nothing else.
|
|
21
|
+
*
|
|
22
|
+
* Narrowed by hand rather than parsed with the login schema on purpose: this function must be unable
|
|
23
|
+
* to carry a token even if the file grows one, and the surest way to guarantee that is never to bind
|
|
24
|
+
* it to a name here.
|
|
25
|
+
*/
|
|
26
|
+
function fromSessionFile(home) {
|
|
27
|
+
try {
|
|
28
|
+
const raw = JSON.parse(readFileSync(join(home, ReticleDir.ROOT, SESSION_FILE), 'utf8'));
|
|
29
|
+
if ('object' !== typeof raw || null === raw)
|
|
30
|
+
return undefined;
|
|
31
|
+
const record = raw;
|
|
32
|
+
// A half-written or hand-edited file must not read as authenticated. `signedIn: true` is the
|
|
33
|
+
// claim that costs something when wrong, because it hides the way in.
|
|
34
|
+
if ('string' !== typeof record['token'] || 0 === record['token'].length)
|
|
35
|
+
return undefined;
|
|
36
|
+
const org = record['orgName'];
|
|
37
|
+
const host = record['url'];
|
|
38
|
+
return {
|
|
39
|
+
signedIn: true,
|
|
40
|
+
...('string' === typeof org && org.length > 0 ? { org } : {}),
|
|
41
|
+
...('string' === typeof host && host.length > 0 ? { host } : {}),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Read the account state for this machine.
|
|
50
|
+
*
|
|
51
|
+
* The env key WINS over the session file: an agent handed a key is authenticating as that key,
|
|
52
|
+
* whatever a human left on disk, and reporting the human's org there would be a lie about who is
|
|
53
|
+
* acting.
|
|
54
|
+
*/
|
|
55
|
+
export function readAccountState(home, env) {
|
|
56
|
+
const key = env[CloudEnv.KEY];
|
|
57
|
+
const url = env[CloudEnv.URL];
|
|
58
|
+
if ('string' === typeof key && key.length > 0) {
|
|
59
|
+
return {
|
|
60
|
+
signedIn: true,
|
|
61
|
+
...('string' === typeof url && url.length > 0 ? { host: url.replace(/\/+$/, '') } : {}),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return fromSessionFile(home) ?? SIGNED_OUT;
|
|
65
|
+
}
|