@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.
- package/dist/id-generator.d.ts +114 -0
- package/dist/id-generator.d.ts.map +1 -0
- package/dist/id-generator.js +165 -0
- package/dist/id-generator.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +692 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/change-parser.d.ts +164 -0
- package/dist/parser/change-parser.d.ts.map +1 -0
- package/dist/parser/change-parser.js +339 -0
- package/dist/parser/change-parser.js.map +1 -0
- package/dist/parser/markdown-utils.d.ts +138 -0
- package/dist/parser/markdown-utils.d.ts.map +1 -0
- package/dist/parser/markdown-utils.js +283 -0
- package/dist/parser/markdown-utils.js.map +1 -0
- package/dist/parser/spec-parser.d.ts +116 -0
- package/dist/parser/spec-parser.d.ts.map +1 -0
- package/dist/parser/spec-parser.js +204 -0
- package/dist/parser/spec-parser.js.map +1 -0
- package/dist/parser/tasks-parser.d.ts +120 -0
- package/dist/parser/tasks-parser.d.ts.map +1 -0
- package/dist/parser/tasks-parser.js +176 -0
- package/dist/parser/tasks-parser.js.map +1 -0
- package/dist/watcher.d.ts +160 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +614 -0
- package/dist/watcher.js.map +1 -0
- package/dist/writer/index.d.ts +9 -0
- package/dist/writer/index.d.ts.map +1 -0
- package/dist/writer/index.js +9 -0
- package/dist/writer/index.js.map +1 -0
- package/dist/writer/spec-writer.d.ts +24 -0
- package/dist/writer/spec-writer.d.ts.map +1 -0
- package/dist/writer/spec-writer.js +75 -0
- package/dist/writer/spec-writer.js.map +1 -0
- package/dist/writer/tasks-writer.d.ts +33 -0
- package/dist/writer/tasks-writer.d.ts.map +1 -0
- package/dist/writer/tasks-writer.js +144 -0
- package/dist/writer/tasks-writer.js.map +1 -0
- package/package.json +43 -0
package/dist/watcher.js
ADDED
|
@@ -0,0 +1,614 @@
|
|
|
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 chokidar from "chokidar";
|
|
15
|
+
import * as path from "path";
|
|
16
|
+
import { createHash } from "crypto";
|
|
17
|
+
import { existsSync, readFileSync, readdirSync } from "fs";
|
|
18
|
+
import { parseSpecFile } from "./parser/spec-parser.js";
|
|
19
|
+
import { parseChangeDirectory, scanChangeDirectories, isChangeDirectory, } from "./parser/change-parser.js";
|
|
20
|
+
import { generateSpecId, generateChangeId, parseOpenSpecId, DEFAULT_SPEC_PREFIX, DEFAULT_CHANGE_PREFIX, } from "./id-generator.js";
|
|
21
|
+
/**
|
|
22
|
+
* OpenSpecWatcher monitors the OpenSpec directory for changes
|
|
23
|
+
*
|
|
24
|
+
* Uses content hashing to detect actual changes vs just file touches.
|
|
25
|
+
* This prevents false positives from atomic writes and other file operations.
|
|
26
|
+
*/
|
|
27
|
+
export class OpenSpecWatcher {
|
|
28
|
+
watcher = null;
|
|
29
|
+
entityHashes = new Map();
|
|
30
|
+
callback = null;
|
|
31
|
+
isProcessing = false;
|
|
32
|
+
debounceTimer = null;
|
|
33
|
+
isRelevantFile = null;
|
|
34
|
+
// Track pending archive moves to detect status changes vs delete+create
|
|
35
|
+
pendingArchiveMoves = new Map();
|
|
36
|
+
ARCHIVE_MOVE_WINDOW_MS = 500; // Time window to detect archive moves
|
|
37
|
+
openspecPath;
|
|
38
|
+
specPrefix;
|
|
39
|
+
changePrefix;
|
|
40
|
+
trackArchived;
|
|
41
|
+
debounceMs;
|
|
42
|
+
constructor(options) {
|
|
43
|
+
this.openspecPath = options.openspecPath;
|
|
44
|
+
this.specPrefix = options.specPrefix || DEFAULT_SPEC_PREFIX;
|
|
45
|
+
this.changePrefix = options.changePrefix || DEFAULT_CHANGE_PREFIX;
|
|
46
|
+
this.trackArchived = options.trackArchived !== false;
|
|
47
|
+
this.debounceMs = options.debounceMs ?? 100;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Update the cached hash for a specific entity after we wrote to it.
|
|
51
|
+
* This prevents the watcher from detecting our own writes as changes.
|
|
52
|
+
*/
|
|
53
|
+
updateEntityHash(entityId, hash) {
|
|
54
|
+
console.log(`[openspec-watcher] Updated hash for ${entityId} after outbound write`);
|
|
55
|
+
this.entityHashes.set(entityId, hash);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Remove an entity from the hash cache (after deletion)
|
|
59
|
+
*/
|
|
60
|
+
removeEntityHash(entityId) {
|
|
61
|
+
console.log(`[openspec-watcher] Removed hash for ${entityId} after outbound delete`);
|
|
62
|
+
this.entityHashes.delete(entityId);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Start watching for changes
|
|
66
|
+
*
|
|
67
|
+
* @param callback - Function to call when changes are detected
|
|
68
|
+
*/
|
|
69
|
+
start(callback) {
|
|
70
|
+
if (this.watcher) {
|
|
71
|
+
console.warn("[openspec-watcher] Already watching");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.callback = callback;
|
|
75
|
+
// Capture initial state
|
|
76
|
+
this.captureState();
|
|
77
|
+
// Watch paths - use directories for better compatibility with chokidar v4
|
|
78
|
+
const watchPaths = [];
|
|
79
|
+
// Watch specs directory
|
|
80
|
+
const specsDir = path.join(this.openspecPath, "specs");
|
|
81
|
+
if (existsSync(specsDir)) {
|
|
82
|
+
watchPaths.push(specsDir);
|
|
83
|
+
}
|
|
84
|
+
// Watch changes directory
|
|
85
|
+
const changesDir = path.join(this.openspecPath, "changes");
|
|
86
|
+
if (existsSync(changesDir)) {
|
|
87
|
+
watchPaths.push(changesDir);
|
|
88
|
+
}
|
|
89
|
+
if (watchPaths.length === 0) {
|
|
90
|
+
console.warn("[openspec-watcher] No paths to watch");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
console.log(`[openspec-watcher] Watching paths:`, watchPaths);
|
|
94
|
+
// Filter function to only process relevant files
|
|
95
|
+
const isRelevantFile = (filePath) => {
|
|
96
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
97
|
+
// Only watch .md files
|
|
98
|
+
if (ext !== ".md") {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
// Check if it's in specs/ directory
|
|
102
|
+
const relativePath = path.relative(this.openspecPath, filePath);
|
|
103
|
+
if (relativePath.startsWith("specs" + path.sep)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
// Check if it's in changes/ directory
|
|
107
|
+
if (relativePath.startsWith("changes" + path.sep)) {
|
|
108
|
+
const fileName = path.basename(filePath);
|
|
109
|
+
// Watch proposal.md, tasks.md, design.md in change directories
|
|
110
|
+
if (["proposal.md", "tasks.md", "design.md"].includes(fileName)) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
// Watch spec.md files in changes/[name]/specs/[cap]/spec.md (proposed specs)
|
|
114
|
+
if (fileName === "spec.md" && relativePath.includes(path.sep + "specs" + path.sep)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
};
|
|
120
|
+
this.watcher = chokidar.watch(watchPaths, {
|
|
121
|
+
persistent: true,
|
|
122
|
+
ignoreInitial: true,
|
|
123
|
+
awaitWriteFinish: {
|
|
124
|
+
stabilityThreshold: this.debounceMs,
|
|
125
|
+
pollInterval: 50,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
// Store file filter for use in handlers
|
|
129
|
+
this.isRelevantFile = isRelevantFile;
|
|
130
|
+
this.watcher.on("ready", () => {
|
|
131
|
+
const watched = this.watcher?.getWatched() || {};
|
|
132
|
+
const dirs = Object.keys(watched);
|
|
133
|
+
console.log(`[openspec-watcher] Ready, watching ${dirs.length} directories in ${this.openspecPath}`);
|
|
134
|
+
});
|
|
135
|
+
this.watcher.on("change", (filePath) => this.handleFileChange(filePath));
|
|
136
|
+
this.watcher.on("add", (filePath) => this.handleFileChange(filePath));
|
|
137
|
+
this.watcher.on("unlink", (filePath) => this.handleFileDeleted(filePath));
|
|
138
|
+
// Watch for directory events to detect archive moves
|
|
139
|
+
this.watcher.on("addDir", (dirPath) => this.handleDirectoryAdded(dirPath));
|
|
140
|
+
this.watcher.on("unlinkDir", (dirPath) => this.handleDirectoryRemoved(dirPath));
|
|
141
|
+
this.watcher.on("error", (error) => {
|
|
142
|
+
console.error("[openspec-watcher] Error:", error);
|
|
143
|
+
});
|
|
144
|
+
console.log(`[openspec-watcher] Setting up watcher for ${this.openspecPath}...`);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Stop watching for changes
|
|
148
|
+
*/
|
|
149
|
+
stop() {
|
|
150
|
+
if (this.debounceTimer) {
|
|
151
|
+
clearTimeout(this.debounceTimer);
|
|
152
|
+
this.debounceTimer = null;
|
|
153
|
+
}
|
|
154
|
+
if (this.watcher) {
|
|
155
|
+
this.watcher.close();
|
|
156
|
+
this.watcher = null;
|
|
157
|
+
this.callback = null;
|
|
158
|
+
console.log("[openspec-watcher] Stopped");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Check if watcher is active
|
|
163
|
+
*/
|
|
164
|
+
isWatching() {
|
|
165
|
+
return this.watcher !== null;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Handle file change event
|
|
169
|
+
*/
|
|
170
|
+
handleFileChange(filePath) {
|
|
171
|
+
// Filter out non-relevant files
|
|
172
|
+
if (this.isRelevantFile && !this.isRelevantFile(filePath)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
console.log(`[openspec-watcher] File changed: ${filePath}`);
|
|
176
|
+
this.scheduleProcessChanges();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Handle file deleted event
|
|
180
|
+
*/
|
|
181
|
+
handleFileDeleted(filePath) {
|
|
182
|
+
// Filter out non-relevant files
|
|
183
|
+
if (this.isRelevantFile && !this.isRelevantFile(filePath)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
console.log(`[openspec-watcher] File deleted: ${filePath}`);
|
|
187
|
+
this.scheduleProcessChanges();
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Handle directory added event
|
|
191
|
+
* Used to detect archive moves (change moved to archive/)
|
|
192
|
+
*/
|
|
193
|
+
handleDirectoryAdded(dirPath) {
|
|
194
|
+
const relativePath = path.relative(this.openspecPath, dirPath);
|
|
195
|
+
// Check if this is a new directory in changes/archive/
|
|
196
|
+
if (relativePath.startsWith("changes" + path.sep + "archive" + path.sep) &&
|
|
197
|
+
isChangeDirectory(dirPath)) {
|
|
198
|
+
const changeName = this.extractChangeNameFromArchive(dirPath);
|
|
199
|
+
if (changeName) {
|
|
200
|
+
console.log(`[openspec-watcher] Archive directory added: ${dirPath} (change: ${changeName})`);
|
|
201
|
+
// Check if we have a pending removal for this change
|
|
202
|
+
const pendingKey = changeName;
|
|
203
|
+
const pending = this.pendingArchiveMoves.get(pendingKey);
|
|
204
|
+
const now = Date.now();
|
|
205
|
+
if (pending && now - pending.timestamp < this.ARCHIVE_MOVE_WINDOW_MS) {
|
|
206
|
+
// This is an archive move, not a delete+create
|
|
207
|
+
console.log(`[openspec-watcher] Detected archive move for change: ${changeName}`);
|
|
208
|
+
this.pendingArchiveMoves.delete(pendingKey);
|
|
209
|
+
}
|
|
210
|
+
this.scheduleProcessChanges();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Handle directory removed event
|
|
216
|
+
* Used to detect archive moves (change moved from changes/)
|
|
217
|
+
*/
|
|
218
|
+
handleDirectoryRemoved(dirPath) {
|
|
219
|
+
const relativePath = path.relative(this.openspecPath, dirPath);
|
|
220
|
+
// Check if this is a removed directory in changes/ (not archive/)
|
|
221
|
+
if (relativePath.startsWith("changes" + path.sep) &&
|
|
222
|
+
!relativePath.includes(path.sep + "archive" + path.sep)) {
|
|
223
|
+
const changeName = path.basename(dirPath);
|
|
224
|
+
// Don't track removal of the archive directory itself
|
|
225
|
+
if (changeName === "archive") {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
console.log(`[openspec-watcher] Change directory removed: ${dirPath} (change: ${changeName})`);
|
|
229
|
+
// Track as potential archive move
|
|
230
|
+
this.pendingArchiveMoves.set(changeName, {
|
|
231
|
+
changeName,
|
|
232
|
+
timestamp: Date.now(),
|
|
233
|
+
});
|
|
234
|
+
// Clean up old pending moves
|
|
235
|
+
this.cleanupPendingArchiveMoves();
|
|
236
|
+
this.scheduleProcessChanges();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Extract change name from an archive directory path
|
|
241
|
+
* Archive pattern: changes/archive/YYYY-MM-DD-name/ or changes/archive/name/
|
|
242
|
+
*/
|
|
243
|
+
extractChangeNameFromArchive(dirPath) {
|
|
244
|
+
const dirName = path.basename(dirPath);
|
|
245
|
+
// Match YYYY-MM-DD-name pattern
|
|
246
|
+
const dateMatch = dirName.match(/^\d{4}-\d{2}-\d{2}-(.+)$/);
|
|
247
|
+
if (dateMatch) {
|
|
248
|
+
return dateMatch[1];
|
|
249
|
+
}
|
|
250
|
+
// Otherwise, the directory name is the change name
|
|
251
|
+
return dirName;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Clean up old pending archive move entries
|
|
255
|
+
*/
|
|
256
|
+
cleanupPendingArchiveMoves() {
|
|
257
|
+
const now = Date.now();
|
|
258
|
+
for (const [key, value] of this.pendingArchiveMoves) {
|
|
259
|
+
if (now - value.timestamp > this.ARCHIVE_MOVE_WINDOW_MS * 2) {
|
|
260
|
+
this.pendingArchiveMoves.delete(key);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Schedule change processing with debouncing
|
|
266
|
+
*/
|
|
267
|
+
scheduleProcessChanges() {
|
|
268
|
+
if (this.debounceTimer) {
|
|
269
|
+
clearTimeout(this.debounceTimer);
|
|
270
|
+
}
|
|
271
|
+
this.debounceTimer = setTimeout(() => {
|
|
272
|
+
this.debounceTimer = null;
|
|
273
|
+
this.processChanges();
|
|
274
|
+
}, this.debounceMs);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Process changes by comparing current state to cached hashes
|
|
278
|
+
*/
|
|
279
|
+
processChanges() {
|
|
280
|
+
// Prevent concurrent processing
|
|
281
|
+
if (this.isProcessing) {
|
|
282
|
+
console.log("[openspec-watcher] Already processing, scheduling retry");
|
|
283
|
+
this.scheduleProcessChanges();
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
this.isProcessing = true;
|
|
287
|
+
try {
|
|
288
|
+
const changes = this.detectChanges();
|
|
289
|
+
if (changes.length > 0) {
|
|
290
|
+
console.log(`[openspec-watcher] Detected ${changes.length} entity change(s):`, changes.map((c) => `${c.change_type}:${c.entity_id}`).join(", "));
|
|
291
|
+
if (this.callback) {
|
|
292
|
+
this.callback(changes);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
console.log("[openspec-watcher] No actual content changes (hashes match)");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
console.error("[openspec-watcher] Error processing changes:", error);
|
|
301
|
+
}
|
|
302
|
+
finally {
|
|
303
|
+
this.isProcessing = false;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Capture current state (entity hashes) for comparison
|
|
308
|
+
*/
|
|
309
|
+
captureState() {
|
|
310
|
+
console.log("[openspec-watcher] Capturing initial state...");
|
|
311
|
+
const entities = this.scanAllEntities();
|
|
312
|
+
this.entityHashes.clear();
|
|
313
|
+
for (const entity of entities) {
|
|
314
|
+
const hash = this.computeEntityHash(entity);
|
|
315
|
+
this.entityHashes.set(entity.id, hash);
|
|
316
|
+
}
|
|
317
|
+
console.log(`[openspec-watcher] Captured state with ${this.entityHashes.size} entities`);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Detect changes by comparing current state to cached state
|
|
321
|
+
*/
|
|
322
|
+
detectChanges() {
|
|
323
|
+
const currentEntities = this.scanAllEntities();
|
|
324
|
+
const changes = [];
|
|
325
|
+
const now = new Date().toISOString();
|
|
326
|
+
const currentIds = new Set();
|
|
327
|
+
// Check for created and updated entities
|
|
328
|
+
for (const entity of currentEntities) {
|
|
329
|
+
currentIds.add(entity.id);
|
|
330
|
+
const newHash = this.computeEntityHash(entity);
|
|
331
|
+
const cachedHash = this.entityHashes.get(entity.id);
|
|
332
|
+
if (!cachedHash) {
|
|
333
|
+
// New entity
|
|
334
|
+
changes.push({
|
|
335
|
+
entity_id: entity.id,
|
|
336
|
+
entity_type: entity.type,
|
|
337
|
+
change_type: "created",
|
|
338
|
+
timestamp: entity.created_at || now,
|
|
339
|
+
data: entity,
|
|
340
|
+
});
|
|
341
|
+
this.entityHashes.set(entity.id, newHash);
|
|
342
|
+
}
|
|
343
|
+
else if (newHash !== cachedHash) {
|
|
344
|
+
// Updated entity
|
|
345
|
+
changes.push({
|
|
346
|
+
entity_id: entity.id,
|
|
347
|
+
entity_type: entity.type,
|
|
348
|
+
change_type: "updated",
|
|
349
|
+
timestamp: entity.updated_at || now,
|
|
350
|
+
data: entity,
|
|
351
|
+
});
|
|
352
|
+
this.entityHashes.set(entity.id, newHash);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Check for deleted entities
|
|
356
|
+
for (const [id] of this.entityHashes) {
|
|
357
|
+
if (!currentIds.has(id)) {
|
|
358
|
+
// Determine entity type from ID
|
|
359
|
+
const parsed = parseOpenSpecId(id);
|
|
360
|
+
const entityType = parsed?.type === "change" ? "issue" : "spec";
|
|
361
|
+
changes.push({
|
|
362
|
+
entity_id: id,
|
|
363
|
+
entity_type: entityType,
|
|
364
|
+
change_type: "deleted",
|
|
365
|
+
timestamp: now,
|
|
366
|
+
});
|
|
367
|
+
this.entityHashes.delete(id);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return changes;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Scan all entities in the OpenSpec directory
|
|
374
|
+
* IMPORTANT: Returns specs FIRST, then issues to ensure proper relationship resolution
|
|
375
|
+
*/
|
|
376
|
+
scanAllEntities() {
|
|
377
|
+
// IMPORTANT: We collect specs FIRST, then issues
|
|
378
|
+
// This ensures specs exist before issues that reference them are synced
|
|
379
|
+
const specEntities = [];
|
|
380
|
+
const issueEntities = [];
|
|
381
|
+
// Track which specs exist in openspec/specs/ (approved specs)
|
|
382
|
+
const approvedSpecs = new Set();
|
|
383
|
+
// Scan specs directory
|
|
384
|
+
const specsDir = path.join(this.openspecPath, "specs");
|
|
385
|
+
if (existsSync(specsDir)) {
|
|
386
|
+
try {
|
|
387
|
+
const entries = readdirSync(specsDir, { withFileTypes: true });
|
|
388
|
+
for (const entry of entries) {
|
|
389
|
+
if (!entry.isDirectory())
|
|
390
|
+
continue;
|
|
391
|
+
const specPath = path.join(specsDir, entry.name, "spec.md");
|
|
392
|
+
if (!existsSync(specPath))
|
|
393
|
+
continue;
|
|
394
|
+
approvedSpecs.add(entry.name);
|
|
395
|
+
try {
|
|
396
|
+
const spec = parseSpecFile(specPath);
|
|
397
|
+
const specId = generateSpecId(entry.name, this.specPrefix);
|
|
398
|
+
specEntities.push(this.specToExternalEntity(spec, specId));
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
console.error(`[openspec-watcher] Error parsing spec at ${specPath}:`, error);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
console.error("[openspec-watcher] Error scanning specs directory:", error);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
// Scan changes directory
|
|
410
|
+
const changesDir = path.join(this.openspecPath, "changes");
|
|
411
|
+
if (existsSync(changesDir)) {
|
|
412
|
+
try {
|
|
413
|
+
const changePaths = scanChangeDirectories(changesDir, this.trackArchived);
|
|
414
|
+
for (const changePath of changePaths) {
|
|
415
|
+
try {
|
|
416
|
+
const change = parseChangeDirectory(changePath);
|
|
417
|
+
const changeId = generateChangeId(change.name, this.changePrefix);
|
|
418
|
+
issueEntities.push(this.changeToExternalEntity(change, changeId));
|
|
419
|
+
// Scan for proposed specs inside this change
|
|
420
|
+
// These are NEW specs in changes/[name]/specs/[cap]/spec.md
|
|
421
|
+
const changeSpecsDir = path.join(changePath, "specs");
|
|
422
|
+
if (existsSync(changeSpecsDir)) {
|
|
423
|
+
const specDirEntries = readdirSync(changeSpecsDir, { withFileTypes: true });
|
|
424
|
+
for (const specEntry of specDirEntries) {
|
|
425
|
+
if (!specEntry.isDirectory())
|
|
426
|
+
continue;
|
|
427
|
+
const proposedSpecPath = path.join(changeSpecsDir, specEntry.name, "spec.md");
|
|
428
|
+
if (!existsSync(proposedSpecPath))
|
|
429
|
+
continue;
|
|
430
|
+
// Only create a separate spec entity for NEW specs
|
|
431
|
+
// (those not in openspec/specs/)
|
|
432
|
+
const isNewSpec = !approvedSpecs.has(specEntry.name);
|
|
433
|
+
if (isNewSpec) {
|
|
434
|
+
try {
|
|
435
|
+
const proposedSpec = parseSpecFile(proposedSpecPath);
|
|
436
|
+
const proposedSpecId = generateSpecId(specEntry.name, this.specPrefix);
|
|
437
|
+
// Add proposed specs to specEntities so they're synced before issues
|
|
438
|
+
specEntities.push(this.proposedSpecToExternalEntity(proposedSpec, proposedSpecId, change.name));
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
console.error(`[openspec-watcher] Error parsing proposed spec at ${proposedSpecPath}:`, error);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
catch (error) {
|
|
448
|
+
console.error(`[openspec-watcher] Error parsing change at ${changePath}:`, error);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
console.error("[openspec-watcher] Error scanning changes directory:", error);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
// Return specs FIRST, then issues
|
|
457
|
+
// This ensures specs are created before issues that implement them
|
|
458
|
+
return [...specEntities, ...issueEntities];
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Compute a hash for an entity to detect changes
|
|
462
|
+
*/
|
|
463
|
+
computeEntityHash(entity) {
|
|
464
|
+
const canonical = JSON.stringify({
|
|
465
|
+
id: entity.id,
|
|
466
|
+
type: entity.type,
|
|
467
|
+
title: entity.title,
|
|
468
|
+
description: entity.description,
|
|
469
|
+
status: entity.status,
|
|
470
|
+
priority: entity.priority,
|
|
471
|
+
});
|
|
472
|
+
return createHash("sha256").update(canonical).digest("hex");
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Convert a parsed OpenSpec spec to ExternalEntity
|
|
476
|
+
*/
|
|
477
|
+
specToExternalEntity(spec, id) {
|
|
478
|
+
// Read raw file content for description
|
|
479
|
+
let rawContent = spec.rawContent;
|
|
480
|
+
try {
|
|
481
|
+
rawContent = readFileSync(spec.filePath, "utf-8");
|
|
482
|
+
}
|
|
483
|
+
catch {
|
|
484
|
+
// Fall back to parsed content
|
|
485
|
+
}
|
|
486
|
+
return {
|
|
487
|
+
id,
|
|
488
|
+
type: "spec",
|
|
489
|
+
title: spec.title,
|
|
490
|
+
description: rawContent,
|
|
491
|
+
priority: 2, // Default priority
|
|
492
|
+
raw: {
|
|
493
|
+
capability: spec.capability,
|
|
494
|
+
purpose: spec.purpose,
|
|
495
|
+
requirements: spec.requirements,
|
|
496
|
+
filePath: spec.filePath,
|
|
497
|
+
},
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Convert a proposed spec (from changes/[name]/specs/) to ExternalEntity
|
|
502
|
+
*
|
|
503
|
+
* Proposed specs are NEW specs that don't exist in openspec/specs/ yet.
|
|
504
|
+
* They are marked with isProposed: true in the raw data.
|
|
505
|
+
*/
|
|
506
|
+
proposedSpecToExternalEntity(spec, id, changeName) {
|
|
507
|
+
// Read raw file content for description
|
|
508
|
+
let rawContent = spec.rawContent;
|
|
509
|
+
try {
|
|
510
|
+
rawContent = readFileSync(spec.filePath, "utf-8");
|
|
511
|
+
}
|
|
512
|
+
catch {
|
|
513
|
+
// Fall back to parsed content
|
|
514
|
+
}
|
|
515
|
+
return {
|
|
516
|
+
id,
|
|
517
|
+
type: "spec",
|
|
518
|
+
title: spec.title,
|
|
519
|
+
description: rawContent,
|
|
520
|
+
priority: 2,
|
|
521
|
+
raw: {
|
|
522
|
+
capability: spec.capability,
|
|
523
|
+
purpose: spec.purpose,
|
|
524
|
+
requirements: spec.requirements,
|
|
525
|
+
filePath: spec.filePath,
|
|
526
|
+
isProposed: true,
|
|
527
|
+
proposedByChange: changeName,
|
|
528
|
+
},
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Convert a parsed OpenSpec change to ExternalEntity (as issue)
|
|
533
|
+
*
|
|
534
|
+
* Changes map to sudocode Issues:
|
|
535
|
+
* - Archived changes → status: "closed"
|
|
536
|
+
* - Active changes with 100% task completion → status: "needs_review"
|
|
537
|
+
* - Active changes with progress → status: "in_progress"
|
|
538
|
+
* - Active changes with no progress → status: "open"
|
|
539
|
+
*/
|
|
540
|
+
changeToExternalEntity(change, id) {
|
|
541
|
+
// Determine status based on archive and task completion
|
|
542
|
+
let status;
|
|
543
|
+
if (change.isArchived) {
|
|
544
|
+
status = "closed";
|
|
545
|
+
}
|
|
546
|
+
else if (change.taskCompletion === 100) {
|
|
547
|
+
status = "needs_review";
|
|
548
|
+
}
|
|
549
|
+
else if (change.taskCompletion > 0) {
|
|
550
|
+
status = "in_progress";
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
status = "open";
|
|
554
|
+
}
|
|
555
|
+
// Build description from proposal content
|
|
556
|
+
const descriptionParts = [];
|
|
557
|
+
if (change.why) {
|
|
558
|
+
descriptionParts.push(`## Why\n${change.why}`);
|
|
559
|
+
}
|
|
560
|
+
if (change.whatChanges) {
|
|
561
|
+
descriptionParts.push(`## What Changes\n${change.whatChanges}`);
|
|
562
|
+
}
|
|
563
|
+
if (change.impact) {
|
|
564
|
+
descriptionParts.push(`## Impact\n${change.impact}`);
|
|
565
|
+
}
|
|
566
|
+
// Add task summary
|
|
567
|
+
if (change.tasks.length > 0) {
|
|
568
|
+
const taskSummary = `## Tasks\n- ${change.tasks.length} total tasks\n- ${change.taskCompletion}% complete`;
|
|
569
|
+
descriptionParts.push(taskSummary);
|
|
570
|
+
}
|
|
571
|
+
const description = descriptionParts.join("\n\n");
|
|
572
|
+
// Build relationships from affected specs
|
|
573
|
+
const relationships = change.affectedSpecs.map((specCapability) => ({
|
|
574
|
+
targetId: generateSpecId(specCapability, this.specPrefix),
|
|
575
|
+
targetType: "spec",
|
|
576
|
+
relationshipType: "implements",
|
|
577
|
+
}));
|
|
578
|
+
return {
|
|
579
|
+
id,
|
|
580
|
+
type: "issue",
|
|
581
|
+
title: change.title,
|
|
582
|
+
description,
|
|
583
|
+
status,
|
|
584
|
+
priority: change.isArchived ? 4 : 2, // Lower priority for archived
|
|
585
|
+
created_at: change.archivedAt?.toISOString(),
|
|
586
|
+
relationships: relationships.length > 0 ? relationships : undefined,
|
|
587
|
+
raw: {
|
|
588
|
+
name: change.name,
|
|
589
|
+
why: change.why,
|
|
590
|
+
whatChanges: change.whatChanges,
|
|
591
|
+
impact: change.impact,
|
|
592
|
+
tasks: change.tasks,
|
|
593
|
+
taskCompletion: change.taskCompletion,
|
|
594
|
+
affectedSpecs: change.affectedSpecs,
|
|
595
|
+
isArchived: change.isArchived,
|
|
596
|
+
archivedAt: change.archivedAt,
|
|
597
|
+
filePath: change.filePath,
|
|
598
|
+
},
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Get current cached hashes (for testing/debugging)
|
|
603
|
+
*/
|
|
604
|
+
getEntityHashes() {
|
|
605
|
+
return new Map(this.entityHashes);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Force refresh of cached state (useful after external sync)
|
|
609
|
+
*/
|
|
610
|
+
refreshState() {
|
|
611
|
+
this.captureState();
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writer module for OpenSpec Integration
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for writing updates back to OpenSpec files
|
|
5
|
+
* during bidirectional synchronization.
|
|
6
|
+
*/
|
|
7
|
+
export { updateAllTasksCompletion, updateTaskByLine, updateTaskByDescription, } from "./tasks-writer.js";
|
|
8
|
+
export { updateSpecContent, updateSpecTitle } from "./spec-writer.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/writer/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writer module for OpenSpec Integration
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for writing updates back to OpenSpec files
|
|
5
|
+
* during bidirectional synchronization.
|
|
6
|
+
*/
|
|
7
|
+
export { updateAllTasksCompletion, updateTaskByLine, updateTaskByDescription, } from "./tasks-writer.js";
|
|
8
|
+
export { updateSpecContent, updateSpecTitle } from "./spec-writer.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/writer/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
|