@shrkcrft/cli 0.1.0-alpha.11 → 0.1.0-alpha.13

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 (81) 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/commands/ai-status.command.d.ts +19 -0
  32. package/dist/commands/ai-status.command.d.ts.map +1 -0
  33. package/dist/commands/ai-status.command.js +94 -0
  34. package/dist/commands/ask.command.d.ts.map +1 -1
  35. package/dist/commands/ask.command.js +10 -9
  36. package/dist/commands/command-catalog.d.ts.map +1 -1
  37. package/dist/commands/command-catalog.js +110 -1
  38. package/dist/commands/deps-audit.command.d.ts +23 -0
  39. package/dist/commands/deps-audit.command.d.ts.map +1 -0
  40. package/dist/commands/deps-audit.command.js +266 -0
  41. package/dist/commands/doctor.command.d.ts.map +1 -1
  42. package/dist/commands/doctor.command.js +100 -3
  43. package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
  44. package/dist/commands/graph-code-subverbs.js +144 -26
  45. package/dist/commands/graph.command.d.ts.map +1 -1
  46. package/dist/commands/graph.command.js +3 -2
  47. package/dist/commands/help.command.d.ts.map +1 -1
  48. package/dist/commands/help.command.js +22 -1
  49. package/dist/commands/impact.command.d.ts.map +1 -1
  50. package/dist/commands/impact.command.js +3 -2
  51. package/dist/commands/move-plan.command.d.ts +23 -0
  52. package/dist/commands/move-plan.command.d.ts.map +1 -0
  53. package/dist/commands/move-plan.command.js +360 -0
  54. package/dist/commands/scaffold-validate.command.d.ts +22 -0
  55. package/dist/commands/scaffold-validate.command.d.ts.map +1 -0
  56. package/dist/commands/scaffold-validate.command.js +215 -0
  57. package/dist/commands/smart-context.command.d.ts +58 -0
  58. package/dist/commands/smart-context.command.d.ts.map +1 -0
  59. package/dist/commands/smart-context.command.js +4524 -0
  60. package/dist/commands/spike.command.d.ts +22 -0
  61. package/dist/commands/spike.command.d.ts.map +1 -0
  62. package/dist/commands/spike.command.js +235 -0
  63. package/dist/commands/surface.command.d.ts +1 -0
  64. package/dist/commands/surface.command.d.ts.map +1 -1
  65. package/dist/commands/surface.command.js +10 -3
  66. package/dist/commands/template-quality.command.d.ts.map +1 -1
  67. package/dist/commands/template-quality.command.js +39 -3
  68. package/dist/commands/templates.command.d.ts.map +1 -1
  69. package/dist/commands/templates.command.js +37 -2
  70. package/dist/commands/watch.command.d.ts +26 -0
  71. package/dist/commands/watch.command.d.ts.map +1 -0
  72. package/dist/commands/watch.command.js +456 -0
  73. package/dist/env/load-dotenv.d.ts +15 -0
  74. package/dist/env/load-dotenv.d.ts.map +1 -0
  75. package/dist/env/load-dotenv.js +70 -0
  76. package/dist/main.d.ts.map +1 -1
  77. package/dist/main.js +105 -2
  78. package/dist/schemas/json-schemas.d.ts +384 -36
  79. package/dist/schemas/json-schemas.d.ts.map +1 -1
  80. package/dist/schemas/json-schemas.js +247 -36
  81. package/package.json +33 -31
@@ -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
+ }
@@ -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
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"ask.command.d.ts","sourceRoot":"","sources":["../../src/commands/ask.command.ts"],"names":[],"mappings":"AAGA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAIhC,eAAO,MAAM,UAAU,EAAE,eA2DxB,CAAC"}
1
+ {"version":3,"file":"ask.command.d.ts","sourceRoot":"","sources":["../../src/commands/ask.command.ts"],"names":[],"mappings":"AAOA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAIhC,eAAO,MAAM,UAAU,EAAE,eA6DxB,CAAC"}
@@ -1,13 +1,13 @@
1
1
  import { inspectSharkcraft, buildProjectOverview, renderOverviewText } from '@shrkcrft/inspector';
