@reticlehq/init 3.6.0 → 3.8.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 +9 -0
- package/dist/detect/detect.js +5 -1
- package/dist/detect/dev-script.d.ts +17 -0
- package/dist/detect/dev-script.js +128 -0
- package/dist/detect/dev-server-ports.d.ts +2 -0
- package/dist/detect/dev-server-ports.js +20 -0
- package/dist/detect/prettier-config.d.ts +21 -0
- package/dist/detect/prettier-config.js +38 -0
- package/dist/detect/workspace-apps.d.ts +11 -0
- package/dist/detect/workspace-apps.js +63 -0
- package/dist/detect/workspace-redirect.js +69 -10
- package/dist/diagnose/closing-hint.d.ts +5 -0
- package/dist/diagnose/closing-hint.js +18 -11
- package/dist/diagnose/init-failure.d.ts +2 -0
- package/dist/diagnose/init-failure.js +2 -0
- package/dist/gather-plan-input.d.ts +11 -0
- package/dist/gather-plan-input.js +468 -0
- package/dist/host.d.ts +6 -0
- package/dist/index.d.ts +11 -4
- package/dist/index.js +14 -4
- package/dist/no-package-json.js +62 -14
- package/dist/node-io.d.ts +1 -1
- package/dist/node-io.js +11 -2
- package/dist/patch/next-patch.d.ts +45 -9
- package/dist/patch/next-patch.js +93 -0
- package/dist/patch/nuxt-snippets.js +1 -1
- package/dist/patch/prettier-ignore.d.ts +34 -0
- package/dist/patch/prettier-ignore.js +49 -0
- package/dist/patch/python-snippets.d.ts +22 -0
- package/dist/patch/python-snippets.js +113 -0
- package/dist/patch/snippets.d.ts +10 -31
- package/dist/patch/snippets.js +42 -105
- package/dist/patch/static-page.d.ts +1 -0
- package/dist/patch/static-page.js +6 -8
- package/dist/patch/vite-config.js +11 -0
- package/dist/plan/connect-steps.d.ts +2 -0
- package/dist/plan/connect-steps.js +6 -0
- package/dist/plan/framework-adapter.d.ts +10 -0
- package/dist/plan/framework-adapter.js +122 -3
- package/dist/plan/notices.js +1 -1
- package/dist/plan/plan-angular.js +1 -1
- package/dist/plan/plan-framework.d.ts +1 -1
- package/dist/plan/plan-framework.js +140 -37
- package/dist/plan/plan-types.d.ts +50 -2
- package/dist/plan/plan-vite.js +15 -0
- package/dist/plan/plan.d.ts +1 -10
- package/dist/plan/plan.js +181 -126
- package/dist/plan/stop-hook-step.d.ts +30 -0
- package/dist/plan/stop-hook-step.js +154 -5
- package/dist/project/agent-rules.d.ts +1 -1
- package/dist/project/agent-rules.js +22 -17
- package/dist/project/refresh-rules.js +2 -1
- package/dist/register/codex-toml.d.ts +12 -0
- package/dist/register/codex-toml.js +44 -0
- package/dist/register/mcp.d.ts +15 -2
- package/dist/register/mcp.js +16 -0
- package/dist/register/prompt-hooks.d.ts +123 -0
- package/dist/register/prompt-hooks.js +449 -0
- package/dist/register/slash-command.d.ts +1 -1
- package/dist/register/slash-command.js +5 -4
- package/dist/run-types.d.ts +10 -0
- package/dist/run.d.ts +1 -1
- package/dist/run.js +15 -390
- package/package.json +2 -2
|
@@ -9,14 +9,39 @@ import { patchNextConfig, patchRootLayout, patchPagesApp } from '../patch/next-p
|
|
|
9
9
|
import { ASTRO_ENV_DTS_PATH, ASTRO_RETICLE_DEV_PATH, astroReticleDevFile, patchAstroConfig, patchAstroEnvDts, patchAstroLayout, } from '../patch/astro-patch.js';
|
|
10
10
|
import { CRA_DEV_MODULE_IMPORT, CRA_ENV_PATH, CRA_TOKEN_PER_MACHINE_NOTICE, TOKEN_VAR, craDevModuleFile, craDevModulePath, craEnvPatch, craImportPatch, } from '../patch/cra.js';
|
|
11
11
|
import { PatchKind } from '../patch/patch-kind.js';
|
|
12
|
-
import { NEXT_LAYOUT_MANUAL, NEXT_LAYOUT_PATH, nextReticleDevFile, NEXT_RETICLE_DEV_PATH, nextConfigManual, svelteKitHooksFile, SVELTEKIT_HOOKS_PATH, SVELTEKIT_SETUP_GATED_NOTE, astroManual, nuxtManual, nuxtPluginFile, nuxtPluginPath, NUXT_PLUGIN_NOTICE, webpack4TranspileNote, WEBPACK4_REACT_SCRIPTS_MAJOR, reactRouterEntryFile, reactRouterEntryPatch, REACT_ROUTER_ENTRY_PATH, UNVERIFIED_TANSTACK_START_NOTE, htmlManual, } from '../patch/snippets.js';
|
|
12
|
+
import { NEXT_LAYOUT_MANUAL, NEXT_LAYOUT_PATH, nextReticleDevFile, NEXT_RETICLE_DEV_PATH, nextConfigManual, svelteKitHooksFile, SVELTEKIT_HOOKS_PATH, SVELTEKIT_SETUP_GATED_NOTE, astroManual, nuxtManual, nuxtPluginFile, nuxtPluginPath, NUXT_PLUGIN_NOTICE, webpack4TranspileNote, WEBPACK4_REACT_SCRIPTS_MAJOR, reactRouterEntryFile, reactRouterEntryPatch, REACT_ROUTER_ENTRY_PATH, UNVERIFIED_TANSTACK_START_NOTE, htmlManual, connectArg, } from '../patch/snippets.js';
|
|
13
13
|
import { StepStatus } from './plan-types.js';
|
|
14
14
|
import { StepTitle } from './connect-steps.js';
|
|
15
15
|
import { patchTanstackStartRoot, tanstackStartConnectFile, tanstackStartConnectPath, tanstackStartManual, TANSTACK_START_ROOT_PATH, } from '../patch/tanstack-start.js';
|
|
16
16
|
import { patchNuxtConfig } from '../patch/nuxt-patch.js';
|
|
17
17
|
import { alreadyOrMovedPort } from './port-steps.js';
|
|
18
18
|
import { capabilitiesTodo, needsManualStore } from './plan-vite.js';
|
|
19
|
-
import { HTML_INDEX_PATH,
|
|
19
|
+
import { HTML_INDEX_PATH, STATIC_GITIGNORE_PATH, STATIC_SNIPPET_MARKER, STATIC_TOKEN_MODULE, staticTokenFiles, withStaticSnippet, } from '../patch/static-page.js';
|
|
20
|
+
/*
|
|
21
|
+
* Threat model for the static page's token module. `reticle.local.js` sits beside `index.html`, so
|
|
22
|
+
* whatever serves the page serves it too, to any client that can reach that server. That is the same
|
|
23
|
+
* exposure every other dev path already has: the Vite plugin bakes the token into the connect module
|
|
24
|
+
* it serves, and the no-package.json path writes this very file. The dev server's bind address is
|
|
25
|
+
* the boundary; the module is gitignored so it never reaches a commit or a published build.
|
|
26
|
+
*/
|
|
27
|
+
const STATIC_TOKEN_DETAIL = `write this machine’s pairing token to ${STATIC_TOKEN_MODULE} beside the page`;
|
|
28
|
+
const STATIC_IGNORE_DETAIL = `add ${STATIC_TOKEN_MODULE} to ${STATIC_GITIGNORE_PATH} — it holds this machine’s pairing token`;
|
|
29
|
+
const STATIC_CONNECT_DETAIL = 'write the dev-only connect snippet (loopback hosts only)';
|
|
30
|
+
const STATIC_CONNECT_ALREADY_DETAIL = `${HTML_INDEX_PATH} already loads the Reticle SDK`;
|
|
31
|
+
/** The package whose presence makes a static page an Electron renderer. */
|
|
32
|
+
const ELECTRON_PACKAGE = 'electron';
|
|
33
|
+
/**
|
|
34
|
+
* An Electron app often serves its renderer from a local HTTP server, so the packaged app runs on
|
|
35
|
+
* `localhost` on every user's machine. The localhost-only guard then lets the snippet run in
|
|
36
|
+
* production, and a packager glob such as `**\/*.js` can ship the token module.
|
|
37
|
+
*/
|
|
38
|
+
const ELECTRON_STATIC_DETAIL = `This is an Electron app. Its packaged renderer can also run on localhost, so init did not ` +
|
|
39
|
+
`write the localhost-only snippet into ${HTML_INDEX_PATH} or the ${STATIC_TOKEN_MODULE} token ` +
|
|
40
|
+
'module. Connect only in development: for example, send `!app.isPackaged` from the main ' +
|
|
41
|
+
'process to the renderer, and call `reticle.connect()` only when it is true. Use ' +
|
|
42
|
+
`@reticlehq/electron for IPC and capture. If ${STATIC_TOKEN_MODULE} is in the project, keep ` +
|
|
43
|
+
`it out of the package: electron-builder \`files: ["!${STATIC_TOKEN_MODULE}"]\`, or Electron ` +
|
|
44
|
+
`Forge \`packagerConfig.ignore: [/${STATIC_TOKEN_MODULE.replaceAll('.', '\\.')}$/]\`.`;
|
|
20
45
|
/**
|
|
21
46
|
* Turn a conservative source patch into a step: applied when it patched, already when the wiring is
|
|
22
47
|
* there, and the hand-edit instructions when the file shape wasn't one we recognise.
|
|
@@ -49,15 +74,21 @@ export function patchStep(title, path, patch, applyDetail, manualDetail) {
|
|
|
49
74
|
*/
|
|
50
75
|
/** The env var withReticle sets from the discovered daemon, and the component must read. */
|
|
51
76
|
const NEXT_DAEMON_URL_ENV = 'NEXT_PUBLIC_RETICLE_URL';
|
|
77
|
+
const NEXT_SDK_VERSION_ENV = 'NEXT_PUBLIC_RETICLE_SDK_VERSION';
|
|
52
78
|
/**
|
|
53
79
|
* The two-line edit that unfreezes an existing install's port.
|
|
54
80
|
*
|
|
55
81
|
* Stated as the edit rather than as a problem, because the reader is an agent that can apply it in
|
|
56
82
|
* one write and is otherwise going to ask what to do.
|
|
57
83
|
*/
|
|
58
|
-
const
|
|
84
|
+
const NEXT_DEV_FILE_STALE_DETAIL_SOLO = 'predates daemon discovery, so it dials the port init saw when it ran. In this file add ' +
|
|
59
85
|
'`const url = process.env.NEXT_PUBLIC_RETICLE_URL;` and spread `...(url ? { url } : {})` into ' +
|
|
60
86
|
'reticle.connect(), after any url already there. Nothing else needs to change.';
|
|
87
|
+
const NEXT_DEV_FILE_STALE_DETAIL_DUAL = 'predates daemon discovery, so it dials the port init saw when it ran. In this file add ' +
|
|
88
|
+
'`const url = process.env.NEXT_PUBLIC_RETICLE_URL;` and spread `...(url ? { url } : {})` into ' +
|
|
89
|
+
'reticle.connect(), after any url already there.';
|
|
90
|
+
const NEXT_SDK_VERSION_DETAIL = 'lacks the SDK version. In this file add `const sdkVersion = process.env.NEXT_PUBLIC_RETICLE_SDK_VERSION;` ' +
|
|
91
|
+
'and spread `...(sdkVersion ? { sdkVersion } : {})` into the reticle.connect() options.';
|
|
61
92
|
export function nextSteps(input) {
|
|
62
93
|
const configFile = input.nextConfigFile ?? 'next.config.mjs';
|
|
63
94
|
const devPath = input.nextReticleDevPath ?? NEXT_RETICLE_DEV_PATH;
|
|
@@ -71,34 +102,52 @@ export function nextSteps(input) {
|
|
|
71
102
|
const devStale = true === input.nextReticleDevExists &&
|
|
72
103
|
'string' === typeof input.nextReticleDevSource &&
|
|
73
104
|
!input.nextReticleDevSource.includes(NEXT_DAEMON_URL_ENV);
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
105
|
+
const sdkVersionMissing = true === input.nextReticleDevExists &&
|
|
106
|
+
'string' === typeof input.nextReticleDevSource &&
|
|
107
|
+
!input.nextReticleDevSource.includes(NEXT_SDK_VERSION_ENV);
|
|
108
|
+
const baseDevStep = devStale
|
|
109
|
+
? {
|
|
110
|
+
title: StepTitle.RETICLE_DEV_COMPONENT,
|
|
111
|
+
target: devPath,
|
|
112
|
+
status: StepStatus.MANUAL,
|
|
113
|
+
detail: sdkVersionMissing
|
|
114
|
+
? `${NEXT_DEV_FILE_STALE_DETAIL_DUAL} Also ${NEXT_SDK_VERSION_DETAIL}`
|
|
115
|
+
: NEXT_DEV_FILE_STALE_DETAIL_SOLO,
|
|
116
|
+
}
|
|
117
|
+
: alreadyOrMovedPort({
|
|
118
|
+
title: StepTitle.RETICLE_DEV_COMPONENT,
|
|
119
|
+
target: devPath,
|
|
120
|
+
status: StepStatus.ALREADY,
|
|
121
|
+
detail: 'file exists',
|
|
122
|
+
}, input.nextReticleDevSource, input.options.port);
|
|
123
|
+
const devNoticeSteps = !devStale && sdkVersionMissing
|
|
124
|
+
? [
|
|
125
|
+
{
|
|
77
126
|
title: StepTitle.RETICLE_DEV_COMPONENT,
|
|
78
127
|
target: devPath,
|
|
79
|
-
status: StepStatus.
|
|
80
|
-
detail:
|
|
81
|
-
}
|
|
82
|
-
|
|
128
|
+
status: StepStatus.NOTICE,
|
|
129
|
+
detail: NEXT_SDK_VERSION_DETAIL,
|
|
130
|
+
},
|
|
131
|
+
]
|
|
132
|
+
: [];
|
|
133
|
+
const devFileSteps = input.nextReticleDevExists
|
|
134
|
+
? [baseDevStep, ...devNoticeSteps]
|
|
135
|
+
: [
|
|
136
|
+
{
|
|
83
137
|
title: StepTitle.RETICLE_DEV_COMPONENT,
|
|
84
138
|
target: devPath,
|
|
85
|
-
status: StepStatus.
|
|
86
|
-
detail: '
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
content: nextReticleDevFile(input.options.port, input.options.projectId, input.testids ?? [], input.storeHints ?? [],
|
|
96
|
-
// Next's dev module is not a sibling of `src/` — its imports are resolved from wherever
|
|
97
|
-
// the component actually lands (`app/`, or `src/app/` in a --src-dir app).
|
|
98
|
-
input.nextFoundStores ?? []),
|
|
139
|
+
status: StepStatus.APPLY,
|
|
140
|
+
detail: 'create dev-only connect component',
|
|
141
|
+
write: {
|
|
142
|
+
path: devPath,
|
|
143
|
+
content: nextReticleDevFile(input.options.port, input.options.projectId, input.testids ?? [], input.storeHints ?? [],
|
|
144
|
+
// Next's dev module is not a sibling of `src/` — its imports are resolved from wherever
|
|
145
|
+
// the component actually lands (`app/`, or `src/app/` in a --src-dir app).
|
|
146
|
+
input.nextFoundStores ?? []),
|
|
147
|
+
},
|
|
148
|
+
dependsOnInstall: true,
|
|
99
149
|
},
|
|
100
|
-
|
|
101
|
-
};
|
|
150
|
+
];
|
|
102
151
|
const configPatch = null === input.nextConfigSource || input.nextConfigSource === undefined
|
|
103
152
|
? { kind: PatchKind.MANUAL, reason: `no ${configFile} found` }
|
|
104
153
|
: patchNextConfig(input.nextConfigSource, true !== input.detection?.customReconciler);
|
|
@@ -106,8 +155,14 @@ export function nextSteps(input) {
|
|
|
106
155
|
// Pages Router mounts through pages/_app, App Router through the root layout — different edits,
|
|
107
156
|
// and picking by path is what stops a Pages app being handed the layout patch that cannot apply.
|
|
108
157
|
const isPagesRouter = layout !== null && /(^|\/)pages\/_app\.[jt]sx?$/.test(layout.path);
|
|
158
|
+
const candidates = input.nextLayoutCandidates ?? [];
|
|
109
159
|
const layoutPatch = null === layout
|
|
110
|
-
? {
|
|
160
|
+
? {
|
|
161
|
+
kind: PatchKind.MANUAL,
|
|
162
|
+
reason: 0 === candidates.length
|
|
163
|
+
? 'no root layout (app/layout.tsx) or pages/_app found'
|
|
164
|
+
: `no app/layout.tsx; route-group root layouts ${candidates.join(', ')}, and none of them alone renders /`,
|
|
165
|
+
}
|
|
111
166
|
: isPagesRouter
|
|
112
167
|
? patchPagesApp(layout.source, input.nextReticleDevImport)
|
|
113
168
|
: patchRootLayout(layout.source);
|
|
@@ -124,11 +179,26 @@ export function nextSteps(input) {
|
|
|
124
179
|
},
|
|
125
180
|
]
|
|
126
181
|
: [];
|
|
182
|
+
// Each route-group root layout renders only its own routes, so one mount covers one group: the
|
|
183
|
+
// routes under the other root layouts render without ReticleDev, and saying nothing about them
|
|
184
|
+
// would read as an app that is fully wired.
|
|
185
|
+
const unmounted = input.nextUnmountedLayouts ?? [];
|
|
186
|
+
const otherRootLayouts = null !== layout && 0 < unmounted.length
|
|
187
|
+
? [
|
|
188
|
+
{
|
|
189
|
+
title: StepTitle.ROUTE_GROUPS_WITHOUT_RETICLE_DEV,
|
|
190
|
+
target: unmounted.join(', '),
|
|
191
|
+
status: StepStatus.NOTICE,
|
|
192
|
+
detail: `<ReticleDev /> is mounted in ${layout.path} only; ${unmounted.join(', ')} ${1 === unmounted.length ? 'is a root layout' : 'are root layouts'} of ${1 === unmounted.length ? 'its' : 'their'} own, so the routes under ${1 === unmounted.length ? 'it' : 'them'} render without it and Reticle sees nothing there. Mount it there too (dev-only) to cover them.`,
|
|
193
|
+
},
|
|
194
|
+
]
|
|
195
|
+
: [];
|
|
127
196
|
return [
|
|
128
|
-
|
|
197
|
+
...devFileSteps,
|
|
129
198
|
...nextTodo,
|
|
130
199
|
patchStep(StepTitle.NEXT_CONFIG, configFile, configPatch, 'wrap the export in withReticle (source mapping, dev-only)', nextConfigManual(configFile, true !== input.detection?.customReconciler)),
|
|
131
200
|
patchStep(StepTitle.MOUNT_RETICLE_DEV, layout?.path ?? NEXT_LAYOUT_PATH, layoutPatch, 'mount <ReticleDev /> in the root layout (dev-only)', NEXT_LAYOUT_MANUAL),
|
|
201
|
+
...otherRootLayouts,
|
|
132
202
|
];
|
|
133
203
|
}
|
|
134
204
|
/**
|
|
@@ -512,28 +582,61 @@ export function astroSteps(input) {
|
|
|
512
582
|
patchStep(StepTitle.ASTRO_ENV_DTS, ASTRO_ENV_DTS_PATH, envPatch, 'declare window.__RETICLE_TOKEN__ / __RETICLE_ROOT__ for astro check', manualWithLayout),
|
|
513
583
|
];
|
|
514
584
|
}
|
|
585
|
+
/** Write the gitignored module that holds this machine's pairing token, and its ignore line. */
|
|
586
|
+
function staticTokenSteps(input) {
|
|
587
|
+
return Object.entries(staticTokenFiles(input.pairingToken, (path) => input.htmlLocalSources?.[path] ?? null)).map(([path, content]) => ({
|
|
588
|
+
title: StepTitle.STATIC_PAIRING_TOKEN,
|
|
589
|
+
target: path,
|
|
590
|
+
status: StepStatus.APPLY,
|
|
591
|
+
detail: STATIC_GITIGNORE_PATH === path ? STATIC_IGNORE_DETAIL : STATIC_TOKEN_DETAIL,
|
|
592
|
+
write: { path, content },
|
|
593
|
+
}));
|
|
594
|
+
}
|
|
515
595
|
/**
|
|
516
|
-
* The plain-HTML path:
|
|
596
|
+
* The plain-HTML path: write the static connect when the page exists, otherwise print the recipe.
|
|
517
597
|
*
|
|
518
598
|
* A function of its own, and NOT a fallthrough. Every framework is sent here on purpose or not at
|
|
519
599
|
* all — a member of `Framework` with no adapter entry is a compile error in `FRAMEWORK_ADAPTERS`,
|
|
520
600
|
* where the if/else chain this replaced used to hand it these instructions silently.
|
|
521
601
|
*/
|
|
522
602
|
export function htmlSteps(input) {
|
|
523
|
-
|
|
524
|
-
// over a page that already connects said "This app will NOT connect until the ⚠ step".
|
|
525
|
-
const index = input.htmlIndexSource ?? null;
|
|
526
|
-
if (null !== index && hasStaticSnippet(index)) {
|
|
603
|
+
if (input.detection.dependencies?.[ELECTRON_PACKAGE] !== undefined) {
|
|
527
604
|
return [
|
|
528
|
-
|
|
605
|
+
{
|
|
529
606
|
title: StepTitle.CONNECT_SNIPPET,
|
|
530
607
|
target: HTML_INDEX_PATH,
|
|
531
|
-
status: StepStatus.
|
|
532
|
-
detail:
|
|
533
|
-
},
|
|
608
|
+
status: StepStatus.MANUAL,
|
|
609
|
+
detail: ELECTRON_STATIC_DETAIL,
|
|
610
|
+
},
|
|
611
|
+
];
|
|
612
|
+
}
|
|
613
|
+
const index = input.htmlIndexSource ?? null;
|
|
614
|
+
if (null !== index) {
|
|
615
|
+
// The page is publishable; the pairing token belongs in its gitignored sibling module instead.
|
|
616
|
+
// Refresh that module even when the connect block itself is already in place.
|
|
617
|
+
const steps = staticTokenSteps(input);
|
|
618
|
+
const written = withStaticSnippet(index, connectArg(input.options.port, input.options.projectId));
|
|
619
|
+
return [
|
|
620
|
+
...steps,
|
|
621
|
+
null !== written
|
|
622
|
+
? {
|
|
623
|
+
title: StepTitle.CONNECT_SNIPPET,
|
|
624
|
+
target: HTML_INDEX_PATH,
|
|
625
|
+
status: StepStatus.APPLY,
|
|
626
|
+
detail: STATIC_CONNECT_DETAIL,
|
|
627
|
+
write: { path: HTML_INDEX_PATH, content: written, expect: [STATIC_SNIPPET_MARKER] },
|
|
628
|
+
}
|
|
629
|
+
: alreadyOrMovedPort({
|
|
630
|
+
title: StepTitle.CONNECT_SNIPPET,
|
|
631
|
+
target: HTML_INDEX_PATH,
|
|
632
|
+
status: StepStatus.ALREADY,
|
|
633
|
+
detail: STATIC_CONNECT_ALREADY_DETAIL,
|
|
634
|
+
}, index, input.options.port),
|
|
534
635
|
];
|
|
535
636
|
}
|
|
536
637
|
return [
|
|
638
|
+
// The manual snippet imports the token from this module rather than printing it.
|
|
639
|
+
...staticTokenSteps(input),
|
|
537
640
|
{
|
|
538
641
|
title: StepTitle.CONNECT_SNIPPET,
|
|
539
642
|
target: HTML_INDEX_PATH,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import type { Detection, Framework, UiLibrary } from '../detect/detect.js';
|
|
9
9
|
import type { FoundStore } from '../detect/capabilities.js';
|
|
10
10
|
import type { McpClient } from '../register/mcp-clients.js';
|
|
11
|
+
import type { PromptHookTarget } from '../register/prompt-hooks.js';
|
|
11
12
|
/** Exported so the init telemetry can tell an MCP-registration failure from a dependency install. */
|
|
12
13
|
export declare const MCP_TARGET = "global (claude user scope)";
|
|
13
14
|
/** The step that runs the package manager — the other thing that commonly fails on a user's machine. */
|
|
@@ -96,6 +97,11 @@ export interface Plan {
|
|
|
96
97
|
}
|
|
97
98
|
export interface PlanInput {
|
|
98
99
|
detection: Detection;
|
|
100
|
+
/**
|
|
101
|
+
* `node_modules` is a link to another tree (a workspace's, a shared cache). A package manager run
|
|
102
|
+
* here replaces the link with a fresh tree, so the install is skipped and named instead.
|
|
103
|
+
*/
|
|
104
|
+
nodeModulesLinked?: boolean | undefined;
|
|
99
105
|
/**
|
|
100
106
|
* Write `captureNetworkBodies: true` into the app's config. Off unless the caller asked (#705).
|
|
101
107
|
*
|
|
@@ -110,6 +116,11 @@ export interface PlanInput {
|
|
|
110
116
|
* handing it an io would let any later step reach the disk from inside `buildPlan`.
|
|
111
117
|
*/
|
|
112
118
|
cspSources?: Readonly<Record<string, string | undefined>> | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* The project's `.prettierignore` content, pre-read so the prettier-ignore step stays pure.
|
|
121
|
+
* Null when the file does not exist — `init` creates it only when the project uses Prettier.
|
|
122
|
+
*/
|
|
123
|
+
prettierIgnoreSource?: string | null | undefined;
|
|
113
124
|
/** Whether the `claude` CLI is installed (so we can register the MCP server globally). */
|
|
114
125
|
claudeCli: boolean;
|
|
115
126
|
/** Whether an `reticle` MCP server is already registered with Claude (any scope) — idempotency. */
|
|
@@ -145,11 +156,18 @@ export interface PlanInput {
|
|
|
145
156
|
configPath: string;
|
|
146
157
|
existing: string | null;
|
|
147
158
|
}[] | undefined;
|
|
159
|
+
/**
|
|
160
|
+
* Whether the `codex` CLI is on PATH. Only probed when Codex was detected, and absent otherwise.
|
|
161
|
+
* With it, Codex registers through `codex mcp add` instead of a block to paste.
|
|
162
|
+
*/
|
|
163
|
+
codexCli?: boolean | undefined;
|
|
148
164
|
/** Discovered Vite config: its path + source, or null if none found. */
|
|
149
165
|
viteConfig: {
|
|
150
166
|
path: string;
|
|
151
167
|
source: string;
|
|
152
168
|
} | null;
|
|
169
|
+
/** Config paths found but not safely attributable to the selected dev command. */
|
|
170
|
+
viteConfigCandidates?: readonly string[] | undefined;
|
|
153
171
|
/** Discovered electron-vite config: its path + source, or null if none found. */
|
|
154
172
|
electronViteConfig?: {
|
|
155
173
|
path: string;
|
|
@@ -200,6 +218,16 @@ export interface PlanInput {
|
|
|
200
218
|
path: string;
|
|
201
219
|
source: string;
|
|
202
220
|
} | null | undefined;
|
|
221
|
+
/**
|
|
222
|
+
* Route-group root layouts `init` could not choose between (`app/(a)/layout.tsx`, ...), set only
|
|
223
|
+
* when there is no top-level layout and no single group renders `/` (#1538).
|
|
224
|
+
*/
|
|
225
|
+
nextLayoutCandidates?: readonly string[] | undefined;
|
|
226
|
+
/**
|
|
227
|
+
* The other route-group root layouts when one was chosen to mount into, that do not mount
|
|
228
|
+
* `<ReticleDev />` themselves: the routes under them render without it.
|
|
229
|
+
*/
|
|
230
|
+
nextUnmountedLayouts?: readonly string[] | undefined;
|
|
203
231
|
/** Where the dev-only connect component goes — never inside `pages/`, which routes on presence. */
|
|
204
232
|
nextReticleDevPath?: string | undefined;
|
|
205
233
|
/** What the mount file should import — a sibling for App Router, `../components/…` for Pages. */
|
|
@@ -277,10 +305,12 @@ export interface PlanInput {
|
|
|
277
305
|
/** The generated `reticle.proxy.mjs`, when a previous run left one (idempotency). */
|
|
278
306
|
angularProxySource?: string | null | undefined;
|
|
279
307
|
/**
|
|
280
|
-
* The plain-HTML app's `index.html`, when it has one —
|
|
281
|
-
*
|
|
308
|
+
* The plain-HTML app's `index.html`, when it has one — patched on the first run, recognised on
|
|
309
|
+
* later runs, and left manual only when there is no page to write into.
|
|
282
310
|
*/
|
|
283
311
|
htmlIndexSource?: string | null | undefined;
|
|
312
|
+
/** Current token module and .gitignore beside the HTML page, for idempotent token-file writes. */
|
|
313
|
+
htmlLocalSources?: Record<string, string | null> | undefined;
|
|
284
314
|
/** CRA's bundled entry (src/index.tsx or .js) — where the connect import has to go. */
|
|
285
315
|
craEntry?: {
|
|
286
316
|
path: string;
|
|
@@ -306,6 +336,14 @@ export interface PlanInput {
|
|
|
306
336
|
* see reticleConfigStep for the port that survived every re-run because of it.
|
|
307
337
|
*/
|
|
308
338
|
reticleConfigSource?: string | null | undefined;
|
|
339
|
+
/**
|
|
340
|
+
* `--new-id`: the app's source files that quote the id being replaced. A hand-written
|
|
341
|
+
* `connect({ projectId: '…' })` still naming it sends this checkout's evidence to the original.
|
|
342
|
+
*/
|
|
343
|
+
copiedIdSources?: readonly {
|
|
344
|
+
path: string;
|
|
345
|
+
source: string;
|
|
346
|
+
}[] | undefined;
|
|
309
347
|
/** Current project-root CLAUDE.md content (for the idempotent agent-rule merge), or null/undefined. */
|
|
310
348
|
claudeMdContent?: string | null | undefined;
|
|
311
349
|
/** Current project-root AGENTS.md content (the cross-agent rule), or null/undefined. */
|
|
@@ -328,6 +366,12 @@ export interface PlanInput {
|
|
|
328
366
|
hooks?: boolean | undefined;
|
|
329
367
|
/** Current .claude/settings.json content, or null when absent (the hook is MERGED into it). */
|
|
330
368
|
claudeSettingsContent?: string | null | undefined;
|
|
369
|
+
/** Install the prompt-capture hook into `.claude/settings.json`: Claude Code is used here. */
|
|
370
|
+
claudePromptHook?: boolean | undefined;
|
|
371
|
+
/** Every OTHER agent found here with a prompt hook, and its config as it is now. */
|
|
372
|
+
promptHooks?: readonly PromptHookTarget[] | undefined;
|
|
373
|
+
/** See `InitHost.hookBin`. */
|
|
374
|
+
hookBin?: string | undefined;
|
|
331
375
|
/**
|
|
332
376
|
* Absolute directory the AGENT runs in, when that is not the app's directory.
|
|
333
377
|
*
|
|
@@ -342,12 +386,16 @@ export interface PlanInput {
|
|
|
342
386
|
* that disagrees with the app's is worse than no root config, and only reading it can tell.
|
|
343
387
|
*/
|
|
344
388
|
agentRootConfigSource?: string | null | undefined;
|
|
389
|
+
/** The agent root holds several apps, so its config would name one and mislead about the rest. */
|
|
390
|
+
agentRootSeveralApps?: boolean | undefined;
|
|
345
391
|
options: {
|
|
346
392
|
port: number | undefined;
|
|
347
393
|
mcp: boolean;
|
|
348
394
|
install: boolean;
|
|
349
395
|
/** Stable project identity derived at init (package.json name + root). Baked into snippets/.reticle.json. */
|
|
350
396
|
projectId?: string;
|
|
397
|
+
/** `--new-id`: the config on disk takes `projectId` above in place of the id it was copied with. */
|
|
398
|
+
newId?: boolean;
|
|
351
399
|
/** The CLI's own version, pinned onto the SDK install so a stale registry cache cannot skew it. */
|
|
352
400
|
sdkVersion?: string;
|
|
353
401
|
};
|
package/dist/plan/plan-vite.js
CHANGED
|
@@ -194,6 +194,21 @@ function viteConfigSteps(input, detail, inject = true) {
|
|
|
194
194
|
// plugin, and a file carrying ours alone would not boot the app.
|
|
195
195
|
const plainVite = Framework.VITE === input.detection.framework;
|
|
196
196
|
if (null === cfg) {
|
|
197
|
+
const candidates = input.viteConfigCandidates ?? [];
|
|
198
|
+
if (candidates.length > 0) {
|
|
199
|
+
const named = candidates.map((path) => `\`${path}\``).join(', ');
|
|
200
|
+
return [
|
|
201
|
+
{
|
|
202
|
+
title: StepTitle.VITE_PLUGIN,
|
|
203
|
+
target: candidates[0] ?? 'vite.config',
|
|
204
|
+
status: StepStatus.MANUAL,
|
|
205
|
+
detail: `Reticle could not safely patch the Vite config used by the dev server. ` +
|
|
206
|
+
`Candidate config(s): ${named}. ` +
|
|
207
|
+
`Add the Reticle plugin to the config passed to createServer().\n\n` +
|
|
208
|
+
viteManual(port, input.detection.uiLibrary, inject, stampSource),
|
|
209
|
+
},
|
|
210
|
+
];
|
|
211
|
+
}
|
|
197
212
|
if (!plainVite) {
|
|
198
213
|
return [
|
|
199
214
|
{
|
package/dist/plan/plan.d.ts
CHANGED
|
@@ -3,18 +3,9 @@
|
|
|
3
3
|
* contents, produce an ordered list of steps — each marked apply / manual / already / skip. The
|
|
4
4
|
* runner performs the `write` side-effects; this module decides *what* should happen.
|
|
5
5
|
*/
|
|
6
|
-
import { Framework, UiLibrary } from '../detect/detect.js';
|
|
7
6
|
import { type Plan, type PlanInput } from './plan-types.js';
|
|
8
7
|
export { DEPS_TARGET, MCP_TARGET, StepStatus, type Step, type Plan, type PlanInput, } from './plan-types.js';
|
|
9
8
|
import { RETICLE_CONFIG_FILE } from '../detect/existing-config.js';
|
|
10
9
|
export { RETICLE_CONFIG_FILE };
|
|
11
|
-
|
|
12
|
-
* The dev-dependencies `reticle init` installs — kit (or sensor) first, build plugin next.
|
|
13
|
-
*
|
|
14
|
-
* `uiLibrary` matters because the framework does not always name the renderer. The rule below was
|
|
15
|
-
* already written for Nuxt, correctly, and applied only there: a Vue app on plain Vite is
|
|
16
|
-
* `Framework.VITE` and a SvelteKit app renders Svelte, and both were being handed the React kit
|
|
17
|
-
* right after `init` had detected the real UI library and said so on screen.
|
|
18
|
-
*/
|
|
19
|
-
export declare function frameworkPackages(framework: Framework, uiLibrary?: UiLibrary): readonly string[];
|
|
10
|
+
export { frameworkPackages } from './framework-adapter.js';
|
|
20
11
|
export declare function buildPlan(input: PlanInput): Plan;
|