@reticlehq/init 3.2.0 → 3.4.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.
Files changed (93) hide show
  1. package/dist/detect/capabilities.d.ts +4 -1
  2. package/dist/detect/capabilities.js +45 -9
  3. package/dist/detect/detect.d.ts +58 -4
  4. package/dist/detect/detect.js +117 -7
  5. package/dist/detect/dev-script.d.ts +26 -2
  6. package/dist/detect/dev-script.js +80 -7
  7. package/dist/detect/non-js-project.d.ts +1 -1
  8. package/dist/detect/non-js-project.js +6 -1
  9. package/dist/detect/workspace-apps.d.ts +21 -0
  10. package/dist/detect/workspace-apps.js +111 -12
  11. package/dist/detect/workspace-redirect.d.ts +2 -1
  12. package/dist/detect/workspace-redirect.js +28 -2
  13. package/dist/diagnose/containerised-dev-server.d.ts +12 -4
  14. package/dist/diagnose/containerised-dev-server.js +36 -4
  15. package/dist/diagnose/csp-check.d.ts +12 -6
  16. package/dist/diagnose/csp-check.js +61 -13
  17. package/dist/diagnose/csp-doctor.d.ts +33 -2
  18. package/dist/diagnose/csp-doctor.js +103 -6
  19. package/dist/diagnose/csp-step.d.ts +27 -0
  20. package/dist/diagnose/csp-step.js +86 -0
  21. package/dist/diagnose/desktop-doctor.d.ts +1 -1
  22. package/dist/diagnose/desktop-doctor.js +8 -2
  23. package/dist/diagnose/install-hint.d.ts +9 -1
  24. package/dist/diagnose/install-hint.js +17 -7
  25. package/dist/diagnose/install-retries.d.ts +18 -2
  26. package/dist/diagnose/install-retries.js +50 -3
  27. package/dist/diagnose/terminal-wrap.d.ts +18 -0
  28. package/dist/diagnose/terminal-wrap.js +63 -0
  29. package/dist/host.d.ts +6 -0
  30. package/dist/host.js +3 -0
  31. package/dist/index.d.ts +8 -3
  32. package/dist/index.js +8 -3
  33. package/dist/no-package-json.d.ts +10 -0
  34. package/dist/no-package-json.js +121 -0
  35. package/dist/node-io.d.ts +9 -5
  36. package/dist/node-io.js +25 -7
  37. package/dist/patch/angular.d.ts +68 -0
  38. package/dist/patch/angular.js +216 -0
  39. package/dist/patch/astro-patch.d.ts +48 -13
  40. package/dist/patch/astro-patch.js +151 -43
  41. package/dist/patch/cra.d.ts +0 -2
  42. package/dist/patch/cra.js +0 -2
  43. package/dist/patch/electron-patch.d.ts +10 -1
  44. package/dist/patch/electron-patch.js +79 -27
  45. package/dist/patch/electron-vite-patch.js +1 -1
  46. package/dist/patch/nuxt-patch.d.ts +1 -1
  47. package/dist/patch/nuxt-patch.js +2 -2
  48. package/dist/patch/nuxt-snippets.d.ts +44 -0
  49. package/dist/patch/nuxt-snippets.js +135 -0
  50. package/dist/patch/remix.d.ts +24 -0
  51. package/dist/patch/remix.js +59 -0
  52. package/dist/patch/snippets.d.ts +58 -57
  53. package/dist/patch/snippets.js +181 -202
  54. package/dist/patch/static-page.d.ts +39 -0
  55. package/dist/patch/static-page.js +102 -0
  56. package/dist/patch/tanstack-start.d.ts +36 -8
  57. package/dist/patch/tanstack-start.js +118 -29
  58. package/dist/patch/vite-config.d.ts +5 -0
  59. package/dist/patch/vite-config.js +8 -0
  60. package/dist/patch/vite-env-types.d.ts +9 -0
  61. package/dist/patch/vite-env-types.js +19 -0
  62. package/dist/patch/vite-owning-config.d.ts +47 -0
  63. package/dist/patch/vite-owning-config.js +104 -19
  64. package/dist/plan/connect-steps.d.ts +10 -3
  65. package/dist/plan/connect-steps.js +22 -3
  66. package/dist/plan/framework-adapter.d.ts +5 -6
  67. package/dist/plan/framework-adapter.js +105 -11
  68. package/dist/plan/notices.js +4 -3
  69. package/dist/plan/plan-angular.d.ts +6 -0
  70. package/dist/plan/plan-angular.js +89 -0
  71. package/dist/plan/plan-electron-vite.d.ts +6 -3
  72. package/dist/plan/plan-electron-vite.js +39 -8
  73. package/dist/plan/plan-framework.d.ts +9 -47
  74. package/dist/plan/plan-framework.js +114 -323
  75. package/dist/plan/plan-types.d.ts +47 -2
  76. package/dist/plan/plan-vite.d.ts +67 -0
  77. package/dist/plan/plan-vite.js +256 -0
  78. package/dist/plan/plan.js +155 -69
  79. package/dist/plan/port-steps.d.ts +45 -0
  80. package/dist/plan/port-steps.js +119 -0
  81. package/dist/plan/preflight.d.ts +17 -3
  82. package/dist/plan/preflight.js +53 -23
  83. package/dist/plan/stop-hook-step.d.ts +4 -0
  84. package/dist/plan/stop-hook-step.js +49 -0
  85. package/dist/project/agent-rules.js +2 -0
  86. package/dist/register/mcp-clients.d.ts +13 -0
  87. package/dist/register/mcp-clients.js +22 -0
  88. package/dist/register/mcp.d.ts +26 -5
  89. package/dist/register/mcp.js +64 -8
  90. package/dist/run-types.d.ts +10 -0
  91. package/dist/run.js +132 -78
  92. package/package.json +3 -4
  93. package/NOTICE +0 -5
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Remix v2's client entry, and the one honest answer for the classic compiler.
3
+ *
4
+ * Remix on Vite is React Router framework mode under its old name: it SSRs its own HTML, so the
5
+ * Vite plugin's `index.html` injection never reaches the page, and the connect has to come from
6
+ * `app/entry.client.tsx` — the same line, the same file, verified by hand to connect.
7
+ */
8
+ /**
9
+ * The client entry `init` writes when a Remix app has none.
10
+ *
11
+ * Like React Router's, `app/entry.client.tsx` is an OVERRIDE of a default Remix supplies — it only
12
+ * exists once somebody runs `remix reveal`. So the written file has to hydrate as well as connect:
13
+ * one holding only our import would replace the default with an app that renders nothing. This is
14
+ * Remix v2's own default entry with one line added.
15
+ */
16
+ export declare function remixEntryFile(): string;
17
+ /**
18
+ * The classic compiler has no Vite, so nothing serves `/@reticle-connect` and nothing stamps source.
19
+ *
20
+ * Said plainly and left as a ⚠ rather than papered over: writing the entry line here would import a
21
+ * module no dev server serves, and the app would log a failed import on every page load instead of
22
+ * connecting.
23
+ */
24
+ export declare const REMIX_CLASSIC_MANUAL = "This is Remix on the classic compiler (remix.config.js, no Vite), and Reticle cannot wire it:\nthe connect module and the source stamping both come from @reticlehq/vite-plugin, and this build\nnever runs Vite.\n\n \u2022 Recommended: move to Remix's Vite plugin (https://remix.run/docs/en/main/guides/vite), or on to\n React Router v7+ framework mode, then re-run `reticle init` \u2014 both are wired automatically.\n \u2022 Or connect by hand from app/entry.client.tsx, dev-only, through the React kit init installed:\n\n if (process.env.NODE_ENV === 'development') {\n void import('@reticlehq/react').then(({ reticle, install }) => {\n install();\n reticle.connect({ token: '<the contents of ~/.reticle/pairing-token>' });\n });\n }\n\n The token is per-machine: keep it out of version control.";
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Remix v2's client entry, and the one honest answer for the classic compiler.
3
+ *
4
+ * Remix on Vite is React Router framework mode under its old name: it SSRs its own HTML, so the
5
+ * Vite plugin's `index.html` injection never reaches the page, and the connect has to come from
6
+ * `app/entry.client.tsx` — the same line, the same file, verified by hand to connect.
7
+ */
8
+ import { REACT_ROUTER_CONNECT_LINE } from './snippets.js';
9
+ /**
10
+ * The client entry `init` writes when a Remix app has none.
11
+ *
12
+ * Like React Router's, `app/entry.client.tsx` is an OVERRIDE of a default Remix supplies — it only
13
+ * exists once somebody runs `remix reveal`. So the written file has to hydrate as well as connect:
14
+ * one holding only our import would replace the default with an app that renders nothing. This is
15
+ * Remix v2's own default entry with one line added.
16
+ */
17
+ export function remixEntryFile() {
18
+ return `import { RemixBrowser } from '@remix-run/react';
19
+ import { startTransition, StrictMode } from 'react';
20
+ import { hydrateRoot } from 'react-dom/client';
21
+
22
+ // Dev-only: Remix renders HTML through its own request handler, so the Vite plugin's index.html
23
+ // injection never fires and the connect script never reaches the page. The plugin is still doing
24
+ // the other half of the job — it stamps data-reticle-source, which puts file:line on every verdict.
25
+ ${REACT_ROUTER_CONNECT_LINE}
26
+
27
+ startTransition(() => {
28
+ hydrateRoot(
29
+ document,
30
+ <StrictMode>
31
+ <RemixBrowser />
32
+ </StrictMode>,
33
+ );
34
+ });
35
+ `;
36
+ }
37
+ /**
38
+ * The classic compiler has no Vite, so nothing serves `/@reticle-connect` and nothing stamps source.
39
+ *
40
+ * Said plainly and left as a ⚠ rather than papered over: writing the entry line here would import a
41
+ * module no dev server serves, and the app would log a failed import on every page load instead of
42
+ * connecting.
43
+ */
44
+ export const REMIX_CLASSIC_MANUAL = `This is Remix on the classic compiler (remix.config.js, no Vite), and Reticle cannot wire it:
45
+ the connect module and the source stamping both come from @reticlehq/vite-plugin, and this build
46
+ never runs Vite.
47
+
48
+ • Recommended: move to Remix's Vite plugin (https://remix.run/docs/en/main/guides/vite), or on to
49
+ React Router v7+ framework mode, then re-run \`reticle init\` — both are wired automatically.
50
+ • Or connect by hand from app/entry.client.tsx, dev-only, through the React kit init installed:
51
+
52
+ if (process.env.NODE_ENV === 'development') {
53
+ void import('@reticlehq/react').then(({ reticle, install }) => {
54
+ install();
55
+ reticle.connect({ token: '<the contents of ~/.reticle/pairing-token>' });
56
+ });
57
+ }
58
+
59
+ The token is per-machine: keep it out of version control.`;
@@ -2,8 +2,34 @@
2
2
  * Generated file contents and copy-paste snippets for `reticle init`. Kept as named constants/builders
