@popoverai/dotrequirements 0.27.0 → 0.27.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.
- package/README.md +3 -3
- package/dist/commands/create-requirement-document.js +2 -1
- package/dist/commands/link.js +1 -1
- package/dist/commands/style-check.js +2 -1
- package/dist/requirements/style-guide-file.d.ts +21 -0
- package/dist/requirements/style-guide-file.js +30 -0
- package/dist/requirements/style-guide.d.ts +20 -22
- package/dist/requirements/style-guide.js +57 -35
- package/dist/schema/browser.d.ts +1 -1
- package/dist/schema/browser.js +4 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/index.js +1 -1
- package/dist/schema/parser-core.d.ts +15 -0
- package/dist/schema/parser-core.js +18 -3
- package/dist/schema/parser.d.ts +1 -1
- package/dist/schema/parser.js +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ pnpm add @popoverai/dotrequirements
|
|
|
32
32
|
### 1. Initialize a project
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
npx
|
|
35
|
+
npx @popoverai/dotrequirements@latest init
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
This creates a `.requirements/` directory with example requirements and configures your project.
|
|
@@ -111,7 +111,7 @@ dotreq init --invite abc123xyz
|
|
|
111
111
|
If a team admin shares an invite command with you, join the team and connect in one step:
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
|
-
npx dotrequirements init --invite abc123xyz
|
|
114
|
+
npx @popoverai/dotrequirements@latest init --invite abc123xyz
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
This shows the team name, prompts you to sign in, adds you to the team, and lets you select a project.
|
|
@@ -140,7 +140,7 @@ dotreq pull --share <token>
|
|
|
140
140
|
If a team member shares a pull command with you, you can pull requirements without creating an account:
|
|
141
141
|
|
|
142
142
|
```bash
|
|
143
|
-
npx @popoverai/dotrequirements pull --share drt_abc123...
|
|
143
|
+
npx @popoverai/dotrequirements@latest pull --share drt_abc123...
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
This gives you read-only access to view requirements. To push changes or report coverage, run `dotreq link` afterward.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getProjectContext } from "../requirements/cloud-ai.js";
|
|
2
2
|
import { loadAllRequirements } from "../requirements/index.js";
|
|
3
|
-
import { generateStyleGuide
|
|
3
|
+
import { generateStyleGuide } from "../requirements/style-guide.js";
|
|
4
|
+
import { readLocalStyleGuide } from "../requirements/style-guide-file.js";
|
|
4
5
|
import { findProjectRoot, getProjectCredentials, } from "../utils/project-settings.js";
|
|
5
6
|
const CONVEX_URL = "https://data.dotrequirements.io";
|
|
6
7
|
export async function createRequirementDocumentCommand(filePath) {
|
package/dist/commands/link.js
CHANGED
|
@@ -262,7 +262,7 @@ async function mintShareArtifacts(client, teamId, projectId) {
|
|
|
262
262
|
const share = (await client.mutation(api.projectSecrets.mutations.ensureShareToken,
|
|
263
263
|
// biome-ignore lint/suspicious/noExplicitAny: CLI workspace doesn't import convex's branded Id type; the runtime value is a plain string the server validates.
|
|
264
264
|
{ target: { type: "project", id: projectId } }));
|
|
265
|
-
artifacts.sharePullCommand = `npx -y @popoverai/dotrequirements pull --share ${share.token}`;
|
|
265
|
+
artifacts.sharePullCommand = `npx -y @popoverai/dotrequirements@latest pull --share ${share.token}`;
|
|
266
266
|
}
|
|
267
267
|
catch {
|
|
268
268
|
// LINK-13.3: connection already succeeded — omit rather than fail
|
|
@@ -2,7 +2,8 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { DEFAULT_API_BASE_URL, fetchStyleCheckFeedback, getProjectContext, } from "../requirements/cloud-ai.js";
|
|
4
4
|
import { filterRequirementsByKeys, loadAllRequirements, } from "../requirements/index.js";
|
|
5
|
-
import { generateStyleGuideBody
|
|
5
|
+
import { generateStyleGuideBody } from "../requirements/style-guide.js";
|
|
6
|
+
import { readLocalStyleGuide } from "../requirements/style-guide-file.js";
|
|
6
7
|
import { findProjectRoot, getProjectCredentials, } from "../utils/project-settings.js";
|
|
7
8
|
const CONVEX_URL = "https://data.dotrequirements.io";
|
|
8
9
|
/**
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem access for the style guide — kept apart from the generator itself.
|
|
3
|
+
*
|
|
4
|
+
* `style-guide.ts` is imported by the web app to serve the same primer to chat
|
|
5
|
+
* agents (REMOTE-MCP-10), which have no repo to read. Everything in that module
|
|
6
|
+
* must therefore stay free of `node:fs`; the workspace lookups live here, where
|
|
7
|
+
* only the CLI reaches them. This mirrors the split the schema module already
|
|
8
|
+
* makes between its node and browser entry points.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Conventional location of a project's STYLE.md, relative to the workspace
|
|
12
|
+
* root. Exported so callers (init, push/pull, tests) can reference one place.
|
|
13
|
+
*/
|
|
14
|
+
export declare const STYLE_MD_PATH = ".requirements/STYLE.md";
|
|
15
|
+
/**
|
|
16
|
+
* Read `.requirements/STYLE.md` if the workspace has one. Returns the file
|
|
17
|
+
* contents on success, `null` if the file is absent. Empty / whitespace-only
|
|
18
|
+
* files are treated as absent so the bundled defaults still apply.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readLocalStyleGuide(workspaceRoot: string): string | null;
|
|
21
|
+
//# sourceMappingURL=style-guide-file.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem access for the style guide — kept apart from the generator itself.
|
|
3
|
+
*
|
|
4
|
+
* `style-guide.ts` is imported by the web app to serve the same primer to chat
|
|
5
|
+
* agents (REMOTE-MCP-10), which have no repo to read. Everything in that module
|
|
6
|
+
* must therefore stay free of `node:fs`; the workspace lookups live here, where
|
|
7
|
+
* only the CLI reaches them. This mirrors the split the schema module already
|
|
8
|
+
* makes between its node and browser entry points.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
/**
|
|
13
|
+
* Conventional location of a project's STYLE.md, relative to the workspace
|
|
14
|
+
* root. Exported so callers (init, push/pull, tests) can reference one place.
|
|
15
|
+
*/
|
|
16
|
+
export const STYLE_MD_PATH = ".requirements/STYLE.md";
|
|
17
|
+
/**
|
|
18
|
+
* Read `.requirements/STYLE.md` if the workspace has one. Returns the file
|
|
19
|
+
* contents on success, `null` if the file is absent. Empty / whitespace-only
|
|
20
|
+
* files are treated as absent so the bundled defaults still apply.
|
|
21
|
+
*/
|
|
22
|
+
export function readLocalStyleGuide(workspaceRoot) {
|
|
23
|
+
const fullPath = join(workspaceRoot, STYLE_MD_PATH);
|
|
24
|
+
if (!existsSync(fullPath)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const contents = readFileSync(fullPath, "utf-8");
|
|
28
|
+
return contents.trim().length > 0 ? contents : null;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=style-guide-file.js.map
|
|
@@ -11,37 +11,35 @@
|
|
|
11
11
|
*
|
|
12
12
|
* If the project has a `.requirements/STYLE.md`, callers can pass its
|
|
13
13
|
* contents via `localStyleGuide` to use that body in place of the bundled
|
|
14
|
-
* defaults. See
|
|
14
|
+
* defaults. See `readLocalStyleGuide` in ./style-guide-file.ts (CLI-only —
|
|
15
|
+
* this module stays free of node:fs so the web can serve the same primer).
|
|
15
16
|
*/
|
|
16
17
|
import type { FlattenedRequirement } from "./index.js";
|
|
17
18
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
19
|
+
* The only fields the guide reads off a requirement.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately narrower than {@link FlattenedRequirement}, which is file-shaped
|
|
22
|
+
* (`sourceFile`, `documentTitle`). The web serves this same guide from cloud
|
|
23
|
+
* requirements, which have no file to name (REMOTE-MCP-10) — asking only for
|
|
24
|
+
* what's used lets both callers pass what they actually have instead of
|
|
25
|
+
* inventing filenames.
|
|
20
26
|
*/
|
|
21
|
-
export
|
|
27
|
+
export type StyleGuideRequirement = Pick<FlattenedRequirement, "id" | "label" | "path">;
|
|
22
28
|
export interface GenerateStyleGuideParams {
|
|
23
|
-
/**
|
|
24
|
-
*
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* cloud project's `requirementsStyleContext` field). Pass null/undefined
|
|
29
|
-
* to omit. */
|
|
29
|
+
/** The existing requirements to discover label and key-prefix patterns from.
|
|
30
|
+
* Pass an empty array when none exist yet. */
|
|
31
|
+
requirements: StyleGuideRequirement[];
|
|
32
|
+
/** Project-owner-supplied custom guidance (sourced from the cloud project's
|
|
33
|
+
* `requirementsStyleContext` field). Pass null/undefined to omit. */
|
|
30
34
|
customStyleGuidance?: string | null;
|
|
31
|
-
/** Suggested target path for the new file. Used only in the preamble
|
|
32
|
-
*
|
|
35
|
+
/** Suggested target path for the new file. Used only in the preamble and
|
|
36
|
+
* "Next Steps" section. Defaults to a generic example path. */
|
|
33
37
|
filePath?: string;
|
|
34
|
-
/** Project-local STYLE.md contents. When provided and non-empty, this
|
|
35
|
-
*
|
|
36
|
-
*
|
|
38
|
+
/** Project-local STYLE.md contents. When provided and non-empty, this body
|
|
39
|
+
* replaces the bundled default. CLI-only — see `readLocalStyleGuide` in
|
|
40
|
+
* ./style-guide-file.ts. */
|
|
37
41
|
localStyleGuide?: string | null;
|
|
38
42
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Read `.requirements/STYLE.md` if the workspace has one. Returns the file
|
|
41
|
-
* contents on success, `null` if the file is absent. Empty / whitespace-only
|
|
42
|
-
* files are treated as absent so the bundled defaults still apply.
|
|
43
|
-
*/
|
|
44
|
-
export declare function readLocalStyleGuide(workspaceRoot: string): string | null;
|
|
45
43
|
/**
|
|
46
44
|
* Build the body of the bundled default style guide. This is the content
|
|
47
45
|
* that lives inside the "# Requirements File Template" preamble — the
|
|
@@ -11,27 +11,47 @@
|
|
|
11
11
|
*
|
|
12
12
|
* If the project has a `.requirements/STYLE.md`, callers can pass its
|
|
13
13
|
* contents via `localStyleGuide` to use that body in place of the bundled
|
|
14
|
-
* defaults. See
|
|
14
|
+
* defaults. See `readLocalStyleGuide` in ./style-guide-file.ts (CLI-only —
|
|
15
|
+
* this module stays free of node:fs so the web can serve the same primer).
|
|
15
16
|
*/
|
|
16
|
-
import {
|
|
17
|
-
import { join } from "node:path";
|
|
17
|
+
import { ROOT_LABEL_MARKER } from "../schema/parser-core.js";
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* How many discovered labels or key prefixes the guide will show.
|
|
20
|
+
*
|
|
21
|
+
* These lists exist under "match the existing pattern", and past ten that
|
|
22
|
+
* instruction stops being actionable — a reader can't match a hundred and forty
|
|
23
|
+
* things. Worse, an uncapped list presents whatever sprawl a codebase has
|
|
24
|
+
* accumulated as the house style, so each new author reproduces it and the list
|
|
25
|
+
* grows: the mechanism meant to hold conventions steady is what compounds their
|
|
26
|
+
* drift. Ten is a sample, and the trailing count says so rather than letting the
|
|
27
|
+
* truncation read as the whole set.
|
|
21
28
|
*/
|
|
22
|
-
|
|
29
|
+
const SAMPLE_LIMIT = 10;
|
|
23
30
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
31
|
+
* The most-used values first, not the alphabetically-first.
|
|
32
|
+
*
|
|
33
|
+
* Sorting by name and taking the head is a trap: on this codebase it yields ten
|
|
34
|
+
* prefixes all beginning with "A", which under "match the existing pattern"
|
|
35
|
+
* teaches a convention nobody has. Frequency is what the phrase actually means —
|
|
36
|
+
* the prefixes carrying the most requirements are the house style. Ties break
|
|
37
|
+
* alphabetically so the sample is stable across runs.
|
|
27
38
|
*/
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
function sample(counts) {
|
|
40
|
+
const ranked = Array.from(counts.entries())
|
|
41
|
+
.sort(([aName, aCount], [bName, bCount]) => bCount === aCount ? aName.localeCompare(bName) : bCount - aCount)
|
|
42
|
+
.map(([name]) => name);
|
|
43
|
+
return {
|
|
44
|
+
list: ranked
|
|
45
|
+
.slice(0, SAMPLE_LIMIT)
|
|
46
|
+
.map((v) => `"${v}"`)
|
|
47
|
+
.join(", "),
|
|
48
|
+
more: ranked.length > SAMPLE_LIMIT
|
|
49
|
+
? ` (and ${ranked.length - SAMPLE_LIMIT} more)`
|
|
50
|
+
: "",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function tally(counts, key) {
|
|
54
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
35
55
|
}
|
|
36
56
|
/**
|
|
37
57
|
* Build the body of the bundled default style guide. This is the content
|
|
@@ -46,43 +66,45 @@ export function readLocalStyleGuide(workspaceRoot) {
|
|
|
46
66
|
*/
|
|
47
67
|
export function generateStyleGuideBody(params) {
|
|
48
68
|
const { requirements, customStyleGuidance } = params;
|
|
49
|
-
const labels = new
|
|
50
|
-
const keyPrefixes = new
|
|
69
|
+
const labels = new Map();
|
|
70
|
+
const keyPrefixes = new Map();
|
|
51
71
|
for (const req of requirements) {
|
|
52
|
-
|
|
53
|
-
|
|
72
|
+
// The root marker is on every root in every workspace and chosen by nobody,
|
|
73
|
+
// so counting it would hand back a storage detail as house style. Worst for
|
|
74
|
+
// a project that took this guide's own advice to leave criteria unlabelled:
|
|
75
|
+
// it would be the only label found, and would suppress the "default to
|
|
76
|
+
// unlabeled" branch below in favour of matching a label nobody types.
|
|
77
|
+
if (req.label?.trim() && req.label !== ROOT_LABEL_MARKER) {
|
|
78
|
+
tally(labels, req.label);
|
|
54
79
|
}
|
|
55
80
|
if (req.path.length === 0 && req.id) {
|
|
56
81
|
const lastDashIndex = req.id.lastIndexOf("-");
|
|
57
82
|
if (lastDashIndex > 0) {
|
|
58
|
-
keyPrefixes
|
|
83
|
+
tally(keyPrefixes, req.id.substring(0, lastDashIndex));
|
|
59
84
|
}
|
|
60
85
|
}
|
|
61
86
|
}
|
|
62
|
-
const discoveredLabels = Array.from(labels).sort();
|
|
63
|
-
const discoveredPrefixes = Array.from(keyPrefixes).sort();
|
|
64
87
|
let labelGuidance;
|
|
65
|
-
if (
|
|
66
|
-
const labelList =
|
|
67
|
-
.slice(0, 10)
|
|
68
|
-
.map((l) => `"${l}"`)
|
|
69
|
-
.join(", ");
|
|
70
|
-
const more = discoveredLabels.length > 10
|
|
71
|
-
? ` (and ${discoveredLabels.length - 10} more)`
|
|
72
|
-
: "";
|
|
88
|
+
if (labels.size > 0) {
|
|
89
|
+
const { list: labelList, more } = sample(labels);
|
|
73
90
|
labelGuidance = `**Existing labels in this codebase:** ${labelList}${more}
|
|
74
91
|
|
|
75
92
|
**Use these existing labels** to maintain consistency. If you're unsure which labels to use for a new requirement, ask the user.`;
|
|
76
93
|
}
|
|
77
94
|
else {
|
|
78
|
-
|
|
95
|
+
// Says *labels*, not requirements. Reaching here means nobody has labelled
|
|
96
|
+
// a criterion — which is what a project following the advice below looks
|
|
97
|
+
// like, not an empty one. The key-prefix branch shares this sentence and is
|
|
98
|
+
// right to: there, an empty set really does mean no requirements. Here it
|
|
99
|
+
// would contradict the prefix list printed two headings above.
|
|
100
|
+
labelGuidance = `**No labelled criteria found in this codebase.**
|
|
79
101
|
|
|
80
102
|
**Default to unlabeled requirements** (\`0. → content\`). If the user wants labels, ask them which format they prefer. Do not choose an opinionated framework like Given/When/Then without explicit user consent.`;
|
|
81
103
|
}
|
|
82
104
|
let keyGuidance;
|
|
83
|
-
if (
|
|
84
|
-
const prefixList
|
|
85
|
-
keyGuidance = `**Existing requirement key prefixes in this codebase:** ${prefixList}
|
|
105
|
+
if (keyPrefixes.size > 0) {
|
|
106
|
+
const { list: prefixList, more } = sample(keyPrefixes);
|
|
107
|
+
keyGuidance = `**Existing requirement key prefixes in this codebase:** ${prefixList}${more}
|
|
86
108
|
|
|
87
109
|
**Match the existing pattern** when creating new requirement keys. Use the same domain prefixes and sequential numbering style.`;
|
|
88
110
|
}
|
package/dist/schema/browser.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
export { buildRequirementMarkdown, buildRequirementsMarkdown, DEFAULT_DELIMITER, } from "./builder.js";
|
|
7
7
|
export type { ConvexRequirement } from "./conversions.js";
|
|
8
8
|
export { buildMetadata, constructKey, convexToRequirements, extractRequirementKeys, groupByRoot, parseKey, requirementsToConvex, } from "./conversions.js";
|
|
9
|
-
export { DELIMITER_PATTERN, extractRequirementBlocks, findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRequirementBlocksFromMarkdown, parseRootLine, } from "./parser-core.js";
|
|
9
|
+
export { DELIMITER_PATTERN, extractRequirementBlocks, findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRequirementBlocksFromMarkdown, parseRootLine, ROOT_LABEL_MARKER, } from "./parser-core.js";
|
|
10
10
|
export type { Metadata, ParsedCriterion, RequirementKey, RequirementNode, RequirementPrefix, RequirementsFile, } from "./schemas.js";
|
|
11
11
|
export { buildRequirementKey, MetadataSchema, normalizePrefix, ParsedCriterionSchema, parseRequirementKey, REQUIREMENT_KEY_PATTERN, REQUIREMENT_PREFIX_PATTERN, RequirementKeySchema, RequirementNodeSchema, RequirementPrefixSchema, RequirementsFileSchema, ValidationError, validateKey, validateMetadata, validatePrefix, validateRequirementNode, validateRequirementsFile, } from "./schemas.js";
|
|
12
12
|
export type { BuildScenarioOptions, Scenario, ScenarioAssertionSource, ScenarioStep, } from "./scenario.js";
|
package/dist/schema/browser.js
CHANGED
|
@@ -8,7 +8,10 @@ export { buildRequirementMarkdown, buildRequirementsMarkdown, DEFAULT_DELIMITER,
|
|
|
8
8
|
export { buildMetadata, constructKey, convexToRequirements, extractRequirementKeys, groupByRoot, parseKey, requirementsToConvex, } from "./conversions.js";
|
|
9
9
|
// Parser core (pure TypeScript - browser-safe, no fs dependency)
|
|
10
10
|
// These functions parse markdown strings directly without file I/O
|
|
11
|
-
export { DELIMITER_PATTERN, extractRequirementBlocks, findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRequirementBlocksFromMarkdown, parseRootLine,
|
|
11
|
+
export { DELIMITER_PATTERN, extractRequirementBlocks, findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRequirementBlocksFromMarkdown, parseRootLine,
|
|
12
|
+
// The web reaches parser-core only through this entry point, so without this
|
|
13
|
+
// its readers have no way to import the marker and must hard-code it.
|
|
14
|
+
ROOT_LABEL_MARKER, } from "./parser-core.js";
|
|
12
15
|
// Schemas and types (uses zod - browser-safe)
|
|
13
16
|
export { buildRequirementKey,
|
|
14
17
|
// Zod schemas
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export { buildRequirementMarkdown, buildRequirementsFile, buildRequirementsMarkdown, } from "./builder.js";
|
|
8
8
|
export type { ConvexRequirement } from "./conversions.js";
|
|
9
9
|
export { buildMetadata, constructKey, convexToRequirements, extractRequirementKeys, groupByRoot, parseKey, requirementsToConvex, } from "./conversions.js";
|
|
10
|
-
export { findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRequirementsFile, parseRequirementsFromFile, } from "./parser.js";
|
|
10
|
+
export { findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRequirementsFile, parseRequirementsFromFile, parseRootLine, } from "./parser.js";
|
|
11
11
|
export { checkPathAmbiguity, findChildrenByLabel, getAllLabelPaths, parsePathSegment, parseRequirementPath, resolvePathSegment, resolveRequirementPath, resolveToNumericPath, } from "./resolver.js";
|
|
12
12
|
export type { BuildScenarioOptions, Scenario, ScenarioAssertionSource, ScenarioStep, } from "./scenario.js";
|
|
13
13
|
export { buildScenarioFromRequirements, requirementTreeToScenario, } from "./scenario.js";
|
package/dist/schema/index.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
export { buildRequirementMarkdown, buildRequirementsFile, buildRequirementsMarkdown, } from "./builder.js";
|
|
9
9
|
export { buildMetadata, constructKey, convexToRequirements, extractRequirementKeys, groupByRoot, parseKey, requirementsToConvex, } from "./conversions.js";
|
|
10
10
|
// Parsing
|
|
11
|
-
export { findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRequirementsFile, parseRequirementsFromFile, } from "./parser.js";
|
|
11
|
+
export { findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRequirementsFile, parseRequirementsFromFile, parseRootLine, } from "./parser.js";
|
|
12
12
|
// Path resolution
|
|
13
13
|
export { checkPathAmbiguity, findChildrenByLabel, getAllLabelPaths, parsePathSegment, parseRequirementPath, resolvePathSegment, resolveRequirementPath, resolveToNumericPath, } from "./resolver.js";
|
|
14
14
|
// Scenario building (for browser-automation / runScenario)
|
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
* making it safe to import in Convex runtime or browser environments.
|
|
6
6
|
*/
|
|
7
7
|
import { type ParsedCriterion, type RequirementNode } from "./schemas.js";
|
|
8
|
+
/**
|
|
9
|
+
* The label stamped on every requirement's root, for indexing and querying.
|
|
10
|
+
*
|
|
11
|
+
* An internal marker, not a convention: no author writes it, the markdown
|
|
12
|
+
* format has no syntax for it, and consumers that show labels to a human or an
|
|
13
|
+
* agent must exclude it — the harness's output filters, Convex's label queries,
|
|
14
|
+
* and the style guide's discovered-label list all do.
|
|
15
|
+
*
|
|
16
|
+
* Declared here because this is where parsing stamps it, but be warned: most of
|
|
17
|
+
* those readers still hard-code the literal, and `web/lib/markdown-conversion`
|
|
18
|
+
* stamps it independently for the BlockNote path. So renaming this does NOT yet
|
|
19
|
+
* move everyone with it — you would have to grep. Each reader migrated here is
|
|
20
|
+
* one that a rename can no longer silently strand.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ROOT_LABEL_MARKER = "requirementHeader";
|
|
8
23
|
/**
|
|
9
24
|
* Default delimiter for requirements.
|
|
10
25
|
* Can be overridden for organization-specific preferences.
|
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
* making it safe to import in Convex runtime or browser environments.
|
|
6
6
|
*/
|
|
7
7
|
import { ValidationError, validateKey, } from "./schemas.js";
|
|
8
|
+
/**
|
|
9
|
+
* The label stamped on every requirement's root, for indexing and querying.
|
|
10
|
+
*
|
|
11
|
+
* An internal marker, not a convention: no author writes it, the markdown
|
|
12
|
+
* format has no syntax for it, and consumers that show labels to a human or an
|
|
13
|
+
* agent must exclude it — the harness's output filters, Convex's label queries,
|
|
14
|
+
* and the style guide's discovered-label list all do.
|
|
15
|
+
*
|
|
16
|
+
* Declared here because this is where parsing stamps it, but be warned: most of
|
|
17
|
+
* those readers still hard-code the literal, and `web/lib/markdown-conversion`
|
|
18
|
+
* stamps it independently for the BlockNote path. So renaming this does NOT yet
|
|
19
|
+
* move everyone with it — you would have to grep. Each reader migrated here is
|
|
20
|
+
* one that a rename can no longer silently strand.
|
|
21
|
+
*/
|
|
22
|
+
export const ROOT_LABEL_MARKER = "requirementHeader";
|
|
8
23
|
/**
|
|
9
24
|
* Default delimiter for requirements.
|
|
10
25
|
* Can be overridden for organization-specific preferences.
|
|
@@ -103,9 +118,9 @@ export function parseRequirementBlock(key, blockContent) {
|
|
|
103
118
|
}
|
|
104
119
|
const root = {
|
|
105
120
|
id: key,
|
|
106
|
-
// Root requirements always use
|
|
107
|
-
//
|
|
108
|
-
label:
|
|
121
|
+
// Root requirements always use this label for indexing/querying. The
|
|
122
|
+
// markdown format doesn't preserve root labels, so we standardize on it.
|
|
123
|
+
label: ROOT_LABEL_MARKER,
|
|
109
124
|
content: rootParsed.content,
|
|
110
125
|
children: [],
|
|
111
126
|
};
|
package/dist/schema/parser.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* requirements file means (SYNC-FORMAT-2.3).
|
|
9
9
|
*/
|
|
10
10
|
import { type RequirementNode, type RequirementsFile } from "./schemas.js";
|
|
11
|
-
export { findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, } from "./parser-core.js";
|
|
11
|
+
export { findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRootLine, } from "./parser-core.js";
|
|
12
12
|
/**
|
|
13
13
|
* Parse a complete requirements Markdown file.
|
|
14
14
|
*/
|
package/dist/schema/parser.js
CHANGED
|
@@ -13,7 +13,7 @@ import { parseRequirementBlocksFromMarkdown, splitFrontmatter, } from "./parser-
|
|
|
13
13
|
import { ValidationError, validateMetadata, } from "./schemas.js";
|
|
14
14
|
// Block/criterion parsing and tree utilities live in parser-core; re-exported
|
|
15
15
|
// here so the schema module's public surface is unchanged.
|
|
16
|
-
export { findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, } from "./parser-core.js";
|
|
16
|
+
export { findRequirementById, flattenRequirementTree, getAllRequirements, parseCriterionLine, parseRequirementBlock, parseRootLine, } from "./parser-core.js";
|
|
17
17
|
/**
|
|
18
18
|
* Extract YAML frontmatter from Markdown content.
|
|
19
19
|
* Returns { frontmatter, body } where frontmatter is the parsed YAML object.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@popoverai/dotrequirements",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.2",
|
|
4
4
|
"description": "Requirements tracking CLI and test harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
".": "./dist/cli.js",
|
|
12
12
|
"./test": "./dist/harness/index.js",
|
|
13
13
|
"./schema": "./dist/schema/index.js",
|
|
14
|
-
"./schema/browser": "./dist/schema/browser.js"
|
|
14
|
+
"./schema/browser": "./dist/schema/browser.js",
|
|
15
|
+
"./style-guide": "./dist/requirements/style-guide.js"
|
|
15
16
|
},
|
|
16
17
|
"publishConfig": {
|
|
17
18
|
"access": "public"
|