@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.
Files changed (3) hide show
  1. package/README.md +22 -8
  2. package/dist/cli.js +101 -14
  3. 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
- Without `--refino-site` the same command sets up a **self-hosted** site, which
66
- holds its own editor password and repository token instead:
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 (the owner gets the site id from the Refino dashboard; without
134
- one, `init --agent` sets up a self-hosted site instead). Add
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` shows what would be
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. You give it the repository, the branch that will carry the
22
- Refino files and be deployed, and where the copy file will live. The copy
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
- Without --refino-site the same steps set up a self-hosted site, which holds its
34
- own password and repository token instead.
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 [--refino-site <id> [--refino-url <origin>]] [--via <installer>] [--route <path>]... [--all] [--agent | --dry-run | --plan] [--yes]
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> Connect to Refino (hosted mode): the site id from the Refino dashboard.
68
- The site then needs no editor password, secret, repository token or server code.
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. npx @getrefino/cli init --agent --via <your name: claude, codex, gemini, grok or other>
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
- 2. Read .refino/AGENT_INSTRUCTIONS.md and .refino/plan.json and do exactly what they say.
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
- 3. npx @getrefino/cli verify (fix only what it reports, then run it again)
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("Nothing was written. Run `refino init --agent` to write these files."));
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.1.0-rc.6",
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.1.0-rc.6"
48
+ "@getrefino/onboarding": "0.2.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/node": "22.20.2",