@reticlehq/init 3.3.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/detect/capabilities.d.ts +4 -1
- package/dist/detect/capabilities.js +45 -9
- package/dist/detect/detect.d.ts +45 -2
- package/dist/detect/detect.js +76 -5
- 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.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 +13 -1
- package/dist/diagnose/csp-doctor.js +2 -2
- package/dist/diagnose/csp-step.d.ts +27 -0
- package/dist/diagnose/csp-step.js +86 -0
- package/dist/diagnose/desktop-doctor.js +8 -2
- package/dist/diagnose/init-failure.d.ts +7 -0
- package/dist/diagnose/init-failure.js +7 -0
- package/dist/diagnose/install-hint.d.ts +9 -1
- package/dist/diagnose/install-hint.js +17 -7
- package/dist/diagnose/install-retries.d.ts +16 -1
- 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/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/dist/no-package-json.d.ts +10 -0
- package/dist/no-package-json.js +131 -0
- package/dist/node-io.d.ts +12 -6
- package/dist/node-io.js +33 -11
- package/dist/patch/angular.d.ts +68 -0
- package/dist/patch/angular.js +216 -0
- package/dist/patch/astro-patch.d.ts +1 -1
- package/dist/patch/astro-patch.js +2 -2
- 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.js +6 -6
- package/dist/patch/remix.d.ts +24 -0
- package/dist/patch/remix.js +59 -0
- package/dist/patch/snippets.d.ts +57 -9
- package/dist/patch/snippets.js +119 -28
- 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-owning-config.d.ts +34 -0
- package/dist/patch/vite-owning-config.js +63 -5
- package/dist/plan/connect-steps.d.ts +7 -1
- package/dist/plan/connect-steps.js +18 -1
- package/dist/plan/framework-adapter.d.ts +3 -1
- package/dist/plan/framework-adapter.js +99 -6
- 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 +8 -46
- package/dist/plan/plan-framework.js +81 -312
- package/dist/plan/plan-types.d.ts +29 -0
- package/dist/plan/plan-vite.d.ts +67 -0
- package/dist/plan/plan-vite.js +256 -0
- package/dist/plan/plan.js +38 -34
- 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/register/mcp-clients.js +5 -3
- package/dist/register/mcp.d.ts +18 -5
- package/dist/register/mcp.js +48 -8
- package/dist/run-types.d.ts +8 -0
- package/dist/run.js +118 -80
- package/package.json +3 -4
- package/NOTICE +0 -5
|
@@ -1,52 +1,141 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The TanStack Start connect
|
|
2
|
+
* The TanStack Start connect: a client-only component, rendered in the document the root route SSRs.
|
|
3
3
|
*
|
|
4
|
-
* Its own module because Start is the one framework whose document module
|
|
5
|
-
*
|
|
4
|
+
* Its own module because Start is the one framework whose document module is ALSO the server
|
|
5
|
+
* render, so what may be written into it — and what must stay out — is a unit.
|
|
6
6
|
*/
|
|
7
|
+
import { posix } from 'node:path';
|
|
7
8
|
import { UiLibrary } from '../detect/detect.js';
|
|
8
|
-
import { connectArg, sdkImport, UNVERIFIED_TANSTACK_START_NOTE } from './snippets.js';
|
|
9
|
+
import { connectArg, devModuleSpecifier, sdkImport, UNVERIFIED_TANSTACK_START_NOTE, } from './snippets.js';
|
|
10
|
+
import { PatchKind } from './patch-kind.js';
|
|
11
|
+
import { VITE_ENV_DEV_DECLARATION } from './vite-env-types.js';
|
|
9
12
|
/** TanStack Start's document module — the file that SSRs `<html>`. */
|
|
10
13
|
export const TANSTACK_START_ROOT_PATH = 'src/routes/__root.tsx';
|
|
14
|
+
/** The component `init` writes, and renders in the root document. */
|
|
15
|
+
const CONNECT_COMPONENT = 'ReticleConnect';
|
|
16
|
+
const CONNECT_FILE_BASENAME = 'reticle-connect';
|
|
17
|
+
/** `<Scripts />` — Start's own client-script outlet, which every root document has to render. */
|
|
18
|
+
const SCRIPTS_OUTLET = /^([ \t]*)<Scripts\s*\/>/m;
|
|
11
19
|
/**
|
|
12
|
-
*
|
|
20
|
+
* Where the connect component goes: beside the `routes/` directory, never inside it — a file under
|
|
21
|
+
* `routes/` is a route to Start's file-based router.
|
|
22
|
+
*/
|
|
23
|
+
export function tanstackStartConnectPath(rootPath = TANSTACK_START_ROOT_PATH) {
|
|
24
|
+
return posix.join(posix.dirname(posix.dirname(rootPath)), `${CONNECT_FILE_BASENAME}.tsx`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The connect component.
|
|
28
|
+
*
|
|
29
|
+
* A dynamic SDK import inside `useEffect`, because a static import on anything the root document
|
|
30
|
+
* imports is evaluated during the server render and 500s the page. Effects never run on the server.
|
|
31
|
+
* The pairing token is the one the Vite plugin inlines as `__RETICLE_TOKEN__`, declared here so the
|
|
32
|
+
* file passes the scaffold's strict `tsc` — the recipe this replaced used the name undeclared and
|
|
33
|
+
* failed with `TS2304: Cannot find name '__RETICLE_TOKEN__'`.
|
|
13
34
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* makes about `app/entry.client.tsx`: a half-written document is worse than a documented manual step.
|
|
35
|
+
* It also loads the app's `src/reticle-dev.ts` after connecting. Start is written `inject: false`,
|
|
36
|
+
* and the plugin's injected connect is the only other thing that imports that file, so without this
|
|
37
|
+
* line every store and capability registered there silently never ran.
|
|
18
38
|
*/
|
|
19
|
-
export function
|
|
39
|
+
export function tanstackStartConnectFile(port, projectId, rootPath = TANSTACK_START_ROOT_PATH) {
|
|
20
40
|
const sdk = sdkImport(UiLibrary.REACT);
|
|
21
41
|
const base = connectArg(port, projectId);
|
|
22
42
|
const fields = '' === base ? '' : `${base.slice(1, -1).trim()}, `;
|
|
23
|
-
const installLine = sdk.usesInstall
|
|
24
|
-
? ' install();'
|
|
25
|
-
: ' // No React adapter here: the sensor has no install() to call.';
|
|
26
43
|
const imports = sdk.usesInstall ? 'reticle, install' : 'reticle';
|
|
44
|
+
const installLine = sdk.usesInstall
|
|
45
|
+
? ' install();'
|
|
46
|
+
: ' // No React adapter here: the sensor has no install() to call.';
|
|
47
|
+
const devModule = devModuleSpecifier(tanstackStartConnectPath(rootPath));
|
|
48
|
+
return `import { useEffect } from 'react';
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Dev-only: connect Reticle from the client. Start SSRs its own <html> and never sends Vite's
|
|
52
|
+
* index.html, so the plugin's injection cannot do it. Rendered once in the root document.
|
|
53
|
+
*/
|
|
54
|
+
export function ${CONNECT_COMPONENT}() {
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!import.meta.env.DEV) return;
|
|
57
|
+
// Inlined by @reticlehq/vite-plugin. The bridge refuses a connect without it, even on localhost.
|
|
58
|
+
const token = typeof __RETICLE_TOKEN__ !== 'undefined' ? __RETICLE_TOKEN__ : '';
|
|
59
|
+
const root = typeof __RETICLE_ROOT__ !== 'undefined' ? __RETICLE_ROOT__ : '';
|
|
60
|
+
void import('${sdk.specifier}').then(({ ${imports} }) => {
|
|
61
|
+
${installLine}
|
|
62
|
+
reticle.connect({
|
|
63
|
+
${fields}...(token.length > 0 ? { token } : {}),
|
|
64
|
+
...(root.length > 0 ? { root } : {}),
|
|
65
|
+
});
|
|
66
|
+
// Your stores and capabilities live here; nothing else loads this file under Start.
|
|
67
|
+
void import('${devModule}');
|
|
68
|
+
});
|
|
69
|
+
}, []);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
declare const __RETICLE_TOKEN__: string | undefined;
|
|
74
|
+
declare const __RETICLE_ROOT__: string | undefined;
|
|
75
|
+
|
|
76
|
+
${VITE_ENV_DEV_DECLARATION}`;
|
|
77
|
+
}
|
|
78
|
+
/** The import the root document gets, relative to where it lives. */
|
|
79
|
+
function connectImport(rootPath) {
|
|
80
|
+
const target = tanstackStartConnectPath(rootPath).replace(/\.tsx$/, '');
|
|
81
|
+
const rel = posix.relative(posix.dirname(rootPath), target);
|
|
82
|
+
return `import { ${CONNECT_COMPONENT} } from '${rel.startsWith('.') ? rel : `./${rel}`}';`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Render the component in the root document, just before `<Scripts />`.
|
|
86
|
+
*
|
|
87
|
+
* `<Scripts />` is the anchor because every Start root has to render it — it is how the client
|
|
88
|
+
* bundle reaches the page — whatever the component around it is called (`RootDocument` as the
|
|
89
|
+
* route's `shellComponent` in the current template; `RootComponent` in older ones). A root without
|
|
90
|
+
* one is a shape we do not recognise, and a half-edited document is worse than a documented step.
|
|
91
|
+
*/
|
|
92
|
+
export function patchTanstackStartRoot(source, rootPath) {
|
|
93
|
+
if (source.includes(CONNECT_COMPONENT))
|
|
94
|
+
return { kind: PatchKind.ALREADY };
|
|
95
|
+
if (!rootPath.endsWith('.tsx')) {
|
|
96
|
+
return { kind: PatchKind.MANUAL, reason: `${rootPath} is not TypeScript` };
|
|
97
|
+
}
|
|
98
|
+
const outlet = SCRIPTS_OUTLET.exec(source);
|
|
99
|
+
if (null === outlet) {
|
|
100
|
+
return { kind: PatchKind.MANUAL, reason: `no <Scripts /> found in ${rootPath}` };
|
|
101
|
+
}
|
|
102
|
+
const indent = outlet[1] ?? '';
|
|
103
|
+
const rendered = source.replace(SCRIPTS_OUTLET, `${indent}<${CONNECT_COMPONENT} />\n$&`);
|
|
104
|
+
const lines = rendered.split('\n');
|
|
105
|
+
let lastImport = -1;
|
|
106
|
+
for (const [index, line] of lines.entries()) {
|
|
107
|
+
if (/^import\s/.test(line))
|
|
108
|
+
lastImport = index;
|
|
109
|
+
}
|
|
110
|
+
lines.splice(lastImport + 1, 0, connectImport(rootPath));
|
|
111
|
+
return { kind: PatchKind.APPLY, code: lines.join('\n') };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The recipe, for a root `patchTanstackStartRoot` would not edit.
|
|
115
|
+
*
|
|
116
|
+
* The same two edits it makes, stated as edits: create the component, render it before
|
|
117
|
+
* `<Scripts />`. It used to say "add this useEffect to the App component", naming a component the
|
|
118
|
+
* current template does not have, and its snippet used `__RETICLE_TOKEN__` undeclared.
|
|
119
|
+
*/
|
|
120
|
+
export function tanstackStartManual(port, projectId, rootPath = TANSTACK_START_ROOT_PATH) {
|
|
121
|
+
const component = tanstackStartConnectFile(port, projectId, rootPath)
|
|
122
|
+
.split('\n')
|
|
123
|
+
.map((line) => (0 === line.length ? line : ` ${line}`))
|
|
124
|
+
.join('\n');
|
|
27
125
|
return `TanStack Start SSRs <html> from ${rootPath} (HeadContent / Scripts) and never sends Vite's
|
|
28
126
|
index.html, so the plugin's connect injection never fires. Keep the plugin anyway, with
|
|
29
127
|
reticle({ inject: false }): only the injection half is inapplicable, and the stamping half is
|
|
30
128
|
what puts data-reticle-source on the JSX. Dropping the plugin because one of its two jobs did
|
|
31
129
|
not apply is how Remix lost file:line.
|
|
32
130
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Add this useEffect to the App component (import useEffect from react if it is not already there):
|
|
131
|
+
1. Create ${tanstackStartConnectPath(rootPath)}. It connects from a CLIENT-ONLY effect: a static SDK
|
|
132
|
+
import on anything the root document imports SSRs and 500s.
|
|
133
|
+
Do not guard on window.location.hostname === 'localhost' — import.meta.env.DEV is the correct
|
|
134
|
+
guard, and it does not care what host you develop on.
|
|
38
135
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
void import('${sdk.specifier}').then(({ ${imports} }) => {
|
|
43
|
-
${installLine}
|
|
44
|
-
reticle.connect({
|
|
45
|
-
${fields}...(token.length > 0 ? { token } : {}),
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}, []);
|
|
136
|
+
${component}
|
|
137
|
+
2. In ${rootPath}, add \`${connectImport(rootPath)}\` and render <${CONNECT_COMPONENT} /> in the
|
|
138
|
+
component that renders <html> (the route's shellComponent), just before <Scripts />.
|
|
50
139
|
|
|
51
140
|
The plugin inlines __RETICLE_TOKEN__ when Vite resolves its config. Start the daemon BEFORE the
|
|
52
141
|
dev server so that file exists; a server that started first froze an empty token and the page
|
|
@@ -14,5 +14,10 @@ export declare const VitePatchKind: {
|
|
|
14
14
|
};
|
|
15
15
|
export type VitePatchKind = PatchKind;
|
|
16
16
|
type VitePatch = SourcePatch;
|
|
17
|
+
/**
|
|
18
|
+
* A whole config for a plain Vite app that has none: Vite's defaults plus the plugin. Written out
|
|
19
|
+
* rather than patched from an empty one, because it is a file the person will open and read.
|
|
20
|
+
*/
|
|
21
|
+
export declare function newViteConfig(port?: number, captureBodies?: boolean, inject?: boolean, sourceMapping?: boolean): string;
|
|
17
22
|
export declare function patchViteConfig(source: string, port?: number, captureBodies?: boolean, inject?: boolean, sourceMapping?: boolean): VitePatch;
|
|
18
23
|
export {};
|
|
@@ -98,6 +98,14 @@ function insertPluginsKey(source, call) {
|
|
|
98
98
|
return multiline ? `${prefix}{\n${indent}${key}` : `${prefix}{ ${key}`;
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* A whole config for a plain Vite app that has none: Vite's defaults plus the plugin. Written out
|
|
103
|
+
* rather than patched from an empty one, because it is a file the person will open and read.
|
|
104
|
+
*/
|
|
105
|
+
export function newViteConfig(port, captureBodies = false, inject = true, sourceMapping = true) {
|
|
106
|
+
const call = reticlePluginCall({ port, captureBodies, inject, sourceMapping });
|
|
107
|
+
return `import { defineConfig } from 'vite';\n${VITE_IMPORT}\n\nexport default defineConfig({\n plugins: [${call}],\n});\n`;
|
|
108
|
+
}
|
|
101
109
|
export function patchViteConfig(source, port, captureBodies = false, inject = true, sourceMapping = true) {
|
|
102
110
|
if (source.includes(RETICLE_MARKER)) {
|
|
103
111
|
return { kind: VitePatchKind.ALREADY };
|
|
@@ -34,5 +34,39 @@ export interface ViteOwningConfig {
|
|
|
34
34
|
* path writes. Astro's path never writes that name into the config, so it supplies its own.
|
|
35
35
|
*/
|
|
36
36
|
readonly alreadyMarker?: string;
|
|
37
|
+
/**
|
|
38
|
+
* The installed Vite's major (see `installedViteMajor`), or null when nothing on disk said.
|
|
39
|
+
*
|
|
40
|
+
* Decides whether the dep-optimizer target is written at all. Vite 7 moved the optimizer to
|
|
41
|
+
* rolldown and deprecated `optimizeDeps.esbuildOptions`: on Nuxt 4.5 / Vite 8 the key printed a
|
|
42
|
+
* deprecation warning on every dev start and build. The target exists for esbuild, which cannot
|
|
43
|
+
* lower some of the SDK's syntax to Vite's older default; rolldown has no such gap, so on 7+ there
|
|
44
|
+
* is nothing to write under either key.
|
|
45
|
+
*/
|
|
46
|
+
readonly viteMajor?: number | null | undefined;
|
|
37
47
|
}
|
|
38
48
|
export declare function patchViteOwningConfig(source: string, config: ViteOwningConfig): SourcePatch;
|
|
49
|
+
/**
|
|
50
|
+
* The major version of the Vite this app will actually run, read from disk.
|
|
51
|
+
*
|
|
52
|
+
* Needed by the configs `init` patches for frameworks that own their Vite instance (Nuxt, Astro):
|
|
53
|
+
* Vite 7 moved the dep optimizer to rolldown and deprecated `optimizeDeps.esbuildOptions`, so the
|
|
54
|
+
* key `init` wrote printed a deprecation warning on every dev start and build there. The Vite
|
|
55
|
+
* plugin answers the same question for itself (`optimizerOptionsKey` in @reticlehq/vite-plugin),
|
|
56
|
+
* but these frameworks never load the plugin.
|
|
57
|
+
*
|
|
58
|
+
* Nuxt and Astro do not list `vite` in the app's package.json — it comes with the framework — so the
|
|
59
|
+
* declared range is the last resort, after the hoisted package and pnpm's store. Null when none
|
|
60
|
+
* says: the caller keeps the older key, as the plugin does, because a deprecation notice is a much
|
|
61
|
+
* smaller failure than an option the installed Vite has never heard of.
|
|
62
|
+
*/
|
|
63
|
+
interface ViteReader {
|
|
64
|
+
readFile(relPath: string): string | null;
|
|
65
|
+
listDirs(relPath: string): readonly string[];
|
|
66
|
+
}
|
|
67
|
+
interface DeclaredDeps {
|
|
68
|
+
dependencies?: Record<string, string>;
|
|
69
|
+
devDependencies?: Record<string, string>;
|
|
70
|
+
}
|
|
71
|
+
export declare function installedViteMajor(io: ViteReader, pkg: DeclaredDeps): number | null;
|
|
72
|
+
export {};
|
|
@@ -15,8 +15,31 @@
|
|
|
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
44
|
const DEFINE_TOKEN_MARKER = '__RETICLE_TOKEN__';
|
|
22
45
|
function usesDefineToken(config) {
|
|
@@ -92,7 +115,7 @@ function viteKeys(config) {
|
|
|
92
115
|
{ key: 'build', inner: `\n target: 'es2022',` },
|
|
93
116
|
{
|
|
94
117
|
key: 'optimizeDeps',
|
|
95
|
-
inner: `\n include: [${sdkInclude(config)}]
|
|
118
|
+
inner: `\n include: [${sdkInclude(config)}],${writesEsbuildTarget(config) ? ESBUILD_TARGET_INNER : ''}`,
|
|
96
119
|
},
|
|
97
120
|
// Merged in first, so a `server: { port }` the app already set keeps its port. An app that
|
|
98
121
|
// already sets `server.watch` itself is the one shape this loses to — the inner `watch` key would
|
|
@@ -111,7 +134,7 @@ function viteKeys(config) {
|
|
|
111
134
|
function wholeKeys(config) {
|
|
112
135
|
const keys = {
|
|
113
136
|
build: `\n build: { target: 'es2022' },`,
|
|
114
|
-
optimizeDeps: `\n optimizeDeps: { include: [${sdkInclude(config)}]
|
|
137
|
+
optimizeDeps: `\n optimizeDeps: { include: [${sdkInclude(config)}]${writesEsbuildTarget(config) ? ESBUILD_TARGET_WHOLE : ''} },`,
|
|
115
138
|
server: `\n server: { watch: { ignored: [${WATCH_IGNORE_LITERAL}] } },`,
|
|
116
139
|
};
|
|
117
140
|
if (usesDefineToken(config)) {
|
|
@@ -182,7 +205,7 @@ function viteBlock(config) {
|
|
|
182
205
|
: '';
|
|
183
206
|
return ` vite: {
|
|
184
207
|
${marker} build: { target: 'es2022' },
|
|
185
|
-
optimizeDeps: { include: [${sdkInclude(config)}]
|
|
208
|
+
optimizeDeps: { include: [${sdkInclude(config)}]${writesEsbuildTarget(config) ? ESBUILD_TARGET_WHOLE : ''} },
|
|
186
209
|
${define} server: { watch: { ignored: [${WATCH_IGNORE_LITERAL}] } },
|
|
187
210
|
},
|
|
188
211
|
`;
|
|
@@ -199,8 +222,12 @@ function withOwningMarker(source, config, braceAt) {
|
|
|
199
222
|
return insertAt(source, braceAt, `\n /* ${alreadyMarker(config)} */`);
|
|
200
223
|
}
|
|
201
224
|
export function patchViteOwningConfig(source, config) {
|
|
202
|
-
if (source.includes(alreadyMarker(config)))
|
|
203
|
-
|
|
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
|
+
}
|
|
204
231
|
// A `vite: { ... }` block is an object literal, so our keys can go straight after the brace and
|
|
205
232
|
// whatever is already in there is untouched. Refusing outright was the only genuine install defect
|
|
206
233
|
// left in the gate: the config bailed while the LAYOUT patch applied anyway, leaving an app with a
|
|
@@ -244,3 +271,34 @@ export function patchViteOwningConfig(source, config) {
|
|
|
244
271
|
code: withHelper(withBlock, config),
|
|
245
272
|
};
|
|
246
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,11 +27,17 @@ 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
43
|
readonly ASTRO_RETICLE_DEV: "Astro ReticleDev module";
|
|
@@ -28,11 +28,17 @@ 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
44
|
ASTRO_RETICLE_DEV: 'Astro ReticleDev module',
|
|
@@ -63,6 +69,14 @@ export const CONNECT_STEP_TITLES = new Set([
|
|
|
63
69
|
StepTitle.NUXT_CONFIG,
|
|
64
70
|
StepTitle.CONNECT_SNIPPET_REACT_ROUTER,
|
|
65
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,
|
|
66
80
|
StepTitle.CLIENT_HOOK,
|
|
67
81
|
StepTitle.CONNECT_MODULE,
|
|
68
82
|
StepTitle.RETICLE_DEV_COMPONENT,
|
|
@@ -87,6 +101,9 @@ export const CONNECT_STEP_TITLES = new Set([
|
|
|
87
101
|
// electron-vite's connect IS the renderer plugin. Without it the SDK never injects, and the
|
|
88
102
|
// preload/capture steps are not enough to produce a session.
|
|
89
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,
|
|
90
107
|
]);
|
|
91
108
|
/** True when this step is what makes the app dial the daemon. */
|
|
92
109
|
export function isConnectStep(title) {
|
|
@@ -18,7 +18,7 @@
|
|
|
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";
|
|
@@ -53,6 +53,8 @@ interface FrameworkAdapter {
|
|
|
53
53
|
*/
|
|
54
54
|
readonly carriesOwnUnverifiedNote: boolean;
|
|
55
55
|
}
|
|
56
|
+
/** Whether the install gate scaffolds this stack — see INSTALL_GATE_STACKS. */
|
|
57
|
+
export declare function installGated(framework: Framework, uiLibrary: UiLibrary): boolean;
|
|
56
58
|
export declare const FRAMEWORK_ADAPTERS: Record<Framework, FrameworkAdapter>;
|
|
57
59
|
/**
|
|
58
60
|
* The per-framework half of the plan, looked up rather than switched.
|
|
@@ -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
|
|
@@ -33,6 +63,29 @@ const RETICLE_VITE_PLUGIN = '@reticlehq/vite-plugin';
|
|
|
33
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,7 +141,12 @@ 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
|
},
|
|
@@ -109,6 +169,35 @@ export const FRAMEWORK_ADAPTERS = {
|
|
|
109
169
|
connectStepTitles: [StepTitle.ELECTRON_VITE_PLUGIN],
|
|
110
170
|
carriesOwnUnverifiedNote: false,
|
|
111
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
|
+
},
|
|
112
201
|
[Framework.TANSTACK_START]: {
|
|
113
202
|
// Start IS a Vite app, so the plugin still stamps `data-reticle-source` — only the connect
|
|
114
203
|
// injection is inapplicable, and that is the plan's business (`inject: false`).
|
|
@@ -117,7 +206,11 @@ export const FRAMEWORK_ADAPTERS = {
|
|
|
117
206
|
...tanstackStartSteps(input),
|
|
118
207
|
...viteSteps(input, VITE_PLUGIN_DETAIL.TANSTACK_START, false),
|
|
119
208
|
],
|
|
120
|
-
connectStepTitles: [
|
|
209
|
+
connectStepTitles: [
|
|
210
|
+
StepTitle.CONNECT_SNIPPET_TANSTACK_START,
|
|
211
|
+
StepTitle.TANSTACK_START_CONNECT_COMPONENT,
|
|
212
|
+
StepTitle.VITE_PLUGIN,
|
|
213
|
+
],
|
|
121
214
|
// The Start recipe carries its own UNVERIFIED line; a second generic notice would argue with it.
|
|
122
215
|
carriesOwnUnverifiedNote: true,
|
|
123
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[];
|