@reticlehq/init 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +105 -0
- package/NOTICE +5 -0
- package/README.md +29 -0
- package/dist/agent-rules.d.ts +116 -0
- package/dist/agent-rules.js +279 -0
- package/dist/app-choice.d.ts +29 -0
- package/dist/app-choice.js +39 -0
- package/dist/astro-host.d.ts +21 -0
- package/dist/astro-host.js +27 -0
- package/dist/astro-patch.d.ts +33 -0
- package/dist/astro-patch.js +103 -0
- package/dist/brace-scan.d.ts +24 -0
- package/dist/brace-scan.js +46 -0
- package/dist/capabilities.d.ts +40 -0
- package/dist/capabilities.js +167 -0
- package/dist/closing-hint.d.ts +35 -0
- package/dist/closing-hint.js +122 -0
- package/dist/codex-toml.d.ts +10 -0
- package/dist/codex-toml.js +144 -0
- package/dist/connect-steps.d.ts +55 -0
- package/dist/connect-steps.js +92 -0
- package/dist/cra.d.ts +82 -0
- package/dist/cra.js +183 -0
- package/dist/csp-check.d.ts +49 -0
- package/dist/csp-check.js +168 -0
- package/dist/csp-doctor.d.ts +32 -0
- package/dist/csp-doctor.js +62 -0
- package/dist/desktop-doctor.d.ts +46 -0
- package/dist/desktop-doctor.js +201 -0
- package/dist/detect.d.ts +225 -0
- package/dist/detect.js +334 -0
- package/dist/dev-script.d.ts +51 -0
- package/dist/dev-script.js +66 -0
- package/dist/dev-server-ports.d.ts +20 -0
- package/dist/dev-server-ports.js +45 -0
- package/dist/electron-patch.d.ts +11 -0
- package/dist/electron-patch.js +70 -0
- package/dist/electron-vite-patch.d.ts +12 -0
- package/dist/electron-vite-patch.js +100 -0
- package/dist/existing-config.d.ts +31 -0
- package/dist/existing-config.js +63 -0
- package/dist/format-generated.d.ts +18 -0
- package/dist/format-generated.js +48 -0
- package/dist/framework-adapter.d.ts +60 -0
- package/dist/framework-adapter.js +138 -0
- package/dist/host.d.ts +41 -0
- package/dist/host.js +21 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +25 -0
- package/dist/init-failure.d.ts +19 -0
- package/dist/init-failure.js +18 -0
- package/dist/init-opt-out.d.ts +17 -0
- package/dist/init-opt-out.js +30 -0
- package/dist/install-hint.d.ts +9 -0
- package/dist/install-hint.js +41 -0
- package/dist/install-retries.d.ts +22 -0
- package/dist/install-retries.js +65 -0
- package/dist/install-source-config.d.ts +18 -0
- package/dist/install-source-config.js +34 -0
- package/dist/lockfiles.d.ts +14 -0
- package/dist/lockfiles.js +49 -0
- package/dist/mcp-clients.d.ts +94 -0
- package/dist/mcp-clients.js +327 -0
- package/dist/mcp-registered.d.ts +12 -0
- package/dist/mcp-registered.js +14 -0
- package/dist/mcp.d.ts +89 -0
- package/dist/mcp.js +129 -0
- package/dist/next-patch.d.ts +49 -0
- package/dist/next-patch.js +237 -0
- package/dist/node-io.d.ts +22 -0
- package/dist/node-io.js +150 -0
- package/dist/non-js-project.d.ts +44 -0
- package/dist/non-js-project.js +137 -0
- package/dist/nuxt-patch.d.ts +18 -0
- package/dist/nuxt-patch.js +33 -0
- package/dist/patch-kind.d.ts +20 -0
- package/dist/patch-kind.js +10 -0
- package/dist/plan-electron-vite.d.ts +16 -0
- package/dist/plan-electron-vite.js +72 -0
- package/dist/plan-framework.d.ts +122 -0
- package/dist/plan-framework.js +773 -0
- package/dist/plan.d.ts +312 -0
- package/dist/plan.js +650 -0
- package/dist/platform.d.ts +16 -0
- package/dist/platform.js +16 -0
- package/dist/preflight.d.ts +30 -0
- package/dist/preflight.js +52 -0
- package/dist/project-id.d.ts +12 -0
- package/dist/project-id.js +25 -0
- package/dist/refresh-rules.d.ts +40 -0
- package/dist/refresh-rules.js +51 -0
- package/dist/remember-project.d.ts +24 -0
- package/dist/remember-project.js +40 -0
- package/dist/run.d.ts +122 -0
- package/dist/run.js +762 -0
- package/dist/slash-command.d.ts +27 -0
- package/dist/slash-command.js +132 -0
- package/dist/snippets.d.ts +267 -0
- package/dist/snippets.js +898 -0
- package/dist/tanstack-start.d.ts +18 -0
- package/dist/tanstack-start.js +57 -0
- package/dist/version.d.ts +18 -0
- package/dist/version.js +23 -0
- package/dist/vite-config.d.ts +18 -0
- package/dist/vite-config.js +111 -0
- package/dist/vite-owning-config.d.ts +25 -0
- package/dist/vite-owning-config.js +219 -0
- package/dist/windows-quote.d.ts +38 -0
- package/dist/windows-quote.js +70 -0
- package/dist/workspace-apps.d.ts +40 -0
- package/dist/workspace-apps.js +188 -0
- package/dist/workspace-redirect.d.ts +22 -0
- package/dist/workspace-redirect.js +97 -0
- package/package.json +53 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { DEV_SCRIPT_NAMES } from './dev-script.js';
|
|
2
|
+
/**
|
|
3
|
+
* The file names that say what a directory IS, shared by everything that has to ask.
|
|
4
|
+
*
|
|
5
|
+
* They lived in run.ts and are read from here now because `findWorkspaceApps` moved and needs them —
|
|
6
|
+
* one definition, imported in both directions of the question ("is this an app?" and "which app?").
|
|
7
|
+
*/
|
|
8
|
+
export const PACKAGE_JSON = 'package.json';
|
|
9
|
+
const PNPM_WORKSPACE = 'pnpm-workspace.yaml';
|
|
10
|
+
export const VITE_CONFIG_CANDIDATES = [
|
|
11
|
+
'vite.config.ts',
|
|
12
|
+
'vite.config.js',
|
|
13
|
+
'vite.config.mjs',
|
|
14
|
+
'vite.config.mts',
|
|
15
|
+
];
|
|
16
|
+
export const ELECTRON_VITE_CONFIG_CANDIDATES = [
|
|
17
|
+
'electron.vite.config.ts',
|
|
18
|
+
'electron.vite.config.js',
|
|
19
|
+
'electron.vite.config.mjs',
|
|
20
|
+
'electron.vite.config.mts',
|
|
21
|
+
];
|
|
22
|
+
export const NEXT_CONFIG_CANDIDATES = [
|
|
23
|
+
'next.config.mjs',
|
|
24
|
+
'next.config.js',
|
|
25
|
+
'next.config.ts',
|
|
26
|
+
'next.config.cjs',
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Which directories to look in for the app, when `reticle init` runs at a monorepo root.
|
|
30
|
+
*
|
|
31
|
+
* This used to be the literal list `['apps', 'packages']`. Measured on a real repo with three Next
|
|
32
|
+
* apps at `web/`, `admin/` and `space/`, it found none — so the redirect never fired, init ran
|
|
33
|
+
* against the root, and it reported ✓ for writing `app/reticle-dev.tsx` into a directory Next never
|
|
34
|
+
* compiles. A ⚠ tells a human to act; a ✓ tells them it is handled.
|
|
35
|
+
*
|
|
36
|
+
* A workspace DECLARES its packages, so that declaration is used first and directory names are not
|
|
37
|
+
* guessed at all. Where nothing is declared, every top-level directory is a better candidate than two
|
|
38
|
+
* hardcoded ones — filtered by the usual non-source suspects, and still subject to the `looksLikeApp`
|
|
39
|
+
* check that follows, so a wrong guess here costs a `package.json` read.
|
|
40
|
+
*/
|
|
41
|
+
/** Directories that are never a workspace package, whatever the layout. */
|
|
42
|
+
const NEVER_A_PACKAGE = new Set(['node_modules', 'dist', 'build', 'out', 'coverage', 'target']);
|
|
43
|
+
/** `packages/*` -> `packages`; `web` -> `web`. The base directory a glob searches. */
|
|
44
|
+
function globBase(pattern) {
|
|
45
|
+
const base = pattern
|
|
46
|
+
.split('/')[0]
|
|
47
|
+
?.trim()
|
|
48
|
+
.replace(/^['"]|['"]$/g, '');
|
|
49
|
+
return base === undefined || '' === base || '.' === base || base.includes('*') ? undefined : base;
|
|
50
|
+
}
|
|
51
|
+
function fromPnpm(yaml) {
|
|
52
|
+
// A deliberately small reader rather than a YAML dependency: this file is a list of globs, and the
|
|
53
|
+
// only shape that matters is `- 'pattern'` under `packages:`. A malformed file yields nothing,
|
|
54
|
+
// which falls through to the top-level scan rather than failing the install.
|
|
55
|
+
const out = [];
|
|
56
|
+
let inPackages = false;
|
|
57
|
+
for (const line of yaml.split('\n')) {
|
|
58
|
+
if (/^packages\s*:/.test(line)) {
|
|
59
|
+
inPackages = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (inPackages && /^\S/.test(line))
|
|
63
|
+
break;
|
|
64
|
+
const item = /^\s*-\s*(.+)$/.exec(line);
|
|
65
|
+
if (inPackages && item?.[1] !== undefined) {
|
|
66
|
+
const base = globBase(item[1]);
|
|
67
|
+
if (base !== undefined)
|
|
68
|
+
out.push(base);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
function fromPkg(workspaces) {
|
|
74
|
+
const list = Array.isArray(workspaces)
|
|
75
|
+
? workspaces
|
|
76
|
+
: 'object' === typeof workspaces && workspaces !== null
|
|
77
|
+
? workspaces.packages
|
|
78
|
+
: undefined;
|
|
79
|
+
if (!Array.isArray(list))
|
|
80
|
+
return [];
|
|
81
|
+
return list
|
|
82
|
+
.filter((p) => 'string' === typeof p)
|
|
83
|
+
.map(globBase)
|
|
84
|
+
.filter((p) => p !== undefined);
|
|
85
|
+
}
|
|
86
|
+
export function workspaceParents(sources) {
|
|
87
|
+
const declared = [
|
|
88
|
+
...(sources.pnpmWorkspace === undefined ? [] : fromPnpm(sources.pnpmWorkspace)),
|
|
89
|
+
...fromPkg(sources.pkgWorkspaces),
|
|
90
|
+
];
|
|
91
|
+
const candidates = declared.length > 0
|
|
92
|
+
? declared
|
|
93
|
+
: (sources.topLevelDirs ?? []).filter((d) => !d.startsWith('.') && !NEVER_A_PACKAGE.has(d));
|
|
94
|
+
return [...new Set(candidates)];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Which directories under this workspace are runnable apps.
|
|
98
|
+
*
|
|
99
|
+
* Moved here from run.ts, which was over the 1000-line cap and had carried a note saying it was at
|
|
100
|
+
* its cohesion limit. `library-path-boundary.test.ts` had already written down that this function
|
|
101
|
+
* "squats in init/ for historical reasons" — it is a general-purpose question about a repository's
|
|
102
|
+
* shape, next to `workspaceParents`, which answers the other half of it.
|
|
103
|
+
*/
|
|
104
|
+
/** Deps that mark a directory as a runnable web app even when it has no bundler config file. */
|
|
105
|
+
export const APP_DEPS = ['next', 'vite', 'electron-vite'];
|
|
106
|
+
function hasDevScript(pkgRaw) {
|
|
107
|
+
try {
|
|
108
|
+
const parsed = JSON.parse(pkgRaw);
|
|
109
|
+
const scripts = 'object' === typeof parsed && parsed !== null
|
|
110
|
+
? parsed.scripts
|
|
111
|
+
: undefined;
|
|
112
|
+
if ('object' !== typeof scripts || null === scripts)
|
|
113
|
+
return false;
|
|
114
|
+
const named = scripts;
|
|
115
|
+
return DEV_SCRIPT_NAMES.some((n) => 'string' === typeof named[n] && '' !== named[n]);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// A manifest that will not parse says nothing either way, and this is a filter, not a verdict.
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function looksLikeApp(dir, io) {
|
|
123
|
+
const pkgRaw = io.readFile(`${dir}/${PACKAGE_JSON}`);
|
|
124
|
+
if (null === pkgRaw)
|
|
125
|
+
return false;
|
|
126
|
+
const configs = [
|
|
127
|
+
...VITE_CONFIG_CANDIDATES,
|
|
128
|
+
...ELECTRON_VITE_CONFIG_CANDIDATES,
|
|
129
|
+
...NEXT_CONFIG_CANDIDATES,
|
|
130
|
+
];
|
|
131
|
+
if (configs.some((c) => io.exists(`${dir}/${c}`)))
|
|
132
|
+
return true;
|
|
133
|
+
// `next.config` is optional in Next, so the dependency list is the other half of the signal.
|
|
134
|
+
if (APP_DEPS.some((d) => pkgRaw.includes(`"${d}"`)))
|
|
135
|
+
return true;
|
|
136
|
+
// And the honest third: an app somebody can SERVE. Asking only for a bundler missed every app
|
|
137
|
+
// built on anything else — Remix, Astro, a plain node server — and in a monorepo missing it means
|
|
138
|
+
// init never redirects, wires the ROOT, and reports ✓ for files nothing compiles.
|
|
139
|
+
//
|
|
140
|
+
// A monorepo root has no dev script by design, and a package that can only be BUILT is not the app
|
|
141
|
+
// somebody is working in, so this stays a filter rather than matching every directory.
|
|
142
|
+
return hasDevScript(pkgRaw);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* App directories under a workspace root.
|
|
146
|
+
*
|
|
147
|
+
* Running `reticle init` at the repo root is what people actually do, and in a monorepo the app is a
|
|
148
|
+
* directory down — so init detected "no framework", printed a wall of manual HTML instructions, and
|
|
149
|
+
* would have installed the SDK into the ROOT package.json. It already walks UP for the lockfile, so
|
|
150
|
+
* it knows it is in a workspace; this is the matching walk DOWN.
|
|
151
|
+
*/
|
|
152
|
+
export function findWorkspaceApps(io) {
|
|
153
|
+
const found = [];
|
|
154
|
+
// A workspace DECLARES its packages; `['apps','packages']` was a guess that missed a real repo
|
|
155
|
+
// with three Next apps at web/, admin/ and space/ — and missing them meant init ran against the
|
|
156
|
+
// root and reported ✓ for a file Next never compiles. See workspace-apps.
|
|
157
|
+
const pkgRaw = io.readFile(PACKAGE_JSON);
|
|
158
|
+
let pkgWorkspaces;
|
|
159
|
+
try {
|
|
160
|
+
const parsed = null === pkgRaw ? undefined : JSON.parse(pkgRaw);
|
|
161
|
+
pkgWorkspaces =
|
|
162
|
+
'object' === typeof parsed && parsed !== null
|
|
163
|
+
? parsed.workspaces
|
|
164
|
+
: undefined;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
pkgWorkspaces = undefined;
|
|
168
|
+
}
|
|
169
|
+
const parents = workspaceParents({
|
|
170
|
+
...(null === io.readFile(PNPM_WORKSPACE)
|
|
171
|
+
? {}
|
|
172
|
+
: { pnpmWorkspace: io.readFile(PNPM_WORKSPACE) ?? '' }),
|
|
173
|
+
...(pkgWorkspaces === undefined ? {} : { pkgWorkspaces }),
|
|
174
|
+
topLevelDirs: io.listDirs('.'),
|
|
175
|
+
});
|
|
176
|
+
// A declared parent can itself BE the app (`workspaces: ["web"]`), so check both the directory and
|
|
177
|
+
// its children rather than assuming one level of nesting.
|
|
178
|
+
for (const parent of parents) {
|
|
179
|
+
if (looksLikeApp(parent, io))
|
|
180
|
+
found.push(parent);
|
|
181
|
+
for (const name of io.listDirs(parent)) {
|
|
182
|
+
const dir = `${parent}/${name}`;
|
|
183
|
+
if (looksLikeApp(dir, io))
|
|
184
|
+
found.push(dir);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return [...new Set(found)];
|
|
188
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace redirect: when `init` is run at a monorepo ROOT, wire the app rather than the root.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `run.ts`, which sits one line under the 1000-line backstop — every init change that
|
|
5
|
+
* touches the orchestration now trips the cap before it can be reviewed. This is the part of that
|
|
6
|
+
* file that answers a single, separable question ("is the app somewhere else, and where?"), so it
|
|
7
|
+
* is the seam that costs nothing to move.
|
|
8
|
+
*
|
|
9
|
+
* `runInit` arrives as a parameter rather than an import: re-entering init is the whole point of a
|
|
10
|
+
* redirect, and taking it as an argument keeps this module a leaf instead of forming a cycle with
|
|
11
|
+
* the file it was cut from.
|
|
12
|
+
*/
|
|
13
|
+
import type { InitIo, InitOptions, InitResult } from './run.js';
|
|
14
|
+
/** Re-enter `init`, scoped to one directory of the workspace. */
|
|
15
|
+
export type RunInit = (options: InitOptions, io: InitIo) => InitResult;
|
|
16
|
+
/**
|
|
17
|
+
* When the current directory is a workspace root with no app of its own, wire the app instead of the
|
|
18
|
+
* root. One candidate is wired silently (there is nothing to ask about); several are listed, because
|
|
19
|
+
* guessing which app someone meant is worse than one line of output.
|
|
20
|
+
* Returns null when there is nothing to redirect to — the caller then proceeds here as before.
|
|
21
|
+
*/
|
|
22
|
+
export declare function redirectToWorkspaceApp(options: InitOptions, io: InitIo, pkg: unknown, runInit: RunInit): InitResult | null;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace redirect: when `init` is run at a monorepo ROOT, wire the app rather than the root.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `run.ts`, which sits one line under the 1000-line backstop — every init change that
|
|
5
|
+
* touches the orchestration now trips the cap before it can be reviewed. This is the part of that
|
|
6
|
+
* file that answers a single, separable question ("is the app somewhere else, and where?"), so it
|
|
7
|
+
* is the seam that costs nothing to move.
|
|
8
|
+
*
|
|
9
|
+
* `runInit` arrives as a parameter rather than an import: re-entering init is the whole point of a
|
|
10
|
+
* redirect, and taking it as an argument keeps this module a leaf instead of forming a cycle with
|
|
11
|
+
* the file it was cut from.
|
|
12
|
+
*/
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { detect, Framework } from './detect.js';
|
|
15
|
+
import { findWorkspaceApps, PACKAGE_JSON } from './workspace-apps.js';
|
|
16
|
+
import { chooseWorkspaceApp, withoutTrailingSlashes } from './app-choice.js';
|
|
17
|
+
const AMBIGUOUS_HEADER = 'Several apps found in this workspace. Re-run `reticle init` inside the one you want:';
|
|
18
|
+
/**
|
|
19
|
+
* When the current directory is a workspace root with no app of its own, wire the app instead of the
|
|
20
|
+
* root. One candidate is wired silently (there is nothing to ask about); several are listed, because
|
|
21
|
+
* guessing which app someone meant is worse than one line of output.
|
|
22
|
+
* Returns null when there is nothing to redirect to — the caller then proceeds here as before.
|
|
23
|
+
*/
|
|
24
|
+
export function redirectToWorkspaceApp(options, io, pkg, runInit) {
|
|
25
|
+
if (true === options.redirected)
|
|
26
|
+
return null;
|
|
27
|
+
const rootFiles = new Set(io.rootFiles());
|
|
28
|
+
const here = detect({
|
|
29
|
+
pkg: 'object' === typeof pkg && pkg !== null ? pkg : {},
|
|
30
|
+
configFiles: rootFiles,
|
|
31
|
+
lockfiles: new Set(),
|
|
32
|
+
});
|
|
33
|
+
// `--app` is an INSTRUCTION, and it is read before the guess below. The guess answers "where is
|
|
34
|
+
// the app?" for somebody who did not say; when somebody said, there is nothing left to infer.
|
|
35
|
+
//
|
|
36
|
+
// It used to be read after, and the check underneath returns early for any directory that looks
|
|
37
|
+
// like an app — which a JS monorepo ROOT does, because shared tooling puts `vite` in its
|
|
38
|
+
// devDependencies. So on a real pnpm+turbo monorepo (measured on nuclear, a Tauri v2 app at
|
|
39
|
+
// product scale) `reticle init --app packages/player` silently ignored the flag, installed the
|
|
40
|
+
// SDK into the root's package.json, wrote `.reticle.json` and a whole `src/reticle-dev.ts` into a
|
|
41
|
+
// repository root that has no `src/`, left `packages/player` untouched — and reported three ✓ and
|
|
42
|
+
// one ⚠. The one flag documented for this shape wired the wrong directory and said it worked.
|
|
43
|
+
//
|
|
44
|
+
// Existence is the test, not membership of the discovered list: discovery scans conventional
|
|
45
|
+
// directories, and somebody who names a path knows their own layout better than the scan does.
|
|
46
|
+
const named = options.app === undefined || '' === options.app ? undefined : options.app;
|
|
47
|
+
if (named !== undefined) {
|
|
48
|
+
const wanted = withoutTrailingSlashes(named);
|
|
49
|
+
if (io.exists(`${wanted}/${PACKAGE_JSON}`))
|
|
50
|
+
return enterApp(options, io, wanted, 'Wiring', runInit);
|
|
51
|
+
io.print(`--app ${named} does not name a directory with a package.json in it.`);
|
|
52
|
+
return { ok: false, applied: 0, manual: 1 };
|
|
53
|
+
}
|
|
54
|
+
if (here.framework !== Framework.HTML)
|
|
55
|
+
return null; // this directory IS the app
|
|
56
|
+
const apps = findWorkspaceApps(io);
|
|
57
|
+
// An explicitly named app answers the ambiguity. Refusing to guess is right, but "re-run inside the
|
|
58
|
+
// one you want" is not something a script, a CI step, or an agent that cannot change directory can
|
|
59
|
+
// act on — so the refusal was a dead end for exactly the callers most likely to hit it.
|
|
60
|
+
const chosen = chooseWorkspaceApp(options.app, apps);
|
|
61
|
+
if (!chosen.ok) {
|
|
62
|
+
io.print(chosen.message);
|
|
63
|
+
return { ok: false, applied: 0, manual: 1 };
|
|
64
|
+
}
|
|
65
|
+
const target = chosen.app ?? (1 === apps.length ? apps[0] : undefined);
|
|
66
|
+
if (target === undefined) {
|
|
67
|
+
if (0 === apps.length)
|
|
68
|
+
return null; // not a workspace — fall through to the normal HTML plan
|
|
69
|
+
io.print(AMBIGUOUS_HEADER);
|
|
70
|
+
for (const a of apps)
|
|
71
|
+
io.print(` ${a}`);
|
|
72
|
+
io.print('');
|
|
73
|
+
io.print(`Or name one without changing directory: reticle init --app ${apps[0] ?? '<dir>'}`);
|
|
74
|
+
return { ok: false, applied: 0, manual: apps.length };
|
|
75
|
+
}
|
|
76
|
+
return enterApp(options, io, target, 'No app in this directory — wiring', runInit);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Re-enter `init` scoped to one directory of a workspace.
|
|
80
|
+
*
|
|
81
|
+
* One implementation for both routes in — the app somebody NAMED and the app discovery found when
|
|
82
|
+
* nobody did. They differ only in the sentence printed; scoping the io, moving the cwd and keeping
|
|
83
|
+
* the agent root has to be identical for both, and was worth having twice for exactly as long as it
|
|
84
|
+
* took to get one of them wrong.
|
|
85
|
+
*/
|
|
86
|
+
function enterApp(options, io, target, lead, runInit) {
|
|
87
|
+
io.print(`${lead} ${target}.`);
|
|
88
|
+
io.print('');
|
|
89
|
+
return runInit({
|
|
90
|
+
...options,
|
|
91
|
+
cwd: join(options.cwd, target),
|
|
92
|
+
redirected: true,
|
|
93
|
+
// Where the human is STANDING, kept across the redirect: their agent session runs here, so
|
|
94
|
+
// this is the only place a `/reticle` command file can be found by it.
|
|
95
|
+
agentRoot: options.agentRoot ?? options.cwd,
|
|
96
|
+
}, io.scoped(target));
|
|
97
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reticlehq/init",
|
|
3
|
+
"version": "2.14.0",
|
|
4
|
+
"description": "Reticle project scaffolder — detects the framework, writes the config, patches the build and registers the MCP server. The build-time half of `reticle init`.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@reticlehq/core": "2.14.0"
|
|
17
|
+
},
|
|
18
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
19
|
+
"author": "Reticle contributors",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/reticlehq/reticle.git",
|
|
23
|
+
"directory": "packages/init"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/reticlehq/reticle#readme",
|
|
26
|
+
"bugs": "https://github.com/reticlehq/reticle/issues",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE",
|
|
31
|
+
"NOTICE"
|
|
32
|
+
],
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"keywords": [
|
|
35
|
+
"mcp",
|
|
36
|
+
"ai-agents",
|
|
37
|
+
"scaffolding",
|
|
38
|
+
"cli"
|
|
39
|
+
],
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=20.0.0"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc -b",
|
|
48
|
+
"typecheck": "tsc -b",
|
|
49
|
+
"lint": "eslint src",
|
|
50
|
+
"test:unit": "vitest run src --passWithNoTests",
|
|
51
|
+
"test:coverage": "vitest run src --passWithNoTests --coverage.enabled --coverage.provider=v8 --coverage.reporter=text-summary --coverage.include='src/**/*.ts' --coverage.exclude='src/**/*.test.ts'"
|
|
52
|
+
}
|
|
53
|
+
}
|