@getrefino/cli 0.1.0-rc.6 → 0.2.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/README.md +22 -8
- package/dist/cli.js +101 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,6 +10,10 @@ This package is how Refino is installed into a website. If you were asked to
|
|
|
10
10
|
npx @getrefino/cli init
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
`init` connects the site to your Refino account and asks for its site id,
|
|
14
|
+
which you get by connecting the site at <https://app.refino.dev>. Refino does
|
|
15
|
+
not host your site; it keeps being built and deployed exactly as it is today.
|
|
16
|
+
|
|
13
17
|
The installed binary is named `refino`. **Refino** is the product; `getrefino`
|
|
14
18
|
is only the npm namespace.
|
|
15
19
|
|
|
@@ -44,7 +48,8 @@ repository.
|
|
|
44
48
|
- The copy file **does not have to exist yet.** `init` writes it in step 2.
|
|
45
49
|
Until the site is installed and deployed, the dashboard shows it as
|
|
46
50
|
*awaiting install*; that is the expected state, not a fault.
|
|
47
|
-
2. **Install into the repository**, passing that site id
|
|
51
|
+
2. **Install into the repository**, passing that site id (run interactively
|
|
52
|
+
without it, `init` asks for it):
|
|
48
53
|
|
|
49
54
|
```bash
|
|
50
55
|
npx @getrefino/cli init --agent --yes --refino-site site_…
|
|
@@ -62,13 +67,19 @@ or moved to another account — it has a new site id, and step 2 is how the
|
|
|
62
67
|
repository learns it. Re-run `init --agent --yes --refino-site <new id>`,
|
|
63
68
|
commit and deploy.
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
### Standalone sites
|
|
71
|
+
|
|
72
|
+
`--standalone` sets up a site that is not connected to Refino at all: it runs
|
|
73
|
+
its own editor login and holds its own editor password and repository token.
|
|
67
74
|
|
|
68
75
|
```bash
|
|
69
|
-
npx @getrefino/cli init --agent
|
|
76
|
+
npx @getrefino/cli init --agent --standalone
|
|
70
77
|
```
|
|
71
78
|
|
|
79
|
+
Before 0.2.0 this was what `init` did when no `--refino-site` was given. From
|
|
80
|
+
0.2.0 connecting to Refino is the default, and `init` without either flag asks
|
|
81
|
+
for a site id (or, when it cannot ask, exits and says how to get one).
|
|
82
|
+
|
|
72
83
|
`init` inspects the repository (framework, router, routes, package manager,
|
|
73
84
|
auth, server, hosting, git), scans the pages for visible copy, proposes stable
|
|
74
85
|
ids, and writes:
|
|
@@ -92,6 +103,7 @@ you installed with, from that version:
|
|
|
92
103
|
```bash
|
|
93
104
|
pnpm add @getrefino/core@<version> @getrefino/react@<version> # or npm install / yarn add / bun add
|
|
94
105
|
npx @getrefino/cli@<version> init --agent --yes --refino-site site_…
|
|
106
|
+
npx @getrefino/cli@<version> init --agent --yes --standalone # standalone sites
|
|
95
107
|
```
|
|
96
108
|
|
|
97
109
|
`init` never changes a dependency already listed in `package.json`, and
|
|
@@ -129,9 +141,11 @@ review — without changing anything.
|
|
|
129
141
|
|
|
130
142
|
## If you are a coding agent
|
|
131
143
|
|
|
132
|
-
1. Run `npx @getrefino/cli init --agent --refino-site <site id>` in the
|
|
133
|
-
repository
|
|
134
|
-
|
|
144
|
+
1. Run `npx @getrefino/cli init --agent --yes --refino-site <site id>` in the
|
|
145
|
+
repository. The owner gets the site id by connecting the site in the
|
|
146
|
+
Refino dashboard (<https://app.refino.dev>); if they have none, ask them
|
|
147
|
+
to do that first. Use `--standalone` only when the owner asks for a
|
|
148
|
+
standalone site. Add
|
|
135
149
|
`--via claude|codex|gemini|grok|other` so Refino knows which installation
|
|
136
150
|
routes work.
|
|
137
151
|
2. Read `.refino/AGENT_INSTRUCTIONS.md` and `.refino/plan.json` and do exactly
|
|
@@ -159,7 +173,7 @@ and do not report the upgrade as done while `init` or `verify` still fails.
|
|
|
159
173
|
| `refino verify` | Check an installation and say exactly what is missing |
|
|
160
174
|
|
|
161
175
|
Every command takes `--json` for machine-readable output and `--cwd <dir>` to
|
|
162
|
-
operate on another directory. `refino init --dry-run
|
|
176
|
+
operate on another directory. `refino init --dry-run --refino-site <id>` shows what would be
|
|
163
177
|
written without writing anything. No command overwrites an existing file, with
|
|
164
178
|
one exception: `init --refino-site <id>` updates the generated `refino/`
|
|
165
179
|
constants module and the `refino` block of `refino.config.json` when they still
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import { writeFileSync } from "node:fs";
|
|
|
6
6
|
import { resolve } from "node:path";
|
|
7
7
|
import { createInterface } from "node:readline/promises";
|
|
8
8
|
import { parseArgs } from "node:util";
|
|
9
|
-
import { INSTRUCTIONS_FILE, PLAN_FILE, TOOL_VERSION, appDirectory, applyPlan, inspectRepository, planMigration, renderAgentInstructions, resolveInstallMethod, scanCopy, verifyIntegration, } from "@getrefino/onboarding";
|
|
9
|
+
import { INSTRUCTIONS_FILE, PLAN_FILE, REFINO_SITE_ID_PATTERN, TOOL_VERSION, appDirectory, applyPlan, inspectRepository, planMigration, renderAgentInstructions, resolveInstallMethod, scanCopy, verifyIntegration, } from "@getrefino/onboarding";
|
|
10
10
|
import { bold, cyan, dim, formatApply, formatCandidates, formatInspection, formatPlanSummary, formatVerification, red, yellow } from "./format.js";
|
|
11
11
|
const TAGLINE = "Refino lets site owners edit visible website copy in the browser while the repository stays the source of truth.";
|
|
12
12
|
const HELP = `refino ${TOOL_VERSION} (@getrefino/cli)
|
|
@@ -18,25 +18,34 @@ commit, and removing Refino leaves the content exactly where it was.
|
|
|
18
18
|
|
|
19
19
|
Install into a site, in this order
|
|
20
20
|
1. Connect the site in the Refino dashboard (https://app.refino.dev) and copy
|
|
21
|
-
its site id.
|
|
22
|
-
Refino files and be deployed, and where the copy file
|
|
23
|
-
file does not have to exist yet.
|
|
21
|
+
its site id. Sign in with GitHub, then give it the repository, the branch
|
|
22
|
+
that will carry the Refino files and be deployed, and where the copy file
|
|
23
|
+
will live. The copy file does not have to exist yet. Refino does not host
|
|
24
|
+
your site: it keeps being built and deployed exactly as it is today.
|
|
24
25
|
2. npx @getrefino/cli init --agent --yes --refino-site <site_id>
|
|
25
26
|
inspects the repo and writes the setup files, .refino/plan.json and
|
|
26
|
-
.refino/AGENT_INSTRUCTIONS.md.
|
|
27
|
+
.refino/AGENT_INSTRUCTIONS.md. Run interactively without --refino-site,
|
|
28
|
+
init asks for the site id.
|
|
27
29
|
3. Hand those two files to your coding agent and let it do exactly what they say.
|
|
28
30
|
4. npx @getrefino/cli verify fix only what it reports; repeat until it passes
|
|
29
31
|
5. Commit and merge that work onto the branch the site is configured to use, then
|
|
30
32
|
deploy it. Refino reads and commits the copy file on that branch.
|
|
31
33
|
6. Open /edit on the deployed site.
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
own password and repository token
|
|
35
|
+
Connecting to your Refino account is the default. To set up a standalone site
|
|
36
|
+
instead, which holds its own editor password and repository token and never
|
|
37
|
+
talks to Refino, pass --standalone:
|
|
38
|
+
|
|
39
|
+
npx @getrefino/cli init --agent --yes --standalone
|
|
35
40
|
|
|
36
41
|
Upgrade an existing installation
|
|
37
42
|
Re-run exactly the command you installed with, from the new version:
|
|
38
43
|
|
|
39
44
|
npx @getrefino/cli@latest init --agent --yes --refino-site <site_id>
|
|
45
|
+
npx @getrefino/cli@latest init --agent --yes --standalone (standalone sites)
|
|
46
|
+
|
|
47
|
+
Before 0.2.0, init without --refino-site set up a standalone site. It now
|
|
48
|
+
needs --standalone to do that.
|
|
40
49
|
|
|
41
50
|
Upgrading the @getrefino/* packages is not enough on its own. Refino also
|
|
42
51
|
copies runtime code into the repository (refino/), and installing a package
|
|
@@ -51,7 +60,7 @@ Upgrade an existing installation
|
|
|
51
60
|
refino verify reports the same three states without changing anything.
|
|
52
61
|
|
|
53
62
|
Usage
|
|
54
|
-
refino init
|
|
63
|
+
refino init (--refino-site <id> [--refino-url <origin>] [--via <installer>] | --standalone) [--route <path>]... [--all] [--agent | --dry-run | --plan] [--yes]
|
|
55
64
|
refino inspect [--json]
|
|
56
65
|
refino scan [--route <path>]... [--all] [--no-shared] [--json] [--include-excluded]
|
|
57
66
|
refino plan [--route <path>]... [--all] [--format text|json|agent] [--out <file>]
|
|
@@ -64,9 +73,14 @@ Options
|
|
|
64
73
|
--all Every discovered route
|
|
65
74
|
--no-shared Exclude shared chrome (layouts, nav, footer)
|
|
66
75
|
--content-file <p> Where the canonical copy file lives (default: content/copy.json)
|
|
67
|
-
--refino-site <id>
|
|
68
|
-
|
|
76
|
+
--refino-site <id> The site id from the Refino dashboard. Connects the site to your
|
|
77
|
+
Refino account, which signs the owner in and commits their edits.
|
|
78
|
+
The site then needs no editor password, secret, repository token
|
|
79
|
+
or server code. Asked for when init runs interactively without it.
|
|
69
80
|
--refino-url <origin> Refino app origin (default: https://app.refino.dev)
|
|
81
|
+
--standalone Do not connect to Refino: the site runs its own editor login and
|
|
82
|
+
commits with its own repository token. This is what init did
|
|
83
|
+
without --refino-site before 0.2.0.
|
|
70
84
|
--via <installer> Who is doing the installation: claude, codex, gemini, grok, cli,
|
|
71
85
|
manual or other. Recorded as a public constant in the site and
|
|
72
86
|
told to Refino so it knows which installation routes work. It is
|
|
@@ -80,11 +94,14 @@ Options
|
|
|
80
94
|
--run verify: also run the repository's typecheck/lint/test/build
|
|
81
95
|
|
|
82
96
|
If you are a coding agent
|
|
83
|
-
1.
|
|
97
|
+
1. Ask the owner for the site id from their Refino dashboard (https://app.refino.dev).
|
|
98
|
+
If they have none, ask them to connect the site there first; do not
|
|
99
|
+
switch to --standalone unless they ask for a standalone site.
|
|
100
|
+
2. npx @getrefino/cli init --agent --yes --refino-site <site_id> --via <your name: claude, codex, gemini, grok or other>
|
|
84
101
|
(inspect, plan, write setup files + instructions)
|
|
85
|
-
|
|
102
|
+
3. Read .refino/AGENT_INSTRUCTIONS.md and .refino/plan.json and do exactly what they say.
|
|
86
103
|
They are authoritative: do not invent integration steps of your own.
|
|
87
|
-
|
|
104
|
+
4. npx @getrefino/cli verify (fix only what it reports, then run it again)
|
|
88
105
|
`;
|
|
89
106
|
function parse(argv) {
|
|
90
107
|
const { values, positionals } = parseArgs({
|
|
@@ -100,6 +117,7 @@ function parse(argv) {
|
|
|
100
117
|
"content-file": { type: "string" },
|
|
101
118
|
"refino-site": { type: "string" },
|
|
102
119
|
"refino-url": { type: "string" },
|
|
120
|
+
standalone: { type: "boolean", default: false },
|
|
103
121
|
via: { type: "string" },
|
|
104
122
|
agent: { type: "boolean", default: false },
|
|
105
123
|
"dry-run": { type: "boolean", default: false },
|
|
@@ -124,6 +142,7 @@ function parse(argv) {
|
|
|
124
142
|
contentFile: values["content-file"],
|
|
125
143
|
refinoSite: values["refino-site"],
|
|
126
144
|
refinoUrl: values["refino-url"],
|
|
145
|
+
standalone: values.standalone,
|
|
127
146
|
via: values.via,
|
|
128
147
|
agent: values.agent,
|
|
129
148
|
dryRun: values["dry-run"],
|
|
@@ -158,6 +177,8 @@ function planOptions(args) {
|
|
|
158
177
|
throw new Error("--refino-url needs --refino-site.");
|
|
159
178
|
else if (args.via)
|
|
160
179
|
throw new Error("--via needs --refino-site: it is recorded on the site connected to Refino.");
|
|
180
|
+
else if (args.standalone && args.command !== "init")
|
|
181
|
+
throw new Error("--standalone only applies to init.");
|
|
161
182
|
return options;
|
|
162
183
|
}
|
|
163
184
|
function inspect(args) {
|
|
@@ -188,6 +209,64 @@ function writePlanOutputs(args, plan) {
|
|
|
188
209
|
writeFileSync(resolve(args.cwd, args.out), content, "utf8");
|
|
189
210
|
console.log(dim(`Wrote ${args.out}`));
|
|
190
211
|
}
|
|
212
|
+
/** Where an owner gets a site id: the only way one is ever minted. */
|
|
213
|
+
const SITE_ID_GUIDANCE = [
|
|
214
|
+
"Refino connects this site to your Refino account, which signs you in and commits your edits.",
|
|
215
|
+
"Refino does not host the site: it keeps being built and deployed exactly as it is today.",
|
|
216
|
+
"",
|
|
217
|
+
"To get a site id:",
|
|
218
|
+
" 1. Open https://app.refino.dev and sign in with GitHub.",
|
|
219
|
+
" 2. Connect the site: its repository, the branch that will carry the Refino files and",
|
|
220
|
+
" be deployed, where the copy file will live (it does not have to exist yet), and the",
|
|
221
|
+
" URL the site is served from.",
|
|
222
|
+
" 3. Copy the site id it shows you (site_…).",
|
|
223
|
+
];
|
|
224
|
+
/**
|
|
225
|
+
* The site id init connects to, or null for a standalone install.
|
|
226
|
+
*
|
|
227
|
+
* Connecting to a Refino account is the default. A standalone install is
|
|
228
|
+
* only ever chosen explicitly with --standalone; nothing falls back to it,
|
|
229
|
+
* because the two write different code into the site and an owner who
|
|
230
|
+
* wanted one should never find the other.
|
|
231
|
+
*/
|
|
232
|
+
async function resolveInitSite(args) {
|
|
233
|
+
if (args.standalone)
|
|
234
|
+
return { siteId: null };
|
|
235
|
+
if (args.refinoSite)
|
|
236
|
+
return { siteId: args.refinoSite };
|
|
237
|
+
const command = "npx @getrefino/cli init --agent --yes --refino-site <site_id>";
|
|
238
|
+
if (args.yes || !process.stdin.isTTY) {
|
|
239
|
+
console.log(red("init needs a Refino site id."));
|
|
240
|
+
console.log("");
|
|
241
|
+
for (const line of SITE_ID_GUIDANCE)
|
|
242
|
+
console.log(line);
|
|
243
|
+
console.log("");
|
|
244
|
+
console.log(`Then run: ${cyan(command)}`);
|
|
245
|
+
console.log(dim("For a standalone site that runs its own editor login instead, pass --standalone."));
|
|
246
|
+
return { exit: 2 };
|
|
247
|
+
}
|
|
248
|
+
for (const line of SITE_ID_GUIDANCE)
|
|
249
|
+
console.log(line);
|
|
250
|
+
console.log("");
|
|
251
|
+
console.log(dim("For a standalone site that runs its own editor login instead, press Enter and re-run with --standalone."));
|
|
252
|
+
for (;;) {
|
|
253
|
+
const answer = await prompt("Refino site id: ");
|
|
254
|
+
if (answer === "") {
|
|
255
|
+
console.log(dim(`Nothing was written. When you have the site id, run: ${command}`));
|
|
256
|
+
return { exit: 2 };
|
|
257
|
+
}
|
|
258
|
+
if (REFINO_SITE_ID_PATTERN.test(answer)) {
|
|
259
|
+
console.log("");
|
|
260
|
+
return { siteId: answer };
|
|
261
|
+
}
|
|
262
|
+
console.log(yellow("That is not a site id. It looks like site_ followed by 32 characters, and is shown on the dashboard."));
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/** The init command that reproduces this run's mode, for messages that tell the owner what to run next. */
|
|
266
|
+
function initCommand(args, extra) {
|
|
267
|
+
const mode = args.refinoSite ? ` --refino-site ${args.refinoSite}` : " --standalone";
|
|
268
|
+
return `refino init ${extra}${mode}`;
|
|
269
|
+
}
|
|
191
270
|
export async function run(argv) {
|
|
192
271
|
let args;
|
|
193
272
|
try {
|
|
@@ -257,6 +336,14 @@ export async function run(argv) {
|
|
|
257
336
|
console.log(TAGLINE);
|
|
258
337
|
console.log(dim("Copy lives in one JSON file in this repository. An edit is a commit. No CMS, no database, no sync."));
|
|
259
338
|
console.log("");
|
|
339
|
+
if (args.standalone && (args.refinoSite || args.refinoUrl || args.via)) {
|
|
340
|
+
throw new Error("--standalone cannot be combined with --refino-site, --refino-url or --via: a standalone site is not connected to Refino.");
|
|
341
|
+
}
|
|
342
|
+
const site = await resolveInitSite(args);
|
|
343
|
+
if ("exit" in site)
|
|
344
|
+
return site.exit;
|
|
345
|
+
if (site.siteId)
|
|
346
|
+
args = { ...args, refinoSite: site.siteId };
|
|
260
347
|
const inspection = inspect(args);
|
|
261
348
|
if (!requireSupported(inspection))
|
|
262
349
|
return 1;
|
|
@@ -299,7 +386,7 @@ export async function run(argv) {
|
|
|
299
386
|
console.log(formatApply(result));
|
|
300
387
|
console.log("");
|
|
301
388
|
if (mode === "dry-run") {
|
|
302
|
-
console.log(dim(
|
|
389
|
+
console.log(dim(`Nothing was written. Run \`${initCommand(args, "--agent")}\` to write these files.`));
|
|
303
390
|
if (!result.needsReview)
|
|
304
391
|
return 0;
|
|
305
392
|
// A dry run is also the read-only way to ask "would this upgrade
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getrefino/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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.
|
|
48
|
+
"@getrefino/onboarding": "0.2.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/node": "22.20.2",
|