2
2
  import { buildContext } from '@shrkcrft/context';
3
- import { ClaudeProvider, AiMessageRole, buildPromptMessages } from '@shrkcrft/ai';
3
+ import { AiMessageRole, buildPromptMessages, selectAiProvider, } from '@shrkcrft/ai';
4
4
  import { flagBool, flagNumber, flagString, resolveCwd, } from "../command-registry.js";
5
5
  import { header } from "../output/format-output.js";
6
6
  import { printError } from "../output/print-error.js";
7
7
  export const askCommand = {
8
8
  name: 'ask',
9
- description: 'Ask a question. Builds repository context, sends prompt to Claude (requires ANTHROPIC_API_KEY).',
10
- usage: 'shrk ask "<question>" [--max-tokens 3000] [--model claude-sonnet-4-6] [--dry-run]',
9
+ description: 'Ask a question. Builds repository context, sends prompt to the local LLM (Ollama / llama.cpp).',
10
+ usage: 'shrk ask "<question>" [--max-tokens 3000] [--provider auto|ollama|llamacpp] [--model <id>] [--dry-run]',
11
11
  async run(args) {
12
12
  const question = args.positional.join(' ').trim();
13
13
  if (!question) {
@@ -16,6 +16,7 @@ export const askCommand = {
16
16
  }
17
17
  const maxTokens = flagNumber(args, 'max-tokens') ?? 3000;
18
18
  const model = flagString(args, 'model');
19
+ const providerKind = flagString(args, 'provider');
19
20
  const dryRun = flagBool(args, 'dry-run');
20
21
  const inspection = await inspectSharkcraft({ cwd: resolveCwd(args) });
21
22
  const overview = buildProjectOverview(inspection.workspace, inspection.config?.projectName);
@@ -36,14 +37,14 @@ export const askCommand = {
36
37
  }
37
38
  return 0;
38
39
  }
39
- const provider = new ClaudeProvider();
40
- if (model)
41
- provider.configure({ model });
42
- if (!provider.isReady()) {
43
- process.stderr.write('ANTHROPIC_API_KEY is not set. Use --dry-run to print the prompt instead.\n');
40
+ const selection = selectAiProvider(providerKind);
41
+ if (!selection.provider) {
42
+ process.stderr.write('No local LLM is ready. Start Ollama (`ollama serve`) or set LLAMACPP_MODEL_PATH=/path/to/model.gguf in .env. Use --dry-run to print the prompt instead.\n');
44
43
  return 1;
45
44
  }
46
- const res = await provider.send({
45
+ if (model)
46
+ selection.provider.configure({ model });
47
+ const res = await selection.provider.send({
47
48
  messages: [...messages, { role: AiMessageRole.User, content: question }],
48
49
  maxTokens: 1024,
49
50
  model,
@@ -1 +1 @@
1
- {"version":3,"file":"command-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/command-catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/command-catalog.ts"],"names":[],"mappings":"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"}
@@ -115,6 +115,16 @@ export const COMMAND_CATALOG = Object.freeze([
115
115
  intendedAudience: [CommandAudience.Human, CommandAudience.Agent, CommandAudience.Ci],
116
116
  taskRole: CommandTaskRole.Diagnose,
117
117
  }),
118
+ entry({
119
+ command: 'ai-status',
120
+ description: 'Report which AI provider shrk would use right now, with setup or upgrade hints. `--ping` verifies the provider actually responds.',
121
+ category: 'core',
122
+ safetyLevel: SafetyLevel.ReadOnly,
123
+ mcpAvailable: false,
124
+ surface: CommandSurface.Common,
125
+ intendedAudience: [CommandAudience.Human, CommandAudience.Agent],
126
+ taskRole: CommandTaskRole.Diagnose,
127
+ }),
118
128
  entry({
119
129
  command: 'context',
120
130
  description: 'Focused context for a task (rules / paths / templates). For "what should I do?" prefer `shrk recommend "<task>"`.',
@@ -256,7 +266,7 @@ export const COMMAND_CATALOG = Object.freeze([
256
266
  }),
257
267
  entry({
258
268
  command: 'graph',
259
- description: 'Knowledge graph nodes, edges, and shortest-path explanations.',
269
+ description: 'Knowledge graph plus code-intelligence subverbs (`index`, `status`, `search`, `context`, `impact`, `callers`, `cycles`, `unresolved`, `deps`, `why`, `export`).',
260
270
  category: 'core',
261
271
  safetyLevel: SafetyLevel.ReadOnly,
262
272
  mcpAvailable: true,
@@ -1182,6 +1192,104 @@ export const COMMAND_CATALOG = Object.freeze([
1182
1192
  category: 'core',
1183
1193
  safetyLevel: SafetyLevel.ReadOnly,
1184
1194
  }),
1195
+ entry({
1196
+ command: 'smart-context',
1197
+ description: 'Build deterministic context and ask an AI provider to synthesise an enriched brief (default), structured plan (--plan), or two-stage development plan (--ai-plan). Opt-in; defaults to Gemini. CLAUDE.md is auto-included in the seed.',
1198
+ category: 'core',
1199
+ safetyLevel: SafetyLevel.ReadOnly,
1200
+ taskRole: CommandTaskRole.Context,
1201
+ }),
1202
+ entry({
1203
+ command: 'smart-context plan-ahead',
1204
+ description: 'Batch-generate AI-backed plans for a queue of upcoming tasks and save each under .sharkcraft/smart-context/.',
1205
+ category: 'core',
1206
+ safetyLevel: SafetyLevel.ReadOnly,
1207
+ taskRole: CommandTaskRole.Context,
1208
+ }),
1209
+ entry({
1210
+ command: 'smart-context list',
1211
+ description: 'List saved smart-context entries under .sharkcraft/smart-context/.',
1212
+ category: 'core',
1213
+ safetyLevel: SafetyLevel.ReadOnly,
1214
+ taskRole: CommandTaskRole.Inspect,
1215
+ }),
1216
+ entry({
1217
+ command: 'smart-context show',
1218
+ description: 'Print a saved smart-context entry by slug.',
1219
+ category: 'core',
1220
+ safetyLevel: SafetyLevel.ReadOnly,
1221
+ taskRole: CommandTaskRole.Inspect,
1222
+ }),
1223
+ entry({
1224
+ command: 'smart-context embeddings-build',
1225
+ description: 'Build or incrementally refresh the semantic file index used by smart-context. Downloads the embedding model on first run.',
1226
+ category: 'core',
1227
+ safetyLevel: SafetyLevel.WritesSessionOnly,
1228
+ taskRole: CommandTaskRole.Context,
1229
+ }),
1230
+ entry({
1231
+ command: 'smart-context embeddings-status',
1232
+ description: 'Report semantic index freshness without loading the embedding model.',
1233
+ category: 'core',
1234
+ safetyLevel: SafetyLevel.ReadOnly,
1235
+ taskRole: CommandTaskRole.Inspect,
1236
+ }),
1237
+ entry({
1238
+ command: 'spike',
1239
+ description: 'Scaffold starter files for a saved smart-context plan\'s recommended MVP. Reads .sharkcraft/smart-context/<slug>.plan.json.',
1240
+ category: 'core',
1241
+ safetyLevel: SafetyLevel.WritesSource,
1242
+ taskRole: CommandTaskRole.Generate,
1243
+ }),
1244
+ entry({
1245
+ command: 'deps-audit',
1246
+ description: 'Compare declared package dependencies (package.json) with actually imported specifiers (graph). Reports missing + unused deps. Read-only.',
1247
+ category: 'core',
1248
+ safetyLevel: SafetyLevel.ReadOnly,
1249
+ taskRole: CommandTaskRole.Inspect,
1250
+ }),
1251
+ entry({
1252
+ command: 'scaffold-validate',
1253
+ description: 'Validate that the files in a saved generation plan exist on disk and look intact (size envelope + type match). Read-only.',
1254
+ category: 'core',
1255
+ safetyLevel: SafetyLevel.ReadOnly,
1256
+ taskRole: CommandTaskRole.Validate,
1257
+ }),
1258
+ entry({
1259
+ command: 'move-plan',
1260
+ description: 'Plan a file move: graph-traced importer rewrites, export touch-ups, cross-package warnings, rollback steps. Read-only.',
1261
+ category: 'core',
1262
+ safetyLevel: SafetyLevel.ReadOnly,
1263
+ taskRole: CommandTaskRole.Generate,
1264
+ }),
1265
+ entry({
1266
+ command: 'watch',
1267
+ description: 'Emit a focused-context packet on stdout JSONL each time the workspace changes. Designed to feed a parallel Claude agent.',
1268
+ category: 'core',
1269
+ safetyLevel: SafetyLevel.WritesSessionOnly,
1270
+ taskRole: CommandTaskRole.Context,
1271
+ }),
1272
+ entry({
1273
+ command: 'watch list',
1274
+ description: 'List active shrk-watch daemons (one per task slug).',
1275
+ category: 'core',
1276
+ safetyLevel: SafetyLevel.ReadOnly,
1277
+ taskRole: CommandTaskRole.Inspect,
1278
+ }),
1279
+ entry({
1280
+ command: 'watch stop',
1281
+ description: 'Stop a running shrk-watch daemon by slug.',
1282
+ category: 'core',
1283
+ safetyLevel: SafetyLevel.WritesSessionOnly,
1284
+ taskRole: CommandTaskRole.Config,
1285
+ }),
1286
+ entry({
1287
+ command: 'watch prune',
1288
+ description: 'Remove stale shrk-watch manifests whose owning processes are no longer alive.',
1289
+ category: 'core',
1290
+ safetyLevel: SafetyLevel.WritesSessionOnly,
1291
+ taskRole: CommandTaskRole.Config,
1292
+ }),
1185
1293
  entry({
1186
1294
  command: 'safety audit',
1187
1295
  description: 'Audit the SharkCraft safety model (commands, MCP, packs, plan signing).',
@@ -3251,6 +3359,7 @@ const PRIMARY_VERBS_ALLOWLIST = new Set([
3251
3359
  'search',
3252
3360
  'impact',
3253
3361
  'graph',
3362
+ 'code-intel',
3254
3363
  // Generate code safely
3255
3364
  'gen',
3256
3365
  'apply',
@@ -0,0 +1,23 @@
1
+ import { type ICommandHandler } from '../command-registry.js';
2
+ /**
3
+ * `shrk deps-audit` — for each workspace package, compare the
4
+ * `package.json` `dependencies` / `devDependencies` / `peerDependencies`
5
+ * against the *specifiers actually imported* from source under
6
+ * `<pkg>/src/` (per the SharkCraft graph).
7
+ *
8
+ * Reports:
9
+ * - missing deps: imported but not declared (likely build failure
10
+ * in the wild — the package depends on its host's resolution)
11
+ * - unused deps: declared but never imported (lint waste)
12
+ *
13
+ * Read-only. JSON output via `--json`. Optionally restricted to one
14
+ * package via `--package <name>`.
15
+ *
16
+ * Known limitations:
17
+ * - Type-only imports (`import type x from 'y'`) still count; the
18
+ * graph can't tell them apart in v3.
19
+ * - Subpath imports (`pkg/sub`) are reduced to their root specifier.
20
+ * - Built-in node modules (`node:fs`, `fs`, …) are ignored.
21
+ */
22
+ export declare const depsAuditCommand: ICommandHandler;
23
+ //# sourceMappingURL=deps-audit.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deps-audit.command.d.ts","sourceRoot":"","sources":["../../src/commands/deps-audit.command.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAmBhC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAmE9B,CAAC"}