@reticlehq/server 3.10.0 → 3.10.1

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.
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
- import { InitConfirmation, OnboardingPhase, OnboardingStop, RETICLE_DEFAULT_PORT, } from '@reticlehq/core';
10
+ import { InitConfirmation, InitStop, OnboardingPhase, OnboardingStop, RETICLE_DEFAULT_PORT, } from '@reticlehq/core';
11
11
  import { COMMUNITY_HINT, FEEDBACK_HINT, Framework, InitFailure, } from '@reticlehq/init';
12
12
  import { confirmInstall, nodeConfirmDeps } from '../terminal/confirm.js';
13
13
  import { writeLicenseKey } from '../license-key.js';
@@ -85,6 +85,11 @@ function printRelaunch(parsed, io, cwd) {
85
85
  }).message);
86
86
  io.print('');
87
87
  }
88
+ /** The dev-server stops caused by the machine, not the app: the files init wrote are right. */
89
+ const WIRED_WHEN_STOPPED_AT = new Set([
90
+ InitStop.PORT_BUSY,
91
+ InitStop.SPLIT_LOOPBACK,
92
+ ]);
88
93
  export async function continueAfterInit(parsed, result, io, cwd,
89
94
  /** init's ending once the connection is proved: coverage and the agent prompt. See `FirstFlowPort`. */
90
95
  firstFlow, agentsBlock) {
@@ -256,6 +261,14 @@ firstFlow, agentsBlock) {
256
261
  : { pendingViteConfig: context.pendingViteConfig }),
257
262
  }, (line) => io.print(line))
