@popoverai/dotrequirements 0.13.0 → 0.15.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 +92 -48
- package/dist/cli.js +1 -10
- package/dist/commands/init.js +166 -226
- package/dist/commands/link.d.ts +9 -10
- package/dist/commands/link.js +81 -106
- package/dist/commands/mcp-setup.js +77 -94
- package/dist/commands/pull.d.ts +1 -0
- package/dist/commands/pull.js +70 -53
- package/dist/commands/push.js +4 -13
- package/dist/config.js +0 -4
- package/dist/harness/cache.d.ts +0 -5
- package/dist/harness/cache.js +0 -48
- package/dist/harness/convexReporting.js +7 -14
- package/dist/harness/finalize.js +7 -12
- package/dist/harness/prepare.js +7 -9
- package/dist/mcp/convexClient.d.ts +9 -1
- package/dist/mcp/convexClient.js +15 -35
- package/dist/mcp/index.js +112 -152
- package/dist/mcp/requirements.d.ts +10 -0
- package/dist/mcp/requirements.js +15 -1
- package/dist/templates/context-file-section.md +59 -0
- package/dist/utils/context-file.d.ts +38 -0
- package/dist/utils/context-file.js +94 -0
- package/dist/utils/env.d.ts +0 -13
- package/dist/utils/env.js +0 -19
- package/dist/utils/gitignore.d.ts +2 -2
- package/dist/utils/gitignore.js +4 -4
- package/dist/utils/oauth-flow.d.ts +0 -1
- package/dist/utils/oauth-flow.js +0 -9
- package/dist/utils/project-discovery.d.ts +3 -5
- package/dist/utils/project-discovery.js +18 -42
- package/dist/utils/project-selector.d.ts +17 -3
- package/dist/utils/project-selector.js +35 -3
- package/dist/utils/project-settings.d.ts +56 -0
- package/dist/utils/project-settings.js +126 -0
- package/dist/utils/templates.d.ts +0 -24
- package/dist/utils/templates.js +0 -39
- package/package.json +1 -1
- package/dist/harness/localReporting.d.ts +0 -6
- package/dist/harness/localReporting.js +0 -49
- package/dist/templates/antigravity-gemini.md +0 -3
- package/dist/templates/antigravity-overview-rule.md +0 -3
- package/dist/templates/antigravity-test-rule.md +0 -3
- package/dist/templates/behavioral-core.md +0 -25
- package/dist/templates/claude-code-overview-skill.md +0 -6
- package/dist/templates/claude-code-skill.md +0 -6
- package/dist/templates/claude-code-test-skill.md +0 -6
- package/dist/templates/codex-agents.md +0 -3
- package/dist/templates/codex-overview-agents.md +0 -3
- package/dist/templates/codex-test-agents.md +0 -3
- package/dist/templates/cursor-overview-rule.mdc +0 -5
- package/dist/templates/cursor-rule.mdc +0 -5
- package/dist/templates/cursor-test-rule.mdc +0 -5
- package/dist/templates/overview-core.md +0 -27
- package/dist/templates/test-writing-core.md +0 -72
- package/dist/utils/detect-existing-project.d.ts +0 -5
- package/dist/utils/detect-existing-project.js +0 -34
package/dist/commands/push.js
CHANGED
|
@@ -5,24 +5,15 @@ import { getConvexUrl } from '../config.js';
|
|
|
5
5
|
import { parseRequirementsFromFile, getAllRequirements, parseRequirementKey, buildRequirementsFile } from '../schema/index.js';
|
|
6
6
|
import { api } from '../convex.js';
|
|
7
7
|
import * as readline from 'readline';
|
|
8
|
-
import { isLocalOnlyProject, CLOUD_FEATURES_REQUIRE_AUTH_MESSAGE } from '../utils/local-project.js';
|
|
9
8
|
import { brand } from '../utils/brand.js';
|
|
10
9
|
import { findRequirementsFiles } from '../mcp/requirements.js';
|
|
10
|
+
import { getProjectCredentials } from '../utils/project-settings.js';
|
|
11
11
|
export async function pushCommand(file, options) {
|
|
12
12
|
try {
|
|
13
13
|
console.log(`Preparing to push requirements to ${brand} cloud...\n`);
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
const projectSecret =
|
|
17
|
-
if (!projectId || !projectSecret) {
|
|
18
|
-
throw new Error('Project credentials not found. Either:\n' +
|
|
19
|
-
' 1. Run "dotreq init" to initialize the project, or\n' +
|
|
20
|
-
' 2. Set DOTREQUIREMENTS_PROJECT_ID and DOTREQUIREMENTS_PROJECT_SECRET in .env.local');
|
|
21
|
-
}
|
|
22
|
-
// AUTHZ-2.0: Check if project is local-only
|
|
23
|
-
if (isLocalOnlyProject(projectId)) {
|
|
24
|
-
throw new Error(CLOUD_FEATURES_REQUIRE_AUTH_MESSAGE);
|
|
25
|
-
}
|
|
14
|
+
// Get project credentials from .requirements/project-settings.json
|
|
15
|
+
// This throws helpful errors if project not found or not connected to cloud
|
|
16
|
+
const { projectId, projectSecret } = getProjectCredentials();
|
|
26
17
|
// Determine which files to push
|
|
27
18
|
let filesToPush;
|
|
28
19
|
if (file) {
|
package/dist/config.js
CHANGED
|
@@ -7,10 +7,6 @@ const CONVEX_URL = 'https://data.dotrequirements.io';
|
|
|
7
7
|
* Get the Convex deployment URL
|
|
8
8
|
*/
|
|
9
9
|
export function getConvexUrl() {
|
|
10
|
-
// Show deprecation warning if user has CONVEX_URL in their env
|
|
11
|
-
if (process.env.CONVEX_URL) {
|
|
12
|
-
console.warn('⚠️ CONVEX_URL is no longer needed and will be ignored. You can safely remove it from your .env.local');
|
|
13
|
-
}
|
|
14
10
|
return CONVEX_URL;
|
|
15
11
|
}
|
|
16
12
|
//# sourceMappingURL=config.js.map
|
package/dist/harness/cache.d.ts
CHANGED
|
@@ -61,11 +61,6 @@ export declare function findProjectRoot(startDir?: string): string | null;
|
|
|
61
61
|
* Get the cache directory path, creating it if necessary
|
|
62
62
|
*/
|
|
63
63
|
export declare function getCacheDir(requirementsDir: string, create?: boolean): string;
|
|
64
|
-
/**
|
|
65
|
-
* Find the dotrequirements project root by looking for .env.local with credentials.
|
|
66
|
-
* Falls back to finding .requirements directory if no credentials found.
|
|
67
|
-
*/
|
|
68
|
-
export declare function findProjectRootWithCredentials(startDir?: string): string;
|
|
69
64
|
/**
|
|
70
65
|
* Find all *.requirements.md files under project root
|
|
71
66
|
*/
|
package/dist/harness/cache.js
CHANGED
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
import * as fs from 'fs';
|
|
10
10
|
import * as path from 'path';
|
|
11
11
|
import { globSync } from 'glob';
|
|
12
|
-
import { findUpSync } from 'find-up';
|
|
13
|
-
import { brandPlain } from '../utils/brand.js';
|
|
14
12
|
// Cache directory structure
|
|
15
13
|
const CACHE_DIR = '.cache';
|
|
16
14
|
const LOOKUP_FILE = 'lookup.json';
|
|
@@ -54,52 +52,6 @@ export function getCacheDir(requirementsDir, create = false) {
|
|
|
54
52
|
}
|
|
55
53
|
return cacheDir;
|
|
56
54
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Check if an .env.local file has dotrequirements credentials.
|
|
59
|
-
*/
|
|
60
|
-
function hasDotrequirementsCredentials(envPath) {
|
|
61
|
-
const envContent = fs.readFileSync(envPath, 'utf-8');
|
|
62
|
-
const hasProjectId = envContent.includes('DOTREQUIREMENTS_PROJECT_ID=');
|
|
63
|
-
const hasProjectSecret = envContent.includes('DOTREQUIREMENTS_PROJECT_SECRET=');
|
|
64
|
-
return hasProjectId && hasProjectSecret;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Find the dotrequirements project root by looking for .env.local with credentials.
|
|
68
|
-
* Falls back to finding .requirements directory if no credentials found.
|
|
69
|
-
*/
|
|
70
|
-
export function findProjectRootWithCredentials(startDir = process.cwd()) {
|
|
71
|
-
let searchDir = startDir;
|
|
72
|
-
while (true) {
|
|
73
|
-
const envPath = findUpSync('.env.local', { cwd: searchDir });
|
|
74
|
-
if (!envPath) {
|
|
75
|
-
// No .env.local found - try to find project root by .requirements directory
|
|
76
|
-
const projectRoot = findProjectRoot(startDir);
|
|
77
|
-
if (projectRoot) {
|
|
78
|
-
return projectRoot;
|
|
79
|
-
}
|
|
80
|
-
throw new Error(`Could not find ${brandPlain} project root. ` +
|
|
81
|
-
`Expected to find .env.local with credentials or a .requirements directory.`);
|
|
82
|
-
}
|
|
83
|
-
// Check if this .env.local has dotrequirements credentials
|
|
84
|
-
if (hasDotrequirementsCredentials(envPath)) {
|
|
85
|
-
return path.dirname(envPath);
|
|
86
|
-
}
|
|
87
|
-
// No credentials - continue searching from parent directory
|
|
88
|
-
const envDir = path.dirname(envPath);
|
|
89
|
-
const parentDir = path.dirname(envDir);
|
|
90
|
-
// If we've reached the root, stop
|
|
91
|
-
if (parentDir === envDir) {
|
|
92
|
-
// Try .requirements as fallback
|
|
93
|
-
const projectRoot = findProjectRoot(startDir);
|
|
94
|
-
if (projectRoot) {
|
|
95
|
-
return projectRoot;
|
|
96
|
-
}
|
|
97
|
-
throw new Error(`Could not find ${brandPlain} project root. ` +
|
|
98
|
-
`Found .env.local files but none contained credentials.`);
|
|
99
|
-
}
|
|
100
|
-
searchDir = parentDir;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
55
|
/**
|
|
104
56
|
* Find all *.requirements.md files under project root
|
|
105
57
|
*/
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { execSync } from "child_process";
|
|
2
2
|
import { getTrackedRequirements } from "./tracking.js";
|
|
3
3
|
import { saveCache, getRequirementsToReport } from "./coverageCache.js";
|
|
4
|
-
import {
|
|
5
|
-
import { loadEnvFile, getProjectCredentials } from "../utils/env.js";
|
|
4
|
+
import { getProjectInfo } from "../utils/project-settings.js";
|
|
6
5
|
/**
|
|
7
6
|
* Get the current git branch, or null if not in a git repo
|
|
8
7
|
*/
|
|
@@ -51,20 +50,14 @@ function parseCallerLocation(location) {
|
|
|
51
50
|
*/
|
|
52
51
|
export async function reportCoverageToConvex(cwd = process.cwd(), trackedReqs) {
|
|
53
52
|
try {
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
console.log("\nℹ️ Skipping cloud coverage reporting (DOTREQUIREMENTS_PROJECT_ID or DOTREQUIREMENTS_PROJECT_SECRET not configured)");
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const { projectId, projectSecret } = credentials;
|
|
63
|
-
// AUTHZ-1.2: Skip cloud reporting for local-only projects (silent)
|
|
64
|
-
if (isLocalOnlyProject(projectId)) {
|
|
65
|
-
// Silently skip - local-only projects track coverage in-memory only
|
|
53
|
+
// Get project info from .requirements/project-settings.json
|
|
54
|
+
const projectInfo = getProjectInfo(cwd);
|
|
55
|
+
// Skip if no project found or not connected to cloud
|
|
56
|
+
if (!projectInfo || projectInfo.status !== 'cloud-connected' || !projectInfo.credentials) {
|
|
57
|
+
console.log("\nℹ️ Skipping cloud coverage reporting (project not connected to cloud)");
|
|
66
58
|
return;
|
|
67
59
|
}
|
|
60
|
+
const { projectId, projectSecret } = projectInfo.credentials;
|
|
68
61
|
// Use provided trackedReqs or fall back to in-memory tracking
|
|
69
62
|
const reqs = trackedReqs ?? getTrackedRequirements();
|
|
70
63
|
const requirementKeys = Array.from(reqs.keys());
|
package/dist/harness/finalize.js
CHANGED
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { execSync } from 'child_process';
|
|
13
13
|
import { findRequirementsDir, findProjectRoot, getTestRunId, cleanupTestRunId, readTrackingEntries, deleteTrackingFile, readLookupCache, readCoverageCache, updateCoverageCache, needsReporting, } from './cache.js';
|
|
14
|
-
import {
|
|
15
|
-
import { isLocalOnlyProject } from '../utils/local-project.js';
|
|
14
|
+
import { getProjectInfo } from '../utils/project-settings.js';
|
|
16
15
|
/**
|
|
17
16
|
* Aggregate tracking entries by requirement key
|
|
18
17
|
*/
|
|
@@ -115,20 +114,16 @@ const CONVEX_URL = 'https://data.dotrequirements.io';
|
|
|
115
114
|
*/
|
|
116
115
|
async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatus) {
|
|
117
116
|
try {
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (!credentials) {
|
|
117
|
+
// Get project info from .requirements/project-settings.json
|
|
118
|
+
const projectInfo = getProjectInfo(projectRoot);
|
|
119
|
+
// Skip if no project found or not connected to cloud
|
|
120
|
+
if (!projectInfo || projectInfo.status !== 'cloud-connected' || !projectInfo.credentials) {
|
|
122
121
|
if (showCloudStatus) {
|
|
123
|
-
console.log('\nℹ️ Skipping cloud coverage reporting (
|
|
122
|
+
console.log('\nℹ️ Skipping cloud coverage reporting (project not connected to cloud)');
|
|
124
123
|
}
|
|
125
124
|
return { sent: false, count: 0 };
|
|
126
125
|
}
|
|
127
|
-
const { projectId, projectSecret } = credentials;
|
|
128
|
-
// Skip for local-only projects
|
|
129
|
-
if (isLocalOnlyProject(projectId)) {
|
|
130
|
-
return { sent: false, count: 0 };
|
|
131
|
-
}
|
|
126
|
+
const { projectId, projectSecret } = projectInfo.credentials;
|
|
132
127
|
const requirementsDir = findRequirementsDir(projectRoot);
|
|
133
128
|
// Get all tracked requirement keys
|
|
134
129
|
const requirementKeys = Array.from(aggregated.keys());
|
package/dist/harness/prepare.js
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Implements: HARNESS-PREPARE-1, HARNESS-PREPARE-2, HARNESS-PREPARE-3
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import { findRequirementsDir, findRequirementsFiles, writeLookupCache, initTestRunId, clearTrackingFile, writeProjectRoot, } from './cache.js';
|
|
12
12
|
import { parseRequirementsFromFile, } from '../schema/index.js';
|
|
13
|
+
import { findProjectRoot } from '../utils/project-settings.js';
|
|
13
14
|
/**
|
|
14
15
|
* Prepare the test harness for a test run.
|
|
15
16
|
*
|
|
@@ -22,14 +23,11 @@ import { parseRequirementsFromFile, } from '../schema/index.js';
|
|
|
22
23
|
*/
|
|
23
24
|
export function prepare(options = {}) {
|
|
24
25
|
const { cwd = process.cwd(), logWarnings = true } = options;
|
|
25
|
-
// Find the project root
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
catch {
|
|
31
|
-
throw new Error('Could not find .requirements directory or .env.local with credentials. ' +
|
|
32
|
-
'Please create a .requirements directory in your project root.');
|
|
26
|
+
// Find the project root by looking for .requirements directory
|
|
27
|
+
const projectRoot = findProjectRoot(cwd);
|
|
28
|
+
if (!projectRoot) {
|
|
29
|
+
throw new Error('Could not find .requirements directory. ' +
|
|
30
|
+
'Please run "dotrequirements init" to initialize your project.');
|
|
33
31
|
}
|
|
34
32
|
// Set environment variable for cross-process persistence (globalSetup → test workers)
|
|
35
33
|
process.env.DOTREQUIREMENTS_PROJECT_ROOT = projectRoot;
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Production Convex deployment URL
|
|
3
|
+
*/
|
|
4
|
+
export declare const CONVEX_URL = "https://data.dotrequirements.io";
|
|
5
|
+
/**
|
|
6
|
+
* Convex configuration for cloud operations
|
|
3
7
|
*/
|
|
4
8
|
interface ConvexConfig {
|
|
5
9
|
convexUrl: string;
|
|
6
10
|
projectId: string;
|
|
7
11
|
projectSecret: string;
|
|
8
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Load Convex configuration from project settings.
|
|
15
|
+
* Returns null if credentials are not configured.
|
|
16
|
+
*/
|
|
9
17
|
export declare function loadConvexConfig(cwd?: string): ConvexConfig | null;
|
|
10
18
|
/**
|
|
11
19
|
* Query Convex for requirement coverage
|
package/dist/mcp/convexClient.js
CHANGED
|
@@ -1,45 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join } from 'path';
|
|
1
|
+
import { getProjectCredentials } from '../utils/project-settings.js';
|
|
3
2
|
/**
|
|
4
3
|
* Production Convex deployment URL
|
|
5
4
|
*/
|
|
6
|
-
const CONVEX_URL = 'https://data.dotrequirements.io';
|
|
5
|
+
export const CONVEX_URL = 'https://data.dotrequirements.io';
|
|
6
|
+
/**
|
|
7
|
+
* Load Convex configuration from project settings.
|
|
8
|
+
* Returns null if credentials are not configured.
|
|
9
|
+
*/
|
|
7
10
|
export function loadConvexConfig(cwd = process.cwd()) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const envContent = readFileSync(envPath, 'utf-8');
|
|
16
|
-
const lines = envContent.split('\n');
|
|
17
|
-
for (const line of lines) {
|
|
18
|
-
const trimmed = line.trim();
|
|
19
|
-
if (trimmed.startsWith('DOTREQUIREMENTS_PROJECT_ID=')) {
|
|
20
|
-
projectId = trimmed.split('=')[1].trim().replace(/['"]/g, '');
|
|
21
|
-
}
|
|
22
|
-
if (trimmed.startsWith('DOTREQUIREMENTS_PROJECT_SECRET=')) {
|
|
23
|
-
projectSecret = trimmed.split('=')[1].trim().replace(/['"]/g, '');
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
// If we found values, stop looking (precedence: .env.local > .env)
|
|
27
|
-
if (projectId && projectSecret) {
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// Environment variables take precedence
|
|
33
|
-
if (process.env.DOTREQUIREMENTS_PROJECT_ID) {
|
|
34
|
-
projectId = process.env.DOTREQUIREMENTS_PROJECT_ID;
|
|
35
|
-
}
|
|
36
|
-
if (process.env.DOTREQUIREMENTS_PROJECT_SECRET) {
|
|
37
|
-
projectSecret = process.env.DOTREQUIREMENTS_PROJECT_SECRET;
|
|
11
|
+
try {
|
|
12
|
+
const credentials = getProjectCredentials(cwd);
|
|
13
|
+
return {
|
|
14
|
+
convexUrl: CONVEX_URL,
|
|
15
|
+
projectId: credentials.projectId,
|
|
16
|
+
projectSecret: credentials.projectSecret,
|
|
17
|
+
};
|
|
38
18
|
}
|
|
39
|
-
|
|
19
|
+
catch {
|
|
20
|
+
// Credentials not found or project not connected to cloud
|
|
40
21
|
return null;
|
|
41
22
|
}
|
|
42
|
-
return { convexUrl: CONVEX_URL, projectId, projectSecret };
|
|
43
23
|
}
|
|
44
24
|
/**
|
|
45
25
|
* Query Convex for requirement coverage
|