@popoverai/dotrequirements 0.23.0 → 0.24.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 +167 -20
- 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-apply.d.ts +12 -0
- package/dist/codebase-to-spec/prompts/planner-apply.js +32 -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/acceptance-test.js +212 -0
- package/dist/commands/ai-setup.d.ts +5 -0
- package/dist/commands/ai-setup.js +441 -0
- package/dist/commands/browsertest.js +34 -27
- 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-setup.js +159 -149
- 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/test.js +53 -59
- 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/grep.d.ts +1 -1
- package/dist/mcp/grep.js +87 -42
- package/dist/mcp/handlers/authoring.d.ts +1 -1
- package/dist/mcp/handlers/authoring.js +30 -234
- package/dist/mcp/handlers/coverage.d.ts +1 -1
- package/dist/mcp/handlers/coverage.js +13 -15
- 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/mcp/requirements.d.ts +2 -2
- package/dist/mcp/requirements.js +30 -30
- package/dist/mcp/testCodeExtractor.js +24 -26
- package/dist/mcp/types.d.ts +1 -1
- 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/requirements/grep.d.ts +33 -0
- package/dist/requirements/grep.js +306 -0
- package/dist/requirements/index.d.ts +73 -0
- package/dist/requirements/index.js +174 -0
- package/dist/requirements/style-guide.d.ts +67 -0
- package/dist/requirements/style-guide.js +299 -0
- package/dist/requirements/testCodeExtractor.d.ts +22 -0
- package/dist/requirements/testCodeExtractor.js +150 -0
- 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 +2 -1
package/dist/schema/schemas.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Zod schemas for Markdown requirements format.
|
|
3
3
|
* TypeScript types are inferred from these schemas using z.infer<>.
|
|
4
4
|
*/
|
|
5
|
-
import { z } from
|
|
6
|
-
import { fromZodError } from
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { fromZodError } from "zod-validation-error";
|
|
7
7
|
// =============================================================================
|
|
8
8
|
// Prefix and Key Validation
|
|
9
9
|
// =============================================================================
|
|
@@ -24,21 +24,21 @@ export const REQUIREMENT_KEY_PATTERN = /^[A-Z][A-Z-]*-[0-9]+$/;
|
|
|
24
24
|
*/
|
|
25
25
|
export const RequirementPrefixSchema = z
|
|
26
26
|
.string()
|
|
27
|
-
.min(1,
|
|
28
|
-
.max(30,
|
|
27
|
+
.min(1, "Prefix must be at least 1 character")
|
|
28
|
+
.max(30, "Prefix must be at most 30 characters")
|
|
29
29
|
.transform((val) => val.toUpperCase())
|
|
30
|
-
.refine((val) => REQUIREMENT_PREFIX_PATTERN.test(val),
|
|
30
|
+
.refine((val) => REQUIREMENT_PREFIX_PATTERN.test(val), "Prefix must start with a letter and contain only uppercase letters and hyphens");
|
|
31
31
|
/**
|
|
32
32
|
* Zod schema for requirement key (PREFIX-number).
|
|
33
33
|
* Normalizes to uppercase and strips leading zeros from numbers.
|
|
34
34
|
*/
|
|
35
35
|
export const RequirementKeySchema = z
|
|
36
36
|
.string()
|
|
37
|
-
.refine((val) => REQUIREMENT_KEY_PATTERN.test(val.toUpperCase()),
|
|
37
|
+
.refine((val) => REQUIREMENT_KEY_PATTERN.test(val.toUpperCase()), "Key must be in format PREFIX-number (e.g., LOGIN-1, AUTH-42)")
|
|
38
38
|
.transform((val) => {
|
|
39
39
|
const upper = val.toUpperCase();
|
|
40
40
|
// Normalize leading zeros: LOGIN-01 -> LOGIN-1, LOGIN-007 -> LOGIN-7
|
|
41
|
-
return upper.replace(/-0+(\d+)$/,
|
|
41
|
+
return upper.replace(/-0+(\d+)$/, "-$1");
|
|
42
42
|
});
|
|
43
43
|
/**
|
|
44
44
|
* Normalize a prefix to uppercase.
|
|
@@ -54,8 +54,9 @@ export function normalizePrefix(prefix) {
|
|
|
54
54
|
export function validatePrefix(prefix) {
|
|
55
55
|
const result = RequirementPrefixSchema.safeParse(prefix);
|
|
56
56
|
if (!result.success) {
|
|
57
|
+
// biome-ignore lint/suspicious/noExplicitAny: zod-validation-error and our zod v3 ZodError have a typing mismatch across versions; the runtime shape is identical.
|
|
57
58
|
const validationError = fromZodError(result.error);
|
|
58
|
-
throw new ValidationError(`Invalid prefix "${prefix}": ${validationError.message}`,
|
|
59
|
+
throw new ValidationError(`Invalid prefix "${prefix}": ${validationError.message}`, "prefix", result.error);
|
|
59
60
|
}
|
|
60
61
|
return result.data;
|
|
61
62
|
}
|
|
@@ -66,8 +67,9 @@ export function validatePrefix(prefix) {
|
|
|
66
67
|
export function validateKey(key) {
|
|
67
68
|
const result = RequirementKeySchema.safeParse(key);
|
|
68
69
|
if (!result.success) {
|
|
70
|
+
// biome-ignore lint/suspicious/noExplicitAny: zod-validation-error and our zod v3 ZodError have a typing mismatch across versions; the runtime shape is identical.
|
|
69
71
|
const validationError = fromZodError(result.error);
|
|
70
|
-
throw new ValidationError(`Invalid key "${key}": ${validationError.message}`,
|
|
72
|
+
throw new ValidationError(`Invalid key "${key}": ${validationError.message}`, "key", result.error);
|
|
71
73
|
}
|
|
72
74
|
return result.data;
|
|
73
75
|
}
|
|
@@ -93,10 +95,10 @@ export function parseRequirementKey(key) {
|
|
|
93
95
|
export function buildRequirementKey(prefix, number) {
|
|
94
96
|
const normalizedPrefix = prefix.toUpperCase();
|
|
95
97
|
if (!REQUIREMENT_PREFIX_PATTERN.test(normalizedPrefix)) {
|
|
96
|
-
throw new ValidationError(`Invalid prefix "${prefix}": must match pattern ${REQUIREMENT_PREFIX_PATTERN}`,
|
|
98
|
+
throw new ValidationError(`Invalid prefix "${prefix}": must match pattern ${REQUIREMENT_PREFIX_PATTERN}`, "prefix");
|
|
97
99
|
}
|
|
98
100
|
if (number < 0 || !Number.isInteger(number)) {
|
|
99
|
-
throw new ValidationError(`Invalid number "${number}": must be a non-negative integer`,
|
|
101
|
+
throw new ValidationError(`Invalid number "${number}": must be a non-negative integer`, "number");
|
|
100
102
|
}
|
|
101
103
|
return `${normalizedPrefix}-${number}`;
|
|
102
104
|
}
|
|
@@ -110,11 +112,13 @@ export function buildRequirementKey(prefix, number) {
|
|
|
110
112
|
export const MetadataSchema = z.object({
|
|
111
113
|
version: z.number().optional(), // Informational - incremented on push
|
|
112
114
|
pulledAt: z.string().optional(), // ISO 8601 timestamp - used for conflict detection
|
|
113
|
-
document: z
|
|
115
|
+
document: z
|
|
116
|
+
.object({
|
|
114
117
|
id: z.string().optional(), // Cloud document link - filled by push when creating
|
|
115
118
|
title: z.string(), // Required for push
|
|
116
119
|
defaultPrefix: z.string().optional(), // Editor hint for new requirement keys
|
|
117
|
-
})
|
|
120
|
+
})
|
|
121
|
+
.optional(),
|
|
118
122
|
});
|
|
119
123
|
// =============================================================================
|
|
120
124
|
// Push Readiness Validation
|
|
@@ -135,31 +139,31 @@ export function validateForPush(metadata) {
|
|
|
135
139
|
if (!metadata.document) {
|
|
136
140
|
return {
|
|
137
141
|
valid: false,
|
|
138
|
-
reason:
|
|
142
|
+
reason: "Missing document section. Add a document section with a title to push this file.",
|
|
139
143
|
};
|
|
140
144
|
}
|
|
141
145
|
// Must have title
|
|
142
|
-
if (!metadata.document.title || metadata.document.title.trim() ===
|
|
146
|
+
if (!metadata.document.title || metadata.document.title.trim() === "") {
|
|
143
147
|
return {
|
|
144
148
|
valid: false,
|
|
145
|
-
reason:
|
|
149
|
+
reason: "Document section missing required title.",
|
|
146
150
|
};
|
|
147
151
|
}
|
|
148
152
|
// Check document.id
|
|
149
153
|
if (!metadata.document.id) {
|
|
150
154
|
// No ID = create new document
|
|
151
|
-
return { valid: true, action:
|
|
155
|
+
return { valid: true, action: "create" };
|
|
152
156
|
}
|
|
153
157
|
// Has ID - check if it's a valid Convex ID
|
|
154
158
|
if (CONVEX_ID_PATTERN.test(metadata.document.id)) {
|
|
155
159
|
// Valid Convex ID = update existing document
|
|
156
|
-
return { valid: true, action:
|
|
160
|
+
return { valid: true, action: "update" };
|
|
157
161
|
}
|
|
158
162
|
// Invalid ID format - will create new document and overwrite
|
|
159
163
|
return {
|
|
160
164
|
valid: true,
|
|
161
|
-
action:
|
|
162
|
-
warning: `Invalid document ID '${metadata.document.id}' will be replaced with a new ID
|
|
165
|
+
action: "create",
|
|
166
|
+
warning: `Invalid document ID '${metadata.document.id}' will be replaced with a new ID.`,
|
|
163
167
|
};
|
|
164
168
|
}
|
|
165
169
|
/**
|
|
@@ -172,31 +176,37 @@ export const RequirementNodeSchema = z.lazy(() => z.object({
|
|
|
172
176
|
content: z.string(), // The actual requirement text
|
|
173
177
|
children: z.array(RequirementNodeSchema).default([]),
|
|
174
178
|
// Optional metadata preserved from Convex
|
|
175
|
-
metadata: z
|
|
179
|
+
metadata: z
|
|
180
|
+
.object({
|
|
176
181
|
convexId: z.string().optional(), // Convex _id
|
|
177
182
|
rootId: z.string().optional(), // Convex rootId
|
|
178
183
|
position: z.string().optional(), // Convex position path
|
|
179
184
|
updatedAt: z.number().optional(),
|
|
180
|
-
externalLinks: z
|
|
185
|
+
externalLinks: z
|
|
186
|
+
.object({
|
|
181
187
|
jira: z.string().optional(),
|
|
182
188
|
notion: z.string().optional(),
|
|
183
|
-
})
|
|
189
|
+
})
|
|
190
|
+
.optional(),
|
|
184
191
|
// New schema fields for bidirectional sync
|
|
185
192
|
prefix: z.string().optional(), // e.g., "REQ"
|
|
186
193
|
index: z.number().optional(), // e.g., 123
|
|
187
194
|
documentId: z.string().optional(), // Convex document ID
|
|
188
|
-
})
|
|
195
|
+
})
|
|
196
|
+
.optional(),
|
|
189
197
|
}));
|
|
190
198
|
/**
|
|
191
199
|
* Complete requirements file structure.
|
|
192
200
|
* Top-level keys are either "_meta" or requirement IDs.
|
|
193
201
|
*/
|
|
194
|
-
export const RequirementsFileSchema = z
|
|
202
|
+
export const RequirementsFileSchema = z
|
|
203
|
+
.object({
|
|
195
204
|
_meta: MetadataSchema,
|
|
196
205
|
// All other keys are requirement roots
|
|
197
206
|
// We'll validate the structure separately since Zod doesn't handle
|
|
198
207
|
// arbitrary keys with specific structure well
|
|
199
|
-
})
|
|
208
|
+
})
|
|
209
|
+
.passthrough(); // Allow additional keys
|
|
200
210
|
/**
|
|
201
211
|
* Parsed criterion from Markdown (position. Label: content format)
|
|
202
212
|
* Example: "0. Given: user has valid credentials"
|
|
@@ -216,7 +226,7 @@ export class ValidationError extends Error {
|
|
|
216
226
|
super(message);
|
|
217
227
|
this.path = path;
|
|
218
228
|
this.cause = cause;
|
|
219
|
-
this.name =
|
|
229
|
+
this.name = "ValidationError";
|
|
220
230
|
}
|
|
221
231
|
}
|
|
222
232
|
/**
|
|
@@ -225,8 +235,9 @@ export class ValidationError extends Error {
|
|
|
225
235
|
export function validateMetadata(data) {
|
|
226
236
|
const result = MetadataSchema.safeParse(data);
|
|
227
237
|
if (!result.success) {
|
|
238
|
+
// biome-ignore lint/suspicious/noExplicitAny: zod-validation-error and our zod v3 ZodError have a typing mismatch across versions; the runtime shape is identical.
|
|
228
239
|
const validationError = fromZodError(result.error);
|
|
229
|
-
throw new ValidationError(`Invalid metadata block:\n${validationError.message}`,
|
|
240
|
+
throw new ValidationError(`Invalid metadata block:\n${validationError.message}`, "_meta", result.error);
|
|
230
241
|
}
|
|
231
242
|
return result.data;
|
|
232
243
|
}
|
|
@@ -236,6 +247,7 @@ export function validateMetadata(data) {
|
|
|
236
247
|
export function validateRequirementNode(data, path) {
|
|
237
248
|
const result = RequirementNodeSchema.safeParse(data);
|
|
238
249
|
if (!result.success) {
|
|
250
|
+
// biome-ignore lint/suspicious/noExplicitAny: zod-validation-error and our zod v3 ZodError have a typing mismatch across versions; the runtime shape is identical.
|
|
239
251
|
const validationError = fromZodError(result.error);
|
|
240
252
|
throw new ValidationError(`Invalid requirement node structure at ${path}:\n${validationError.message}`, path, result.error);
|
|
241
253
|
}
|
|
@@ -247,6 +259,7 @@ export function validateRequirementNode(data, path) {
|
|
|
247
259
|
export function validateRequirementsFile(data) {
|
|
248
260
|
const result = RequirementsFileSchema.safeParse(data);
|
|
249
261
|
if (!result.success) {
|
|
262
|
+
// biome-ignore lint/suspicious/noExplicitAny: zod-validation-error and our zod v3 ZodError have a typing mismatch across versions; the runtime shape is identical.
|
|
250
263
|
const validationError = fromZodError(result.error);
|
|
251
264
|
throw new ValidationError(`Invalid requirements file structure:\n${validationError.message}`, undefined, result.error);
|
|
252
265
|
}
|
|
@@ -1,59 +1,59 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Quick test to verify the new YAML schema is valid and round-trips correctly.
|
|
3
3
|
*/
|
|
4
|
-
import { buildRequirementsMarkdown, parseRequirementsFile,
|
|
4
|
+
import { buildMetadata, buildRequirementsMarkdown, parseRequirementsFile, } from "./index.js";
|
|
5
5
|
// Create test data
|
|
6
6
|
const metadata = buildMetadata(1);
|
|
7
7
|
const testRequirements = [
|
|
8
8
|
{
|
|
9
|
-
id:
|
|
10
|
-
label:
|
|
11
|
-
content:
|
|
9
|
+
id: "REQ123",
|
|
10
|
+
label: "requirement",
|
|
11
|
+
content: "User can authenticate",
|
|
12
12
|
children: [
|
|
13
13
|
{
|
|
14
|
-
id:
|
|
15
|
-
label:
|
|
16
|
-
content:
|
|
14
|
+
id: "REQ123.0",
|
|
15
|
+
label: "given",
|
|
16
|
+
content: "user has valid credentials",
|
|
17
17
|
children: [],
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
id:
|
|
21
|
-
label:
|
|
22
|
-
content:
|
|
20
|
+
id: "REQ123.1",
|
|
21
|
+
label: "when",
|
|
22
|
+
content: "user submits login form",
|
|
23
23
|
children: [
|
|
24
24
|
{
|
|
25
|
-
id:
|
|
26
|
-
label:
|
|
27
|
-
content:
|
|
25
|
+
id: "REQ123.1.0",
|
|
26
|
+
label: "then",
|
|
27
|
+
content: "system validates credentials",
|
|
28
28
|
children: [],
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
|
-
id:
|
|
32
|
-
label:
|
|
33
|
-
content:
|
|
31
|
+
id: "REQ123.1.1",
|
|
32
|
+
label: "then",
|
|
33
|
+
content: "system creates session",
|
|
34
34
|
children: [],
|
|
35
35
|
},
|
|
36
36
|
],
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
|
-
id:
|
|
40
|
-
label:
|
|
41
|
-
content:
|
|
39
|
+
id: "REQ123.2",
|
|
40
|
+
label: "then",
|
|
41
|
+
content: "user is redirected to dashboard",
|
|
42
42
|
children: [],
|
|
43
43
|
},
|
|
44
44
|
],
|
|
45
45
|
},
|
|
46
46
|
];
|
|
47
|
-
console.log(
|
|
47
|
+
console.log("=== Building Markdown ===\n");
|
|
48
48
|
const markdown = buildRequirementsMarkdown(metadata, testRequirements);
|
|
49
49
|
console.log(markdown);
|
|
50
|
-
console.log(
|
|
50
|
+
console.log("\n=== Parsing Markdown back ===\n");
|
|
51
51
|
try {
|
|
52
52
|
const { metadata: parsedMeta, requirements: parsedReqs } = parseRequirementsFile(markdown);
|
|
53
|
-
console.log(
|
|
54
|
-
console.log(
|
|
53
|
+
console.log("Metadata:", JSON.stringify(parsedMeta, null, 2));
|
|
54
|
+
console.log("\nRequirements tree:");
|
|
55
55
|
function printTree(node, indent = 0) {
|
|
56
|
-
const spaces =
|
|
56
|
+
const spaces = " ".repeat(indent);
|
|
57
57
|
console.log(`${spaces}${node.id}: ${node.label} → ${node.content}`);
|
|
58
58
|
for (const child of node.children) {
|
|
59
59
|
printTree(child, indent + 1);
|
|
@@ -62,9 +62,9 @@ try {
|
|
|
62
62
|
for (const req of parsedReqs) {
|
|
63
63
|
printTree(req);
|
|
64
64
|
}
|
|
65
|
-
console.log(
|
|
65
|
+
console.log("\n✅ Round-trip successful!");
|
|
66
66
|
// Verify structure
|
|
67
|
-
console.log(
|
|
67
|
+
console.log("\n=== Verifying structure ===");
|
|
68
68
|
const req = parsedReqs[0];
|
|
69
69
|
console.log(`Root ID: ${req.id}`);
|
|
70
70
|
console.log(`Root label: ${req.label}`);
|
|
@@ -75,7 +75,7 @@ try {
|
|
|
75
75
|
console.log(`First grandchild ID: ${req.children[1].children[0].id}`);
|
|
76
76
|
}
|
|
77
77
|
catch (error) {
|
|
78
|
-
console.error(
|
|
78
|
+
console.error("❌ Failed to parse Markdown:", error);
|
|
79
79
|
process.exit(1);
|
|
80
80
|
}
|
|
81
81
|
//# sourceMappingURL=test-schema.js.map
|
|
@@ -47,7 +47,7 @@ test(requirement('REQ-ID.0'), () => { /* test specific criterion */ });
|
|
|
47
47
|
### MCP Tools
|
|
48
48
|
|
|
49
49
|
**Exploration:**
|
|
50
|
-
- `
|
|
50
|
+
- `list_requirements` - Overview of all requirements (set `untested: true` to filter to coverage gaps)
|
|
51
51
|
- `get_requirement` - Requirement tree with test coverage
|
|
52
52
|
- `search_requirements` - Search by text/regex
|
|
53
53
|
|
|
@@ -59,5 +59,6 @@ test(requirement('REQ-ID.0'), () => { /* test specific criterion */ });
|
|
|
59
59
|
|
|
60
60
|
**Testing:**
|
|
61
61
|
- `get_requirements_by_test` - See requirements a test file covers
|
|
62
|
-
- `
|
|
62
|
+
- `list_requirements` (with `untested: true`) - Find requirements without tests
|
|
63
|
+
- `report_coverage` - Get test coverage from local cache or cloud
|
|
63
64
|
- `review_test` - Validate tests match requirement intent
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This template is used for both local-only and authenticated init flows.
|
|
5
5
|
* It demonstrates the dotrequirements markdown format with nested requirements.
|
|
6
6
|
*/
|
|
7
|
-
export function generateExampleRequirements(projectId =
|
|
7
|
+
export function generateExampleRequirements(projectId = "local") {
|
|
8
8
|
const now = new Date().toISOString();
|
|
9
9
|
return `---
|
|
10
10
|
projectId: ${projectId}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* This template is used for both local-only and authenticated init flows.
|
|
5
5
|
* It demonstrates the dotrequirements markdown format with nested requirements.
|
|
6
6
|
*/
|
|
7
|
-
export function generateExampleRequirements(
|
|
7
|
+
export function generateExampleRequirements(
|
|
8
|
+
projectId: string = "local",
|
|
9
|
+
): string {
|
|
8
10
|
const now = new Date().toISOString();
|
|
9
11
|
|
|
10
12
|
return `---
|
|
@@ -23,7 +23,7 @@ Requirements use the \`*.requirements.md\` naming pattern. See the [Requirements
|
|
|
23
23
|
|
|
24
24
|
- \`dotrequirements pull\` - Sync requirements from cloud
|
|
25
25
|
- \`dotrequirements push\` - Push local requirements to cloud
|
|
26
|
-
- \`dotrequirements
|
|
26
|
+
- \`dotrequirements validate\` - Validate requirement files
|
|
27
27
|
|
|
28
28
|
Learn more: https://dotrequirements.io
|
|
29
29
|
`;
|
|
@@ -23,7 +23,7 @@ Requirements use the \`*.requirements.md\` naming pattern. See the [Requirements
|
|
|
23
23
|
|
|
24
24
|
- \`dotrequirements pull\` - Sync requirements from cloud
|
|
25
25
|
- \`dotrequirements push\` - Push local requirements to cloud
|
|
26
|
-
- \`dotrequirements
|
|
26
|
+
- \`dotrequirements validate\` - Validate requirement files
|
|
27
27
|
|
|
28
28
|
Learn more: https://dotrequirements.io
|
|
29
29
|
`;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codebase-to-spec
|
|
3
|
+
description: Generate dotrequirements behavioral specifications from a codebase. Use this when the user wants to capture what an existing codebase does as a set of testable behavioral requirements — e.g. for legacy systems, third-party libraries, or before refactoring.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Codebase to Spec
|
|
7
|
+
|
|
8
|
+
You are a thin conversational wrapper around the `dotrequirements cts run` CLI. **You do not implement any pipeline logic yourself.** The CLI handles packing, planning, fan-out parallelism, retry, resumability, review loops, and presentation. Your job is to:
|
|
9
|
+
|
|
10
|
+
1. Confirm the user's scope.
|
|
11
|
+
2. Run the CLI via the Bash tool.
|
|
12
|
+
3. Narrate progress as the CLI emits it.
|
|
13
|
+
4. Surface the final summary and residual notes.
|
|
14
|
+
5. Offer sensible follow-ups (push to cloud, re-run, narrow scope, etc.).
|
|
15
|
+
|
|
16
|
+
## When this skill is right
|
|
17
|
+
|
|
18
|
+
Use it when the user wants behavioral requirements *from* code that already exists. Typical phrasings:
|
|
19
|
+
- "Generate requirements from this codebase"
|
|
20
|
+
- "Capture the behavior of this library"
|
|
21
|
+
- "I want a behavioral spec for the auth module"
|
|
22
|
+
- "Document what this service does"
|
|
23
|
+
|
|
24
|
+
Do **not** use it for:
|
|
25
|
+
- New feature design (use `dotreq-requirements` / the capture flow instead)
|
|
26
|
+
- Bug investigation
|
|
27
|
+
- Code review
|
|
28
|
+
|
|
29
|
+
## Workflow
|
|
30
|
+
|
|
31
|
+
### Step 1 — Confirm scope
|
|
32
|
+
|
|
33
|
+
If the user passed a scope argument (e.g. a path like `src/auth`), use it. Otherwise, ask one concise question:
|
|
34
|
+
|
|
35
|
+
> "Which part of the codebase should I spec? You can give me a path (e.g. `src/auth`) or say 'the whole thing'."
|
|
36
|
+
|
|
37
|
+
Whole-codebase runs are fine for small repos. For larger ones, encourage scoping to a single area — the CLI will tell you if the working-context budget is exceeded.
|
|
38
|
+
|
|
39
|
+
### Step 2 — Run the CLI
|
|
40
|
+
|
|
41
|
+
Invoke the pipeline via Bash. The command is:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
dotrequirements cts run --scope <PATH> --non-interactive
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Flags:
|
|
48
|
+
- `--scope <path>` — limit packing to a subdirectory. Omit for the whole repo.
|
|
49
|
+
- `--non-interactive` — important: you're running in an agentic context, so prompts won't work.
|
|
50
|
+
- `--overwrite` — replace existing `.requirements/*.requirements.md` files.
|
|
51
|
+
- `--skip-existing` — leave existing files untouched.
|
|
52
|
+
- `--fresh` — clear the cache before running (use only if a previous run is corrupt).
|
|
53
|
+
|
|
54
|
+
Default to `--non-interactive`. Decide between `--overwrite` and `--skip-existing` based on what the user wants if there are existing `.requirements/` files; otherwise neither flag is needed (the default `fail-fast` policy will surface conflicts).
|
|
55
|
+
|
|
56
|
+
### Step 3 — Narrate progress
|
|
57
|
+
|
|
58
|
+
The CLI emits lines like:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
[CTS] pack/done Packed 16 files → ... (compressed), ... (uncompressed)
|
|
62
|
+
[CTS] plan/done Plan loop converged at turn 1 with verdict: approved-with-revisions
|
|
63
|
+
[CTS] specify/summary Completed: 7 / Skipped (resume): 0 / Failed: 0
|
|
64
|
+
[CTS] spec-review/done Edit loop converged at turn 1 with verdict: approved-with-revisions
|
|
65
|
+
[CTS] present/created created: .../sample.requirements.md
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Surface these to the user in conversational form as they appear. **Do not invent progress claims** — narrate only what the CLI has actually emitted. If the CLI is silent for a long stretch (specifier fan-out can take minutes), a single reassuring note ("still working — the specifier fan-out runs in parallel and takes a few minutes for larger areas") is fine. Don't repeat it.
|
|
69
|
+
|
|
70
|
+
### Step 4 — Surface the final summary
|
|
71
|
+
|
|
72
|
+
When the CLI finishes successfully, it prints a "Pipeline summary:" block with:
|
|
73
|
+
- total areas
|
|
74
|
+
- total top-level requirements
|
|
75
|
+
- outline review turns and verdict
|
|
76
|
+
- specifier completion count
|
|
77
|
+
- spec review turns and verdict
|
|
78
|
+
- the list of output files written
|
|
79
|
+
- residual notes (issues the reviewer flagged in `approved-with-revisions` outcomes)
|
|
80
|
+
|
|
81
|
+
Present that summary back to the user. **Highlight the residual notes** prominently — these are concerns the reviewer wanted the human to verify. Common categories:
|
|
82
|
+
- `outline.coverage_gap` — files the planner didn't assign to any area
|
|
83
|
+
- `spec.coverage_gap` — behaviors the spec missed
|
|
84
|
+
- `spec.framing_error` — requirements written as guidance/explanation rather than observable behavior
|
|
85
|
+
- `spec.cross_area` — duplication across areas
|
|
86
|
+
- `spec.internal_mechanics` — internal vocabulary that leaked into a user-facing spec
|
|
87
|
+
|
|
88
|
+
### Step 5 — Offer follow-ups
|
|
89
|
+
|
|
90
|
+
After surfacing the summary, ask the user what they want next. Useful options:
|
|
91
|
+
|
|
92
|
+
- **Push to cloud** — `dotrequirements push` syncs the generated `.requirements/*.requirements.md` files to dotrequirements cloud. Only suggest this if the user has a cloud account (you can check by reading `.dotrequirements/config.json` or asking).
|
|
93
|
+
- **Refine a specific area** — re-run `dotrequirements cts specify-area "<name>"` for one area, optionally with `--model <name>` for a stronger model.
|
|
94
|
+
- **Refine the whole spec** — re-run `dotrequirements cts edit-loop` to iterate on the composed spec.
|
|
95
|
+
- **Narrow the scope** — re-run with a smaller `--scope`.
|
|
96
|
+
- **Hand-edit** — the output files are plain Markdown; the user can edit them directly.
|
|
97
|
+
|
|
98
|
+
## Failure handling
|
|
99
|
+
|
|
100
|
+
The CLI uses stable exit codes (see `dotrequirements cts run --help`). Common cases:
|
|
101
|
+
|
|
102
|
+
- **Exit code 10 (BudgetExceeded)** — the codebase is too large for a single agent's context window after compression. Explain this in plain language and offer to retry with a narrower `--scope`.
|
|
103
|
+
- **Exit code 11 (MaxTurnsHit)** — a review loop hit its cap without converging. The CLI still writes the latest artifact; surface the residual review and ask the user whether to ship it, re-run the stage (`dotrequirements cts edit-loop`), or hand-edit.
|
|
104
|
+
- **Exit code 12 (OverwriteRefused)** — existing `.requirements/` files would be overwritten in non-interactive mode. Offer `--overwrite` or `--skip-existing`.
|
|
105
|
+
- **Exit code 3 (StageFailed)** — a stage errored. Read stderr for details. Offer: resume (re-run the same command — the cache means earlier stages are skipped), restart fresh (`--fresh`), or investigate (read files in `.dotrequirements-cache/`).
|
|
106
|
+
- **Any other non-zero exit** — surface stderr verbatim, then offer the same three options.
|
|
107
|
+
|
|
108
|
+
## What you must NOT do
|
|
109
|
+
|
|
110
|
+
- Don't try to generate requirements yourself; always use the CLI.
|
|
111
|
+
- Don't paraphrase or summarize the CLI's progress lines in ways that change their meaning.
|
|
112
|
+
- Don't claim the pipeline did something it didn't (e.g. don't say "the reviewer approved this" if the verdict was `approved-with-revisions`).
|
|
113
|
+
- Don't push to cloud without asking — `dotrequirements push` is a destructive sync.
|
|
114
|
+
- Don't suggest editing files inside `.dotrequirements-cache/`; that's internal CLI state.
|
|
115
|
+
|
|
116
|
+
## Host portability
|
|
117
|
+
|
|
118
|
+
This skill makes no assumptions about subagent mechanisms, Task tools, or framework-specific features. Its only host requirements are: Agent Skills format support, a Bash tool (or equivalent shell-out), and `dotrequirements` installed on the user's machine.
|
package/dist/utils/brand.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import chalk from
|
|
1
|
+
import chalk from "chalk";
|
|
2
2
|
// Cyan color: rgb(8, 145, 178)
|
|
3
3
|
const bulletColor = chalk.rgb(8, 145, 178);
|
|
4
4
|
/** Branded name for terminal output (colored bullet) */
|
|
5
|
-
export const brand = `dot${bulletColor(
|
|
5
|
+
export const brand = `dot${bulletColor("•")}requirements`;
|
|
6
6
|
/** Branded name for plain text (MCP descriptions, etc) */
|
|
7
|
-
export const brandPlain =
|
|
7
|
+
export const brandPlain = "dot•requirements";
|
|
8
8
|
//# sourceMappingURL=brand.js.map
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Uses the `open` npm package for secure, cross-platform browser launching
|
|
7
7
|
* without shell command injection vulnerabilities.
|
|
8
8
|
*/
|
|
9
|
-
import open from
|
|
9
|
+
import open from "open";
|
|
10
10
|
/**
|
|
11
11
|
* Open a URL in the user's default browser
|
|
12
12
|
*
|
|
@@ -26,10 +26,10 @@ export async function openBrowser(url) {
|
|
|
26
26
|
export async function openBrowserWithFallback(url) {
|
|
27
27
|
try {
|
|
28
28
|
await openBrowser(url);
|
|
29
|
-
console.log(
|
|
29
|
+
console.log("Opening browser for authentication...");
|
|
30
30
|
}
|
|
31
|
-
catch
|
|
32
|
-
console.error(
|
|
31
|
+
catch {
|
|
32
|
+
console.error("Could not automatically open browser.");
|
|
33
33
|
console.log(`\nPlease open this URL in your browser manually:\n${url}\n`);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -28,7 +28,7 @@ export declare function wrapInSectionMarkers(content: string): string;
|
|
|
28
28
|
* Returns: { action: 'created' | 'appended' | 'updated', existingContent?: string }
|
|
29
29
|
*/
|
|
30
30
|
export declare function appendOrUpdateSection(filePath: string, sectionContent: string): {
|
|
31
|
-
action:
|
|
31
|
+
action: "created" | "appended" | "updated";
|
|
32
32
|
existingContent?: string;
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync
|
|
2
|
-
import {
|
|
3
|
-
import { findUp } from
|
|
4
|
-
const SECTION_START =
|
|
5
|
-
const SECTION_END =
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { findUp } from "find-up";
|
|
4
|
+
const SECTION_START = "<!-- dotrequirements:start -->";
|
|
5
|
+
const SECTION_END = "<!-- dotrequirements:end -->";
|
|
6
6
|
/**
|
|
7
7
|
* Platform to context file mapping
|
|
8
8
|
*/
|
|
9
9
|
const PLATFORM_CONTEXT_FILES = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
"claude-code": "CLAUDE.md",
|
|
11
|
+
cursor: "AGENTS.md",
|
|
12
|
+
codex: "AGENTS.md",
|
|
13
|
+
"github-copilot": "AGENTS.md",
|
|
14
|
+
antigravity: "GEMINI.md",
|
|
15
15
|
};
|
|
16
16
|
/**
|
|
17
17
|
* Get the appropriate context file name for a platform
|
|
@@ -23,7 +23,7 @@ export function getContextFileName(platform) {
|
|
|
23
23
|
* Find the git root directory
|
|
24
24
|
*/
|
|
25
25
|
export async function findGitRoot() {
|
|
26
|
-
const gitDir = await findUp(
|
|
26
|
+
const gitDir = await findUp(".git", { type: "directory" });
|
|
27
27
|
return gitDir ? dirname(gitDir) : null;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
@@ -61,23 +61,23 @@ export function appendOrUpdateSection(filePath, sectionContent) {
|
|
|
61
61
|
const wrappedContent = wrapInSectionMarkers(sectionContent);
|
|
62
62
|
if (!existsSync(filePath)) {
|
|
63
63
|
// Create new file with just the section
|
|
64
|
-
writeFileSync(filePath, wrappedContent
|
|
65
|
-
return { action:
|
|
64
|
+
writeFileSync(filePath, `${wrappedContent}\n`, "utf-8");
|
|
65
|
+
return { action: "created" };
|
|
66
66
|
}
|
|
67
|
-
const existingFile = readFileSync(filePath,
|
|
67
|
+
const existingFile = readFileSync(filePath, "utf-8");
|
|
68
68
|
const existingSection = findDotrequirementsSection(existingFile);
|
|
69
69
|
if (!existingSection) {
|
|
70
70
|
// Append section to end of file
|
|
71
|
-
const separator = existingFile.endsWith(
|
|
72
|
-
writeFileSync(filePath, existingFile + separator + wrappedContent
|
|
73
|
-
return { action:
|
|
71
|
+
const separator = existingFile.endsWith("\n") ? "\n" : "\n\n";
|
|
72
|
+
writeFileSync(filePath, `${existingFile + separator + wrappedContent}\n`, "utf-8");
|
|
73
|
+
return { action: "appended" };
|
|
74
74
|
}
|
|
75
75
|
// Replace existing section
|
|
76
76
|
const newContent = existingFile.slice(0, existingSection.start) +
|
|
77
77
|
wrappedContent +
|
|
78
78
|
existingFile.slice(existingSection.end);
|
|
79
|
-
writeFileSync(filePath, newContent,
|
|
80
|
-
return { action:
|
|
79
|
+
writeFileSync(filePath, newContent, "utf-8");
|
|
80
|
+
return { action: "updated", existingContent: existingSection.content };
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
83
|
* Get the full path to the context file for a platform
|
|
@@ -102,12 +102,12 @@ export function buildNoGitRepoMessage(fileName) {
|
|
|
102
102
|
return [
|
|
103
103
|
`⚠️ Skipped writing ${fileName}: not inside a git repository.`,
|
|
104
104
|
` ${fileName} would have been created at the git repo root, but no .git directory was found.`,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
].join(
|
|
105
|
+
"",
|
|
106
|
+
" To finish setup, either:",
|
|
107
|
+
" • run `git init` here, then re-run `dotreq ai-setup`, or",
|
|
108
|
+
" • `cd` into an existing project directory and run `dotreq ai-setup` there.",
|
|
109
|
+
"",
|
|
110
|
+
" Note: the MCP server itself was configured successfully — only the context file step was skipped.",
|
|
111
|
+
].join("\n");
|
|
112
112
|
}
|
|
113
113
|
//# sourceMappingURL=context-file.js.map
|