@reticlehq/init 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/LICENSE +105 -0
  2. package/NOTICE +5 -0
  3. package/README.md +29 -0
  4. package/dist/agent-rules.d.ts +116 -0
  5. package/dist/agent-rules.js +279 -0
  6. package/dist/app-choice.d.ts +29 -0
  7. package/dist/app-choice.js +39 -0
  8. package/dist/astro-host.d.ts +21 -0
  9. package/dist/astro-host.js +27 -0
  10. package/dist/astro-patch.d.ts +33 -0
  11. package/dist/astro-patch.js +103 -0
  12. package/dist/brace-scan.d.ts +24 -0
  13. package/dist/brace-scan.js +46 -0
  14. package/dist/capabilities.d.ts +40 -0
  15. package/dist/capabilities.js +167 -0
  16. package/dist/closing-hint.d.ts +35 -0
  17. package/dist/closing-hint.js +122 -0
  18. package/dist/codex-toml.d.ts +10 -0
  19. package/dist/codex-toml.js +144 -0
  20. package/dist/connect-steps.d.ts +55 -0
  21. package/dist/connect-steps.js +92 -0
  22. package/dist/cra.d.ts +82 -0
  23. package/dist/cra.js +183 -0
  24. package/dist/csp-check.d.ts +49 -0
  25. package/dist/csp-check.js +168 -0
  26. package/dist/csp-doctor.d.ts +32 -0
  27. package/dist/csp-doctor.js +62 -0
  28. package/dist/desktop-doctor.d.ts +46 -0
  29. package/dist/desktop-doctor.js +201 -0
  30. package/dist/detect.d.ts +225 -0
  31. package/dist/detect.js +334 -0
  32. package/dist/dev-script.d.ts +51 -0
  33. package/dist/dev-script.js +66 -0
  34. package/dist/dev-server-ports.d.ts +20 -0
  35. package/dist/dev-server-ports.js +45 -0
  36. package/dist/electron-patch.d.ts +11 -0
  37. package/dist/electron-patch.js +70 -0
  38. package/dist/electron-vite-patch.d.ts +12 -0
  39. package/dist/electron-vite-patch.js +100 -0
  40. package/dist/existing-config.d.ts +31 -0
  41. package/dist/existing-config.js +63 -0
  42. package/dist/format-generated.d.ts +18 -0
  43. package/dist/format-generated.js +48 -0
  44. package/dist/framework-adapter.d.ts +60 -0
  45. package/dist/framework-adapter.js +138 -0
  46. package/dist/host.d.ts +41 -0
  47. package/dist/host.js +21 -0
  48. package/dist/index.d.ts +25 -0
  49. package/dist/index.js +25 -0
  50. package/dist/init-failure.d.ts +19 -0
  51. package/dist/init-failure.js +18 -0
  52. package/dist/init-opt-out.d.ts +17 -0
  53. package/dist/init-opt-out.js +30 -0
  54. package/dist/install-hint.d.ts +9 -0
  55. package/dist/install-hint.js +41 -0
  56. package/dist/install-retries.d.ts +22 -0
  57. package/dist/install-retries.js +65 -0
  58. package/dist/install-source-config.d.ts +18 -0
  59. package/dist/install-source-config.js +34 -0
  60. package/dist/lockfiles.d.ts +14 -0
  61. package/dist/lockfiles.js +49 -0
  62. package/dist/mcp-clients.d.ts +94 -0
  63. package/dist/mcp-clients.js +327 -0
  64. package/dist/mcp-registered.d.ts +12 -0
  65. package/dist/mcp-registered.js +14 -0
  66. package/dist/mcp.d.ts +89 -0
  67. package/dist/mcp.js +129 -0
  68. package/dist/next-patch.d.ts +49 -0
  69. package/dist/next-patch.js +237 -0
  70. package/dist/node-io.d.ts +22 -0
  71. package/dist/node-io.js +150 -0
  72. package/dist/non-js-project.d.ts +44 -0
  73. package/dist/non-js-project.js +137 -0
  74. package/dist/nuxt-patch.d.ts +18 -0
  75. package/dist/nuxt-patch.js +33 -0
  76. package/dist/patch-kind.d.ts +20 -0
  77. package/dist/patch-kind.js +10 -0
  78. package/dist/plan-electron-vite.d.ts +16 -0
  79. package/dist/plan-electron-vite.js +72 -0
  80. package/dist/plan-framework.d.ts +122 -0
  81. package/dist/plan-framework.js +773 -0
  82. package/dist/plan.d.ts +312 -0
  83. package/dist/plan.js +650 -0
  84. package/dist/platform.d.ts +16 -0
  85. package/dist/platform.js +16 -0
  86. package/dist/preflight.d.ts +30 -0
  87. package/dist/preflight.js +52 -0
  88. package/dist/project-id.d.ts +12 -0
  89. package/dist/project-id.js +25 -0
  90. package/dist/refresh-rules.d.ts +40 -0
  91. package/dist/refresh-rules.js +51 -0
  92. package/dist/remember-project.d.ts +24 -0
  93. package/dist/remember-project.js +40 -0
  94. package/dist/run.d.ts +122 -0
  95. package/dist/run.js +762 -0
  96. package/dist/slash-command.d.ts +27 -0
  97. package/dist/slash-command.js +132 -0
  98. package/dist/snippets.d.ts +267 -0
  99. package/dist/snippets.js +898 -0
  100. package/dist/tanstack-start.d.ts +18 -0
  101. package/dist/tanstack-start.js +57 -0
  102. package/dist/version.d.ts +18 -0
  103. package/dist/version.js +23 -0
  104. package/dist/vite-config.d.ts +18 -0
  105. package/dist/vite-config.js +111 -0
  106. package/dist/vite-owning-config.d.ts +25 -0
  107. package/dist/vite-owning-config.js +219 -0
  108. package/dist/windows-quote.d.ts +38 -0
  109. package/dist/windows-quote.js +70 -0
  110. package/dist/workspace-apps.d.ts +40 -0
  111. package/dist/workspace-apps.js +188 -0
  112. package/dist/workspace-redirect.d.ts +22 -0
  113. package/dist/workspace-redirect.js +97 -0
  114. package/package.json +53 -0
