@orkestrel/scaffold 0.0.107 → 0.0.109
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/dist/agents/skills/orkestrel-dispatch/scripts/bench.js +326 -91
- package/dist/agents/skills/orkestrel-dispatch/scripts/brief.js +110 -14
- package/dist/agents/skills/orkestrel-dispatch/scripts/chain.js +280 -0
- package/dist/agents/skills/orkestrel-dispatch/scripts/cite.js +188 -26
- package/dist/agents/skills/orkestrel-dispatch/scripts/launch.js +142 -43
- package/dist/agents/skills/orkestrel-dispatch/scripts/login.js +240 -62
- package/dist/agents/skills/orkestrel-dispatch/scripts/patch.js +323 -0
- package/dist/agents/skills/orkestrel-dispatch/scripts/result.js +169 -32
- package/dist/agents/skills/orkestrel-dispatch/scripts/sweep.js +368 -27
- package/dist/agents/skills/orkestrel-falsify/scripts/mutate.js +560 -0
- package/dist/agents/skills/orkestrel-harden/scripts/discovery.js +1052 -205
- package/dist/agents/skills/orkestrel-harden/scripts/measure.js +361 -0
- package/dist/agents/skills/orkestrel-harden/scripts/titles.js +455 -80
- package/dist/agents/skills/orkestrel-parallel/scripts/cases.js +327 -0
- package/dist/agents/skills/orkestrel-publish/scripts/compare.js +298 -51
- package/dist/agents/skills/orkestrel-publish/scripts/pins.js +170 -13
- package/dist/agents/skills/orkestrel-publish/scripts/swap.js +956 -191
- package/dist/agents/skills/orkestrel-publish/scripts/wave.js +707 -112
- package/dist/agents/skills/orkestrel-publish/scripts/window.js +235 -41
- package/dist/agents/skills/orkestrel-scout/scripts/map.js +341 -54
- package/dist/agents/templates/brief.md +1 -1
- package/dist/bin/main.js +51 -46
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +26 -20
- package/dist/host/agents/orchestration.md +98 -58
- package/dist/host/agents/platforms/posix.md +15 -0
- package/dist/host/agents/platforms/windows.md +37 -0
- package/dist/host/agents/skills/orkestrel-align/SKILL.md +10 -13
- package/dist/host/agents/skills/orkestrel-align/references/fleet.md +4 -10
- package/dist/host/agents/skills/orkestrel-align/references/integration.md +1 -1
- package/dist/host/agents/skills/orkestrel-build/SKILL.md +16 -48
- package/dist/host/agents/skills/orkestrel-build/agents/openai.yaml +1 -1
- package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +19 -16
- package/dist/host/agents/skills/orkestrel-debrief/agents/openai.yaml +1 -1
- package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +15 -28
- package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +5 -6
- package/dist/host/agents/skills/orkestrel-debrief/references/retention.md +12 -14
- package/dist/host/agents/skills/orkestrel-dispatch/SKILL.md +36 -24
- package/dist/host/agents/skills/orkestrel-dispatch/references/launch.md +14 -11
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/bench.ts +366 -75
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/brief.ts +126 -16
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/chain.ts +323 -0
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/cite.ts +220 -31
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/launch.ts +176 -33
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/login.ts +294 -59
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/patch.ts +401 -0
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/result.ts +199 -34
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/sweep.ts +428 -27
- package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +10 -8
- package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +1 -5
- package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +1 -1
- package/dist/host/agents/skills/orkestrel-falsify/scripts/mutate.ts +701 -0
- package/dist/host/agents/skills/orkestrel-harden/SKILL.md +16 -12
- package/dist/host/agents/skills/orkestrel-harden/references/bindings.md +23 -81
- package/dist/host/agents/skills/orkestrel-harden/references/centralization.md +4 -5
- package/dist/host/agents/skills/orkestrel-harden/references/contract.md +2 -0
- package/dist/host/agents/skills/orkestrel-harden/references/document.md +33 -0
- package/dist/host/agents/skills/orkestrel-harden/references/equivalence.md +6 -3
- package/dist/host/agents/skills/orkestrel-harden/references/hardening.md +8 -4
- package/dist/host/agents/skills/orkestrel-harden/references/research.md +2 -0
- package/dist/host/agents/skills/orkestrel-harden/scripts/discovery.ts +1272 -279
- package/dist/host/agents/skills/orkestrel-harden/scripts/measure.ts +425 -0
- package/dist/host/agents/skills/orkestrel-harden/scripts/titles.ts +603 -98
- package/dist/host/agents/skills/orkestrel-journey/SKILL.md +75 -98
- package/dist/host/agents/skills/orkestrel-journey/references/captures.md +54 -17
- package/dist/host/agents/skills/orkestrel-journey/references/decide.md +1 -20
- package/dist/host/agents/skills/orkestrel-journey/references/layer.md +21 -31
- package/dist/host/agents/skills/orkestrel-journey/references/styles.md +1 -1
- package/dist/host/agents/skills/orkestrel-parallel/SKILL.md +91 -30
- package/dist/host/agents/skills/orkestrel-parallel/agents/openai.yaml +2 -2
- package/dist/host/agents/skills/orkestrel-parallel/references/claude.md +34 -0
- package/dist/host/agents/skills/orkestrel-parallel/references/codex.md +29 -0
- package/dist/host/agents/skills/orkestrel-parallel/references/cursor.md +29 -0
- package/dist/host/agents/skills/orkestrel-parallel/references/t3.md +31 -0
- package/dist/host/agents/skills/orkestrel-parallel/scripts/cases.ts +389 -0
- package/dist/host/agents/skills/orkestrel-polish/SKILL.md +16 -20
- package/dist/host/agents/skills/orkestrel-polish/references/capture-harness.md +16 -26
- package/dist/host/agents/skills/orkestrel-publish/SKILL.md +12 -26
- package/dist/host/agents/skills/orkestrel-publish/agents/openai.yaml +2 -2
- package/dist/host/agents/skills/orkestrel-publish/references/adopt.md +23 -0
- package/dist/host/agents/skills/orkestrel-publish/references/release.md +4 -4
- package/dist/host/agents/skills/orkestrel-publish/references/wave.md +12 -10
- package/dist/host/agents/skills/orkestrel-publish/references/window.md +20 -25
- package/dist/host/agents/skills/orkestrel-publish/scripts/compare.ts +348 -59
- package/dist/host/agents/skills/orkestrel-publish/scripts/pins.ts +202 -22
- package/dist/host/agents/skills/orkestrel-publish/scripts/swap.ts +1061 -191
- package/dist/host/agents/skills/orkestrel-publish/scripts/wave.ts +812 -140
- package/dist/host/agents/skills/orkestrel-publish/scripts/window.ts +280 -38
- package/dist/host/agents/skills/orkestrel-scout/SKILL.md +3 -3
- package/dist/host/agents/skills/orkestrel-scout/scripts/map.ts +428 -70
- package/dist/host/agents/templates/brief.md +1 -1
- package/dist/host/agents/transports/claude-cli.md +3 -3
- package/dist/host/agents/transports/codex.md +3 -8
- package/dist/host/agents/transports/cursor.md +2 -3
- package/dist/host/claude/AGENTS.md +7 -10
- package/dist/host/claude/agents/analyst.md +3 -3
- package/dist/host/claude/agents/astra.md +3 -3
- package/dist/host/claude/agents/builder.md +1 -1
- package/dist/host/claude/agents/checker.md +1 -1
- package/dist/host/claude/agents/distiller.md +1 -1
- package/dist/host/claude/agents/grok.md +1 -1
- package/dist/host/claude/agents/opus.md +2 -2
- package/dist/host/claude/agents/orkestrel.md +57 -90
- package/dist/host/claude/agents/researcher.md +1 -1
- package/dist/host/claude/agents/reviewer.md +4 -0
- package/dist/host/claude/agents/scout.md +1 -1
- package/dist/host/claude/agents/verifier.md +1 -1
- package/dist/host/claude/rules/application.md +14 -21
- package/dist/host/claude/rules/architecture.md +34 -44
- package/dist/host/claude/rules/browser.md +3 -4
- package/dist/host/claude/rules/campaign.md +55 -0
- package/dist/host/claude/rules/documentation.md +26 -11
- package/dist/host/claude/rules/names.md +9 -4
- package/dist/host/claude/rules/patterns.md +6 -7
- package/dist/host/claude/rules/portability.md +2 -3
- package/dist/host/claude/rules/quality.md +4 -5
- package/dist/host/claude/rules/styles.md +2 -2
- package/dist/host/claude/rules/tests.md +57 -114
- package/dist/host/claude/rules/typescript.md +8 -10
- package/dist/host/claude/rules/workspace.md +21 -19
- package/dist/host/claude/rules/writing.md +3 -3
- package/dist/host/claude/skills/orkestrel-dispatch/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-harden/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-parallel/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-publish/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-scout/SKILL.md +1 -1
- package/dist/host/codex/agents/analyst.toml +9 -3
- package/dist/host/codex/agents/astra.toml +3 -4
- package/dist/host/codex/agents/builder.toml +1 -1
- package/dist/host/codex/agents/opus.toml +3 -4
- package/dist/host/codex/agents/orkestrel.toml +1 -1
- package/dist/host/codex/agents/researcher.toml +2 -2
- package/dist/host/codex/agents/verifier.toml +1 -1
- package/dist/host/codex/config.toml +3 -3
- package/dist/host/configs/helpers.ts +21 -1
- package/dist/host/configs/policy.ts +405 -16
- package/dist/host/cursor/rules/orchestration.mdc +1 -0
- package/dist/host/dotfiles/oxlintrc.json +141 -5
- package/dist/host/guides/agent.md +111 -134
- package/dist/host/guides/capture.md +801 -0
- package/dist/host/guides/probe.md +27 -8
- package/dist/host/guides/scaffold.md +152 -19
- package/dist/host/guides/study.md +534 -440
- package/dist/host/guides/test.md +111 -44
- package/dist/host/manifest.json +199 -242
- package/dist/host/tests/config.test.ts +1558 -219
- package/dist/host/tests/policy.test.ts +127 -1
- package/dist/host/tests/setupPolicy.ts +1389 -39
- package/dist/src/core/index.cjs +239 -87
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +123 -39
- package/dist/src/core/index.d.ts +123 -39
- package/dist/src/core/index.js +234 -86
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +20 -27
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.js +21 -28
- package/dist/src/server/index.js.map +1 -1
- package/package.json +11 -11
- package/dist/agents/skills/orkestrel-dispatch/scripts/helpers.js +0 -283
- package/dist/host/agents/skills/orkestrel-dispatch/references/bench.md +0 -25
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/helpers.ts +0 -333
- package/dist/host/agents/skills/orkestrel-parallel/references/harnesses.md +0 -19
- package/dist/host/guides/supervisor.md +0 -4890
|
@@ -1,38 +1,216 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// The package defaults to the manifest's name and the version to what the registry serves; --tarball
|
|
5
|
-
// compares against a local .tgz instead of fetching. Sourcemaps are excluded, a text file differs
|
|
6
|
-
// only when it differs with all whitespace removed, and a binary file differs on any byte. The
|
|
7
|
-
// summary lists the paths added, removed, and changed. Exit 0 when nothing material differs, 3 when
|
|
8
|
-
// something does, 2 when the tarball cannot be read, 64 on usage.
|
|
9
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
10
|
-
import { relative } from 'node:path';
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, relative } from 'node:path';
|
|
11
4
|
import { gunzipSync } from 'node:zlib';
|
|
12
|
-
|
|
13
|
-
const BLOCK = 512;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
/** Holds the byte size of one tar block. */
|
|
6
|
+
export const BLOCK = 512;
|
|
7
|
+
/** Names the directory every npm tarball entry sits under. */
|
|
8
|
+
export const PACKAGE_PREFIX = 'package/';
|
|
9
|
+
/** Names the directories every tree walk skips by default. */
|
|
10
|
+
export const SKIPPED_DIRECTORIES = new Set([
|
|
11
|
+
'node_modules',
|
|
12
|
+
'.git',
|
|
13
|
+
'dist',
|
|
14
|
+
'tmp',
|
|
15
|
+
'.orkestrel',
|
|
16
|
+
'.idea',
|
|
17
|
+
]);
|
|
18
|
+
/** Holds the empty skip set, because a dist tree holds nothing a walk skips, so every emitted file counts. */
|
|
19
|
+
export const NOTHING_SKIPPED = new Set();
|
|
20
|
+
/** Lists every flag the script reads, value flags and switches alike. */
|
|
21
|
+
export const FLAGS = ['--package', '--version', '--tarball', '--dist', '--json'];
|
|
22
|
+
/** Holds the usage line the script prints on a usage refusal. */
|
|
23
|
+
export const USAGE = 'usage: compare.ts [--package NAME] [--version V] [--tarball PATH] [--dist dist] [--json]';
|
|
24
|
+
/**
|
|
25
|
+
* Normalizes a host path to forward slashes.
|
|
26
|
+
*
|
|
27
|
+
* @param path - A host path.
|
|
28
|
+
* @returns The same path with every backslash replaced by a slash.
|
|
29
|
+
*/
|
|
30
|
+
export function normalizeSlashes(path) {
|
|
31
|
+
return path.split('\\').join('/');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reads the value that follows a flag.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* Reads `--flag value` pairs: the first occurrence of a flag wins, a following value that opens
|
|
38
|
+
* with `--` is a missing value, and the `--flag=value` form is not read.
|
|
39
|
+
*
|
|
40
|
+
* @param argv - The arguments after the script path.
|
|
41
|
+
* @param name - The flag, such as `--package`.
|
|
42
|
+
* @returns The value after the flag, or undefined when the flag is absent, last, or followed by
|
|
43
|
+
* another flag.
|
|
44
|
+
*/
|
|
45
|
+
export function readOption(argv, name) {
|
|
46
|
+
const index = argv.indexOf(name);
|
|
47
|
+
const value = index === -1 ? undefined : argv[index + 1];
|
|
48
|
+
return value === undefined || value.startsWith('--') ? undefined : value;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Names the value flags a caller gave with no value.
|
|
52
|
+
*
|
|
53
|
+
* @param argv - The arguments after the script path.
|
|
54
|
+
* @param names - The flags that take a value.
|
|
55
|
+
* @returns Each named flag that appears last or is followed by another flag, in argument order.
|
|
56
|
+
*/
|
|
57
|
+
export function readMissingFlags(argv, names) {
|
|
58
|
+
return names.filter((name) => argv.includes(name) && readOption(argv, name) === undefined);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Names the flags a caller gave that the script does not read.
|
|
62
|
+
*
|
|
63
|
+
* @remarks
|
|
64
|
+
* Reads the arguments before a bare `--`, which opens a command a script passes on. A `--flag=value`
|
|
65
|
+
* argument is unknown, because the script reads no such form.
|
|
66
|
+
*
|
|
67
|
+
* @param argv - The arguments after the script path.
|
|
68
|
+
* @param flags - Every flag the script reads, value flags and switches alike.
|
|
69
|
+
* @returns Each argument that opens with `--` and is not a read flag, in argument order.
|
|
70
|
+
*/
|
|
71
|
+
export function readUnknownFlags(argv, flags) {
|
|
72
|
+
const end = argv.indexOf('--');
|
|
73
|
+
return (end === -1 ? argv : argv.slice(0, end)).filter((argument) => argument.startsWith('--') && !flags.includes(argument));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Lists every regular file beneath a directory, skipping the directories named.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* A skipped name matches a directory at any depth, exactly and case-sensitively.
|
|
80
|
+
*
|
|
81
|
+
* @param directory - The directory to walk.
|
|
82
|
+
* @param skipped - The directory names to skip. Default: {@link SKIPPED_DIRECTORIES}.
|
|
83
|
+
* @returns Each file's forward-slash path and modification time, in walk order.
|
|
84
|
+
* @throws Thrown when `directory` does not exist or cannot be read; check `existsSync` first.
|
|
85
|
+
*/
|
|
86
|
+
export function listFiles(directory, skipped = SKIPPED_DIRECTORIES) {
|
|
87
|
+
const files = [];
|
|
88
|
+
const pending = [directory];
|
|
89
|
+
while (pending.length > 0) {
|
|
90
|
+
const current = pending.pop();
|
|
91
|
+
if (current === undefined)
|
|
92
|
+
break;
|
|
93
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
94
|
+
if (skipped.has(entry.name))
|
|
95
|
+
continue;
|
|
96
|
+
const path = join(current, entry.name);
|
|
97
|
+
if (entry.isDirectory())
|
|
98
|
+
pending.push(path);
|
|
99
|
+
else if (entry.isFile()) {
|
|
100
|
+
files.push({ path: normalizeSlashes(path), modified: statSync(path).mtimeMs });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return files;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parses a whole text as one JSON object.
|
|
108
|
+
*
|
|
109
|
+
* @param text - A JSON document, formatted or not, such as a manifest.
|
|
110
|
+
* @returns The parsed object, or undefined when the text is not a JSON object.
|
|
111
|
+
*/
|
|
112
|
+
export function parseJsonRecord(text) {
|
|
113
|
+
try {
|
|
114
|
+
const parsed = JSON.parse(text);
|
|
115
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
116
|
+
return Object.fromEntries(Object.entries(parsed));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch { }
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Reads a string member of a record.
|
|
124
|
+
*
|
|
125
|
+
* @param record - The record, or undefined.
|
|
126
|
+
* @param key - The member name.
|
|
127
|
+
* @returns The string, or undefined when the member is absent or not a string.
|
|
128
|
+
*/
|
|
129
|
+
export function readString(record, key) {
|
|
130
|
+
const value = record?.[key];
|
|
131
|
+
return typeof value === 'string' ? value : undefined;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Resolves the npm command for this host.
|
|
135
|
+
*
|
|
136
|
+
* @remarks
|
|
137
|
+
* The `npm-cli.js` entry beside the running Node binary spawns without a shell on every host; the
|
|
138
|
+
* `npm` shim on Windows is a `.cmd` file that needs one, so that path is the fallback alone.
|
|
139
|
+
*
|
|
140
|
+
* @returns The file to spawn, the arguments that precede npm's own, and whether a shell is needed.
|
|
141
|
+
*/
|
|
142
|
+
export function resolveNpm() {
|
|
143
|
+
const cli = join(dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js');
|
|
144
|
+
if (existsSync(cli))
|
|
145
|
+
return { file: process.execPath, prefix: [cli], shell: false };
|
|
146
|
+
return { file: 'npm', prefix: [], shell: process.platform === 'win32' };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Runs npm with the given arguments and returns the finished child.
|
|
150
|
+
*
|
|
151
|
+
* @param args - The npm arguments, such as `['view', '@orkestrel/scaffold', 'version']`.
|
|
152
|
+
* @param cwd - The working directory. Default: the current directory.
|
|
153
|
+
* @returns The spawn result with `utf8` stdout and stderr.
|
|
154
|
+
*/
|
|
155
|
+
export function runNpm(args, cwd) {
|
|
156
|
+
const npm = resolveNpm();
|
|
157
|
+
return spawnSync(npm.file, [...npm.prefix, ...args], {
|
|
158
|
+
encoding: 'utf8',
|
|
159
|
+
windowsHide: true,
|
|
160
|
+
shell: npm.shell,
|
|
161
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
162
|
+
...(cwd === undefined ? {} : { cwd }),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Reads the name and version a directory's package manifest declares.
|
|
167
|
+
*
|
|
168
|
+
* @param directory - The directory that holds `package.json`.
|
|
169
|
+
* @returns The name and version, each undefined when the manifest is absent, unreadable, or lacks it.
|
|
170
|
+
*/
|
|
171
|
+
export function readManifest(directory) {
|
|
172
|
+
const path = join(directory, 'package.json');
|
|
173
|
+
if (!existsSync(path))
|
|
17
174
|
return { name: undefined, version: undefined };
|
|
18
175
|
try {
|
|
19
|
-
const record = parseJsonRecord(readFileSync(
|
|
176
|
+
const record = parseJsonRecord(readFileSync(path, 'utf8'));
|
|
20
177
|
return { name: readString(record, 'name'), version: readString(record, 'version') };
|
|
21
178
|
}
|
|
22
179
|
catch {
|
|
23
180
|
return { name: undefined, version: undefined };
|
|
24
181
|
}
|
|
25
182
|
}
|
|
26
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Reads one value npm printed as JSON.
|
|
185
|
+
*
|
|
186
|
+
* @param text - npm's output with the surrounding whitespace removed.
|
|
187
|
+
* @returns The text without its enclosing quotes, or undefined when nothing remains.
|
|
188
|
+
*/
|
|
189
|
+
export function readField(text) {
|
|
27
190
|
const stripped = text.replace(/^"|"$/gu, '');
|
|
28
191
|
return stripped === '' ? undefined : stripped;
|
|
29
192
|
}
|
|
30
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Reads a NUL-terminated text field out of a tar header block.
|
|
195
|
+
*
|
|
196
|
+
* @param header - The header block.
|
|
197
|
+
* @param start - The field's first byte.
|
|
198
|
+
* @param length - The field's byte length.
|
|
199
|
+
* @returns The field's text up to its first NUL.
|
|
200
|
+
*/
|
|
201
|
+
export function readHeaderText(header, start, length) {
|
|
31
202
|
const slice = header.subarray(start, start + length);
|
|
32
203
|
const end = slice.indexOf(0);
|
|
33
204
|
return slice.subarray(0, end === -1 ? slice.length : end).toString('utf8');
|
|
34
205
|
}
|
|
35
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Reads the `path` record out of a pax extended header.
|
|
208
|
+
*
|
|
209
|
+
* @param data - The header's data blocks, each record written as `LENGTH KEY=VALUE` and a line feed.
|
|
210
|
+
* @param offset - The byte where the search starts. Default: 0.
|
|
211
|
+
* @returns The path the first `path=` record names, or undefined when no record does or one is malformed.
|
|
212
|
+
*/
|
|
213
|
+
export function readPaxPath(data, offset = 0) {
|
|
36
214
|
if (offset >= data.length)
|
|
37
215
|
return undefined;
|
|
38
216
|
const space = data.indexOf(0x20, offset);
|
|
@@ -46,9 +224,20 @@ function readPaxPath(data, offset = 0) {
|
|
|
46
224
|
? record.slice('path='.length)
|
|
47
225
|
: readPaxPath(data, offset + length);
|
|
48
226
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
227
|
+
/**
|
|
228
|
+
* Advances a tar reader by the block at one offset.
|
|
229
|
+
*
|
|
230
|
+
* @remarks
|
|
231
|
+
* A tar entry occupies a header block and the data blocks its size names, so a step ignores every
|
|
232
|
+
* block offset an earlier entry already consumed.
|
|
233
|
+
*
|
|
234
|
+
* @param archive - The uncompressed archive.
|
|
235
|
+
* @param state - The reader's state before this block.
|
|
236
|
+
* @param offset - The block's first byte.
|
|
237
|
+
* @returns The state after the block: a regular file added, a pax or GNU long name remembered for the
|
|
238
|
+
* next entry, or the reader done at the first all-zero block.
|
|
239
|
+
*/
|
|
240
|
+
export function stepTar(archive, state, offset) {
|
|
52
241
|
if (state.done || offset < state.next)
|
|
53
242
|
return state;
|
|
54
243
|
const header = archive.subarray(offset, offset + BLOCK);
|
|
@@ -73,9 +262,15 @@ function stepTar(archive, state, offset) {
|
|
|
73
262
|
done: !Number.isFinite(next),
|
|
74
263
|
};
|
|
75
264
|
}
|
|
76
|
-
|
|
265
|
+
/**
|
|
266
|
+
* Reads the regular files out of an uncompressed tar archive.
|
|
267
|
+
*
|
|
268
|
+
* @param archive - The uncompressed archive.
|
|
269
|
+
* @returns Each file's path and bytes; a later entry of the same name replaces an earlier one at the
|
|
270
|
+
* earlier position, as a map write does.
|
|
271
|
+
*/
|
|
272
|
+
export function readTar(archive) {
|
|
77
273
|
const offsets = Array.from({ length: Math.floor(archive.length / BLOCK) }, (_, index) => index * BLOCK);
|
|
78
|
-
// A later entry of the same name replaces an earlier one at the earlier position, as a map write does.
|
|
79
274
|
return new Map(offsets.reduce((state, offset) => stepTar(archive, state, offset), {
|
|
80
275
|
next: 0,
|
|
81
276
|
name: undefined,
|
|
@@ -83,7 +278,13 @@ function readTar(archive) {
|
|
|
83
278
|
done: false,
|
|
84
279
|
}).files);
|
|
85
280
|
}
|
|
86
|
-
|
|
281
|
+
/**
|
|
282
|
+
* Unpacks a gzip-compressed tar archive.
|
|
283
|
+
*
|
|
284
|
+
* @param archive - The compressed archive.
|
|
285
|
+
* @returns The regular files it holds, or the error that stopped the unpacking.
|
|
286
|
+
*/
|
|
287
|
+
export function unpackTar(archive) {
|
|
87
288
|
try {
|
|
88
289
|
return readTar(gunzipSync(archive));
|
|
89
290
|
}
|
|
@@ -91,7 +292,42 @@ function unpackTar(archive) {
|
|
|
91
292
|
return error instanceof Error ? error : new Error(String(error));
|
|
92
293
|
}
|
|
93
294
|
}
|
|
94
|
-
|
|
295
|
+
/**
|
|
296
|
+
* Reads one value from npm's view of the registry.
|
|
297
|
+
*
|
|
298
|
+
* @param args - The npm arguments, such as `['view', 'name', 'version', '--json']`.
|
|
299
|
+
* @returns The value npm printed, or undefined when npm exited nonzero or printed nothing.
|
|
300
|
+
*/
|
|
301
|
+
export function readNpmValue(args) {
|
|
302
|
+
const result = runNpm(args);
|
|
303
|
+
return result.status === 0 ? readField(result.stdout.trim()) : undefined;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Fetches a tarball over HTTP.
|
|
307
|
+
*
|
|
308
|
+
* @param url - The tarball's address.
|
|
309
|
+
* @returns The response body, or undefined when the request failed or answered a non-success status.
|
|
310
|
+
*/
|
|
311
|
+
export async function fetchTarball(url) {
|
|
312
|
+
try {
|
|
313
|
+
const response = await fetch(url);
|
|
314
|
+
if (!response.ok)
|
|
315
|
+
return undefined;
|
|
316
|
+
return Buffer.from(await response.arrayBuffer());
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Reads the tarball a run compares against.
|
|
324
|
+
*
|
|
325
|
+
* @param name - The package name to look up when no tarball file is given.
|
|
326
|
+
* @param requested - The version to compare, or undefined for the one the registry serves.
|
|
327
|
+
* @param tarball - A local `.tgz` path, or undefined to fetch from the registry.
|
|
328
|
+
* @returns The archive with its version, or the reason none could be read.
|
|
329
|
+
*/
|
|
330
|
+
export async function readSource(name, requested, tarball) {
|
|
95
331
|
if (tarball !== undefined) {
|
|
96
332
|
return existsSync(tarball)
|
|
97
333
|
? { archive: readFileSync(tarball), version: requested, failure: undefined }
|
|
@@ -113,34 +349,54 @@ async function readSource(name, requested, tarball) {
|
|
|
113
349
|
? { archive: undefined, version, failure: `fetching ${url} failed` }
|
|
114
350
|
: { archive: fetched, version, failure: undefined };
|
|
115
351
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
function isMaterial(path) {
|
|
352
|
+
/**
|
|
353
|
+
* Checks whether a published path counts in the comparison.
|
|
354
|
+
*
|
|
355
|
+
* @param path - A path inside the tarball or the dist tree.
|
|
356
|
+
* @returns True if the path is not a sourcemap; false otherwise.
|
|
357
|
+
*/
|
|
358
|
+
export function isMaterial(path) {
|
|
123
359
|
return !path.endsWith('.map');
|
|
124
360
|
}
|
|
125
|
-
|
|
361
|
+
/**
|
|
362
|
+
* Checks whether two versions of one file differ materially.
|
|
363
|
+
*
|
|
364
|
+
* @param left - One version's bytes.
|
|
365
|
+
* @param right - The other version's bytes.
|
|
366
|
+
* @returns True if a file holding a NUL byte differs on any byte, or a text file differs with all
|
|
367
|
+
* whitespace removed; false otherwise.
|
|
368
|
+
*/
|
|
369
|
+
export function differs(left, right) {
|
|
126
370
|
if (left.includes(0) || right.includes(0))
|
|
127
371
|
return !left.equals(right);
|
|
128
372
|
return left.toString('utf8').replace(/\s+/gu, '') !== right.toString('utf8').replace(/\s+/gu, '');
|
|
129
373
|
}
|
|
130
|
-
|
|
374
|
+
/**
|
|
375
|
+
* Runs the comparison and prints its summary.
|
|
376
|
+
*
|
|
377
|
+
* @param argv - The arguments after the script path.
|
|
378
|
+
* @returns The exit code: 0 when nothing material differs, 3 when something does, 2 when the tarball
|
|
379
|
+
* cannot be read, 64 on usage.
|
|
380
|
+
*/
|
|
381
|
+
export async function main(argv) {
|
|
382
|
+
const unknown = readUnknownFlags(argv, FLAGS);
|
|
383
|
+
if (unknown.length > 0) {
|
|
384
|
+
console.error(`compare: unknown flag ${unknown.join(', ')}; give each flag and its value as separate arguments\n${USAGE}`);
|
|
385
|
+
return 64;
|
|
386
|
+
}
|
|
131
387
|
const missing = readMissingFlags(argv, ['--package', '--version', '--tarball', '--dist']);
|
|
132
388
|
if (missing.length > 0) {
|
|
133
389
|
console.error(`compare: ${missing.join(', ')} given with no value`);
|
|
134
390
|
return 64;
|
|
135
391
|
}
|
|
136
|
-
const manifest = readManifest();
|
|
392
|
+
const manifest = readManifest('.');
|
|
137
393
|
const name = readOption(argv, '--package') ?? manifest.name;
|
|
138
394
|
const dist = readOption(argv, '--dist') ?? 'dist';
|
|
139
395
|
const tarball = readOption(argv, '--tarball');
|
|
140
396
|
if (name === undefined ||
|
|
141
397
|
!existsSync(dist) ||
|
|
142
398
|
(argv.includes('--tarball') && tarball === undefined)) {
|
|
143
|
-
console.error(
|
|
399
|
+
console.error(USAGE);
|
|
144
400
|
return 64;
|
|
145
401
|
}
|
|
146
402
|
const source = await readSource(name, readOption(argv, '--version'), tarball);
|
|
@@ -159,7 +415,7 @@ async function main(argv) {
|
|
|
159
415
|
? [[path.slice(prefixed.length), content]]
|
|
160
416
|
: []));
|
|
161
417
|
const local = new Map(listFiles(dist, NOTHING_SKIPPED).flatMap(({ path }) => {
|
|
162
|
-
const key = relative(dist, path)
|
|
418
|
+
const key = normalizeSlashes(relative(dist, path));
|
|
163
419
|
return isMaterial(key) ? [[key, readFileSync(path)]] : [];
|
|
164
420
|
}));
|
|
165
421
|
const added = [...local.keys()].filter((key) => !published.has(key)).sort();
|
|
@@ -196,17 +452,8 @@ async function main(argv) {
|
|
|
196
452
|
}
|
|
197
453
|
return material ? 3 : 0;
|
|
198
454
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return undefined;
|
|
204
|
-
return Buffer.from(await response.arrayBuffer());
|
|
205
|
-
}
|
|
206
|
-
catch {
|
|
207
|
-
return undefined;
|
|
208
|
-
}
|
|
455
|
+
if (process.argv[1] !== undefined && realpathSync(process.argv[1]) === import.meta.filename) {
|
|
456
|
+
main(process.argv.slice(2)).then((code) => {
|
|
457
|
+
process.exitCode = code;
|
|
458
|
+
});
|
|
209
459
|
}
|
|
210
|
-
main(process.argv.slice(2)).then((code) => {
|
|
211
|
-
process.exitCode = code;
|
|
212
|
-
});
|
|
@@ -8,21 +8,158 @@
|
|
|
8
8
|
// range (`>=1.2.0 <2.0.0`, `8.x`) hits its literal bounded the same way and not preceded by another
|
|
9
9
|
// range operator. Each matching line prints once as path:line: text, naming the first requested
|
|
10
10
|
// literal that matched in the order --version then each --range, so the operator rules on it.
|
|
11
|
-
// Exit 0 with no hits, 3 with hits, 64 on usage
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
// Exit 0 with no hits, 3 with hits, 64 on usage, including a flag the script does not read and the
|
|
12
|
+
// `--flag=value` form.
|
|
13
|
+
import { readdirSync, readFileSync, realpathSync, statSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
/** Matches the file extensions the sweep skips as binary. */
|
|
16
|
+
export const BINARY = /\.(png|jpg|jpeg|gif|webp|ico|woff2?|ttf|otf|eot|zip|tgz|gz|pdf|wasm)$/u;
|
|
17
|
+
/** Matches a range that is one comparator over one full version and captures the version. */
|
|
18
|
+
export const COMPARATOR = /^(?:\^|~|>=|>|<=|<|=)?v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)$/u;
|
|
19
|
+
/** Names the directories every tree walk skips. */
|
|
20
|
+
export const SKIPPED_DIRECTORIES = new Set([
|
|
21
|
+
'node_modules',
|
|
22
|
+
'.git',
|
|
23
|
+
'dist',
|
|
24
|
+
'tmp',
|
|
25
|
+
'.orkestrel',
|
|
26
|
+
'.idea',
|
|
27
|
+
]);
|
|
28
|
+
/** Lists every flag the script reads, value flags and switches alike. */
|
|
29
|
+
export const FLAGS = ['--version', '--range', '--paths', '--json'];
|
|
30
|
+
/** Holds the usage line the script prints on a usage refusal. */
|
|
31
|
+
export const USAGE = 'usage: pins.ts --version PRIOR [--range PRIOR_RANGE ...] [--paths src,tests] [--json]';
|
|
32
|
+
/**
|
|
33
|
+
* Normalizes a host path to forward slashes.
|
|
34
|
+
*
|
|
35
|
+
* @param path - A host path.
|
|
36
|
+
* @returns The same path with every backslash replaced by a slash.
|
|
37
|
+
*/
|
|
38
|
+
export function normalizeSlashes(path) {
|
|
39
|
+
return path.split('\\').join('/');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Reads the value that follows a flag.
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* Reads `--flag value` pairs: the first occurrence of a flag wins, a following value that opens
|
|
46
|
+
* with `--` is a missing value, and the `--flag=value` form is not read.
|
|
47
|
+
*
|
|
48
|
+
* @param argv - The arguments after the script path.
|
|
49
|
+
* @param name - The flag, such as `--paths`.
|
|
50
|
+
* @returns The value after the flag, or undefined when the flag is absent, last, or followed by
|
|
51
|
+
* another flag.
|
|
52
|
+
*/
|
|
53
|
+
export function readOption(argv, name) {
|
|
54
|
+
const index = argv.indexOf(name);
|
|
55
|
+
const value = index === -1 ? undefined : argv[index + 1];
|
|
56
|
+
return value === undefined || value.startsWith('--') ? undefined : value;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Names the value flags a caller gave with no value.
|
|
60
|
+
*
|
|
61
|
+
* @param argv - The arguments after the script path.
|
|
62
|
+
* @param names - The flags that take a value.
|
|
63
|
+
* @returns Each named flag that appears last or is followed by another flag, in argument order.
|
|
64
|
+
*/
|
|
65
|
+
export function readMissingFlags(argv, names) {
|
|
66
|
+
return names.filter((name) => argv.includes(name) && readOption(argv, name) === undefined);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Names the flags a caller gave that the script does not read.
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
72
|
+
* Reads the arguments before a bare `--`, which opens a command a script passes on. A `--flag=value`
|
|
73
|
+
* argument is unknown, because the script reads no such form.
|
|
74
|
+
*
|
|
75
|
+
* @param argv - The arguments after the script path.
|
|
76
|
+
* @param flags - Every flag the script reads, value flags and switches alike.
|
|
77
|
+
* @returns Each argument that opens with `--` and is not a read flag, in argument order.
|
|
78
|
+
*/
|
|
79
|
+
export function readUnknownFlags(argv, flags) {
|
|
80
|
+
const end = argv.indexOf('--');
|
|
81
|
+
return (end === -1 ? argv : argv.slice(0, end)).filter((argument) => argument.startsWith('--') && !flags.includes(argument));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Reads every value that follows a repeatable flag.
|
|
85
|
+
*
|
|
86
|
+
* @param argv - The arguments after the script path.
|
|
87
|
+
* @param name - The flag, such as `--range`.
|
|
88
|
+
* @returns The values in order, empty when the flag never appears.
|
|
89
|
+
*/
|
|
90
|
+
export function readOptions(argv, name) {
|
|
91
|
+
return argv.flatMap((argument, index) => {
|
|
92
|
+
const value = argv[index + 1];
|
|
93
|
+
return argument === name && value !== undefined && !value.startsWith('--') ? [value] : [];
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Lists every regular file beneath a directory, skipping the directories the sweep never reads.
|
|
98
|
+
*
|
|
99
|
+
* @remarks
|
|
100
|
+
* A skipped name matches a directory at any depth, exactly and case-sensitively, so a
|
|
101
|
+
* `src/dist/` directory is skipped with the build output and a `Node_Modules/` directory is not.
|
|
102
|
+
*
|
|
103
|
+
* @param directory - The directory to walk.
|
|
104
|
+
* @param skipped - The directory names to skip. Default: {@link SKIPPED_DIRECTORIES}.
|
|
105
|
+
* @returns Each file's forward-slash path and modification time, in walk order.
|
|
106
|
+
* @throws Thrown when `directory` does not exist or cannot be read; check `statSync` first.
|
|
107
|
+
*/
|
|
108
|
+
export function listFiles(directory, skipped = SKIPPED_DIRECTORIES) {
|
|
109
|
+
const files = [];
|
|
110
|
+
const pending = [directory];
|
|
111
|
+
while (pending.length > 0) {
|
|
112
|
+
const current = pending.pop();
|
|
113
|
+
if (current === undefined)
|
|
114
|
+
break;
|
|
115
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
116
|
+
if (skipped.has(entry.name))
|
|
117
|
+
continue;
|
|
118
|
+
const path = join(current, entry.name);
|
|
119
|
+
if (entry.isDirectory())
|
|
120
|
+
pending.push(path);
|
|
121
|
+
else if (entry.isFile()) {
|
|
122
|
+
files.push({ path: normalizeSlashes(path), modified: statSync(path).mtimeMs });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return files;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Escapes a literal for use inside a regular expression.
|
|
130
|
+
*
|
|
131
|
+
* @param literal - The text to match exactly.
|
|
132
|
+
* @returns The text with every regular expression metacharacter backslash-escaped.
|
|
133
|
+
*/
|
|
134
|
+
export function escapePattern(literal) {
|
|
17
135
|
return literal.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
18
136
|
}
|
|
19
|
-
|
|
137
|
+
/**
|
|
138
|
+
* Builds the pattern that finds a version bounded by characters other than digits and dots.
|
|
139
|
+
*
|
|
140
|
+
* @param version - The version literal.
|
|
141
|
+
* @returns The pattern.
|
|
142
|
+
*/
|
|
143
|
+
export function buildVersionPattern(version) {
|
|
20
144
|
return new RegExp(`(?<![0-9.])${escapePattern(version)}(?![0-9.])`, 'u');
|
|
21
145
|
}
|
|
22
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Builds the literal for a requested version.
|
|
148
|
+
*
|
|
149
|
+
* @param literal - The version as the operator wrote it.
|
|
150
|
+
* @returns The literal with its bounded pattern.
|
|
151
|
+
*/
|
|
152
|
+
export function buildVersionLiteral(literal) {
|
|
23
153
|
return { literal, pattern: buildVersionPattern(literal) };
|
|
24
154
|
}
|
|
25
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Builds the literal for a requested range.
|
|
157
|
+
*
|
|
158
|
+
* @param literal - The range as the operator wrote it.
|
|
159
|
+
* @returns A one-comparator range matched by its bare version in any form, any other range matched as
|
|
160
|
+
* its own text not preceded by a range operator.
|
|
161
|
+
*/
|
|
162
|
+
export function buildRangeLiteral(literal) {
|
|
26
163
|
const version = COMPARATOR.exec(literal)?.[1];
|
|
27
164
|
if (version !== undefined)
|
|
28
165
|
return { literal, pattern: buildVersionPattern(version) };
|
|
@@ -31,7 +168,14 @@ function buildRangeLiteral(literal) {
|
|
|
31
168
|
pattern: new RegExp(`(?<![0-9.^~<>=])${escapePattern(literal)}(?![0-9.])`, 'u'),
|
|
32
169
|
};
|
|
33
170
|
}
|
|
34
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Finds the lines of one file that carry a requested literal.
|
|
173
|
+
*
|
|
174
|
+
* @param path - The file to read.
|
|
175
|
+
* @param literals - The literals to look for, in the order that names a line's literal.
|
|
176
|
+
* @returns One hit per matching line, naming the first literal that matched; none for a binary file.
|
|
177
|
+
*/
|
|
178
|
+
export function sweepFile(path, literals) {
|
|
35
179
|
const content = readFileSync(path);
|
|
36
180
|
if (content.includes(0))
|
|
37
181
|
return [];
|
|
@@ -45,7 +189,18 @@ function sweepFile(path, literals) {
|
|
|
45
189
|
: [{ path, line: index + 1, literal: match.literal, text: text.trim() }];
|
|
46
190
|
});
|
|
47
191
|
}
|
|
48
|
-
|
|
192
|
+
/**
|
|
193
|
+
* Runs the sweep and prints its hits.
|
|
194
|
+
*
|
|
195
|
+
* @param argv - The arguments after the script path.
|
|
196
|
+
* @returns The exit code: 0 with no hits, 3 with hits, 64 on usage.
|
|
197
|
+
*/
|
|
198
|
+
export function main(argv) {
|
|
199
|
+
const unknown = readUnknownFlags(argv, FLAGS);
|
|
200
|
+
if (unknown.length > 0) {
|
|
201
|
+
console.error(`pins: unknown flag ${unknown.join(', ')}; give each flag and its value as separate arguments\n${USAGE}`);
|
|
202
|
+
return 64;
|
|
203
|
+
}
|
|
49
204
|
const missing = readMissingFlags(argv, ['--version', '--range', '--paths']);
|
|
50
205
|
if (missing.length > 0) {
|
|
51
206
|
console.error(`pins: ${missing.join(', ')} given with no value`);
|
|
@@ -55,7 +210,7 @@ function main(argv) {
|
|
|
55
210
|
const ranges = readOptions(argv, '--range');
|
|
56
211
|
const paths = (readOptions(argv, '--paths')[0] ?? 'src,tests').split(',');
|
|
57
212
|
if (version === undefined && ranges.length === 0) {
|
|
58
|
-
console.error(
|
|
213
|
+
console.error(USAGE);
|
|
59
214
|
return 64;
|
|
60
215
|
}
|
|
61
216
|
const literals = [
|
|
@@ -88,4 +243,6 @@ function main(argv) {
|
|
|
88
243
|
}
|
|
89
244
|
return hits.length === 0 ? 0 : 3;
|
|
90
245
|
}
|
|
91
|
-
process.
|
|
246
|
+
if (process.argv[1] !== undefined && realpathSync(process.argv[1]) === import.meta.filename) {
|
|
247
|
+
process.exitCode = main(process.argv.slice(2));
|
|
248
|
+
}
|