@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.
- package/dist/detect/capabilities.d.ts +4 -1
- package/dist/detect/capabilities.js +45 -9
- package/dist/detect/detect.d.ts +58 -4
- package/dist/detect/detect.js +117 -7
- package/dist/detect/dev-script.d.ts +26 -2
- package/dist/detect/dev-script.js +80 -7
- package/dist/detect/non-js-project.d.ts +1 -1
- package/dist/detect/non-js-project.js +6 -1
- package/dist/detect/workspace-apps.d.ts +21 -0
- package/dist/detect/workspace-apps.js +111 -12
- package/dist/detect/workspace-redirect.d.ts +2 -1
- package/dist/detect/workspace-redirect.js +28 -2
- package/dist/diagnose/containerised-dev-server.d.ts +12 -4
- package/dist/diagnose/containerised-dev-server.js +36 -4
- package/dist/diagnose/csp-check.d.ts +12 -6
- package/dist/diagnose/csp-check.js +61 -13
- package/dist/diagnose/csp-doctor.d.ts +33 -2
- package/dist/diagnose/csp-doctor.js +103 -6
- package/dist/diagnose/csp-step.d.ts +27 -0
- package/dist/diagnose/csp-step.js +86 -0
- package/dist/diagnose/desktop-doctor.d.ts +1 -1
- package/dist/diagnose/desktop-doctor.js +8 -2
- package/dist/diagnose/install-hint.d.ts +9 -1
- package/dist/diagnose/install-hint.js +17 -7
- package/dist/diagnose/install-retries.d.ts +18 -2
- package/dist/diagnose/install-retries.js +50 -3
- package/dist/diagnose/terminal-wrap.d.ts +18 -0
- package/dist/diagnose/terminal-wrap.js +63 -0
- package/dist/host.d.ts +6 -0
- package/dist/host.js +3 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.js +8 -3
- package/dist/no-package-json.d.ts +10 -0
- package/dist/no-package-json.js +121 -0
- package/dist/node-io.d.ts +9 -5
- package/dist/node-io.js +25 -7
- package/dist/patch/angular.d.ts +68 -0
- package/dist/patch/angular.js +216 -0
- package/dist/patch/astro-patch.d.ts +48 -13
- package/dist/patch/astro-patch.js +151 -43
- package/dist/patch/cra.d.ts +0 -2
- package/dist/patch/cra.js +0 -2
- package/dist/patch/electron-patch.d.ts +10 -1
- package/dist/patch/electron-patch.js +79 -27
- package/dist/patch/electron-vite-patch.js +1 -1
- package/dist/patch/nuxt-patch.d.ts +1 -1
- package/dist/patch/nuxt-patch.js +2 -2
- package/dist/patch/nuxt-snippets.d.ts +44 -0
- package/dist/patch/nuxt-snippets.js +135 -0
- package/dist/patch/remix.d.ts +24 -0
- package/dist/patch/remix.js +59 -0
- package/dist/patch/snippets.d.ts +58 -57
- package/dist/patch/snippets.js +181 -202
- package/dist/patch/static-page.d.ts +39 -0
- package/dist/patch/static-page.js +102 -0
- package/dist/patch/tanstack-start.d.ts +36 -8
- package/dist/patch/tanstack-start.js +118 -29
- package/dist/patch/vite-config.d.ts +5 -0
- package/dist/patch/vite-config.js +8 -0
- package/dist/patch/vite-env-types.d.ts +9 -0
- package/dist/patch/vite-env-types.js +19 -0
- package/dist/patch/vite-owning-config.d.ts +47 -0
- package/dist/patch/vite-owning-config.js +104 -19
- package/dist/plan/connect-steps.d.ts +10 -3
- package/dist/plan/connect-steps.js +22 -3
- package/dist/plan/framework-adapter.d.ts +5 -6
- package/dist/plan/framework-adapter.js +105 -11
- package/dist/plan/notices.js +4 -3
- package/dist/plan/plan-angular.d.ts +6 -0
- package/dist/plan/plan-angular.js +89 -0
- package/dist/plan/plan-electron-vite.d.ts +6 -3
- package/dist/plan/plan-electron-vite.js +39 -8
- package/dist/plan/plan-framework.d.ts +9 -47
- package/dist/plan/plan-framework.js +114 -323
- package/dist/plan/plan-types.d.ts +47 -2
- package/dist/plan/plan-vite.d.ts +67 -0
- package/dist/plan/plan-vite.js +256 -0
- package/dist/plan/plan.js +155 -69
- package/dist/plan/port-steps.d.ts +45 -0
- package/dist/plan/port-steps.js +119 -0
- package/dist/plan/preflight.d.ts +17 -3
- package/dist/plan/preflight.js +53 -23
- package/dist/plan/stop-hook-step.d.ts +4 -0
- package/dist/plan/stop-hook-step.js +49 -0
- package/dist/project/agent-rules.js +2 -0
- package/dist/register/mcp-clients.d.ts +13 -0
- package/dist/register/mcp-clients.js +22 -0
- package/dist/register/mcp.d.ts +26 -5
- package/dist/register/mcp.js +64 -8
- package/dist/run-types.d.ts +10 -0
- package/dist/run.js +132 -78
- package/package.json +3 -4
- package/NOTICE +0 -5
|
@@ -15,10 +15,39 @@
|
|
|
15
15
|
* Half-editing somebody's build config is worse than a documented manual step.
|
|
16
16
|
*/
|
|
17
17
|
import { ReticleDir } from '@reticlehq/core';
|
|
18
|
+
import { parseMajor } from '../detect/detect.js';
|
|
18
19
|
import { blockAfter } from './brace-scan.js';
|
|
19
20
|
import { PatchKind } from './patch-kind.js';
|
|
21
|
+
/** The first Vite whose dep optimizer is rolldown — the same line the Vite plugin draws. */
|
|
22
|
+
const ROLLDOWN_OPTIMIZER_MAJOR = 7;
|
|
23
|
+
function writesEsbuildTarget(config) {
|
|
24
|
+
const major = config.viteMajor;
|
|
25
|
+
return undefined === major || null === major || major < ROLLDOWN_OPTIMIZER_MAJOR;
|
|
26
|
+
}
|
|
27
|
+
/** The optimizer target, in each of the two shapes this file writes it. */
|
|
28
|
+
const ESBUILD_TARGET = "esbuildOptions: { target: 'es2022' }";
|
|
29
|
+
const ESBUILD_TARGET_INNER = `\n ${ESBUILD_TARGET},`;
|
|
30
|
+
const ESBUILD_TARGET_WHOLE = `, ${ESBUILD_TARGET}`;
|
|
31
|
+
/**
|
|
32
|
+
* A config an older `init` patched, with the esbuild target taken back out on a rolldown Vite.
|
|
33
|
+
*
|
|
34
|
+
* Only our own literal, in the exact shapes we wrote it — an `esbuildOptions` the app set itself is
|
|
35
|
+
* theirs, and is left to Vite's deprecation notice to talk about.
|
|
36
|
+
*/
|
|
37
|
+
function withoutStaleEsbuildTarget(source, config) {
|
|
38
|
+
if (writesEsbuildTarget(config) || !source.includes(ESBUILD_TARGET))
|
|
39
|
+
return null;
|
|
40
|
+
const out = source.replace(ESBUILD_TARGET_INNER, '').replace(ESBUILD_TARGET_WHOLE, '');
|
|
41
|
+
return out === source ? null : out;
|
|
42
|
+
}
|
|
20
43
|
/** Present in a patched config AND in a hand-followed recipe — so both count as already wired. */
|
|
21
|
-
const
|
|
44
|
+
const DEFINE_TOKEN_MARKER = '__RETICLE_TOKEN__';
|
|
45
|
+
function usesDefineToken(config) {
|
|
46
|
+
return config.defineToken !== false;
|
|
47
|
+
}
|
|
48
|
+
function alreadyMarker(config) {
|
|
49
|
+
return config.alreadyMarker ?? DEFINE_TOKEN_MARKER;
|
|
50
|
+
}
|
|
22
51
|
/**
|
|
23
52
|
* The SDK, declared so Vite pre-bundles it BEFORE the first page load.
|
|
24
53
|
*
|
|
@@ -82,30 +111,36 @@ import { join } from 'node:path';
|
|
|
82
111
|
* cosmetic: Astro's default down-levels the modern SDK bundle and dies on a destructuring transform.
|
|
83
112
|
*/
|
|
84
113
|
function viteKeys(config) {
|
|
85
|
-
|
|
114
|
+
const keys = [
|
|
86
115
|
{ key: 'build', inner: `\n target: 'es2022',` },
|
|
87
116
|
{
|
|
88
117
|
key: 'optimizeDeps',
|
|
89
|
-
inner: `\n include: [${sdkInclude(config)}]
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
key: 'define',
|
|
93
|
-
inner: `\n __RETICLE_TOKEN__: JSON.stringify(reticleToken()),\n __RETICLE_ROOT__: JSON.stringify(process.cwd()),`,
|
|
118
|
+
inner: `\n include: [${sdkInclude(config)}],${writesEsbuildTarget(config) ? ESBUILD_TARGET_INNER : ''}`,
|
|
94
119
|
},
|
|
95
120
|
// Merged in first, so a `server: { port }` the app already set keeps its port. An app that
|
|
96
121
|
// already sets `server.watch` itself is the one shape this loses to — the inner `watch` key would
|
|
97
122
|
// be duplicated and the app's would win — which is the same nested-merge ceiling `build` has.
|
|
98
123
|
{ key: 'server', inner: `\n watch: { ignored: [${WATCH_IGNORE_LITERAL}] },` },
|
|
99
124
|
];
|
|
125
|
+
if (usesDefineToken(config)) {
|
|
126
|
+
keys.splice(2, 0, {
|
|
127
|
+
key: 'define',
|
|
128
|
+
inner: `\n __RETICLE_TOKEN__: JSON.stringify(reticleToken()),\n __RETICLE_ROOT__: JSON.stringify(process.cwd()),`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return keys;
|
|
100
132
|
}
|
|
101
133
|
/** Whole-key form, for a `vite:` block that does not have the key at all. */
|
|
102
134
|
function wholeKeys(config) {
|
|
103
|
-
|
|
135
|
+
const keys = {
|
|
104
136
|
build: `\n build: { target: 'es2022' },`,
|
|
105
|
-
optimizeDeps: `\n optimizeDeps: { include: [${sdkInclude(config)}]
|
|
106
|
-
define: `\n define: {\n __RETICLE_TOKEN__: JSON.stringify(reticleToken()),\n __RETICLE_ROOT__: JSON.stringify(process.cwd()),\n },`,
|
|
137
|
+
optimizeDeps: `\n optimizeDeps: { include: [${sdkInclude(config)}]${writesEsbuildTarget(config) ? ESBUILD_TARGET_WHOLE : ''} },`,
|
|
107
138
|
server: `\n server: { watch: { ignored: [${WATCH_IGNORE_LITERAL}] } },`,
|
|
108
139
|
};
|
|
140
|
+
if (usesDefineToken(config)) {
|
|
141
|
+
keys.define = `\n define: {\n __RETICLE_TOKEN__: JSON.stringify(reticleToken()),\n __RETICLE_ROOT__: JSON.stringify(process.cwd()),\n },`;
|
|
142
|
+
}
|
|
143
|
+
return keys;
|
|
109
144
|
}
|
|
110
145
|
/**
|
|
111
146
|
* Add our keys to an existing `vite: { ... }` block, merging into any the app already set.
|
|
@@ -160,20 +195,39 @@ function withoutInclude(inner, config) {
|
|
|
160
195
|
* that ran `init`.
|
|
161
196
|
*/
|
|
162
197
|
function viteBlock(config) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
define: {
|
|
198
|
+
const marker = usesDefineToken(config) ? '' : ` /* ${alreadyMarker(config)} */\n`;
|
|
199
|
+
const define = usesDefineToken(config)
|
|
200
|
+
? ` define: {
|
|
167
201
|
__RETICLE_TOKEN__: JSON.stringify(reticleToken()),
|
|
168
202
|
__RETICLE_ROOT__: JSON.stringify(process.cwd()),
|
|
169
203
|
},
|
|
170
|
-
|
|
204
|
+
`
|
|
205
|
+
: '';
|
|
206
|
+
return ` vite: {
|
|
207
|
+
${marker} build: { target: 'es2022' },
|
|
208
|
+
optimizeDeps: { include: [${sdkInclude(config)}]${writesEsbuildTarget(config) ? ESBUILD_TARGET_WHOLE : ''} },
|
|
209
|
+
${define} server: { watch: { ignored: [${WATCH_IGNORE_LITERAL}] } },
|
|
171
210
|
},
|
|
172
211
|
`;
|
|
173
212
|
}
|
|
213
|
+
function withHelper(source, config) {
|
|
214
|
+
if (!usesDefineToken(config)) {
|
|
215
|
+
return source.endsWith('\n') ? source : `${source}\n`;
|
|
216
|
+
}
|
|
217
|
+
return `${HELPER_IMPORTS}${source.trimStart()}\n${HELPER}`.trimEnd() + '\n';
|
|
218
|
+
}
|
|
219
|
+
function withOwningMarker(source, config, braceAt) {
|
|
220
|
+
if (usesDefineToken(config) || source.includes(alreadyMarker(config)))
|
|
221
|
+
return source;
|
|
222
|
+
return insertAt(source, braceAt, `\n /* ${alreadyMarker(config)} */`);
|
|
223
|
+
}
|
|
174
224
|
export function patchViteOwningConfig(source, config) {
|
|
175
|
-
if (source.includes(
|
|
176
|
-
|
|
225
|
+
if (source.includes(alreadyMarker(config))) {
|
|
226
|
+
const cleaned = withoutStaleEsbuildTarget(source, config);
|
|
227
|
+
return null === cleaned
|
|
228
|
+
? { kind: PatchKind.ALREADY }
|
|
229
|
+
: { kind: PatchKind.APPLY, code: cleaned };
|
|
230
|
+
}
|
|
177
231
|
// A `vite: { ... }` block is an object literal, so our keys can go straight after the brace and
|
|
178
232
|
// whatever is already in there is untouched. Refusing outright was the only genuine install defect
|
|
179
233
|
// left in the gate: the config bailed while the LAYOUT patch applied anyway, leaving an app with a
|
|
@@ -186,7 +240,7 @@ export function patchViteOwningConfig(source, config) {
|
|
|
186
240
|
if (merged !== null) {
|
|
187
241
|
return {
|
|
188
242
|
kind: PatchKind.APPLY,
|
|
189
|
-
code:
|
|
243
|
+
code: withHelper(withOwningMarker(merged, config, at), config),
|
|
190
244
|
};
|
|
191
245
|
}
|
|
192
246
|
return {
|
|
@@ -214,6 +268,37 @@ export function patchViteOwningConfig(source, config) {
|
|
|
214
268
|
const withBlock = `${source.slice(0, at)}\n${viteBlock(config)}${source.slice(at)}`;
|
|
215
269
|
return {
|
|
216
270
|
kind: PatchKind.APPLY,
|
|
217
|
-
code:
|
|
271
|
+
code: withHelper(withBlock, config),
|
|
218
272
|
};
|
|
219
273
|
}
|
|
274
|
+
const HOISTED_VITE = 'node_modules/vite/package.json';
|
|
275
|
+
const PNPM_STORE = 'node_modules/.pnpm';
|
|
276
|
+
/** A pnpm store entry for vite itself: `vite@8.0.16` or `vite@7.1.2_@types+node@24…`. */
|
|
277
|
+
const PNPM_VITE_ENTRY = /^vite@(\d+)\./;
|
|
278
|
+
export function installedViteMajor(io, pkg) {
|
|
279
|
+
const hoisted = io.readFile(HOISTED_VITE);
|
|
280
|
+
if (null !== hoisted) {
|
|
281
|
+
try {
|
|
282
|
+
const parsed = JSON.parse(hoisted);
|
|
283
|
+
const version = 'object' === typeof parsed && null !== parsed
|
|
284
|
+
? parsed.version
|
|
285
|
+
: undefined;
|
|
286
|
+
const major = 'string' === typeof version ? parseMajor(version) : undefined;
|
|
287
|
+
if (major !== undefined)
|
|
288
|
+
return major;
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
// Unreadable manifest: fall through to the store and the declared range.
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// ponytail: several copies can sit in the store and the newest is taken; resolving the framework's
|
|
295
|
+
// own `vite` through its dependency chain is the upgrade if a stale newer copy ever misleads this.
|
|
296
|
+
const stored = io
|
|
297
|
+
.listDirs(PNPM_STORE)
|
|
298
|
+
.map((name) => PNPM_VITE_ENTRY.exec(name)?.[1])
|
|
299
|
+
.filter((major) => major !== undefined)
|
|
300
|
+
.map(Number);
|
|
301
|
+
if (stored.length > 0)
|
|
302
|
+
return Math.max(...stored);
|
|
303
|
+
return parseMajor(pkg.dependencies?.['vite'] ?? pkg.devDependencies?.['vite']) ?? null;
|
|
304
|
+
}
|
|
@@ -27,15 +27,22 @@ export declare const StepTitle: {
|
|
|
27
27
|
readonly NUXT_RESTART: "Restart the Nuxt dev server";
|
|
28
28
|
readonly CONNECT_SNIPPET_REACT_ROUTER: "Connect snippet (React Router)";
|
|
29
29
|
readonly CONNECT_SNIPPET_TANSTACK_START: "Connect snippet (TanStack Start)";
|
|
30
|
+
readonly TANSTACK_START_CONNECT_COMPONENT: "ReticleConnect component (TanStack Start)";
|
|
31
|
+
readonly CONNECT_SNIPPET_REMIX: "Connect snippet (Remix)";
|
|
32
|
+
readonly CONNECT_SNIPPET_ANGULAR: "Connect snippet (Angular)";
|
|
33
|
+
readonly ANGULAR_TOKEN_PROXY: "Angular dev-server token route";
|
|
34
|
+
readonly ANGULAR_SERVE_CONFIG: "Angular serve target (proxyConfig)";
|
|
35
|
+
readonly ANGULAR_SETUP_GATED: "Angular setup verified, drive unverified";
|
|
30
36
|
readonly ELECTRON_VITE_PLUGIN: "Vite plugin (electron-vite renderer)";
|
|
31
37
|
readonly ELECTRON_PRELOAD: "Electron preload (IPC shim)";
|
|
32
38
|
readonly ELECTRON_CAPTURE: "Electron capture (screenshots)";
|
|
33
39
|
readonly TANSTACK_START_UNVERIFIED: "TanStack Start is UNVERIFIED";
|
|
34
|
-
readonly
|
|
40
|
+
readonly SVELTEKIT_SETUP_GATED: "SvelteKit setup verified, drive unverified";
|
|
35
41
|
readonly CLIENT_HOOK: "Reticle client hook";
|
|
36
42
|
readonly CONNECT_SNIPPET_ASTRO: "Connect snippet (Astro)";
|
|
37
|
-
readonly
|
|
38
|
-
readonly
|
|
43
|
+
readonly ASTRO_RETICLE_DEV: "Astro ReticleDev module";
|
|
44
|
+
readonly ASTRO_CONFIG: "Astro config (build target)";
|
|
45
|
+
readonly ASTRO_ENV_DTS: "Astro env types (window token)";
|
|
39
46
|
readonly CSP: "Content-Security-Policy";
|
|
40
47
|
readonly CONNECT_SNIPPET: "Connect snippet";
|
|
41
48
|
};
|
|
@@ -28,15 +28,22 @@ export const StepTitle = {
|
|
|
28
28
|
NUXT_RESTART: 'Restart the Nuxt dev server',
|
|
29
29
|
CONNECT_SNIPPET_REACT_ROUTER: 'Connect snippet (React Router)',
|
|
30
30
|
CONNECT_SNIPPET_TANSTACK_START: 'Connect snippet (TanStack Start)',
|
|
31
|
+
TANSTACK_START_CONNECT_COMPONENT: 'ReticleConnect component (TanStack Start)',
|
|
32
|
+
CONNECT_SNIPPET_REMIX: 'Connect snippet (Remix)',
|
|
33
|
+
CONNECT_SNIPPET_ANGULAR: 'Connect snippet (Angular)',
|
|
34
|
+
ANGULAR_TOKEN_PROXY: 'Angular dev-server token route',
|
|
35
|
+
ANGULAR_SERVE_CONFIG: 'Angular serve target (proxyConfig)',
|
|
36
|
+
ANGULAR_SETUP_GATED: 'Angular setup verified, drive unverified',
|
|
31
37
|
ELECTRON_VITE_PLUGIN: 'Vite plugin (electron-vite renderer)',
|
|
32
38
|
ELECTRON_PRELOAD: 'Electron preload (IPC shim)',
|
|
33
39
|
ELECTRON_CAPTURE: 'Electron capture (screenshots)',
|
|
34
40
|
TANSTACK_START_UNVERIFIED: 'TanStack Start is UNVERIFIED',
|
|
35
|
-
|
|
41
|
+
SVELTEKIT_SETUP_GATED: 'SvelteKit setup verified, drive unverified',
|
|
36
42
|
CLIENT_HOOK: 'Reticle client hook',
|
|
37
43
|
CONNECT_SNIPPET_ASTRO: 'Connect snippet (Astro)',
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
ASTRO_RETICLE_DEV: 'Astro ReticleDev module',
|
|
45
|
+
ASTRO_CONFIG: 'Astro config (build target)',
|
|
46
|
+
ASTRO_ENV_DTS: 'Astro env types (window token)',
|
|
40
47
|
CSP: CSP_STEP_TITLE,
|
|
41
48
|
CONNECT_SNIPPET: 'Connect snippet',
|
|
42
49
|
};
|
|
@@ -54,6 +61,7 @@ export const CONNECT_STEP_TITLES = new Set([
|
|
|
54
61
|
StepTitle.CONNECT_SNIPPET,
|
|
55
62
|
StepTitle.CONNECT_SNIPPET_CRA,
|
|
56
63
|
StepTitle.CONNECT_SNIPPET_ASTRO,
|
|
64
|
+
StepTitle.ASTRO_RETICLE_DEV,
|
|
57
65
|
StepTitle.CONNECT_SNIPPET_NUXT,
|
|
58
66
|
// The config is the other half of the Nuxt connect, not a nicety: it is the only thing in a Nuxt
|
|
59
67
|
// app that can inline the pairing token, and the bridge refuses a connect without one even on
|
|
@@ -61,6 +69,14 @@ export const CONNECT_STEP_TITLES = new Set([
|
|
|
61
69
|
StepTitle.NUXT_CONFIG,
|
|
62
70
|
StepTitle.CONNECT_SNIPPET_REACT_ROUTER,
|
|
63
71
|
StepTitle.CONNECT_SNIPPET_TANSTACK_START,
|
|
72
|
+
// The component and the line that renders it are two steps, for the reason Next's are.
|
|
73
|
+
StepTitle.TANSTACK_START_CONNECT_COMPONENT,
|
|
74
|
+
StepTitle.CONNECT_SNIPPET_REMIX,
|
|
75
|
+
StepTitle.CONNECT_SNIPPET_ANGULAR,
|
|
76
|
+
// Both halves of how an Angular page gets its pairing token. Without the route the connect is
|
|
77
|
+
// refused on the token, and without the serve-target entry `ng serve` never mounts the route.
|
|
78
|
+
StepTitle.ANGULAR_TOKEN_PROXY,
|
|
79
|
+
StepTitle.ANGULAR_SERVE_CONFIG,
|
|
64
80
|
StepTitle.CLIENT_HOOK,
|
|
65
81
|
StepTitle.CONNECT_MODULE,
|
|
66
82
|
StepTitle.RETICLE_DEV_COMPONENT,
|
|
@@ -85,6 +101,9 @@ export const CONNECT_STEP_TITLES = new Set([
|
|
|
85
101
|
// electron-vite's connect IS the renderer plugin. Without it the SDK never injects, and the
|
|
86
102
|
// preload/capture steps are not enough to produce a session.
|
|
87
103
|
StepTitle.ELECTRON_VITE_PLUGIN,
|
|
104
|
+
// A policy that refuses the bridge WebSocket is a guaranteed non-connection on EVERY framework, so
|
|
105
|
+
// a ⚠ on it (a policy init could not edit) must fail init rather than read as advice.
|
|
106
|
+
StepTitle.CSP,
|
|
88
107
|
]);
|
|
89
108
|
/** True when this step is what makes the app dial the daemon. */
|
|
90
109
|
export function isConnectStep(title) {
|
|
@@ -18,17 +18,13 @@
|
|
|
18
18
|
*
|
|
19
19
|
* `framework-adapter.test.ts` asserts the seam between the two halves.
|
|
20
20
|
*/
|
|
21
|
-
import { Framework } from '../detect/detect.js';
|
|
21
|
+
import { Framework, UiLibrary } from '../detect/detect.js';
|
|
22
22
|
import { StepTitle } from './connect-steps.js';
|
|
23
23
|
import type { PlanInput, Step } from './plan-types.js';
|
|
24
24
|
export declare const RETICLE_REACT_KIT = "@reticlehq/react";
|
|
25
25
|
/** The framework-neutral sensor, for stacks the React adapter has nothing to attach to. */
|
|
26
26
|
export declare const RETICLE_BROWSER_SDK = "@reticlehq/browser";
|
|
27
|
-
|
|
28
|
-
export declare const RETICLE_NEXT_PLUGIN = "@reticlehq/next";
|
|
29
|
-
/** The Electron main/preload helper — what makes IPC and screenshots exist at all. */
|
|
30
|
-
export declare const RETICLE_ELECTRON = "@reticlehq/electron";
|
|
31
|
-
export interface FrameworkAdapter {
|
|
27
|
+
interface FrameworkAdapter {
|
|
32
28
|
/**
|
|
33
29
|
* The dev dependencies `init` installs, given the kit the UI-library check chose
|
|
34
30
|
* (`@reticlehq/react` or the neutral sensor). A framework that knows its own renderer ignores the
|
|
@@ -57,6 +53,8 @@ export interface FrameworkAdapter {
|
|
|
57
53
|
*/
|
|
58
54
|
readonly carriesOwnUnverifiedNote: boolean;
|
|
59
55
|
}
|
|
56
|
+
/** Whether the install gate scaffolds this stack — see INSTALL_GATE_STACKS. */
|
|
57
|
+
export declare function installGated(framework: Framework, uiLibrary: UiLibrary): boolean;
|
|
60
58
|
export declare const FRAMEWORK_ADAPTERS: Record<Framework, FrameworkAdapter>;
|
|
61
59
|
/**
|
|
62
60
|
* The per-framework half of the plan, looked up rather than switched.
|
|
@@ -67,3 +65,4 @@ export declare const FRAMEWORK_ADAPTERS: Record<Framework, FrameworkAdapter>;
|
|
|
67
65
|
* for the packages, the connect-step titles and the unverified-note flag in the same edit.
|
|
68
66
|
*/
|
|
69
67
|
export declare function frameworkSteps(input: PlanInput): Step[];
|
|
68
|
+
export {};
|
|
@@ -18,10 +18,40 @@
|
|
|
18
18
|
*
|
|
19
19
|
* `framework-adapter.test.ts` asserts the seam between the two halves.
|
|
20
20
|
*/
|
|
21
|
-
import { Framework } from '../detect/detect.js';
|
|
21
|
+
import { Framework, UiLibrary } from '../detect/detect.js';
|
|
22
22
|
import { StepTitle } from './connect-steps.js';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
23
|
+
import { astroSteps, craSteps, htmlSteps, nextSteps, nuxtSteps, reactRouterSteps, svelteKitSteps, tanstackStartSteps, } from './plan-framework.js';
|
|
24
|
+
import { VITE_PLUGIN_DETAIL, viteSteps } from './plan-vite.js';
|
|
25
|
+
import { electronForgeSteps, electronViteSteps } from './plan-electron-vite.js';
|
|
26
|
+
import { angularSteps } from './plan-angular.js';
|
|
27
|
+
import { REMIX_CLASSIC_MANUAL, remixEntryFile } from '../patch/remix.js';
|
|
28
|
+
import { StepStatus } from './plan-types.js';
|
|
29
|
+
/** Where the classic Remix compiler's ⚠ points: the file that says which compiler this is. */
|
|
30
|
+
const REMIX_CLASSIC_TARGET = 'remix.config.js';
|
|
31
|
+
/**
|
|
32
|
+
* Remix v2: React Router framework mode's steps, with Remix's own default entry and title.
|
|
33
|
+
*
|
|
34
|
+
* No Vite config is the classic compiler — `vitePlugin` is the only way Remix runs on Vite, and it
|
|
35
|
+
* lives in that file — and wiring the entry there would import a module nothing serves.
|
|
36
|
+
*/
|
|
37
|
+
function remixSteps(input) {
|
|
38
|
+
if (null === input.viteConfig) {
|
|
39
|
+
return [
|
|
40
|
+
{
|
|
41
|
+
title: StepTitle.CONNECT_SNIPPET_REMIX,
|
|
42
|
+
target: REMIX_CLASSIC_TARGET,
|
|
43
|
+
status: StepStatus.MANUAL,
|
|
44
|
+
detail: REMIX_CLASSIC_MANUAL,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
return [
|
|
49
|
+
...reactRouterSteps(input, StepTitle.CONNECT_SNIPPET_REMIX, remixEntryFile),
|
|
50
|
+
// The plugin stamps file:line, and it is also what serves the `/@reticle-connect` module the
|
|
51
|
+
// entry imports.
|
|
52
|
+
...viteSteps(input, VITE_PLUGIN_DETAIL.REACT_ROUTER),
|
|
53
|
+
];
|
|
54
|
+
}
|
|
25
55
|
// An app dev installs exactly the audience-scoped browser-side dependencies — never the retired
|
|
26
56
|
// `@reticlehq/core` umbrella (which dragged the Node MCP server + ws into every app). The kit is the
|
|
27
57
|
// framework adapter (it re-exports the browser sensor), paired with that framework's dev-only build
|
|
@@ -29,10 +59,33 @@ import { electronViteSteps } from './plan-electron-vite.js';
|
|
|
29
59
|
export const RETICLE_REACT_KIT = '@reticlehq/react';
|
|
30
60
|
/** The framework-neutral sensor, for stacks the React adapter has nothing to attach to. */
|
|
31
61
|
export const RETICLE_BROWSER_SDK = '@reticlehq/browser';
|
|
32
|
-
|
|
33
|
-
|
|
62
|
+
const RETICLE_VITE_PLUGIN = '@reticlehq/vite-plugin';
|
|
63
|
+
const RETICLE_NEXT_PLUGIN = '@reticlehq/next';
|
|
34
64
|
/** The Electron main/preload helper — what makes IPC and screenshots exist at all. */
|
|
35
|
-
|
|
65
|
+
const RETICLE_ELECTRON = '@reticlehq/electron';
|
|
66
|
+
/**
|
|
67
|
+
* The stacks the install gate scaffolds from scratch on every change (`SCAFFOLDS` in
|
|
68
|
+
* `apps/e2e/install-gate.mjs`), as framework → the UI libraries its scaffolds render.
|
|
69
|
+
*
|
|
70
|
+
* The one place `init` says which setups are PROVEN. Nuxt was labelled "vue is UNVERIFIED" while the
|
|
71
|
+
* gate scaffolded it on every change, because nothing here knew the gate existed. Add a scaffold
|
|
72
|
+
* there, add its stack here. Only the setup is proven: no gate drives these apps to a verdict.
|
|
73
|
+
*/
|
|
74
|
+
const INSTALL_GATE_STACKS = {
|
|
75
|
+
[Framework.VITE]: [UiLibrary.REACT, UiLibrary.VUE, UiLibrary.UNKNOWN],
|
|
76
|
+
[Framework.NEXT]: [UiLibrary.REACT],
|
|
77
|
+
[Framework.NUXT]: [UiLibrary.VUE],
|
|
78
|
+
[Framework.REACT_ROUTER]: [UiLibrary.REACT],
|
|
79
|
+
[Framework.REMIX]: [UiLibrary.REACT],
|
|
80
|
+
[Framework.ASTRO]: [UiLibrary.UNKNOWN],
|
|
81
|
+
[Framework.SVELTEKIT]: [UiLibrary.SVELTE],
|
|
82
|
+
[Framework.CRA]: [UiLibrary.REACT],
|
|
83
|
+
[Framework.ANGULAR]: [UiLibrary.UNKNOWN],
|
|
84
|
+
};
|
|
85
|
+
/** Whether the install gate scaffolds this stack — see INSTALL_GATE_STACKS. */
|
|
86
|
+
export function installGated(framework, uiLibrary) {
|
|
87
|
+
return INSTALL_GATE_STACKS[framework]?.includes(uiLibrary) ?? false;
|
|
88
|
+
}
|
|
36
89
|
export const FRAMEWORK_ADAPTERS = {
|
|
37
90
|
[Framework.NEXT]: {
|
|
38
91
|
// Next is React by construction, so the detection cannot disagree in a way worth honouring.
|
|
@@ -72,7 +125,9 @@ export const FRAMEWORK_ADAPTERS = {
|
|
|
72
125
|
packages: (kit) => [kit, RETICLE_VITE_PLUGIN],
|
|
73
126
|
// The Vite plugin too, for the reason SvelteKit gets it: React Router framework mode IS a Vite
|
|
74
127
|
// app, and the plugin is what stamps data-reticle-source. Without it the app connects and every
|
|
75
|
-
// verdict comes back with no file:line.
|
|
128
|
+
// verdict comes back with no file:line. Injection stays ON, unlike SvelteKit and Start: the
|
|
129
|
+
// client entry imports `/@reticle-connect`, which the plugin serves only while inject is on, and
|
|
130
|
+
// that module is what loads the dev module here.
|
|
76
131
|
steps: (input) => [
|
|
77
132
|
...reactRouterSteps(input),
|
|
78
133
|
...viteSteps(input, VITE_PLUGIN_DETAIL.REACT_ROUTER),
|
|
@@ -86,16 +141,22 @@ export const FRAMEWORK_ADAPTERS = {
|
|
|
86
141
|
// The Vite plugin as well as the client hook. `init` already INSTALLS @reticlehq/vite-plugin for
|
|
87
142
|
// SvelteKit and then never wired it into the config, so it sat in package.json doing nothing —
|
|
88
143
|
// which is why a SvelteKit app connected fine and every verdict had no file:line.
|
|
89
|
-
|
|
144
|
+
// `inject: false` because the client hook connects; the plugin's injection never fires here, and
|
|
145
|
+
// left on it only warns ten seconds into every page load that the app will never connect.
|
|
146
|
+
steps: (input) => [
|
|
147
|
+
...svelteKitSteps(input),
|
|
148
|
+
...viteSteps(input, VITE_PLUGIN_DETAIL.SVELTEKIT, false),
|
|
149
|
+
],
|
|
90
150
|
connectStepTitles: [StepTitle.CLIENT_HOOK, StepTitle.VITE_PLUGIN],
|
|
91
151
|
carriesOwnUnverifiedNote: true,
|
|
92
152
|
},
|
|
93
153
|
[Framework.ASTRO]: {
|
|
94
154
|
// Astro owns its own Vite instance and renders its own HTML, so there is no config for the
|
|
95
|
-
// plugin to attach to — the kit alone, connected from a
|
|
155
|
+
// plugin to attach to — the kit alone, connected from a local module the page imports
|
|
156
|
+
// (see astroManual).
|
|
96
157
|
packages: (kit) => [kit],
|
|
97
158
|
steps: astroSteps,
|
|
98
|
-
connectStepTitles: [StepTitle.CONNECT_SNIPPET_ASTRO],
|
|
159
|
+
connectStepTitles: [StepTitle.CONNECT_SNIPPET_ASTRO, StepTitle.ASTRO_RETICLE_DEV],
|
|
99
160
|
carriesOwnUnverifiedNote: false,
|
|
100
161
|
},
|
|
101
162
|
[Framework.ELECTRON_VITE]: {
|
|
@@ -108,6 +169,35 @@ export const FRAMEWORK_ADAPTERS = {
|
|
|
108
169
|
connectStepTitles: [StepTitle.ELECTRON_VITE_PLUGIN],
|
|
109
170
|
carriesOwnUnverifiedNote: false,
|
|
110
171
|
},
|
|
172
|
+
[Framework.ELECTRON_FORGE]: {
|
|
173
|
+
// electron-vite's three packages, with the kit the UI-library check chose: Forge's Vite template
|
|
174
|
+
// renders no React, and `@reticlehq/react` carries `react` in its peer dependencies.
|
|
175
|
+
packages: (kit) => [kit, RETICLE_VITE_PLUGIN, RETICLE_ELECTRON],
|
|
176
|
+
steps: electronForgeSteps,
|
|
177
|
+
// The renderer config's plugin IS the connect, as under electron-vite.
|
|
178
|
+
connectStepTitles: [StepTitle.VITE_PLUGIN],
|
|
179
|
+
carriesOwnUnverifiedNote: false,
|
|
180
|
+
},
|
|
181
|
+
[Framework.REMIX]: {
|
|
182
|
+
// React Router framework mode's packages, for the reason its steps are that mode's: the same
|
|
183
|
+
// framework under its previous name.
|
|
184
|
+
packages: (kit) => [kit, RETICLE_VITE_PLUGIN],
|
|
185
|
+
steps: remixSteps,
|
|
186
|
+
connectStepTitles: [StepTitle.CONNECT_SNIPPET_REMIX, StepTitle.VITE_PLUGIN],
|
|
187
|
+
carriesOwnUnverifiedNote: false,
|
|
188
|
+
},
|
|
189
|
+
[Framework.ANGULAR]: {
|
|
190
|
+
// The sensor alone. There is no build plugin for the Angular CLI to load, and the React kit is
|
|
191
|
+
// what used to be installed here, with `react` beside it.
|
|
192
|
+
packages: () => [RETICLE_BROWSER_SDK],
|
|
193
|
+
steps: angularSteps,
|
|
194
|
+
connectStepTitles: [
|
|
195
|
+
StepTitle.CONNECT_SNIPPET_ANGULAR,
|
|
196
|
+
StepTitle.ANGULAR_TOKEN_PROXY,
|
|
197
|
+
StepTitle.ANGULAR_SERVE_CONFIG,
|
|
198
|
+
],
|
|
199
|
+
carriesOwnUnverifiedNote: true,
|
|
200
|
+
},
|
|
111
201
|
[Framework.TANSTACK_START]: {
|
|
112
202
|
// Start IS a Vite app, so the plugin still stamps `data-reticle-source` — only the connect
|
|
113
203
|
// injection is inapplicable, and that is the plan's business (`inject: false`).
|
|
@@ -116,7 +206,11 @@ export const FRAMEWORK_ADAPTERS = {
|
|
|
116
206
|
...tanstackStartSteps(input),
|
|
117
207
|
...viteSteps(input, VITE_PLUGIN_DETAIL.TANSTACK_START, false),
|
|
118
208
|
],
|
|
119
|
-
connectStepTitles: [
|
|
209
|
+
connectStepTitles: [
|
|
210
|
+
StepTitle.CONNECT_SNIPPET_TANSTACK_START,
|
|
211
|
+
StepTitle.TANSTACK_START_CONNECT_COMPONENT,
|
|
212
|
+
StepTitle.VITE_PLUGIN,
|
|
213
|
+
],
|
|
120
214
|
// The Start recipe carries its own UNVERIFIED line; a second generic notice would argue with it.
|
|
121
215
|
carriesOwnUnverifiedNote: true,
|
|
122
216
|
},
|
package/dist/plan/notices.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { CONTAINERISED_TITLE, containerisedDevServerNote } from '../diagnose/containerised-dev-server.js';
|
|
12
12
|
import { mcpWindowsNote } from '../register/mcp.js';
|
|
13
13
|
import { unverifiedUiLibraryNote, WEBGL_CANVAS_LIMIT_NOTE } from '../patch/snippets.js';
|
|
14
|
-
import { FRAMEWORK_ADAPTERS } from './framework-adapter.js';
|
|
14
|
+
import { FRAMEWORK_ADAPTERS, installGated } from './framework-adapter.js';
|
|
15
15
|
import { NodePlatform } from '../detect/platform.js';
|
|
16
16
|
import { UiLibrary } from '../detect/detect.js';
|
|
17
17
|
// `Step` and `PlanInput` are TYPES, so importing them back from `plan.ts` is erased at build
|
|
@@ -64,12 +64,13 @@ export function uiLibraryStep(input) {
|
|
|
64
64
|
return [];
|
|
65
65
|
if (lib === UiLibrary.UNKNOWN)
|
|
66
66
|
return [];
|
|
67
|
+
const gated = installGated(input.detection.framework, lib);
|
|
67
68
|
return [
|
|
68
69
|
{
|
|
69
|
-
title: `${lib} is UNVERIFIED`,
|
|
70
|
+
title: gated ? `${lib} setup verified, drive unverified` : `${lib} is UNVERIFIED`,
|
|
70
71
|
target: 'package.json',
|
|
71
72
|
status: StepStatus.NOTICE,
|
|
72
|
-
detail: unverifiedUiLibraryNote(lib),
|
|
73
|
+
detail: unverifiedUiLibraryNote(lib, gated),
|
|
73
74
|
},
|
|
74
75
|
];
|
|
75
76
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular CLI: the dev-only connect in the browser entry, and the dev-server route that hands it
|
|
3
|
+
* the pairing token. See `patch/angular.ts` for why the token takes that route and no other.
|
|
4
|
+
*/
|
|
5
|
+
import { type PlanInput, type Step } from './plan-types.js';
|
|
6
|
+
export declare function angularSteps(input: PlanInput): Step[];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angular CLI: the dev-only connect in the browser entry, and the dev-server route that hands it
|
|
3
|
+
* the pairing token. See `patch/angular.ts` for why the token takes that route and no other.
|
|
4
|
+
*/
|
|
5
|
+
import { ANGULAR_DEFAULT_ENTRY, ANGULAR_PROXY_PATH, ANGULAR_TOKEN_PATH, angularProxyFile, patchAngularJson, patchAngularMain, } from '../patch/angular.js';
|
|
6
|
+
import { PatchKind } from '../patch/patch-kind.js';
|
|
7
|
+
import { ANGULAR_WORKSPACE_FILE } from '../detect/detect.js';
|
|
8
|
+
import { StepTitle } from './connect-steps.js';
|
|
9
|
+
import { patchStep } from './plan-framework.js';
|
|
10
|
+
import { alreadyOrMovedPort, retargetPort } from './port-steps.js';
|
|
11
|
+
import { StepStatus } from './plan-types.js';
|
|
12
|
+
const ANGULAR_SETUP_GATED_NOTE = 'The install gate scaffolds an Angular app (Angular 21, no SSR) on every release and requires a ' +
|
|
13
|
+
'session, and this wiring was proven by hand on Angular 22 with and without SSR; nothing yet ' +
|
|
14
|
+
'drives an Angular app to a verdict on each change. DOM, network, console and state ' +
|
|
15
|
+
'tools work here; component identity does not (that is the React adapter). If no session ' +
|
|
16
|
+
'appears, please open an issue.';
|
|
17
|
+
const ENTRY_DETAIL = 'connect from the browser entry, dev-only (`ngDevMode`), through a dynamic import the ' +
|
|
18
|
+
'production build drops';
|
|
19
|
+
const PROXY_DETAIL = 'the `ng serve`-only module that hands the page this machine’s pairing token, read from ' +
|
|
20
|
+
'~/.reticle at request time — never written into the project';
|
|
21
|
+
const SERVE_DETAIL = `point the serve target's proxyConfig at ${ANGULAR_PROXY_PATH} (\`ng build\` never reads it)`;
|
|
22
|
+
/** The full recipe, for when the entry is not a file `init` can see. */
|
|
23
|
+
function entryManual(input, entryPath) {
|
|
24
|
+
const recipe = patchAngularMain('', input.options.port, input.options.projectId);
|
|
25
|
+
const code = recipe.kind === PatchKind.APPLY ? recipe.code : '';
|
|
26
|
+
return `Add this to your browser entry (${entryPath}):\n\n${code}`;
|
|
27
|
+
}
|
|
28
|
+
function proxyStep(input) {
|
|
29
|
+
const existing = input.angularProxySource ?? null;
|
|
30
|
+
if (null !== existing && existing.includes(ANGULAR_TOKEN_PATH)) {
|
|
31
|
+
return {
|
|
32
|
+
title: StepTitle.ANGULAR_TOKEN_PROXY,
|
|
33
|
+
target: ANGULAR_PROXY_PATH,
|
|
34
|
+
status: StepStatus.ALREADY,
|
|
35
|
+
detail: 'already there',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
title: StepTitle.ANGULAR_TOKEN_PROXY,
|
|
40
|
+
target: ANGULAR_PROXY_PATH,
|
|
41
|
+
status: StepStatus.APPLY,
|
|
42
|
+
detail: PROXY_DETAIL,
|
|
43
|
+
write: { path: ANGULAR_PROXY_PATH, content: angularProxyFile(), expect: [ANGULAR_TOKEN_PATH] },
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function serveStep(input) {
|
|
47
|
+
const workspace = input.angularWorkspace ?? null;
|
|
48
|
+
const manual = `In ${ANGULAR_WORKSPACE_FILE}, set the serve target's "options.proxyConfig" to "${ANGULAR_PROXY_PATH}".`;
|
|
49
|
+
if (null === workspace) {
|
|
50
|
+
return {
|
|
51
|
+
title: StepTitle.ANGULAR_SERVE_CONFIG,
|
|
52
|
+
target: ANGULAR_WORKSPACE_FILE,
|
|
53
|
+
status: StepStatus.MANUAL,
|
|
54
|
+
detail: manual,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return patchStep(StepTitle.ANGULAR_SERVE_CONFIG, workspace.path, patchAngularJson(workspace.source), SERVE_DETAIL, manual);
|
|
58
|
+
}
|
|
59
|
+
function entryStep(input) {
|
|
60
|
+
const entry = input.angularEntry ?? null;
|
|
61
|
+
if (null === entry) {
|
|
62
|
+
return {
|
|
63
|
+
title: StepTitle.CONNECT_SNIPPET_ANGULAR,
|
|
64
|
+
target: ANGULAR_DEFAULT_ENTRY,
|
|
65
|
+
status: StepStatus.MANUAL,
|
|
66
|
+
detail: entryManual(input, ANGULAR_DEFAULT_ENTRY),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// "already wired" read the entry without reading the port baked into its connect, so a re-run
|
|
70
|
+
// with a new `--port` left the page dialling the old daemon.
|
|
71
|
+
const patch = patchAngularMain(entry.source, input.options.port, input.options.projectId);
|
|
72
|
+
// An entry the previous version wired is rewritten in place (its guard), so a re-run that ALSO
|
|
73
|
+
// moves the port has to move it in the rewritten code — the ALREADY path below never sees it.
|
|
74
|
+
const moved = PatchKind.APPLY === patch.kind ? retargetPort(patch.code, input.options.port) : null;
|
|
75
|
+
return alreadyOrMovedPort(patchStep(StepTitle.CONNECT_SNIPPET_ANGULAR, entry.path, null === moved ? patch : { kind: PatchKind.APPLY, code: moved.code }, ENTRY_DETAIL, entryManual(input, entry.path)), entry.source, input.options.port);
|
|
76
|
+
}
|
|
77
|
+
export function angularSteps(input) {
|
|
78
|
+
return [
|
|
79
|
+
{
|
|
80
|
+
title: StepTitle.ANGULAR_SETUP_GATED,
|
|
81
|
+
target: ANGULAR_WORKSPACE_FILE,
|
|
82
|
+
status: StepStatus.NOTICE,
|
|
83
|
+
detail: ANGULAR_SETUP_GATED_NOTE,
|
|
84
|
+
},
|
|
85
|
+
entryStep(input),
|
|
86
|
+
proxyStep(input),
|
|
87
|
+
serveStep(input),
|
|
88
|
+
];
|
|
89
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The plan's
|
|
2
|
+
* The plan's Electron half: the renderer plugin, capabilities, and the two Electron steps — for
|
|
3
|
+
* electron-vite and for Electron Forge's Vite template, which differ only in where the renderer's
|
|
4
|
+
* Vite config lives.
|
|
3
5
|
*
|
|
4
|
-
* Its own module because
|
|
5
|
-
* a preload and a main process the web frameworks have no equivalent of.
|
|
6
|
+
* Its own module because these are the only frameworks whose wiring reaches outside the renderer,
|
|
7
|
+
* into a preload and a main process the web frameworks have no equivalent of.
|
|
6
8
|
*/
|
|
7
9
|
import { type PlanInput, type Step } from './plan-types.js';
|
|
8
10
|
/**
|
|
@@ -13,3 +15,4 @@ import { type PlanInput, type Step } from './plan-types.js';
|
|
|
13
15
|
* manual recipe the way Astro's config+layout pair does.
|
|
14
16
|
*/
|
|
15
17
|
export declare function electronViteSteps(input: PlanInput): Step[];
|
|
18
|
+
export declare function electronForgeSteps(input: PlanInput): Step[];
|