package/dist/plan.d.ts ADDED
@@ -0,0 +1,312 @@
1
+ /**
2
+ * Pure assembly of the `reticle init` action plan. Given the detection result and the relevant file
3
+ * contents, produce an ordered list of steps — each marked apply / manual / already / skip. The
4
+ * runner performs the `write` side-effects; this module decides *what* should happen.
5
+ */
6
+ import { Framework, UiLibrary, type Detection } from './detect.js';
7
+ import type { FoundStore } from './capabilities.js';
8
+ import { McpClient } from './mcp-clients.js';
9
+ import { RETICLE_CONFIG_FILE } from './existing-config.js';
10
+ export { RETICLE_CONFIG_FILE };
11
+ /**
12
+ * The dev-dependencies `reticle init` installs — kit (or sensor) first, build plugin next.
13
+ *
14
+ * `uiLibrary` matters because the framework does not always name the renderer. The rule below was
15
+ * already written for Nuxt, correctly, and applied only there: a Vue app on plain Vite is
16
+ * `Framework.VITE` and a SvelteKit app renders Svelte, and both were being handed the React kit
17
+ * right after `init` had detected the real UI library and said so on screen.
18
+ */
19
+ export declare function frameworkPackages(framework: Framework, uiLibrary?: UiLibrary): readonly string[];
20
+ /** Exported so the init telemetry can tell an MCP-registration failure from a dependency install. */
21
+ export declare const MCP_TARGET = "global (claude user scope)";
22
+ /** The step that runs the package manager — the other thing that commonly fails on a user's machine. */
23
+ export declare const DEPS_TARGET = "package.json";
24
+ export declare const StepStatus: {
25
+ readonly APPLY: "apply";
26
+ readonly MANUAL: "manual";
27
+ readonly ALREADY: "already";
28
+ readonly SKIP: "skip";
29
+ /**
30
+ * Something the user should KNOW, not something they must DO. The UNVERIFIED lines are the case:
31
+ * a Preact or SvelteKit app is wired and working, it just isn't covered by a gate. Reporting those
32
+ * as `manual` made "steps left to do" a number that could never reach zero, and made a release gate
33
+ * read two regressions that were not regressions.
34
+ */
35
+ readonly NOTICE: "notice";
36
+ };
37
+ export type StepStatus = (typeof StepStatus)[keyof typeof StepStatus];
38
+ export interface Step {
39
+ title: string;
40
+ target: string;
41
+ status: StepStatus;
42
+ detail: string;
43
+ /**
44
+ * Present only when status is APPLY and a file must be written.
45
+ *
46
+ * `expect` is what must be READABLE BACK from the file afterwards, for a step whose write is a
47
+ * PATCH of somebody else's file rather than a file we own outright. Existence is enough to
48
+ * confirm a file we generated whole; it confirms nothing about a config we edited in place, and
49
+ * that gap is what #882 cost: `vite.config.ts` never received `reticle()`, the tick printed
50
+ * anyway, and the SDK was absent from the bundle with nothing pointing at the config.
51
+ */
52
+ write?: {
53
+ path: string;
54
+ content: string;
55
+ expect?: readonly string[];
56
+ };
57
+ /** Present only when status is APPLY and a subprocess must run (the dependency install). */
58
+ exec?: {
59
+ command: string;
60
+ args: string[];
61
+ fallback: string;
62
+ };
63
+ /**
64
+ * Weaker attempts to run when `exec` fails, IN ORDER, each with what to tell the user if it works.
65
+ *
66
+ * Ordered by how much each one gives up, cheapest concession first, because the first that
67
+ * succeeds is the one that stands. Two causes are covered today and they cost different things:
68
+ *
69
+ * - **A peer-dependency conflict.** npm dies on ERESOLVE in repos that are built with
70
+ * `--legacy-peer-deps` everywhere else. Relaxing peers keeps the VERSION PIN, so it goes first.
71
+ * Reported from a CRA repo where the failed install also skipped the connect module and the
72
+ * entry snippet, so the first run produced no wiring at all.
73
+ * - **A release-age hold.** The pinned install is refused outright by pnpm's `minimumReleaseAge`
74
+ * for as long as its window lasts — so for ~48 hours after every release, a project with that
75
+ * setting could not install Reticle. An unpinned install still works (it resolves the newest
76
+ * MATURE version), so it trades the exact version for a working install. That is the more
77
+ * expensive concession and it is last.
78
+ *
79
+ * A retry must never be silent: an older SDK against a newer daemon is the skew the pin exists to
80
+ * prevent, and a peer override the user did not ask for is theirs to know about.
81
+ */
82
+ retries?: {
83
+ command: string;
84
+ args: string[];
85
+ note: string;
86
+ }[];
87
+ /**
88
+ * This step wires the app to a package the install step provides. If that install fails, applying
89
+ * it anyway leaves the app importing a module that is not there — `next.config.ts` importing
90
+ * `@reticlehq/next` took a dev server down exactly this way. Installing Reticle must never be the
91
+ * reason an app stops booting.
92
+ */
93
+ dependsOnInstall?: boolean;
94
+ }
95
+ export interface Plan {
96
+ framework: Framework;
97
+ /**
98
+ * The renderer this app actually uses, carried so every consumer agrees on WHICH packages the
99
+ * plan installed. The retry guard checks node_modules for exactly those names; without this it
100
+ * looked for `@reticlehq/react` in a Vue app that had correctly been given the sensor, decided the
101
+ * install had failed, and skipped every wiring step on the retry.
102
+ */
103
+ uiLibrary: UiLibrary;
104
+ steps: Step[];
105
+ }
106
+ export interface PlanInput {
107
+ detection: Detection;
108
+ /**
109
+ * Write `captureNetworkBodies: true` into the app's config. Off unless the caller asked (#705).
110
+ *
111
+ * Optional so every existing caller and test keeps the safe default without naming it — the one
112
+ * direction a default about somebody else's data should be wrong in.
113
+ */
114
+ captureBodies?: boolean | undefined;
115
+ /**
116
+ * The CSP-bearing files this project actually has, keyed by path — read once in `gatherPlanInput`.
117
+ *
118
+ * Pre-read rather than given a reader, because `PlanInput` is the pure input to a pure planner and
119
+ * handing it an io would let any later step reach the disk from inside `buildPlan`.
120
+ */
121
+ cspSources?: Readonly<Record<string, string | undefined>> | undefined;
122
+ /** Whether the `claude` CLI is installed (so we can register the MCP server globally). */
123
+ claudeCli: boolean;
124
+ /** Whether an `reticle` MCP server is already registered with Claude (any scope) — idempotency. */
125
+ mcpExists: boolean;
126
+ /** `process.platform`. Injected so this module stays pure. Windows is the only branch. */
127
+ platform?: string;
128
+ /**
129
+ * The install channel the environment declared, or undefined when nothing declared one.
130
+ *
131
+ * Injected for the same reason as `platform`: reading the environment from inside a pure planner
132
+ * is a hidden input. Only ever written when it is actually KNOWN — `unknown` in `.reticle.json`
133
+ * is indistinguishable from a config written before the field existed, and those are different
134
+ * facts.
135
+ */
136
+ installSource?: string | undefined;
137
+ /** Whether THIS project has a .cursor/ directory — the signal that Cursor works on this repo. */
138
+ cursorProjectPresent?: boolean | undefined;
139
+ /**
140
+ * Every OTHER MCP client detected on this machine, with its config path and current content.
141
+ *
142
+ * Claude Code and Cursor keep their own steps — Claude registers through its CLI, and Cursor's
143
+ * predates this. Everything else is uniform: read the file, merge, write.
144
+ */
145
+ detectedClients?: readonly {
146
+ id: McpClient;
147
+ configPath: string;
148
+ existing: string | null;
149
+ }[] | undefined;
150
+ /** Discovered Vite config: its path + source, or null if none found. */
151
+ viteConfig: {
152
+ path: string;
153
+ source: string;
154
+ } | null;
155
+ /** Discovered electron-vite config: its path + source, or null if none found. */
156
+ electronViteConfig?: {
157
+ path: string;
158
+ source: string;
159
+ } | null | undefined;
160
+ /** Electron preload source we can patch, or null when none was found. */
161
+ electronPreload?: {
162
+ path: string;
163
+ source: string;
164
+ } | null | undefined;
165
+ /** Electron main-process source we can patch, or null when none was found. */
166
+ electronMain?: {
167
+ path: string;
168
+ source: string;
169
+ } | null | undefined;
170
+ /** Discovered Astro config: its path + source, or null if none found. */
171
+ astroConfig?: {
172
+ path: string;
173
+ source: string;
174
+ } | null | undefined;
175
+ /**
176
+ * The single layout to instrument, or null when the choice is not obvious.
177
+ *
178
+ * WHICH page or layout to instrument is a real decision — so `init` only makes it when there is
179
+ * exactly one candidate. Zero or several falls back to the printed recipe rather than guessing at
180
+ * the file every page of the user's site inherits from.
181
+ */
182
+ astroLayout?: {
183
+ path: string;
184
+ source: string;
185
+ } | null | undefined;
186
+ /**
187
+ * Existing `src/env.d.ts` content, when present — where the Vite-define ambient declarations go
188
+ * so `astro check` can see `__RETICLE_TOKEN__` / `__RETICLE_ROOT__` (#677).
189
+ */
190
+ astroEnvDts?: string | null | undefined;
191
+ /** Discovered Next config filename (e.g. 'next.config.mjs'), or null. */
192
+ nextConfigFile: string | null;
193
+ /** Source of that Next config, so the export can be wrapped in withReticle. */
194
+ nextConfigSource?: string | null | undefined;
195
+ /** Discovered Next root layout: its path + source, or null (App Router only). */
196
+ nextLayout?: {
197
+ path: string;
198
+ source: string;
199
+ } | null | undefined;
200
+ /** Where the dev-only connect component goes — never inside `pages/`, which routes on presence. */
201
+ nextReticleDevPath?: string | undefined;
202
+ /** What the mount file should import — a sibling for App Router, `../components/…` for Pages. */
203
+ nextReticleDevImport?: string | undefined;
204
+ /** Whether the ReticleDev component file already exists. */
205
+ nextReticleDevExists: boolean;
206
+ /**
207
+ * The existing ReticleDev component's source, when there is one.
208
+ *
209
+ * Read so an install predating daemon discovery can be told apart from a current one. Undefined
210
+ * means NOT READ, and an unread file is reported as already-wired rather than as stale: inventing
211
+ * work from missing information is how a plan grows steps that can never be completed.
212
+ */
213
+ nextReticleDevSource?: string | null | undefined;
214
+ /** `data-testid` values scanned from the app's source, for the generated capabilities block. */
215
+ testids?: readonly string[] | undefined;
216
+ /** Ready-to-uncomment `registerStore` lines for the state libraries the app actually depends on. */
217
+ storeHints?: readonly string[] | undefined;
218
+ /** Store instances found in the app's own source — imported and registered outright, not hinted. */
219
+ foundStores?: readonly FoundStore[] | undefined;
220
+ /** The same stores, with specifiers resolved from Next's dev-module directory instead of `src/`. */
221
+ nextFoundStores?: readonly FoundStore[] | undefined;
222
+ /** Whether src/reticle-dev.ts already exists — it is the one generated file users are meant to edit. */
223
+ viteDevModuleExists?: boolean | undefined;
224
+ /** Whether src/hooks.client.ts already exists (SvelteKit idempotency). */
225
+ svelteKitHooksExists?: boolean;
226
+ /** Whether app/entry.client.tsx already exists — it decides whether init writes one or patches it. */
227
+ reactRouterEntryExists?: boolean;
228
+ /**
229
+ * Its SOURCE, when it is there.
230
+ *
231
+ * Content rather than existence, because the two cases need different files: an absent entry is
232
+ * written from React Router's own default plus our import, and an existing one gets that import
233
+ * added to whatever the app already put in it. Existence alone could only ever print a recipe.
234
+ */
235
+ reactRouterEntrySource?: string | null | undefined;
236
+ /** Discovered Nuxt config: its path + source, or null. It is where the pairing token is inlined. */
237
+ nuxtConfig?: {
238
+ path: string;
239
+ source: string;
240
+ } | null | undefined;
241
+ /** Whether the app has an `app/` directory — Nuxt 4's srcDir, and so where plugins are scanned. */
242
+ nuxtHasAppDir?: boolean | undefined;
243
+ /** Whether the Nuxt client plugin already exists (idempotency — the file is the owner's to edit). */
244
+ nuxtPluginExists?: boolean | undefined;
245
+ /**
246
+ * TanStack Start's document module, when found (`src/routes/__root.tsx` or `app/routes/__root.tsx`).
247
+ *
248
+ * The recipe is printed rather than written either way — a static import on that file SSRs and
249
+ * 500s — but the path has to be the one that actually exists, not a guess.
250
+ */
251
+ tanstackStartRoot?: string | undefined;
252
+ /** CRA's bundled entry (src/index.tsx or .js) — where the connect import has to go. */
253
+ craEntry?: {
254
+ path: string;
255
+ source: string;
256
+ } | null;
257
+ /** Existing .env.development.local, so an unrelated variable in it survives. */
258
+ craEnv?: string | null;
259
+ /** The daemon's pairing token, inlined for CRA through the one channel it supports. */
260
+ pairingToken?: string;
261
+ /** Whether .reticle.json already exists in the project root (idempotency). */
262
+ reticleConfigExists?: boolean;
263
+ /**
264
+ * Its CONTENT, so an existing config can be checked instead of trusted.
265
+ *
266
+ * Existence alone said "a file is present" and was reported as "this is configured correctly" —
267
+ * see reticleConfigStep for the port that survived every re-run because of it.
268
+ */
269
+ reticleConfigSource?: string | null | undefined;
270
+ /** Current project-root CLAUDE.md content (for the idempotent agent-rule merge), or null/undefined. */
271
+ claudeMdContent?: string | null | undefined;
272
+ /** Current project-root AGENTS.md content (the cross-agent rule), or null/undefined. */
273
+ agentsMdContent?: string | null | undefined;
274
+ /** Current project-root RETICLE.md content (the full rules), or null when absent. */
275
+ reticleMdContent?: string | null | undefined;
276
+ /**
277
+ * Current .cursor/rules/reticle.mdc content, or null when absent.
278
+ *
279
+ * CONTENT, not existence. Gating on the file merely being there froze a Cursor project's rule at
280
+ * whatever release wrote it — so the CLAUDE.md path refreshed itself while the Cursor one never
281
+ * could, and a rule added later (`version_skew`) never reached a Cursor-only project at all.
282
+ */
283
+ cursorRuleContent?: string | null | undefined;
284
+ /** Current .claude/commands/reticle.md content, or null when absent (slash-command idempotency). */
285
+ claudeCommandContent?: string | null | undefined;
286
+ /** Current .cursor/commands/reticle.md content, or null when absent. */
287
+ cursorCommandContent?: string | null | undefined;
288
+ /**
289
+ * Absolute directory the AGENT runs in, when that is not the app's directory.
290
+ *
291
+ * The rule and command files are read by the agent, not by the app, so a monorepo whose app is a
292
+ * directory down must still get its `/reticle` where the human's session actually stands. Absent
293
+ * (the single-package case) leaves every path project-relative exactly as before.
294
+ */
295
+ agentFileRoot?: string | undefined;
296
+ /**
297
+ * Content of the `.reticle.json` already sitting at that agent root, or null/undefined when there
298
+ * is none. Content rather than existence, for the reason `reticleConfigSource` is: a root config
299
+ * that disagrees with the app's is worse than no root config, and only reading it can tell.
300
+ */
301
+ agentRootConfigSource?: string | null | undefined;
302
+ options: {
303
+ port: number | undefined;
304
+ mcp: boolean;
305
+ install: boolean;
306
+ /** Stable project identity derived at init (package.json name + root). Baked into snippets/.reticle.json. */
307
+ projectId?: string;
308
+ /** The CLI's own version, pinned onto the SDK install so a stale registry cache cannot skew it. */
309
+ sdkVersion?: string;
310
+ };
311
+ }
312
+ export declare function buildPlan(input: PlanInput): Plan;