rigline 1.0.0-alpha.13 → 1.0.0-alpha.15
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 +12 -5
- package/dist/commands.js +2 -1
- package/dist/engine.js +29 -9
- package/dist/floor.js +21 -0
- package/dist/index.js +10 -27
- package/dist/lock.js +3 -2
- package/dist/main.js +40 -0
- package/dist/registry.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,6 +36,12 @@ directory until *Developer: Reload Window*.
|
|
|
36
36
|
|
|
37
37
|
**That is the whole of Rigline, and it needs nothing else.** Everything below is optional.
|
|
38
38
|
|
|
39
|
+
**Where it works:** VS Code on Windows, Linux and macOS, in a local window, with Node 22.12 or
|
|
40
|
+
newer. **Not supported yet:** remote windows, other editors built on VS Code, a portable VS Code, and
|
|
41
|
+
a custom extensions directory. In any of them, Claude Code's panel stays as it ships.
|
|
42
|
+
[Where Rigline works](https://github.com/Rigline/Rigline/blob/main/docs/support.md) lists each, and
|
|
43
|
+
how to ask for one.
|
|
44
|
+
|
|
39
45
|
## Optional: let an extension do the remembering
|
|
40
46
|
|
|
41
47
|
rigline vscode-setup
|
|
@@ -60,11 +66,13 @@ your injection alone, and `rigline restore` is what undoes the injection itself.
|
|
|
60
66
|
|
|
61
67
|
rigline install inject every version, bake plugins, report drift, record the baseline
|
|
62
68
|
rigline check the same report, writing nothing
|
|
69
|
+
rigline watch install, and again whenever an extension update lands, until stopped
|
|
63
70
|
rigline status per version: vanilla or patched, by backup
|
|
64
71
|
rigline restore every version back to the extension's own bytes
|
|
72
|
+
rigline vscode-setup install the companion into VS Code; --remove takes it out
|
|
65
73
|
|
|
66
74
|
rigline add SPEC install a plugin from a directory or npm, and re-inject
|
|
67
|
-
rigline remove N delete a plugin rigline
|
|
75
|
+
rigline remove N delete a plugin from ~/.rigline/plugins, and re-inject
|
|
68
76
|
rigline disable N switch a plugin off, and re-inject
|
|
69
77
|
rigline enable N switch it back on, and re-inject
|
|
70
78
|
rigline update move the engine and every npm plugin to what its tag resolves to
|
|
@@ -81,9 +89,8 @@ your injection alone, and `rigline restore` is what undoes the injection itself.
|
|
|
81
89
|
rigline --help the whole surface, from the engine
|
|
82
90
|
|
|
83
91
|
`add` never runs a package manager for a plugin: a published plugin is one bundled ES module and a
|
|
84
|
-
manifest, so there is nothing to resolve. A version must
|
|
85
|
-
|
|
86
|
-
silence. `update` applies the same rule to the engine, and says which version it moved from so
|
|
92
|
+
manifest, so there is nothing to resolve. A version must be a day old before `add` or `update` will
|
|
93
|
+
take it, unless you pass `--now`, and a withheld version is named rather than skipped in silence. `update` applies the same rule to the engine, and says which version it moved from so
|
|
87
94
|
going back is one command.
|
|
88
95
|
|
|
89
96
|
## How it is put together
|
|
@@ -100,7 +107,7 @@ project that can declare dependencies does not need a delivery mechanism.
|
|
|
100
107
|
|
|
101
108
|
## Writing a plugin
|
|
102
109
|
|
|
103
|
-
npm create rigline-plugin
|
|
110
|
+
npm create rigline-plugin my-plugin
|
|
104
111
|
|
|
105
112
|
[The authoring guide](https://github.com/Rigline/Rigline/blob/main/docs/authoring.md) is the long
|
|
106
113
|
form. [Anchors](https://github.com/Rigline/Rigline/blob/main/docs/anchors.md) is what to read when
|
package/dist/commands.js
CHANGED
|
@@ -37,7 +37,8 @@ export async function updateCommand(args, options = {}) {
|
|
|
37
37
|
throw new UserError(problem);
|
|
38
38
|
notice(engine.version, wrapper);
|
|
39
39
|
const code = await engine.run(["update", ...forward]);
|
|
40
|
-
|
|
40
|
+
const needsYou = moved.outcome === "failed" || (moved.outcome === "withheld" && moved.by === "node");
|
|
41
|
+
return needsYou ? 1 : code;
|
|
41
42
|
}
|
|
42
43
|
export function notice(engine, wrapper = wrapperVersion()) {
|
|
43
44
|
const line = newerWrapper(wrapper, engine);
|
package/dist/engine.js
CHANGED
|
@@ -4,8 +4,10 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { UserError } from "./errors.js";
|
|
7
|
+
import { belowFloor } from "./floor.js";
|
|
7
8
|
import { withHomeLock } from "./lock.js";
|
|
8
9
|
import { releaseAgeProblem, resolveVersion } from "./registry.js";
|
|
10
|
+
export { belowFloor } from "./floor.js";
|
|
9
11
|
export const ENGINE_PACKAGE = "@rigline/core";
|
|
10
12
|
export const ENGINE_BIN = "rigline-engine";
|
|
11
13
|
export function riglineHome(env = process.env) {
|
|
@@ -59,7 +61,7 @@ export function majorProblem(wrapper, engine) {
|
|
|
59
61
|
if (ours === null || theirs === null || ours === theirs)
|
|
60
62
|
return null;
|
|
61
63
|
return (`rigline ${ours}.x cannot run engine ${theirs}.x (${ENGINE_PACKAGE} ${engine}). ` +
|
|
62
|
-
"Run npm i -g rigline@latest.");
|
|
64
|
+
"Run npm i -g rigline@latest, then rigline vscode-setup if you use the companion.");
|
|
63
65
|
}
|
|
64
66
|
export function compareVersions(a, b) {
|
|
65
67
|
const x = parseVersion(a);
|
|
@@ -118,14 +120,12 @@ export function handOffProblem(wrapper, engine) {
|
|
|
118
120
|
}
|
|
119
121
|
export function findNpmCli(execPath = process.execPath, exists = existsSync) {
|
|
120
122
|
const here = dirname(execPath);
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
join(here, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
|
|
124
|
-
];
|
|
123
|
+
const npmIn = (...dir) => join(here, ...dir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
124
|
+
const candidates = [npmIn(), npmIn("..", "lib"), npmIn("..", "libexec", "lib")];
|
|
125
125
|
const found = candidates.find(exists);
|
|
126
126
|
if (found === undefined) {
|
|
127
127
|
throw new UserError(`no npm was found beside ${execPath}, so the engine cannot be installed. ` +
|
|
128
|
-
`Run: npm install --prefix ${engineDir()} --save-exact --ignore-scripts ${ENGINE_PACKAGE}@latest`);
|
|
128
|
+
`Run: npm install --prefix "${engineDir()}" --save-exact --ignore-scripts ${ENGINE_PACKAGE}@latest`);
|
|
129
129
|
}
|
|
130
130
|
return found;
|
|
131
131
|
}
|
|
@@ -246,9 +246,19 @@ export async function updateEngine(options = {}) {
|
|
|
246
246
|
};
|
|
247
247
|
}
|
|
248
248
|
if (installed !== null) {
|
|
249
|
-
const
|
|
250
|
-
if (
|
|
251
|
-
return {
|
|
249
|
+
const node = nodeFloorProblem(resolved, options);
|
|
250
|
+
if (node !== null) {
|
|
251
|
+
return {
|
|
252
|
+
outcome: "withheld",
|
|
253
|
+
from: installed,
|
|
254
|
+
to: resolved.version,
|
|
255
|
+
reason: node,
|
|
256
|
+
by: "node",
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const age = releaseAgeProblem(resolved, options.registry);
|
|
260
|
+
if (age !== null) {
|
|
261
|
+
return { outcome: "withheld", from: installed, to: resolved.version, reason: age, by: "age" };
|
|
252
262
|
}
|
|
253
263
|
}
|
|
254
264
|
try {
|
|
@@ -266,6 +276,16 @@ export async function updateEngine(options = {}) {
|
|
|
266
276
|
? { outcome: "installed", to: resolved.version }
|
|
267
277
|
: { outcome: "moved", from: installed, to: resolved.version };
|
|
268
278
|
}
|
|
279
|
+
function nodeFloorProblem(resolved, options) {
|
|
280
|
+
const running = options.nodeVersion ?? (options.nodePath === undefined ? process.versions.node : null);
|
|
281
|
+
if (running === null || resolved.enginesNode === null)
|
|
282
|
+
return null;
|
|
283
|
+
const floor = belowFloor(running, resolved.enginesNode);
|
|
284
|
+
if (floor === null)
|
|
285
|
+
return null;
|
|
286
|
+
return (`${ENGINE_PACKAGE} ${resolved.version} needs Node ${floor} or newer, and ` +
|
|
287
|
+
`${options.nodePath ?? process.execPath} is Node ${running}. Install a newer Node to move to it.`);
|
|
288
|
+
}
|
|
269
289
|
export function formatEngineUpdate(update, home = riglineHome()) {
|
|
270
290
|
switch (update.outcome) {
|
|
271
291
|
case "installed":
|
package/dist/floor.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
export function belowFloor(running, range) {
|
|
3
|
+
const floor = /^>=\s*(\d+)\.(\d+)\.(\d+)$/.exec((range ?? "").trim());
|
|
4
|
+
if (floor === null)
|
|
5
|
+
return null;
|
|
6
|
+
const have = running.split(".").map(Number);
|
|
7
|
+
for (let at = 0; at < 3; at++) {
|
|
8
|
+
const want = Number(floor[at + 1]);
|
|
9
|
+
const got = have[at] ?? 0;
|
|
10
|
+
if (got > want)
|
|
11
|
+
return null;
|
|
12
|
+
if (got < want)
|
|
13
|
+
return floor.slice(1).join(".");
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
export function enginesNode() {
|
|
18
|
+
const manifest = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
19
|
+
return manifest?.engines?.node;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=floor.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return await updateCommand(rest);
|
|
13
|
-
default: {
|
|
14
|
-
const engine = await ensureEngine();
|
|
15
|
-
notice(engine.version);
|
|
16
|
-
return await engine.run(argv);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
2
|
+
import { belowFloor, enginesNode } from "./floor.js";
|
|
3
|
+
const floor = belowFloor(process.versions.node, enginesNode());
|
|
4
|
+
if (floor === null) {
|
|
5
|
+
const { runWrapper } = await import("./main.js");
|
|
6
|
+
process.exitCode = await runWrapper(process.argv.slice(2));
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
console.error(`rigline: Rigline needs Node ${floor} or newer, and ${process.execPath} is Node ` +
|
|
10
|
+
`${process.versions.node}; https://nodejs.org has one.`);
|
|
11
|
+
process.exitCode = 1;
|
|
19
12
|
}
|
|
20
|
-
main(process.argv.slice(2)).then((code) => {
|
|
21
|
-
process.exitCode = code;
|
|
22
|
-
}, (error) => {
|
|
23
|
-
if (error instanceof UserError) {
|
|
24
|
-
console.error(`rigline: ${error.message}`);
|
|
25
|
-
process.exitCode = 1;
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
throw error;
|
|
29
|
-
});
|
|
30
13
|
//# sourceMappingURL=index.js.map
|
package/dist/lock.js
CHANGED
|
@@ -2,6 +2,7 @@ import { closeSync, mkdirSync, openSync, readFileSync, rmSync, statSync, writeFi
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { UserError } from "./errors.js";
|
|
4
4
|
const STALE_MS = 60_000;
|
|
5
|
+
const HELD_MAX_MS = 10 * 60_000;
|
|
5
6
|
const WAIT_MS = 30_000;
|
|
6
7
|
const POLL_MS = 250;
|
|
7
8
|
export function lockPath(home) {
|
|
@@ -41,8 +42,8 @@ function writtenAt(path) {
|
|
|
41
42
|
}
|
|
42
43
|
export function isStale(holder, fileTime, now, staleMs, isAlive) {
|
|
43
44
|
const since = holder === null ? fileTime : Date.parse(holder.since);
|
|
44
|
-
const
|
|
45
|
-
return
|
|
45
|
+
const age = Number.isNaN(since) ? Number.POSITIVE_INFINITY : now - since;
|
|
46
|
+
return age >= HELD_MAX_MS || (age >= staleMs && (holder === null || !isAlive(holder.pid)));
|
|
46
47
|
}
|
|
47
48
|
export class HomeLockedError extends UserError {
|
|
48
49
|
holder;
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
import { notice, updateCommand, versionCommand } from "./commands.js";
|
|
3
|
+
import { ensureEngine } from "./engine.js";
|
|
4
|
+
import { UserError } from "./errors.js";
|
|
5
|
+
export async function runWrapper(argv) {
|
|
6
|
+
try {
|
|
7
|
+
return await dispatch(argv);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
if (!(error instanceof UserError))
|
|
11
|
+
throw error;
|
|
12
|
+
console.error(`rigline: ${error.message}`);
|
|
13
|
+
return 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async function dispatch(argv) {
|
|
17
|
+
const [command, ...rest] = argv;
|
|
18
|
+
switch (command) {
|
|
19
|
+
case "--version":
|
|
20
|
+
case "-v":
|
|
21
|
+
noArguments(rest);
|
|
22
|
+
return versionCommand();
|
|
23
|
+
case "update":
|
|
24
|
+
return await updateCommand(rest);
|
|
25
|
+
default: {
|
|
26
|
+
const engine = await ensureEngine();
|
|
27
|
+
notice(engine.version);
|
|
28
|
+
return await engine.run(argv);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function noArguments(args) {
|
|
33
|
+
try {
|
|
34
|
+
parseArgs({ args: [...args], options: {}, strict: true, allowPositionals: false });
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
throw new UserError(`${error.message}\n\`rigline --help\` lists what each command takes.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=main.js.map
|
package/dist/registry.js
CHANGED
|
@@ -17,6 +17,7 @@ export async function resolveVersion(spec, options = {}) {
|
|
|
17
17
|
if (typeof tarball !== "string" || tarball.length === 0) {
|
|
18
18
|
throw new UserError(`${spec.name}@${version} has no tarball on ${registryOf(options)}`);
|
|
19
19
|
}
|
|
20
|
+
const node = release.engines?.node;
|
|
20
21
|
return {
|
|
21
22
|
name: spec.name,
|
|
22
23
|
version,
|
|
@@ -24,6 +25,7 @@ export async function resolveVersion(spec, options = {}) {
|
|
|
24
25
|
tarball,
|
|
25
26
|
integrity: integrityOf(release, `${spec.name}@${version}`),
|
|
26
27
|
ageMinutes,
|
|
28
|
+
enginesNode: typeof node === "string" ? node : null,
|
|
27
29
|
};
|
|
28
30
|
}
|
|
29
31
|
export function releaseAgeProblem(resolved, options = {}) {
|
|
@@ -35,7 +37,7 @@ export function releaseAgeProblem(resolved, options = {}) {
|
|
|
35
37
|
return (`${resolved.name}@${resolved.version} was published ${describeAge(resolved.ageMinutes)} ago, ` +
|
|
36
38
|
`and rigline waits ${describeAge(minimum)} before installing a version. That window is where ` +
|
|
37
39
|
"a compromised publish is usually caught, and it costs little here because the urgent repair " +
|
|
38
|
-
"— an anchor an extension update retired — is a local edit rather than a release
|
|
40
|
+
"— an anchor an extension update retired — is a local edit rather than a release. " +
|
|
39
41
|
"Wait, or pass --now.");
|
|
40
42
|
}
|
|
41
43
|
export function describeAge(minutes) {
|