@shrkcrft/cli 0.1.0-alpha.7 → 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.
Files changed (41) hide show
  1. package/dist/commands/command-catalog.d.ts +7 -3
  2. package/dist/commands/command-catalog.d.ts.map +1 -1
  3. package/dist/commands/command-catalog.js +112 -33
  4. package/dist/commands/commands.command.d.ts.map +1 -1
  5. package/dist/commands/commands.command.js +4 -4
  6. package/dist/commands/constructs.command.d.ts.map +1 -1
  7. package/dist/commands/constructs.command.js +5 -22
  8. package/dist/commands/diff-check.command.d.ts +30 -0
  9. package/dist/commands/diff-check.command.d.ts.map +1 -0
  10. package/dist/commands/diff-check.command.js +210 -0
  11. package/dist/commands/doctor.command.d.ts.map +1 -1
  12. package/dist/commands/doctor.command.js +34 -2
  13. package/dist/commands/export.command.d.ts.map +1 -1
  14. package/dist/commands/export.command.js +76 -3
  15. package/dist/commands/help.command.d.ts +4 -3
  16. package/dist/commands/help.command.d.ts.map +1 -1
  17. package/dist/commands/help.command.js +74 -16
  18. package/dist/commands/helper.command.js +1 -1
  19. package/dist/commands/import.command.d.ts.map +1 -1
  20. package/dist/commands/import.command.js +121 -5
  21. package/dist/commands/init.command.d.ts.map +1 -1
  22. package/dist/commands/init.command.js +151 -7
  23. package/dist/commands/packs-new.d.ts +1 -1
  24. package/dist/commands/packs-new.d.ts.map +1 -1
  25. package/dist/commands/packs-new.js +2 -26
  26. package/dist/commands/profiles.command.js +4 -4
  27. package/dist/commands/release.command.js +13 -13
  28. package/dist/commands/search.command.js +1 -1
  29. package/dist/commands/task-context.command.js +0 -16
  30. package/dist/export/claude-commands-export.d.ts +60 -0
  31. package/dist/export/claude-commands-export.d.ts.map +1 -0
  32. package/dist/export/claude-commands-export.js +276 -0
  33. package/dist/export/export-formats.d.ts +1 -1
  34. package/dist/export/export-formats.d.ts.map +1 -1
  35. package/dist/export/export-formats.js +139 -12
  36. package/dist/main.d.ts.map +1 -1
  37. package/dist/main.js +104 -11
  38. package/package.json +20 -20
  39. package/dist/commands/plugin.command.d.ts +0 -11
  40. package/dist/commands/plugin.command.d.ts.map +0 -1
  41. package/dist/commands/plugin.command.js +0 -394
@@ -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
- * primary + common are visible and advanced / machine / internal / legacy
240
- * are hidden. Deprecated and retired commands are always hidden by
241
- * default regardless of surface.
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":"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"}
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 (plugin-lifecycle, migration, conventions, …). Subcommands: list, get, doctor, search.',
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/adopter).',
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
- * primary + common are visible and advanced / machine / internal / legacy
3144
- * are hidden. Deprecated and retired commands are always hidden by
3145
- * default regardless of surface.
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":"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"}
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, } from "../command-registry.js";
1
+ import { flagBool, flagString } from "../command-registry.js";
2
2
  import { asJson, header } from "../output/format-output.js";
