@reticlehq/server 2.3.0 → 2.5.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 +702 -0
- package/dist/bridge/auth-failure-reason.d.ts +19 -0
- package/dist/bridge/auth-failure-reason.js +29 -0
- package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
- package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
- package/dist/{bridge.d.ts → bridge/bridge.d.ts} +1 -1
- package/dist/{bridge.js → bridge/bridge.js} +105 -15
- package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +6 -11
- package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +21 -9
- package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
- package/dist/capsule/capsule-store.d.ts +8 -3
- package/dist/capsule/capsule-store.js +7 -2
- package/dist/capsule/capsule.js +3 -3
- package/dist/capsule/causal-summary.d.ts +8 -0
- package/dist/capsule/causal-summary.js +22 -12
- package/dist/capsule/divergence.d.ts +9 -4
- package/dist/capsule/divergence.js +8 -8
- package/dist/capsule/predicate-to-links.js +11 -8
- package/dist/{cli-doctor.js → cli/cli-doctor.js} +9 -2
- package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
- package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
- package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
- package/dist/cli/cli-launch.js +171 -0
- package/dist/cli/cli-parse.d.ts +143 -0
- package/dist/{cli-parse.js → cli/cli-parse.js} +146 -65
- package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +15 -0
- package/dist/{cli-port.js → cli/cli-port.js} +29 -8
- package/dist/cli/cli-update-commands.d.ts +4 -0
- package/dist/cli/cli-update-commands.js +93 -0
- package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
- package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +182 -93
- package/dist/cloud/cloud-config.d.ts +0 -1
- package/dist/cloud/cloud-config.js +9 -9
- package/dist/cloud/cloud-sync.d.ts +1 -7
- package/dist/cloud/cloud-sync.js +12 -12
- package/dist/crawl/crawl-empty.d.ts +16 -0
- package/dist/crawl/crawl-empty.js +24 -0
- package/dist/crawl/crawl-tools.js +4 -1
- package/dist/crawl/crawl.js +26 -7
- package/dist/daemon/daemon-resilience.d.ts +49 -0
- package/dist/daemon/daemon-resilience.js +191 -0
- package/dist/daemon/daemon-usefulness.d.ts +61 -0
- package/dist/daemon/daemon-usefulness.js +62 -0
- package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
- package/dist/{daemon.js → daemon/daemon.js} +80 -48
- package/dist/daemon/idle-grace.d.ts +32 -0
- package/dist/daemon/idle-grace.js +41 -0
- package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +13 -0
- package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +27 -4
- package/dist/domain/domain-model.js +2 -2
- package/dist/events/body-failures.js +8 -8
- package/dist/events/contradictions.d.ts +1 -1
- package/dist/events/contradictions.js +60 -10
- package/dist/events/echo-mismatch.js +10 -10
- package/dist/events/event-filters.js +6 -6
- package/dist/events/json-salvage.d.ts +2 -1
- package/dist/events/json-salvage.js +6 -6
- package/dist/events/observed-in-window.d.ts +12 -0
- package/dist/events/observed-in-window.js +21 -0
- package/dist/events/predicate-eval.d.ts +43 -20
- package/dist/events/predicate-eval.js +159 -55
- package/dist/events/predicate.d.ts +2 -2
- package/dist/events/predicate.js +112 -35
- package/dist/events/reconcile.js +5 -5
- package/dist/events/ring-buffer.js +1 -1
- package/dist/events/stale-response.js +6 -6
- package/dist/events/testid-near-miss.d.ts +22 -0
- package/dist/events/testid-near-miss.js +33 -0
- package/dist/events/unit-mismatch.js +8 -8
- package/dist/flows/affected-tools.js +19 -4
- package/dist/flows/affected.js +1 -1
- package/dist/flows/annotate-target.d.ts +1 -0
- package/dist/flows/annotate-target.js +20 -0
- package/dist/flows/annotate-tools.js +25 -3
- package/dist/flows/annotate.js +17 -4
- package/dist/flows/assertion-integrity.d.ts +2 -1
- package/dist/flows/assertion-tiers-store.d.ts +3 -66
- package/dist/flows/assertion-tiers-store.js +2 -2
- package/dist/flows/attributed-failure.d.ts +17 -0
- package/dist/flows/attributed-failure.js +20 -0
- package/dist/flows/buddy-status.d.ts +2 -1
- package/dist/flows/buddy-status.js +2 -2
- package/dist/flows/coverage.d.ts +3 -2
- package/dist/flows/coverage.js +2 -2
- package/dist/flows/decision.d.ts +0 -6
- package/dist/flows/decision.js +64 -8
- package/dist/flows/empty-flow.d.ts +6 -0
- package/dist/flows/empty-flow.js +24 -0
- package/dist/flows/flake-store.d.ts +0 -1
- package/dist/flows/flake-store.js +1 -1
- package/dist/flows/flake.d.ts +2 -1
- package/dist/flows/flake.js +2 -2
- package/dist/flows/flow-classify.js +12 -0
- package/dist/flows/flow-replay-run.js +4 -4
- package/dist/flows/flow-replay.d.ts +5 -7
- package/dist/flows/flow-replay.js +114 -47
- package/dist/flows/flow-report.js +1 -1
- package/dist/flows/flow-scope.d.ts +1 -6
- package/dist/flows/flow-step-runners.d.ts +26 -6
- package/dist/flows/flow-step-runners.js +157 -6
- package/dist/flows/flow-success.js +20 -15
- package/dist/flows/flow-tools.js +67 -13
- package/dist/flows/flows.js +15 -11
- package/dist/flows/gate.d.ts +4 -3
- package/dist/flows/gate.js +1 -1
- package/dist/flows/heal-run.d.ts +0 -8
- package/dist/flows/heal-run.js +5 -5
- package/dist/flows/heal.js +3 -3
- package/dist/flows/predicate-to-expect.d.ts +38 -0
- package/dist/flows/predicate-to-expect.js +95 -0
- package/dist/flows/replay.d.ts +16 -1
- package/dist/flows/replay.js +58 -22
- package/dist/flows/role-anchor-nearest.d.ts +6 -0
- package/dist/flows/role-anchor-nearest.js +45 -0
- package/dist/flows/server-verify.d.ts +1 -1
- package/dist/flows/server-verify.js +5 -5
- package/dist/flows/verify-change-tools.js +32 -10
- package/dist/flows/verify-change-verdict.d.ts +15 -0
- package/dist/flows/verify-change-verdict.js +25 -0
- package/dist/flows/watch-batcher.d.ts +3 -2
- package/dist/honesty/already-true.d.ts +2 -0
- package/dist/honesty/already-true.js +31 -0
- package/dist/honesty/blind-spots.d.ts +16 -3
- package/dist/honesty/blind-spots.js +24 -12
- package/dist/honesty/honesty.d.ts +3 -2
- package/dist/honesty/honesty.js +4 -4
- package/dist/honesty/uncaptured-bodies.js +1 -1
- package/dist/honesty/unread-outcome.js +2 -2
- package/dist/honesty/verified.d.ts +22 -3
- package/dist/honesty/verified.js +48 -8
- package/dist/http-server.js +14 -7
- package/dist/hunt/hunt-report.d.ts +2 -1
- package/dist/hunt/hunt-report.js +2 -2
- package/dist/index.d.ts +8 -6
- package/dist/index.js +32 -25
- package/dist/init/agent-rules.d.ts +2 -1
- package/dist/init/agent-rules.js +45 -7
- package/dist/init/app-choice.d.ts +20 -0
- package/dist/init/app-choice.js +25 -0
- package/dist/init/astro-host.d.ts +21 -0
- package/dist/init/astro-host.js +27 -0
- package/dist/init/astro-patch.d.ts +16 -0
- package/dist/init/astro-patch.js +240 -0
- package/dist/init/capabilities.d.ts +17 -0
- package/dist/init/capabilities.js +54 -0
- package/dist/init/cra.d.ts +37 -0
- package/dist/init/cra.js +90 -0
- package/dist/init/cursor.js +39 -4
- package/dist/init/desktop-doctor.d.ts +3 -2
- package/dist/init/desktop-doctor.js +4 -4
- package/dist/init/detect.d.ts +26 -0
- package/dist/init/detect.js +78 -5
- package/dist/init/mcp-registered.d.ts +12 -0
- package/dist/init/mcp-registered.js +14 -0
- package/dist/init/mcp.d.ts +27 -2
- package/dist/init/mcp.js +40 -4
- package/dist/init/next-patch.d.ts +39 -0
- package/dist/init/next-patch.js +196 -0
- package/dist/init/node-io.js +48 -6
- package/dist/init/patch-kind.d.ts +20 -0
- package/dist/init/patch-kind.js +10 -0
- package/dist/init/plan-framework.d.ts +50 -0
- package/dist/init/plan-framework.js +341 -0
- package/dist/init/plan.d.ts +119 -6
- package/dist/init/plan.js +230 -131
- package/dist/init/project-id.d.ts +5 -9
- package/dist/init/project-id.js +10 -22
- package/dist/init/run.d.ts +22 -0
- package/dist/init/run.js +393 -28
- package/dist/init/slash-command.d.ts +27 -0
- package/dist/init/slash-command.js +61 -0
- package/dist/init/snippets.d.ts +41 -3
- package/dist/init/snippets.js +185 -10
- package/dist/init/vite-config.d.ts +4 -10
- package/dist/init/vite-config.js +15 -7
- package/dist/init/workspace-apps.d.ts +23 -0
- package/dist/init/workspace-apps.js +68 -0
- package/dist/input/driven-redaction.d.ts +15 -0
- package/dist/input/driven-redaction.js +76 -0
- package/dist/input/network-detail.d.ts +9 -3
- package/dist/input/network-detail.js +43 -23
- package/dist/input/network-mock-tools.js +2 -2
- package/dist/input/network-mock.js +4 -4
- package/dist/input/real-input.js +8 -3
- package/dist/input/scroll-find.js +2 -2
- package/dist/input/scroll-tools.d.ts +0 -5
- package/dist/input/scroll-tools.js +11 -4
- package/dist/input/viewport-tools.js +2 -2
- package/dist/journal/ambient-store.d.ts +0 -2
- package/dist/journal/ambient-store.js +1 -1
- package/dist/journal/ambient.js +1 -1
- package/dist/journal/attach-journal.d.ts +2 -1
- package/dist/journal/deviation-report.js +6 -6
- package/dist/journal/deviation-service.js +1 -1
- package/dist/journal/envelope-store.d.ts +0 -2
- package/dist/journal/envelope-store.js +1 -1
- package/dist/journal/envelope.d.ts +2 -3
- package/dist/journal/envelope.js +3 -3
- package/dist/journal/journal-query.js +1 -1
- package/dist/journal/journal-recorder.d.ts +2 -1
- package/dist/journal/journal-recorder.js +2 -2
- package/dist/journal/rollups.js +9 -9
- package/dist/journal/session-end.d.ts +2 -1
- package/dist/journal/session-journal.js +4 -4
- package/dist/license/license.d.ts +0 -14
- package/dist/license/license.js +8 -8
- package/dist/log.d.ts +10 -0
- package/dist/log.js +11 -1
- package/dist/mcp/mcp-is-error.d.ts +13 -0
- package/dist/mcp/mcp-is-error.js +18 -0
- package/dist/mcp/mcp-outage.d.ts +31 -0
- package/dist/mcp/mcp-outage.js +48 -0
- package/dist/mcp/mcp-proxy.d.ts +124 -0
- package/dist/mcp/mcp-proxy.js +697 -0
- package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
- package/dist/{mcp.js → mcp/mcp.js} +110 -35
- package/dist/mcp/proxy-handshake.d.ts +3 -0
- package/dist/mcp/proxy-handshake.js +54 -0
- package/dist/mcp/proxy-lifecycle.d.ts +64 -0
- package/dist/mcp/proxy-lifecycle.js +70 -0
- package/dist/mcp/tool-catalog-cache.d.ts +29 -0
- package/dist/mcp/tool-catalog-cache.js +55 -0
- package/dist/oracles/propose-consequences.d.ts +2 -1
- package/dist/oracles/propose-consequences.js +16 -11
- package/dist/oracles/self-instrument.d.ts +2 -1
- package/dist/oracles/self-instrument.js +1 -1
- package/dist/phenomena/phenomena.js +3 -3
- package/dist/platform.d.ts +16 -0
- package/dist/platform.js +16 -0
- package/dist/pool/playwright-launcher.d.ts +15 -2
- package/dist/pool/playwright-launcher.js +21 -2
- package/dist/project/fs-port.js +1 -1
- package/dist/project/project-tools.js +2 -2
- package/dist/runs/build-verification-run.js +1 -1
- package/dist/runs/repair-prompt.d.ts +0 -6
- package/dist/runs/repair-prompt.js +3 -3
- package/dist/runs/risk-classify.js +1 -1
- package/dist/runs/run-diff.d.ts +0 -2
- package/dist/runs/run-diff.js +3 -3
- package/dist/runs/run-tools.js +2 -2
- package/dist/runs/verification-sync.js +2 -2
- package/dist/runs/verify-http.js +1 -1
- package/dist/runs/verify-server.js +1 -1
- package/dist/session/command-timeout.d.ts +11 -3
- package/dist/session/command-timeout.js +2 -2
- package/dist/session/control-envelope.d.ts +6 -0
- package/dist/session/control-envelope.js +7 -1
- package/dist/session/dev-server-probe.d.ts +13 -0
- package/dist/session/dev-server-probe.js +52 -0
- package/dist/session/last-act.d.ts +17 -3
- package/dist/session/last-act.js +16 -4
- package/dist/session/live-control-tools.js +7 -2
- package/dist/session/live-control.js +1 -1
- package/dist/session/looks-like-dev-server.d.ts +14 -0
- package/dist/session/looks-like-dev-server.js +25 -0
- package/dist/session/no-session-diagnosis.d.ts +38 -0
- package/dist/session/no-session-diagnosis.js +70 -0
- package/dist/session/no-session-watch.d.ts +19 -0
- package/dist/session/no-session-watch.js +61 -0
- package/dist/session/observed-state.d.ts +4 -0
- package/dist/session/observed-state.js +19 -1
- package/dist/session/output-budget.js +1 -1
- package/dist/session/session-health.d.ts +8 -1
- package/dist/session/session-health.js +8 -7
- package/dist/session/session-info.d.ts +26 -7
- package/dist/session/session-info.js +42 -1
- package/dist/session/session-lease.d.ts +0 -11
- package/dist/session/session-lease.js +1 -1
- package/dist/session/session-manager.d.ts +3 -0
- package/dist/session/session-manager.js +58 -9
- package/dist/session/session-readiness.d.ts +1 -1
- package/dist/session/session-readiness.js +6 -1
- package/dist/session/session-reaper.js +1 -1
- package/dist/session/session-reconnect.d.ts +32 -0
- package/dist/session/session-reconnect.js +42 -0
- package/dist/session/session.d.ts +20 -2
- package/dist/session/session.js +76 -26
- package/dist/session/state-select.d.ts +1 -1
- package/dist/session/state-select.js +1 -1
- package/dist/status-payload.d.ts +19 -0
- package/dist/status-payload.js +11 -0
- package/dist/telemetry/argument-shape.js +10 -1
- package/dist/telemetry/browser-mode.d.ts +27 -0
- package/dist/telemetry/browser-mode.js +33 -0
- package/dist/telemetry/bug-found.d.ts +17 -21
- package/dist/telemetry/bug-found.js +120 -8
- package/dist/telemetry/cli-telemetry.d.ts +2 -12
- package/dist/telemetry/cli-telemetry.js +27 -4
- package/dist/telemetry/daemon-telemetry.d.ts +19 -0
- package/dist/telemetry/daemon-telemetry.js +12 -2
- package/dist/telemetry/dev-repo.js +4 -4
- package/dist/telemetry/error-fingerprint.js +21 -2
- package/dist/telemetry/feedback-cli.d.ts +1 -1
- package/dist/telemetry/feedback-cli.js +4 -4
- package/dist/telemetry/feedback-context.d.ts +22 -0
- package/dist/telemetry/feedback-context.js +41 -1
- package/dist/telemetry/feedback-delivery.d.ts +20 -0
- package/dist/telemetry/feedback-delivery.js +30 -0
- package/dist/telemetry/feedback-outbox.d.ts +22 -0
- package/dist/telemetry/feedback-outbox.js +87 -0
- package/dist/telemetry/feedback.d.ts +22 -1
- package/dist/telemetry/feedback.js +67 -8
- package/dist/telemetry/git-facts.js +1 -1
- package/dist/telemetry/session-metrics.d.ts +2 -0
- package/dist/telemetry/session-metrics.js +68 -6
- package/dist/telemetry/telemetry.d.ts +27 -2
- package/dist/telemetry/telemetry.js +119 -29
- package/dist/telemetry/verification-of.d.ts +22 -0
- package/dist/telemetry/verification-of.js +84 -0
- package/dist/tools/act-capsule.js +2 -2
- package/dist/tools/act-danger.d.ts +12 -0
- package/dist/tools/act-danger.js +20 -3
- package/dist/tools/act-helpers.js +4 -4
- package/dist/tools/act-tools.d.ts +0 -8
- package/dist/tools/act-tools.js +84 -115
- package/dist/tools/act-view.js +7 -7
- package/dist/tools/alias-args.d.ts +17 -0
- package/dist/tools/alias-args.js +25 -0
- package/dist/tools/assert-grade.js +9 -9
- package/dist/tools/assert-verdict.d.ts +3 -1
- package/dist/tools/assert-verdict.js +8 -5
- package/dist/tools/browser-tools.js +30 -11
- package/dist/tools/contract-tools.js +1 -1
- package/dist/tools/coverage-identity.d.ts +34 -0
- package/dist/tools/coverage-identity.js +46 -0
- package/dist/tools/coverage-tools.js +10 -14
- package/dist/tools/dynamic-tools.d.ts +2 -1
- package/dist/tools/dynamic-tools.js +90 -18
- package/dist/tools/error-recovery.d.ts +20 -2
- package/dist/tools/error-recovery.js +179 -4
- package/dist/tools/feedback-tools.d.ts +12 -1
- package/dist/tools/feedback-tools.js +28 -5
- package/dist/tools/invoke-tool.d.ts +0 -6
- package/dist/tools/invoke-tool.js +57 -32
- package/dist/tools/lease-hint.d.ts +17 -0
- package/dist/tools/lease-hint.js +24 -0
- package/dist/tools/lease-tools.js +6 -5
- package/dist/tools/merge-tools.d.ts +10 -1
- package/dist/tools/merge-tools.js +9 -3
- package/dist/tools/merged-name-redirect.d.ts +13 -0
- package/dist/tools/merged-name-redirect.js +55 -0
- package/dist/tools/navigate-result.d.ts +17 -0
- package/dist/tools/navigate-result.js +31 -0
- package/dist/tools/observe-tools.js +54 -20
- package/dist/tools/observed-nothing.d.ts +25 -0
- package/dist/tools/observed-nothing.js +33 -0
- package/dist/tools/query-paginate.js +2 -2
- package/dist/tools/query-shape.d.ts +18 -0
- package/dist/tools/query-shape.js +39 -0
- package/dist/tools/read-tools.js +85 -20
- package/dist/tools/real-input-attempt.d.ts +28 -0
- package/dist/tools/real-input-attempt.js +88 -0
- package/dist/tools/reconcile-tools.js +7 -7
- package/dist/tools/reload-result.d.ts +14 -0
- package/dist/tools/reload-result.js +29 -0
- package/dist/tools/snapshot-delta.d.ts +4 -5
- package/dist/tools/snapshot-delta.js +0 -0
- package/dist/tools/tool-kit.d.ts +8 -0
- package/dist/tools/tool-surface.d.ts +83 -0
- package/dist/tools/tool-surface.js +204 -0
- package/dist/tools/tools-helpers.js +6 -6
- package/dist/tools/tools.d.ts +15 -0
- package/dist/tools/tools.js +53 -17
- package/dist/tools/unadvertised-help.d.ts +5 -0
- package/dist/tools/unadvertised-help.js +39 -0
- package/dist/trace.d.ts +69 -0
- package/dist/trace.js +150 -0
- package/dist/update/nudge-credit.d.ts +4 -0
- package/dist/update/nudge-credit.js +53 -0
- package/dist/update/sdk-sync.d.ts +21 -0
- package/dist/update/sdk-sync.js +42 -0
- package/dist/update/update-checker.js +3 -3
- package/dist/update/update-nudge.d.ts +63 -6
- package/dist/update/update-nudge.js +128 -15
- package/dist/update/updater.d.ts +1 -9
- package/dist/update/updater.js +13 -8
- package/dist/version/peer-announce.d.ts +4 -0
- package/dist/version/peer-announce.js +30 -0
- package/dist/{server-version.js → version/server-version.js} +5 -1
- package/dist/version/version-nudge.d.ts +28 -0
- package/dist/version/version-nudge.js +40 -0
- package/dist/version/version-skew.d.ts +66 -0
- package/dist/version/version-skew.js +71 -0
- package/dist/visual/visual-diff.js +2 -2
- package/dist/visual/visual-tools.js +4 -4
- package/docs/agent-cheatsheet.md +85 -0
- package/docs/architecture.md +113 -0
- package/docs/benchmarks.md +255 -0
- package/docs/debugging.md +102 -0
- package/docs/deploy-checks.md +69 -0
- package/docs/desktop-apps.md +256 -0
- package/docs/enterprise.md +62 -0
- package/docs/fixtures.md +28 -0
- package/docs/flows.md +166 -0
- package/docs/getting-started.md +469 -0
- package/docs/human-control.md +63 -0
- package/docs/integration-patterns.md +171 -0
- package/docs/local-registry.md +126 -0
- package/docs/mint.json +61 -0
- package/docs/multi-agent-testing.md +55 -0
- package/docs/platform-integration.md +122 -0
- package/docs/telemetry-contract.md +214 -0
- package/docs/telemetry.md +184 -0
- package/docs/testing.md +82 -0
- package/docs/token-efficiency.md +80 -0
- package/docs/usage.md +1046 -0
- package/package.json +8 -5
- package/dist/cli-launch.js +0 -112
- package/dist/cli-parse.d.ts +0 -140
- package/dist/daemon-resilience.d.ts +0 -22
- package/dist/daemon-resilience.js +0 -85
- package/dist/mcp-proxy.d.ts +0 -35
- package/dist/mcp-proxy.js +0 -190
- package/dist/tools/profiles.d.ts +0 -37
- package/dist/tools/profiles.js +0 -139
- /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
- /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
- /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
- /package/dist/{cli-doctor.d.ts → cli/cli-doctor.d.ts} +0 -0
- /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
- /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
- /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
* imports are unchanged.
|
|
6
6
|
*/
|
|
7
7
|
export const CLI_USAGE = `usage:
|
|
8
|
-
reticle init [--dry-run] [--port N] [--no-mcp] [--no-install] (wire Reticle into the project in this directory)
|
|
9
|
-
|
|
8
|
+
reticle init [--dry-run] [--port N] [--no-mcp] [--no-install] [--app <dir>] (wire Reticle into the project in this directory)
|
|
9
|
+
--app picks WHICH app in a monorepo, when several are found
|
|
10
|
+
--no-mcp skips MORE than the server registration: also the agent rule files
|
|
11
|
+
(CLAUDE.md / AGENTS.md / .cursor) and the /reticle command, because all three
|
|
12
|
+
only make sense once the tools are reachable.
|
|
13
|
+
reticle serve [--port N] [--drive <url>] [--headless] [--http] [--http-port N] [--http-token T]
|
|
10
14
|
reticle stop [--port N] [--quiet]
|
|
11
15
|
reticle status [--port N]
|
|
12
16
|
reticle doctor [--port N] (diagnose setup: Chromium, daemon, port — one command)
|
|
@@ -15,8 +19,8 @@ export const CLI_USAGE = `usage:
|
|
|
15
19
|
reticle affected [--since <ref>] [file...] (which saved flows must re-verify for the changed files)
|
|
16
20
|
reticle gate [--since <ref>] [file...] (exit non-zero unless passing artifacts cover the affected flows)
|
|
17
21
|
reticle watch [url] (on save, report which saved flows must re-verify)
|
|
18
|
-
reticle drive <url> [--
|
|
19
|
-
reticle mcp [--port N] [--drive <url>] [--
|
|
22
|
+
reticle drive <url> [--headless] (foreground mode — for debugging)
|
|
23
|
+
reticle mcp [--port N] [--drive <url>] [--headless] (MCP stdio proxy — auto-starts daemon if needed)
|
|
20
24
|
reticle update (install the latest server version and restart)
|
|
21
25
|
reticle rollback (restore the previous server version and restart)
|
|
22
26
|
reticle license (show enterprise license status: active | eval | missing)
|
|
@@ -32,7 +36,10 @@ Cloud (link this project to Reticle Cloud — runs/flows recorded on the dashboa
|
|
|
32
36
|
reticle project <ls|create <name>> (list or create cloud projects)
|
|
33
37
|
reticle config [--runs on|off] [--memory on|off] [--flows on|off] [--verify local|server]
|
|
34
38
|
reticle push (send local run artifacts to the dashboard)
|
|
35
|
-
reticle runs | regression | share <runId> (read cloud state; regression exits 3 if any flow broke)
|
|
39
|
+
reticle runs | regression | share <runId> (read cloud state; regression exits 3 if any flow broke)
|
|
40
|
+
|
|
41
|
+
'drive' shows the browser; everything else is hidden (serve/mcp own the pool behind leases, replay
|
|
42
|
+
and the spec runner — batch work). --headed opts any of them in, --headless hides drive, CI hides it.`;
|
|
36
43
|
const INIT_COMMAND = 'init';
|
|
37
44
|
const SERVE_COMMAND = 'serve';
|
|
38
45
|
const STOP_COMMAND = 'stop';
|
|
@@ -53,10 +60,10 @@ const VERSION_COMMAND = 'version';
|
|
|
53
60
|
const TELEMETRY_COMMAND = 'telemetry';
|
|
54
61
|
const FEEDBACK_COMMAND = 'feedback';
|
|
55
62
|
const IDENTIFY_COMMAND = 'identify';
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
const COMPANY_FLAG = '--company';
|
|
64
|
+
const EMAIL_FLAG = '--email';
|
|
65
|
+
const CONTEXT_FLAG = '--context';
|
|
66
|
+
const FORGET_FLAG = '--forget';
|
|
60
67
|
/** `reticle feedback --rating 4 "the words"` — the human half of the channel. */
|
|
61
68
|
export const RATING_FLAG = '--rating';
|
|
62
69
|
export const BUG_FLAG = '--bug';
|
|
@@ -115,24 +122,51 @@ const KNOWN_COMMANDS = new Set([
|
|
|
115
122
|
]);
|
|
116
123
|
/** The subcommand name if we recognize it, else `unknown`. Bare `reticle` reports `help`. */
|
|
117
124
|
export function knownCommand(arg) {
|
|
118
|
-
if (arg === undefined ||
|
|
125
|
+
if (arg === undefined || '' === arg)
|
|
119
126
|
return 'help';
|
|
120
127
|
return KNOWN_COMMANDS.has(arg) ? arg : UNKNOWN_COMMAND;
|
|
121
128
|
}
|
|
122
129
|
export const HEADED_FLAG = '--headed';
|
|
130
|
+
/**
|
|
131
|
+
* Force a hidden browser. The default is now HEADED: a run nobody can see is a run nobody trusts,
|
|
132
|
+
* and every "did it actually do anything?" question cost a round-trip. CI passes this (or just sets
|
|
133
|
+
* CI, which flips the default) because there is no display there to be headed on.
|
|
134
|
+
*/
|
|
135
|
+
const HEADLESS_FLAG = '--headless';
|
|
123
136
|
export const PORT_FLAG = '--port';
|
|
124
137
|
export const DRIVE_FLAG = '--drive';
|
|
125
138
|
const QUIET_FLAG = '--quiet';
|
|
126
139
|
const DRY_RUN_FLAG = '--dry-run';
|
|
127
140
|
const YES_FLAG = '--yes';
|
|
128
141
|
const NO_MCP_FLAG = '--no-mcp';
|
|
142
|
+
const APP_FLAG = '--app';
|
|
129
143
|
const NO_INSTALL_FLAG = '--no-install';
|
|
130
144
|
export const HTTP_FLAG = '--http';
|
|
131
145
|
export const HTTP_PORT_FLAG = '--http-port';
|
|
132
146
|
export const HTTP_TOKEN_FLAG = '--http-token';
|
|
133
147
|
const TIMEOUT_FLAG = '--timeout';
|
|
134
148
|
const STORAGE_STATE_FLAG = '--storage-state';
|
|
135
|
-
|
|
149
|
+
const unknownArgument = (arg) => ({
|
|
150
|
+
kind: 'error',
|
|
151
|
+
message: `unknown argument '${arg}'`,
|
|
152
|
+
});
|
|
153
|
+
const missingValue = (flag) => ({
|
|
154
|
+
kind: 'error',
|
|
155
|
+
message: `${flag} needs a value`,
|
|
156
|
+
});
|
|
157
|
+
const notANumber = (flag, value) => ({
|
|
158
|
+
kind: 'error',
|
|
159
|
+
message: `${flag} expects a number, got '${value}'`,
|
|
160
|
+
});
|
|
161
|
+
const missingOperand = (command, what) => ({
|
|
162
|
+
kind: 'error',
|
|
163
|
+
message: `${command} needs ${what}`,
|
|
164
|
+
});
|
|
165
|
+
const unknownCommand = (command) => ({
|
|
166
|
+
kind: 'error',
|
|
167
|
+
message: `unknown command '${command}'`,
|
|
168
|
+
});
|
|
169
|
+
function parseServeFlags(args, defaultPort, _defaultHeadless) {
|
|
136
170
|
let port = defaultPort;
|
|
137
171
|
let driveUrl;
|
|
138
172
|
let headless = true;
|
|
@@ -142,25 +176,32 @@ function parseServeFlags(args, defaultPort) {
|
|
|
142
176
|
let i = 0;
|
|
143
177
|
while (i < args.length) {
|
|
144
178
|
const arg = args[i];
|
|
179
|
+
// `i < args.length` already guarantees this, but the index signature does not say so and the
|
|
180
|
+
// unknown-argument error needs a real string to name.
|
|
181
|
+
if (arg === undefined)
|
|
182
|
+
break;
|
|
145
183
|
if (arg === PORT_FLAG) {
|
|
146
184
|
i++;
|
|
147
185
|
const n = args[i];
|
|
148
186
|
if (n === undefined)
|
|
149
|
-
return
|
|
187
|
+
return missingValue(PORT_FLAG);
|
|
150
188
|
const parsed = parseInt(n, 10);
|
|
151
189
|
if (isNaN(parsed))
|
|
152
|
-
return
|
|
190
|
+
return notANumber(PORT_FLAG, n);
|
|
153
191
|
port = parsed;
|
|
154
192
|
}
|
|
155
193
|
else if (arg === DRIVE_FLAG) {
|
|
156
194
|
i++;
|
|
157
195
|
driveUrl = args[i];
|
|
158
196
|
if (driveUrl === undefined)
|
|
159
|
-
return
|
|
197
|
+
return missingValue(DRIVE_FLAG);
|
|
160
198
|
}
|
|
161
199
|
else if (arg === HEADED_FLAG) {
|
|
162
200
|
headless = false;
|
|
163
201
|
}
|
|
202
|
+
else if (arg === HEADLESS_FLAG) {
|
|
203
|
+
headless = true;
|
|
204
|
+
}
|
|
164
205
|
else if (arg === HTTP_FLAG) {
|
|
165
206
|
http = true;
|
|
166
207
|
}
|
|
@@ -168,20 +209,20 @@ function parseServeFlags(args, defaultPort) {
|
|
|
168
209
|
i++;
|
|
169
210
|
const n = args[i];
|
|
170
211
|
if (n === undefined)
|
|
171
|
-
return
|
|
212
|
+
return missingValue(HTTP_PORT_FLAG);
|
|
172
213
|
const parsed = parseInt(n, 10);
|
|
173
214
|
if (isNaN(parsed))
|
|
174
|
-
return
|
|
215
|
+
return notANumber(HTTP_PORT_FLAG, n);
|
|
175
216
|
httpPort = parsed;
|
|
176
217
|
}
|
|
177
218
|
else if (arg === HTTP_TOKEN_FLAG) {
|
|
178
219
|
i++;
|
|
179
220
|
httpToken = args[i];
|
|
180
221
|
if (httpToken === undefined)
|
|
181
|
-
return
|
|
222
|
+
return missingValue(HTTP_TOKEN_FLAG);
|
|
182
223
|
}
|
|
183
224
|
else {
|
|
184
|
-
return
|
|
225
|
+
return unknownArgument(arg);
|
|
185
226
|
}
|
|
186
227
|
i++;
|
|
187
228
|
}
|
|
@@ -197,7 +238,7 @@ function parseServeFlags(args, defaultPort) {
|
|
|
197
238
|
}
|
|
198
239
|
function parsePortFlag(args, defaultPort) {
|
|
199
240
|
const idx = args.indexOf(PORT_FLAG);
|
|
200
|
-
if (
|
|
241
|
+
if (-1 === idx)
|
|
201
242
|
return defaultPort;
|
|
202
243
|
const n = args[idx + 1];
|
|
203
244
|
if (n === undefined)
|
|
@@ -205,25 +246,28 @@ function parsePortFlag(args, defaultPort) {
|
|
|
205
246
|
const parsed = parseInt(n, 10);
|
|
206
247
|
return isNaN(parsed) ? defaultPort : parsed;
|
|
207
248
|
}
|
|
208
|
-
function parseDriveSuffix(args, port) {
|
|
209
|
-
let headless =
|
|
249
|
+
function parseDriveSuffix(args, port, defaultHeadless) {
|
|
250
|
+
let headless = defaultHeadless;
|
|
210
251
|
let driveUrl;
|
|
211
252
|
for (const arg of args) {
|
|
212
253
|
if (arg === HEADED_FLAG) {
|
|
213
254
|
headless = false;
|
|
214
255
|
}
|
|
256
|
+
else if (arg === HEADLESS_FLAG) {
|
|
257
|
+
headless = true;
|
|
258
|
+
}
|
|
215
259
|
else if (arg.startsWith('--')) {
|
|
216
|
-
return
|
|
260
|
+
return unknownArgument(arg);
|
|
217
261
|
}
|
|
218
262
|
else if (driveUrl === undefined) {
|
|
219
263
|
driveUrl = arg;
|
|
220
264
|
}
|
|
221
265
|
else {
|
|
222
|
-
return
|
|
266
|
+
return unknownArgument(arg);
|
|
223
267
|
}
|
|
224
268
|
}
|
|
225
269
|
if (driveUrl === undefined)
|
|
226
|
-
return
|
|
270
|
+
return missingOperand(DRIVE_COMMAND, 'a url');
|
|
227
271
|
return { kind: 'ok', port, driveUrl, headless };
|
|
228
272
|
}
|
|
229
273
|
/**
|
|
@@ -247,32 +291,32 @@ function parseVerifySuffix(args) {
|
|
|
247
291
|
i++;
|
|
248
292
|
const n = args[i];
|
|
249
293
|
if (n === undefined)
|
|
250
|
-
return
|
|
294
|
+
return missingValue(TIMEOUT_FLAG);
|
|
251
295
|
const parsed = parseInt(n, 10);
|
|
252
296
|
if (isNaN(parsed))
|
|
253
|
-
return
|
|
297
|
+
return notANumber(TIMEOUT_FLAG, n);
|
|
254
298
|
timeoutMs = parsed;
|
|
255
299
|
}
|
|
256
300
|
else if (arg === STORAGE_STATE_FLAG) {
|
|
257
301
|
i++;
|
|
258
302
|
const v = args[i];
|
|
259
303
|
if (v === undefined)
|
|
260
|
-
return
|
|
304
|
+
return missingValue(STORAGE_STATE_FLAG);
|
|
261
305
|
storageState = v;
|
|
262
306
|
}
|
|
263
307
|
else if (arg.startsWith('--')) {
|
|
264
|
-
return
|
|
308
|
+
return unknownArgument(arg);
|
|
265
309
|
}
|
|
266
310
|
else if (url === undefined) {
|
|
267
311
|
url = arg;
|
|
268
312
|
}
|
|
269
313
|
else {
|
|
270
|
-
return
|
|
314
|
+
return unknownArgument(arg);
|
|
271
315
|
}
|
|
272
316
|
i++;
|
|
273
317
|
}
|
|
274
318
|
if (url === undefined)
|
|
275
|
-
return
|
|
319
|
+
return missingOperand(VERIFY_COMMAND, 'a url');
|
|
276
320
|
return {
|
|
277
321
|
kind: 'ok',
|
|
278
322
|
url,
|
|
@@ -286,19 +330,31 @@ function parseInitFlags(args) {
|
|
|
286
330
|
let mcp = true;
|
|
287
331
|
let dryRun = false;
|
|
288
332
|
let install = true;
|
|
333
|
+
let app;
|
|
289
334
|
let i = 0;
|
|
290
335
|
while (i < args.length) {
|
|
291
336
|
const arg = args[i];
|
|
337
|
+
// `i < args.length` already guarantees this, but the index signature does not say so and the
|
|
338
|
+
// unknown-argument error needs a real string to name.
|
|
339
|
+
if (arg === undefined)
|
|
340
|
+
break;
|
|
292
341
|
if (arg === PORT_FLAG) {
|
|
293
342
|
i++;
|
|
294
343
|
const n = args[i];
|
|
295
344
|
if (n === undefined)
|
|
296
|
-
return
|
|
345
|
+
return missingValue(PORT_FLAG);
|
|
297
346
|
const parsed = parseInt(n, 10);
|
|
298
347
|
if (isNaN(parsed))
|
|
299
|
-
return
|
|
348
|
+
return notANumber(PORT_FLAG, n);
|
|
300
349
|
port = parsed;
|
|
301
350
|
}
|
|
351
|
+
else if (arg === APP_FLAG) {
|
|
352
|
+
i++;
|
|
353
|
+
const value = args[i];
|
|
354
|
+
if (value === undefined)
|
|
355
|
+
return missingValue(APP_FLAG);
|
|
356
|
+
app = value;
|
|
357
|
+
}
|
|
302
358
|
else if (arg === NO_MCP_FLAG) {
|
|
303
359
|
mcp = false;
|
|
304
360
|
}
|
|
@@ -312,15 +368,29 @@ function parseInitFlags(args) {
|
|
|
312
368
|
// Accepted for scripting/CI; init has no interactive prompts today.
|
|
313
369
|
}
|
|
314
370
|
else {
|
|
315
|
-
return
|
|
371
|
+
return unknownArgument(arg);
|
|
316
372
|
}
|
|
317
373
|
i++;
|
|
318
374
|
}
|
|
319
|
-
return { kind: 'ok', port, mcp, dryRun, install };
|
|
375
|
+
return { kind: 'ok', port, mcp, dryRun, install, app };
|
|
320
376
|
}
|
|
321
377
|
/** Pure CLI arg parser — exported for unit tests. argv = process.argv.slice(2). */
|
|
322
378
|
const SINCE_FLAG = '--since';
|
|
323
379
|
/** Parse `[--since <ref>] [file...]` shared by `affected` and `gate`. */
|
|
380
|
+
/**
|
|
381
|
+
* What `reticle gate` / `reticle affected` mean with NOTHING after them: the working tree.
|
|
382
|
+
*
|
|
383
|
+
* They used to mean a usage error — while the rule `reticle init` writes into the agent's own
|
|
384
|
+
* instruction file says, in as many words, "run `reticle gate`". An instruction the tool rejects is
|
|
385
|
+
* worse than no instruction: the agent spends a turn on it and concludes Reticle is broken.
|
|
386
|
+
*
|
|
387
|
+
* HEAD is the ref that answers the question being asked. Explicit files or an explicit --since still
|
|
388
|
+
* win; this only fills the empty case.
|
|
389
|
+
*/
|
|
390
|
+
const WORKING_TREE_REF = 'HEAD';
|
|
391
|
+
function implicitSince(files) {
|
|
392
|
+
return 0 === files.length ? WORKING_TREE_REF : undefined;
|
|
393
|
+
}
|
|
324
394
|
function parseTargetArgs(rest) {
|
|
325
395
|
const files = [];
|
|
326
396
|
let since;
|
|
@@ -336,28 +406,45 @@ function parseTargetArgs(rest) {
|
|
|
336
406
|
}
|
|
337
407
|
return since === undefined ? { files } : { files, since };
|
|
338
408
|
}
|
|
339
|
-
|
|
340
|
-
|
|
409
|
+
/**
|
|
410
|
+
* @param defaultHeadless Whether a browser Reticle launches should be hidden when no flag says
|
|
411
|
+
* otherwise. Injected rather than read from the environment here, because this module is pure —
|
|
412
|
+
* `cli.ts` decides it from `CI`. The product default is FALSE: showing the run is what makes it
|
|
413
|
+
* trustworthy, and asking people to opt into seeing their own app was backwards.
|
|
414
|
+
*/
|
|
415
|
+
export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
416
|
+
// Bare `reticle` is `serve` — a pool-owning command, so headless like the rest of that family.
|
|
417
|
+
if (0 === argv.length)
|
|
341
418
|
return { kind: 'serve', port: defaultPort, headless: true, http: false };
|
|
342
419
|
const [cmd, ...rest] = argv;
|
|
420
|
+
// Guaranteed by the bare-argv check above; restated so the unknown-command error can name it.
|
|
421
|
+
if (cmd === undefined)
|
|
422
|
+
return { kind: 'error', message: CLI_USAGE };
|
|
343
423
|
// `version` (or the conventional -v/--version flags) prints the running version — the diagnostic the
|
|
344
424
|
// troubleshooting docs lean on to confirm which npx-resolved build is actually executing.
|
|
345
|
-
if (cmd === VERSION_COMMAND ||
|
|
425
|
+
if (cmd === VERSION_COMMAND || '--version' === cmd || '-v' === cmd)
|
|
346
426
|
return { kind: 'version' };
|
|
347
427
|
// `help` (and the conventional -h/--help) print usage to stdout and exit 0 — the universal first move
|
|
348
428
|
// for a new user, which otherwise fell through to a JSON error with exit 1.
|
|
349
|
-
if (
|
|
429
|
+
if ('help' === cmd || '--help' === cmd || '-h' === cmd)
|
|
350
430
|
return { kind: 'help' };
|
|
351
431
|
switch (cmd) {
|
|
352
432
|
case INIT_COMMAND: {
|
|
353
433
|
const r = parseInitFlags(rest);
|
|
354
|
-
if (r.kind
|
|
434
|
+
if ('error' === r.kind)
|
|
355
435
|
return r;
|
|
356
|
-
return {
|
|
436
|
+
return {
|
|
437
|
+
kind: 'init',
|
|
438
|
+
port: r.port,
|
|
439
|
+
mcp: r.mcp,
|
|
440
|
+
dryRun: r.dryRun,
|
|
441
|
+
install: r.install,
|
|
442
|
+
app: r.app,
|
|
443
|
+
};
|
|
357
444
|
}
|
|
358
445
|
case SERVE_COMMAND: {
|
|
359
|
-
const r = parseServeFlags(rest, defaultPort);
|
|
360
|
-
if (r.kind
|
|
446
|
+
const r = parseServeFlags(rest, defaultPort, defaultHeadless);
|
|
447
|
+
if ('error' === r.kind)
|
|
361
448
|
return r;
|
|
362
449
|
return {
|
|
363
450
|
kind: 'serve',
|
|
@@ -396,7 +483,7 @@ export function parseCliArgs(argv, defaultPort) {
|
|
|
396
483
|
case IDENTIFY_COMMAND: {
|
|
397
484
|
const flag = (name) => {
|
|
398
485
|
const at = rest.indexOf(name);
|
|
399
|
-
return
|
|
486
|
+
return -1 === at ? undefined : rest[at + 1];
|
|
400
487
|
};
|
|
401
488
|
const context = flag(CONTEXT_FLAG);
|
|
402
489
|
const company = flag(COMPANY_FLAG);
|
|
@@ -411,13 +498,13 @@ export function parseCliArgs(argv, defaultPort) {
|
|
|
411
498
|
}
|
|
412
499
|
case FEEDBACK_COMMAND: {
|
|
413
500
|
const ratingAt = rest.indexOf(RATING_FLAG);
|
|
414
|
-
const rating =
|
|
501
|
+
const rating = -1 === ratingAt ? undefined : Number(rest[ratingAt + 1]);
|
|
415
502
|
if (rating !== undefined && (!Number.isInteger(rating) || rating < 1 || rating > 5)) {
|
|
416
503
|
return { kind: 'error', message: `${RATING_FLAG} takes a whole number from 1 to 5` };
|
|
417
504
|
}
|
|
418
505
|
// Everything that is not a flag or the rating's value is the message. Quoting is the user's
|
|
419
506
|
// job for shell reasons, but joining the remainder means an unquoted sentence still works.
|
|
420
|
-
const consumed = new Set(
|
|
507
|
+
const consumed = new Set(-1 === ratingAt ? [] : [ratingAt, ratingAt + 1]);
|
|
421
508
|
const text = rest
|
|
422
509
|
.filter((arg, i) => !consumed.has(i) && !arg.startsWith('--'))
|
|
423
510
|
.join(' ')
|
|
@@ -436,14 +523,14 @@ export function parseCliArgs(argv, defaultPort) {
|
|
|
436
523
|
return url !== undefined ? { kind: 'open', port, url } : { kind: 'open', port };
|
|
437
524
|
}
|
|
438
525
|
case DRIVE_COMMAND: {
|
|
439
|
-
const r = parseDriveSuffix(rest, defaultPort);
|
|
440
|
-
if (r.kind
|
|
526
|
+
const r = parseDriveSuffix(rest, defaultPort, defaultHeadless);
|
|
527
|
+
if ('error' === r.kind)
|
|
441
528
|
return r;
|
|
442
529
|
return { kind: 'drive', port: r.port, driveUrl: r.driveUrl, headless: r.headless };
|
|
443
530
|
}
|
|
444
531
|
case DAEMON_INNER_COMMAND: {
|
|
445
|
-
const r = parseServeFlags(rest, defaultPort);
|
|
446
|
-
if (r.kind
|
|
532
|
+
const r = parseServeFlags(rest, defaultPort, defaultHeadless);
|
|
533
|
+
if ('error' === r.kind)
|
|
447
534
|
return r;
|
|
448
535
|
return {
|
|
449
536
|
kind: '_daemon',
|
|
@@ -457,7 +544,7 @@ export function parseCliArgs(argv, defaultPort) {
|
|
|
457
544
|
}
|
|
458
545
|
case VERIFY_COMMAND: {
|
|
459
546
|
const r = parseVerifySuffix(rest);
|
|
460
|
-
if (r.kind
|
|
547
|
+
if ('error' === r.kind)
|
|
461
548
|
return r;
|
|
462
549
|
return {
|
|
463
550
|
kind: 'verify',
|
|
@@ -477,21 +564,13 @@ export function parseCliArgs(argv, defaultPort) {
|
|
|
477
564
|
}
|
|
478
565
|
case AFFECTED_COMMAND: {
|
|
479
566
|
const t = parseTargetArgs(rest);
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
return {
|
|
484
|
-
kind: 'affected',
|
|
485
|
-
files: t.files,
|
|
486
|
-
...(t.since === undefined ? {} : { since: t.since }),
|
|
487
|
-
};
|
|
567
|
+
const since = t.since ?? implicitSince(t.files);
|
|
568
|
+
return { kind: 'affected', files: t.files, ...(since === undefined ? {} : { since }) };
|
|
488
569
|
}
|
|
489
570
|
case GATE_COMMAND: {
|
|
490
571
|
const t = parseTargetArgs(rest);
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
return { kind: 'gate', files: t.files, ...(t.since === undefined ? {} : { since: t.since }) };
|
|
572
|
+
const since = t.since ?? implicitSince(t.files);
|
|
573
|
+
return { kind: 'gate', files: t.files, ...(since === undefined ? {} : { since }) };
|
|
495
574
|
}
|
|
496
575
|
case WATCH_COMMAND: {
|
|
497
576
|
// `reticle watch [url]` — on file save, report which saved flows must re-verify.
|
|
@@ -503,8 +582,8 @@ export function parseCliArgs(argv, defaultPort) {
|
|
|
503
582
|
case ROLLBACK_COMMAND:
|
|
504
583
|
return { kind: 'rollback' };
|
|
505
584
|
case MCP_COMMAND: {
|
|
506
|
-
const r = parseServeFlags(rest, defaultPort);
|
|
507
|
-
if (r.kind
|
|
585
|
+
const r = parseServeFlags(rest, defaultPort, defaultHeadless);
|
|
586
|
+
if ('error' === r.kind)
|
|
508
587
|
return r;
|
|
509
588
|
return {
|
|
510
589
|
kind: 'mcp',
|
|
@@ -517,6 +596,8 @@ export function parseCliArgs(argv, defaultPort) {
|
|
|
517
596
|
};
|
|
518
597
|
}
|
|
519
598
|
default:
|
|
520
|
-
|
|
599
|
+
// A bare `reticle` never lands here — it defaults to `serve` above — so `cmd` is always a real
|
|
600
|
+
// word somebody typed, and naming it is strictly more useful than reprinting the whole help.
|
|
601
|
+
return unknownCommand(cmd);
|
|
521
602
|
}
|
|
522
603
|
}
|
|
@@ -7,6 +7,21 @@
|
|
|
7
7
|
* 3..reticle.json "port" field in the cwd ← per-project isolation
|
|
8
8
|
* 4. RETICLE_DEFAULT_PORT (4400)
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* Ports that belong to a DEV SERVER, not to Reticle's bridge. Next defaults to 3000, Vite to 5173,
|
|
12
|
+
* Astro to 4321, and so on.
|
|
13
|
+
*
|
|
14
|
+
* `.reticle.json`'s `port` is the bridge — the daemon ↔ SDK channel, default 4400 — and it has
|
|
15
|
+
* nothing to do with the port the app is served on. Setting it to the dev-server port makes the
|
|
16
|
+
* daemon try to bind the port the app already holds; what the user sees is either a bind failure or
|
|
17
|
+
* a daemon that never connects, neither of which mentions the actual mistake. The old setup skill
|
|
18
|
+
* asked "what port does your dev server run on?" a few lines before showing this field, which is how
|
|
19
|
+
* the confusion got manufactured in the first place.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEV_SERVER_PORTS: ReadonlySet<number>;
|
|
22
|
+
export declare function isLikelyDevServerPort(port: number): boolean;
|
|
23
|
+
/** The warning printed when a project pins the bridge to something that looks like its dev server. */
|
|
24
|
+
export declare function devServerPortWarning(port: number): string;
|
|
10
25
|
/**
|
|
11
26
|
* Read the port stored in the project's .reticle.json (written by `reticle init`).
|
|
12
27
|
* Returns undefined if the file is absent, unreadable, or has no valid numeric port.
|
|
@@ -8,6 +8,27 @@
|
|
|
8
8
|
* 4. RETICLE_DEFAULT_PORT (4400)
|
|
9
9
|
*/
|
|
10
10
|
import { readFileSync } from 'node:fs';
|
|
11
|
+
/**
|
|
12
|
+
* Ports that belong to a DEV SERVER, not to Reticle's bridge. Next defaults to 3000, Vite to 5173,
|
|
13
|
+
* Astro to 4321, and so on.
|
|
14
|
+
*
|
|
15
|
+
* `.reticle.json`'s `port` is the bridge — the daemon ↔ SDK channel, default 4400 — and it has
|
|
16
|
+
* nothing to do with the port the app is served on. Setting it to the dev-server port makes the
|
|
17
|
+
* daemon try to bind the port the app already holds; what the user sees is either a bind failure or
|
|
18
|
+
* a daemon that never connects, neither of which mentions the actual mistake. The old setup skill
|
|
19
|
+
* asked "what port does your dev server run on?" a few lines before showing this field, which is how
|
|
20
|
+
* the confusion got manufactured in the first place.
|
|
21
|
+
*/
|
|
22
|
+
export const DEV_SERVER_PORTS = new Set([
|
|
23
|
+
3000, 3001, 4200, 4321, 5000, 5173, 5174, 8000, 8080, 8100, 9000,
|
|
24
|
+
]);
|
|
25
|
+
export function isLikelyDevServerPort(port) {
|
|
26
|
+
return DEV_SERVER_PORTS.has(port);
|
|
27
|
+
}
|
|
28
|
+
/** The warning printed when a project pins the bridge to something that looks like its dev server. */
|
|
29
|
+
export function devServerPortWarning(port) {
|
|
30
|
+
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.`;
|
|
31
|
+
}
|
|
11
32
|
/**
|
|
12
33
|
* Read the port stored in the project's .reticle.json (written by `reticle init`).
|
|
13
34
|
* Returns undefined if the file is absent, unreadable, or has no valid numeric port.
|
|
@@ -16,9 +37,9 @@ export function readProjectPort(cwd) {
|
|
|
16
37
|
try {
|
|
17
38
|
const raw = readFileSync(`${cwd}/.reticle.json`, 'utf8');
|
|
18
39
|
const config = JSON.parse(raw);
|
|
19
|
-
if (typeof config
|
|
40
|
+
if ('object' === typeof config && config !== null) {
|
|
20
41
|
const p = config['port'];
|
|
21
|
-
if (typeof p
|
|
42
|
+
if ('number' === typeof p && Number.isInteger(p) && p > 0 && p < 65536)
|
|
22
43
|
return p;
|
|
23
44
|
}
|
|
24
45
|
}
|
|
@@ -36,9 +57,9 @@ export function readProjectId(cwd) {
|
|
|
36
57
|
try {
|
|
37
58
|
const raw = readFileSync(`${cwd}/.reticle.json`, 'utf8');
|
|
38
59
|
const config = JSON.parse(raw);
|
|
39
|
-
if (typeof config
|
|
60
|
+
if ('object' === typeof config && config !== null) {
|
|
40
61
|
const id = config['projectId'];
|
|
41
|
-
if (typeof id
|
|
62
|
+
if ('string' === typeof id && id.length > 0)
|
|
42
63
|
return id;
|
|
43
64
|
}
|
|
44
65
|
}
|
|
@@ -55,16 +76,16 @@ export function readProjectId(cwd) {
|
|
|
55
76
|
export function readJournalEnabled(cwd, env) {
|
|
56
77
|
if (env !== undefined) {
|
|
57
78
|
const v = env.trim().toLowerCase();
|
|
58
|
-
if (
|
|
79
|
+
if ('0' === v || 'false' === v || 'off' === v)
|
|
59
80
|
return false;
|
|
60
|
-
if (
|
|
81
|
+
if ('1' === v || 'true' === v || 'on' === v)
|
|
61
82
|
return true;
|
|
62
83
|
}
|
|
63
84
|
try {
|
|
64
85
|
const raw = readFileSync(`${cwd}/.reticle.json`, 'utf8');
|
|
65
86
|
const config = JSON.parse(raw);
|
|
66
|
-
if (typeof config
|
|
67
|
-
if (config['journal']
|
|
87
|
+
if ('object' === typeof config && config !== null) {
|
|
88
|
+
if (false === config['journal'])
|
|
68
89
|
return false;
|
|
69
90
|
}
|
|
70
91
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** `reticle update` — install the latest server version, sync the app's SDK, and restart. */
|
|
2
|
+
export declare function handleUpdate(): Promise<void>;
|
|
3
|
+
/** `reticle rollback` — restore the previous server version and restart. */
|
|
4
|
+
export declare function handleRollback(): Promise<void>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The self-update command pair — `reticle update` and `reticle rollback`.
|
|
3
|
+
*
|
|
4
|
+
* Split out of cli.ts, which sits at the 600-line cap: these two are one cohesive unit (swap the
|
|
5
|
+
* installed version, restart) and the file they came from is the CLI's dispatch table, which grows
|
|
6
|
+
* for entirely different reasons.
|
|
7
|
+
*/
|
|
8
|
+
import { checkForUpdate } from '../update/update-checker.js';
|
|
9
|
+
import { updateTarget } from '../update/update-nudge.js';
|
|
10
|
+
import { applyUpdate, rollback } from '../update/updater.js';
|
|
11
|
+
import { SERVER_VERSION } from '../version/server-version.js';
|
|
12
|
+
import { log } from '../log.js';
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { reticleDepsOf, sdkSyncCommand } from '../update/sdk-sync.js';
|
|
16
|
+
import { detectPackageManager } from '../init/detect.js';
|
|
17
|
+
import { buildNodeIo } from '../init/node-io.js';
|
|
18
|
+
/**
|
|
19
|
+
* Bring the SDK in the CURRENT project to the version being installed.
|
|
20
|
+
*
|
|
21
|
+
* Best-effort and non-fatal on purpose: `reticle update` is run from wherever the human happens to
|
|
22
|
+
* be, which is often not an app at all. A directory with no manifest, or one that has none of our
|
|
23
|
+
* packages, simply has nothing to sync — that is a normal outcome, not a failure, and it must never
|
|
24
|
+
* stop the CLI half from happening.
|
|
25
|
+
*/
|
|
26
|
+
function syncProjectSdk(target) {
|
|
27
|
+
const cwd = process.cwd();
|
|
28
|
+
let manifest;
|
|
29
|
+
try {
|
|
30
|
+
manifest = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf8'));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return; // not an app directory
|
|
34
|
+
}
|
|
35
|
+
const packages = reticleDepsOf(manifest);
|
|
36
|
+
const io = buildNodeIo(cwd);
|
|
37
|
+
const pm = detectPackageManager(new Set(io.rootFiles()), new Set(io.listDirs('node_modules')));
|
|
38
|
+
const cmd = sdkSyncCommand(pm, packages, target);
|
|
39
|
+
if (null === cmd) {
|
|
40
|
+
log('reticle_update_sdk', { synced: false, reason: 'no @reticlehq packages in this project' });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const ok = io.exec(cmd.command, cmd.args);
|
|
44
|
+
log('reticle_update_sdk', { synced: ok, packages, to: target, packageManager: pm });
|
|
45
|
+
if (!ok) {
|
|
46
|
+
log('reticle_update_sdk_failed', {
|
|
47
|
+
hint: `run \`${cmd.command} ${cmd.args.join(' ')}\` by hand, then restart the dev server`,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** `reticle update` — install the latest server version, sync the app's SDK, and restart. */
|
|
52
|
+
export async function handleUpdate() {
|
|
53
|
+
try {
|
|
54
|
+
const manifest = await checkForUpdate(SERVER_VERSION, () => Date.now());
|
|
55
|
+
// Direction, not inequality: the registry being DIFFERENT is not the registry being newer, and
|
|
56
|
+
// the old gate happily installed a downgrade — reported by a user. See updateTarget.
|
|
57
|
+
const target = updateTarget(manifest);
|
|
58
|
+
if (target === undefined) {
|
|
59
|
+
log('reticle_update', {
|
|
60
|
+
ok: false,
|
|
61
|
+
message: 'already on the latest version',
|
|
62
|
+
version: SERVER_VERSION,
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
log('reticle_update', { ok: true, from: SERVER_VERSION, to: target });
|
|
67
|
+
// The app's SDK FIRST, then the CLI. `reticle update` used to swap only the CLI, so the command
|
|
68
|
+
// whose job is keeping an install current was itself a way to produce a version-skewed pair —
|
|
69
|
+
// and the skew message told people to run it to fix an outdated SDK, which it could not do.
|
|
70
|
+
//
|
|
71
|
+
// Before the CLI swap because `applyUpdate` never returns (it execs and exits). If this half
|
|
72
|
+
// fails the daemon is still the older one, which is the direction the HELLO check names clearly
|
|
73
|
+
// and a re-run fixes; the reverse would leave a new daemon talking to an old page.
|
|
74
|
+
syncProjectSdk(target);
|
|
75
|
+
await applyUpdate(target); // calls process.exit; Claude Code restarts
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
log('reticle_update_failed', { error: error instanceof Error ? error.message : String(error) });
|
|
79
|
+
process.exitCode = 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** `reticle rollback` — restore the previous server version and restart. */
|
|
83
|
+
export async function handleRollback() {
|
|
84
|
+
try {
|
|
85
|
+
await rollback(); // calls process.exit
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
log('reticle_rollback_failed', {
|
|
89
|
+
error: error instanceof Error ? error.message : String(error),
|
|
90
|
+
});
|
|
91
|
+
process.exitCode = 1;
|
|
92
|
+
}
|
|
93
|
+
}
|