@shrkcrft/cli 0.1.0-alpha.6 → 0.1.0-alpha.8
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/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +19 -2
- package/dist/commands/command-catalog.d.ts +7 -3
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +112 -33
- package/dist/commands/commands.command.d.ts.map +1 -1
- package/dist/commands/commands.command.js +4 -4
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +5 -22
- package/dist/commands/diff-check.command.d.ts +30 -0
- package/dist/commands/diff-check.command.d.ts.map +1 -0
- package/dist/commands/diff-check.command.js +210 -0
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +41 -7
- package/dist/commands/export.command.d.ts.map +1 -1
- package/dist/commands/export.command.js +76 -3
- package/dist/commands/help.command.d.ts +4 -3
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +74 -16
- package/dist/commands/helper.command.js +1 -1
- package/dist/commands/import.command.d.ts.map +1 -1
- package/dist/commands/import.command.js +121 -5
- package/dist/commands/init.command.d.ts.map +1 -1
- package/dist/commands/init.command.js +151 -7
- package/dist/commands/packs-new.d.ts +1 -1
- package/dist/commands/packs-new.d.ts.map +1 -1
- package/dist/commands/packs-new.js +5 -36
- package/dist/commands/packs.command.d.ts.map +1 -1
- package/dist/commands/packs.command.js +2 -10
- package/dist/commands/profiles.command.js +4 -4
- package/dist/commands/release.command.js +13 -13
- package/dist/commands/search.command.js +1 -1
- package/dist/commands/task-context.command.js +0 -16
- package/dist/export/claude-commands-export.d.ts +60 -0
- package/dist/export/claude-commands-export.d.ts.map +1 -0
- package/dist/export/claude-commands-export.js +276 -0
- package/dist/export/export-formats.d.ts +1 -1
- package/dist/export/export-formats.d.ts.map +1 -1
- package/dist/export/export-formats.js +139 -12
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +104 -11
- package/dist/output/watch-loop.d.ts +9 -1
- package/dist/output/watch-loop.d.ts.map +1 -1
- package/dist/output/watch-loop.js +13 -3
- package/package.json +20 -20
- package/dist/commands/plugin.command.d.ts +0 -11
- package/dist/commands/plugin.command.d.ts.map +0 -1
- package/dist/commands/plugin.command.js +0 -394
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.command.d.ts","sourceRoot":"","sources":["../../src/commands/check.command.ts"],"names":[],"mappings":"AAmBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"check.command.d.ts","sourceRoot":"","sources":["../../src/commands/check.command.ts"],"names":[],"mappings":"AAmBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAikBhC,eAAO,MAAM,YAAY,EAAE,eAmD1B,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs';
|
|
|
3
3
|
import * as nodePath from 'node:path';
|
|
4
4
|
import { flagBool, flagNumber, flagString, flagVars, resolveCwd, } from "../command-registry.js";
|
|
5
5
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
6
|
+
import { maybeRunInWatchMode } from "../output/watch-loop.js";
|
|
6
7
|
import { validateTemplateVariables } from '@shrkcrft/templates';
|
|
7
8
|
import { FileChangeType, planGeneration } from '@shrkcrft/generator';
|
|
8
9
|
import { evaluateBoundaries, loadTsconfigPaths, scanImports, summarizeImports, } from '@shrkcrft/boundaries';
|
|
@@ -305,6 +306,22 @@ function readChangedScopeOptions(args, cwd) {
|
|
|
305
306
|
return out;
|
|
306
307
|
}
|
|
307
308
|
async function checkBoundaries(args) {
|
|
309
|
+
const watchExit = await maybeRunInWatchMode(args, checkBoundariesOnce, {
|
|
310
|
+
defaultPaths: BOUNDARIES_DEFAULT_WATCH_PATHS,
|
|
311
|
+
});
|
|
312
|
+
if (watchExit !== null)
|
|
313
|
+
return watchExit;
|
|
314
|
+
return checkBoundariesOnce(args);
|
|
315
|
+
}
|
|
316
|
+
const BOUNDARIES_DEFAULT_WATCH_PATHS = [
|
|
317
|
+
'sharkcraft',
|
|
318
|
+
'packages',
|
|
319
|
+
'apps',
|
|
320
|
+
'libs',
|
|
321
|
+
'src',
|
|
322
|
+
'tools',
|
|
323
|
+
];
|
|
324
|
+
async function checkBoundariesOnce(args) {
|
|
308
325
|
const cwd = resolveCwd(args);
|
|
309
326
|
const inspection = await inspectSharkcraft({ cwd });
|
|
310
327
|
const rules = inspection.boundaryRegistry.list();
|
|
@@ -504,8 +521,8 @@ async function checkBoundaries(args) {
|
|
|
504
521
|
// ────────────────────────────────────────────────────────────────────────
|
|
505
522
|
export const checkCommand = {
|
|
506
523
|
name: 'check',
|
|
507
|
-
description: 'Run SharkCraft-level validation across knowledge / rules / templates / pipelines / packs / action hints / doctor.',
|
|
508
|
-
usage: 'shrk [--cwd <dir>] check [packs|pipelines|knowledge|generation] [--strict] [--min-score <0-100>] [--json]',
|
|
524
|
+
description: 'Run SharkCraft-level validation across knowledge / rules / templates / pipelines / packs / action hints / doctor. `check boundaries [--watch [--paths a,b] [--debounce N] [--once]]` re-runs the boundary scan on file changes.',
|
|
525
|
+
usage: 'shrk [--cwd <dir>] check [packs|pipelines|knowledge|generation|boundaries|imports] [--strict] [--min-score <0-100>] [--json] [--watch [--paths <list>] [--debounce N] [--once]]',
|
|
509
526
|
async run(args) {
|
|
510
527
|
const sub = args.positional[0];
|
|
511
528
|
if (sub === 'generation')
|
|
@@ -236,9 +236,13 @@ export declare function commandLifecycle(e: ICommandCatalogEntry): CommandLifecy
|
|
|
236
236
|
/**
|
|
237
237
|
* Default-help visibility rule. Honors an explicit
|
|
238
238
|
* {@link ICommandCatalogEntry.showInDefaultHelp} when set; otherwise
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
239
|
+
* the {@link PRIMARY_VERBS_ALLOWLIST} gates membership in the visible
|
|
240
|
+
* surface (primary + common entries whose top-level verb pays rent
|
|
241
|
+
* make the cut; everything else is hidden from `--full-help`).
|
|
242
|
+
*
|
|
243
|
+
* Deprecated, retired, aliased commands and anything in the
|
|
244
|
+
* {@link R46_OVERLAY} are always hidden regardless of allowlist
|
|
245
|
+
* membership.
|
|
242
246
|
*/
|
|
243
247
|
export declare function defaultShowInHelp(e: ICommandCatalogEntry): boolean;
|
|
244
248
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/command-catalog.ts"],"names":[],"mappings":"AAAA,oBAAY,WAAW;IACrB,QAAQ,cAAc;IACtB,iBAAiB,mBAAmB;IACpC,gBAAgB,kBAAkB;IAClC,YAAY,kBAAkB;IAC9B,SAAS,eAAe;IACxB,cAAc,oBAAoB;CACnC;AAED;;;;;;GAMG;AACH,oBAAY,cAAc;IACxB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAED,8BAA8B;AAC9B,oBAAY,eAAe;IACzB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,EAAE,OAAO;IACT,UAAU,gBAAgB;IAC1B,UAAU,eAAe;CAC1B;AAED;;;;;;GAMG;AACH,oBAAY,eAAe;IACzB,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,MAAM,WAAW;CAClB;AAED;;;;;;GAMG;AACH,oBAAY,gBAAgB;IAC1B,MAAM,WAAW;IACjB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,UAAU,eAAe;IACzB,OAAO,YAAY;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,YAAY,iBAAiB;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,kCAAkC;IAClC,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,oBAAoB,
|
|
1
|
+
{"version":3,"file":"command-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/command-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -291,6 +291,15 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
291
291
|
surface: CommandSurface.Common,
|
|
292
292
|
taskRole: CommandTaskRole.Validate,
|
|
293
293
|
}),
|
|
294
|
+
entry({
|
|
295
|
+
command: 'diff-check',
|
|
296
|
+
description: 'Self-check current git diff against boundary + import-hygiene rules. Single-call composite for agents to validate edits before declaring done. Read-only.',
|
|
297
|
+
category: 'core',
|
|
298
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
299
|
+
mcpAvailable: true,
|
|
300
|
+
surface: CommandSurface.Common,
|
|
301
|
+
taskRole: CommandTaskRole.Validate,
|
|
302
|
+
}),
|
|
294
303
|
entry({
|
|
295
304
|
command: 'review',
|
|
296
305
|
description: 'PR-review packet — changed files, affected rules, missing tests heuristic.',
|
|
@@ -634,6 +643,11 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
634
643
|
category: 'task-context',
|
|
635
644
|
safetyLevel: SafetyLevel.ReadOnly,
|
|
636
645
|
mcpAvailable: true,
|
|
646
|
+
// Overlaps with `shrk task` (machine packet) and `shrk recommend`
|
|
647
|
+
// (human routing). Pointing at `task` as canonical so users who
|
|
648
|
+
// hit this via tab-complete see the canonical machine-pipe form.
|
|
649
|
+
overlapsWith: ['task', 'recommend'],
|
|
650
|
+
preferredCommand: 'shrk task "<task>"',
|
|
637
651
|
}),
|
|
638
652
|
entry({
|
|
639
653
|
command: 'validate-change',
|
|
@@ -1007,7 +1021,7 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
1007
1021
|
// `commands doctor` is honest.
|
|
1008
1022
|
entry({
|
|
1009
1023
|
command: 'profiles',
|
|
1010
|
-
description: 'List / inspect pack-contributed profiles (
|
|
1024
|
+
description: 'List / inspect pack-contributed profiles (migration, conventions, …). Subcommands: list, get, doctor, search.',
|
|
1011
1025
|
category: 'core',
|
|
1012
1026
|
safetyLevel: SafetyLevel.ReadOnly,
|
|
1013
1027
|
mcpAvailable: true,
|
|
@@ -2316,7 +2330,7 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
2316
2330
|
}),
|
|
2317
2331
|
entry({
|
|
2318
2332
|
command: 'release smoke --matrix',
|
|
2319
|
-
description: 'Run smoke scenarios across multiple repo targets (sharkcraft/dogfood/synthetic/
|
|
2333
|
+
description: 'Run smoke scenarios across multiple repo targets (sharkcraft/dogfood/synthetic/consumer).',
|
|
2320
2334
|
category: 'release',
|
|
2321
2335
|
safetyLevel: SafetyLevel.WritesDraftsOnly,
|
|
2322
2336
|
writesFiles: true,
|
|
@@ -2708,34 +2722,6 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
2708
2722
|
safetyLevel: SafetyLevel.ReadOnly,
|
|
2709
2723
|
mcpAvailable: true,
|
|
2710
2724
|
}),
|
|
2711
|
-
entry({
|
|
2712
|
-
command: 'plugin rename',
|
|
2713
|
-
description: 'Plan-only plugin rename (profile-driven) — emits replace ops + manual folder rename checklist.',
|
|
2714
|
-
category: 'lifecycle',
|
|
2715
|
-
safetyLevel: SafetyLevel.WritesDraftsOnly,
|
|
2716
|
-
mcpAvailable: true,
|
|
2717
|
-
}),
|
|
2718
|
-
entry({
|
|
2719
|
-
command: 'plugin remove',
|
|
2720
|
-
description: 'Plan-only destructive plugin remove (profile-driven) — destructive; requires human approval.',
|
|
2721
|
-
category: 'lifecycle',
|
|
2722
|
-
safetyLevel: SafetyLevel.WritesDraftsOnly,
|
|
2723
|
-
mcpAvailable: true,
|
|
2724
|
-
}),
|
|
2725
|
-
entry({
|
|
2726
|
-
command: 'plugin lifecycle list',
|
|
2727
|
-
description: 'List plugins detected under the active profile roots and key-table. Read-only.',
|
|
2728
|
-
category: 'lifecycle',
|
|
2729
|
-
safetyLevel: SafetyLevel.ReadOnly,
|
|
2730
|
-
mcpAvailable: false,
|
|
2731
|
-
}),
|
|
2732
|
-
entry({
|
|
2733
|
-
command: 'plugin lifecycle inspect',
|
|
2734
|
-
description: 'Inspect references to a plugin across the profile layers + key-table. Read-only.',
|
|
2735
|
-
category: 'lifecycle',
|
|
2736
|
-
safetyLevel: SafetyLevel.ReadOnly,
|
|
2737
|
-
mcpAvailable: false,
|
|
2738
|
-
}),
|
|
2739
2725
|
entry({
|
|
2740
2726
|
command: 'helper list',
|
|
2741
2727
|
description: 'List available helper plan generators. Read-only.',
|
|
@@ -3137,12 +3123,99 @@ export function commandLifecycle(e) {
|
|
|
3137
3123
|
return CommandLifecycle.Deprecated;
|
|
3138
3124
|
return CommandLifecycle.Active;
|
|
3139
3125
|
}
|
|
3126
|
+
/**
|
|
3127
|
+
* The "Primary verbs" allowlist — top-level commands that pay rent in
|
|
3128
|
+
* the default help surface. Everything else stays callable but is
|
|
3129
|
+
* hidden from `--full-help` and from MCP tool advertising; users find
|
|
3130
|
+
* them via `shrk surface list`, `shrk help <cmd>`, or `--full-help`.
|
|
3131
|
+
*
|
|
3132
|
+
* Picked to cover the canonical agent-flow journeys:
|
|
3133
|
+
* - bootstrap a repo, verify it
|
|
3134
|
+
* - get a brief / context / task packet for an agent
|
|
3135
|
+
* - generate safely (plan → apply → check)
|
|
3136
|
+
* - browse what shrk knows (rules / paths / templates / presets)
|
|
3137
|
+
* - inline the rules into the agent's prompt (export, mcp, dashboard)
|
|
3138
|
+
* - daily operations (review, impact, search, explain, why, surface)
|
|
3139
|
+
*
|
|
3140
|
+
* Anything not in this set falls back to the legacy
|
|
3141
|
+
* surface-tier-based visibility, with deprecated / retired / aliased
|
|
3142
|
+
* commands hidden regardless. Adding a verb here is the explicit
|
|
3143
|
+
* "this is rent-paying" decision.
|
|
3144
|
+
*/
|
|
3145
|
+
const PRIMARY_VERBS_ALLOWLIST = new Set([
|
|
3146
|
+
// Bootstrap
|
|
3147
|
+
'init',
|
|
3148
|
+
'doctor',
|
|
3149
|
+
'inspect',
|
|
3150
|
+
'onboard',
|
|
3151
|
+
'version',
|
|
3152
|
+
'help',
|
|
3153
|
+
'preflight',
|
|
3154
|
+
'self-config',
|
|
3155
|
+
// Per-task
|
|
3156
|
+
'brief',
|
|
3157
|
+
'recommend',
|
|
3158
|
+
'context',
|
|
3159
|
+
'task',
|
|
3160
|
+
'coverage',
|
|
3161
|
+
'explain',
|
|
3162
|
+
'why',
|
|
3163
|
+
'search',
|
|
3164
|
+
'impact',
|
|
3165
|
+
'graph',
|
|
3166
|
+
// Generate code safely
|
|
3167
|
+
'gen',
|
|
3168
|
+
'apply',
|
|
3169
|
+
'check',
|
|
3170
|
+
'quality',
|
|
3171
|
+
'plan',
|
|
3172
|
+
'fix',
|
|
3173
|
+
// Browse / inline
|
|
3174
|
+
'knowledge',
|
|
3175
|
+
'rules',
|
|
3176
|
+
'templates',
|
|
3177
|
+
'paths',
|
|
3178
|
+
'import',
|
|
3179
|
+
'export',
|
|
3180
|
+
// Architecture & quality gates
|
|
3181
|
+
'drift',
|
|
3182
|
+
'safety',
|
|
3183
|
+
// Run for an agent
|
|
3184
|
+
'mcp',
|
|
3185
|
+
'dashboard',
|
|
3186
|
+
// Ops
|
|
3187
|
+
'surface',
|
|
3188
|
+
'presets',
|
|
3189
|
+
'review',
|
|
3190
|
+
'packs',
|
|
3191
|
+
'ci',
|
|
3192
|
+
'commands',
|
|
3193
|
+
]);
|
|
3194
|
+
function topLevelVerb(command) {
|
|
3195
|
+
// Strip leading `--cwd <dir>` / `--<flag>` tokens and angle-bracket
|
|
3196
|
+
// placeholders; the canonical first verb is whatever leads.
|
|
3197
|
+
const tokens = command.split(/\s+/);
|
|
3198
|
+
for (const t of tokens) {
|
|
3199
|
+
if (!t)
|
|
3200
|
+
continue;
|
|
3201
|
+
if (t.startsWith('--') || t.startsWith('-'))
|
|
3202
|
+
continue;
|
|
3203
|
+
if (t.startsWith('<') || t.startsWith('"'))
|
|
3204
|
+
continue;
|
|
3205
|
+
return t;
|
|
3206
|
+
}
|
|
3207
|
+
return command;
|
|
3208
|
+
}
|
|
3140
3209
|
/**
|
|
3141
3210
|
* Default-help visibility rule. Honors an explicit
|
|
3142
3211
|
* {@link ICommandCatalogEntry.showInDefaultHelp} when set; otherwise
|
|
3143
|
-
*
|
|
3144
|
-
*
|
|
3145
|
-
*
|
|
3212
|
+
* the {@link PRIMARY_VERBS_ALLOWLIST} gates membership in the visible
|
|
3213
|
+
* surface (primary + common entries whose top-level verb pays rent
|
|
3214
|
+
* make the cut; everything else is hidden from `--full-help`).
|
|
3215
|
+
*
|
|
3216
|
+
* Deprecated, retired, aliased commands and anything in the
|
|
3217
|
+
* {@link R46_OVERLAY} are always hidden regardless of allowlist
|
|
3218
|
+
* membership.
|
|
3146
3219
|
*/
|
|
3147
3220
|
export function defaultShowInHelp(e) {
|
|
3148
3221
|
if (e.showInDefaultHelp !== undefined)
|
|
@@ -3155,6 +3228,12 @@ export function defaultShowInHelp(e) {
|
|
|
3155
3228
|
return false;
|
|
3156
3229
|
if (lc === CommandLifecycle.Alias)
|
|
3157
3230
|
return false;
|
|
3231
|
+
// Allowlist gate — the top-level verb must be one of the ~30
|
|
3232
|
+
// rent-paying verbs. Subcommands of an allowlisted verb inherit
|
|
3233
|
+
// visibility (so `check boundaries` shows under `check`).
|
|
3234
|
+
const verb = topLevelVerb(e.command);
|
|
3235
|
+
if (!PRIMARY_VERBS_ALLOWLIST.has(verb))
|
|
3236
|
+
return false;
|
|
3158
3237
|
const surface = commandSurface(e);
|
|
3159
3238
|
return surface === CommandSurface.Primary || surface === CommandSurface.Common;
|
|
3160
3239
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.command.d.ts","sourceRoot":"","sources":["../../src/commands/commands.command.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"commands.command.d.ts","sourceRoot":"","sources":["../../src/commands/commands.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { flagBool, flagString
|
|
1
|
+
import { flagBool, flagString } from "../command-registry.js";
|
|
2
2
|
import { asJson, header } from "../output/format-output.js";
|
|
3
|
-
import { COMMAND_CATALOG, CommandLifecycle,
|
|
4
|
-
import { buildCommandTaxonomy, buildPrimaryCommandsReport, renderCommandTaxonomyMarkdown, renderCommandTaxonomyText, renderPrimaryCommandsText
|
|
3
|
+
import { buildCommandSafetyMatrix, COMMAND_CATALOG, CommandLifecycle, commandLifecycle, CommandSurface, commandSurface, commandTaskRole, defaultShowInHelp, R46_OVERLAY, renderCommandSafetyMatrixMarkdown, SafetyLevel } from "./command-catalog.js";
|
|
4
|
+
import { buildCommandTaxonomy, buildPrimaryCommandsReport, renderCommandTaxonomyMarkdown, renderCommandTaxonomyText, renderPrimaryCommandsText } from '@shrkcrft/inspector';
|
|
5
5
|
export function makeCommandsCommand(registry) {
|
|
6
6
|
return {
|
|
7
7
|
name: 'commands',
|
|
@@ -589,7 +589,7 @@ export function buildCommandsUxReport() {
|
|
|
589
589
|
// issue is clearly structural (none of these currently rise to error).
|
|
590
590
|
for (const e of COMMAND_CATALOG) {
|
|
591
591
|
const surface = commandSurface(e);
|
|
592
|
-
// (a) primary commands should declare an audience (so
|
|
592
|
+
// (a) primary commands should declare an audience (so consumers can see
|
|
593
593
|
// who the command is for at a glance).
|
|
594
594
|
if (surface === CommandSurface.Primary && (!e.intendedAudience || e.intendedAudience.length === 0)) {
|
|
595
595
|
issues.push({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constructs.command.d.ts","sourceRoot":"","sources":["../../src/commands/constructs.command.ts"],"names":[],"mappings":"AA6BA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAahC,eAAO,MAAM,qBAAqB,EAAE,eAqBnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAoDlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA8DpC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,
|
|
1
|
+
{"version":3,"file":"constructs.command.d.ts","sourceRoot":"","sources":["../../src/commands/constructs.command.ts"],"names":[],"mappings":"AA6BA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAahC,eAAO,MAAM,qBAAqB,EAAE,eAqBnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAoDlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA8DpC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAoErC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAmCtC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAwBpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAiClC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAiBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAiBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eA4BrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eA8BrC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0DpC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0LpC,CAAC"}
|
|
@@ -91,7 +91,7 @@ export const constructsGetCommand = {
|
|
|
91
91
|
};
|
|
92
92
|
export const constructsTraceCommand = {
|
|
93
93
|
name: 'trace',
|
|
94
|
-
description: 'Trace all files / publicApi / events / tokens belonging to a construct. --deep adds related/
|
|
94
|
+
description: 'Trace all files / publicApi / events / tokens belonging to a construct. --deep adds related / test pointers when present.',
|
|
95
95
|
usage: 'shrk constructs trace <id> [--deep] [--json]',
|
|
96
96
|
async run(args) {
|
|
97
97
|
const id = args.positional[0];
|
|
@@ -118,7 +118,7 @@ export const constructsTraceCommand = {
|
|
|
118
118
|
? {
|
|
119
119
|
related: relatedAll,
|
|
120
120
|
tags: c.tags ?? [],
|
|
121
|
-
registryHints: c.tags?.filter((t) => /(registry|
|
|
121
|
+
registryHints: c.tags?.filter((t) => /(registry|barrel)/i.test(t)) ?? [],
|
|
122
122
|
}
|
|
123
123
|
: undefined;
|
|
124
124
|
if (flagBool(args, 'json')) {
|
|
@@ -175,28 +175,11 @@ export const constructsImpactCommand = {
|
|
|
175
175
|
}
|
|
176
176
|
const trace = traceConstruct(c);
|
|
177
177
|
/**
|
|
178
|
-
* Registry touch-points are inferred
|
|
179
|
-
*
|
|
180
|
-
*
|
|
178
|
+
* Registry touch-points are not inferred — pack-contributed
|
|
179
|
+
* touch-point hints can be added in the future via the convention
|
|
180
|
+
* registry.
|
|
181
181
|
*/
|
|
182
182
|
const registryTouchPoints = [];
|
|
183
|
-
try {
|
|
184
|
-
const { listPluginLifecycleProfiles } = await import('@shrkcrft/inspector');
|
|
185
|
-
const profiles = await listPluginLifecycleProfiles(inspection);
|
|
186
|
-
for (const entry of profiles) {
|
|
187
|
-
const p = entry.profile;
|
|
188
|
-
if (c.tags?.some((t) => /plugin-key|key-table/i.test(t)) && p.keyTable) {
|
|
189
|
-
registryTouchPoints.push(p.keyTable.path);
|
|
190
|
-
}
|
|
191
|
-
if (c.tags?.some((t) => /barrel|public-api/i.test(t)) && p.barrels) {
|
|
192
|
-
for (const b of p.barrels)
|
|
193
|
-
registryTouchPoints.push(b.path);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
// Best-effort enrichment; absence of profiles just means no touch-points.
|
|
199
|
-
}
|
|
200
183
|
const verificationCommands = [
|
|
201
184
|
'shrk check boundaries --changed-only',
|
|
202
185
|
'shrk doctor',
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `shrk diff-check` — agent self-validation after edits.
|
|
3
|
+
*
|
|
4
|
+
* The story this command tells:
|
|
5
|
+
* 1. An AI agent (Claude Code, Cursor, etc.) makes some file changes.
|
|
6
|
+
* 2. Before declaring "done", the agent runs `shrk diff-check`.
|
|
7
|
+
* 3. The command scopes both the boundary check and the
|
|
8
|
+
* import-hygiene check to only the files the agent touched in the
|
|
9
|
+
* current git diff.
|
|
10
|
+
* 4. The output is a single agent-friendly JSON envelope with a
|
|
11
|
+
* verdict (ok / warnings / errors) and a one-line next action.
|
|
12
|
+
*
|
|
13
|
+
* Why a new command instead of "just run `shrk check boundaries
|
|
14
|
+
* --changed-only` and `shrk check imports --changed-only`":
|
|
15
|
+
*
|
|
16
|
+
* - One command instead of two — agents reliably run the *one* tool
|
|
17
|
+
* they're told to run; chained-command workflows get skipped.
|
|
18
|
+
* - One verdict — no need to OR two separate JSON outputs.
|
|
19
|
+
* - Stable, narrow schema — designed for agent consumption, not
|
|
20
|
+
* human terminals. Won't grow flags over time.
|
|
21
|
+
* - Concrete `nextAction` line — the agent knows exactly what to do
|
|
22
|
+
* next (declare done, fix N things, or re-run after a manual fix).
|
|
23
|
+
*
|
|
24
|
+
* This is a pure composer — all real logic stays in
|
|
25
|
+
* `@shrkcrft/inspector` and `@shrkcrft/boundaries`. We just stitch
|
|
26
|
+
* their outputs together with consistent scoping.
|
|
27
|
+
*/
|
|
28
|
+
import { type ICommandHandler } from '../command-registry.js';
|
|
29
|
+
export declare const diffCheckCommand: ICommandHandler;
|
|
30
|
+
//# sourceMappingURL=diff-check.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-check.command.d.ts","sourceRoot":"","sources":["../../src/commands/diff-check.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAcH,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA0GhC,eAAO,MAAM,gBAAgB,EAAE,eAiI9B,CAAC"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `shrk diff-check` — agent self-validation after edits.
|
|
3
|
+
*
|
|
4
|
+
* The story this command tells:
|
|
5
|
+
* 1. An AI agent (Claude Code, Cursor, etc.) makes some file changes.
|
|
6
|
+
* 2. Before declaring "done", the agent runs `shrk diff-check`.
|
|
7
|
+
* 3. The command scopes both the boundary check and the
|
|
8
|
+
* import-hygiene check to only the files the agent touched in the
|
|
9
|
+
* current git diff.
|
|
10
|
+
* 4. The output is a single agent-friendly JSON envelope with a
|
|
11
|
+
* verdict (ok / warnings / errors) and a one-line next action.
|
|
12
|
+
*
|
|
13
|
+
* Why a new command instead of "just run `shrk check boundaries
|
|
14
|
+
* --changed-only` and `shrk check imports --changed-only`":
|
|
15
|
+
*
|
|
16
|
+
* - One command instead of two — agents reliably run the *one* tool
|
|
17
|
+
* they're told to run; chained-command workflows get skipped.
|
|
18
|
+
* - One verdict — no need to OR two separate JSON outputs.
|
|
19
|
+
* - Stable, narrow schema — designed for agent consumption, not
|
|
20
|
+
* human terminals. Won't grow flags over time.
|
|
21
|
+
* - Concrete `nextAction` line — the agent knows exactly what to do
|
|
22
|
+
* next (declare done, fix N things, or re-run after a manual fix).
|
|
23
|
+
*
|
|
24
|
+
* This is a pure composer — all real logic stays in
|
|
25
|
+
* `@shrkcrft/inspector` and `@shrkcrft/boundaries`. We just stitch
|
|
26
|
+
* their outputs together with consistent scoping.
|
|
27
|
+
*/
|
|
28
|
+
import { buildImportHygieneReport, filterViolationsToChangedScope, inspectSharkcraft, resolveChangedFiles, } from '@shrkcrft/inspector';
|
|
29
|
+
import { evaluateBoundaries, loadTsconfigPaths, scanImports, } from '@shrkcrft/boundaries';
|
|
30
|
+
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
31
|
+
import { asJson, bullet, header, kv } from "../output/format-output.js";
|
|
32
|
+
const SCHEMA = 'sharkcraft.diff-check/v1';
|
|
33
|
+
function resolveScope(args, cwd) {
|
|
34
|
+
const staged = flagBool(args, 'staged');
|
|
35
|
+
const since = flagString(args, 'since');
|
|
36
|
+
const filesRaw = flagString(args, 'files');
|
|
37
|
+
const files = filesRaw
|
|
38
|
+
? filesRaw.split(',').map((s) => s.trim()).filter((s) => s.length > 0)
|
|
39
|
+
: [];
|
|
40
|
+
if (files.length > 0) {
|
|
41
|
+
return { mode: 'files', options: { projectRoot: cwd, files } };
|
|
42
|
+
}
|
|
43
|
+
if (staged) {
|
|
44
|
+
return { mode: 'staged', options: { projectRoot: cwd, staged: true } };
|
|
45
|
+
}
|
|
46
|
+
if (since) {
|
|
47
|
+
return { mode: 'since', options: { projectRoot: cwd, since } };
|
|
48
|
+
}
|
|
49
|
+
// Default: worktree (== `--changed-only` from `shrk check boundaries`).
|
|
50
|
+
return {
|
|
51
|
+
mode: 'worktree',
|
|
52
|
+
options: { projectRoot: cwd, includeWorktree: true },
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function deriveVerdict(env) {
|
|
56
|
+
const bErr = env.boundaries.counts.error;
|
|
57
|
+
const bWarn = env.boundaries.counts.warning;
|
|
58
|
+
const iErr = env.imports.verdict === 'errors' ? (env.imports.counts.error ?? env.imports.findings.length) : 0;
|
|
59
|
+
const iWarn = env.imports.verdict === 'warnings' ? (env.imports.counts.warning ?? env.imports.findings.length) : 0;
|
|
60
|
+
if (env.scope.fileCount === 0) {
|
|
61
|
+
return {
|
|
62
|
+
verdict: 'ok',
|
|
63
|
+
summary: 'No files changed in the current diff scope.',
|
|
64
|
+
nextAction: 'Nothing to check. If you expected changes, verify your `--staged` / `--since <ref>` flag or save your edits first.',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (bErr > 0 || iErr > 0) {
|
|
68
|
+
const parts = [];
|
|
69
|
+
if (bErr > 0)
|
|
70
|
+
parts.push(`${bErr} boundary violation${bErr === 1 ? '' : 's'}`);
|
|
71
|
+
if (iErr > 0)
|
|
72
|
+
parts.push(`${iErr} import-hygiene error${iErr === 1 ? '' : 's'}`);
|
|
73
|
+
return {
|
|
74
|
+
verdict: 'errors',
|
|
75
|
+
summary: `Diff fails the gate: ${parts.join(', ')}.`,
|
|
76
|
+
nextAction: 'Fix every error in `boundaries.violations` and `imports.findings` (look at each entry\'s `suggestedFix` line), then re-run `shrk diff-check`.',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (bWarn > 0 || iWarn > 0) {
|
|
80
|
+
const parts = [];
|
|
81
|
+
if (bWarn > 0)
|
|
82
|
+
parts.push(`${bWarn} boundary warning${bWarn === 1 ? '' : 's'}`);
|
|
83
|
+
if (iWarn > 0)
|
|
84
|
+
parts.push(`${iWarn} import-hygiene warning${iWarn === 1 ? '' : 's'}`);
|
|
85
|
+
return {
|
|
86
|
+
verdict: 'warnings',
|
|
87
|
+
summary: `Diff passes the gate with ${parts.join(', ')}.`,
|
|
88
|
+
nextAction: 'Safe to declare done. Review warnings if the diff touches a sensitive area; otherwise these are non-blocking.',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
verdict: 'ok',
|
|
93
|
+
summary: `Diff passes the gate (${env.scope.fileCount} file${env.scope.fileCount === 1 ? '' : 's'}, 0 violations).`,
|
|
94
|
+
nextAction: 'Safe to declare done.',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export const diffCheckCommand = {
|
|
98
|
+
name: 'diff-check',
|
|
99
|
+
description: 'Self-check the current git diff against this project\'s boundary + import-hygiene rules. Single-call composite of `shrk check boundaries --changed-only` + `shrk check imports --changed-only`, with one verdict and one nextAction line. Designed for AI agents to run after editing — pass --json for the structured envelope.',
|
|
100
|
+
usage: 'shrk [--cwd <dir>] diff-check [--staged | --since <ref> | --files a.ts,b.ts] [--json]',
|
|
101
|
+
async run(args) {
|
|
102
|
+
const cwd = resolveCwd(args);
|
|
103
|
+
const wantJson = flagBool(args, 'json');
|
|
104
|
+
const { mode, options: scopeOptions } = resolveScope(args, cwd);
|
|
105
|
+
// 1. Resolve the changed file set once. Both engines re-use it.
|
|
106
|
+
const changed = resolveChangedFiles(scopeOptions);
|
|
107
|
+
const changedFiles = changed.files;
|
|
108
|
+
// 2. Boundary engine — only if rules exist.
|
|
109
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
110
|
+
const rules = inspection.boundaryRegistry.list();
|
|
111
|
+
let boundaryBlock = {
|
|
112
|
+
ran: false,
|
|
113
|
+
rulesEvaluated: 0,
|
|
114
|
+
counts: { error: 0, warning: 0, info: 0 },
|
|
115
|
+
violations: [],
|
|
116
|
+
};
|
|
117
|
+
if (rules.length > 0 && changedFiles.length > 0) {
|
|
118
|
+
const scan = scanImports({ projectRoot: cwd });
|
|
119
|
+
const tsconfigPaths = loadTsconfigPaths(cwd);
|
|
120
|
+
const evalResult = evaluateBoundaries(scan, rules, {
|
|
121
|
+
...(tsconfigPaths.aliases.size > 0 ? { tsconfigPaths } : {}),
|
|
122
|
+
});
|
|
123
|
+
const filtered = filterViolationsToChangedScope(evalResult.violations, scopeOptions);
|
|
124
|
+
boundaryBlock = {
|
|
125
|
+
ran: true,
|
|
126
|
+
rulesEvaluated: evalResult.rulesEvaluated,
|
|
127
|
+
counts: {
|
|
128
|
+
error: filtered.includedViolations.filter((v) => v.severity === 'error').length,
|
|
129
|
+
warning: filtered.includedViolations.filter((v) => v.severity === 'warning').length,
|
|
130
|
+
info: filtered.includedViolations.filter((v) => v.severity === 'info').length,
|
|
131
|
+
},
|
|
132
|
+
violations: filtered.includedViolations,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
else if (rules.length > 0 && changedFiles.length === 0) {
|
|
136
|
+
boundaryBlock = { ...boundaryBlock, ran: true, rulesEvaluated: rules.length };
|
|
137
|
+
}
|
|
138
|
+
// 3. Import-hygiene engine — always runs, but scoped to changed files.
|
|
139
|
+
let importsBlock = {
|
|
140
|
+
ran: false,
|
|
141
|
+
verdict: 'skipped',
|
|
142
|
+
counts: {},
|
|
143
|
+
findings: [],
|
|
144
|
+
};
|
|
145
|
+
if (changedFiles.length > 0) {
|
|
146
|
+
const report = buildImportHygieneReport(cwd, { files: changedFiles });
|
|
147
|
+
importsBlock = {
|
|
148
|
+
ran: true,
|
|
149
|
+
verdict: report.verdict,
|
|
150
|
+
counts: report.counts ?? {},
|
|
151
|
+
findings: report.findings,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// 4. Build envelope + derive verdict.
|
|
155
|
+
const partial = {
|
|
156
|
+
schema: SCHEMA,
|
|
157
|
+
generatedAt: new Date().toISOString(),
|
|
158
|
+
scope: {
|
|
159
|
+
mode,
|
|
160
|
+
files: changedFiles,
|
|
161
|
+
fileCount: changedFiles.length,
|
|
162
|
+
},
|
|
163
|
+
boundaries: boundaryBlock,
|
|
164
|
+
imports: importsBlock,
|
|
165
|
+
};
|
|
166
|
+
const { verdict, summary, nextAction } = deriveVerdict(partial);
|
|
167
|
+
const envelope = { ...partial, verdict, summary, nextAction };
|
|
168
|
+
// 5. Render.
|
|
169
|
+
if (wantJson) {
|
|
170
|
+
process.stdout.write(asJson(envelope) + '\n');
|
|
171
|
+
return verdict === 'errors' ? 1 : 0;
|
|
172
|
+
}
|
|
173
|
+
process.stdout.write(header('Diff check'));
|
|
174
|
+
process.stdout.write(kv('scope', `${envelope.scope.mode} (${envelope.scope.fileCount} file${envelope.scope.fileCount === 1 ? '' : 's'})`) + '\n');
|
|
175
|
+
process.stdout.write(kv('boundaries', envelope.boundaries.ran
|
|
176
|
+
? `${envelope.boundaries.counts.error} errors, ${envelope.boundaries.counts.warning} warnings`
|
|
177
|
+
: '(no rules configured or no scoped files)') + '\n');
|
|
178
|
+
process.stdout.write(kv('imports', envelope.imports.ran
|
|
179
|
+
? `verdict=${envelope.imports.verdict} (${envelope.imports.findings.length} finding${envelope.imports.findings.length === 1 ? '' : 's'})`
|
|
180
|
+
: '(no scoped files)') + '\n');
|
|
181
|
+
process.stdout.write(kv('verdict', envelope.verdict) + '\n');
|
|
182
|
+
process.stdout.write('\n');
|
|
183
|
+
process.stdout.write(envelope.summary + '\n');
|
|
184
|
+
if (envelope.boundaries.violations.length > 0) {
|
|
185
|
+
process.stdout.write('\nBoundary violations:\n');
|
|
186
|
+
for (const v of envelope.boundaries.violations.slice(0, 10)) {
|
|
187
|
+
const file = String(v.file ?? '');
|
|
188
|
+
const rule = String(v.ruleId ?? '');
|
|
189
|
+
const fix = v.suggestedFix ? ` — ${String(v.suggestedFix)}` : '';
|
|
190
|
+
process.stdout.write(bullet(`${rule} in ${file}${fix}`) + '\n');
|
|
191
|
+
}
|
|
192
|
+
if (envelope.boundaries.violations.length > 10) {
|
|
193
|
+
process.stdout.write(` … and ${envelope.boundaries.violations.length - 10} more (pass --json for full list).\n`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (envelope.imports.findings.length > 0) {
|
|
197
|
+
process.stdout.write('\nImport findings:\n');
|
|
198
|
+
for (const f of envelope.imports.findings.slice(0, 10)) {
|
|
199
|
+
const file = String(f.path ?? f.file ?? '');
|
|
200
|
+
const kind = String(f.kind ?? '');
|
|
201
|
+
process.stdout.write(bullet(`${kind} in ${file}`) + '\n');
|
|
202
|
+
}
|
|
203
|
+
if (envelope.imports.findings.length > 10) {
|
|
204
|
+
process.stdout.write(` … and ${envelope.imports.findings.length - 10} more (pass --json for full list).\n`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
process.stdout.write(`\nNext: ${envelope.nextAction}\n`);
|
|
208
|
+
return verdict === 'errors' ? 1 : 0;
|
|
209
|
+
},
|
|
210
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.command.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.command.ts"],"names":[],"mappings":"AAqBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.command.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.command.ts"],"names":[],"mappings":"AAqBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA0JhC,eAAO,MAAM,aAAa,EAAE,eAW3B,CAAC;AA+bF,eAAO,MAAM,qBAAqB,EAAE,eAmCnC,CAAC;AAuDF,eAAO,MAAM,yBAAyB,EAAE,eAavC,CAAC;AAIF,eAAO,MAAM,wBAAwB,EAAE,eA2CtC,CAAC;AAgCF,eAAO,MAAM,6BAA6B,EAAE,eAa3C,CAAC"}
|