258
263
  .then(async (outcome) => {
264
+ // The files are written before the app starts. When the app could not be reached for a reason
265
+ // of the machine, not of the app (its port was taken, or it answered on one loopback address
266
+ // and not the other), the project is wired and not confirmed yet: not a failed install.
267
+ // A dev server that exits, hangs or does not exist, and a failure to connect, still fail.
268
+ const wiredNotStarted = !outcome.ok &&
269
+ outcome.reachedPhase === SetupPhase.DEV_SERVER &&
270
+ undefined !== outcome.stop &&
271
+ WIRED_WHEN_STOPPED_AT.has(outcome.stop);
259
272
  if (result.outcome !== undefined) {
260
273
  const init = {
261
274
  ...result.outcome,
@@ -265,6 +278,14 @@ firstFlow, agentsBlock) {
265
278
  delete init.reason;
266
279
  init.confirmation = InitConfirmation.CONNECTED;
267
280
  }
281
+ else if (wiredNotStarted) {
282
+ init.ok = true;
283
+ delete init.reason;
284
+ init.confirmation = InitConfirmation.DEV_SERVER_NOT_STARTED;
285
+ if (outcome.stop !== undefined) {
286
+ init.stop = outcome.stop;
287
+ }
288
+ }
268
289
  else {
269
290
  // A failed startup does not establish whether a daemon or instrumented page exists.
270
291
  // Keep the watcher's no_daemon/no_session/no_page classifications for observed facts.
@@ -281,7 +302,11 @@ firstFlow, agentsBlock) {
281
302
  }
282
303
  // One object, so an agent reads a result instead of interpreting a report.
283
304
  if (true === parsed.json) {
284
- process.stdout.write(`${JSON.stringify(outcome, null, 2)}\n`);
305
+ const answer = wiredNotStarted ? { ...outcome, ok: true, confirmed: false } : outcome;
306
+ process.stdout.write(`${JSON.stringify(answer, null, 2)}\n`);
307
+ if (wiredNotStarted) {
308
+ return;
309
+ }
285
310
  if (!outcome.ok) {
286
311
  stop();
287
312
  }
@@ -334,6 +359,16 @@ firstFlow, agentsBlock) {
334
359
  io.print(COMMUNITY_HINT);
335
360
  return;
336
361
  }
362
+ if (wiredNotStarted) {
363
+ io.print('✓ Reticle is wired into this app. Its dev server did not start, so the connection is not ' +
364
+ 'confirmed yet. To confirm it:');
365
+ for (const [i, step] of outcome.fallback.entries()) {
366
+ io.print(` ${String(i + 1)}. ${step}`);
367
+ }
368
+ io.print(` ${String(outcome.fallback.length + 1)}. Run \`reticle status\`: it lists the app when it connects.`);
369
+ ask();
370
+ return;
371
+ }
337
372
  // A run that produced no verdict did not succeed, and the exit code is the one place a caller
338
373
  // reads that without parsing anything.
339
374
  io.print('⚠ setup did not finish. To carry on from here:');
package/docs/cli/init.mdx CHANGED
@@ -122,8 +122,8 @@ In the two captures above, the punctuation that separates the two halves of the
122
122
 
123
123
  | Code | Meaning |
124
124
  | --- | --- |
125
- | `0` | The app connected. Steps marked `⚠` still need a hand, and do not change the code |
126
- | `1` | No session connected, init failed, an unknown flag was passed, or several apps were found and none was chosen |
125
+ | `0` | The app connected. Or the files are written and the machine kept the dev server from starting (its port was taken, or it answered on one loopback address only): init prints the steps to confirm the connection (`--json` answers `"confirmed": false`). Steps marked `⚠` still need a hand, and do not change the code |
126
+ | `1` | The dev server exited, hung or does not exist, a running app did not connect, init failed, an unknown flag was passed, or several apps were found and none was chosen |
127
127
 
128
128
  An unknown flag is rejected by name: `reticle init --bogus` prints `unknown argument '--bogus'`, then the short usage (`reticle --help`), and exits `1`.
129
129
 
@@ -70,7 +70,7 @@ jobs:
70
70
  runs-on: ubuntu-latest
71
71
  steps:
72
72
  - uses: actions/checkout@v4
73
- - uses: reticlehq/reticle/action@v3.10.0
73
+ - uses: reticlehq/reticle/action@v3.10.1
74
74
  with:
75
75
  api-key: ${{ secrets.RETICLE_API_KEY }}
76
76
  # Only for a Vercel preview behind Deployment Protection.
package/docs/skill.md CHANGED
@@ -3,7 +3,7 @@ name: reticle-docs
3
3
  description: Install, instrument and verify this running web app from the inside (DOM, network, routing, console and framework state) instead of screenshots or guessing. Drives one real flow end to end and returns a verdict with the file:line to fix. Use when the user asks to set up or install Reticle, when a user-facing change needs proving before you call it done, when a test passes but the UI is broken, or when the user types /reticle.
4
4
  license: Apache-2.0
5
5
  metadata:
6
- version: 3.10.0
6
+ version: 3.10.1
7
7
  homepage: https://docs.reticle.sh
8
8
  repository: https://github.com/reticlehq/reticle
9
9
  internal: true
@@ -11,6 +11,35 @@ Reticle is a verification layer that runs a dev-only SDK inside your running web
11
11
 
12
12
  Most of these were hit while writing these docs. The diagnostics quoted are real output.
13
13
 
14
+ ## Quick fixes
15
+
16
+ | What you see | Why | Fix |
17
+ | --- | --- | --- |
18
+ | Agent says the `reticle_*` tools do not exist | It read its tool list before Reticle was installed | Restart the agent once. Mid-conversation: `reticle init --relaunch` prints the resume command |
19
+ | "no browser session connected" | The dev server was already running when `init` edited the build config, so it serves a bundle without the SDK | Restart the dev server and hard-reload the tab |
20
+ | Browser console: `[Reticle] this page could not open a websocket to …` | The app and Reticle disagree on the port | `RETICLE_PORT=4400 npm run dev` (Vite plugin), `reticle({ port: 4400 })` in `vite.config`, or `reticle.connect({ url: 'ws://localhost:4400/reticle' })` by hand |
21
+ | `init` stops with "Several apps found" | A monorepo | Rerun with the `reticle init --app <dir>` line it printed |
22
+ | Codex does not see the tools | The `codex` command was not on PATH, so the installer could not run `codex mcp add` | `codex mcp add reticle -- npx @reticlehq/server mcp`, or add the block from [Manual install](/install-manual#codex-cli) to `~/.codex/config.toml` |
23
+ | `reticle: command not found` | npm's global bin is not on your PATH | `export PATH="$(npm prefix -g)/bin:$PATH"`, or use `npx @reticlehq/server …` |
24
+ | Anything else | | `reticle doctor` checks the browser, the background service and the port in one go, and names the fix |
25
+
26
+ Still stuck? `reticle feedback "what happened"` reaches us directly and prints exactly what it sends. Or ask in [Discord](https://discord.gg/BwAbzv9ZRz).
27
+
28
+ <details>
29
+ <summary><b>Installing with an AI agent? The rules it should follow</b></summary>
30
+
31
+ <br />
32
+
33
+ The full agent guide is [SKILL.md](https://github.com/reticlehq/reticle/blob/main/SKILL.md). These are the rules that matter most during install:
34
+
35
+ - `init` changes the user's files. Run it only when the user asked to set up Reticle, or agreed when you offered. Run it in the app's folder. Use `reticle init --json`, so you read one object instead of parsing text. Add `--app <dir>` in a monorepo, and `--env KEY=VALUE` for anything the app needs to start.
36
+ - If the dev server was already running when `init` ran, restart it and reload the tab. Until you do, the app serves a bundle without the SDK.
37
+ - Run `reticle connect` only if the user asked for the dashboard. A person must approve the sign-in in a browser.
38
+ - If the `reticle_*` tools are not in your client, ask the user to run the installer and restart the client. Then stop. If the tools were registered while you were running, `reticle init --relaunch` prints the command that resumes this conversation with them loaded.
39
+ - A session listed means the SDK reached the page. Setup is finished when the first run returns a verdict.
40
+ - `unknown` is not a pass. Report it as "cannot tell", with the reason Reticle gives.
41
+ - Stuck? Run `reticle doctor` and report what it says. To report a problem with Reticle, run `reticle feedback --agent --kind bug "…"`.
42
+
14
43
  ## Start here
15
44
 
16
45
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reticlehq/server",
3
- "version": "3.10.0",
3
+ "version": "3.10.1",
4
4
  "mcpName": "io.github.reticlehq/reticle",
5
5
  "description": "Reticle CLI, bridge and MCP server: a coding agent drives your running web app from the inside and gets a verdict with evidence, for change verification, access control, accessibility, performance and SEO checks.",
6
6
  "type": "module",
@@ -23,11 +23,11 @@
23
23
  "@modelcontextprotocol/sdk": "^1.32.2",
24
24
  "ws": "^8.22.1",
25
25
  "zod": "^4.6.6",
26
- "@reticlehq/browser": "3.10.0",
27
- "@reticlehq/init": "3.10.0",
28
- "@reticlehq/core": "3.10.0",
29
- "@reticlehq/engine": "3.10.0",
30
- "open-verification": "1.1.0"
26
+ "@reticlehq/browser": "3.10.1",
27
+ "@reticlehq/init": "3.10.1",
28
+ "open-verification": "1.1.0",
29
+ "@reticlehq/engine": "3.10.1",
30
+ "@reticlehq/core": "3.10.1"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/pngjs": "^6.0.5",
@@ -65,11 +65,8 @@
65
65
  "cli"
66
66
  ],
67
67
  "reticle": {
68
- "changelog": "3.10.0 checks every change against what worked before. reticle compare and verify --against list what users would see change between two builds, and reticle grade grades a finished run from the app's stored data. Several false verdicts are fixed, most of them text checks that answered no for text that was on the page. An agent in a Claude Code worktree now reaches its own tab. Update the CLI and the SDK in your app.",
69
- "breakingChanges": [
70
- "The commands kill, login, link, project, whoami, push, regression, share, issues and memory are removed. Each prints the command that replaces it and exits 1. See MIGRATION.md.",
71
- "The MCP tools reticle_explore and reticle_replay left the tool surface. Use reticle_look { action: \"page\", mode: \"interactive\" } and reticle_record { action: \"replay\" }."
72
- ]
68
+ "changelog": "3.10.1 fixes reticle init on a busy machine. When the dev server could not start because its port was taken, or the app answered on one loopback address only, init reported a failed install although the project was wired. Now it says Reticle is wired, prints the steps to confirm the connection, and exits 0.",
69
+ "breakingChanges": []
73
70
  },
74
71
  "publishConfig": {
75
72
  "access": "public"