@popoverai/dotrequirements 0.11.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.
Files changed (127) hide show
  1. package/README.md +478 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.js +82 -0
  4. package/dist/commands/init.d.ts +6 -0
  5. package/dist/commands/init.js +355 -0
  6. package/dist/commands/link.d.ts +15 -0
  7. package/dist/commands/link.js +156 -0
  8. package/dist/commands/login.d.ts +12 -0
  9. package/dist/commands/login.js +117 -0
  10. package/dist/commands/logout.d.ts +5 -0
  11. package/dist/commands/logout.js +17 -0
  12. package/dist/commands/mcp-setup.d.ts +5 -0
  13. package/dist/commands/mcp-setup.js +367 -0
  14. package/dist/commands/mcp.d.ts +6 -0
  15. package/dist/commands/mcp.js +10 -0
  16. package/dist/commands/pull.d.ts +7 -0
  17. package/dist/commands/pull.js +171 -0
  18. package/dist/commands/push.d.ts +11 -0
  19. package/dist/commands/push.js +310 -0
  20. package/dist/commands/test.d.ts +6 -0
  21. package/dist/commands/test.js +78 -0
  22. package/dist/config.d.ts +5 -0
  23. package/dist/config.js +16 -0
  24. package/dist/convex.d.ts +56 -0
  25. package/dist/convex.js +58 -0
  26. package/dist/harness/cache.d.ts +135 -0
  27. package/dist/harness/cache.js +342 -0
  28. package/dist/harness/convexReporting.d.ts +15 -0
  29. package/dist/harness/convexReporting.js +136 -0
  30. package/dist/harness/coverageCache.d.ts +30 -0
  31. package/dist/harness/coverageCache.js +70 -0
  32. package/dist/harness/finalize.d.ts +48 -0
  33. package/dist/harness/finalize.js +299 -0
  34. package/dist/harness/index.d.ts +70 -0
  35. package/dist/harness/index.js +103 -0
  36. package/dist/harness/localReporting.d.ts +6 -0
  37. package/dist/harness/localReporting.js +49 -0
  38. package/dist/harness/prepare.d.ts +41 -0
  39. package/dist/harness/prepare.js +83 -0
  40. package/dist/harness/requirementsLoader.d.ts +45 -0
  41. package/dist/harness/requirementsLoader.js +201 -0
  42. package/dist/harness/tracking.d.ts +49 -0
  43. package/dist/harness/tracking.js +179 -0
  44. package/dist/harness/types.d.ts +12 -0
  45. package/dist/harness/types.js +6 -0
  46. package/dist/mcp/convexClient.d.ts +43 -0
  47. package/dist/mcp/convexClient.js +101 -0
  48. package/dist/mcp/grep.d.ts +24 -0
  49. package/dist/mcp/grep.js +261 -0
  50. package/dist/mcp/index.d.ts +3 -0
  51. package/dist/mcp/index.js +1758 -0
  52. package/dist/mcp/requirements.d.ts +47 -0
  53. package/dist/mcp/requirements.js +141 -0
  54. package/dist/mcp/testCodeExtractor.d.ts +22 -0
  55. package/dist/mcp/testCodeExtractor.js +152 -0
  56. package/dist/mcp/types.d.ts +27 -0
  57. package/dist/mcp/types.js +2 -0
  58. package/dist/schema/browser.d.ts +12 -0
  59. package/dist/schema/browser.js +24 -0
  60. package/dist/schema/builder.d.ts +25 -0
  61. package/dist/schema/builder.js +125 -0
  62. package/dist/schema/conversions.d.ts +69 -0
  63. package/dist/schema/conversions.js +201 -0
  64. package/dist/schema/index.d.ts +14 -0
  65. package/dist/schema/index.js +24 -0
  66. package/dist/schema/parser-core.d.ts +61 -0
  67. package/dist/schema/parser-core.js +247 -0
  68. package/dist/schema/parser.d.ts +44 -0
  69. package/dist/schema/parser.js +295 -0
  70. package/dist/schema/resolver.d.ts +66 -0
  71. package/dist/schema/resolver.js +185 -0
  72. package/dist/schema/schemas.d.ts +312 -0
  73. package/dist/schema/schemas.js +258 -0
  74. package/dist/schema/test-schema.d.ts +5 -0
  75. package/dist/schema/test-schema.js +81 -0
  76. package/dist/templates/antigravity-gemini.md +3 -0
  77. package/dist/templates/antigravity-overview-rule.md +3 -0
  78. package/dist/templates/antigravity-test-rule.md +3 -0
  79. package/dist/templates/behavioral-core.md +25 -0
  80. package/dist/templates/claude-code-overview-skill.md +6 -0
  81. package/dist/templates/claude-code-skill.md +6 -0
  82. package/dist/templates/claude-code-test-skill.md +6 -0
  83. package/dist/templates/codex-agents.md +3 -0
  84. package/dist/templates/codex-overview-agents.md +3 -0
  85. package/dist/templates/codex-test-agents.md +3 -0
  86. package/dist/templates/cursor-overview-rule.mdc +5 -0
  87. package/dist/templates/cursor-rule.mdc +5 -0
  88. package/dist/templates/cursor-test-rule.mdc +5 -0
  89. package/dist/templates/example-requirements.d.ts +8 -0
  90. package/dist/templates/example-requirements.js +88 -0
  91. package/dist/templates/example-requirements.ts +88 -0
  92. package/dist/templates/overview-core.md +27 -0
  93. package/dist/templates/requirements-readme.d.ts +5 -0
  94. package/dist/templates/requirements-readme.js +31 -0
  95. package/dist/templates/requirements-readme.ts +30 -0
  96. package/dist/templates/test-writing-core.md +72 -0
  97. package/dist/utils/brand.d.ts +5 -0
  98. package/dist/utils/brand.js +8 -0
  99. package/dist/utils/browser-launch.d.ts +19 -0
  100. package/dist/utils/browser-launch.js +36 -0
  101. package/dist/utils/detect-existing-project.d.ts +5 -0
  102. package/dist/utils/detect-existing-project.js +34 -0
  103. package/dist/utils/env.d.ts +19 -0
  104. package/dist/utils/env.js +56 -0
  105. package/dist/utils/gitignore.d.ts +7 -0
  106. package/dist/utils/gitignore.js +29 -0
  107. package/dist/utils/local-project.d.ts +31 -0
  108. package/dist/utils/local-project.js +33 -0
  109. package/dist/utils/oauth-callback-server.d.ts +28 -0
  110. package/dist/utils/oauth-callback-server.js +156 -0
  111. package/dist/utils/oauth-flow.d.ts +22 -0
  112. package/dist/utils/oauth-flow.js +120 -0
  113. package/dist/utils/project-discovery.d.ts +57 -0
  114. package/dist/utils/project-discovery.js +146 -0
  115. package/dist/utils/project-name.d.ts +8 -0
  116. package/dist/utils/project-name.js +48 -0
  117. package/dist/utils/project-selector.d.ts +25 -0
  118. package/dist/utils/project-selector.js +69 -0
  119. package/dist/utils/prompts.d.ts +33 -0
  120. package/dist/utils/prompts.js +60 -0
  121. package/dist/utils/templates.d.ts +29 -0
  122. package/dist/utils/templates.js +67 -0
  123. package/dist/utils/token-refresh.d.ts +24 -0
  124. package/dist/utils/token-refresh.js +69 -0
  125. package/dist/utils/token-storage.d.ts +31 -0
  126. package/dist/utils/token-storage.js +57 -0
  127. package/package.json +82 -0