3
- import { COMMAND_CATALOG, CommandLifecycle, CommandSurface, R46_OVERLAY, SafetyLevel, buildCommandSafetyMatrix, commandLifecycle, commandSurface, commandTaskRole, defaultShowInHelp, renderCommandSafetyMatrixMarkdown, } from "./command-catalog.js";
4
- import { buildCommandTaxonomy, buildPrimaryCommandsReport, renderCommandTaxonomyMarkdown, renderCommandTaxonomyText, renderPrimaryCommandsText, } from '@shrkcrft/inspector';
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 adopters can see
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,eAmFrC,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"}
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/sandbox/test pointers when present.',
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|composer|defaults|sandbox|demo|barrel)/i.test(t)) ?? [],
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 from the active plugin
179
- * lifecycle profile (key-table + barrels). The engine no longer
180
- * hardcodes project-specific paths.
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;AA0JhC,eAAO,MAAM,aAAa,EAAE,eAW3B,CAAC;AA0ZF,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"}
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"}
@@ -460,10 +460,27 @@ async function doctorCommandImpl(args) {
460
460
  if (!inspection.sharkcraftDir) {
461
461
  process.stdout.write('\nNothing here yet — try `shrk init --zero-config` to detect your stack and pick a preset.\n');
462
462
  }
463
- process.stdout.write(`\nAI-readiness: ${report.score} / 100 (${report.grade})\n`);
463
+ // Honest binary verdicts come first — yes/no on the two questions
464
+ // users actually want answered (can I let an agent write here? can
465
+ // I let an agent read here?). The 0..100 score follows, scoped to
466
+ // the workspace shape so libraries don't get dinged for "no
467
+ // pipelines" and apps don't get dinged for "no published API".
468
+ process.stdout.write(`\nShape: ${report.workspaceShape.label}` +
469
+ ` (score counts ${report.dimensions.filter((d) => d.applies === 'core').length} of ${report.dimensions.length} dimensions)\n`);
470
+ process.stdout.write(` ${report.verdicts.readyForAgentReads ? '✓' : '✗'} Ready for agent reads (context / task lookups)\n`);
471
+ process.stdout.write(` ${report.verdicts.readyForAgentWrites ? '✓' : '✗'} Ready for agent writes (apply / generate)\n`);
472
+ if (report.verdicts.blockers.length > 0) {
473
+ process.stdout.write(` Blockers:\n`);
474
+ for (const b of report.verdicts.blockers) {
475
+ process.stdout.write(` • ${b}\n`);
476
+ }
477
+ }
478
+ process.stdout.write(`\nAI-readiness: ${report.score} / 100 (${report.grade}, shape-aware)\n`);
464
479
  if (report.topRecommendations.length) {
465
480
  // Keep the default doctor output short: top 3 recommendations,
466
- // pass `--verbose` for the full list.
481
+ // pass `--verbose` for the full list. Recommendations only fire
482
+ // from `core` dimensions now — n/a-for-shape dimensions stop
483
+ // generating the misleading "add a pipeline" advice for libraries.
467
484
  const verbose = flagBool(args, 'verbose');
468
485
  const visible = verbose ? report.topRecommendations : report.topRecommendations.slice(0, 3);
469
486
  process.stdout.write(`Top recommendations${verbose ? '' : ` (top ${visible.length})`}:\n`);
@@ -473,6 +490,21 @@ async function doctorCommandImpl(args) {
473
490
  process.stdout.write(` … (${report.topRecommendations.length - visible.length} more — pass --verbose to see all)\n`);
474
491
  }
475
492
  }
493
+ // Surface N/A dimensions when --show-na is passed, so users can see
494
+ // what was deliberately skipped and disagree if they want to.
495
+ if (flagBool(args, 'show-na')) {
496
+ const skipped = report.dimensions.filter((d) => d.applies !== 'core');
497
+ if (skipped.length > 0) {
498
+ process.stdout.write(`\nNot counted in score (${skipped.length} dimensions):\n`);
499
+ for (const d of skipped) {
500
+ const tag = d.applies === 'n/a-for-shape' ? 'n/a' : 'advisory';
501
+ process.stdout.write(` [${tag}] ${d.title}: ${d.note}`);
502
+ if (d.appliesReason)
503
+ process.stdout.write(` — ${d.appliesReason}`);
504
+ process.stdout.write('\n');
505
+ }
506
+ }
507
+ }
476
508
  if (strictEval.failed) {
477
509
  process.stdout.write(`\nStrict mode: failing because ${strictEval.countedWarnings} warning(s) + ${result.summary.errors} error(s) exist (${strictEval.reason}).\n`);
478
510
  }
@@ -1 +1 @@
1
- {"version":3,"file":"export.command.d.ts","sourceRoot":"","sources":["../../src/commands/export.command.ts"],"names":[],"mappings":"AAQA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAgBhC,eAAO,MAAM,aAAa,EAAE,eAkF3B,CAAC"}
1
+ {"version":3,"file":"export.command.d.ts","sourceRoot":"","sources":["../../src/commands/export.command.ts"],"names":[],"mappings":"AASA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAgBhC,eAAO,MAAM,aAAa,EAAE,eAuF3B,CAAC"}