@shrkcrft/cli 0.1.0-alpha.2 → 0.1.0-alpha.21

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 (228) hide show
  1. package/dist/audit/knowledge-audit-llm.d.ts +19 -0
  2. package/dist/audit/knowledge-audit-llm.d.ts.map +1 -0
  3. package/dist/audit/knowledge-audit-llm.js +164 -0
  4. package/dist/audit/knowledge-audit.d.ts +61 -0
  5. package/dist/audit/knowledge-audit.d.ts.map +1 -0
  6. package/dist/audit/knowledge-audit.js +203 -0
  7. package/dist/audit/knowledge-fix-plan-llm.d.ts +11 -0
  8. package/dist/audit/knowledge-fix-plan-llm.d.ts.map +1 -0
  9. package/dist/audit/knowledge-fix-plan-llm.js +141 -0
  10. package/dist/audit/knowledge-fix-plan.d.ts +41 -0
  11. package/dist/audit/knowledge-fix-plan.d.ts.map +1 -0
  12. package/dist/audit/knowledge-fix-plan.js +125 -0
  13. package/dist/audit/pipeline-audit-llm.d.ts +11 -0
  14. package/dist/audit/pipeline-audit-llm.d.ts.map +1 -0
  15. package/dist/audit/pipeline-audit-llm.js +134 -0
  16. package/dist/audit/pipeline-audit.d.ts +69 -0
  17. package/dist/audit/pipeline-audit.d.ts.map +1 -0
  18. package/dist/audit/pipeline-audit.js +166 -0
  19. package/dist/audit/templates-audit-llm.d.ts +19 -0
  20. package/dist/audit/templates-audit-llm.d.ts.map +1 -0
  21. package/dist/audit/templates-audit-llm.js +207 -0
  22. package/dist/audit/templates-audit.d.ts +63 -0
  23. package/dist/audit/templates-audit.d.ts.map +1 -0
  24. package/dist/audit/templates-audit.js +171 -0
  25. package/dist/audit/templates-fix-plan-llm.d.ts +19 -0
  26. package/dist/audit/templates-fix-plan-llm.d.ts.map +1 -0
  27. package/dist/audit/templates-fix-plan-llm.js +162 -0
  28. package/dist/audit/templates-fix-plan.d.ts +37 -0
  29. package/dist/audit/templates-fix-plan.d.ts.map +1 -0
  30. package/dist/audit/templates-fix-plan.js +174 -0
  31. package/dist/command-registry.d.ts +28 -0
  32. package/dist/command-registry.d.ts.map +1 -1
  33. package/dist/command-registry.js +91 -1
  34. package/dist/commands/ai-status.command.d.ts +19 -0
  35. package/dist/commands/ai-status.command.d.ts.map +1 -0
  36. package/dist/commands/ai-status.command.js +94 -0
  37. package/dist/commands/api-diff.command.d.ts +11 -0
  38. package/dist/commands/api-diff.command.d.ts.map +1 -0
  39. package/dist/commands/api-diff.command.js +144 -0
  40. package/dist/commands/apply.command.d.ts.map +1 -1
  41. package/dist/commands/apply.command.js +10 -2
  42. package/dist/commands/arch.command.d.ts +9 -0
  43. package/dist/commands/arch.command.d.ts.map +1 -0
  44. package/dist/commands/arch.command.js +186 -0
  45. package/dist/commands/ask.command.d.ts.map +1 -1
  46. package/dist/commands/ask.command.js +10 -9
  47. package/dist/commands/cache-align.command.d.ts +12 -0
  48. package/dist/commands/cache-align.command.d.ts.map +1 -0
  49. package/dist/commands/cache-align.command.js +78 -0
  50. package/dist/commands/check.command.d.ts.map +1 -1
  51. package/dist/commands/check.command.js +26 -2
  52. package/dist/commands/code-intel.command.d.ts +18 -0
  53. package/dist/commands/code-intel.command.d.ts.map +1 -0
  54. package/dist/commands/code-intel.command.js +146 -0
  55. package/dist/commands/codemod.command.d.ts.map +1 -1
  56. package/dist/commands/codemod.command.js +27 -6
  57. package/dist/commands/command-catalog.d.ts +15 -3
  58. package/dist/commands/command-catalog.d.ts.map +1 -1
  59. package/dist/commands/command-catalog.js +407 -34
  60. package/dist/commands/commands.command.d.ts.map +1 -1
  61. package/dist/commands/commands.command.js +4 -4
  62. package/dist/commands/completion.command.d.ts +10 -0
  63. package/dist/commands/completion.command.d.ts.map +1 -0
  64. package/dist/commands/completion.command.js +121 -0
  65. package/dist/commands/compress.command.d.ts +8 -0
  66. package/dist/commands/compress.command.d.ts.map +1 -0
  67. package/dist/commands/compress.command.js +147 -0
  68. package/dist/commands/constructs.command.d.ts.map +1 -1
  69. package/dist/commands/constructs.command.js +89 -23
  70. package/dist/commands/context.command.d.ts.map +1 -1
  71. package/dist/commands/context.command.js +121 -1
  72. package/dist/commands/contract-gate.command.d.ts.map +1 -1
  73. package/dist/commands/contract-gate.command.js +5 -1
  74. package/dist/commands/delegate.command.d.ts +65 -0
  75. package/dist/commands/delegate.command.d.ts.map +1 -0
  76. package/dist/commands/delegate.command.js +657 -0
  77. package/dist/commands/deps-audit.command.d.ts +23 -0
  78. package/dist/commands/deps-audit.command.d.ts.map +1 -0
  79. package/dist/commands/deps-audit.command.js +270 -0
  80. package/dist/commands/dev.command.d.ts.map +1 -1
  81. package/dist/commands/dev.command.js +5 -2
  82. package/dist/commands/diff-check.command.d.ts +30 -0
  83. package/dist/commands/diff-check.command.d.ts.map +1 -0
  84. package/dist/commands/diff-check.command.js +210 -0
  85. package/dist/commands/doctor.command.d.ts.map +1 -1
  86. package/dist/commands/doctor.command.js +162 -10
  87. package/dist/commands/export.command.d.ts.map +1 -1
  88. package/dist/commands/export.command.js +76 -3
  89. package/dist/commands/framework.command.d.ts +12 -0
  90. package/dist/commands/framework.command.d.ts.map +1 -0
  91. package/dist/commands/framework.command.js +180 -0
  92. package/dist/commands/gate.command.d.ts +15 -0
  93. package/dist/commands/gate.command.d.ts.map +1 -0
  94. package/dist/commands/gate.command.js +300 -0
  95. package/dist/commands/gen.command.d.ts.map +1 -1
  96. package/dist/commands/gen.command.js +13 -1
  97. package/dist/commands/graph-code-subverbs.d.ts +33 -0
  98. package/dist/commands/graph-code-subverbs.d.ts.map +1 -0
  99. package/dist/commands/graph-code-subverbs.js +1385 -0
  100. package/dist/commands/graph.command.d.ts.map +1 -1
  101. package/dist/commands/graph.command.js +31 -2
  102. package/dist/commands/help.command.d.ts +4 -3
  103. package/dist/commands/help.command.d.ts.map +1 -1
  104. package/dist/commands/help.command.js +86 -18
  105. package/dist/commands/helper.command.js +1 -1
  106. package/dist/commands/impact.command.d.ts.map +1 -1
  107. package/dist/commands/impact.command.js +171 -1
  108. package/dist/commands/import.command.d.ts.map +1 -1
  109. package/dist/commands/import.command.js +121 -5
  110. package/dist/commands/ingest.command.d.ts.map +1 -1
  111. package/dist/commands/ingest.command.js +5 -1
  112. package/dist/commands/init.command.d.ts.map +1 -1
  113. package/dist/commands/init.command.js +174 -7
  114. package/dist/commands/knowledge-author.command.d.ts.map +1 -1
  115. package/dist/commands/knowledge-author.command.js +9 -0
  116. package/dist/commands/knowledge-propose.command.d.ts.map +1 -1
  117. package/dist/commands/knowledge-propose.command.js +4 -2
  118. package/dist/commands/knowledge.command.d.ts.map +1 -1
  119. package/dist/commands/knowledge.command.js +26 -3
  120. package/dist/commands/migrate.command.d.ts +13 -0
  121. package/dist/commands/migrate.command.d.ts.map +1 -0
  122. package/dist/commands/migrate.command.js +152 -0
  123. package/dist/commands/move-plan.command.d.ts +23 -0
  124. package/dist/commands/move-plan.command.d.ts.map +1 -0
  125. package/dist/commands/move-plan.command.js +360 -0
  126. package/dist/commands/packs-new.d.ts +1 -1
  127. package/dist/commands/packs-new.d.ts.map +1 -1
  128. package/dist/commands/packs-new.js +5 -36
  129. package/dist/commands/packs.command.d.ts.map +1 -1
  130. package/dist/commands/packs.command.js +2 -10
  131. package/dist/commands/plan-context.command.d.ts +11 -0
  132. package/dist/commands/plan-context.command.d.ts.map +1 -0
  133. package/dist/commands/plan-context.command.js +85 -0
  134. package/dist/commands/preflight.command.d.ts.map +1 -1
  135. package/dist/commands/preflight.command.js +15 -0
  136. package/dist/commands/profiles.command.js +4 -4
  137. package/dist/commands/recommend.command.d.ts +6 -0
  138. package/dist/commands/recommend.command.d.ts.map +1 -1
  139. package/dist/commands/recommend.command.js +119 -5
  140. package/dist/commands/release.command.js +13 -13
  141. package/dist/commands/rule-graph-subverbs.d.ts +3 -0
  142. package/dist/commands/rule-graph-subverbs.d.ts.map +1 -0
  143. package/dist/commands/rule-graph-subverbs.js +132 -0
  144. package/dist/commands/rules.command.d.ts.map +1 -1
  145. package/dist/commands/rules.command.js +20 -3
  146. package/dist/commands/scaffold-validate.command.d.ts +22 -0
  147. package/dist/commands/scaffold-validate.command.d.ts.map +1 -0
  148. package/dist/commands/scaffold-validate.command.js +215 -0
  149. package/dist/commands/search-structural.command.d.ts +18 -0
  150. package/dist/commands/search-structural.command.d.ts.map +1 -0
  151. package/dist/commands/search-structural.command.js +376 -0
  152. package/dist/commands/search.command.js +1 -1
  153. package/dist/commands/smart-context.command.d.ts +67 -0
  154. package/dist/commands/smart-context.command.d.ts.map +1 -0
  155. package/dist/commands/smart-context.command.js +4728 -0
  156. package/dist/commands/spike.command.d.ts +22 -0
  157. package/dist/commands/spike.command.d.ts.map +1 -0
  158. package/dist/commands/spike.command.js +235 -0
  159. package/dist/commands/surface.command.d.ts +1 -0
  160. package/dist/commands/surface.command.d.ts.map +1 -1
  161. package/dist/commands/surface.command.js +10 -3
  162. package/dist/commands/task-context.command.d.ts.map +1 -1
  163. package/dist/commands/task-context.command.js +5 -17
  164. package/dist/commands/task.command.d.ts.map +1 -1
  165. package/dist/commands/task.command.js +8 -2
  166. package/dist/commands/template-quality.command.d.ts.map +1 -1
  167. package/dist/commands/template-quality.command.js +39 -3
  168. package/dist/commands/templates.command.d.ts.map +1 -1
  169. package/dist/commands/templates.command.js +37 -2
  170. package/dist/commands/tests.command.d.ts.map +1 -1
  171. package/dist/commands/tests.command.js +13 -2
  172. package/dist/commands/watch.command.d.ts +26 -0
  173. package/dist/commands/watch.command.d.ts.map +1 -0
  174. package/dist/commands/watch.command.js +456 -0
  175. package/dist/dashboard/code-intelligence-data.d.ts +33 -0
  176. package/dist/dashboard/code-intelligence-data.d.ts.map +1 -0
  177. package/dist/dashboard/code-intelligence-data.js +329 -0
  178. package/dist/dashboard/dashboard-api-server.d.ts.map +1 -1
  179. package/dist/dashboard/dashboard-api-server.js +256 -2
  180. package/dist/dashboard/knowledge-ask.d.ts +4 -0
  181. package/dist/dashboard/knowledge-ask.d.ts.map +1 -0
  182. package/dist/dashboard/knowledge-ask.js +112 -0
  183. package/dist/env/load-dotenv.d.ts +15 -0
  184. package/dist/env/load-dotenv.d.ts.map +1 -0
  185. package/dist/env/load-dotenv.js +70 -0
  186. package/dist/export/claude-commands-export.d.ts +60 -0
  187. package/dist/export/claude-commands-export.d.ts.map +1 -0
  188. package/dist/export/claude-commands-export.js +276 -0
  189. package/dist/export/export-formats.d.ts +1 -1
  190. package/dist/export/export-formats.d.ts.map +1 -1
  191. package/dist/export/export-formats.js +139 -12
  192. package/dist/index.d.ts +3 -0
  193. package/dist/index.d.ts.map +1 -1
  194. package/dist/index.js +3 -0
  195. package/dist/init/init-templates.d.ts.map +1 -1
  196. package/dist/init/init-templates.js +133 -113
  197. package/dist/init/paths-advisory.d.ts +20 -0
  198. package/dist/init/paths-advisory.d.ts.map +1 -0
  199. package/dist/init/paths-advisory.js +88 -0
  200. package/dist/main.d.ts.map +1 -1
  201. package/dist/main.js +331 -17
  202. package/dist/output/ccr-store-config.d.ts +18 -0
  203. package/dist/output/ccr-store-config.d.ts.map +1 -0
  204. package/dist/output/ccr-store-config.js +41 -0
  205. package/dist/output/format-output.d.ts.map +1 -1
  206. package/dist/output/format-output.js +6 -1
  207. package/dist/output/output-compression.d.ts +15 -0
  208. package/dist/output/output-compression.d.ts.map +1 -0
  209. package/dist/output/output-compression.js +60 -0
  210. package/dist/output/resolve-compress-type.d.ts +22 -0
  211. package/dist/output/resolve-compress-type.d.ts.map +1 -0
  212. package/dist/output/resolve-compress-type.js +21 -0
  213. package/dist/output/watch-loop.d.ts +9 -1
  214. package/dist/output/watch-loop.d.ts.map +1 -1
  215. package/dist/output/watch-loop.js +13 -3
  216. package/dist/schemas/json-schemas.d.ts +384 -36
  217. package/dist/schemas/json-schemas.d.ts.map +1 -1
  218. package/dist/schemas/json-schemas.js +247 -36
  219. package/dist/surface/profiles.d.ts.map +1 -1
  220. package/dist/surface/profiles.js +54 -10
  221. package/dist/surface/surface-config-writer.d.ts.map +1 -1
  222. package/dist/surface/surface-config-writer.js +23 -11
  223. package/dist/validation/run-validation-loop.d.ts.map +1 -1
  224. package/dist/validation/run-validation-loop.js +5 -1
  225. package/package.json +35 -21
  226. package/dist/commands/plugin.command.d.ts +0 -11
  227. package/dist/commands/plugin.command.d.ts.map +0 -1
  228. package/dist/commands/plugin.command.js +0 -394
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deps-audit.command.d.ts","sourceRoot":"","sources":["../../src/commands/deps-audit.command.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAmBhC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAmE9B,CAAC"}
@@ -0,0 +1,270 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
2
+ import * as nodePath from 'node:path';
3
+ import { GraphQueryApi, GraphStore, NodeKind } from '@shrkcrft/graph';
4
+ import { flagBool, resolveCwd, } from "../command-registry.js";
5
+ import { asJson, header } from "../output/format-output.js";
6
+ /**
7
+ * `shrk deps-audit` — for each workspace package, compare the
8
+ * `package.json` `dependencies` / `devDependencies` / `peerDependencies`
9
+ * against the *specifiers actually imported* from source under
10
+ * `<pkg>/src/` (per the SharkCraft graph).
11
+ *
12
+ * Reports:
13
+ * - missing deps: imported but not declared (likely build failure
14
+ * in the wild — the package depends on its host's resolution)
15
+ * - unused deps: declared but never imported (lint waste)
16
+ *
17
+ * Read-only. JSON output via `--json`. Optionally restricted to one
18
+ * package via `--package <name>`.
19
+ *
20
+ * Known limitations:
21
+ * - Type-only imports (`import type x from 'y'`) still count; the
22
+ * graph can't tell them apart in v3.
23
+ * - Subpath imports (`pkg/sub`) are reduced to their root specifier.
24
+ * - Built-in node modules (`node:fs`, `fs`, …) are ignored.
25
+ */
26
+ export const depsAuditCommand = {
27
+ name: 'deps-audit',
28
+ description: 'Audit declared dependencies vs imports actually seen in each package source. Reports missing + unused deps. Read-only.',
29
+ usage: 'shrk deps-audit [--package <name>] [--json]',
30
+ async run(args) {
31
+ const cwd = resolveCwd(args);
32
+ const json = flagBool(args, 'json');
33
+ const onlyPackage = typeof args.flags.get('package') === 'string'
34
+ ? args.flags.get('package')
35
+ : null;
36
+ const store = new GraphStore(cwd);
37
+ if (!store.exists()) {
38
+ process.stderr.write('No SharkCraft graph found. Run `shrk graph index` first so deps-audit has import data.\n');
39
+ return 1;
40
+ }
41
+ const api = GraphQueryApi.fromStore(cwd);
42
+ const packages = listWorkspacePackages(cwd, onlyPackage);
43
+ if (packages.length === 0) {
44
+ process.stderr.write('No packages found (looked under packages/*, libs/*, apps/*).\n');
45
+ return 1;
46
+ }
47
+ const reports = [];
48
+ for (const pkg of packages) {
49
+ reports.push(buildPackageReport(api, cwd, pkg));
50
+ }
51
+ if (json) {
52
+ process.stdout.write(asJson({ packages: reports }) + '\n');
53
+ return 0;
54
+ }
55
+ let missingTotal = 0;
56
+ let unusedTotal = 0;
57
+ for (const r of reports) {
58
+ missingTotal += r.missingDeps.length;
59
+ unusedTotal += r.unusedDeps.length;
60
+ }
61
+ process.stdout.write(header(`deps-audit — ${reports.length} package(s), ${missingTotal} missing dep(s), ${unusedTotal} unused dep(s)`));
62
+ for (const r of reports) {
63
+ if (r.missingDeps.length === 0 && r.unusedDeps.length === 0)
64
+ continue;
65
+ process.stdout.write(`\n${r.packageName} (${r.packageDir})\n`);
66
+ if (r.missingDeps.length > 0) {
67
+ process.stdout.write(' missing (imported, not declared):\n');
68
+ for (const m of r.missingDeps) {
69
+ process.stdout.write(` - ${m.specifier} (imported ${m.importedFromCount}×)\n`);
70
+ }
71
+ }
72
+ if (r.unusedDeps.length > 0) {
73
+ process.stdout.write(' unused (declared, never imported):\n');
74
+ for (const u of r.unusedDeps) {
75
+ process.stdout.write(` - ${u.specifier} [${u.section}]\n`);
76
+ }
77
+ }
78
+ }
79
+ if (missingTotal === 0 && unusedTotal === 0) {
80
+ process.stdout.write('\nAll declared deps match actual imports. ✓\n');
81
+ }
82
+ return 0;
83
+ },
84
+ };
85
+ function listWorkspacePackages(cwd, onlyName) {
86
+ const roots = ['packages', 'libs', 'apps'].map((r) => nodePath.join(cwd, r)).filter((d) => existsSync(d));
87
+ const out = [];
88
+ for (const root of roots) {
89
+ let entries;
90
+ try {
91
+ entries = readdirSync(root);
92
+ }
93
+ catch {
94
+ continue;
95
+ }
96
+ for (const entry of entries) {
97
+ const dir = nodePath.join(root, entry);
98
+ let stat;
99
+ try {
100
+ stat = statSync(dir);
101
+ }
102
+ catch {
103
+ continue;
104
+ }
105
+ if (!stat.isDirectory())
106
+ continue;
107
+ const pkgJsonPath = nodePath.join(dir, 'package.json');
108
+ if (!existsSync(pkgJsonPath))
109
+ continue;
110
+ let pkgJson;
111
+ try {
112
+ pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf8'));
113
+ }
114
+ catch {
115
+ continue;
116
+ }
117
+ if (!pkgJson.name)
118
+ continue;
119
+ if (onlyName !== null && pkgJson.name !== onlyName)
120
+ continue;
121
+ out.push({ name: pkgJson.name, dir, pkgJsonPath });
122
+ }
123
+ }
124
+ return out;
125
+ }
126
+ function buildPackageReport(api, cwd, pkg) {
127
+ const declared = readDeclaredDeps(pkg.pkgJsonPath);
128
+ const importedSpecifiers = collectImportedSpecifiersForPackage(api, cwd, pkg.dir);
129
+ // Count how many distinct files inside the package import each specifier.
130
+ const importerCounts = new Map();
131
+ for (const spec of importedSpecifiers) {
132
+ importerCounts.set(spec, (importerCounts.get(spec) ?? 0) + 1);
133
+ }
134
+ const distinctImported = new Set(importedSpecifiers);
135
+ const declaredAll = new Map();
136
+ const declaredSections = [
137
+ ['dependencies', declared.dependencies],
138
+ ['devDependencies', declared.devDependencies],
139
+ ['peerDependencies', declared.peerDependencies],
140
+ ['optionalDependencies', declared.optionalDependencies],
141
+ ];
142
+ for (const [section, map] of declaredSections) {
143
+ for (const k of Object.keys(map))
144
+ declaredAll.set(k, section);
145
+ }
146
+ const missingDeps = [];
147
+ for (const spec of distinctImported) {
148
+ if (declaredAll.has(spec))
149
+ continue;
150
+ if (spec === pkg.name)
151
+ continue; // self-import via package name
152
+ missingDeps.push({ specifier: spec, importedFromCount: importerCounts.get(spec) ?? 0 });
153
+ }
154
+ missingDeps.sort((a, b) => b.importedFromCount - a.importedFromCount);
155
+ const unusedDeps = [];
156
+ for (const [spec, section] of declaredAll.entries()) {
157
+ if (distinctImported.has(spec))
158
+ continue;
159
+ // devDependencies for build/test tools often don't show up in graph
160
+ // imports; we still report them so the user can prune if desired.
161
+ unusedDeps.push({ specifier: spec, section });
162
+ }
163
+ unusedDeps.sort((a, b) => a.specifier.localeCompare(b.specifier));
164
+ return {
165
+ packageName: pkg.name,
166
+ packageDir: nodePath.relative(cwd, pkg.dir) || '.',
167
+ declared,
168
+ importedSpecifiers: [...distinctImported],
169
+ missingDeps,
170
+ unusedDeps,
171
+ };
172
+ }
173
+ function readDeclaredDeps(pkgJsonPath) {
174
+ try {
175
+ const body = JSON.parse(readFileSync(pkgJsonPath, 'utf8'));
176
+ return {
177
+ dependencies: asStringMap(body['dependencies']),
178
+ devDependencies: asStringMap(body['devDependencies']),
179
+ peerDependencies: asStringMap(body['peerDependencies']),
180
+ optionalDependencies: asStringMap(body['optionalDependencies']),
181
+ };
182
+ }
183
+ catch {
184
+ return { dependencies: {}, devDependencies: {}, peerDependencies: {}, optionalDependencies: {} };
185
+ }
186
+ }
187
+ function asStringMap(value) {
188
+ if (!value || typeof value !== 'object' || Array.isArray(value))
189
+ return {};
190
+ const out = {};
191
+ for (const [k, v] of Object.entries(value)) {
192
+ if (typeof v === 'string')
193
+ out[k] = v;
194
+ }
195
+ return out;
196
+ }
197
+ function collectImportedSpecifiersForPackage(api, cwd, packageDir) {
198
+ const out = [];
199
+ const relDir = nodePath.relative(cwd, packageDir).replace(/\\/g, '/');
200
+ for (const file of api.allFiles()) {
201
+ if (file.kind !== NodeKind.File)
202
+ continue;
203
+ const p = file.path ?? '';
204
+ if (!p.startsWith(relDir + '/src/') && !p.startsWith(relDir + '/'))
205
+ continue;
206
+ // Each ImportsFile edge resolves to a file node; we want the *raw*
207
+ // import specifier, which the graph carries on the edge's data
208
+ // payload. We don't have direct access here, so we approximate by
209
+ // reading the file contents and extracting from-clauses.
210
+ const abs = nodePath.isAbsolute(p) ? p : nodePath.join(cwd, p);
211
+ if (!existsSync(abs))
212
+ continue;
213
+ let body;
214
+ try {
215
+ body = readFileSync(abs, 'utf8');
216
+ }
217
+ catch {
218
+ continue;
219
+ }
220
+ for (const spec of extractRootSpecifiers(body)) {
221
+ if (isBuiltinModule(spec))
222
+ continue;
223
+ if (spec.startsWith('.') || spec.startsWith('/'))
224
+ continue; // relative
225
+ out.push(rootOfSpecifier(spec));
226
+ }
227
+ }
228
+ return out;
229
+ }
230
+ const IMPORT_FROM_RE = /(?:^|\n)\s*(?:import|export)\s+[^;]*?\s+from\s+['"]([^'"]+)['"]/g;
231
+ const REQUIRE_RE = /\brequire\(\s*['"]([^'"]+)['"]\s*\)/g;
232
+ const DYNAMIC_IMPORT_RE = /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
233
+ function extractRootSpecifiers(body) {
234
+ const out = [];
235
+ for (const m of body.matchAll(IMPORT_FROM_RE)) {
236
+ if (m[1])
237
+ out.push(m[1]);
238
+ }
239
+ for (const m of body.matchAll(REQUIRE_RE)) {
240
+ if (m[1])
241
+ out.push(m[1]);
242
+ }
243
+ for (const m of body.matchAll(DYNAMIC_IMPORT_RE)) {
244
+ if (m[1])
245
+ out.push(m[1]);
246
+ }
247
+ return out;
248
+ }
249
+ function rootOfSpecifier(spec) {
250
+ if (spec.startsWith('@')) {
251
+ const parts = spec.split('/');
252
+ return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : spec;
253
+ }
254
+ return spec.split('/')[0];
255
+ }
256
+ function isBuiltinModule(spec) {
257
+ if (spec.startsWith('node:'))
258
+ return true;
259
+ // Bun runtime builtins (`bun:test`, `bun:sqlite`, `bun:ffi`, …) are provided by
260
+ // the runtime, never an npm dependency — so they are not "missing".
261
+ if (spec.startsWith('bun:'))
262
+ return true;
263
+ // Common bare-name builtins.
264
+ return new Set([
265
+ 'fs', 'path', 'os', 'crypto', 'http', 'https', 'url', 'util', 'stream',
266
+ 'events', 'child_process', 'process', 'buffer', 'querystring', 'zlib',
267
+ 'tls', 'net', 'dns', 'dgram', 'cluster', 'worker_threads', 'perf_hooks',
268
+ 'readline', 'tty', 'vm',
269
+ ]).has(spec);
270
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"dev.command.d.ts","sourceRoot":"","sources":["../../src/commands/dev.command.ts"],"names":[],"mappings":"AA6CA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA67ChC,eAAO,MAAM,UAAU,EAAE,eAkExB,CAAC"}
1
+ {"version":3,"file":"dev.command.d.ts","sourceRoot":"","sources":["../../src/commands/dev.command.ts"],"names":[],"mappings":"AA6CA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAg8ChC,eAAO,MAAM,UAAU,EAAE,eAkExB,CAAC"}
@@ -24,7 +24,6 @@ const SUBCOMMANDS = new Set([
24
24
  'plans',
25
25
  'reports',
26
26
  'commands',
27
- 'cycle',
28
27
  ]);
29
28
  function slugify(s) {
30
29
  return s
@@ -672,7 +671,11 @@ async function validateSession(args) {
672
671
  const allVerifications = flagBool(args, 'all-verifications');
673
672
  const allowPackCommands = flagBool(args, 'allow-pack-commands');
674
673
  const wantStrict = flagBool(args, 'strict');
675
- const wantReport = flagBool(args, 'report') !== false; // default: write report
674
+ // flagBool is two-valued (absent → false), so `flagBool(...) !== false` is
675
+ // false when the flag is absent — the opposite of the intended default. Read
676
+ // the raw value: write the report by default, opt out only via --report=false.
677
+ const reportFlag = args.flags.get('report');
678
+ const wantReport = reportFlag !== false && reportFlag !== 'false';
676
679
  const wantJson = flagBool(args, 'json');
677
680
  const startedAt = new Date().toISOString();
678
681
  const reportFileName = `validate-${startedAt.replace(/[:.]/g, '-')}.json`;
@@ -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;AAwJhC,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;AA6PhC,eAAO,MAAM,aAAa,EAAE,eAW3B,CAAC;AAwfF,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"}