@getrefino/onboarding 0.1.0-rc.1 → 0.1.0-rc.3
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/README.md +17 -1
- package/dist/agent.d.ts +0 -4
- package/dist/agent.js +2 -1
- package/dist/apply.js +92 -16
- package/dist/generated.d.ts +30 -0
- package/dist/generated.js +168 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +3 -1
- package/dist/install-method.d.ts +26 -0
- package/dist/install-method.js +32 -0
- package/dist/plan.js +1 -1
- package/dist/template-file.d.ts +38 -0
- package/dist/template-file.js +44 -0
- package/dist/templates-hosted.d.ts +19 -15
- package/dist/templates-hosted.js +165 -16
- package/dist/templates-legacy.d.ts +25 -0
- package/dist/templates-legacy.js +221 -0
- package/dist/templates.d.ts +2 -4
- package/dist/templates.js +32 -41
- package/dist/types.d.ts +83 -1
- package/dist/verify.js +88 -2
- package/package.json +2 -2
package/dist/templates.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Boilerplate written by `refino init --
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Boilerplate written by `refino init --agent`. Each file is isolated under
|
|
3
|
+
* `refino/` (or is a new route file). Authored in TypeScript; JavaScript
|
|
4
|
+
* projects get a transpiled copy.
|
|
5
|
+
*
|
|
6
|
+
* A file that already exists is refreshed only when Refino can prove the
|
|
7
|
+
* bytes on disk are still the ones it wrote (generated.ts); otherwise it is
|
|
8
|
+
* left exactly as it is and reported. Each entry therefore declares who owns
|
|
9
|
+
* it -- `machine` for Refino's runtime code, `scaffold` for a page the owner
|
|
10
|
+
* is invited to restyle -- and, when its body has changed since a released
|
|
11
|
+
* version, the byte-exact body that version wrote.
|
|
6
12
|
*/
|
|
7
|
-
import ts from "typescript";
|
|
8
13
|
import { BOILERPLATE_DIR } from "./plan.js";
|
|
14
|
+
import { createTemplateFactory } from "./template-file.js";
|
|
9
15
|
import { hostedFiles } from "./templates-hosted.js";
|
|
10
16
|
const BOILERPLATE_DIR_NAME = BOILERPLATE_DIR;
|
|
11
17
|
function relativeImport(fromFile, toFile) {
|
|
@@ -601,71 +607,56 @@ COPY_GITHUB_REPO=owner/name
|
|
|
601
607
|
COPY_GITHUB_BRANCH=main
|
|
602
608
|
COPY_FILE_PATH=
|
|
603
609
|
`;
|
|
604
|
-
function transpileToJs(path, source) {
|
|
605
|
-
const output = ts.transpileModule(source, {
|
|
606
|
-
compilerOptions: {
|
|
607
|
-
target: ts.ScriptTarget.ES2022,
|
|
608
|
-
module: ts.ModuleKind.ESNext,
|
|
609
|
-
jsx: ts.JsxEmit.Preserve,
|
|
610
|
-
removeComments: false,
|
|
611
|
-
verbatimModuleSyntax: false,
|
|
612
|
-
},
|
|
613
|
-
fileName: path,
|
|
614
|
-
});
|
|
615
|
-
return { path: path.replace(/\.tsx$/, ".jsx").replace(/\.ts$/, ".js"), content: output.outputText.replace(/^export \{\};\s*$/m, "").replace(/\n{3,}/g, "\n\n") };
|
|
616
|
-
}
|
|
617
610
|
/** Files the apply step may create for a plan, in TS or JS as the project requires. */
|
|
618
611
|
export function boilerplateFiles(plan) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
return plan
|
|
622
|
-
}
|
|
612
|
+
const make = createTemplateFactory(plan.repository.language);
|
|
613
|
+
if (plan.refino)
|
|
614
|
+
return hostedFiles(plan, make);
|
|
623
615
|
const dir = plan.integration.boilerplateDir;
|
|
624
616
|
const strategy = plan.integration.provider.strategy;
|
|
625
617
|
const host = plan.integration.host;
|
|
626
618
|
// Server-rendered hosts pass `editing` from a cookie check; everything else probes the session in the browser.
|
|
627
619
|
const serverRenderedEditing = strategy === "next-app-root-layout" || strategy === "next-pages-app";
|
|
628
620
|
const handlers = `${dir}/request-handlers.ts`;
|
|
621
|
+
// The self-hosted templates below are byte-identical to every release so
|
|
622
|
+
// far, so none of them carries a `previous` rendering yet.
|
|
629
623
|
const files = [
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
624
|
+
make.machine(`${dir}/editor-auth.ts`, EDITOR_AUTH),
|
|
625
|
+
make.machine(`${dir}/content-adapter.ts`, CONTENT_ADAPTER(plan.contentFile.path)),
|
|
626
|
+
make.machine(handlers, REQUEST_HANDLERS),
|
|
627
|
+
make.machine(`${dir}/copy-editing.tsx`, serverRenderedEditing ? COPY_EDITING : COPY_EDITING_CLIENT_SESSION),
|
|
634
628
|
];
|
|
635
629
|
if (strategy === "next-app-root-layout-client-session") {
|
|
636
630
|
const routesDir = plan.files.find((file) => /\/edit\/page\.\w+$/.test(file.path))?.path.replace(/\/edit\/page\.\w+$/, "") ?? "app";
|
|
637
|
-
files.push(
|
|
638
|
-
files.push(
|
|
631
|
+
files.push(make.scaffold(`${routesDir}/edit/layout.tsx`, EDIT_LAYOUT_STATIC));
|
|
632
|
+
files.push(make.scaffold(`${routesDir}/edit/page.tsx`, EDIT_PAGE_STATIC));
|
|
639
633
|
}
|
|
640
634
|
const copyFile = host.copyEndpoint.replace(/\.\w+$/, ".ts");
|
|
641
635
|
const sessionFile = host.sessionEndpoint.replace(/\.\w+$/, ".ts");
|
|
642
636
|
switch (host.kind) {
|
|
643
637
|
case "next-route-handlers": {
|
|
644
638
|
const editPage = `${copyFile.replace(/\/api\/copy\/route\.ts$/, "")}/edit/page.tsx`;
|
|
645
|
-
files.push(
|
|
646
|
-
files.push(
|
|
647
|
-
files.push(
|
|
648
|
-
files.push(
|
|
639
|
+
files.push(make.machine(`${dir}/editor-session.ts`, EDITOR_SESSION_NEXT));
|
|
640
|
+
files.push(make.machine(copyFile, COPY_ROUTE_NEXT(relativeImport(copyFile, handlers))));
|
|
641
|
+
files.push(make.machine(sessionFile, SESSION_ROUTE_NEXT(relativeImport(sessionFile, handlers))));
|
|
642
|
+
files.push(make.scaffold(editPage, EDIT_PAGE_NEXT(relativeImport(editPage, `${dir}/editor-session.ts`))));
|
|
649
643
|
break;
|
|
650
644
|
}
|
|
651
645
|
case "cloudflare-pages-functions":
|
|
652
|
-
files.push(
|
|
653
|
-
files.push(
|
|
646
|
+
files.push(make.machine(copyFile, CLOUDFLARE_FUNCTION("copy", relativeImport(copyFile, handlers))));
|
|
647
|
+
files.push(make.machine(sessionFile, CLOUDFLARE_FUNCTION("edit-session", relativeImport(sessionFile, handlers))));
|
|
654
648
|
break;
|
|
655
649
|
case "netlify-functions":
|
|
656
|
-
files.push(
|
|
657
|
-
files.push(
|
|
650
|
+
files.push(make.machine(copyFile, NETLIFY_FUNCTION("copy", relativeImport(copyFile, handlers))));
|
|
651
|
+
files.push(make.machine(sessionFile, NETLIFY_FUNCTION("edit-session", relativeImport(sessionFile, handlers))));
|
|
658
652
|
break;
|
|
659
653
|
case "vercel-functions":
|
|
660
|
-
files.push(
|
|
661
|
-
files.push(
|
|
654
|
+
files.push(make.machine(copyFile, VERCEL_FUNCTION("copy", relativeImport(copyFile, handlers))));
|
|
655
|
+
files.push(make.machine(sessionFile, VERCEL_FUNCTION("edit-session", relativeImport(sessionFile, handlers))));
|
|
662
656
|
break;
|
|
663
657
|
default:
|
|
664
658
|
// next-api-routes, custom-server, unknown: the agent adapts request-handlers (see the instructions).
|
|
665
659
|
break;
|
|
666
660
|
}
|
|
667
|
-
if (plan.repository.language === "javascript") {
|
|
668
|
-
return files.map((file) => transpileToJs(file.path, file.content));
|
|
669
|
-
}
|
|
670
661
|
return files;
|
|
671
662
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Structured results shared by the CLI and any future hosted onboarding.
|
|
3
3
|
* Everything here is plain JSON-serializable data. No secrets, ever.
|
|
4
4
|
*/
|
|
5
|
+
import type { InstallMethod } from "./install-method.js";
|
|
5
6
|
export type PackageManager = "pnpm" | "npm" | "yarn" | "bun" | "unknown";
|
|
6
7
|
export type Framework = "next" | "vite-react" | "react" | "unsupported";
|
|
7
8
|
export type Router = "next-app" | "next-pages" | "react-router" | "single-page" | "unknown";
|
|
@@ -142,6 +143,68 @@ export interface HostIntegration {
|
|
|
142
143
|
/** Runtime facts the agent and the owner need (filesystem, compatibility flags, variables). */
|
|
143
144
|
readonly notes: readonly string[];
|
|
144
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Who owns a file Refino generated.
|
|
148
|
+
*
|
|
149
|
+
* `machine` Refino's own runtime code. It carries behaviour the editor and
|
|
150
|
+
* the hosted service depend on, holds nothing a site is meant to
|
|
151
|
+
* hand-write, and Refino refreshes it whenever it can prove the
|
|
152
|
+
* bytes on disk are still the ones it wrote.
|
|
153
|
+
* `scaffold` A generated starting point the owner is invited to restyle (the
|
|
154
|
+
* /edit pages). Refino refreshes an untouched one and never
|
|
155
|
+
* argues with a restyled one.
|
|
156
|
+
*
|
|
157
|
+
* Everything Refino merges rather than owns -- the copy file, package.json,
|
|
158
|
+
* .env.example, refino.config.json -- is customer-owned and is not in this
|
|
159
|
+
* vocabulary at all: it is never overwritten, only merged.
|
|
160
|
+
*/
|
|
161
|
+
export type GeneratedOwnership = "machine" | "scaffold";
|
|
162
|
+
/**
|
|
163
|
+
* What became of one generated file on an init run, or what verification
|
|
164
|
+
* found there.
|
|
165
|
+
*
|
|
166
|
+
* `create` it did not exist; Refino wrote it.
|
|
167
|
+
* `current` the bytes on disk are exactly what this version generates.
|
|
168
|
+
* `update` stale, and provably untouched since Refino wrote it, so it was
|
|
169
|
+
* (or can be) refreshed in place.
|
|
170
|
+
* `customized` changed locally, and Refino's own version of it has not moved
|
|
171
|
+
* since: nothing to upgrade, nothing to warn about.
|
|
172
|
+
* `review` changed locally *and* stale, or impossible to prove untouched.
|
|
173
|
+
* Never overwritten; always reported.
|
|
174
|
+
*/
|
|
175
|
+
export type GeneratedFileStatus = "create" | "current" | "update" | "customized" | "review";
|
|
176
|
+
/** One generated file, its ownership, and where its bytes came from. */
|
|
177
|
+
export interface GeneratedFileState {
|
|
178
|
+
readonly path: string;
|
|
179
|
+
readonly ownership: GeneratedOwnership;
|
|
180
|
+
readonly status: GeneratedFileStatus;
|
|
181
|
+
/** Refino version whose output the bytes on disk match, when that is knowable. */
|
|
182
|
+
readonly from: string | null;
|
|
183
|
+
/** Refino version generating the desired bytes. */
|
|
184
|
+
readonly to: string;
|
|
185
|
+
/** Why this status, in one sentence. Always set for `review`. */
|
|
186
|
+
readonly reason: string;
|
|
187
|
+
/**
|
|
188
|
+
* For `review`: the repository-relative file Refino wrote the current
|
|
189
|
+
* template to, beside the original, so the difference can be read and
|
|
190
|
+
* merged by hand. The original is never touched.
|
|
191
|
+
*/
|
|
192
|
+
readonly comparisonPath?: string;
|
|
193
|
+
}
|
|
194
|
+
/** `.refino/generated.json`: what Refino wrote, so a later run can tell. */
|
|
195
|
+
export interface GeneratedManifest {
|
|
196
|
+
readonly version: 1;
|
|
197
|
+
/** Refino version that last wrote this manifest. */
|
|
198
|
+
readonly tool: string;
|
|
199
|
+
readonly files: Readonly<Record<string, GeneratedManifestEntry>>;
|
|
200
|
+
}
|
|
201
|
+
export interface GeneratedManifestEntry {
|
|
202
|
+
readonly ownership: GeneratedOwnership;
|
|
203
|
+
/** Refino version that wrote these bytes. */
|
|
204
|
+
readonly toolVersion: string;
|
|
205
|
+
/** sha256, hex, of the exact bytes Refino wrote. */
|
|
206
|
+
readonly sha256: string;
|
|
207
|
+
}
|
|
145
208
|
export interface PlannedFile {
|
|
146
209
|
readonly path: string;
|
|
147
210
|
readonly action: "create" | "merge" | "append" | "modify";
|
|
@@ -236,17 +299,23 @@ export interface MigrationPlan {
|
|
|
236
299
|
};
|
|
237
300
|
readonly unresolved: readonly string[];
|
|
238
301
|
}
|
|
239
|
-
/** Public identifiers of a site connected to Refino.
|
|
302
|
+
/** Public identifiers of a site connected to Refino. None of these is a secret. */
|
|
240
303
|
export interface RefinoSite {
|
|
241
304
|
readonly siteId: string;
|
|
242
305
|
/** Origin of the Refino app, e.g. "https://app.refino.dev". */
|
|
243
306
|
readonly appUrl: string;
|
|
307
|
+
/**
|
|
308
|
+
* What `refino init --via <method>` was told, or "unknown". Committed to
|
|
309
|
+
* the repository with the site id so the owner can see and change it.
|
|
310
|
+
*/
|
|
311
|
+
readonly installMethod: InstallMethod;
|
|
244
312
|
}
|
|
245
313
|
export interface PlanOptions {
|
|
246
314
|
/** Connect to Refino (hosted mode): the site id from the Refino dashboard, and optionally the app origin. */
|
|
247
315
|
readonly refino?: {
|
|
248
316
|
readonly siteId: string;
|
|
249
317
|
readonly appUrl?: string;
|
|
318
|
+
readonly installMethod?: InstallMethod;
|
|
250
319
|
};
|
|
251
320
|
/** Routes to migrate. Defaults to ["/"] when the route exists. */
|
|
252
321
|
readonly routes?: readonly string[];
|
|
@@ -265,6 +334,19 @@ export interface ApplyResult {
|
|
|
265
334
|
readonly reason: string;
|
|
266
335
|
}[];
|
|
267
336
|
readonly installCommand: string | null;
|
|
337
|
+
/**
|
|
338
|
+
* Every file Refino generates, and what this run did with it. `written`
|
|
339
|
+
* and `skipped` stay what they always were (the files this run touched or
|
|
340
|
+
* left alone); this is the upgrade story, and the only place a stale or
|
|
341
|
+
* locally modified generated file is visible.
|
|
342
|
+
*/
|
|
343
|
+
readonly generated: readonly GeneratedFileState[];
|
|
344
|
+
/**
|
|
345
|
+
* True when a generated file was left in place although Refino's version
|
|
346
|
+
* of it has moved on. An installation with this set is not current, and no
|
|
347
|
+
* caller may report it as one.
|
|
348
|
+
*/
|
|
349
|
+
readonly needsReview: boolean;
|
|
268
350
|
}
|
|
269
351
|
export type CheckStatus = "pass" | "fail" | "warn" | "skip";
|
|
270
352
|
export interface VerificationCheck {
|
package/dist/verify.js
CHANGED
|
@@ -8,9 +8,12 @@ import { join } 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
|
+
import { COMPARISON_SUFFIX, classifyGeneratedFiles, readGeneratedManifest } from "./generated.js";
|
|
11
12
|
import { parseSource, readPathAliases, reachableFiles, resolveImport } from "./graph.js";
|
|
12
13
|
import { LEGACY_CONFIG_FILE_NAME, appDirectory, inspectRepository } from "./inspect.js";
|
|
13
|
-
import {
|
|
14
|
+
import { isInstallMethod } from "./install-method.js";
|
|
15
|
+
import { BOILERPLATE_DIR, CONFIG_FILE, TOOL_VERSION, buildPlan, verificationCommands } from "./plan.js";
|
|
16
|
+
import { boilerplateFiles } from "./templates.js";
|
|
14
17
|
const SECRET_NAMES = ["COPY_GITHUB_TOKEN", "EDITOR_SESSION_SECRET", "EDITOR_PASSWORD"];
|
|
15
18
|
const SERVER_ONLY_IMPORTS = ["@getrefino/github", "@getrefino/core/local-file"];
|
|
16
19
|
function collectEditableTextUses(appDir, files) {
|
|
@@ -143,7 +146,20 @@ function hostedChecks(appDir, inspection, hosted, sourceFiles, rendersProvider,
|
|
|
143
146
|
else if (!siteText.includes(JSON.stringify(hosted.siteId)) || !siteText.includes(JSON.stringify(hosted.appUrl)))
|
|
144
147
|
add({ id: "refino-site", status: "fail", message: `${siteFile} does not name site ${hosted.siteId} at ${hosted.appUrl} as ${CONFIG_FILE} does.`, fix: "Regenerate the module or fix the config so both agree." });
|
|
145
148
|
else
|
|
146
|
-
add({
|
|
149
|
+
add({
|
|
150
|
+
id: "refino-site",
|
|
151
|
+
status: "pass",
|
|
152
|
+
message: `Connected to Refino site ${hosted.siteId} at ${hosted.appUrl}.`,
|
|
153
|
+
// Deliberately a local check. Verification makes no network calls and
|
|
154
|
+
// holds no credential, so it can prove the repository agrees with
|
|
155
|
+
// itself and nothing more: whether this site id is still the one Refino
|
|
156
|
+
// has is a question only an authorized request can answer, and /edit
|
|
157
|
+
// asks it on every load.
|
|
158
|
+
details: [
|
|
159
|
+
"Checked in this repository only: Refino is never contacted from here, so this cannot prove the site id still exists.",
|
|
160
|
+
`If /edit says the site is not connected to your account, compare ${hosted.siteId} with the site id on your Refino dashboard and re-run \`refino init --agent --yes --refino-site <id>\` if they differ.`,
|
|
161
|
+
],
|
|
162
|
+
});
|
|
147
163
|
const missing = ["refino-client", "copy-editing", "edit-page"].filter((name) => !find(`${BOILERPLATE_DIR}/${name}`));
|
|
148
164
|
if (missing.length > 0)
|
|
149
165
|
add({ id: "refino-client", status: "fail", message: `Missing generated hosted modules: ${missing.map((name) => `${BOILERPLATE_DIR}/${name}`).join(", ")}.`, fix: "Run `refino init --agent --refino-site …` again; existing files are kept." });
|
|
@@ -176,6 +192,74 @@ function hostedChecks(appDir, inspection, hosted, sourceFiles, rendersProvider,
|
|
|
176
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.` });
|
|
177
193
|
}
|
|
178
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Is the Refino runtime code in this repository the code this Refino
|
|
197
|
+
* generates?
|
|
198
|
+
*
|
|
199
|
+
* Package versions cannot answer that. Upgrading `@getrefino/*` replaces what
|
|
200
|
+
* `node_modules` holds and leaves every file Refino copied into the
|
|
201
|
+
* repository exactly where it was, which is how a site ran rc.2 packages
|
|
202
|
+
* against rc.1 generated code and passed verification. So the files
|
|
203
|
+
* themselves are regenerated in memory and compared, and the answer is one of
|
|
204
|
+
* three: current, stale but provably untouched (one command fixes it), or
|
|
205
|
+
* stale and locally edited (a person has to look).
|
|
206
|
+
*
|
|
207
|
+
* Read-only, like the rest of verification: nothing here writes.
|
|
208
|
+
*/
|
|
209
|
+
function generatedChecks(appDir, inspection, contentFile, hosted, installMethod, add) {
|
|
210
|
+
let states;
|
|
211
|
+
try {
|
|
212
|
+
const plan = buildPlan(inspection, { filesScanned: [], candidates: [] }, {
|
|
213
|
+
contentFile,
|
|
214
|
+
...(hosted ? { refino: { siteId: hosted.siteId, appUrl: hosted.appUrl, ...(isInstallMethod(installMethod) ? { installMethod } : {}) } } : {}),
|
|
215
|
+
});
|
|
216
|
+
states = classifyGeneratedFiles(appDir, boilerplateFiles(plan), readGeneratedManifest(appDir));
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// A repository this build cannot plan for has no generated files to judge.
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const present = states.filter((state) => state.status !== "create");
|
|
223
|
+
if (present.length === 0)
|
|
224
|
+
return;
|
|
225
|
+
const upgrade = hosted
|
|
226
|
+
? `npx @getrefino/cli@${TOOL_VERSION} init --agent --yes --refino-site ${hosted.siteId}`
|
|
227
|
+
: `npx @getrefino/cli@${TOOL_VERSION} init --agent --yes`;
|
|
228
|
+
const stale = present.filter((state) => state.status === "update");
|
|
229
|
+
if (stale.length > 0) {
|
|
230
|
+
add({
|
|
231
|
+
id: "generated-stale",
|
|
232
|
+
status: "fail",
|
|
233
|
+
message: `${stale.length} generated Refino runtime file(s) are from an earlier release, although the installed packages are not.`,
|
|
234
|
+
details: stale.map((state) => `${state.path} ${state.from ?? "unknown"} → ${state.to}`),
|
|
235
|
+
fix: `Run \`${upgrade}\`. Each file listed is byte-identical to what Refino wrote, so it is refreshed in place; nothing you wrote is touched.`,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
const review = present.filter((state) => state.status === "review");
|
|
239
|
+
if (review.length > 0) {
|
|
240
|
+
// A restyled /edit page is a normal thing to own; Refino's own runtime
|
|
241
|
+
// modules are not, and a stale one of those is a real problem.
|
|
242
|
+
const machine = review.some((state) => state.ownership === "machine");
|
|
243
|
+
add({
|
|
244
|
+
id: "generated-review",
|
|
245
|
+
status: machine ? "fail" : "warn",
|
|
246
|
+
message: `${review.length} generated Refino file(s) have local changes and are from an earlier release, so Refino will not refresh them.`,
|
|
247
|
+
details: review.map((state) => `${state.path} ${state.reason}`),
|
|
248
|
+
fix: `Run \`${upgrade}\`: it leaves these files alone and writes Refino's current version beside each one as \`<file>${COMPARISON_SUFFIX}\`. Move your changes onto that version, replace the original with it, delete the \`${COMPARISON_SUFFIX}\` file, then run init again.`,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (stale.length === 0 && review.length === 0) {
|
|
252
|
+
const customized = present.filter((state) => state.status === "customized");
|
|
253
|
+
add({
|
|
254
|
+
id: "generated-current",
|
|
255
|
+
status: "pass",
|
|
256
|
+
message: `Generated Refino runtime files are the ${TOOL_VERSION} ones (${present.length} file(s)).`,
|
|
257
|
+
...(customized.length > 0
|
|
258
|
+
? { details: customized.map((state) => `${state.path} has local changes, and Refino's version of it has not changed since — nothing to upgrade.`) }
|
|
259
|
+
: {}),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
179
263
|
export function verifyIntegration(rootPath, options = {}) {
|
|
180
264
|
const inspection = inspectRepository(rootPath, options);
|
|
181
265
|
const appDir = appDirectory(inspection);
|
|
@@ -386,6 +470,8 @@ export function verifyIntegration(rootPath, options = {}) {
|
|
|
386
470
|
add({ id: "env-example", status: "pass", message: ".env.example documents the Refino variables." });
|
|
387
471
|
else
|
|
388
472
|
add({ id: "env-example", status: "warn", message: ".env.example does not document EDITOR_*/COPY_* variables.", fix: "Run `refino init --agent` or add the block by hand." });
|
|
473
|
+
// Generated runtime files: current, refreshable, or the owner's now.
|
|
474
|
+
generatedChecks(appDir, inspection, contentFile, hosted, config?.refino?.installMethod, add);
|
|
389
475
|
// Scripts (plus a tsc fallback when a TypeScript project has no typecheck script).
|
|
390
476
|
const commands = [];
|
|
391
477
|
for (const command of verificationCommands(inspection)) {
|
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.3",
|
|
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.3"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "22.20.2",
|