@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.
- package/dist/audit/knowledge-audit-llm.d.ts +19 -0
- package/dist/audit/knowledge-audit-llm.d.ts.map +1 -0
- package/dist/audit/knowledge-audit-llm.js +164 -0
- package/dist/audit/knowledge-audit.d.ts +61 -0
- package/dist/audit/knowledge-audit.d.ts.map +1 -0
- package/dist/audit/knowledge-audit.js +203 -0
- package/dist/audit/knowledge-fix-plan-llm.d.ts +11 -0
- package/dist/audit/knowledge-fix-plan-llm.d.ts.map +1 -0
- package/dist/audit/knowledge-fix-plan-llm.js +141 -0
- package/dist/audit/knowledge-fix-plan.d.ts +41 -0
- package/dist/audit/knowledge-fix-plan.d.ts.map +1 -0
- package/dist/audit/knowledge-fix-plan.js +125 -0
- package/dist/audit/pipeline-audit-llm.d.ts +11 -0
- package/dist/audit/pipeline-audit-llm.d.ts.map +1 -0
- package/dist/audit/pipeline-audit-llm.js +134 -0
- package/dist/audit/pipeline-audit.d.ts +69 -0
- package/dist/audit/pipeline-audit.d.ts.map +1 -0
- package/dist/audit/pipeline-audit.js +166 -0
- package/dist/audit/templates-audit-llm.d.ts +19 -0
- package/dist/audit/templates-audit-llm.d.ts.map +1 -0
- package/dist/audit/templates-audit-llm.js +207 -0
- package/dist/audit/templates-audit.d.ts +63 -0
- package/dist/audit/templates-audit.d.ts.map +1 -0
- package/dist/audit/templates-audit.js +171 -0
- package/dist/audit/templates-fix-plan-llm.d.ts +19 -0
- package/dist/audit/templates-fix-plan-llm.d.ts.map +1 -0
- package/dist/audit/templates-fix-plan-llm.js +162 -0
- package/dist/audit/templates-fix-plan.d.ts +37 -0
- package/dist/audit/templates-fix-plan.d.ts.map +1 -0
- package/dist/audit/templates-fix-plan.js +174 -0
- package/dist/command-registry.d.ts +28 -0
- package/dist/command-registry.d.ts.map +1 -1
- package/dist/command-registry.js +91 -1
- package/dist/commands/ai-status.command.d.ts +19 -0
- package/dist/commands/ai-status.command.d.ts.map +1 -0
- package/dist/commands/ai-status.command.js +94 -0
- package/dist/commands/api-diff.command.d.ts +11 -0
- package/dist/commands/api-diff.command.d.ts.map +1 -0
- package/dist/commands/api-diff.command.js +144 -0
- package/dist/commands/apply.command.d.ts.map +1 -1
- package/dist/commands/apply.command.js +10 -2
- package/dist/commands/arch.command.d.ts +9 -0
- package/dist/commands/arch.command.d.ts.map +1 -0
- package/dist/commands/arch.command.js +186 -0
- package/dist/commands/ask.command.d.ts.map +1 -1
- package/dist/commands/ask.command.js +10 -9
- package/dist/commands/cache-align.command.d.ts +12 -0
- package/dist/commands/cache-align.command.d.ts.map +1 -0
- package/dist/commands/cache-align.command.js +78 -0
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +19 -2
- package/dist/commands/code-intel.command.d.ts +18 -0
- package/dist/commands/code-intel.command.d.ts.map +1 -0
- package/dist/commands/code-intel.command.js +146 -0
- package/dist/commands/codemod.command.d.ts.map +1 -1
- package/dist/commands/codemod.command.js +27 -6
- package/dist/commands/command-catalog.d.ts +15 -3
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +387 -34
- package/dist/commands/commands.command.d.ts.map +1 -1
- package/dist/commands/commands.command.js +4 -4
- package/dist/commands/completion.command.d.ts +10 -0
- package/dist/commands/completion.command.d.ts.map +1 -0
- package/dist/commands/completion.command.js +121 -0
- package/dist/commands/compress.command.d.ts +8 -0
- package/dist/commands/compress.command.d.ts.map +1 -0
- package/dist/commands/compress.command.js +147 -0
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +89 -23
- package/dist/commands/context.command.d.ts.map +1 -1
- package/dist/commands/context.command.js +121 -1
- package/dist/commands/contract-gate.command.d.ts.map +1 -1
- package/dist/commands/contract-gate.command.js +5 -1
- package/dist/commands/delegate.command.d.ts +65 -0
- package/dist/commands/delegate.command.d.ts.map +1 -0
- package/dist/commands/delegate.command.js +657 -0
- package/dist/commands/deps-audit.command.d.ts +23 -0
- package/dist/commands/deps-audit.command.d.ts.map +1 -0
- package/dist/commands/deps-audit.command.js +270 -0
- package/dist/commands/dev.command.d.ts.map +1 -1
- package/dist/commands/dev.command.js +5 -1
- package/dist/commands/diff-check.command.d.ts +30 -0
- package/dist/commands/diff-check.command.d.ts.map +1 -0
- package/dist/commands/diff-check.command.js +210 -0
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +162 -10
- package/dist/commands/export.command.d.ts.map +1 -1
- package/dist/commands/export.command.js +76 -3
- package/dist/commands/framework.command.d.ts +12 -0
- package/dist/commands/framework.command.d.ts.map +1 -0
- package/dist/commands/framework.command.js +180 -0
- package/dist/commands/gate.command.d.ts +15 -0
- package/dist/commands/gate.command.d.ts.map +1 -0
- package/dist/commands/gate.command.js +300 -0
- package/dist/commands/gen.command.d.ts.map +1 -1
- package/dist/commands/gen.command.js +13 -1
- package/dist/commands/graph-code-subverbs.d.ts +33 -0
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -0
- package/dist/commands/graph-code-subverbs.js +1366 -0
- package/dist/commands/graph.command.d.ts.map +1 -1
- package/dist/commands/graph.command.js +31 -2
- package/dist/commands/help.command.d.ts +4 -3
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +86 -18
- package/dist/commands/helper.command.js +1 -1
- package/dist/commands/impact.command.d.ts.map +1 -1
- package/dist/commands/impact.command.js +171 -1
- package/dist/commands/import.command.d.ts.map +1 -1
- package/dist/commands/import.command.js +121 -5
- package/dist/commands/ingest.command.d.ts.map +1 -1
- package/dist/commands/ingest.command.js +5 -1
- package/dist/commands/init.command.d.ts.map +1 -1
- package/dist/commands/init.command.js +174 -7
- package/dist/commands/knowledge-author.command.d.ts.map +1 -1
- package/dist/commands/knowledge-author.command.js +9 -0
- package/dist/commands/knowledge-propose.command.d.ts.map +1 -1
- package/dist/commands/knowledge-propose.command.js +4 -2
- package/dist/commands/knowledge.command.d.ts.map +1 -1
- package/dist/commands/knowledge.command.js +26 -3
- package/dist/commands/migrate.command.d.ts +13 -0
- package/dist/commands/migrate.command.d.ts.map +1 -0
- package/dist/commands/migrate.command.js +152 -0
- package/dist/commands/move-plan.command.d.ts +23 -0
- package/dist/commands/move-plan.command.d.ts.map +1 -0
- package/dist/commands/move-plan.command.js +360 -0
- package/dist/commands/packs-new.d.ts +1 -1
- package/dist/commands/packs-new.d.ts.map +1 -1
- package/dist/commands/packs-new.js +5 -36
- package/dist/commands/packs.command.d.ts.map +1 -1
- package/dist/commands/packs.command.js +2 -10
- package/dist/commands/plan-context.command.d.ts +11 -0
- package/dist/commands/plan-context.command.d.ts.map +1 -0
- package/dist/commands/plan-context.command.js +85 -0
- package/dist/commands/preflight.command.d.ts.map +1 -1
- package/dist/commands/preflight.command.js +15 -0
- package/dist/commands/profiles.command.js +4 -4
- package/dist/commands/recommend.command.d.ts +6 -0
- package/dist/commands/recommend.command.d.ts.map +1 -1
- package/dist/commands/recommend.command.js +119 -5
- package/dist/commands/release.command.js +13 -13
- package/dist/commands/rule-graph-subverbs.d.ts +3 -0
- package/dist/commands/rule-graph-subverbs.d.ts.map +1 -0
- package/dist/commands/rule-graph-subverbs.js +132 -0
- package/dist/commands/rules.command.d.ts.map +1 -1
- package/dist/commands/rules.command.js +20 -3
- package/dist/commands/scaffold-validate.command.d.ts +22 -0
- package/dist/commands/scaffold-validate.command.d.ts.map +1 -0
- package/dist/commands/scaffold-validate.command.js +215 -0
- package/dist/commands/search-structural.command.d.ts +18 -0
- package/dist/commands/search-structural.command.d.ts.map +1 -0
- package/dist/commands/search-structural.command.js +376 -0
- package/dist/commands/search.command.js +1 -1
- package/dist/commands/smart-context.command.d.ts +67 -0
- package/dist/commands/smart-context.command.d.ts.map +1 -0
- package/dist/commands/smart-context.command.js +4728 -0
- package/dist/commands/spike.command.d.ts +22 -0
- package/dist/commands/spike.command.d.ts.map +1 -0
- package/dist/commands/spike.command.js +235 -0
- package/dist/commands/surface.command.d.ts +1 -0
- package/dist/commands/surface.command.d.ts.map +1 -1
- package/dist/commands/surface.command.js +10 -3
- package/dist/commands/task-context.command.d.ts.map +1 -1
- package/dist/commands/task-context.command.js +5 -17
- package/dist/commands/task.command.d.ts.map +1 -1
- package/dist/commands/task.command.js +8 -2
- package/dist/commands/template-quality.command.d.ts.map +1 -1
- package/dist/commands/template-quality.command.js +39 -3
- package/dist/commands/templates.command.d.ts.map +1 -1
- package/dist/commands/templates.command.js +37 -2
- package/dist/commands/tests.command.d.ts.map +1 -1
- package/dist/commands/tests.command.js +13 -2
- package/dist/commands/watch.command.d.ts +26 -0
- package/dist/commands/watch.command.d.ts.map +1 -0
- package/dist/commands/watch.command.js +456 -0
- package/dist/dashboard/code-intelligence-data.d.ts +33 -0
- package/dist/dashboard/code-intelligence-data.d.ts.map +1 -0
- package/dist/dashboard/code-intelligence-data.js +329 -0
- package/dist/dashboard/dashboard-api-server.d.ts.map +1 -1
- package/dist/dashboard/dashboard-api-server.js +256 -2
- package/dist/dashboard/knowledge-ask.d.ts +4 -0
- package/dist/dashboard/knowledge-ask.d.ts.map +1 -0
- package/dist/dashboard/knowledge-ask.js +112 -0
- package/dist/env/load-dotenv.d.ts +15 -0
- package/dist/env/load-dotenv.d.ts.map +1 -0
- package/dist/env/load-dotenv.js +70 -0
- package/dist/export/claude-commands-export.d.ts +60 -0
- package/dist/export/claude-commands-export.d.ts.map +1 -0
- package/dist/export/claude-commands-export.js +276 -0
- package/dist/export/export-formats.d.ts +1 -1
- package/dist/export/export-formats.d.ts.map +1 -1
- package/dist/export/export-formats.js +139 -12
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/init/init-templates.d.ts.map +1 -1
- package/dist/init/init-templates.js +133 -113
- package/dist/init/paths-advisory.d.ts +20 -0
- package/dist/init/paths-advisory.d.ts.map +1 -0
- package/dist/init/paths-advisory.js +88 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +331 -17
- package/dist/output/ccr-store-config.d.ts +18 -0
- package/dist/output/ccr-store-config.d.ts.map +1 -0
- package/dist/output/ccr-store-config.js +41 -0
- package/dist/output/format-output.d.ts.map +1 -1
- package/dist/output/format-output.js +6 -1
- package/dist/output/output-compression.d.ts +15 -0
- package/dist/output/output-compression.d.ts.map +1 -0
- package/dist/output/output-compression.js +60 -0
- package/dist/output/resolve-compress-type.d.ts +22 -0
- package/dist/output/resolve-compress-type.d.ts.map +1 -0
- package/dist/output/resolve-compress-type.js +21 -0
- package/dist/output/watch-loop.d.ts +9 -1
- package/dist/output/watch-loop.d.ts.map +1 -1
- package/dist/output/watch-loop.js +13 -3
- package/dist/schemas/json-schemas.d.ts +384 -36
- package/dist/schemas/json-schemas.d.ts.map +1 -1
- package/dist/schemas/json-schemas.js +247 -36
- package/dist/surface/profiles.d.ts.map +1 -1
- package/dist/surface/profiles.js +54 -9
- package/dist/surface/surface-config-writer.d.ts.map +1 -1
- package/dist/surface/surface-config-writer.js +23 -11
- package/dist/validation/run-validation-loop.d.ts.map +1 -1
- package/dist/validation/run-validation-loop.js +5 -1
- package/package.json +35 -21
- package/dist/commands/plugin.command.d.ts +0 -11
- package/dist/commands/plugin.command.d.ts.map +0 -1
- package/dist/commands/plugin.command.js +0 -394
|
@@ -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":"AAEA,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACrC,0EAA0E;IAC1E,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACjD;AAED;;;;;GAKG;AACH,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAMD,mDAAmD;AACnD,MAAM,WAAW,kBAAkB;IACjC,mFAAmF;IACnF,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,sEAAsE;IACtE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,6EAA6E;IAC7E,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoC;IACzD,uFAAuF;IACvF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;IAE5D,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAIxC,0DAA0D;IAC1D,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAIjE;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAgBnE,qCAAqC;IACrC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKlD,uCAAuC;IACvC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKpD,iEAAiE;IACjE,OAAO,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAa9E,gCAAgC;IAChC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAK9C,8BAA8B;IAC9B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAOhE,8DAA8D;IAC9D,KAAK,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,GAAG,SAAS;IAK3D,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAInC,UAAU,IAAI,SAAS,MAAM,EAAE;IAW/B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,eAAe,EAAE;IAWpD,2EAA2E;IAC3E,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE;IAUzD,gBAAgB,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAI/C,kBAAkB,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAIjD,gDAAgD;IAChD,IAAI,IAAI,SAAS,eAAe,EAAE;IAQlC,oDAAoD;IACpD,OAAO,IAAI,aAAa,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;KAAE,CAAC;IAMjG;;;;;;;;OAQG;IACH,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,kBAAkB;IAsBtD,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,UAAU;CAWnB;AAQD,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"command-registry.d.ts","sourceRoot":"","sources":["../src/command-registry.ts"],"names":[],"mappings":"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"}
|
package/dist/command-registry.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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"}
|