@reticlehq/server 2.4.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} +63 -13
- package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +1 -11
- package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +9 -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-parse.d.ts → cli/cli-parse.d.ts} +2 -11
- package/dist/{cli-parse.js → cli/cli-parse.js} +113 -60
- package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +12 -0
- package/dist/{cli-port.js → cli/cli-port.js} +9 -9
- 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 +174 -92
- 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.js +24 -9
- 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 +53 -7
- 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.js +4 -1
- 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 +3 -2
- package/dist/init/detect.js +16 -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 +2 -4
- package/dist/init/next-patch.js +109 -19
- package/dist/init/node-io.js +23 -6
- package/dist/init/plan-framework.d.ts +16 -1
- package/dist/init/plan-framework.js +132 -8
- package/dist/init/plan.d.ts +73 -8
- package/dist/init/plan.js +133 -34
- package/dist/init/project-id.d.ts +5 -9
- package/dist/init/project-id.js +10 -22
- package/dist/init/run.d.ts +5 -0
- package/dist/init/run.js +210 -36
- package/dist/init/slash-command.d.ts +9 -0
- package/dist/init/slash-command.js +10 -1
- package/dist/init/snippets.d.ts +7 -10
- package/dist/init/snippets.js +44 -15
- package/dist/init/vite-config.js +1 -1
- package/dist/init/workspace-apps.d.ts +23 -0
- package/dist/init/workspace-apps.js +68 -0
- package/dist/input/driven-redaction.js +1 -1
- package/dist/input/network-detail.js +8 -8
- 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 +52 -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 +14 -2
- package/dist/session/session.js +69 -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 +81 -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/daemon-resilience.d.ts +0 -22
- package/dist/daemon-resilience.js +0 -85
- package/dist/mcp-proxy.d.ts +0 -67
- package/dist/mcp-proxy.js +0 -337
- 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,7 +5,11 @@
|
|
|
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)
|
|
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.
|
|
9
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]
|
|
@@ -56,10 +60,10 @@ const VERSION_COMMAND = 'version';
|
|
|
56
60
|
const TELEMETRY_COMMAND = 'telemetry';
|
|
57
61
|
const FEEDBACK_COMMAND = 'feedback';
|
|
58
62
|
const IDENTIFY_COMMAND = 'identify';
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
const COMPANY_FLAG = '--company';
|
|
64
|
+
const EMAIL_FLAG = '--email';
|
|
65
|
+
const CONTEXT_FLAG = '--context';
|
|
66
|
+
const FORGET_FLAG = '--forget';
|
|
63
67
|
/** `reticle feedback --rating 4 "the words"` — the human half of the channel. */
|
|
64
68
|
export const RATING_FLAG = '--rating';
|
|
65
69
|
export const BUG_FLAG = '--bug';
|
|
@@ -118,7 +122,7 @@ const KNOWN_COMMANDS = new Set([
|
|
|
118
122
|
]);
|
|
119
123
|
/** The subcommand name if we recognize it, else `unknown`. Bare `reticle` reports `help`. */
|
|
120
124
|
export function knownCommand(arg) {
|
|
121
|
-
if (arg === undefined ||
|
|
125
|
+
if (arg === undefined || '' === arg)
|
|
122
126
|
return 'help';
|
|
123
127
|
return KNOWN_COMMANDS.has(arg) ? arg : UNKNOWN_COMMAND;
|
|
124
128
|
}
|
|
@@ -128,25 +132,40 @@ export const HEADED_FLAG = '--headed';
|
|
|
128
132
|
* and every "did it actually do anything?" question cost a round-trip. CI passes this (or just sets
|
|
129
133
|
* CI, which flips the default) because there is no display there to be headed on.
|
|
130
134
|
*/
|
|
131
|
-
|
|
135
|
+
const HEADLESS_FLAG = '--headless';
|
|
132
136
|
export const PORT_FLAG = '--port';
|
|
133
137
|
export const DRIVE_FLAG = '--drive';
|
|
134
138
|
const QUIET_FLAG = '--quiet';
|
|
135
139
|
const DRY_RUN_FLAG = '--dry-run';
|
|
136
140
|
const YES_FLAG = '--yes';
|
|
137
141
|
const NO_MCP_FLAG = '--no-mcp';
|
|
142
|
+
const APP_FLAG = '--app';
|
|
138
143
|
const NO_INSTALL_FLAG = '--no-install';
|
|
139
144
|
export const HTTP_FLAG = '--http';
|
|
140
145
|
export const HTTP_PORT_FLAG = '--http-port';
|
|
141
146
|
export const HTTP_TOKEN_FLAG = '--http-token';
|
|
142
147
|
const TIMEOUT_FLAG = '--timeout';
|
|
143
148
|
const STORAGE_STATE_FLAG = '--storage-state';
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
+
});
|
|
150
169
|
function parseServeFlags(args, defaultPort, _defaultHeadless) {
|
|
151
170
|
let port = defaultPort;
|
|
152
171
|
let driveUrl;
|
|
@@ -157,21 +176,25 @@ function parseServeFlags(args, defaultPort, _defaultHeadless) {
|
|
|
157
176
|
let i = 0;
|
|
158
177
|
while (i < args.length) {
|
|
159
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;
|
|
160
183
|
if (arg === PORT_FLAG) {
|
|
161
184
|
i++;
|
|
162
185
|
const n = args[i];
|
|
163
186
|
if (n === undefined)
|
|
164
|
-
return
|
|
187
|
+
return missingValue(PORT_FLAG);
|
|
165
188
|
const parsed = parseInt(n, 10);
|
|
166
189
|
if (isNaN(parsed))
|
|
167
|
-
return
|
|
190
|
+
return notANumber(PORT_FLAG, n);
|
|
168
191
|
port = parsed;
|
|
169
192
|
}
|
|
170
193
|
else if (arg === DRIVE_FLAG) {
|
|
171
194
|
i++;
|
|
172
195
|
driveUrl = args[i];
|
|
173
196
|
if (driveUrl === undefined)
|
|
174
|
-
return
|
|
197
|
+
return missingValue(DRIVE_FLAG);
|
|
175
198
|
}
|
|
176
199
|
else if (arg === HEADED_FLAG) {
|
|
177
200
|
headless = false;
|
|
@@ -186,20 +209,20 @@ function parseServeFlags(args, defaultPort, _defaultHeadless) {
|
|
|
186
209
|
i++;
|
|
187
210
|
const n = args[i];
|
|
188
211
|
if (n === undefined)
|
|
189
|
-
return
|
|
212
|
+
return missingValue(HTTP_PORT_FLAG);
|
|
190
213
|
const parsed = parseInt(n, 10);
|
|
191
214
|
if (isNaN(parsed))
|
|
192
|
-
return
|
|
215
|
+
return notANumber(HTTP_PORT_FLAG, n);
|
|
193
216
|
httpPort = parsed;
|
|
194
217
|
}
|
|
195
218
|
else if (arg === HTTP_TOKEN_FLAG) {
|
|
196
219
|
i++;
|
|
197
220
|
httpToken = args[i];
|
|
198
221
|
if (httpToken === undefined)
|
|
199
|
-
return
|
|
222
|
+
return missingValue(HTTP_TOKEN_FLAG);
|
|
200
223
|
}
|
|
201
224
|
else {
|
|
202
|
-
return
|
|
225
|
+
return unknownArgument(arg);
|
|
203
226
|
}
|
|
204
227
|
i++;
|
|
205
228
|
}
|
|
@@ -215,7 +238,7 @@ function parseServeFlags(args, defaultPort, _defaultHeadless) {
|
|
|
215
238
|
}
|
|
216
239
|
function parsePortFlag(args, defaultPort) {
|
|
217
240
|
const idx = args.indexOf(PORT_FLAG);
|
|
218
|
-
if (
|
|
241
|
+
if (-1 === idx)
|
|
219
242
|
return defaultPort;
|
|
220
243
|
const n = args[idx + 1];
|
|
221
244
|
if (n === undefined)
|
|
@@ -234,17 +257,17 @@ function parseDriveSuffix(args, port, defaultHeadless) {
|
|
|
234
257
|
headless = true;
|
|
235
258
|
}
|
|
236
259
|
else if (arg.startsWith('--')) {
|
|
237
|
-
return
|
|
260
|
+
return unknownArgument(arg);
|
|
238
261
|
}
|
|
239
262
|
else if (driveUrl === undefined) {
|
|
240
263
|
driveUrl = arg;
|
|
241
264
|
}
|
|
242
265
|
else {
|
|
243
|
-
return
|
|
266
|
+
return unknownArgument(arg);
|
|
244
267
|
}
|
|
245
268
|
}
|
|
246
269
|
if (driveUrl === undefined)
|
|
247
|
-
return
|
|
270
|
+
return missingOperand(DRIVE_COMMAND, 'a url');
|
|
248
271
|
return { kind: 'ok', port, driveUrl, headless };
|
|
249
272
|
}
|
|
250
273
|
/**
|
|
@@ -268,32 +291,32 @@ function parseVerifySuffix(args) {
|
|
|
268
291
|
i++;
|
|
269
292
|
const n = args[i];
|
|
270
293
|
if (n === undefined)
|
|
271
|
-
return
|
|
294
|
+
return missingValue(TIMEOUT_FLAG);
|
|
272
295
|
const parsed = parseInt(n, 10);
|
|
273
296
|
if (isNaN(parsed))
|
|
274
|
-
return
|
|
297
|
+
return notANumber(TIMEOUT_FLAG, n);
|
|
275
298
|
timeoutMs = parsed;
|
|
276
299
|
}
|
|
277
300
|
else if (arg === STORAGE_STATE_FLAG) {
|
|
278
301
|
i++;
|
|
279
302
|
const v = args[i];
|
|
280
303
|
if (v === undefined)
|
|
281
|
-
return
|
|
304
|
+
return missingValue(STORAGE_STATE_FLAG);
|
|
282
305
|
storageState = v;
|
|
283
306
|
}
|
|
284
307
|
else if (arg.startsWith('--')) {
|
|
285
|
-
return
|
|
308
|
+
return unknownArgument(arg);
|
|
286
309
|
}
|
|
287
310
|
else if (url === undefined) {
|
|
288
311
|
url = arg;
|
|
289
312
|
}
|
|
290
313
|
else {
|
|
291
|
-
return
|
|
314
|
+
return unknownArgument(arg);
|
|
292
315
|
}
|
|
293
316
|
i++;
|
|
294
317
|
}
|
|
295
318
|
if (url === undefined)
|
|
296
|
-
return
|
|
319
|
+
return missingOperand(VERIFY_COMMAND, 'a url');
|
|
297
320
|
return {
|
|
298
321
|
kind: 'ok',
|
|
299
322
|
url,
|
|
@@ -307,19 +330,31 @@ function parseInitFlags(args) {
|
|
|
307
330
|
let mcp = true;
|
|
308
331
|
let dryRun = false;
|
|
309
332
|
let install = true;
|
|
333
|
+
let app;
|
|
310
334
|
let i = 0;
|
|
311
335
|
while (i < args.length) {
|
|
312
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;
|
|
313
341
|
if (arg === PORT_FLAG) {
|
|
314
342
|
i++;
|
|
315
343
|
const n = args[i];
|
|
316
344
|
if (n === undefined)
|
|
317
|
-
return
|
|
345
|
+
return missingValue(PORT_FLAG);
|
|
318
346
|
const parsed = parseInt(n, 10);
|
|
319
347
|
if (isNaN(parsed))
|
|
320
|
-
return
|
|
348
|
+
return notANumber(PORT_FLAG, n);
|
|
321
349
|
port = parsed;
|
|
322
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
|
+
}
|
|
323
358
|
else if (arg === NO_MCP_FLAG) {
|
|
324
359
|
mcp = false;
|
|
325
360
|
}
|
|
@@ -333,15 +368,29 @@ function parseInitFlags(args) {
|
|
|
333
368
|
// Accepted for scripting/CI; init has no interactive prompts today.
|
|
334
369
|
}
|
|
335
370
|
else {
|
|
336
|
-
return
|
|
371
|
+
return unknownArgument(arg);
|
|
337
372
|
}
|
|
338
373
|
i++;
|
|
339
374
|
}
|
|
340
|
-
return { kind: 'ok', port, mcp, dryRun, install };
|
|
375
|
+
return { kind: 'ok', port, mcp, dryRun, install, app };
|
|
341
376
|
}
|
|
342
377
|
/** Pure CLI arg parser — exported for unit tests. argv = process.argv.slice(2). */
|
|
343
378
|
const SINCE_FLAG = '--since';
|
|
344
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
|
+
}
|
|
345
394
|
function parseTargetArgs(rest) {
|
|
346
395
|
const files = [];
|
|
347
396
|
let since;
|
|
@@ -365,27 +414,37 @@ function parseTargetArgs(rest) {
|
|
|
365
414
|
*/
|
|
366
415
|
export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
367
416
|
// Bare `reticle` is `serve` — a pool-owning command, so headless like the rest of that family.
|
|
368
|
-
if (argv.length
|
|
417
|
+
if (0 === argv.length)
|
|
369
418
|
return { kind: 'serve', port: defaultPort, headless: true, http: false };
|
|
370
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 };
|
|
371
423
|
// `version` (or the conventional -v/--version flags) prints the running version — the diagnostic the
|
|
372
424
|
// troubleshooting docs lean on to confirm which npx-resolved build is actually executing.
|
|
373
|
-
if (cmd === VERSION_COMMAND ||
|
|
425
|
+
if (cmd === VERSION_COMMAND || '--version' === cmd || '-v' === cmd)
|
|
374
426
|
return { kind: 'version' };
|
|
375
427
|
// `help` (and the conventional -h/--help) print usage to stdout and exit 0 — the universal first move
|
|
376
428
|
// for a new user, which otherwise fell through to a JSON error with exit 1.
|
|
377
|
-
if (
|
|
429
|
+
if ('help' === cmd || '--help' === cmd || '-h' === cmd)
|
|
378
430
|
return { kind: 'help' };
|
|
379
431
|
switch (cmd) {
|
|
380
432
|
case INIT_COMMAND: {
|
|
381
433
|
const r = parseInitFlags(rest);
|
|
382
|
-
if (r.kind
|
|
434
|
+
if ('error' === r.kind)
|
|
383
435
|
return r;
|
|
384
|
-
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
|
+
};
|
|
385
444
|
}
|
|
386
445
|
case SERVE_COMMAND: {
|
|
387
446
|
const r = parseServeFlags(rest, defaultPort, defaultHeadless);
|
|
388
|
-
if (r.kind
|
|
447
|
+
if ('error' === r.kind)
|
|
389
448
|
return r;
|
|
390
449
|
return {
|
|
391
450
|
kind: 'serve',
|
|
@@ -424,7 +483,7 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
424
483
|
case IDENTIFY_COMMAND: {
|
|
425
484
|
const flag = (name) => {
|
|
426
485
|
const at = rest.indexOf(name);
|
|
427
|
-
return
|
|
486
|
+
return -1 === at ? undefined : rest[at + 1];
|
|
428
487
|
};
|
|
429
488
|
const context = flag(CONTEXT_FLAG);
|
|
430
489
|
const company = flag(COMPANY_FLAG);
|
|
@@ -439,13 +498,13 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
439
498
|
}
|
|
440
499
|
case FEEDBACK_COMMAND: {
|
|
441
500
|
const ratingAt = rest.indexOf(RATING_FLAG);
|
|
442
|
-
const rating =
|
|
501
|
+
const rating = -1 === ratingAt ? undefined : Number(rest[ratingAt + 1]);
|
|
443
502
|
if (rating !== undefined && (!Number.isInteger(rating) || rating < 1 || rating > 5)) {
|
|
444
503
|
return { kind: 'error', message: `${RATING_FLAG} takes a whole number from 1 to 5` };
|
|
445
504
|
}
|
|
446
505
|
// Everything that is not a flag or the rating's value is the message. Quoting is the user's
|
|
447
506
|
// job for shell reasons, but joining the remainder means an unquoted sentence still works.
|
|
448
|
-
const consumed = new Set(
|
|
507
|
+
const consumed = new Set(-1 === ratingAt ? [] : [ratingAt, ratingAt + 1]);
|
|
449
508
|
const text = rest
|
|
450
509
|
.filter((arg, i) => !consumed.has(i) && !arg.startsWith('--'))
|
|
451
510
|
.join(' ')
|
|
@@ -465,13 +524,13 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
465
524
|
}
|
|
466
525
|
case DRIVE_COMMAND: {
|
|
467
526
|
const r = parseDriveSuffix(rest, defaultPort, defaultHeadless);
|
|
468
|
-
if (r.kind
|
|
527
|
+
if ('error' === r.kind)
|
|
469
528
|
return r;
|
|
470
529
|
return { kind: 'drive', port: r.port, driveUrl: r.driveUrl, headless: r.headless };
|
|
471
530
|
}
|
|
472
531
|
case DAEMON_INNER_COMMAND: {
|
|
473
532
|
const r = parseServeFlags(rest, defaultPort, defaultHeadless);
|
|
474
|
-
if (r.kind
|
|
533
|
+
if ('error' === r.kind)
|
|
475
534
|
return r;
|
|
476
535
|
return {
|
|
477
536
|
kind: '_daemon',
|
|
@@ -485,7 +544,7 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
485
544
|
}
|
|
486
545
|
case VERIFY_COMMAND: {
|
|
487
546
|
const r = parseVerifySuffix(rest);
|
|
488
|
-
if (r.kind
|
|
547
|
+
if ('error' === r.kind)
|
|
489
548
|
return r;
|
|
490
549
|
return {
|
|
491
550
|
kind: 'verify',
|
|
@@ -505,21 +564,13 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
505
564
|
}
|
|
506
565
|
case AFFECTED_COMMAND: {
|
|
507
566
|
const t = parseTargetArgs(rest);
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}
|
|
511
|
-
return {
|
|
512
|
-
kind: 'affected',
|
|
513
|
-
files: t.files,
|
|
514
|
-
...(t.since === undefined ? {} : { since: t.since }),
|
|
515
|
-
};
|
|
567
|
+
const since = t.since ?? implicitSince(t.files);
|
|
568
|
+
return { kind: 'affected', files: t.files, ...(since === undefined ? {} : { since }) };
|
|
516
569
|
}
|
|
517
570
|
case GATE_COMMAND: {
|
|
518
571
|
const t = parseTargetArgs(rest);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
}
|
|
522
|
-
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 }) };
|
|
523
574
|
}
|
|
524
575
|
case WATCH_COMMAND: {
|
|
525
576
|
// `reticle watch [url]` — on file save, report which saved flows must re-verify.
|
|
@@ -532,7 +583,7 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
532
583
|
return { kind: 'rollback' };
|
|
533
584
|
case MCP_COMMAND: {
|
|
534
585
|
const r = parseServeFlags(rest, defaultPort, defaultHeadless);
|
|
535
|
-
if (r.kind
|
|
586
|
+
if ('error' === r.kind)
|
|
536
587
|
return r;
|
|
537
588
|
return {
|
|
538
589
|
kind: 'mcp',
|
|
@@ -545,6 +596,8 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
545
596
|
};
|
|
546
597
|
}
|
|
547
598
|
default:
|
|
548
|
-
|
|
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);
|
|
549
602
|
}
|
|
550
603
|
}
|
|
@@ -7,6 +7,18 @@
|
|
|
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>;
|
|
10
22
|
export declare function isLikelyDevServerPort(port: number): boolean;
|
|
11
23
|
/** The warning printed when a project pins the bridge to something that looks like its dev server. */
|
|
12
24
|
export declare function devServerPortWarning(port: number): string;
|
|
@@ -19,7 +19,7 @@ import { readFileSync } from 'node:fs';
|
|
|
19
19
|
* asked "what port does your dev server run on?" a few lines before showing this field, which is how
|
|
20
20
|
* the confusion got manufactured in the first place.
|
|
21
21
|
*/
|
|
22
|
-
const DEV_SERVER_PORTS = new Set([
|
|
22
|
+
export const DEV_SERVER_PORTS = new Set([
|
|
23
23
|
3000, 3001, 4200, 4321, 5000, 5173, 5174, 8000, 8080, 8100, 9000,
|
|
24
24
|
]);
|
|
25
25
|
export function isLikelyDevServerPort(port) {
|
|
@@ -37,9 +37,9 @@ export function readProjectPort(cwd) {
|
|
|
37
37
|
try {
|
|
38
38
|
const raw = readFileSync(`${cwd}/.reticle.json`, 'utf8');
|
|
39
39
|
const config = JSON.parse(raw);
|
|
40
|
-
if (typeof config
|
|
40
|
+
if ('object' === typeof config && config !== null) {
|
|
41
41
|
const p = config['port'];
|
|
42
|
-
if (typeof p
|
|
42
|
+
if ('number' === typeof p && Number.isInteger(p) && p > 0 && p < 65536)
|
|
43
43
|
return p;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -57,9 +57,9 @@ export function readProjectId(cwd) {
|
|
|
57
57
|
try {
|
|
58
58
|
const raw = readFileSync(`${cwd}/.reticle.json`, 'utf8');
|
|
59
59
|
const config = JSON.parse(raw);
|
|
60
|
-
if (typeof config
|
|
60
|
+
if ('object' === typeof config && config !== null) {
|
|
61
61
|
const id = config['projectId'];
|
|
62
|
-
if (typeof id
|
|
62
|
+
if ('string' === typeof id && id.length > 0)
|
|
63
63
|
return id;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -76,16 +76,16 @@ export function readProjectId(cwd) {
|
|
|
76
76
|
export function readJournalEnabled(cwd, env) {
|
|
77
77
|
if (env !== undefined) {
|
|
78
78
|
const v = env.trim().toLowerCase();
|
|
79
|
-
if (
|
|
79
|
+
if ('0' === v || 'false' === v || 'off' === v)
|
|
80
80
|
return false;
|
|
81
|
-
if (
|
|
81
|
+
if ('1' === v || 'true' === v || 'on' === v)
|
|
82
82
|
return true;
|
|
83
83
|
}
|
|
84
84
|
try {
|
|
85
85
|
const raw = readFileSync(`${cwd}/.reticle.json`, 'utf8');
|
|
86
86
|
const config = JSON.parse(raw);
|
|
87
|
-
if (typeof config
|
|
88
|
-
if (config['journal']
|
|
87
|
+
if ('object' === typeof config && config !== null) {
|
|
88
|
+
if (false === config['journal'])
|
|
89
89
|
return false;
|
|
90
90
|
}
|
|
91
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
|
+
}
|
|
@@ -12,18 +12,18 @@
|
|
|
12
12
|
import { join, basename } from 'node:path';
|
|
13
13
|
import { randomUUID } from 'node:crypto';
|
|
14
14
|
import { RETICLE_DEFAULT_PORT, ReticleEnv, bridgeWsUrl, isLoopbackHostname, ReticleDir, RunAgentKind, RunFramework, RunProfile, RunTrigger, VerdictStatus, } from '@reticlehq/core';
|
|
15
|
-
import { start } from '
|
|
16
|
-
import { resolveCloudConfig, syncRunToCloud, SyncOutcome } from '
|
|
17
|
-
import { ReticleRunner } from '
|
|
18
|
-
import { createRunnerPort } from '
|
|
19
|
-
import { RunStore } from '
|
|
20
|
-
import { renderRunReport } from '
|
|
21
|
-
import { BaselineStore } from '
|
|
22
|
-
import { RecordingStore } from '
|
|
23
|
-
import { FlowStore } from '
|
|
24
|
-
import { ProjectStore } from '
|
|
25
|
-
import { AnnotationStore } from '
|
|
26
|
-
import { createNodeFileSystem } from '
|
|
15
|
+
import { start } from '../index.js';
|
|
16
|
+
import { resolveCloudConfig, syncRunToCloud, SyncOutcome } from '../cloud/cloud-sync.js';
|
|
17
|
+
import { ReticleRunner } from '../runs/reticle-runner.js';
|
|
18
|
+
import { createRunnerPort } from '../runs/runner-port.js';
|
|
19
|
+
import { RunStore } from '../runs/run-store.js';
|
|
20
|
+
import { renderRunReport } from '../runs/render-report.js';
|
|
21
|
+
import { BaselineStore } from '../project/baselines.js';
|
|
22
|
+
import { RecordingStore } from '../flows/recordings.js';
|
|
23
|
+
import { FlowStore } from '../flows/flows.js';
|
|
24
|
+
import { ProjectStore } from '../project/project-store.js';
|
|
25
|
+
import { AnnotationStore } from '../flows/annotation-store.js';
|
|
26
|
+
import { createNodeFileSystem } from '../project/fs-port.js';
|
|
27
27
|
const EXIT_PASS = 0;
|
|
28
28
|
const EXIT_FAIL = 1;
|
|
29
29
|
const DEFAULT_SESSION_TIMEOUT_MS = 15_000;
|
|
@@ -63,7 +63,7 @@ export async function runVerify(args, ports) {
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
const names = await conn.listFlows();
|
|
66
|
-
if (names.length
|
|
66
|
+
if (0 === names.length) {
|
|
67
67
|
ports.fail(MSG_NO_FLOWS);
|
|
68
68
|
ports.exit(EXIT_FAIL);
|
|
69
69
|
return;
|
|
@@ -89,7 +89,7 @@ export async function runVerify(args, ports) {
|
|
|
89
89
|
*/
|
|
90
90
|
async function pushRunToCloud(run, ports) {
|
|
91
91
|
const config = resolveCloudConfig(process.env);
|
|
92
|
-
if (
|
|
92
|
+
if (null === config)
|
|
93
93
|
return;
|
|
94
94
|
const result = await syncRunToCloud(run, config, (url, init) => fetch(url, init));
|
|
95
95
|
if (result.outcome === SyncOutcome.SYNCED) {
|