@popoverai/dotrequirements 0.24.0 → 0.24.2

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.
Files changed (60) hide show
  1. package/README.md +4 -3
  2. package/dist/cli.js +0 -0
  3. package/dist/codebase-to-spec/claude.d.ts +1 -0
  4. package/dist/codebase-to-spec/claude.js +9 -0
  5. package/dist/codebase-to-spec/pack.d.ts +16 -0
  6. package/dist/codebase-to-spec/pack.js +17 -3
  7. package/dist/codebase-to-spec/present.d.ts +8 -1
  8. package/dist/codebase-to-spec/present.js +7 -4
  9. package/dist/codebase-to-spec/progress.d.ts +6 -0
  10. package/dist/codebase-to-spec/progress.js +34 -0
  11. package/dist/codebase-to-spec/prompts/outline-reviewer.d.ts +1 -1
  12. package/dist/codebase-to-spec/prompts/outline-reviewer.js +3 -1
  13. package/dist/codebase-to-spec/prompts/planner-initial.d.ts +1 -1
  14. package/dist/codebase-to-spec/prompts/planner-initial.js +4 -0
  15. package/dist/codebase-to-spec/prompts/planner-revise.d.ts +1 -1
  16. package/dist/codebase-to-spec/prompts/planner-revise.js +2 -2
  17. package/dist/codebase-to-spec/prompts/spec-reviewer.d.ts +1 -1
  18. package/dist/codebase-to-spec/prompts/spec-reviewer.js +6 -1
  19. package/dist/codebase-to-spec/prompts/specifier.d.ts +1 -1
  20. package/dist/codebase-to-spec/prompts/specifier.js +6 -4
  21. package/dist/codebase-to-spec/prompts/style-check.d.ts +10 -2
  22. package/dist/codebase-to-spec/prompts/style-check.js +76 -46
  23. package/dist/codebase-to-spec/schemas.d.ts +85 -1
  24. package/dist/codebase-to-spec/schemas.js +25 -1
  25. package/dist/codebase-to-spec/specifier.js +6 -0
  26. package/dist/commands/codebase-to-spec/index.js +13 -0
  27. package/dist/commands/codebase-to-spec/pack.d.ts +6 -0
  28. package/dist/commands/codebase-to-spec/pack.js +1 -0
  29. package/dist/commands/codebase-to-spec/present.d.ts +5 -0
  30. package/dist/commands/codebase-to-spec/present.js +6 -1
  31. package/dist/commands/codebase-to-spec/run.js +1 -0
  32. package/package.json +5 -6
  33. package/dist/codebase-to-spec/prompts/planner-apply.d.ts +0 -12
  34. package/dist/codebase-to-spec/prompts/planner-apply.js +0 -32
  35. package/dist/commands/browsertest.d.ts +0 -6
  36. package/dist/commands/browsertest.js +0 -212
  37. package/dist/commands/login.d.ts +0 -12
  38. package/dist/commands/login.js +0 -117
  39. package/dist/commands/logout.d.ts +0 -5
  40. package/dist/commands/logout.js +0 -17
  41. package/dist/commands/mcp-setup.d.ts +0 -5
  42. package/dist/commands/mcp-setup.js +0 -441
  43. package/dist/commands/test.d.ts +0 -6
  44. package/dist/commands/test.js +0 -72
  45. package/dist/mcp/grep.d.ts +0 -24
  46. package/dist/mcp/grep.js +0 -306
  47. package/dist/mcp/handlers/coverage.d.ts +0 -44
  48. package/dist/mcp/handlers/coverage.js +0 -103
  49. package/dist/mcp/requirements.d.ts +0 -57
  50. package/dist/mcp/requirements.js +0 -155
  51. package/dist/mcp/testCodeExtractor.d.ts +0 -22
  52. package/dist/mcp/testCodeExtractor.js +0 -150
  53. package/dist/mcp/types.d.ts +0 -27
  54. package/dist/mcp/types.js +0 -2
  55. package/dist/utils/local-project.d.ts +0 -31
  56. package/dist/utils/local-project.js +0 -33
  57. package/dist/utils/token-refresh.d.ts +0 -24
  58. package/dist/utils/token-refresh.js +0 -69
  59. package/dist/utils/token-storage.d.ts +0 -31
  60. package/dist/utils/token-storage.js +0 -57
