@rness/cli 0.5.0 → 0.5.2
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 +62 -6
- package/dist/bin/rness.js +26 -4
- package/dist/bin/rness.js.map +1 -1
- package/dist/{chunk-WSGPDTPQ.js → chunk-P4YG6P7I.js} +268 -85
- package/dist/chunk-P4YG6P7I.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/scaffold/.github/dependabot.yml +12 -0
- package/scaffold/.github/workflows/validate.yml +4 -1
- package/dist/chunk-WSGPDTPQ.js.map +0 -1
package/README.md
CHANGED
|
@@ -103,9 +103,20 @@ dependency does this: `util.styleText`, and a banner kept as a constant.
|
|
|
103
103
|
The version is written in one place, `.rness/package.json`. `upgrade` pins it
|
|
104
104
|
there (exact, the rest of the file untouched), installs with the workspace's
|
|
105
105
|
package manager, then syncs through the new copy; a failed install restores
|
|
106
|
-
the file. Commit `.rness
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
the file. Commit `.rness`. Teammates pull, and the next `rness` command in that
|
|
107
|
+
workspace installs the new pin itself — frozen, so the working tree stays
|
|
108
|
+
clean — and carries on: nothing to remember, nothing to run.
|
|
109
|
+
`RNESS_NO_INSTALL=1` turns that off and restores the warning, for CI, a
|
|
110
|
+
container image, or a machine that cannot install. A workspace still on 0.5.0
|
|
111
|
+
has no such catch-up: moving it to 0.5.1 is the last manual install.
|
|
112
|
+
|
|
113
|
+
Usually nobody runs `upgrade` at all. A workspace ships
|
|
114
|
+
`.github/dependabot.yml`, so each release opens a pull request on the
|
|
115
|
+
organization's `.rness`: the pin and the lockfile in the diff, `validate`
|
|
116
|
+
running on the new version, review, merge. `upgrade` writes that file into
|
|
117
|
+
workspaces created before 0.5.1.
|
|
118
|
+
|
|
119
|
+
`upgrade` is never delegated to the pinned copy, which is what it replaces
|
|
109
120
|
— so a workspace pinned below 0.5.0, whose copy has no such command, starts
|
|
110
121
|
with the `npx` form.
|
|
111
122
|
|
|
@@ -116,6 +127,34 @@ its content does.
|
|
|
116
127
|
Exit codes: 0 success, 1 failure, 2 usage — or a refusal without a TTY.
|
|
117
128
|
`RNESS_DEBUG=1` adds stack traces; `RNESS_NO_DELEGATE=1` skips the delegation.
|
|
118
129
|
|
|
130
|
+
## 0.5.2 — the block points at a file that exists
|
|
131
|
+
|
|
132
|
+
- The generated block told agents to read `.rness/STATUS.md`, a file neither
|
|
133
|
+
the scaffold nor any command writes. It now sends them to
|
|
134
|
+
`.rness/AGENTS.md`, which every workspace has and which sets the reading
|
|
135
|
+
order.
|
|
136
|
+
- The intro is part of the hashed body: every block written by 0.5.1 or
|
|
137
|
+
earlier is out of date under 0.5.2. Run `rness sync` once after upgrading,
|
|
138
|
+
then commit the refreshed `AGENTS.md` in each repository; until then
|
|
139
|
+
`rness sync --check` exits 1.
|
|
140
|
+
|
|
141
|
+
## 0.5.1 — the version of a workspace moves by pull request
|
|
142
|
+
|
|
143
|
+
- Joining an organization pinned to an older `@rness/cli` no longer mentions
|
|
144
|
+
versions, and no longer invites a newcomer to move the whole team: the
|
|
145
|
+
workspace is served by the version the organization agreed on.
|
|
146
|
+
- A workspace whose pin moved is reinstalled on the next command, with the
|
|
147
|
+
package manager's frozen install so the working tree stays clean. Set
|
|
148
|
+
`RNESS_NO_INSTALL=1` to keep the old warning instead — for CI, a container
|
|
149
|
+
image, or a machine that cannot install.
|
|
150
|
+
- New workspaces ship `.github/dependabot.yml`, and `rness upgrade` writes it
|
|
151
|
+
into workspaces created earlier: a pull request per release, reviewed, with
|
|
152
|
+
`validate` running on the new version before the merge.
|
|
153
|
+
- A delegated child can no longer wait on an invisible SSH passphrase prompt:
|
|
154
|
+
it fails with a readable line instead of hanging.
|
|
155
|
+
- A join that wrote its blocks succeeds even when a repository nobody picked
|
|
156
|
+
failed to clone; those failures are hints.
|
|
157
|
+
|
|
119
158
|
## 0.5.0 — the organization is the workspace; rness.json is its catalogue
|
|
120
159
|
|
|
121
160
|
- `create <org>` names the organization, not a directory any more (`--org
|
|
@@ -209,9 +248,26 @@ Exit codes: 0 success, 1 failure, 2 usage — or a refusal without a TTY.
|
|
|
209
248
|
pnpm --filter @rness/cli test # node:test on the TypeScript sources
|
|
210
249
|
pnpm --filter @rness/cli typecheck
|
|
211
250
|
pnpm --filter @rness/cli build # tsup → dist/
|
|
212
|
-
|
|
251
|
+
pnpm dev --help # the CLI, straight from these sources
|
|
252
|
+
|
|
253
|
+
`pnpm dev` runs `packages/cli/src/bin/rness.ts`: Node ≥ 24 strips the types,
|
|
254
|
+
so nothing is built between an edit and the next run. It turns delegation off,
|
|
255
|
+
because inside a workspace the launcher would otherwise hand the command to the
|
|
256
|
+
published `@rness/cli` pinned in `.rness/` rather than to the sources under
|
|
257
|
+
test; `RNESS_NO_DELEGATE=0 pnpm dev …` puts it back, to exercise delegation
|
|
258
|
+
itself.
|
|
259
|
+
|
|
260
|
+
To reach it from a workspace elsewhere on the machine, link it once:
|
|
261
|
+
|
|
262
|
+
ln -s "$PWD/scripts/dev.mjs" ~/.local/bin/rness-dev # from the repository root
|
|
263
|
+
cd ~/somewhere/acme && rness-dev validate
|
|
264
|
+
|
|
265
|
+
`create` is never delegated, so it always runs these sources — and it refuses
|
|
266
|
+
to run inside a workspace, so call it from an empty directory.
|
|
213
267
|
|
|
214
|
-
|
|
215
|
-
|
|
268
|
+
`pnpm verdaccio` is the other loop: a local registry that serves this build as
|
|
269
|
+
a real package, for what only shows up through an install (`npm create rness`,
|
|
270
|
+
the pinned copy, a version bump). It is slower, and its caches have to be
|
|
271
|
+
forgotten on every redeploy, which `deploy` now does.
|
|
216
272
|
|
|
217
273
|
Node ≥ 24. MIT.
|
package/dist/bin/rness.js
CHANGED
|
@@ -2,12 +2,17 @@
|
|
|
2
2
|
import {
|
|
3
3
|
VERSION,
|
|
4
4
|
driftWarning,
|
|
5
|
+
ensureInstalled,
|
|
5
6
|
findDelegate,
|
|
7
|
+
findWorkspace,
|
|
8
|
+
pinDrift,
|
|
9
|
+
pinnedBinPath,
|
|
6
10
|
reportError,
|
|
7
11
|
run
|
|
8
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-P4YG6P7I.js";
|
|
9
13
|
|
|
10
14
|
// src/bin/rness.ts
|
|
15
|
+
import { spawnSync } from "child_process";
|
|
11
16
|
import { pathToFileURL } from "url";
|
|
12
17
|
|
|
13
18
|
// src/core/node-version.ts
|
|
@@ -45,10 +50,27 @@ async function main() {
|
|
|
45
50
|
const noDelegate = process.env["RNESS_NO_DELEGATE"] === "1";
|
|
46
51
|
const skipDelegation = own || noDelegate;
|
|
47
52
|
const command = argv[0];
|
|
48
|
-
if (command !== void 0 && !command.startsWith("-") && !
|
|
49
|
-
const
|
|
50
|
-
|
|
53
|
+
if (command !== void 0 && !command.startsWith("-") && !skipDelegation) {
|
|
54
|
+
const ws = await findWorkspace(process.cwd()).catch(() => null);
|
|
55
|
+
const outcome = ws === null ? null : await ensureInstalled(ws.rnessDir, {
|
|
56
|
+
announce: (pin) => process.stderr.write(`installing @rness/cli ${pin} in .rness\u2026
|
|
57
|
+
`)
|
|
58
|
+
});
|
|
59
|
+
if (outcome !== null && !outcome.installed) {
|
|
60
|
+
const warning = await driftWarning(process.cwd());
|
|
61
|
+
if (warning !== null) process.stderr.write(`${warning}
|
|
51
62
|
`);
|
|
63
|
+
}
|
|
64
|
+
if (ws !== null && outcome?.installed === true && await pinDrift(ws.rnessDir) === null) {
|
|
65
|
+
const pinnedBin = await pinnedBinPath(ws.rnessDir);
|
|
66
|
+
if (pinnedBin !== null) {
|
|
67
|
+
const { status } = spawnSync(process.execPath, [pinnedBin, ...argv], {
|
|
68
|
+
cwd: process.cwd(),
|
|
69
|
+
stdio: "inherit"
|
|
70
|
+
});
|
|
71
|
+
return status ?? 1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
52
74
|
}
|
|
53
75
|
const delegate = skipDelegation ? null : await findDelegate(process.cwd(), VERSION);
|
|
54
76
|
if (delegate !== null) {
|
package/dist/bin/rness.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bin/rness.ts","../../src/core/node-version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { pathToFileURL } from 'node:url'\n\nimport { run } from '../cli.ts'\nimport { findDelegate } from '../core/delegate.ts'\nimport { MIN_NODE_MAJOR, isSupportedNode } from '../core/node-version.ts'\nimport { driftWarning } from '../core/pinned.ts'\nimport { reportError } from '../report.ts'\nimport { VERSION } from '../version.ts'\n\n// `rness context | head`: once the reader has its lines it closes the pipe and\n// every further write emits EPIPE on stdout. Nothing is left to deliver, so end\n// quietly with success. This is the one process.exit() in the code base — it\n// runs only when there is no output left to drain (see main() below).\nprocess.stdout.on('error', (e: NodeJS.ErrnoException) => {\n if (e.code === 'EPIPE') process.exit(0)\n throw e\n})\n\n// Set process.exitCode rather than calling process.exit(): process.exit()\n// terminates before Node drains an async stdout pipe, truncating piped output\n// at the ~64 KiB pipe buffer (breaks `rness context --json | jq`, `$(...)`).\nasync function main(): Promise<number> {\n if (!isSupportedNode(process.versions.node)) {\n process.stderr.write(\n `rness needs Node ${MIN_NODE_MAJOR} or newer (running ${process.version})\\n`\n )\n return 1\n }\n const argv = process.argv.slice(2)\n // `create` makes a workspace and `upgrade` replaces the pinned copy: both\n // are served by the copy the user invoked (spec 0006 §3). The login concerns\n // the machine, not a workspace — and git runs `git-credential` from inside\n // a clone, on every fetch: no delegation, and no warning there either.\n const own = [\n 'create',\n 'upgrade',\n 'update',\n 'login',\n 'logout',\n 'git-credential',\n ].includes(argv[0] ?? '')\n const noDelegate = process.env['RNESS_NO_DELEGATE'] === '1'\n const skipDelegation = own || noDelegate\n const command = argv[0]\n if (
|
|
1
|
+
{"version":3,"sources":["../../src/bin/rness.ts","../../src/core/node-version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { spawnSync } from 'node:child_process'\nimport { pathToFileURL } from 'node:url'\n\nimport { run } from '../cli.ts'\nimport { findDelegate, pinnedBinPath } from '../core/delegate.ts'\nimport { MIN_NODE_MAJOR, isSupportedNode } from '../core/node-version.ts'\nimport { driftWarning, ensureInstalled, pinDrift } from '../core/pinned.ts'\nimport { findWorkspace } from '../core/workspace.ts'\nimport { reportError } from '../report.ts'\nimport { VERSION } from '../version.ts'\n\n// `rness context | head`: once the reader has its lines it closes the pipe and\n// every further write emits EPIPE on stdout. Nothing is left to deliver, so end\n// quietly with success. This is the one process.exit() in the code base — it\n// runs only when there is no output left to drain (see main() below).\nprocess.stdout.on('error', (e: NodeJS.ErrnoException) => {\n if (e.code === 'EPIPE') process.exit(0)\n throw e\n})\n\n// Set process.exitCode rather than calling process.exit(): process.exit()\n// terminates before Node drains an async stdout pipe, truncating piped output\n// at the ~64 KiB pipe buffer (breaks `rness context --json | jq`, `$(...)`).\nasync function main(): Promise<number> {\n if (!isSupportedNode(process.versions.node)) {\n process.stderr.write(\n `rness needs Node ${MIN_NODE_MAJOR} or newer (running ${process.version})\\n`\n )\n return 1\n }\n const argv = process.argv.slice(2)\n // `create` makes a workspace and `upgrade` replaces the pinned copy: both\n // are served by the copy the user invoked (spec 0006 §3). The login concerns\n // the machine, not a workspace — and git runs `git-credential` from inside\n // a clone, on every fetch: no delegation, and no warning there either.\n const own = [\n 'create',\n 'upgrade',\n 'update',\n 'login',\n 'logout',\n 'git-credential',\n ].includes(argv[0] ?? '')\n const noDelegate = process.env['RNESS_NO_DELEGATE'] === '1'\n const skipDelegation = own || noDelegate\n const command = argv[0]\n if (command !== undefined && !command.startsWith('-') && !skipDelegation) {\n const ws = await findWorkspace(process.cwd()).catch(() => null)\n // The version was decided by the pull request that moved the pin, so\n // catching up asks nothing (spec 0008 §4).\n const outcome =\n ws === null\n ? null\n : await ensureInstalled(ws.rnessDir, {\n announce: (pin) =>\n process.stderr.write(`installing @rness/cli ${pin} in .rness…\\n`),\n })\n if (outcome !== null && !outcome.installed) {\n const warning = await driftWarning(process.cwd())\n if (warning !== null) process.stderr.write(`${warning}\\n`)\n }\n // The pinned tree was just rebuilt: importing out of it in this process is\n // fragile, so the freshly installed copy runs as its own process.\n // Only hand off when the install actually closed the drift: a child that\n // would install again on every run must never be spawned.\n if (\n ws !== null &&\n outcome?.installed === true &&\n (await pinDrift(ws.rnessDir)) === null\n ) {\n const pinnedBin = await pinnedBinPath(ws.rnessDir)\n if (pinnedBin !== null) {\n const { status } = spawnSync(process.execPath, [pinnedBin, ...argv], {\n cwd: process.cwd(),\n stdio: 'inherit',\n })\n return status ?? 1\n }\n }\n }\n const delegate = skipDelegation\n ? null\n : await findDelegate(process.cwd(), VERSION)\n if (delegate !== null) {\n const broken = (reason: string): Error =>\n new Error(\n `@rness/cli ${delegate.version} pinned in ${delegate.root}/.rness is not installed correctly (${reason}); reinstall in .rness/`\n )\n if (process.env['RNESS_DEBUG'] === '1') {\n process.stderr.write(\n `rness: delegating to @rness/cli ${delegate.version} (${delegate.entry})\\n`\n )\n }\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(delegate.entry).href)) as Record<\n string,\n unknown\n >\n } catch (e) {\n throw broken(e instanceof Error ? e.message : String(e))\n }\n if (typeof mod['run'] !== 'function')\n throw broken('dist/index.js does not export run')\n const delegateRun = mod['run'] as (argv: string[]) => Promise<unknown>\n const code = await delegateRun(argv)\n return typeof code === 'number' ? code : 1\n }\n return run(argv)\n}\n\nmain()\n .then((code) => {\n process.exitCode = code\n })\n .catch((e: unknown) => {\n process.exitCode = reportError(e)\n })\n","export const MIN_NODE_MAJOR = 24\n\nexport function nodeMajor(version: string): number {\n const major = Number.parseInt(version.split('.')[0] ?? '', 10)\n return Number.isNaN(major) ? 0 : major\n}\n\nexport function isSupportedNode(version: string): boolean {\n return nodeMajor(version) >= MIN_NODE_MAJOR\n}\n"],"mappings":";;;;;;;;;;;;;;AACA,SAAS,iBAAiB;AAC1B,SAAS,qBAAqB;;;ACFvB,IAAM,iBAAiB;AAEvB,SAAS,UAAU,SAAyB;AACjD,QAAM,QAAQ,OAAO,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,EAAE;AAC7D,SAAO,OAAO,MAAM,KAAK,IAAI,IAAI;AACnC;AAEO,SAAS,gBAAgB,SAA0B;AACxD,SAAO,UAAU,OAAO,KAAK;AAC/B;;;ADOA,QAAQ,OAAO,GAAG,SAAS,CAAC,MAA6B;AACvD,MAAI,EAAE,SAAS,QAAS,SAAQ,KAAK,CAAC;AACtC,QAAM;AACR,CAAC;AAKD,eAAe,OAAwB;AACrC,MAAI,CAAC,gBAAgB,QAAQ,SAAS,IAAI,GAAG;AAC3C,YAAQ,OAAO;AAAA,MACb,oBAAoB,cAAc,sBAAsB,QAAQ,OAAO;AAAA;AAAA,IACzE;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AAKjC,QAAM,MAAM;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,SAAS,KAAK,CAAC,KAAK,EAAE;AACxB,QAAM,aAAa,QAAQ,IAAI,mBAAmB,MAAM;AACxD,QAAM,iBAAiB,OAAO;AAC9B,QAAM,UAAU,KAAK,CAAC;AACtB,MAAI,YAAY,UAAa,CAAC,QAAQ,WAAW,GAAG,KAAK,CAAC,gBAAgB;AACxE,UAAM,KAAK,MAAM,cAAc,QAAQ,IAAI,CAAC,EAAE,MAAM,MAAM,IAAI;AAG9D,UAAM,UACJ,OAAO,OACH,OACA,MAAM,gBAAgB,GAAG,UAAU;AAAA,MACjC,UAAU,CAAC,QACT,QAAQ,OAAO,MAAM,yBAAyB,GAAG;AAAA,CAAe;AAAA,IACpE,CAAC;AACP,QAAI,YAAY,QAAQ,CAAC,QAAQ,WAAW;AAC1C,YAAM,UAAU,MAAM,aAAa,QAAQ,IAAI,CAAC;AAChD,UAAI,YAAY,KAAM,SAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAAA,IAC3D;AAKA,QACE,OAAO,QACP,SAAS,cAAc,QACtB,MAAM,SAAS,GAAG,QAAQ,MAAO,MAClC;AACA,YAAM,YAAY,MAAM,cAAc,GAAG,QAAQ;AACjD,UAAI,cAAc,MAAM;AACtB,cAAM,EAAE,OAAO,IAAI,UAAU,QAAQ,UAAU,CAAC,WAAW,GAAG,IAAI,GAAG;AAAA,UACnE,KAAK,QAAQ,IAAI;AAAA,UACjB,OAAO;AAAA,QACT,CAAC;AACD,eAAO,UAAU;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,iBACb,OACA,MAAM,aAAa,QAAQ,IAAI,GAAG,OAAO;AAC7C,MAAI,aAAa,MAAM;AACrB,UAAM,SAAS,CAAC,WACd,IAAI;AAAA,MACF,cAAc,SAAS,OAAO,cAAc,SAAS,IAAI,uCAAuC,MAAM;AAAA,IACxG;AACF,QAAI,QAAQ,IAAI,aAAa,MAAM,KAAK;AACtC,cAAQ,OAAO;AAAA,QACb,mCAAmC,SAAS,OAAO,KAAK,SAAS,KAAK;AAAA;AAAA,MACxE;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,YAAO,MAAM,OAAO,cAAc,SAAS,KAAK,EAAE;AAAA,IAIpD,SAAS,GAAG;AACV,YAAM,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IACzD;AACA,QAAI,OAAO,IAAI,KAAK,MAAM;AACxB,YAAM,OAAO,mCAAmC;AAClD,UAAM,cAAc,IAAI,KAAK;AAC7B,UAAM,OAAO,MAAM,YAAY,IAAI;AACnC,WAAO,OAAO,SAAS,WAAW,OAAO;AAAA,EAC3C;AACA,SAAO,IAAI,IAAI;AACjB;AAEA,KAAK,EACF,KAAK,CAAC,SAAS;AACd,UAAQ,WAAW;AACrB,CAAC,EACA,MAAM,CAAC,MAAe;AACrB,UAAQ,WAAW,YAAY,CAAC;AAClC,CAAC;","names":[]}
|