@shrkcrft/mcp-server 0.1.0-alpha.2 → 0.1.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/dist/index.d.ts +4 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +4 -0
  4. package/dist/server/columnar-format.d.ts +34 -0
  5. package/dist/server/columnar-format.d.ts.map +1 -0
  6. package/dist/server/columnar-format.js +95 -0
  7. package/dist/server/create-mcp-server.d.ts +3 -0
  8. package/dist/server/create-mcp-server.d.ts.map +1 -1
  9. package/dist/server/create-mcp-server.js +24 -9
  10. package/dist/server/fit-array-to-budget.d.ts +24 -0
  11. package/dist/server/fit-array-to-budget.d.ts.map +1 -0
  12. package/dist/server/fit-array-to-budget.js +60 -0
  13. package/dist/server/serialize-tool-data.d.ts +15 -0
  14. package/dist/server/serialize-tool-data.d.ts.map +1 -0
  15. package/dist/server/serialize-tool-data.js +22 -0
  16. package/dist/server/tool-definition.d.ts +15 -0
  17. package/dist/server/tool-definition.d.ts.map +1 -1
  18. package/dist/server/tool-input-validators.d.ts.map +1 -1
  19. package/dist/server/tool-input-validators.js +43 -0
  20. package/dist/tools/agent-brief.tool.d.ts.map +1 -1
  21. package/dist/tools/agent-brief.tool.js +20 -0
  22. package/dist/tools/align-cache.tool.d.ts +11 -0
  23. package/dist/tools/align-cache.tool.d.ts.map +1 -0
  24. package/dist/tools/align-cache.tool.js +76 -0
  25. package/dist/tools/all-tools.d.ts.map +1 -1
  26. package/dist/tools/all-tools.js +72 -7
  27. package/dist/tools/architecture-map.tool.d.ts.map +1 -1
  28. package/dist/tools/architecture-map.tool.js +4 -2
  29. package/dist/tools/code-find-usages.tool.d.ts +16 -0
  30. package/dist/tools/code-find-usages.tool.d.ts.map +1 -0
  31. package/dist/tools/code-find-usages.tool.js +180 -0
  32. package/dist/tools/command-catalog.tool.d.ts.map +1 -1
  33. package/dist/tools/command-catalog.tool.js +11 -7
  34. package/dist/tools/compress-context.tool.d.ts +8 -0
  35. package/dist/tools/compress-context.tool.d.ts.map +1 -0
  36. package/dist/tools/compress-context.tool.js +81 -0
  37. package/dist/tools/dashboard-summary.tool.d.ts.map +1 -1
  38. package/dist/tools/dashboard-summary.tool.js +2 -4
  39. package/dist/tools/delegate-task.tool.d.ts +3 -0
  40. package/dist/tools/delegate-task.tool.d.ts.map +1 -0
  41. package/dist/tools/delegate-task.tool.js +94 -0
  42. package/dist/tools/deps-audit.tool.d.ts +10 -0
  43. package/dist/tools/deps-audit.tool.d.ts.map +1 -0
  44. package/dist/tools/deps-audit.tool.js +251 -0
  45. package/dist/tools/diff-check.tool.d.ts +15 -0
  46. package/dist/tools/diff-check.tool.d.ts.map +1 -0
  47. package/dist/tools/diff-check.tool.js +157 -0
  48. package/dist/tools/file-advice.tool.d.ts +22 -0
  49. package/dist/tools/file-advice.tool.d.ts.map +1 -0
  50. package/dist/tools/file-advice.tool.js +88 -0
  51. package/dist/tools/get-api-surface-diff.tool.d.ts +3 -0
  52. package/dist/tools/get-api-surface-diff.tool.d.ts.map +1 -0
  53. package/dist/tools/get-api-surface-diff.tool.js +60 -0
  54. package/dist/tools/get-arch-violations.tool.d.ts +3 -0
  55. package/dist/tools/get-arch-violations.tool.d.ts.map +1 -0
  56. package/dist/tools/get-arch-violations.tool.js +30 -0
  57. package/dist/tools/get-code-intelligence-state.tool.d.ts +11 -0
  58. package/dist/tools/get-code-intelligence-state.tool.d.ts.map +1 -0
  59. package/dist/tools/get-code-intelligence-state.tool.js +60 -0
  60. package/dist/tools/get-context-pack.tool.d.ts +3 -0
  61. package/dist/tools/get-context-pack.tool.d.ts.map +1 -0
  62. package/dist/tools/get-context-pack.tool.js +40 -0
  63. package/dist/tools/get-framework-entities.tool.d.ts +3 -0
  64. package/dist/tools/get-framework-entities.tool.d.ts.map +1 -0
  65. package/dist/tools/get-framework-entities.tool.js +68 -0
  66. package/dist/tools/get-graph-callers.tool.d.ts +3 -0
  67. package/dist/tools/get-graph-callers.tool.d.ts.map +1 -0
  68. package/dist/tools/get-graph-callers.tool.js +94 -0
  69. package/dist/tools/get-graph-context.tool.d.ts +3 -0
  70. package/dist/tools/get-graph-context.tool.d.ts.map +1 -0
  71. package/dist/tools/get-graph-context.tool.js +125 -0
  72. package/dist/tools/get-graph-cycles.tool.d.ts +10 -0
  73. package/dist/tools/get-graph-cycles.tool.d.ts.map +1 -0
  74. package/dist/tools/get-graph-cycles.tool.js +58 -0
  75. package/dist/tools/get-graph-deps.tool.d.ts +12 -0
  76. package/dist/tools/get-graph-deps.tool.d.ts.map +1 -0
  77. package/dist/tools/get-graph-deps.tool.js +80 -0
  78. package/dist/tools/get-graph-hubs.tool.d.ts +3 -0
  79. package/dist/tools/get-graph-hubs.tool.d.ts.map +1 -0
  80. package/dist/tools/get-graph-hubs.tool.js +61 -0
  81. package/dist/tools/get-graph-impact-analysis.tool.d.ts +3 -0
  82. package/dist/tools/get-graph-impact-analysis.tool.d.ts.map +1 -0
  83. package/dist/tools/get-graph-impact-analysis.tool.js +44 -0
  84. package/dist/tools/get-graph-impact.tool.d.ts +3 -0
  85. package/dist/tools/get-graph-impact.tool.d.ts.map +1 -0
  86. package/dist/tools/get-graph-impact.tool.js +150 -0
  87. package/dist/tools/get-graph-path.tool.d.ts +3 -0
  88. package/dist/tools/get-graph-path.tool.d.ts.map +1 -0
  89. package/dist/tools/get-graph-path.tool.js +144 -0
  90. package/dist/tools/get-graph-search.tool.d.ts +3 -0
  91. package/dist/tools/get-graph-search.tool.d.ts.map +1 -0
  92. package/dist/tools/get-graph-search.tool.js +95 -0
  93. package/dist/tools/get-graph-status.tool.d.ts +11 -0
  94. package/dist/tools/get-graph-status.tool.d.ts.map +1 -0
  95. package/dist/tools/get-graph-status.tool.js +55 -0
  96. package/dist/tools/get-graph-unresolved.tool.d.ts +11 -0
  97. package/dist/tools/get-graph-unresolved.tool.d.ts.map +1 -0
  98. package/dist/tools/get-graph-unresolved.tool.js +85 -0
  99. package/dist/tools/get-impact-baseline.tool.d.ts +9 -0
  100. package/dist/tools/get-impact-baseline.tool.d.ts.map +1 -0
  101. package/dist/tools/get-impact-baseline.tool.js +65 -0
  102. package/dist/tools/get-intent-benchmark-run.tool.d.ts +12 -0
  103. package/dist/tools/get-intent-benchmark-run.tool.d.ts.map +1 -0
  104. package/dist/tools/get-intent-benchmark-run.tool.js +55 -0
  105. package/dist/tools/get-knowledge-graph.tool.d.ts +7 -0
  106. package/dist/tools/get-knowledge-graph.tool.d.ts.map +1 -1
  107. package/dist/tools/get-knowledge-graph.tool.js +62 -3
  108. package/dist/tools/get-migrations.tool.d.ts +3 -0
  109. package/dist/tools/get-migrations.tool.d.ts.map +1 -0
  110. package/dist/tools/get-migrations.tool.js +70 -0
  111. package/dist/tools/get-pattern-registry.tool.d.ts +8 -0
  112. package/dist/tools/get-pattern-registry.tool.d.ts.map +1 -0
  113. package/dist/tools/get-pattern-registry.tool.js +40 -0
  114. package/dist/tools/get-quality-gate.tool.d.ts +3 -0
  115. package/dist/tools/get-quality-gate.tool.d.ts.map +1 -0
  116. package/dist/tools/get-quality-gate.tool.js +27 -0
  117. package/dist/tools/get-relevant-context.tool.d.ts.map +1 -1
  118. package/dist/tools/get-relevant-context.tool.js +30 -6
  119. package/dist/tools/get-rules-for-file.tool.d.ts +3 -0
  120. package/dist/tools/get-rules-for-file.tool.d.ts.map +1 -0
  121. package/dist/tools/get-rules-for-file.tool.js +54 -0
  122. package/dist/tools/get-structural-rewrite-plan.tool.d.ts +3 -0
  123. package/dist/tools/get-structural-rewrite-plan.tool.d.ts.map +1 -0
  124. package/dist/tools/get-structural-rewrite-plan.tool.js +46 -0
  125. package/dist/tools/get-structural-search.tool.d.ts +3 -0
  126. package/dist/tools/get-structural-search.tool.d.ts.map +1 -0
  127. package/dist/tools/get-structural-search.tool.js +35 -0
  128. package/dist/tools/get-task-packet.tool.d.ts.map +1 -1
  129. package/dist/tools/get-task-packet.tool.js +26 -22
  130. package/dist/tools/graph-staleness.d.ts +34 -0
  131. package/dist/tools/graph-staleness.d.ts.map +1 -0
  132. package/dist/tools/graph-staleness.js +36 -0
  133. package/dist/tools/list-boundary-rules.tool.d.ts.map +1 -1
  134. package/dist/tools/list-boundary-rules.tool.js +20 -16
  135. package/dist/tools/list-knowledge.tool.d.ts.map +1 -1
  136. package/dist/tools/list-knowledge.tool.js +14 -13
  137. package/dist/tools/list-packs.tool.d.ts.map +1 -1
  138. package/dist/tools/list-packs.tool.js +19 -15
  139. package/dist/tools/list-path-conventions.tool.d.ts.map +1 -1
  140. package/dist/tools/list-path-conventions.tool.js +19 -15
  141. package/dist/tools/list-pipelines.tool.d.ts.map +1 -1
  142. package/dist/tools/list-pipelines.tool.js +18 -14
  143. package/dist/tools/list-presets.tool.d.ts.map +1 -1
  144. package/dist/tools/list-presets.tool.js +25 -21
  145. package/dist/tools/list-rules.tool.d.ts.map +1 -1
  146. package/dist/tools/list-rules.tool.js +18 -14
  147. package/dist/tools/list-templates.tool.d.ts.map +1 -1
  148. package/dist/tools/list-templates.tool.js +18 -14
  149. package/dist/tools/plan-quality-review.tool.d.ts +21 -0
  150. package/dist/tools/plan-quality-review.tool.d.ts.map +1 -0
  151. package/dist/tools/plan-quality-review.tool.js +294 -0
  152. package/dist/tools/primary-tools.d.ts +24 -0
  153. package/dist/tools/primary-tools.d.ts.map +1 -0
  154. package/dist/tools/primary-tools.js +86 -0
  155. package/dist/tools/r19-extras.tool.js +1 -1
  156. package/dist/tools/r32-profiles.tool.d.ts +0 -3
  157. package/dist/tools/r32-profiles.tool.d.ts.map +1 -1
  158. package/dist/tools/r32-profiles.tool.js +3 -54
  159. package/dist/tools/retrieve-original.tool.d.ts +9 -0
  160. package/dist/tools/retrieve-original.tool.d.ts.map +1 -0
  161. package/dist/tools/retrieve-original.tool.js +47 -0
  162. package/dist/tools/runtime-reports.tool.d.ts.map +1 -1
  163. package/dist/tools/runtime-reports.tool.js +1 -3
  164. package/dist/tools/safety-audit.tool.d.ts.map +1 -1
  165. package/dist/tools/safety-audit.tool.js +1 -4
  166. package/dist/tools/search-knowledge.tool.d.ts.map +1 -1
  167. package/dist/tools/search-knowledge.tool.js +17 -13
  168. package/dist/tools/search.tool.d.ts.map +1 -1
  169. package/dist/tools/search.tool.js +11 -8
  170. package/dist/tools/smart-context-bundle.tool.d.ts +17 -0
  171. package/dist/tools/smart-context-bundle.tool.d.ts.map +1 -0
  172. package/dist/tools/smart-context-bundle.tool.js +110 -0
  173. package/dist/tools/smart-context-feed.tool.d.ts +17 -0
  174. package/dist/tools/smart-context-feed.tool.d.ts.map +1 -0
  175. package/dist/tools/smart-context-feed.tool.js +138 -0
  176. package/dist/tools/start-here.tool.js +2 -2
  177. package/package.json +28 -16
  178. package/dist/tools/r22-extras.tool.d.ts +0 -4
  179. package/dist/tools/r22-extras.tool.d.ts.map +0 -1
  180. package/dist/tools/r22-extras.tool.js +0 -42
  181. package/dist/tools/r26-ingest.tool.d.ts +0 -10
  182. package/dist/tools/r26-ingest.tool.d.ts.map +0 -1
  183. package/dist/tools/r26-ingest.tool.js +0 -174
  184. package/dist/tools/r28-plugin-lifecycle.tool.d.ts +0 -4
  185. package/dist/tools/r28-plugin-lifecycle.tool.d.ts.map +0 -1
  186. package/dist/tools/r28-plugin-lifecycle.tool.js +0 -94
  187. package/dist/tools/r34-search-unified.tool.d.ts +0 -3
  188. package/dist/tools/r34-search-unified.tool.d.ts.map +0 -1
  189. package/dist/tools/r34-search-unified.tool.js +0 -38
