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

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 +19 -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 +387 -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 -1
  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 +1366 -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 -9
  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,174 @@
1
+ const TEMPLATES_FILE = 'sharkcraft/templates.ts';
2
+ export function buildFixPlan(report) {
3
+ const fixes = [];
4
+ const skipped = [];
5
+ for (const entry of report.templates) {
6
+ for (const f of entry.deterministicFindings) {
7
+ const out = dispatchDeterministic(entry, f);
8
+ if (out.kind === 'fix')
9
+ fixes.push(out.fix);
10
+ else
11
+ skipped.push(out.skip);
12
+ }
13
+ for (const f of entry.llmFindings) {
14
+ fixes.push(makeLlmFix(entry, f));
15
+ }
16
+ }
17
+ const summary = {
18
+ fixCount: fixes.length,
19
+ highConfidence: fixes.filter((f) => f.confidence === 'high').length,
20
+ mediumConfidence: fixes.filter((f) => f.confidence === 'medium').length,
21
+ lowConfidence: fixes.filter((f) => f.confidence === 'low').length,
22
+ skipped: skipped.length,
23
+ };
24
+ const generatedAt = new Date().toISOString();
25
+ return {
26
+ fixPlanId: `fix-${generatedAt.replace(/[:.]/g, '-')}`,
27
+ generatedAt,
28
+ auditId: report.auditId,
29
+ sourceFiles: [TEMPLATES_FILE],
30
+ fixes,
31
+ skipped,
32
+ summary,
33
+ };
34
+ }
35
+ function dispatchDeterministic(entry, f) {
36
+ switch (f.category) {
37
+ case 'unsafe-target':
38
+ return {
39
+ kind: 'skip',
40
+ skip: {
41
+ templateId: entry.templateId,
42
+ findingCategory: f.category,
43
+ finding: f.message,
44
+ reason: 'security-sensitive — requires human review',
45
+ },
46
+ };
47
+ case 'missing-name':
48
+ return makeFix(entry, f, 'high', 'Add a `name` field to this template.', [
49
+ `Open ${TEMPLATES_FILE}. Find the template literal with id "${entry.templateId}".`,
50
+ `Add a \`name: '<human-readable name>'\` field next to \`id\`.`,
51
+ `The name should briefly describe what the template scaffolds (e.g. "CLI command (shrk subcommand)").`,
52
+ `Do not change other fields. Verify the file still parses.`,
53
+ ].join('\n'));
54
+ case 'missing-description':
55
+ return makeFix(entry, f, 'high', 'Add a `description` field to this template.', [
56
+ `Open ${TEMPLATES_FILE}. Find the template literal with id "${entry.templateId}".`,
57
+ `Add a \`description: '<one-sentence description>'\` field. The description appears in \`shrk templates list\` and should explain what the template generates.`,
58
+ `Do not change other fields. Verify the file still parses.`,
59
+ ].join('\n'));
60
+ case 'related-id-unresolved': {
61
+ const id = extractQuoted(f.message);
62
+ if (!id) {
63
+ return makeFix(entry, f, 'medium', 'Remove an unresolved related id (id could not be auto-extracted from the message).', [
64
+ `Open ${TEMPLATES_FILE}. Find the template literal with id "${entry.templateId}".`,
65
+ `The finding is: "${f.message}"`,
66
+ `Remove the unresolved related id from the \`related\` array. Do not invent a replacement; if no real id applies, leave the array empty or omit the field.`,
67
+ `Verify the file still parses.`,
68
+ ].join('\n'));
69
+ }
70
+ return makeFix(entry, f, 'high', `Remove "${id}" from the \`related\` array.`, [
71
+ `Open ${TEMPLATES_FILE}. Find the template literal with id "${entry.templateId}".`,
72
+ `In its \`related\` array, remove the string "${id}". Do not change any other entries.`,
73
+ `Verify the file still parses and that "${id}" is not referenced elsewhere in the file.`,
74
+ ].join('\n'));
75
+ }
76
+ case 'undocumented-var': {
77
+ const varName = extractQuoted(f.message);
78
+ const where = varName ? `the variable named "${varName}"` : 'the variable referenced in the finding';
79
+ return makeFix(entry, f, 'medium', varName
80
+ ? `Add a description to variable "${varName}".`
81
+ : 'Add a description to an undocumented variable.', [
82
+ `Open ${TEMPLATES_FILE}. Find the template literal with id "${entry.templateId}".`,
83
+ `Locate ${where} inside the \`variables\` array.`,
84
+ `Add a \`description: '<short explanation>'\` field. The description should explain what the variable controls and where its value ends up in the generated output.`,
85
+ `Verify the file still parses.`,
86
+ ].join('\n'));
87
+ }
88
+ case 'required-var-no-example': {
89
+ const varName = extractQuoted(f.message);
90
+ const where = varName ? `the variable named "${varName}"` : 'the required variable referenced in the finding';
91
+ return makeFix(entry, f, 'medium', varName
92
+ ? `Add an example value to required variable "${varName}".`
93
+ : 'Add an example value to a required variable that lacks one.', [
94
+ `Open ${TEMPLATES_FILE}. Find the template literal with id "${entry.templateId}".`,
95
+ `Locate ${where} inside the \`variables\` array.`,
96
+ `Add an \`examples: ['<sample value>']\` field. Choose a sample that's representative of real usage — readable by humans, valid against any \`pattern\` that may also be defined.`,
97
+ `Verify the file still parses.`,
98
+ ].join('\n'));
99
+ }
100
+ case 'undeclared-var': {
101
+ const varName = extractPlaceholder(f.message);
102
+ const where = varName ? `\`{{${varName}}}\`` : 'the undeclared placeholder named in the finding';
103
+ return makeFix(entry, f, 'medium', varName
104
+ ? `Resolve undeclared placeholder ${where}.`
105
+ : 'Resolve an undeclared placeholder in the template body.', [
106
+ `Open ${TEMPLATES_FILE}. Find the template literal with id "${entry.templateId}".`,
107
+ `The template body uses placeholder ${where} that isn't declared in \`variables[]\`.`,
108
+ `Pick one:`,
109
+ ` (a) Add a corresponding entry to \`variables[]\` (with \`name\`, \`required\`, and ideally a \`description\` + \`examples\`). This is right if the placeholder represents intended user input.`,
110
+ ` (b) Remove the placeholder from the template body. This is right if it was a typo or leftover.`,
111
+ `Choose based on what the surrounding body and template description imply. Verify the file still parses.`,
112
+ ].join('\n'));
113
+ }
114
+ case 'path-no-convention': {
115
+ const samplePath = extractQuoted(f.message);
116
+ return makeFix(entry, f, 'low', samplePath
117
+ ? `Align template targetPath with path conventions (sample: "${samplePath}").`
118
+ : 'Align template targetPath with path conventions.', [
119
+ `The sample target path${samplePath ? ` "${samplePath}"` : ''} doesn't match any entry in \`sharkcraft/paths.ts\`.`,
120
+ `Decide between two fixes:`,
121
+ ` (a) Update the template's \`targetPath\` so its rendered output matches an existing path convention. Edit ${TEMPLATES_FILE}, find template "${entry.templateId}", and adjust its \`targetPath\` function/string.`,
122
+ ` (b) Add a matching entry to \`sharkcraft/paths.ts\` if this template's output really does belong in a new location.`,
123
+ `Prefer (a) unless the template represents a genuinely new file-shape for the project. Verify both files parse.`,
124
+ ].join('\n'));
125
+ }
126
+ default:
127
+ return makeFix(entry, f, 'low', `Address finding "${f.category}".`, [
128
+ `Open ${TEMPLATES_FILE}. Find the template literal with id "${entry.templateId}".`,
129
+ `The audit reported: ${f.message}`,
130
+ f.suggestion ? `Suggested fix from the inspector: ${f.suggestion}` : 'No specific suggestion was supplied — use judgment.',
131
+ `Apply a minimal change that resolves the finding without touching unrelated fields. Verify the file still parses.`,
132
+ ].filter(Boolean).join('\n'));
133
+ }
134
+ }
135
+ function makeFix(entry, f, confidence, intent, agentPrompt) {
136
+ return {
137
+ kind: 'fix',
138
+ fix: {
139
+ templateId: entry.templateId,
140
+ findingCategory: f.category,
141
+ finding: f.message,
142
+ severity: f.severity,
143
+ intent,
144
+ agentPrompt,
145
+ confidence,
146
+ source: 'deterministic',
147
+ },
148
+ };
149
+ }
150
+ function makeLlmFix(entry, f) {
151
+ return {
152
+ templateId: entry.templateId,
153
+ findingCategory: f.category,
154
+ finding: f.message,
155
+ severity: f.severity,
156
+ intent: `Review the LLM-flagged "${f.category}" finding and decide whether to act.`,
157
+ agentPrompt: [
158
+ `Open ${TEMPLATES_FILE}. Find the template literal with id "${entry.templateId}".`,
159
+ `An LLM critique flagged (confidence ${f.confidence.toFixed(2)}): ${f.message}`,
160
+ `LLM findings are advisory — verify against the template body and sibling templates before acting.`,
161
+ `If you choose to act, keep the change minimal and scoped to the finding. If you don't, that's also a valid outcome — record the decision in your response.`,
162
+ ].join('\n'),
163
+ confidence: 'low',
164
+ source: 'llm',
165
+ };
166
+ }
167
+ function extractQuoted(message) {
168
+ const m = message.match(/"([^"]+)"/);
169
+ return m ? m[1] : null;
170
+ }
171
+ function extractPlaceholder(message) {
172
+ const m = message.match(/\{\{\s*([A-Za-z_$][A-Za-z0-9_$]*)\s*\}\}/);
173
+ return m ? m[1] : null;
174
+ }
@@ -10,6 +10,14 @@ export interface ICommandHandler {
10
10
  name: string;
11
11
  description: string;
12
12
  usage: string;
13
+ /**
14
+ * Flags that take NO value (e.g. `json`, `no-enhance`). Listed here so the
15
+ * parser doesn't greedily swallow the following token as the flag's value —
16
+ * `compress --json <file>` / `smart-context --no-enhance "<task>"` keep the
17
+ * token as a positional regardless of argument order (the order an LLM
18
+ * naturally emits). Optional; commands without it parse exactly as before.
19
+ */
20
+ booleanFlags?: ReadonlySet<string>;
13
21
  run(args: ParsedArgs): Promise<number> | number;
14
22
  }
