@popoverai/dotrequirements 0.11.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/README.md +478 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +82 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.js +355 -0
- package/dist/commands/link.d.ts +15 -0
- package/dist/commands/link.js +156 -0
- package/dist/commands/login.d.ts +12 -0
- package/dist/commands/login.js +117 -0
- package/dist/commands/logout.d.ts +5 -0
- package/dist/commands/logout.js +17 -0
- package/dist/commands/mcp-setup.d.ts +5 -0
- package/dist/commands/mcp-setup.js +367 -0
- package/dist/commands/mcp.d.ts +6 -0
- package/dist/commands/mcp.js +10 -0
- package/dist/commands/pull.d.ts +7 -0
- package/dist/commands/pull.js +171 -0
- package/dist/commands/push.d.ts +11 -0
- package/dist/commands/push.js +310 -0
- package/dist/commands/test.d.ts +6 -0
- package/dist/commands/test.js +78 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +16 -0
- package/dist/convex.d.ts +56 -0
- package/dist/convex.js +58 -0
- package/dist/harness/cache.d.ts +135 -0
- package/dist/harness/cache.js +342 -0
- package/dist/harness/convexReporting.d.ts +15 -0
- package/dist/harness/convexReporting.js +136 -0
- package/dist/harness/coverageCache.d.ts +30 -0
- package/dist/harness/coverageCache.js +70 -0
- package/dist/harness/finalize.d.ts +48 -0
- package/dist/harness/finalize.js +299 -0
- package/dist/harness/index.d.ts +70 -0
- package/dist/harness/index.js +103 -0
- package/dist/harness/localReporting.d.ts +6 -0
- package/dist/harness/localReporting.js +49 -0
- package/dist/harness/prepare.d.ts +41 -0
- package/dist/harness/prepare.js +83 -0
- package/dist/harness/requirementsLoader.d.ts +45 -0
- package/dist/harness/requirementsLoader.js +201 -0
- package/dist/harness/tracking.d.ts +49 -0
- package/dist/harness/tracking.js +179 -0
- package/dist/harness/types.d.ts +12 -0
- package/dist/harness/types.js +6 -0
- package/dist/mcp/convexClient.d.ts +43 -0
- package/dist/mcp/convexClient.js +101 -0
- package/dist/mcp/grep.d.ts +24 -0
- package/dist/mcp/grep.js +261 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.js +1758 -0
- package/dist/mcp/requirements.d.ts +47 -0
- package/dist/mcp/requirements.js +141 -0
- package/dist/mcp/testCodeExtractor.d.ts +22 -0
- package/dist/mcp/testCodeExtractor.js +152 -0
- package/dist/mcp/types.d.ts +27 -0
- package/dist/mcp/types.js +2 -0
- package/dist/schema/browser.d.ts +12 -0
- package/dist/schema/browser.js +24 -0
- package/dist/schema/builder.d.ts +25 -0
- package/dist/schema/builder.js +125 -0
- package/dist/schema/conversions.d.ts +69 -0
- package/dist/schema/conversions.js +201 -0
- package/dist/schema/index.d.ts +14 -0
- package/dist/schema/index.js +24 -0
- package/dist/schema/parser-core.d.ts +61 -0
- package/dist/schema/parser-core.js +247 -0
- package/dist/schema/parser.d.ts +44 -0
- package/dist/schema/parser.js +295 -0
- package/dist/schema/resolver.d.ts +66 -0
- package/dist/schema/resolver.js +185 -0
- package/dist/schema/schemas.d.ts +312 -0
- package/dist/schema/schemas.js +258 -0
- package/dist/schema/test-schema.d.ts +5 -0
- package/dist/schema/test-schema.js +81 -0
- package/dist/templates/antigravity-gemini.md +3 -0
- package/dist/templates/antigravity-overview-rule.md +3 -0
- package/dist/templates/antigravity-test-rule.md +3 -0
- package/dist/templates/behavioral-core.md +25 -0
- package/dist/templates/claude-code-overview-skill.md +6 -0
- package/dist/templates/claude-code-skill.md +6 -0
- package/dist/templates/claude-code-test-skill.md +6 -0
- package/dist/templates/codex-agents.md +3 -0
- package/dist/templates/codex-overview-agents.md +3 -0
- package/dist/templates/codex-test-agents.md +3 -0
- package/dist/templates/cursor-overview-rule.mdc +5 -0
- package/dist/templates/cursor-rule.mdc +5 -0
- package/dist/templates/cursor-test-rule.mdc +5 -0
- package/dist/templates/example-requirements.d.ts +8 -0
- package/dist/templates/example-requirements.js +88 -0
- package/dist/templates/example-requirements.ts +88 -0
- package/dist/templates/overview-core.md +27 -0
- package/dist/templates/requirements-readme.d.ts +5 -0
- package/dist/templates/requirements-readme.js +31 -0
- package/dist/templates/requirements-readme.ts +30 -0
- package/dist/templates/test-writing-core.md +72 -0
- package/dist/utils/brand.d.ts +5 -0
- package/dist/utils/brand.js +8 -0
- package/dist/utils/browser-launch.d.ts +19 -0
- package/dist/utils/browser-launch.js +36 -0
- package/dist/utils/detect-existing-project.d.ts +5 -0
- package/dist/utils/detect-existing-project.js +34 -0
- package/dist/utils/env.d.ts +19 -0
- package/dist/utils/env.js +56 -0
- package/dist/utils/gitignore.d.ts +7 -0
- package/dist/utils/gitignore.js +29 -0
- package/dist/utils/local-project.d.ts +31 -0
- package/dist/utils/local-project.js +33 -0
- package/dist/utils/oauth-callback-server.d.ts +28 -0
- package/dist/utils/oauth-callback-server.js +156 -0
- package/dist/utils/oauth-flow.d.ts +22 -0
- package/dist/utils/oauth-flow.js +120 -0
- package/dist/utils/project-discovery.d.ts +57 -0
- package/dist/utils/project-discovery.js +146 -0
- package/dist/utils/project-name.d.ts +8 -0
- package/dist/utils/project-name.js +48 -0
- package/dist/utils/project-selector.d.ts +25 -0
- package/dist/utils/project-selector.js +69 -0
- package/dist/utils/prompts.d.ts +33 -0
- package/dist/utils/prompts.js +60 -0
- package/dist/utils/templates.d.ts +29 -0
- package/dist/utils/templates.js +67 -0
- package/dist/utils/token-refresh.d.ts +24 -0
- package/dist/utils/token-refresh.js +69 -0
- package/dist/utils/token-storage.d.ts +31 -0
- package/dist/utils/token-storage.js +57 -0
- package/package.json +82 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for example.requirements.md
|
|
3
|
+
*
|
|
4
|
+
* This template is used for both local-only and authenticated init flows.
|
|
5
|
+
* It demonstrates the dotrequirements markdown format with nested requirements.
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateExampleRequirements(projectId?: string): string;
|
|
8
|
+
//# sourceMappingURL=example-requirements.d.ts.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for example.requirements.md
|
|
3
|
+
*
|
|
4
|
+
* This template is used for both local-only and authenticated init flows.
|
|
5
|
+
* It demonstrates the dotrequirements markdown format with nested requirements.
|
|
6
|
+
*/
|
|
7
|
+
export function generateExampleRequirements(projectId = 'local') {
|
|
8
|
+
const now = new Date().toISOString();
|
|
9
|
+
return `---
|
|
10
|
+
projectId: ${projectId}
|
|
11
|
+
pulledAt: ${now}
|
|
12
|
+
version: 1
|
|
13
|
+
document:
|
|
14
|
+
title: "Example Requirements"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Example Requirements
|
|
18
|
+
|
|
19
|
+
This file demonstrates the dotrequirements format. Feel free to edit or delete it.
|
|
20
|
+
|
|
21
|
+
## HOW-TO: How to use dotrequirements
|
|
22
|
+
|
|
23
|
+
\`\`\`dotrequirements
|
|
24
|
+
HOW-TO: How to use dotrequirements
|
|
25
|
+
0. → Requirements live here and are referenced by index, like requirement('HOW-TO.0')
|
|
26
|
+
1. Labels → Anything before the arrow is a label. You can reference a requirement by its index or its label: requirement('HOW-TO.1') == requirement('HOW-TO.labels')
|
|
27
|
+
2. Labels → Repeated labels can be referenced sequentially: requirement('HOW-TO.labels#2')
|
|
28
|
+
2.0. Nesting → You can keep nesting. Label references don't need to be nested: requirement('HOW-TO.nesting').
|
|
29
|
+
2.1. Several words → Reference multi-word labels using kebab-case. Label references are never case sensitive: requirement('HOW-TO.several-words')
|
|
30
|
+
3. → While you _can_ write your requirements longhand in this format, there are a number of better ways.
|
|
31
|
+
3.0. MCP → The dotrequirements MCP equips an AI assistant to develop requirements with you
|
|
32
|
+
3.1. Your current tools → Dotrequirements has a composer for Jira, Confluence, and Notion
|
|
33
|
+
3.2. Our composer → You can use our requirements composer at app.dotrequirements.io
|
|
34
|
+
4. Have fun → Especially in the time you get back from having a more stable, transparent, and AI-friendly codebase
|
|
35
|
+
\`\`\`
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## USER-AUTH: User authentication flow
|
|
40
|
+
|
|
41
|
+
**Implementation notes:** Use bcrypt for password hashing with work factor >= 12.
|
|
42
|
+
|
|
43
|
+
\`\`\`dotrequirements
|
|
44
|
+
USER-AUTH: User authentication flow
|
|
45
|
+
0. AC → Login form accepts email and password
|
|
46
|
+
1. AC → Invalid credentials show error message
|
|
47
|
+
2. Edge-case → Rate limiting after 5 failed attempts
|
|
48
|
+
2.0. Requirement → Lock account for 15 minutes
|
|
49
|
+
2.1. Requirement → Display countdown timer to user
|
|
50
|
+
\`\`\`
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## PERF-1: API endpoints respond within acceptable time limits
|
|
55
|
+
|
|
56
|
+
\`\`\`dotrequirements
|
|
57
|
+
PERF-1: API endpoints respond within acceptable time limits
|
|
58
|
+
0. Benchmark → Tested with 1000 concurrent users
|
|
59
|
+
1. Requirement → p95 latency under 200ms
|
|
60
|
+
2. Requirement → p99 latency under 500ms
|
|
61
|
+
\`\`\`
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Referencing in Tests
|
|
66
|
+
|
|
67
|
+
You can reference these requirements in your tests:
|
|
68
|
+
|
|
69
|
+
\`\`\`javascript
|
|
70
|
+
import { requirement } from '@popoverai/dotrequirements/test';
|
|
71
|
+
|
|
72
|
+
test('login with valid credentials', () => {
|
|
73
|
+
// Reference by numeric path
|
|
74
|
+
const ac = requirement('USER-AUTH.0');
|
|
75
|
+
// Returns: "AC: Login form accepts email and password"
|
|
76
|
+
|
|
77
|
+
// Reference by label
|
|
78
|
+
const edgeCase = requirement('USER-AUTH.edge-case');
|
|
79
|
+
// Returns: "Edge-case: Rate limiting after 5 failed attempts"
|
|
80
|
+
|
|
81
|
+
// Your test implementation...
|
|
82
|
+
});
|
|
83
|
+
\`\`\`
|
|
84
|
+
|
|
85
|
+
See the [test harness documentation](https://docs.dotrequirements.io/harness) for more details.
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=example-requirements.js.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for example.requirements.md
|
|
3
|
+
*
|
|
4
|
+
* This template is used for both local-only and authenticated init flows.
|
|
5
|
+
* It demonstrates the dotrequirements markdown format with nested requirements.
|
|
6
|
+
*/
|
|
7
|
+
export function generateExampleRequirements(projectId: string = 'local'): string {
|
|
8
|
+
const now = new Date().toISOString();
|
|
9
|
+
|
|
10
|
+
return `---
|
|
11
|
+
projectId: ${projectId}
|
|
12
|
+
pulledAt: ${now}
|
|
13
|
+
version: 1
|
|
14
|
+
document:
|
|
15
|
+
title: "Example Requirements"
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Example Requirements
|
|
19
|
+
|
|
20
|
+
This file demonstrates the dotrequirements format. Feel free to edit or delete it.
|
|
21
|
+
|
|
22
|
+
## HOW-TO: How to use dotrequirements
|
|
23
|
+
|
|
24
|
+
\`\`\`dotrequirements
|
|
25
|
+
HOW-TO: How to use dotrequirements
|
|
26
|
+
0. → Requirements live here and are referenced by index, like requirement('HOW-TO.0')
|
|
27
|
+
1. Labels → Anything before the arrow is a label. You can reference a requirement by its index or its label: requirement('HOW-TO.1') == requirement('HOW-TO.labels')
|
|
28
|
+
2. Labels → Repeated labels can be referenced sequentially: requirement('HOW-TO.labels#2')
|
|
29
|
+
2.0. Nesting → You can keep nesting. Label references don't need to be nested: requirement('HOW-TO.nesting').
|
|
30
|
+
2.1. Several words → Reference multi-word labels using kebab-case. Label references are never case sensitive: requirement('HOW-TO.several-words')
|
|
31
|
+
3. → While you _can_ write your requirements longhand in this format, there are a number of better ways.
|
|
32
|
+
3.0. MCP → The dotrequirements MCP equips an AI assistant to develop requirements with you
|
|
33
|
+
3.1. Your current tools → Dotrequirements has a composer for Jira, Confluence, and Notion
|
|
34
|
+
3.2. Our composer → You can use our requirements composer at app.dotrequirements.io
|
|
35
|
+
4. Have fun → Especially in the time you get back from having a more stable, transparent, and AI-friendly codebase
|
|
36
|
+
\`\`\`
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## USER-AUTH: User authentication flow
|
|
41
|
+
|
|
42
|
+
**Implementation notes:** Use bcrypt for password hashing with work factor >= 12.
|
|
43
|
+
|
|
44
|
+
\`\`\`dotrequirements
|
|
45
|
+
USER-AUTH: User authentication flow
|
|
46
|
+
0. AC → Login form accepts email and password
|
|
47
|
+
1. AC → Invalid credentials show error message
|
|
48
|
+
2. Edge-case → Rate limiting after 5 failed attempts
|
|
49
|
+
2.0. Requirement → Lock account for 15 minutes
|
|
50
|
+
2.1. Requirement → Display countdown timer to user
|
|
51
|
+
\`\`\`
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## PERF-1: API endpoints respond within acceptable time limits
|
|
56
|
+
|
|
57
|
+
\`\`\`dotrequirements
|
|
58
|
+
PERF-1: API endpoints respond within acceptable time limits
|
|
59
|
+
0. Benchmark → Tested with 1000 concurrent users
|
|
60
|
+
1. Requirement → p95 latency under 200ms
|
|
61
|
+
2. Requirement → p99 latency under 500ms
|
|
62
|
+
\`\`\`
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Referencing in Tests
|
|
67
|
+
|
|
68
|
+
You can reference these requirements in your tests:
|
|
69
|
+
|
|
70
|
+
\`\`\`javascript
|
|
71
|
+
import { requirement } from '@popoverai/dotrequirements/test';
|
|
72
|
+
|
|
73
|
+
test('login with valid credentials', () => {
|
|
74
|
+
// Reference by numeric path
|
|
75
|
+
const ac = requirement('USER-AUTH.0');
|
|
76
|
+
// Returns: "AC: Login form accepts email and password"
|
|
77
|
+
|
|
78
|
+
// Reference by label
|
|
79
|
+
const edgeCase = requirement('USER-AUTH.edge-case');
|
|
80
|
+
// Returns: "Edge-case: Rate limiting after 5 failed attempts"
|
|
81
|
+
|
|
82
|
+
// Your test implementation...
|
|
83
|
+
});
|
|
84
|
+
\`\`\`
|
|
85
|
+
|
|
86
|
+
See the [test harness documentation](https://docs.dotrequirements.io/harness) for more details.
|
|
87
|
+
`;
|
|
88
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Understanding Expected Behavior
|
|
2
|
+
|
|
3
|
+
ALWAYS use this when you want to understand what the system is supposed to do.
|
|
4
|
+
|
|
5
|
+
## Where to Find Expected Behavior
|
|
6
|
+
|
|
7
|
+
This project uses **requirements as the source of truth** for expected behavior.
|
|
8
|
+
|
|
9
|
+
**Location:** `.requirements/` directory contains `*.requirements.md` files
|
|
10
|
+
|
|
11
|
+
**Format:** Requirements are structured as:
|
|
12
|
+
- Requirement IDs (e.g., `AUTH-1`, `LOGIN-2`)
|
|
13
|
+
- Descriptions of expected behavior
|
|
14
|
+
- Hierarchical structure (parent requirements with child criteria)
|
|
15
|
+
|
|
16
|
+
## MCP Tools for Exploration
|
|
17
|
+
|
|
18
|
+
- `list_all_requirements` - Get overview of all requirements in the project
|
|
19
|
+
- `get_requirement` - Get detailed requirement tree with test coverage
|
|
20
|
+
- `search_requirements` - Search by text/regex across all requirements
|
|
21
|
+
- `get_requirements_by_test` - See what a test file validates
|
|
22
|
+
|
|
23
|
+
## Next Steps
|
|
24
|
+
|
|
25
|
+
Once you understand the expected behavior:
|
|
26
|
+
- **Adding new behavior?** Use the `dotreq-requirements` skill
|
|
27
|
+
- **Writing tests?** Use the `dotreq-tests` skill
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for .requirements/README.md
|
|
3
|
+
*/
|
|
4
|
+
export function generateRequirementsReadme() {
|
|
5
|
+
return `# Requirements
|
|
6
|
+
|
|
7
|
+
This directory contains requirements for the project. Requirements can be:
|
|
8
|
+
- Hand-authored locally in Markdown files
|
|
9
|
+
- Generated via \`dotrequirements pull\` from dot•requirements cloud
|
|
10
|
+
- Synced bidirectionally with \`dotrequirements push\`
|
|
11
|
+
|
|
12
|
+
## File Format
|
|
13
|
+
|
|
14
|
+
Requirements use the \`*.requirements.md\` naming pattern. See the [Markdown Schema](https://docs.dotrequirements.io/schema) for format details.
|
|
15
|
+
|
|
16
|
+
## Getting Started
|
|
17
|
+
|
|
18
|
+
1. Edit \`example.requirements.md\` or create new \`*.requirements.md\` files
|
|
19
|
+
2. Reference requirements in tests using the test harness
|
|
20
|
+
3. Run tests to track coverage
|
|
21
|
+
|
|
22
|
+
## Commands
|
|
23
|
+
|
|
24
|
+
- \`dotrequirements pull\` - Sync requirements from cloud
|
|
25
|
+
- \`dotrequirements push\` - Push local requirements to cloud
|
|
26
|
+
- \`dotrequirements test\` - Validate requirement files
|
|
27
|
+
|
|
28
|
+
Learn more: https://dotrequirements.io
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=requirements-readme.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for .requirements/README.md
|
|
3
|
+
*/
|
|
4
|
+
export function generateRequirementsReadme(): string {
|
|
5
|
+
return `# Requirements
|
|
6
|
+
|
|
7
|
+
This directory contains requirements for the project. Requirements can be:
|
|
8
|
+
- Hand-authored locally in Markdown files
|
|
9
|
+
- Generated via \`dotrequirements pull\` from dot•requirements cloud
|
|
10
|
+
- Synced bidirectionally with \`dotrequirements push\`
|
|
11
|
+
|
|
12
|
+
## File Format
|
|
13
|
+
|
|
14
|
+
Requirements use the \`*.requirements.md\` naming pattern. See the [Markdown Schema](https://docs.dotrequirements.io/schema) for format details.
|
|
15
|
+
|
|
16
|
+
## Getting Started
|
|
17
|
+
|
|
18
|
+
1. Edit \`example.requirements.md\` or create new \`*.requirements.md\` files
|
|
19
|
+
2. Reference requirements in tests using the test harness
|
|
20
|
+
3. Run tests to track coverage
|
|
21
|
+
|
|
22
|
+
## Commands
|
|
23
|
+
|
|
24
|
+
- \`dotrequirements pull\` - Sync requirements from cloud
|
|
25
|
+
- \`dotrequirements push\` - Push local requirements to cloud
|
|
26
|
+
- \`dotrequirements test\` - Validate requirement files
|
|
27
|
+
|
|
28
|
+
Learn more: https://dotrequirements.io
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Test Writing with Requirements
|
|
2
|
+
|
|
3
|
+
ALWAYS use this guidance when writing tests based on requirements.
|
|
4
|
+
|
|
5
|
+
## Core Principle
|
|
6
|
+
|
|
7
|
+
Use `requirement()` AS the test description, not in the body or comments.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// ✅ Good
|
|
11
|
+
test(requirement('AUTH-1'), () => { /* test */ });
|
|
12
|
+
|
|
13
|
+
// ❌ Bad
|
|
14
|
+
test("user can log in", () => { requirement('AUTH-1'); });
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Test Structure
|
|
18
|
+
|
|
19
|
+
**Match the requirement hierarchy:**
|
|
20
|
+
|
|
21
|
+
For structured requirements, nest describe/it blocks:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
describe(requirement('LOGIN-1'), () => {
|
|
25
|
+
describe(requirement('LOGIN-1.given'), () => {
|
|
26
|
+
// Arrange
|
|
27
|
+
});
|
|
28
|
+
describe(requirement('LOGIN-1.when'), () => {
|
|
29
|
+
// Act
|
|
30
|
+
it(requirement('LOGIN-1.then'), () => {
|
|
31
|
+
// Assert
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For simple requirements, use a single test block.
|
|
38
|
+
|
|
39
|
+
## Comments
|
|
40
|
+
|
|
41
|
+
Comments should describe the TEST implementation, not copy the requirement text verbatim.
|
|
42
|
+
|
|
43
|
+
**NEVER document coverage in comments.** Our MCP tools track coverage automatically.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// ❌ Bad - creates second source of truth
|
|
47
|
+
/**
|
|
48
|
+
* Requirements coverage:
|
|
49
|
+
* - AUTH-9.0: Backend creates project ✓
|
|
50
|
+
* - AUTH-9.1: CLI writes to .env.local ✓
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
// ✅ Good - use MCP tools instead
|
|
54
|
+
// Use get_requirement, get_requirements_by_test to see coverage
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Workflow
|
|
58
|
+
|
|
59
|
+
After writing tests:
|
|
60
|
+
|
|
61
|
+
1. Run tests to ensure they don't throw errors
|
|
62
|
+
2. **ALWAYS run `review_test`** on the test file to validate tests actually check what requirements specify
|
|
63
|
+
3. Fix any issues identified by the review
|
|
64
|
+
|
|
65
|
+
## MCP Tools for Test Writing
|
|
66
|
+
|
|
67
|
+
- `get_requirement` - Get requirement tree with existing coverage
|
|
68
|
+
- `get_requirements_by_test` - See requirements referenced in a test file
|
|
69
|
+
- `list_untested_requirements` - Find requirements without tests
|
|
70
|
+
- `review_test` - Validate test actually checks what requirement specifies (run after writing tests)
|
|
71
|
+
|
|
72
|
+
Note: Users can also explicitly trigger this workflow with `/write-tests`.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
// Cyan color: rgb(8, 145, 178)
|
|
3
|
+
const bulletColor = chalk.rgb(8, 145, 178);
|
|
4
|
+
/** Branded name for terminal output (colored bullet) */
|
|
5
|
+
export const brand = `dot${bulletColor('•')}requirements`;
|
|
6
|
+
/** Branded name for plain text (MCP descriptions, etc) */
|
|
7
|
+
export const brandPlain = 'dot•requirements';
|
|
8
|
+
//# sourceMappingURL=brand.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform browser launching utility for OAuth flows.
|
|
3
|
+
*
|
|
4
|
+
* Implements AUTH-23: Browser launch utility for OAuth flow
|
|
5
|
+
*
|
|
6
|
+
* Uses the `open` npm package for secure, cross-platform browser launching
|
|
7
|
+
* without shell command injection vulnerabilities.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Open a URL in the user's default browser
|
|
11
|
+
*
|
|
12
|
+
* Works cross-platform (macOS, Windows, Linux)
|
|
13
|
+
*/
|
|
14
|
+
export declare function openBrowser(url: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Open browser with fallback instructions if automatic launch fails
|
|
17
|
+
*/
|
|
18
|
+
export declare function openBrowserWithFallback(url: string): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=browser-launch.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform browser launching utility for OAuth flows.
|
|
3
|
+
*
|
|
4
|
+
* Implements AUTH-23: Browser launch utility for OAuth flow
|
|
5
|
+
*
|
|
6
|
+
* Uses the `open` npm package for secure, cross-platform browser launching
|
|
7
|
+
* without shell command injection vulnerabilities.
|
|
8
|
+
*/
|
|
9
|
+
import open from 'open';
|
|
10
|
+
/**
|
|
11
|
+
* Open a URL in the user's default browser
|
|
12
|
+
*
|
|
13
|
+
* Works cross-platform (macOS, Windows, Linux)
|
|
14
|
+
*/
|
|
15
|
+
export async function openBrowser(url) {
|
|
16
|
+
try {
|
|
17
|
+
await open(url);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
throw new Error(`Failed to open browser: ${error instanceof Error ? error.message : String(error)}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Open browser with fallback instructions if automatic launch fails
|
|
25
|
+
*/
|
|
26
|
+
export async function openBrowserWithFallback(url) {
|
|
27
|
+
try {
|
|
28
|
+
await openBrowser(url);
|
|
29
|
+
console.log('Opening browser for authentication...');
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error('Could not automatically open browser.');
|
|
33
|
+
console.log(`\nPlease open this URL in your browser manually:\n${url}\n`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=browser-launch.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { parseRequirementsFromFile } from '../schema/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Detect if .requirements/ directory exists and extract projectId from files
|
|
6
|
+
*/
|
|
7
|
+
export function detectExistingProject(cwd) {
|
|
8
|
+
const requirementsDir = path.join(cwd, '.requirements');
|
|
9
|
+
if (!fs.existsSync(requirementsDir)) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
// Look for .requirements.md files
|
|
13
|
+
const files = fs.readdirSync(requirementsDir)
|
|
14
|
+
.filter(f => f.endsWith('.requirements.md'));
|
|
15
|
+
if (files.length === 0) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
// Try to parse first file to get projectId
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
try {
|
|
21
|
+
const filePath = path.join(requirementsDir, file);
|
|
22
|
+
const parsed = parseRequirementsFromFile(filePath);
|
|
23
|
+
if (parsed.metadata.projectId) {
|
|
24
|
+
return parsed.metadata.projectId;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
// Skip files that can't be parsed
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=detect-existing-project.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load environment variables from .env.local file
|
|
3
|
+
* Merges with existing process.env (process.env takes precedence)
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadEnvFile(cwd?: string): void;
|
|
6
|
+
/**
|
|
7
|
+
* Get project credentials from environment
|
|
8
|
+
* Returns undefined if not found
|
|
9
|
+
*/
|
|
10
|
+
export declare function getProjectCredentials(): {
|
|
11
|
+
projectId: string;
|
|
12
|
+
projectSecret: string;
|
|
13
|
+
} | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Get project ID from environment
|
|
16
|
+
* Returns undefined if not found
|
|
17
|
+
*/
|
|
18
|
+
export declare function getProjectId(): string | undefined;
|
|
19
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Load environment variables from .env.local file
|
|
5
|
+
* Merges with existing process.env (process.env takes precedence)
|
|
6
|
+
*/
|
|
7
|
+
export function loadEnvFile(cwd = process.cwd()) {
|
|
8
|
+
const envPath = path.join(cwd, '.env.local');
|
|
9
|
+
if (!fs.existsSync(envPath)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const content = fs.readFileSync(envPath, 'utf-8');
|
|
14
|
+
const lines = content.split('\n');
|
|
15
|
+
for (const line of lines) {
|
|
16
|
+
// Skip empty lines and comments
|
|
17
|
+
if (!line.trim() || line.trim().startsWith('#')) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
// Parse KEY=VALUE format
|
|
21
|
+
const match = line.match(/^([^=]+)=(.*)$/);
|
|
22
|
+
if (match) {
|
|
23
|
+
const key = match[1].trim();
|
|
24
|
+
const value = match[2].trim();
|
|
25
|
+
// Only set if not already in process.env
|
|
26
|
+
if (!process.env[key]) {
|
|
27
|
+
process.env[key] = value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
// Silently fail if we can't read the file
|
|
34
|
+
// The commands will error appropriately if env vars are missing
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get project credentials from environment
|
|
39
|
+
* Returns undefined if not found
|
|
40
|
+
*/
|
|
41
|
+
export function getProjectCredentials() {
|
|
42
|
+
const projectId = process.env.DOTREQUIREMENTS_PROJECT_ID;
|
|
43
|
+
const projectSecret = process.env.DOTREQUIREMENTS_PROJECT_SECRET;
|
|
44
|
+
if (!projectId || !projectSecret) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
return { projectId, projectSecret };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get project ID from environment
|
|
51
|
+
* Returns undefined if not found
|
|
52
|
+
*/
|
|
53
|
+
export function getProjectId() {
|
|
54
|
+
return process.env.DOTREQUIREMENTS_PROJECT_ID;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Ensure .env.local is in .gitignore
|
|
5
|
+
* Creates .gitignore if it doesn't exist
|
|
6
|
+
* Appends .env.local if not already present
|
|
7
|
+
*/
|
|
8
|
+
export function ensureGitignore(cwd = process.cwd()) {
|
|
9
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
10
|
+
const entryToAdd = '.env.local';
|
|
11
|
+
const comment = '# dotrequirements credentials';
|
|
12
|
+
// Check if .gitignore exists
|
|
13
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
14
|
+
// Create new .gitignore
|
|
15
|
+
fs.writeFileSync(gitignorePath, `${comment}\n${entryToAdd}\n`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
// Read existing .gitignore
|
|
19
|
+
const content = fs.readFileSync(gitignorePath, 'utf-8');
|
|
20
|
+
// Check if .env.local is already present
|
|
21
|
+
if (content.includes(entryToAdd)) {
|
|
22
|
+
return; // Already present, nothing to do
|
|
23
|
+
}
|
|
24
|
+
// Append to .gitignore
|
|
25
|
+
const separator = content.endsWith('\n') ? '' : '\n';
|
|
26
|
+
const newContent = `${content}${separator}\n${comment}\n${entryToAdd}\n`;
|
|
27
|
+
fs.writeFileSync(gitignorePath, newContent);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=gitignore.js.map
|