@reticlehq/server 2.13.0 → 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/dev-server-wait.d.ts +8 -0
- package/dist/setup/dev-server-wait.js +3 -1
- 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 +155 -48
- 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
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
3
|
+
import { LOOPBACK_HOST, MCP_SSE_PATH } from '@reticlehq/core';
|
|
4
|
+
import { TOKEN_QUERY_PARAM } from '../bridge/token-auth.js';
|
|
5
|
+
import { ReticleTool } from '../tools/tool-names.js';
|
|
6
|
+
/** `verified` is the only field that decides the exit code. Everything else is for the reader. */
|
|
7
|
+
const PROVED = 'yes';
|
|
8
|
+
function endpointFor(port, token) {
|
|
9
|
+
const url = new URL(`http://${LOOPBACK_HOST}:${String(port)}${MCP_SSE_PATH}`);
|
|
10
|
+
if (token !== undefined && token.length > 0)
|
|
11
|
+
url.searchParams.set(TOKEN_QUERY_PARAM, token);
|
|
12
|
+
return url;
|
|
13
|
+
}
|
|
14
|
+
async function connectOverSse(endpoint) {
|
|
15
|
+
const client = new Client({ name: 'reticle-cli', version: '1' }, { capabilities: {} });
|
|
16
|
+
await client.connect(new SSEClientTransport(endpoint));
|
|
17
|
+
return {
|
|
18
|
+
call: async (name, args) => await client.callTool({ name, arguments: args }),
|
|
19
|
+
close: async () => {
|
|
20
|
+
await client.close();
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** The verdict object an MCP tool result carries, or undefined when the shape is not one. */
|
|
25
|
+
function verdictOf(result) {
|
|
26
|
+
const structured = result?.structuredContent;
|
|
27
|
+
if ('object' === typeof structured && null !== structured) {
|
|
28
|
+
return structured;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The tool's own words when it refused, rather than the envelope carrying them.
|
|
34
|
+
*
|
|
35
|
+
* A refusal from these tools is the most useful text they produce — it names the cause and the next
|
|
36
|
+
* action — and printing the MCP result object around it buries that in JSON escaping. The reader is
|
|
37
|
+
* at a terminal; give them the sentence.
|
|
38
|
+
*/
|
|
39
|
+
function refusalText(result) {
|
|
40
|
+
const r = result;
|
|
41
|
+
if (true !== r?.isError || !Array.isArray(r.content))
|
|
42
|
+
return undefined;
|
|
43
|
+
const text = r.content
|
|
44
|
+
.map((part) => part.text)
|
|
45
|
+
.filter((t) => 'string' === typeof t)
|
|
46
|
+
.join('\n');
|
|
47
|
+
if (0 === text.length)
|
|
48
|
+
return undefined;
|
|
49
|
+
// The tools answer with a JSON envelope whose `error` is the sentence; unwrap when it is one.
|
|
50
|
+
try {
|
|
51
|
+
const parsed = JSON.parse(text);
|
|
52
|
+
const inner = parsed?.error;
|
|
53
|
+
return 'string' === typeof inner ? inner : text;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return text;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Navigate (optionally) and assert, against the daemon already on this port.
|
|
61
|
+
*
|
|
62
|
+
* Exit code 0 ONLY for `verified: "yes"`. `unknown` exits non-zero on purpose: it means Reticle could
|
|
63
|
+
* not tell what happened, and a CI step that treats "could not tell" as success is the false green
|
|
64
|
+
* this whole product exists to prevent.
|
|
65
|
+
*/
|
|
66
|
+
export async function runAdhocVerdict(options) {
|
|
67
|
+
const connect = options.connect ?? connectOverSse;
|
|
68
|
+
let caller;
|
|
69
|
+
try {
|
|
70
|
+
caller = await connect(endpointFor(options.port, options.token));
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
code: 1,
|
|
75
|
+
lines: [
|
|
76
|
+
`could not reach the daemon on port ${String(options.port)}: ${error instanceof Error ? error.message : String(error)}`,
|
|
77
|
+
'It answers `reticle status`; if that works and this does not, the daemon is older than this CLI.',
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
if (options.url !== undefined && options.url.length > 0) {
|
|
83
|
+
await caller.call(ReticleTool.NAVIGATE, { url: options.url });
|
|
84
|
+
}
|
|
85
|
+
const result = await caller.call(ReticleTool.ASSERT, { predicate: options.predicate });
|
|
86
|
+
const refusal = refusalText(result);
|
|
87
|
+
if (refusal !== undefined) {
|
|
88
|
+
return { code: 1, lines: [`verified: unknown`, refusal] };
|
|
89
|
+
}
|
|
90
|
+
const verdict = verdictOf(result);
|
|
91
|
+
// Narrowed rather than stringified: these arrive as `unknown` off a record, and a verdict field
|
|
92
|
+
// that is accidentally an object must not print as `[object Object]` in the one line a reader
|
|
93
|
+
// acts on.
|
|
94
|
+
const asText = (value) => 'string' === typeof value ? value : undefined;
|
|
95
|
+
const verified = asText(verdict?.['verified']);
|
|
96
|
+
const reason = asText(verdict?.['verifiedReason']) ?? asText(verdict?.['failureReason']);
|
|
97
|
+
const lines = [
|
|
98
|
+
`verified: ${verified ?? 'unknown'}`,
|
|
99
|
+
...(reason === undefined ? [] : [`reason: ${reason}`]),
|
|
100
|
+
JSON.stringify(verdict ?? result, null, 2),
|
|
101
|
+
];
|
|
102
|
+
return { code: PROVED === verified ? 0 : 1, lines };
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
code: 1,
|
|
107
|
+
lines: [
|
|
108
|
+
`the verdict could not be taken: ${error instanceof Error ? error.message : String(error)}`,
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
await caller.close().catch(() => undefined);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -34,14 +34,28 @@ export interface ChromiumProbe {
|
|
|
34
34
|
browsersRoot?: string | undefined;
|
|
35
35
|
/** Chromium revisions actually sitting in that root, wanted or not. */
|
|
36
36
|
installedRevisions?: readonly string[] | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* The `node_modules` roots this process would resolve `playwright` from, nearest first.
|
|
39
|
+
*
|
|
40
|
+
* Only meaningful when playwright is ABSENT, and it is the evidence that branch was missing. The
|
|
41
|
+
* daemon usually runs from npx or a global install, so it resolves from its OWN location and not
|
|
42
|
+
* from the user's project — a reporter installed the right playwright in two project directories
|
|
43
|
+
* and kept reading "not installed", with no way to see that neither was ever searched.
|
|
44
|
+
*/
|
|
45
|
+
searchedPaths?: readonly string[] | undefined;
|
|
37
46
|
}
|
|
47
|
+
/** The install command, pinned when we know what to pin to. */
|
|
48
|
+
export declare function chromiumInstallCommand(playwrightVersion?: string): string;
|
|
38
49
|
/**
|
|
39
|
-
* The install command, pinned
|
|
50
|
+
* The install-deps command, pinned the same way `chromiumInstallCommand` is.
|
|
40
51
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
52
|
+
* A missing OS shared library (e.g. `libnspr4.so`) is a different failure from a missing browser
|
|
53
|
+
* binary: the binary is already there, but Playwright's own host-requirement check refuses to launch
|
|
54
|
+
* it. `npx playwright install chromium` does nothing for that case — the fix is `install-deps`, and
|
|
55
|
+
* it needs the same pin for the same reason: unpinned, `npx` can resolve a different playwright than
|
|
56
|
+
* the one the daemon bundles.
|
|
43
57
|
*/
|
|
44
|
-
export declare function
|
|
58
|
+
export declare function chromiumInstallDepsCommand(playwrightVersion?: string): string;
|
|
45
59
|
/**
|
|
46
60
|
* Split a resolved executable path into the browsers root and the revision under it, or null.
|
|
47
61
|
*
|
|
@@ -33,14 +33,31 @@ const CHROMIUM_DIR = /^chromium-\d+$/;
|
|
|
33
33
|
/** The same directory name as a path segment, on either separator, so Windows paths split too. */
|
|
34
34
|
const CHROMIUM_SEGMENT = /[\\/](chromium-\d+)[\\/]/;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Pin an `npx playwright <subcommand>` invocation to the playwright the daemon actually bundles.
|
|
37
37
|
*
|
|
38
38
|
* Unpinned is still the right fallback: a wrong-revision download is a bad outcome, but no command
|
|
39
|
-
* at all is a worse one.
|
|
39
|
+
* at all is a worse one. Shared by `chromiumInstallCommand` and `chromiumInstallDepsCommand`, which
|
|
40
|
+
* differ only in the subcommand they need pinned.
|
|
40
41
|
*/
|
|
41
|
-
|
|
42
|
+
function pinnedPlaywrightCommand(subcommand, playwrightVersion) {
|
|
42
43
|
const pin = playwrightVersion === undefined ? 'playwright' : `playwright@${playwrightVersion}`;
|
|
43
|
-
return `npx ${pin}
|
|
44
|
+
return `npx ${pin} ${subcommand}`;
|
|
45
|
+
}
|
|
46
|
+
/** The install command, pinned when we know what to pin to. */
|
|
47
|
+
export function chromiumInstallCommand(playwrightVersion) {
|
|
48
|
+
return pinnedPlaywrightCommand('install chromium', playwrightVersion);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The install-deps command, pinned the same way `chromiumInstallCommand` is.
|
|
52
|
+
*
|
|
53
|
+
* A missing OS shared library (e.g. `libnspr4.so`) is a different failure from a missing browser
|
|
54
|
+
* binary: the binary is already there, but Playwright's own host-requirement check refuses to launch
|
|
55
|
+
* it. `npx playwright install chromium` does nothing for that case — the fix is `install-deps`, and
|
|
56
|
+
* it needs the same pin for the same reason: unpinned, `npx` can resolve a different playwright than
|
|
57
|
+
* the one the daemon bundles.
|
|
58
|
+
*/
|
|
59
|
+
export function chromiumInstallDepsCommand(playwrightVersion) {
|
|
60
|
+
return pinnedPlaywrightCommand('install-deps chromium', playwrightVersion);
|
|
44
61
|
}
|
|
45
62
|
/**
|
|
46
63
|
* Split a resolved executable path into the browsers root and the revision under it, or null.
|
|
@@ -79,6 +96,7 @@ function installedRevisions(root) {
|
|
|
79
96
|
* in, which is why the probe never reads `PLAYWRIGHT_BROWSERS_PATH` itself.
|
|
80
97
|
*/
|
|
81
98
|
export async function probeChromium() {
|
|
99
|
+
const searched = playwrightResolutionRoots();
|
|
82
100
|
try {
|
|
83
101
|
const { chromium } = await import('playwright');
|
|
84
102
|
const executablePath = chromium.executablePath();
|
|
@@ -98,7 +116,32 @@ export async function probeChromium() {
|
|
|
98
116
|
}
|
|
99
117
|
catch {
|
|
100
118
|
// Playwright itself is absent — a different problem from a missing browser, and the hint says so.
|
|
101
|
-
|
|
119
|
+
// The roots are gathered HERE rather than in the hint so the hint stays pure: this is the only
|
|
120
|
+
// place that knows which module did the resolving.
|
|
121
|
+
return { exists: false, ...(0 === searched.length ? {} : { searchedPaths: searched }) };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Where `import('playwright')` would look from HERE — the roots that EXIST, nearest first.
|
|
126
|
+
*
|
|
127
|
+
* The existence filter is the part that makes this evidence rather than noise. Node's ancestor chain
|
|
128
|
+
* runs to the filesystem root and its nearest entries are usually directories nobody ever created:
|
|
129
|
+
* measured from the built daemon, the two nearest are `dist/cli/node_modules` and `dist/node_modules`,
|
|
130
|
+
* and the informative one — the daemon's own `node_modules` — is third. Printing the first two
|
|
131
|
+
* unfiltered would name two paths the reader cannot check and hide the one they can.
|
|
132
|
+
*
|
|
133
|
+
* Capped after filtering, because the point is to show whether this process searched where the
|
|
134
|
+
* reader installed, not to dump the chain.
|
|
135
|
+
*/
|
|
136
|
+
const MAX_SEARCHED_ROOTS = 2;
|
|
137
|
+
function playwrightResolutionRoots() {
|
|
138
|
+
try {
|
|
139
|
+
const roots = createRequire(import.meta.url).resolve.paths('playwright') ?? [];
|
|
140
|
+
return roots.filter((root) => existsSync(root)).slice(0, MAX_SEARCHED_ROOTS);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// An environment that cannot enumerate its own resolution paths still gets the bare verdict.
|
|
144
|
+
return [];
|
|
102
145
|
}
|
|
103
146
|
}
|
|
104
147
|
/** The bundled playwright's version, or undefined if it cannot be read (the hint then goes unpinned). */
|
|
@@ -128,7 +171,12 @@ export function chromiumHint(probe) {
|
|
|
128
171
|
}
|
|
129
172
|
const command = chromiumInstallCommand(probe.playwrightVersion);
|
|
130
173
|
if (probe.executablePath === undefined) {
|
|
131
|
-
|
|
174
|
+
// Same rule as the missing-browser line below: a verdict with nowhere to check it against reads
|
|
175
|
+
// as a broken check. The roots say whether this process even searched the directory the reader
|
|
176
|
+
// installed into — which for a daemon run from npx or a global install it usually did not.
|
|
177
|
+
const searched = probe.searchedPaths ?? [];
|
|
178
|
+
const where = 0 === searched.length ? '' : ` — looked in ${searched.join(', ')}`;
|
|
179
|
+
return `✗ the playwright package is not installed${where}; run: ${command}`;
|
|
132
180
|
}
|
|
133
181
|
const present = probe.installedRevisions ?? [];
|
|
134
182
|
if (present.length > 0 && probe.wantedRevision !== undefined) {
|
package/dist/cli/cli-doctor.js
CHANGED
|
@@ -13,8 +13,7 @@ import { captureLookup, describeForeignHolder, findPortHolder } from './port-hol
|
|
|
13
13
|
import { chromiumHint, probeChromium } from './chromium-hint.js';
|
|
14
14
|
import { SERVER_VERSION } from '../version/server-version.js';
|
|
15
15
|
import { CONTRACT_FINGERPRINT } from '@reticlehq/core';
|
|
16
|
-
import { diagnoseDesktop, isDesktopProject } from '
|
|
17
|
-
import { diagnoseWebCsp } from '../init/csp-doctor.js';
|
|
16
|
+
import { diagnoseDesktop, isDesktopProject, diagnoseWebCsp } from '@reticlehq/init';
|
|
18
17
|
import { RETICLE_CONFIG_BASENAME, diagnosePortMismatch, readProjectId, readProjectPort, } from './cli-port.js';
|
|
19
18
|
import { DoctorRow, doctorRow } from './doctor-rows.js';
|
|
20
19
|
import { attachState, describeAttachState } from '../mcp/attach-memory.js';
|
|
@@ -5,12 +5,26 @@
|
|
|
5
5
|
* opens first. These five functions form one cohesive group: they all read the flow store and report on
|
|
6
6
|
* verification state, and none of them touch daemon lifecycle, which is what the rest of cli.ts does.
|
|
7
7
|
*/
|
|
8
|
+
import { type ChangedFiles } from '../flows/git-changed.js';
|
|
8
9
|
import { type FileSystemPort } from '../project/fs-port.js';
|
|
9
10
|
import { type NamedFlow } from '../flows/flow-sources.js';
|
|
10
11
|
/** Load the {name, steps} of every saved flow for the active project. */
|
|
11
12
|
/** Explicit files plus, when --since is given, the git-changed files since that ref. */
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* `cwd` is the tree to diff, and it is a PARAMETER because the two callers do not share one. From a
|
|
15
|
+
* terminal `process.cwd()` is the project; inside a globally-registered daemon it is `/` or `$HOME`,
|
|
16
|
+
* where `git diff` answers about the wrong repository or about none.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveChangedFiles(files: string[], since: string | undefined, cwd: string): Promise<ChangedFiles>;
|
|
19
|
+
/**
|
|
20
|
+
* `projectId` is a PARAMETER for the same reason `reticleRoot` already is: the two together are one
|
|
21
|
+
* address, and reading half of it from a global made them disagree. Resolved through `sessionRoot`
|
|
22
|
+
* the root named the session's project while `readProjectId(process.cwd())` named the daemon's —
|
|
23
|
+
* and a daemon started outside a project has none, so the list came back EMPTY. `affected` renders
|
|
24
|
+
* that as "no saved flows exist yet" and `verify_change` as nothing covering the change: a
|
|
25
|
+
* confident negative about somebody else's project, which is worse than an error.
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadNamedFlows(fs: FileSystemPort, reticleRoot: string, projectId: string | undefined): Promise<NamedFlow[]>;
|
|
14
28
|
/**
|
|
15
29
|
* `reticle watch [url]` — on every save, report which saved flows must re-verify (the affected set).
|
|
16
30
|
* Environment-side (costs the agent nothing per turn); the buddy loop. This v1 detects + reports on
|
|
@@ -27,13 +27,31 @@ import { watch } from 'node:fs';
|
|
|
27
27
|
import { log } from '../log.js';
|
|
28
28
|
/** Load the {name, steps} of every saved flow for the active project. */
|
|
29
29
|
/** Explicit files plus, when --since is given, the git-changed files since that ref. */
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* `cwd` is the tree to diff, and it is a PARAMETER because the two callers do not share one. From a
|
|
32
|
+
* terminal `process.cwd()` is the project; inside a globally-registered daemon it is `/` or `$HOME`,
|
|
33
|
+
* where `git diff` answers about the wrong repository or about none.
|
|
34
|
+
*/
|
|
35
|
+
export async function resolveChangedFiles(files, since, cwd) {
|
|
36
|
+
// No ref means no question was asked of git, which is not a failure to answer one.
|
|
31
37
|
if (since === undefined)
|
|
32
|
-
return files;
|
|
33
|
-
|
|
38
|
+
return { files, failed: false };
|
|
39
|
+
const changed = await changedFilesSince(since, cwd);
|
|
40
|
+
return {
|
|
41
|
+
files: [...new Set([...files, ...changed.files])],
|
|
42
|
+
failed: changed.failed,
|
|
43
|
+
...(changed.reason === undefined ? {} : { reason: changed.reason }),
|
|
44
|
+
};
|
|
34
45
|
}
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
/**
|
|
47
|
+
* `projectId` is a PARAMETER for the same reason `reticleRoot` already is: the two together are one
|
|
48
|
+
* address, and reading half of it from a global made them disagree. Resolved through `sessionRoot`
|
|
49
|
+
* the root named the session's project while `readProjectId(process.cwd())` named the daemon's —
|
|
50
|
+
* and a daemon started outside a project has none, so the list came back EMPTY. `affected` renders
|
|
51
|
+
* that as "no saved flows exist yet" and `verify_change` as nothing covering the change: a
|
|
52
|
+
* confident negative about somebody else's project, which is worse than an error.
|
|
53
|
+
*/
|
|
54
|
+
export async function loadNamedFlows(fs, reticleRoot, projectId) {
|
|
37
55
|
const store = new FlowStore(fs, reticleRoot, { now: () => Date.now() });
|
|
38
56
|
const flows = [];
|
|
39
57
|
for (const name of await store.list(projectId)) {
|
|
@@ -88,7 +106,7 @@ export function handleWatch() {
|
|
|
88
106
|
setTimeout(fn, ms).unref();
|
|
89
107
|
},
|
|
90
108
|
onFlush: (files) => {
|
|
91
|
-
void loadNamedFlows(fs, reticleRoot)
|
|
109
|
+
void loadNamedFlows(fs, reticleRoot, readProjectId(process.cwd()))
|
|
92
110
|
.then(async (flows) => {
|
|
93
111
|
const result = affectedSavedFlows(flows, files);
|
|
94
112
|
if (result.affected.length > 0) {
|
|
@@ -105,7 +123,7 @@ export function handleWatch() {
|
|
|
105
123
|
});
|
|
106
124
|
log('reticle_watch_started', { cwd: process.cwd() });
|
|
107
125
|
// Print the ambient line once at startup so the human sees where they stand before touching anything.
|
|
108
|
-
void loadNamedFlows(fs, reticleRoot)
|
|
126
|
+
void loadNamedFlows(fs, reticleRoot, readProjectId(process.cwd()))
|
|
109
127
|
.then((flows) => emitBuddyStatus(fs, reticleRoot, flows, []))
|
|
110
128
|
.catch(() => undefined);
|
|
111
129
|
watch(process.cwd(), { recursive: true }, (_event, filename) => {
|
|
@@ -151,8 +169,9 @@ hook = false) {
|
|
|
151
169
|
try {
|
|
152
170
|
const fs = createNodeFileSystem();
|
|
153
171
|
const reticleRoot = join(process.cwd(), ReticleDir.ROOT);
|
|
154
|
-
|
|
155
|
-
const
|
|
172
|
+
// Same deliberate degradation as the gate: a terminal caller sees git's own error anyway.
|
|
173
|
+
const changed = (await resolveChangedFiles(files, since, process.cwd())).files;
|
|
174
|
+
const allFlows = await loadNamedFlows(fs, reticleRoot, readProjectId(process.cwd()));
|
|
156
175
|
const affected = affectedSavedFlows(allFlows, changed).affected;
|
|
157
176
|
const latest = await new RunStore(fs, reticleRoot).latest();
|
|
158
177
|
const passing = (latest?.flows ?? [])
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* is the one command whose arguments are free text, so it is the only place in the grammar where
|
|
6
6
|
* "everything that is not a flag" is a rule with edge cases rather than a one-liner.
|
|
7
7
|
*/
|
|
8
|
-
import { FeedbackKind } from '@reticlehq/core';
|
|
8
|
+
import { FeedbackKind } from '@reticlehq/core/telemetry';
|
|
9
9
|
/** `reticle feedback --rating 4 "the words"` — the human half of the channel. */
|
|
10
10
|
export const RATING_FLAG = '--rating';
|
|
11
11
|
export const BUG_FLAG = '--bug';
|
package/dist/cli/cli-parse.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { AGENT_FLAG, BUG_FLAG, FEEDBACK_KINDS, KIND_FLAG, RATING_FLAG, } from '.
|
|
|
13
13
|
* telling readers to do exactly that on 110 lines before it was caught, so the invocation now leads
|
|
14
14
|
* the usage block rather than being a footnote somewhere else.
|
|
15
15
|
*/
|
|
16
|
-
export declare const CLI_USAGE = "usage: npx @reticlehq/server <command> (or `reticle <command>` once the bin is on your PATH)\n\n reticle init [--dry-run] [--port N] [--no-mcp] [--no-install] [--app <dir>]\n [--flow \"<what to drive>\"] [--env KEY=VALUE]... [--files-only] (wire Reticle into the project in this directory)\n --app picks WHICH app in a monorepo, when several are found\n --flow names the journey worth proving, in your own words. Only you know\n which one matters, and naming it is the difference between a drive that\n finishes and one that spends its budget looking for something to do\n --env is what the app needs to reach a usable state: the key from\n .env.example, the mock backend, the variable that skips an auth wall.\n Repeatable, and a value may contain spaces and equals signs\n --files-only writes the files and stops, which is what init did before it\n learned to boot the app and prove the install works\n --license writes the key to .env and keeps .env out of git\n --json puts the result on stdout, so an agent reads one object\n --no-drive / --no-open / --no-agents / --url / --timeout / --drive-model\n are the runtime dials: CI, a headless box, or an app you already run\n --no-mcp skips MORE than the server registration: also the agent rule files\n (CLAUDE.md / AGENTS.md / .cursor) and the /reticle command, because all three\n only make sense once the tools are reachable.\n reticle serve [--port N] [--drive <url>] [--headless] [--http] [--http-port N] [--http-token T]\n reticle stop [--port N] [--quiet] (stop the daemon we started, by its recorded pid)\n reticle kill [--port N] [--force] (free the port by its LISTENER, never the agent's mcp proxy)\n reticle restart [--port N] [--force] (kill, then start a daemon and wait for a real bind)\n reticle status [--port N]\n reticle doctor [--port N] (one command to diagnose setup: Chromium, daemon, port)\n reticle open [url] [--port N] (show the app: reuse the connected tab, else open one)\n reticle verify <url> [--port N] [--headed] [--timeout N] [--storage-state <file>] [--session-id <id>] (one-shot: drive the URL, verify saved flows, exit 0=pass)\n reticle affected [--since <ref>] [file...] (which saved flows must re-verify for the changed files)\n reticle gate [--since <ref>] [file...] (exit non-zero unless passing artifacts cover the affected flows)\n reticle watch [url] (on save, report which saved flows must re-verify)\n reticle drive <url> [--headless] (foreground mode, for debugging)\n reticle mcp [--port N] [--drive <url>] [--headless] (MCP stdio proxy; auto-starts daemon if needed)\n reticle update (install the latest server version and restart)\n reticle rollback (restore the previous server version and restart)\n reticle license (show enterprise license status: active | eval | missing)\n reticle telemetry [status|enable|disable] (anonymous usage metrics; status shows what's sent + the policy)\n reticle feedback [--rating 1-5] [--bug] \"message\" (tell us what worked and what didn't; prints exactly what it sends)\n reticle feedback --agent --kind <bug|gap|ambiguity|feature_request|improvement|experience> \"message\"\n (agents: file from anywhere, including a setup that never finished)\n reticle identify --context company|side_project|open_source|learning [--company N] [--email E] [--forget]\n (OPT-IN: tell us who you are, e.g. for support or an enterprise trial)\n\nCloud (link this project to Reticle; runs/flows recorded on the dashboard):\n reticle login [--url <u>] [--email <e>] [--code <c>] [--org <n>]\n (browser device flow by default; --email mails a code)\n reticle logout [--url <u>] (sign out of ONE host; others stay signed in)\n reticle link [--project <name|id>] (bind this repo: mints a scoped key, writes .reticle/cloud.json)\n reticle whoami (who am I signed in as, and is this repo attached?)\n reticle project <ls|create <name>> (list or create cloud projects)\n reticle config [--runs on|off] [--memory on|off] [--flows on|off] [--verify local|server]\n reticle push | sync [--watch] (one sync cycle: send the difference, collect decisions)\n reticle runs | regression | share <runId> (read cloud state; regression exits 3 if any flow broke)\n\n'drive' shows the browser; everything else is hidden (serve/mcp own the pool behind leases, replay\nand the spec runner: batch work). --headed opts any of them in, --headless hides drive, CI hides it.";
|
|
16
|
+
export declare const CLI_USAGE = "usage: npx @reticlehq/server <command> (or `reticle <command>` once the bin is on your PATH)\n\n reticle init [--dry-run] [--port N] [--no-mcp] [--no-install] [--app <dir>]\n [--flow \"<what to drive>\"] [--env KEY=VALUE]... [--files-only] (wire Reticle into the project in this directory)\n --app picks WHICH app in a monorepo, when several are found\n --flow names the journey worth proving, in your own words. Only you know\n which one matters, and naming it is the difference between a drive that\n finishes and one that spends its budget looking for something to do\n --env is what the app needs to reach a usable state: the key from\n .env.example, the mock backend, the variable that skips an auth wall.\n Repeatable, and a value may contain spaces and equals signs\n --files-only writes the files and stops, which is what init did before it\n learned to boot the app and prove the install works\n --relaunch prints the exact command that restarts THIS conversation with\n the tools loaded, so the restart is not a chore handed to a human. It\n refuses when the session id has no transcript behind it, because\n --resume on an empty id opens a blank conversation that looks like\n success. Works with --files-only\n --license writes the key to .env and keeps .env out of git\n --json puts the result on stdout, so an agent reads one object\n --no-drive / --no-open / --no-agents / --url / --timeout / --drive-model\n are the runtime dials: CI, a headless box, or an app you already run\n --no-mcp skips MORE than the server registration: also the agent rule files\n (CLAUDE.md / AGENTS.md / .cursor) and the /reticle command, because all three\n only make sense once the tools are reachable.\n reticle serve [--port N] [--drive <url>] [--headless] [--http] [--http-port N] [--http-token T]\n reticle stop [--port N] [--quiet] (stop the daemon we started, by its recorded pid)\n reticle kill [--port N] [--force] (free the port by its LISTENER, never the agent's mcp proxy)\n reticle restart [--port N] [--force] (kill, then start a daemon and wait for a real bind)\n reticle status [--port N]\n reticle doctor [--port N] (one command to diagnose setup: Chromium, daemon, port)\n reticle open [url] [--port N] (show the app: reuse the connected tab, else open one)\n reticle verify <url> [--port N] [--headed] [--timeout N] [--storage-state <file>] [--session-id <id>] (one-shot: drive the URL, verify saved flows, exit 0=pass)\n [--expect '<json predicate>'] (one verdict, no saved flows needed \u2014 asks\n the daemon that is already running, so nothing is bound and nothing is stopped. This\n is the path when your client never loaded the reticle_* tools. exit 0 ONLY on\n verified:\"yes\" \u2014 \"unknown\" is not a pass)\n reticle affected [--since <ref>] [file...] (which saved flows must re-verify for the changed files)\n reticle gate [--since <ref>] [file...] (exit non-zero unless passing artifacts cover the affected flows)\n reticle watch [url] (on save, report which saved flows must re-verify)\n reticle drive <url> [--headless] (foreground mode, for debugging)\n reticle mcp [--port N] [--drive <url>] [--headless] (MCP stdio proxy; auto-starts daemon if needed)\n reticle update (install the latest server version and restart)\n reticle rollback (restore the previous server version and restart)\n reticle license (show enterprise license status: active | eval | missing)\n reticle telemetry [status|enable|disable] (anonymous usage metrics; status shows what's sent + the policy)\n reticle feedback [--rating 1-5] [--bug] \"message\" (tell us what worked and what didn't; prints exactly what it sends)\n reticle feedback --agent --kind <bug|gap|ambiguity|feature_request|improvement|experience> \"message\"\n (agents: file from anywhere, including a setup that never finished)\n reticle identify --context company|side_project|open_source|learning [--company N] [--email E] [--forget]\n (OPT-IN: tell us who you are, e.g. for support or an enterprise trial)\n\nCloud (link this project to Reticle; runs/flows recorded on the dashboard):\n reticle login [--url <u>] [--email <e>] [--code <c>] [--org <n>]\n (browser device flow by default; --email mails a code)\n reticle logout [--url <u>] (sign out of ONE host; others stay signed in)\n reticle link [--project <name|id>] (bind this repo: mints a scoped key, writes .reticle/cloud.json)\n reticle whoami (who am I signed in as, and is this repo attached?)\n reticle project <ls|create <name>> (list or create cloud projects)\n reticle config [--runs on|off] [--memory on|off] [--flows on|off] [--verify local|server]\n reticle push | sync [--watch] (one sync cycle: send the difference, collect decisions)\n reticle runs | regression | share <runId> (read cloud state; regression exits 3 if any flow broke)\n\n'drive' shows the browser; everything else is hidden (serve/mcp own the pool behind leases, replay\nand the spec runner: batch work). --headed opts any of them in, --headless hides drive, CI hides it.";
|
|
17
17
|
/** The `reticle telemetry` sub-actions. Bare `reticle telemetry` means `status`. */
|
|
18
18
|
export declare const TelemetryAction: {
|
|
19
19
|
readonly STATUS: "status";
|
|
@@ -128,6 +128,7 @@ export type CliResult = {
|
|
|
128
128
|
timeoutMs?: number;
|
|
129
129
|
storageState?: string;
|
|
130
130
|
sessionId?: string;
|
|
131
|
+
expect?: unknown;
|
|
131
132
|
} | {
|
|
132
133
|
kind: 'affected';
|
|
133
134
|
files: string[];
|
package/dist/cli/cli-parse.js
CHANGED
|
@@ -28,6 +28,11 @@ export const CLI_USAGE = `usage: npx @reticlehq/server <command> (or \`reticl
|
|
|
28
28
|
Repeatable, and a value may contain spaces and equals signs
|
|
29
29
|
--files-only writes the files and stops, which is what init did before it
|
|
30
30
|
learned to boot the app and prove the install works
|
|
31
|
+
--relaunch prints the exact command that restarts THIS conversation with
|
|
32
|
+
the tools loaded, so the restart is not a chore handed to a human. It
|
|
33
|
+
refuses when the session id has no transcript behind it, because
|
|
34
|
+
--resume on an empty id opens a blank conversation that looks like
|
|
35
|
+
success. Works with --files-only
|
|
31
36
|
--license writes the key to .env and keeps .env out of git
|
|
32
37
|
--json puts the result on stdout, so an agent reads one object
|
|
33
38
|
--no-drive / --no-open / --no-agents / --url / --timeout / --drive-model
|
|
@@ -43,6 +48,10 @@ export const CLI_USAGE = `usage: npx @reticlehq/server <command> (or \`reticl
|
|
|
43
48
|
reticle doctor [--port N] (one command to diagnose setup: Chromium, daemon, port)
|
|
44
49
|
reticle open [url] [--port N] (show the app: reuse the connected tab, else open one)
|
|
45
50
|
reticle verify <url> [--port N] [--headed] [--timeout N] [--storage-state <file>] [--session-id <id>] (one-shot: drive the URL, verify saved flows, exit 0=pass)
|
|
51
|
+
[--expect '<json predicate>'] (one verdict, no saved flows needed — asks
|
|
52
|
+
the daemon that is already running, so nothing is bound and nothing is stopped. This
|
|
53
|
+
is the path when your client never loaded the reticle_* tools. exit 0 ONLY on
|
|
54
|
+
verified:"yes" — "unknown" is not a pass)
|
|
46
55
|
reticle affected [--since <ref>] [file...] (which saved flows must re-verify for the changed files)
|
|
47
56
|
reticle gate [--since <ref>] [file...] (exit non-zero unless passing artifacts cover the affected flows)
|
|
48
57
|
reticle watch [url] (on save, report which saved flows must re-verify)
|
|
@@ -233,6 +242,15 @@ export const HTTP_PORT_FLAG = '--http-port';
|
|
|
233
242
|
export const HTTP_TOKEN_FLAG = '--http-token';
|
|
234
243
|
const TIMEOUT_FLAG = '--timeout';
|
|
235
244
|
const STORAGE_STATE_FLAG = '--storage-state';
|
|
245
|
+
/**
|
|
246
|
+
* A predicate for a flow-free, one-shot verdict against the daemon that is already running.
|
|
247
|
+
*
|
|
248
|
+
* The dead end this removes: a client that never loaded the `reticle_*` tools had no path to a
|
|
249
|
+
* verdict at all. `verify` refused because the daemon owned the port — the normal state after a
|
|
250
|
+
* working install — the other verdict paths need saved flows a first-install project does not have,
|
|
251
|
+
* and stopping the daemon cuts the agent's own MCP link.
|
|
252
|
+
*/
|
|
253
|
+
const EXPECT_FLAG = '--expect';
|
|
236
254
|
const SESSION_ID_FLAG = '--session-id';
|
|
237
255
|
const unknownArgument = (arg) => ({
|
|
238
256
|
kind: 'error',
|
|
@@ -380,6 +398,7 @@ function parseVerifySuffix(args, defaultPort) {
|
|
|
380
398
|
let timeoutMs;
|
|
381
399
|
let storageState;
|
|
382
400
|
let sessionId;
|
|
401
|
+
let expect;
|
|
383
402
|
let port = defaultPort;
|
|
384
403
|
let i = 0;
|
|
385
404
|
while (i < args.length) {
|
|
@@ -423,6 +442,23 @@ function parseVerifySuffix(args, defaultPort) {
|
|
|
423
442
|
return missingValue(SESSION_ID_FLAG);
|
|
424
443
|
sessionId = v;
|
|
425
444
|
}
|
|
445
|
+
else if (arg === EXPECT_FLAG) {
|
|
446
|
+
i++;
|
|
447
|
+
const v = args[i];
|
|
448
|
+
if (v === undefined)
|
|
449
|
+
return missingValue(EXPECT_FLAG);
|
|
450
|
+
try {
|
|
451
|
+
expect = JSON.parse(v);
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
// Named as a JSON problem rather than an unknown argument: the value IS the predicate, and
|
|
455
|
+
// "unknown argument" would send the reader looking at the flag instead of at their quoting.
|
|
456
|
+
return {
|
|
457
|
+
kind: 'error',
|
|
458
|
+
message: `${EXPECT_FLAG} needs a JSON predicate; could not parse: ${v}`,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
}
|
|
426
462
|
else if (arg.startsWith('--')) {
|
|
427
463
|
return unknownArgument(arg);
|
|
428
464
|
}
|
|
@@ -441,6 +477,7 @@ function parseVerifySuffix(args, defaultPort) {
|
|
|
441
477
|
url,
|
|
442
478
|
headless,
|
|
443
479
|
port,
|
|
480
|
+
...(expect !== undefined ? { expect } : {}),
|
|
444
481
|
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
445
482
|
...(storageState !== undefined ? { storageState } : {}),
|
|
446
483
|
...(sessionId !== undefined ? { sessionId } : {}),
|
|
@@ -778,6 +815,7 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
778
815
|
...(r.timeoutMs !== undefined ? { timeoutMs: r.timeoutMs } : {}),
|
|
779
816
|
...(r.storageState !== undefined ? { storageState: r.storageState } : {}),
|
|
780
817
|
...(r.sessionId !== undefined ? { sessionId: r.sessionId } : {}),
|
|
818
|
+
...(r.expect !== undefined ? { expect: r.expect } : {}),
|
|
781
819
|
};
|
|
782
820
|
}
|
|
783
821
|
case CAPSULES_COMMAND:
|
package/dist/cli/cli-port.d.ts
CHANGED
|
@@ -23,20 +23,12 @@ export declare const RETICLE_CONFIG_BASENAME = ".reticle.json";
|
|
|
23
23
|
*/
|
|
24
24
|
export declare function findProjectConfig(cwd: string): Record<string, unknown> | undefined;
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* nothing to do with the port the app is served on. Setting it to the dev-server port makes the
|
|
31
|
-
* daemon try to bind the port the app already holds; what the user sees is either a bind failure or
|
|
32
|
-
* a daemon that never connects, neither of which mentions the actual mistake. The old setup skill
|
|
33
|
-
* asked "what port does your dev server run on?" a few lines before showing this field, which is how
|
|
34
|
-
* the confusion got manufactured in the first place.
|
|
26
|
+
* The dev-server port heuristics live in `@reticlehq/init` — `existing-config.ts` is what diagnoses
|
|
27
|
+
* a `.reticle.json` whose `port` is the app's own dev-server port, and the scaffolder may not import
|
|
28
|
+
* the daemon. Re-exported here so the runtime readers (the dev-server probe, the no-session
|
|
29
|
+
* diagnosis, and `cli.ts`) are unchanged.
|
|
35
30
|
*/
|
|
36
|
-
export
|
|
37
|
-
export declare function isLikelyDevServerPort(port: number): boolean;
|
|
38
|
-
/** The warning printed when a project pins the bridge to something that looks like its dev server. */
|
|
39
|
-
export declare function devServerPortWarning(port: number): string;
|
|
31
|
+
export { DEV_SERVER_PORTS, isLikelyDevServerPort, devServerPortWarning } from '@reticlehq/init';
|
|
40
32
|
/**
|
|
41
33
|
* Read the port stored in the project's .reticle.json (written by `reticle init`).
|
|
42
34
|
* Returns undefined if the file is absent, unreadable, or has no valid numeric port.
|
package/dist/cli/cli-port.js
CHANGED
|
@@ -53,45 +53,12 @@ export function findProjectConfig(cwd) {
|
|
|
53
53
|
return undefined;
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* nothing to do with the port the app is served on. Setting it to the dev-server port makes the
|
|
61
|
-
* daemon try to bind the port the app already holds; what the user sees is either a bind failure or
|
|
62
|
-
* a daemon that never connects, neither of which mentions the actual mistake. The old setup skill
|
|
63
|
-
* asked "what port does your dev server run on?" a few lines before showing this field, which is how
|
|
64
|
-
* the confusion got manufactured in the first place.
|
|
56
|
+
* The dev-server port heuristics live in `@reticlehq/init` — `existing-config.ts` is what diagnoses
|
|
57
|
+
* a `.reticle.json` whose `port` is the app's own dev-server port, and the scaffolder may not import
|
|
58
|
+
* the daemon. Re-exported here so the runtime readers (the dev-server probe, the no-session
|
|
59
|
+
* diagnosis, and `cli.ts`) are unchanged.
|
|
65
60
|
*/
|
|
66
|
-
export
|
|
67
|
-
3000,
|
|
68
|
-
3001,
|
|
69
|
-
4200,
|
|
70
|
-
4321,
|
|
71
|
-
5000,
|
|
72
|
-
5173,
|
|
73
|
-
5174,
|
|
74
|
-
8000,
|
|
75
|
-
8080,
|
|
76
|
-
8100,
|
|
77
|
-
9000,
|
|
78
|
-
// Added after the scan reported "nothing is listening" at people whose app was plainly running.
|
|
79
|
-
// A narrow list is not just unhelpful, it is CONFIDENTLY wrong — the message states absence as a
|
|
80
|
-
// fact — so the defaults of the frameworks agents actually meet belong in it.
|
|
81
|
-
1420, // Tauri
|
|
82
|
-
3100, // Next, second instance
|
|
83
|
-
4173, // vite preview
|
|
84
|
-
5175, // Vite, third instance
|
|
85
|
-
7860, // Gradio
|
|
86
|
-
8501, // Streamlit
|
|
87
|
-
]);
|
|
88
|
-
export function isLikelyDevServerPort(port) {
|
|
89
|
-
return DEV_SERVER_PORTS.has(port);
|
|
90
|
-
}
|
|
91
|
-
/** The warning printed when a project pins the bridge to something that looks like its dev server. */
|
|
92
|
-
export function devServerPortWarning(port) {
|
|
93
|
-
return `[reticle] .reticle.json sets "port": ${port}, which is a common DEV-SERVER port. That field is the Reticle BRIDGE port (default 4400), not the port your app is served on — they must be different, or the daemon fights your dev server for it. Remove "port" unless you are running several apps at once.`;
|
|
94
|
-
}
|
|
61
|
+
export { DEV_SERVER_PORTS, isLikelyDevServerPort, devServerPortWarning } from '@reticlehq/init';
|
|
95
62
|
/**
|
|
96
63
|
* Read the port stored in the project's .reticle.json (written by `reticle init`).
|
|
97
64
|
* Returns undefined if the file is absent, unreadable, or has no valid numeric port.
|
|
@@ -8,14 +8,12 @@
|
|
|
8
8
|
import { checkForUpdate } from '../update/update-checker.js';
|
|
9
9
|
import { updateTarget } from '../update/update-nudge.js';
|
|
10
10
|
import { applyUpdate, rollback } from '../update/updater.js';
|
|
11
|
-
import { refreshAgentRules } from '
|
|
11
|
+
import { refreshAgentRules, detectPackageManager, buildNodeIo, SILENT_HOST } from '@reticlehq/init';
|
|
12
12
|
import { SERVER_VERSION } from '../version/server-version.js';
|
|
13
13
|
import { log } from '../log.js';
|
|
14
14
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
15
15
|
import { join } from 'node:path';
|
|
16
16
|
import { reticleDepsOf, sdkSyncCommand } from '../update/sdk-sync.js';
|
|
17
|
-
import { detectPackageManager } from '../init/detect.js';
|
|
18
|
-
import { buildNodeIo } from '../init/node-io.js';
|
|
19
17
|
/**
|
|
20
18
|
* Bring the SDK in the CURRENT project to the version being installed.
|
|
21
19
|
*
|
|
@@ -34,7 +32,9 @@ function syncProjectSdk(target) {
|
|
|
34
32
|
return; // not an app directory
|
|
35
33
|
}
|
|
36
34
|
const packages = reticleDepsOf(manifest);
|
|
37
|
-
|
|
35
|
+
// Nothing to trace and nothing to report: this reads the manifest and runs one package-manager
|
|
36
|
+
// command. It never enters `runInit`, so there is no init outcome for a host to carry.
|
|
37
|
+
const io = buildNodeIo(cwd, SILENT_HOST);
|
|
38
38
|
const pm = detectPackageManager(new Set(io.rootFiles()), new Set(io.listDirs('node_modules')));
|
|
39
39
|
const cmd = sdkSyncCommand(pm, packages, target);
|
|
40
40
|
if (null === cmd) {
|