@planu/cli 1.2.0 → 1.4.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/dev-lifecycle-catalog.json +22 -0
- package/dist/config/license-plans.json +20 -1
- package/dist/engine/aider-prompt-generator.d.ts +26 -0
- package/dist/engine/aider-prompt-generator.d.ts.map +1 -0
- package/dist/engine/aider-prompt-generator.js +144 -0
- package/dist/engine/aider-prompt-generator.js.map +1 -0
- package/dist/engine/claude-config-auditor/settings-auditor.d.ts.map +1 -1
- package/dist/engine/claude-config-auditor/settings-auditor.js +20 -1
- package/dist/engine/claude-config-auditor/settings-auditor.js.map +1 -1
- package/dist/engine/code-graph-configurator.d.ts +23 -0
- package/dist/engine/code-graph-configurator.d.ts.map +1 -0
- package/dist/engine/code-graph-configurator.js +80 -0
- package/dist/engine/code-graph-configurator.js.map +1 -0
- package/dist/engine/continue-config-generator.d.ts +15 -0
- package/dist/engine/continue-config-generator.d.ts.map +1 -0
- package/dist/engine/continue-config-generator.js +53 -0
- package/dist/engine/continue-config-generator.js.map +1 -0
- package/dist/engine/doc-compliance-checker.d.ts +23 -0
- package/dist/engine/doc-compliance-checker.d.ts.map +1 -0
- package/dist/engine/doc-compliance-checker.js +168 -0
- package/dist/engine/doc-compliance-checker.js.map +1 -0
- package/dist/engine/e2e-test-generator.d.ts +19 -0
- package/dist/engine/e2e-test-generator.d.ts.map +1 -0
- package/dist/engine/e2e-test-generator.js +210 -0
- package/dist/engine/e2e-test-generator.js.map +1 -0
- package/dist/engine/ecosystem-detector.d.ts +13 -0
- package/dist/engine/ecosystem-detector.d.ts.map +1 -0
- package/dist/engine/ecosystem-detector.js +128 -0
- package/dist/engine/ecosystem-detector.js.map +1 -0
- package/dist/engine/memory-config-generator.d.ts +8 -0
- package/dist/engine/memory-config-generator.d.ts.map +1 -0
- package/dist/engine/memory-config-generator.js +101 -0
- package/dist/engine/memory-config-generator.js.map +1 -0
- package/dist/engine/pr-spec-validator.d.ts +25 -0
- package/dist/engine/pr-spec-validator.d.ts.map +1 -0
- package/dist/engine/pr-spec-validator.js +172 -0
- package/dist/engine/pr-spec-validator.js.map +1 -0
- package/dist/engine/skill-generator/sections-docs.d.ts +13 -0
- package/dist/engine/skill-generator/sections-docs.d.ts.map +1 -0
- package/dist/engine/skill-generator/sections-docs.js +59 -0
- package/dist/engine/skill-generator/sections-docs.js.map +1 -0
- package/dist/engine/skill-generator/skills-content.d.ts +1 -1
- package/dist/engine/skill-generator/skills-content.d.ts.map +1 -1
- package/dist/engine/skill-generator/skills-content.js +3 -2
- package/dist/engine/skill-generator/skills-content.js.map +1 -1
- package/dist/engine/skill-generator/skills.d.ts +1 -0
- package/dist/engine/skill-generator/skills.d.ts.map +1 -1
- package/dist/engine/skill-generator/skills.js +1 -0
- package/dist/engine/skill-generator/skills.js.map +1 -1
- package/dist/engine/skill-generator.d.ts.map +1 -1
- package/dist/engine/skill-generator.js +21 -2
- package/dist/engine/skill-generator.js.map +1 -1
- package/dist/engine/sweep-issue-generator.d.ts +14 -0
- package/dist/engine/sweep-issue-generator.d.ts.map +1 -0
- package/dist/engine/sweep-issue-generator.js +140 -0
- package/dist/engine/sweep-issue-generator.js.map +1 -0
- package/dist/engine/web-fetcher/docs-intelligence.d.ts +8 -0
- package/dist/engine/web-fetcher/docs-intelligence.d.ts.map +1 -0
- package/dist/engine/web-fetcher/docs-intelligence.js +154 -0
- package/dist/engine/web-fetcher/docs-intelligence.js.map +1 -0
- package/dist/engine/web-fetcher/registry-auto-discovery.d.ts +20 -0
- package/dist/engine/web-fetcher/registry-auto-discovery.d.ts.map +1 -0
- package/dist/engine/web-fetcher/registry-auto-discovery.js +184 -0
- package/dist/engine/web-fetcher/registry-auto-discovery.js.map +1 -0
- package/dist/engine/web-fetcher/stack-detector.d.ts +4 -0
- package/dist/engine/web-fetcher/stack-detector.d.ts.map +1 -0
- package/dist/engine/web-fetcher/stack-detector.js +155 -0
- package/dist/engine/web-fetcher/stack-detector.js.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/aider-launcher-handler.d.ts +4 -0
- package/dist/tools/aider-launcher-handler.d.ts.map +1 -0
- package/dist/tools/aider-launcher-handler.js +69 -0
- package/dist/tools/aider-launcher-handler.js.map +1 -0
- package/dist/tools/code-graph-handler.d.ts +6 -0
- package/dist/tools/code-graph-handler.d.ts.map +1 -0
- package/dist/tools/code-graph-handler.js +68 -0
- package/dist/tools/code-graph-handler.js.map +1 -0
- package/dist/tools/continue-config-handler.d.ts +4 -0
- package/dist/tools/continue-config-handler.d.ts.map +1 -0
- package/dist/tools/continue-config-handler.js +88 -0
- package/dist/tools/continue-config-handler.js.map +1 -0
- package/dist/tools/create-spec/spec-builder.d.ts.map +1 -1
- package/dist/tools/create-spec/spec-builder.js +20 -0
- package/dist/tools/create-spec/spec-builder.js.map +1 -1
- package/dist/tools/create-spec-hu/docs-criteria-adapter.d.ts +14 -0
- package/dist/tools/create-spec-hu/docs-criteria-adapter.d.ts.map +1 -0
- package/dist/tools/create-spec-hu/docs-criteria-adapter.js +50 -0
- package/dist/tools/create-spec-hu/docs-criteria-adapter.js.map +1 -0
- package/dist/tools/create-spec-hu.d.ts +1 -1
- package/dist/tools/create-spec-hu.d.ts.map +1 -1
- package/dist/tools/create-spec-hu.js +5 -1
- package/dist/tools/create-spec-hu.js.map +1 -1
- package/dist/tools/create-spec.d.ts.map +1 -1
- package/dist/tools/create-spec.js +2 -2
- package/dist/tools/create-spec.js.map +1 -1
- package/dist/tools/doc-compliance-handler.d.ts +3 -0
- package/dist/tools/doc-compliance-handler.d.ts.map +1 -0
- package/dist/tools/doc-compliance-handler.js +48 -0
- package/dist/tools/doc-compliance-handler.js.map +1 -0
- package/dist/tools/docs-registry-handler.d.ts +6 -0
- package/dist/tools/docs-registry-handler.d.ts.map +1 -0
- package/dist/tools/docs-registry-handler.js +73 -0
- package/dist/tools/docs-registry-handler.js.map +1 -0
- package/dist/tools/e2e-test-generator-handler.d.ts +12 -0
- package/dist/tools/e2e-test-generator-handler.d.ts.map +1 -0
- package/dist/tools/e2e-test-generator-handler.js +54 -0
- package/dist/tools/e2e-test-generator-handler.js.map +1 -0
- package/dist/tools/ecosystem-tools-handler.d.ts +4 -0
- package/dist/tools/ecosystem-tools-handler.d.ts.map +1 -0
- package/dist/tools/ecosystem-tools-handler.js +57 -0
- package/dist/tools/ecosystem-tools-handler.js.map +1 -0
- package/dist/tools/memory-config-handler.d.ts +4 -0
- package/dist/tools/memory-config-handler.d.ts.map +1 -0
- package/dist/tools/memory-config-handler.js +110 -0
- package/dist/tools/memory-config-handler.js.map +1 -0
- package/dist/tools/pr-agent-handler.d.ts +12 -0
- package/dist/tools/pr-agent-handler.d.ts.map +1 -0
- package/dist/tools/pr-agent-handler.js +47 -0
- package/dist/tools/pr-agent-handler.js.map +1 -0
- package/dist/tools/register-aider-tools.d.ts +3 -0
- package/dist/tools/register-aider-tools.d.ts.map +1 -0
- package/dist/tools/register-aider-tools.js +28 -0
- package/dist/tools/register-aider-tools.js.map +1 -0
- package/dist/tools/register-code-graph-tools.d.ts +3 -0
- package/dist/tools/register-code-graph-tools.d.ts.map +1 -0
- package/dist/tools/register-code-graph-tools.js +36 -0
- package/dist/tools/register-code-graph-tools.js.map +1 -0
- package/dist/tools/register-continue-tools.d.ts +3 -0
- package/dist/tools/register-continue-tools.d.ts.map +1 -0
- package/dist/tools/register-continue-tools.js +38 -0
- package/dist/tools/register-continue-tools.js.map +1 -0
- package/dist/tools/register-doc-compliance-tools.d.ts +3 -0
- package/dist/tools/register-doc-compliance-tools.d.ts.map +1 -0
- package/dist/tools/register-doc-compliance-tools.js +18 -0
- package/dist/tools/register-doc-compliance-tools.js.map +1 -0
- package/dist/tools/register-docs-registry-tools.d.ts +3 -0
- package/dist/tools/register-docs-registry-tools.d.ts.map +1 -0
- package/dist/tools/register-docs-registry-tools.js +35 -0
- package/dist/tools/register-docs-registry-tools.js.map +1 -0
- package/dist/tools/register-e2e-test-generator-tools.d.ts +3 -0
- package/dist/tools/register-e2e-test-generator-tools.d.ts.map +1 -0
- package/dist/tools/register-e2e-test-generator-tools.js +35 -0
- package/dist/tools/register-e2e-test-generator-tools.js.map +1 -0
- package/dist/tools/register-memory-config-tools.d.ts +3 -0
- package/dist/tools/register-memory-config-tools.d.ts.map +1 -0
- package/dist/tools/register-memory-config-tools.js +34 -0
- package/dist/tools/register-memory-config-tools.js.map +1 -0
- package/dist/tools/register-pr-agent-tools.d.ts +3 -0
- package/dist/tools/register-pr-agent-tools.d.ts.map +1 -0
- package/dist/tools/register-pr-agent-tools.js +34 -0
- package/dist/tools/register-pr-agent-tools.js.map +1 -0
- package/dist/tools/register-sweep-tools.d.ts +3 -0
- package/dist/tools/register-sweep-tools.d.ts.map +1 -0
- package/dist/tools/register-sweep-tools.js +42 -0
- package/dist/tools/register-sweep-tools.js.map +1 -0
- package/dist/tools/register-token-optimizer-tools.d.ts +3 -0
- package/dist/tools/register-token-optimizer-tools.d.ts.map +1 -0
- package/dist/tools/register-token-optimizer-tools.js +22 -0
- package/dist/tools/register-token-optimizer-tools.js.map +1 -0
- package/dist/tools/sweep-integration-handler.d.ts +4 -0
- package/dist/tools/sweep-integration-handler.d.ts.map +1 -0
- package/dist/tools/sweep-integration-handler.js +60 -0
- package/dist/tools/sweep-integration-handler.js.map +1 -0
- package/dist/types/aider.d.ts +21 -0
- package/dist/types/aider.d.ts.map +1 -0
- package/dist/types/aider.js +3 -0
- package/dist/types/aider.js.map +1 -0
- package/dist/types/code-graph-integration.d.ts +22 -0
- package/dist/types/code-graph-integration.d.ts.map +1 -0
- package/dist/types/code-graph-integration.js +3 -0
- package/dist/types/code-graph-integration.js.map +1 -0
- package/dist/types/continue-integration.d.ts +32 -0
- package/dist/types/continue-integration.d.ts.map +1 -0
- package/dist/types/continue-integration.js +3 -0
- package/dist/types/continue-integration.js.map +1 -0
- package/dist/types/docs.d.ts +70 -0
- package/dist/types/docs.d.ts.map +1 -1
- package/dist/types/e2e-test-generator.d.ts +27 -0
- package/dist/types/e2e-test-generator.d.ts.map +1 -0
- package/dist/types/e2e-test-generator.js +3 -0
- package/dist/types/e2e-test-generator.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/mcp.d.ts +17 -0
- package/dist/types/mcp.d.ts.map +1 -1
- package/dist/types/pr-agent.d.ts +28 -0
- package/dist/types/pr-agent.d.ts.map +1 -0
- package/dist/types/pr-agent.js +3 -0
- package/dist/types/pr-agent.js.map +1 -0
- package/dist/types/spec/core.d.ts +2 -0
- package/dist/types/spec/core.d.ts.map +1 -1
- package/dist/types/sweep.d.ts +22 -0
- package/dist/types/sweep.d.ts.map +1 -0
- package/dist/types/sweep.js +3 -0
- package/dist/types/sweep.js.map +1 -0
- package/dist/types/tooling/index.d.ts +2 -0
- package/dist/types/tooling/index.d.ts.map +1 -1
- package/dist/types/tooling/memory-config.d.ts +25 -0
- package/dist/types/tooling/memory-config.d.ts.map +1 -0
- package/dist/types/tooling/memory-config.js +3 -0
- package/dist/types/tooling/memory-config.js.map +1 -0
- package/dist/types/tooling/token-optimizer.d.ts +42 -0
- package/dist/types/tooling/token-optimizer.d.ts.map +1 -0
- package/dist/types/tooling/token-optimizer.js +3 -0
- package/dist/types/tooling/token-optimizer.js.map +1 -0
- package/dist/types/tooling.d.ts +1 -1
- package/dist/types/tooling.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/config/dev-lifecycle-catalog.json +22 -0
- package/src/config/license-plans.json +20 -1
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// engine/doc-compliance-checker.ts — SPEC-385
|
|
2
|
+
// Checks a spec against official documentation for anti-patterns and missing best practices.
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { detectTechsFromText } from './web-fetcher/stack-detector.js';
|
|
5
|
+
import { fetchDocsBatch } from './web-fetcher/docs-intelligence.js';
|
|
6
|
+
/**
|
|
7
|
+
* Checks if any anti-pattern from official docs appears in spec content.
|
|
8
|
+
* Returns a DocComplianceIssue for each match found.
|
|
9
|
+
*/
|
|
10
|
+
export function detectAntiPatterns(tech, docsResult, specContent) {
|
|
11
|
+
const issues = [];
|
|
12
|
+
const lower = specContent.toLowerCase();
|
|
13
|
+
for (const ap of docsResult.antiPatterns) {
|
|
14
|
+
// Extract key terms from the anti-pattern description (first 5 words)
|
|
15
|
+
const keyTerms = ap
|
|
16
|
+
.toLowerCase()
|
|
17
|
+
.replace(/[^a-z0-9\s]/g, ' ')
|
|
18
|
+
.split(/\s+/)
|
|
19
|
+
.filter((w) => w.length > 3)
|
|
20
|
+
.slice(0, 5);
|
|
21
|
+
const matchCount = keyTerms.filter((term) => lower.includes(term)).length;
|
|
22
|
+
if (matchCount >= 2) {
|
|
23
|
+
issues.push({
|
|
24
|
+
tech,
|
|
25
|
+
issueType: 'anti-pattern',
|
|
26
|
+
description: ap,
|
|
27
|
+
source: docsResult.docsUrl,
|
|
28
|
+
severity: 'high',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return issues;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Identifies best practices from official docs that are NOT covered in the spec.
|
|
36
|
+
* Returns a list of missing best practice descriptions.
|
|
37
|
+
*/
|
|
38
|
+
export function detectMissingBestPractices(tech, docsResult, specContent) {
|
|
39
|
+
const issues = [];
|
|
40
|
+
const lower = specContent.toLowerCase();
|
|
41
|
+
for (const bp of docsResult.bestPractices.slice(0, 5)) {
|
|
42
|
+
const keyTerms = bp
|
|
43
|
+
.toLowerCase()
|
|
44
|
+
.replace(/[^a-z0-9\s]/g, ' ')
|
|
45
|
+
.split(/\s+/)
|
|
46
|
+
.filter((w) => w.length > 3)
|
|
47
|
+
.slice(0, 5);
|
|
48
|
+
if (keyTerms.length === 0) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const matchCount = keyTerms.filter((term) => lower.includes(term)).length;
|
|
52
|
+
// If fewer than 1/3 of key terms appear, best practice is likely missing
|
|
53
|
+
if (matchCount < Math.max(1, Math.ceil(keyTerms.length / 3))) {
|
|
54
|
+
issues.push({
|
|
55
|
+
tech,
|
|
56
|
+
issueType: 'missing-best-practice',
|
|
57
|
+
description: `Missing: ${bp}`,
|
|
58
|
+
source: docsResult.docsUrl,
|
|
59
|
+
severity: 'medium',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return issues;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Calculates a compliance score 0-100 based on issues found.
|
|
67
|
+
* High severity issues cost more points.
|
|
68
|
+
*/
|
|
69
|
+
export function calculateComplianceScore(issues, totalChecks) {
|
|
70
|
+
if (totalChecks === 0) {
|
|
71
|
+
return 100;
|
|
72
|
+
}
|
|
73
|
+
const penalty = issues.reduce((sum, issue) => {
|
|
74
|
+
return sum + (issue.severity === 'high' ? 15 : issue.severity === 'medium' ? 8 : 3);
|
|
75
|
+
}, 0);
|
|
76
|
+
return Math.max(0, Math.min(100, 100 - penalty));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Extracts spec title from frontmatter or first heading.
|
|
80
|
+
*/
|
|
81
|
+
function extractSpecTitle(specContent, fallback) {
|
|
82
|
+
const titleMatch = /^title:\s*"?([^"\n]+)"?/m.exec(specContent) ??
|
|
83
|
+
/^#\s+(?:SPEC-\d+[:\s]+)?(.+)/m.exec(specContent);
|
|
84
|
+
return titleMatch?.[1]?.trim() ?? fallback;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Main entry point: checks a spec file against official documentation.
|
|
88
|
+
* Reads the spec file, detects techs, fetches docs, and checks for issues.
|
|
89
|
+
*/
|
|
90
|
+
export async function checkDocCompliance(specPath, specId) {
|
|
91
|
+
// Read spec content
|
|
92
|
+
let specContent;
|
|
93
|
+
let specTitle;
|
|
94
|
+
try {
|
|
95
|
+
specContent = await readFile(specPath, 'utf-8');
|
|
96
|
+
specTitle = extractSpecTitle(specContent, specId);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// fallback to specId as search text
|
|
100
|
+
specContent = specId;
|
|
101
|
+
specTitle = specId;
|
|
102
|
+
}
|
|
103
|
+
// Detect technologies
|
|
104
|
+
const detected = detectTechsFromText(specContent);
|
|
105
|
+
const techs = detected
|
|
106
|
+
.filter((t) => t.confidence === 'high' || t.confidence === 'medium')
|
|
107
|
+
.map((t) => t.name)
|
|
108
|
+
.slice(0, 6);
|
|
109
|
+
if (techs.length === 0) {
|
|
110
|
+
return {
|
|
111
|
+
specId,
|
|
112
|
+
specTitle,
|
|
113
|
+
checkedAt: new Date().toISOString(),
|
|
114
|
+
techs: [],
|
|
115
|
+
issues: [],
|
|
116
|
+
bestPracticesCovered: [],
|
|
117
|
+
complianceScore: 100,
|
|
118
|
+
summary: 'No technologies detected in spec — skipping doc compliance check.',
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Fetch docs for detected techs
|
|
122
|
+
const docsMap = await fetchDocsBatch(techs, { timeout: 5_000, concurrency: 3 });
|
|
123
|
+
// Run checks
|
|
124
|
+
const allIssues = [];
|
|
125
|
+
const bestPracticesCovered = [];
|
|
126
|
+
let totalChecks = 0;
|
|
127
|
+
for (const [tech, docsResult] of docsMap) {
|
|
128
|
+
if (docsResult.source === 'fallback') {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const antiPatternIssues = detectAntiPatterns(tech, docsResult, specContent);
|
|
132
|
+
const missingBpIssues = detectMissingBestPractices(tech, docsResult, specContent);
|
|
133
|
+
allIssues.push(...antiPatternIssues);
|
|
134
|
+
allIssues.push(...missingBpIssues);
|
|
135
|
+
totalChecks += docsResult.antiPatterns.length + docsResult.bestPractices.slice(0, 5).length;
|
|
136
|
+
// Track covered best practices
|
|
137
|
+
const lower = specContent.toLowerCase();
|
|
138
|
+
for (const bp of docsResult.bestPractices.slice(0, 5)) {
|
|
139
|
+
const keyTerms = bp
|
|
140
|
+
.toLowerCase()
|
|
141
|
+
.replace(/[^a-z0-9\s]/g, ' ')
|
|
142
|
+
.split(/\s+/)
|
|
143
|
+
.filter((w) => w.length > 3)
|
|
144
|
+
.slice(0, 5);
|
|
145
|
+
const matchCount = keyTerms.filter((term) => lower.includes(term)).length;
|
|
146
|
+
if (matchCount >= Math.max(1, Math.ceil(keyTerms.length / 3))) {
|
|
147
|
+
bestPracticesCovered.push(`[${tech}] ${bp.slice(0, 80)}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const complianceScore = calculateComplianceScore(allIssues, totalChecks);
|
|
152
|
+
const highIssues = allIssues.filter((i) => i.severity === 'high').length;
|
|
153
|
+
const mediumIssues = allIssues.filter((i) => i.severity === 'medium').length;
|
|
154
|
+
const summary = allIssues.length === 0
|
|
155
|
+
? `Spec is fully compliant with official docs for: ${techs.join(', ')}.`
|
|
156
|
+
: `Found ${highIssues} high + ${mediumIssues} medium issues against official docs for: ${techs.join(', ')}.`;
|
|
157
|
+
return {
|
|
158
|
+
specId,
|
|
159
|
+
specTitle,
|
|
160
|
+
checkedAt: new Date().toISOString(),
|
|
161
|
+
techs,
|
|
162
|
+
issues: allIssues,
|
|
163
|
+
bestPracticesCovered,
|
|
164
|
+
complianceScore,
|
|
165
|
+
summary,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=doc-compliance-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-compliance-checker.js","sourceRoot":"","sources":["../../src/engine/doc-compliance-checker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { E2eTestFramework, GenerateE2eTestsResult, E2eTestStatusResult } from '../types/index.js';
|
|
2
|
+
/** Generate Gherkin feature file content. */
|
|
3
|
+
export declare function generateGherkin(title: string, description: string, criteria: string[]): string;
|
|
4
|
+
/** Generate Playwright TypeScript test content. */
|
|
5
|
+
export declare function generatePlaywright(title: string, criteria: string[]): string;
|
|
6
|
+
/** Generate testRigor plain English steps. */
|
|
7
|
+
export declare function generateTestRigor(title: string, criteria: string[]): string;
|
|
8
|
+
/** Generate plain numbered list. */
|
|
9
|
+
export declare function generatePlain(criteria: string[]): string;
|
|
10
|
+
/** Get file extension for each framework. */
|
|
11
|
+
export declare function getFrameworkExtension(framework: E2eTestFramework): string;
|
|
12
|
+
/** Generate E2E tests from a spec. */
|
|
13
|
+
export declare function generateE2eTests(specId: string, projectPath: string, framework?: E2eTestFramework, outputPath?: string): Promise<GenerateE2eTestsResult | {
|
|
14
|
+
isError: true;
|
|
15
|
+
message: string;
|
|
16
|
+
}>;
|
|
17
|
+
/** List existing E2E test files matching SPEC-XXX pattern. */
|
|
18
|
+
export declare function getE2eTestStatus(projectPath: string): Promise<E2eTestStatusResult>;
|
|
19
|
+
//# sourceMappingURL=e2e-test-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2e-test-generator.d.ts","sourceRoot":"","sources":["../../src/engine/e2e-test-generator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,gBAAgB,EAChB,sBAAsB,EAEtB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AA8C3B,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAa9F;AAED,mDAAmD;AACnD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAgB5E;AAED,8CAA8C;AAC9C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAG3E;AAED,oCAAoC;AACpC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAExD;AAED,6CAA6C;AAC7C,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,CAWzE;AAgCD,sCAAsC;AACtC,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,gBAA4B,EACvC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,sBAAsB,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA+DtE;AAED,8DAA8D;AAC9D,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAwCxF"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// Planu — E2E Test Generator engine (SPEC-381)
|
|
2
|
+
// Pure functions for generating E2E tests from spec acceptance criteria.
|
|
3
|
+
import { readFile, readdir, mkdir, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { join, extname } from 'node:path';
|
|
5
|
+
/** Extract acceptance criteria from spec.md content (checkbox lines). */
|
|
6
|
+
function extractAcceptanceCriteria(specContent) {
|
|
7
|
+
const lines = specContent.split('\n');
|
|
8
|
+
const criteria = [];
|
|
9
|
+
for (const line of lines) {
|
|
10
|
+
const match = /^\s*-\s*\[[ xX]?\]\s+(.+)$/.exec(line);
|
|
11
|
+
if (match?.[1]) {
|
|
12
|
+
criteria.push(match[1].trim());
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return criteria;
|
|
16
|
+
}
|
|
17
|
+
/** Extract spec title from frontmatter or first H1. */
|
|
18
|
+
function extractSpecTitle(specContent) {
|
|
19
|
+
const titleMatch = /^#\s+(.+)$/m.exec(specContent);
|
|
20
|
+
if (titleMatch?.[1]) {
|
|
21
|
+
return titleMatch[1].replace(/^SPEC-\d+[:\s-]+/i, '').trim();
|
|
22
|
+
}
|
|
23
|
+
const fmMatch = /^title:\s*(.+)$/m.exec(specContent);
|
|
24
|
+
return fmMatch?.[1]?.trim() ?? 'Spec';
|
|
25
|
+
}
|
|
26
|
+
/** Extract spec description from frontmatter or first paragraph. */
|
|
27
|
+
function extractSpecDescription(specContent) {
|
|
28
|
+
const descMatch = /^description:\s*(.+)$/m.exec(specContent);
|
|
29
|
+
if (descMatch?.[1]) {
|
|
30
|
+
return descMatch[1].trim();
|
|
31
|
+
}
|
|
32
|
+
const lines = specContent.split('\n');
|
|
33
|
+
for (const line of lines) {
|
|
34
|
+
const trimmed = line.trim();
|
|
35
|
+
if (trimmed &&
|
|
36
|
+
!trimmed.startsWith('#') &&
|
|
37
|
+
!trimmed.startsWith('-') &&
|
|
38
|
+
!trimmed.startsWith('`')) {
|
|
39
|
+
return trimmed;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return '';
|
|
43
|
+
}
|
|
44
|
+
/** Generate Gherkin feature file content. */
|
|
45
|
+
export function generateGherkin(title, description, criteria) {
|
|
46
|
+
const scenarios = criteria
|
|
47
|
+
.map((criterion) => ` Scenario: ${criterion}\n` +
|
|
48
|
+
` Given the system is ready\n` +
|
|
49
|
+
` When the user performs the action\n` +
|
|
50
|
+
` Then ${criterion}`)
|
|
51
|
+
.join('\n\n');
|
|
52
|
+
const descLine = description ? ` ${description}\n\n` : '';
|
|
53
|
+
return `Feature: ${title}\n${descLine}${scenarios}\n`;
|
|
54
|
+
}
|
|
55
|
+
/** Generate Playwright TypeScript test content. */
|
|
56
|
+
export function generatePlaywright(title, criteria) {
|
|
57
|
+
const tests = criteria
|
|
58
|
+
.map((criterion) => ` test('${criterion.replace(/'/g, "\\'")}', async ({ page }) => {\n` +
|
|
59
|
+
` // TODO: implement test for: ${criterion}\n` +
|
|
60
|
+
` });`)
|
|
61
|
+
.join('\n\n');
|
|
62
|
+
return (`import { test, expect } from '@playwright/test';\n\n` +
|
|
63
|
+
`test.describe('${title.replace(/'/g, "\\'")}', () => {\n` +
|
|
64
|
+
`${tests}\n` +
|
|
65
|
+
`});\n`);
|
|
66
|
+
}
|
|
67
|
+
/** Generate testRigor plain English steps. */
|
|
68
|
+
export function generateTestRigor(title, criteria) {
|
|
69
|
+
const steps = criteria.map((criterion, i) => `${i + 1}. ${criterion}`).join('\n');
|
|
70
|
+
return `# ${title}\n\n${steps}\n`;
|
|
71
|
+
}
|
|
72
|
+
/** Generate plain numbered list. */
|
|
73
|
+
export function generatePlain(criteria) {
|
|
74
|
+
return criteria.map((criterion, i) => `${i + 1}. Verify that ${criterion}`).join('\n') + '\n';
|
|
75
|
+
}
|
|
76
|
+
/** Get file extension for each framework. */
|
|
77
|
+
export function getFrameworkExtension(framework) {
|
|
78
|
+
switch (framework) {
|
|
79
|
+
case 'gherkin':
|
|
80
|
+
return 'feature';
|
|
81
|
+
case 'playwright':
|
|
82
|
+
return 'spec.ts';
|
|
83
|
+
case 'testRigor':
|
|
84
|
+
return 'txt';
|
|
85
|
+
case 'plain':
|
|
86
|
+
return 'txt';
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Derive default output path for tests. */
|
|
90
|
+
function deriveDefaultOutputPath(specId, slug, framework) {
|
|
91
|
+
const ext = getFrameworkExtension(framework);
|
|
92
|
+
const fileName = `${specId}-${slug}.${ext}`;
|
|
93
|
+
return join('tests', 'e2e', fileName);
|
|
94
|
+
}
|
|
95
|
+
/** Extract slug from spec directory name. */
|
|
96
|
+
function extractSlug(specDirName) {
|
|
97
|
+
return specDirName.replace(/^SPEC-\d+-?/i, '').toLowerCase() || 'spec';
|
|
98
|
+
}
|
|
99
|
+
/** Resolve spec directory from specId and projectPath. */
|
|
100
|
+
async function resolveSpecDir(specId, projectPath) {
|
|
101
|
+
const specsBase = join(projectPath, 'planu', 'specs');
|
|
102
|
+
let entries;
|
|
103
|
+
try {
|
|
104
|
+
entries = await readdir(specsBase);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const upper = specId.toUpperCase();
|
|
110
|
+
const match = entries.find((e) => e.toUpperCase().startsWith(upper));
|
|
111
|
+
return match ? join(specsBase, match) : null;
|
|
112
|
+
}
|
|
113
|
+
/** Generate E2E tests from a spec. */
|
|
114
|
+
export async function generateE2eTests(specId, projectPath, framework = 'gherkin', outputPath) {
|
|
115
|
+
const specDir = await resolveSpecDir(specId, projectPath);
|
|
116
|
+
if (!specDir) {
|
|
117
|
+
return { isError: true, message: `Spec ${specId} not found in ${projectPath}/planu/specs/` };
|
|
118
|
+
}
|
|
119
|
+
let specContent;
|
|
120
|
+
try {
|
|
121
|
+
specContent = await readFile(join(specDir, 'spec.md'), 'utf8');
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return { isError: true, message: `Could not read spec.md for ${specId}` };
|
|
125
|
+
}
|
|
126
|
+
const criteria = extractAcceptanceCriteria(specContent);
|
|
127
|
+
const title = extractSpecTitle(specContent);
|
|
128
|
+
const description = extractSpecDescription(specContent);
|
|
129
|
+
let content;
|
|
130
|
+
switch (framework) {
|
|
131
|
+
case 'gherkin':
|
|
132
|
+
content = generateGherkin(title, description, criteria);
|
|
133
|
+
break;
|
|
134
|
+
case 'playwright':
|
|
135
|
+
content = generatePlaywright(title, criteria);
|
|
136
|
+
break;
|
|
137
|
+
case 'testRigor':
|
|
138
|
+
content = generateTestRigor(title, criteria);
|
|
139
|
+
break;
|
|
140
|
+
case 'plain':
|
|
141
|
+
content = generatePlain(criteria);
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
const specDirName = specDir.split('/').pop() ?? specId;
|
|
145
|
+
const slug = extractSlug(specDirName);
|
|
146
|
+
const resolvedOutputPath = outputPath ?? deriveDefaultOutputPath(specId, slug, framework);
|
|
147
|
+
const absoluteOutputPath = resolvedOutputPath.startsWith('/')
|
|
148
|
+
? resolvedOutputPath
|
|
149
|
+
: join(projectPath, resolvedOutputPath);
|
|
150
|
+
try {
|
|
151
|
+
const dir = absoluteOutputPath.substring(0, absoluteOutputPath.lastIndexOf('/'));
|
|
152
|
+
await mkdir(dir, { recursive: true });
|
|
153
|
+
await writeFile(absoluteOutputPath, content, 'utf8');
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// If write fails, still return content without outputPath
|
|
157
|
+
return {
|
|
158
|
+
framework,
|
|
159
|
+
specId,
|
|
160
|
+
testCount: criteria.length,
|
|
161
|
+
content,
|
|
162
|
+
outputPath: null,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
framework,
|
|
167
|
+
specId,
|
|
168
|
+
testCount: criteria.length,
|
|
169
|
+
content,
|
|
170
|
+
outputPath: absoluteOutputPath,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/** List existing E2E test files matching SPEC-XXX pattern. */
|
|
174
|
+
export async function getE2eTestStatus(projectPath) {
|
|
175
|
+
const e2eDir = join(projectPath, 'tests', 'e2e');
|
|
176
|
+
let files;
|
|
177
|
+
try {
|
|
178
|
+
files = await readdir(e2eDir);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return { testFiles: [], total: 0 };
|
|
182
|
+
}
|
|
183
|
+
const specPattern = /^(SPEC-\d+)/i;
|
|
184
|
+
const testFiles = [];
|
|
185
|
+
for (const file of files) {
|
|
186
|
+
const ext = extname(file);
|
|
187
|
+
const isTestFile = file.endsWith('.feature') || file.endsWith('.spec.ts') || file.endsWith('.test.ts');
|
|
188
|
+
if (!isTestFile) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const match = specPattern.exec(file);
|
|
192
|
+
if (!match?.[1]) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
const specId = match[1].toUpperCase();
|
|
196
|
+
let framework;
|
|
197
|
+
if (file.endsWith('.feature')) {
|
|
198
|
+
framework = 'gherkin';
|
|
199
|
+
}
|
|
200
|
+
else if (ext === '.ts') {
|
|
201
|
+
framework = 'playwright';
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
framework = 'unknown';
|
|
205
|
+
}
|
|
206
|
+
testFiles.push({ file, specId, framework });
|
|
207
|
+
}
|
|
208
|
+
return { testFiles, total: testFiles.length };
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=e2e-test-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2e-test-generator.js","sourceRoot":"","sources":["../../src/engine/e2e-test-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TokenOptimizerStatus, TokenOptimizerRecommendation } from '../types/index.js';
|
|
2
|
+
export declare function detectRtkHooks(projectPath: string): Promise<number>;
|
|
3
|
+
export declare function detectHeadroomPackage(projectPath: string): Promise<{
|
|
4
|
+
installed: boolean;
|
|
5
|
+
version?: string;
|
|
6
|
+
}>;
|
|
7
|
+
export declare function detectRtkPackage(projectPath: string): Promise<{
|
|
8
|
+
installed: boolean;
|
|
9
|
+
version?: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function getTokenOptimizerStatus(projectPath: string): Promise<TokenOptimizerStatus>;
|
|
12
|
+
export declare function buildTokenOptimizerRecommendations(projectPath: string): Promise<TokenOptimizerRecommendation[]>;
|
|
13
|
+
//# sourceMappingURL=ecosystem-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecosystem-detector.d.ts","sourceRoot":"","sources":["../../src/engine/ecosystem-detector.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,oBAAoB,EACpB,4BAA4B,EAG7B,MAAM,mBAAmB,CAAC;AAW3B,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUzE;AAED,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBnD;AAED,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBnD;AAED,wBAAsB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAkBhG;AAED,wBAAsB,kCAAkC,CACtD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,4BAA4B,EAAE,CAAC,CAyDzC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Planu — Ecosystem detector engine (SPEC-374)
|
|
2
|
+
// Pure functions to detect token optimization tools (RTK, Headroom)
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
async function readJsonFile(filePath) {
|
|
6
|
+
try {
|
|
7
|
+
const content = await readFile(filePath, 'utf-8');
|
|
8
|
+
return JSON.parse(content);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function detectRtkHooks(projectPath) {
|
|
15
|
+
const settingsPath = join(projectPath, '.claude', 'settings.json');
|
|
16
|
+
const settings = await readJsonFile(settingsPath);
|
|
17
|
+
if (!settings?.hooks?.PreToolUse) {
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
return settings.hooks.PreToolUse.filter((hook) => {
|
|
21
|
+
const hooksArr = hook.hooks ?? [];
|
|
22
|
+
return hooksArr.some((h) => typeof h === 'string' && h.toLowerCase().includes('rtk'));
|
|
23
|
+
}).length;
|
|
24
|
+
}
|
|
25
|
+
export async function detectHeadroomPackage(projectPath) {
|
|
26
|
+
const pkgPath = join(projectPath, 'package.json');
|
|
27
|
+
const pkg = await readJsonFile(pkgPath);
|
|
28
|
+
if (!pkg) {
|
|
29
|
+
return { installed: false };
|
|
30
|
+
}
|
|
31
|
+
const allDeps = {
|
|
32
|
+
...(pkg.devDependencies ?? {}),
|
|
33
|
+
...(pkg.dependencies ?? {}),
|
|
34
|
+
};
|
|
35
|
+
const headroom = allDeps.headroom;
|
|
36
|
+
const headroomCli = allDeps['@headroom/cli'];
|
|
37
|
+
const version = headroom ?? headroomCli;
|
|
38
|
+
if (version !== undefined) {
|
|
39
|
+
return { installed: true, version };
|
|
40
|
+
}
|
|
41
|
+
return { installed: false };
|
|
42
|
+
}
|
|
43
|
+
export async function detectRtkPackage(projectPath) {
|
|
44
|
+
const pkgPath = join(projectPath, 'package.json');
|
|
45
|
+
const pkg = await readJsonFile(pkgPath);
|
|
46
|
+
if (!pkg) {
|
|
47
|
+
return { installed: false };
|
|
48
|
+
}
|
|
49
|
+
const allDeps = {
|
|
50
|
+
...(pkg.devDependencies ?? {}),
|
|
51
|
+
...(pkg.dependencies ?? {}),
|
|
52
|
+
};
|
|
53
|
+
const rtk = allDeps.rtk;
|
|
54
|
+
const rtkCli = allDeps['@rtk/cli'];
|
|
55
|
+
const version = rtk ?? rtkCli;
|
|
56
|
+
if (version !== undefined) {
|
|
57
|
+
return { installed: true, version };
|
|
58
|
+
}
|
|
59
|
+
return { installed: false };
|
|
60
|
+
}
|
|
61
|
+
export async function getTokenOptimizerStatus(projectPath) {
|
|
62
|
+
const [rtkPkg, headroomPkg, rtkHooks] = await Promise.all([
|
|
63
|
+
detectRtkPackage(projectPath),
|
|
64
|
+
detectHeadroomPackage(projectPath),
|
|
65
|
+
detectRtkHooks(projectPath),
|
|
66
|
+
]);
|
|
67
|
+
return {
|
|
68
|
+
rtk: {
|
|
69
|
+
installed: rtkPkg.installed,
|
|
70
|
+
version: rtkPkg.version,
|
|
71
|
+
hooksConfigured: rtkHooks,
|
|
72
|
+
},
|
|
73
|
+
headroom: {
|
|
74
|
+
installed: headroomPkg.installed,
|
|
75
|
+
version: headroomPkg.version,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export async function buildTokenOptimizerRecommendations(projectPath) {
|
|
80
|
+
const status = await getTokenOptimizerStatus(projectPath);
|
|
81
|
+
const recommendations = [];
|
|
82
|
+
if (!status.rtk.installed) {
|
|
83
|
+
recommendations.push({
|
|
84
|
+
tool: 'rtk',
|
|
85
|
+
installed: false,
|
|
86
|
+
reason: 'RTK (Response Token Killer) filters verbose Claude output via PreToolUse hooks, reducing token usage by 30-60% on large codebases.',
|
|
87
|
+
installCommand: 'npm install --save-dev rtk',
|
|
88
|
+
configExample: JSON.stringify({
|
|
89
|
+
hooks: {
|
|
90
|
+
PreToolUse: [
|
|
91
|
+
{
|
|
92
|
+
matcher: 'Bash',
|
|
93
|
+
hooks: ['npx rtk filter'],
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
}, null, 2),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
recommendations.push({
|
|
102
|
+
tool: 'rtk',
|
|
103
|
+
installed: true,
|
|
104
|
+
reason: `RTK is installed (${status.rtk.version ?? 'unknown version'}). ${status.rtk.hooksConfigured === 0
|
|
105
|
+
? 'No PreToolUse hooks configured yet — add hooks to .claude/settings.json to activate filtering.'
|
|
106
|
+
: `${String(status.rtk.hooksConfigured)} PreToolUse hook(s) configured.`}`,
|
|
107
|
+
installCommand: 'npm install --save-dev rtk',
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (!status.headroom.installed) {
|
|
111
|
+
recommendations.push({
|
|
112
|
+
tool: 'headroom',
|
|
113
|
+
installed: false,
|
|
114
|
+
reason: 'Headroom monitors your context window usage in real-time and warns before you hit the limit, preventing lost work.',
|
|
115
|
+
installCommand: 'npm install --save-dev headroom',
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
recommendations.push({
|
|
120
|
+
tool: 'headroom',
|
|
121
|
+
installed: true,
|
|
122
|
+
reason: `Headroom is installed (${status.headroom.version ?? 'unknown version'}).`,
|
|
123
|
+
installCommand: 'npm install --save-dev headroom',
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return recommendations;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=ecosystem-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecosystem-detector.js","sourceRoot":"","sources":["../../src/engine/ecosystem-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MemoryProvider, MemoryStatusResult, ClaudeJsonConfig } from '../types/index.js';
|
|
2
|
+
export declare function resolveClaudeJsonPath(projectPath: string): string;
|
|
3
|
+
export declare function detectMemoryProvider(config: ClaudeJsonConfig): MemoryProvider;
|
|
4
|
+
export declare function getMemoryStatus(projectPath: string): Promise<MemoryStatusResult>;
|
|
5
|
+
export declare function setupOpenMemory(projectPath: string): Promise<string>;
|
|
6
|
+
export declare function setupMem0Cloud(projectPath: string, apiKey: string): Promise<string>;
|
|
7
|
+
export declare function resetMemoryConfig(projectPath: string): Promise<string>;
|
|
8
|
+
//# sourceMappingURL=memory-config-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-config-generator.d.ts","sourceRoot":"","sources":["../../src/engine/memory-config-generator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAEjB,MAAM,mBAAmB,CAAC;AAe3B,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,gBAAgB,GAAG,cAAc,CAkB7E;AAED,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAWtF;AAED,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmB1E;AAED,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBzF;AAED,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkB5E"}
|