@sudocode-ai/integration-openspec 0.1.14

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 (41) hide show
  1. package/dist/id-generator.d.ts +114 -0
  2. package/dist/id-generator.d.ts.map +1 -0
  3. package/dist/id-generator.js +165 -0
  4. package/dist/id-generator.js.map +1 -0
  5. package/dist/index.d.ts +29 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +692 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/parser/change-parser.d.ts +164 -0
  10. package/dist/parser/change-parser.d.ts.map +1 -0
  11. package/dist/parser/change-parser.js +339 -0
  12. package/dist/parser/change-parser.js.map +1 -0
  13. package/dist/parser/markdown-utils.d.ts +138 -0
  14. package/dist/parser/markdown-utils.d.ts.map +1 -0
  15. package/dist/parser/markdown-utils.js +283 -0
  16. package/dist/parser/markdown-utils.js.map +1 -0
  17. package/dist/parser/spec-parser.d.ts +116 -0
  18. package/dist/parser/spec-parser.d.ts.map +1 -0
  19. package/dist/parser/spec-parser.js +204 -0
  20. package/dist/parser/spec-parser.js.map +1 -0
  21. package/dist/parser/tasks-parser.d.ts +120 -0
  22. package/dist/parser/tasks-parser.d.ts.map +1 -0
  23. package/dist/parser/tasks-parser.js +176 -0
  24. package/dist/parser/tasks-parser.js.map +1 -0
  25. package/dist/watcher.d.ts +160 -0
  26. package/dist/watcher.d.ts.map +1 -0
  27. package/dist/watcher.js +614 -0
  28. package/dist/watcher.js.map +1 -0
  29. package/dist/writer/index.d.ts +9 -0
  30. package/dist/writer/index.d.ts.map +1 -0
  31. package/dist/writer/index.js +9 -0
  32. package/dist/writer/index.js.map +1 -0
  33. package/dist/writer/spec-writer.d.ts +24 -0
  34. package/dist/writer/spec-writer.d.ts.map +1 -0
  35. package/dist/writer/spec-writer.js +75 -0
  36. package/dist/writer/spec-writer.js.map +1 -0
  37. package/dist/writer/tasks-writer.d.ts +33 -0
  38. package/dist/writer/tasks-writer.d.ts.map +1 -0
  39. package/dist/writer/tasks-writer.js +144 -0
  40. package/dist/writer/tasks-writer.js.map +1 -0
  41. package/package.json +43 -0