@@ -0,0 +1,47 @@
1
+ import { type RequirementNode, type Metadata } from '../schema/index.js';
2
+ import type { FlattenedRequirement } from './types.js';
3
+ /**
4
+ * Parsed requirements file
5
+ */
6
+ export interface ParsedRequirementsFile {
7
+ metadata: Metadata;
8
+ requirements: RequirementNode[];
9
+ }
10
+ /**
11
+ * Find all *.requirements.md files in the workspace.
12
+ * Supports both .requirements/ directories and colocated files.
13
+ * Excludes example files, test fixtures, and build artifacts.
14
+ */
15
+ export declare function findRequirementsFiles(workspaceRoot: string): Promise<string[]>;
16
+ /**
17
+ * Load all requirements from the workspace
18
+ */
19
+ export declare function loadAllRequirements(workspaceRoot: string): Promise<{
20
+ files: ParsedRequirementsFile[];
21
+ flattened: FlattenedRequirement[];
22
+ }>;
23
+ /**
24
+ * Flatten a requirements file into searchable requirements
25
+ */
26
+ export declare function flattenRequirementsFile(file: ParsedRequirementsFile, sourceFile: string): FlattenedRequirement[];
27
+ /**
28
+ * Search requirements by text query
29
+ */
30
+ export declare function searchRequirements(requirements: FlattenedRequirement[], query: string): FlattenedRequirement[];
31
+ /**
32
+ * Get a specific requirement by ID (supports partial matching)
33
+ */
34
+ export declare function getRequirementById(requirements: FlattenedRequirement[], id: string): FlattenedRequirement | undefined;
35
+ /**
36
+ * Get a requirement and all its children
37
+ */
38
+ export declare function getRequirementTree(requirements: FlattenedRequirement[], rootId: string): FlattenedRequirement[];
39
+ /**
40
+ * Format a requirement for display
41
+ */
42
+ export declare function formatRequirement(req: FlattenedRequirement): string;
43
+ /**
44
+ * Format a requirement tree for display
45
+ */
46
+ export declare function formatRequirementTree(requirements: FlattenedRequirement[]): string;
47
+ //# sourceMappingURL=requirements.d.ts.map
@@ -0,0 +1,141 @@
1
+ import * as path from 'path';
2
+ import { glob } from 'glob';
3
+ import { parseRequirementsFromFile, getAllRequirements, } from '../schema/index.js';
4
+ /**
5
+ * Find all *.requirements.md files in the workspace.
6
+ * Supports both .requirements/ directories and colocated files.
7
+ * Excludes example files, test fixtures, and build artifacts.
8
+ */
9
+ export async function findRequirementsFiles(workspaceRoot) {
10
+ const pattern = '**/*.requirements.md';
11
+ const matches = await glob(pattern, {
12
+ cwd: workspaceRoot,
13
+ ignore: [
14
+ '**/node_modules/**',
15
+ '**/dist/**',
16
+ '**/.git/**',
17
+ '**/build/**',
18
+ // Exclude example and test fixture directories
19
+ '**/example/**',
20
+ '**/examples/**',
21
+ '**/__tests__/**',
22
+ '**/fixtures/**',
23
+ '**/.fixtures/**',
24
+ ],
25
+ dot: true, // Include dotfiles/dotdirs like .requirements/
26
+ });
27
+ return matches.map(m => path.join(workspaceRoot, m));
28
+ }
29
+ /**
30
+ * Load all requirements from the workspace
31
+ */
32
+ export async function loadAllRequirements(workspaceRoot) {
33
+ const filePaths = await findRequirementsFiles(workspaceRoot);
34
+ const allFiles = [];
35
+ const allFlattened = [];
36
+ for (const filePath of filePaths) {
37
+ try {
38
+ const parsed = parseRequirementsFromFile(filePath);
39
+ allFiles.push(parsed);
40
+ const flattened = flattenRequirementsFile(parsed, filePath);
41
+ allFlattened.push(...flattened);
42
+ }
43
+ catch (error) {
44
+ // Skip invalid files
45
+ console.error(`Failed to parse ${filePath}:`, error);
46
+ }
47
+ }
48
+ return { files: allFiles, flattened: allFlattened };
49
+ }
50
+ /**
51
+ * Flatten a requirements file into searchable requirements
52
+ */
53
+ export function flattenRequirementsFile(file, sourceFile) {
54
+ const results = [];
55
+ // Use shared utility to get all requirements (flattened)
56
+ const allReqs = getAllRequirements(file.requirements);
57
+ for (const req of allReqs) {
58
+ // Extract position from ID (e.g., "REQ123.0.1" -> "0.1")
59
+ const idParts = req.id.split('.');
60
+ const rootId = idParts[0];
61
+ const position = idParts.slice(1).join('.');
62
+ results.push({
63
+ id: req.id,
64
+ rootId: rootId,
65
+ label: req.label,
66
+ content: req.content,
67
+ path: idParts.slice(1), // ["0", "1"] for "REQ123.0.1"
68
+ sourceFile: sourceFile,
69
+ documentTitle: file.metadata.document?.title || rootId,
70
+ });
71
+ }
72
+ return results;
73
+ }
74
+ /**
75
+ * Search requirements by text query
76
+ */
77
+ export function searchRequirements(requirements, query) {
78
+ const lowerQuery = query.toLowerCase();
79
+ return requirements.filter(req => {
80
+ // Search in ID
81
+ if (req.id.toLowerCase().includes(lowerQuery))
82
+ return true;
83
+ // Search in content
84
+ if (req.content.toLowerCase().includes(lowerQuery))
85
+ return true;
86
+ // Search in label
87
+ if (req.label.toLowerCase().includes(lowerQuery))
88
+ return true;
89
+ return false;
90
+ });
91
+ }
92
+ /**
93
+ * Get a specific requirement by ID (supports partial matching)
94
+ */
95
+ export function getRequirementById(requirements, id) {
96
+ // Exact match first
97
+ const exact = requirements.find(r => r.id === id);
98
+ if (exact)
99
+ return exact;
100
+ // Try partial match (just the root ID)
101
+ return requirements.find(r => r.rootId === id || r.id.startsWith(id + '.'));
102
+ }
103
+ /**
104
+ * Get a requirement and all its children
105
+ */
106
+ export function getRequirementTree(requirements, rootId) {
107
+ return requirements.filter(r => r.rootId === rootId || r.id === rootId);
108
+ }
109
+ /**
110
+ * Format a requirement for display
111
+ */
112
+ export function formatRequirement(req) {
113
+ const indent = ' '.repeat(req.path.length);
114
+ const label = req.label ? ` (${req.label})` : '';
115
+ return `${indent}${req.id}${label}: ${req.content}`;
116
+ }
117
+ /**
118
+ * Format a requirement tree for display
119
+ */
120
+ export function formatRequirementTree(requirements) {
121
+ // Sort by path to maintain hierarchy - children appear immediately after parent
122
+ const sorted = [...requirements].sort((a, b) => {
123
+ // Compare paths element by element for proper tree order
124
+ const maxLen = Math.max(a.path.length, b.path.length);
125
+ for (let i = 0; i < maxLen; i++) {
126
+ const aVal = i < a.path.length ? parseInt(a.path[i]) : -1;
127
+ const bVal = i < b.path.length ? parseInt(b.path[i]) : -1;
128
+ // If one path is a prefix of the other, the shorter one comes first
129
+ if (aVal === -1)
130
+ return -1;
131
+ if (bVal === -1)
132
+ return 1;
133
+ if (aVal !== bVal) {
134
+ return aVal - bVal;
135
+ }
136
+ }
137
+ return 0;
138
+ });
139
+ return sorted.map(formatRequirement).join('\n');
140
+ }
141
+ //# sourceMappingURL=requirements.js.map
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Extract test code context using @babel/parser AST traversal.
3
+ *
4
+ * Finds requirement() call references and extracts the enclosing
5
+ * meaningful code block (function, describe, test, etc.)
6
+ */
7
+ export interface TestCodeReference {
8
+ file: string;
9
+ startLine: number;
10
+ endLine: number;
11
+ code: string;
12
+ requirementId: string;
13
+ }
14
+ /**
15
+ * Find all test code blocks that reference a specific requirement
16
+ */
17
+ export declare function findTestCodeForRequirement(filePath: string, requirementId: string): TestCodeReference[];
18
+ /**
19
+ * Find all files that reference a requirement
20
+ */
21
+ export declare function findFilesWithRequirement(files: string[], requirementId: string): string[];
22
+ //# sourceMappingURL=testCodeExtractor.d.ts.map
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Extract test code context using @babel/parser AST traversal.
3
+ *
4
+ * Finds requirement() call references and extracts the enclosing
5
+ * meaningful code block (function, describe, test, etc.)
6
+ */
7
+ import { parse } from '@babel/parser';
8
+ import traverse from '@babel/traverse';
9
+ import * as t from '@babel/types';
10
+ import * as fs from 'fs';
11
+ /**
12
+ * Find all test code blocks that reference a specific requirement
13
+ */
14
+ export function findTestCodeForRequirement(filePath, requirementId) {
15
+ try {
16
+ const code = fs.readFileSync(filePath, 'utf-8');
17
+ const results = [];
18
+ // Parse with TypeScript and JSX support
19
+ const ast = parse(code, {
20
+ sourceType: 'module',
21
+ plugins: ['typescript', 'jsx'],
22
+ errorRecovery: true,
23
+ });
24
+ // Handle both ES module and CommonJS exports
25
+ const traverseFunc = typeof traverse === 'function' ? traverse : traverse.default;
26
+ traverseFunc(ast, {
27
+ CallExpression(path) {
28
+ // Check if this is a requirement('ID', ...) call
29
+ const callee = path.node.callee;
30
+ if (t.isIdentifier(callee) && callee.name === 'requirement') {
31
+ const args = path.node.arguments;
32
+ // Extract all string literal arguments (supports multi-requirement calls)
33
+ const refIds = [];
34
+ for (const arg of args) {
35
+ if (t.isStringLiteral(arg)) {
36
+ refIds.push(arg.value);
37
+ }
38
+ }
39
+ // Check if any argument matches the requirement we're looking for
40
+ // Match exact ID or if it's a child (e.g., searching for REQ-123 matches REQ-123.0)
41
+ for (const refId of refIds) {
42
+ const isMatch = refId === requirementId ||
43
+ refId.startsWith(`${requirementId}.`);
44
+ if (isMatch) {
45
+ // Find the meaningful enclosing block
46
+ const contextNode = findMeaningfulParent(path);
47
+ if (contextNode && contextNode.node.loc) {
48
+ const { start, end } = contextNode.node.loc;
49
+ const nodeStart = contextNode.node.start ?? 0;
50
+ const nodeEnd = contextNode.node.end ?? code.length;
51
+ results.push({
52
+ file: filePath,
53
+ startLine: start.line,
54
+ endLine: end.line,
55
+ code: code.slice(nodeStart, nodeEnd),
56
+ requirementId: refId,
57
+ });
58
+ }
59
+ // Only add one result per call expression, even if multiple refs match
60
+ break;
61
+ }
62
+ }
63
+ }
64
+ },
65
+ });
66
+ return results;
67
+ }
68
+ catch (error) {
69
+ console.error(`Error parsing ${filePath}:`, error);
70
+ return [];
71
+ }
72
+ }
73
+ /**
74
+ * Walk up the AST to find the nearest "meaningful" parent node.
75
+ * This could be a function, describe/test/it call, method, etc.
76
+ */
77
+ function findMeaningfulParent(path) {
78
+ let current = path;
79
+ while (current) {
80
+ const node = current.node;
81
+ // Check for various meaningful boundaries
82
+ if (t.isFunctionDeclaration(node) ||
83
+ t.isFunctionExpression(node) ||
84
+ t.isArrowFunctionExpression(node) ||
85
+ t.isClassMethod(node) ||
86
+ t.isObjectMethod(node)) {
87
+ return current;
88
+ }
89
+ // Check for call expressions (describe, test, it, etc.)
90
+ if (t.isCallExpression(node)) {
91
+ const callee = node.callee;
92
+ // Common test framework function names
93
+ const testFunctionNames = [
94
+ 'describe',
95
+ 'it',
96
+ 'test',
97
+ 'suite',
98
+ 'context',
99
+ 'beforeEach',
100
+ 'afterEach',
101
+ 'beforeAll',
102
+ 'afterAll',
103
+ ];
104
+ if (t.isIdentifier(callee) && testFunctionNames.includes(callee.name)) {
105
+ return current;
106
+ }
107
+ }
108
+ // Check for variable declarations that might contain test functions
109
+ if (t.isVariableDeclarator(node)) {
110
+ return current;
111
+ }
112
+ // Check for export declarations (for Storybook stories, etc.)
113
+ if (t.isExportNamedDeclaration(node) ||
114
+ t.isExportDefaultDeclaration(node)) {
115
+ return current;
116
+ }
117
+ current = current.parentPath;
118
+ }
119
+ return null;
120
+ }
121
+ /**
122
+ * Find all files that reference a requirement
123
+ */
124
+ export function findFilesWithRequirement(files, requirementId) {
125
+ const matchingFiles = [];
126
+ for (const file of files) {
127
+ try {
128
+ const code = fs.readFileSync(file, 'utf-8');
129
+ // Check for exact match or child references (e.g., AUTH-VALID-LOGIN or AUTH-VALID-LOGIN.0)
130
+ // Simple string search first for performance
131
+ // Patterns match both single and multi-arg calls:
132
+ // requirement('REQ-123')
133
+ // requirement('REQ-123', 'REQ-456')
134
+ // requirement('REQ-456', 'REQ-123') <-- ID anywhere in args
135
+ const hasMatch = code.includes(`'${requirementId}'`) ||
136
+ code.includes(`"${requirementId}"`) ||
137
+ code.includes(`\`${requirementId}\``) ||
138
+ code.includes(`'${requirementId}.`) ||
139
+ code.includes(`"${requirementId}.`) ||
140
+ code.includes(`\`${requirementId}.`);
141
+ if (hasMatch) {
142
+ matchingFiles.push(file);
143
+ }
144
+ }
145
+ catch (error) {
146
+ // Skip files that can't be read
147
+ continue;
148
+ }
149
+ }
150
+ return matchingFiles;
151
+ }
152
+ //# sourceMappingURL=testCodeExtractor.js.map
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Re-export shared types from CLI schema module
3
+ */
4
+ export type { Metadata, RequirementNode, RequirementsFile, } from '../schema/index.js';
5
+ /**
6
+ * Flattened requirement for search results
7
+ */
8
+ export interface FlattenedRequirement {
9
+ id: string;
10
+ rootId: string;
11
+ label: string;
12
+ content: string;
13
+ path: string[];
14
+ sourceFile: string;
15
+ documentTitle: string;
16
+ }
17
+ /**
18
+ * Test reference found in codebase
19
+ */
20
+ export interface TestReference {
21
+ file: string;
22
+ line: number;
23
+ column: number;
24
+ requirementId: string;
25
+ context: string;
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Browser-safe exports from the schema module.
3
+ * This file excludes Node.js-specific functionality (file I/O, fs module).
4
+ * Use this entry point when importing from browser/web environments.
5
+ */
6
+ export { MetadataSchema, RequirementNodeSchema, RequirementsFileSchema, ParsedCriterionSchema, RequirementPrefixSchema, RequirementKeySchema, REQUIREMENT_PREFIX_PATTERN, REQUIREMENT_KEY_PATTERN, ValidationError, validateMetadata, validateRequirementNode, validateRequirementsFile, validatePrefix, validateKey, normalizePrefix, parseRequirementKey, buildRequirementKey, } from './schemas.js';
7
+ export type { Metadata, RequirementNode, RequirementsFile, ParsedCriterion, RequirementPrefix, RequirementKey, } from './schemas.js';
8
+ export { DEFAULT_DELIMITER, buildRequirementsMarkdown, buildRequirementMarkdown, } from './builder.js';
9
+ export type { ConvexRequirement, } from './conversions.js';
10
+ export { convexToRequirements, requirementsToConvex, buildMetadata, extractRequirementKeys, groupByRoot, constructKey, parseKey, } from './conversions.js';
11
+ export { DELIMITER_PATTERN, parseCriterionLine, parseRootLine, parseRequirementBlock, extractRequirementBlocks, parseRequirementBlocksFromMarkdown, flattenRequirementTree, findRequirementById, getAllRequirements, } from './parser-core.js';
12
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Browser-safe exports from the schema module.
3
+ * This file excludes Node.js-specific functionality (file I/O, fs module).
4
+ * Use this entry point when importing from browser/web environments.
5
+ */
6
+ // Schemas and types (uses zod - browser-safe)
7
+ export {
8
+ // Zod schemas
9
+ MetadataSchema, RequirementNodeSchema, RequirementsFileSchema, ParsedCriterionSchema, RequirementPrefixSchema, RequirementKeySchema,
10
+ // Patterns (for external validation)
11
+ REQUIREMENT_PREFIX_PATTERN, REQUIREMENT_KEY_PATTERN,
12
+ // Validation
13
+ ValidationError, validateMetadata, validateRequirementNode, validateRequirementsFile, validatePrefix, validateKey,
14
+ // Prefix/key utilities
15
+ normalizePrefix, parseRequirementKey, buildRequirementKey, } from './schemas.js';
16
+ // Building (uses yaml package - browser-safe)
17
+ export { DEFAULT_DELIMITER, buildRequirementsMarkdown, buildRequirementMarkdown, } from './builder.js';
18
+ export { convexToRequirements, requirementsToConvex, buildMetadata, extractRequirementKeys, groupByRoot, constructKey, parseKey, } from './conversions.js';
19
+ // Parser core (pure TypeScript - browser-safe, no fs dependency)
20
+ // These functions parse markdown strings directly without file I/O
21
+ export { DELIMITER_PATTERN, parseCriterionLine, parseRootLine, parseRequirementBlock, extractRequirementBlocks, parseRequirementBlocksFromMarkdown, flattenRequirementTree, findRequirementById, getAllRequirements, } from './parser-core.js';
22
+ // NOTE: parser.ts and resolver.ts are excluded because they use Node.js 'fs' module.
23
+ // Use parser-core.ts functions above for browser/Convex environments.
24
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Build Markdown requirements files from structured data.
3
+ */
4
+ import { RequirementNode, Metadata } from './schemas.js';
5
+ /**
6
+ * Default delimiter for requirements.
7
+ * Can be overridden for organization-specific preferences.
8
+ */
9
+ export declare const DEFAULT_DELIMITER = "\u2192";
10
+ /**
11
+ * Build complete Markdown requirements document.
12
+ */
13
+ export declare function buildRequirementsMarkdown(metadata: Metadata, requirements: RequirementNode[], documentTitle?: string): string;
14
+ /**
15
+ * Build Markdown for a single requirement (for testing/debugging).
16
+ */
17
+ export declare function buildRequirementMarkdown(node: RequirementNode): string;
18
+ /**
19
+ * Build a complete requirements file from metadata and raw markdown content.
20
+ * Used by CLI pull to combine frontmatter with cloud-sourced markdown.
21
+ *
22
+ * SYNC-ARCH-1: markdownContent is the source of truth from the cloud.
23
+ */
24
+ export declare function buildRequirementsFile(metadata: Metadata, markdownContent: string): string;
25
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Build Markdown requirements files from structured data.
3
+ */
4
+ import YAML from 'yaml';
5
+ /**
6
+ * Default delimiter for requirements.
7
+ * Can be overridden for organization-specific preferences.
8
+ */
9
+ export const DEFAULT_DELIMITER = '→';
10
+ /**
11
+ * Build YAML frontmatter from metadata.
12
+ */
13
+ function buildFrontmatter(metadata) {
14
+ const yamlStr = YAML.stringify(metadata, {
15
+ lineWidth: 0, // Don't wrap lines
16
+ minContentWidth: 0,
17
+ });
18
+ return `---\n${yamlStr.trim()}\n---`;
19
+ }
20
+ /**
21
+ * Build a dotrequirements block from a requirement node.
22
+ * Formats children with explicit position paths and proper indentation.
23
+ */
24
+ function buildRequirementBlock(node, delimiter = DEFAULT_DELIMITER) {
25
+ // First line: root requirement with delimiter
26
+ // Include label if it's not empty (empty string means unlabeled)
27
+ const rootLabel = node.label
28
+ ? `${node.label.charAt(0).toUpperCase() + node.label.slice(1)} `
29
+ : '';
30
+ let block = `${rootLabel}${delimiter} ${node.content}\n`;
31
+ // Recursively build criteria lines
32
+ function addCriteria(children, parentPosition = '') {
33
+ children.forEach((child, index) => {
34
+ const position = parentPosition === '' ? `${index}` : `${parentPosition}.${index}`;
35
+ const depth = position.split('.').length - 1;
36
+ const indent = ' '.repeat(depth + 1); // 2 spaces per level
37
+ // Include label if present, otherwise just delimiter
38
+ const labelPart = child.label
39
+ ? `${child.label.charAt(0).toUpperCase() + child.label.slice(1)} `
40
+ : '';
41
+ block += `${indent}${position}. ${labelPart}${delimiter} ${child.content}\n`;
42
+ // Recursively add grandchildren
43
+ if (child.children && child.children.length > 0) {
44
+ addCriteria(child.children, position);
45
+ }
46
+ });
47
+ }
48
+ addCriteria(node.children);
49
+ return block.trimEnd();
50
+ }
51
+ /**
52
+ * Build the children portion of a requirement block (without the root line).
53
+ */
54
+ function buildChildrenBlock(children) {
55
+ let block = '';
56
+ function addChildren(nodes, parentPosition = '') {
57
+ nodes.forEach((child, index) => {
58
+ const position = parentPosition === '' ? `${index}` : `${parentPosition}.${index}`;
59
+ const depth = position.split('.').length - 1;
60
+ const indent = ' '.repeat(depth + 1); // 2 spaces per level
61
+ // Include label if present, otherwise just delimiter
62
+ const labelPart = child.label
63
+ ? `${child.label.charAt(0).toUpperCase() + child.label.slice(1)} `
64
+ : '';
65
+ block += `${indent}${position}. ${labelPart}→ ${child.content}\n`;
66
+ // Recursively add grandchildren
67
+ if (child.children && child.children.length > 0) {
68
+ addChildren(child.children, position);
69
+ }
70
+ });
71
+ }
72
+ addChildren(children);
73
+ return block.trimEnd();
74
+ }
75
+ /**
76
+ * Build a complete requirement section (heading + block).
77
+ */
78
+ function buildRequirementSection(node, title) {
79
+ const displayTitle = title || node.content;
80
+ // Heading now just has the title, no key
81
+ let section = `## ${displayTitle}\n\n`;
82
+ section += '```dotrequirements\n';
83
+ // First line of block has the key
84
+ section += `${node.id}: ${node.content}\n`;
85
+ // Then add children
86
+ if (node.children && node.children.length > 0) {
87
+ section += buildChildrenBlock(node.children);
88
+ }
89
+ section += '\n```\n';
90
+ return section;
91
+ }
92
+ /**
93
+ * Build complete Markdown requirements document.
94
+ */
95
+ export function buildRequirementsMarkdown(metadata, requirements, documentTitle) {
96
+ let markdown = buildFrontmatter(metadata);
97
+ markdown += '\n\n';
98
+ // Add document title if provided
99
+ if (documentTitle) {
100
+ markdown += `# ${documentTitle}\n\n`;
101
+ }
102
+ // Add each requirement section
103
+ for (const req of requirements) {
104
+ markdown += buildRequirementSection(req);
105
+ markdown += '\n';
106
+ }
107
+ return markdown.trimEnd() + '\n';
108
+ }
109
+ /**
110
+ * Build Markdown for a single requirement (for testing/debugging).
111
+ */
112
+ export function buildRequirementMarkdown(node) {
113
+ return buildRequirementSection(node);
114
+ }
115
+ /**
116
+ * Build a complete requirements file from metadata and raw markdown content.
117
+ * Used by CLI pull to combine frontmatter with cloud-sourced markdown.
118
+ *
119
+ * SYNC-ARCH-1: markdownContent is the source of truth from the cloud.
120
+ */
121
+ export function buildRequirementsFile(metadata, markdownContent) {
122
+ const frontmatter = buildFrontmatter(metadata);
123
+ return `${frontmatter}\n\n${markdownContent.trim()}\n`;
124
+ }
125
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Convert between Convex flat representation and hierarchical RequirementNode trees.
3
+ */
4
+ import { RequirementNode, Metadata } from './schemas.js';
5
+ /**
6
+ * Convex requirement type (flat structure with position paths).
7
+ * This mirrors the Convex database schema.
8
+ */
9
+ export interface ConvexRequirement {
10
+ _id: string;
11
+ prefix: string;
12
+ index: number;
13
+ documentId: string;
14
+ label: string;
15
+ content: string;
16
+ projectId: string;
17
+ rootId?: string;
18
+ position?: string;
19
+ metadata?: any;
20
+ externalLinks?: {
21
+ jira?: string;
22
+ notion?: string;
23
+ };
24
+ updatedAt: number;
25
+ }
26
+ /**
27
+ * Construct a requirement key from prefix and index.
28
+ * E.g., ("REQ", 123) -> "REQ-123"
29
+ */
30
+ export declare function constructKey(prefix: string, index: number): string;
31
+ /**
32
+ * Parse a requirement key into prefix and index.
33
+ * E.g., "REQ-123" -> { prefix: "REQ", index: 123 }
34
+ * Returns null if key doesn't match expected format.
35
+ */
36
+ export declare function parseKey(key: string): {
37
+ prefix: string;
38
+ index: number;
39
+ } | null;
40
+ /**
41
+ * Build a hierarchical tree from flat Convex requirements.
42
+ * Uses position paths to reconstruct parent-child relationships.
43
+ */
44
+ export declare function convexToRequirements(convexReqs: ConvexRequirement[]): RequirementNode[];
45
+ /**
46
+ * Flatten a hierarchical structure back to Convex flat format.
47
+ * Generates position paths for each node.
48
+ */
49
+ export declare function requirementsToConvex(nodes: RequirementNode[], projectId: string, documentId: string): ConvexRequirement[];
50
+ /**
51
+ * Build metadata from project info and pull time.
52
+ * DOC-HEADER-11.3: When pulling, include defaultPrefix in the frontmatter.
53
+ */
54
+ export declare function buildMetadata(projectId: string, version?: number, document?: {
55
+ id?: string;
56
+ title: string;
57
+ defaultPrefix?: string;
58
+ }): Metadata;
59
+ /**
60
+ * Extract unique requirement keys from Convex data.
61
+ * Useful for detecting duplicates or tracking which requirements exist.
62
+ */
63
+ export declare function extractRequirementKeys(convexReqs: ConvexRequirement[]): Set<string>;
64
+ /**
65
+ * Group Convex requirements by their root.
66
+ * Returns a map of rootId → children.
67
+ */
68
+ export declare function groupByRoot(convexReqs: ConvexRequirement[]): Map<string | undefined, ConvexRequirement[]>;
69
+ //# sourceMappingURL=conversions.d.ts.map