15
23
  /**
@@ -101,6 +109,8 @@ export declare class CommandRegistry {
101
109
  export interface ParseArgsOptions {
102
110
  /** Global cwd resolved during pre-parse, propagated to the command. */
103
111
  globalCwd?: string;
112
+ /** Flags that take no value — they never consume the following token. */
113
+ booleanFlags?: ReadonlySet<string>;
104
114
  }
105
115
  export declare function parseArgs(argv: readonly string[], options?: ParseArgsOptions): ParsedArgs;
106
116
  /**
@@ -111,6 +121,24 @@ export declare function extractGlobalCwd(argv: readonly string[]): {
111
121
  cwd?: string;
112
122
  rest: string[];
113
123
  };
124
+ /** A request to compress a command's stdout, parsed from the global flags. */
125
+ export interface IGlobalCompressDirective {
126
+ /** Force a content type for the compressor (else auto-detect). */
127
+ type?: string;
128
+ /** Query text that biases which lines/matches the compressor keeps. */
129
+ query?: string;
130
+ }
131
+ /**
132
+ * Extracts the global output-compression flags from anywhere in argv:
133
+ * `--compress` / `--ccr` (synonyms; turn it on) plus optional
134
+ * `--compress-type <t>` and `--compress-query <q>`. Returns the directive (when
135
+ * any was present) and the remaining argv with those flags removed — so the
136
+ * underlying command can be re-run cleanly without them (and never recurses).
137
+ */
138
+ export declare function extractGlobalCompress(argv: readonly string[]): {
139
+ directive?: IGlobalCompressDirective;
140
+ rest: string[];
141
+ };
114
142
  /**
115
143
  * Returns the absolute cwd for the current command:
116
144
  * 1. Command-level --cwd flag (if passed after the command)
@@ -1 +1 @@
1
- {"version":3,"file":"command-registry.d.ts","sourceRoot":"","sources":["../src/command-registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command-registry.d.ts","sourceRoot":"","sources":["../src/command-registry.ts"],"names":[],"mappings":"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"}
@@ -222,7 +222,13 @@ export function parseArgs(argv, options = {}) {
222
222
  else {
223
223
  key = arg.slice(2);
224
224
  const next = argv[i + 1];
225
- if (next !== undefined && !next.startsWith('-')) {
225
+ // A known boolean flag never consumes the following token, so
226
+ // flag-first ordering (`--json <file>`, `--no-enhance "<task>"`) keeps
227
+ // the token as a positional instead of swallowing it as the value.
228
+ if (options.booleanFlags?.has(key)) {
229
+ value = true;
230
+ }
231
+ else if (next !== undefined && !next.startsWith('-')) {
226
232
  value = next;
227
233
  i += 1;
228
234
  }
@@ -256,6 +262,13 @@ export function extractGlobalCwd(argv) {
256
262
  let cwd;
257
263
  for (let i = 0; i < argv.length; i += 1) {
258
264
  const t = argv[i];
265
+ // Honor the POSIX `--` end-of-options separator (as parseArgs does):
266
+ // everything after it is a literal positional, so a `--cwd` there must not
267
+ // be intercepted. Preserve `--` and the remainder verbatim.
268
+ if (t === '--') {
269
+ rest.push(...argv.slice(i));
270
+ break;
271
+ }
259
272
  if (t === '--cwd') {
260
273
  const next = argv[i + 1];
261
274
  if (next !== undefined && !next.startsWith('-')) {
@@ -277,6 +290,83 @@ export function extractGlobalCwd(argv) {
277
290
  cwd = nodePath.resolve(process.cwd(), cwd);
278
291
  return cwd === undefined ? { rest } : { cwd, rest };
279
292
  }
293
+ /**
294
+ * Extracts the global output-compression flags from anywhere in argv:
295
+ * `--compress` / `--ccr` (synonyms; turn it on) plus optional
296
+ * `--compress-type <t>` and `--compress-query <q>`. Returns the directive (when
297
+ * any was present) and the remaining argv with those flags removed — so the
298
+ * underlying command can be re-run cleanly without them (and never recurses).
299
+ */
300
+ export function extractGlobalCompress(argv) {
301
+ const rest = [];
302
+ let active = false;
303
+ let type;
304
+ let query;
305
+ const valued = (token, flag, set, i) => {
306
+ if (token === flag) {
307
+ const next = argv[i + 1];
308
+ if (next !== undefined && !next.startsWith('-')) {
309
+ set(next);
310
+ return true; // caller skips next
311
+ }
312
+ return false;
313
+ }
314
+ return false;
315
+ };
316
+ for (let i = 0; i < argv.length; i += 1) {
317
+ const t = argv[i];
318
+ // Honor the POSIX `--` end-of-options separator exactly as parseArgs does:
319
+ // everything after it is a literal positional, so a compress-flag-shaped
320
+ // token there must NOT be intercepted (and the next token must not be
321
+ // swallowed as a value). Preserve `--` and the remainder verbatim for the
322
+ // child to re-parse.
323
+ if (t === '--') {
324
+ rest.push(...argv.slice(i));
325
+ break;
326
+ }
327
+ if (t === '--compress' || t === '--ccr') {
328
+ active = true;
329
+ continue;
330
+ }
331
+ if (t.startsWith('--compress-type=')) {
332
+ type = t.slice('--compress-type='.length);
333
+ active = true;
334
+ continue;
335
+ }
336
+ if (t.startsWith('--compress-query=')) {
337
+ query = t.slice('--compress-query='.length);
338
+ active = true;
339
+ continue;
340
+ }
341
+ if (t === '--compress-type') {
342
+ if (valued(t, '--compress-type', (v) => (type = v), i)) {
343
+ active = true;
344
+ i += 1;
345
+ continue;
346
+ }
347
+ active = true;
348
+ continue;
349
+ }
350
+ if (t === '--compress-query') {
351
+ if (valued(t, '--compress-query', (v) => (query = v), i)) {
352
+ active = true;
353
+ i += 1;
354
+ continue;
355
+ }
356
+ active = true;
357
+ continue;
358
+ }
359
+ rest.push(t);
360
+ }
361
+ if (!active)
362
+ return { rest };
363
+ const directive = {};
364
+ if (type !== undefined)
365
+ directive.type = type;
366
+ if (query !== undefined)
367
+ directive.query = query;
368
+ return { directive, rest };
369
+ }
280
370
  /**
281
371
  * Returns the absolute cwd for the current command:
282
372
  * 1. Command-level --cwd flag (if passed after the command)
@@ -0,0 +1,19 @@
1
+ import { type ICommandHandler } from '../command-registry.js';
2
+ /**
3
+ * `shrk ai-status` — one-shot self-check of the LLM wiring.
4
+ *
5
+ * Designed for agents (like Claude) that want to know whether shrk's
6
+ * LLM enrichment is going to do anything useful, without having to
7
+ * run a full audit. Three pieces of information:
8
+ * 1. Which provider, if any, the local-first walk would pick.
9
+ * 2. The structured `ai` block (the same one every audit emits) so
10
+ * the agent can act on the hints.
11
+ * 3. Optional `--ping`: a tiny live request that proves the
12
+ * provider really responds (the resolver only checks env vars).
13
+ *
14
+ * The deterministic baseline contract: works without LLM. With no
15
+ * provider reachable, the output is still useful — it carries the
16
+ * setup hints.
17
+ */
18
+ export declare const aiStatusCommand: ICommandHandler;
19
+ //# sourceMappingURL=ai-status.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-status.command.d.ts","sourceRoot":"","sources":["../../src/commands/ai-status.command.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,eAAe,EAAE,eAkD7B,CAAC"}
@@ -0,0 +1,94 @@
1
+ import { AiMessageRole, buildAiBlock, renderAiBlockMarkdown, selectAiProvider, } from '@shrkcrft/ai';
2
+ import { flagBool, flagNumber, flagString, } from "../command-registry.js";
3
+ import { asJson, header, kv } from "../output/format-output.js";
4
+ /**
5
+ * `shrk ai-status` — one-shot self-check of the LLM wiring.
6
+ *
7
+ * Designed for agents (like Claude) that want to know whether shrk's
8
+ * LLM enrichment is going to do anything useful, without having to
9
+ * run a full audit. Three pieces of information:
10
+ * 1. Which provider, if any, the local-first walk would pick.
11
+ * 2. The structured `ai` block (the same one every audit emits) so
12
+ * the agent can act on the hints.
13
+ * 3. Optional `--ping`: a tiny live request that proves the
14
+ * provider really responds (the resolver only checks env vars).
15
+ *
16
+ * The deterministic baseline contract: works without LLM. With no
17
+ * provider reachable, the output is still useful — it carries the
18
+ * setup hints.
19
+ */
20
+ export const aiStatusCommand = {
21
+ name: 'ai-status',
22
+ description: 'Report which AI provider shrk would use right now, with setup or upgrade hints. `--ping` verifies the provider actually responds. Read-only.',
23
+ usage: 'shrk ai-status [--provider auto|ollama|llamacpp|claude|gemini] [--ping] [--ping-timeout <ms>] [--json]',
24
+ async run(args) {
25
+ const providerKind = flagString(args, 'provider');
26
+ const json = flagBool(args, 'json');
27
+ const wantPing = flagBool(args, 'ping');
28
+ const pingTimeoutMs = flagNumber(args, 'ping-timeout') ?? 8000;
29
+ const selection = selectAiProvider(providerKind);
30
+ const ai = buildAiBlock({ selection, userOptedOut: false });
31
+ let ping = null;
32
+ if (wantPing) {
33
+ ping = selection.provider
34
+ ? await pingProvider(selection.provider, pingTimeoutMs)
35
+ : { ok: false, reason: 'no provider reachable — nothing to ping', elapsedMs: 0 };
36
+ }
37
+ if (json) {
38
+ process.stdout.write(asJson({
39
+ ai,
40
+ ...(ping ? { ping } : {}),
41
+ }) + '\n');
42
+ return ai.reachable && (!ping || ping.ok) ? 0 : 1;
43
+ }
44
+ process.stdout.write(header('AI status'));
45
+ process.stdout.write(kv('reachable', ai.reachable ? 'yes' : 'no') + '\n');
46
+ process.stdout.write(kv('requested provider', ai.requestedProvider) + '\n');
47
+ process.stdout.write(kv('resolved provider', ai.providerId ?? '(none)') + '\n');
48
+ if (ping) {
49
+ process.stdout.write(kv('ping', ping.ok
50
+ ? `ok in ${ping.elapsedMs}ms` + (ping.model ? ` (model: ${ping.model})` : '')
51
+ : `failed: ${ping.reason}`) + '\n');
52
+ }
53
+ process.stdout.write('\n');
54
+ process.stdout.write(renderAiBlockMarkdown(ai));
55
+ return ai.reachable && (!ping || ping.ok) ? 0 : 1;
56
+ },
57
+ };
58
+ async function pingProvider(provider, timeoutMs) {
59
+ const start = Date.now();
60
+ // Tiny prompt with bounded output — we just want to prove the round-trip works.
61
+ const requestPromise = provider.send({
62
+ messages: [
63
+ { role: AiMessageRole.System, content: 'Respond with the single word: ok' },
64
+ { role: AiMessageRole.User, content: 'ping' },
65
+ ],
66
+ maxTokens: 8,
67
+ });
68
+ const timeoutPromise = new Promise((resolve) => {
69
+ setTimeout(() => resolve({ ok: false, error: new Error(`timed out after ${timeoutMs}ms`) }), timeoutMs);
70
+ });
71
+ try {
72
+ const res = (await Promise.race([requestPromise, timeoutPromise]));
73
+ const elapsedMs = Date.now() - start;
74
+ if (!('value' in res) || !res.ok) {
75
+ const reason = 'error' in res
76
+ ? res.error.message ?? String(res.error)
77
+ : 'no response';
78
+ return { ok: false, reason, elapsedMs };
79
+ }
80
+ const value = res.value;
81
+ return {
82
+ ok: true,
83
+ elapsedMs,
84
+ ...(value.model ? { model: value.model } : {}),
85
+ };
86
+ }
87
+ catch (e) {
88
+ return {
89
+ ok: false,
90
+ reason: e.message,
91
+ elapsedMs: Date.now() - start,
92
+ };
93
+ }
94
+ }
@@ -0,0 +1,11 @@
1
+ import { type ICommandHandler } from '../command-registry.js';
2
+ /**
3
+ * `shrk api-diff` — compare the current code-graph's public-API
4
+ * surface to a saved baseline (or another snapshot file).
5
+ *
6
+ * Sub-verbs:
7
+ * - shrk api-diff capture --output <path> write the current surface to disk
8
+ * - shrk api-diff <baseline.json> diff current vs baseline
9
+ */
10
+ export declare const apiDiffCommand: ICommandHandler;
11
+ //# sourceMappingURL=api-diff.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-diff.command.d.ts","sourceRoot":"","sources":["../../src/commands/api-diff.command.ts"],"names":[],"mappings":"AASA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,EAAE,eAoB5B,CAAC"}
@@ -0,0 +1,144 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import * as nodePath from 'node:path';
3
+ import { diffApiSurfaces, extractApiSurface, extractApiSurfaceWithProgram, } from '@shrkcrft/api-surface-diff';
4
+ import { GraphStore } from '@shrkcrft/graph';
5
+ import { flagBool, flagList, flagString, resolveCwd, } from "../command-registry.js";
6
+ import { asJson, header, kv } from "../output/format-output.js";
7
+ /**
8
+ * `shrk api-diff` — compare the current code-graph's public-API
9
+ * surface to a saved baseline (or another snapshot file).
10
+ *
11
+ * Sub-verbs:
12
+ * - shrk api-diff capture --output <path> write the current surface to disk
13
+ * - shrk api-diff <baseline.json> diff current vs baseline
14
+ */
15
+ export const apiDiffCommand = {
16
+ name: 'api-diff',
17
+ description: 'Compare the current public API surface to a saved baseline. Reports added / removed / kind-changed / moved symbols, with breaking-change severity.',
18
+ usage: 'shrk api-diff capture --output <path> [--packages @scope/a,@scope/b] [--with-signatures] | shrk api-diff <baseline.json> [--packages @scope/a,@scope/b] [--with-signatures] [--json] [--fail-on-breaking] (--packages takes EXACT workspace package names, comma-separated or repeated)',
19
+ async run(args) {
20
+ const cwd = resolveCwd(args);
21
+ const wantJson = flagBool(args, 'json');
22
+ const sub = args.positional[0];
23
+ if (!sub) {
24
+ process.stderr.write(this.usage + '\n');
25
+ return 2;
26
+ }
27
+ if (sub === 'capture') {
28
+ return runCapture(args, cwd, wantJson);
29
+ }
30
+ return runDiff(args, cwd, wantJson, sub);
31
+ },
32
+ };
33
+ async function runCapture(args, cwd, wantJson) {
34
+ const outputFlag = flagString(args, 'output');
35
+ if (!outputFlag) {
36
+ process.stderr.write('shrk api-diff capture requires --output <path>\n');
37
+ return 2;
38
+ }
39
+ const surface = readSurfaceFromCwd(cwd, args);
40
+ if (!surface)
41
+ return 1;
42
+ const abs = nodePath.isAbsolute(outputFlag) ? outputFlag : nodePath.resolve(cwd, outputFlag);
43
+ mkdirSync(nodePath.dirname(abs), { recursive: true });
44
+ writeFileSync(abs, JSON.stringify(surface, null, 2), 'utf8');
45
+ if (wantJson) {
46
+ process.stdout.write(asJson({ ok: true, wrote: abs, total: surface.total }) + '\n');
47
+ return 0;
48
+ }
49
+ process.stdout.write(header('API surface capture'));
50
+ process.stdout.write(kv('wrote', abs) + '\n');
51
+ process.stdout.write(kv('symbols', String(surface.total)) + '\n');
52
+ return 0;
53
+ }
54
+ async function runDiff(args, cwd, wantJson, baselinePath) {
55
+ const baselineAbs = nodePath.isAbsolute(baselinePath)
56
+ ? baselinePath
57
+ : nodePath.resolve(cwd, baselinePath);
58
+ let baseline;
59
+ try {
60
+ baseline = JSON.parse(readFileSync(baselineAbs, 'utf8'));
61
+ }
62
+ catch (e) {
63
+ process.stderr.write(`Baseline read error: ${e.message}\n`);
64
+ return 2;
65
+ }
66
+ const current = readSurfaceFromCwd(cwd, args);
67
+ if (!current)
68
+ return 1;
69
+ const diff = diffApiSurfaces(baseline, current);
70
+ const failOnBreaking = flagBool(args, 'fail-on-breaking');
71
+ if (wantJson) {
72
+ process.stdout.write(asJson(diff) + '\n');
73
+ return failOnBreaking && diff.breakingCount > 0 ? 1 : 0;
74
+ }
75
+ process.stdout.write(header('API surface diff'));
76
+ process.stdout.write(kv('schema', diff.schema) + '\n');
77
+ process.stdout.write(kv('baseline symbols', String(diff.baselineTotal)) + '\n');
78
+ process.stdout.write(kv('current symbols', String(diff.currentTotal)) + '\n');
79
+ process.stdout.write(kv('added', String(diff.added)) + '\n');
80
+ process.stdout.write(kv('removed', String(diff.removed)) + '\n');
81
+ process.stdout.write(kv('changed', String(diff.changed)) + '\n');
82
+ process.stdout.write(kv('breaking', String(diff.breakingCount)) + '\n');
83
+ if (diff.entries.length === 0) {
84
+ process.stdout.write('\nNo changes.\n');
85
+ return 0;
86
+ }
87
+ process.stdout.write('\nEntries:\n');
88
+ for (const e of diff.entries.slice(0, 80)) {
89
+ process.stdout.write(` [${e.severity}] [${e.kind}] ${e.message}\n`);
90
+ }
91
+ if (diff.entries.length > 80) {
92
+ process.stdout.write(` … (${diff.entries.length - 80} more)\n`);
93
+ }
94
+ return failOnBreaking && diff.breakingCount > 0 ? 1 : 0;
95
+ }
96
+ function readSurfaceFromCwd(cwd, args) {
97
+ const packages = flagList(args, 'packages');
98
+ const withSignatures = flagBool(args, 'with-signatures');
99
+ let surface;
100
+ if (withSignatures) {
101
+ const result = extractApiSurfaceWithProgram({
102
+ projectRoot: cwd,
103
+ ...(packages.length > 0 ? { packageFilter: packages } : {}),
104
+ });
105
+ for (const d of result.diagnostics.slice(0, 5)) {
106
+ process.stderr.write(`! ${d}\n`);
107
+ }
108
+ surface = result.surface;
109
+ }
110
+ else {
111
+ const store = new GraphStore(cwd);
112
+ if (!store.exists()) {
113
+ process.stderr.write("Code-graph store missing. Run 'shrk graph index' first.\n");
114
+ return undefined;
115
+ }
116
+ const snap = store.loadSnapshot();
117
+ surface = extractApiSurface(snap, {
118
+ ...(packages.length > 0 ? { packageFilter: packages } : {}),
119
+ });
120
+ }
121
+ return applyPackageFilterGuard(surface, packages);
122
+ }
123
+ /**
124
+ * A `--packages` filter that resolves to no known workspace package is a quiet
125
+ * footgun: the extractor silently returns a 0-symbol surface (exit 0) that is
126
+ * indistinguishable from a package that genuinely exports nothing. When EVERY
127
+ * requested filter is unknown, abort loudly; when only some are, warn and keep
128
+ * the partial result.
129
+ */
130
+ function applyPackageFilterGuard(surface, packages) {
131
+ const unmatched = surface.unmatchedFilters ?? [];
132
+ if (packages.length === 0 || unmatched.length === 0)
133
+ return surface;
134
+ const matched = Object.keys(surface.countsByPackage).filter((k) => k !== '<no-package>');
135
+ if (unmatched.length === packages.length) {
136
+ process.stderr.write(`--packages matched no known workspace package: ${unmatched.join(', ')}\n` +
137
+ ' Pass exact package names (npm "name", e.g. @shrkcrft/core), comma-separated or repeated.\n');
138
+ return undefined;
139
+ }
140
+ process.stderr.write(`! --packages: ignoring unknown package(s): ${unmatched.join(', ')}` +
141
+ (matched.length > 0 ? ` (matched: ${matched.join(', ')})` : '') +
142
+ '\n');
143
+ return surface;
144
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"apply.command.d.ts","sourceRoot":"","sources":["../../src/commands/apply.command.ts"],"names":[],"mappings":"AAqDA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAyLhC,eAAO,MAAM,YAAY,EAAE,eAyrB1B,CAAC"}
1
+ {"version":3,"file":"apply.command.d.ts","sourceRoot":"","sources":["../../src/commands/apply.command.ts"],"names":[],"mappings":"AAqDA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAyLhC,eAAO,MAAM,YAAY,EAAE,eAisB1B,CAAC"}