@reticlehq/init 3.2.0 → 3.3.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/detect.d.ts +13 -2
- package/dist/detect/detect.js +41 -2
- package/dist/detect/workspace-redirect.d.ts +2 -1
- package/dist/diagnose/csp-doctor.d.ts +20 -1
- package/dist/diagnose/csp-doctor.js +101 -4
- package/dist/diagnose/desktop-doctor.d.ts +1 -1
- package/dist/diagnose/install-retries.d.ts +2 -1
- package/dist/host.d.ts +6 -0
- package/dist/host.js +3 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/patch/astro-patch.d.ts +47 -12
- package/dist/patch/astro-patch.js +149 -41
- package/dist/patch/nuxt-snippets.d.ts +44 -0
- package/dist/patch/nuxt-snippets.js +135 -0
- package/dist/patch/snippets.d.ts +1 -48
- package/dist/patch/snippets.js +63 -175
- 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 +13 -0
- package/dist/patch/vite-owning-config.js +43 -16
- package/dist/plan/connect-steps.d.ts +3 -2
- package/dist/plan/connect-steps.js +4 -2
- package/dist/plan/framework-adapter.d.ts +2 -5
- package/dist/plan/framework-adapter.js +6 -5
- package/dist/plan/plan-framework.d.ts +1 -1
- package/dist/plan/plan-framework.js +33 -11
- package/dist/plan/plan-types.d.ts +18 -2
- package/dist/plan/plan.js +117 -35
- 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 +8 -0
- package/dist/register/mcp.js +16 -0
- package/dist/run-types.d.ts +2 -0
- package/dist/run.js +22 -1
- package/package.json +2 -2
package/dist/detect/detect.d.ts
CHANGED
|
@@ -143,9 +143,20 @@ export interface Detection {
|
|
|
143
143
|
*/
|
|
144
144
|
webGlSubtree?: boolean | undefined;
|
|
145
145
|
packageManager: PackageManager;
|
|
146
|
+
/**
|
|
147
|
+
* Every dependency this package DECLARES, by name, merged across the three blocks.
|
|
148
|
+
*
|
|
149
|
+
* So the planner can tell "not wired yet" from "wired already". Without it the install step could
|
|
150
|
+
* only ever say APPLY, and a re-run over an instrumented project therefore ran a package-manager
|
|
151
|
+
* install it did not need - which is the step that touches `node_modules`.
|
|
152
|
+
*
|
|
153
|
+
* Optional so every existing construction keeps working; absent reads as "nothing known", which
|
|
154
|
+
* installs, and installing twice is the harmless direction.
|
|
155
|
+
*/
|
|
156
|
+
dependencies?: Readonly<Record<string, string>> | undefined;
|
|
146
157
|
}
|
|
147
158
|
/** What identifies one framework in a project root: a dependency name, or a config file basename. */
|
|
148
|
-
|
|
159
|
+
interface FrameworkSignals {
|
|
149
160
|
/** `package.json` dependency names that name this framework outright. */
|
|
150
161
|
readonly deps: readonly string[];
|
|
151
162
|
/** Root config-file basenames that name it when the dependency is absent. */
|
|
@@ -196,7 +207,7 @@ export declare function parseMajor(range: string | undefined): number | undefine
|
|
|
196
207
|
* lockfile once the project's own tree can answer the question.
|
|
197
208
|
*/
|
|
198
209
|
export declare function namesAPackageManager(markers: ReadonlySet<string>): boolean;
|
|
199
|
-
export declare function detectPackageManager(lockfiles: ReadonlySet<string>, nodeModulesMarkers: ReadonlySet<string
|
|
210
|
+
export declare function detectPackageManager(lockfiles: ReadonlySet<string>, nodeModulesMarkers: ReadonlySet<string>, pkg?: unknown): PackageManager;
|
|
200
211
|
export declare function detect(input: DetectInput): Detection;
|
|
201
212
|
interface InstallCommand {
|
|
202
213
|
command: string;
|
package/dist/detect/detect.js
CHANGED
|
@@ -221,7 +221,41 @@ function packageManagerFromNodeModules(markers) {
|
|
|
221
221
|
export function namesAPackageManager(markers) {
|
|
222
222
|
return packageManagerFromNodeModules(markers) !== undefined;
|
|
223
223
|
}
|
|
224
|
-
|
|
224
|
+
/**
|
|
225
|
+
* The manager a project DECLARES, via corepack's `packageManager` field.
|
|
226
|
+
*
|
|
227
|
+
* The strongest signal there is, and stronger than anything else here: a lockfile is evidence of
|
|
228
|
+
* what was run once, an installed tree is evidence of what was run last, and this is the project
|
|
229
|
+
* SAYING which one it uses. Corepack enforces it — it refuses to run a different manager on the
|
|
230
|
+
* project's behalf — so choosing against it produces a command that cannot work.
|
|
231
|
+
*
|
|
232
|
+
* Unrecognised values fall through rather than defaulting. A field naming something we do not know
|
|
233
|
+
* must not quietly become npm; that is how a pnpm repo gets an `npm i`.
|
|
234
|
+
*/
|
|
235
|
+
function packageManagerFromField(pkg) {
|
|
236
|
+
if ('object' !== typeof pkg || null === pkg)
|
|
237
|
+
return undefined;
|
|
238
|
+
const declared = pkg['packageManager'];
|
|
239
|
+
if ('string' !== typeof declared)
|
|
240
|
+
return undefined;
|
|
241
|
+
// `name@version`, and the version is not ours to care about — only which binary runs.
|
|
242
|
+
const name = declared.split('@')[0]?.trim().toLowerCase();
|
|
243
|
+
const known = {
|
|
244
|
+
npm: PackageManager.NPM,
|
|
245
|
+
pnpm: PackageManager.PNPM,
|
|
246
|
+
yarn: PackageManager.YARN,
|
|
247
|
+
bun: PackageManager.BUN,
|
|
248
|
+
};
|
|
249
|
+
return name === undefined ? undefined : known[name];
|
|
250
|
+
}
|
|
251
|
+
export function detectPackageManager(lockfiles, nodeModulesMarkers, pkg) {
|
|
252
|
+
// What the project SAYS beats every trace of what was once run in it. Reported from the field: an
|
|
253
|
+
// already-instrumented npm workspaces project had a pnpm dependency migration run over it, which
|
|
254
|
+
// moved its `node_modules` aside and broke the dev server. Moving an installed tree is not
|
|
255
|
+
// something a scaffolder may do to a working checkout.
|
|
256
|
+
const declared = packageManagerFromField(pkg);
|
|
257
|
+
if (declared !== undefined)
|
|
258
|
+
return declared;
|
|
225
259
|
if (lockfiles.has('pnpm-lock.yaml'))
|
|
226
260
|
return PackageManager.PNPM;
|
|
227
261
|
if (lockfiles.has('yarn.lock'))
|
|
@@ -231,6 +265,10 @@ export function detectPackageManager(lockfiles, nodeModulesMarkers) {
|
|
|
231
265
|
// No lockfile is not the same as "npm". An already-installed tree says which manager built it.
|
|
232
266
|
return packageManagerFromNodeModules(nodeModulesMarkers) ?? PackageManager.NPM;
|
|
233
267
|
}
|
|
268
|
+
/** Every declared dependency, by name. Later blocks do not override earlier ones by accident. */
|
|
269
|
+
function declaredDependencies(pkg) {
|
|
270
|
+
return { ...pkg.peerDependencies, ...pkg.devDependencies, ...pkg.dependencies };
|
|
271
|
+
}
|
|
234
272
|
function detectFramework(input) {
|
|
235
273
|
for (const framework of DETECTION_ORDER) {
|
|
236
274
|
const signals = FRAMEWORK_SIGNALS[framework];
|
|
@@ -272,7 +310,8 @@ export function detect(input) {
|
|
|
272
310
|
needsSourceMapping: reactMajor !== undefined && reactMajor >= 19,
|
|
273
311
|
customReconciler: CUSTOM_RECONCILER_DEPS.some((name) => depVersion(input.pkg, name) !== undefined),
|
|
274
312
|
webGlSubtree: WEBGL_SUBTREE_DEPS.some((name) => depVersion(input.pkg, name) !== undefined),
|
|
275
|
-
packageManager: detectPackageManager(input.lockfiles, input.nodeModulesMarkers ?? new Set()),
|
|
313
|
+
packageManager: detectPackageManager(input.lockfiles, input.nodeModulesMarkers ?? new Set(), input.pkg),
|
|
314
|
+
dependencies: declaredDependencies(input.pkg),
|
|
276
315
|
};
|
|
277
316
|
}
|
|
278
317
|
const INSTALL_ARGS = {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { InitIo, InitOptions, InitResult } from '../run-types.js';
|
|
12
12
|
/** Re-enter `init`, scoped to one directory of the workspace. */
|
|
13
|
-
|
|
13
|
+
type RunInit = (options: InitOptions, io: InitIo) => InitResult;
|
|
14
14
|
/**
|
|
15
15
|
* When the current directory is a workspace root with no app of its own, wire the app instead of the
|
|
16
16
|
* root. One candidate is wired silently (there is nothing to ask about); several are listed, because
|
|
@@ -18,3 +18,4 @@ export type RunInit = (options: InitOptions, io: InitIo) => InitResult;
|
|
|
18
18
|
* Returns null when there is nothing to redirect to — the caller then proceeds here as before.
|
|
19
19
|
*/
|
|
20
20
|
export declare function redirectToWorkspaceApp(options: InitOptions, io: InitIo, pkg: unknown, runInit: RunInit): InitResult | null;
|
|
21
|
+
export {};
|
|
@@ -13,13 +13,24 @@
|
|
|
13
13
|
*/
|
|
14
14
|
/** Read a project-relative file, or undefined when it is absent/unreadable. */
|
|
15
15
|
type ReadFile = (relative: string) => string | undefined;
|
|
16
|
-
|
|
16
|
+
export declare const CspBasis: {
|
|
17
|
+
readonly OBSERVED: "observed";
|
|
18
|
+
readonly PREDICTED: "predicted";
|
|
19
|
+
};
|
|
20
|
+
export interface CspDiagnosis {
|
|
17
21
|
/** Which file to look at. */
|
|
18
22
|
file: string;
|
|
19
23
|
/** What is wrong, in one line. */
|
|
20
24
|
problem: string;
|
|
21
25
|
/** Exactly what to add — copy-pasteable, with the port actually in use. */
|
|
22
26
|
fix: string;
|
|
27
|
+
/** Whether the policy was read from the served document or inferred from project source. */
|
|
28
|
+
basis: (typeof CspBasis)[keyof typeof CspBasis];
|
|
29
|
+
}
|
|
30
|
+
export interface ObservedWebDocument {
|
|
31
|
+
url: string;
|
|
32
|
+
headers: readonly string[];
|
|
33
|
+
html: string;
|
|
23
34
|
}
|
|
24
35
|
/**
|
|
25
36
|
* The places a Content-Security-Policy gets written in a JS app.
|
|
@@ -29,4 +40,12 @@ interface CspDiagnosis {
|
|
|
29
40
|
*/
|
|
30
41
|
export declare const CSP_FILES: readonly string[];
|
|
31
42
|
export declare function diagnoseWebCsp(read: ReadFile, port: number, alsoCheck?: readonly string[]): CspDiagnosis[];
|
|
43
|
+
/** Diagnose only policies observed on the served development document. */
|
|
44
|
+
export declare function diagnoseObservedWebCsp(document: ObservedWebDocument, port: number): CspDiagnosis[];
|
|
45
|
+
/** Runtime evidence outranks source prediction; a connected SDK disproves a blocking policy. */
|
|
46
|
+
export declare function resolveWebCspFindings(input: {
|
|
47
|
+
predicted: readonly CspDiagnosis[];
|
|
48
|
+
observed?: readonly CspDiagnosis[];
|
|
49
|
+
connected: boolean;
|
|
50
|
+
}): CspDiagnosis[];
|
|
32
51
|
export {};
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
* would find policy strings in test fixtures and documentation.
|
|
13
13
|
*/
|
|
14
14
|
import { cspConnectSrcProblem, cspInlineScriptProblem, devCspAddition, externalScriptRemedy, } from './csp-check.js';
|
|
15
|
+
export const CspBasis = {
|
|
16
|
+
OBSERVED: 'observed',
|
|
17
|
+
PREDICTED: 'predicted',
|
|
18
|
+
};
|
|
15
19
|
/**
|
|
16
20
|
* The places a Content-Security-Policy gets written in a JS app.
|
|
17
21
|
*
|
|
@@ -39,24 +43,117 @@ export const CSP_FILES = [
|
|
|
39
43
|
'vercel.json',
|
|
40
44
|
'netlify.toml',
|
|
41
45
|
];
|
|
46
|
+
/**
|
|
47
|
+
* Next's `images.contentSecurityPolicy` is sent only with optimized images, never with the page.
|
|
48
|
+
* Treating it as a document policy tells a working app to weaken a header that cannot block it.
|
|
49
|
+
*/
|
|
50
|
+
function pagePolicySource(file, source) {
|
|
51
|
+
if (!file.startsWith('next.config.'))
|
|
52
|
+
return source;
|
|
53
|
+
return source.replace(/contentSecurityPolicy\s*[:=]\s*(['\x22`])[\s\S]*?\1/g, '');
|
|
54
|
+
}
|
|
42
55
|
export function diagnoseWebCsp(read, port, alsoCheck = []) {
|
|
43
56
|
const findings = [];
|
|
44
57
|
for (const file of [...alsoCheck, ...CSP_FILES]) {
|
|
45
|
-
const
|
|
46
|
-
if (
|
|
58
|
+
const raw = read(file);
|
|
59
|
+
if (raw === undefined)
|
|
47
60
|
continue;
|
|
61
|
+
const source = pagePolicySource(file, raw);
|
|
48
62
|
// `script-src` first, because it is the earlier failure. A policy that blocks the inline
|
|
49
63
|
// snippet means there is no SDK at all, so a `connect-src` finding on the same file would be
|
|
50
64
|
// describing a socket that is never opened -- true, and the wrong thing to fix first (#679).
|
|
51
65
|
const inline = cspInlineScriptProblem(source, port);
|
|
52
66
|
if (inline !== undefined) {
|
|
53
|
-
findings.push({
|
|
67
|
+
findings.push({
|
|
68
|
+
file,
|
|
69
|
+
problem: inline,
|
|
70
|
+
fix: externalScriptRemedy(),
|
|
71
|
+
basis: CspBasis.PREDICTED,
|
|
72
|
+
});
|
|
54
73
|
continue;
|
|
55
74
|
}
|
|
56
75
|
const problem = cspConnectSrcProblem(source, port);
|
|
57
76
|
if (problem === undefined)
|
|
58
77
|
continue;
|
|
59
|
-
findings.push({ file, problem, fix: devCspAddition(port) });
|
|
78
|
+
findings.push({ file, problem, fix: devCspAddition(port), basis: CspBasis.PREDICTED });
|
|
79
|
+
}
|
|
80
|
+
return findings;
|
|
81
|
+
}
|
|
82
|
+
function observedFinding(policy, file, port) {
|
|
83
|
+
const inline = cspInlineScriptProblem(policy, port);
|
|
84
|
+
if (inline !== undefined) {
|
|
85
|
+
return {
|
|
86
|
+
file,
|
|
87
|
+
problem: inline,
|
|
88
|
+
fix: externalScriptRemedy(),
|
|
89
|
+
basis: CspBasis.OBSERVED,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const connect = cspConnectSrcProblem(policy, port);
|
|
93
|
+
return connect === undefined
|
|
94
|
+
? undefined
|
|
95
|
+
: {
|
|
96
|
+
file,
|
|
97
|
+
problem: connect,
|
|
98
|
+
fix: devCspAddition(port),
|
|
99
|
+
basis: CspBasis.OBSERVED,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function attributeValue(tag, name) {
|
|
103
|
+
const pattern = new RegExp(`\\b${name}\\s*=\\s*(?:\\x22([^\\x22]*)\\x22|'([^']*)'|([^\\s>]+))`, 'i');
|
|
104
|
+
const match = pattern.exec(tag);
|
|
105
|
+
return match?.[1] ?? match?.[2] ?? match?.[3];
|
|
106
|
+
}
|
|
107
|
+
/** CSP meta policies from the document the development server actually returned. */
|
|
108
|
+
function withoutHtmlComments(html) {
|
|
109
|
+
const visible = [];
|
|
110
|
+
let cursor = 0;
|
|
111
|
+
while (cursor < html.length) {
|
|
112
|
+
const start = html.indexOf('<!--', cursor);
|
|
113
|
+
if (-1 === start) {
|
|
114
|
+
visible.push(html.slice(cursor));
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
visible.push(html.slice(cursor, start));
|
|
118
|
+
const end = html.indexOf('-->', start + 4);
|
|
119
|
+
if (-1 === end)
|
|
120
|
+
break;
|
|
121
|
+
cursor = end + 3;
|
|
122
|
+
}
|
|
123
|
+
return visible.join('');
|
|
124
|
+
}
|
|
125
|
+
function metaPolicies(html) {
|
|
126
|
+
const withoutComments = withoutHtmlComments(html);
|
|
127
|
+
const policies = [];
|
|
128
|
+
for (const match of withoutComments.matchAll(/<meta\b[^>]*>/gi)) {
|
|
129
|
+
const tag = match[0];
|
|
130
|
+
const equivalent = attributeValue(tag, 'http-equiv');
|
|
131
|
+
if (equivalent?.toLowerCase() !== 'content-security-policy')
|
|
132
|
+
continue;
|
|
133
|
+
const content = attributeValue(tag, 'content');
|
|
134
|
+
if (content !== undefined && content.length > 0)
|
|
135
|
+
policies.push(content);
|
|
136
|
+
}
|
|
137
|
+
return policies;
|
|
138
|
+
}
|
|
139
|
+
/** Diagnose only policies observed on the served development document. */
|
|
140
|
+
export function diagnoseObservedWebCsp(document, port) {
|
|
141
|
+
const findings = [];
|
|
142
|
+
for (const policy of document.headers) {
|
|
143
|
+
const found = observedFinding(policy, `response header at ${document.url}`, port);
|
|
144
|
+
if (found !== undefined)
|
|
145
|
+
findings.push(found);
|
|
146
|
+
}
|
|
147
|
+
for (const policy of metaPolicies(document.html)) {
|
|
148
|
+
const found = observedFinding(policy, `<meta> in ${document.url}`, port);
|
|
149
|
+
if (found !== undefined)
|
|
150
|
+
findings.push(found);
|
|
60
151
|
}
|
|
61
152
|
return findings;
|
|
62
153
|
}
|
|
154
|
+
/** Runtime evidence outranks source prediction; a connected SDK disproves a blocking policy. */
|
|
155
|
+
export function resolveWebCspFindings(input) {
|
|
156
|
+
if (input.connected)
|
|
157
|
+
return [];
|
|
158
|
+
return [...(input.observed ?? input.predicted)];
|
|
159
|
+
}
|
|
@@ -23,7 +23,7 @@ export declare const DesktopFinding: {
|
|
|
23
23
|
readonly ELECTRON_CAPTURE_MISSING: "electron-capture-missing";
|
|
24
24
|
};
|
|
25
25
|
export type DesktopFinding = (typeof DesktopFinding)[keyof typeof DesktopFinding];
|
|
26
|
-
|
|
26
|
+
interface DesktopDiagnosis {
|
|
27
27
|
code: DesktopFinding;
|
|
28
28
|
/** Which file to look at. */
|
|
29
29
|
file: string;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* a different cost and a different sentence to say afterwards.
|
|
7
7
|
*/
|
|
8
8
|
import { PackageManager } from '../detect/detect.js';
|
|
9
|
-
|
|
9
|
+
interface InstallRetry {
|
|
10
10
|
command: string;
|
|
11
11
|
args: string[];
|
|
12
12
|
note: string;
|
|
@@ -19,3 +19,4 @@ export interface InstallRetry {
|
|
|
19
19
|
* the second failure blaming a flag the user never asked for.
|
|
20
20
|
*/
|
|
21
21
|
export declare function installRetries(pm: PackageManager, pinned: readonly string[], unpinned: readonly string[], sdkVersion: string | undefined): InstallRetry[];
|
|
22
|
+
export {};
|
package/dist/host.d.ts
CHANGED
|
@@ -43,6 +43,12 @@ export interface InitHost {
|
|
|
43
43
|
pairingToken(): string;
|
|
44
44
|
/** The install channel the environment declares, or undefined when nothing declared one. */
|
|
45
45
|
installSource(): string | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Whether this run was started from inside Claude Code: the one case where writing its project
|
|
48
|
+
* `.mcp.json` is known to be wanted. A host question because it is read from the environment,
|
|
49
|
+
* which the scaffolder does not read for itself.
|
|
50
|
+
*/
|
|
51
|
+
insideClaudeCode(): boolean;
|
|
46
52
|
}
|
|
47
53
|
/**
|
|
48
54
|
* A host that does nothing, for callers that drive `init`'s file surface without running an install
|
package/dist/host.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -28,9 +28,10 @@ export { configWithInstallSource } from './project/install-source-config.js';
|
|
|
28
28
|
export { projectIdOf, rememberProjectOnDisk, type RegistryIo } from './project/remember-project.js';
|
|
29
29
|
export { detectPackageManager, installCommandParts, parseMajor, PackageManager, } from './detect/detect.js';
|
|
30
30
|
export { findWorkspaceApps } from './detect/workspace-apps.js';
|
|
31
|
+
export { deriveProjectId, packageName } from './project/project-id.js';
|
|
31
32
|
export { refreshAgentRules } from './project/refresh-rules.js';
|
|
32
33
|
export { diagnoseDesktop, isDesktopProject } from './diagnose/desktop-doctor.js';
|
|
33
|
-
export { diagnoseWebCsp } from './diagnose/csp-doctor.js';
|
|
34
|
+
export { CspBasis, diagnoseObservedWebCsp, diagnoseWebCsp, resolveWebCspFindings, type CspDiagnosis, type ObservedWebDocument, } from './diagnose/csp-doctor.js';
|
|
34
35
|
export { reticleConfigContent } from './patch/snippets.js';
|
|
35
36
|
/**
|
|
36
37
|
* MCP registration, for a caller that has no project.
|
package/dist/index.js
CHANGED
|
@@ -28,9 +28,10 @@ export { configWithInstallSource } from './project/install-source-config.js';
|
|
|
28
28
|
export { projectIdOf, rememberProjectOnDisk } from './project/remember-project.js';
|
|
29
29
|
export { detectPackageManager, installCommandParts, parseMajor, PackageManager, } from './detect/detect.js';
|
|
30
30
|
export { findWorkspaceApps } from './detect/workspace-apps.js';
|
|
31
|
+
export { deriveProjectId, packageName } from './project/project-id.js';
|
|
31
32
|
export { refreshAgentRules } from './project/refresh-rules.js';
|
|
32
33
|
export { diagnoseDesktop, isDesktopProject } from './diagnose/desktop-doctor.js';
|
|
33
|
-
export { diagnoseWebCsp } from './diagnose/csp-doctor.js';
|
|
34
|
+
export { CspBasis, diagnoseObservedWebCsp, diagnoseWebCsp, resolveWebCspFindings, } from './diagnose/csp-doctor.js';
|
|
34
35
|
export { reticleConfigContent } from './patch/snippets.js';
|
|
35
36
|
/**
|
|
36
37
|
* MCP registration, for a caller that has no project.
|
|
@@ -1,33 +1,68 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pure, conservative patchers for an Astro app: the config gets the
|
|
3
|
-
*
|
|
2
|
+
* Pure, conservative patchers for an Astro app: the config gets the raised build target and the
|
|
3
|
+
* watcher ignore, one layout gets the pairing token via frontmatter `<meta>` tags and a processed
|
|
4
|
+
* `<script>` that statically imports a local connect module.
|
|
4
5
|
*
|
|
5
6
|
* Astro was the last gated framework where `init` printed a correct recipe and applied none of it —
|
|
6
7
|
* the only ⚠ left on a supported stack, and the user's first session was two hand-copied snippets
|
|
7
8
|
* away. Astro is Vite-based but renders its own HTML, so the Vite plugin's injection never fires and
|
|
8
|
-
* there is no entry module to wire: the connect has to live in a page or layout
|
|
9
|
-
*
|
|
9
|
+
* there is no entry module to wire: the connect has to live in a page or layout.
|
|
10
|
+
*
|
|
11
|
+
* The token used to be inlined by `vite.define`. On Astro 7.2+ that substitution no longer reaches
|
|
12
|
+
* the client pipeline (#1008), so the identifier stays literal, `connect()` omits `token`, and the
|
|
13
|
+
* bridge refuses with "no pairing token on the page". The channel that does work is a `<meta>`: read
|
|
14
|
+
* the file in frontmatter and let a local module query `meta[name="reticle-pairing-token"]`. Reading
|
|
15
|
+
* per request also means a token written after the dev server started needs no restart. The SDK import
|
|
16
|
+
* lives in `src/components/ReticleDev.ts` so the page only ever statically imports a project module.
|
|
10
17
|
*
|
|
11
18
|
* Both patchers bail to `manual` (the printed recipe) on any shape they do not fully recognise.
|
|
12
19
|
* Half-editing a build config is worse than a documented manual step.
|
|
13
20
|
*/
|
|
14
21
|
import { type SourcePatch } from './patch-kind.js';
|
|
15
22
|
import { UiLibrary } from '../detect/detect.js';
|
|
23
|
+
/**
|
|
24
|
+
* Local module `init` writes for Astro. A processed page `<script>` statically imports this file
|
|
25
|
+
* so Vite owns the SDK the same way it owns any other project module.
|
|
26
|
+
*
|
|
27
|
+
* `.ts`, not `.tsx`: the install-gate scaffold is `create-astro --template minimal`, which has no
|
|
28
|
+
* React integration. The example app uses the same static import in a processed page `<script>`.
|
|
29
|
+
*/
|
|
30
|
+
export declare const ASTRO_RETICLE_DEV_PATH = "src/components/ReticleDev.ts";
|
|
31
|
+
/**
|
|
32
|
+
* Dev-only Astro connect module. Static SDK import, token from frontmatter `<meta>` tags.
|
|
33
|
+
*/
|
|
34
|
+
export declare function astroReticleDevFile(port: number | undefined, projectId: string | undefined, uiLibrary?: UiLibrary, testids?: readonly string[]): string;
|
|
35
|
+
/**
|
|
36
|
+
* Written into the Astro `vite:` block so a second init reports ALREADY. The Nuxt path uses
|
|
37
|
+
* `__RETICLE_TOKEN__` in `define` as its marker; Astro no longer writes that name into the config.
|
|
38
|
+
*/
|
|
39
|
+
export declare const ASTRO_VITE_OWNING_MARKER = "reticle-vite-owning";
|
|
40
|
+
/**
|
|
41
|
+
* The one runtime condition that guarantees a refused connect, said out loud on the page.
|
|
42
|
+
*
|
|
43
|
+
* Matching the Vite plugin's missing-token wording, because Astro never loads that plugin. The
|
|
44
|
+
* token is read at render time now, not at config load, so a reload is enough — the user does not
|
|
45
|
+
* have to restart the dev server.
|
|
46
|
+
*/
|
|
47
|
+
export declare const ASTRO_MISSING_TOKEN_WARNING: string;
|
|
16
48
|
export declare function patchAstroConfig(source: string): SourcePatch;
|
|
17
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Import path from a layout/page to the generated connect module, always relative and posix.
|
|
51
|
+
*
|
|
52
|
+
* `src/layouts/Layout.astro` and `src/pages/index.astro` both resolve to `../components/ReticleDev`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function astroReticleDevImport(layoutPath: string): string;
|
|
55
|
+
export declare function patchAstroLayout(source: string, layoutPath?: string): SourcePatch;
|
|
18
56
|
/** Where Astro keeps ambient types — `create-astro` ships this file. */
|
|
19
57
|
export declare const ASTRO_ENV_DTS_PATH = "src/env.d.ts";
|
|
20
58
|
/**
|
|
21
|
-
* The declarations `astro check` needs for the
|
|
22
|
-
*
|
|
23
|
-
* Matching SvelteKit's `hooks.client.ts` typing: `string | undefined`, because the define can be
|
|
24
|
-
* absent when the pairing token file is missing.
|
|
59
|
+
* The declarations `astro check` needs for the window names the inline script writes (#677, #1008).
|
|
25
60
|
*/
|
|
26
61
|
export declare const ASTRO_ENV_DTS_DECLARES: string;
|
|
27
62
|
/**
|
|
28
|
-
* Append the
|
|
63
|
+
* Append the window ambient declarations to `src/env.d.ts`, or create the file.
|
|
29
64
|
*
|
|
30
|
-
* Without this, `create-astro`'s default `"astro check && astro build"` fails with
|
|
31
|
-
* `ts(
|
|
65
|
+
* Without this, `create-astro`'s default `"astro check && astro build"` fails with
|
|
66
|
+
* `ts(2339) Property '__RETICLE_TOKEN__' does not exist on type 'Window'` after a clean init.
|
|
32
67
|
*/
|
|
33
68
|
export declare function patchAstroEnvDts(existing: string | null): SourcePatch;
|