@shrkcrft/cli 0.1.0-alpha.22 → 0.1.0-alpha.24
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/command-registry.d.ts +9 -0
- package/dist/command-registry.d.ts.map +1 -1
- package/dist/command-registry.js +15 -0
- package/dist/commands/ai-status.command.d.ts.map +1 -1
- package/dist/commands/ai-status.command.js +10 -0
- package/dist/commands/apply.command.d.ts.map +1 -1
- package/dist/commands/apply.command.js +9 -2
- package/dist/commands/ask.command.d.ts.map +1 -1
- package/dist/commands/ask.command.js +2 -1
- package/dist/commands/changes.command.d.ts.map +1 -1
- package/dist/commands/changes.command.js +14 -4
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +139 -7
- package/dist/commands/command-catalog.d.ts +11 -0
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +291 -0
- package/dist/commands/commands.command.d.ts +15 -0
- package/dist/commands/commands.command.d.ts.map +1 -1
- package/dist/commands/commands.command.js +162 -3
- package/dist/commands/compress.command.d.ts.map +1 -1
- package/dist/commands/compress.command.js +39 -4
- package/dist/commands/context.command.d.ts.map +1 -1
- package/dist/commands/context.command.js +3 -1
- package/dist/commands/daily.commands.d.ts.map +1 -1
- package/dist/commands/daily.commands.js +48 -5
- package/dist/commands/diff-check.command.d.ts.map +1 -1
- package/dist/commands/diff-check.command.js +6 -2
- package/dist/commands/feedback.command.d.ts.map +1 -1
- package/dist/commands/feedback.command.js +4 -0
- package/dist/commands/finish.command.d.ts +3 -0
- package/dist/commands/finish.command.d.ts.map +1 -0
- package/dist/commands/finish.command.js +70 -0
- package/dist/commands/framework.command.d.ts.map +1 -1
- package/dist/commands/framework.command.js +20 -3
- package/dist/commands/gate.command.d.ts.map +1 -1
- package/dist/commands/gate.command.js +98 -13
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
- package/dist/commands/graph-code-subverbs.js +215 -81
- package/dist/commands/graph.command.d.ts.map +1 -1
- package/dist/commands/graph.command.js +6 -0
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +20 -2
- package/dist/commands/impact.command.d.ts.map +1 -1
- package/dist/commands/impact.command.js +86 -1
- package/dist/commands/knowledge.command.d.ts.map +1 -1
- package/dist/commands/knowledge.command.js +21 -1
- package/dist/commands/onboard.command.d.ts.map +1 -1
- package/dist/commands/onboard.command.js +11 -2
- package/dist/commands/orchestrate.command.d.ts.map +1 -1
- package/dist/commands/orchestrate.command.js +6 -1
- package/dist/commands/pack-author.command.d.ts.map +1 -1
- package/dist/commands/pack-author.command.js +13 -1
- package/dist/commands/packs.command.d.ts.map +1 -1
- package/dist/commands/packs.command.js +95 -17
- package/dist/commands/paths.command.d.ts.map +1 -1
- package/dist/commands/paths.command.js +8 -1
- package/dist/commands/pipelines.command.d.ts.map +1 -1
- package/dist/commands/pipelines.command.js +2 -1
- package/dist/commands/plan-context.command.d.ts.map +1 -1
- package/dist/commands/plan-context.command.js +6 -3
- package/dist/commands/plan-simulate.command.js +1 -1
- package/dist/commands/policy-lint.command.d.ts.map +1 -1
- package/dist/commands/policy-lint.command.js +20 -7
- package/dist/commands/recommend.command.d.ts.map +1 -1
- package/dist/commands/recommend.command.js +10 -2
- package/dist/commands/registry.command.d.ts.map +1 -1
- package/dist/commands/registry.command.js +117 -9
- package/dist/commands/report.command.js +1 -1
- package/dist/commands/reuse.command.d.ts.map +1 -1
- package/dist/commands/reuse.command.js +17 -5
- package/dist/commands/review.command.d.ts.map +1 -1
- package/dist/commands/review.command.js +20 -2
- package/dist/commands/rule-graph-subverbs.d.ts.map +1 -1
- package/dist/commands/rule-graph-subverbs.js +31 -4
- package/dist/commands/search-structural.command.d.ts.map +1 -1
- package/dist/commands/search-structural.command.js +2 -2
- package/dist/commands/search.command.d.ts.map +1 -1
- package/dist/commands/search.command.js +19 -1
- package/dist/commands/simulate.command.d.ts.map +1 -1
- package/dist/commands/simulate.command.js +6 -1
- package/dist/commands/smart-context.command.d.ts.map +1 -1
- package/dist/commands/smart-context.command.js +101 -41
- package/dist/commands/spec.command.d.ts.map +1 -1
- package/dist/commands/spec.command.js +73 -13
- package/dist/commands/task-context.command.d.ts.map +1 -1
- package/dist/commands/task-context.command.js +26 -2
- package/dist/commands/test.command.d.ts.map +1 -1
- package/dist/commands/test.command.js +17 -0
- package/dist/commands/trace.command.d.ts.map +1 -1
- package/dist/commands/trace.command.js +87 -4
- package/dist/commands/wiring.command.d.ts +12 -0
- package/dist/commands/wiring.command.d.ts.map +1 -0
- package/dist/commands/wiring.command.js +384 -0
- package/dist/diff/collect-changed-paths.d.ts +5 -3
- package/dist/diff/collect-changed-paths.d.ts.map +1 -1
- package/dist/diff/collect-changed-paths.js +73 -36
- package/dist/diff/deleted-orphans.d.ts +42 -0
- package/dist/diff/deleted-orphans.d.ts.map +1 -0
- package/dist/diff/deleted-orphans.js +46 -0
- package/dist/finish/run-finish.d.ts +62 -0
- package/dist/finish/run-finish.d.ts.map +1 -0
- package/dist/finish/run-finish.js +239 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +19 -1
- package/dist/status/freshness.d.ts +30 -0
- package/dist/status/freshness.d.ts.map +1 -0
- package/dist/status/freshness.js +81 -0
- package/package.json +33 -33
|
@@ -390,6 +390,14 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
390
390
|
surface: CommandSurface.Common,
|
|
391
391
|
taskRole: CommandTaskRole.Validate,
|
|
392
392
|
}),
|
|
393
|
+
entry({
|
|
394
|
+
command: 'check orphans',
|
|
395
|
+
description: 'Write-safety guard: after deleting file(s)/export(s), finds surviving files that still import them or reference a symbol they declared — alias-resolved, incl. barrel re-exports the type checker misses. Reverse-closure over the diff vs --since (or --staged) against the code-graph snapshot; each survivor reported with file:line. [--since <ref>] [--staged] [--json]',
|
|
396
|
+
category: 'core',
|
|
397
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
398
|
+
surface: CommandSurface.Common,
|
|
399
|
+
taskRole: CommandTaskRole.Validate,
|
|
400
|
+
}),
|
|
393
401
|
entry({
|
|
394
402
|
command: 'policy-lint',
|
|
395
403
|
description: 'Lint template/markup, stylesheet, and AOT-invisible TS surfaces against config-defined policyRules[] — sees `.html` files AND inline `template:` strings that tsc/AOT cannot. Deterministic; no AI. [--surface template|style|ts] [--changed-only] [--only <ids>] [--json]',
|
|
@@ -398,6 +406,46 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
398
406
|
surface: CommandSurface.Common,
|
|
399
407
|
taskRole: CommandTaskRole.Validate,
|
|
400
408
|
}),
|
|
409
|
+
entry({
|
|
410
|
+
command: 'wiring explain',
|
|
411
|
+
description: 'Dry-run ONE configured wiringRule and print the declared set + registered set it extracts (token + file:line), the alias-resolved set-difference, and the verdict — the author-loop view of what `check wiring` sees, without re-running the gate. [--json]',
|
|
412
|
+
category: 'core',
|
|
413
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
414
|
+
surface: CommandSurface.Advanced,
|
|
415
|
+
taskRole: CommandTaskRole.Explain,
|
|
416
|
+
}),
|
|
417
|
+
entry({
|
|
418
|
+
command: 'wiring test',
|
|
419
|
+
description: 'Dry-run an EPHEMERAL candidate wiring rule (a .json file or inline JSON) against the live tree — see the declared/registered sets + diff it would produce before committing it to sharkcraft.config.ts. Never writes config. [--json]',
|
|
420
|
+
category: 'core',
|
|
421
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
422
|
+
surface: CommandSurface.Advanced,
|
|
423
|
+
taskRole: CommandTaskRole.Explain,
|
|
424
|
+
}),
|
|
425
|
+
entry({
|
|
426
|
+
command: 'wiring chain',
|
|
427
|
+
description: 'Registration/DI graph query: the declared → provided → consumed chain of a token across files/layers, alias-resolved, with file:line at each hop + a verdict (wired / unprovided / orphan). Models runtime wiring imports can\'t see. Idioms from sharkcraft.config.ts registrationGraph[]. [--json]',
|
|
428
|
+
category: 'analysis',
|
|
429
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
430
|
+
surface: CommandSurface.Advanced,
|
|
431
|
+
taskRole: CommandTaskRole.Inspect,
|
|
432
|
+
}),
|
|
433
|
+
entry({
|
|
434
|
+
command: 'wiring unprovided',
|
|
435
|
+
description: 'Registration/DI graph query: tokens DECLARED or INJECTED but never PROVIDED — the silent-at-runtime class (typecheck/AOT-green, resolves to undefined at runtime). The write-safety check imports/grep structurally can\'t do. [--json]',
|
|
436
|
+
category: 'analysis',
|
|
437
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
438
|
+
surface: CommandSurface.Advanced,
|
|
439
|
+
taskRole: CommandTaskRole.Validate,
|
|
440
|
+
}),
|
|
441
|
+
entry({
|
|
442
|
+
command: 'wiring orphans',
|
|
443
|
+
description: 'Registration/DI graph query: tokens PROVIDED/registered that nothing CONSUMES — a build-clean dead registration (or a sign the consumer was renamed/removed). [--json]',
|
|
444
|
+
category: 'analysis',
|
|
445
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
446
|
+
surface: CommandSurface.Advanced,
|
|
447
|
+
taskRole: CommandTaskRole.Inspect,
|
|
448
|
+
}),
|
|
401
449
|
entry({
|
|
402
450
|
command: 'reuse',
|
|
403
451
|
description: 'Intent → the canonical primitive to reuse: matches your intent against config reusePrimitives[] then resolves the symbol through the code graph (transitive star-barrels) to its import path, sibling exports, and real consumer files to copy. Read-only; no AI.',
|
|
@@ -415,6 +463,14 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
415
463
|
surface: CommandSurface.Common,
|
|
416
464
|
taskRole: CommandTaskRole.Validate,
|
|
417
465
|
}),
|
|
466
|
+
entry({
|
|
467
|
+
command: 'finish',
|
|
468
|
+
description: 'Composite "is this changeset safe to finish?" gate: EXECUTES boundaries + import-hygiene + wiring + policy + deleted-orphans changed-only inline, plus an impact summary, and returns ONE pass/fail. The trustworthy "done?" call after editing — superset of diff-check; honors 0-rules→skipped. Read-only. [files… | --staged | --since <ref>] [--json]',
|
|
469
|
+
category: 'core',
|
|
470
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
471
|
+
surface: CommandSurface.Common,
|
|
472
|
+
taskRole: CommandTaskRole.Validate,
|
|
473
|
+
}),
|
|
418
474
|
entry({
|
|
419
475
|
command: 'review',
|
|
420
476
|
description: 'PR-review packet — changed files, affected rules, missing tests heuristic.',
|
|
@@ -1658,6 +1714,14 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
1658
1714
|
safetyLevel: SafetyLevel.ReadOnly,
|
|
1659
1715
|
mcpAvailable: true,
|
|
1660
1716
|
}),
|
|
1717
|
+
entry({
|
|
1718
|
+
command: 'trace literal',
|
|
1719
|
+
description: 'Trace an EXACT string literal across the codebase, classified by direction: declare → register → consume sites of a cross-fence contract (kind slug, permission id, route key) the type system can\'t link and grep can\'t classify. Resolves `const X = "lit"` aliases. Generalizes `registry … where` to any literal — no pre-declared registry. [--glob <g>] [--no-aliases] [--limit N] [--json]',
|
|
1720
|
+
category: 'analysis',
|
|
1721
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
1722
|
+
surface: CommandSurface.Advanced,
|
|
1723
|
+
taskRole: CommandTaskRole.Inspect,
|
|
1724
|
+
}),
|
|
1661
1725
|
entry({
|
|
1662
1726
|
command: 'feedback',
|
|
1663
1727
|
description: 'Feedback ingestion (ingest|summarize|actions|convert-to-backlog). Read-only.',
|
|
@@ -3206,6 +3270,206 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
3206
3270
|
intendedAudience: [CommandAudience.Human, CommandAudience.Maintainer],
|
|
3207
3271
|
taskRole: CommandTaskRole.Inspect,
|
|
3208
3272
|
}),
|
|
3273
|
+
// ── D3-2: registered command groups that resolved live but had ZERO
|
|
3274
|
+
// catalog entries, so `shrk commands doctor` was blind to them and
|
|
3275
|
+
// `shrk help <group>` had no metadata. One canonical row per registered
|
|
3276
|
+
// sub-verb. Everything is ReadOnly except `checks run --execute`
|
|
3277
|
+
// (RunsShell) and `audit project-coupling` (RunsShell, advanced).
|
|
3278
|
+
// `mcpAvailable` mirrors a real read-only MCP tool where one exists.
|
|
3279
|
+
//
|
|
3280
|
+
// paths — path-convention registry
|
|
3281
|
+
// (MCP: list_path_conventions / get_path_convention / search_path_conventions).
|
|
3282
|
+
entry({
|
|
3283
|
+
command: 'paths list',
|
|
3284
|
+
description: 'List path conventions.',
|
|
3285
|
+
category: 'paths',
|
|
3286
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3287
|
+
mcpAvailable: true,
|
|
3288
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3289
|
+
}),
|
|
3290
|
+
entry({
|
|
3291
|
+
command: 'paths get',
|
|
3292
|
+
description: 'Get one path convention by id.',
|
|
3293
|
+
category: 'paths',
|
|
3294
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3295
|
+
mcpAvailable: true,
|
|
3296
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3297
|
+
}),
|
|
3298
|
+
entry({
|
|
3299
|
+
command: 'paths search',
|
|
3300
|
+
description: 'Search path conventions by scope / query.',
|
|
3301
|
+
category: 'paths',
|
|
3302
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3303
|
+
mcpAvailable: true,
|
|
3304
|
+
taskRole: CommandTaskRole.Search,
|
|
3305
|
+
}),
|
|
3306
|
+
entry({
|
|
3307
|
+
command: 'paths best',
|
|
3308
|
+
description: 'Pick the best path convention for a task.',
|
|
3309
|
+
category: 'paths',
|
|
3310
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3311
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3312
|
+
}),
|
|
3313
|
+
// pipelines — pipeline registry
|
|
3314
|
+
// (MCP: list_pipelines / get_pipeline / get_pipeline_context / create_pipeline_plan).
|
|
3315
|
+
entry({
|
|
3316
|
+
command: 'pipelines list',
|
|
3317
|
+
description: 'List available pipelines.',
|
|
3318
|
+
category: 'pipelines',
|
|
3319
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3320
|
+
mcpAvailable: true,
|
|
3321
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3322
|
+
}),
|
|
3323
|
+
entry({
|
|
3324
|
+
command: 'pipelines get',
|
|
3325
|
+
description: 'Show one pipeline by id.',
|
|
3326
|
+
category: 'pipelines',
|
|
3327
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3328
|
+
mcpAvailable: true,
|
|
3329
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3330
|
+
}),
|
|
3331
|
+
entry({
|
|
3332
|
+
command: 'pipelines context',
|
|
3333
|
+
description: 'Token-budgeted context for a pipeline + task.',
|
|
3334
|
+
category: 'pipelines',
|
|
3335
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3336
|
+
mcpAvailable: true,
|
|
3337
|
+
taskRole: CommandTaskRole.Context,
|
|
3338
|
+
}),
|
|
3339
|
+
entry({
|
|
3340
|
+
command: 'pipelines plan',
|
|
3341
|
+
description: 'Render a pipeline as an ordered step plan for a task.',
|
|
3342
|
+
category: 'pipelines',
|
|
3343
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3344
|
+
mcpAvailable: true,
|
|
3345
|
+
taskRole: CommandTaskRole.Context,
|
|
3346
|
+
}),
|
|
3347
|
+
entry({
|
|
3348
|
+
command: 'pipelines script',
|
|
3349
|
+
description: 'Render a pipeline as a runnable bash-style preview script (no execution).',
|
|
3350
|
+
category: 'pipelines',
|
|
3351
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3352
|
+
taskRole: CommandTaskRole.Context,
|
|
3353
|
+
}),
|
|
3354
|
+
entry({
|
|
3355
|
+
command: 'pipelines next',
|
|
3356
|
+
description: 'Show the next recommended step in a pipeline for a task.',
|
|
3357
|
+
category: 'pipelines',
|
|
3358
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3359
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3360
|
+
}),
|
|
3361
|
+
entry({
|
|
3362
|
+
command: 'pipelines vars',
|
|
3363
|
+
description: 'List the variables a pipeline consumes.',
|
|
3364
|
+
category: 'pipelines',
|
|
3365
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3366
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3367
|
+
}),
|
|
3368
|
+
// checks — custom-check registry declared by rules (metadata.checks[]).
|
|
3369
|
+
entry({
|
|
3370
|
+
command: 'checks list',
|
|
3371
|
+
description: 'List custom checks declared by rules (metadata.checks[]). Read-only.',
|
|
3372
|
+
category: 'checks',
|
|
3373
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3374
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3375
|
+
}),
|
|
3376
|
+
entry({
|
|
3377
|
+
command: 'checks doctor',
|
|
3378
|
+
description: 'Validate custom-check descriptors (missing fields, duplicate ids).',
|
|
3379
|
+
category: 'checks',
|
|
3380
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3381
|
+
taskRole: CommandTaskRole.Diagnose,
|
|
3382
|
+
}),
|
|
3383
|
+
entry({
|
|
3384
|
+
command: 'checks run',
|
|
3385
|
+
description: 'Preview a custom check. Read-only by default — pass --execute to run it.',
|
|
3386
|
+
category: 'checks',
|
|
3387
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3388
|
+
taskRole: CommandTaskRole.Validate,
|
|
3389
|
+
}),
|
|
3390
|
+
entry({
|
|
3391
|
+
command: 'checks run --execute',
|
|
3392
|
+
description: 'Actually invoke the custom check command (runs the configured shell command).',
|
|
3393
|
+
category: 'checks',
|
|
3394
|
+
safetyLevel: SafetyLevel.RunsShell,
|
|
3395
|
+
runsShell: true,
|
|
3396
|
+
requiresReview: true,
|
|
3397
|
+
taskRole: CommandTaskRole.Validate,
|
|
3398
|
+
}),
|
|
3399
|
+
entry({
|
|
3400
|
+
command: 'checks parse-report',
|
|
3401
|
+
description: 'Parse a check report file into the canonical finding shape. Read-only.',
|
|
3402
|
+
category: 'checks',
|
|
3403
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3404
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3405
|
+
}),
|
|
3406
|
+
entry({
|
|
3407
|
+
command: 'checks import',
|
|
3408
|
+
description: 'Import an external tool report into the universal check-result protocol. Read-only.',
|
|
3409
|
+
category: 'checks',
|
|
3410
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3411
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3412
|
+
}),
|
|
3413
|
+
entry({
|
|
3414
|
+
command: 'checks aggregate',
|
|
3415
|
+
description: 'Aggregate multiple check reports into one verdict. Read-only.',
|
|
3416
|
+
category: 'checks',
|
|
3417
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3418
|
+
taskRole: CommandTaskRole.Validate,
|
|
3419
|
+
}),
|
|
3420
|
+
entry({
|
|
3421
|
+
command: 'checks report',
|
|
3422
|
+
description: 'Render aggregated check results in the chosen format. Read-only.',
|
|
3423
|
+
category: 'checks',
|
|
3424
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3425
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3426
|
+
}),
|
|
3427
|
+
entry({
|
|
3428
|
+
command: 'checks convert',
|
|
3429
|
+
description: 'Convert a check report between supported formats. Read-only.',
|
|
3430
|
+
category: 'checks',
|
|
3431
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3432
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3433
|
+
}),
|
|
3434
|
+
// audit — project-specific coupling audit (MCP: get_project_coupling_report).
|
|
3435
|
+
// RunsShell/advanced per the brief: the report/plan modes materialise
|
|
3436
|
+
// artifacts and the audit is a heavyweight, opt-in surface.
|
|
3437
|
+
entry({
|
|
3438
|
+
command: 'audit project-coupling',
|
|
3439
|
+
description: 'Audit / plan / report project-specific coupling. Pass --token to scan for identifiers; the engine ships zero built-in tokens.',
|
|
3440
|
+
category: 'analysis',
|
|
3441
|
+
safetyLevel: SafetyLevel.RunsShell,
|
|
3442
|
+
runsShell: true,
|
|
3443
|
+
mcpAvailable: true,
|
|
3444
|
+
surface: CommandSurface.Advanced,
|
|
3445
|
+
intendedAudience: [CommandAudience.Human, CommandAudience.Agent],
|
|
3446
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3447
|
+
}),
|
|
3448
|
+
// ownership — CODEOWNERS / sharkcraft ownership registry
|
|
3449
|
+
// (MCP: get_ownership / match_owners).
|
|
3450
|
+
entry({
|
|
3451
|
+
command: 'ownership list',
|
|
3452
|
+
description: 'List ownership rules from CODEOWNERS / sharkcraft/ownership.ts.',
|
|
3453
|
+
category: 'ownership',
|
|
3454
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3455
|
+
mcpAvailable: true,
|
|
3456
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3457
|
+
}),
|
|
3458
|
+
entry({
|
|
3459
|
+
command: 'ownership for',
|
|
3460
|
+
description: 'Show the ownership match for a single file.',
|
|
3461
|
+
category: 'ownership',
|
|
3462
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3463
|
+
mcpAvailable: true,
|
|
3464
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3465
|
+
}),
|
|
3466
|
+
entry({
|
|
3467
|
+
command: 'ownership affected',
|
|
3468
|
+
description: 'Show owners affected by --since <ref>, --bundle <id>, or --files a,b.',
|
|
3469
|
+
category: 'ownership',
|
|
3470
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
3471
|
+
taskRole: CommandTaskRole.Inspect,
|
|
3472
|
+
}),
|
|
3209
3473
|
]);
|
|
3210
3474
|
/** Return every canonical command string in the catalog. */
|
|
3211
3475
|
export function listCatalogCommandStrings() {
|
|
@@ -3464,6 +3728,7 @@ const PRIMARY_VERBS_ALLOWLIST = new Set([
|
|
|
3464
3728
|
'gen',
|
|
3465
3729
|
'apply',
|
|
3466
3730
|
'check',
|
|
3731
|
+
'finish',
|
|
3467
3732
|
'quality',
|
|
3468
3733
|
'plan',
|
|
3469
3734
|
'fix',
|
|
@@ -3534,6 +3799,32 @@ export function defaultShowInHelp(e) {
|
|
|
3534
3799
|
const surface = commandSurface(e);
|
|
3535
3800
|
return surface === CommandSurface.Primary || surface === CommandSurface.Common;
|
|
3536
3801
|
}
|
|
3802
|
+
/**
|
|
3803
|
+
* The "explain / dry-run" command family: entries that show you what a gate,
|
|
3804
|
+
* ranker, or graph *sees* before you act (`search tuning explain`, `wiring
|
|
3805
|
+
* explain`/`wiring test`, `boundaries explain`, `surface explain`, …). Several
|
|
3806
|
+
* carry an Advanced surface, so {@link defaultShowInHelp} hides them despite
|
|
3807
|
+
* being high-value — which is exactly why an agent finds them only by guessing.
|
|
3808
|
+
* `shrk --full-help` lists this family in a dedicated section so they stop
|
|
3809
|
+
* being hidden. Returns callable entries only (retired/deprecated/alias and
|
|
3810
|
+
* R46-pruned are excluded), sorted by command.
|
|
3811
|
+
*/
|
|
3812
|
+
export function listExplainFamily() {
|
|
3813
|
+
return COMMAND_CATALOG.filter((e) => {
|
|
3814
|
+
const lc = commandLifecycle(e);
|
|
3815
|
+
if (lc === CommandLifecycle.Deprecated ||
|
|
3816
|
+
lc === CommandLifecycle.Retired ||
|
|
3817
|
+
lc === CommandLifecycle.Alias) {
|
|
3818
|
+
return false;
|
|
3819
|
+
}
|
|
3820
|
+
if (R46_OVERLAY[e.command])
|
|
3821
|
+
return false;
|
|
3822
|
+
const role = commandTaskRole(e);
|
|
3823
|
+
return role === CommandTaskRole.Explain || /(^|\s)explain$/.test(e.command);
|
|
3824
|
+
})
|
|
3825
|
+
.slice()
|
|
3826
|
+
.sort((a, b) => a.command.localeCompare(b.command));
|
|
3827
|
+
}
|
|
3537
3828
|
/**
|
|
3538
3829
|
* Short "Use this when…" line derived from `surface`, `taskRole`,
|
|
3539
3830
|
* `preferredCommand`, `replacedBy`, and `machineOnly`. Empty string when
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { type CommandRegistry, type ICommandHandler } from '../command-registry.js';
|
|
2
|
+
import { type ISurfaceProfile } from '../surface/profiles.js';
|
|
3
|
+
import { type ICommandCatalogEntry } from './command-catalog.js';
|
|
2
4
|
export declare function makeCommandsCommand(registry: CommandRegistry): ICommandHandler;
|
|
5
|
+
export interface ICommandsProfileView {
|
|
6
|
+
profile: ISurfaceProfile;
|
|
7
|
+
entries: readonly ICommandCatalogEntry[];
|
|
8
|
+
hidden: readonly string[];
|
|
9
|
+
catalogTotal: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Pure: render the catalog as a surface profile sees it. Every command the
|
|
13
|
+
* profile lists in `hidden` is filtered out of `entries` (commands stay
|
|
14
|
+
* callable — this is a listing filter, not a disable). Returns undefined when
|
|
15
|
+
* the profile id is unknown. Exported for tests.
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildCommandsProfileView(profileId: string, packProfiles?: readonly ISurfaceProfile[]): ICommandsProfileView | undefined;
|
|
3
18
|
export interface IRetirementPlanGroup {
|
|
4
19
|
reason: 'deprecated' | 'aliases' | 'machine-in-help' | 'overlapping' | 'missing-replacedBy' | 'legacy-no-removeAfter';
|
|
5
20
|
entries: readonly {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.command.d.ts","sourceRoot":"","sources":["../../src/commands/commands.command.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EAGpB,KAAK,eAAe,
|
|
1
|
+
{"version":3,"file":"commands.command.d.ts","sourceRoot":"","sources":["../../src/commands/commands.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { flagBool, flagString } from "../command-registry.js";
|
|
1
|
+
import { flagBool, flagString, resolveCwd } from "../command-registry.js";
|
|
2
2
|
import { asJson, header } from "../output/format-output.js";
|
|
3
|
+
import { BUILTIN_PROFILES, getProfile } from "../surface/profiles.js";
|
|
3
4
|
import { buildCommandSafetyMatrix, COMMAND_CATALOG, CommandLifecycle, commandLifecycle, CommandSurface, commandSurface, commandTaskRole, defaultShowInHelp, R46_OVERLAY, renderCommandSafetyMatrixMarkdown, SafetyLevel } from "./command-catalog.js";
|
|
4
5
|
import { buildCommandTaxonomy, buildPrimaryCommandsReport, renderCommandTaxonomyMarkdown, renderCommandTaxonomyText, renderPrimaryCommandsText } from '@shrkcrft/inspector';
|
|
5
6
|
export function makeCommandsCommand(registry) {
|
|
6
7
|
return {
|
|
7
8
|
name: 'commands',
|
|
8
|
-
description: 'Browse the command catalog. Default view is compact (primary + common); pass --all for the full catalog. Subcommands: primary | advanced | deprecated | hidden | retirement-plan | docs-check | surface | machine | legacy | overlaps | taxonomy | matrix | tree | search | suggest | explain | entrypoints | doctor | ux-check.',
|
|
9
|
-
usage: 'shrk commands [primary|advanced|deprecated|hidden|retirement-plan|docs-check|surface <s>|machine|legacy|overlaps|taxonomy|matrix|tree|search <q>|suggest <p>|explain <cmd>|entrypoints|doctor|ux-check] [--all] [--safety <level>] [--category <name>] [--json]',
|
|
9
|
+
description: 'Browse the command catalog. Default view is compact (primary + common); pass --all for the full catalog, or --profile <id> (e.g. agent) for the surface a profile sees. Subcommands: primary | advanced | deprecated | hidden | retirement-plan | docs-check | surface | profile | machine | legacy | overlaps | taxonomy | matrix | tree | search | suggest | explain | entrypoints | doctor | ux-check.',
|
|
10
|
+
usage: 'shrk commands [primary|advanced|deprecated|hidden|retirement-plan|docs-check|surface <s>|profile [<id>]|machine|legacy|overlaps|taxonomy|matrix|tree|search <q>|suggest <p>|explain <cmd>|entrypoints|doctor|ux-check] [--all] [--profile <id>] [--safety <level>] [--category <name>] [--json]',
|
|
10
11
|
async run(args) {
|
|
11
12
|
const sub = args.positional[0];
|
|
12
13
|
if (sub === 'doctor') {
|
|
@@ -95,6 +96,12 @@ export function makeCommandsCommand(registry) {
|
|
|
95
96
|
if (sub === 'surface') {
|
|
96
97
|
return runCommandsSurface(args);
|
|
97
98
|
}
|
|
99
|
+
// `shrk commands profile [<id>]` — list surface profiles, or render the
|
|
100
|
+
// catalog as one profile sees it (the curated view, e.g. `agent`).
|
|
101
|
+
if (sub === 'profile') {
|
|
102
|
+
const id = args.positional[1];
|
|
103
|
+
return id ? runCommandsProfile(args, id) : runCommandsProfileList(args);
|
|
104
|
+
}
|
|
98
105
|
if (sub === 'machine') {
|
|
99
106
|
return runCommandsMachine(args);
|
|
100
107
|
}
|
|
@@ -120,8 +127,34 @@ export function makeCommandsCommand(registry) {
|
|
|
120
127
|
if (sub === 'docs-check') {
|
|
121
128
|
return runCommandsDocsCheck(args);
|
|
122
129
|
}
|
|
130
|
+
// `--profile <id>` renders the catalog curated for a surface profile
|
|
131
|
+
// (e.g. `--profile agent` hides CI/release/pack-maintenance machinery an
|
|
132
|
+
// inline agent doesn't need). Commands stay callable; this is a listing
|
|
133
|
+
// filter, not a disable.
|
|
134
|
+
const profileFilter = flagString(args, 'profile');
|
|
135
|
+
if (profileFilter) {
|
|
136
|
+
return runCommandsProfile(args, profileFilter);
|
|
137
|
+
}
|
|
123
138
|
const safetyFilter = flagString(args, 'safety');
|
|
124
139
|
const categoryFilter = flagString(args, 'category');
|
|
140
|
+
// Validate the filter values against real allowlists — a typo (e.g.
|
|
141
|
+
// `--safety read` or `--category typo`) previously matched nothing and
|
|
142
|
+
// returned "commands (0)" with exit 0, which reads like an empty result
|
|
143
|
+
// rather than a mistake. Reject with the valid set + exit 2 instead.
|
|
144
|
+
if (safetyFilter !== undefined) {
|
|
145
|
+
const validSafety = new Set(Object.values(SafetyLevel));
|
|
146
|
+
if (!validSafety.has(safetyFilter)) {
|
|
147
|
+
process.stderr.write(`Unknown --safety "${safetyFilter}". Valid: ${[...validSafety].sort().join(', ')}\n`);
|
|
148
|
+
return 2;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (categoryFilter !== undefined) {
|
|
152
|
+
const validCategories = new Set(COMMAND_CATALOG.map((e) => e.category));
|
|
153
|
+
if (!validCategories.has(categoryFilter)) {
|
|
154
|
+
process.stderr.write(`Unknown --category "${categoryFilter}". Valid: ${[...validCategories].sort().join(', ')}\n`);
|
|
155
|
+
return 2;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
125
158
|
const wantsAll = flagBool(args, 'all');
|
|
126
159
|
let entries = COMMAND_CATALOG;
|
|
127
160
|
if (safetyFilter) {
|
|
@@ -186,6 +219,97 @@ function runCommandsSurface(args) {
|
|
|
186
219
|
}
|
|
187
220
|
return 0;
|
|
188
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Pure: render the catalog as a surface profile sees it. Every command the
|
|
224
|
+
* profile lists in `hidden` is filtered out of `entries` (commands stay
|
|
225
|
+
* callable — this is a listing filter, not a disable). Returns undefined when
|
|
226
|
+
* the profile id is unknown. Exported for tests.
|
|
227
|
+
*/
|
|
228
|
+
export function buildCommandsProfileView(profileId, packProfiles = []) {
|
|
229
|
+
const profile = getProfile(profileId, packProfiles);
|
|
230
|
+
if (!profile)
|
|
231
|
+
return undefined;
|
|
232
|
+
const hidden = new Set(profile.hidden ?? []);
|
|
233
|
+
const entries = COMMAND_CATALOG.filter((e) => !hidden.has(e.command));
|
|
234
|
+
return { profile, entries, hidden: [...hidden].sort(), catalogTotal: COMMAND_CATALOG.length };
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* `shrk commands --profile <id>` / `shrk commands profile <id>` renders the
|
|
238
|
+
* catalog curated for a surface profile (e.g. `agent` hides
|
|
239
|
+
* CI/release/pack-maintenance machinery an inline agent doesn't need) without
|
|
240
|
+
* editing `sharkcraft.config.ts`. Builtin profiles resolve instantly; an
|
|
241
|
+
* unknown id falls back to discovering pack-contributed profiles via the
|
|
242
|
+
* surface context (best-effort — needs a workspace).
|
|
243
|
+
*/
|
|
244
|
+
async function runCommandsProfile(args, profileId) {
|
|
245
|
+
let view = buildCommandsProfileView(profileId);
|
|
246
|
+
let validIds = BUILTIN_PROFILES.map((p) => p.id);
|
|
247
|
+
if (!view) {
|
|
248
|
+
try {
|
|
249
|
+
const { loadSurfaceContext } = await import("../surface/load-surface-context.js");
|
|
250
|
+
const ctx = await loadSurfaceContext({ cwd: resolveCwd(args) });
|
|
251
|
+
validIds = ctx.availableProfiles.map((p) => p.id);
|
|
252
|
+
view = buildCommandsProfileView(profileId, ctx.availableProfiles);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// Pack discovery failed (e.g. outside a project) — builtin-only.
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (!view) {
|
|
259
|
+
process.stderr.write(`Unknown profile "${profileId}". Valid: ${[...validIds].sort().join(', ')}\n`);
|
|
260
|
+
return 2;
|
|
261
|
+
}
|
|
262
|
+
const { profile, entries, hidden, catalogTotal } = view;
|
|
263
|
+
if (flagBool(args, 'json')) {
|
|
264
|
+
process.stdout.write(asJson({
|
|
265
|
+
profile: profile.id,
|
|
266
|
+
description: profile.description,
|
|
267
|
+
source: profile.source,
|
|
268
|
+
total: entries.length,
|
|
269
|
+
catalogTotal,
|
|
270
|
+
hiddenCount: hidden.length,
|
|
271
|
+
hidden,
|
|
272
|
+
entries,
|
|
273
|
+
}) + '\n');
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
process.stdout.write(header(`Commands — profile=${profile.id} (${entries.length} of ${catalogTotal} visible)`));
|
|
277
|
+
process.stdout.write(` ${profile.description}\n`);
|
|
278
|
+
if (hidden.length > 0) {
|
|
279
|
+
process.stdout.write(` (${hidden.length} command(s) hidden by this profile — still callable)\n`);
|
|
280
|
+
}
|
|
281
|
+
const grouped = new Map();
|
|
282
|
+
for (const e of entries) {
|
|
283
|
+
const arr = grouped.get(e.category) ?? [];
|
|
284
|
+
arr.push(e);
|
|
285
|
+
grouped.set(e.category, arr);
|
|
286
|
+
}
|
|
287
|
+
for (const [cat, items] of [...grouped.entries()].sort(([a], [b]) => a.localeCompare(b))) {
|
|
288
|
+
process.stdout.write(`\n## ${cat}\n`);
|
|
289
|
+
for (const e of items.sort((a, b) => a.command.localeCompare(b.command))) {
|
|
290
|
+
process.stdout.write(` ${safetyTag(e.safetyLevel)} ${e.command.padEnd(34)} ${e.description}\n`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
/** `shrk commands profile` (no id) lists the available surface profiles. */
|
|
296
|
+
function runCommandsProfileList(args) {
|
|
297
|
+
const rows = BUILTIN_PROFILES.map((p) => ({
|
|
298
|
+
id: p.id,
|
|
299
|
+
description: p.description,
|
|
300
|
+
hides: (p.hidden ?? []).length,
|
|
301
|
+
}));
|
|
302
|
+
if (flagBool(args, 'json')) {
|
|
303
|
+
process.stdout.write(asJson({ total: rows.length, profiles: rows }) + '\n');
|
|
304
|
+
return 0;
|
|
305
|
+
}
|
|
306
|
+
process.stdout.write(header(`Surface profiles (${rows.length})`));
|
|
307
|
+
for (const r of rows) {
|
|
308
|
+
process.stdout.write(` ${r.id.padEnd(12)} hides=${String(r.hides).padEnd(4)} ${r.description}\n`);
|
|
309
|
+
}
|
|
310
|
+
process.stdout.write(`\nUsage: shrk commands profile <id> | shrk commands --profile <id> (render the curated view)\n`);
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
189
313
|
/** `shrk commands machine` lists machine-oriented commands. */
|
|
190
314
|
function runCommandsMachine(args) {
|
|
191
315
|
const matches = COMMAND_CATALOG.filter((e) => commandSurface(e) === CommandSurface.Machine || e.machineOnly === true);
|
|
@@ -487,6 +611,10 @@ export const commandsCommand = {
|
|
|
487
611
|
// Keep the new views available even via the back-compat entry.
|
|
488
612
|
if (sub === 'surface')
|
|
489
613
|
return runCommandsSurface(args);
|
|
614
|
+
if (sub === 'profile') {
|
|
615
|
+
const id = args.positional[1];
|
|
616
|
+
return id ? runCommandsProfile(args, id) : runCommandsProfileList(args);
|
|
617
|
+
}
|
|
490
618
|
if (sub === 'machine')
|
|
491
619
|
return runCommandsMachine(args);
|
|
492
620
|
if (sub === 'legacy')
|
|
@@ -503,6 +631,10 @@ export const commandsCommand = {
|
|
|
503
631
|
return runCommandsRetirementPlan(args);
|
|
504
632
|
if (sub === 'docs-check')
|
|
505
633
|
return await runCommandsDocsCheck(args);
|
|
634
|
+
const profileFilter = flagString(args, 'profile');
|
|
635
|
+
if (profileFilter) {
|
|
636
|
+
return runCommandsProfile(args, profileFilter);
|
|
637
|
+
}
|
|
506
638
|
const safetyFilter = flagString(args, 'safety');
|
|
507
639
|
const categoryFilter = flagString(args, 'category');
|
|
508
640
|
let entries = COMMAND_CATALOG;
|
|
@@ -882,6 +1014,33 @@ export function buildCommandsDoctorReport(registry) {
|
|
|
882
1014
|
});
|
|
883
1015
|
}
|
|
884
1016
|
}
|
|
1017
|
+
// 8. registerSubcommand-only GROUPS without a catalog entry.
|
|
1018
|
+
// Check #7 above only sees depth-1 nodes that carry a handler
|
|
1019
|
+
// (registry.list()). Groups registered purely via registerSubcommand
|
|
1020
|
+
// (e.g. paths / pipelines / checks / audit / ownership) are handler-less
|
|
1021
|
+
// group nodes — they resolve live yet never appear in list(), so the
|
|
1022
|
+
// doctor reported "No issues" while those groups had zero catalog
|
|
1023
|
+
// coverage. Walk listGroups() and flag any group no catalog entry
|
|
1024
|
+
// covers. Pure alias groups (listGroupAliases) are skipped — their
|
|
1025
|
+
// canonical target carries the entry.
|
|
1026
|
+
const aliasGroups = new Set(registry.listGroupAliases().keys());
|
|
1027
|
+
const catalogTopWords = new Set();
|
|
1028
|
+
for (const e of COMMAND_CATALOG) {
|
|
1029
|
+
const top = e.command.split(/\s+/)[0];
|
|
1030
|
+
if (top)
|
|
1031
|
+
catalogTopWords.add(top);
|
|
1032
|
+
}
|
|
1033
|
+
for (const g of registry.listGroups()) {
|
|
1034
|
+
if (aliasGroups.has(g))
|
|
1035
|
+
continue;
|
|
1036
|
+
if (!catalogTopWords.has(g)) {
|
|
1037
|
+
issues.push({
|
|
1038
|
+
code: 'missing-catalog-entry',
|
|
1039
|
+
message: `command group "${g}" is registered (registerSubcommand) but no catalog entry covers it`,
|
|
1040
|
+
severity: 'error',
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
885
1044
|
}
|
|
886
1045
|
const errors = issues.filter((i) => i.severity === 'error').length;
|
|
887
1046
|
const warnings = issues.filter((i) => i.severity === 'warning').length;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.command.d.ts","sourceRoot":"","sources":["../../src/commands/compress.command.ts"],"names":[],"mappings":"AAQA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"compress.command.d.ts","sourceRoot":"","sources":["../../src/commands/compress.command.ts"],"names":[],"mappings":"AAQA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAqEhC,eAAO,MAAM,eAAe,EAAE,eAoG7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,eA4B3B,CAAC"}
|
|
@@ -5,6 +5,35 @@ import { flagBool, flagNumber, flagString, resolveCwd, } from "../command-regist
|
|
|
5
5
|
import { asJson } from "../output/format-output.js";
|
|
6
6
|
import { ccrDir, openCcrStore } from "../output/ccr-store-config.js";
|
|
7
7
|
const CONTENT_TYPES = new Set(Object.values(EContentType));
|
|
8
|
+
// `--type` accepts the EContentType wire strings plus ergonomic aliases. `code`
|
|
9
|
+
// is an alias for `source-code`: it routes to the structure-preserving code
|
|
10
|
+
// outline (ECompressionStrategy.Code), NOT the markdown line-omission a bare
|
|
11
|
+
// `code` used to silently fall through to under auto-detect.
|
|
12
|
+
const TYPE_ALIASES = {
|
|
13
|
+
code: EContentType.SourceCode,
|
|
14
|
+
};
|
|
15
|
+
// The full set of accepted `--type` tokens (content-type wire strings +
|
|
16
|
+
// aliases), sorted and rendered once so the rejection message and the
|
|
17
|
+
// passthrough hint advertise exactly what `resolveContentType` accepts.
|
|
18
|
+
const VALID_TYPE_TOKENS = [...CONTENT_TYPES, ...Object.keys(TYPE_ALIASES)].sort().join(', ');
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a raw `--type` value into a forced {@link EContentType}. Unlike the
|
|
21
|
+
* old `CONTENT_TYPES.has` check — which silently dropped unknown values and let
|
|
22
|
+
* the phantom `code` fall through to auto-detect (markdown line-omission) — an
|
|
23
|
+
* unrecognized non-empty value yields an `error` so the caller can reject with a
|
|
24
|
+
* non-zero exit, and `code` is mapped to the real source-code strategy. A
|
|
25
|
+
* missing/empty value is a no-op (auto-detect).
|
|
26
|
+
*/
|
|
27
|
+
function resolveContentType(raw) {
|
|
28
|
+
if (raw === undefined || raw === '')
|
|
29
|
+
return {};
|
|
30
|
+
const aliased = TYPE_ALIASES[raw];
|
|
31
|
+
if (aliased)
|
|
32
|
+
return { type: aliased };
|
|
33
|
+
if (CONTENT_TYPES.has(raw))
|
|
34
|
+
return { type: raw };
|
|
35
|
+
return { error: `compress: unknown --type "${raw}". Valid types: ${VALID_TYPE_TOKENS}.` };
|
|
36
|
+
}
|
|
8
37
|
// Below this size a passthrough no-op isn't worth a warning (tiny snippets
|
|
9
38
|
// legitimately have nothing to compress). Above it, a silent `−0%` re-emit is
|
|
10
39
|
// the opposite of the tool's purpose — nudge the user toward `--type`.
|
|
@@ -36,6 +65,13 @@ export const compressCommand = {
|
|
|
36
65
|
booleanFlags: COMPRESS_BOOLEAN_FLAGS,
|
|
37
66
|
run(args) {
|
|
38
67
|
const cwd = resolveCwd(args);
|
|
68
|
+
// Validate `--type` up front: an unknown value is a user error, not a
|
|
69
|
+
// silent fall-through to auto-detect — fail fast before reading input.
|
|
70
|
+
const resolvedType = resolveContentType(flagString(args, 'type'));
|
|
71
|
+
if (resolvedType.error) {
|
|
72
|
+
process.stderr.write(resolvedType.error + '\n');
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
39
75
|
let content;
|
|
40
76
|
try {
|
|
41
77
|
content = readInput(args);
|
|
@@ -59,9 +95,8 @@ export const compressCommand = {
|
|
|
59
95
|
opts.maxItems = Math.floor(max);
|
|
60
96
|
if (flagBool(args, 'lossless'))
|
|
61
97
|
opts.lossless = true;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
opts.contentType = type;
|
|
98
|
+
if (resolvedType.type)
|
|
99
|
+
opts.contentType = resolvedType.type;
|
|
65
100
|
const result = compressContent(content, opts);
|
|
66
101
|
const pct = Math.round(result.savings.ratio * 100);
|
|
67
102
|
// A lossy result with no cached original (i.e. --no-cache) can't be undone
|
|
@@ -109,7 +144,7 @@ export const compressCommand = {
|
|
|
109
144
|
inputBytes >= PASSTHROUGH_HINT_MIN_BYTES &&
|
|
110
145
|
!flagBool(args, 'lossless')) {
|
|
111
146
|
process.stderr.write(`hint: nothing was compressed — auto-detect classified this as ${result.contentType} and found no win. ` +
|
|
112
|
-
|
|
147
|
+
`Try \`--type <content-type>\` to force a strategy (${VALID_TYPE_TOKENS}).\n`);
|
|
113
148
|
}
|
|
114
149
|
return 0;
|
|
115
150
|
},
|