@@ -1,6 +0,0 @@
1
- interface BrowserTestOptions {
2
- json?: boolean;
3
- }
4
- export declare function browserTestCommand(requirementKey: string, url: string | undefined, options: BrowserTestOptions): Promise<void>;
5
- export {};
6
- //# sourceMappingURL=browsertest.d.ts.map
@@ -1,212 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import { promisify } from "node:util";
3
- import { formatRequirement, getRequirementTree, loadAllRequirements, } from "../mcp/requirements.js";
4
- import { getProjectInfo, readProjectSettings, } from "../utils/project-settings.js";
5
- const execFileAsync = promisify(execFile);
6
- function extractResults(parsed) {
7
- if (Array.isArray(parsed))
8
- return parsed;
9
- if (parsed && typeof parsed === "object") {
10
- const obj = parsed;
11
- // { results: [...] } format
12
- if (Array.isArray(obj.results))
13
- return obj.results;
14
- // { structured_output: { results: [...] } } format
15
- if (obj.structured_output && typeof obj.structured_output === "object") {
16
- const so = obj.structured_output;
17
- if (Array.isArray(so.results))
18
- return so.results;
19
- }
20
- }
21
- throw new Error("Unexpected browser-automation output format");
22
- }
23
- export async function browserTestCommand(requirementKey, url, options) {
24
- // 1. Find project and load settings
25
- const projectInfo = getProjectInfo();
26
- if (!projectInfo) {
27
- console.error("Error: No dotrequirements project found.");
28
- console.log('Run "dotrequirements init" to create one.');
29
- process.exit(1);
30
- }
31
- let settings;
32
- try {
33
- settings = readProjectSettings(projectInfo.rootPath);
34
- }
35
- catch (err) {
36
- // Settings file exists but is invalid
37
- console.error(`Error: ${err.message}`);
38
- process.exit(1);
39
- }
40
- // 2. Determine URL
41
- const targetURL = url || settings?.defaultURL;
42
- if (!targetURL) {
43
- console.error("Error: No URL provided and no defaultURL in project-settings.json.");
44
- console.log('Either provide a URL argument or add "defaultURL" to .requirements/project-settings.json');
45
- process.exit(1);
46
- }
47
- // 3. Resolve model config
48
- const modelName = settings?.browserTest?.modelName;
49
- const modelApiKey = settings?.browserTest?.modelApiKey;
50
- const geminiApiKey = settings?.browserTest?.geminiApiKey;
51
- if (!modelName && !modelApiKey && !geminiApiKey) {
52
- console.error("Error: no browser-test model configured in project-settings.json.");
53
- console.log("Add a block like:\n" +
54
- ' "browserTest": {\n' +
55
- ' "modelName": "gateway/anthropic/claude-haiku-4-5",\n' +
56
- ' "modelApiKey": "..."\n' +
57
- " }\n" +
58
- "to .requirements/project-settings.json. See the docs for supported models.");
59
- process.exit(1);
60
- }
61
- if ((modelName && !modelApiKey) || (modelApiKey && !modelName)) {
62
- console.error("Error: browserTest.modelName and browserTest.modelApiKey must be set together.");
63
- process.exit(1);
64
- }
65
- // 4. Load requirements
66
- const { flattened } = await loadAllRequirements(projectInfo.rootPath);
67
- if (flattened.length === 0) {
68
- console.error("Error: No requirements found in .requirements/");
69
- process.exit(1);
70
- }
71
- // 5. Find the requirement tree
72
- const requirementTree = getRequirementTree(flattened, requirementKey);
73
- if (requirementTree.length === 0) {
74
- console.error(`Error: Requirement "${requirementKey}" not found.`);
75
- process.exit(1);
76
- }
77
- // 6. Format each requirement as an assertion
78
- const assertions = requirementTree.map((req) => formatRequirement(req));
79
- // 7. Build environment with injected secrets
80
- const env = { ...process.env };
81
- // env var keeps the key out of process listings (not a CLI flag)
82
- if (modelApiKey) {
83
- env.MODEL_API_KEY = modelApiKey;
84
- }
85
- else if (geminiApiKey) {
86
- env.GEMINI_API_KEY = geminiApiKey;
87
- }
88
- if (settings?.browserTest?.vercelBypassSecret) {
89
- env.VERCEL_AUTOMATION_BYPASS_SECRET =
90
- settings.browserTest.vercelBypassSecret;
91
- }
92
- if (settings?.browserTest?.browserbaseApiKey) {
93
- env.BROWSERBASE_API_KEY = settings.browserTest.browserbaseApiKey;
94
- }
95
- if (settings?.browserTest?.browserbaseProjectId) {
96
- env.BROWSERBASE_PROJECT_ID = settings.browserTest.browserbaseProjectId;
97
- }
98
- // 8. Run browser-automation
99
- if (!options.json) {
100
- console.log(`Testing ${requirementKey} against ${targetURL}...\n`);
101
- }
102
- try {
103
- const modelFlags = modelName ? ["--modelName", modelName] : [];
104
- const { stdout } = await execFileAsync("npx", [
105
- "@popoverai/browser-automation",
106
- "test",
107
- ...modelFlags,
108
- targetURL,
109
- ...assertions,
110
- ], { env, maxBuffer: 10 * 1024 * 1024 });
111
- // 9. Parse results
112
- let results;
113
- try {
114
- const parsed = JSON.parse(stdout.trim());
115
- results = extractResults(parsed);
116
- }
117
- catch (parseErr) {
118
- console.error("Error: Could not parse browser-automation output");
119
- console.error(parseErr.message);
120
- console.error(stdout);
121
- process.exit(1);
122
- }
123
- // 10. Display results
124
- if (options.json) {
125
- outputJson(requirementTree, results);
126
- }
127
- else {
128
- displayResults(requirementTree, results);
129
- }
130
- // 11. Exit with appropriate code
131
- const failedCount = results.filter((r) => r.status !== "passed").length;
132
- if (failedCount > 0) {
133
- process.exit(1);
134
- }
135
- }
136
- catch (err) {
137
- const error = err;
138
- // browser-automation returns exit code 1 on failure, but still outputs JSON
139
- if (error.stdout) {
140
- try {
141
- const parsed = JSON.parse(error.stdout.trim());
142
- const results = extractResults(parsed);
143
- if (options.json) {
144
- outputJson(requirementTree, results);
145
- }
146
- else {
147
- displayResults(requirementTree, results);
148
- }
149
- process.exit(1);
150
- }
151
- catch {
152
- // Not JSON, show raw output
153
- console.error("browser-automation error:");
154
- if (error.stdout)
155
- console.error(error.stdout);
156
- if (error.stderr)
157
- console.error(error.stderr);
158
- process.exit(1);
159
- }
160
- }
161
- else {
162
- console.error(`Error running browser-automation: ${error.message}`);
163
- if (error.stderr)
164
- console.error(error.stderr);
165
- process.exit(1);
166
- }
167
- }
168
- }
169
- function displayResults(requirements, results) {
170
- let passedCount = 0;
171
- let failedCount = 0;
172
- for (let i = 0; i < requirements.length; i++) {
173
- const req = requirements[i];
174
- const result = results[i];
175
- if (!result) {
176
- console.log(` ? ${req.id}: No result`);
177
- failedCount++;
178
- continue;
179
- }
180
- const indent = " ".repeat(req.path.length);
181
- const label = req.label ? ` (${req.label})` : "";
182
- const icon = result.status === "passed" ? "\u2713" : "\u2717";
183
- console.log(`${indent}${icon} ${req.id}${label}: ${req.content}`);
184
- if (result.status !== "passed" && result.notes) {
185
- console.log(`${indent} \u2192 ${result.notes}`);
186
- }
187
- if (result.status === "passed") {
188
- passedCount++;
189
- }
190
- else {
191
- failedCount++;
192
- }
193
- }
194
- console.log();
195
- if (failedCount === 0) {
196
- console.log(`${passedCount}/${requirements.length} passed`);
197
- }
198
- else {
199
- console.log(`${passedCount}/${requirements.length} passed, ${failedCount} failed`);
200
- }
201
- }
202
- function outputJson(requirements, results) {
203
- const combined = requirements.map((req, i) => ({
204
- id: req.id,
205
- label: req.label || null,
206
- content: req.content,
207
- status: results[i]?.status || "blocked",
208
- notes: results[i]?.notes || null,
209
- }));
210
- console.log(JSON.stringify(combined, null, 2));
211
- }
212
- //# sourceMappingURL=browsertest.js.map
@@ -1,12 +0,0 @@
1
- /**
2
- * Login command - authenticate with WorkOS and manage project credentials.
3
- *
4
- * Implements:
5
- * - LOGIN-1: CLI OAuth implementation
6
- * - LOGIN-2: Upgrade from placeholder to real credentials
7
- * - LOGIN-3: Refresh existing project credentials
8
- * - LOGIN-4: Already logged in detection
9
- * - LOGIN-6: Handle missing .env.local
10
- */
11
- export declare function loginCommand(): Promise<void>;
12
- //# sourceMappingURL=login.d.ts.map
@@ -1,117 +0,0 @@
1
- /**
2
- * Login command - authenticate with WorkOS and manage project credentials.
3
- *
4
- * Implements:
5
- * - LOGIN-1: CLI OAuth implementation
6
- * - LOGIN-2: Upgrade from placeholder to real credentials
7
- * - LOGIN-3: Refresh existing project credentials
8
- * - LOGIN-4: Already logged in detection
9
- * - LOGIN-6: Handle missing .env.local
10
- */
11
- import { executeOAuthFlow } from '../utils/oauth-flow.js';
12
- import { getConvexUrl } from '../config.js';
13
- import { hasValidTokens } from '../utils/token-storage.js';
14
- import { isLocalOnlyProject } from '../utils/local-project.js';
15
- import * as fs from 'fs';
16
- import { ConvexHttpClient } from 'convex/browser';
17
- import { findUp } from 'find-up';
18
- import { brand } from '../utils/brand.js';
19
- export async function loginCommand() {
20
- console.log(`Logging in to ${brand}...\n`);
21
- // LOGIN-4: Check if already logged in
22
- if (await hasValidTokens()) {
23
- console.log('✓ Already logged in');
24
- console.log('Run "dotrequirements logout" to log in as a different user.');
25
- return;
26
- }
27
- // LOGIN-1: Execute OAuth flow
28
- const result = await executeOAuthFlow();
29
- console.log('\n✓ Logged in successfully!');
30
- // LOGIN-6: Check if there's a .env.local in the current directory
31
- const envPath = await findUp('.env.local');
32
- if (envPath) {
33
- await handleExistingProject(envPath, result.accessToken);
34
- }
35
- else {
36
- // LOGIN-6.1: No project in current directory
37
- console.log('\nNo project found in this directory.');
38
- console.log('Run "dotrequirements init" to create a new project in the current directory.');
39
- }
40
- }
41
- /**
42
- * Handle existing project based on credential type (placeholder vs real)
43
- */
44
- async function handleExistingProject(envPath, accessToken) {
45
- try {
46
- // Read .env.local to get project ID and secret
47
- const envContent = fs.readFileSync(envPath, 'utf-8');
48
- const projectIdMatch = envContent.match(/DOTREQUIREMENTS_PROJECT_ID=(.+)/);
49
- const secretMatch = envContent.match(/DOTREQUIREMENTS_PROJECT_SECRET=(.+)/);
50
- if (!projectIdMatch || !secretMatch) {
51
- console.log('\n.env.local found but missing project credentials.');
52
- return;
53
- }
54
- const projectId = projectIdMatch[1].trim();
55
- const projectSecret = secretMatch[1].trim();
56
- const convexUrl = getConvexUrl();
57
- const client = new ConvexHttpClient(convexUrl);
58
- client.setAuth(accessToken);
59
- // LOGIN-2: Check if placeholder credentials
60
- if (isLocalOnlyProject(projectId)) {
61
- await upgradeFromPlaceholder(envPath, envContent, client);
62
- }
63
- else {
64
- // LOGIN-3: Refresh existing project credentials
65
- await refreshCredentials(envPath, envContent, projectId, client);
66
- }
67
- }
68
- catch (error) {
69
- console.error('\nFailed to update project credentials:');
70
- console.error(error instanceof Error ? error.message : String(error));
71
- console.log('\nYour authentication was successful.');
72
- console.log('You can continue using the project with its existing credentials.');
73
- }
74
- }
75
- /**
76
- * LOGIN-2: Upgrade from placeholder credentials to real project
77
- */
78
- async function upgradeFromPlaceholder(envPath, envContent, client) {
79
- console.log('\nUpgrading from local-only mode to cloud access...');
80
- // LOGIN-2.0, LOGIN-2.1: Create team and project
81
- const result = await client.mutation('lib/authMutations:createProjectForAuthenticatedUser', {});
82
- if (!result.success) {
83
- throw new Error(result.error || 'Unknown error');
84
- }
85
- console.log('✓ Created new project in your team');
86
- // LOGIN-2.3: Update .env.local with real credentials
87
- const updatedEnv = envContent
88
- .replace(/DOTREQUIREMENTS_PROJECT_ID=.+/, `DOTREQUIREMENTS_PROJECT_ID=${result.projectId}`)
89
- .replace(/DOTREQUIREMENTS_PROJECT_SECRET=.+/, `DOTREQUIREMENTS_PROJECT_SECRET=${result.projectSecret}`);
90
- fs.writeFileSync(envPath, updatedEnv);
91
- console.log('✓ Updated .env.local with cloud credentials');
92
- // LOGIN-2.4: Display next steps
93
- console.log('\nYour project is now connected to the cloud!');
94
- console.log('Run "dotrequirements push" to sync your requirements.');
95
- }
96
- /**
97
- * LOGIN-3: Refresh existing project credentials
98
- */
99
- async function refreshCredentials(envPath, envContent, projectId, client) {
100
- console.log('\nRefreshing your project credentials...');
101
- // LOGIN-3.0: Verify access and generate new secret
102
- const result = await client.mutation('lib/authMutations:refreshProjectSecret', {
103
- projectId: projectId, // Cast to Id<"projects">
104
- });
105
- if (!result.success) {
106
- // LOGIN-3.4: User doesn't have access
107
- throw new Error(result.error || 'Unknown error');
108
- }
109
- // LOGIN-3.2: Update .env.local with new secret
110
- const updatedEnv = envContent.replace(/DOTREQUIREMENTS_PROJECT_SECRET=.+/, `DOTREQUIREMENTS_PROJECT_SECRET=${result.projectSecret}`);
111
- fs.writeFileSync(envPath, updatedEnv);
112
- // LOGIN-3.3: Confirm access extended
113
- const expiryDate = new Date(result.expiresAt).toLocaleDateString();
114
- console.log(`✓ Access extended until ${expiryDate}`);
115
- console.log('✓ Updated .env.local with new credentials');
116
- }
117
- //# sourceMappingURL=login.js.map
@@ -1,5 +0,0 @@
1
- /**
2
- * Logout command - clear stored authentication tokens.
3
- */
4
- export declare function logoutCommand(): Promise<void>;
5
- //# sourceMappingURL=logout.d.ts.map
@@ -1,17 +0,0 @@
1
- /**
2
- * Logout command - clear stored authentication tokens.
3
- */
4
- import { deleteTokens, hasValidTokens } from '../utils/token-storage.js';
5
- export async function logoutCommand() {
6
- const wasLoggedIn = await hasValidTokens();
7
- await deleteTokens();
8
- if (wasLoggedIn) {
9
- console.log('Logged out successfully.');
10
- }
11
- else {
12
- console.log('No active session found.');
13
- }
14
- console.log('\nYour project credentials in .env.local are unchanged.');
15
- console.log('Run "dotrequirements login" to authenticate again.');
16
- }
17
- //# sourceMappingURL=logout.js.map
@@ -1,5 +0,0 @@
1
- /**
2
- * MCP setup command - configures the MCP server for AI assistants
3
- */
4
- export declare function mcpSetupCommand(): Promise<void>;
5
- //# sourceMappingURL=mcp-setup.d.ts.map