@popoverai/dotrequirements 0.23.0 → 0.24.1
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/README.md +169 -22
- package/dist/cli.js +121 -60
- package/dist/codebase-to-spec/budget.d.ts +53 -0
- package/dist/codebase-to-spec/budget.js +80 -0
- package/dist/codebase-to-spec/cache.d.ts +49 -0
- package/dist/codebase-to-spec/cache.js +54 -0
- package/dist/codebase-to-spec/claude.d.ts +69 -0
- package/dist/codebase-to-spec/claude.js +126 -0
- package/dist/codebase-to-spec/compose.d.ts +49 -0
- package/dist/codebase-to-spec/compose.js +124 -0
- package/dist/codebase-to-spec/edit-loop.d.ts +54 -0
- package/dist/codebase-to-spec/edit-loop.js +195 -0
- package/dist/codebase-to-spec/editor.d.ts +54 -0
- package/dist/codebase-to-spec/editor.js +74 -0
- package/dist/codebase-to-spec/exit-codes.d.ts +40 -0
- package/dist/codebase-to-spec/exit-codes.js +58 -0
- package/dist/codebase-to-spec/fan-out.d.ts +63 -0
- package/dist/codebase-to-spec/fan-out.js +215 -0
- package/dist/codebase-to-spec/interactive.d.ts +30 -0
- package/dist/codebase-to-spec/interactive.js +48 -0
- package/dist/codebase-to-spec/outline-review-loop.d.ts +51 -0
- package/dist/codebase-to-spec/outline-review-loop.js +187 -0
- package/dist/codebase-to-spec/pack.d.ts +51 -0
- package/dist/codebase-to-spec/pack.js +127 -0
- package/dist/codebase-to-spec/planner.d.ts +41 -0
- package/dist/codebase-to-spec/planner.js +76 -0
- package/dist/codebase-to-spec/present.d.ts +94 -0
- package/dist/codebase-to-spec/present.js +288 -0
- package/dist/codebase-to-spec/progress.d.ts +33 -0
- package/dist/codebase-to-spec/progress.js +28 -0
- package/dist/codebase-to-spec/prompts/editor.d.ts +13 -0
- package/dist/codebase-to-spec/prompts/editor.js +57 -0
- package/dist/codebase-to-spec/prompts/outline-reviewer.d.ts +12 -0
- package/dist/codebase-to-spec/prompts/outline-reviewer.js +87 -0
- package/dist/codebase-to-spec/prompts/planner-initial.d.ts +11 -0
- package/dist/codebase-to-spec/prompts/planner-initial.js +125 -0
- package/dist/codebase-to-spec/prompts/planner-revise.d.ts +14 -0
- package/dist/codebase-to-spec/prompts/planner-revise.js +60 -0
- package/dist/codebase-to-spec/prompts/spec-reviewer.d.ts +16 -0
- package/dist/codebase-to-spec/prompts/spec-reviewer.js +96 -0
- package/dist/codebase-to-spec/prompts/specifier.d.ts +12 -0
- package/dist/codebase-to-spec/prompts/specifier.js +100 -0
- package/dist/codebase-to-spec/prompts/style-check.d.ts +12 -0
- package/dist/codebase-to-spec/prompts/style-check.js +78 -0
- package/dist/codebase-to-spec/schemas.d.ts +257 -0
- package/dist/codebase-to-spec/schemas.js +183 -0
- package/dist/codebase-to-spec/skill-install.d.ts +57 -0
- package/dist/codebase-to-spec/skill-install.js +79 -0
- package/dist/codebase-to-spec/slice.d.ts +49 -0
- package/dist/codebase-to-spec/slice.js +111 -0
- package/dist/codebase-to-spec/specifier.d.ts +60 -0
- package/dist/codebase-to-spec/specifier.js +79 -0
- package/dist/codebase-to-spec/style-check.d.ts +29 -0
- package/dist/codebase-to-spec/style-check.js +33 -0
- package/dist/codebase-to-spec/summary.d.ts +51 -0
- package/dist/codebase-to-spec/summary.js +183 -0
- package/dist/codebase-to-spec/validate.d.ts +46 -0
- package/dist/codebase-to-spec/validate.js +130 -0
- package/dist/commands/acceptance-test.d.ts +6 -0
- package/dist/commands/{browsertest.js → acceptance-test.js} +36 -29
- package/dist/commands/ai-setup.d.ts +5 -0
- package/dist/commands/ai-setup.js +441 -0
- package/dist/commands/codebase-to-spec/compose.d.ts +14 -0
- package/dist/commands/codebase-to-spec/compose.js +57 -0
- package/dist/commands/codebase-to-spec/edit-loop.d.ts +16 -0
- package/dist/commands/codebase-to-spec/edit-loop.js +83 -0
- package/dist/commands/codebase-to-spec/fan-out.d.ts +19 -0
- package/dist/commands/codebase-to-spec/fan-out.js +77 -0
- package/dist/commands/codebase-to-spec/index.d.ts +9 -0
- package/dist/commands/codebase-to-spec/index.js +135 -0
- package/dist/commands/codebase-to-spec/pack.d.ts +22 -0
- package/dist/commands/codebase-to-spec/pack.js +76 -0
- package/dist/commands/codebase-to-spec/plan-loop.d.ts +26 -0
- package/dist/commands/codebase-to-spec/plan-loop.js +105 -0
- package/dist/commands/codebase-to-spec/present.d.ts +21 -0
- package/dist/commands/codebase-to-spec/present.js +92 -0
- package/dist/commands/codebase-to-spec/run.d.ts +20 -0
- package/dist/commands/codebase-to-spec/run.js +85 -0
- package/dist/commands/codebase-to-spec/skill-install.d.ts +20 -0
- package/dist/commands/codebase-to-spec/skill-install.js +51 -0
- package/dist/commands/codebase-to-spec/specify-area.d.ts +18 -0
- package/dist/commands/codebase-to-spec/specify-area.js +82 -0
- package/dist/commands/codebase-to-spec/style-check.d.ts +15 -0
- package/dist/commands/codebase-to-spec/style-check.js +42 -0
- package/dist/commands/codebase-to-spec/validate.d.ts +18 -0
- package/dist/commands/codebase-to-spec/validate.js +38 -0
- package/dist/commands/create-requirement-document.d.ts +2 -0
- package/dist/commands/create-requirement-document.js +41 -0
- package/dist/commands/finalize.js +7 -7
- package/dist/commands/get.d.ts +2 -0
- package/dist/commands/get.js +55 -0
- package/dist/commands/init.js +132 -117
- package/dist/commands/link.js +27 -27
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.js +43 -0
- package/dist/commands/mcp.js +1 -1
- package/dist/commands/prepare.js +4 -4
- package/dist/commands/pull.js +116 -121
- package/dist/commands/push.js +106 -112
- package/dist/commands/report.d.ts +6 -2
- package/dist/commands/report.js +177 -122
- package/dist/commands/requirements-for.d.ts +2 -0
- package/dist/commands/requirements-for.js +29 -0
- package/dist/commands/review-test.d.ts +2 -0
- package/dist/commands/review-test.js +75 -0
- package/dist/commands/search.d.ts +6 -0
- package/dist/commands/search.js +39 -0
- package/dist/commands/style-check.d.ts +7 -0
- package/dist/commands/style-check.js +75 -0
- package/dist/commands/tests-for.d.ts +2 -0
- package/dist/commands/tests-for.js +80 -0
- package/dist/commands/validate.d.ts +6 -0
- package/dist/commands/validate.js +72 -0
- package/dist/config.js +1 -1
- package/dist/convex.d.ts +34 -22
- package/dist/convex.js +38 -22
- package/dist/harness/cache.d.ts +1 -5
- package/dist/harness/cache.js +49 -59
- package/dist/harness/convexReporting.d.ts +1 -1
- package/dist/harness/convexReporting.js +9 -7
- package/dist/harness/coverageCache.js +3 -3
- package/dist/harness/finalize.js +59 -46
- package/dist/harness/index.d.ts +6 -7
- package/dist/harness/index.js +9 -10
- package/dist/harness/prepare.js +6 -5
- package/dist/harness/requirementsLoader.d.ts +2 -2
- package/dist/harness/requirementsLoader.js +13 -35
- package/dist/harness/tracking.js +18 -18
- package/dist/harness/types.d.ts +1 -1
- package/dist/mcp/convexClient.d.ts +0 -39
- package/dist/mcp/convexClient.js +2 -107
- package/dist/mcp/handlers/authoring.d.ts +1 -1
- package/dist/mcp/handlers/authoring.js +30 -234
- package/dist/mcp/handlers/debug.d.ts +2 -3
- package/dist/mcp/handlers/debug.js +10 -10
- package/dist/mcp/handlers/get.d.ts +1 -1
- package/dist/mcp/handlers/get.js +11 -10
- package/dist/mcp/handlers/index.d.ts +20 -20
- package/dist/mcp/handlers/index.js +10 -10
- package/dist/mcp/handlers/list.d.ts +4 -33
- package/dist/mcp/handlers/list.js +16 -38
- package/dist/mcp/handlers/push.d.ts +1 -1
- package/dist/mcp/handlers/push.js +28 -18
- package/dist/mcp/handlers/report.d.ts +16 -0
- package/dist/mcp/handlers/report.js +134 -0
- package/dist/mcp/handlers/review.d.ts +1 -1
- package/dist/mcp/handlers/review.js +40 -59
- package/dist/mcp/handlers/search.d.ts +1 -1
- package/dist/mcp/handlers/search.js +7 -9
- package/dist/mcp/handlers/test-mapping.d.ts +1 -1
- package/dist/mcp/handlers/test-mapping.js +14 -14
- package/dist/mcp/handlers/types.d.ts +3 -3
- package/dist/mcp/handlers/types.js +2 -2
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +147 -167
- package/dist/push/core.d.ts +2 -2
- package/dist/push/core.js +20 -20
- package/dist/push/index.d.ts +1 -1
- package/dist/push/index.js +2 -2
- package/dist/requirements/cloud-ai.d.ts +57 -0
- package/dist/requirements/cloud-ai.js +104 -0
- package/dist/requirements/cloud-coverage.d.ts +41 -0
- package/dist/requirements/cloud-coverage.js +60 -0
- package/dist/requirements/coverage.d.ts +45 -0
- package/dist/requirements/coverage.js +114 -0
- package/dist/{mcp → requirements}/grep.d.ts +10 -1
- package/dist/{mcp → requirements}/grep.js +89 -44
- package/dist/{mcp/requirements.d.ts → requirements/index.d.ts} +19 -3
- package/dist/{mcp/requirements.js → requirements/index.js} +54 -35
- package/dist/requirements/style-guide.d.ts +67 -0
- package/dist/requirements/style-guide.js +299 -0
- package/dist/{mcp → requirements}/testCodeExtractor.js +24 -26
- package/dist/schema/browser.d.ts +8 -8
- package/dist/schema/browser.js +13 -15
- package/dist/schema/builder.d.ts +1 -1
- package/dist/schema/builder.js +13 -44
- package/dist/schema/conversions.d.ts +2 -2
- package/dist/schema/conversions.js +11 -11
- package/dist/schema/index.d.ts +9 -9
- package/dist/schema/index.js +15 -15
- package/dist/schema/parser-core.d.ts +1 -1
- package/dist/schema/parser-core.js +23 -22
- package/dist/schema/parser.d.ts +3 -3
- package/dist/schema/parser.js +27 -31
- package/dist/schema/resolver.d.ts +1 -1
- package/dist/schema/resolver.js +9 -9
- package/dist/schema/scenario.d.ts +1 -1
- package/dist/schema/scenario.js +1 -1
- package/dist/schema/schemas.d.ts +3 -3
- package/dist/schema/schemas.js +41 -28
- package/dist/schema/test-schema.js +27 -27
- package/dist/templates/context-file-section.md +3 -2
- package/dist/templates/example-requirements.js +1 -1
- package/dist/templates/example-requirements.ts +3 -1
- package/dist/templates/requirements-readme.js +1 -1
- package/dist/templates/requirements-readme.ts +1 -1
- package/dist/templates/skills/codebase-to-spec/SKILL.md +118 -0
- package/dist/utils/brand.js +3 -3
- package/dist/utils/browser-launch.js +4 -4
- package/dist/utils/context-file.d.ts +1 -1
- package/dist/utils/context-file.js +26 -26
- package/dist/utils/env.js +7 -7
- package/dist/utils/gitignore.js +7 -7
- package/dist/utils/oauth-callback-server.d.ts +1 -1
- package/dist/utils/oauth-callback-server.js +27 -25
- package/dist/utils/oauth-flow.js +32 -29
- package/dist/utils/project-discovery.d.ts +3 -3
- package/dist/utils/project-discovery.js +18 -17
- package/dist/utils/project-name.js +8 -8
- package/dist/utils/project-selector.d.ts +1 -1
- package/dist/utils/project-selector.js +24 -21
- package/dist/utils/project-settings.d.ts +1 -1
- package/dist/utils/project-settings.js +24 -22
- package/dist/utils/templates.js +6 -6
- package/package.json +3 -2
- package/dist/commands/browsertest.d.ts +0 -6
- package/dist/commands/login.d.ts +0 -12
- package/dist/commands/login.js +0 -117
- package/dist/commands/logout.d.ts +0 -5
- package/dist/commands/logout.js +0 -17
- package/dist/commands/mcp-setup.d.ts +0 -5
- package/dist/commands/mcp-setup.js +0 -431
- package/dist/commands/test.d.ts +0 -6
- package/dist/commands/test.js +0 -78
- package/dist/mcp/handlers/coverage.d.ts +0 -44
- package/dist/mcp/handlers/coverage.js +0 -105
- package/dist/mcp/types.d.ts +0 -27
- package/dist/mcp/types.js +0 -2
- package/dist/utils/local-project.d.ts +0 -31
- package/dist/utils/local-project.js +0 -33
- package/dist/utils/token-refresh.d.ts +0 -24
- package/dist/utils/token-refresh.js +0 -69
- package/dist/utils/token-storage.d.ts +0 -31
- package/dist/utils/token-storage.js +0 -57
- /package/dist/{mcp → requirements}/testCodeExtractor.d.ts +0 -0
|
@@ -1,431 +0,0 @@
|
|
|
1
|
-
import { execSync } from 'child_process';
|
|
2
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
3
|
-
import { homedir } from 'os';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
import prompts from 'prompts';
|
|
6
|
-
import { loadTemplate } from '../utils/templates.js';
|
|
7
|
-
import { brand } from '../utils/brand.js';
|
|
8
|
-
import { getContextFileName, findGitRoot, findDotrequirementsSection, appendOrUpdateSection, buildNoGitRepoMessage, } from '../utils/context-file.js';
|
|
9
|
-
/**
|
|
10
|
-
* Load the context file section template
|
|
11
|
-
*/
|
|
12
|
-
function loadContextFileSection() {
|
|
13
|
-
return loadTemplate('context-file-section.md');
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Install workflow guidance to the appropriate context file for a platform
|
|
17
|
-
*/
|
|
18
|
-
async function installContextFileSection(platform) {
|
|
19
|
-
const fileName = getContextFileName(platform);
|
|
20
|
-
if (!fileName) {
|
|
21
|
-
console.error(`\n❌ Unknown platform: ${platform}`);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const gitRoot = await findGitRoot();
|
|
25
|
-
if (!gitRoot) {
|
|
26
|
-
console.log('\n' + buildNoGitRepoMessage(fileName) + '\n');
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
const contextFilePath = join(gitRoot, fileName);
|
|
30
|
-
const sectionContent = loadContextFileSection();
|
|
31
|
-
// Check if file exists and has existing section
|
|
32
|
-
let existingSection = null;
|
|
33
|
-
if (existsSync(contextFilePath)) {
|
|
34
|
-
const content = readFileSync(contextFilePath, 'utf-8');
|
|
35
|
-
const section = findDotrequirementsSection(content);
|
|
36
|
-
if (section) {
|
|
37
|
-
existingSection = section.content;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
// Prompt user
|
|
41
|
-
const action = existingSection ? 'Update' : existsSync(contextFilePath) ? 'Add to' : 'Create';
|
|
42
|
-
const response = await prompts({
|
|
43
|
-
type: 'confirm',
|
|
44
|
-
name: 'install',
|
|
45
|
-
message: `${action} ${fileName} with dotrequirements workflow guidance?`,
|
|
46
|
-
initial: true,
|
|
47
|
-
});
|
|
48
|
-
if (!response.install) {
|
|
49
|
-
console.log('');
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
// If updating, show what will change
|
|
53
|
-
if (existingSection) {
|
|
54
|
-
const confirmUpdate = await prompts({
|
|
55
|
-
type: 'confirm',
|
|
56
|
-
name: 'confirm',
|
|
57
|
-
message: 'Existing dotrequirements section found. Replace it?',
|
|
58
|
-
initial: true,
|
|
59
|
-
});
|
|
60
|
-
if (!confirmUpdate.confirm) {
|
|
61
|
-
console.log(' Skipped.\n');
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
try {
|
|
66
|
-
const result = appendOrUpdateSection(contextFilePath, sectionContent);
|
|
67
|
-
const actionVerb = result.action === 'created' ? 'Created' : result.action === 'appended' ? 'Added to' : 'Updated';
|
|
68
|
-
console.log(`✅ ${actionVerb} ${contextFilePath}\n`);
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
console.error(`❌ Failed to update ${fileName}`);
|
|
72
|
-
console.log(` Error: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* MCP setup command - configures the MCP server for AI assistants
|
|
77
|
-
*/
|
|
78
|
-
export async function mcpSetupCommand() {
|
|
79
|
-
console.log(`🔧 Setting up ${brand} MCP server\n`);
|
|
80
|
-
// Interactive client selector
|
|
81
|
-
const response = await prompts({
|
|
82
|
-
type: 'select',
|
|
83
|
-
name: 'client',
|
|
84
|
-
message: 'Which AI assistant are you using?',
|
|
85
|
-
choices: [
|
|
86
|
-
{ title: 'Claude Code', value: 'claude-code' },
|
|
87
|
-
{ title: 'Claude Desktop', value: 'claude-desktop' },
|
|
88
|
-
{ title: 'Cursor', value: 'cursor' },
|
|
89
|
-
{ title: 'Google Antigravity', value: 'antigravity' },
|
|
90
|
-
{ title: 'OpenAI Codex', value: 'codex' },
|
|
91
|
-
{ title: 'GitHub Copilot', value: 'github-copilot' },
|
|
92
|
-
{ title: 'Other (custom path)', value: 'other' },
|
|
93
|
-
],
|
|
94
|
-
initial: 0,
|
|
95
|
-
});
|
|
96
|
-
if (!response.client) {
|
|
97
|
-
console.log('\nSetup cancelled.');
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
switch (response.client) {
|
|
101
|
-
case 'claude-code':
|
|
102
|
-
await setupClaudeCode();
|
|
103
|
-
break;
|
|
104
|
-
case 'claude-desktop':
|
|
105
|
-
await setupClaudeDesktop();
|
|
106
|
-
break;
|
|
107
|
-
case 'cursor':
|
|
108
|
-
await setupCursor();
|
|
109
|
-
break;
|
|
110
|
-
case 'antigravity':
|
|
111
|
-
await setupAntigravity();
|
|
112
|
-
break;
|
|
113
|
-
case 'codex':
|
|
114
|
-
await setupCodex();
|
|
115
|
-
break;
|
|
116
|
-
case 'github-copilot':
|
|
117
|
-
await setupGitHubCopilot();
|
|
118
|
-
break;
|
|
119
|
-
case 'other':
|
|
120
|
-
await setupOther();
|
|
121
|
-
break;
|
|
122
|
-
default:
|
|
123
|
-
console.log(`\n❌ ${response.client} is not yet supported.`);
|
|
124
|
-
console.log('Please refer to the documentation for manual setup.');
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
async function setupClaudeCode() {
|
|
128
|
-
console.log('\n📦 Configuring MCP for Claude Code...\n');
|
|
129
|
-
const command = `claude mcp add-json dotrequirements '{"type":"stdio","command":"npx","args":["-y","@popoverai/dotrequirements","mcp"]}'`;
|
|
130
|
-
let mcpConfigured = false;
|
|
131
|
-
try {
|
|
132
|
-
execSync(command, { stdio: 'pipe' });
|
|
133
|
-
console.log('✅ MCP configured successfully for Claude Code!');
|
|
134
|
-
mcpConfigured = true;
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
const stderr = error.stderr?.toString() || '';
|
|
138
|
-
const errorMessage = error.message || '';
|
|
139
|
-
const combinedError = stderr + errorMessage;
|
|
140
|
-
if (combinedError.includes('already exists')) {
|
|
141
|
-
console.log('✅ MCP server already configured for Claude Code');
|
|
142
|
-
mcpConfigured = true;
|
|
143
|
-
}
|
|
144
|
-
else {
|
|
145
|
-
console.error('❌ Failed to configure MCP automatically.');
|
|
146
|
-
console.log('\nYou can manually run:');
|
|
147
|
-
console.log(` ${command}`);
|
|
148
|
-
if (stderr) {
|
|
149
|
-
console.log(`\nError: ${stderr}`);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (mcpConfigured) {
|
|
154
|
-
console.log('\n⚠️ Important: Restart Claude Code for changes to take effect.');
|
|
155
|
-
console.log('\nYou can now ask your AI assistant to help write requirements!\n');
|
|
156
|
-
await installContextFileSection('claude-code');
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
async function setupClaudeDesktop() {
|
|
160
|
-
console.log('\n📦 Configuring MCP for Claude Desktop...\n');
|
|
161
|
-
// Determine config path based on OS
|
|
162
|
-
const platform = process.platform;
|
|
163
|
-
let configPath;
|
|
164
|
-
let configDir;
|
|
165
|
-
if (platform === 'darwin') {
|
|
166
|
-
configDir = join(homedir(), 'Library', 'Application Support', 'Claude');
|
|
167
|
-
configPath = join(configDir, 'claude_desktop_config.json');
|
|
168
|
-
}
|
|
169
|
-
else if (platform === 'win32') {
|
|
170
|
-
const appData = process.env.APPDATA || join(homedir(), 'AppData', 'Roaming');
|
|
171
|
-
configDir = join(appData, 'Claude');
|
|
172
|
-
configPath = join(configDir, 'claude_desktop_config.json');
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
console.error('❌ Claude Desktop is only supported on macOS and Windows.');
|
|
176
|
-
console.log('\nFor Linux, please manually configure the MCP server.');
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
const mcpServerConfig = {
|
|
180
|
-
command: 'npx',
|
|
181
|
-
args: ['-y', '@popoverai/dotrequirements', 'mcp'],
|
|
182
|
-
env: {
|
|
183
|
-
REQUIREMENTS_DIR: process.cwd(),
|
|
184
|
-
},
|
|
185
|
-
};
|
|
186
|
-
try {
|
|
187
|
-
if (!existsSync(configDir)) {
|
|
188
|
-
console.log('Creating Claude Desktop config directory...');
|
|
189
|
-
mkdirSync(configDir, { recursive: true });
|
|
190
|
-
}
|
|
191
|
-
let config = {};
|
|
192
|
-
if (existsSync(configPath)) {
|
|
193
|
-
try {
|
|
194
|
-
const existingContent = readFileSync(configPath, 'utf-8');
|
|
195
|
-
if (existingContent.trim()) {
|
|
196
|
-
config = JSON.parse(existingContent);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
catch (parseError) {
|
|
200
|
-
console.log('⚠️ Existing config file is invalid, creating fresh config...');
|
|
201
|
-
config = {};
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (!config.mcpServers) {
|
|
205
|
-
config.mcpServers = {};
|
|
206
|
-
}
|
|
207
|
-
config.mcpServers['dotrequirements'] = mcpServerConfig;
|
|
208
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
209
|
-
console.log(`✅ MCP configured successfully!`);
|
|
210
|
-
console.log(` Config file: ${configPath}`);
|
|
211
|
-
console.log(` REQUIREMENTS_DIR: ${process.cwd()}\n`);
|
|
212
|
-
console.log('⚠️ Important: Quit and restart Claude Desktop for changes to take effect.');
|
|
213
|
-
console.log(' (Cmd+Q on macOS, not just close the window)\n');
|
|
214
|
-
console.log('You can now ask Claude Desktop to help write requirements!\n');
|
|
215
|
-
// Claude Desktop doesn't use skills like Claude Code, so we skip that step
|
|
216
|
-
}
|
|
217
|
-
catch (error) {
|
|
218
|
-
console.error('❌ Failed to configure MCP automatically.');
|
|
219
|
-
console.log(`\nError: ${error instanceof Error ? error.message : String(error)}`);
|
|
220
|
-
console.log('\nYou can manually edit the config file at:');
|
|
221
|
-
console.log(` ${configPath}\n`);
|
|
222
|
-
console.log('Add the following configuration:');
|
|
223
|
-
const manualConfig = {
|
|
224
|
-
mcpServers: {
|
|
225
|
-
dotrequirements: mcpServerConfig,
|
|
226
|
-
},
|
|
227
|
-
};
|
|
228
|
-
console.log(JSON.stringify(manualConfig, null, 2));
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
async function setupCursor() {
|
|
232
|
-
console.log('\n📦 Configuring MCP for Cursor (project-specific)...\n');
|
|
233
|
-
const configPath = join(process.cwd(), '.cursor', 'mcp.json');
|
|
234
|
-
const configDir = join(process.cwd(), '.cursor');
|
|
235
|
-
const mcpServerConfig = {
|
|
236
|
-
command: 'npx',
|
|
237
|
-
args: ['-y', '@popoverai/dotrequirements', 'mcp'],
|
|
238
|
-
};
|
|
239
|
-
try {
|
|
240
|
-
if (!existsSync(configDir)) {
|
|
241
|
-
console.log('Creating Cursor config directory...');
|
|
242
|
-
mkdirSync(configDir, { recursive: true });
|
|
243
|
-
}
|
|
244
|
-
let config = {};
|
|
245
|
-
if (existsSync(configPath)) {
|
|
246
|
-
try {
|
|
247
|
-
const existingContent = readFileSync(configPath, 'utf-8');
|
|
248
|
-
if (existingContent.trim()) {
|
|
249
|
-
config = JSON.parse(existingContent);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
catch (parseError) {
|
|
253
|
-
console.log('⚠️ Existing config file is invalid, creating fresh config...');
|
|
254
|
-
config = {};
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
if (!config.mcpServers) {
|
|
258
|
-
config.mcpServers = {};
|
|
259
|
-
}
|
|
260
|
-
config.mcpServers['dotrequirements'] = mcpServerConfig;
|
|
261
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
262
|
-
console.log(`✅ MCP configured successfully!`);
|
|
263
|
-
console.log(` Config file: ${configPath}\n`);
|
|
264
|
-
console.log('⚠️ Important: Reload or restart Cursor for changes to take effect.');
|
|
265
|
-
console.log('\nYou can now ask your AI assistant to help write requirements!\n');
|
|
266
|
-
await installContextFileSection('cursor');
|
|
267
|
-
}
|
|
268
|
-
catch (error) {
|
|
269
|
-
console.error('❌ Failed to configure MCP automatically.');
|
|
270
|
-
console.log(`\nError: ${error instanceof Error ? error.message : String(error)}`);
|
|
271
|
-
console.log('\nYou can manually edit the config file at:');
|
|
272
|
-
console.log(` ${configPath}\n`);
|
|
273
|
-
console.log('Add the following configuration:');
|
|
274
|
-
const manualConfig = {
|
|
275
|
-
mcpServers: {
|
|
276
|
-
dotrequirements: mcpServerConfig,
|
|
277
|
-
},
|
|
278
|
-
};
|
|
279
|
-
console.log(JSON.stringify(manualConfig, null, 2));
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
async function setupAntigravity() {
|
|
283
|
-
console.log('\n📦 Configuring MCP for Google Antigravity...\n');
|
|
284
|
-
const configPath = join(homedir(), '.gemini', 'antigravity', 'mcp_config.json');
|
|
285
|
-
const configDir = join(homedir(), '.gemini', 'antigravity');
|
|
286
|
-
// Check if we're in a dotrequirements project directory
|
|
287
|
-
const envLocalPath = join(process.cwd(), '.env.local');
|
|
288
|
-
let projectId = null;
|
|
289
|
-
let projectPath = null;
|
|
290
|
-
if (existsSync(envLocalPath)) {
|
|
291
|
-
try {
|
|
292
|
-
const envContent = readFileSync(envLocalPath, 'utf-8');
|
|
293
|
-
const lines = envContent.split('\n');
|
|
294
|
-
for (const line of lines) {
|
|
295
|
-
const trimmed = line.trim();
|
|
296
|
-
if (trimmed.startsWith('DOTREQUIREMENTS_PROJECT_ID=')) {
|
|
297
|
-
projectId = trimmed.split('=')[1]?.trim().replace(/['"]/g, '');
|
|
298
|
-
projectPath = process.cwd();
|
|
299
|
-
break;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
catch (error) {
|
|
304
|
-
// .env.local exists but couldn't read it - continue with global setup
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
try {
|
|
308
|
-
if (!existsSync(configDir)) {
|
|
309
|
-
console.log('Creating Antigravity config directory...');
|
|
310
|
-
mkdirSync(configDir, { recursive: true });
|
|
311
|
-
}
|
|
312
|
-
let config = {};
|
|
313
|
-
if (existsSync(configPath)) {
|
|
314
|
-
try {
|
|
315
|
-
const existingContent = readFileSync(configPath, 'utf-8');
|
|
316
|
-
if (existingContent.trim()) {
|
|
317
|
-
config = JSON.parse(existingContent);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
catch (parseError) {
|
|
321
|
-
console.log('⚠️ Existing config file is invalid, creating fresh config...');
|
|
322
|
-
config = {};
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
if (!config.mcpServers) {
|
|
326
|
-
config.mcpServers = {};
|
|
327
|
-
}
|
|
328
|
-
if (!config.mcpServers['dotrequirements']) {
|
|
329
|
-
config.mcpServers['dotrequirements'] = {
|
|
330
|
-
command: 'npx',
|
|
331
|
-
args: ['-y', '@popoverai/dotrequirements', 'mcp'],
|
|
332
|
-
env: {},
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
const dotreqServer = config.mcpServers['dotrequirements'];
|
|
336
|
-
if (!dotreqServer.env) {
|
|
337
|
-
dotreqServer.env = {};
|
|
338
|
-
}
|
|
339
|
-
if (projectId && projectPath) {
|
|
340
|
-
const envKey = `PROJ_${projectId}`;
|
|
341
|
-
dotreqServer.env[envKey] = projectPath;
|
|
342
|
-
console.log(`✅ Added project to MCP config: ${envKey}`);
|
|
343
|
-
console.log(` Path: ${projectPath}\n`);
|
|
344
|
-
}
|
|
345
|
-
else {
|
|
346
|
-
console.log(`ℹ️ Not in a ${brand} project directory (no .env.local with DOTREQUIREMENTS_PROJECT_ID found)`);
|
|
347
|
-
console.log(' Setting up global MCP server only.\n');
|
|
348
|
-
}
|
|
349
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
350
|
-
console.log(`✅ MCP configured successfully!`);
|
|
351
|
-
console.log(` Config file: ${configPath}\n`);
|
|
352
|
-
console.log('⚠️ Important: Reload or restart Google Antigravity for changes to take effect.');
|
|
353
|
-
console.log('\nYou can now ask your AI assistant to help write requirements!');
|
|
354
|
-
if (projectId) {
|
|
355
|
-
console.log(`\n💡 To add more projects, run \`dotreq mcp-setup\` from each project directory.\n`);
|
|
356
|
-
}
|
|
357
|
-
else {
|
|
358
|
-
console.log('');
|
|
359
|
-
}
|
|
360
|
-
await installContextFileSection('antigravity');
|
|
361
|
-
}
|
|
362
|
-
catch (error) {
|
|
363
|
-
console.error('❌ Failed to configure MCP automatically.');
|
|
364
|
-
console.log(`\nError: ${error instanceof Error ? error.message : String(error)}`);
|
|
365
|
-
console.log('\nYou can manually edit the config file at:');
|
|
366
|
-
console.log(` ${configPath}`);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
async function setupCodex() {
|
|
370
|
-
console.log('\n📦 Configuring MCP for OpenAI Codex...\n');
|
|
371
|
-
const command = `codex mcp add dotrequirements -- npx -y @popoverai/dotrequirements mcp`;
|
|
372
|
-
try {
|
|
373
|
-
execSync(command, { stdio: 'inherit' });
|
|
374
|
-
console.log('\n✅ MCP configured successfully for Codex!');
|
|
375
|
-
console.log('\n⚠️ Important: Restart Codex for changes to take effect.');
|
|
376
|
-
console.log('\nYou can now ask your AI assistant to help write requirements!\n');
|
|
377
|
-
await installContextFileSection('codex');
|
|
378
|
-
}
|
|
379
|
-
catch (error) {
|
|
380
|
-
console.error('\n❌ Failed to configure MCP automatically.');
|
|
381
|
-
console.log('\nYou can manually run:');
|
|
382
|
-
console.log(` ${command}`);
|
|
383
|
-
console.log('\nOr manually edit ~/.codex/config.toml and add:');
|
|
384
|
-
console.log('[mcp_servers.dotrequirements]');
|
|
385
|
-
console.log('command = "npx"');
|
|
386
|
-
console.log('args = ["-y", "@popoverai/dotrequirements", "mcp"]');
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
async function setupGitHubCopilot() {
|
|
390
|
-
console.log('\n📦 Configuring skills for GitHub Copilot...\n');
|
|
391
|
-
console.log('ℹ️ GitHub Copilot discovers MCP servers from your IDE configuration.');
|
|
392
|
-
console.log(' Please configure the MCP server in VS Code settings or GitHub settings.\n');
|
|
393
|
-
console.log(' MCP server command: npx -y @popoverai/dotrequirements mcp\n');
|
|
394
|
-
await installContextFileSection('github-copilot');
|
|
395
|
-
}
|
|
396
|
-
async function setupOther() {
|
|
397
|
-
console.log('\n📦 Custom Context File Setup\n');
|
|
398
|
-
console.log('ℹ️ Workflow guidance is added to a context file at your project root.');
|
|
399
|
-
console.log(' Common file names by platform:');
|
|
400
|
-
console.log(' - CLAUDE.md (Claude Code)');
|
|
401
|
-
console.log(' - AGENTS.md (Cursor, Codex, GitHub Copilot)');
|
|
402
|
-
console.log(' - GEMINI.md (Antigravity)\n');
|
|
403
|
-
const response = await prompts({
|
|
404
|
-
type: 'select',
|
|
405
|
-
name: 'file',
|
|
406
|
-
message: 'Which context file should we update?',
|
|
407
|
-
choices: [
|
|
408
|
-
{ title: 'AGENTS.md (most compatible)', value: 'AGENTS.md' },
|
|
409
|
-
{ title: 'CLAUDE.md', value: 'CLAUDE.md' },
|
|
410
|
-
{ title: 'GEMINI.md', value: 'GEMINI.md' },
|
|
411
|
-
],
|
|
412
|
-
initial: 0,
|
|
413
|
-
});
|
|
414
|
-
if (!response.file) {
|
|
415
|
-
console.log('\nSetup cancelled.');
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
console.log('\n📝 MCP Server Setup\n');
|
|
419
|
-
console.log('Configure your AI assistant to run the MCP server:');
|
|
420
|
-
console.log(' Command: npx');
|
|
421
|
-
console.log(' Args: -y @popoverai/dotrequirements mcp\n');
|
|
422
|
-
// Determine platform based on file choice for the install function
|
|
423
|
-
const platformMap = {
|
|
424
|
-
'CLAUDE.md': 'claude-code',
|
|
425
|
-
'AGENTS.md': 'cursor', // Any AGENTS.md platform works
|
|
426
|
-
'GEMINI.md': 'antigravity',
|
|
427
|
-
};
|
|
428
|
-
const platform = platformMap[response.file];
|
|
429
|
-
await installContextFileSection(platform);
|
|
430
|
-
}
|
|
431
|
-
//# sourceMappingURL=mcp-setup.js.map
|
package/dist/commands/test.d.ts
DELETED
package/dist/commands/test.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { parseRequirementsFromFile } from '../schema/index.js';
|
|
4
|
-
export async function testCommand(options) {
|
|
5
|
-
try {
|
|
6
|
-
console.log('Parsing and validating requirements...');
|
|
7
|
-
const requirementsDir = path.join(process.cwd(), '.requirements');
|
|
8
|
-
if (!fs.existsSync(requirementsDir)) {
|
|
9
|
-
console.error('Error: .requirements/ directory not found.');
|
|
10
|
-
console.log('Run "dotrequirements pull" first to sync requirements.');
|
|
11
|
-
process.exit(1);
|
|
12
|
-
}
|
|
13
|
-
// Get files to test
|
|
14
|
-
let files;
|
|
15
|
-
if (options.file) {
|
|
16
|
-
files = [options.file];
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
files = fs
|
|
20
|
-
.readdirSync(requirementsDir)
|
|
21
|
-
.filter((f) => f.endsWith('.requirements.md'))
|
|
22
|
-
.map((f) => path.join(requirementsDir, f));
|
|
23
|
-
}
|
|
24
|
-
if (files.length === 0) {
|
|
25
|
-
console.log('No Markdown requirements files found to test.');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
let totalRequirements = 0;
|
|
29
|
-
let passCount = 0;
|
|
30
|
-
let failCount = 0;
|
|
31
|
-
for (const filePath of files) {
|
|
32
|
-
const fileName = path.basename(filePath);
|
|
33
|
-
console.log(`\nTesting: ${fileName}`);
|
|
34
|
-
try {
|
|
35
|
-
// Parse and validate using shared schema module
|
|
36
|
-
const { metadata, requirements } = parseRequirementsFromFile(filePath);
|
|
37
|
-
// Count total requirements (root + all descendants)
|
|
38
|
-
let count = 0;
|
|
39
|
-
for (const req of requirements) {
|
|
40
|
-
count += countRequirementsInTree(req);
|
|
41
|
-
}
|
|
42
|
-
totalRequirements += count;
|
|
43
|
-
console.log(` ✓ Valid structure (${count} requirement(s))`);
|
|
44
|
-
console.log(` ✓ Version: ${metadata.version}`);
|
|
45
|
-
console.log(` ✓ Last sync: ${metadata.pulledAt}`);
|
|
46
|
-
passCount++;
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
console.error(` ✗ Validation failed:`, error);
|
|
50
|
-
failCount++;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
console.log(`\n${'='.repeat(50)}`);
|
|
54
|
-
console.log(`Total files: ${files.length}`);
|
|
55
|
-
console.log(`Passed: ${passCount}`);
|
|
56
|
-
console.log(`Failed: ${failCount}`);
|
|
57
|
-
console.log(`Total requirements: ${totalRequirements}`);
|
|
58
|
-
if (failCount > 0) {
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
// Re-throw to let the CLI error handler display it cleanly
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Recursively count requirements in a tree (1 for root + all descendants)
|
|
69
|
-
*/
|
|
70
|
-
function countRequirementsInTree(node) {
|
|
71
|
-
let count = 1; // Count this node
|
|
72
|
-
// Count all children
|
|
73
|
-
for (const child of node.children) {
|
|
74
|
-
count += countRequirementsInTree(child);
|
|
75
|
-
}
|
|
76
|
-
return count;
|
|
77
|
-
}
|
|
78
|
-
//# sourceMappingURL=test.js.map
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Coverage handlers for MCP tools
|
|
3
|
-
*
|
|
4
|
-
* Provides cloud coverage query functionality:
|
|
5
|
-
* - get_requirement_coverage: Coverage for a specific requirement
|
|
6
|
-
* - get_project_coverage_summary: Project-wide coverage summary
|
|
7
|
-
*/
|
|
8
|
-
import type { HandlerContext, ToolResponse } from './types.js';
|
|
9
|
-
/**
|
|
10
|
-
* Arguments for get_requirement_coverage tool
|
|
11
|
-
*/
|
|
12
|
-
export interface GetRequirementCoverageArgs {
|
|
13
|
-
requirementKey: string;
|
|
14
|
-
projectId?: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Arguments for get_project_coverage_summary tool
|
|
18
|
-
*/
|
|
19
|
-
export interface GetProjectCoverageSummaryArgs {
|
|
20
|
-
branch?: string;
|
|
21
|
-
sinceTimestamp?: number;
|
|
22
|
-
projectId?: string;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Handler for get_requirement_coverage tool
|
|
26
|
-
*
|
|
27
|
-
* Requirements covered:
|
|
28
|
-
* - MCP-COVERAGE-1.0: When credentials are valid, the response shows when the requirement was last tested
|
|
29
|
-
* - MCP-COVERAGE-1.1: The response includes the most recent branch and test file where coverage was recorded
|
|
30
|
-
* - MCP-COVERAGE-1.2: When the requirement has no coverage records, the response indicates this
|
|
31
|
-
* - MCP-COVERAGE-1.3: When credentials are missing or invalid, an error explains how to authenticate
|
|
32
|
-
*/
|
|
33
|
-
export declare function handleGetRequirementCoverage(args: GetRequirementCoverageArgs, context: HandlerContext): Promise<ToolResponse>;
|
|
34
|
-
/**
|
|
35
|
-
* Handler for get_project_coverage_summary tool
|
|
36
|
-
*
|
|
37
|
-
* Requirements covered:
|
|
38
|
-
* - MCP-COVERAGE-2.0: The response summarizes which requirements have been tested and which have not
|
|
39
|
-
* - MCP-COVERAGE-2.1: When a branch filter is provided, coverage results include only records from that branch
|
|
40
|
-
* - MCP-COVERAGE-2.2: When sinceTimestamp is provided, only coverage recorded after that time is included
|
|
41
|
-
* - MCP-COVERAGE-2.3: When credentials are missing or invalid, an error explains how to authenticate
|
|
42
|
-
*/
|
|
43
|
-
export declare function handleGetProjectCoverageSummary(args: GetProjectCoverageSummaryArgs, context: HandlerContext): Promise<ToolResponse>;
|
|
44
|
-
//# sourceMappingURL=coverage.d.ts.map
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Coverage handlers for MCP tools
|
|
3
|
-
*
|
|
4
|
-
* Provides cloud coverage query functionality:
|
|
5
|
-
* - get_requirement_coverage: Coverage for a specific requirement
|
|
6
|
-
* - get_project_coverage_summary: Project-wide coverage summary
|
|
7
|
-
*/
|
|
8
|
-
import { textResponse, errorResponse } from './types.js';
|
|
9
|
-
import { CONVEX_URL, getRequirementCoverage as queryRequirementCoverage, getProjectCoverage as queryProjectCoverage, } from '../convexClient.js';
|
|
10
|
-
/**
|
|
11
|
-
* Handler for get_requirement_coverage tool
|
|
12
|
-
*
|
|
13
|
-
* Requirements covered:
|
|
14
|
-
* - MCP-COVERAGE-1.0: When credentials are valid, the response shows when the requirement was last tested
|
|
15
|
-
* - MCP-COVERAGE-1.1: The response includes the most recent branch and test file where coverage was recorded
|
|
16
|
-
* - MCP-COVERAGE-1.2: When the requirement has no coverage records, the response indicates this
|
|
17
|
-
* - MCP-COVERAGE-1.3: When credentials are missing or invalid, an error explains how to authenticate
|
|
18
|
-
*/
|
|
19
|
-
export async function handleGetRequirementCoverage(args, context) {
|
|
20
|
-
const { requirementKey, projectId } = args;
|
|
21
|
-
// MCP-COVERAGE-1.3: Get project credentials (throws if not configured)
|
|
22
|
-
let project;
|
|
23
|
-
try {
|
|
24
|
-
project = await context.getProjectFromDiscovery(projectId);
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
return errorResponse(`Coverage query requires project credentials. Run \`dotrequirements link\` to connect to cloud.\n\nError: ${error instanceof Error ? error.message : String(error)}`);
|
|
28
|
-
}
|
|
29
|
-
// Query cloud for coverage
|
|
30
|
-
const coverage = await queryRequirementCoverage(requirementKey, project.projectId, project.projectSecret, CONVEX_URL);
|
|
31
|
-
// MCP-COVERAGE-1.2: No coverage records
|
|
32
|
-
if (!coverage.lastTestedAt) {
|
|
33
|
-
return textResponse(`**${requirementKey}** has not been tested yet.`);
|
|
34
|
-
}
|
|
35
|
-
// MCP-COVERAGE-1.0: Show when requirement was last tested
|
|
36
|
-
const lastTested = new Date(coverage.lastTestedAt);
|
|
37
|
-
// MCP-COVERAGE-1.1: Include branch and test file
|
|
38
|
-
const testLocation = coverage.testFile
|
|
39
|
-
? `\n**Test Location:** \`${coverage.testFile}${coverage.testLine ? `:${coverage.testLine}` : ''}\``
|
|
40
|
-
: '';
|
|
41
|
-
let branchInfo = `\n**Branch:** ${coverage.branch}`;
|
|
42
|
-
if (coverage.allBranches.length > 1) {
|
|
43
|
-
const otherBranches = coverage.allBranches
|
|
44
|
-
.filter((b) => b.branch !== coverage.branch)
|
|
45
|
-
.map((b) => `- ${b.branch}: ${new Date(b.lastTestedAt).toISOString()}`)
|
|
46
|
-
.join('\n');
|
|
47
|
-
branchInfo += `\n\n**Also tested on:**\n${otherBranches}`;
|
|
48
|
-
}
|
|
49
|
-
return textResponse(`# Coverage for ${requirementKey}\n\n**Last Tested:** ${lastTested.toISOString()}${branchInfo}${testLocation}`);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Handler for get_project_coverage_summary tool
|
|
53
|
-
*
|
|
54
|
-
* Requirements covered:
|
|
55
|
-
* - MCP-COVERAGE-2.0: The response summarizes which requirements have been tested and which have not
|
|
56
|
-
* - MCP-COVERAGE-2.1: When a branch filter is provided, coverage results include only records from that branch
|
|
57
|
-
* - MCP-COVERAGE-2.2: When sinceTimestamp is provided, only coverage recorded after that time is included
|
|
58
|
-
* - MCP-COVERAGE-2.3: When credentials are missing or invalid, an error explains how to authenticate
|
|
59
|
-
*/
|
|
60
|
-
export async function handleGetProjectCoverageSummary(args, context) {
|
|
61
|
-
const { branch, sinceTimestamp, projectId } = args;
|
|
62
|
-
// MCP-COVERAGE-2.3: Get project credentials (throws if not configured)
|
|
63
|
-
let project;
|
|
64
|
-
try {
|
|
65
|
-
project = await context.getProjectFromDiscovery(projectId);
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
return errorResponse(`Coverage query requires project credentials. Run \`dotrequirements link\` to connect to cloud.\n\nError: ${error instanceof Error ? error.message : String(error)}`);
|
|
69
|
-
}
|
|
70
|
-
// Query cloud for project coverage with optional filters
|
|
71
|
-
const coverage = await queryProjectCoverage(project.projectId, project.projectSecret, CONVEX_URL, { branch, sinceTimestamp });
|
|
72
|
-
// MCP-COVERAGE-2.0: Calculate and display coverage summary
|
|
73
|
-
const total = coverage.tested.length + coverage.untested.length;
|
|
74
|
-
const percentage = total > 0 ? ((coverage.tested.length / total) * 100).toFixed(1) : '0.0';
|
|
75
|
-
// MCP-COVERAGE-2.1 & MCP-COVERAGE-2.2: Show filter info if provided
|
|
76
|
-
let filterInfo = '';
|
|
77
|
-
if (branch) {
|
|
78
|
-
filterInfo += `\n**Branch:** ${branch}`;
|
|
79
|
-
}
|
|
80
|
-
if (sinceTimestamp) {
|
|
81
|
-
filterInfo += `\n**Since:** ${new Date(sinceTimestamp).toISOString()}`;
|
|
82
|
-
}
|
|
83
|
-
let testedSection = '';
|
|
84
|
-
if (coverage.tested.length > 0) {
|
|
85
|
-
const testedList = coverage.tested
|
|
86
|
-
.map((t) => {
|
|
87
|
-
const date = new Date(t.lastTestedAt).toISOString();
|
|
88
|
-
const location = t.testFile
|
|
89
|
-
? ` (\`${t.testFile}${t.testLine ? `:${t.testLine}` : ''}\`)`
|
|
90
|
-
: '';
|
|
91
|
-
return `- **${t.requirementKey}** [${t.branch}]: ${date}${location}`;
|
|
92
|
-
})
|
|
93
|
-
.join('\n');
|
|
94
|
-
testedSection = `\n\n## Tested Requirements (${coverage.tested.length})\n\n${testedList}`;
|
|
95
|
-
}
|
|
96
|
-
let untestedSection = '';
|
|
97
|
-
if (coverage.untested.length > 0) {
|
|
98
|
-
const untestedList = coverage.untested
|
|
99
|
-
.map((key) => `- ${key}`)
|
|
100
|
-
.join('\n');
|
|
101
|
-
untestedSection = `\n\n## Untested Requirements (${coverage.untested.length})\n\n${untestedList}`;
|
|
102
|
-
}
|
|
103
|
-
return textResponse(`# Project Coverage Summary\n\n**Total Requirements:** ${total}\n**Coverage:** ${percentage}%${filterInfo}${testedSection}${untestedSection}`);
|
|
104
|
-
}
|
|
105
|
-
//# sourceMappingURL=coverage.js.map
|