@@ -0,0 +1,204 @@
1
+ /**
2
+ * OpenSpec Spec Parser
3
+ *
4
+ * Parses OpenSpec specification files from `openspec/specs/[capability]/spec.md`.
5
+ *
6
+ * OpenSpec spec format:
7
+ * - Title from H1 heading: `# Title`
8
+ * - Purpose section: `## Purpose`
9
+ * - Requirements: `### Requirement: Name`
10
+ * - Scenarios: `#### Scenario: Description` with GIVEN/WHEN/THEN steps
11
+ */
12
+ import { readFileSync } from "fs";
13
+ import * as path from "path";
14
+ import { extractTitle, extractSection } from "./markdown-utils.js";
15
+ // ============================================================================
16
+ // Regex Patterns
17
+ // ============================================================================
18
+ /**
19
+ * OpenSpec-specific patterns for parsing spec files
20
+ */
21
+ export const SPEC_PATTERNS = {
22
+ /** Match requirement header: ### Requirement: Name */
23
+ REQUIREMENT: /^###\s+Requirement:\s*(.+)$/m,
24
+ /** Match scenario header: #### Scenario: Description */
25
+ SCENARIO: /^####\s+Scenario:\s*(.+)$/m,
26
+ /** Match GIVEN step: - **GIVEN** content or **GIVEN**: content */
27
+ GIVEN: /^-?\s*\*\*GIVEN\*\*:?\s*(.+)$/i,
28
+ /** Match WHEN step: - **WHEN** content or **WHEN**: content */
29
+ WHEN: /^-?\s*\*\*WHEN\*\*:?\s*(.+)$/i,
30
+ /** Match THEN step: - **THEN** content or **THEN**: content */
31
+ THEN: /^-?\s*\*\*THEN\*\*:?\s*(.+)$/i,
32
+ };
33
+ // ============================================================================
34
+ // Parser Functions
35
+ // ============================================================================
36
+ /**
37
+ * Parse an OpenSpec spec file
38
+ *
39
+ * @param filePath - Absolute path to the spec.md file
40
+ * @returns Parsed spec object
41
+ * @throws Error if file cannot be read
42
+ *
43
+ * @example
44
+ * const spec = parseSpecFile("/path/to/openspec/specs/cli-init/spec.md");
45
+ * console.log(spec.title); // "CLI Init Specification"
46
+ * console.log(spec.capability); // "cli-init"
47
+ * console.log(spec.requirements); // Array of parsed requirements
48
+ */
49
+ export function parseSpecFile(filePath) {
50
+ const rawContent = readFileSync(filePath, "utf-8");
51
+ const lines = rawContent.split("\n");
52
+ // Extract capability from directory name
53
+ const capability = extractCapability(filePath);
54
+ // Extract title from H1 heading
55
+ const title = extractTitle(lines) || capability;
56
+ // Extract purpose section
57
+ const purposeLines = extractSection(lines, "Purpose", 2);
58
+ const purpose = purposeLines ? purposeLines.join("\n").trim() : undefined;
59
+ // Parse requirements
60
+ const requirements = parseRequirements(rawContent);
61
+ return {
62
+ capability,
63
+ title,
64
+ purpose,
65
+ requirements,
66
+ rawContent,
67
+ filePath,
68
+ };
69
+ }
70
+ /**
71
+ * Extract the capability name from the file path
72
+ *
73
+ * Assumes path structure: .../specs/[capability]/spec.md
74
+ *
75
+ * @param filePath - Path to the spec file
76
+ * @returns Capability directory name
77
+ */
78
+ export function extractCapability(filePath) {
79
+ const parts = filePath.split(path.sep);
80
+ const specIndex = parts.lastIndexOf("spec.md");
81
+ if (specIndex > 0) {
82
+ return parts[specIndex - 1];
83
+ }
84
+ // Fallback: use parent directory name
85
+ return path.basename(path.dirname(filePath));
86
+ }
87
+ /**
88
+ * Parse all requirements from spec content
89
+ *
90
+ * @param content - Full markdown content
91
+ * @returns Array of parsed requirements
92
+ */
93
+ export function parseRequirements(content) {
94
+ const requirements = [];
95
+ const lines = content.split("\n");
96
+ // Find all requirement header positions
97
+ const requirementPositions = [];
98
+ for (let i = 0; i < lines.length; i++) {
99
+ const match = lines[i].match(SPEC_PATTERNS.REQUIREMENT);
100
+ if (match) {
101
+ requirementPositions.push({
102
+ name: match[1].trim(),
103
+ lineIndex: i,
104
+ });
105
+ }
106
+ }
107
+ // Extract content for each requirement
108
+ for (let i = 0; i < requirementPositions.length; i++) {
109
+ const req = requirementPositions[i];
110
+ const startLine = req.lineIndex + 1;
111
+ // End at next requirement or end of file
112
+ const endLine = i < requirementPositions.length - 1
113
+ ? requirementPositions[i + 1].lineIndex
114
+ : lines.length;
115
+ // Get requirement content (excluding the header line)
116
+ const requirementLines = lines.slice(startLine, endLine);
117
+ const requirementContent = requirementLines.join("\n").trim();
118
+ // Parse scenarios within this requirement
119
+ const scenarios = parseScenarios(requirementContent);
120
+ requirements.push({
121
+ name: req.name,
122
+ content: requirementContent,
123
+ scenarios,
124
+ });
125
+ }
126
+ return requirements;
127
+ }
128
+ /**
129
+ * Parse scenarios from requirement content
130
+ *
131
+ * @param content - Requirement section content
132
+ * @returns Array of parsed scenarios
133
+ */
134
+ export function parseScenarios(content) {
135
+ const scenarios = [];
136
+ const lines = content.split("\n");
137
+ // Find all scenario header positions
138
+ const scenarioPositions = [];
139
+ for (let i = 0; i < lines.length; i++) {
140
+ const match = lines[i].match(SPEC_PATTERNS.SCENARIO);
141
+ if (match) {
142
+ scenarioPositions.push({
143
+ description: match[1].trim(),
144
+ lineIndex: i,
145
+ });
146
+ }
147
+ }
148
+ // Extract content for each scenario
149
+ for (let i = 0; i < scenarioPositions.length; i++) {
150
+ const scenario = scenarioPositions[i];
151
+ const startLine = scenario.lineIndex + 1;
152
+ // End at next scenario or end of content
153
+ const endLine = i < scenarioPositions.length - 1
154
+ ? scenarioPositions[i + 1].lineIndex
155
+ : lines.length;
156
+ // Get scenario content
157
+ const scenarioLines = lines.slice(startLine, endLine);
158
+ // Parse GIVEN/WHEN/THEN steps
159
+ const { given, when, then } = parseGivenWhenThen(scenarioLines);
160
+ scenarios.push({
161
+ description: scenario.description,
162
+ given: given.length > 0 ? given : undefined,
163
+ when: when.length > 0 ? when : undefined,
164
+ then: then.length > 0 ? then : undefined,
165
+ });
166
+ }
167
+ return scenarios;
168
+ }
169
+ /**
170
+ * Parse GIVEN/WHEN/THEN steps from scenario lines
171
+ *
172
+ * @param lines - Lines within a scenario section
173
+ * @returns Object with given, when, then arrays
174
+ */
175
+ export function parseGivenWhenThen(lines) {
176
+ const given = [];
177
+ const when = [];
178
+ const then = [];
179
+ for (const line of lines) {
180
+ const trimmed = line.trim();
181
+ if (!trimmed)
182
+ continue;
183
+ // Check for GIVEN
184
+ const givenMatch = trimmed.match(SPEC_PATTERNS.GIVEN);
185
+ if (givenMatch) {
186
+ given.push(givenMatch[1].trim());
187
+ continue;
188
+ }
189
+ // Check for WHEN
190
+ const whenMatch = trimmed.match(SPEC_PATTERNS.WHEN);
191
+ if (whenMatch) {
192
+ when.push(whenMatch[1].trim());
193
+ continue;
194
+ }
195
+ // Check for THEN
196
+ const thenMatch = trimmed.match(SPEC_PATTERNS.THEN);
197
+ if (thenMatch) {
198
+ then.push(thenMatch[1].trim());
199
+ continue;
200
+ }
201
+ }
202
+ return { given, when, then };
203
+ }
204
+ //# sourceMappingURL=spec-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-parser.js","sourceRoot":"","sources":["../../src/parser/spec-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Tasks Parser for OpenSpec Integration
3
+ *
4
+ * Parses tasks.md files from OpenSpec change directories and extracts tasks.
5
+ *
6
+ * OpenSpec tasks.md format (simpler than spec-kit):
7
+ * ```markdown
8
+ * # Tasks
9
+ *
10
+ * - [ ] First task to complete
11
+ * - [x] Completed task
12
+ * - [ ] Another incomplete task
13
+ * - [ ] Nested subtask (if any)
14
+ * ```
15
+ *
16
+ * Task format: `- [ ] Description`
17
+ * - Checkbox: `[ ]` (incomplete) or `[x]` (complete)
18
+ * - Description: Rest of the line
19
+ * - Indentation: Optional nesting via leading spaces
20
+ */
21
+ /**
22
+ * Parsed task from an OpenSpec tasks.md file
23
+ */
24
+ export interface ParsedTask {
25
+ /** Task description */
26
+ description: string;
27
+ /** Whether the task is completed */
28
+ completed: boolean;
29
+ /** Line number in the source file (1-indexed) */
30
+ lineNumber: number;
31
+ /** Indentation level (for nested tasks) */
32
+ indentLevel: number;
33
+ /** Raw line from the file */
34
+ rawLine: string;
35
+ }
36
+ /**
37
+ * Parsed result from an OpenSpec tasks.md file
38
+ */
39
+ export interface ParsedTasksFile {
40
+ /** Array of parsed tasks */
41
+ tasks: ParsedTask[];
42
+ /** Source file path */
43
+ filePath: string;
44
+ /** Summary statistics */
45
+ stats: {
46
+ total: number;
47
+ completed: number;
48
+ incomplete: number;
49
+ };
50
+ /** Completion percentage (0-100) */
51
+ completionPercentage: number;
52
+ }
53
+ /**
54
+ * Regex patterns for OpenSpec task parsing
55
+ */
56
+ export declare const TASK_PATTERNS: {
57
+ /** Match task line: - [ ] Description or - [x] Description (requires space after hyphen) */
58
+ TASK_LINE: RegExp;
59
+ };
60
+ /**
61
+ * Parse an OpenSpec tasks.md file and extract all tasks
62
+ *
63
+ * @param filePath - Absolute path to the tasks.md file
64
+ * @returns Parsed tasks data or null if file doesn't exist
65
+ *
66
+ * @example
67
+ * const tasksFile = parseTasks("/project/openspec/changes/add-feature/tasks.md");
68
+ * console.log(tasksFile?.tasks.length); // 5
69
+ * console.log(tasksFile?.completionPercentage); // 40
70
+ */
71
+ export declare function parseTasks(filePath: string): ParsedTasksFile | null;
72
+ /**
73
+ * Parse tasks content from a string (for testing or in-memory parsing)
74
+ *
75
+ * @param content - Markdown content string
76
+ * @param filePath - Optional file path for reference
77
+ * @returns Parsed tasks data
78
+ */
79
+ export declare function parseTasksContent(content: string, filePath?: string): ParsedTasksFile;
80
+ /**
81
+ * Get all tasks from a file as a simple array
82
+ *
83
+ * @param filePath - Path to the tasks file
84
+ * @returns Array of parsed tasks or empty array
85
+ */
86
+ export declare function getAllTasks(filePath: string): ParsedTask[];
87
+ /**
88
+ * Get incomplete tasks from a file
89
+ *
90
+ * @param filePath - Path to the tasks file
91
+ * @returns Array of incomplete tasks
92
+ */
93
+ export declare function getIncompleteTasks(filePath: string): ParsedTask[];
94
+ /**
95
+ * Get task completion statistics
96
+ *
97
+ * @param filePath - Path to the tasks file
98
+ * @returns Statistics object or null
99
+ */
100
+ export declare function getTaskStats(filePath: string): {
101
+ total: number;
102
+ completed: number;
103
+ incomplete: number;
104
+ completionPercentage: number;
105
+ } | null;
106
+ /**
107
+ * Calculate completion percentage from tasks array
108
+ *
109
+ * @param tasks - Array of parsed tasks
110
+ * @returns Completion percentage (0-100)
111
+ */
112
+ export declare function calculateCompletionPercentage(tasks: ParsedTask[]): number;
113
+ /**
114
+ * Check if a file appears to be a valid tasks.md file
115
+ *
116
+ * @param filePath - Path to check
117
+ * @returns true if the file looks like a tasks file
118
+ */
119
+ export declare function isTasksFile(filePath: string): boolean;
120
+ //# sourceMappingURL=tasks-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks-parser.d.ts","sourceRoot":"","sources":["../../src/parser/tasks-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,oCAAoC;IACpC,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,eAAO,MAAM,aAAa;IACxB,4FAA4F;;CAE7F,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAYnE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAAmB,GAC5B,eAAe,CAkCjB;AAwBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAG1D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAGjE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,GAAG,IAAI,CAQP;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAIzE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAoBrD"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Tasks Parser for OpenSpec Integration
3
+ *
4
+ * Parses tasks.md files from OpenSpec change directories and extracts tasks.
5
+ *
6
+ * OpenSpec tasks.md format (simpler than spec-kit):
7
+ * ```markdown
8
+ * # Tasks
9
+ *
10
+ * - [ ] First task to complete
11
+ * - [x] Completed task
12
+ * - [ ] Another incomplete task
13
+ * - [ ] Nested subtask (if any)
14
+ * ```
15
+ *
16
+ * Task format: `- [ ] Description`
17
+ * - Checkbox: `[ ]` (incomplete) or `[x]` (complete)
18
+ * - Description: Rest of the line
19
+ * - Indentation: Optional nesting via leading spaces
20
+ */
21
+ import { readFileSync, existsSync } from "fs";
22
+ /**
23
+ * Regex patterns for OpenSpec task parsing
24
+ */
25
+ export const TASK_PATTERNS = {
26
+ /** Match task line: - [ ] Description or - [x] Description (requires space after hyphen) */
27
+ TASK_LINE: /^(\s*)-\s+\[([ xX])\]\s*(.+)$/,
28
+ };
29
+ /**
30
+ * Parse an OpenSpec tasks.md file and extract all tasks
31
+ *
32
+ * @param filePath - Absolute path to the tasks.md file
33
+ * @returns Parsed tasks data or null if file doesn't exist
34
+ *
35
+ * @example
36
+ * const tasksFile = parseTasks("/project/openspec/changes/add-feature/tasks.md");
37
+ * console.log(tasksFile?.tasks.length); // 5
38
+ * console.log(tasksFile?.completionPercentage); // 40
39
+ */
40
+ export function parseTasks(filePath) {
41
+ if (!existsSync(filePath)) {
42
+ return null;
43
+ }
44
+ try {
45
+ const content = readFileSync(filePath, "utf-8");
46
+ return parseTasksContent(content, filePath);
47
+ }
48
+ catch (error) {
49
+ console.error(`[tasks-parser] Failed to parse ${filePath}:`, error);
50
+ return null;
51
+ }
52
+ }
53
+ /**
54
+ * Parse tasks content from a string (for testing or in-memory parsing)
55
+ *
56
+ * @param content - Markdown content string
57
+ * @param filePath - Optional file path for reference
58
+ * @returns Parsed tasks data
59
+ */
60
+ export function parseTasksContent(content, filePath = "<string>") {
61
+ const lines = content.split("\n");
62
+ const tasks = [];
63
+ // Parse each line
64
+ for (let i = 0; i < lines.length; i++) {
65
+ const line = lines[i];
66
+ const lineNumber = i + 1; // 1-indexed
67
+ // Check for task line
68
+ const taskMatch = line.match(TASK_PATTERNS.TASK_LINE);
69
+ if (taskMatch) {
70
+ const task = parseTaskLine(line, taskMatch, lineNumber);
71
+ tasks.push(task);
72
+ }
73
+ }
74
+ // Calculate stats
75
+ const stats = {
76
+ total: tasks.length,
77
+ completed: tasks.filter((t) => t.completed).length,
78
+ incomplete: tasks.filter((t) => !t.completed).length,
79
+ };
80
+ // Calculate completion percentage
81
+ const completionPercentage = stats.total > 0 ? Math.round((stats.completed / stats.total) * 100) : 0;
82
+ return {
83
+ tasks,
84
+ filePath,
85
+ stats,
86
+ completionPercentage,
87
+ };
88
+ }
89
+ /**
90
+ * Parse a single task line
91
+ */
92
+ function parseTaskLine(line, match, lineNumber) {
93
+ const [, leadingSpace, checkbox, description] = match;
94
+ // Calculate indent level (2 spaces = 1 level)
95
+ const indentLevel = Math.floor(leadingSpace.length / 2);
96
+ return {
97
+ description: description.trim(),
98
+ completed: checkbox.toLowerCase() === "x",
99
+ lineNumber,
100
+ indentLevel,
101
+ rawLine: line,
102
+ };
103
+ }
104
+ /**
105
+ * Get all tasks from a file as a simple array
106
+ *
107
+ * @param filePath - Path to the tasks file
108
+ * @returns Array of parsed tasks or empty array
109
+ */
110
+ export function getAllTasks(filePath) {
111
+ const result = parseTasks(filePath);
112
+ return result?.tasks || [];
113
+ }
114
+ /**
115
+ * Get incomplete tasks from a file
116
+ *
117
+ * @param filePath - Path to the tasks file
118
+ * @returns Array of incomplete tasks
119
+ */
120
+ export function getIncompleteTasks(filePath) {
121
+ const tasks = getAllTasks(filePath);
122
+ return tasks.filter((t) => !t.completed);
123
+ }
124
+ /**
125
+ * Get task completion statistics
126
+ *
127
+ * @param filePath - Path to the tasks file
128
+ * @returns Statistics object or null
129
+ */
130
+ export function getTaskStats(filePath) {
131
+ const result = parseTasks(filePath);
132
+ if (!result)
133
+ return null;
134
+ return {
135
+ ...result.stats,
136
+ completionPercentage: result.completionPercentage,
137
+ };
138
+ }
139
+ /**
140
+ * Calculate completion percentage from tasks array
141
+ *
142
+ * @param tasks - Array of parsed tasks
143
+ * @returns Completion percentage (0-100)
144
+ */
145
+ export function calculateCompletionPercentage(tasks) {
146
+ if (tasks.length === 0)
147
+ return 0;
148
+ const completed = tasks.filter((t) => t.completed).length;
149
+ return Math.round((completed / tasks.length) * 100);
150
+ }
151
+ /**
152
+ * Check if a file appears to be a valid tasks.md file
153
+ *
154
+ * @param filePath - Path to check
155
+ * @returns true if the file looks like a tasks file
156
+ */
157
+ export function isTasksFile(filePath) {
158
+ if (!existsSync(filePath)) {
159
+ return false;
160
+ }
161
+ try {
162
+ const content = readFileSync(filePath, "utf-8");
163
+ const lines = content.split("\n").slice(0, 30); // Check first 30 lines
164
+ // Look for task-like lines
165
+ for (const line of lines) {
166
+ if (TASK_PATTERNS.TASK_LINE.test(line)) {
167
+ return true;
168
+ }
169
+ }
170
+ return false;
171
+ }
172
+ catch {
173
+ return false;
174
+ }
175
+ }
176
+ //# sourceMappingURL=tasks-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks-parser.js","sourceRoot":"","sources":["../../src/parser/tasks-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * File watcher for OpenSpec integration
3
+ *
4
+ * Watches the OpenSpec directory for changes to spec files and change directories.
5
+ * Detects which entities were created, updated, or deleted.
6
+ *
7
+ * Watch patterns:
8
+ * - specs/ directory (all .md files) - Spec file changes
9
+ * - changes/<name>/proposal.md - Change proposal updates
10
+ * - changes/<name>/tasks.md - Change task updates
11
+ * - changes/archive/<name>/ - Archived change detection
12
+ * - changes/<name>/specs/<cap>/ - Delta directory changes
13
+ */
14
+ import type { ExternalChange, ExternalEntity } from "@sudocode-ai/types";
15
+ /**
16
+ * Callback type for change notifications
17
+ */
18
+ export type ChangeCallback = (changes: ExternalChange[]) => void;
19
+ /**
20
+ * Options for the OpenSpecWatcher
21
+ */
22
+ export interface OpenSpecWatcherOptions {
23
+ /** Path to the OpenSpec directory */
24
+ openspecPath: string;
25
+ /** Prefix for spec IDs (default: "os") */
26
+ specPrefix?: string;
27
+ /** Prefix for change IDs (default: "osc") */
28
+ changePrefix?: string;
29
+ /** Include archived changes in tracking (default: true) */
30
+ trackArchived?: boolean;
31
+ /** Debounce interval in milliseconds (default: 100) */
32
+ debounceMs?: number;
33
+ }
34
+ /**
35
+ * OpenSpecWatcher monitors the OpenSpec directory for changes
36
+ *
37
+ * Uses content hashing to detect actual changes vs just file touches.
38
+ * This prevents false positives from atomic writes and other file operations.
39
+ */
40
+ export declare class OpenSpecWatcher {
41
+ private watcher;
42
+ private entityHashes;
43
+ private callback;
44
+ private isProcessing;
45
+ private debounceTimer;
46
+ private isRelevantFile;
47
+ private pendingArchiveMoves;
48
+ private readonly ARCHIVE_MOVE_WINDOW_MS;
49
+ private readonly openspecPath;
50
+ private readonly specPrefix;
51
+ private readonly changePrefix;
52
+ private readonly trackArchived;
53
+ private readonly debounceMs;
54
+ constructor(options: OpenSpecWatcherOptions);
55
+ /**
56
+ * Update the cached hash for a specific entity after we wrote to it.
57
+ * This prevents the watcher from detecting our own writes as changes.
58
+ */
59
+ updateEntityHash(entityId: string, hash: string): void;
60
+ /**
61
+ * Remove an entity from the hash cache (after deletion)
62
+ */
63
+ removeEntityHash(entityId: string): void;
64
+ /**
65
+ * Start watching for changes
66
+ *
67
+ * @param callback - Function to call when changes are detected
68
+ */
69
+ start(callback: ChangeCallback): void;
70
+ /**
71
+ * Stop watching for changes
72
+ */
73
+ stop(): void;
74
+ /**
75
+ * Check if watcher is active
76
+ */
77
+ isWatching(): boolean;
78
+ /**
79
+ * Handle file change event
80
+ */
81
+ private handleFileChange;
82
+ /**
83
+ * Handle file deleted event
84
+ */
85
+ private handleFileDeleted;
86
+ /**
87
+ * Handle directory added event
88
+ * Used to detect archive moves (change moved to archive/)
89
+ */
90
+ private handleDirectoryAdded;
91
+ /**
92
+ * Handle directory removed event
93
+ * Used to detect archive moves (change moved from changes/)
94
+ */
95
+ private handleDirectoryRemoved;
96
+ /**
97
+ * Extract change name from an archive directory path
98
+ * Archive pattern: changes/archive/YYYY-MM-DD-name/ or changes/archive/name/
99
+ */
100
+ private extractChangeNameFromArchive;
101
+ /**
102
+ * Clean up old pending archive move entries
103
+ */
104
+ private cleanupPendingArchiveMoves;
105
+ /**
106
+ * Schedule change processing with debouncing
107
+ */
108
+ private scheduleProcessChanges;
109
+ /**
110
+ * Process changes by comparing current state to cached hashes
111
+ */
112
+ private processChanges;
113
+ /**
114
+ * Capture current state (entity hashes) for comparison
115
+ */
116
+ captureState(): void;
117
+ /**
118
+ * Detect changes by comparing current state to cached state
119
+ */
120
+ private detectChanges;
121
+ /**
122
+ * Scan all entities in the OpenSpec directory
123
+ * IMPORTANT: Returns specs FIRST, then issues to ensure proper relationship resolution
124
+ */
125
+ private scanAllEntities;
126
+ /**
127
+ * Compute a hash for an entity to detect changes
128
+ */
129
+ computeEntityHash(entity: ExternalEntity): string;
130
+ /**
131
+ * Convert a parsed OpenSpec spec to ExternalEntity
132
+ */
133
+ private specToExternalEntity;
134
+ /**
135
+ * Convert a proposed spec (from changes/[name]/specs/) to ExternalEntity
136
+ *
137
+ * Proposed specs are NEW specs that don't exist in openspec/specs/ yet.
138
+ * They are marked with isProposed: true in the raw data.
139
+ */
140
+ private proposedSpecToExternalEntity;
141
+ /**
142
+ * Convert a parsed OpenSpec change to ExternalEntity (as issue)
143
+ *
144
+ * Changes map to sudocode Issues:
145
+ * - Archived changes → status: "closed"
146
+ * - Active changes with 100% task completion → status: "needs_review"
147
+ * - Active changes with progress → status: "in_progress"
148
+ * - Active changes with no progress → status: "open"
149
+ */
150
+ private changeToExternalEntity;
151
+ /**
152
+ * Get current cached hashes (for testing/debugging)
153
+ */
154
+ getEntityHashes(): Map<string, string>;
155
+ /**
156
+ * Force refresh of cached state (useful after external sync)
157
+ */
158
+ refreshState(): void;
159
+ }
160
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAgBzE;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,qCAAqC;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,cAAc,CAAgD;IAGtE,OAAO,CAAC,mBAAmB,CAGb;IACd,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAO;IAE9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,OAAO,EAAE,sBAAsB;IAQ3C;;;OAGG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAOtD;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOxC;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI;IAyGrC;;OAEG;IACH,IAAI,IAAI,IAAI;IAcZ;;OAEG;IACH,UAAU,IAAI,OAAO;IAIrB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAgC5B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAgC9B;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAapC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IASlC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;OAEG;IACH,OAAO,CAAC,cAAc;IAiCtB;;OAEG;IACH,YAAY,IAAI,IAAI;IAcpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAuDrB;;;OAGG;IACH,OAAO,CAAC,eAAe;IA2GvB;;OAEG;IACH,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM;IAYjD;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA2B5B;;;;;OAKG;IACH,OAAO,CAAC,4BAA4B;IA8BpC;;;;;;;;OAQG;IACH,OAAO,CAAC,sBAAsB;IAqE9B;;OAEG;IACH,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAItC;;OAEG;IACH,YAAY,IAAI,IAAI;CAGrB"}