@specsafe/core 0.1.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/LICENSE +21 -0
- package/README.md +282 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/tracker.d.ts +42 -0
- package/dist/tracker.d.ts.map +1 -0
- package/dist/tracker.js +287 -0
- package/dist/tracker.js.map +1 -0
- package/dist/types.d.ts +87 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +10 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +27 -0
- package/dist/validation.js.map +1 -0
- package/dist/workflow.d.ts +67 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +193 -0
- package/dist/workflow.js.map +1 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Agentic Engineering
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# @specsafe/core
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://img.shields.io/npm/v/@specsafe/core.svg" alt="npm version">
|
|
5
|
+
<img src="https://img.shields.io/npm/l/@specsafe/core.svg" alt="license">
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
Core workflow engine, types, and utilities for the SpecSafe spec-driven development framework.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @specsafe/core
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## What It Provides
|
|
17
|
+
|
|
18
|
+
- **Workflow Engine** - Manage spec lifecycle from creation to archive
|
|
19
|
+
- **ProjectTracker** - Track project state and spec metadata
|
|
20
|
+
- **TypeScript Types** - Full type definitions for specs, requirements, and reports
|
|
21
|
+
- **Validation Utilities** - Schema validation and ID validation
|
|
22
|
+
|
|
23
|
+
## API Reference
|
|
24
|
+
|
|
25
|
+
### Workflow Class
|
|
26
|
+
|
|
27
|
+
The main class for managing spec workflows.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { Workflow } from '@specsafe/core';
|
|
31
|
+
|
|
32
|
+
const workflow = new Workflow({
|
|
33
|
+
specsDir: './specs',
|
|
34
|
+
projectName: 'My Project'
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
#### `createSpec(specId: string, content: string): Promise<Spec>`
|
|
39
|
+
|
|
40
|
+
Create a new specification.
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
const spec = await workflow.createSpec('user-auth', `# User Authentication
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
### REQ-001: Login
|
|
48
|
+
**Given** a registered user
|
|
49
|
+
**When** they enter valid credentials
|
|
50
|
+
**Then** they should be logged in
|
|
51
|
+
`);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### `moveToTest(specId: string): Promise<Spec>`
|
|
55
|
+
|
|
56
|
+
Move a spec to the "test" phase.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const spec = await workflow.moveToTest('user-auth');
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### `moveToCode(specId: string): Promise<Spec>`
|
|
63
|
+
|
|
64
|
+
Move a spec to the "code" phase.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const spec = await workflow.moveToCode('user-auth');
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### `moveToQA(specId: string, report?: QAReport): Promise<Spec>`
|
|
71
|
+
|
|
72
|
+
Transition a spec into QA review or mark QA as complete. Optionally accepts a QAReport to record results.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const spec = await workflow.moveToQA('user-auth', {
|
|
76
|
+
passed: true,
|
|
77
|
+
notes: 'All tests passing'
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### `complete(specId: string): Promise<Spec>`
|
|
82
|
+
|
|
83
|
+
Mark a spec as complete.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const spec = await workflow.complete('user-auth');
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### `archive(specId: string): Promise<Spec>`
|
|
90
|
+
|
|
91
|
+
Archive a completed spec.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const spec = await workflow.archive('user-auth');
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### `getSpec(specId: string): Promise<Spec | null>`
|
|
98
|
+
|
|
99
|
+
Get a spec by ID.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const spec = await workflow.getSpec('user-auth');
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### `listSpecs(phase?: Phase): Promise<Spec[]>`
|
|
106
|
+
|
|
107
|
+
List all specs or filter by phase.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// All specs
|
|
111
|
+
const allSpecs = await workflow.listSpecs();
|
|
112
|
+
|
|
113
|
+
// Only active specs
|
|
114
|
+
const activeSpecs = await workflow.listSpecs('active');
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### ProjectTracker Class
|
|
120
|
+
|
|
121
|
+
Track project-level state and metadata.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { ProjectTracker } from '@specsafe/core';
|
|
125
|
+
|
|
126
|
+
const tracker = new ProjectTracker('./specs');
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### `getProjectState(): Promise<ProjectState>`
|
|
130
|
+
|
|
131
|
+
Get the current project state.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const state = await tracker.getProjectState();
|
|
135
|
+
console.log(state.activeSpecs.length);
|
|
136
|
+
console.log(state.completedSpecs.length);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### `updateSpecStatus(specId: string, status: SpecStatus): Promise<void>`
|
|
140
|
+
|
|
141
|
+
Update the status of a spec.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
await tracker.updateSpecStatus('user-auth', 'in-progress');
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Validation Utilities
|
|
150
|
+
|
|
151
|
+
#### `validateSpecId(specId: string): boolean`
|
|
152
|
+
|
|
153
|
+
Validate a spec ID format.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { validateSpecId } from '@specsafe/core';
|
|
157
|
+
|
|
158
|
+
validateSpecId('user-auth'); // true
|
|
159
|
+
validateSpecId('user_auth'); // false (underscores not allowed)
|
|
160
|
+
validateSpecId('user-auth-123'); // true
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## TypeScript Types
|
|
166
|
+
|
|
167
|
+
### Spec
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
interface Spec {
|
|
171
|
+
id: string;
|
|
172
|
+
title: string;
|
|
173
|
+
description: string;
|
|
174
|
+
phase: Phase;
|
|
175
|
+
status: SpecStatus;
|
|
176
|
+
requirements: Requirement[];
|
|
177
|
+
acceptanceCriteria: string[];
|
|
178
|
+
technicalNotes?: string;
|
|
179
|
+
createdAt: Date;
|
|
180
|
+
updatedAt: Date;
|
|
181
|
+
completedAt?: Date;
|
|
182
|
+
qaReport?: QAReport;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Requirement
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
interface Requirement {
|
|
190
|
+
id: string;
|
|
191
|
+
title: string;
|
|
192
|
+
given: string;
|
|
193
|
+
when: string;
|
|
194
|
+
then: string;
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### QAReport
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
interface QAReport {
|
|
202
|
+
passed: boolean;
|
|
203
|
+
notes?: string;
|
|
204
|
+
testedAt: Date;
|
|
205
|
+
testedBy?: string;
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Phase
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
type Phase = 'draft' | 'active' | 'test' | 'code' | 'qa' | 'completed' | 'archived';
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### SpecStatus
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
type SpecStatus = 'pending' | 'in-progress' | 'blocked' | 'completed';
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Usage Examples
|
|
224
|
+
|
|
225
|
+
### Basic Workflow
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
import { Workflow } from '@specsafe/core';
|
|
229
|
+
|
|
230
|
+
async function main() {
|
|
231
|
+
const workflow = new Workflow({
|
|
232
|
+
specsDir: './specs',
|
|
233
|
+
projectName: 'My App'
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Create a spec
|
|
237
|
+
await workflow.createSpec('email-validation', `
|
|
238
|
+
# Email Validation
|
|
239
|
+
|
|
240
|
+
## Requirements
|
|
241
|
+
|
|
242
|
+
### REQ-001: Valid Email Format
|
|
243
|
+
**Given** an email input field
|
|
244
|
+
**When** the user enters "user@example.com"
|
|
245
|
+
**Then** the email should be marked as valid
|
|
246
|
+
|
|
247
|
+
### REQ-002: Invalid Email Format
|
|
248
|
+
**Given** an email input field
|
|
249
|
+
**When** the user enters "invalid-email"
|
|
250
|
+
**Then** an error message should be shown
|
|
251
|
+
`);
|
|
252
|
+
|
|
253
|
+
// Move through phases
|
|
254
|
+
await workflow.moveToTest('email-validation');
|
|
255
|
+
await workflow.moveToCode('email-validation');
|
|
256
|
+
await workflow.moveToQA('email-validation', { passed: true });
|
|
257
|
+
await workflow.complete('email-validation');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
main();
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Project Statistics
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { ProjectTracker } from '@specsafe/core';
|
|
267
|
+
|
|
268
|
+
async function printStats() {
|
|
269
|
+
const tracker = new ProjectTracker('./specs');
|
|
270
|
+
const state = await tracker.getProjectState();
|
|
271
|
+
|
|
272
|
+
console.log(`Active specs: ${state.activeSpecs.length}`);
|
|
273
|
+
console.log(`Completed: ${state.completedSpecs.length}`);
|
|
274
|
+
console.log(`Archived: ${state.archivedSpecs.length}`);
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## License
|
|
281
|
+
|
|
282
|
+
MIT © Agentic Engineering
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecSafe Core - Workflow Engine and Types
|
|
3
|
+
*
|
|
4
|
+
* This package provides the core types and workflow engine for the SpecSafe
|
|
5
|
+
* Test-Driven Development framework.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Workflow, ProjectTracker } from '@specsafe/core';
|
|
10
|
+
*
|
|
11
|
+
* const workflow = new Workflow();
|
|
12
|
+
* const spec = workflow.createSpec('auth-001', 'User Authentication', '...', 'dev', 'myapp');
|
|
13
|
+
*
|
|
14
|
+
* workflow.moveToTest(spec.id);
|
|
15
|
+
* workflow.moveToCode(spec.id);
|
|
16
|
+
* workflow.moveToQA(spec.id);
|
|
17
|
+
*
|
|
18
|
+
* // After QA passes
|
|
19
|
+
* workflow.moveToComplete(spec.id, qaReport);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export type { Spec, SpecStage, Requirement, Scenario, QAReport, TestResult, CoverageReport, Issue, ProjectState, SpecSummary, ProjectMetrics } from './types.js';
|
|
23
|
+
export { Workflow } from './workflow.js';
|
|
24
|
+
export { ProjectTracker } from './tracker.js';
|
|
25
|
+
export { validateSpecId } from './validation.js';
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,YAAY,EACV,IAAI,EACJ,SAAS,EACT,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,cAAc,EACd,KAAK,EACL,YAAY,EACZ,WAAW,EACX,cAAc,EACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecSafe Core - Workflow Engine and Types
|
|
3
|
+
*
|
|
4
|
+
* This package provides the core types and workflow engine for the SpecSafe
|
|
5
|
+
* Test-Driven Development framework.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Workflow, ProjectTracker } from '@specsafe/core';
|
|
10
|
+
*
|
|
11
|
+
* const workflow = new Workflow();
|
|
12
|
+
* const spec = workflow.createSpec('auth-001', 'User Authentication', '...', 'dev', 'myapp');
|
|
13
|
+
*
|
|
14
|
+
* workflow.moveToTest(spec.id);
|
|
15
|
+
* workflow.moveToCode(spec.id);
|
|
16
|
+
* workflow.moveToQA(spec.id);
|
|
17
|
+
*
|
|
18
|
+
* // After QA passes
|
|
19
|
+
* workflow.moveToComplete(spec.id, qaReport);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
// Workflow engine
|
|
23
|
+
export { Workflow } from './workflow.js';
|
|
24
|
+
// Project tracker
|
|
25
|
+
export { ProjectTracker } from './tracker.js';
|
|
26
|
+
// Validation utilities
|
|
27
|
+
export { validateSpecId } from './validation.js';
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAiBH,kBAAkB;AAClB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,uBAAuB;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecSafe Project State Tracker
|
|
3
|
+
* Manages PROJECT_STATE.md for tracking all specs
|
|
4
|
+
*/
|
|
5
|
+
import type { Spec, ProjectState } from './types.js';
|
|
6
|
+
import type { Workflow } from './workflow.js';
|
|
7
|
+
export declare class ProjectTracker {
|
|
8
|
+
private projectPath;
|
|
9
|
+
private stateFile;
|
|
10
|
+
constructor(projectPath: string);
|
|
11
|
+
/**
|
|
12
|
+
* Initialize a new PROJECT_STATE.md
|
|
13
|
+
*/
|
|
14
|
+
initialize(projectName: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Read current project state
|
|
17
|
+
*/
|
|
18
|
+
readState(): Promise<ProjectState | null>;
|
|
19
|
+
/**
|
|
20
|
+
* Update PROJECT_STATE.md with new spec
|
|
21
|
+
*/
|
|
22
|
+
addSpec(spec: Spec): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Write state to PROJECT_STATE.md
|
|
25
|
+
*/
|
|
26
|
+
private writeState;
|
|
27
|
+
/**
|
|
28
|
+
* Generate markdown content
|
|
29
|
+
*/
|
|
30
|
+
private generateMarkdown;
|
|
31
|
+
private generateSpecsTable;
|
|
32
|
+
private getPercentage;
|
|
33
|
+
private calculateProgress;
|
|
34
|
+
private calculateMetrics;
|
|
35
|
+
private parseMarkdown;
|
|
36
|
+
/**
|
|
37
|
+
* Load all specs from PROJECT_STATE.md into a Workflow instance
|
|
38
|
+
*/
|
|
39
|
+
loadSpecsIntoWorkflow(workflow: Workflow): Promise<void>;
|
|
40
|
+
private createDefaultState;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../src/tracker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAA0C,MAAM,YAAY,CAAC;AAC7F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;gBAEd,WAAW,EAAE,MAAM;IAK/B;;OAEG;IACG,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBpD;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAiB/C;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BxC;;OAEG;YACW,UAAU;IAKxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAyCxB,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,gBAAgB;IAsCxB,OAAO,CAAC,aAAa;IAuCrB;;OAEG;IACG,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;YAwChD,kBAAkB;CAcjC"}
|
package/dist/tracker.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecSafe Project State Tracker
|
|
3
|
+
* Manages PROJECT_STATE.md for tracking all specs
|
|
4
|
+
*/
|
|
5
|
+
import { writeFile, readFile, access } from 'fs/promises';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
export class ProjectTracker {
|
|
8
|
+
projectPath;
|
|
9
|
+
stateFile;
|
|
10
|
+
constructor(projectPath) {
|
|
11
|
+
this.projectPath = projectPath;
|
|
12
|
+
this.stateFile = join(projectPath, 'PROJECT_STATE.md');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Initialize a new PROJECT_STATE.md
|
|
16
|
+
*/
|
|
17
|
+
async initialize(projectName) {
|
|
18
|
+
const state = {
|
|
19
|
+
projectName,
|
|
20
|
+
version: '1.0.0',
|
|
21
|
+
lastUpdated: new Date(),
|
|
22
|
+
specs: [],
|
|
23
|
+
metrics: {
|
|
24
|
+
totalSpecs: 0,
|
|
25
|
+
byStage: {
|
|
26
|
+
spec: 0,
|
|
27
|
+
test: 0,
|
|
28
|
+
code: 0,
|
|
29
|
+
qa: 0,
|
|
30
|
+
complete: 0,
|
|
31
|
+
archived: 0
|
|
32
|
+
},
|
|
33
|
+
completionRate: 0,
|
|
34
|
+
averageCycleTime: 0
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
await this.writeState(state);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Read current project state
|
|
41
|
+
*/
|
|
42
|
+
async readState() {
|
|
43
|
+
try {
|
|
44
|
+
await access(this.stateFile);
|
|
45
|
+
const content = await readFile(this.stateFile, 'utf-8');
|
|
46
|
+
const parsed = this.parseMarkdown(content);
|
|
47
|
+
if (parsed === null && content.length > 0) {
|
|
48
|
+
throw new Error('Failed to parse PROJECT_STATE.md - file exists but is malformed');
|
|
49
|
+
}
|
|
50
|
+
return parsed;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (error.code === 'ENOENT') {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Update PROJECT_STATE.md with new spec
|
|
61
|
+
*/
|
|
62
|
+
async addSpec(spec) {
|
|
63
|
+
const state = await this.readState() || await this.createDefaultState();
|
|
64
|
+
const summary = {
|
|
65
|
+
id: spec.id,
|
|
66
|
+
name: spec.name,
|
|
67
|
+
stage: spec.stage,
|
|
68
|
+
progress: this.calculateProgress(spec),
|
|
69
|
+
lastUpdated: spec.updatedAt,
|
|
70
|
+
createdAt: spec.createdAt,
|
|
71
|
+
completedAt: spec.completedAt
|
|
72
|
+
};
|
|
73
|
+
// Update or add spec
|
|
74
|
+
const existingIndex = state.specs.findIndex(s => s.id === spec.id);
|
|
75
|
+
if (existingIndex >= 0) {
|
|
76
|
+
// Preserve createdAt from existing summary if not set
|
|
77
|
+
if (!summary.createdAt && state.specs[existingIndex].createdAt) {
|
|
78
|
+
summary.createdAt = state.specs[existingIndex].createdAt;
|
|
79
|
+
}
|
|
80
|
+
state.specs[existingIndex] = summary;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
state.specs.push(summary);
|
|
84
|
+
}
|
|
85
|
+
state.lastUpdated = new Date();
|
|
86
|
+
state.metrics = this.calculateMetrics(state.specs);
|
|
87
|
+
await this.writeState(state);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Write state to PROJECT_STATE.md
|
|
91
|
+
*/
|
|
92
|
+
async writeState(state) {
|
|
93
|
+
const markdown = this.generateMarkdown(state);
|
|
94
|
+
await writeFile(this.stateFile, markdown, 'utf-8');
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Generate markdown content
|
|
98
|
+
*/
|
|
99
|
+
generateMarkdown(state) {
|
|
100
|
+
const date = state.lastUpdated.toISOString().split('T')[0];
|
|
101
|
+
return `# ${state.projectName} - Project State
|
|
102
|
+
|
|
103
|
+
**Version:** ${state.version}
|
|
104
|
+
**Last Updated:** ${date}
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 📊 Metrics
|
|
109
|
+
|
|
110
|
+
| Metric | Value |
|
|
111
|
+
|--------|-------|
|
|
112
|
+
| Total Specs | ${state.metrics.totalSpecs} |
|
|
113
|
+
| Completion Rate | ${(state.metrics.completionRate * 100).toFixed(1)}% |
|
|
114
|
+
| Avg Cycle Time | ${state.metrics.averageCycleTime.toFixed(1)} days |
|
|
115
|
+
|
|
116
|
+
### By Stage
|
|
117
|
+
|
|
118
|
+
| Stage | Count | Percentage |
|
|
119
|
+
|-------|-------|------------|
|
|
120
|
+
| SPEC | ${state.metrics.byStage.spec} | ${this.getPercentage(state.metrics.byStage.spec, state.metrics.totalSpecs)}% |
|
|
121
|
+
| TEST | ${state.metrics.byStage.test} | ${this.getPercentage(state.metrics.byStage.test, state.metrics.totalSpecs)}% |
|
|
122
|
+
| CODE | ${state.metrics.byStage.code} | ${this.getPercentage(state.metrics.byStage.code, state.metrics.totalSpecs)}% |
|
|
123
|
+
| QA | ${state.metrics.byStage.qa} | ${this.getPercentage(state.metrics.byStage.qa, state.metrics.totalSpecs)}% |
|
|
124
|
+
| COMPLETE | ${state.metrics.byStage.complete} | ${this.getPercentage(state.metrics.byStage.complete, state.metrics.totalSpecs)}% |
|
|
125
|
+
| ARCHIVED | ${state.metrics.byStage.archived} | ${this.getPercentage(state.metrics.byStage.archived, state.metrics.totalSpecs)}% |
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 📋 Active Specs
|
|
130
|
+
|
|
131
|
+
${this.generateSpecsTable(state.specs)}
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
*This file is auto-generated by SpecSafe*
|
|
136
|
+
`;
|
|
137
|
+
}
|
|
138
|
+
generateSpecsTable(specs) {
|
|
139
|
+
if (specs.length === 0)
|
|
140
|
+
return 'No specs yet.';
|
|
141
|
+
const rows = specs
|
|
142
|
+
.sort((a, b) => b.lastUpdated.getTime() - a.lastUpdated.getTime())
|
|
143
|
+
.map(s => `| ${s.id} | ${s.name} | ${s.stage.toUpperCase()} | ${s.progress}% | ${s.lastUpdated.toISOString().split('T')[0]} |`)
|
|
144
|
+
.join('\n');
|
|
145
|
+
return `| ID | Name | Stage | Progress | Last Updated |
|
|
146
|
+
|----|------|-------|----------|--------------|
|
|
147
|
+
${rows}`;
|
|
148
|
+
}
|
|
149
|
+
getPercentage(count, total) {
|
|
150
|
+
if (total === 0)
|
|
151
|
+
return '0.0';
|
|
152
|
+
return ((count / total) * 100).toFixed(1);
|
|
153
|
+
}
|
|
154
|
+
calculateProgress(spec) {
|
|
155
|
+
const stageWeights = {
|
|
156
|
+
spec: 20,
|
|
157
|
+
test: 40,
|
|
158
|
+
code: 60,
|
|
159
|
+
qa: 80,
|
|
160
|
+
complete: 100,
|
|
161
|
+
archived: 100
|
|
162
|
+
};
|
|
163
|
+
return stageWeights[spec.stage] || 0;
|
|
164
|
+
}
|
|
165
|
+
calculateMetrics(specs) {
|
|
166
|
+
const total = specs.length;
|
|
167
|
+
const byStage = {
|
|
168
|
+
spec: specs.filter(s => s.stage === 'spec').length,
|
|
169
|
+
test: specs.filter(s => s.stage === 'test').length,
|
|
170
|
+
code: specs.filter(s => s.stage === 'code').length,
|
|
171
|
+
qa: specs.filter(s => s.stage === 'qa').length,
|
|
172
|
+
complete: specs.filter(s => s.stage === 'complete').length,
|
|
173
|
+
archived: specs.filter(s => s.stage === 'archived').length
|
|
174
|
+
};
|
|
175
|
+
const completionRate = total > 0 ? byStage.complete / total : 0;
|
|
176
|
+
// Calculate average cycle time for completed specs (in days)
|
|
177
|
+
let totalCycleTime = 0;
|
|
178
|
+
let completedCount = 0;
|
|
179
|
+
for (const spec of specs) {
|
|
180
|
+
const isCompleted = spec.stage === 'complete' || spec.stage === 'archived';
|
|
181
|
+
if (isCompleted && spec.completedAt && spec.createdAt) {
|
|
182
|
+
const cycleTime = spec.completedAt.getTime() - spec.createdAt.getTime();
|
|
183
|
+
totalCycleTime += cycleTime;
|
|
184
|
+
completedCount++;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const averageCycleTime = completedCount > 0
|
|
188
|
+
? totalCycleTime / completedCount / (1000 * 60 * 60 * 24)
|
|
189
|
+
: 0;
|
|
190
|
+
return {
|
|
191
|
+
totalSpecs: total,
|
|
192
|
+
byStage,
|
|
193
|
+
completionRate,
|
|
194
|
+
averageCycleTime
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
parseMarkdown(content) {
|
|
198
|
+
try {
|
|
199
|
+
// Extract project name from header
|
|
200
|
+
const nameMatch = content.match(/^#\s+(.+?)\s+-\s+Project\s+State/m);
|
|
201
|
+
const projectName = nameMatch ? nameMatch[1] : 'Untitled Project';
|
|
202
|
+
// Extract version
|
|
203
|
+
const versionMatch = content.match(/\*\*Version:\*\*\s*(.+)/m);
|
|
204
|
+
const version = versionMatch ? versionMatch[1].trim() : '1.0.0';
|
|
205
|
+
// Extract specs from table
|
|
206
|
+
const specs = [];
|
|
207
|
+
const tableRegex = /\|\s*(SPEC-\d+-\d+)\s*\|\s*([^|]+)\|\s*(SPEC|TEST|CODE|QA|COMPLETE|ARCHIVED)\s*\|\s*(\d+)%?\s*\|\s*(\d{4}-\d{2}-\d{2})\s*\|/gi;
|
|
208
|
+
let match;
|
|
209
|
+
while ((match = tableRegex.exec(content)) !== null) {
|
|
210
|
+
specs.push({
|
|
211
|
+
id: match[1].trim(),
|
|
212
|
+
name: match[2].trim(),
|
|
213
|
+
stage: match[3].toLowerCase(),
|
|
214
|
+
progress: parseInt(match[4], 10),
|
|
215
|
+
lastUpdated: new Date(match[5])
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
// Calculate metrics
|
|
219
|
+
const metrics = this.calculateMetrics(specs);
|
|
220
|
+
return {
|
|
221
|
+
projectName,
|
|
222
|
+
version,
|
|
223
|
+
lastUpdated: new Date(),
|
|
224
|
+
specs,
|
|
225
|
+
metrics
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Load all specs from PROJECT_STATE.md into a Workflow instance
|
|
234
|
+
*/
|
|
235
|
+
async loadSpecsIntoWorkflow(workflow) {
|
|
236
|
+
const state = await this.readState();
|
|
237
|
+
if (!state)
|
|
238
|
+
return;
|
|
239
|
+
for (const summary of state.specs) {
|
|
240
|
+
// Try to read the actual spec file for full details
|
|
241
|
+
const dir = summary.stage === 'complete' || summary.stage === 'archived' ? 'completed' : 'active';
|
|
242
|
+
const specPath = join(this.projectPath, 'specs', dir, `${summary.id}.md`);
|
|
243
|
+
// Create spec object from summary data
|
|
244
|
+
const spec = {
|
|
245
|
+
id: summary.id,
|
|
246
|
+
name: summary.name,
|
|
247
|
+
description: '',
|
|
248
|
+
stage: summary.stage,
|
|
249
|
+
createdAt: summary.createdAt || summary.lastUpdated,
|
|
250
|
+
updatedAt: summary.lastUpdated,
|
|
251
|
+
completedAt: summary.completedAt,
|
|
252
|
+
requirements: [],
|
|
253
|
+
testFiles: [],
|
|
254
|
+
implementationFiles: [],
|
|
255
|
+
metadata: {
|
|
256
|
+
author: '',
|
|
257
|
+
project: '',
|
|
258
|
+
tags: []
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
// Try to read actual spec file for richer data
|
|
262
|
+
try {
|
|
263
|
+
await access(specPath);
|
|
264
|
+
// File exists — we could parse more details here in the future
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// Spec file not found, still load the summary-based spec
|
|
268
|
+
}
|
|
269
|
+
workflow.loadSpec(spec);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
async createDefaultState() {
|
|
273
|
+
return {
|
|
274
|
+
projectName: 'Untitled Project',
|
|
275
|
+
version: '1.0.0',
|
|
276
|
+
lastUpdated: new Date(),
|
|
277
|
+
specs: [],
|
|
278
|
+
metrics: {
|
|
279
|
+
totalSpecs: 0,
|
|
280
|
+
byStage: { spec: 0, test: 0, code: 0, qa: 0, complete: 0, archived: 0 },
|
|
281
|
+
completionRate: 0,
|
|
282
|
+
averageCycleTime: 0
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.js","sourceRoot":"","sources":["../src/tracker.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecSafe Core Types
|
|
3
|
+
* Defines the data structures for the SPEC → TEST → CODE → QA → COMPLETE workflow
|
|
4
|
+
*/
|
|
5
|
+
export type SpecStage = 'spec' | 'test' | 'code' | 'qa' | 'complete' | 'archived';
|
|
6
|
+
export interface Requirement {
|
|
7
|
+
id: string;
|
|
8
|
+
text: string;
|
|
9
|
+
priority: 'P0' | 'P1' | 'P2';
|
|
10
|
+
scenarios: Scenario[];
|
|
11
|
+
}
|
|
12
|
+
export interface Scenario {
|
|
13
|
+
id: string;
|
|
14
|
+
given: string;
|
|
15
|
+
when: string;
|
|
16
|
+
then: string;
|
|
17
|
+
}
|
|
18
|
+
export interface Spec {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
stage: SpecStage;
|
|
23
|
+
createdAt: Date;
|
|
24
|
+
updatedAt: Date;
|
|
25
|
+
completedAt?: Date;
|
|
26
|
+
requirements: Requirement[];
|
|
27
|
+
testFiles: string[];
|
|
28
|
+
implementationFiles: string[];
|
|
29
|
+
qaReport?: QAReport;
|
|
30
|
+
metadata: {
|
|
31
|
+
author: string;
|
|
32
|
+
project: string;
|
|
33
|
+
tags: string[];
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export interface QAReport {
|
|
37
|
+
id: string;
|
|
38
|
+
specId: string;
|
|
39
|
+
timestamp: Date;
|
|
40
|
+
testResults: TestResult[];
|
|
41
|
+
coverage: CoverageReport;
|
|
42
|
+
recommendation: 'GO' | 'NO-GO';
|
|
43
|
+
issues: Issue[];
|
|
44
|
+
notes: string;
|
|
45
|
+
}
|
|
46
|
+
export interface TestResult {
|
|
47
|
+
file: string;
|
|
48
|
+
passed: number;
|
|
49
|
+
failed: number;
|
|
50
|
+
skipped: number;
|
|
51
|
+
duration: number;
|
|
52
|
+
}
|
|
53
|
+
export interface CoverageReport {
|
|
54
|
+
statements: number;
|
|
55
|
+
branches: number;
|
|
56
|
+
functions: number;
|
|
57
|
+
lines: number;
|
|
58
|
+
}
|
|
59
|
+
export interface Issue {
|
|
60
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
61
|
+
description: string;
|
|
62
|
+
file?: string;
|
|
63
|
+
line?: number;
|
|
64
|
+
}
|
|
65
|
+
export interface ProjectState {
|
|
66
|
+
projectName: string;
|
|
67
|
+
version: string;
|
|
68
|
+
lastUpdated: Date;
|
|
69
|
+
specs: SpecSummary[];
|
|
70
|
+
metrics: ProjectMetrics;
|
|
71
|
+
}
|
|
72
|
+
export interface SpecSummary {
|
|
73
|
+
id: string;
|
|
74
|
+
name: string;
|
|
75
|
+
stage: SpecStage;
|
|
76
|
+
progress: number;
|
|
77
|
+
lastUpdated: Date;
|
|
78
|
+
createdAt?: Date;
|
|
79
|
+
completedAt?: Date;
|
|
80
|
+
}
|
|
81
|
+
export interface ProjectMetrics {
|
|
82
|
+
totalSpecs: number;
|
|
83
|
+
byStage: Record<SpecStage, number>;
|
|
84
|
+
completionRate: number;
|
|
85
|
+
averageCycleTime: number;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,UAAU,GAAG,UAAU,CAAC;AAElF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,QAAQ,EAAE,cAAc,CAAC;IACzB,cAAc,EAAE,IAAI,GAAG,OAAO,CAAC;IAC/B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,IAAI,CAAC;IAClB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,OAAO,EAAE,cAAc,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation utilities for SpecSafe
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Validates that a spec ID matches the required format: SPEC-YYYYMMDD-NNN
|
|
6
|
+
* @param id - The spec ID to validate
|
|
7
|
+
* @throws Error if the ID is invalid
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateSpecId(id: string): void;
|
|
10
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAiB/C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation utilities for SpecSafe
|
|
3
|
+
*/
|
|
4
|
+
const SPEC_ID_REGEX = /^SPEC-\d{8}-\d{3}$/;
|
|
5
|
+
/**
|
|
6
|
+
* Validates that a spec ID matches the required format: SPEC-YYYYMMDD-NNN
|
|
7
|
+
* @param id - The spec ID to validate
|
|
8
|
+
* @throws Error if the ID is invalid
|
|
9
|
+
*/
|
|
10
|
+
export function validateSpecId(id) {
|
|
11
|
+
if (!id || typeof id !== 'string') {
|
|
12
|
+
throw new Error('Spec ID is required and must be a string');
|
|
13
|
+
}
|
|
14
|
+
if (!SPEC_ID_REGEX.test(id)) {
|
|
15
|
+
throw new Error(`Invalid spec ID format: "${id}". Expected format: SPEC-YYYYMMDD-NNN (e.g., SPEC-20250211-001)`);
|
|
16
|
+
}
|
|
17
|
+
// Validate the date portion is a real date
|
|
18
|
+
const dateStr = id.substring(5, 13); // YYYYMMDD
|
|
19
|
+
const year = parseInt(dateStr.substring(0, 4), 10);
|
|
20
|
+
const month = parseInt(dateStr.substring(4, 6), 10);
|
|
21
|
+
const day = parseInt(dateStr.substring(6, 8), 10);
|
|
22
|
+
const date = new Date(year, month - 1, day);
|
|
23
|
+
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
|
|
24
|
+
throw new Error(`Invalid spec ID "${id}": contains invalid date ${dateStr}. Expected format: SPEC-YYYYMMDD-NNN`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAE3C;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,EAAU;IACvC,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,4BAA4B,EAAE,iEAAiE,CAAC,CAAC;IACnH,CAAC;IAED,2CAA2C;IAC3C,MAAM,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW;IAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,EAAE,CAAC;QAC3F,MAAM,IAAI,KAAK,CAAC,oBAAoB,EAAE,4BAA4B,OAAO,sCAAsC,CAAC,CAAC;IACnH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecSafe Workflow Engine
|
|
3
|
+
* Manages the 5-stage development cycle: SPEC → TEST → CODE → QA → COMPLETE
|
|
4
|
+
*/
|
|
5
|
+
import type { Spec, SpecStage, QAReport } from './types.js';
|
|
6
|
+
export declare class Workflow {
|
|
7
|
+
private specs;
|
|
8
|
+
/**
|
|
9
|
+
* Create a new spec in the SPEC stage
|
|
10
|
+
*/
|
|
11
|
+
createSpec(id: string, name: string, description: string, author: string, project: string): Spec;
|
|
12
|
+
/**
|
|
13
|
+
* Get a spec by ID
|
|
14
|
+
*/
|
|
15
|
+
getSpec(id: string): Spec | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Load an existing spec into the workflow (for hydration from disk)
|
|
18
|
+
*/
|
|
19
|
+
loadSpec(spec: Spec): void;
|
|
20
|
+
/**
|
|
21
|
+
* Get all specs
|
|
22
|
+
*/
|
|
23
|
+
getAllSpecs(): Spec[];
|
|
24
|
+
/**
|
|
25
|
+
* Get specs by stage
|
|
26
|
+
*/
|
|
27
|
+
getSpecsByStage(stage: SpecStage): Spec[];
|
|
28
|
+
/**
|
|
29
|
+
* Transition spec to TEST stage
|
|
30
|
+
* Requirements must be defined
|
|
31
|
+
*/
|
|
32
|
+
moveToTest(specId: string): Spec;
|
|
33
|
+
/**
|
|
34
|
+
* Transition spec to CODE stage
|
|
35
|
+
* Tests must be generated
|
|
36
|
+
*/
|
|
37
|
+
moveToCode(specId: string): Spec;
|
|
38
|
+
/**
|
|
39
|
+
* Transition spec to QA stage
|
|
40
|
+
* Implementation must be complete
|
|
41
|
+
*/
|
|
42
|
+
moveToQA(specId: string): Spec;
|
|
43
|
+
/**
|
|
44
|
+
* Transition spec to COMPLETE stage
|
|
45
|
+
* QA report must be provided with GO recommendation
|
|
46
|
+
*/
|
|
47
|
+
moveToComplete(specId: string, qaReport: QAReport): Spec;
|
|
48
|
+
/**
|
|
49
|
+
* Archive a completed spec
|
|
50
|
+
*/
|
|
51
|
+
archiveSpec(specId: string): Spec;
|
|
52
|
+
/**
|
|
53
|
+
* Get workflow status summary
|
|
54
|
+
*/
|
|
55
|
+
getStatus(): {
|
|
56
|
+
stage: SpecStage;
|
|
57
|
+
count: number;
|
|
58
|
+
}[];
|
|
59
|
+
/**
|
|
60
|
+
* Validate stage transition
|
|
61
|
+
*/
|
|
62
|
+
canTransition(specId: string, toStage: SpecStage): {
|
|
63
|
+
valid: boolean;
|
|
64
|
+
reason?: string;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE5D,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAAgC;IAE7C;;OAEG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IA0BhG;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIrC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAI1B;;OAEG;IACH,WAAW,IAAI,IAAI,EAAE;IAIrB;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,EAAE;IAIzC;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAehC;;;OAGG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAehC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAe9B;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAqBxD;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAYjC;;OAEG;IACH,SAAS,IAAI;QAAE,KAAK,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE;IAQlD;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAgCvF"}
|
package/dist/workflow.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecSafe Workflow Engine
|
|
3
|
+
* Manages the 5-stage development cycle: SPEC → TEST → CODE → QA → COMPLETE
|
|
4
|
+
*/
|
|
5
|
+
export class Workflow {
|
|
6
|
+
specs = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Create a new spec in the SPEC stage
|
|
9
|
+
*/
|
|
10
|
+
createSpec(id, name, description, author, project) {
|
|
11
|
+
// Check if spec already exists to prevent overwriting
|
|
12
|
+
if (this.specs.has(id)) {
|
|
13
|
+
throw new Error(`Spec with ID ${id} already exists. Use a different name or delete the existing spec first.`);
|
|
14
|
+
}
|
|
15
|
+
const spec = {
|
|
16
|
+
id,
|
|
17
|
+
name,
|
|
18
|
+
description,
|
|
19
|
+
stage: 'spec',
|
|
20
|
+
createdAt: new Date(),
|
|
21
|
+
updatedAt: new Date(),
|
|
22
|
+
requirements: [],
|
|
23
|
+
testFiles: [],
|
|
24
|
+
implementationFiles: [],
|
|
25
|
+
metadata: {
|
|
26
|
+
author,
|
|
27
|
+
project,
|
|
28
|
+
tags: []
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
this.specs.set(id, spec);
|
|
32
|
+
return spec;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get a spec by ID
|
|
36
|
+
*/
|
|
37
|
+
getSpec(id) {
|
|
38
|
+
return this.specs.get(id);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Load an existing spec into the workflow (for hydration from disk)
|
|
42
|
+
*/
|
|
43
|
+
loadSpec(spec) {
|
|
44
|
+
this.specs.set(spec.id, spec);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get all specs
|
|
48
|
+
*/
|
|
49
|
+
getAllSpecs() {
|
|
50
|
+
return Array.from(this.specs.values());
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get specs by stage
|
|
54
|
+
*/
|
|
55
|
+
getSpecsByStage(stage) {
|
|
56
|
+
return this.getAllSpecs().filter(s => s.stage === stage);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Transition spec to TEST stage
|
|
60
|
+
* Requirements must be defined
|
|
61
|
+
*/
|
|
62
|
+
moveToTest(specId) {
|
|
63
|
+
const spec = this.getSpec(specId);
|
|
64
|
+
if (!spec)
|
|
65
|
+
throw new Error(`Spec ${specId} not found`);
|
|
66
|
+
if (spec.stage !== 'spec') {
|
|
67
|
+
throw new Error(`Cannot move to TEST from ${spec.stage}. Must be in SPEC stage.`);
|
|
68
|
+
}
|
|
69
|
+
if (spec.requirements.length === 0) {
|
|
70
|
+
throw new Error('Cannot move to TEST: No requirements defined');
|
|
71
|
+
}
|
|
72
|
+
spec.stage = 'test';
|
|
73
|
+
spec.updatedAt = new Date();
|
|
74
|
+
return spec;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Transition spec to CODE stage
|
|
78
|
+
* Tests must be generated
|
|
79
|
+
*/
|
|
80
|
+
moveToCode(specId) {
|
|
81
|
+
const spec = this.getSpec(specId);
|
|
82
|
+
if (!spec)
|
|
83
|
+
throw new Error(`Spec ${specId} not found`);
|
|
84
|
+
if (spec.stage !== 'test') {
|
|
85
|
+
throw new Error(`Cannot move to CODE from ${spec.stage}. Must be in TEST stage.`);
|
|
86
|
+
}
|
|
87
|
+
if (spec.testFiles.length === 0) {
|
|
88
|
+
throw new Error('Cannot move to CODE: No test files generated');
|
|
89
|
+
}
|
|
90
|
+
spec.stage = 'code';
|
|
91
|
+
spec.updatedAt = new Date();
|
|
92
|
+
return spec;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Transition spec to QA stage
|
|
96
|
+
* Implementation must be complete
|
|
97
|
+
*/
|
|
98
|
+
moveToQA(specId) {
|
|
99
|
+
const spec = this.getSpec(specId);
|
|
100
|
+
if (!spec)
|
|
101
|
+
throw new Error(`Spec ${specId} not found`);
|
|
102
|
+
if (spec.stage !== 'code') {
|
|
103
|
+
throw new Error(`Cannot move to QA from ${spec.stage}. Must be in CODE stage.`);
|
|
104
|
+
}
|
|
105
|
+
if (spec.implementationFiles.length === 0) {
|
|
106
|
+
throw new Error('Cannot move to QA: No implementation files');
|
|
107
|
+
}
|
|
108
|
+
spec.stage = 'qa';
|
|
109
|
+
spec.updatedAt = new Date();
|
|
110
|
+
return spec;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Transition spec to COMPLETE stage
|
|
114
|
+
* QA report must be provided with GO recommendation
|
|
115
|
+
*/
|
|
116
|
+
moveToComplete(specId, qaReport) {
|
|
117
|
+
const spec = this.getSpec(specId);
|
|
118
|
+
if (!spec)
|
|
119
|
+
throw new Error(`Spec ${specId} not found`);
|
|
120
|
+
if (spec.stage !== 'qa') {
|
|
121
|
+
throw new Error(`Cannot move to COMPLETE from ${spec.stage}. Must be in QA stage.`);
|
|
122
|
+
}
|
|
123
|
+
// Validate QA report belongs to target spec
|
|
124
|
+
if (qaReport.specId !== specId) {
|
|
125
|
+
throw new Error(`QA report spec ID (${qaReport.specId}) does not match target spec (${specId})`);
|
|
126
|
+
}
|
|
127
|
+
if (qaReport.recommendation !== 'GO') {
|
|
128
|
+
throw new Error('Cannot complete: QA report recommends NO-GO. Address issues first.');
|
|
129
|
+
}
|
|
130
|
+
spec.stage = 'complete';
|
|
131
|
+
spec.qaReport = qaReport;
|
|
132
|
+
spec.completedAt = new Date();
|
|
133
|
+
spec.updatedAt = new Date();
|
|
134
|
+
return spec;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Archive a completed spec
|
|
138
|
+
*/
|
|
139
|
+
archiveSpec(specId) {
|
|
140
|
+
const spec = this.getSpec(specId);
|
|
141
|
+
if (!spec)
|
|
142
|
+
throw new Error(`Spec ${specId} not found`);
|
|
143
|
+
if (spec.stage !== 'complete') {
|
|
144
|
+
throw new Error(`Cannot archive spec in ${spec.stage} stage. Must be COMPLETE.`);
|
|
145
|
+
}
|
|
146
|
+
spec.stage = 'archived';
|
|
147
|
+
spec.updatedAt = new Date();
|
|
148
|
+
return spec;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get workflow status summary
|
|
152
|
+
*/
|
|
153
|
+
getStatus() {
|
|
154
|
+
const stages = ['spec', 'test', 'code', 'qa', 'complete', 'archived'];
|
|
155
|
+
return stages.map(stage => ({
|
|
156
|
+
stage,
|
|
157
|
+
count: this.getSpecsByStage(stage).length
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Validate stage transition
|
|
162
|
+
*/
|
|
163
|
+
canTransition(specId, toStage) {
|
|
164
|
+
const spec = this.getSpec(specId);
|
|
165
|
+
if (!spec)
|
|
166
|
+
return { valid: false, reason: 'Spec not found' };
|
|
167
|
+
const transitions = {
|
|
168
|
+
spec: ['test'],
|
|
169
|
+
test: ['code'],
|
|
170
|
+
code: ['qa'],
|
|
171
|
+
qa: ['complete'],
|
|
172
|
+
complete: ['archived'],
|
|
173
|
+
archived: []
|
|
174
|
+
};
|
|
175
|
+
if (!transitions[spec.stage].includes(toStage)) {
|
|
176
|
+
return { valid: false, reason: `Cannot transition from ${spec.stage} to ${toStage}` };
|
|
177
|
+
}
|
|
178
|
+
// Validate prerequisites based on target stage
|
|
179
|
+
if (toStage === 'test' && spec.requirements.length === 0) {
|
|
180
|
+
return { valid: false, reason: 'Cannot move to TEST: No requirements defined' };
|
|
181
|
+
}
|
|
182
|
+
if (toStage === 'code' && spec.testFiles.length === 0) {
|
|
183
|
+
return { valid: false, reason: 'Cannot move to CODE: No test files generated' };
|
|
184
|
+
}
|
|
185
|
+
if (toStage === 'qa' && spec.implementationFiles.length === 0) {
|
|
186
|
+
return { valid: false, reason: 'Cannot move to QA: No implementation files' };
|
|
187
|
+
}
|
|
188
|
+
// Note: 'complete' transition requires a QA report, but that's validated in moveToComplete()
|
|
189
|
+
// since canTransition() doesn't have access to the QAReport parameter
|
|
190
|
+
return { valid: true };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.js","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@specsafe/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core types and workflow engine for SpecSafe",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^20.0.0",
|
|
27
|
+
"typescript": "^5.3.0",
|
|
28
|
+
"vitest": "^1.0.0"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"dev": "tsc --watch",
|
|
33
|
+
"test": "vitest --passWithNoTests",
|
|
34
|
+
"typecheck": "tsc --noEmit"
|
|
35
|
+
}
|
|
36
|
+
}
|