@openspecui/core 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1712 -0
- package/dist/index.mjs +2706 -0
- package/package.json +36 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1712 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { EventEmitter } from "events";
|
|
4
|
+
|
|
5
|
+
//#region src/schemas.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* File metadata for a change directory entry.
|
|
9
|
+
*/
|
|
10
|
+
declare const ChangeFileSchema: z.ZodObject<{
|
|
11
|
+
/** Path relative to the change root (e.g., "proposal.md" or "specs/auth/spec.md") */
|
|
12
|
+
path: z.ZodString;
|
|
13
|
+
/** Entry type */
|
|
14
|
+
type: z.ZodEnum<["file", "directory"]>;
|
|
15
|
+
/** Optional file content for text files */
|
|
16
|
+
content: z.ZodOptional<z.ZodString>;
|
|
17
|
+
/** Optional byte size for files */
|
|
18
|
+
size: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
path: string;
|
|
21
|
+
type: "file" | "directory";
|
|
22
|
+
content?: string | undefined;
|
|
23
|
+
size?: number | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
path: string;
|
|
26
|
+
type: "file" | "directory";
|
|
27
|
+
content?: string | undefined;
|
|
28
|
+
size?: number | undefined;
|
|
29
|
+
}>;
|
|
30
|
+
type ChangeFile = z.infer<typeof ChangeFileSchema>;
|
|
31
|
+
/**
|
|
32
|
+
* A requirement within a specification.
|
|
33
|
+
* Requirements should use RFC 2119 keywords (SHALL, MUST, etc.)
|
|
34
|
+
*/
|
|
35
|
+
declare const RequirementSchema: z.ZodObject<{
|
|
36
|
+
/** Unique identifier within the spec (e.g., "req-1") */
|
|
37
|
+
id: z.ZodString;
|
|
38
|
+
/** Requirement text, should contain SHALL/MUST keywords */
|
|
39
|
+
text: z.ZodString;
|
|
40
|
+
/** Test scenarios for this requirement */
|
|
41
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
42
|
+
rawText: z.ZodString;
|
|
43
|
+
}, "strip", z.ZodTypeAny, {
|
|
44
|
+
rawText: string;
|
|
45
|
+
}, {
|
|
46
|
+
rawText: string;
|
|
47
|
+
}>, "many">;
|
|
48
|
+
}, "strip", z.ZodTypeAny, {
|
|
49
|
+
id: string;
|
|
50
|
+
text: string;
|
|
51
|
+
scenarios: {
|
|
52
|
+
rawText: string;
|
|
53
|
+
}[];
|
|
54
|
+
}, {
|
|
55
|
+
id: string;
|
|
56
|
+
text: string;
|
|
57
|
+
scenarios: {
|
|
58
|
+
rawText: string;
|
|
59
|
+
}[];
|
|
60
|
+
}>;
|
|
61
|
+
type Requirement = z.infer<typeof RequirementSchema>;
|
|
62
|
+
/**
|
|
63
|
+
* A specification document.
|
|
64
|
+
* Located at: openspec/specs/{id}/spec.md
|
|
65
|
+
*/
|
|
66
|
+
declare const SpecSchema: z.ZodObject<{
|
|
67
|
+
/** Directory name (e.g., "user-auth") */
|
|
68
|
+
id: z.ZodString;
|
|
69
|
+
/** Human-readable name from # heading */
|
|
70
|
+
name: z.ZodString;
|
|
71
|
+
/** Purpose/overview section content */
|
|
72
|
+
overview: z.ZodString;
|
|
73
|
+
/** List of requirements */
|
|
74
|
+
requirements: z.ZodArray<z.ZodObject<{
|
|
75
|
+
/** Unique identifier within the spec (e.g., "req-1") */
|
|
76
|
+
id: z.ZodString;
|
|
77
|
+
/** Requirement text, should contain SHALL/MUST keywords */
|
|
78
|
+
text: z.ZodString;
|
|
79
|
+
/** Test scenarios for this requirement */
|
|
80
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
81
|
+
rawText: z.ZodString;
|
|
82
|
+
}, "strip", z.ZodTypeAny, {
|
|
83
|
+
rawText: string;
|
|
84
|
+
}, {
|
|
85
|
+
rawText: string;
|
|
86
|
+
}>, "many">;
|
|
87
|
+
}, "strip", z.ZodTypeAny, {
|
|
88
|
+
id: string;
|
|
89
|
+
text: string;
|
|
90
|
+
scenarios: {
|
|
91
|
+
rawText: string;
|
|
92
|
+
}[];
|
|
93
|
+
}, {
|
|
94
|
+
id: string;
|
|
95
|
+
text: string;
|
|
96
|
+
scenarios: {
|
|
97
|
+
rawText: string;
|
|
98
|
+
}[];
|
|
99
|
+
}>, "many">;
|
|
100
|
+
/** Optional metadata */
|
|
101
|
+
metadata: z.ZodOptional<z.ZodObject<{
|
|
102
|
+
version: z.ZodDefault<z.ZodString>;
|
|
103
|
+
format: z.ZodDefault<z.ZodLiteral<"openspec">>;
|
|
104
|
+
sourcePath: z.ZodOptional<z.ZodString>;
|
|
105
|
+
}, "strip", z.ZodTypeAny, {
|
|
106
|
+
version: string;
|
|
107
|
+
format: "openspec";
|
|
108
|
+
sourcePath?: string | undefined;
|
|
109
|
+
}, {
|
|
110
|
+
version?: string | undefined;
|
|
111
|
+
format?: "openspec" | undefined;
|
|
112
|
+
sourcePath?: string | undefined;
|
|
113
|
+
}>>;
|
|
114
|
+
}, "strip", z.ZodTypeAny, {
|
|
115
|
+
id: string;
|
|
116
|
+
name: string;
|
|
117
|
+
overview: string;
|
|
118
|
+
requirements: {
|
|
119
|
+
id: string;
|
|
120
|
+
text: string;
|
|
121
|
+
scenarios: {
|
|
122
|
+
rawText: string;
|
|
123
|
+
}[];
|
|
124
|
+
}[];
|
|
125
|
+
metadata?: {
|
|
126
|
+
version: string;
|
|
127
|
+
format: "openspec";
|
|
128
|
+
sourcePath?: string | undefined;
|
|
129
|
+
} | undefined;
|
|
130
|
+
}, {
|
|
131
|
+
id: string;
|
|
132
|
+
name: string;
|
|
133
|
+
overview: string;
|
|
134
|
+
requirements: {
|
|
135
|
+
id: string;
|
|
136
|
+
text: string;
|
|
137
|
+
scenarios: {
|
|
138
|
+
rawText: string;
|
|
139
|
+
}[];
|
|
140
|
+
}[];
|
|
141
|
+
metadata?: {
|
|
142
|
+
version?: string | undefined;
|
|
143
|
+
format?: "openspec" | undefined;
|
|
144
|
+
sourcePath?: string | undefined;
|
|
145
|
+
} | undefined;
|
|
146
|
+
}>;
|
|
147
|
+
type Spec = z.infer<typeof SpecSchema>;
|
|
148
|
+
/**
|
|
149
|
+
* A delta describes changes to a spec within a change proposal.
|
|
150
|
+
* Deltas track which specs are affected and how.
|
|
151
|
+
*/
|
|
152
|
+
declare const DeltaOperationType: z.ZodEnum<["ADDED", "MODIFIED", "REMOVED", "RENAMED"]>;
|
|
153
|
+
declare const DeltaSchema: z.ZodObject<{
|
|
154
|
+
/** Target spec ID */
|
|
155
|
+
spec: z.ZodString;
|
|
156
|
+
/** Type of change */
|
|
157
|
+
operation: z.ZodEnum<["ADDED", "MODIFIED", "REMOVED", "RENAMED"]>;
|
|
158
|
+
/** Human-readable description */
|
|
159
|
+
description: z.ZodString;
|
|
160
|
+
/** Single requirement change */
|
|
161
|
+
requirement: z.ZodOptional<z.ZodObject<{
|
|
162
|
+
/** Unique identifier within the spec (e.g., "req-1") */
|
|
163
|
+
id: z.ZodString;
|
|
164
|
+
/** Requirement text, should contain SHALL/MUST keywords */
|
|
165
|
+
text: z.ZodString;
|
|
166
|
+
/** Test scenarios for this requirement */
|
|
167
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
168
|
+
rawText: z.ZodString;
|
|
169
|
+
}, "strip", z.ZodTypeAny, {
|
|
170
|
+
rawText: string;
|
|
171
|
+
}, {
|
|
172
|
+
rawText: string;
|
|
173
|
+
}>, "many">;
|
|
174
|
+
}, "strip", z.ZodTypeAny, {
|
|
175
|
+
id: string;
|
|
176
|
+
text: string;
|
|
177
|
+
scenarios: {
|
|
178
|
+
rawText: string;
|
|
179
|
+
}[];
|
|
180
|
+
}, {
|
|
181
|
+
id: string;
|
|
182
|
+
text: string;
|
|
183
|
+
scenarios: {
|
|
184
|
+
rawText: string;
|
|
185
|
+
}[];
|
|
186
|
+
}>>;
|
|
187
|
+
/** Multiple requirement changes */
|
|
188
|
+
requirements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
189
|
+
/** Unique identifier within the spec (e.g., "req-1") */
|
|
190
|
+
id: z.ZodString;
|
|
191
|
+
/** Requirement text, should contain SHALL/MUST keywords */
|
|
192
|
+
text: z.ZodString;
|
|
193
|
+
/** Test scenarios for this requirement */
|
|
194
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
195
|
+
rawText: z.ZodString;
|
|
196
|
+
}, "strip", z.ZodTypeAny, {
|
|
197
|
+
rawText: string;
|
|
198
|
+
}, {
|
|
199
|
+
rawText: string;
|
|
200
|
+
}>, "many">;
|
|
201
|
+
}, "strip", z.ZodTypeAny, {
|
|
202
|
+
id: string;
|
|
203
|
+
text: string;
|
|
204
|
+
scenarios: {
|
|
205
|
+
rawText: string;
|
|
206
|
+
}[];
|
|
207
|
+
}, {
|
|
208
|
+
id: string;
|
|
209
|
+
text: string;
|
|
210
|
+
scenarios: {
|
|
211
|
+
rawText: string;
|
|
212
|
+
}[];
|
|
213
|
+
}>, "many">>;
|
|
214
|
+
/** Rename details (for RENAMED operation) */
|
|
215
|
+
rename: z.ZodOptional<z.ZodObject<{
|
|
216
|
+
from: z.ZodString;
|
|
217
|
+
to: z.ZodString;
|
|
218
|
+
}, "strip", z.ZodTypeAny, {
|
|
219
|
+
from: string;
|
|
220
|
+
to: string;
|
|
221
|
+
}, {
|
|
222
|
+
from: string;
|
|
223
|
+
to: string;
|
|
224
|
+
}>>;
|
|
225
|
+
}, "strip", z.ZodTypeAny, {
|
|
226
|
+
spec: string;
|
|
227
|
+
operation: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED";
|
|
228
|
+
description: string;
|
|
229
|
+
requirements?: {
|
|
230
|
+
id: string;
|
|
231
|
+
text: string;
|
|
232
|
+
scenarios: {
|
|
233
|
+
rawText: string;
|
|
234
|
+
}[];
|
|
235
|
+
}[] | undefined;
|
|
236
|
+
requirement?: {
|
|
237
|
+
id: string;
|
|
238
|
+
text: string;
|
|
239
|
+
scenarios: {
|
|
240
|
+
rawText: string;
|
|
241
|
+
}[];
|
|
242
|
+
} | undefined;
|
|
243
|
+
rename?: {
|
|
244
|
+
from: string;
|
|
245
|
+
to: string;
|
|
246
|
+
} | undefined;
|
|
247
|
+
}, {
|
|
248
|
+
spec: string;
|
|
249
|
+
operation: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED";
|
|
250
|
+
description: string;
|
|
251
|
+
requirements?: {
|
|
252
|
+
id: string;
|
|
253
|
+
text: string;
|
|
254
|
+
scenarios: {
|
|
255
|
+
rawText: string;
|
|
256
|
+
}[];
|
|
257
|
+
}[] | undefined;
|
|
258
|
+
requirement?: {
|
|
259
|
+
id: string;
|
|
260
|
+
text: string;
|
|
261
|
+
scenarios: {
|
|
262
|
+
rawText: string;
|
|
263
|
+
}[];
|
|
264
|
+
} | undefined;
|
|
265
|
+
rename?: {
|
|
266
|
+
from: string;
|
|
267
|
+
to: string;
|
|
268
|
+
} | undefined;
|
|
269
|
+
}>;
|
|
270
|
+
type Delta = z.infer<typeof DeltaSchema>;
|
|
271
|
+
type DeltaOperation = z.infer<typeof DeltaOperationType>;
|
|
272
|
+
/**
|
|
273
|
+
* A task within a change proposal.
|
|
274
|
+
* Tasks are parsed from tasks.md using checkbox syntax: - [ ] or - [x]
|
|
275
|
+
*/
|
|
276
|
+
declare const TaskSchema: z.ZodObject<{
|
|
277
|
+
/** Unique identifier (e.g., "task-1") */
|
|
278
|
+
id: z.ZodString;
|
|
279
|
+
/** Task description text */
|
|
280
|
+
text: z.ZodString;
|
|
281
|
+
/** Whether the task is completed */
|
|
282
|
+
completed: z.ZodBoolean;
|
|
283
|
+
/** Optional section heading the task belongs to */
|
|
284
|
+
section: z.ZodOptional<z.ZodString>;
|
|
285
|
+
}, "strip", z.ZodTypeAny, {
|
|
286
|
+
id: string;
|
|
287
|
+
text: string;
|
|
288
|
+
completed: boolean;
|
|
289
|
+
section?: string | undefined;
|
|
290
|
+
}, {
|
|
291
|
+
id: string;
|
|
292
|
+
text: string;
|
|
293
|
+
completed: boolean;
|
|
294
|
+
section?: string | undefined;
|
|
295
|
+
}>;
|
|
296
|
+
type Task = z.infer<typeof TaskSchema>;
|
|
297
|
+
/**
|
|
298
|
+
* A delta spec file from changes/{id}/specs/{specId}/spec.md
|
|
299
|
+
* Contains the proposed changes to a spec
|
|
300
|
+
*/
|
|
301
|
+
declare const DeltaSpecSchema: z.ZodObject<{
|
|
302
|
+
/** Spec ID (directory name under changes/{id}/specs/) */
|
|
303
|
+
specId: z.ZodString;
|
|
304
|
+
/** Raw markdown content of the delta spec */
|
|
305
|
+
content: z.ZodString;
|
|
306
|
+
}, "strip", z.ZodTypeAny, {
|
|
307
|
+
specId: string;
|
|
308
|
+
content: string;
|
|
309
|
+
}, {
|
|
310
|
+
specId: string;
|
|
311
|
+
content: string;
|
|
312
|
+
}>;
|
|
313
|
+
type DeltaSpec = z.infer<typeof DeltaSpecSchema>;
|
|
314
|
+
/**
|
|
315
|
+
* A change proposal document.
|
|
316
|
+
* Located at: openspec/changes/{id}/proposal.md + tasks.md
|
|
317
|
+
*
|
|
318
|
+
* Change proposals describe why a change is needed, what will change,
|
|
319
|
+
* which specs are affected (deltas), and trackable tasks.
|
|
320
|
+
*/
|
|
321
|
+
declare const ChangeSchema: z.ZodObject<{
|
|
322
|
+
/** Directory name (e.g., "add-oauth") */
|
|
323
|
+
id: z.ZodString;
|
|
324
|
+
/** Human-readable name from # heading */
|
|
325
|
+
name: z.ZodString;
|
|
326
|
+
/** Why section - motivation for the change */
|
|
327
|
+
why: z.ZodString;
|
|
328
|
+
/** What Changes section - description of changes */
|
|
329
|
+
whatChanges: z.ZodString;
|
|
330
|
+
/** Affected specs and their changes */
|
|
331
|
+
deltas: z.ZodArray<z.ZodObject<{
|
|
332
|
+
/** Target spec ID */
|
|
333
|
+
spec: z.ZodString;
|
|
334
|
+
/** Type of change */
|
|
335
|
+
operation: z.ZodEnum<["ADDED", "MODIFIED", "REMOVED", "RENAMED"]>;
|
|
336
|
+
/** Human-readable description */
|
|
337
|
+
description: z.ZodString;
|
|
338
|
+
/** Single requirement change */
|
|
339
|
+
requirement: z.ZodOptional<z.ZodObject<{
|
|
340
|
+
/** Unique identifier within the spec (e.g., "req-1") */
|
|
341
|
+
id: z.ZodString;
|
|
342
|
+
/** Requirement text, should contain SHALL/MUST keywords */
|
|
343
|
+
text: z.ZodString;
|
|
344
|
+
/** Test scenarios for this requirement */
|
|
345
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
346
|
+
rawText: z.ZodString;
|
|
347
|
+
}, "strip", z.ZodTypeAny, {
|
|
348
|
+
rawText: string;
|
|
349
|
+
}, {
|
|
350
|
+
rawText: string;
|
|
351
|
+
}>, "many">;
|
|
352
|
+
}, "strip", z.ZodTypeAny, {
|
|
353
|
+
id: string;
|
|
354
|
+
text: string;
|
|
355
|
+
scenarios: {
|
|
356
|
+
rawText: string;
|
|
357
|
+
}[];
|
|
358
|
+
}, {
|
|
359
|
+
id: string;
|
|
360
|
+
text: string;
|
|
361
|
+
scenarios: {
|
|
362
|
+
rawText: string;
|
|
363
|
+
}[];
|
|
364
|
+
}>>;
|
|
365
|
+
/** Multiple requirement changes */
|
|
366
|
+
requirements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
367
|
+
/** Unique identifier within the spec (e.g., "req-1") */
|
|
368
|
+
id: z.ZodString;
|
|
369
|
+
/** Requirement text, should contain SHALL/MUST keywords */
|
|
370
|
+
text: z.ZodString;
|
|
371
|
+
/** Test scenarios for this requirement */
|
|
372
|
+
scenarios: z.ZodArray<z.ZodObject<{
|
|
373
|
+
rawText: z.ZodString;
|
|
374
|
+
}, "strip", z.ZodTypeAny, {
|
|
375
|
+
rawText: string;
|
|
376
|
+
}, {
|
|
377
|
+
rawText: string;
|
|
378
|
+
}>, "many">;
|
|
379
|
+
}, "strip", z.ZodTypeAny, {
|
|
380
|
+
id: string;
|
|
381
|
+
text: string;
|
|
382
|
+
scenarios: {
|
|
383
|
+
rawText: string;
|
|
384
|
+
}[];
|
|
385
|
+
}, {
|
|
386
|
+
id: string;
|
|
387
|
+
text: string;
|
|
388
|
+
scenarios: {
|
|
389
|
+
rawText: string;
|
|
390
|
+
}[];
|
|
391
|
+
}>, "many">>;
|
|
392
|
+
/** Rename details (for RENAMED operation) */
|
|
393
|
+
rename: z.ZodOptional<z.ZodObject<{
|
|
394
|
+
from: z.ZodString;
|
|
395
|
+
to: z.ZodString;
|
|
396
|
+
}, "strip", z.ZodTypeAny, {
|
|
397
|
+
from: string;
|
|
398
|
+
to: string;
|
|
399
|
+
}, {
|
|
400
|
+
from: string;
|
|
401
|
+
to: string;
|
|
402
|
+
}>>;
|
|
403
|
+
}, "strip", z.ZodTypeAny, {
|
|
404
|
+
spec: string;
|
|
405
|
+
operation: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED";
|
|
406
|
+
description: string;
|
|
407
|
+
requirements?: {
|
|
408
|
+
id: string;
|
|
409
|
+
text: string;
|
|
410
|
+
scenarios: {
|
|
411
|
+
rawText: string;
|
|
412
|
+
}[];
|
|
413
|
+
}[] | undefined;
|
|
414
|
+
requirement?: {
|
|
415
|
+
id: string;
|
|
416
|
+
text: string;
|
|
417
|
+
scenarios: {
|
|
418
|
+
rawText: string;
|
|
419
|
+
}[];
|
|
420
|
+
} | undefined;
|
|
421
|
+
rename?: {
|
|
422
|
+
from: string;
|
|
423
|
+
to: string;
|
|
424
|
+
} | undefined;
|
|
425
|
+
}, {
|
|
426
|
+
spec: string;
|
|
427
|
+
operation: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED";
|
|
428
|
+
description: string;
|
|
429
|
+
requirements?: {
|
|
430
|
+
id: string;
|
|
431
|
+
text: string;
|
|
432
|
+
scenarios: {
|
|
433
|
+
rawText: string;
|
|
434
|
+
}[];
|
|
435
|
+
}[] | undefined;
|
|
436
|
+
requirement?: {
|
|
437
|
+
id: string;
|
|
438
|
+
text: string;
|
|
439
|
+
scenarios: {
|
|
440
|
+
rawText: string;
|
|
441
|
+
}[];
|
|
442
|
+
} | undefined;
|
|
443
|
+
rename?: {
|
|
444
|
+
from: string;
|
|
445
|
+
to: string;
|
|
446
|
+
} | undefined;
|
|
447
|
+
}>, "many">;
|
|
448
|
+
/** Trackable tasks from tasks.md */
|
|
449
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
450
|
+
/** Unique identifier (e.g., "task-1") */
|
|
451
|
+
id: z.ZodString;
|
|
452
|
+
/** Task description text */
|
|
453
|
+
text: z.ZodString;
|
|
454
|
+
/** Whether the task is completed */
|
|
455
|
+
completed: z.ZodBoolean;
|
|
456
|
+
/** Optional section heading the task belongs to */
|
|
457
|
+
section: z.ZodOptional<z.ZodString>;
|
|
458
|
+
}, "strip", z.ZodTypeAny, {
|
|
459
|
+
id: string;
|
|
460
|
+
text: string;
|
|
461
|
+
completed: boolean;
|
|
462
|
+
section?: string | undefined;
|
|
463
|
+
}, {
|
|
464
|
+
id: string;
|
|
465
|
+
text: string;
|
|
466
|
+
completed: boolean;
|
|
467
|
+
section?: string | undefined;
|
|
468
|
+
}>, "many">;
|
|
469
|
+
/** Task completion progress */
|
|
470
|
+
progress: z.ZodObject<{
|
|
471
|
+
total: z.ZodNumber;
|
|
472
|
+
completed: z.ZodNumber;
|
|
473
|
+
}, "strip", z.ZodTypeAny, {
|
|
474
|
+
completed: number;
|
|
475
|
+
total: number;
|
|
476
|
+
}, {
|
|
477
|
+
completed: number;
|
|
478
|
+
total: number;
|
|
479
|
+
}>;
|
|
480
|
+
/** Optional design.md content */
|
|
481
|
+
design: z.ZodOptional<z.ZodString>;
|
|
482
|
+
/** Delta specs from changes/{id}/specs/ directory */
|
|
483
|
+
deltaSpecs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
484
|
+
/** Spec ID (directory name under changes/{id}/specs/) */
|
|
485
|
+
specId: z.ZodString;
|
|
486
|
+
/** Raw markdown content of the delta spec */
|
|
487
|
+
content: z.ZodString;
|
|
488
|
+
}, "strip", z.ZodTypeAny, {
|
|
489
|
+
specId: string;
|
|
490
|
+
content: string;
|
|
491
|
+
}, {
|
|
492
|
+
specId: string;
|
|
493
|
+
content: string;
|
|
494
|
+
}>, "many">>;
|
|
495
|
+
/** Optional metadata */
|
|
496
|
+
metadata: z.ZodOptional<z.ZodObject<{
|
|
497
|
+
version: z.ZodDefault<z.ZodString>;
|
|
498
|
+
format: z.ZodDefault<z.ZodLiteral<"openspec-change">>;
|
|
499
|
+
}, "strip", z.ZodTypeAny, {
|
|
500
|
+
version: string;
|
|
501
|
+
format: "openspec-change";
|
|
502
|
+
}, {
|
|
503
|
+
version?: string | undefined;
|
|
504
|
+
format?: "openspec-change" | undefined;
|
|
505
|
+
}>>;
|
|
506
|
+
}, "strip", z.ZodTypeAny, {
|
|
507
|
+
id: string;
|
|
508
|
+
name: string;
|
|
509
|
+
why: string;
|
|
510
|
+
whatChanges: string;
|
|
511
|
+
deltas: {
|
|
512
|
+
spec: string;
|
|
513
|
+
operation: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED";
|
|
514
|
+
description: string;
|
|
515
|
+
requirements?: {
|
|
516
|
+
id: string;
|
|
517
|
+
text: string;
|
|
518
|
+
scenarios: {
|
|
519
|
+
rawText: string;
|
|
520
|
+
}[];
|
|
521
|
+
}[] | undefined;
|
|
522
|
+
requirement?: {
|
|
523
|
+
id: string;
|
|
524
|
+
text: string;
|
|
525
|
+
scenarios: {
|
|
526
|
+
rawText: string;
|
|
527
|
+
}[];
|
|
528
|
+
} | undefined;
|
|
529
|
+
rename?: {
|
|
530
|
+
from: string;
|
|
531
|
+
to: string;
|
|
532
|
+
} | undefined;
|
|
533
|
+
}[];
|
|
534
|
+
tasks: {
|
|
535
|
+
id: string;
|
|
536
|
+
text: string;
|
|
537
|
+
completed: boolean;
|
|
538
|
+
section?: string | undefined;
|
|
539
|
+
}[];
|
|
540
|
+
progress: {
|
|
541
|
+
completed: number;
|
|
542
|
+
total: number;
|
|
543
|
+
};
|
|
544
|
+
metadata?: {
|
|
545
|
+
version: string;
|
|
546
|
+
format: "openspec-change";
|
|
547
|
+
} | undefined;
|
|
548
|
+
design?: string | undefined;
|
|
549
|
+
deltaSpecs?: {
|
|
550
|
+
specId: string;
|
|
551
|
+
content: string;
|
|
552
|
+
}[] | undefined;
|
|
553
|
+
}, {
|
|
554
|
+
id: string;
|
|
555
|
+
name: string;
|
|
556
|
+
why: string;
|
|
557
|
+
whatChanges: string;
|
|
558
|
+
deltas: {
|
|
559
|
+
spec: string;
|
|
560
|
+
operation: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED";
|
|
561
|
+
description: string;
|
|
562
|
+
requirements?: {
|
|
563
|
+
id: string;
|
|
564
|
+
text: string;
|
|
565
|
+
scenarios: {
|
|
566
|
+
rawText: string;
|
|
567
|
+
}[];
|
|
568
|
+
}[] | undefined;
|
|
569
|
+
requirement?: {
|
|
570
|
+
id: string;
|
|
571
|
+
text: string;
|
|
572
|
+
scenarios: {
|
|
573
|
+
rawText: string;
|
|
574
|
+
}[];
|
|
575
|
+
} | undefined;
|
|
576
|
+
rename?: {
|
|
577
|
+
from: string;
|
|
578
|
+
to: string;
|
|
579
|
+
} | undefined;
|
|
580
|
+
}[];
|
|
581
|
+
tasks: {
|
|
582
|
+
id: string;
|
|
583
|
+
text: string;
|
|
584
|
+
completed: boolean;
|
|
585
|
+
section?: string | undefined;
|
|
586
|
+
}[];
|
|
587
|
+
progress: {
|
|
588
|
+
completed: number;
|
|
589
|
+
total: number;
|
|
590
|
+
};
|
|
591
|
+
metadata?: {
|
|
592
|
+
version?: string | undefined;
|
|
593
|
+
format?: "openspec-change" | undefined;
|
|
594
|
+
} | undefined;
|
|
595
|
+
design?: string | undefined;
|
|
596
|
+
deltaSpecs?: {
|
|
597
|
+
specId: string;
|
|
598
|
+
content: string;
|
|
599
|
+
}[] | undefined;
|
|
600
|
+
}>;
|
|
601
|
+
type Change = z.infer<typeof ChangeSchema>;
|
|
602
|
+
//#endregion
|
|
603
|
+
//#region src/validator.d.ts
|
|
604
|
+
interface ValidationIssue {
|
|
605
|
+
severity: 'ERROR' | 'WARNING' | 'INFO';
|
|
606
|
+
message: string;
|
|
607
|
+
path?: string;
|
|
608
|
+
line?: number;
|
|
609
|
+
}
|
|
610
|
+
interface ValidationResult {
|
|
611
|
+
valid: boolean;
|
|
612
|
+
issues: ValidationIssue[];
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Validator for OpenSpec documents
|
|
616
|
+
*/
|
|
617
|
+
declare class Validator {
|
|
618
|
+
/**
|
|
619
|
+
* Validate a spec document
|
|
620
|
+
*/
|
|
621
|
+
validateSpec(spec: Spec): ValidationResult;
|
|
622
|
+
/**
|
|
623
|
+
* Validate a change proposal
|
|
624
|
+
*/
|
|
625
|
+
validateChange(change: Change): ValidationResult;
|
|
626
|
+
}
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region src/adapter.d.ts
|
|
629
|
+
/** Spec metadata with time info */
|
|
630
|
+
interface SpecMeta {
|
|
631
|
+
id: string;
|
|
632
|
+
name: string;
|
|
633
|
+
createdAt: number;
|
|
634
|
+
updatedAt: number;
|
|
635
|
+
}
|
|
636
|
+
/** Change metadata with time info */
|
|
637
|
+
interface ChangeMeta {
|
|
638
|
+
id: string;
|
|
639
|
+
name: string;
|
|
640
|
+
progress: {
|
|
641
|
+
total: number;
|
|
642
|
+
completed: number;
|
|
643
|
+
};
|
|
644
|
+
createdAt: number;
|
|
645
|
+
updatedAt: number;
|
|
646
|
+
}
|
|
647
|
+
/** Archived change metadata with time info */
|
|
648
|
+
interface ArchiveMeta {
|
|
649
|
+
id: string;
|
|
650
|
+
name: string;
|
|
651
|
+
createdAt: number;
|
|
652
|
+
updatedAt: number;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* OpenSpec filesystem adapter
|
|
656
|
+
* Handles reading, writing, and managing OpenSpec files
|
|
657
|
+
*/
|
|
658
|
+
declare class OpenSpecAdapter {
|
|
659
|
+
private projectDir;
|
|
660
|
+
private parser;
|
|
661
|
+
private validator;
|
|
662
|
+
constructor(projectDir: string);
|
|
663
|
+
private get openspecDir();
|
|
664
|
+
private get specsDir();
|
|
665
|
+
private get changesDir();
|
|
666
|
+
private get archiveDir();
|
|
667
|
+
isInitialized(): Promise<boolean>;
|
|
668
|
+
/** File time info derived from filesystem (reactive) */
|
|
669
|
+
private getFileTimeInfo;
|
|
670
|
+
listSpecs(): Promise<string[]>;
|
|
671
|
+
/**
|
|
672
|
+
* List specs with metadata (id, name, and time info)
|
|
673
|
+
* Only returns specs that have valid spec.md
|
|
674
|
+
* Sorted by updatedAt descending (most recent first)
|
|
675
|
+
*/
|
|
676
|
+
listSpecsWithMeta(): Promise<SpecMeta[]>;
|
|
677
|
+
listChanges(): Promise<string[]>;
|
|
678
|
+
/**
|
|
679
|
+
* List changes with metadata (id, name, progress, and time info)
|
|
680
|
+
* Only returns changes that have valid proposal.md
|
|
681
|
+
* Sorted by updatedAt descending (most recent first)
|
|
682
|
+
*/
|
|
683
|
+
listChangesWithMeta(): Promise<ChangeMeta[]>;
|
|
684
|
+
listArchivedChanges(): Promise<string[]>;
|
|
685
|
+
/**
|
|
686
|
+
* List archived changes with metadata and time info
|
|
687
|
+
* Only returns archives that have valid proposal.md
|
|
688
|
+
* Sorted by updatedAt descending (most recent first)
|
|
689
|
+
*/
|
|
690
|
+
listArchivedChangesWithMeta(): Promise<ArchiveMeta[]>;
|
|
691
|
+
/**
|
|
692
|
+
* Read project.md content (reactive)
|
|
693
|
+
*/
|
|
694
|
+
readProjectMd(): Promise<string | null>;
|
|
695
|
+
/**
|
|
696
|
+
* Read AGENTS.md content (reactive)
|
|
697
|
+
*/
|
|
698
|
+
readAgentsMd(): Promise<string | null>;
|
|
699
|
+
/**
|
|
700
|
+
* Write project.md content
|
|
701
|
+
*/
|
|
702
|
+
writeProjectMd(content: string): Promise<void>;
|
|
703
|
+
/**
|
|
704
|
+
* Write AGENTS.md content
|
|
705
|
+
*/
|
|
706
|
+
writeAgentsMd(content: string): Promise<void>;
|
|
707
|
+
readSpec(specId: string): Promise<Spec | null>;
|
|
708
|
+
readSpecRaw(specId: string): Promise<string | null>;
|
|
709
|
+
readChange(changeId: string): Promise<Change | null>;
|
|
710
|
+
readChangeFiles(changeId: string): Promise<ChangeFile[]>;
|
|
711
|
+
readArchivedChangeFiles(changeId: string): Promise<ChangeFile[]>;
|
|
712
|
+
private readFilesUnderRoot;
|
|
713
|
+
private collectChangeFiles;
|
|
714
|
+
readChangeRaw(changeId: string): Promise<{
|
|
715
|
+
proposal: string;
|
|
716
|
+
tasks: string;
|
|
717
|
+
design?: string;
|
|
718
|
+
deltaSpecs: DeltaSpec[];
|
|
719
|
+
} | null>;
|
|
720
|
+
/** Read delta specs from a specs directory */
|
|
721
|
+
private readDeltaSpecs;
|
|
722
|
+
/**
|
|
723
|
+
* Read an archived change
|
|
724
|
+
*/
|
|
725
|
+
readArchivedChange(changeId: string): Promise<Change | null>;
|
|
726
|
+
/**
|
|
727
|
+
* Read raw archived change files (reactive)
|
|
728
|
+
*/
|
|
729
|
+
readArchivedChangeRaw(changeId: string): Promise<{
|
|
730
|
+
proposal: string;
|
|
731
|
+
tasks: string;
|
|
732
|
+
design?: string;
|
|
733
|
+
deltaSpecs: DeltaSpec[];
|
|
734
|
+
} | null>;
|
|
735
|
+
writeSpec(specId: string, content: string): Promise<void>;
|
|
736
|
+
writeChange(changeId: string, proposal: string, tasks?: string): Promise<void>;
|
|
737
|
+
archiveChange(changeId: string): Promise<boolean>;
|
|
738
|
+
init(): Promise<void>;
|
|
739
|
+
/**
|
|
740
|
+
* Toggle a task's completion status in tasks.md
|
|
741
|
+
* @param changeId - The change ID
|
|
742
|
+
* @param taskIndex - 1-based task index
|
|
743
|
+
* @param completed - New completion status
|
|
744
|
+
*/
|
|
745
|
+
toggleTask(changeId: string, taskIndex: number, completed: boolean): Promise<boolean>;
|
|
746
|
+
validateSpec(specId: string): Promise<ValidationResult>;
|
|
747
|
+
validateChange(changeId: string): Promise<ValidationResult>;
|
|
748
|
+
getDashboardData(): Promise<{
|
|
749
|
+
specs: {
|
|
750
|
+
id: string;
|
|
751
|
+
name: string;
|
|
752
|
+
overview: string;
|
|
753
|
+
requirements: {
|
|
754
|
+
id: string;
|
|
755
|
+
text: string;
|
|
756
|
+
scenarios: {
|
|
757
|
+
rawText: string;
|
|
758
|
+
}[];
|
|
759
|
+
}[];
|
|
760
|
+
metadata?: {
|
|
761
|
+
version: string;
|
|
762
|
+
format: "openspec";
|
|
763
|
+
sourcePath?: string | undefined;
|
|
764
|
+
} | undefined;
|
|
765
|
+
}[];
|
|
766
|
+
changes: {
|
|
767
|
+
id: string;
|
|
768
|
+
name: string;
|
|
769
|
+
why: string;
|
|
770
|
+
whatChanges: string;
|
|
771
|
+
deltas: {
|
|
772
|
+
spec: string;
|
|
773
|
+
operation: "ADDED" | "MODIFIED" | "REMOVED" | "RENAMED";
|
|
774
|
+
description: string;
|
|
775
|
+
requirements?: {
|
|
776
|
+
id: string;
|
|
777
|
+
text: string;
|
|
778
|
+
scenarios: {
|
|
779
|
+
rawText: string;
|
|
780
|
+
}[];
|
|
781
|
+
}[] | undefined;
|
|
782
|
+
requirement?: {
|
|
783
|
+
id: string;
|
|
784
|
+
text: string;
|
|
785
|
+
scenarios: {
|
|
786
|
+
rawText: string;
|
|
787
|
+
}[];
|
|
788
|
+
} | undefined;
|
|
789
|
+
rename?: {
|
|
790
|
+
from: string;
|
|
791
|
+
to: string;
|
|
792
|
+
} | undefined;
|
|
793
|
+
}[];
|
|
794
|
+
tasks: {
|
|
795
|
+
id: string;
|
|
796
|
+
text: string;
|
|
797
|
+
completed: boolean;
|
|
798
|
+
section?: string | undefined;
|
|
799
|
+
}[];
|
|
800
|
+
progress: {
|
|
801
|
+
completed: number;
|
|
802
|
+
total: number;
|
|
803
|
+
};
|
|
804
|
+
metadata?: {
|
|
805
|
+
version: string;
|
|
806
|
+
format: "openspec-change";
|
|
807
|
+
} | undefined;
|
|
808
|
+
design?: string | undefined;
|
|
809
|
+
deltaSpecs?: {
|
|
810
|
+
specId: string;
|
|
811
|
+
content: string;
|
|
812
|
+
}[] | undefined;
|
|
813
|
+
}[];
|
|
814
|
+
archivedCount: number;
|
|
815
|
+
summary: {
|
|
816
|
+
specCount: number;
|
|
817
|
+
requirementCount: number;
|
|
818
|
+
activeChangeCount: number;
|
|
819
|
+
archivedChangeCount: number;
|
|
820
|
+
totalTasks: number;
|
|
821
|
+
completedTasks: number;
|
|
822
|
+
progressPercent: number;
|
|
823
|
+
};
|
|
824
|
+
}>;
|
|
825
|
+
}
|
|
826
|
+
//#endregion
|
|
827
|
+
//#region src/parser.d.ts
|
|
828
|
+
/**
|
|
829
|
+
* Markdown parser for OpenSpec documents
|
|
830
|
+
*/
|
|
831
|
+
declare class MarkdownParser {
|
|
832
|
+
/**
|
|
833
|
+
* Parse a spec markdown content into a Spec object
|
|
834
|
+
*/
|
|
835
|
+
parseSpec(specId: string, content: string): Spec;
|
|
836
|
+
/**
|
|
837
|
+
* Parse a change proposal markdown content into a Change object
|
|
838
|
+
*/
|
|
839
|
+
parseChange(changeId: string, proposalContent: string, tasksContent?: string, options?: {
|
|
840
|
+
design?: string;
|
|
841
|
+
deltaSpecs?: DeltaSpec[];
|
|
842
|
+
}): Change;
|
|
843
|
+
private parseDeltasFromWhatChanges;
|
|
844
|
+
private parseDeltasFromDeltaSpecs;
|
|
845
|
+
private parseDeltaSpecContent;
|
|
846
|
+
/**
|
|
847
|
+
* Parse tasks from a tasks.md content
|
|
848
|
+
*/
|
|
849
|
+
parseTasks(content: string): Task[];
|
|
850
|
+
/**
|
|
851
|
+
* Serialize a spec back to markdown
|
|
852
|
+
*/
|
|
853
|
+
serializeSpec(spec: Spec): string;
|
|
854
|
+
}
|
|
855
|
+
//#endregion
|
|
856
|
+
//#region src/reactive-fs/reactive-state.d.ts
|
|
857
|
+
interface IReactiveContext {
|
|
858
|
+
track(state: ReactiveState<unknown>): void;
|
|
859
|
+
notifyChange(): void;
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* 全局的 AsyncLocalStorage,用于在异步调用链中传递 ReactiveContext
|
|
863
|
+
* 这是实现依赖收集的核心机制
|
|
864
|
+
*/
|
|
865
|
+
declare const contextStorage: AsyncLocalStorage<IReactiveContext>;
|
|
866
|
+
/** ReactiveState 配置选项 */
|
|
867
|
+
interface ReactiveStateOptions<T> {
|
|
868
|
+
/** 自定义相等性比较函数 */
|
|
869
|
+
equals?: (a: T, b: T) => boolean;
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* 响应式状态类,类似 Signal.State
|
|
873
|
+
*
|
|
874
|
+
* 核心机制:
|
|
875
|
+
* - get() 时自动注册到当前 ReactiveContext 的依赖列表
|
|
876
|
+
* - set() 时如果值变化,通知所有依赖的 Context
|
|
877
|
+
*/
|
|
878
|
+
declare class ReactiveState<T> {
|
|
879
|
+
private currentValue;
|
|
880
|
+
private readonly equals;
|
|
881
|
+
/** 所有依赖此状态的 Context */
|
|
882
|
+
private readonly subscribers;
|
|
883
|
+
constructor(initialValue: T, options?: ReactiveStateOptions<T>);
|
|
884
|
+
/**
|
|
885
|
+
* 获取当前值
|
|
886
|
+
* 如果在 ReactiveContext 中调用,会自动注册依赖
|
|
887
|
+
*/
|
|
888
|
+
get(): T;
|
|
889
|
+
/**
|
|
890
|
+
* 设置新值
|
|
891
|
+
* 如果值变化,通知所有订阅者
|
|
892
|
+
* @returns 是否发生了变化
|
|
893
|
+
*/
|
|
894
|
+
set(newValue: T): boolean;
|
|
895
|
+
/**
|
|
896
|
+
* 取消订阅
|
|
897
|
+
* 当 Context 销毁时调用
|
|
898
|
+
*/
|
|
899
|
+
unsubscribe(context: IReactiveContext): void;
|
|
900
|
+
/**
|
|
901
|
+
* 获取当前订阅者数量(用于调试)
|
|
902
|
+
*/
|
|
903
|
+
get subscriberCount(): number;
|
|
904
|
+
}
|
|
905
|
+
//#endregion
|
|
906
|
+
//#region src/reactive-fs/reactive-context.d.ts
|
|
907
|
+
/**
|
|
908
|
+
* 响应式上下文,管理依赖收集和变更通知
|
|
909
|
+
*
|
|
910
|
+
* 核心机制:
|
|
911
|
+
* - 在 stream() 中执行任务时,通过 AsyncLocalStorage 传递 this
|
|
912
|
+
* - 任务中的所有 ReactiveState.get() 调用都会自动注册依赖
|
|
913
|
+
* - 当任何依赖变更时,重新执行任务并 yield 新结果
|
|
914
|
+
*/
|
|
915
|
+
declare class ReactiveContext {
|
|
916
|
+
/** 当前追踪的依赖 */
|
|
917
|
+
private dependencies;
|
|
918
|
+
/** 等待变更的 Promise */
|
|
919
|
+
private changePromise?;
|
|
920
|
+
/** 是否已销毁 */
|
|
921
|
+
private destroyed;
|
|
922
|
+
/**
|
|
923
|
+
* 追踪依赖
|
|
924
|
+
* 由 ReactiveState.get() 调用
|
|
925
|
+
*/
|
|
926
|
+
track(state: ReactiveState<unknown>): void;
|
|
927
|
+
/**
|
|
928
|
+
* 通知变更
|
|
929
|
+
* 由 ReactiveState.set() 调用
|
|
930
|
+
*/
|
|
931
|
+
notifyChange(): void;
|
|
932
|
+
/**
|
|
933
|
+
* 运行响应式任务流
|
|
934
|
+
* 每次依赖变更时重新执行任务并 yield 结果
|
|
935
|
+
*
|
|
936
|
+
* @param task 要执行的异步任务
|
|
937
|
+
* @param signal 用于取消的 AbortSignal
|
|
938
|
+
*/
|
|
939
|
+
stream<T>(task: () => Promise<T>, signal?: AbortSignal): AsyncGenerator<T>;
|
|
940
|
+
/**
|
|
941
|
+
* 执行一次任务(非响应式)
|
|
942
|
+
* 用于初始数据获取
|
|
943
|
+
*/
|
|
944
|
+
runOnce<T>(task: () => Promise<T>): Promise<T>;
|
|
945
|
+
/**
|
|
946
|
+
* 清理依赖
|
|
947
|
+
*/
|
|
948
|
+
private clearDependencies;
|
|
949
|
+
/**
|
|
950
|
+
* 销毁上下文
|
|
951
|
+
* @param reason 可选的销毁原因,如果提供则 reject changePromise
|
|
952
|
+
*/
|
|
953
|
+
private destroy;
|
|
954
|
+
/**
|
|
955
|
+
* 等待 AbortSignal
|
|
956
|
+
*/
|
|
957
|
+
private waitForAbort;
|
|
958
|
+
}
|
|
959
|
+
//#endregion
|
|
960
|
+
//#region src/reactive-fs/reactive-fs.d.ts
|
|
961
|
+
/**
|
|
962
|
+
* 响应式读取文件内容
|
|
963
|
+
*
|
|
964
|
+
* 特性:
|
|
965
|
+
* - 自动注册文件监听
|
|
966
|
+
* - 文件变更时自动更新状态
|
|
967
|
+
* - 在 ReactiveContext 中调用时自动追踪依赖
|
|
968
|
+
* - 支持监听尚未创建的文件(通过 @parcel/watcher)
|
|
969
|
+
*
|
|
970
|
+
* @param filepath 文件路径
|
|
971
|
+
* @returns 文件内容,文件不存在时返回 null
|
|
972
|
+
*/
|
|
973
|
+
declare function reactiveReadFile(filepath: string): Promise<string | null>;
|
|
974
|
+
/**
|
|
975
|
+
* 响应式读取目录内容
|
|
976
|
+
*
|
|
977
|
+
* 特性:
|
|
978
|
+
* - 自动注册目录监听
|
|
979
|
+
* - 目录变更时自动更新状态
|
|
980
|
+
* - 在 ReactiveContext 中调用时自动追踪依赖
|
|
981
|
+
* - 支持监听尚未创建的目录(通过 @parcel/watcher)
|
|
982
|
+
*
|
|
983
|
+
* @param dirpath 目录路径
|
|
984
|
+
* @param options 选项
|
|
985
|
+
* @returns 目录项名称数组
|
|
986
|
+
*/
|
|
987
|
+
declare function reactiveReadDir(dirpath: string, options?: {
|
|
988
|
+
/** 是否只返回目录 */
|
|
989
|
+
directoriesOnly?: boolean;
|
|
990
|
+
/** 是否只返回文件 */
|
|
991
|
+
filesOnly?: boolean;
|
|
992
|
+
/** 是否包含隐藏文件(以 . 开头) */
|
|
993
|
+
includeHidden?: boolean;
|
|
994
|
+
/** 排除的名称 */
|
|
995
|
+
exclude?: string[];
|
|
996
|
+
}): Promise<string[]>;
|
|
997
|
+
/**
|
|
998
|
+
* 响应式检查路径是否存在
|
|
999
|
+
*
|
|
1000
|
+
* @param path 路径
|
|
1001
|
+
* @returns 是否存在
|
|
1002
|
+
*/
|
|
1003
|
+
declare function reactiveExists(path: string): Promise<boolean>;
|
|
1004
|
+
/**
|
|
1005
|
+
* 响应式获取文件/目录的 stat 信息
|
|
1006
|
+
*
|
|
1007
|
+
* @param path 路径
|
|
1008
|
+
* @returns stat 信息,不存在时返回 null
|
|
1009
|
+
*/
|
|
1010
|
+
declare function reactiveStat(path: string): Promise<{
|
|
1011
|
+
isDirectory: boolean;
|
|
1012
|
+
isFile: boolean;
|
|
1013
|
+
mtime: number;
|
|
1014
|
+
birthtime: number;
|
|
1015
|
+
} | null>;
|
|
1016
|
+
/**
|
|
1017
|
+
* 清除指定路径的缓存(用于测试)
|
|
1018
|
+
*/
|
|
1019
|
+
declare function clearCache(path?: string): void;
|
|
1020
|
+
/**
|
|
1021
|
+
* 获取缓存大小(用于调试)
|
|
1022
|
+
*/
|
|
1023
|
+
declare function getCacheSize(): number;
|
|
1024
|
+
//#endregion
|
|
1025
|
+
//#region src/reactive-fs/watcher-pool.d.ts
|
|
1026
|
+
/**
|
|
1027
|
+
* 初始化 watcher pool
|
|
1028
|
+
*
|
|
1029
|
+
* 必须在使用 acquireWatcher 之前调用。
|
|
1030
|
+
* 通常由 server 在启动时调用。
|
|
1031
|
+
*
|
|
1032
|
+
* @param projectDir 项目根目录
|
|
1033
|
+
*/
|
|
1034
|
+
declare function initWatcherPool(projectDir: string): Promise<void>;
|
|
1035
|
+
/**
|
|
1036
|
+
* 获取或创建文件/目录监听器
|
|
1037
|
+
*
|
|
1038
|
+
* 特性:
|
|
1039
|
+
* - 使用 @parcel/watcher 监听项目根目录
|
|
1040
|
+
* - 自动处理新创建的目录(解决 init 后无法监听的问题)
|
|
1041
|
+
* - 同一路径共享订阅
|
|
1042
|
+
* - 引用计数管理生命周期
|
|
1043
|
+
* - 内置防抖机制
|
|
1044
|
+
*
|
|
1045
|
+
* @param path 要监听的路径
|
|
1046
|
+
* @param onChange 变更回调
|
|
1047
|
+
* @param options 监听选项
|
|
1048
|
+
* @returns 释放函数,调用后取消订阅
|
|
1049
|
+
*/
|
|
1050
|
+
declare function acquireWatcher(path: string, onChange: () => void, options?: {
|
|
1051
|
+
recursive?: boolean;
|
|
1052
|
+
debounceMs?: number;
|
|
1053
|
+
onError?: () => void;
|
|
1054
|
+
}): () => void;
|
|
1055
|
+
/**
|
|
1056
|
+
* 获取当前活跃的监听器数量(用于调试)
|
|
1057
|
+
*/
|
|
1058
|
+
declare function getActiveWatcherCount(): number;
|
|
1059
|
+
/**
|
|
1060
|
+
* 关闭所有监听器(用于测试清理)
|
|
1061
|
+
*/
|
|
1062
|
+
declare function closeAllWatchers(): Promise<void>;
|
|
1063
|
+
/**
|
|
1064
|
+
* 检查 watcher pool 是否已初始化
|
|
1065
|
+
*/
|
|
1066
|
+
declare function isWatcherPoolInitialized(): boolean;
|
|
1067
|
+
/**
|
|
1068
|
+
* 获取当前监听的项目目录
|
|
1069
|
+
*/
|
|
1070
|
+
declare function getWatchedProjectDir(): string | null;
|
|
1071
|
+
//#endregion
|
|
1072
|
+
//#region src/reactive-fs/project-watcher.d.ts
|
|
1073
|
+
/**
|
|
1074
|
+
* 事件类型
|
|
1075
|
+
*/
|
|
1076
|
+
type WatchEventType = 'create' | 'update' | 'delete';
|
|
1077
|
+
/**
|
|
1078
|
+
* 监听事件
|
|
1079
|
+
*/
|
|
1080
|
+
interface WatchEvent {
|
|
1081
|
+
type: WatchEventType;
|
|
1082
|
+
path: string;
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* 路径订阅回调
|
|
1086
|
+
*/
|
|
1087
|
+
type PathCallback = (events: WatchEvent[]) => void;
|
|
1088
|
+
/**
|
|
1089
|
+
* 项目监听器
|
|
1090
|
+
*
|
|
1091
|
+
* 使用 @parcel/watcher 监听项目根目录,
|
|
1092
|
+
* 然后通过路径前缀匹配分发事件给订阅者。
|
|
1093
|
+
*
|
|
1094
|
+
* 特性:
|
|
1095
|
+
* - 单个 watcher 监听整个项目
|
|
1096
|
+
* - 自动处理新创建的目录
|
|
1097
|
+
* - 内置防抖机制
|
|
1098
|
+
* - 高性能原生实现
|
|
1099
|
+
*/
|
|
1100
|
+
declare class ProjectWatcher {
|
|
1101
|
+
private projectDir;
|
|
1102
|
+
private subscription;
|
|
1103
|
+
private pathSubscriptions;
|
|
1104
|
+
private pendingEvents;
|
|
1105
|
+
private debounceTimer;
|
|
1106
|
+
private debounceMs;
|
|
1107
|
+
private ignore;
|
|
1108
|
+
private initialized;
|
|
1109
|
+
private initPromise;
|
|
1110
|
+
private healthCheckTimer;
|
|
1111
|
+
private lastEventTime;
|
|
1112
|
+
private healthCheckPending;
|
|
1113
|
+
private enableHealthCheck;
|
|
1114
|
+
private reinitializeTimer;
|
|
1115
|
+
private reinitializePending;
|
|
1116
|
+
constructor(projectDir: string, options?: {
|
|
1117
|
+
debounceMs?: number;
|
|
1118
|
+
ignore?: string[];
|
|
1119
|
+
/** 是否启用健康检查(默认 true) */
|
|
1120
|
+
enableHealthCheck?: boolean;
|
|
1121
|
+
});
|
|
1122
|
+
/**
|
|
1123
|
+
* 初始化 watcher
|
|
1124
|
+
* 懒加载,首次订阅时自动调用
|
|
1125
|
+
*/
|
|
1126
|
+
init(): Promise<void>;
|
|
1127
|
+
private doInit;
|
|
1128
|
+
/**
|
|
1129
|
+
* 处理 watcher 错误
|
|
1130
|
+
* 对于 FSEvents dropped 错误,触发延迟重建
|
|
1131
|
+
*/
|
|
1132
|
+
private handleWatcherError;
|
|
1133
|
+
/**
|
|
1134
|
+
* 延迟重建 watcher(防抖,避免频繁重建)
|
|
1135
|
+
*/
|
|
1136
|
+
private scheduleReinitialize;
|
|
1137
|
+
/**
|
|
1138
|
+
* 处理原始事件
|
|
1139
|
+
*/
|
|
1140
|
+
private handleEvents;
|
|
1141
|
+
/**
|
|
1142
|
+
* 分发事件给订阅者
|
|
1143
|
+
*/
|
|
1144
|
+
private flushEvents;
|
|
1145
|
+
/**
|
|
1146
|
+
* 检查事件是否匹配订阅
|
|
1147
|
+
*/
|
|
1148
|
+
private matchPath;
|
|
1149
|
+
/**
|
|
1150
|
+
* 同步订阅路径变更(watcher 必须已初始化)
|
|
1151
|
+
*
|
|
1152
|
+
* 这是同步版本,用于在 watcher 已初始化后快速注册订阅。
|
|
1153
|
+
* 如果 watcher 未初始化,抛出错误。
|
|
1154
|
+
*
|
|
1155
|
+
* @param path 要监听的路径
|
|
1156
|
+
* @param callback 变更回调
|
|
1157
|
+
* @param options 订阅选项
|
|
1158
|
+
* @returns 取消订阅函数
|
|
1159
|
+
*/
|
|
1160
|
+
subscribeSync(path: string, callback: PathCallback, options?: {
|
|
1161
|
+
watchChildren?: boolean;
|
|
1162
|
+
}): () => void;
|
|
1163
|
+
/**
|
|
1164
|
+
* 订阅路径变更(异步版本,自动初始化)
|
|
1165
|
+
*
|
|
1166
|
+
* @param path 要监听的路径
|
|
1167
|
+
* @param callback 变更回调
|
|
1168
|
+
* @param options 订阅选项
|
|
1169
|
+
* @returns 取消订阅函数
|
|
1170
|
+
*/
|
|
1171
|
+
subscribe(path: string, callback: PathCallback, options?: {
|
|
1172
|
+
watchChildren?: boolean;
|
|
1173
|
+
}): Promise<() => void>;
|
|
1174
|
+
/**
|
|
1175
|
+
* 获取当前订阅数量(用于调试)
|
|
1176
|
+
*/
|
|
1177
|
+
get subscriptionCount(): number;
|
|
1178
|
+
/**
|
|
1179
|
+
* 检查是否已初始化
|
|
1180
|
+
*/
|
|
1181
|
+
get isInitialized(): boolean;
|
|
1182
|
+
/**
|
|
1183
|
+
* 启动健康检查定时器
|
|
1184
|
+
*/
|
|
1185
|
+
private startHealthCheck;
|
|
1186
|
+
/**
|
|
1187
|
+
* 停止健康检查定时器
|
|
1188
|
+
*/
|
|
1189
|
+
private stopHealthCheck;
|
|
1190
|
+
/**
|
|
1191
|
+
* 执行健康检查
|
|
1192
|
+
*
|
|
1193
|
+
* 工作流程:
|
|
1194
|
+
* 1. 如果最近有事件,无需检查
|
|
1195
|
+
* 2. 如果上次探测还在等待中,说明 watcher 可能失效,尝试重建
|
|
1196
|
+
* 3. 否则,创建临时文件触发事件,等待下次检查验证
|
|
1197
|
+
*/
|
|
1198
|
+
private performHealthCheck;
|
|
1199
|
+
/**
|
|
1200
|
+
* 发送探测:通过 utimesSync 修改项目目录的时间戳来触发 watcher 事件
|
|
1201
|
+
*/
|
|
1202
|
+
private sendProbe;
|
|
1203
|
+
/**
|
|
1204
|
+
* 重新初始化 watcher
|
|
1205
|
+
*/
|
|
1206
|
+
private reinitialize;
|
|
1207
|
+
/**
|
|
1208
|
+
* 等待项目目录被创建
|
|
1209
|
+
*/
|
|
1210
|
+
private waitForProjectDir;
|
|
1211
|
+
/**
|
|
1212
|
+
* 关闭 watcher
|
|
1213
|
+
*/
|
|
1214
|
+
close(): Promise<void>;
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* 获取或创建项目监听器
|
|
1218
|
+
*/
|
|
1219
|
+
declare function getProjectWatcher(projectDir: string, options?: ConstructorParameters<typeof ProjectWatcher>[1]): ProjectWatcher;
|
|
1220
|
+
/**
|
|
1221
|
+
* 关闭所有 ProjectWatcher(用于测试清理)
|
|
1222
|
+
*/
|
|
1223
|
+
declare function closeAllProjectWatchers(): Promise<void>;
|
|
1224
|
+
//#endregion
|
|
1225
|
+
//#region src/watcher.d.ts
|
|
1226
|
+
/**
|
|
1227
|
+
* File change event types
|
|
1228
|
+
*/
|
|
1229
|
+
type FileChangeType = 'spec' | 'change' | 'archive' | 'project';
|
|
1230
|
+
/**
|
|
1231
|
+
* File change event payload
|
|
1232
|
+
*/
|
|
1233
|
+
interface FileChangeEvent {
|
|
1234
|
+
type: FileChangeType;
|
|
1235
|
+
action: 'create' | 'update' | 'delete';
|
|
1236
|
+
id?: string;
|
|
1237
|
+
path: string;
|
|
1238
|
+
timestamp: number;
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* OpenSpec file watcher
|
|
1242
|
+
* Watches the openspec/ directory for changes and emits events
|
|
1243
|
+
*/
|
|
1244
|
+
declare class OpenSpecWatcher extends EventEmitter {
|
|
1245
|
+
private projectDir;
|
|
1246
|
+
private watchers;
|
|
1247
|
+
private debounceTimers;
|
|
1248
|
+
private debounceMs;
|
|
1249
|
+
constructor(projectDir: string, options?: {
|
|
1250
|
+
debounceMs?: number;
|
|
1251
|
+
});
|
|
1252
|
+
private get openspecDir();
|
|
1253
|
+
private get specsDir();
|
|
1254
|
+
private get changesDir();
|
|
1255
|
+
private get archiveDir();
|
|
1256
|
+
/**
|
|
1257
|
+
* Start watching for file changes
|
|
1258
|
+
*/
|
|
1259
|
+
start(): void;
|
|
1260
|
+
/**
|
|
1261
|
+
* Stop watching for file changes
|
|
1262
|
+
*/
|
|
1263
|
+
stop(): void;
|
|
1264
|
+
/**
|
|
1265
|
+
* Watch a directory recursively
|
|
1266
|
+
*/
|
|
1267
|
+
private watchDir;
|
|
1268
|
+
/**
|
|
1269
|
+
* Emit event with debouncing to avoid duplicate events
|
|
1270
|
+
*/
|
|
1271
|
+
private emitDebounced;
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Create a file change observable for use with tRPC subscriptions
|
|
1275
|
+
*/
|
|
1276
|
+
declare function createFileChangeObservable(watcher: OpenSpecWatcher): {
|
|
1277
|
+
subscribe: (observer: {
|
|
1278
|
+
next: (event: FileChangeEvent) => void;
|
|
1279
|
+
error?: (error: Error) => void;
|
|
1280
|
+
complete?: () => void;
|
|
1281
|
+
}) => {
|
|
1282
|
+
unsubscribe: () => void;
|
|
1283
|
+
};
|
|
1284
|
+
};
|
|
1285
|
+
//#endregion
|
|
1286
|
+
//#region src/config.d.ts
|
|
1287
|
+
/**
|
|
1288
|
+
* 解析 CLI 命令字符串为数组
|
|
1289
|
+
*
|
|
1290
|
+
* 支持两种格式:
|
|
1291
|
+
* 1. JSON 数组:以 `[` 开头,如 `["npx", "@fission-ai/openspec"]`
|
|
1292
|
+
* 2. 简单字符串:用空格分割,如 `npx @fission-ai/openspec`
|
|
1293
|
+
*
|
|
1294
|
+
* 注意:简单字符串解析不支持带引号的参数,如需复杂命令请使用 JSON 数组格式
|
|
1295
|
+
*/
|
|
1296
|
+
declare function parseCliCommand(command: string): string[];
|
|
1297
|
+
/** CLI 嗅探结果 */
|
|
1298
|
+
interface CliSniffResult {
|
|
1299
|
+
/** 是否存在全局 openspec 命令 */
|
|
1300
|
+
hasGlobal: boolean;
|
|
1301
|
+
/** 全局命令的版本(仅当 hasGlobal 为 true 时有值) */
|
|
1302
|
+
version?: string;
|
|
1303
|
+
/** npm registry 上的最新版本 */
|
|
1304
|
+
latestVersion?: string;
|
|
1305
|
+
/** 是否有可用更新 */
|
|
1306
|
+
hasUpdate?: boolean;
|
|
1307
|
+
/** 错误信息(如果检测失败) */
|
|
1308
|
+
error?: string;
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* 嗅探全局 openspec 命令(无缓存)
|
|
1312
|
+
*
|
|
1313
|
+
* 使用 `openspec --version` 检测是否有全局命令可用。
|
|
1314
|
+
* 同时检查 npm registry 上的最新版本。
|
|
1315
|
+
* 每次调用都会重新检测,不使用缓存。
|
|
1316
|
+
*/
|
|
1317
|
+
declare function sniffGlobalCli(): Promise<CliSniffResult>;
|
|
1318
|
+
/**
|
|
1319
|
+
* 获取默认 CLI 命令(异步,带检测)
|
|
1320
|
+
*
|
|
1321
|
+
* @returns CLI 命令数组,如 `['openspec']` 或 `['npx', '@fission-ai/openspec']`
|
|
1322
|
+
*/
|
|
1323
|
+
declare function getDefaultCliCommand(): Promise<readonly string[]>;
|
|
1324
|
+
/**
|
|
1325
|
+
* 获取默认 CLI 命令的字符串形式(用于 UI 显示)
|
|
1326
|
+
*/
|
|
1327
|
+
declare function getDefaultCliCommandString(): Promise<string>;
|
|
1328
|
+
/**
|
|
1329
|
+
* OpenSpecUI 配置 Schema
|
|
1330
|
+
*
|
|
1331
|
+
* 存储在 openspec/.openspecui.json 中,利用文件监听实现响应式更新
|
|
1332
|
+
*/
|
|
1333
|
+
declare const OpenSpecUIConfigSchema: z.ZodObject<{
|
|
1334
|
+
/** CLI 命令配置 */
|
|
1335
|
+
cli: z.ZodDefault<z.ZodObject<{
|
|
1336
|
+
/** CLI 命令前缀 */
|
|
1337
|
+
command: z.ZodOptional<z.ZodString>;
|
|
1338
|
+
}, "strip", z.ZodTypeAny, {
|
|
1339
|
+
command?: string | undefined;
|
|
1340
|
+
}, {
|
|
1341
|
+
command?: string | undefined;
|
|
1342
|
+
}>>;
|
|
1343
|
+
/** UI 配置 */
|
|
1344
|
+
ui: z.ZodDefault<z.ZodObject<{
|
|
1345
|
+
/** 主题 */
|
|
1346
|
+
theme: z.ZodDefault<z.ZodEnum<["light", "dark", "system"]>>;
|
|
1347
|
+
}, "strip", z.ZodTypeAny, {
|
|
1348
|
+
theme: "light" | "dark" | "system";
|
|
1349
|
+
}, {
|
|
1350
|
+
theme?: "light" | "dark" | "system" | undefined;
|
|
1351
|
+
}>>;
|
|
1352
|
+
}, "strip", z.ZodTypeAny, {
|
|
1353
|
+
cli: {
|
|
1354
|
+
command?: string | undefined;
|
|
1355
|
+
};
|
|
1356
|
+
ui: {
|
|
1357
|
+
theme: "light" | "dark" | "system";
|
|
1358
|
+
};
|
|
1359
|
+
}, {
|
|
1360
|
+
cli?: {
|
|
1361
|
+
command?: string | undefined;
|
|
1362
|
+
} | undefined;
|
|
1363
|
+
ui?: {
|
|
1364
|
+
theme?: "light" | "dark" | "system" | undefined;
|
|
1365
|
+
} | undefined;
|
|
1366
|
+
}>;
|
|
1367
|
+
type OpenSpecUIConfig = z.infer<typeof OpenSpecUIConfigSchema>;
|
|
1368
|
+
/** 默认配置(静态,用于测试和类型) */
|
|
1369
|
+
declare const DEFAULT_CONFIG: OpenSpecUIConfig;
|
|
1370
|
+
/**
|
|
1371
|
+
* 配置管理器
|
|
1372
|
+
*
|
|
1373
|
+
* 负责读写 openspec/.openspecui.json 配置文件。
|
|
1374
|
+
* 读取操作使用 reactiveReadFile,支持响应式更新。
|
|
1375
|
+
*/
|
|
1376
|
+
declare class ConfigManager {
|
|
1377
|
+
private configPath;
|
|
1378
|
+
constructor(projectDir: string);
|
|
1379
|
+
/**
|
|
1380
|
+
* 读取配置(响应式)
|
|
1381
|
+
*
|
|
1382
|
+
* 如果配置文件不存在,返回默认配置。
|
|
1383
|
+
* 如果配置文件格式错误,返回默认配置并打印警告。
|
|
1384
|
+
*/
|
|
1385
|
+
readConfig(): Promise<OpenSpecUIConfig>;
|
|
1386
|
+
/**
|
|
1387
|
+
* 写入配置
|
|
1388
|
+
*
|
|
1389
|
+
* 会触发文件监听,自动更新订阅者。
|
|
1390
|
+
*/
|
|
1391
|
+
writeConfig(config: Partial<OpenSpecUIConfig>): Promise<void>;
|
|
1392
|
+
/**
|
|
1393
|
+
* 获取 CLI 命令(数组形式)
|
|
1394
|
+
*
|
|
1395
|
+
* 优先级:配置文件 > 全局 openspec 命令 > npx fallback
|
|
1396
|
+
*
|
|
1397
|
+
* @returns CLI 命令数组,如 `['openspec']` 或 `['npx', '@fission-ai/openspec']`
|
|
1398
|
+
*/
|
|
1399
|
+
getCliCommand(): Promise<readonly string[]>;
|
|
1400
|
+
/**
|
|
1401
|
+
* 获取 CLI 命令的字符串形式(用于 UI 显示)
|
|
1402
|
+
*/
|
|
1403
|
+
getCliCommandString(): Promise<string>;
|
|
1404
|
+
/**
|
|
1405
|
+
* 设置 CLI 命令
|
|
1406
|
+
*/
|
|
1407
|
+
setCliCommand(command: string): Promise<void>;
|
|
1408
|
+
}
|
|
1409
|
+
//#endregion
|
|
1410
|
+
//#region src/cli-executor.d.ts
|
|
1411
|
+
/** CLI 执行结果 */
|
|
1412
|
+
interface CliResult {
|
|
1413
|
+
success: boolean;
|
|
1414
|
+
stdout: string;
|
|
1415
|
+
stderr: string;
|
|
1416
|
+
exitCode: number | null;
|
|
1417
|
+
}
|
|
1418
|
+
/** CLI 流式输出事件 */
|
|
1419
|
+
interface CliStreamEvent {
|
|
1420
|
+
type: 'command' | 'stdout' | 'stderr' | 'exit';
|
|
1421
|
+
data?: string;
|
|
1422
|
+
exitCode?: number | null;
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* CLI 执行器
|
|
1426
|
+
*
|
|
1427
|
+
* 负责调用外部 openspec CLI 命令。
|
|
1428
|
+
* 命令前缀从 ConfigManager 获取,支持:
|
|
1429
|
+
* - ['npx', '@fission-ai/openspec'] (默认)
|
|
1430
|
+
* - ['openspec'] (全局安装)
|
|
1431
|
+
* - 自定义数组或字符串
|
|
1432
|
+
*
|
|
1433
|
+
* 注意:所有命令都使用 shell: false 执行,避免 shell 注入风险
|
|
1434
|
+
*/
|
|
1435
|
+
declare class CliExecutor {
|
|
1436
|
+
private configManager;
|
|
1437
|
+
private projectDir;
|
|
1438
|
+
constructor(configManager: ConfigManager, projectDir: string);
|
|
1439
|
+
/**
|
|
1440
|
+
* 创建干净的环境变量,移除 pnpm 特有的配置
|
|
1441
|
+
* 避免 pnpm 环境变量污染 npx/npm 执行
|
|
1442
|
+
*/
|
|
1443
|
+
private getCleanEnv;
|
|
1444
|
+
/**
|
|
1445
|
+
* 构建完整命令数组
|
|
1446
|
+
*
|
|
1447
|
+
* @param args CLI 参数,如 ['init'] 或 ['archive', 'change-id']
|
|
1448
|
+
* @returns [command, ...commandArgs, ...args]
|
|
1449
|
+
*/
|
|
1450
|
+
private buildCommandArray;
|
|
1451
|
+
/**
|
|
1452
|
+
* 执行 CLI 命令
|
|
1453
|
+
*
|
|
1454
|
+
* @param args CLI 参数,如 ['init'] 或 ['archive', 'change-id']
|
|
1455
|
+
* @returns 执行结果
|
|
1456
|
+
*/
|
|
1457
|
+
execute(args: string[]): Promise<CliResult>;
|
|
1458
|
+
/**
|
|
1459
|
+
* 执行 openspec init(非交互式)
|
|
1460
|
+
*
|
|
1461
|
+
* @param tools 工具列表,如 ['claude', 'cursor'] 或 'all' 或 'none'
|
|
1462
|
+
*/
|
|
1463
|
+
init(tools?: string[] | 'all' | 'none'): Promise<CliResult>;
|
|
1464
|
+
/**
|
|
1465
|
+
* 执行 openspec archive <changeId>(非交互式)
|
|
1466
|
+
*
|
|
1467
|
+
* @param changeId 要归档的 change ID
|
|
1468
|
+
* @param options 选项
|
|
1469
|
+
*/
|
|
1470
|
+
archive(changeId: string, options?: {
|
|
1471
|
+
skipSpecs?: boolean;
|
|
1472
|
+
noValidate?: boolean;
|
|
1473
|
+
}): Promise<CliResult>;
|
|
1474
|
+
/**
|
|
1475
|
+
* 执行 openspec validate [type] [id]
|
|
1476
|
+
*/
|
|
1477
|
+
validate(type?: 'spec' | 'change', id?: string): Promise<CliResult>;
|
|
1478
|
+
/**
|
|
1479
|
+
* 流式执行 openspec validate
|
|
1480
|
+
*/
|
|
1481
|
+
validateStream(type: 'spec' | 'change' | undefined, id: string | undefined, onEvent: (event: CliStreamEvent) => void): Promise<() => void>;
|
|
1482
|
+
/**
|
|
1483
|
+
* 检查 CLI 是否可用
|
|
1484
|
+
* @param timeout 超时时间(毫秒),默认 10 秒
|
|
1485
|
+
*/
|
|
1486
|
+
checkAvailability(timeout?: number): Promise<{
|
|
1487
|
+
available: boolean;
|
|
1488
|
+
version?: string;
|
|
1489
|
+
error?: string;
|
|
1490
|
+
}>;
|
|
1491
|
+
/**
|
|
1492
|
+
* 流式执行 CLI 命令
|
|
1493
|
+
*
|
|
1494
|
+
* @param args CLI 参数
|
|
1495
|
+
* @param onEvent 事件回调
|
|
1496
|
+
* @returns 取消函数
|
|
1497
|
+
*/
|
|
1498
|
+
executeStream(args: string[], onEvent: (event: CliStreamEvent) => void): Promise<() => void>;
|
|
1499
|
+
/**
|
|
1500
|
+
* 流式执行 openspec init
|
|
1501
|
+
*/
|
|
1502
|
+
initStream(tools: string[] | 'all' | 'none', onEvent: (event: CliStreamEvent) => void): Promise<() => void>;
|
|
1503
|
+
/**
|
|
1504
|
+
* 流式执行 openspec archive
|
|
1505
|
+
*/
|
|
1506
|
+
archiveStream(changeId: string, options: {
|
|
1507
|
+
skipSpecs?: boolean;
|
|
1508
|
+
noValidate?: boolean;
|
|
1509
|
+
}, onEvent: (event: CliStreamEvent) => void): Promise<() => void>;
|
|
1510
|
+
/**
|
|
1511
|
+
* 流式执行任意命令(数组形式)
|
|
1512
|
+
*
|
|
1513
|
+
* 用于执行不需要 openspec CLI 前缀的命令,如 npm install。
|
|
1514
|
+
* 使用 shell: false 避免 shell 注入风险。
|
|
1515
|
+
*
|
|
1516
|
+
* @param command 命令数组,如 ['npm', 'install', '-g', '@fission-ai/openspec']
|
|
1517
|
+
* @param onEvent 事件回调
|
|
1518
|
+
* @returns 取消函数
|
|
1519
|
+
*/
|
|
1520
|
+
executeCommandStream(command: readonly string[], onEvent: (event: CliStreamEvent) => void): () => void;
|
|
1521
|
+
}
|
|
1522
|
+
//#endregion
|
|
1523
|
+
//#region src/tool-config.d.ts
|
|
1524
|
+
/**
|
|
1525
|
+
* 工具配置检测模块
|
|
1526
|
+
*
|
|
1527
|
+
* 完全对齐 @fission-ai/openspec 的官方实现
|
|
1528
|
+
* 用于检测项目中已配置的 AI 工具
|
|
1529
|
+
*
|
|
1530
|
+
* 重要:使用响应式文件系统实现,监听配置目录,
|
|
1531
|
+
* 当配置文件变化时会自动触发更新。
|
|
1532
|
+
*
|
|
1533
|
+
* @see references/openspec/src/core/config.ts (AI_TOOLS)
|
|
1534
|
+
* @see references/openspec/src/core/configurators/slash/
|
|
1535
|
+
* @see references/openspec/src/core/init.ts (isToolConfigured)
|
|
1536
|
+
*/
|
|
1537
|
+
/**
|
|
1538
|
+
* 检测路径范围
|
|
1539
|
+
* - project: 相对于项目根目录
|
|
1540
|
+
* - global: 绝对路径(如 Codex 的 ~/.codex/prompts/)
|
|
1541
|
+
* - none: 无检测路径(如 Universal AGENTS.md 通过项目 AGENTS.md 检测)
|
|
1542
|
+
*/
|
|
1543
|
+
type DetectionScope = 'project' | 'global' | 'none';
|
|
1544
|
+
/**
|
|
1545
|
+
* AI 工具选项(与官方 OpenSpec CLI 完全一致)
|
|
1546
|
+
* @see references/openspec/src/core/config.ts
|
|
1547
|
+
*/
|
|
1548
|
+
interface AIToolOption {
|
|
1549
|
+
/** 显示名称 */
|
|
1550
|
+
name: string;
|
|
1551
|
+
/** 工具 ID(用于 CLI 参数) */
|
|
1552
|
+
value: string;
|
|
1553
|
+
/** 是否可用(available: false 的工具不会出现在主列表中) */
|
|
1554
|
+
available: boolean;
|
|
1555
|
+
/** 成功消息中使用的标签 */
|
|
1556
|
+
successLabel?: string;
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1559
|
+
* 工具检测配置
|
|
1560
|
+
*/
|
|
1561
|
+
interface ToolDetectionConfig {
|
|
1562
|
+
/** 检测路径范围 */
|
|
1563
|
+
scope: DetectionScope;
|
|
1564
|
+
/**
|
|
1565
|
+
* 检测路径
|
|
1566
|
+
* - scope='project': 相对于项目根目录的路径
|
|
1567
|
+
* - scope='global': 返回绝对路径的函数
|
|
1568
|
+
* - scope='none': undefined
|
|
1569
|
+
*/
|
|
1570
|
+
detectionPath?: string | (() => string);
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* 完整的工具配置(元信息 + 检测配置)
|
|
1574
|
+
*/
|
|
1575
|
+
interface ToolConfig extends AIToolOption, ToolDetectionConfig {}
|
|
1576
|
+
/**
|
|
1577
|
+
* 所有支持的 AI 工具配置
|
|
1578
|
+
*
|
|
1579
|
+
* 完全对齐官方 OpenSpec CLI 的 AI_TOOLS
|
|
1580
|
+
* 按字母顺序排序(与官方一致)
|
|
1581
|
+
*
|
|
1582
|
+
* @see references/openspec/src/core/config.ts
|
|
1583
|
+
* @see references/openspec/src/core/configurators/slash/registry.ts
|
|
1584
|
+
*/
|
|
1585
|
+
declare const AI_TOOLS: ToolConfig[];
|
|
1586
|
+
/**
|
|
1587
|
+
* 获取所有可用的工具(available: true)
|
|
1588
|
+
*/
|
|
1589
|
+
declare function getAvailableTools(): ToolConfig[];
|
|
1590
|
+
/**
|
|
1591
|
+
* 获取所有可用的工具 ID 列表(available: true)
|
|
1592
|
+
*/
|
|
1593
|
+
declare function getAvailableToolIds(): string[];
|
|
1594
|
+
/**
|
|
1595
|
+
* 获取所有工具(包括 available: false 的)
|
|
1596
|
+
*/
|
|
1597
|
+
declare function getAllTools(): ToolConfig[];
|
|
1598
|
+
/**
|
|
1599
|
+
* 获取所有工具 ID 列表(包括 available: false 的)
|
|
1600
|
+
*/
|
|
1601
|
+
declare function getAllToolIds(): string[];
|
|
1602
|
+
/**
|
|
1603
|
+
* 根据工具 ID 获取工具配置
|
|
1604
|
+
*/
|
|
1605
|
+
declare function getToolById(toolId: string): ToolConfig | undefined;
|
|
1606
|
+
/**
|
|
1607
|
+
* 检测项目中已配置的工具(响应式)
|
|
1608
|
+
*
|
|
1609
|
+
* 监听两类目录:
|
|
1610
|
+
* 1. 项目级配置目录(如 .claude, .cursor 等)
|
|
1611
|
+
* 2. 全局配置目录(如 ~/.codex/prompts/)
|
|
1612
|
+
*
|
|
1613
|
+
* @param projectDir 项目根目录
|
|
1614
|
+
* @returns 已配置的工具 ID 列表
|
|
1615
|
+
*/
|
|
1616
|
+
declare function getConfiguredTools(projectDir: string): Promise<string[]>;
|
|
1617
|
+
/**
|
|
1618
|
+
* 检查特定工具是否已配置
|
|
1619
|
+
*
|
|
1620
|
+
* @param projectDir 项目根目录
|
|
1621
|
+
* @param toolId 工具 ID
|
|
1622
|
+
* @returns 是否已配置
|
|
1623
|
+
*/
|
|
1624
|
+
declare function isToolConfigured(projectDir: string, toolId: string): Promise<boolean>;
|
|
1625
|
+
//#endregion
|
|
1626
|
+
//#region src/export-types.d.ts
|
|
1627
|
+
/**
|
|
1628
|
+
* Types for static export / SSG
|
|
1629
|
+
*/
|
|
1630
|
+
/**
|
|
1631
|
+
* Complete snapshot of an OpenSpec project for static export
|
|
1632
|
+
*/
|
|
1633
|
+
interface ExportSnapshot {
|
|
1634
|
+
/** Snapshot metadata */
|
|
1635
|
+
meta: {
|
|
1636
|
+
timestamp: string;
|
|
1637
|
+
version: string;
|
|
1638
|
+
projectDir: string;
|
|
1639
|
+
};
|
|
1640
|
+
/** Dashboard summary data */
|
|
1641
|
+
dashboard: {
|
|
1642
|
+
specsCount: number;
|
|
1643
|
+
changesCount: number;
|
|
1644
|
+
archivesCount: number;
|
|
1645
|
+
};
|
|
1646
|
+
/** All specs with parsed content */
|
|
1647
|
+
specs: Array<{
|
|
1648
|
+
id: string;
|
|
1649
|
+
name: string;
|
|
1650
|
+
content: string;
|
|
1651
|
+
overview: string;
|
|
1652
|
+
requirements: Array<{
|
|
1653
|
+
id: string;
|
|
1654
|
+
text: string;
|
|
1655
|
+
scenarios: Array<{
|
|
1656
|
+
rawText: string;
|
|
1657
|
+
}>;
|
|
1658
|
+
}>;
|
|
1659
|
+
createdAt: number;
|
|
1660
|
+
updatedAt: number;
|
|
1661
|
+
}>;
|
|
1662
|
+
/** All active changes with parsed content */
|
|
1663
|
+
changes: Array<{
|
|
1664
|
+
id: string;
|
|
1665
|
+
name: string;
|
|
1666
|
+
proposal: string;
|
|
1667
|
+
tasks?: string;
|
|
1668
|
+
design?: string;
|
|
1669
|
+
why: string;
|
|
1670
|
+
whatChanges: string;
|
|
1671
|
+
parsedTasks: Array<{
|
|
1672
|
+
id: string;
|
|
1673
|
+
text: string;
|
|
1674
|
+
completed: boolean;
|
|
1675
|
+
section?: string;
|
|
1676
|
+
}>;
|
|
1677
|
+
deltas: Array<{
|
|
1678
|
+
capability: string;
|
|
1679
|
+
content: string;
|
|
1680
|
+
}>;
|
|
1681
|
+
progress: {
|
|
1682
|
+
total: number;
|
|
1683
|
+
completed: number;
|
|
1684
|
+
};
|
|
1685
|
+
createdAt: number;
|
|
1686
|
+
updatedAt: number;
|
|
1687
|
+
}>;
|
|
1688
|
+
/** All archived changes */
|
|
1689
|
+
archives: Array<{
|
|
1690
|
+
id: string;
|
|
1691
|
+
name: string;
|
|
1692
|
+
proposal: string;
|
|
1693
|
+
tasks?: string;
|
|
1694
|
+
design?: string;
|
|
1695
|
+
why: string;
|
|
1696
|
+
whatChanges: string;
|
|
1697
|
+
parsedTasks: Array<{
|
|
1698
|
+
id: string;
|
|
1699
|
+
text: string;
|
|
1700
|
+
completed: boolean;
|
|
1701
|
+
section?: string;
|
|
1702
|
+
}>;
|
|
1703
|
+
createdAt: number;
|
|
1704
|
+
updatedAt: number;
|
|
1705
|
+
}>;
|
|
1706
|
+
/** Project.md content */
|
|
1707
|
+
projectMd?: string;
|
|
1708
|
+
/** AGENTS.md content */
|
|
1709
|
+
agentsMd?: string;
|
|
1710
|
+
}
|
|
1711
|
+
//#endregion
|
|
1712
|
+
export { type AIToolOption, AI_TOOLS, type ArchiveMeta, type Change, type ChangeFile, ChangeFileSchema, type ChangeMeta, ChangeSchema, CliExecutor, type CliResult, type CliSniffResult, type CliStreamEvent, ConfigManager, DEFAULT_CONFIG, type Delta, type DeltaOperation, DeltaOperationType, DeltaSchema, type DeltaSpec, DeltaSpecSchema, type ExportSnapshot, type FileChangeEvent, type FileChangeType, MarkdownParser, OpenSpecAdapter, type OpenSpecUIConfig, OpenSpecUIConfigSchema, OpenSpecWatcher, type PathCallback, ProjectWatcher, ReactiveContext, ReactiveState, type ReactiveStateOptions, type Requirement, RequirementSchema, type Spec, type SpecMeta, SpecSchema, type Task, TaskSchema, type ToolConfig, type ToolDetectionConfig, type ValidationIssue, type ValidationResult, Validator, type WatchEvent, type WatchEventType, acquireWatcher, clearCache, closeAllProjectWatchers, closeAllWatchers, contextStorage, createFileChangeObservable, getActiveWatcherCount, getAllToolIds, getAllTools, getAvailableToolIds, getAvailableTools, getCacheSize, getConfiguredTools, getDefaultCliCommand, getDefaultCliCommandString, getProjectWatcher, getToolById, getWatchedProjectDir, initWatcherPool, isToolConfigured, isWatcherPoolInitialized, parseCliCommand, reactiveExists, reactiveReadDir, reactiveReadFile, reactiveStat, sniffGlobalCli };
|