3
3
  * so the runner never inlines free strings.
4
4
  */
5
- import { UiLibrary } from '../detect/detect.js';
5
+ import { Framework, UiLibrary } from '../detect/detect.js';
6
6
  import type { FoundStore } from '../detect/capabilities.js';
7
+ /**
8
+ * The SDK as one import a plain page can actually resolve.
9
+ *
10
+ * `init` used to tell static-HTML users that a page with no build step could not load the SDK, and
11
+ * to go and stand up a bundler. That is true of a BARE specifier and false of a URL, and the
12
+ * difference was the whole road for every server-rendered app we hear from: FastAPI, Flask, Django,
13
+ * Streamlit, Rails. Proven end to end before this shipped, on a page served by `python3 -m
14
+ * http.server`: a session connected, a snapshot returned, and two act_and_wait calls came back
15
+ * `verified: "yes"`.
16
+ *
17
+ * jsDelivr rather than esm.sh, measured: a third of the requests and a third of the bytes for the
18
+ * same result. `/+esm` is what makes it work, and the bare package URL does NOT: every file in
19
+ * `dist` still carries bare workspace specifiers such as `@reticlehq/core`, so an unbundled entry
20
+ * point dies on the first import. That is also why adding `unpkg`/`jsdelivr` fields to package.json
21
+ * would not help.
22
+ *
23
+ * PINNED to this server's version on purpose. A floating import upgrades the page SDK underneath a
24
+ * daemon that did not move, which is `version_skew` arriving by a route nothing checks.
25
+ */
26
+ /**
27
+ * Where a generated file sends someone to learn `registerStore`. A URL, not a path into
28
+ * `node_modules/@reticlehq/server`: the server is never installed into the app, so the path the
29
+ * generated files used to name did not exist in any project they were written into.
30
+ */
31
+ export declare const STATE_DOCS_URL = "https://docs.reticle.sh/state-management";
32
+ export declare const CDN_SDK_URL: string;
7
33
  /**
8
34
  * The connect argument literal: a non-default port adds a `url`, and a projectId is always passed
9
35
  * (so the app is identifiable across port changes). Empty string only when neither applies.
@@ -22,6 +48,7 @@ export declare function connectArg(port: number | undefined, projectId?: string)
22
48
  * one that does hold a token.
23
49
  */
