@popoverai/dotrequirements 0.24.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 +3 -3
- package/dist/cli.js +0 -0
- package/package.json +2 -2
- package/dist/codebase-to-spec/prompts/planner-apply.d.ts +0 -12
- package/dist/codebase-to-spec/prompts/planner-apply.js +0 -32
- package/dist/commands/browsertest.d.ts +0 -6
- package/dist/commands/browsertest.js +0 -212
- 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 -441
- package/dist/commands/test.d.ts +0 -6
- package/dist/commands/test.js +0 -72
- package/dist/mcp/grep.d.ts +0 -24
- package/dist/mcp/grep.js +0 -306
- package/dist/mcp/handlers/coverage.d.ts +0 -44
- package/dist/mcp/handlers/coverage.js +0 -103
- package/dist/mcp/requirements.d.ts +0 -57
- package/dist/mcp/requirements.js +0 -155
- package/dist/mcp/testCodeExtractor.d.ts +0 -22
- package/dist/mcp/testCodeExtractor.js +0 -150
- 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/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Tests prove *something* works—but nobody is certain it's the right something.
|
|
|
9
9
|
|
|
10
10
|
**dot•requirements** closes this gap. Write requirements as structured Markdown, reference them directly in tests, and see coverage update automatically. When a requirement changes, the tests that validate it are one click away.
|
|
11
11
|
|
|
12
|
-
> **Alpha Software** — Under active development. Please report issues to support@
|
|
12
|
+
> **Alpha Software** — Under active development. Please report issues to support@dotrequirements.io.
|
|
13
13
|
|
|
14
14
|
## Who Is This For?
|
|
15
15
|
|
|
@@ -253,7 +253,7 @@ dotreq cts skill-install # install the conversational skill wr
|
|
|
253
253
|
|
|
254
254
|
`cts` shells out to `claude -p` and uses whatever auth mode you've configured for Claude Code. Each pipeline stage is also runnable on its own (`dotreq cts pack`, `plan-loop`, `fan-out`, `compose`, `edit-loop`, `present`) for partial re-runs and debugging.
|
|
255
255
|
|
|
256
|
-
> **Alpha:** output quality is prompt-sensitive and varies by codebase. See the [Codebase to Spec docs](https://dotrequirements.io/tools/cli/codebase-to-spec) for prerequisites, options, exit codes, and known rough edges. Feedback to support@
|
|
256
|
+
> **Alpha:** output quality is prompt-sensitive and varies by codebase. See the [Codebase to Spec docs](https://docs.dotrequirements.io/tools/cli/codebase-to-spec) for prerequisites, options, exit codes, and known rough edges. Feedback to support@dotrequirements.io welcome.
|
|
257
257
|
|
|
258
258
|
> **Heads up:** as of June 15, 2026, `claude -p` bills against your Claude subscription's API credit instead of the subscription seat (per Anthropic's May 13, 2026 announcement). `cts` runs will draw from that credit.
|
|
259
259
|
|
|
@@ -725,7 +725,7 @@ This file is automatically added to `.gitignore` during initialization.
|
|
|
725
725
|
|
|
726
726
|
- [Documentation](https://docs.dotrequirements.io)
|
|
727
727
|
- [Getting Started Guide](https://docs.dotrequirements.io/getting-started)
|
|
728
|
-
- [Support](mailto:support@
|
|
728
|
+
- [Support](mailto:support@dotrequirements.io)
|
|
729
729
|
|
|
730
730
|
---
|
|
731
731
|
|
package/dist/cli.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@popoverai/dotrequirements",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "Requirements tracking CLI, test harness, and MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"license": "MIT",
|
|
43
43
|
"homepage": "https://dotrequirements.io",
|
|
44
44
|
"bugs": {
|
|
45
|
-
"email": "support@
|
|
45
|
+
"email": "support@dotrequirements.io"
|
|
46
46
|
},
|
|
47
47
|
"engines": {
|
|
48
48
|
"node": ">=18"
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* System prompt for the applying planner (apply mode).
|
|
3
|
-
*
|
|
4
|
-
* Receives the prior outline + an explicit list of mechanical revisions and
|
|
5
|
-
* applies them verbatim. Used when the reviewer's verdict was
|
|
6
|
-
* `approved-with-revisions`.
|
|
7
|
-
*
|
|
8
|
-
* Requirements covered:
|
|
9
|
-
* - CTS-PLAN-4: Approved-with-revisions outline triggers one mechanical revision
|
|
10
|
-
*/
|
|
11
|
-
export declare const PLANNER_APPLY_PROMPT = "You are applying mechanical revisions to a planning outline. A reviewer has approved the outline subject to a specific list of small revisions. Your job is to apply each revision verbatim and emit the revised outline.\n\nYou are NOT revising the outline using your own judgment. You are NOT adding new areas, dropping existing areas, or restructuring. You ONLY apply the listed revisions.\n\nYou will output a JSON object matching the schema you have been given. No prose preamble, no explanation, no markdown fences \u2014 JSON only.\n\nYou will receive:\n1. The previous outline as JSON\n2. An explicit list of revisions, each phrased as a directive\n\n## Process\n\nFor each revision in the list:\n- Apply the directive exactly as stated.\n- If the directive is ambiguous or would require new judgment, leave that area unchanged and proceed.\n\nPreserve everything else from the prior outline byte-for-byte (modulo the listed changes).\n\n## Output\n\nOutput ONLY the JSON object matching the supplied schema. No preamble. Begin with `{`.";
|
|
12
|
-
//# sourceMappingURL=planner-apply.d.ts.map
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* System prompt for the applying planner (apply mode).
|
|
3
|
-
*
|
|
4
|
-
* Receives the prior outline + an explicit list of mechanical revisions and
|
|
5
|
-
* applies them verbatim. Used when the reviewer's verdict was
|
|
6
|
-
* `approved-with-revisions`.
|
|
7
|
-
*
|
|
8
|
-
* Requirements covered:
|
|
9
|
-
* - CTS-PLAN-4: Approved-with-revisions outline triggers one mechanical revision
|
|
10
|
-
*/
|
|
11
|
-
export const PLANNER_APPLY_PROMPT = `You are applying mechanical revisions to a planning outline. A reviewer has approved the outline subject to a specific list of small revisions. Your job is to apply each revision verbatim and emit the revised outline.
|
|
12
|
-
|
|
13
|
-
You are NOT revising the outline using your own judgment. You are NOT adding new areas, dropping existing areas, or restructuring. You ONLY apply the listed revisions.
|
|
14
|
-
|
|
15
|
-
You will output a JSON object matching the schema you have been given. No prose preamble, no explanation, no markdown fences — JSON only.
|
|
16
|
-
|
|
17
|
-
You will receive:
|
|
18
|
-
1. The previous outline as JSON
|
|
19
|
-
2. An explicit list of revisions, each phrased as a directive
|
|
20
|
-
|
|
21
|
-
## Process
|
|
22
|
-
|
|
23
|
-
For each revision in the list:
|
|
24
|
-
- Apply the directive exactly as stated.
|
|
25
|
-
- If the directive is ambiguous or would require new judgment, leave that area unchanged and proceed.
|
|
26
|
-
|
|
27
|
-
Preserve everything else from the prior outline byte-for-byte (modulo the listed changes).
|
|
28
|
-
|
|
29
|
-
## Output
|
|
30
|
-
|
|
31
|
-
Output ONLY the JSON object matching the supplied schema. No preamble. Begin with \`{\`.`;
|
|
32
|
-
//# sourceMappingURL=planner-apply.js.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
|
package/dist/commands/login.d.ts
DELETED
|
@@ -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
|
package/dist/commands/login.js
DELETED
|
@@ -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
|
package/dist/commands/logout.js
DELETED
|
@@ -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
|