@planu/cli 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/ai-tool-registry.json +71 -0
- package/dist/config/autopilot-config.json +21 -0
- package/dist/config/competitive-catalog.json +83 -0
- package/dist/config/license-plans.json +43 -2
- package/dist/engine/agent-registry/lifecycle-manager.d.ts +8 -0
- package/dist/engine/agent-registry/lifecycle-manager.d.ts.map +1 -0
- package/dist/engine/agent-registry/lifecycle-manager.js +81 -0
- package/dist/engine/agent-registry/lifecycle-manager.js.map +1 -0
- package/dist/engine/agent-registry/role-catalog.d.ts +17 -0
- package/dist/engine/agent-registry/role-catalog.d.ts.map +1 -0
- package/dist/engine/agent-registry/role-catalog.js +55 -0
- package/dist/engine/agent-registry/role-catalog.js.map +1 -0
- package/dist/engine/api-compat/compatibility-checker.d.ts +4 -0
- package/dist/engine/api-compat/compatibility-checker.d.ts.map +1 -0
- package/dist/engine/api-compat/compatibility-checker.js +118 -0
- package/dist/engine/api-compat/compatibility-checker.js.map +1 -0
- package/dist/engine/autopilot/action-executor.d.ts +18 -0
- package/dist/engine/autopilot/action-executor.d.ts.map +1 -0
- package/dist/engine/autopilot/action-executor.js +91 -0
- package/dist/engine/autopilot/action-executor.js.map +1 -0
- package/dist/engine/autopilot/event-bus.d.ts +8 -0
- package/dist/engine/autopilot/event-bus.d.ts.map +1 -0
- package/dist/engine/autopilot/event-bus.js +28 -0
- package/dist/engine/autopilot/event-bus.js.map +1 -0
- package/dist/engine/autopilot/trigger-rules.d.ts +3 -0
- package/dist/engine/autopilot/trigger-rules.d.ts.map +1 -0
- package/dist/engine/autopilot/trigger-rules.js +125 -0
- package/dist/engine/autopilot/trigger-rules.js.map +1 -0
- package/dist/engine/checkpoint/checkpoint-manager.d.ts +22 -0
- package/dist/engine/checkpoint/checkpoint-manager.d.ts.map +1 -0
- package/dist/engine/checkpoint/checkpoint-manager.js +76 -0
- package/dist/engine/checkpoint/checkpoint-manager.js.map +1 -0
- package/dist/engine/checkpoint/policy-engine.d.ts +10 -0
- package/dist/engine/checkpoint/policy-engine.d.ts.map +1 -0
- package/dist/engine/checkpoint/policy-engine.js +87 -0
- package/dist/engine/checkpoint/policy-engine.js.map +1 -0
- package/dist/engine/competitive/gap-analyzer.d.ts +12 -0
- package/dist/engine/competitive/gap-analyzer.d.ts.map +1 -0
- package/dist/engine/competitive/gap-analyzer.js +214 -0
- package/dist/engine/competitive/gap-analyzer.js.map +1 -0
- package/dist/engine/compliance/auto-remediator.d.ts +9 -0
- package/dist/engine/compliance/auto-remediator.d.ts.map +1 -0
- package/dist/engine/compliance/auto-remediator.js +118 -0
- package/dist/engine/compliance/auto-remediator.js.map +1 -0
- package/dist/engine/context-profile/profile-catalog.d.ts +5 -0
- package/dist/engine/context-profile/profile-catalog.d.ts.map +1 -0
- package/dist/engine/context-profile/profile-catalog.js +145 -0
- package/dist/engine/context-profile/profile-catalog.js.map +1 -0
- package/dist/engine/critical-path/path-analyzer.d.ts +3 -0
- package/dist/engine/critical-path/path-analyzer.d.ts.map +1 -0
- package/dist/engine/critical-path/path-analyzer.js +145 -0
- package/dist/engine/critical-path/path-analyzer.js.map +1 -0
- package/dist/engine/drift/violation-resolver.d.ts +9 -0
- package/dist/engine/drift/violation-resolver.d.ts.map +1 -0
- package/dist/engine/drift/violation-resolver.js +128 -0
- package/dist/engine/drift/violation-resolver.js.map +1 -0
- package/dist/engine/ears/criterion-scorer.d.ts +7 -0
- package/dist/engine/ears/criterion-scorer.d.ts.map +1 -0
- package/dist/engine/ears/criterion-scorer.js +87 -0
- package/dist/engine/ears/criterion-scorer.js.map +1 -0
- package/dist/engine/ears/pattern-matcher.d.ts +5 -0
- package/dist/engine/ears/pattern-matcher.d.ts.map +1 -0
- package/dist/engine/ears/pattern-matcher.js +48 -0
- package/dist/engine/ears/pattern-matcher.js.map +1 -0
- package/dist/engine/ears/rewriter.d.ts +7 -0
- package/dist/engine/ears/rewriter.d.ts.map +1 -0
- package/dist/engine/ears/rewriter.js +45 -0
- package/dist/engine/ears/rewriter.js.map +1 -0
- package/dist/engine/ears/spec-linter.d.ts +7 -0
- package/dist/engine/ears/spec-linter.d.ts.map +1 -0
- package/dist/engine/ears/spec-linter.js +127 -0
- package/dist/engine/ears/spec-linter.js.map +1 -0
- package/dist/engine/health/auto-fixer.d.ts +7 -0
- package/dist/engine/health/auto-fixer.d.ts.map +1 -0
- package/dist/engine/health/auto-fixer.js +130 -0
- package/dist/engine/health/auto-fixer.js.map +1 -0
- package/dist/engine/hook-generator/ai-hook-templates.d.ts +8 -0
- package/dist/engine/hook-generator/ai-hook-templates.d.ts.map +1 -0
- package/dist/engine/hook-generator/ai-hook-templates.js +43 -0
- package/dist/engine/hook-generator/ai-hook-templates.js.map +1 -0
- package/dist/engine/hook-generator/hook-merger.d.ts +13 -0
- package/dist/engine/hook-generator/hook-merger.d.ts.map +1 -0
- package/dist/engine/hook-generator/hook-merger.js +148 -0
- package/dist/engine/hook-generator/hook-merger.js.map +1 -0
- package/dist/engine/hook-generator/stack-hook-templates.d.ts +10 -0
- package/dist/engine/hook-generator/stack-hook-templates.d.ts.map +1 -0
- package/dist/engine/hook-generator/stack-hook-templates.js +105 -0
- package/dist/engine/hook-generator/stack-hook-templates.js.map +1 -0
- package/dist/engine/mcp-catalog/catalog-advisor.d.ts +3 -0
- package/dist/engine/mcp-catalog/catalog-advisor.d.ts.map +1 -0
- package/dist/engine/mcp-catalog/catalog-advisor.js +180 -0
- package/dist/engine/mcp-catalog/catalog-advisor.js.map +1 -0
- package/dist/engine/project-dna/ai-tool-detector.d.ts +12 -0
- package/dist/engine/project-dna/ai-tool-detector.d.ts.map +1 -0
- package/dist/engine/project-dna/ai-tool-detector.js +103 -0
- package/dist/engine/project-dna/ai-tool-detector.js.map +1 -0
- package/dist/engine/project-dna/rules-generator.d.ts +18 -0
- package/dist/engine/project-dna/rules-generator.d.ts.map +1 -0
- package/dist/engine/project-dna/rules-generator.js +193 -0
- package/dist/engine/project-dna/rules-generator.js.map +1 -0
- package/dist/engine/project-dna/stack-detector.d.ts +24 -0
- package/dist/engine/project-dna/stack-detector.d.ts.map +1 -0
- package/dist/engine/project-dna/stack-detector.js +309 -0
- package/dist/engine/project-dna/stack-detector.js.map +1 -0
- package/dist/engine/similar-problems/similarity-finder.d.ts +3 -0
- package/dist/engine/similar-problems/similarity-finder.d.ts.map +1 -0
- package/dist/engine/similar-problems/similarity-finder.js +144 -0
- package/dist/engine/similar-problems/similarity-finder.js.map +1 -0
- package/dist/engine/sync/asana-puller.d.ts +9 -0
- package/dist/engine/sync/asana-puller.d.ts.map +1 -0
- package/dist/engine/sync/asana-puller.js +91 -0
- package/dist/engine/sync/asana-puller.js.map +1 -0
- package/dist/engine/sync/conflict-resolver.d.ts +17 -0
- package/dist/engine/sync/conflict-resolver.d.ts.map +1 -0
- package/dist/engine/sync/conflict-resolver.js +58 -0
- package/dist/engine/sync/conflict-resolver.js.map +1 -0
- package/dist/engine/sync/monday-puller.d.ts +9 -0
- package/dist/engine/sync/monday-puller.d.ts.map +1 -0
- package/dist/engine/sync/monday-puller.js +110 -0
- package/dist/engine/sync/monday-puller.js.map +1 -0
- package/dist/engine/sync/notion-puller.d.ts +15 -0
- package/dist/engine/sync/notion-puller.d.ts.map +1 -0
- package/dist/engine/sync/notion-puller.js +101 -0
- package/dist/engine/sync/notion-puller.js.map +1 -0
- package/dist/engine/verifier/code-scanner.d.ts +8 -0
- package/dist/engine/verifier/code-scanner.d.ts.map +1 -0
- package/dist/engine/verifier/code-scanner.js +73 -0
- package/dist/engine/verifier/code-scanner.js.map +1 -0
- package/dist/engine/verifier/compliance-scorer.d.ts +17 -0
- package/dist/engine/verifier/compliance-scorer.d.ts.map +1 -0
- package/dist/engine/verifier/compliance-scorer.js +131 -0
- package/dist/engine/verifier/compliance-scorer.js.map +1 -0
- package/dist/engine/verifier/criterion-matcher.d.ts +15 -0
- package/dist/engine/verifier/criterion-matcher.d.ts.map +1 -0
- package/dist/engine/verifier/criterion-matcher.js +210 -0
- package/dist/engine/verifier/criterion-matcher.js.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -1
- package/dist/storage/agent-registry-store.d.ts +11 -0
- package/dist/storage/agent-registry-store.d.ts.map +1 -0
- package/dist/storage/agent-registry-store.js +45 -0
- package/dist/storage/agent-registry-store.js.map +1 -0
- package/dist/storage/compliance-score-store.d.ts +16 -0
- package/dist/storage/compliance-score-store.d.ts.map +1 -0
- package/dist/storage/compliance-score-store.js +30 -0
- package/dist/storage/compliance-score-store.js.map +1 -0
- package/dist/storage/context-profile-store.d.ts +14 -0
- package/dist/storage/context-profile-store.d.ts.map +1 -0
- package/dist/storage/context-profile-store.js +34 -0
- package/dist/storage/context-profile-store.js.map +1 -0
- package/dist/storage/workflow-checkpoint-store.d.ts +16 -0
- package/dist/storage/workflow-checkpoint-store.d.ts.map +1 -0
- package/dist/storage/workflow-checkpoint-store.js +71 -0
- package/dist/storage/workflow-checkpoint-store.js.map +1 -0
- package/dist/tools/checkpoint/approve-checkpoint-handler.d.ts +3 -0
- package/dist/tools/checkpoint/approve-checkpoint-handler.d.ts.map +1 -0
- package/dist/tools/checkpoint/approve-checkpoint-handler.js +32 -0
- package/dist/tools/checkpoint/approve-checkpoint-handler.js.map +1 -0
- package/dist/tools/checkpoint/configure-policy-handler.d.ts +3 -0
- package/dist/tools/checkpoint/configure-policy-handler.d.ts.map +1 -0
- package/dist/tools/checkpoint/configure-policy-handler.js +60 -0
- package/dist/tools/checkpoint/configure-policy-handler.js.map +1 -0
- package/dist/tools/checkpoint/list-checkpoints-handler.d.ts +3 -0
- package/dist/tools/checkpoint/list-checkpoints-handler.d.ts.map +1 -0
- package/dist/tools/checkpoint/list-checkpoints-handler.js +25 -0
- package/dist/tools/checkpoint/list-checkpoints-handler.js.map +1 -0
- package/dist/tools/checkpoint/reject-checkpoint-handler.d.ts +3 -0
- package/dist/tools/checkpoint/reject-checkpoint-handler.d.ts.map +1 -0
- package/dist/tools/checkpoint/reject-checkpoint-handler.js +32 -0
- package/dist/tools/checkpoint/reject-checkpoint-handler.js.map +1 -0
- package/dist/tools/checkpoint/require-checkpoint-handler.d.ts +3 -0
- package/dist/tools/checkpoint/require-checkpoint-handler.d.ts.map +1 -0
- package/dist/tools/checkpoint/require-checkpoint-handler.js +44 -0
- package/dist/tools/checkpoint/require-checkpoint-handler.js.map +1 -0
- package/dist/tools/competitive-handlers.d.ts +30 -0
- package/dist/tools/competitive-handlers.d.ts.map +1 -0
- package/dist/tools/competitive-handlers.js +155 -0
- package/dist/tools/competitive-handlers.js.map +1 -0
- package/dist/tools/create-spec/post-creation.d.ts +1 -1
- package/dist/tools/create-spec/post-creation.d.ts.map +1 -1
- package/dist/tools/create-spec/post-creation.js +13 -1
- package/dist/tools/create-spec/post-creation.js.map +1 -1
- package/dist/tools/create-spec.js +1 -1
- package/dist/tools/create-spec.js.map +1 -1
- package/dist/tools/hook-generator-handler.d.ts +8 -0
- package/dist/tools/hook-generator-handler.d.ts.map +1 -0
- package/dist/tools/hook-generator-handler.js +154 -0
- package/dist/tools/hook-generator-handler.js.map +1 -0
- package/dist/tools/project-dna-handler.d.ts +34 -0
- package/dist/tools/project-dna-handler.d.ts.map +1 -0
- package/dist/tools/project-dna-handler.js +261 -0
- package/dist/tools/project-dna-handler.js.map +1 -0
- package/dist/tools/pull-sync-handler.d.ts +25 -0
- package/dist/tools/pull-sync-handler.d.ts.map +1 -0
- package/dist/tools/pull-sync-handler.js +161 -0
- package/dist/tools/pull-sync-handler.js.map +1 -0
- package/dist/tools/register-agent-registry.d.ts +5 -0
- package/dist/tools/register-agent-registry.d.ts.map +1 -0
- package/dist/tools/register-agent-registry.js +254 -0
- package/dist/tools/register-agent-registry.js.map +1 -0
- package/dist/tools/register-auto-remediation.d.ts +3 -0
- package/dist/tools/register-auto-remediation.d.ts.map +1 -0
- package/dist/tools/register-auto-remediation.js +174 -0
- package/dist/tools/register-auto-remediation.js.map +1 -0
- package/dist/tools/register-autopilot.d.ts +3 -0
- package/dist/tools/register-autopilot.d.ts.map +1 -0
- package/dist/tools/register-autopilot.js +78 -0
- package/dist/tools/register-autopilot.js.map +1 -0
- package/dist/tools/register-checkpoints.d.ts +3 -0
- package/dist/tools/register-checkpoints.d.ts.map +1 -0
- package/dist/tools/register-checkpoints.js +134 -0
- package/dist/tools/register-checkpoints.js.map +1 -0
- package/dist/tools/register-competitive.d.ts +3 -0
- package/dist/tools/register-competitive.d.ts.map +1 -0
- package/dist/tools/register-competitive.js +88 -0
- package/dist/tools/register-competitive.js.map +1 -0
- package/dist/tools/register-context-profile.d.ts +3 -0
- package/dist/tools/register-context-profile.d.ts.map +1 -0
- package/dist/tools/register-context-profile.js +106 -0
- package/dist/tools/register-context-profile.js.map +1 -0
- package/dist/tools/register-ears.d.ts +3 -0
- package/dist/tools/register-ears.d.ts.map +1 -0
- package/dist/tools/register-ears.js +148 -0
- package/dist/tools/register-ears.js.map +1 -0
- package/dist/tools/register-enterprise-compliance.js +1 -1
- package/dist/tools/register-enterprise-compliance.js.map +1 -1
- package/dist/tools/register-hook-generator.d.ts +3 -0
- package/dist/tools/register-hook-generator.d.ts.map +1 -0
- package/dist/tools/register-hook-generator.js +96 -0
- package/dist/tools/register-hook-generator.js.map +1 -0
- package/dist/tools/register-project-dna.d.ts +3 -0
- package/dist/tools/register-project-dna.d.ts.map +1 -0
- package/dist/tools/register-project-dna.js +43 -0
- package/dist/tools/register-project-dna.js.map +1 -0
- package/dist/tools/register-pull-sync.d.ts +3 -0
- package/dist/tools/register-pull-sync.d.ts.map +1 -0
- package/dist/tools/register-pull-sync.js +71 -0
- package/dist/tools/register-pull-sync.js.map +1 -0
- package/dist/tools/register-spec405-tools.d.ts +7 -0
- package/dist/tools/register-spec405-tools.d.ts.map +1 -0
- package/dist/tools/register-spec405-tools.js +194 -0
- package/dist/tools/register-spec405-tools.js.map +1 -0
- package/dist/tools/register-verifier.d.ts +3 -0
- package/dist/tools/register-verifier.d.ts.map +1 -0
- package/dist/tools/register-verifier.js +141 -0
- package/dist/tools/register-verifier.js.map +1 -0
- package/dist/tools/update-status/side-effects.d.ts.map +1 -1
- package/dist/tools/update-status/side-effects.js +32 -0
- package/dist/tools/update-status/side-effects.js.map +1 -1
- package/dist/types/agent-registry.d.ts +53 -0
- package/dist/types/agent-registry.d.ts.map +1 -0
- package/dist/types/agent-registry.js +2 -0
- package/dist/types/agent-registry.js.map +1 -0
- package/dist/types/analysis.d.ts +98 -0
- package/dist/types/analysis.d.ts.map +1 -1
- package/dist/types/autopilot.d.ts +36 -0
- package/dist/types/autopilot.d.ts.map +1 -0
- package/dist/types/autopilot.js +3 -0
- package/dist/types/autopilot.js.map +1 -0
- package/dist/types/competitive.d.ts +41 -0
- package/dist/types/competitive.d.ts.map +1 -0
- package/dist/types/competitive.js +3 -0
- package/dist/types/competitive.js.map +1 -0
- package/dist/types/context-profile.d.ts +22 -0
- package/dist/types/context-profile.d.ts.map +1 -0
- package/dist/types/context-profile.js +2 -0
- package/dist/types/context-profile.js.map +1 -0
- package/dist/types/ears.d.ts +34 -0
- package/dist/types/ears.d.ts.map +1 -0
- package/dist/types/ears.js +3 -0
- package/dist/types/ears.js.map +1 -0
- package/dist/types/health.d.ts +40 -0
- package/dist/types/health.d.ts.map +1 -0
- package/dist/types/health.js +3 -0
- package/dist/types/health.js.map +1 -0
- package/dist/types/hook-generator.d.ts +49 -0
- package/dist/types/hook-generator.d.ts.map +1 -0
- package/dist/types/hook-generator.js +3 -0
- package/dist/types/hook-generator.js.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +9 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/notion-asana-monday.d.ts +38 -0
- package/dist/types/notion-asana-monday.d.ts.map +1 -1
- package/dist/types/project-dna.d.ts +46 -0
- package/dist/types/project-dna.d.ts.map +1 -0
- package/dist/types/project-dna.js +4 -0
- package/dist/types/project-dna.js.map +1 -0
- package/dist/types/workflow-checkpoint.d.ts +66 -0
- package/dist/types/workflow-checkpoint.d.ts.map +1 -0
- package/dist/types/workflow-checkpoint.js +4 -0
- package/dist/types/workflow-checkpoint.js.map +1 -0
- package/package.json +1 -1
- package/src/config/ai-tool-registry.json +71 -0
- package/src/config/autopilot-config.json +21 -0
- package/src/config/competitive-catalog.json +83 -0
- package/src/config/license-plans.json +43 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-autopilot.d.ts","sourceRoot":"","sources":["../../src/tools/register-autopilot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgG9D"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// tools/register-autopilot.ts — SPEC-413: Registers configure_autopilot MCP tool
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { safeLicensed } from './safe-handler.js';
|
|
4
|
+
import { loadAutopilotConfig, saveAutopilotConfig, getAutopilotStatus, } from '../engine/autopilot/action-executor.js';
|
|
5
|
+
export function registerAutopilotTools(server) {
|
|
6
|
+
server.registerTool('configure_autopilot', {
|
|
7
|
+
description: 'Enable/disable individual autopilot triggers, set thresholds, or view current autopilot status. Autopilot auto-triggers tools like validate_criteria_quality, tdd_scaffold, and resolve_drift_violations at the right moments in the spec lifecycle.',
|
|
8
|
+
inputSchema: {
|
|
9
|
+
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
10
|
+
action: z
|
|
11
|
+
.enum(['enable', 'disable', 'status', 'set-threshold'])
|
|
12
|
+
.describe('Action to perform. Values: enable — activate a trigger rule, disable — deactivate a trigger rule, status — show all rules and their state, set-threshold — update numeric threshold for a conditional rule.'),
|
|
13
|
+
triggerId: z
|
|
14
|
+
.string()
|
|
15
|
+
.max(200)
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('ID of the trigger rule to enable/disable/configure. Example: "post-create:validate_criteria_quality". Required for enable/disable/set-threshold.'),
|
|
18
|
+
threshold: z
|
|
19
|
+
.number()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Threshold value for set-threshold action. For hour-based triggers: minimum estimated hours. For drift triggers: minimum drift score (0-1).'),
|
|
22
|
+
},
|
|
23
|
+
annotations: { readOnlyHint: false },
|
|
24
|
+
}, safeLicensed('configure_autopilot', async (args) => {
|
|
25
|
+
if (args.action === 'status') {
|
|
26
|
+
const status = await getAutopilotStatus(args.projectPath);
|
|
27
|
+
const lines = status.rules.map((r) => `${r.enabled ? '✅' : '⬜'} \`${r.id}\` — ${r.description}`);
|
|
28
|
+
return {
|
|
29
|
+
content: [
|
|
30
|
+
{
|
|
31
|
+
type: 'text',
|
|
32
|
+
text: `## Autopilot Status\n\n**${status.enabledRules}/${status.totalRules} rules enabled**\n\n${lines.join('\n')}`,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (!args.triggerId) {
|
|
38
|
+
return {
|
|
39
|
+
isError: true,
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: 'text',
|
|
43
|
+
text: 'triggerId is required for enable/disable/set-threshold actions.',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const config = await loadAutopilotConfig(args.projectPath);
|
|
49
|
+
if (args.action === 'enable') {
|
|
50
|
+
config.rules[args.triggerId] = {
|
|
51
|
+
...(config.rules[args.triggerId] ?? {}),
|
|
52
|
+
enabled: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
else if (args.action === 'disable') {
|
|
56
|
+
config.rules[args.triggerId] = {
|
|
57
|
+
...(config.rules[args.triggerId] ?? {}),
|
|
58
|
+
enabled: false,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
else if (args.action === 'set-threshold' && args.threshold !== undefined) {
|
|
62
|
+
config.rules[args.triggerId] = {
|
|
63
|
+
...(config.rules[args.triggerId] ?? { enabled: true }),
|
|
64
|
+
threshold: args.threshold,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
await saveAutopilotConfig(args.projectPath, config);
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: 'text',
|
|
72
|
+
text: `✅ Autopilot rule \`${args.triggerId}\` updated (action: ${args.action}).`,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=register-autopilot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-autopilot.js","sourceRoot":"","sources":["../../src/tools/register-autopilot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-checkpoints.d.ts","sourceRoot":"","sources":["../../src/tools/register-checkpoints.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgBzE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsL/D"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// tools/register-checkpoints.ts — Registers approval checkpoint tools (SPEC-411)
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { safeTracked } from './safe-handler.js';
|
|
4
|
+
import { handleConfigureCheckpointPolicy } from './checkpoint/configure-policy-handler.js';
|
|
5
|
+
import { handleRequireCheckpoint } from './checkpoint/require-checkpoint-handler.js';
|
|
6
|
+
import { handleApproveCheckpoint } from './checkpoint/approve-checkpoint-handler.js';
|
|
7
|
+
import { handleRejectCheckpoint } from './checkpoint/reject-checkpoint-handler.js';
|
|
8
|
+
import { handleListPendingCheckpoints } from './checkpoint/list-checkpoints-handler.js';
|
|
9
|
+
export function registerCheckpointTools(server) {
|
|
10
|
+
// -------------------------------------------------------------------------
|
|
11
|
+
// configure_checkpoint_policy — set up approval gates for transitions
|
|
12
|
+
// -------------------------------------------------------------------------
|
|
13
|
+
server.registerTool('configure_checkpoint_policy', {
|
|
14
|
+
description: 'Configure approval checkpoints that block spec status transitions until a designated role approves. ' +
|
|
15
|
+
'Apply a built-in preset (strict/balanced/relaxed) or define custom per-transition policies. ' +
|
|
16
|
+
'This implements the Judge gate in Planner→Worker→Judge governance.',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
19
|
+
preset: z
|
|
20
|
+
.enum(['strict', 'balanced', 'relaxed'])
|
|
21
|
+
.optional()
|
|
22
|
+
.describe('Policy preset: strict=all transitions need approval (draft->review, review->approved, approved->implementing, implementing->done), ' +
|
|
23
|
+
'balanced=key transitions only (review->approved, implementing->done), ' +
|
|
24
|
+
'relaxed=only completion needs approval (implementing->done).'),
|
|
25
|
+
policies: z
|
|
26
|
+
.array(z.object({
|
|
27
|
+
transition: z
|
|
28
|
+
.string()
|
|
29
|
+
.min(1)
|
|
30
|
+
.describe('Transition to gate, e.g. "review->approved". ' +
|
|
31
|
+
'Valid statuses: draft, review, approved, implementing, done, discarded.'),
|
|
32
|
+
requiredRole: z
|
|
33
|
+
.string()
|
|
34
|
+
.min(1)
|
|
35
|
+
.describe('Role that must approve: developer, tech_lead, qa, product_owner, admin.'),
|
|
36
|
+
description: z
|
|
37
|
+
.string()
|
|
38
|
+
.min(1)
|
|
39
|
+
.describe('Human-readable explanation of why this checkpoint exists.'),
|
|
40
|
+
autoApproveAfterHours: z
|
|
41
|
+
.number()
|
|
42
|
+
.positive()
|
|
43
|
+
.optional()
|
|
44
|
+
.describe('Hours before the checkpoint auto-approves if no action is taken.'),
|
|
45
|
+
}))
|
|
46
|
+
.optional()
|
|
47
|
+
.describe('Custom policies (used when preset is not set). ' +
|
|
48
|
+
'Replaces all existing policies for the project.'),
|
|
49
|
+
},
|
|
50
|
+
annotations: { title: 'Configure Checkpoint Policy', destructiveHint: false },
|
|
51
|
+
}, safeTracked('configure_checkpoint_policy', (args) => handleConfigureCheckpointPolicy(args)));
|
|
52
|
+
// -------------------------------------------------------------------------
|
|
53
|
+
// require_checkpoint — manually create a pending checkpoint
|
|
54
|
+
// -------------------------------------------------------------------------
|
|
55
|
+
server.registerTool('require_checkpoint', {
|
|
56
|
+
description: 'Create a pending checkpoint that blocks a specific spec status transition. ' +
|
|
57
|
+
'Returns the checkpoint ID and instructions on who needs to approve it. ' +
|
|
58
|
+
'The checkpoint must be approved via approve_checkpoint before the transition can proceed.',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
61
|
+
specId: z.string().min(1).max(500).describe('Spec ID to block, e.g. SPEC-042.'),
|
|
62
|
+
transition: z
|
|
63
|
+
.string()
|
|
64
|
+
.min(1)
|
|
65
|
+
.describe('Status transition to block, e.g. "review->approved". ' +
|
|
66
|
+
'Must match a configured policy.'),
|
|
67
|
+
requestedBy: z
|
|
68
|
+
.string()
|
|
69
|
+
.optional()
|
|
70
|
+
.describe('Identifier of who is requesting the checkpoint (defaults to "system").'),
|
|
71
|
+
},
|
|
72
|
+
annotations: { title: 'Require Checkpoint', destructiveHint: false },
|
|
73
|
+
}, safeTracked('require_checkpoint', (args) => handleRequireCheckpoint(args)));
|
|
74
|
+
// -------------------------------------------------------------------------
|
|
75
|
+
// approve_checkpoint — approve a pending checkpoint
|
|
76
|
+
// -------------------------------------------------------------------------
|
|
77
|
+
server.registerTool('approve_checkpoint', {
|
|
78
|
+
description: 'Approve a pending checkpoint, unblocking the associated spec status transition. ' +
|
|
79
|
+
'Returns confirmation and next steps for the spec.',
|
|
80
|
+
inputSchema: {
|
|
81
|
+
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
82
|
+
checkpointId: z
|
|
83
|
+
.string()
|
|
84
|
+
.min(1)
|
|
85
|
+
.describe('ID of the checkpoint to approve (returned by require_checkpoint).'),
|
|
86
|
+
approvedBy: z
|
|
87
|
+
.string()
|
|
88
|
+
.optional()
|
|
89
|
+
.describe('Identifier of the approver (defaults to "anonymous").'),
|
|
90
|
+
},
|
|
91
|
+
annotations: { title: 'Approve Checkpoint', destructiveHint: false },
|
|
92
|
+
}, safeTracked('approve_checkpoint', (args) => handleApproveCheckpoint(args)));
|
|
93
|
+
// -------------------------------------------------------------------------
|
|
94
|
+
// reject_checkpoint — reject a pending checkpoint
|
|
95
|
+
// -------------------------------------------------------------------------
|
|
96
|
+
server.registerTool('reject_checkpoint', {
|
|
97
|
+
description: 'Reject a pending checkpoint, blocking the associated spec status transition. ' +
|
|
98
|
+
'A rejection reason is required. The spec stays in its current status.',
|
|
99
|
+
inputSchema: {
|
|
100
|
+
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
101
|
+
checkpointId: z
|
|
102
|
+
.string()
|
|
103
|
+
.min(1)
|
|
104
|
+
.describe('ID of the checkpoint to reject (returned by require_checkpoint).'),
|
|
105
|
+
rejectedBy: z
|
|
106
|
+
.string()
|
|
107
|
+
.optional()
|
|
108
|
+
.describe('Identifier of the reviewer rejecting (defaults to "anonymous").'),
|
|
109
|
+
reason: z
|
|
110
|
+
.string()
|
|
111
|
+
.min(1)
|
|
112
|
+
.describe('Mandatory explanation of why the checkpoint was rejected.'),
|
|
113
|
+
},
|
|
114
|
+
annotations: { title: 'Reject Checkpoint', destructiveHint: false },
|
|
115
|
+
}, safeTracked('reject_checkpoint', (args) => handleRejectCheckpoint(args)));
|
|
116
|
+
// -------------------------------------------------------------------------
|
|
117
|
+
// list_pending_checkpoints — list checkpoints awaiting approval
|
|
118
|
+
// -------------------------------------------------------------------------
|
|
119
|
+
server.registerTool('list_pending_checkpoints', {
|
|
120
|
+
description: 'List all pending approval checkpoints for a project. ' +
|
|
121
|
+
'Optionally filter by required role to see only checkpoints relevant to you. ' +
|
|
122
|
+
'Returns spec ID, transition being blocked, required role, and requester.',
|
|
123
|
+
inputSchema: {
|
|
124
|
+
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
125
|
+
role: z
|
|
126
|
+
.string()
|
|
127
|
+
.optional()
|
|
128
|
+
.describe('Filter by required role: developer, tech_lead, qa, product_owner, admin. ' +
|
|
129
|
+
'Omit to list all pending checkpoints.'),
|
|
130
|
+
},
|
|
131
|
+
annotations: { title: 'List Pending Checkpoints', readOnlyHint: true },
|
|
132
|
+
}, safeTracked('list_pending_checkpoints', (args) => handleListPendingCheckpoints(args)));
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=register-checkpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-checkpoints.js","sourceRoot":"","sources":["../../src/tools/register-checkpoints.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-competitive.d.ts","sourceRoot":"","sources":["../../src/tools/register-competitive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAYzE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgHhE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { listCompetitorsHandler, competitiveGapAnalysisHandler, updateCatalogHandler, } from './competitive-handlers.js';
|
|
3
|
+
import { safeTracked, safeLicensed } from './safe-handler.js';
|
|
4
|
+
export function registerCompetitiveTools(server) {
|
|
5
|
+
// -------------------------------------------------------------------------
|
|
6
|
+
// list_competitors — FREE
|
|
7
|
+
// -------------------------------------------------------------------------
|
|
8
|
+
server.registerTool('list_competitors', {
|
|
9
|
+
description: 'List all competitors in the competitive catalog. Shows each competitor with their ' +
|
|
10
|
+
'tracked capabilities and last update date. Free tool — no license required.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
projectPath: z.string().min(1).max(1000).describe('Absolute path to the project root.'),
|
|
13
|
+
},
|
|
14
|
+
annotations: { readOnlyHint: true },
|
|
15
|
+
}, safeTracked('list_competitors', async (args) => listCompetitorsHandler(args)));
|
|
16
|
+
// -------------------------------------------------------------------------
|
|
17
|
+
// competitive_gap_analysis — PRO
|
|
18
|
+
// -------------------------------------------------------------------------
|
|
19
|
+
server.registerTool('competitive_gap_analysis', {
|
|
20
|
+
description: 'Analyze a spec or feature description against the competitive catalog to determine ' +
|
|
21
|
+
'Planu positioning (differentiator / parity / lagging), coverage by competitor, ' +
|
|
22
|
+
'unique capabilities, opportunity gaps, and differentiation suggestions. Requires Pro license.',
|
|
23
|
+
inputSchema: {
|
|
24
|
+
projectPath: z.string().min(1).max(1000).describe('Absolute path to the project root.'),
|
|
25
|
+
specId: z
|
|
26
|
+
.string()
|
|
27
|
+
.max(100)
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Spec ID to analyze (e.g. "SPEC-042"). The tool reads the spec title and description ' +
|
|
30
|
+
'to extract feature keywords. Either specId or featureDescription is required.'),
|
|
31
|
+
featureDescription: z
|
|
32
|
+
.string()
|
|
33
|
+
.max(5000)
|
|
34
|
+
.optional()
|
|
35
|
+
.describe('Free-text description of the feature to analyze vs competitors. ' +
|
|
36
|
+
'Either specId or featureDescription is required.'),
|
|
37
|
+
competitors: z
|
|
38
|
+
.array(z.string().max(100))
|
|
39
|
+
.max(20)
|
|
40
|
+
.optional()
|
|
41
|
+
.describe('Subset of competitor IDs to compare against (e.g. ["kiro", "linear"]). ' +
|
|
42
|
+
'Valid values: kiro, tessl, github-spec-kit, linear, jira, notion, shortcut. ' +
|
|
43
|
+
'Omit to compare against all competitors.'),
|
|
44
|
+
},
|
|
45
|
+
annotations: { readOnlyHint: true },
|
|
46
|
+
}, safeLicensed('competitive_gap_analysis', async (args) => competitiveGapAnalysisHandler(args)));
|
|
47
|
+
// -------------------------------------------------------------------------
|
|
48
|
+
// update_competitive_catalog — PRO
|
|
49
|
+
// -------------------------------------------------------------------------
|
|
50
|
+
server.registerTool('update_competitive_catalog', {
|
|
51
|
+
description: 'Add or update a competitor in the competitive catalog. Writes to a project-local ' +
|
|
52
|
+
'competitive-catalog.json in the planu/ directory, which overrides the bundled catalog. ' +
|
|
53
|
+
'Requires Pro license.',
|
|
54
|
+
inputSchema: {
|
|
55
|
+
projectPath: z.string().min(1).max(1000).describe('Absolute path to the project root.'),
|
|
56
|
+
competitor: z.object({
|
|
57
|
+
id: z
|
|
58
|
+
.string()
|
|
59
|
+
.min(1)
|
|
60
|
+
.max(100)
|
|
61
|
+
.describe('Unique identifier for the competitor (e.g. "kiro", "my-tool").'),
|
|
62
|
+
name: z
|
|
63
|
+
.string()
|
|
64
|
+
.min(1)
|
|
65
|
+
.max(200)
|
|
66
|
+
.describe('Display name of the competitor (e.g. "Kiro (AWS)").'),
|
|
67
|
+
url: z.string().max(500).optional().describe('Homepage URL of the competitor.'),
|
|
68
|
+
capabilities: z
|
|
69
|
+
.array(z.string().max(200))
|
|
70
|
+
.max(50)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe('List of capability identifiers the competitor supports.'),
|
|
73
|
+
strengths: z
|
|
74
|
+
.array(z.string().max(300))
|
|
75
|
+
.max(20)
|
|
76
|
+
.optional()
|
|
77
|
+
.describe('Known strengths of this competitor.'),
|
|
78
|
+
weaknesses: z
|
|
79
|
+
.array(z.string().max(300))
|
|
80
|
+
.max(20)
|
|
81
|
+
.optional()
|
|
82
|
+
.describe('Known weaknesses of this competitor.'),
|
|
83
|
+
}),
|
|
84
|
+
},
|
|
85
|
+
annotations: { readOnlyHint: false },
|
|
86
|
+
}, safeLicensed('update_competitive_catalog', async (args) => updateCatalogHandler(args)));
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=register-competitive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-competitive.js","sourceRoot":"","sources":["../../src/tools/register-competitive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-context-profile.d.ts","sourceRoot":"","sources":["../../src/tools/register-context-profile.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2BzE,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiHnE"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { safeTracked } from './safe-handler.js';
|
|
3
|
+
import { setActiveProfile, getActiveProfile } from '../storage/context-profile-store.js';
|
|
4
|
+
import { getProfile, getAllProfiles } from '../engine/context-profile/profile-catalog.js';
|
|
5
|
+
const AVAILABLE_PHASES = ['brainstorm', 'plan', 'implement', 'review', 'release'];
|
|
6
|
+
const projectPathField = z
|
|
7
|
+
.string()
|
|
8
|
+
.min(1)
|
|
9
|
+
.max(4096)
|
|
10
|
+
.describe('Absolute path to the project root directory.');
|
|
11
|
+
const phaseField = z
|
|
12
|
+
.enum(['brainstorm', 'plan', 'implement', 'review', 'release'])
|
|
13
|
+
.describe('Work phase to activate: ' +
|
|
14
|
+
'brainstorm=explore ideas, ' +
|
|
15
|
+
'plan=design specs, ' +
|
|
16
|
+
'implement=build features, ' +
|
|
17
|
+
'review=validate quality, ' +
|
|
18
|
+
'release=publish');
|
|
19
|
+
export function registerContextProfileTools(server) {
|
|
20
|
+
// -------------------------------------------------------------------------
|
|
21
|
+
// set_context_profile
|
|
22
|
+
// -------------------------------------------------------------------------
|
|
23
|
+
server.registerTool('set_context_profile', {
|
|
24
|
+
description: 'Activate a work-phase context profile that guides the LLM to use only the ' +
|
|
25
|
+
'relevant tools for the current phase (brainstorm/plan/implement/review/release). ' +
|
|
26
|
+
'Reduces token waste by surfacing only the ~10 most relevant tools per phase.',
|
|
27
|
+
inputSchema: {
|
|
28
|
+
projectPath: projectPathField,
|
|
29
|
+
phase: phaseField,
|
|
30
|
+
},
|
|
31
|
+
annotations: { readOnlyHint: false },
|
|
32
|
+
}, safeTracked('set_context_profile', async (args) => {
|
|
33
|
+
const { projectPath, phase } = args;
|
|
34
|
+
await setActiveProfile(projectPath, phase);
|
|
35
|
+
const profile = getProfile(phase);
|
|
36
|
+
const focusList = profile.focusTools.map((t) => ` • ${t}`).join('\n');
|
|
37
|
+
const tipsList = profile.tips.map((t) => ` - ${t}`).join('\n');
|
|
38
|
+
const text = `You are now in **${profile.name}**.\n\n` +
|
|
39
|
+
`${profile.description}\n\n` +
|
|
40
|
+
`**Focus tools (~${profile.estimatedTokensSaved}% token savings):**\n${focusList}\n\n` +
|
|
41
|
+
`**Tips:**\n${tipsList}`;
|
|
42
|
+
return { content: [{ type: 'text', text }] };
|
|
43
|
+
}));
|
|
44
|
+
// -------------------------------------------------------------------------
|
|
45
|
+
// get_context_profile
|
|
46
|
+
// -------------------------------------------------------------------------
|
|
47
|
+
server.registerTool('get_context_profile', {
|
|
48
|
+
description: 'Get the currently active context profile for a project, ' +
|
|
49
|
+
'including focus tools and phase-specific tips. ' +
|
|
50
|
+
'Returns a prompt when no profile is active.',
|
|
51
|
+
inputSchema: {
|
|
52
|
+
projectPath: projectPathField,
|
|
53
|
+
},
|
|
54
|
+
annotations: { readOnlyHint: true },
|
|
55
|
+
}, safeTracked('get_context_profile', async (args) => {
|
|
56
|
+
const { projectPath } = args;
|
|
57
|
+
const active = await getActiveProfile(projectPath);
|
|
58
|
+
if (!active) {
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: 'text',
|
|
63
|
+
text: 'No active context profile. Use set_context_profile to activate one.\n\n' +
|
|
64
|
+
`Available phases: ${AVAILABLE_PHASES.join(', ')}`,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const profile = getProfile(active.phase);
|
|
70
|
+
const focusList = profile.focusTools.map((t) => ` • ${t}`).join('\n');
|
|
71
|
+
const avoidList = profile.avoidTools.map((t) => ` • ${t}`).join('\n');
|
|
72
|
+
const tipsList = profile.tips.map((t) => ` - ${t}`).join('\n');
|
|
73
|
+
const text = `**Active profile: ${profile.name}**\n` +
|
|
74
|
+
`Activated: ${active.activatedAt}\n\n` +
|
|
75
|
+
`${profile.description}\n\n` +
|
|
76
|
+
`**Focus tools:**\n${focusList}\n\n` +
|
|
77
|
+
`**Avoid tools:**\n${avoidList}\n\n` +
|
|
78
|
+
`**Tips:**\n${tipsList}\n\n` +
|
|
79
|
+
`Estimated token savings: ~${profile.estimatedTokensSaved}%`;
|
|
80
|
+
return { content: [{ type: 'text', text }] };
|
|
81
|
+
}));
|
|
82
|
+
// -------------------------------------------------------------------------
|
|
83
|
+
// list_context_profiles
|
|
84
|
+
// -------------------------------------------------------------------------
|
|
85
|
+
server.registerTool('list_context_profiles', {
|
|
86
|
+
description: 'List all 5 available context profiles (brainstorm/plan/implement/review/release) ' +
|
|
87
|
+
'with their focus tools and estimated token savings. ' +
|
|
88
|
+
'Use this to discover which profile is best for the current work.',
|
|
89
|
+
inputSchema: {
|
|
90
|
+
projectPath: projectPathField,
|
|
91
|
+
},
|
|
92
|
+
annotations: { readOnlyHint: true },
|
|
93
|
+
}, safeTracked('list_context_profiles', async (args) => {
|
|
94
|
+
const { projectPath } = args;
|
|
95
|
+
const active = await getActiveProfile(projectPath);
|
|
96
|
+
const profiles = getAllProfiles();
|
|
97
|
+
const lines = ['**Available context profiles:**\n'];
|
|
98
|
+
for (const p of profiles) {
|
|
99
|
+
const isActive = active?.phase === p.phase ? ' (ACTIVE)' : '';
|
|
100
|
+
lines.push(`### ${p.name}${isActive}`, `Phase: \`${p.phase}\``, p.description, `Focus: ${p.focusTools.slice(0, 5).join(', ')}${p.focusTools.length > 5 ? ` +${String(p.focusTools.length - 5)} more` : ''}`, `Token savings: ~${String(p.estimatedTokensSaved)}%`, '');
|
|
101
|
+
}
|
|
102
|
+
lines.push(`Use set_context_profile with phase=<phase> to activate one.`);
|
|
103
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=register-context-profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-context-profile.js","sourceRoot":"","sources":["../../src/tools/register-context-profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-ears.d.ts","sourceRoot":"","sources":["../../src/tools/register-ears.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkLzD"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// tools/register-ears.ts — EARS criteria quality tools (SPEC-410)
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { safeTracked } from './safe-handler.js';
|
|
4
|
+
import { lintSpec, lintAllSpecs } from '../engine/ears/spec-linter.js';
|
|
5
|
+
import { scoreCriterion } from '../engine/ears/criterion-scorer.js';
|
|
6
|
+
import { generateRewrites } from '../engine/ears/rewriter.js';
|
|
7
|
+
import { detectEarsPattern } from '../engine/ears/pattern-matcher.js';
|
|
8
|
+
export function registerEarsTools(server) {
|
|
9
|
+
// -------------------------------------------------------------------------
|
|
10
|
+
// validate_criteria_quality — score AC quality for a spec or raw criteria
|
|
11
|
+
// -------------------------------------------------------------------------
|
|
12
|
+
server.registerTool('validate_criteria_quality', {
|
|
13
|
+
description: 'Score acceptance criteria quality using EARS (Easy Approach to Requirements Syntax). ' +
|
|
14
|
+
'Detects vague language, scores testability and specificity (0-10 each), ' +
|
|
15
|
+
'identifies the EARS pattern, and suggests rewrites for low-scoring criteria. ' +
|
|
16
|
+
'Provide either specId (reads from spec file) or criteria (raw text array). ' +
|
|
17
|
+
'Returns per-criterion scores, overall grade (A-F), and rewrite suggestions.',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
projectPath: z
|
|
20
|
+
.string()
|
|
21
|
+
.min(1)
|
|
22
|
+
.max(4096)
|
|
23
|
+
.describe('Absolute path to the project root where planu/ directory lives.'),
|
|
24
|
+
specId: z
|
|
25
|
+
.string()
|
|
26
|
+
.min(1)
|
|
27
|
+
.max(500)
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Spec ID to validate (e.g. SPEC-042). Reads criteria from the spec file.'),
|
|
30
|
+
criteria: z
|
|
31
|
+
.array(z.string().min(1).max(2000))
|
|
32
|
+
.optional()
|
|
33
|
+
.describe('Raw acceptance criteria text array to score. Used when specId is not provided.'),
|
|
34
|
+
},
|
|
35
|
+
annotations: { title: 'Validate Criteria Quality', readOnlyHint: true },
|
|
36
|
+
}, safeTracked('validate_criteria_quality', async (args) => {
|
|
37
|
+
const { projectPath, specId, criteria } = args;
|
|
38
|
+
if (specId !== undefined) {
|
|
39
|
+
const report = await lintSpec(specId, projectPath);
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: 'text', text: JSON.stringify(report, null, 2) }],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (criteria !== undefined && criteria.length > 0) {
|
|
45
|
+
const scored = criteria.map(scoreCriterion);
|
|
46
|
+
const overallScore = scored.length > 0
|
|
47
|
+
? Math.round((scored.reduce((sum, c) => sum + c.overallScore, 0) / scored.length) * 10) / 10
|
|
48
|
+
: 0;
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: 'text',
|
|
53
|
+
text: JSON.stringify({ criteria: scored, overallScore }, null, 2),
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
text: 'Provide either specId or criteria array.',
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
isError: true,
|
|
66
|
+
};
|
|
67
|
+
}));
|
|
68
|
+
// -------------------------------------------------------------------------
|
|
69
|
+
// rewrite_criteria_ears — score a single criterion and get EARS rewrites
|
|
70
|
+
// -------------------------------------------------------------------------
|
|
71
|
+
server.registerTool('rewrite_criteria_ears', {
|
|
72
|
+
description: 'Score a single acceptance criterion and generate 2 EARS-format rewrite suggestions. ' +
|
|
73
|
+
'Returns current testability and specificity scores, detected vagueness flags, ' +
|
|
74
|
+
'EARS pattern classification, and concrete rewrite alternatives. ' +
|
|
75
|
+
'No LLM call — rewrites are template-driven for consistency and speed.',
|
|
76
|
+
inputSchema: {
|
|
77
|
+
projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root.'),
|
|
78
|
+
criterion: z
|
|
79
|
+
.string()
|
|
80
|
+
.min(1)
|
|
81
|
+
.max(2000)
|
|
82
|
+
.describe('The acceptance criterion text to score and rewrite.'),
|
|
83
|
+
},
|
|
84
|
+
annotations: { title: 'Rewrite Criteria as EARS', readOnlyHint: true },
|
|
85
|
+
}, safeTracked('rewrite_criteria_ears', (args) => {
|
|
86
|
+
const { criterion } = args;
|
|
87
|
+
const scored = scoreCriterion(criterion);
|
|
88
|
+
const pattern = detectEarsPattern(criterion);
|
|
89
|
+
const rewrites = generateRewrites(criterion, pattern);
|
|
90
|
+
return Promise.resolve({
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: 'text',
|
|
94
|
+
text: JSON.stringify({ ...scored, rewrites }, null, 2),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
}));
|
|
99
|
+
// -------------------------------------------------------------------------
|
|
100
|
+
// ears_lint — lint all specs in the project and report worst criteria
|
|
101
|
+
// -------------------------------------------------------------------------
|
|
102
|
+
server.registerTool('ears_lint', {
|
|
103
|
+
description: 'Lint all specs in the project for EARS compliance and criteria quality. ' +
|
|
104
|
+
'Returns project-wide average score, letter grade, and top 10 worst criteria ranked by score. ' +
|
|
105
|
+
'Use minScore to filter and only report criteria below a threshold. ' +
|
|
106
|
+
'Helpful for identifying which specs need the most improvement.',
|
|
107
|
+
inputSchema: {
|
|
108
|
+
projectPath: z
|
|
109
|
+
.string()
|
|
110
|
+
.min(1)
|
|
111
|
+
.max(4096)
|
|
112
|
+
.describe('Absolute path to the project root where planu/specs/ directory lives.'),
|
|
113
|
+
minScore: z
|
|
114
|
+
.number()
|
|
115
|
+
.min(0)
|
|
116
|
+
.max(10)
|
|
117
|
+
.optional()
|
|
118
|
+
.describe('Optional score threshold (0-10). Only report criteria with overallScore below this value. ' +
|
|
119
|
+
'Defaults to 10 (report all criteria regardless of score).'),
|
|
120
|
+
},
|
|
121
|
+
annotations: { title: 'EARS Lint All Specs', readOnlyHint: true },
|
|
122
|
+
}, safeTracked('ears_lint', async (args) => {
|
|
123
|
+
const { projectPath, minScore } = args;
|
|
124
|
+
const report = await lintAllSpecs(projectPath);
|
|
125
|
+
const threshold = minScore ?? 10;
|
|
126
|
+
const filteredWorst = report.topWorstCriteria.filter((c) => c.score < threshold);
|
|
127
|
+
const summary = {
|
|
128
|
+
projectPath: report.projectPath,
|
|
129
|
+
totalSpecs: report.totalSpecs,
|
|
130
|
+
averageScore: report.averageScore,
|
|
131
|
+
grade: report.averageScore >= 9
|
|
132
|
+
? 'A'
|
|
133
|
+
: report.averageScore >= 7
|
|
134
|
+
? 'B'
|
|
135
|
+
: report.averageScore >= 5
|
|
136
|
+
? 'C'
|
|
137
|
+
: report.averageScore >= 3
|
|
138
|
+
? 'D'
|
|
139
|
+
: 'F',
|
|
140
|
+
topWorstCriteria: filteredWorst,
|
|
141
|
+
generatedAt: report.generatedAt,
|
|
142
|
+
};
|
|
143
|
+
return {
|
|
144
|
+
content: [{ type: 'text', text: JSON.stringify(summary, null, 2) }],
|
|
145
|
+
};
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=register-ears.js.map
|