@oa-sdk/spec-bundler 0.1.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/LICENSE +201 -0
- package/README.md +240 -0
- package/dist/archiver.d.ts +22 -0
- package/dist/archiver.js +155 -0
- package/dist/category-parser.d.ts +15 -0
- package/dist/category-parser.js +115 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +760 -0
- package/dist/context-generator.d.ts +14 -0
- package/dist/context-generator.js +297 -0
- package/dist/freshness.d.ts +41 -0
- package/dist/freshness.js +365 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +705 -0
- package/dist/link-rewriter.d.ts +65 -0
- package/dist/link-rewriter.js +777 -0
- package/dist/resolver.d.ts +27 -0
- package/dist/resolver.js +276 -0
- package/dist/schema.d.ts +563 -0
- package/dist/schema.js +670 -0
- package/dist/section-slicer.d.ts +12 -0
- package/dist/section-slicer.js +114 -0
- package/dist/topic.d.ts +62 -0
- package/dist/topic.js +262 -0
- package/dist/tree-shaker.d.ts +40 -0
- package/dist/tree-shaker.js +523 -0
- package/dist/types.d.ts +369 -0
- package/dist/types.js +2 -0
- package/package.json +29 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,760 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { createBundle, loadManifest, unpackBundle, verifyBundle, inspectBundle, emitJsonSchema, explainReachability, resolveBundlePath, listManifestTopics, resolveTopicManifest, createTopicProfile, addTopicToManifest, } from "./index.js";
|
|
5
|
+
import { checkFreshness, getLockfilePath } from "./freshness.js";
|
|
6
|
+
function printUsage() {
|
|
7
|
+
console.log(`
|
|
8
|
+
@spec-platform/meta-bundler CLI
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
spec-bundler pack [--config <file>] [--topic <name>] [--all-topics] [--tree-shake] [--force] [--dry-run] [--json] [--diff] [--explain <target>]
|
|
12
|
+
Builds the bundle, rewrites internal markdown links to bundle coordinates,
|
|
13
|
+
deduplicates entries, packages the ZIP archive, and synchronizes the lockfile.
|
|
14
|
+
Use --topic <name> to package a specific topic profile slice with boundary scoping.
|
|
15
|
+
Use --all-topics to package all declared topic profiles sequentially.
|
|
16
|
+
Use --tree-shake to enforce reachability pruning from entrypoints.
|
|
17
|
+
Use --dry-run to preview packaging without writing files to disk.
|
|
18
|
+
Use --json to output structured machine-readable JSON.
|
|
19
|
+
Use --diff to display detailed terminal diff reporting of planned rewrites.
|
|
20
|
+
Use --explain <target> to display the reachability provenance for a file.
|
|
21
|
+
|
|
22
|
+
spec-bundler topic create <name> [--phase <develop|fix|test|review>] [--entry <file>] [--author <name>]
|
|
23
|
+
Easily creates and registers a new topic profile in the manifest using lifecycle presets
|
|
24
|
+
(develop, fix, test, review) with tailored directions, category filters, and fidelity levels.
|
|
25
|
+
|
|
26
|
+
spec-bundler topics [--config <file>] [--json]
|
|
27
|
+
Lists all declared topic profiles configured in the manifest with their targets and outputs.
|
|
28
|
+
|
|
29
|
+
spec-bundler resolve <archive.zip> <path-or-reference> [--json]
|
|
30
|
+
Resolves a source file path, relative reference, or TypeSpec target (including #anchors)
|
|
31
|
+
to its exact coordinate inside the compressed bundle archive using the manifest BOM.
|
|
32
|
+
|
|
33
|
+
spec-bundler inspect [--config <file>] [--topic <name>]
|
|
34
|
+
Renders the visual hierarchical ASCII dependency reachability tree, size breakdown,
|
|
35
|
+
and entrypoint mapping.
|
|
36
|
+
|
|
37
|
+
spec-bundler check [--config <file>] [--topic <name>]
|
|
38
|
+
CI coverage & drift gate. Exits with code 0 if the bundle and lockfile are fresh,
|
|
39
|
+
or code 1 if upstream source files were modified without regenerating the bundle.
|
|
40
|
+
|
|
41
|
+
spec-bundler verify [--config <file>] [--topic <name>] [--check-anchors]
|
|
42
|
+
Validates link integrity (checks for dead links with fuzzy 'Did you mean?' suggestions),
|
|
43
|
+
anchor validity (#heading-slug), and collision warnings.
|
|
44
|
+
|
|
45
|
+
spec-bundler schema [--out <file>]
|
|
46
|
+
Emits the official JSON Schema (Draft 2020-12) for bundle manifest files.
|
|
47
|
+
|
|
48
|
+
spec-bundler unpack <archive.zip> [--dest <dir>]
|
|
49
|
+
Extracts a bundle archive cleanly into a target directory (default: current directory).
|
|
50
|
+
`);
|
|
51
|
+
}
|
|
52
|
+
function findConfigFile(customConfig) {
|
|
53
|
+
if (customConfig) {
|
|
54
|
+
const abs = path.resolve(process.cwd(), customConfig);
|
|
55
|
+
if (!fs.existsSync(abs)) {
|
|
56
|
+
console.error(`ā Specified config file not found: ${customConfig}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
return abs;
|
|
60
|
+
}
|
|
61
|
+
const candidates = [
|
|
62
|
+
"evidence-bundle.manifest.json",
|
|
63
|
+
"bundle.manifest.json",
|
|
64
|
+
"bundle.config.json",
|
|
65
|
+
];
|
|
66
|
+
for (const candidate of candidates) {
|
|
67
|
+
const full = path.join(process.cwd(), candidate);
|
|
68
|
+
if (fs.existsSync(full)) {
|
|
69
|
+
return full;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
console.error(`ā No manifest file found in current directory. Expected one of: ${candidates.join(", ")}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
async function main() {
|
|
76
|
+
const args = process.argv.slice(2);
|
|
77
|
+
const command = args[0];
|
|
78
|
+
if (!command || command === "--help" || command === "-h") {
|
|
79
|
+
printUsage();
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
let customConfig;
|
|
83
|
+
let force = false;
|
|
84
|
+
let dryRun = false;
|
|
85
|
+
let json = false;
|
|
86
|
+
let diff = false;
|
|
87
|
+
let explainTarget;
|
|
88
|
+
let destDir;
|
|
89
|
+
let outPath;
|
|
90
|
+
let checkAnchors = false;
|
|
91
|
+
let topic;
|
|
92
|
+
let allTopics = false;
|
|
93
|
+
let treeShake;
|
|
94
|
+
for (let i = 1; i < args.length; i++) {
|
|
95
|
+
const arg = args[i];
|
|
96
|
+
if ((arg === "--config" || arg === "-c") && args[i + 1]) {
|
|
97
|
+
customConfig = args[++i];
|
|
98
|
+
}
|
|
99
|
+
else if (arg === "--topic" && args[i + 1]) {
|
|
100
|
+
topic = args[++i];
|
|
101
|
+
}
|
|
102
|
+
else if (arg === "--all-topics") {
|
|
103
|
+
allTopics = true;
|
|
104
|
+
}
|
|
105
|
+
else if (arg === "--tree-shake") {
|
|
106
|
+
treeShake = true;
|
|
107
|
+
}
|
|
108
|
+
else if (arg === "--no-tree-shake") {
|
|
109
|
+
treeShake = false;
|
|
110
|
+
}
|
|
111
|
+
else if (arg === "--force" || arg === "-f") {
|
|
112
|
+
force = true;
|
|
113
|
+
}
|
|
114
|
+
else if (arg === "--dry-run") {
|
|
115
|
+
dryRun = true;
|
|
116
|
+
}
|
|
117
|
+
else if (arg === "--json") {
|
|
118
|
+
json = true;
|
|
119
|
+
}
|
|
120
|
+
else if (arg === "--diff") {
|
|
121
|
+
diff = true;
|
|
122
|
+
}
|
|
123
|
+
else if (arg === "--check-anchors") {
|
|
124
|
+
checkAnchors = true;
|
|
125
|
+
}
|
|
126
|
+
else if (arg === "--explain" && args[i + 1]) {
|
|
127
|
+
explainTarget = args[++i];
|
|
128
|
+
}
|
|
129
|
+
else if ((arg === "--dest" || arg === "-d") && args[i + 1]) {
|
|
130
|
+
destDir = args[++i];
|
|
131
|
+
}
|
|
132
|
+
else if ((arg === "--out" || arg === "-o") && args[i + 1]) {
|
|
133
|
+
outPath = args[++i];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (command === "create-topic" || (command === "topic" && args[1] === "create")) {
|
|
137
|
+
let topicName;
|
|
138
|
+
let phaseStr;
|
|
139
|
+
let author;
|
|
140
|
+
const entries = [];
|
|
141
|
+
let description;
|
|
142
|
+
let domain;
|
|
143
|
+
let issue;
|
|
144
|
+
let prompt;
|
|
145
|
+
let output;
|
|
146
|
+
let format;
|
|
147
|
+
let config;
|
|
148
|
+
const startIndex = command === "create-topic" ? 1 : 2;
|
|
149
|
+
for (let i = startIndex; i < args.length; i++) {
|
|
150
|
+
const arg = args[i];
|
|
151
|
+
if ((arg === "--phase" || arg === "-p") && args[i + 1]) {
|
|
152
|
+
phaseStr = args[++i];
|
|
153
|
+
}
|
|
154
|
+
else if ((arg === "--author" || arg === "-a") && args[i + 1]) {
|
|
155
|
+
author = args[++i];
|
|
156
|
+
}
|
|
157
|
+
else if ((arg === "--entry" || arg === "-e") && args[i + 1]) {
|
|
158
|
+
entries.push(args[++i]);
|
|
159
|
+
}
|
|
160
|
+
else if ((arg === "--desc" || arg === "--description") && args[i + 1]) {
|
|
161
|
+
description = args[++i];
|
|
162
|
+
}
|
|
163
|
+
else if (arg === "--domain" && args[i + 1]) {
|
|
164
|
+
domain = args[++i];
|
|
165
|
+
}
|
|
166
|
+
else if (arg === "--issue" && args[i + 1]) {
|
|
167
|
+
issue = args[++i];
|
|
168
|
+
}
|
|
169
|
+
else if (arg === "--prompt" && args[i + 1]) {
|
|
170
|
+
prompt = args[++i];
|
|
171
|
+
}
|
|
172
|
+
else if ((arg === "--output" || arg === "--out" || arg === "-o") && args[i + 1]) {
|
|
173
|
+
output = args[++i];
|
|
174
|
+
}
|
|
175
|
+
else if (arg === "--format" && args[i + 1]) {
|
|
176
|
+
const fmt = args[++i];
|
|
177
|
+
if (fmt === "zip" || fmt === "directory") {
|
|
178
|
+
format = fmt;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if ((arg === "--config" || arg === "-c") && args[i + 1]) {
|
|
182
|
+
config = args[++i];
|
|
183
|
+
}
|
|
184
|
+
else if (!arg.startsWith("-") && !topicName) {
|
|
185
|
+
topicName = arg;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (!topicName) {
|
|
189
|
+
console.error(`\nā Topic name is required. Usage: spec-bundler topic create <name> [--phase <develop|fix|test|review>] [--entry <file>] [--author <name>]`);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
if (phaseStr &&
|
|
193
|
+
phaseStr !== "develop" &&
|
|
194
|
+
phaseStr !== "fix" &&
|
|
195
|
+
phaseStr !== "test" &&
|
|
196
|
+
phaseStr !== "review") {
|
|
197
|
+
console.error(`\nā Invalid phase '${phaseStr}'. Expected one of: develop, fix, test, review`);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
const configPath = findConfigFile(config ?? customConfig);
|
|
201
|
+
try {
|
|
202
|
+
const profile = createTopicProfile({
|
|
203
|
+
name: topicName,
|
|
204
|
+
phase: phaseStr,
|
|
205
|
+
author,
|
|
206
|
+
entrypoints: entries.length > 0 ? entries : undefined,
|
|
207
|
+
description,
|
|
208
|
+
domain,
|
|
209
|
+
issue,
|
|
210
|
+
prompt,
|
|
211
|
+
output,
|
|
212
|
+
format,
|
|
213
|
+
});
|
|
214
|
+
const res = addTopicToManifest(configPath, topicName, profile);
|
|
215
|
+
console.log(`\nā Successfully created topic '${topicName}' in ${path.relative(process.cwd(), configPath)}:`);
|
|
216
|
+
console.log(` Work Phase: ${profile.phase ?? "develop"}`);
|
|
217
|
+
if (profile.author) {
|
|
218
|
+
console.log(` Author: ${profile.author}`);
|
|
219
|
+
}
|
|
220
|
+
if (profile.scope?.direction) {
|
|
221
|
+
console.log(` Direction: ${profile.scope.direction}`);
|
|
222
|
+
}
|
|
223
|
+
if (profile.scope?.includeCategories) {
|
|
224
|
+
console.log(` Categories: ${profile.scope.includeCategories.join(", ")}`);
|
|
225
|
+
}
|
|
226
|
+
if (profile.scope?.entrypoints && profile.scope.entrypoints.length > 0) {
|
|
227
|
+
console.log(` Entrypoint: ${profile.scope.entrypoints.join(", ")}`);
|
|
228
|
+
}
|
|
229
|
+
if (profile.context?.issue) {
|
|
230
|
+
console.log(` Issue: ${profile.context.issue}`);
|
|
231
|
+
}
|
|
232
|
+
console.log(` Topics: ${res.topicCount} declared topic profile(s) in manifest`);
|
|
233
|
+
console.log(`\nš Next steps:`);
|
|
234
|
+
console.log(` spec-bundler inspect --topic ${topicName}`);
|
|
235
|
+
console.log(` spec-bundler pack --topic ${topicName}`);
|
|
236
|
+
process.exit(0);
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
console.error(`\nā Failed to create topic: ${err.message}`);
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (command === "topics" || (command === "topic" && (args[1] === "list" || !args[1] || args[1].startsWith("-")))) {
|
|
244
|
+
const configPath = findConfigFile(customConfig);
|
|
245
|
+
try {
|
|
246
|
+
const manifest = loadManifest(configPath);
|
|
247
|
+
const summaries = listManifestTopics(manifest);
|
|
248
|
+
if (json) {
|
|
249
|
+
console.log(JSON.stringify(summaries, null, 2));
|
|
250
|
+
process.exit(0);
|
|
251
|
+
}
|
|
252
|
+
console.log(`\nš Declared Topic Profiles in ${path.relative(process.cwd(), configPath)}:`);
|
|
253
|
+
if (summaries.length === 0) {
|
|
254
|
+
console.log(" (No topic profiles declared under 'topics')");
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
for (const s of summaries) {
|
|
258
|
+
console.log(` - ${s.name} (${s.format}, ${s.targetCount} target mapping${s.targetCount === 1 ? "" : "s"}):`);
|
|
259
|
+
if (s.phase)
|
|
260
|
+
console.log(` Phase: ${s.phase}`);
|
|
261
|
+
if (s.author)
|
|
262
|
+
console.log(` Author: ${s.author}`);
|
|
263
|
+
if (s.description)
|
|
264
|
+
console.log(` Description: ${s.description}`);
|
|
265
|
+
if (s.domain)
|
|
266
|
+
console.log(` Domain: ${s.domain}`);
|
|
267
|
+
if (s.issue)
|
|
268
|
+
console.log(` Issue: ${s.issue}`);
|
|
269
|
+
if (s.tags && s.tags.length > 0)
|
|
270
|
+
console.log(` Tags: ${s.tags.join(", ")}`);
|
|
271
|
+
if (s.contextDocsCount && s.contextDocsCount > 0) {
|
|
272
|
+
console.log(` Context: ${s.contextDocsCount} ambient document(s)`);
|
|
273
|
+
}
|
|
274
|
+
if (s.hasScope) {
|
|
275
|
+
console.log(` Scope: Configured (entrypoints, boundary filters)`);
|
|
276
|
+
}
|
|
277
|
+
if (s.direction) {
|
|
278
|
+
console.log(` Direction: ${s.direction}`);
|
|
279
|
+
}
|
|
280
|
+
console.log(` Output: ${s.output}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
process.exit(0);
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
console.error(`\nā Failed to read topics: ${err.message}`);
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (command === "schema") {
|
|
291
|
+
const schemaContent = emitJsonSchema();
|
|
292
|
+
if (outPath) {
|
|
293
|
+
const absOut = path.resolve(process.cwd(), outPath);
|
|
294
|
+
fs.mkdirSync(path.dirname(absOut), { recursive: true });
|
|
295
|
+
fs.writeFileSync(absOut, schemaContent, "utf8");
|
|
296
|
+
console.log(`ā Emitted JSON Schema to ${path.relative(process.cwd(), absOut)}`);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
console.log(schemaContent);
|
|
300
|
+
}
|
|
301
|
+
process.exit(0);
|
|
302
|
+
}
|
|
303
|
+
if (command === "inspect" || command === "tree") {
|
|
304
|
+
const configPath = findConfigFile(customConfig);
|
|
305
|
+
try {
|
|
306
|
+
const inspection = inspectBundle(configPath, { topic });
|
|
307
|
+
const topicSuffix = topic ? ` - Topic: ${topic}` : "";
|
|
308
|
+
console.log(`\nš¦ Bundle Dependency Reachability Tree (${path.relative(process.cwd(), configPath)}${topicSuffix}):`);
|
|
309
|
+
if (inspection.manifest.phase) {
|
|
310
|
+
console.log(` Phase: ${inspection.manifest.phase}`);
|
|
311
|
+
}
|
|
312
|
+
if (inspection.manifest.author) {
|
|
313
|
+
console.log(` Author: ${inspection.manifest.author}`);
|
|
314
|
+
}
|
|
315
|
+
if (inspection.manifest.context) {
|
|
316
|
+
const ctx = inspection.manifest.context;
|
|
317
|
+
if (ctx.domain)
|
|
318
|
+
console.log(` Domain: ${ctx.domain}`);
|
|
319
|
+
if (ctx.issue)
|
|
320
|
+
console.log(` Issue: ${ctx.issue}`);
|
|
321
|
+
if (ctx.tags && ctx.tags.length > 0)
|
|
322
|
+
console.log(` Tags: ${ctx.tags.join(", ")}`);
|
|
323
|
+
if (ctx.prompt)
|
|
324
|
+
console.log(` Prompt: ${ctx.prompt.slice(0, 80)}${ctx.prompt.length > 80 ? "..." : ""}`);
|
|
325
|
+
}
|
|
326
|
+
const direction = inspection.manifest.treeShake?.direction ?? inspection.manifest.scope?.direction;
|
|
327
|
+
if (direction) {
|
|
328
|
+
console.log(` Direction: ${direction}`);
|
|
329
|
+
}
|
|
330
|
+
const cats = inspection.manifest.treeShake?.includeCategories ?? inspection.manifest.scope?.includeCategories;
|
|
331
|
+
if (cats && cats.length > 0) {
|
|
332
|
+
console.log(` Categories: ${cats.join(", ")}`);
|
|
333
|
+
}
|
|
334
|
+
if (inspection.manifest.scope?.sections && inspection.manifest.scope.sections.length > 0) {
|
|
335
|
+
console.log(` Sections: ${inspection.manifest.scope.sections.join(", ")}`);
|
|
336
|
+
}
|
|
337
|
+
console.log("--------------------------------------------------------------------------------");
|
|
338
|
+
if (inspection.asciiTree) {
|
|
339
|
+
process.stdout.write(inspection.asciiTree);
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
console.log(" (No entrypoints or reachable files found)");
|
|
343
|
+
}
|
|
344
|
+
console.log("--------------------------------------------------------------------------------");
|
|
345
|
+
console.log(`ā Reachable: ${inspection.reachableCount} files (${(inspection.totalSizeBytes / 1024).toFixed(1)} KB)`);
|
|
346
|
+
if (inspection.eliminatedCount > 0) {
|
|
347
|
+
console.log(`ā Eliminated: ${inspection.eliminatedCount} unreferenced files`);
|
|
348
|
+
}
|
|
349
|
+
if (inspection.boundaryTerminals && inspection.boundaryTerminals.length > 0) {
|
|
350
|
+
console.log(`š Boundary: ${inspection.boundaryTerminals.length} terminal reference(s) halted traversal`);
|
|
351
|
+
}
|
|
352
|
+
if (inspection.warnings.length > 0) {
|
|
353
|
+
console.warn(`\nā ļø Warnings (${inspection.warnings.length}):`);
|
|
354
|
+
for (const w of inspection.warnings)
|
|
355
|
+
console.warn(` - ${w}`);
|
|
356
|
+
}
|
|
357
|
+
process.exit(0);
|
|
358
|
+
}
|
|
359
|
+
catch (err) {
|
|
360
|
+
console.error(`\nā Inspection failed: ${err.message}`);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (command === "pack") {
|
|
365
|
+
const configPath = findConfigFile(customConfig);
|
|
366
|
+
try {
|
|
367
|
+
if (allTopics) {
|
|
368
|
+
const manifest = loadManifest(configPath);
|
|
369
|
+
const summaries = listManifestTopics(manifest);
|
|
370
|
+
if (summaries.length === 0) {
|
|
371
|
+
console.warn(`ā ļø No topics found under 'topics' in ${path.relative(process.cwd(), configPath)}.`);
|
|
372
|
+
process.exit(0);
|
|
373
|
+
}
|
|
374
|
+
console.log(`š¦ Packaging ${summaries.length} topic profile${summaries.length === 1 ? "" : "s"}...`);
|
|
375
|
+
let hadFailure = false;
|
|
376
|
+
for (const s of summaries) {
|
|
377
|
+
console.log(`\n------------------------------------------------------------`);
|
|
378
|
+
console.log(`šÆ Packaging Topic: ${s.name}${s.phase ? ` [Phase: ${s.phase}]` : ""}${s.author ? ` (Author: ${s.author})` : ""}`);
|
|
379
|
+
console.log(`------------------------------------------------------------`);
|
|
380
|
+
try {
|
|
381
|
+
const result = createBundle(configPath, { force, dryRun, json: false, diff, topic: s.name, treeShake });
|
|
382
|
+
console.log(`ā Successfully generated topic bundle: ${path.relative(process.cwd(), result.outputPath)} (${result.filesCount} files)`);
|
|
383
|
+
}
|
|
384
|
+
catch (err) {
|
|
385
|
+
console.error(`ā Failed packaging topic '${s.name}': ${err.message}`);
|
|
386
|
+
hadFailure = true;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
process.exit(hadFailure ? 1 : 0);
|
|
390
|
+
}
|
|
391
|
+
if (explainTarget) {
|
|
392
|
+
const inspection = inspectBundle(configPath, { topic });
|
|
393
|
+
const epList = inspection.manifest.treeShake?.entrypoints ?? [];
|
|
394
|
+
const hops = explainReachability(explainTarget, inspection.lineage, epList, inspection.boundaryEdges);
|
|
395
|
+
console.log(`\nš Reachability Explanation for '${explainTarget}':`);
|
|
396
|
+
if (hops === null) {
|
|
397
|
+
console.log(` ā Target '${explainTarget}' was NOT reachable from any entrypoint (eliminated or unbundled).`);
|
|
398
|
+
}
|
|
399
|
+
else if (hops.length === 0) {
|
|
400
|
+
console.log(` ā Target '${explainTarget}' is a declared root entrypoint.`);
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
console.log(` ā Reachable via ${hops.length} hop(s):`);
|
|
404
|
+
hops.forEach((h, idx) => {
|
|
405
|
+
console.log(` ${idx + 1}. ${h.from} -> ${h.to} (ref: '${h.ref}')`);
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
process.exit(0);
|
|
409
|
+
}
|
|
410
|
+
const result = createBundle(configPath, { force, dryRun, json, diff, topic, treeShake });
|
|
411
|
+
if (json) {
|
|
412
|
+
let manifestObj;
|
|
413
|
+
try {
|
|
414
|
+
manifestObj = loadManifest(configPath);
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
manifestObj = {};
|
|
418
|
+
}
|
|
419
|
+
const jsonReport = {
|
|
420
|
+
manifest: path.relative(process.cwd(), configPath),
|
|
421
|
+
topic: result.topic,
|
|
422
|
+
phase: result.phase,
|
|
423
|
+
author: result.author,
|
|
424
|
+
bundleName: result.predictedLockfile?.bundleName ?? manifestObj.name ?? "bundle",
|
|
425
|
+
bundleVersion: result.predictedLockfile?.manifestVersion ?? manifestObj.version ?? "1.0.0",
|
|
426
|
+
outputPath: path.relative(process.cwd(), result.outputPath),
|
|
427
|
+
format: manifestObj.format ?? "zip",
|
|
428
|
+
dryRun: Boolean(result.dryRun),
|
|
429
|
+
skipped: result.skipped,
|
|
430
|
+
filesCount: result.filesCount,
|
|
431
|
+
totalSizeBytes: result.totalSizeBytes,
|
|
432
|
+
aggregateHash: result.aggregateHash,
|
|
433
|
+
plannedEntries: result.plannedEntries ?? [],
|
|
434
|
+
rewrites: result.rewrites ?? [],
|
|
435
|
+
diagnostics: result.diagnostics,
|
|
436
|
+
unbundledDiagnostics: result.unbundledDiagnostics ?? [],
|
|
437
|
+
predictedLockfile: result.predictedLockfile,
|
|
438
|
+
freshness: result.freshness,
|
|
439
|
+
eliminatedFiles: result.eliminatedFiles ?? [],
|
|
440
|
+
boundaryTerminals: result.boundaryTerminals ?? [],
|
|
441
|
+
upstreamNodes: result.upstreamNodes ?? [],
|
|
442
|
+
direction: result.direction,
|
|
443
|
+
categoryBreakdown: result.categoryBreakdown,
|
|
444
|
+
};
|
|
445
|
+
console.log(JSON.stringify(jsonReport, null, 2));
|
|
446
|
+
const errors = result.diagnostics.filter((d) => d.severity === "error");
|
|
447
|
+
if (errors.length > 0) {
|
|
448
|
+
process.exit(1);
|
|
449
|
+
}
|
|
450
|
+
process.exit(0);
|
|
451
|
+
}
|
|
452
|
+
if (result.skipped) {
|
|
453
|
+
console.log(`ā Bundle is already up to date! (Aggregate Hash: ${result.aggregateHash.slice(0, 12)}...)`);
|
|
454
|
+
console.log(` Use --force to rebuild unconditionally.`);
|
|
455
|
+
process.exit(0);
|
|
456
|
+
}
|
|
457
|
+
const topicHeader = result.topic ? ` [Topic: ${result.topic}]` : "";
|
|
458
|
+
if (dryRun || diff) {
|
|
459
|
+
const prefix = dryRun ? "š [Dry Run Simulation]" : "š¦";
|
|
460
|
+
console.log(`${prefix}${topicHeader} Packaging bundle using ${path.relative(process.cwd(), configPath)}...`);
|
|
461
|
+
if (result.plannedEntries && result.plannedEntries.length > 0) {
|
|
462
|
+
console.log(`\nš Planned Destination Mappings (${result.plannedEntries.length} file${result.plannedEntries.length === 1 ? "" : "s"}):`);
|
|
463
|
+
for (const entry of result.plannedEntries) {
|
|
464
|
+
const sizeKb = (entry.size / 1024).toFixed(1);
|
|
465
|
+
console.log(` - ${entry.source} -> ${entry.dest} (${sizeKb} KB, sha256: ${entry.sha256.slice(0, 12)}...)`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (result.rewrites && result.rewrites.length > 0) {
|
|
469
|
+
console.log(`\nš Recalculated Link Rewrites (${result.rewrites.length} link${result.rewrites.length === 1 ? "" : "s"}):`);
|
|
470
|
+
for (const rw of result.rewrites) {
|
|
471
|
+
console.log(` - ${rw.file}:${rw.line}:${rw.column}: '${rw.originalHref}' -> '${rw.rewrittenHref}'`);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
console.log(`\nš Recalculated Link Rewrites: 0 (No relative links required rewriting)`);
|
|
476
|
+
}
|
|
477
|
+
if (result.predictedLockfile) {
|
|
478
|
+
console.log(`\nš Predicted Lockfile State:`);
|
|
479
|
+
console.log(` - Aggregate Hash: ${result.predictedLockfile.aggregateHash.slice(0, 16)}...`);
|
|
480
|
+
console.log(` - Files Count: ${result.predictedLockfile.filesCount}`);
|
|
481
|
+
console.log(` - Total Size: ${result.predictedLockfile.totalSizeBytes} bytes`);
|
|
482
|
+
if (result.freshness) {
|
|
483
|
+
const freshStr = result.freshness.isFresh
|
|
484
|
+
? "ā Synchronized"
|
|
485
|
+
: `ā ļø Drift detected (+${result.freshness.added.length}, -${result.freshness.removed.length}, ~${result.freshness.modified.length})`;
|
|
486
|
+
console.log(` - Freshness: ${freshStr}`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (result.eliminatedFiles && result.eliminatedFiles.length > 0) {
|
|
490
|
+
console.log(` - Tree-shaken: ${result.eliminatedFiles.length} unreferenced files eliminated`);
|
|
491
|
+
}
|
|
492
|
+
if (result.boundaryTerminals && result.boundaryTerminals.length > 0) {
|
|
493
|
+
console.log(` - Boundary Halt: ${result.boundaryTerminals.length} terminal reference(s) halted traversal`);
|
|
494
|
+
}
|
|
495
|
+
if (result.phase) {
|
|
496
|
+
console.log(` - Work Phase: ${result.phase}`);
|
|
497
|
+
}
|
|
498
|
+
if (result.author) {
|
|
499
|
+
console.log(` - Initial Author:${result.author}`);
|
|
500
|
+
}
|
|
501
|
+
if (result.direction) {
|
|
502
|
+
console.log(` - Direction: ${result.direction}`);
|
|
503
|
+
}
|
|
504
|
+
if (result.categoryBreakdown) {
|
|
505
|
+
const catEntries = Object.entries(result.categoryBreakdown)
|
|
506
|
+
.map(([cat, count]) => `${cat}: ${count}`)
|
|
507
|
+
.join(", ");
|
|
508
|
+
console.log(` - Categories: ${catEntries}`);
|
|
509
|
+
}
|
|
510
|
+
if (result.upstreamNodes && result.upstreamNodes.length > 0) {
|
|
511
|
+
console.log(` - Upstream Nodes:${result.upstreamNodes.length} caller document(s) included`);
|
|
512
|
+
}
|
|
513
|
+
if (result.unbundledDiagnostics && result.unbundledDiagnostics.length > 0) {
|
|
514
|
+
console.log(`\nā ļø Unbundled Reference Diagnostics (${result.unbundledDiagnostics.length} target${result.unbundledDiagnostics.length === 1 ? "" : "s"}):`);
|
|
515
|
+
for (const u of result.unbundledDiagnostics) {
|
|
516
|
+
const colStr = u.column ? `:${u.column}` : "";
|
|
517
|
+
const icon = u.severity === "error" ? "ā" : u.severity === "warning" ? "ā ļø" : "ā¹ļø";
|
|
518
|
+
console.log(` ${icon} ${u.file}:${u.line}${colStr}: ${u.message}`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const unbundledOriginalHrefs = new Set((result.unbundledDiagnostics ?? []).map((u) => `${u.file}:${u.line}:${u.column ?? 1}:${u.originalHref}`));
|
|
522
|
+
const otherWarnings = result.diagnostics.filter((d) => d.severity === "warning" &&
|
|
523
|
+
!unbundledOriginalHrefs.has(`${d.file}:${d.line}:${d.column ?? 1}:${d.originalHref}`));
|
|
524
|
+
if (otherWarnings.length > 0) {
|
|
525
|
+
console.log(`\nā ļø [Link Warnings] (${otherWarnings.length} issues):`);
|
|
526
|
+
for (const w of otherWarnings) {
|
|
527
|
+
const colStr = w.column ? `:${w.column}` : "";
|
|
528
|
+
console.log(` - ${w.file}:${w.line}${colStr}: ${w.message}`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
const allErrors = result.diagnostics.filter((d) => d.severity === "error");
|
|
532
|
+
if (allErrors.length > 0) {
|
|
533
|
+
console.error(`\nā [Dead Link Errors] (${allErrors.length} issues):`);
|
|
534
|
+
for (const e of allErrors) {
|
|
535
|
+
const colStr = e.column ? `:${e.column}` : "";
|
|
536
|
+
console.error(` - ${e.file}:${e.line}${colStr}: ${e.message}`);
|
|
537
|
+
}
|
|
538
|
+
process.exit(1);
|
|
539
|
+
}
|
|
540
|
+
if (dryRun) {
|
|
541
|
+
console.log(`\nā Dry run simulation complete. Zero disk modifications made.`);
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
console.log(`\nā Successfully generated bundle: ${path.relative(process.cwd(), result.outputPath)}`);
|
|
545
|
+
}
|
|
546
|
+
process.exit(0);
|
|
547
|
+
}
|
|
548
|
+
// Normal non-dryRun, non-diff output
|
|
549
|
+
console.log(`š¦${topicHeader} Packaging bundle using ${path.relative(process.cwd(), configPath)}...`);
|
|
550
|
+
console.log(`\nā Successfully generated bundle: ${path.relative(process.cwd(), result.outputPath)}`);
|
|
551
|
+
console.log(` - Files bundled: ${result.filesCount}`);
|
|
552
|
+
if (result.phase) {
|
|
553
|
+
console.log(` - Work Phase: ${result.phase}`);
|
|
554
|
+
}
|
|
555
|
+
if (result.author) {
|
|
556
|
+
console.log(` - Initial Author:${result.author}`);
|
|
557
|
+
}
|
|
558
|
+
if (result.eliminatedFiles && result.eliminatedFiles.length > 0) {
|
|
559
|
+
console.log(` - Tree-shaken: ${result.eliminatedFiles.length} unreferenced files eliminated`);
|
|
560
|
+
}
|
|
561
|
+
if (result.boundaryTerminals && result.boundaryTerminals.length > 0) {
|
|
562
|
+
console.log(` - Boundary Halt: ${result.boundaryTerminals.length} terminal reference(s) halted traversal`);
|
|
563
|
+
}
|
|
564
|
+
if (result.direction) {
|
|
565
|
+
console.log(` - Direction: ${result.direction}`);
|
|
566
|
+
}
|
|
567
|
+
if (result.categoryBreakdown) {
|
|
568
|
+
const catEntries = Object.entries(result.categoryBreakdown)
|
|
569
|
+
.map(([cat, count]) => `${cat}: ${count}`)
|
|
570
|
+
.join(", ");
|
|
571
|
+
console.log(` - Categories: ${catEntries}`);
|
|
572
|
+
}
|
|
573
|
+
if (result.upstreamNodes && result.upstreamNodes.length > 0) {
|
|
574
|
+
console.log(` - Upstream Nodes:${result.upstreamNodes.length} caller document(s) included`);
|
|
575
|
+
}
|
|
576
|
+
console.log(` - Total size: ${result.totalSizeBytes} bytes`);
|
|
577
|
+
console.log(` - SHA-256 BOM: ${result.aggregateHash.slice(0, 16)}...`);
|
|
578
|
+
const warnings = result.diagnostics.filter((d) => d.severity === "warning");
|
|
579
|
+
const errors = result.diagnostics.filter((d) => d.severity === "error");
|
|
580
|
+
if (warnings.length > 0) {
|
|
581
|
+
console.warn(`\nā ļø [Link Warnings] (${warnings.length} issues):`);
|
|
582
|
+
for (const w of warnings) {
|
|
583
|
+
const colStr = w.column ? `:${w.column}` : "";
|
|
584
|
+
console.warn(` - ${w.file}:${w.line}${colStr}: ${w.message}`);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (errors.length > 0) {
|
|
588
|
+
console.error(`\nā [Dead Link Errors] (${errors.length} issues):`);
|
|
589
|
+
for (const e of errors) {
|
|
590
|
+
const colStr = e.column ? `:${e.column}` : "";
|
|
591
|
+
console.error(` - ${e.file}:${e.line}${colStr}: ${e.message}`);
|
|
592
|
+
}
|
|
593
|
+
process.exit(1);
|
|
594
|
+
}
|
|
595
|
+
process.exit(0);
|
|
596
|
+
}
|
|
597
|
+
catch (err) {
|
|
598
|
+
console.error(`\nā Packaging failed: ${err.message}`);
|
|
599
|
+
process.exit(1);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (command === "check") {
|
|
603
|
+
const configPath = findConfigFile(customConfig);
|
|
604
|
+
let rawManifest;
|
|
605
|
+
try {
|
|
606
|
+
rawManifest = loadManifest(configPath);
|
|
607
|
+
}
|
|
608
|
+
catch (err) {
|
|
609
|
+
console.error(`\nā [CI Gate Failed] ${err.message}`);
|
|
610
|
+
process.exit(1);
|
|
611
|
+
}
|
|
612
|
+
const manifest = topic ? resolveTopicManifest(rawManifest, topic) : rawManifest;
|
|
613
|
+
const baseDir = path.dirname(configPath);
|
|
614
|
+
const effectiveLockfileMode = rawManifest.lockfileMode;
|
|
615
|
+
const lockfilePath = getLockfilePath(configPath, topic, effectiveLockfileMode);
|
|
616
|
+
const topicLabel = topic ? ` for topic '${topic}'` : "";
|
|
617
|
+
const freshness = checkFreshness(manifest, baseDir, lockfilePath, {
|
|
618
|
+
topic,
|
|
619
|
+
diff,
|
|
620
|
+
lockfileMode: effectiveLockfileMode,
|
|
621
|
+
});
|
|
622
|
+
if (json) {
|
|
623
|
+
console.log(JSON.stringify(freshness, null, 2));
|
|
624
|
+
process.exit(freshness.isFresh ? 0 : 1);
|
|
625
|
+
}
|
|
626
|
+
if (freshness.isFresh) {
|
|
627
|
+
console.log(`ā [CI Gate Pass] Bundle and lockfile${topicLabel} are synchronized. (Hash: ${freshness.currentAggregateHash.slice(0, 12)}...)`);
|
|
628
|
+
process.exit(0);
|
|
629
|
+
}
|
|
630
|
+
console.error(`\nā [CI Gate Failed] Bundle drift detected${topicLabel}! Upstream sources have changed:`);
|
|
631
|
+
if (freshness.added.length > 0) {
|
|
632
|
+
console.error(` - Added files (${freshness.added.length}): ${freshness.added.slice(0, 5).join(", ")}${freshness.added.length > 5 ? "..." : ""}`);
|
|
633
|
+
}
|
|
634
|
+
if (freshness.removed.length > 0) {
|
|
635
|
+
console.error(` - Removed files (${freshness.removed.length}): ${freshness.removed.slice(0, 5).join(", ")}${freshness.removed.length > 5 ? "..." : ""}`);
|
|
636
|
+
}
|
|
637
|
+
if (freshness.modified.length > 0) {
|
|
638
|
+
console.error(` - Modified files (${freshness.modified.length}): ${freshness.modified.slice(0, 5).join(", ")}${freshness.modified.length > 5 ? "..." : ""}`);
|
|
639
|
+
}
|
|
640
|
+
if (diff && freshness.semanticDiff) {
|
|
641
|
+
const sDiff = freshness.semanticDiff;
|
|
642
|
+
if (sDiff.modifiedFiles.length > 0) {
|
|
643
|
+
console.error(`\nš Semantic Structural Drift Details:`);
|
|
644
|
+
for (const m of sDiff.modifiedFiles) {
|
|
645
|
+
console.error(` š ${m.file} [${m.type}]:`);
|
|
646
|
+
if (m.addedAnchors && m.addedAnchors.length > 0) {
|
|
647
|
+
console.error(` + Added anchors (${m.addedAnchors.length}): ${m.addedAnchors.join(", ")}`);
|
|
648
|
+
}
|
|
649
|
+
if (m.removedAnchors && m.removedAnchors.length > 0) {
|
|
650
|
+
console.error(` - Removed anchors (${m.removedAnchors.length}): ${m.removedAnchors.join(", ")}`);
|
|
651
|
+
}
|
|
652
|
+
if (m.addedSymbols && m.addedSymbols.length > 0) {
|
|
653
|
+
console.error(` + Added symbols (${m.addedSymbols.length}): ${m.addedSymbols.join(", ")}`);
|
|
654
|
+
}
|
|
655
|
+
if (m.removedSymbols && m.removedSymbols.length > 0) {
|
|
656
|
+
console.error(` - Removed symbols (${m.removedSymbols.length}): ${m.removedSymbols.join(", ")}`);
|
|
657
|
+
}
|
|
658
|
+
if (m.lineDelta !== undefined && m.lineDelta !== 0) {
|
|
659
|
+
const sign = m.lineDelta > 0 ? "+" : "";
|
|
660
|
+
console.error(` ~ Line delta: ${sign}${m.lineDelta} lines`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
const topicArg = topic ? ` --topic ${topic}` : "";
|
|
666
|
+
console.error(`\nš” To synchronize the bundle and lockfile, run:`);
|
|
667
|
+
console.error(` spec-bundler pack --config ${path.relative(process.cwd(), configPath)}${topicArg}`);
|
|
668
|
+
if (process.env.GITHUB_ACTIONS) {
|
|
669
|
+
console.error(`::error file=${configPath}::Bundle drift detected. Run 'spec-bundler pack' to synchronize.`);
|
|
670
|
+
}
|
|
671
|
+
process.exit(1);
|
|
672
|
+
}
|
|
673
|
+
if (command === "verify") {
|
|
674
|
+
const configPath = findConfigFile(customConfig);
|
|
675
|
+
const { freshness, deadLinks, warnings } = verifyBundle(configPath, { checkAnchors, topic });
|
|
676
|
+
const topicSuffix = topic ? ` (Topic: ${topic})` : "";
|
|
677
|
+
console.log(`\nš Verifying ${path.relative(process.cwd(), configPath)}${topicSuffix}:`);
|
|
678
|
+
console.log(` - Freshness status: ${freshness.isFresh ? "ā Synchronized" : "ā ļø Drift detected"}`);
|
|
679
|
+
if (warnings.length > 0) {
|
|
680
|
+
console.warn(` - Collision / Resolver Warnings (${warnings.length}):`);
|
|
681
|
+
for (const w of warnings)
|
|
682
|
+
console.warn(` * ${w}`);
|
|
683
|
+
}
|
|
684
|
+
const deadLinkErrors = deadLinks.filter((d) => d.severity === "error");
|
|
685
|
+
const deadLinkWarnings = deadLinks.filter((d) => d.severity === "warning");
|
|
686
|
+
if (deadLinkWarnings.length > 0) {
|
|
687
|
+
console.warn(` ā ļø Unbundled / Non-fatal Link Warnings (${deadLinkWarnings.length}):`);
|
|
688
|
+
for (const w of deadLinkWarnings) {
|
|
689
|
+
console.warn(` * ${w.file}:${w.line}: ${w.message}`);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
if (deadLinkErrors.length > 0) {
|
|
693
|
+
console.error(` - Dead links inside bundle (${deadLinkErrors.length}):`);
|
|
694
|
+
for (const d of deadLinkErrors) {
|
|
695
|
+
console.error(` * ${d.file}:${d.line}: ${d.message}`);
|
|
696
|
+
}
|
|
697
|
+
process.exit(1);
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
console.log(` - Dead links inside bundle: 0 (All internal references valid)`);
|
|
701
|
+
}
|
|
702
|
+
process.exit(0);
|
|
703
|
+
}
|
|
704
|
+
if (command === "unpack") {
|
|
705
|
+
const archivePath = args[1];
|
|
706
|
+
if (!archivePath || archivePath.startsWith("-")) {
|
|
707
|
+
console.error("Usage: spec-bundler unpack <archive.zip> [--dest <dir>]");
|
|
708
|
+
process.exit(1);
|
|
709
|
+
}
|
|
710
|
+
const targetDest = destDir ?? process.cwd();
|
|
711
|
+
console.log(`š Unpacking ${archivePath} into ${targetDest}...`);
|
|
712
|
+
const { extractedCount, files } = unpackBundle(archivePath, targetDest);
|
|
713
|
+
console.log(`ā Extracted ${extractedCount} files successfully.`);
|
|
714
|
+
process.exit(0);
|
|
715
|
+
}
|
|
716
|
+
if (command === "resolve") {
|
|
717
|
+
const archiveArg = args[1];
|
|
718
|
+
const refArg = args[2];
|
|
719
|
+
if (!archiveArg || !refArg || archiveArg.startsWith("-")) {
|
|
720
|
+
console.error("Usage: spec-bundler resolve <archive.zip> <path-or-reference> [--json]");
|
|
721
|
+
process.exit(1);
|
|
722
|
+
}
|
|
723
|
+
const isJson = json || args.includes("--json");
|
|
724
|
+
try {
|
|
725
|
+
const resolution = resolveBundlePath(archiveArg, refArg);
|
|
726
|
+
if (isJson) {
|
|
727
|
+
console.log(JSON.stringify(resolution, null, 2));
|
|
728
|
+
process.exit(resolution.existsInBundle ? 0 : 1);
|
|
729
|
+
}
|
|
730
|
+
if (resolution.existsInBundle) {
|
|
731
|
+
console.log(`ā Resolved '${refArg}' inside bundle archive:`);
|
|
732
|
+
console.log(` - Bundle Path: ${resolution.bundlePath}`);
|
|
733
|
+
console.log(` - Full Reference: ${resolution.fullReference}`);
|
|
734
|
+
if (resolution.anchor) {
|
|
735
|
+
console.log(` - Target Anchor: ${resolution.anchor}`);
|
|
736
|
+
}
|
|
737
|
+
process.exit(0);
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
console.error(`ā Reference '${refArg}' could not be resolved inside bundle archive.`);
|
|
741
|
+
if (resolution.suggestedTarget) {
|
|
742
|
+
console.error(` š” Did you mean '${resolution.suggestedTarget}'?`);
|
|
743
|
+
}
|
|
744
|
+
process.exit(1);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
catch (err) {
|
|
748
|
+
console.error(`ā Resolution error: ${err.message}`);
|
|
749
|
+
process.exit(1);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
console.error(`Unknown command: ${command}`);
|
|
753
|
+
printUsage();
|
|
754
|
+
process.exit(1);
|
|
755
|
+
}
|
|
756
|
+
main().catch((err) => {
|
|
757
|
+
console.error(err);
|
|
758
|
+
process.exit(1);
|
|
759
|
+
});
|
|
760
|
+
//# sourceMappingURL=cli.js.map
|