@@ -0,0 +1,294 @@
1
+ import { existsSync } from 'node:fs';
2
+ import * as nodePath from 'node:path';
3
+ /**
4
+ * `plan_quality_review` — score a plan blob for hallucination,
5
+ * generic boilerplate, contradictions, and ungrounded commands.
6
+ *
7
+ * Inputs:
8
+ * - `plan`: either a stringified JSON / Markdown plan body, OR a
9
+ * `{ from: { slug } }` reference that resolves to a saved
10
+ * `.sharkcraft/smart-context/<slug>.plan.json`.
11
+ * - `recommendedCommands` (optional): the set of commands that are
12
+ * considered "real" (typically `verificationCommands` from the
13
+ * same focused bundle). Anything outside this set in
14
+ * `firstCommands`/`validationCommands` gets flagged.
15
+ *
16
+ * Output: structured findings + an overall verdict so the calling
17
+ * agent can decide whether to use, retry, or reject the plan.
18
+ *
19
+ * Read-only — does not modify or rewrite the plan.
20
+ */
21
+ export const planQualityReviewTool = {
22
+ name: 'plan_quality_review',
23
+ description: 'Critique a plan (JSON or Markdown) for hallucinated paths, generic boilerplate, contradictions, and ungrounded commands. Read-only.',
24
+ inputSchema: {
25
+ type: 'object',
26
+ properties: {
27
+ plan: { type: 'string' },
28
+ planFrom: { type: 'object' },
29
+ recommendedCommands: { type: 'array', items: { type: 'string' } },
30
+ },
31
+ additionalProperties: false,
32
+ },
33
+ async handler(input, ctx) {
34
+ let planText;
35
+ const planFrom = input['planFrom'];
36
+ if (typeof input['plan'] === 'string' && input['plan'].length > 0) {
37
+ planText = input['plan'];
38
+ }
39
+ else if (planFrom && typeof planFrom === 'object') {
40
+ const slug = typeof planFrom['slug'] === 'string'
41
+ ? planFrom['slug']
42
+ : '';
43
+ if (slug.length === 0) {
44
+ return { data: { error: 'planFrom.slug is required when using planFrom' } };
45
+ }
46
+ const path = nodePath.join(ctx.cwd, '.sharkcraft', 'smart-context', `${slug}.plan.json`);
47
+ if (!existsSync(path)) {
48
+ return { data: { error: 'no-plan-for-slug', slug, lookedAt: path } };
49
+ }
50
+ try {
51
+ const { readFileSync } = await import('node:fs');
52
+ planText = readFileSync(path, 'utf8');
53
+ }
54
+ catch (e) {
55
+ return { data: { error: `read failed: ${e.message}` } };
56
+ }
57
+ }
58
+ else {
59
+ return { data: { error: 'one of `plan` or `planFrom` is required' } };
60
+ }
61
+ if (!planText)
62
+ return { data: { error: 'empty plan' } };
63
+ const parsed = tryExtractJson(planText);
64
+ const recommendedCommandsRaw = Array.isArray(input['recommendedCommands'])
65
+ ? input['recommendedCommands'].filter((c) => typeof c === 'string')
66
+ : [];
67
+ const knownCommands = new Set(recommendedCommandsRaw.map(normaliseCommand));
68
+ const findings = analysePlan({
69
+ cwd: ctx.cwd,
70
+ raw: planText,
71
+ parsed,
72
+ knownCommands,
73
+ });
74
+ const score = scoreFindings(findings);
75
+ const verdict = score >= 0.85
76
+ ? 'good'
77
+ : score >= 0.6
78
+ ? 'usable-with-review'
79
+ : score >= 0.35
80
+ ? 'weak'
81
+ : 'reject';
82
+ return {
83
+ data: {
84
+ verdict,
85
+ score,
86
+ parsed: parsed !== null,
87
+ findings,
88
+ handoffForClaude: verdict === 'reject'
89
+ ? 'Reject this plan — too many ungrounded claims.'
90
+ : verdict === 'weak'
91
+ ? 'Plan is weak; consider regenerating with --polish or a stronger model.'
92
+ : verdict === 'usable-with-review'
93
+ ? 'Plan is usable but verify the flagged paths and commands.'
94
+ : 'Plan looks well-grounded.',
95
+ },
96
+ };
97
+ },
98
+ };
99
+ function analysePlan(input) {
100
+ const out = [];
101
+ // 1. Hallucinated paths — walk the parsed JSON.
102
+ if (input.parsed) {
103
+ const seen = new Set();
104
+ walkPathLeaves(input.parsed, '$', (path, where) => {
105
+ const id = `${where}:${path}`;
106
+ if (seen.has(id))
107
+ return;
108
+ seen.add(id);
109
+ if (!looksLikePathRef(path))
110
+ return;
111
+ if (!pathExistsInWorkspace(input.cwd, path)) {
112
+ out.push({
113
+ category: 'hallucinated-path',
114
+ severity: 'high',
115
+ message: `Path "${path}" does not exist in the workspace.`,
116
+ where,
117
+ });
118
+ }
119
+ });
120
+ }
121
+ // 2. Generic boilerplate (the polish preamble's anti-patterns).
122
+ const genericPatterns = [
123
+ { re: /may require additional resources and infrastructure/i, msg: 'Generic "additional resources" boilerplate.' },
124
+ { re: /may introduce additional complexity/i, msg: 'Generic "additional complexity" boilerplate.' },
125
+ { re: /may require additional security and privacy considerations/i, msg: 'Generic "security and privacy" boilerplate.' },
126
+ { re: /can be implemented as a separate tool or as a plugin/i, msg: '"Can be implemented as a separate tool" — useless differentiation.' },
127
+ { re: /documentation and support level/i, msg: 'Enterprise-boilerplate question about "documentation and support level".' },
128
+ { re: /\bGET\b.*\b(cli|file|stdout|mcp)/i, msg: 'HTTP verb on a CLI/file/stdout/MCP surface.' },
129
+ ];
130
+ for (const p of genericPatterns) {
131
+ if (p.re.test(input.raw)) {
132
+ out.push({ category: 'generic-boilerplate', severity: 'medium', message: p.msg });
133
+ }
134
+ }
135
+ // 3. Contradictions: filesToAvoid ∩ likelyFilesToModify.
136
+ if (input.parsed) {
137
+ const avoid = collectPathSet(input.parsed['filesToAvoid']);
138
+ const modify = collectPathSet(input.parsed['likelyFilesToModify']);
139
+ const overlap = [...avoid].filter((p) => modify.has(p));
140
+ for (const p of overlap) {
141
+ out.push({
142
+ category: 'contradiction',
143
+ severity: 'high',
144
+ message: `"${p}" appears in both filesToAvoid and likelyFilesToModify.`,
145
+ });
146
+ }
147
+ }
148
+ // 4. Ungrounded commands.
149
+ if (input.parsed && input.knownCommands.size > 0) {
150
+ const firstCmds = collectStringArrayFromKey(input.parsed['firstCommands'], 'command');
151
+ const valCmds = collectStringArrayFromKey(input.parsed['validationCommands'], 'command');
152
+ const plainVal = collectStringArray(input.parsed['validationCommands']);
153
+ const all = new Set([...firstCmds, ...valCmds, ...plainVal].map(normaliseCommand));
154
+ for (const c of all) {
155
+ if (c.length === 0)
156
+ continue;
157
+ // Don't flag commands that obviously start with `git` or `bun x tsc` —
158
+ // those are universal even when the rule registry doesn't list them.
159
+ if (/^(git|bun\s+x\s+tsc|npm|pnpm|yarn)\b/.test(c))
160
+ continue;
161
+ if (!input.knownCommands.has(c)) {
162
+ out.push({
163
+ category: 'ungrounded-command',
164
+ severity: 'low',
165
+ message: `Command "${c}" is not in the supplied recommendedCommands.`,
166
+ });
167
+ }
168
+ }
169
+ }
170
+ // 5. Missing-section heuristic for arch-plan shapes.
171
+ if (input.parsed) {
172
+ if ('candidateArchitectures' in input.parsed) {
173
+ // architecture mode — recommendedMvp + firstSpike are required.
174
+ if (!input.parsed['recommendedMvp']) {
175
+ out.push({
176
+ category: 'missing-section',
177
+ severity: 'medium',
178
+ message: 'architecture plan is missing recommendedMvp.',
179
+ });
180
+ }
181
+ if (!input.parsed['firstSpike']) {
182
+ out.push({
183
+ category: 'missing-section',
184
+ severity: 'medium',
185
+ message: 'architecture plan is missing firstSpike.',
186
+ });
187
+ }
188
+ }
189
+ }
190
+ return out;
191
+ }
192
+ function scoreFindings(findings) {
193
+ if (findings.length === 0)
194
+ return 1;
195
+ let penalty = 0;
196
+ for (const f of findings) {
197
+ penalty += f.severity === 'high' ? 0.2 : f.severity === 'medium' ? 0.08 : 0.03;
198
+ }
199
+ return Math.max(0, 1 - penalty);
200
+ }
201
+ function walkPathLeaves(value, where, visit) {
202
+ if (Array.isArray(value)) {
203
+ for (let i = 0; i < value.length; i += 1)
204
+ walkPathLeaves(value[i], `${where}[${i}]`, visit);
205
+ return;
206
+ }
207
+ if (value === null || typeof value !== 'object')
208
+ return;
209
+ const rec = value;
210
+ for (const k of Object.keys(rec)) {
211
+ if (k === 'path' && typeof rec[k] === 'string') {
212
+ visit(rec[k], `${where}.${k}`);
213
+ continue;
214
+ }
215
+ walkPathLeaves(rec[k], `${where}.${k}`, visit);
216
+ }
217
+ }
218
+ function collectPathSet(value) {
219
+ const out = new Set();
220
+ if (!Array.isArray(value))
221
+ return out;
222
+ for (const item of value) {
223
+ if (item && typeof item === 'object' && typeof item['path'] === 'string') {
224
+ out.add(item['path'].trim());
225
+ }
226
+ }
227
+ return out;
228
+ }
229
+ function collectStringArrayFromKey(value, key) {
230
+ const out = [];
231
+ if (!Array.isArray(value))
232
+ return out;
233
+ for (const item of value) {
234
+ if (item && typeof item === 'object' && typeof item[key] === 'string') {
235
+ out.push(item[key].trim());
236
+ }
237
+ }
238
+ return out;
239
+ }
240
+ function collectStringArray(value) {
241
+ if (!Array.isArray(value))
242
+ return [];
243
+ return value.filter((s) => typeof s === 'string');
244
+ }
245
+ function looksLikePathRef(s) {
246
+ if (s.length === 0)
247
+ return false;
248
+ if (/[<>{}]/.test(s))
249
+ return false;
250
+ if (s.includes('/'))
251
+ return true;
252
+ return /\.(ts|tsx|js|jsx|mjs|cjs|json|md|yml|yaml|css|html)$/.test(s);
253
+ }
254
+ function pathExistsInWorkspace(cwd, candidate) {
255
+ const normalised = candidate.replace(/\\/g, '/').replace(/^\.\//, '');
256
+ const abs = nodePath.isAbsolute(normalised) ? normalised : nodePath.join(cwd, normalised);
257
+ try {
258
+ return existsSync(abs);
259
+ }
260
+ catch {
261
+ return false;
262
+ }
263
+ }
264
+ function normaliseCommand(c) {
265
+ return c.trim().replace(/\s+/g, ' ');
266
+ }
267
+ function tryExtractJson(text) {
268
+ const trimmed = text.trim();
269
+ const fenced = trimmed.match(/```json\s*([\s\S]*?)```/i);
270
+ const candidate = fenced?.[1]?.trim() ?? trimmed;
271
+ try {
272
+ const parsed = JSON.parse(candidate);
273
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
274
+ return parsed;
275
+ }
276
+ }
277
+ catch {
278
+ // Try balanced extraction
279
+ }
280
+ const first = candidate.indexOf('{');
281
+ const last = candidate.lastIndexOf('}');
282
+ if (first >= 0 && last > first) {
283
+ try {
284
+ const parsed = JSON.parse(candidate.slice(first, last + 1));
285
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
286
+ return parsed;
287
+ }
288
+ }
289
+ catch {
290
+ // ignore
291
+ }
292
+ }
293
+ return null;
294
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Primary MCP tools — the core set advertised to a connected agent
3
+ * by default. Every tool in {@link ALL_TOOLS} stays callable (so an
4
+ * agent that already knows the name can use it), but `tools/list`
5
+ * only advertises the primary set. Smaller surface = better
6
+ * tool-selection accuracy for the agent.
7
+ *
8
+ * Picked to match the CLI's allowlist semantics: anything an agent
9
+ * could realistically reach for during a normal task — discovery,
10
+ * context, planning, validation — is in. Internal introspection
11
+ * (catalog dumps, fix-preview internals, drift baselines) is out;
12
+ * still callable, just not in the default tool list.
13
+ *
14
+ * Escape hatch: set `SHRK_MCP_FULL_TOOLS=1` to advertise the full
15
+ * catalog (useful when debugging an agent's tool selection).
16
+ */
17
+ export declare const PRIMARY_MCP_TOOLS: ReadonlySet<string>;
18
+ /**
19
+ * Should `tools/list` advertise the full catalog instead of the
20
+ * primary set? Driven by the env var so an agent operator can flip it
21
+ * without rebuilding.
22
+ */
23
+ export declare function shouldAdvertiseFullToolset(): boolean;
24
+ //# sourceMappingURL=primary-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primary-tools.d.ts","sourceRoot":"","sources":["../../src/tools/primary-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CA4DhD,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAGpD"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Primary MCP tools — the core set advertised to a connected agent
3
+ * by default. Every tool in {@link ALL_TOOLS} stays callable (so an
4
+ * agent that already knows the name can use it), but `tools/list`
5
+ * only advertises the primary set. Smaller surface = better
6
+ * tool-selection accuracy for the agent.
7
+ *
8
+ * Picked to match the CLI's allowlist semantics: anything an agent
9
+ * could realistically reach for during a normal task — discovery,
10
+ * context, planning, validation — is in. Internal introspection
11
+ * (catalog dumps, fix-preview internals, drift baselines) is out;
12
+ * still callable, just not in the default tool list.
13
+ *
14
+ * Escape hatch: set `SHRK_MCP_FULL_TOOLS=1` to advertise the full
15
+ * catalog (useful when debugging an agent's tool selection).
16
+ */
17
+ export const PRIMARY_MCP_TOOLS = new Set([
18
+ // Project orientation
19
+ 'inspect_workspace',
20
+ 'get_project_overview',
21
+ 'get_agent_instructions',
22
+ 'get_start_here',
23
+ // Context / task routing
24
+ 'get_relevant_context',
25
+ 'get_task_packet',
26
+ 'get_action_hints',
27
+ 'create_agent_brief',
28
+ 'get_relevant_rules',
29
+ 'explain_command',
30
+ // Browse the registries
31
+ 'list_knowledge',
32
+ 'get_knowledge',
33
+ 'list_rules',
34
+ 'get_rule',
35
+ 'list_path_conventions',
36
+ 'list_templates',
37
+ 'get_template',
38
+ 'list_pipelines',
39
+ 'get_pipeline',
40
+ 'list_presets',
41
+ 'get_preset',
42
+ 'list_packs',
43
+ 'get_pack',
44
+ // Safe code generation (plan-first)
45
+ 'create_generation_plan',
46
+ 'render_template_preview',
47
+ 'explain_generation_target',
48
+ // Validation gates (read-only)
49
+ 'check_boundaries',
50
+ 'get_diff_check_report',
51
+ 'get_file_advice',
52
+ 'get_architecture_constraints',
53
+ 'get_architecture_violations',
54
+ // Doctor / readiness
55
+ 'get_ai_readiness_report',
56
+ 'doctor_packs',
57
+ // Code-intelligence graph — the agent's grep replacement for understanding
58
+ // existing code: who calls X, where is X used (path:line), what breaks if I
59
+ // change X, is X wired. Verifiable file:line truth from the indexed graph.
60
+ 'get_graph_callers',
61
+ 'code_find_usages',
62
+ 'get_graph_impact',
63
+ 'get_graph_path',
64
+ 'get_graph_hubs',
65
+ 'graph_why',
66
+ 'get_graph_node',
67
+ 'get_graph_search',
68
+ // Search
69
+ 'search_all',
70
+ 'search_knowledge',
71
+ 'search_commands',
72
+ // Token compression (deterministic, reversible)
73
+ 'compress_context',
74
+ 'retrieve_original',
75
+ 'align_cache',
76
+ 'restore_cache',
77
+ ]);
78
+ /**
79
+ * Should `tools/list` advertise the full catalog instead of the
80
+ * primary set? Driven by the env var so an agent operator can flip it
81
+ * without rebuilding.
82
+ */
83
+ export function shouldAdvertiseFullToolset() {
84
+ const v = process.env.SHRK_MCP_FULL_TOOLS;
85
+ return v === '1' || v === 'true' || v === 'yes';
86
+ }
@@ -93,7 +93,7 @@ export const getCommandTaxonomyTool = {
93
93
  inputSchema: { type: 'object', properties: {}, additionalProperties: false },
94
94
  async handler() {
95
95
  // The CLI carries the canonical catalog; here we describe the surface
96
- // without importing it (no inspector → CLI dependency). Adopters can
96
+ // without importing it (no inspector → CLI dependency). Consumers can
97
97
  // run `shrk commands taxonomy` for the full grouped output.
98
98
  return {
99
99
  data: {
@@ -2,7 +2,4 @@ import type { IToolDefinition } from '../server/tool-definition.js';
2
2
  export declare const listProfilesTool: IToolDefinition;
3
3
  export declare const getProfileTool: IToolDefinition;
4
4
  export declare const getProfilesDoctorTool: IToolDefinition;
5
- export declare const listPluginLifecycleProfilesTool: IToolDefinition;
6
- export declare const getPluginLifecycleProfileTool: IToolDefinition;
7
- export declare const getPluginLifecycleProfileDoctorTool: IToolDefinition;
8
5
  //# sourceMappingURL=r32-profiles.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"r32-profiles.tool.d.ts","sourceRoot":"","sources":["../../src/tools/r32-profiles.tool.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,eAAO,MAAM,gBAAgB,EAAE,eAe9B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,eAsB5B,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,eAOnC,CAAC;AAEF,eAAO,MAAM,+BAA+B,EAAE,eAO7C,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,eAmB3C,CAAC;AAEF,eAAO,MAAM,mCAAmC,EAAE,eAqBjD,CAAC"}
1
+ {"version":3,"file":"r32-profiles.tool.d.ts","sourceRoot":"","sources":["../../src/tools/r32-profiles.tool.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,eAAO,MAAM,gBAAgB,EAAE,eAe9B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,eAsB5B,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,eAOnC,CAAC"}
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Read-only MCP tools for profiles + lifecycle profiles.
2
+ * Read-only MCP tools for profiles.
3
3
  *
4
4
  * Engine never writes from MCP. These tools surface pack-contributed and
5
5
  * locally configured profiles so an agent can decide which one to pass to
6
- * `shrk plugin rename|remove --profile <id>` (the human runs the CLI).
6
+ * a profile-aware command (the human runs the CLI).
7
7
  */
8
- import { checkPluginLifecycleProfileHealth, findProfile, listProfileIssues, listProfiles, listPluginLifecycleProfiles, ProfileKind, } from '@shrkcrft/inspector';
8
+ import { findProfile, listProfileIssues, listProfiles, ProfileKind, } from '@shrkcrft/inspector';
9
9
  export const listProfilesTool = {
10
10
  name: 'list_profiles',
11
11
  description: 'List all pack-contributed and locally configured profiles. Read-only.',
@@ -54,54 +54,3 @@ export const getProfilesDoctorTool = {
54
54
  return { data: { issues: await listProfileIssues(ctx.inspection) } };
55
55
  },
56
56
  };
57
- export const listPluginLifecycleProfilesTool = {
58
- name: 'list_plugin_lifecycle_profiles',
59
- description: 'List registered plugin lifecycle profiles. Read-only.',
60
- inputSchema: { type: 'object', additionalProperties: false, properties: {} },
61
- async handler(_input, ctx) {
62
- return { data: await listPluginLifecycleProfiles(ctx.inspection) };
63
- },
64
- };
65
- export const getPluginLifecycleProfileTool = {
66
- name: 'get_plugin_lifecycle_profile',
67
- description: 'Get one plugin lifecycle profile by id. Read-only.',
68
- inputSchema: {
69
- type: 'object',
70
- additionalProperties: false,
71
- required: ['id'],
72
- properties: { id: { type: 'string' } },
73
- },
74
- async handler(input, ctx) {
75
- const id = typeof input.id === 'string' ? input.id : '';
76
- if (!id)
77
- return { isError: true, error: { code: 'invalid-input', message: 'id is required.' } };
78
- const entries = await listPluginLifecycleProfiles(ctx.inspection);
79
- const entry = entries.find((e) => e.profile.id === id);
80
- if (!entry) {
81
- return { isError: true, error: { code: 'not-found', message: `Unknown lifecycle profile "${id}".` } };
82
- }
83
- return { data: entry };
84
- },
85
- };
86
- export const getPluginLifecycleProfileDoctorTool = {
87
- name: 'get_plugin_lifecycle_profile_doctor',
88
- description: 'Health check for plugin lifecycle profiles. Read-only.',
89
- inputSchema: {
90
- type: 'object',
91
- additionalProperties: false,
92
- properties: { id: { type: 'string' } },
93
- },
94
- async handler(input, ctx) {
95
- const id = typeof input.id === 'string' ? input.id : undefined;
96
- const entries = await listPluginLifecycleProfiles(ctx.inspection);
97
- const targets = id ? entries.filter((e) => e.profile.id === id) : entries;
98
- if (id && targets.length === 0) {
99
- return { isError: true, error: { code: 'not-found', message: `Unknown lifecycle profile "${id}".` } };
100
- }
101
- const health = {};
102
- for (const e of targets) {
103
- health[e.profile.id] = checkPluginLifecycleProfileHealth(ctx.cwd, e.profile);
104
- }
105
- return { data: { health } };
106
- },
107
- };
@@ -0,0 +1,9 @@
1
+ import type { IToolDefinition } from '../server/tool-definition.js';
2
+ /**
3
+ * The retrieve half of Compress-Cache-Retrieve. Given a `<<ccr:KEY>>` key
4
+ * emitted by `compress_context`, return the full uncompressed original. Reads
5
+ * from the server's in-memory store only — never the filesystem — so it stays
6
+ * read-only.
7
+ */
8
+ export declare const retrieveOriginalTool: IToolDefinition;
9
+ //# sourceMappingURL=retrieve-original.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieve-original.tool.d.ts","sourceRoot":"","sources":["../../src/tools/retrieve-original.tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,eAyClC,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The retrieve half of Compress-Cache-Retrieve. Given a `<<ccr:KEY>>` key
3
+ * emitted by `compress_context`, return the full uncompressed original. Reads
4
+ * from the server's in-memory store only — never the filesystem — so it stays
5
+ * read-only.
6
+ */
7
+ export const retrieveOriginalTool = {
8
+ name: 'retrieve_original',
9
+ description: 'Retrieve the full, uncompressed original that `compress_context` cached, by its `<<ccr:KEY>>` key. The reverse of compression — use it when a compressed blob elided a detail you now need. Cache lives for the MCP server session. Read-only.',
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {
13
+ key: { type: 'string', description: 'The CCR key from a `<<ccr:KEY>>` marker.' },
14
+ },
15
+ required: ['key'],
16
+ additionalProperties: false,
17
+ },
18
+ handler(input, ctx) {
19
+ const key = typeof input.key === 'string' ? input.key.trim() : '';
20
+ if (key.length === 0) {
21
+ return {
22
+ isError: true,
23
+ text: 'retrieve_original requires a "key".',
24
+ error: { code: 'invalid-input', message: 'key is required' },
25
+ };
26
+ }
27
+ if (!ctx.ccrStore) {
28
+ return {
29
+ isError: true,
30
+ text: 'No CCR store is wired on this server.',
31
+ error: { code: 'unavailable', message: 'ccr store not available' },
32
+ };
33
+ }
34
+ const entry = ctx.ccrStore.get(key);
35
+ if (!entry) {
36
+ return {
37
+ isError: true,
38
+ text: `No cached original for key "${key}". It may have been evicted (cache is bounded) or never existed in this session.`,
39
+ error: { code: 'cache-miss', message: `unknown ccr key ${key}` },
40
+ };
41
+ }
42
+ return {
43
+ data: { key: entry.key, bytes: entry.bytes, content: entry.content },
44
+ text: entry.content,
45
+ };
46
+ },
47
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-reports.tool.d.ts","sourceRoot":"","sources":["../../src/tools/runtime-reports.tool.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAYpE,eAAO,MAAM,qBAAqB,EAAE,eAsBnC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAsBtC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAgBtC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAqBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAqCrC,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,eAU3C,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,eAUxC,CAAC"}
1
+ {"version":3,"file":"runtime-reports.tool.d.ts","sourceRoot":"","sources":["../../src/tools/runtime-reports.tool.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAYpE,eAAO,MAAM,qBAAqB,EAAE,eAsBnC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAsBtC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAgBtC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAqBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAqCrC,CAAC;AAEF,eAAO,MAAM,6BAA6B,EAAE,eAU3C,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,eAUxC,CAAC"}
@@ -6,8 +6,6 @@
6
6
  import { existsSync, readFileSync } from 'node:fs';
7
7
  import * as nodePath from 'node:path';
8
8
  import { buildAdoptionReport, buildCoverageReport, buildDriftReport, buildOnboardingAdoptionPlan, buildOnboardingPlan, buildQualityReport, buildSafetyAudit, readAdoptionState, renderAdoptionReportHtml, renderAdoptionReportMarkdown, renderAdoptionReportText, renderDevSessionHtml, renderDevSessionFinalReport, renderReviewComment, renderReviewHtml, renderQualityHtml, renderSafetyHtml, scanDevSession, } from '@shrkcrft/inspector';
9
- // DX#4 — derive audit view from ALL_TOOLS at runtime.
10
- import { ALL_TOOLS } from "./all-tools.js";
11
9
  function pickFormat(input, fallback = 'json') {
12
10
  const f = String(input.format ?? fallback).toLowerCase();
13
11
  if (f === 'text' || f === 'markdown' || f === 'html' || f === 'json')
@@ -95,7 +93,7 @@ export const getSafetyHtmlReportTool = {
95
93
  const audit = buildSafetyAudit({
96
94
  inspection: ctx.inspection,
97
95
  catalog: [],
98
- mcpTools: ALL_TOOLS.map((t) => ({ name: t.name, description: t.description, canWrite: false })),
96
+ mcpTools: (ctx.allTools ?? []).map((t) => ({ name: t.name, description: t.description, canWrite: false })),
99
97
  planSecretEnv: 'SHARKCRAFT_PLAN_SECRET',
100
98
  planSecretConfigured: typeof process.env.SHARKCRAFT_PLAN_SECRET === 'string' && process.env.SHARKCRAFT_PLAN_SECRET.length > 0,
101
99
  });
@@ -1 +1 @@
1
- {"version":3,"file":"safety-audit.tool.d.ts","sourceRoot":"","sources":["../../src/tools/safety-audit.tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAQpE,eAAO,MAAM,kBAAkB,EAAE,eAqChC,CAAC"}
1
+ {"version":3,"file":"safety-audit.tool.d.ts","sourceRoot":"","sources":["../../src/tools/safety-audit.tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAKpE,eAAO,MAAM,kBAAkB,EAAE,eAqChC,CAAC"}
@@ -1,7 +1,4 @@
1
1
  import { buildSafetyAudit } from '@shrkcrft/inspector';
2
- // DX#4 — derive the audit list at runtime from ALL_TOOLS instead of
3
- // maintaining a parallel static list.
4
- import { ALL_TOOLS } from "./all-tools.js";
5
2
  import { COMMAND_CATALOG_EXPORT } from "./command-catalog.tool.js";
6
3
  const PLAN_SECRET_ENV = 'SHARKCRAFT_PLAN_SECRET';
7
4
  export const getSafetyAuditTool = {
@@ -26,7 +23,7 @@ export const getSafetyAuditTool = {
26
23
  requiresReview: e.requiresReview,
27
24
  mcpAvailable: e.mcpAvailable,
28
25
  }));
29
- const mcpTools = ALL_TOOLS.map((t) => ({
26
+ const mcpTools = (ctx.allTools ?? []).map((t) => ({
30
27
  name: t.name,
31
28
  description: t.description,
32
29
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"search-knowledge.tool.d.ts","sourceRoot":"","sources":["../../src/tools/search-knowledge.tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAGpE,eAAO,MAAM,mBAAmB,EAAE,eAwCjC,CAAC"}
1
+ {"version":3,"file":"search-knowledge.tool.d.ts","sourceRoot":"","sources":["../../src/tools/search-knowledge.tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAIpE,eAAO,MAAM,mBAAmB,EAAE,eA4CjC,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import { searchKnowledge } from '@shrkcrft/knowledge';
2
+ import { FORMAT_INPUT_PROPERTY, formatRows } from "../server/columnar-format.js";
2
3
  export const searchKnowledgeTool = {
3
4
  name: 'search_knowledge',
4
- description: 'Search knowledge entries by query/tags/types/scope/appliesWhen.',
5
+ description: 'Search knowledge entries by query/tags/types/scope/appliesWhen. Pass `format:"table"` for a token-efficient columnar payload.',
5
6
  inputSchema: {
6
7
  type: 'object',
7
8
  properties: {
@@ -12,6 +13,7 @@ export const searchKnowledgeTool = {
12
13
  appliesWhen: { type: 'array', items: { type: 'string' } },
13
14
  minPriority: { type: 'string' },
14
15
  limit: { type: 'integer', minimum: 1 },
16
+ ...FORMAT_INPUT_PROPERTY,
15
17
  },
16
18
  additionalProperties: false,
17
19
  },
@@ -26,17 +28,19 @@ export const searchKnowledgeTool = {
26
28
  minPriority: typeof input.minPriority === 'string' ? input.minPriority : undefined,
27
29
  limit,
28
30
  });
29
- return {
30
- data: results.map((r) => ({
31
- id: r.entry.id,
32
- title: r.entry.title,
33
- score: r.score,
34
- type: r.entry.type,
35
- priority: r.entry.priority,
36
- tags: r.entry.tags,
37
- scope: r.entry.scope,
38
- reasons: r.reasons,
39
- })),
40
- };
31
+ const rows = results.map((r) => ({
32
+ id: r.entry.id,
33
+ title: r.entry.title,
34
+ score: r.score,
35
+ type: r.entry.type,
36
+ priority: r.entry.priority,
37
+ tags: r.entry.tags,
38
+ scope: r.entry.scope,
39
+ reasons: r.reasons,
40
+ }));
41
+ // `format:"table"` columnar-encodes the homogeneous hit rows; scalars and
42
+ // string-array cells (tags/scope/reasons) reconstruct losslessly. Default
43
+ // (no format / format:"json") returns the bare array unchanged.
44
+ return { data: formatRows(rows, input) };
41
45
  },
42
46
  };