24
50
  export declare function connectArgWithToken(port: number | undefined, projectId: string | undefined, pairingToken: string | undefined): string;
51
+ export declare function usesReactKit(uiLibrary: UiLibrary, framework?: Framework): boolean;
25
52
  /**
26
53
  * Which SDK package the GENERATED code should import, and whether `install()` applies.
27
54
  *
@@ -33,7 +60,7 @@ export declare function connectArgWithToken(port: number | undefined, projectId:
33
60
  * `install()` is the React adapter's, not the sensor's: `@reticlehq/browser` exports `reticle` and no
34
61
  * `install`, so swapping the specifier alone would trade a missing module for a missing export.
35
62
  */
36
- export declare function sdkImport(uiLibrary: UiLibrary): {
63
+ export declare function sdkImport(uiLibrary: UiLibrary, framework?: Framework): {
37
64
  specifier: string;
38
65
  usesInstall: boolean;
39
66
  };
@@ -42,8 +69,11 @@ export declare function viteManual(port: number | undefined, uiLibrary?: UiLibra
42
69
  /**
43
70
  * The electron-vite recipe: the plugin belongs in `renderer`, never in `main` or `preload`.
44
71
  *
45
- * `desktop: true` is load-bearing. Without it the plugin is serve-only, so a packaged renderer
46
- * (a production build with no dev server) ships with no connect() at all.
72
+ * `desktop: true` is load-bearing: it injects connect() into the entry module and passes
73
+ * `allowInProduction`, because a packaged renderer has no dev server and reports
74
+ * `NODE_ENV=production`, so without it the SDK's production backstop refuses to start. It does not
75
+ * instrument a release — a production-mode `electron-vite build` is stubbed like a web bundle — so
76
+ * a packaged renderer that should be driven is built with `--mode development`.
47
77
  */
48
78
  export declare function electronViteManual(port: number | undefined, uiLibrary?: UiLibrary): string;
49
79
  /** Next.js config wrap — always printed (we never auto-rewrite next.config). */
@@ -89,9 +119,14 @@ export declare function registerCapabilitiesCall(testids: readonly string[], ind
89
119
  * breaks the module everything else hangs off. So the store lines are generated COMMENTED, naming
90
120
  * the libraries actually found in package.json, with the exact call to uncomment.
91
121
  */
92
- export declare function viteDevModuleFile(testids: readonly string[], stores: readonly string[], found?: readonly FoundStore[], uiLibrary?: UiLibrary): string;
122
+ export declare function viteDevModuleFile(testids: readonly string[], stores: readonly string[], found?: readonly FoundStore[], uiLibrary?: UiLibrary, framework?: Framework): string;
93
123
  /** Where that module goes. Matches @reticlehq/vite-plugin's convention list. */
94
124
  export declare const VITE_DEV_MODULE_PATH = "src/reticle-dev.ts";
125
+ /**
126
+ * The dev module as a relative import from `fromFile` — for the frameworks that connect themselves
127
+ * and so have to load it themselves (see svelteKitHooksFile, tanstackStartConnectFile).
128
+ */
129
+ export declare function devModuleSpecifier(fromFile: string): string;
95
130
  /**
96
131
  * electron-vite's renderer Vite root is `src/renderer`, so the plugin looks for
97
132
  * `src/renderer/src/reticle-dev.ts` — not the package-root path a plain Vite app uses.
@@ -137,7 +172,7 @@ export declare function streamlitPageSnippet(connectArgLiteral: string): string;
137
172
  * `<head>`, so the SDK sees a parsed document.
138
173
  */
139
174
  export declare function djangoMiddlewareSnippet(connectArgLiteral: string): string;
140
- export declare function htmlManual(port: number | undefined, projectId?: string, pairingToken?: string): string;
175
+ export declare function htmlManual(port: number | undefined, projectId?: string, pairingToken?: string, uiLibrary?: UiLibrary): string;
141
176
  export declare const NEXT_RETICLE_DEV_PATH = "app/reticle-dev.tsx";
142
177
  export declare const SVELTEKIT_HOOKS_PATH = "src/hooks.client.ts";
143
178
  /**
@@ -146,9 +181,9 @@ export declare const SVELTEKIT_HOOKS_PATH = "src/hooks.client.ts";
146
181
  * component names and source mapping do not, and no CI gate covers this stack. Saying so beats
147
182
  * reporting all-green.
148
183
  */
149
- export declare function unverifiedUiLibraryNote(library: string): string;
150
- export declare const UNVERIFIED_FRAMEWORK_NOTE = "Reticle has no SvelteKit app and no CI gate for one, so this wiring is untested \u2014 it may work, but nothing proves it and nothing will tell us if it breaks. Supported and gated today: Vite + React, Next.js, Remix and Astro. If the hook does not register a session, please open an issue.";
151
- export declare const UNVERIFIED_TANSTACK_START_NOTE = "Reticle has no TanStack Start app and no CI gate for one, so this wiring is untested \u2014 it may work, but nothing proves it and nothing will tell us if it breaks. Supported and gated today: Vite + React, Next.js, Remix and Astro. If the client effect does not register a session, please open an issue.";
184
+ export declare function unverifiedUiLibraryNote(library: string, installGated?: boolean): string;
185
+ export declare const SVELTEKIT_SETUP_GATED_NOTE = "The install gate scaffolds a SvelteKit app on every release and requires this hook to connect a session, so the wiring is proven; driving flows on SvelteKit to a verdict is not. If the hook does not register a session, please open an issue.";
186
+ export declare const UNVERIFIED_TANSTACK_START_NOTE = "Reticle has no TanStack Start app and no CI gate for one, so this wiring is untested \u2014 it may work, but nothing proves it and nothing will tell us if it breaks. Gated today: Vite (React, Vue), Next.js, Nuxt, React Router, Remix, Astro, SvelteKit, Create React App and Angular. If the client effect does not register a session, please open an issue.";
152
187
  /**
153
188
  * Printed when init detects react-three-fiber. Reticle's model is DOM + store + network; a WebGL
154
189
  * canvas is none of those. Without this line, init succeeds, sessions connect, and surrounding UI
@@ -181,8 +216,19 @@ export declare const WEBPACK4_REACT_SCRIPTS_MAJOR = 5;
181
216
  export declare function webpack4TranspileNote(reactScriptsMajor: number): string;
182
217
  /** React Router's client-entry override point, in framework mode. */
183
218
  export declare const REACT_ROUTER_ENTRY_PATH = "app/entry.client.tsx";
184
- /** The one line that puts Reticle in a React Router client entry. */
185
- export declare const REACT_ROUTER_CONNECT_LINE = "if (import.meta.env.DEV) void import('/@reticle-connect');";
219
+ /**
220
+ * The one line that puts Reticle in a React Router client entry — and in a Remix one.
221
+ *
222
+ * The specifier is BUILT, not written as a literal. `import('/@reticle-connect')` is a module only
223
+ * the Vite dev server can answer, so `tsc` cannot resolve it: a fresh framework-mode scaffold went
224
+ * red on `npm run typecheck` (`TS2307: Cannot find module '/@reticle-connect'`) the moment `init`
225
+ * wrote it. A computed specifier is typed `Promise<any>` and never resolved, so no declaration, no
226
+ * suppression comment and no tsconfig edit is needed. The browser still asks the dev server for the
227
+ * same URL, which the plugin serves; `BASE_URL` keeps it right under a non-root `base`. `@vite-ignore`
228
+ * is Vite's own marker for a dynamic import it should not try to analyse, not a lint suppression. In
229
+ * a production build `import.meta.env.DEV` is false and the whole line is dropped.
230
+ */
231
+ export declare const REACT_ROUTER_CONNECT_LINE = "if (import.meta.env.DEV) void import(/* @vite-ignore */ `${import.meta.env.BASE_URL}@reticle-connect`);";
186
232
  /**
187
233
  * The client entry `init` writes when React Router framework mode has none.
188
234
  *
@@ -204,52 +250,7 @@ export declare function reactRouterEntryFile(): string;
204
250
  * still be evaluated first, and this is a side-effect import.
205
251
  */
206
252
  export declare function reactRouterEntryPatch(source: string): string | null;
207
- /** Where a Nuxt dev-only client plugin belongs. `.client` keeps it out of SSR; Nuxt auto-registers it. */
208
- export declare const NUXT_PLUGIN_PATH = "app/plugins/reticle.client.ts";
209
- /**
210
- * The plugin directory Nuxt actually scans, which is not the same on 3 and 4.
211
- *
212
- * Nuxt 4's default `srcDir` is `app/`, so plugins live in `app/plugins/`. Nuxt 3's is the project
213
- * root, so they live in `plugins/`. Writing to the wrong one is the silent failure this whole change
214
- * exists to remove: the file is on disk, `init` reports it green, Nuxt never scans that directory,
215
- * and no plugin is ever registered. Keyed on whether the app HAS an `app/` directory, which is the
216
- * same signal Nuxt itself uses to pick its srcDir.
217
- */
218
- export declare function nuxtPluginPath(hasAppDir: boolean): string;
219
- /**
220
- * The dev-only Nuxt client plugin `init` writes.
221
- *
222
- * Every trap in it is one somebody actually hit. `import.meta.dev` rather than a hostname check: the
223
- * reported failure was a snippet guarded on `window.location.hostname === 'localhost'`, which is
224
- * false on any hosts-file alias or LAN address and throws during SSR, so the connect never ran with
225
- * no error and no log line. `.client.ts` rather than an SSR guard, because that suffix is what keeps
226
- * this out of the server bundle. `@reticlehq/browser` rather than the React kit, because installing
227
- * a package named `@reticlehq/react` into a Vue codebase is the single thing most likely to make
228
- * somebody abandon the setup.
229
- *
230
- * The token is inlined by `nuxt.config`'s `vite.define` (see nuxt-patch.ts). The bridge requires it
231
- * even on localhost, and nothing in a browser can read the file it lives in.
232
- */
233
- export declare function nuxtPluginFile(port: number | undefined, projectId?: string, testids?: readonly string[]): string;
234
- /**
235
- * Said as its own NOTICE beside the write, not inside it: a running dev server does not pick up a
236
- * new plugin, and off localhost the connect needs two more arguments.
237
- *
238
- * A ✓ line is one SKILL.md tells the reader to skip, so a caveat carried on the ✓ is a caveat nobody
239
- * reads — and both of these end with an app that boots, looks correct and never pairs.
240
- */
241
- export declare const NUXT_PLUGIN_NOTICE: string;
242
- /**
243
- * The Nuxt recipe, written out in full because each trap in it is one a Nuxt 4 app actually hit:
244
- * a Vue codebase classified as `html` and handed `@reticlehq/react`, a connect guarded on
245
- * `window.location.hostname === 'localhost'` (false on any hosts-file alias, and `window` does not
246
- * exist during SSR), and a running dev server that never picked up the new plugin.
247
- *
248
- * So: `import.meta.dev` instead of a hostname check, `.client.ts` instead of an SSR guard, the
249
- * framework-neutral sensor instead of the React kit, the non-localhost flag named up front, and the
250
- * restart said out loud.
251
- */
252
- export declare function nuxtManual(port: number | undefined, projectId?: string): string;
253
+ export { nuxtPluginPath, nuxtPluginFile, NUXT_PLUGIN_NOTICE, nuxtManual } from './nuxt-snippets.js';
253
254
  /**
254
255
  * Root-level project config for Reticle. Written by `reticle init`; read by `reticle mcp` for the port
255
256
  * and by tooling for the stable projectId (the app's identity across port changes).