@getrefino/onboarding 0.1.0-rc.3 → 0.1.0-rc.4
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/inspect.d.ts +2 -0
- package/dist/inspect.js +14 -0
- package/dist/verify.js +75 -8
- package/package.json +2 -2
package/dist/inspect.d.ts
CHANGED
|
@@ -16,4 +16,6 @@ export declare function appDirectory(inspection: RepositoryInspection): string;
|
|
|
16
16
|
export declare function packageManagerRun(pm: PackageManager, script: string): string;
|
|
17
17
|
/** Run a binary from node_modules through the package manager. */
|
|
18
18
|
export declare function packageManagerExec(pm: PackageManager, command: string): string;
|
|
19
|
+
/** Add (or move) dependencies to exact specs, e.g. `pnpm add @getrefino/core@0.1.0`. */
|
|
20
|
+
export declare function packageManagerAdd(pm: PackageManager, specs: readonly string[]): string;
|
|
19
21
|
export declare function packageManagerInstall(pm: PackageManager): string;
|
package/dist/inspect.js
CHANGED
|
@@ -457,6 +457,20 @@ export function packageManagerExec(pm, command) {
|
|
|
457
457
|
return `npx ${command}`;
|
|
458
458
|
}
|
|
459
459
|
}
|
|
460
|
+
/** Add (or move) dependencies to exact specs, e.g. `pnpm add @getrefino/core@0.1.0`. */
|
|
461
|
+
export function packageManagerAdd(pm, specs) {
|
|
462
|
+
const list = specs.join(" ");
|
|
463
|
+
switch (pm) {
|
|
464
|
+
case "pnpm":
|
|
465
|
+
return `pnpm add ${list}`;
|
|
466
|
+
case "yarn":
|
|
467
|
+
return `yarn add ${list}`;
|
|
468
|
+
case "bun":
|
|
469
|
+
return `bun add ${list}`;
|
|
470
|
+
default:
|
|
471
|
+
return `npm install ${list}`;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
460
474
|
export function packageManagerInstall(pm) {
|
|
461
475
|
switch (pm) {
|
|
462
476
|
case "pnpm":
|
package/dist/verify.js
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* repository's own verification scripts.
|
|
5
5
|
*/
|
|
6
6
|
import { spawnSync } from "node:child_process";
|
|
7
|
-
import { join } from "node:path";
|
|
7
|
+
import { dirname, join, resolve } from "node:path";
|
|
8
8
|
import { isContentId, parseCopy } from "@getrefino/core";
|
|
9
9
|
import ts from "typescript";
|
|
10
10
|
import { exists, isFile, isTestOrStoryFile, readJson, readText, rel, walkFiles } from "./fs.js";
|
|
11
11
|
import { COMPARISON_SUFFIX, classifyGeneratedFiles, readGeneratedManifest } from "./generated.js";
|
|
12
12
|
import { parseSource, readPathAliases, reachableFiles, resolveImport } from "./graph.js";
|
|
13
|
-
import { LEGACY_CONFIG_FILE_NAME, appDirectory, inspectRepository } from "./inspect.js";
|
|
13
|
+
import { LEGACY_CONFIG_FILE_NAME, appDirectory, inspectRepository, packageManagerAdd } from "./inspect.js";
|
|
14
14
|
import { isInstallMethod } from "./install-method.js";
|
|
15
15
|
import { BOILERPLATE_DIR, CONFIG_FILE, TOOL_VERSION, buildPlan, verificationCommands } from "./plan.js";
|
|
16
16
|
import { boilerplateFiles } from "./templates.js";
|
|
@@ -192,18 +192,44 @@ function hostedChecks(appDir, inspection, hosted, sourceFiles, rendersProvider,
|
|
|
192
192
|
add({ id: "hosted-provider", status: "fail", message: `${file} decides edit mode on the server; a Refino-hosted site decides it in the browser.`, fix: `Render <CopyEditing content={copy}> from ${BOILERPLATE_DIR}/copy-editing without an editing prop and without next/headers.` });
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
+
const EXACT_VERSION = /^[=v]?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)(?:\+[0-9A-Za-z.-]+)?$/;
|
|
196
|
+
function normalizeVersion(value) {
|
|
197
|
+
return EXACT_VERSION.exec(value.trim())?.[1] ?? null;
|
|
198
|
+
}
|
|
199
|
+
function resolveRuntimePackages(inspection, appDir) {
|
|
200
|
+
const root = resolve(inspection.root);
|
|
201
|
+
return inspection.refino.packages
|
|
202
|
+
.filter((pkg) => pkg.name.startsWith("@getrefino/"))
|
|
203
|
+
.map((pkg) => {
|
|
204
|
+
for (let dir = resolve(appDir);; dir = dirname(dir)) {
|
|
205
|
+
const installed = readJson(join(dir, "node_modules", pkg.name, "package.json"));
|
|
206
|
+
const version = typeof installed?.version === "string" ? normalizeVersion(installed.version) : null;
|
|
207
|
+
if (version)
|
|
208
|
+
return { name: pkg.name, declared: pkg.version, version, source: "installed" };
|
|
209
|
+
if (dir === root || dirname(dir) === dir)
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
const pinned = normalizeVersion(pkg.version);
|
|
213
|
+
return pinned
|
|
214
|
+
? { name: pkg.name, declared: pkg.version, version: pinned, source: "pinned" }
|
|
215
|
+
: { name: pkg.name, declared: pkg.version, version: null, source: "range" };
|
|
216
|
+
});
|
|
217
|
+
}
|
|
195
218
|
/**
|
|
196
219
|
* Is the Refino runtime code in this repository the code this Refino
|
|
197
|
-
* generates?
|
|
220
|
+
* generates, and do the installed packages match it?
|
|
198
221
|
*
|
|
199
|
-
* Package versions cannot answer
|
|
200
|
-
* `node_modules` holds and leaves every file Refino copied into
|
|
201
|
-
* repository exactly where it was, which is how a site ran rc.2 packages
|
|
222
|
+
* Package versions cannot answer the first question. Upgrading `@getrefino/*`
|
|
223
|
+
* replaces what `node_modules` holds and leaves every file Refino copied into
|
|
224
|
+
* the repository exactly where it was, which is how a site ran rc.2 packages
|
|
202
225
|
* against rc.1 generated code and passed verification. So the files
|
|
203
226
|
* themselves are regenerated in memory and compared, and the answer is one of
|
|
204
227
|
* three: current, stale but provably untouched (one command fixes it), or
|
|
205
228
|
* stale and locally edited (a person has to look).
|
|
206
229
|
*
|
|
230
|
+
* The converse happened too: rc.3 generated files next to rc.2 packages
|
|
231
|
+
* passed, because nothing compared the two. `package-versions` does.
|
|
232
|
+
*
|
|
207
233
|
* Read-only, like the rest of verification: nothing here writes.
|
|
208
234
|
*/
|
|
209
235
|
function generatedChecks(appDir, inspection, contentFile, hosted, installMethod, add) {
|
|
@@ -222,6 +248,11 @@ function generatedChecks(appDir, inspection, contentFile, hosted, installMethod,
|
|
|
222
248
|
const present = states.filter((state) => state.status !== "create");
|
|
223
249
|
if (present.length === 0)
|
|
224
250
|
return;
|
|
251
|
+
const packages = resolveRuntimePackages(inspection, appDir);
|
|
252
|
+
// The normal upgrade, in the order it has to happen: packages to this
|
|
253
|
+
// release, then init to refresh what Refino generated.
|
|
254
|
+
const packagesNotCurrent = packages.filter((pkg) => pkg.version !== TOOL_VERSION);
|
|
255
|
+
const installPackages = packagesNotCurrent.length > 0 ? packageManagerAdd(inspection.packageManager, packagesNotCurrent.map((pkg) => `${pkg.name}@${TOOL_VERSION}`)) : null;
|
|
225
256
|
const upgrade = hosted
|
|
226
257
|
? `npx @getrefino/cli@${TOOL_VERSION} init --agent --yes --refino-site ${hosted.siteId}`
|
|
227
258
|
: `npx @getrefino/cli@${TOOL_VERSION} init --agent --yes`;
|
|
@@ -230,9 +261,9 @@ function generatedChecks(appDir, inspection, contentFile, hosted, installMethod,
|
|
|
230
261
|
add({
|
|
231
262
|
id: "generated-stale",
|
|
232
263
|
status: "fail",
|
|
233
|
-
message: `${stale.length} generated Refino runtime file(s) are from an earlier release
|
|
264
|
+
message: `${stale.length} generated Refino runtime file(s) are from an earlier release than this CLI (${TOOL_VERSION}).`,
|
|
234
265
|
details: stale.map((state) => `${state.path} ${state.from ?? "unknown"} → ${state.to}`),
|
|
235
|
-
fix: `Run \`${upgrade}
|
|
266
|
+
fix: `${installPackages ? `Run \`${installPackages}\`, then \`${upgrade}\`` : `Run \`${upgrade}\``}. Each file listed is byte-identical to what Refino wrote, so it is refreshed in place; nothing you wrote is touched.`,
|
|
236
267
|
});
|
|
237
268
|
}
|
|
238
269
|
const review = present.filter((state) => state.status === "review");
|
|
@@ -259,6 +290,42 @@ function generatedChecks(appDir, inspection, contentFile, hosted, installMethod,
|
|
|
259
290
|
: {}),
|
|
260
291
|
});
|
|
261
292
|
}
|
|
293
|
+
// Which release the generated integration is. Only files whose bytes are a
|
|
294
|
+
// known release's output say so; an edited file's recorded version is where
|
|
295
|
+
// it started, not what it is. Files from more than one release have no
|
|
296
|
+
// single version to compare against, and generated-stale already fails.
|
|
297
|
+
const generatedVersions = new Set(present.filter((state) => state.status === "current" || state.status === "update").map((state) => state.from));
|
|
298
|
+
const generatedVersion = generatedVersions.size === 1 ? [...generatedVersions][0] : null;
|
|
299
|
+
if (generatedVersion === null || packages.length === 0)
|
|
300
|
+
return;
|
|
301
|
+
const describe = (pkg) => pkg.source === "installed" ? `${pkg.name} ${pkg.version} (installed)` : pkg.source === "pinned" ? `${pkg.name} ${pkg.version} (pinned in package.json, not installed)` : `${pkg.name} "${pkg.declared}" (a range in package.json, not installed)`;
|
|
302
|
+
const mismatched = packages.filter((pkg) => pkg.version !== null && pkg.version !== generatedVersion);
|
|
303
|
+
const unresolved = packages.filter((pkg) => pkg.version === null);
|
|
304
|
+
const fix = [
|
|
305
|
+
installPackages ? `Run \`${installPackages}\`` : null,
|
|
306
|
+
generatedVersion !== TOOL_VERSION ? `${installPackages ? "then " : "Run "}\`${upgrade}\`` : null,
|
|
307
|
+
].filter(Boolean).join(", ");
|
|
308
|
+
if (mismatched.length > 0) {
|
|
309
|
+
add({
|
|
310
|
+
id: "package-versions",
|
|
311
|
+
status: "fail",
|
|
312
|
+
message: `Installed Refino packages do not match the generated integration (${generatedVersion}).`,
|
|
313
|
+
details: [...mismatched, ...unresolved].map(describe),
|
|
314
|
+
fix: `${fix || `Run \`${upgrade}\``}, so the packages and the generated integration are the same release.`,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
else if (unresolved.length > 0) {
|
|
318
|
+
add({
|
|
319
|
+
id: "package-versions",
|
|
320
|
+
status: "warn",
|
|
321
|
+
message: `Cannot confirm the installed Refino package versions match the generated integration (${generatedVersion}).`,
|
|
322
|
+
details: unresolved.map(describe),
|
|
323
|
+
fix: `Install dependencies, or pin them: \`${packageManagerAdd(inspection.packageManager, unresolved.map((pkg) => `${pkg.name}@${generatedVersion}`))}\`.`,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
add({ id: "package-versions", status: "pass", message: `Installed Refino packages match the generated integration (${generatedVersion}).` });
|
|
328
|
+
}
|
|
262
329
|
}
|
|
263
330
|
export function verifyIntegration(rootPath, options = {}) {
|
|
264
331
|
const inspection = inspectRepository(rootPath, options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getrefino/onboarding",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.4",
|
|
4
4
|
"description": "The engine behind `npx @getrefino/cli init`: deterministic repository inspection, copy discovery, migration planning, agent instructions and verification for adding Refino to an existing React site. Development tooling only; never part of a site's runtime.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"refino",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"typescript": ">=5.5 <7",
|
|
41
|
-
"@getrefino/core": "0.1.0-rc.
|
|
41
|
+
"@getrefino/core": "0.1.0-rc.4"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "22.20.2",
|