@planu/cli 4.1.0 → 4.1.2
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/CHANGELOG.md +21 -0
- package/dist/config/license-plans.json +65 -361
- package/dist/engine/hooks/git-hook-generator.js +31 -0
- package/dist/tools/git/hook-ops.js +53 -9
- package/dist/tools/tool-registry/group-infra.js +22 -0
- package/package.json +8 -7
- package/dist/engine/escalator/index.d.ts +0 -5
- package/dist/engine/escalator/index.js +0 -5
- package/dist/engine/freeze/retro-audit.d.ts +0 -6
- package/dist/engine/freeze/retro-audit.js +0 -24
- package/dist/engine/heal/backup.d.ts +0 -9
- package/dist/engine/heal/backup.js +0 -21
- package/dist/engine/idioma-validator/index.d.ts +0 -17
- package/dist/engine/idioma-validator/index.js +0 -89
- package/dist/engine/saga/index.d.ts +0 -4
- package/dist/engine/saga/index.js +0 -4
- package/dist/engine/spec-state-machine/index.d.ts +0 -3
- package/dist/engine/spec-state-machine/index.js +0 -2
- package/dist/engine/spec-summary-html/dashboard-renderer.d.ts +0 -6
- package/dist/engine/spec-summary-html/dashboard-renderer.js +0 -333
- package/dist/engine/triagier/index.d.ts +0 -5
- package/dist/engine/triagier/index.js +0 -5
- package/dist/engine/universal-rules/index.d.ts +0 -5
- package/dist/engine/universal-rules/index.js +0 -6
- package/dist/testing/cassette/index.d.ts +0 -23
- package/dist/testing/cassette/index.js +0 -26
- package/dist/tools/domain-bundle-handler.d.ts +0 -37
- package/dist/tools/domain-bundle-handler.js +0 -71
- package/dist/tools/figma/rules-file.d.ts +0 -5
- package/dist/tools/figma/rules-file.js +0 -45
- package/dist/tools/heal-planu-root.d.ts +0 -8
- package/dist/tools/heal-planu-root.js +0 -144
- package/dist/tools/opencode-host-adapter.d.ts +0 -3
- package/dist/tools/opencode-host-adapter.js +0 -33
- package/dist/tools/plan-team-distribution.d.ts +0 -3
- package/dist/tools/plan-team-distribution.js +0 -71
- package/dist/tools/reconcile-status-json.d.ts +0 -4
- package/dist/tools/reconcile-status-json.js +0 -209
- package/dist/tools/register-all-tools.d.ts +0 -8
- package/dist/tools/register-all-tools.js +0 -239
- package/dist/tools/tool-registry/group-analysis-monitoring.d.ts +0 -3
- package/dist/tools/tool-registry/group-analysis-monitoring.js +0 -942
- package/dist/tools/tool-registry/group-integrations.d.ts +0 -3
- package/dist/tools/tool-registry/group-integrations.js +0 -1046
- package/dist/tools/tool-registry/group-misc.d.ts +0 -3
- package/dist/tools/tool-registry/group-misc.js +0 -1367
- package/dist/tools/tool-registry/group-platform.d.ts +0 -3
- package/dist/tools/tool-registry/group-platform.js +0 -1681
- package/dist/tools/tool-registry/group-session-knowledge.d.ts +0 -3
- package/dist/tools/tool-registry/group-session-knowledge.js +0 -1416
- package/dist/tools/tool-registry/group-spec-ops.d.ts +0 -3
- package/dist/tools/tool-registry/group-spec-ops.js +0 -917
- package/dist/tools/workspace-overview.d.ts +0 -4
- package/dist/tools/workspace-overview.js +0 -316
- package/dist/transports/middleware/index.d.ts +0 -9
- package/dist/transports/middleware/index.js +0 -7
- package/dist/transports/middleware/with-sandbox.d.ts +0 -21
- package/dist/transports/middleware/with-sandbox.js +0 -68
- package/dist/types/heal.d.ts +0 -18
- package/dist/types/heal.js +0 -3
|
@@ -1,942 +0,0 @@
|
|
|
1
|
-
/* eslint-disable max-lines -- thematic registry group consolidated by SPEC refactor-phase3 (commit aafeea60); each block is a declarative tool registration ~20 lines, split would re-create the ~120 register-*.ts files this phase intentionally collapsed */
|
|
2
|
-
// tools/tool-registry/group-analysis-monitoring.ts — Declarative registry: analysis & monitoring tools.
|
|
3
|
-
//
|
|
4
|
-
// Phase 3 (refactor/registry-phase3): consolidates register-*.ts files for:
|
|
5
|
-
// analytics-report, code-impact, dependency-impact, tech-debt,
|
|
6
|
-
// drift-monitor, drift-watcher (empty shim), manage-drift,
|
|
7
|
-
// code-graph, estimation-accuracy, team-analytics,
|
|
8
|
-
// spec-scheduler, crash-shield, self-healing, auto-remediation, auto-promoter
|
|
9
|
-
import { z } from 'zod';
|
|
10
|
-
import { safeLicensed, safeTracked } from '../safe-handler.js';
|
|
11
|
-
import { projectIdSchema, withProject } from '../tool-registry-helpers.js';
|
|
12
|
-
import { makeDeprecationStub } from './deprecated-stubs.js';
|
|
13
|
-
import { registerFromEntries } from '../tool-entry.js';
|
|
14
|
-
// ── Analytics report (register-analytics-report-tools.ts) ────────────────────
|
|
15
|
-
import { handleAnalyticsReport } from '../analytics-report-handler.js';
|
|
16
|
-
import { handleSpecEffectivenessScore } from '../spec-effectiveness-score.js';
|
|
17
|
-
import { toolResult, formatError } from '../response-helpers.js';
|
|
18
|
-
// ── Code impact (register-code-impact-tools.ts) ───────────────────────────────
|
|
19
|
-
import { handleAnalyzeCodeImpact, handleCodeChangeCompliance, handleSuggestSpecUpdate, handleGitDiffToSpecImpact, } from '../code-impact-handler.js';
|
|
20
|
-
// ── Dependency impact (register-dependency-impact-tools.ts) ───────────────────
|
|
21
|
-
import { handleRegisterApiSurface, handleAnalyzeBreakingChanges, handleDependencyImpactReport, handleCheckApiCompatibility, } from '../dependency-impact-handler.js';
|
|
22
|
-
// ── Tech debt (register-tech-debt-tools.ts) ───────────────────────────────────
|
|
23
|
-
import { handleTrackTechDebt, handleTechDebtBudget, handleListTechDebt, handleDebtForecast, handleResolveTechDebt, } from '../tech-debt-handler.js';
|
|
24
|
-
// ── Drift monitor (register-drift-monitor-tools.ts) ───────────────────────────
|
|
25
|
-
import { handleConfigureDriftMonitoring, handleDriftAlertRules, } from '../drift-monitor-handler.js';
|
|
26
|
-
// ── Manage drift (register-manage-drift-tool.ts) ──────────────────────────────
|
|
27
|
-
import { handleManageDrift } from '../manage-drift-handler.js';
|
|
28
|
-
// ── Code graph (register-code-graph-tools.ts) ─────────────────────────────────
|
|
29
|
-
import { handleConfigureCodeGraph, handleCodeGraphStatus } from '../code-graph-handler.js';
|
|
30
|
-
// ── Estimation accuracy (register-estimation-accuracy-tools.ts) ───────────────
|
|
31
|
-
import { handleRecordActual, handleCalibrateEstimates } from '../estimation-accuracy-handler.js';
|
|
32
|
-
// ── Team analytics (register-team-analytics-tools.ts) ────────────────────────
|
|
33
|
-
import { handleWorkloadDistribution } from '../team-analytics-handler.js';
|
|
34
|
-
// ── Spec scheduler (register-spec-scheduler-tools.ts) ────────────────────────
|
|
35
|
-
import { handleSimulateParallelExecution, handleCriticalPathAnalyzer, handleParallelEfficiencyScore, handleOptimizeSpecScheduling, } from '../spec-scheduler-handler.js';
|
|
36
|
-
// ── Crash shield (register-crash-shield-tools.ts) ────────────────────────────
|
|
37
|
-
import { handleScanCrashRisks, handleFixCrashRisks, handleConfigureCrashRules, ScanCrashRisksSchema, FixCrashRisksSchema, ConfigureCrashRulesSchema, } from '../crash-shield-handler.js';
|
|
38
|
-
// ── Self healing (register-self-healing-tools.ts) ────────────────────────────
|
|
39
|
-
import { handleAutoFixValidation } from '../auto-fix-validation.js';
|
|
40
|
-
import { autoFixHealth } from '../../engine/health/auto-fixer.js';
|
|
41
|
-
import { hashProjectPath } from '../../storage/base-store.js';
|
|
42
|
-
// ── Auto remediation (register-auto-remediation.ts) ──────────────────────────
|
|
43
|
-
import { autoRemediateCompliance } from '../../engine/compliance/auto-remediator.js';
|
|
44
|
-
// ── Auto promoter (register-auto-promoter-tools.ts) ──────────────────────────
|
|
45
|
-
import { handleConfigureAutoPromotion, handleCheckAutoPromotion, } from '../auto-promoter-handler.js';
|
|
46
|
-
// ── Observatory insights (SPEC-572) ───────────────────────────────────────────
|
|
47
|
-
import { handleObservatoryInsights } from '../observatory-insights.js';
|
|
48
|
-
// ── Multi-teammate review (SPEC-593) ──────────────────────────────────────────
|
|
49
|
-
import { registerMultiTeammateReviewTool } from '../multi-teammate-review.js';
|
|
50
|
-
// ── Code duplication detection (SPEC-970) ────────────────────────────────────
|
|
51
|
-
import { handleDetectDuplication } from '../detect-duplication.js';
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
// Shared schema constants
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
const REPORT_TYPE_VALUES = [
|
|
56
|
-
'velocity',
|
|
57
|
-
'velocity-trend',
|
|
58
|
-
'tech-debt',
|
|
59
|
-
'estimation-accuracy',
|
|
60
|
-
'team',
|
|
61
|
-
];
|
|
62
|
-
const SEVERITY_ENUM = z
|
|
63
|
-
.enum(['low', 'medium', 'high', 'critical'])
|
|
64
|
-
.describe('Severity level. Values: low, medium, high, critical.');
|
|
65
|
-
const CATEGORY_ENUM = z
|
|
66
|
-
.enum(['testing', 'documentation', 'refactoring', 'architecture', 'security'])
|
|
67
|
-
.describe('Category. Values: testing, documentation, refactoring, architecture, security.');
|
|
68
|
-
const STATUS_ENUM = z
|
|
69
|
-
.enum(['open', 'resolved', 'all'])
|
|
70
|
-
.describe('Filter by status. Values: open, resolved, all.');
|
|
71
|
-
const SURFACE_TYPE_ENUM = z
|
|
72
|
-
.enum(['rest-endpoint', 'graphql', 'typescript-interface', 'database-schema', 'event'])
|
|
73
|
-
.describe('Surface type. Values: rest-endpoint, graphql, typescript-interface, database-schema, event.');
|
|
74
|
-
const surfaceSchema = z.object({
|
|
75
|
-
type: SURFACE_TYPE_ENUM,
|
|
76
|
-
definition: z.string().min(1).max(500).describe('Description of the surface.'),
|
|
77
|
-
isBreakingIfRemoved: z
|
|
78
|
-
.boolean()
|
|
79
|
-
.optional()
|
|
80
|
-
.describe('Whether removing this surface would be a breaking change.'),
|
|
81
|
-
});
|
|
82
|
-
// ---------------------------------------------------------------------------
|
|
83
|
-
// Registration
|
|
84
|
-
// ---------------------------------------------------------------------------
|
|
85
|
-
// eslint-disable-next-line max-lines-per-function -- registration catalog: one block per tool, each ~20 lines
|
|
86
|
-
export function registerAnalysisMonitoringGroupTools(s) {
|
|
87
|
-
// ── Analytics report ─────────────────────────────────────────────────────────
|
|
88
|
-
s.registerTool('analytics_report', {
|
|
89
|
-
description: 'Unified analytics report. Consolidates velocity_report, velocity_trend, ' +
|
|
90
|
-
'tech_debt_report, estimation_accuracy_report, and team_analytics into a single tool. ' +
|
|
91
|
-
'Choose the report type via the `type` parameter.',
|
|
92
|
-
annotations: { readOnlyHint: true },
|
|
93
|
-
inputSchema: {
|
|
94
|
-
type: z
|
|
95
|
-
.enum(REPORT_TYPE_VALUES)
|
|
96
|
-
.describe('Report type. Values: velocity, velocity-trend, tech-debt, estimation-accuracy, team'),
|
|
97
|
-
projectPath: z
|
|
98
|
-
.string()
|
|
99
|
-
.min(1)
|
|
100
|
-
.max(4096)
|
|
101
|
-
.optional()
|
|
102
|
-
.describe('Absolute path to the project root (required for most report types).'),
|
|
103
|
-
projectId: z
|
|
104
|
-
.string()
|
|
105
|
-
.min(1)
|
|
106
|
-
.max(256)
|
|
107
|
-
.optional()
|
|
108
|
-
.describe('Project ID (alternative to projectPath for estimation-accuracy).'),
|
|
109
|
-
window: z
|
|
110
|
-
.number()
|
|
111
|
-
.int()
|
|
112
|
-
.min(1)
|
|
113
|
-
.max(365)
|
|
114
|
-
.optional()
|
|
115
|
-
.default(30)
|
|
116
|
-
.describe('Days window for metrics (default: 30).'),
|
|
117
|
-
},
|
|
118
|
-
}, safeTracked('analytics_report', async (args) => handleAnalyticsReport(args)));
|
|
119
|
-
// Deprecated shims
|
|
120
|
-
s.registerTool('velocity_report', {
|
|
121
|
-
description: '[DEPRECATED] Use analytics_report({ type: "velocity" }) instead. Generate a velocity metrics report: throughput, lead time, cycle time, WIP, flow efficiency.',
|
|
122
|
-
annotations: { readOnlyHint: true },
|
|
123
|
-
inputSchema: {
|
|
124
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
125
|
-
weeks: z.number().int().min(1).max(52).optional().describe('Number of weeks to analyze.'),
|
|
126
|
-
window: z
|
|
127
|
-
.number()
|
|
128
|
-
.int()
|
|
129
|
-
.min(1)
|
|
130
|
-
.max(365)
|
|
131
|
-
.optional()
|
|
132
|
-
.describe('Days window (ignored; use weeks).'),
|
|
133
|
-
},
|
|
134
|
-
}, safeTracked('velocity_report', async (args) => {
|
|
135
|
-
const window = args.weeks ? args.weeks * 7 : 30;
|
|
136
|
-
const result = await handleAnalyticsReport({
|
|
137
|
-
type: 'velocity',
|
|
138
|
-
projectPath: args.projectPath,
|
|
139
|
-
window,
|
|
140
|
-
});
|
|
141
|
-
const deprecationNote = '⚠️ velocity_report is deprecated — use analytics_report({ type: "velocity" }) instead\n\n';
|
|
142
|
-
const firstContent = result.content[0];
|
|
143
|
-
if (firstContent) {
|
|
144
|
-
return {
|
|
145
|
-
...result,
|
|
146
|
-
content: [
|
|
147
|
-
{ ...firstContent, text: deprecationNote + firstContent.text },
|
|
148
|
-
...result.content.slice(1),
|
|
149
|
-
],
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
return result;
|
|
153
|
-
}));
|
|
154
|
-
s.registerTool('velocity_trend', {
|
|
155
|
-
description: '[DEPRECATED] Use analytics_report({ type: "velocity-trend" }) instead. Compare team velocity between last N weeks and previous N weeks.',
|
|
156
|
-
annotations: { readOnlyHint: true },
|
|
157
|
-
inputSchema: {
|
|
158
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
159
|
-
compareWeeks: z
|
|
160
|
-
.number()
|
|
161
|
-
.int()
|
|
162
|
-
.min(1)
|
|
163
|
-
.max(26)
|
|
164
|
-
.optional()
|
|
165
|
-
.describe('Weeks per comparison window.'),
|
|
166
|
-
},
|
|
167
|
-
}, safeTracked('velocity_trend', async (args) => {
|
|
168
|
-
const window = args.compareWeeks ? args.compareWeeks * 2 * 7 : 56;
|
|
169
|
-
const result = await handleAnalyticsReport({
|
|
170
|
-
type: 'velocity-trend',
|
|
171
|
-
projectPath: args.projectPath,
|
|
172
|
-
window,
|
|
173
|
-
});
|
|
174
|
-
const deprecationNote = '⚠️ velocity_trend is deprecated — use analytics_report({ type: "velocity-trend" }) instead\n\n';
|
|
175
|
-
const firstContent = result.content[0];
|
|
176
|
-
if (firstContent) {
|
|
177
|
-
return {
|
|
178
|
-
...result,
|
|
179
|
-
content: [
|
|
180
|
-
{ ...firstContent, text: deprecationNote + firstContent.text },
|
|
181
|
-
...result.content.slice(1),
|
|
182
|
-
],
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
return result;
|
|
186
|
-
}));
|
|
187
|
-
s.registerTool('tech_debt_report', {
|
|
188
|
-
description: '[DEPRECATED] Use analytics_report({ type: "tech-debt" }) instead. Generate an HTML report of all tech debt items.',
|
|
189
|
-
annotations: { readOnlyHint: true },
|
|
190
|
-
inputSchema: {
|
|
191
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
192
|
-
},
|
|
193
|
-
}, safeTracked('tech_debt_report', async (args) => {
|
|
194
|
-
if (!args.projectPath) {
|
|
195
|
-
return toolResult(formatError('projectPath is required'), undefined, true);
|
|
196
|
-
}
|
|
197
|
-
const result = await handleAnalyticsReport({
|
|
198
|
-
type: 'tech-debt',
|
|
199
|
-
projectPath: args.projectPath,
|
|
200
|
-
});
|
|
201
|
-
const deprecationNote = '⚠️ tech_debt_report is deprecated — use analytics_report({ type: "tech-debt" }) instead\n\n';
|
|
202
|
-
const firstContent = result.content[0];
|
|
203
|
-
if (firstContent) {
|
|
204
|
-
return {
|
|
205
|
-
...result,
|
|
206
|
-
content: [
|
|
207
|
-
{ ...firstContent, text: deprecationNote + firstContent.text },
|
|
208
|
-
...result.content.slice(1),
|
|
209
|
-
],
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
return result;
|
|
213
|
-
}));
|
|
214
|
-
s.registerTool('estimation_accuracy_report', {
|
|
215
|
-
description: '[DEPRECATED] Use analytics_report({ type: "estimation-accuracy" }) instead. Generate a historical estimation accuracy report.',
|
|
216
|
-
annotations: { readOnlyHint: true },
|
|
217
|
-
inputSchema: {
|
|
218
|
-
projectPath: z
|
|
219
|
-
.string()
|
|
220
|
-
.min(1)
|
|
221
|
-
.max(4096)
|
|
222
|
-
.optional()
|
|
223
|
-
.describe('Absolute path to the project root.'),
|
|
224
|
-
projectId: z.string().min(1).max(256).optional().describe('Project ID.'),
|
|
225
|
-
},
|
|
226
|
-
}, safeTracked('estimation_accuracy_report', async (args) => {
|
|
227
|
-
const result = await handleAnalyticsReport({
|
|
228
|
-
type: 'estimation-accuracy',
|
|
229
|
-
projectPath: args.projectPath,
|
|
230
|
-
projectId: args.projectId,
|
|
231
|
-
});
|
|
232
|
-
const deprecationNote = '⚠️ estimation_accuracy_report is deprecated — use analytics_report({ type: "estimation-accuracy" }) instead\n\n';
|
|
233
|
-
const firstContent = result.content[0];
|
|
234
|
-
if (firstContent) {
|
|
235
|
-
return {
|
|
236
|
-
...result,
|
|
237
|
-
content: [
|
|
238
|
-
{ ...firstContent, text: deprecationNote + firstContent.text },
|
|
239
|
-
...result.content.slice(1),
|
|
240
|
-
],
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
return result;
|
|
244
|
-
}));
|
|
245
|
-
s.registerTool('team_analytics', {
|
|
246
|
-
description: '[DEPRECATED] Use analytics_report({ type: "team" }) instead. Generate per-member performance metrics.',
|
|
247
|
-
annotations: { readOnlyHint: true },
|
|
248
|
-
inputSchema: {
|
|
249
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
250
|
-
weeks: z.number().int().min(1).max(52).optional().describe('Number of weeks to analyze.'),
|
|
251
|
-
},
|
|
252
|
-
}, safeTracked('team_analytics', async (args) => {
|
|
253
|
-
const window = args.weeks ? args.weeks * 7 : 28;
|
|
254
|
-
const result = await handleAnalyticsReport({
|
|
255
|
-
type: 'team',
|
|
256
|
-
projectPath: args.projectPath,
|
|
257
|
-
window,
|
|
258
|
-
});
|
|
259
|
-
const deprecationNote = '⚠️ team_analytics is deprecated — use analytics_report({ type: "team" }) instead\n\n';
|
|
260
|
-
const firstContent = result.content[0];
|
|
261
|
-
if (firstContent) {
|
|
262
|
-
return {
|
|
263
|
-
...result,
|
|
264
|
-
content: [
|
|
265
|
-
{ ...firstContent, text: deprecationNote + firstContent.text },
|
|
266
|
-
...result.content.slice(1),
|
|
267
|
-
],
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
return result;
|
|
271
|
-
}));
|
|
272
|
-
// ── Spec Effectiveness Score (SPEC-611) ──────────────────────────────────
|
|
273
|
-
s.registerTool('spec_effectiveness_score', {
|
|
274
|
-
description: 'Compute the Spec Effectiveness Score for a spec or aggregate across the project. Composite 0-100 score from adherence rate, first-pass success, rework ratio, estimation accuracy, and drift frequency. Pass specId for per-spec; omit or set aggregate=true for project-wide report with trends and patterns.',
|
|
275
|
-
annotations: { readOnlyHint: true },
|
|
276
|
-
inputSchema: {
|
|
277
|
-
specId: z
|
|
278
|
-
.string()
|
|
279
|
-
.min(1)
|
|
280
|
-
.max(256)
|
|
281
|
-
.optional()
|
|
282
|
-
.describe('Spec ID for per-spec score. Omit for project-wide report.'),
|
|
283
|
-
aggregate: z
|
|
284
|
-
.boolean()
|
|
285
|
-
.optional()
|
|
286
|
-
.describe('When true, return project-level aggregate report instead of per-spec.'),
|
|
287
|
-
projectPath: z
|
|
288
|
-
.string()
|
|
289
|
-
.min(1)
|
|
290
|
-
.max(4096)
|
|
291
|
-
.optional()
|
|
292
|
-
.describe('Absolute path to the project root.'),
|
|
293
|
-
projectId: z.string().min(1).max(256).optional().describe('Project ID.'),
|
|
294
|
-
},
|
|
295
|
-
}, safeTracked('spec_effectiveness_score', async (args) => handleSpecEffectivenessScore(args)));
|
|
296
|
-
// ── Code impact ──────────────────────────────────────────────────────────────
|
|
297
|
-
s.registerTool('analyze_code_impact', {
|
|
298
|
-
description: 'Analyze which specs are impacted by a code change. Provide filePath, diffText, or both. Returns related specs with relation type: direct-binding, filename-match, or semantic-match.',
|
|
299
|
-
inputSchema: {
|
|
300
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
301
|
-
filePath: z
|
|
302
|
-
.string()
|
|
303
|
-
.optional()
|
|
304
|
-
.describe('Path to the changed file (relative or absolute).'),
|
|
305
|
-
diffText: z
|
|
306
|
-
.string()
|
|
307
|
-
.optional()
|
|
308
|
-
.describe('Raw diff text (e.g. output of git diff). Used for semantic matching.'),
|
|
309
|
-
},
|
|
310
|
-
annotations: { title: 'Analyze Code Impact', readOnlyHint: true },
|
|
311
|
-
}, safeTracked('analyze_code_impact', (args) => handleAnalyzeCodeImpact(args)));
|
|
312
|
-
s.registerTool('code_change_compliance', {
|
|
313
|
-
description: 'Check whether a code change is justified by an approved spec. Returns a compliance score (0-100%), justifying specs, and unjustified changes.',
|
|
314
|
-
inputSchema: {
|
|
315
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
316
|
-
filePath: z
|
|
317
|
-
.string()
|
|
318
|
-
.optional()
|
|
319
|
-
.describe('Path to the changed file to check compliance for.'),
|
|
320
|
-
commitHash: z
|
|
321
|
-
.string()
|
|
322
|
-
.optional()
|
|
323
|
-
.describe('Git commit hash to analyze (uses git show internally).'),
|
|
324
|
-
},
|
|
325
|
-
annotations: { title: 'Code Change Compliance', readOnlyHint: true },
|
|
326
|
-
}, safeTracked('code_change_compliance', (args) => handleCodeChangeCompliance(args)));
|
|
327
|
-
s.registerTool('suggest_spec_update', {
|
|
328
|
-
description: 'Suggest which specs to update (or create) based on a changed file. Returns a list of suggestions with type (update/create), spec ID, and reason.',
|
|
329
|
-
inputSchema: {
|
|
330
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
331
|
-
filePath: z.string().min(1).max(4096).describe('Path to the changed file.'),
|
|
332
|
-
},
|
|
333
|
-
annotations: { title: 'Suggest Spec Update', readOnlyHint: true },
|
|
334
|
-
}, safeTracked('suggest_spec_update', (args) => handleSuggestSpecUpdate(args)));
|
|
335
|
-
s.registerTool('git_diff_to_spec_impact', {
|
|
336
|
-
description: 'Run git diff HEAD on the project and analyze which specs are impacted. Convenience alias that combines git diff + analyze_code_impact.',
|
|
337
|
-
inputSchema: {
|
|
338
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
339
|
-
},
|
|
340
|
-
annotations: { title: 'Git Diff to Spec Impact', readOnlyHint: true },
|
|
341
|
-
}, safeTracked('git_diff_to_spec_impact', (args) => handleGitDiffToSpecImpact(args)));
|
|
342
|
-
// ── Dependency impact ────────────────────────────────────────────────────────
|
|
343
|
-
s.registerTool('register_api_surface', {
|
|
344
|
-
description: 'Register or update the API surfaces exposed by a spec (REST endpoints, GraphQL schemas, TypeScript interfaces, database schemas, or events).',
|
|
345
|
-
inputSchema: {
|
|
346
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
347
|
-
specId: z.string().min(1).describe('ID of the spec that exposes these surfaces.'),
|
|
348
|
-
surfaces: z.array(surfaceSchema).min(1).describe('List of API surface definitions.'),
|
|
349
|
-
},
|
|
350
|
-
}, safeTracked('register_api_surface', async (args) => handleRegisterApiSurface(args)));
|
|
351
|
-
s.registerTool('analyze_breaking_changes', {
|
|
352
|
-
description: "Analyze which other specs may be impacted by a change to a spec's API surface. Returns affected specs with impact level (high/medium/low).",
|
|
353
|
-
annotations: { readOnlyHint: true },
|
|
354
|
-
inputSchema: {
|
|
355
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
356
|
-
specId: z.string().min(1).describe('ID of the spec being changed.'),
|
|
357
|
-
changeDescription: z
|
|
358
|
-
.string()
|
|
359
|
-
.min(1)
|
|
360
|
-
.max(1000)
|
|
361
|
-
.describe('Description of the change being made.'),
|
|
362
|
-
},
|
|
363
|
-
}, safeTracked('analyze_breaking_changes', async (args) => handleAnalyzeBreakingChanges(args)));
|
|
364
|
-
s.registerTool('dependency_impact_report', {
|
|
365
|
-
description: 'Generate an HTML report of specs affected by a change, including impact classification.',
|
|
366
|
-
annotations: { readOnlyHint: true },
|
|
367
|
-
inputSchema: {
|
|
368
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
369
|
-
specId: z.string().min(1).describe('ID of the spec being changed.'),
|
|
370
|
-
changeDescription: z
|
|
371
|
-
.string()
|
|
372
|
-
.min(1)
|
|
373
|
-
.max(1000)
|
|
374
|
-
.describe('Description of the change being made.'),
|
|
375
|
-
},
|
|
376
|
-
}, safeTracked('dependency_impact_report', async (args) => handleDependencyImpactReport(args)));
|
|
377
|
-
s.registerTool('check_api_compatibility', {
|
|
378
|
-
description: "Check which other specs depend on a given spec's API surfaces, helping identify compatibility risks.",
|
|
379
|
-
annotations: { readOnlyHint: true },
|
|
380
|
-
inputSchema: {
|
|
381
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
382
|
-
specId: z.string().min(1).describe('ID of the spec to check compatibility for.'),
|
|
383
|
-
},
|
|
384
|
-
}, safeTracked('check_api_compatibility', async (args) => handleCheckApiCompatibility(args)));
|
|
385
|
-
// ── Tech debt ────────────────────────────────────────────────────────────────
|
|
386
|
-
s.registerTool('track_tech_debt', {
|
|
387
|
-
description: 'Track a new tech debt item for a project. Records description, estimated hours, severity, and category.',
|
|
388
|
-
inputSchema: {
|
|
389
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
390
|
-
description: z.string().min(1).max(500).describe('Description of the tech debt.'),
|
|
391
|
-
estimatedHours: z
|
|
392
|
-
.number()
|
|
393
|
-
.min(0.5)
|
|
394
|
-
.max(1000)
|
|
395
|
-
.describe('Estimated hours to resolve this debt.'),
|
|
396
|
-
severity: SEVERITY_ENUM,
|
|
397
|
-
category: CATEGORY_ENUM,
|
|
398
|
-
specId: z.string().optional().describe('Optional spec ID this debt is linked to.'),
|
|
399
|
-
},
|
|
400
|
-
}, safeTracked('track_tech_debt', async (args) => handleTrackTechDebt(args)));
|
|
401
|
-
s.registerTool('tech_debt_budget', {
|
|
402
|
-
description: 'Configure tech debt budget limits: max hours allowed, max percent of backlog, and alert threshold.',
|
|
403
|
-
inputSchema: {
|
|
404
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
405
|
-
maxHours: z
|
|
406
|
-
.number()
|
|
407
|
-
.min(1)
|
|
408
|
-
.optional()
|
|
409
|
-
.describe('Maximum total open hours of tech debt allowed.'),
|
|
410
|
-
maxPercentOfBacklog: z
|
|
411
|
-
.number()
|
|
412
|
-
.min(1)
|
|
413
|
-
.max(100)
|
|
414
|
-
.optional()
|
|
415
|
-
.describe('Maximum tech debt as a percentage of backlog hours.'),
|
|
416
|
-
alertThreshold: z
|
|
417
|
-
.number()
|
|
418
|
-
.min(1)
|
|
419
|
-
.max(100)
|
|
420
|
-
.optional()
|
|
421
|
-
.describe('Percentage of budget that triggers an alert.'),
|
|
422
|
-
},
|
|
423
|
-
}, safeTracked('tech_debt_budget', async (args) => handleTechDebtBudget(args)));
|
|
424
|
-
s.registerTool('list_tech_debt', {
|
|
425
|
-
description: 'List tech debt items for a project, optionally filtered by status, severity, or category.',
|
|
426
|
-
annotations: { readOnlyHint: true },
|
|
427
|
-
inputSchema: {
|
|
428
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
429
|
-
status: STATUS_ENUM.optional().default('open'),
|
|
430
|
-
severity: SEVERITY_ENUM.optional(),
|
|
431
|
-
category: CATEGORY_ENUM.optional(),
|
|
432
|
-
},
|
|
433
|
-
}, safeTracked('list_tech_debt', async (args) => handleListTechDebt(args)));
|
|
434
|
-
s.registerTool('debt_forecast', {
|
|
435
|
-
description: 'Forecast tech debt growth based on historical accumulation rate. Projects weeks until budget is exceeded.',
|
|
436
|
-
annotations: { readOnlyHint: true },
|
|
437
|
-
inputSchema: {
|
|
438
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
439
|
-
},
|
|
440
|
-
}, safeTracked('debt_forecast', async (args) => handleDebtForecast(args)));
|
|
441
|
-
s.registerTool('resolve_tech_debt', {
|
|
442
|
-
description: 'Mark a tech debt item as resolved.',
|
|
443
|
-
inputSchema: {
|
|
444
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
445
|
-
id: z.string().min(1).describe('ID of the tech debt item to resolve.'),
|
|
446
|
-
resolvedNotes: z
|
|
447
|
-
.string()
|
|
448
|
-
.max(500)
|
|
449
|
-
.optional()
|
|
450
|
-
.describe('Optional notes on how it was resolved.'),
|
|
451
|
-
},
|
|
452
|
-
}, safeTracked('resolve_tech_debt', async (args) => handleResolveTechDebt(args)));
|
|
453
|
-
// ── Drift monitor ────────────────────────────────────────────────────────────
|
|
454
|
-
s.registerTool('configure_drift_monitoring', {
|
|
455
|
-
description: 'Configure continuous drift monitoring for a project. Drift monitoring detects when code diverges from its spec over time.',
|
|
456
|
-
inputSchema: {
|
|
457
|
-
projectPath: z.string().describe('Absolute path to the project root.'),
|
|
458
|
-
action: z
|
|
459
|
-
.enum(['enable', 'disable', 'set-threshold', 'set-schedule', 'status'])
|
|
460
|
-
.describe('Action to perform. Values: enable, disable, set-threshold, set-schedule, status.'),
|
|
461
|
-
threshold: z
|
|
462
|
-
.number()
|
|
463
|
-
.min(0)
|
|
464
|
-
.max(100)
|
|
465
|
-
.optional()
|
|
466
|
-
.describe('Drift score (0–100) above which alerts fire. Used with set-threshold.'),
|
|
467
|
-
scheduleHours: z
|
|
468
|
-
.number()
|
|
469
|
-
.min(1)
|
|
470
|
-
.optional()
|
|
471
|
-
.describe('How often to check for drift (in hours). Used with set-schedule.'),
|
|
472
|
-
},
|
|
473
|
-
annotations: { title: 'Configure Drift Monitoring', destructiveHint: false },
|
|
474
|
-
}, safeTracked('configure_drift_monitoring', async (args) => handleConfigureDriftMonitoring(args)));
|
|
475
|
-
s.registerTool('drift_alert_rules', {
|
|
476
|
-
description: 'Manage alert rules for drift monitoring. Rules allow fine-grained thresholds per spec pattern.',
|
|
477
|
-
inputSchema: {
|
|
478
|
-
projectPath: z.string().describe('Absolute path to the project root.'),
|
|
479
|
-
action: z
|
|
480
|
-
.enum(['set-rules', 'list'])
|
|
481
|
-
.describe('Action to perform. Values: set-rules (replace all rules), list.'),
|
|
482
|
-
rules: z
|
|
483
|
-
.array(z.object({
|
|
484
|
-
name: z.string().describe('Human-readable rule name.'),
|
|
485
|
-
specIdPattern: z
|
|
486
|
-
.string()
|
|
487
|
-
.describe('Spec ID pattern to match (e.g. SPEC-* or SPEC-001).'),
|
|
488
|
-
thresholdOverride: z
|
|
489
|
-
.number()
|
|
490
|
-
.min(0)
|
|
491
|
-
.max(100)
|
|
492
|
-
.optional()
|
|
493
|
-
.describe('Override threshold for matching specs.'),
|
|
494
|
-
enabled: z.boolean().describe('Whether this rule is active.'),
|
|
495
|
-
}))
|
|
496
|
-
.optional()
|
|
497
|
-
.describe('Array of rules to set. Required for set-rules action.'),
|
|
498
|
-
},
|
|
499
|
-
annotations: { title: 'Drift Alert Rules', destructiveHint: false },
|
|
500
|
-
}, safeTracked('drift_alert_rules', async (args) => handleDriftAlertRules(args)));
|
|
501
|
-
// ── Manage drift ─────────────────────────────────────────────────────────────
|
|
502
|
-
s.registerTool('manage_drift', {
|
|
503
|
-
description: 'Unified drift management tool. Drift = spec criteria with no matching code artifact. ' +
|
|
504
|
-
'NOT drift: style differences, naming conventions, test coverage gaps. ' +
|
|
505
|
-
'Actions: detect (find unmatched criteria), summary (current drift state), ' +
|
|
506
|
-
'resolve (auto-create follow-up specs for unmatched criteria), ' +
|
|
507
|
-
'watch (start/stop file-system monitoring).',
|
|
508
|
-
inputSchema: {
|
|
509
|
-
action: z
|
|
510
|
-
.enum(['detect', 'summary', 'resolve', 'watch'])
|
|
511
|
-
.describe('Drift management action. Values: detect (find drift), summary (current drift report), resolve (mark as resolved), watch (enable/disable monitoring)'),
|
|
512
|
-
projectPath: z
|
|
513
|
-
.string()
|
|
514
|
-
.min(1)
|
|
515
|
-
.max(4096)
|
|
516
|
-
.optional()
|
|
517
|
-
.describe('Absolute path to the project root directory. Required for all actions.'),
|
|
518
|
-
specId: z
|
|
519
|
-
.string()
|
|
520
|
-
.min(1)
|
|
521
|
-
.max(200)
|
|
522
|
-
.optional()
|
|
523
|
-
.describe('Specific spec to check drift for (e.g. "SPEC-042"). Used with detect and watch.'),
|
|
524
|
-
projectId: z
|
|
525
|
-
.string()
|
|
526
|
-
.optional()
|
|
527
|
-
.describe('Project ID (hash). Auto-derived from projectPath when not provided.'),
|
|
528
|
-
dryRun: z
|
|
529
|
-
.boolean()
|
|
530
|
-
.optional()
|
|
531
|
-
.describe('Preview what would be changed without writing files. Used with detect and resolve.'),
|
|
532
|
-
watchAction: z
|
|
533
|
-
.enum(['start', 'stop', 'status'])
|
|
534
|
-
.optional()
|
|
535
|
-
.describe('Sub-action for watch mode. Values: start (begin watching), stop (stop watcher), status (check state). Defaults to status.'),
|
|
536
|
-
specIds: z
|
|
537
|
-
.array(z.string())
|
|
538
|
-
.optional()
|
|
539
|
-
.describe('List of spec IDs to include in summary. If omitted, includes all specs.'),
|
|
540
|
-
},
|
|
541
|
-
annotations: { title: 'Manage Drift', destructiveHint: false },
|
|
542
|
-
}, safeTracked('manage_drift', async (args) => handleManageDrift(args)));
|
|
543
|
-
// Deprecated drift shims
|
|
544
|
-
s.registerTool('watch_spec_drift', {
|
|
545
|
-
description: '[DEPRECATED] Use manage_drift with action=watch instead. This shim delegates to manage_drift for backward compatibility.',
|
|
546
|
-
inputSchema: {
|
|
547
|
-
projectPath: z.string().min(1).describe('Absolute path to the project root directory.'),
|
|
548
|
-
specId: z.string().min(1).describe('Spec ID to watch.'),
|
|
549
|
-
action: z.enum(['start', 'stop', 'status']).describe('start/stop/status for the watcher.'),
|
|
550
|
-
},
|
|
551
|
-
annotations: { title: '[Deprecated] Watch Spec Drift', destructiveHint: false },
|
|
552
|
-
}, safeTracked('watch_spec_drift', async (args) => {
|
|
553
|
-
const { projectPath, specId, action } = args;
|
|
554
|
-
return handleManageDrift({ action: 'watch', projectPath, specId, watchAction: action });
|
|
555
|
-
}));
|
|
556
|
-
s.registerTool('drift_summary_report', {
|
|
557
|
-
description: '[DEPRECATED] Use manage_drift with action=summary instead. This shim delegates to manage_drift for backward compatibility.',
|
|
558
|
-
inputSchema: {
|
|
559
|
-
projectPath: z.string().describe('Absolute path to the project root.'),
|
|
560
|
-
specIds: z.array(z.string()).optional().describe('Optional list of spec IDs.'),
|
|
561
|
-
},
|
|
562
|
-
annotations: { title: '[Deprecated] Drift Summary Report', readOnlyHint: true },
|
|
563
|
-
}, safeTracked('drift_summary_report', async (args) => {
|
|
564
|
-
const { projectPath, specIds } = args;
|
|
565
|
-
return handleManageDrift({ action: 'summary', projectPath, specIds });
|
|
566
|
-
}));
|
|
567
|
-
s.registerTool('resolve_drift_violations', {
|
|
568
|
-
description: '[DEPRECATED] Use manage_drift with action=resolve instead. This shim delegates to manage_drift for backward compatibility.',
|
|
569
|
-
inputSchema: {
|
|
570
|
-
projectPath: z.string().min(1).describe('Absolute path to the project root directory.'),
|
|
571
|
-
dryRun: z.boolean().optional().describe('Preview without writing files.'),
|
|
572
|
-
},
|
|
573
|
-
annotations: { title: '[Deprecated] Resolve Drift Violations', destructiveHint: false },
|
|
574
|
-
}, safeTracked('resolve_drift_violations', async (args) => {
|
|
575
|
-
const { projectPath, dryRun } = args;
|
|
576
|
-
return handleManageDrift({ action: 'resolve', projectPath, dryRun });
|
|
577
|
-
}));
|
|
578
|
-
// ── Code graph ───────────────────────────────────────────────────────────────
|
|
579
|
-
s.registerTool('configure_code_graph', {
|
|
580
|
-
description: 'Configure a Code Graph MCP provider for semantic code navigation. ' +
|
|
581
|
-
'Supports CodeGraphContext, Pathfinder, and Axon. ' +
|
|
582
|
-
'Each setup action adds the provider to .claude.json so it is available in Claude Code. ' +
|
|
583
|
-
'Actions: "setup-codegraph-context" | "setup-pathfinder" | "setup-axon" | "status".',
|
|
584
|
-
inputSchema: {
|
|
585
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
586
|
-
action: z
|
|
587
|
-
.enum(['setup-codegraph-context', 'setup-pathfinder', 'setup-axon', 'status'])
|
|
588
|
-
.describe('"setup-codegraph-context" adds the CodeGraphContext MCP server. "setup-pathfinder" adds Pathfinder. "setup-axon" adds Axon. "status" reports which providers are configured.'),
|
|
589
|
-
},
|
|
590
|
-
annotations: { title: 'Configure Code Graph Provider' },
|
|
591
|
-
}, safeLicensed('configure_code_graph', (args) => handleConfigureCodeGraph(args)));
|
|
592
|
-
s.registerTool('code_graph_status', {
|
|
593
|
-
description: 'Report which Code Graph MCP providers are configured in .claude.json. Returns providers list and the first active provider name.',
|
|
594
|
-
inputSchema: {
|
|
595
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
596
|
-
},
|
|
597
|
-
annotations: { title: 'Code Graph Status', readOnlyHint: true },
|
|
598
|
-
}, safeLicensed('code_graph_status', (args) => handleCodeGraphStatus(args)));
|
|
599
|
-
// ── Estimation accuracy ───────────────────────────────────────────────────────
|
|
600
|
-
s.registerTool('record_actual', {
|
|
601
|
-
description: 'Record the actual hours spent on a completed spec to track estimation accuracy. ' +
|
|
602
|
-
'Use after marking a spec as done to close the feedback loop. ' +
|
|
603
|
-
'Data is stored per-project and used by estimation_accuracy_report and calibrate_estimates.',
|
|
604
|
-
inputSchema: {
|
|
605
|
-
...projectIdSchema,
|
|
606
|
-
specId: z.string().min(1).describe('Spec ID to record actuals for (e.g. "SPEC-287").'),
|
|
607
|
-
actualHours: z
|
|
608
|
-
.number()
|
|
609
|
-
.min(0)
|
|
610
|
-
.describe('Total hours actually spent implementing this spec (dev + review combined).'),
|
|
611
|
-
notes: z
|
|
612
|
-
.string()
|
|
613
|
-
.max(1000)
|
|
614
|
-
.optional()
|
|
615
|
-
.describe('Optional notes explaining the deviation (e.g. "scope crept", "faster than expected").'),
|
|
616
|
-
},
|
|
617
|
-
annotations: { readOnlyHint: false },
|
|
618
|
-
}, safeLicensed('record_actual', withProject((args) => handleRecordActual(args))));
|
|
619
|
-
s.registerTool('calibrate_estimates', {
|
|
620
|
-
description: 'Recalculate estimation calibration factors based on accumulated historical actuals. ' +
|
|
621
|
-
'When historical data shows systematic over/underestimation (>20% avg deviation), ' +
|
|
622
|
-
'saves multipliers that the estimate tool uses to adjust future estimates automatically. ' +
|
|
623
|
-
'Overwrites previous calibration. Requires at least minSamples records per dimension.',
|
|
624
|
-
inputSchema: {
|
|
625
|
-
...projectIdSchema,
|
|
626
|
-
minSamples: z
|
|
627
|
-
.number()
|
|
628
|
-
.int()
|
|
629
|
-
.min(1)
|
|
630
|
-
.optional()
|
|
631
|
-
.describe('Minimum number of actuals per scope/type before a calibration factor is applied (default: 3).'),
|
|
632
|
-
},
|
|
633
|
-
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
634
|
-
}, safeLicensed('calibrate_estimates', withProject((args) => handleCalibrateEstimates(args))));
|
|
635
|
-
// ── Workload distribution ────────────────────────────────────────────────────
|
|
636
|
-
s.registerTool('workload_distribution', {
|
|
637
|
-
description: 'Show current workload distribution across team members: WIP items, backlog (approved but not started), estimated hours, and imbalance warnings when one member has more than 2× the average WIP.',
|
|
638
|
-
annotations: { readOnlyHint: true },
|
|
639
|
-
inputSchema: {
|
|
640
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
641
|
-
weeks: z
|
|
642
|
-
.number()
|
|
643
|
-
.int()
|
|
644
|
-
.min(1)
|
|
645
|
-
.max(52)
|
|
646
|
-
.optional()
|
|
647
|
-
.describe('Unused for workload snapshot, accepted for API consistency.'),
|
|
648
|
-
},
|
|
649
|
-
}, safeTracked('workload_distribution', async (args) => handleWorkloadDistribution(args)));
|
|
650
|
-
// ── Spec scheduler ───────────────────────────────────────────────────────────
|
|
651
|
-
s.registerTool('simulate_parallel_execution', {
|
|
652
|
-
description: 'Simulate parallel execution of a set of specs across multiple agents. Returns a timeline with Gantt chart and critical path.',
|
|
653
|
-
annotations: { readOnlyHint: true },
|
|
654
|
-
inputSchema: {
|
|
655
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
656
|
-
specIds: z
|
|
657
|
-
.array(z.string())
|
|
658
|
-
.min(1)
|
|
659
|
-
.describe('List of spec IDs to include in the simulation.'),
|
|
660
|
-
numAgents: z
|
|
661
|
-
.number()
|
|
662
|
-
.int()
|
|
663
|
-
.min(1)
|
|
664
|
-
.max(20)
|
|
665
|
-
.describe('Number of agents (parallel workers) to simulate.'),
|
|
666
|
-
},
|
|
667
|
-
}, safeTracked('simulate_parallel_execution', async (args) => handleSimulateParallelExecution(args)));
|
|
668
|
-
s.registerTool('critical_path_analyzer', {
|
|
669
|
-
description: 'Identify the critical path (longest chain of specs by estimated hours) for a project or a subset of specs.',
|
|
670
|
-
annotations: { readOnlyHint: true },
|
|
671
|
-
inputSchema: {
|
|
672
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
673
|
-
specIds: z
|
|
674
|
-
.array(z.string())
|
|
675
|
-
.optional()
|
|
676
|
-
.describe('Optional subset of spec IDs. Omit to analyze all project specs.'),
|
|
677
|
-
},
|
|
678
|
-
}, safeTracked('critical_path_analyzer', async (args) => handleCriticalPathAnalyzer(args)));
|
|
679
|
-
s.registerTool('parallel_efficiency_score', {
|
|
680
|
-
description: 'Calculate the parallel efficiency (utilization ratio) for executing a set of specs with N agents. Returns a score and interpretation.',
|
|
681
|
-
annotations: { readOnlyHint: true },
|
|
682
|
-
inputSchema: {
|
|
683
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
684
|
-
specIds: z
|
|
685
|
-
.array(z.string())
|
|
686
|
-
.min(1)
|
|
687
|
-
.describe('List of spec IDs to include in the efficiency calculation.'),
|
|
688
|
-
numAgents: z
|
|
689
|
-
.number()
|
|
690
|
-
.int()
|
|
691
|
-
.min(1)
|
|
692
|
-
.max(20)
|
|
693
|
-
.describe('Number of agents to calculate efficiency for.'),
|
|
694
|
-
},
|
|
695
|
-
}, safeTracked('parallel_efficiency_score', async (args) => handleParallelEfficiencyScore(args)));
|
|
696
|
-
s.registerTool('optimize_spec_scheduling', {
|
|
697
|
-
description: 'Suggest an optimized scheduling order for specs to minimize agent idle time when executing in parallel.',
|
|
698
|
-
annotations: { readOnlyHint: true },
|
|
699
|
-
inputSchema: {
|
|
700
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
701
|
-
specIds: z
|
|
702
|
-
.array(z.string())
|
|
703
|
-
.optional()
|
|
704
|
-
.describe('Optional subset of spec IDs. Omit to optimize all project specs.'),
|
|
705
|
-
numAgents: z
|
|
706
|
-
.number()
|
|
707
|
-
.int()
|
|
708
|
-
.min(1)
|
|
709
|
-
.max(20)
|
|
710
|
-
.optional()
|
|
711
|
-
.describe('Number of agents (default: 2).'),
|
|
712
|
-
},
|
|
713
|
-
}, safeTracked('optimize_spec_scheduling', async (args) => handleOptimizeSpecScheduling(args)));
|
|
714
|
-
// ── Crash shield ─────────────────────────────────────────────────────────────
|
|
715
|
-
s.registerTool('scan_crash_risks', {
|
|
716
|
-
description: 'Scan a project for crash risks: unhandled promise rejections, missing null checks, ' +
|
|
717
|
-
'uncaught exceptions, and other patterns that cause runtime crashes. ' +
|
|
718
|
-
'Returns a safety score (0–100) and a list of risks by severity. ' +
|
|
719
|
-
'Free tool — no license required.',
|
|
720
|
-
inputSchema: ScanCrashRisksSchema.shape,
|
|
721
|
-
annotations: { title: 'Scan Crash Risks', readOnlyHint: true },
|
|
722
|
-
}, safeTracked('scan_crash_risks', async (args) => handleScanCrashRisks(args)));
|
|
723
|
-
s.registerTool('fix_crash_risks', {
|
|
724
|
-
description: 'Auto-fix crash risks detected by scan_crash_risks. ' +
|
|
725
|
-
'Use dryRun:true first to preview what would change.',
|
|
726
|
-
inputSchema: FixCrashRisksSchema.shape,
|
|
727
|
-
annotations: { title: 'Fix Crash Risks', destructiveHint: true },
|
|
728
|
-
}, safeLicensed('fix_crash_risks', async (args) => handleFixCrashRisks(args)));
|
|
729
|
-
s.registerTool('configure_crash_rules', {
|
|
730
|
-
description: 'Configure custom crash risk detection rules for a project.',
|
|
731
|
-
inputSchema: ConfigureCrashRulesSchema.shape,
|
|
732
|
-
annotations: { title: 'Configure Crash Rules', destructiveHint: false },
|
|
733
|
-
}, safeLicensed('configure_crash_rules', async (args) => handleConfigureCrashRules(args)));
|
|
734
|
-
// ── Self healing ──────────────────────────────────────────────────────────────
|
|
735
|
-
s.registerTool('auto_fix_health', {
|
|
736
|
-
description: 'Auto-fix common health issues in a project (missing spec files, stale sessions, invalid JSON, etc.). Run after validate to repair issues automatically.',
|
|
737
|
-
inputSchema: {
|
|
738
|
-
projectPath: z
|
|
739
|
-
.string()
|
|
740
|
-
.min(1)
|
|
741
|
-
.max(4096)
|
|
742
|
-
.describe('Absolute path to the project root directory'),
|
|
743
|
-
},
|
|
744
|
-
annotations: { title: 'Auto-Fix Health Issues', destructiveHint: false },
|
|
745
|
-
}, safeLicensed('auto_fix_health', async (args) => {
|
|
746
|
-
const { projectPath, dryRun = false } = args;
|
|
747
|
-
const projectId = hashProjectPath(projectPath);
|
|
748
|
-
const result = await autoFixHealth(projectPath, projectId, dryRun);
|
|
749
|
-
const lines = [
|
|
750
|
-
dryRun ? '[DRY RUN] Auto-fix health report:' : 'Auto-fix health report:',
|
|
751
|
-
'',
|
|
752
|
-
`Fixed: ${result.fixedCount}`,
|
|
753
|
-
`Skipped (manual action required): ${result.skippedCount}`,
|
|
754
|
-
`Executed at: ${result.executedAt}`,
|
|
755
|
-
];
|
|
756
|
-
if (result.fixes.length > 0) {
|
|
757
|
-
lines.push('', 'Fixes applied:');
|
|
758
|
-
for (const fix of result.fixes) {
|
|
759
|
-
lines.push(` [${fix.success ? 'OK' : 'FAIL'}] ${fix.affectedItem}: ${fix.action}`);
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
if (result.skipped.length > 0) {
|
|
763
|
-
lines.push('', 'Skipped (requires manual action):');
|
|
764
|
-
for (const skip of result.skipped) {
|
|
765
|
-
lines.push(` - ${skip.issue}: ${skip.reason}`);
|
|
766
|
-
for (const step of skip.manualSteps) {
|
|
767
|
-
lines.push(` → ${step}`);
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
772
|
-
}));
|
|
773
|
-
s.registerTool('auto_fix_validation', {
|
|
774
|
-
description: 'Diagnose and auto-fix a specific validation failure. Supports failureType: typescript (tsc errors), lint (eslint --fix), test (test scaffolding), coverage (stub generation). Returns a detailed report of what was fixed and what still needs manual attention.',
|
|
775
|
-
inputSchema: {
|
|
776
|
-
projectPath: z
|
|
777
|
-
.string()
|
|
778
|
-
.min(1)
|
|
779
|
-
.max(4096)
|
|
780
|
-
.describe('Absolute path to the project root directory'),
|
|
781
|
-
specId: z
|
|
782
|
-
.string()
|
|
783
|
-
.min(1)
|
|
784
|
-
.max(200)
|
|
785
|
-
.describe('Spec ID associated with the failing validation (e.g. SPEC-474)'),
|
|
786
|
-
failureType: z
|
|
787
|
-
.enum(['typescript', 'lint', 'test', 'coverage'])
|
|
788
|
-
.describe('Type of validation failure. Values: typescript, lint, test, coverage.'),
|
|
789
|
-
failureDetails: z
|
|
790
|
-
.string()
|
|
791
|
-
.min(1)
|
|
792
|
-
.max(4096)
|
|
793
|
-
.describe('Full error output or description of the validation failure'),
|
|
794
|
-
},
|
|
795
|
-
annotations: { title: 'Auto-Fix Validation Failure', destructiveHint: false },
|
|
796
|
-
}, safeLicensed('auto_fix_validation', async (args) => handleAutoFixValidation(args)));
|
|
797
|
-
// ── run_healing_loop (migrated to skill, SPEC-658) ───────────────────────────
|
|
798
|
-
// Tool stays registered for backward compat; callers receive a deprecation notice.
|
|
799
|
-
registerFromEntries(s, [
|
|
800
|
-
makeDeprecationStub('run_healing_loop', '.claude/skills/spec-health.md', 'spec-health'),
|
|
801
|
-
]);
|
|
802
|
-
// ── Auto remediation ──────────────────────────────────────────────────────────
|
|
803
|
-
s.registerTool('auto_remediate_compliance', {
|
|
804
|
-
description: 'For each compliance control gap, creates a stub spec so the team has a tracked work item. ' +
|
|
805
|
-
'Already-covered controls are reported. Partially-covered controls list manual actions needed. ' +
|
|
806
|
-
'Use dryRun=true to preview without creating any files.',
|
|
807
|
-
inputSchema: {
|
|
808
|
-
projectPath: z
|
|
809
|
-
.string()
|
|
810
|
-
.min(1)
|
|
811
|
-
.max(4096)
|
|
812
|
-
.describe('Absolute path to the project root directory'),
|
|
813
|
-
framework: z
|
|
814
|
-
.enum(['SOC2', 'GDPR', 'HIPAA', 'ISO27001'])
|
|
815
|
-
.describe('Compliance framework to remediate: SOC2=service org controls, GDPR=EU data privacy, HIPAA=US health data, ISO27001=security management'),
|
|
816
|
-
dryRun: z
|
|
817
|
-
.boolean()
|
|
818
|
-
.optional()
|
|
819
|
-
.describe('When true, report what would be created without writing any files (default: false)'),
|
|
820
|
-
},
|
|
821
|
-
annotations: { title: 'Auto Remediate Compliance Gaps' },
|
|
822
|
-
}, safeLicensed('auto_remediate_compliance', async (args) => {
|
|
823
|
-
const { projectPath, framework, dryRun = false, } = args;
|
|
824
|
-
const projectId = hashProjectPath(projectPath);
|
|
825
|
-
const result = await autoRemediateCompliance(projectPath, projectId, framework, dryRun);
|
|
826
|
-
const lines = [
|
|
827
|
-
dryRun
|
|
828
|
-
? `[DRY RUN] Compliance remediation for ${result.framework}:`
|
|
829
|
-
: `Compliance remediation for ${result.framework}:`,
|
|
830
|
-
'',
|
|
831
|
-
`Specs created: ${result.createdSpecs.length}`,
|
|
832
|
-
`Controls already covered: ${result.alreadyCovered.length}`,
|
|
833
|
-
`Manual actions required: ${result.manualActionRequired.length}`,
|
|
834
|
-
];
|
|
835
|
-
if (result.createdSpecs.length > 0) {
|
|
836
|
-
lines.push('', 'Specs created:');
|
|
837
|
-
for (const id of result.createdSpecs) {
|
|
838
|
-
lines.push(` + ${id}`);
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
if (result.alreadyCovered.length > 0) {
|
|
842
|
-
lines.push('', 'Already covered controls:');
|
|
843
|
-
for (const ctrl of result.alreadyCovered) {
|
|
844
|
-
lines.push(` ✓ ${ctrl}`);
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
if (result.manualActionRequired.length > 0) {
|
|
848
|
-
lines.push('', 'Manual actions required:');
|
|
849
|
-
for (const action of result.manualActionRequired) {
|
|
850
|
-
lines.push(` - ${action.control}: ${action.description}`);
|
|
851
|
-
for (const step of action.steps) {
|
|
852
|
-
lines.push(` → ${step}`);
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
857
|
-
}));
|
|
858
|
-
// ── Auto promoter ─────────────────────────────────────────────────────────────
|
|
859
|
-
s.registerTool('configure_auto_promotion', {
|
|
860
|
-
description: 'Configure auto-promotion settings for a project. ' +
|
|
861
|
-
'When enabled, specs that reach the confidence threshold are eligible for automatic status promotion. ' +
|
|
862
|
-
'High-risk specs are never auto-promoted regardless of settings.',
|
|
863
|
-
inputSchema: {
|
|
864
|
-
projectPath: z.string().describe('Absolute path to the project directory.'),
|
|
865
|
-
enabled: z
|
|
866
|
-
.boolean()
|
|
867
|
-
.optional()
|
|
868
|
-
.describe('Enable or disable auto-promotion for the project.'),
|
|
869
|
-
threshold: z
|
|
870
|
-
.number()
|
|
871
|
-
.min(0)
|
|
872
|
-
.max(100)
|
|
873
|
-
.optional()
|
|
874
|
-
.describe('Confidence score threshold (0-100). Specs below this are not auto-promoted. Default: 85.'),
|
|
875
|
-
maxRisk: z
|
|
876
|
-
.enum(['low', 'medium'])
|
|
877
|
-
.optional()
|
|
878
|
-
.describe('Maximum risk level allowed for auto-promotion. Valid values: "low" (only low-risk specs), "medium" (low and medium). High-risk specs are never auto-promoted.'),
|
|
879
|
-
},
|
|
880
|
-
annotations: { title: 'Configure Auto Promotion' },
|
|
881
|
-
}, safeLicensed('configure_auto_promotion', async (args) => handleConfigureAutoPromotion(args)));
|
|
882
|
-
s.registerTool('check_auto_promotion', {
|
|
883
|
-
description: 'Check whether a spec is eligible for auto-promotion by computing its confidence score. Returns the score breakdown (readiness, risk penalty, dependency bonus) and eligibility verdict.',
|
|
884
|
-
inputSchema: {
|
|
885
|
-
projectPath: z.string().describe('Absolute path to the project directory.'),
|
|
886
|
-
specId: z.string().describe('Spec ID to evaluate (e.g., "SPEC-042").'),
|
|
887
|
-
},
|
|
888
|
-
annotations: { title: 'Check Auto Promotion', readOnlyHint: true },
|
|
889
|
-
}, safeLicensed('check_auto_promotion', async (args) => handleCheckAutoPromotion(args)));
|
|
890
|
-
// ── Multi-teammate review (SPEC-593) ─────────────────────────────────────────
|
|
891
|
-
registerMultiTeammateReviewTool(s);
|
|
892
|
-
// ── Observatory insights (SPEC-572) ──────────────────────────────────────────
|
|
893
|
-
s.registerTool('observatory_insights', {
|
|
894
|
-
description: 'Planu Observatory: derive cross-project aggregated telemetry insights. ' +
|
|
895
|
-
'Local mode (always available): computes patterns from your own spec actuals history — ' +
|
|
896
|
-
'estimation bias, velocity averages, per-scope accuracy. ' +
|
|
897
|
-
'Remote mode (opt-in via configure_telemetry enableObservatory=true): fetches community ' +
|
|
898
|
-
'patterns from planu.dev/api/observatory with a 24-hour cache. ' +
|
|
899
|
-
'PRIVACY: only aggregate numbers are computed — no file paths, spec titles, or personal data.',
|
|
900
|
-
annotations: { title: 'Observatory Insights', readOnlyHint: true },
|
|
901
|
-
inputSchema: {
|
|
902
|
-
projectPath: z
|
|
903
|
-
.string()
|
|
904
|
-
.min(1)
|
|
905
|
-
.max(4096)
|
|
906
|
-
.optional()
|
|
907
|
-
.describe('Absolute path to a specific project. Omit to analyze all registered projects.'),
|
|
908
|
-
includeGlobal: z
|
|
909
|
-
.boolean()
|
|
910
|
-
.optional()
|
|
911
|
-
.describe('When true, also fetch community insights from planu.dev (requires enableObservatory=true in telemetry config). ' +
|
|
912
|
-
'Results are cached for 24 hours. Falls back to local-only on network failure.'),
|
|
913
|
-
},
|
|
914
|
-
}, safeTracked('observatory_insights', async (args) => handleObservatoryInsights(args)));
|
|
915
|
-
// ── Code duplication detection (SPEC-970) ──────────────────────────────────
|
|
916
|
-
s.registerTool('detect_duplication', {
|
|
917
|
-
description: 'Scan a project for code duplication. Uses token-based sliding window detection ' +
|
|
918
|
-
'to find duplicate blocks of code across files. Returns clusters with file locations, ' +
|
|
919
|
-
'line counts, severity, and extraction suggestions.',
|
|
920
|
-
annotations: { title: 'Detect Code Duplication', readOnlyHint: true },
|
|
921
|
-
inputSchema: {
|
|
922
|
-
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
923
|
-
minLines: z
|
|
924
|
-
.number()
|
|
925
|
-
.int()
|
|
926
|
-
.min(2)
|
|
927
|
-
.max(100)
|
|
928
|
-
.optional()
|
|
929
|
-
.default(5)
|
|
930
|
-
.describe('Minimum number of consecutive lines to consider a duplicate (default: 5).'),
|
|
931
|
-
exclude: z
|
|
932
|
-
.array(z.string())
|
|
933
|
-
.optional()
|
|
934
|
-
.describe('Additional glob patterns to exclude beyond the defaults.'),
|
|
935
|
-
languages: z
|
|
936
|
-
.array(z.enum(['typescript', 'javascript']))
|
|
937
|
-
.optional()
|
|
938
|
-
.describe('Languages to scan. Values: typescript, javascript. Defaults to both.'),
|
|
939
|
-
},
|
|
940
|
-
}, safeTracked('detect_duplication', async (args) => handleDetectDuplication(args)));
|
|
941
|
-
}
|
|
942
|
-
//# sourceMappingURL=group-analysis-monitoring.js.map
|