@getrefino/cli 0.1.0-rc.2 → 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 +44 -0
- package/dist/cli.js +36 -1
- package/dist/format.d.ts +7 -0
- package/dist/format.js +44 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -84,6 +84,43 @@ Then check the result:
|
|
|
84
84
|
npx @getrefino/cli verify
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
## Upgrading a site to a newer Refino
|
|
88
|
+
|
|
89
|
+
Run the command you installed with, from the newer version:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx @getrefino/cli@latest init --agent --yes --refino-site site_…
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Updating the `@getrefino/*` packages is only half of an upgrade. Refino also
|
|
96
|
+
generates runtime code into your repository (`refino/`, the `/edit` route), and
|
|
97
|
+
installing a package never touches a file already committed there — so a site
|
|
98
|
+
can be on the newest packages and still running an older release's integration.
|
|
99
|
+
`init` is what moves that half.
|
|
100
|
+
|
|
101
|
+
You never have to delete or move a generated file. `init` refreshes every one
|
|
102
|
+
it can prove you have not edited and reports it:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
Updated Refino-generated integration:
|
|
106
|
+
refino/refino-site.ts 0.1.0-rc.1 → 0.1.0-rc.3
|
|
107
|
+
refino/copy-editing.tsx 0.1.0-rc.1 → 0.1.0-rc.3
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
A file **you** changed is never overwritten. It is listed as needing review,
|
|
111
|
+
Refino's current version is written beside it as `<file>.refino-new`, and
|
|
112
|
+
`init` exits non-zero rather than let a half-upgraded site look finished. Move
|
|
113
|
+
your changes onto that version, replace the original with it, delete the
|
|
114
|
+
`.refino-new` file, and run `init` again.
|
|
115
|
+
|
|
116
|
+
Refino knows which is which from `.refino/generated.json`, the record it writes
|
|
117
|
+
of the exact bytes it generated — commit it with the rest. Sites installed
|
|
118
|
+
before that file existed are recognised from the bytes of the older release, so
|
|
119
|
+
they upgrade the same way.
|
|
120
|
+
|
|
121
|
+
`refino verify` reports the same three states — current, refreshable, needs
|
|
122
|
+
review — without changing anything.
|
|
123
|
+
|
|
87
124
|
## If you are a coding agent
|
|
88
125
|
|
|
89
126
|
1. Run `npx @getrefino/cli init --agent --refino-site <site id>` in the
|
|
@@ -98,6 +135,13 @@ npx @getrefino/cli verify
|
|
|
98
135
|
3. Run `npx @getrefino/cli verify` and fix only what it reports. Repeat until
|
|
99
136
|
it passes.
|
|
100
137
|
|
|
138
|
+
If you are **upgrading** an existing installation rather than creating one, run
|
|
139
|
+
the same `init` command from the newer version and read its output. A non-zero
|
|
140
|
+
exit means a generated file has local changes Refino would have had to discard:
|
|
141
|
+
resolve each one against the `.refino-new` file it left beside the original,
|
|
142
|
+
then run `init` again. Do not delete or move generated files to get past it,
|
|
143
|
+
and do not report the upgrade as done while `init` or `verify` still fails.
|
|
144
|
+
|
|
101
145
|
## Commands
|
|
102
146
|
|
|
103
147
|
| Command | What it does |
|
package/dist/cli.js
CHANGED
|
@@ -33,6 +33,23 @@ Install into a site, in this order
|
|
|
33
33
|
Without --refino-site the same steps set up a self-hosted site, which holds its
|
|
34
34
|
own password and repository token instead.
|
|
35
35
|
|
|
36
|
+
Upgrade an existing installation
|
|
37
|
+
Re-run exactly the command you installed with, from the new version:
|
|
38
|
+
|
|
39
|
+
npx @getrefino/cli@latest init --agent --yes --refino-site <site_id>
|
|
40
|
+
|
|
41
|
+
Upgrading the @getrefino/* packages is not enough on its own. Refino also
|
|
42
|
+
copies runtime code into the repository (refino/), and installing a package
|
|
43
|
+
does not touch a file already committed there, so both have to move. init
|
|
44
|
+
refreshes every generated file it can prove you have not edited, says which
|
|
45
|
+
ones it changed and from which version, and never touches one you have:
|
|
46
|
+
those are listed as needing review, Refino's current version is written
|
|
47
|
+
beside each as <file>.refino-new, and init exits non-zero so a half-upgraded
|
|
48
|
+
site is never reported as a finished one. You never have to delete or move a
|
|
49
|
+
generated file yourself.
|
|
50
|
+
|
|
51
|
+
refino verify reports the same three states without changing anything.
|
|
52
|
+
|
|
36
53
|
Usage
|
|
37
54
|
refino init [--refino-site <id> [--refino-url <origin>]] [--via <installer>] [--route <path>]... [--all] [--agent | --dry-run | --plan] [--yes]
|
|
38
55
|
refino inspect [--json]
|
|
@@ -283,7 +300,25 @@ export async function run(argv) {
|
|
|
283
300
|
console.log("");
|
|
284
301
|
if (mode === "dry-run") {
|
|
285
302
|
console.log(dim("Nothing was written. Run `refino init --agent` to write these files."));
|
|
286
|
-
|
|
303
|
+
if (!result.needsReview)
|
|
304
|
+
return 0;
|
|
305
|
+
// A dry run is also the read-only way to ask "would this upgrade
|
|
306
|
+
// cleanly?", so it answers with the same exit code the real run would.
|
|
307
|
+
console.log(red(`${result.generated.filter((state) => state.status === "review").length} generated file(s) have local changes and would not be updated; --agent would leave them alone and report them.`));
|
|
308
|
+
return 1;
|
|
309
|
+
}
|
|
310
|
+
// A generated file Refino left behind because it had been edited means
|
|
311
|
+
// this site is not running the integration this version generates. That
|
|
312
|
+
// is the whole failure this exit code exists for: init used to say
|
|
313
|
+
// "Next steps" over a half-upgraded site, and nothing downstream could
|
|
314
|
+
// tell. Say what is true, and fail.
|
|
315
|
+
if (result.needsReview) {
|
|
316
|
+
const count = result.generated.filter((state) => state.status === "review").length;
|
|
317
|
+
console.log(red(bold(`Refino did not finish: ${count} generated file(s) listed above were left as they are, and are not what Refino ${TOOL_VERSION} generates.`)));
|
|
318
|
+
console.log(red("This installation is NOT current. Resolve each one, then run this command again."));
|
|
319
|
+
console.log("");
|
|
320
|
+
console.log(dim(`Everything else was written; ${PLAN_FILE} and ${INSTRUCTIONS_FILE} are up to date.`));
|
|
321
|
+
return 1;
|
|
287
322
|
}
|
|
288
323
|
console.log(bold("Next steps"));
|
|
289
324
|
if (result.installCommand)
|
package/dist/format.d.ts
CHANGED
|
@@ -11,4 +11,11 @@ export declare function formatCandidates(candidates: readonly CopyCandidate[], o
|
|
|
11
11
|
}): string;
|
|
12
12
|
export declare function formatPlanSummary(plan: MigrationPlan): string;
|
|
13
13
|
export declare function formatApply(result: ApplyResult): string;
|
|
14
|
+
/**
|
|
15
|
+
* The upgrade half of an init run: what Refino refreshed, and what it refused
|
|
16
|
+
* to touch. The second list is the important one -- it is the difference
|
|
17
|
+
* between "your installation is current" and "your installation is not", and
|
|
18
|
+
* it has to be impossible to skim past.
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatGeneratedUpgrade(result: ApplyResult): string;
|
|
14
21
|
export declare function formatVerification(result: VerificationResult): string;
|
package/dist/format.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { COMPARISON_SUFFIX } from "@getrefino/onboarding";
|
|
1
2
|
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
2
3
|
const paint = (code) => (text) => (useColor ? `[${code}m${text}[0m` : text);
|
|
3
4
|
export const bold = paint("1");
|
|
@@ -124,6 +125,49 @@ export function formatApply(result) {
|
|
|
124
125
|
for (const item of result.skipped)
|
|
125
126
|
rows.push(` ${dim("skip".padEnd(7))} ${item.path} ${dim(item.reason)}`);
|
|
126
127
|
}
|
|
128
|
+
const upgrade = formatGeneratedUpgrade(result);
|
|
129
|
+
if (upgrade) {
|
|
130
|
+
rows.push("");
|
|
131
|
+
rows.push(upgrade);
|
|
132
|
+
}
|
|
133
|
+
return rows.join("\n");
|
|
134
|
+
}
|
|
135
|
+
function versionArrow(state) {
|
|
136
|
+
return state.from && state.from !== state.to ? `${state.from} → ${state.to}` : state.to;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The upgrade half of an init run: what Refino refreshed, and what it refused
|
|
140
|
+
* to touch. The second list is the important one -- it is the difference
|
|
141
|
+
* between "your installation is current" and "your installation is not", and
|
|
142
|
+
* it has to be impossible to skim past.
|
|
143
|
+
*/
|
|
144
|
+
export function formatGeneratedUpgrade(result) {
|
|
145
|
+
const updated = result.generated.filter((state) => state.status === "update");
|
|
146
|
+
const review = result.generated.filter((state) => state.status === "review");
|
|
147
|
+
if (updated.length === 0 && review.length === 0)
|
|
148
|
+
return "";
|
|
149
|
+
const rows = [];
|
|
150
|
+
const width = updated.length > 0 ? Math.max(...updated.map((state) => state.path.length)) : 0;
|
|
151
|
+
if (updated.length > 0) {
|
|
152
|
+
rows.push(bold(result.dryRun ? "Refino-generated integration that would be updated:" : "Updated Refino-generated integration:"));
|
|
153
|
+
for (const state of updated)
|
|
154
|
+
rows.push(` ${state.path.padEnd(width)} ${cyan(versionArrow(state))}`);
|
|
155
|
+
}
|
|
156
|
+
if (review.length > 0) {
|
|
157
|
+
if (updated.length > 0)
|
|
158
|
+
rows.push("");
|
|
159
|
+
rows.push(red(bold("Needs manual review — NOT updated:")));
|
|
160
|
+
for (const state of review) {
|
|
161
|
+
// No version arrow here: the whole point is that this file's provenance
|
|
162
|
+
// could not be established, so printing one would be a claim.
|
|
163
|
+
rows.push(` ${yellow(state.path)}`);
|
|
164
|
+
rows.push(` ${dim("why:")} ${state.reason}`);
|
|
165
|
+
if (!result.dryRun && state.comparisonPath) {
|
|
166
|
+
rows.push(` ${dim("next:")} Compare it with ${state.comparisonPath} (Refino's ${state.to} version, written beside it just now).`);
|
|
167
|
+
rows.push(` Move your changes onto that version, replace ${state.path} with it, delete the ${COMPARISON_SUFFIX} file, then run init again.`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
127
171
|
return rows.join("\n");
|
|
128
172
|
}
|
|
129
173
|
export function formatVerification(result) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getrefino/cli",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.3",
|
|
4
4
|
"description": "Refino installer. Run `npx @getrefino/cli init` in a website's repository to let its owner edit visible copy in the browser while Git remains the source of truth. Inspects the repo, writes an authoritative migration plan and instructions for a coding agent, then verifies the result.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"refino",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"./package.json": "./package.json"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@getrefino/onboarding": "0.1.0-rc.
|
|
48
|
+
"@getrefino/onboarding": "0.1.0-rc.3"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/node": "22.20.2",
|