@shrkcrft/cli 0.1.0-alpha.7 → 0.1.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/command-catalog.d.ts +7 -3
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +112 -33
- package/dist/commands/commands.command.d.ts.map +1 -1
- package/dist/commands/commands.command.js +4 -4
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +5 -22
- package/dist/commands/diff-check.command.d.ts +30 -0
- package/dist/commands/diff-check.command.d.ts.map +1 -0
- package/dist/commands/diff-check.command.js +210 -0
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +34 -2
- package/dist/commands/export.command.d.ts.map +1 -1
- package/dist/commands/export.command.js +76 -3
- package/dist/commands/help.command.d.ts +4 -3
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +74 -16
- package/dist/commands/helper.command.js +1 -1
- package/dist/commands/import.command.d.ts.map +1 -1
- package/dist/commands/import.command.js +121 -5
- package/dist/commands/init.command.d.ts.map +1 -1
- package/dist/commands/init.command.js +151 -7
- package/dist/commands/packs-new.d.ts +1 -1
- package/dist/commands/packs-new.d.ts.map +1 -1
- package/dist/commands/packs-new.js +2 -26
- package/dist/commands/profiles.command.js +4 -4
- package/dist/commands/release.command.js +13 -13
- package/dist/commands/search.command.js +1 -1
- package/dist/commands/task-context.command.js +0 -16
- package/dist/export/claude-commands-export.d.ts +60 -0
- package/dist/export/claude-commands-export.d.ts.map +1 -0
- package/dist/export/claude-commands-export.js +276 -0
- package/dist/export/export-formats.d.ts +1 -1
- package/dist/export/export-formats.d.ts.map +1 -1
- package/dist/export/export-formats.js +139 -12
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +104 -11
- package/package.json +20 -20
- package/dist/commands/plugin.command.d.ts +0 -11
- package/dist/commands/plugin.command.d.ts.map +0 -1
- package/dist/commands/plugin.command.js +0 -394
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
import { aggregateActionHints, KnowledgeType } from '@shrkcrft/knowledge';
|
|
2
2
|
import { priorityWeight } from '@shrkcrft/knowledge';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
function projectSlug(name) {
|
|
4
|
+
if (!name)
|
|
5
|
+
return 'project';
|
|
6
|
+
return (name
|
|
7
|
+
.toLowerCase()
|
|
8
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
9
|
+
.replace(/^-+|-+$/g, '')
|
|
10
|
+
.slice(0, 48) || 'project');
|
|
11
|
+
}
|
|
12
|
+
function defaultOutputFor(format, inspection) {
|
|
13
|
+
switch (format) {
|
|
14
|
+
case 'agents-md':
|
|
15
|
+
return 'AGENTS.md';
|
|
16
|
+
case 'claude-md':
|
|
17
|
+
return 'CLAUDE.md';
|
|
18
|
+
case 'claude-skill':
|
|
19
|
+
return `.claude/skills/${projectSlug(inspection.config?.projectName)}/SKILL.md`;
|
|
20
|
+
case 'cursor-rules':
|
|
21
|
+
return '.cursor/rules/sharkcraft.mdc';
|
|
22
|
+
case 'copilot-instructions':
|
|
23
|
+
return '.github/copilot-instructions.md';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
9
26
|
function selectTopByPriority(entries, limit) {
|
|
10
27
|
return [...entries]
|
|
11
28
|
.sort((a, b) => priorityWeight(b.priority) - priorityWeight(a.priority))
|
|
@@ -100,23 +117,131 @@ function renderBody(inspection, options) {
|
|
|
100
117
|
}
|
|
101
118
|
return sections.join('\n\n');
|
|
102
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Filter rules / paths to the high-signal subset for an inlined skill.
|
|
122
|
+
*
|
|
123
|
+
* Every rule the skill carries pays in Claude's context every time the
|
|
124
|
+
* skill is loaded. Low-priority items dilute the signal of the
|
|
125
|
+
* load-bearing ones (`Critical` safety + `High` architecture). We keep
|
|
126
|
+
* only Critical + High by default, falling back to "all" only if the
|
|
127
|
+
* filtered list is empty (e.g. a repo with no high-priority entries
|
|
128
|
+
* yet shouldn't ship an empty skill).
|
|
129
|
+
*/
|
|
130
|
+
function filterHighSignal(entries) {
|
|
131
|
+
const filtered = entries.filter((e) => {
|
|
132
|
+
const p = String(e.priority).toLowerCase();
|
|
133
|
+
return p === 'critical' || p === 'high';
|
|
134
|
+
});
|
|
135
|
+
return filtered.length > 0 ? filtered : [...entries];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Render the body in tight, decision-driving form for the Claude Code
|
|
139
|
+
* Skill format. Skills get loaded into Claude's prompt when the skill's
|
|
140
|
+
* `description` matches the current task, so the body must be short and
|
|
141
|
+
* directly actionable — no preamble, no metadata about generation, no
|
|
142
|
+
* pipelines (Claude can run `shrk task` for those when needed).
|
|
143
|
+
*
|
|
144
|
+
* Sections:
|
|
145
|
+
* 1. Where files belong (path conventions, top N) — most-leveraged signal.
|
|
146
|
+
* 2. Rules to follow (Critical + High only) — pads context otherwise.
|
|
147
|
+
* 3. Do / Don't — forbidden actions and verification commands.
|
|
148
|
+
* 4. How to write code in this repo — the gen → review → apply loop
|
|
149
|
+
* verbatim, since Claude needs to know shrk is the write path.
|
|
150
|
+
*/
|
|
151
|
+
function renderSkillBody(inspection, options) {
|
|
152
|
+
const { rules: allRules, paths: allPaths } = gatherRulesAndPaths(inspection, {
|
|
153
|
+
...options,
|
|
154
|
+
// Pull more upfront, then filter down to high-signal — keeps the
|
|
155
|
+
// softcap-at-15 default but the inlined skill stays terse.
|
|
156
|
+
maxRules: options.maxRules ?? 24,
|
|
157
|
+
maxPaths: options.maxPaths ?? 18,
|
|
158
|
+
});
|
|
159
|
+
// Skills are inlined into the prompt — every entry costs Claude
|
|
160
|
+
// context. Only ship the items the user said are load-bearing.
|
|
161
|
+
const rules = filterHighSignal(allRules).slice(0, options.maxRules ?? 12);
|
|
162
|
+
const paths = filterHighSignal(allPaths).slice(0, options.maxPaths ?? 10);
|
|
163
|
+
const sections = [];
|
|
164
|
+
if (inspection.config?.description) {
|
|
165
|
+
sections.push(`## About this codebase\n\n${inspection.config.description}`);
|
|
166
|
+
}
|
|
167
|
+
const pathsBody = renderPathsSection(paths);
|
|
168
|
+
if (pathsBody) {
|
|
169
|
+
sections.push(`## Where files belong\n\nWhen creating or moving a file, place it according to these conventions:\n\n${pathsBody}`);
|
|
170
|
+
}
|
|
171
|
+
const rulesBody = renderRulesSection(rules);
|
|
172
|
+
if (rulesBody) {
|
|
173
|
+
sections.push(`## Rules this codebase follows\n\nApply these whenever you generate, modify, or review code:\n\n${rulesBody}`);
|
|
174
|
+
}
|
|
175
|
+
const agg = aggregateActionHints(inspection.knowledgeEntries);
|
|
176
|
+
const doDont = [];
|
|
177
|
+
if (agg.forbiddenActions.length) {
|
|
178
|
+
doDont.push('**Do not:**');
|
|
179
|
+
for (const f of agg.forbiddenActions.slice(0, 8))
|
|
180
|
+
doDont.push(`- ${f}`);
|
|
181
|
+
doDont.push('');
|
|
182
|
+
}
|
|
183
|
+
if (agg.verificationCommands.length) {
|
|
184
|
+
doDont.push('**Verify changes with:**');
|
|
185
|
+
for (const c of agg.verificationCommands.slice(0, 6))
|
|
186
|
+
doDont.push(`- \`${c}\``);
|
|
187
|
+
}
|
|
188
|
+
if (doDont.length) {
|
|
189
|
+
sections.push(`## Do / Don't\n\n${doDont.join('\n').trim()}`);
|
|
190
|
+
}
|
|
191
|
+
sections.push(`## How to write code in this repo\n\n` +
|
|
192
|
+
`This repository uses [SharkCraft](https://github.com/shrkcrft/sharkcraft) to gate writes — the CLI is the only write path, and writes go through a plan → review → apply loop.\n\n` +
|
|
193
|
+
`1. **Get a task packet** before non-trivial work: \`shrk task "<one-sentence task>"\` returns the focused rules, paths, templates, and verification commands for that task.\n` +
|
|
194
|
+
`2. **Scaffold via templates** instead of writing files freehand: \`shrk gen <template-id> <name> --dry-run --save-plan plan.json\` produces a signed plan.\n` +
|
|
195
|
+
`3. **Apply the plan** through the CLI: \`shrk apply plan.json --verify-signature\` — never write through MCP.\n` +
|
|
196
|
+
`4. **Check the result**: \`shrk check boundaries\` + the verification commands listed above.\n\n` +
|
|
197
|
+
`For ad-hoc questions about the codebase, query the MCP server (\`shrk mcp serve\`) or run \`shrk context --task "<query>"\` for token-budgeted context.`);
|
|
198
|
+
return sections.join('\n\n');
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Build the YAML frontmatter for a Claude Code Skill. The `description`
|
|
202
|
+
* field is what Claude uses to decide whether to load this skill — keep
|
|
203
|
+
* it specific (project name + what's covered) so it doesn't trigger on
|
|
204
|
+
* unrelated tasks.
|
|
205
|
+
*/
|
|
206
|
+
function renderSkillFrontmatter(inspection) {
|
|
207
|
+
const slug = projectSlug(inspection.config?.projectName);
|
|
208
|
+
const projectName = inspection.config?.projectName ?? slug;
|
|
209
|
+
const description = `Codebase rules, path conventions, and review gates for ${projectName}. ` +
|
|
210
|
+
`Use this skill whenever generating, modifying, or reviewing code in this repository — ` +
|
|
211
|
+
`it tells you the per-file path conventions, the architecture boundaries, the verification commands, ` +
|
|
212
|
+
`and the safe write path (CLI plan → review → apply).`;
|
|
213
|
+
return `---\nname: ${slug}\ndescription: ${JSON.stringify(description)}\n---`;
|
|
214
|
+
}
|
|
103
215
|
export function renderExport(inspection, options) {
|
|
104
|
-
const
|
|
105
|
-
const suggestedPath = DEFAULT_OUTPUT_PATH[options.format];
|
|
216
|
+
const suggestedPath = defaultOutputFor(options.format, inspection);
|
|
106
217
|
let content = '';
|
|
107
218
|
switch (options.format) {
|
|
108
|
-
case 'agents-md':
|
|
219
|
+
case 'agents-md': {
|
|
220
|
+
const body = renderBody(inspection, options);
|
|
109
221
|
content = `# Agents Guide\n\n${PREAMBLE}\n\n${body}\n`;
|
|
110
222
|
break;
|
|
111
|
-
|
|
223
|
+
}
|
|
224
|
+
case 'claude-md': {
|
|
225
|
+
const body = renderBody(inspection, options);
|
|
112
226
|
content = `# CLAUDE.md\n\n${PREAMBLE}\n\nThis file is read by Claude Code (claude.ai/code) at session start. Treat it as a compatibility view of the project's SharkCraft knowledge — use the MCP server (\`shrk mcp serve\`) for the live, queryable source of truth.\n\n${body}\n`;
|
|
113
227
|
break;
|
|
228
|
+
}
|
|
229
|
+
case 'claude-skill': {
|
|
230
|
+
// Claude Code Skill: YAML frontmatter declares when to load this,
|
|
231
|
+
// body is tight decision-driving content. No preamble, no boilerplate
|
|
232
|
+
// — every token in here costs Claude context when loaded.
|
|
233
|
+
const frontmatter = renderSkillFrontmatter(inspection);
|
|
234
|
+
const projectName = inspection.config?.projectName ?? 'this codebase';
|
|
235
|
+
const body = renderSkillBody(inspection, options);
|
|
236
|
+
content = `${frontmatter}\n\n# ${projectName} — codebase guide\n\n${body}\n`;
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
114
239
|
case 'cursor-rules':
|
|
115
240
|
// Cursor MDC frontmatter: leave alwaysApply off so the user can tune.
|
|
116
|
-
content = `---\ndescription: SharkCraft project rules (auto-generated)\nalwaysApply: false\n---\n\n${PREAMBLE}\n\n${
|
|
241
|
+
content = `---\ndescription: SharkCraft project rules (auto-generated)\nalwaysApply: false\n---\n\n${PREAMBLE}\n\n${renderBody(inspection, options)}\n`;
|
|
117
242
|
break;
|
|
118
243
|
case 'copilot-instructions':
|
|
119
|
-
content = `# Copilot instructions\n\n${PREAMBLE}\n\n${
|
|
244
|
+
content = `# Copilot instructions\n\n${PREAMBLE}\n\n${renderBody(inspection, options)}\n`;
|
|
120
245
|
break;
|
|
121
246
|
}
|
|
122
247
|
return { format: options.format, suggestedPath, content };
|
|
@@ -124,12 +249,14 @@ export function renderExport(inspection, options) {
|
|
|
124
249
|
export function isExportFormat(value) {
|
|
125
250
|
return (value === 'agents-md' ||
|
|
126
251
|
value === 'claude-md' ||
|
|
252
|
+
value === 'claude-skill' ||
|
|
127
253
|
value === 'cursor-rules' ||
|
|
128
254
|
value === 'copilot-instructions');
|
|
129
255
|
}
|
|
130
256
|
export const ALL_EXPORT_FORMATS = Object.freeze([
|
|
131
257
|
'agents-md',
|
|
132
258
|
'claude-md',
|
|
259
|
+
'claude-skill',
|
|
133
260
|
'cursor-rules',
|
|
134
261
|
'copilot-instructions',
|
|
135
262
|
]);
|
package/dist/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,EACL,eAAe,EAIhB,MAAM,uBAAuB,CAAC;AAyV/B,wBAAgB,aAAa,IAAI,eAAe,CA2V/C;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BrE;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,EACL,eAAe,EAIhB,MAAM,uBAAuB,CAAC;AAyV/B,wBAAgB,aAAa,IAAI,eAAe,CA2V/C;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BrE;AAkGD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CA4CxE"}
|
package/dist/main.js
CHANGED
|
@@ -20,6 +20,7 @@ import { presetsListCommand, presetsGetCommand, presetsExplainCommand, presetsRe
|
|
|
20
20
|
import { taskCommand } from "./commands/task.command.js";
|
|
21
21
|
import { preflightCommand } from "./commands/preflight.command.js";
|
|
22
22
|
import { checkCommand } from "./commands/check.command.js";
|
|
23
|
+
import { diffCheckCommand } from "./commands/diff-check.command.js";
|
|
23
24
|
import { driftCommand } from "./commands/drift.command.js";
|
|
24
25
|
import { graphCommand } from "./commands/graph.command.js";
|
|
25
26
|
import { coverageCommand } from "./commands/coverage.command.js";
|
|
@@ -56,7 +57,6 @@ import { biomeCommand } from "./commands/biome.command.js";
|
|
|
56
57
|
import { ideCommand } from "./commands/ide.command.js";
|
|
57
58
|
import { makeCommandsCommand } from "./commands/commands.command.js";
|
|
58
59
|
import { safetyCommand } from "./commands/safety.command.js";
|
|
59
|
-
import { pluginCommand } from "./commands/plugin.command.js";
|
|
60
60
|
import { profilesCommand } from "./commands/profiles.command.js";
|
|
61
61
|
import { auditProjectCouplingCommand } from "./commands/audit.command.js";
|
|
62
62
|
import { conventionsCommand } from "./commands/conventions.command.js";
|
|
@@ -162,6 +162,7 @@ export function buildRegistry() {
|
|
|
162
162
|
registry.register(taskCommand);
|
|
163
163
|
registry.register(explainCommand);
|
|
164
164
|
registry.register(checkCommand);
|
|
165
|
+
registry.register(diffCheckCommand);
|
|
165
166
|
// changed-only preflight orchestrator.
|
|
166
167
|
registry.register(preflightCommand);
|
|
167
168
|
registry.register(driftCommand);
|
|
@@ -192,7 +193,6 @@ export function buildRegistry() {
|
|
|
192
193
|
registry.register(eslintCommand);
|
|
193
194
|
registry.register(biomeCommand);
|
|
194
195
|
registry.register(ideCommand);
|
|
195
|
-
registry.register(pluginCommand);
|
|
196
196
|
registry.register(profilesCommand);
|
|
197
197
|
registry.registerSubcommand('audit', auditProjectCouplingCommand);
|
|
198
198
|
registry.register(conventionsCommand);
|
|
@@ -506,7 +506,14 @@ async function runCliInner(argv) {
|
|
|
506
506
|
return registry.get('help').run(parseArgs([], { globalCwd }));
|
|
507
507
|
}
|
|
508
508
|
if (first === '--full-help') {
|
|
509
|
-
|
|
509
|
+
// Pass through `--all` (catalog dump) and `--verbose` if the user
|
|
510
|
+
// included them after `--full-help`.
|
|
511
|
+
const extra = [];
|
|
512
|
+
if (argv.includes('--all'))
|
|
513
|
+
extra.push('--all');
|
|
514
|
+
if (argv.includes('--verbose') || argv.includes('-v'))
|
|
515
|
+
extra.push('--verbose');
|
|
516
|
+
return registry.get('help').run(parseArgs(['--full', ...extra], { globalCwd }));
|
|
510
517
|
}
|
|
511
518
|
if (first === '--version' || first === '-v') {
|
|
512
519
|
return registry.get('version').run(parseArgs([], { globalCwd }));
|
|
@@ -550,7 +557,7 @@ async function runCliInner(argv) {
|
|
|
550
557
|
return 2;
|
|
551
558
|
}
|
|
552
559
|
const attempted = probe.slice(0, 2).join(' ');
|
|
553
|
-
process.stderr.write(`
|
|
560
|
+
process.stderr.write(`shrk doesn't have a \`${attempted}\` command.\n`);
|
|
554
561
|
printDidYouMean(attempted);
|
|
555
562
|
return 2;
|
|
556
563
|
}
|
|
@@ -658,21 +665,107 @@ async function checkSurfaceGate(matchedPath, cwd) {
|
|
|
658
665
|
return null;
|
|
659
666
|
}
|
|
660
667
|
}
|
|
668
|
+
// Score thresholds for did-you-mean output. Picked from observed
|
|
669
|
+
// scoring: 1-char-off typos score 8+ on plain commands; 3-4-char-off
|
|
670
|
+
// near-misses score ~5; loose / token-overlap matches score 1-3.
|
|
671
|
+
// Junk matches (frobnicate → bundle diff) can score 8 too because of
|
|
672
|
+
// token overlap, so we sharpen by also requiring the suggestion's
|
|
673
|
+
// command name to be reasonably close in length to the attempt.
|
|
674
|
+
const SUGGEST_CONFIDENT_SCORE = 7;
|
|
675
|
+
const SUGGEST_VISIBLE_SCORE = 3;
|
|
676
|
+
function reorderCandidates(attempted, candidates) {
|
|
677
|
+
// Stable sort: higher score first, then shorter command (more likely
|
|
678
|
+
// canonical), then lexicographic. The base suggester returns ties in
|
|
679
|
+
// arbitrary order — this makes the top suggestion more predictable.
|
|
680
|
+
const ranked = [...candidates];
|
|
681
|
+
ranked.sort((a, b) => {
|
|
682
|
+
if (b.score !== a.score)
|
|
683
|
+
return b.score - a.score;
|
|
684
|
+
if (a.command.length !== b.command.length) {
|
|
685
|
+
return a.command.length - b.command.length;
|
|
686
|
+
}
|
|
687
|
+
return a.command < b.command ? -1 : a.command > b.command ? 1 : 0;
|
|
688
|
+
});
|
|
689
|
+
return ranked;
|
|
690
|
+
}
|
|
691
|
+
/** Edit distance (Levenshtein). Used to gate did-you-mean confidence. */
|
|
692
|
+
function editDistance(a, b) {
|
|
693
|
+
const m = a.length;
|
|
694
|
+
const n = b.length;
|
|
695
|
+
if (m === 0)
|
|
696
|
+
return n;
|
|
697
|
+
if (n === 0)
|
|
698
|
+
return m;
|
|
699
|
+
const dp = new Array(n + 1);
|
|
700
|
+
for (let j = 0; j <= n; j += 1)
|
|
701
|
+
dp[j] = j;
|
|
702
|
+
for (let i = 1; i <= m; i += 1) {
|
|
703
|
+
let prev = dp[0];
|
|
704
|
+
dp[0] = i;
|
|
705
|
+
for (let j = 1; j <= n; j += 1) {
|
|
706
|
+
const tmp = dp[j];
|
|
707
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
708
|
+
dp[j] = Math.min(dp[j] + 1, dp[j - 1] + 1, prev + cost);
|
|
709
|
+
prev = tmp;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return dp[n];
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Suggestion is "confident" when the candidate's top token is close
|
|
716
|
+
* to the attempt in edit-distance terms — `doctorz`→`doctor` (1 edit)
|
|
717
|
+
* or `inspct`→`inspect` (1 edit) qualify; `frobnicate`→`bundle` (10
|
|
718
|
+
* edits) does not, even when the suggester scores them similarly
|
|
719
|
+
* because of incidental token overlap in descriptions.
|
|
720
|
+
*
|
|
721
|
+
* Threshold: edit distance ≤ max(1, attempt.length / 4) AND raw score
|
|
722
|
+
* meets `SUGGEST_VISIBLE_SCORE`. This catches typical fingers-on-keys
|
|
723
|
+
* typos while rejecting "you typed something totally different."
|
|
724
|
+
*/
|
|
725
|
+
function isConfidentMatch(attempted, suggestion) {
|
|
726
|
+
if (suggestion.score < SUGGEST_VISIBLE_SCORE)
|
|
727
|
+
return false;
|
|
728
|
+
const lower = attempted.toLowerCase();
|
|
729
|
+
const head = (suggestion.command.split(/\s+/)[0] ?? suggestion.command).toLowerCase();
|
|
730
|
+
const dist = editDistance(lower, head);
|
|
731
|
+
const tolerance = Math.max(1, Math.floor(lower.length / 4));
|
|
732
|
+
return dist <= tolerance;
|
|
733
|
+
}
|
|
661
734
|
function printDidYouMean(attempted) {
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
735
|
+
const rawCandidates = suggestDidYouMean(COMMAND_CATALOG, [attempted], 5);
|
|
736
|
+
const reordered = reorderCandidates(attempted, rawCandidates).filter((c) => c.score >= SUGGEST_VISIBLE_SCORE);
|
|
737
|
+
if (reordered.length === 0) {
|
|
738
|
+
process.stderr.write('Run `shrk help` to see the curated commands, or `shrk --full-help` for the full catalog.\n');
|
|
739
|
+
const footer = errorFooterFor('unknown-command', { task: attempted });
|
|
740
|
+
if (footer)
|
|
741
|
+
process.stderr.write(renderErrorFooter(footer));
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
// Confident single-match path: surface ONE suggestion clearly.
|
|
745
|
+
const top = reordered[0];
|
|
746
|
+
if (isConfidentMatch(attempted, top)) {
|
|
747
|
+
process.stderr.write(`Did you mean \`shrk ${top.command}\`?\n`);
|
|
748
|
+
process.stderr.write(` ${top.description}\n`);
|
|
749
|
+
// Second-tier suggestions only if they're also strong.
|
|
750
|
+
const others = reordered.slice(1, 3).filter((c) => isConfidentMatch(attempted, c));
|
|
751
|
+
if (others.length > 0) {
|
|
752
|
+
process.stderr.write('Other close matches:\n');
|
|
753
|
+
for (const c of others) {
|
|
754
|
+
process.stderr.write(` shrk ${c.command} — ${c.description}\n`);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
665
757
|
const footer = errorFooterFor('unknown-command', { task: attempted });
|
|
666
758
|
if (footer)
|
|
667
759
|
process.stderr.write(renderErrorFooter(footer));
|
|
668
760
|
return;
|
|
669
761
|
}
|
|
670
|
-
|
|
671
|
-
|
|
762
|
+
// Low-confidence: show up to 3 as "closest matches", honest about
|
|
763
|
+
// not knowing which is right.
|
|
764
|
+
process.stderr.write('Closest matches in the catalog:\n');
|
|
765
|
+
for (const c of reordered.slice(0, 3)) {
|
|
672
766
|
process.stderr.write(` shrk ${c.command} — ${c.description}\n`);
|
|
673
767
|
}
|
|
674
|
-
|
|
675
|
-
// always has a deterministic exit route.
|
|
768
|
+
process.stderr.write("If none of those look right, run `shrk help` or `shrk \"<task>\"` to route as a free-form task.\n");
|
|
676
769
|
const footer = errorFooterFor('unknown-command', { task: attempted });
|
|
677
770
|
if (footer)
|
|
678
771
|
process.stderr.write(renderErrorFooter(footer));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.8",
|
|
4
4
|
"description": "SharkCraft CLI (`shrk`): structured project intelligence for AI coding agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
@@ -47,25 +47,25 @@
|
|
|
47
47
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@shrkcrft/core": "^0.1.0-alpha.
|
|
51
|
-
"@shrkcrft/config": "^0.1.0-alpha.
|
|
52
|
-
"@shrkcrft/workspace": "^0.1.0-alpha.
|
|
53
|
-
"@shrkcrft/knowledge": "^0.1.0-alpha.
|
|
54
|
-
"@shrkcrft/context": "^0.1.0-alpha.
|
|
55
|
-
"@shrkcrft/rules": "^0.1.0-alpha.
|
|
56
|
-
"@shrkcrft/paths": "^0.1.0-alpha.
|
|
57
|
-
"@shrkcrft/templates": "^0.1.0-alpha.
|
|
58
|
-
"@shrkcrft/plugin-api": "^0.1.0-alpha.
|
|
59
|
-
"@shrkcrft/dashboard-api": "^0.1.0-alpha.
|
|
60
|
-
"@shrkcrft/pipelines": "^0.1.0-alpha.
|
|
61
|
-
"@shrkcrft/presets": "^0.1.0-alpha.
|
|
62
|
-
"@shrkcrft/boundaries": "^0.1.0-alpha.
|
|
63
|
-
"@shrkcrft/generator": "^0.1.0-alpha.
|
|
64
|
-
"@shrkcrft/importer": "^0.1.0-alpha.
|
|
65
|
-
"@shrkcrft/inspector": "^0.1.0-alpha.
|
|
66
|
-
"@shrkcrft/ai": "^0.1.0-alpha.
|
|
67
|
-
"@shrkcrft/shared": "^0.1.0-alpha.
|
|
68
|
-
"@shrkcrft/mcp-server": "^0.1.0-alpha.
|
|
50
|
+
"@shrkcrft/core": "^0.1.0-alpha.8",
|
|
51
|
+
"@shrkcrft/config": "^0.1.0-alpha.8",
|
|
52
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.8",
|
|
53
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.8",
|
|
54
|
+
"@shrkcrft/context": "^0.1.0-alpha.8",
|
|
55
|
+
"@shrkcrft/rules": "^0.1.0-alpha.8",
|
|
56
|
+
"@shrkcrft/paths": "^0.1.0-alpha.8",
|
|
57
|
+
"@shrkcrft/templates": "^0.1.0-alpha.8",
|
|
58
|
+
"@shrkcrft/plugin-api": "^0.1.0-alpha.8",
|
|
59
|
+
"@shrkcrft/dashboard-api": "^0.1.0-alpha.8",
|
|
60
|
+
"@shrkcrft/pipelines": "^0.1.0-alpha.8",
|
|
61
|
+
"@shrkcrft/presets": "^0.1.0-alpha.8",
|
|
62
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.8",
|
|
63
|
+
"@shrkcrft/generator": "^0.1.0-alpha.8",
|
|
64
|
+
"@shrkcrft/importer": "^0.1.0-alpha.8",
|
|
65
|
+
"@shrkcrft/inspector": "^0.1.0-alpha.8",
|
|
66
|
+
"@shrkcrft/ai": "^0.1.0-alpha.8",
|
|
67
|
+
"@shrkcrft/shared": "^0.1.0-alpha.8",
|
|
68
|
+
"@shrkcrft/mcp-server": "^0.1.0-alpha.8"
|
|
69
69
|
},
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type ICommandHandler } from '../command-registry.js';
|
|
2
|
-
export declare const pluginRenameCommand: ICommandHandler;
|
|
3
|
-
export declare const pluginRemoveCommand: ICommandHandler;
|
|
4
|
-
export declare const pluginLifecycleListCommand: ICommandHandler;
|
|
5
|
-
export declare const pluginLifecycleInspectCommand: ICommandHandler;
|
|
6
|
-
export declare const pluginLifecycleProfilesCommand: ICommandHandler;
|
|
7
|
-
export declare const pluginLifecycleProfileCommand: ICommandHandler;
|
|
8
|
-
export declare const pluginLifecycleDoctorCommand: ICommandHandler;
|
|
9
|
-
export declare const pluginLifecycleCommand: ICommandHandler;
|
|
10
|
-
export declare const pluginCommand: ICommandHandler;
|
|
11
|
-
//# sourceMappingURL=plugin.command.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.command.d.ts","sourceRoot":"","sources":["../../src/commands/plugin.command.ts"],"names":[],"mappings":"AA+BA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA2BhC,eAAO,MAAM,mBAAmB,EAAE,eAmEjC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,eAkEjC,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,eAwBxC,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,eAsC3C,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,eA4B5C,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,eAkD3C,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAE,eA0C1C,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAepC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,eAc3B,CAAC"}
|