sysprom 1.2.0 → 1.2.1
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/README.md +1 -0
- package/dist/src/canonical-json.d.ts +0 -1
- package/dist/src/canonical-json.js +0 -1
- package/dist/src/cli/define-command.d.ts +15 -0
- package/dist/src/cli/define-command.js +11 -0
- package/dist/src/cli/shared.d.ts +17 -2
- package/dist/src/cli/shared.js +14 -2
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.js +0 -1
- package/dist/src/io.d.ts +0 -2
- package/dist/src/io.js +0 -2
- package/dist/src/json-to-md.d.ts +0 -3
- package/dist/src/json-to-md.js +0 -3
- package/dist/src/md-to-json.d.ts +0 -3
- package/dist/src/md-to-json.js +0 -3
- package/dist/src/operations/add-node.d.ts +1 -2
- package/dist/src/operations/add-node.js +1 -2
- package/dist/src/operations/add-plan-task.d.ts +1 -2
- package/dist/src/operations/add-plan-task.js +1 -2
- package/dist/src/operations/add-relationship.d.ts +1 -2
- package/dist/src/operations/add-relationship.js +1 -2
- package/dist/src/operations/define-operation.d.ts +5 -8
- package/dist/src/operations/define-operation.js +1 -2
- package/dist/src/operations/mark-task-done.d.ts +1 -2
- package/dist/src/operations/mark-task-done.js +1 -2
- package/dist/src/operations/mark-task-undone.d.ts +1 -2
- package/dist/src/operations/mark-task-undone.js +1 -2
- package/dist/src/operations/next-id.d.ts +1 -2
- package/dist/src/operations/next-id.js +1 -2
- package/dist/src/operations/remove-node.d.ts +1 -2
- package/dist/src/operations/remove-node.js +1 -2
- package/dist/src/operations/remove-relationship.d.ts +1 -2
- package/dist/src/operations/remove-relationship.js +1 -2
- package/dist/src/operations/rename.d.ts +1 -2
- package/dist/src/operations/rename.js +1 -2
- package/dist/src/operations/task-list.d.ts +1 -2
- package/dist/src/operations/task-list.js +1 -2
- package/dist/src/operations/update-node.d.ts +1 -2
- package/dist/src/operations/update-node.js +1 -2
- package/dist/src/operations/update-plan-task.d.ts +1 -2
- package/dist/src/operations/update-plan-task.js +1 -2
- package/dist/src/schema.d.ts +4 -1
- package/dist/src/schema.js +4 -1
- package/dist/src/speckit/generate.d.ts +36 -6
- package/dist/src/speckit/generate.js +58 -6
- package/dist/src/speckit/parse.d.ts +37 -6
- package/dist/src/speckit/parse.js +53 -6
- package/dist/src/speckit/plan.d.ts +22 -0
- package/dist/src/speckit/plan.js +53 -0
- package/dist/src/speckit/project.d.ts +9 -0
- package/dist/src/speckit/project.js +17 -0
- package/dist/src/text.d.ts +6 -4
- package/dist/src/text.js +6 -4
- package/package.json +2 -1
package/dist/src/schema.d.ts
CHANGED
|
@@ -930,6 +930,9 @@ export type Node = z.infer<typeof Node>;
|
|
|
930
930
|
export declare const NODE_FILE_MAP: Record<string, string[]>;
|
|
931
931
|
/** Conventional ID prefix for each node type. */
|
|
932
932
|
export declare const NODE_ID_PREFIX: Record<string, string>;
|
|
933
|
-
/**
|
|
933
|
+
/**
|
|
934
|
+
* Generate the JSON Schema representation of the SysProM document schema.
|
|
935
|
+
* @returns The JSON Schema object with Draft 2020-12 metadata.
|
|
936
|
+
*/
|
|
934
937
|
export declare function toJSONSchema(): Record<string, unknown>;
|
|
935
938
|
export {};
|
package/dist/src/schema.js
CHANGED
|
@@ -371,7 +371,10 @@ export const NODE_ID_PREFIX = {
|
|
|
371
371
|
function isRecord(value) {
|
|
372
372
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
373
373
|
}
|
|
374
|
-
/**
|
|
374
|
+
/**
|
|
375
|
+
* Generate the JSON Schema representation of the SysProM document schema.
|
|
376
|
+
* @returns The JSON Schema object with Draft 2020-12 metadata.
|
|
377
|
+
*/
|
|
375
378
|
export function toJSONSchema() {
|
|
376
379
|
const generated = z.toJSONSchema(SysProMDocument, {
|
|
377
380
|
target: "draft-2020-12",
|
|
@@ -1,13 +1,43 @@
|
|
|
1
1
|
import type { SysProMDocument } from "../schema.js";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Generate a Spec-Kit constitution file from a SysProM document's principles and invariants.
|
|
4
|
+
* @param doc - The SysProM document.
|
|
5
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
6
|
+
* @returns The generated markdown.
|
|
7
|
+
*/
|
|
3
8
|
export declare function generateConstitution(doc: SysProMDocument, prefix: string): string;
|
|
4
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Generate a Spec-Kit specification file from a SysProM document's user stories, FRs, and acceptance criteria.
|
|
11
|
+
* @param doc - The SysProM document.
|
|
12
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
13
|
+
* @returns The generated markdown.
|
|
14
|
+
*/
|
|
5
15
|
export declare function generateSpec(doc: SysProMDocument, prefix: string): string;
|
|
6
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Generate a Spec-Kit plan file from a SysProM document's phases and milestones.
|
|
18
|
+
* @param doc - The SysProM document.
|
|
19
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
20
|
+
* @returns The generated markdown.
|
|
21
|
+
*/
|
|
7
22
|
export declare function generatePlan(doc: SysProMDocument, prefix: string): string;
|
|
8
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Generate a Spec-Kit tasks file from a SysProM document's change nodes.
|
|
25
|
+
* @param doc - The SysProM document.
|
|
26
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
27
|
+
* @returns The generated markdown.
|
|
28
|
+
*/
|
|
9
29
|
export declare function generateTasks(doc: SysProMDocument, prefix: string): string;
|
|
10
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Generate a Spec-Kit checklist file from a SysProM document's gate nodes.
|
|
32
|
+
* @param doc - The SysProM document.
|
|
33
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
34
|
+
* @returns The generated markdown.
|
|
35
|
+
*/
|
|
11
36
|
export declare function generateChecklist(doc: SysProMDocument, prefix: string): string;
|
|
12
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Generate a complete Spec-Kit project directory from a SysProM document — constitution, spec, plan, tasks, and checklist files.
|
|
39
|
+
* @param doc - The SysProM document.
|
|
40
|
+
* @param outputDir - Output directory path.
|
|
41
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
42
|
+
*/
|
|
13
43
|
export declare function generateSpecKitProject(doc: SysProMDocument, outputDir: string, prefix: string): void;
|
|
@@ -6,18 +6,28 @@ import { textToString } from "../text.js";
|
|
|
6
6
|
// ============================================================================
|
|
7
7
|
/**
|
|
8
8
|
* Find a single node by ID, or null if not found.
|
|
9
|
+
* @param doc - The document to search.
|
|
10
|
+
* @param id - The node ID to find.
|
|
11
|
+
* @returns The matching node, or null.
|
|
9
12
|
*/
|
|
10
13
|
function findNode(doc, id) {
|
|
11
14
|
return doc.nodes.find((n) => n.id === id) ?? null;
|
|
12
15
|
}
|
|
13
16
|
/**
|
|
14
17
|
* Find all nodes of a specific type.
|
|
18
|
+
* @param doc - The document to search.
|
|
19
|
+
* @param type - The node type to filter by.
|
|
20
|
+
* @returns Matching nodes.
|
|
15
21
|
*/
|
|
16
22
|
function findNodesByType(doc, type) {
|
|
17
23
|
return doc.nodes.filter((n) => n.type === type);
|
|
18
24
|
}
|
|
19
25
|
/**
|
|
20
26
|
* Find relationships from a source node to nodes of a target type.
|
|
27
|
+
* @param doc - The document to search.
|
|
28
|
+
* @param fromId - Source node ID.
|
|
29
|
+
* @param relationType - Optional relationship type filter.
|
|
30
|
+
* @returns Matching relationships.
|
|
21
31
|
*/
|
|
22
32
|
function findRelationshipsFrom(doc, fromId, relationType) {
|
|
23
33
|
return (doc.relationships ?? []).filter((r) => {
|
|
@@ -30,6 +40,10 @@ function findRelationshipsFrom(doc, fromId, relationType) {
|
|
|
30
40
|
}
|
|
31
41
|
/**
|
|
32
42
|
* Find relationships to a target node.
|
|
43
|
+
* @param doc - The document to search.
|
|
44
|
+
* @param toId - Target node ID.
|
|
45
|
+
* @param relationType - Optional relationship type filter.
|
|
46
|
+
* @returns Matching relationships.
|
|
33
47
|
*/
|
|
34
48
|
function findRelationshipsTo(doc, toId, relationType) {
|
|
35
49
|
return (doc.relationships ?? []).filter((r) => {
|
|
@@ -43,6 +57,8 @@ function findRelationshipsTo(doc, toId, relationType) {
|
|
|
43
57
|
/**
|
|
44
58
|
* Extract priority from a node's name, description, or lifecycle fields.
|
|
45
59
|
* Looks for patterns like "P1", "P2", "Priority: P1", etc.
|
|
60
|
+
* @param node - The node to extract priority from.
|
|
61
|
+
* @returns Priority string (e.g. "P1").
|
|
46
62
|
*/
|
|
47
63
|
function extractPriority(node) {
|
|
48
64
|
const text = [
|
|
@@ -57,6 +73,8 @@ function extractPriority(node) {
|
|
|
57
73
|
}
|
|
58
74
|
/**
|
|
59
75
|
* Extract numeric suffix from an ID (e.g., "PREFIX-SPEC-001" -> "001").
|
|
76
|
+
* @param id - The node ID.
|
|
77
|
+
* @returns The numeric suffix.
|
|
60
78
|
*/
|
|
61
79
|
function getIdSuffix(id) {
|
|
62
80
|
const parts = id.split("-");
|
|
@@ -64,6 +82,8 @@ function getIdSuffix(id) {
|
|
|
64
82
|
}
|
|
65
83
|
/**
|
|
66
84
|
* Parse tasks from a change node's plan array.
|
|
85
|
+
* @param node - The change node.
|
|
86
|
+
* @returns Array of task descriptions and done flags.
|
|
67
87
|
*/
|
|
68
88
|
function parseTasks(node) {
|
|
69
89
|
return (node.plan ?? []).map((task) => ({
|
|
@@ -73,6 +93,8 @@ function parseTasks(node) {
|
|
|
73
93
|
}
|
|
74
94
|
/**
|
|
75
95
|
* Format the status for spec output: "proposed" -> "Draft", etc.
|
|
96
|
+
* @param status - The node status string.
|
|
97
|
+
* @returns Formatted status label.
|
|
76
98
|
*/
|
|
77
99
|
function formatStatus(status) {
|
|
78
100
|
if (!status)
|
|
@@ -87,7 +109,12 @@ function formatStatus(status) {
|
|
|
87
109
|
// ============================================================================
|
|
88
110
|
// generate Constitution
|
|
89
111
|
// ============================================================================
|
|
90
|
-
/**
|
|
112
|
+
/**
|
|
113
|
+
* Generate a Spec-Kit constitution file from a SysProM document's principles and invariants.
|
|
114
|
+
* @param doc - The SysProM document.
|
|
115
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
116
|
+
* @returns The generated markdown.
|
|
117
|
+
*/
|
|
91
118
|
export function generateConstitution(doc, prefix) {
|
|
92
119
|
const protocolId = `${prefix}-CONST`;
|
|
93
120
|
const protocol = findNode(doc, protocolId);
|
|
@@ -160,7 +187,12 @@ export function generateConstitution(doc, prefix) {
|
|
|
160
187
|
// ============================================================================
|
|
161
188
|
// generateSpec
|
|
162
189
|
// ============================================================================
|
|
163
|
-
/**
|
|
190
|
+
/**
|
|
191
|
+
* Generate a Spec-Kit specification file from a SysProM document's user stories, FRs, and acceptance criteria.
|
|
192
|
+
* @param doc - The SysProM document.
|
|
193
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
194
|
+
* @returns The generated markdown.
|
|
195
|
+
*/
|
|
164
196
|
export function generateSpec(doc, prefix) {
|
|
165
197
|
const specId = `${prefix}-SPEC`;
|
|
166
198
|
const spec = findNode(doc, specId);
|
|
@@ -274,7 +306,12 @@ export function generateSpec(doc, prefix) {
|
|
|
274
306
|
// ============================================================================
|
|
275
307
|
// generatePlan
|
|
276
308
|
// ============================================================================
|
|
277
|
-
/**
|
|
309
|
+
/**
|
|
310
|
+
* Generate a Spec-Kit plan file from a SysProM document's phases and milestones.
|
|
311
|
+
* @param doc - The SysProM document.
|
|
312
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
313
|
+
* @returns The generated markdown.
|
|
314
|
+
*/
|
|
278
315
|
export function generatePlan(doc, prefix) {
|
|
279
316
|
const implProtocolId = `${prefix}-PROT-IMPL`;
|
|
280
317
|
const protocol = findNode(doc, implProtocolId);
|
|
@@ -325,7 +362,12 @@ export function generatePlan(doc, prefix) {
|
|
|
325
362
|
// ============================================================================
|
|
326
363
|
// generateTasks
|
|
327
364
|
// ============================================================================
|
|
328
|
-
/**
|
|
365
|
+
/**
|
|
366
|
+
* Generate a Spec-Kit tasks file from a SysProM document's change nodes.
|
|
367
|
+
* @param doc - The SysProM document.
|
|
368
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
369
|
+
* @returns The generated markdown.
|
|
370
|
+
*/
|
|
329
371
|
export function generateTasks(doc, prefix) {
|
|
330
372
|
const implProtocolId = `${prefix}-PROT-IMPL`;
|
|
331
373
|
const protocol = findNode(doc, implProtocolId);
|
|
@@ -465,7 +507,12 @@ export function generateTasks(doc, prefix) {
|
|
|
465
507
|
// ============================================================================
|
|
466
508
|
// generateChecklist
|
|
467
509
|
// ============================================================================
|
|
468
|
-
/**
|
|
510
|
+
/**
|
|
511
|
+
* Generate a Spec-Kit checklist file from a SysProM document's gate nodes.
|
|
512
|
+
* @param doc - The SysProM document.
|
|
513
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
514
|
+
* @returns The generated markdown.
|
|
515
|
+
*/
|
|
469
516
|
export function generateChecklist(doc, prefix) {
|
|
470
517
|
const gateId = `${prefix}-CHK`;
|
|
471
518
|
const gate = findNode(doc, gateId);
|
|
@@ -520,7 +567,12 @@ export function generateChecklist(doc, prefix) {
|
|
|
520
567
|
// ============================================================================
|
|
521
568
|
// generateSpecKitProject
|
|
522
569
|
// ============================================================================
|
|
523
|
-
/**
|
|
570
|
+
/**
|
|
571
|
+
* Generate a complete Spec-Kit project directory from a SysProM document — constitution, spec, plan, tasks, and checklist files.
|
|
572
|
+
* @param doc - The SysProM document.
|
|
573
|
+
* @param outputDir - Output directory path.
|
|
574
|
+
* @param prefix - ID prefix identifying nodes to include.
|
|
575
|
+
*/
|
|
524
576
|
export function generateSpecKitProject(doc, outputDir, prefix) {
|
|
525
577
|
// Create output directory if it doesn't exist
|
|
526
578
|
mkdirSync(outputDir, { recursive: true });
|
|
@@ -6,15 +6,46 @@ export interface ParseResult {
|
|
|
6
6
|
/** Relationships extracted from the parsed content. */
|
|
7
7
|
relationships: Relationship[];
|
|
8
8
|
}
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Parse a Spec-Kit constitution file into SysProM nodes (principles and invariants) and relationships.
|
|
11
|
+
* @param content - Markdown file content.
|
|
12
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
13
|
+
* @returns The result.
|
|
14
|
+
*/
|
|
10
15
|
export declare function parseConstitution(content: string, idPrefix: string): ParseResult;
|
|
11
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Parse a Spec-Kit specification file into SysProM nodes (user stories, functional requirements, acceptance criteria).
|
|
18
|
+
* @param content - Markdown file content.
|
|
19
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
20
|
+
* @returns The result.
|
|
21
|
+
*/
|
|
12
22
|
export declare function parseSpec(content: string, idPrefix: string): ParseResult;
|
|
13
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Parse a Spec-Kit plan file into SysProM nodes (phases, milestones) and relationships.
|
|
25
|
+
* @param content - Markdown file content.
|
|
26
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
27
|
+
* @returns The result.
|
|
28
|
+
*/
|
|
14
29
|
export declare function parsePlan(content: string, idPrefix: string): ParseResult;
|
|
15
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Parse a Spec-Kit tasks file into SysProM change nodes with task plans.
|
|
32
|
+
* @param content - Markdown file content.
|
|
33
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
34
|
+
* @returns The result.
|
|
35
|
+
*/
|
|
16
36
|
export declare function parseTasks(content: string, idPrefix: string): ParseResult;
|
|
17
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Parse a Spec-Kit checklist file into SysProM gate nodes with task plans.
|
|
39
|
+
* @param content - Markdown file content.
|
|
40
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
41
|
+
* @returns The result.
|
|
42
|
+
*/
|
|
18
43
|
export declare function parseChecklist(content: string, idPrefix: string): ParseResult;
|
|
19
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Parse an entire Spec-Kit feature directory into a SysProM document, combining constitution, spec, plan, tasks, and checklist.
|
|
46
|
+
* @param featureDir - Path to Spec-Kit feature directory.
|
|
47
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
48
|
+
* @param constitutionPath - Path to constitution.md, or undefined.
|
|
49
|
+
* @returns The parsed SysProM document.
|
|
50
|
+
*/
|
|
20
51
|
export declare function parseSpecKitFeature(featureDir: string, idPrefix: string, constitutionPath?: string): SysProMDocument;
|
|
@@ -5,6 +5,8 @@ import { join, basename } from "node:path";
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
/**
|
|
7
7
|
* Parse markdown content into a hierarchical section tree by heading level.
|
|
8
|
+
* @param body - Markdown body text.
|
|
9
|
+
* @returns The result.
|
|
8
10
|
*/
|
|
9
11
|
function parseSections(body) {
|
|
10
12
|
const lines = body.split("\n");
|
|
@@ -49,6 +51,8 @@ function parseSections(body) {
|
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
51
53
|
* Extract bold key-value pairs from markdown like "**Key**: value" or "**Key**: value text".
|
|
54
|
+
* @param content - Markdown file content.
|
|
55
|
+
* @returns The result.
|
|
52
56
|
*/
|
|
53
57
|
function parseFrontMatterish(content) {
|
|
54
58
|
const result = {};
|
|
@@ -64,6 +68,8 @@ function parseFrontMatterish(content) {
|
|
|
64
68
|
}
|
|
65
69
|
/**
|
|
66
70
|
* Parse checkbox lines like "- [x] ID text" or "- [ ] ID text".
|
|
71
|
+
* @param body - Markdown body text.
|
|
72
|
+
* @returns The result.
|
|
67
73
|
*/
|
|
68
74
|
function parseCheckboxes(body) {
|
|
69
75
|
const items = [];
|
|
@@ -84,6 +90,8 @@ function parseCheckboxes(body) {
|
|
|
84
90
|
}
|
|
85
91
|
/**
|
|
86
92
|
* Flatten all sections in the tree into a single array for easier searching.
|
|
93
|
+
* @param sections - Parsed section tree.
|
|
94
|
+
* @returns The result.
|
|
87
95
|
*/
|
|
88
96
|
function flattenSections(sections) {
|
|
89
97
|
const result = [];
|
|
@@ -98,12 +106,17 @@ function flattenSections(sections) {
|
|
|
98
106
|
}
|
|
99
107
|
/**
|
|
100
108
|
* Find the first section whose heading matches a predicate (searches entire tree).
|
|
109
|
+
* @param sections - Parsed section tree.
|
|
110
|
+
* @param predicate - Filter function.
|
|
111
|
+
* @returns The result.
|
|
101
112
|
*/
|
|
102
113
|
function findSection(sections, predicate) {
|
|
103
114
|
return flattenSections(sections).find((s) => predicate(s.heading));
|
|
104
115
|
}
|
|
105
116
|
/**
|
|
106
117
|
* Convert status-like strings to NodeStatus. Recognizes common spec-kit patterns.
|
|
118
|
+
* @param value - Raw status string.
|
|
119
|
+
* @returns The result.
|
|
107
120
|
*/
|
|
108
121
|
function mapStatusValue(value) {
|
|
109
122
|
const lower = value.toLowerCase().trim();
|
|
@@ -130,6 +143,9 @@ function mapStatusValue(value) {
|
|
|
130
143
|
}
|
|
131
144
|
/**
|
|
132
145
|
* Extract a single line value from body text (e.g., "**Created**: 2025-01-01").
|
|
146
|
+
* @param body - Markdown body text.
|
|
147
|
+
* @param key - Front-matter key to extract.
|
|
148
|
+
* @returns The result.
|
|
133
149
|
*/
|
|
134
150
|
function extractValue(body, key) {
|
|
135
151
|
const pattern = new RegExp(`^\\*\\*${key}\\*\\*:\\s*(.+)$`, "m");
|
|
@@ -139,7 +155,12 @@ function extractValue(body, key) {
|
|
|
139
155
|
// ---------------------------------------------------------------------------
|
|
140
156
|
// constitution.md parser
|
|
141
157
|
// ---------------------------------------------------------------------------
|
|
142
|
-
/**
|
|
158
|
+
/**
|
|
159
|
+
* Parse a Spec-Kit constitution file into SysProM nodes (principles and invariants) and relationships.
|
|
160
|
+
* @param content - Markdown file content.
|
|
161
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
162
|
+
* @returns The result.
|
|
163
|
+
*/
|
|
143
164
|
export function parseConstitution(content, idPrefix) {
|
|
144
165
|
const sections = parseSections(content);
|
|
145
166
|
const nodes = [];
|
|
@@ -228,7 +249,12 @@ export function parseConstitution(content, idPrefix) {
|
|
|
228
249
|
// ---------------------------------------------------------------------------
|
|
229
250
|
// spec.md parser
|
|
230
251
|
// ---------------------------------------------------------------------------
|
|
231
|
-
/**
|
|
252
|
+
/**
|
|
253
|
+
* Parse a Spec-Kit specification file into SysProM nodes (user stories, functional requirements, acceptance criteria).
|
|
254
|
+
* @param content - Markdown file content.
|
|
255
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
256
|
+
* @returns The result.
|
|
257
|
+
*/
|
|
232
258
|
export function parseSpec(content, idPrefix) {
|
|
233
259
|
const sections = parseSections(content);
|
|
234
260
|
const allSections = flattenSections(sections);
|
|
@@ -412,7 +438,12 @@ export function parseSpec(content, idPrefix) {
|
|
|
412
438
|
// ---------------------------------------------------------------------------
|
|
413
439
|
// plan.md parser
|
|
414
440
|
// ---------------------------------------------------------------------------
|
|
415
|
-
/**
|
|
441
|
+
/**
|
|
442
|
+
* Parse a Spec-Kit plan file into SysProM nodes (phases, milestones) and relationships.
|
|
443
|
+
* @param content - Markdown file content.
|
|
444
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
445
|
+
* @returns The result.
|
|
446
|
+
*/
|
|
416
447
|
export function parsePlan(content, idPrefix) {
|
|
417
448
|
const sections = parseSections(content);
|
|
418
449
|
const allSections = flattenSections(sections);
|
|
@@ -505,7 +536,12 @@ export function parsePlan(content, idPrefix) {
|
|
|
505
536
|
// ---------------------------------------------------------------------------
|
|
506
537
|
// tasks.md parser
|
|
507
538
|
// ---------------------------------------------------------------------------
|
|
508
|
-
/**
|
|
539
|
+
/**
|
|
540
|
+
* Parse a Spec-Kit tasks file into SysProM change nodes with task plans.
|
|
541
|
+
* @param content - Markdown file content.
|
|
542
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
543
|
+
* @returns The result.
|
|
544
|
+
*/
|
|
509
545
|
export function parseTasks(content, idPrefix) {
|
|
510
546
|
const sections = parseSections(content);
|
|
511
547
|
const allSections = flattenSections(sections);
|
|
@@ -611,7 +647,12 @@ export function parseTasks(content, idPrefix) {
|
|
|
611
647
|
// ---------------------------------------------------------------------------
|
|
612
648
|
// checklist.md parser
|
|
613
649
|
// ---------------------------------------------------------------------------
|
|
614
|
-
/**
|
|
650
|
+
/**
|
|
651
|
+
* Parse a Spec-Kit checklist file into SysProM gate nodes with task plans.
|
|
652
|
+
* @param content - Markdown file content.
|
|
653
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
654
|
+
* @returns The result.
|
|
655
|
+
*/
|
|
615
656
|
export function parseChecklist(content, idPrefix) {
|
|
616
657
|
const sections = parseSections(content);
|
|
617
658
|
const allSections = flattenSections(sections);
|
|
@@ -660,7 +701,13 @@ export function parseChecklist(content, idPrefix) {
|
|
|
660
701
|
// ---------------------------------------------------------------------------
|
|
661
702
|
// Full feature directory parser
|
|
662
703
|
// ---------------------------------------------------------------------------
|
|
663
|
-
/**
|
|
704
|
+
/**
|
|
705
|
+
* Parse an entire Spec-Kit feature directory into a SysProM document, combining constitution, spec, plan, tasks, and checklist.
|
|
706
|
+
* @param featureDir - Path to Spec-Kit feature directory.
|
|
707
|
+
* @param idPrefix - ID prefix for generated nodes.
|
|
708
|
+
* @param constitutionPath - Path to constitution.md, or undefined.
|
|
709
|
+
* @returns The parsed SysProM document.
|
|
710
|
+
*/
|
|
664
711
|
export function parseSpecKitFeature(featureDir, idPrefix, constitutionPath) {
|
|
665
712
|
const nodes = [];
|
|
666
713
|
const relationships = [];
|
|
@@ -74,6 +74,9 @@ export interface TaskCount {
|
|
|
74
74
|
* - {prefix}-CHK governed_by {prefix}-PROT-IMPL
|
|
75
75
|
*
|
|
76
76
|
* Tasks are not pre-scaffolded; use addTask to add them.
|
|
77
|
+
* @param prefix - Plan prefix.
|
|
78
|
+
* @param name - Name for the new item.
|
|
79
|
+
* @returns The result.
|
|
77
80
|
*/
|
|
78
81
|
export declare function initDocument(prefix: string, name: string): SysProMDocument;
|
|
79
82
|
/**
|
|
@@ -88,6 +91,11 @@ export declare function initDocument(prefix: string, name: string): SysProMDocum
|
|
|
88
91
|
*
|
|
89
92
|
* Wires must_follow to previous sibling change node at the same level.
|
|
90
93
|
* Default name: "Task N".
|
|
94
|
+
* @param doc - The SysProM document.
|
|
95
|
+
* @param prefix - Plan prefix.
|
|
96
|
+
* @param name - Name for the new item.
|
|
97
|
+
* @param parentId - Parent task ID.
|
|
98
|
+
* @returns The result.
|
|
91
99
|
*/
|
|
92
100
|
export declare function addTask(doc: SysProMDocument, prefix: string, name?: string, parentId?: string): SysProMDocument;
|
|
93
101
|
/**
|
|
@@ -97,6 +105,8 @@ export declare function addTask(doc: SysProMDocument, prefix: string, name?: str
|
|
|
97
105
|
* - All items in node.plan must have done === true AND at least one item must exist
|
|
98
106
|
* If subsystem has change children:
|
|
99
107
|
* - All children must be recursively done AND own plan items (if any) must be done
|
|
108
|
+
* @param node - The node to check.
|
|
109
|
+
* @returns The result.
|
|
100
110
|
*/
|
|
101
111
|
export declare function isTaskDone(node: Node): boolean;
|
|
102
112
|
/**
|
|
@@ -104,16 +114,24 @@ export declare function isTaskDone(node: Node): boolean;
|
|
|
104
114
|
*
|
|
105
115
|
* Sums plan[] items from this node and recursively from all change nodes in
|
|
106
116
|
* subsystem (and their subsystems).
|
|
117
|
+
* @param node - The node to check.
|
|
118
|
+
* @returns The result.
|
|
107
119
|
*/
|
|
108
120
|
export declare function countTasks(node: Node): TaskCount;
|
|
109
121
|
/**
|
|
110
122
|
* Inspect a document and return workflow completeness for a given prefix.
|
|
111
123
|
* Never throws — missing nodes are reported as "not defined".
|
|
124
|
+
* @param doc - The SysProM document.
|
|
125
|
+
* @param prefix - Plan prefix.
|
|
126
|
+
* @returns The result.
|
|
112
127
|
*/
|
|
113
128
|
export declare function planStatus(doc: SysProMDocument, prefix: string): PlanStatus;
|
|
114
129
|
/**
|
|
115
130
|
* Return per-task completion data.
|
|
116
131
|
* Tasks (change nodes) are discovered from PROT-IMPL.subsystem, sorted topologically.
|
|
132
|
+
* @param doc - The SysProM document.
|
|
133
|
+
* @param prefix - Plan prefix.
|
|
134
|
+
* @returns The result.
|
|
117
135
|
*/
|
|
118
136
|
export declare function planProgress(doc: SysProMDocument, prefix: string): PhaseProgress[];
|
|
119
137
|
/**
|
|
@@ -126,5 +144,9 @@ export declare function planProgress(doc: SysProMDocument, prefix: string): Phas
|
|
|
126
144
|
*
|
|
127
145
|
* Additionally for phase N > 1:
|
|
128
146
|
* - All tasks in phase N-1 must be done
|
|
147
|
+
* @param doc - The SysProM document.
|
|
148
|
+
* @param prefix - Plan prefix.
|
|
149
|
+
* @param phase - Phase number (1-indexed).
|
|
150
|
+
* @returns Gate check result with readiness flag and issues.
|
|
129
151
|
*/
|
|
130
152
|
export declare function checkGate(doc: SysProMDocument, prefix: string, phase: number): GateResult;
|
package/dist/src/speckit/plan.js
CHANGED
|
@@ -4,12 +4,18 @@ import { textToString } from "../text.js";
|
|
|
4
4
|
// ============================================================================
|
|
5
5
|
/**
|
|
6
6
|
* Find a single node by ID, or null if not found.
|
|
7
|
+
* @param doc - The SysProM document.
|
|
8
|
+
* @param id - Node ID to find.
|
|
9
|
+
* @returns The result.
|
|
7
10
|
*/
|
|
8
11
|
function findNode(doc, id) {
|
|
9
12
|
return doc.nodes.find((n) => n.id === id) ?? null;
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
15
|
* Find a single node by ID in a subsystem, or null if not found.
|
|
16
|
+
* @param subsystem - The subsystem document.
|
|
17
|
+
* @param id - Node ID to find.
|
|
18
|
+
* @returns The result.
|
|
13
19
|
*/
|
|
14
20
|
function findNodeInSubsystem(subsystem, id) {
|
|
15
21
|
if (!subsystem)
|
|
@@ -18,12 +24,18 @@ function findNodeInSubsystem(subsystem, id) {
|
|
|
18
24
|
}
|
|
19
25
|
/**
|
|
20
26
|
* Find all nodes of a specific type.
|
|
27
|
+
* @param doc - The SysProM document.
|
|
28
|
+
* @param type - Node type to filter by.
|
|
29
|
+
* @returns The result.
|
|
21
30
|
*/
|
|
22
31
|
function findNodesByType(doc, type) {
|
|
23
32
|
return doc.nodes.filter((n) => n.type === type);
|
|
24
33
|
}
|
|
25
34
|
/**
|
|
26
35
|
* Find all nodes of a specific type in a subsystem.
|
|
36
|
+
* @param subsystem - The subsystem document.
|
|
37
|
+
* @param type - Node type to filter by.
|
|
38
|
+
* @returns The result.
|
|
27
39
|
*/
|
|
28
40
|
function findNodesByTypeInSubsystem(subsystem, type) {
|
|
29
41
|
if (!subsystem)
|
|
@@ -32,6 +44,10 @@ function findNodesByTypeInSubsystem(subsystem, type) {
|
|
|
32
44
|
}
|
|
33
45
|
/**
|
|
34
46
|
* Find relationships from a source node to nodes of a target type (within a subsystem).
|
|
47
|
+
* @param subsystem - The subsystem document.
|
|
48
|
+
* @param fromId - Source node ID.
|
|
49
|
+
* @param relationType - Relationship type filter.
|
|
50
|
+
* @returns The result.
|
|
35
51
|
*/
|
|
36
52
|
function findRelationshipsFrom(subsystem, fromId, relationType) {
|
|
37
53
|
if (!subsystem)
|
|
@@ -46,6 +62,10 @@ function findRelationshipsFrom(subsystem, fromId, relationType) {
|
|
|
46
62
|
}
|
|
47
63
|
/**
|
|
48
64
|
* Find relationships to a target node (within a subsystem).
|
|
65
|
+
* @param subsystem - The subsystem document.
|
|
66
|
+
* @param toId - Target node ID.
|
|
67
|
+
* @param relationType - Relationship type filter.
|
|
68
|
+
* @returns The result.
|
|
49
69
|
*/
|
|
50
70
|
function findRelationshipsTo(subsystem, toId, relationType) {
|
|
51
71
|
if (!subsystem)
|
|
@@ -61,6 +81,8 @@ function findRelationshipsTo(subsystem, toId, relationType) {
|
|
|
61
81
|
/**
|
|
62
82
|
* Detect if a text contains non-placeholder acceptance criteria.
|
|
63
83
|
* Looks for GIVEN/WHEN/THEN patterns (case-insensitive).
|
|
84
|
+
* @param description - Task description text.
|
|
85
|
+
* @returns The result.
|
|
64
86
|
*/
|
|
65
87
|
function hasAcceptanceCriteria(description) {
|
|
66
88
|
if (!description)
|
|
@@ -70,6 +92,9 @@ function hasAcceptanceCriteria(description) {
|
|
|
70
92
|
}
|
|
71
93
|
/**
|
|
72
94
|
* Sort change nodes topologically using must_follow relationships.
|
|
95
|
+
* @param subsystem - The subsystem document.
|
|
96
|
+
* @param changeNodes - Array of change nodes.
|
|
97
|
+
* @returns The result.
|
|
73
98
|
*/
|
|
74
99
|
function sortChangesByOrder(subsystem, changeNodes) {
|
|
75
100
|
const subsystemToUse = subsystem ?? { nodes: [], relationships: [] };
|
|
@@ -122,6 +147,9 @@ function sortChangesByOrder(subsystem, changeNodes) {
|
|
|
122
147
|
* - {prefix}-CHK governed_by {prefix}-PROT-IMPL
|
|
123
148
|
*
|
|
124
149
|
* Tasks are not pre-scaffolded; use addTask to add them.
|
|
150
|
+
* @param prefix - Plan prefix.
|
|
151
|
+
* @param name - Name for the new item.
|
|
152
|
+
* @returns The result.
|
|
125
153
|
*/
|
|
126
154
|
export function initDocument(prefix, name) {
|
|
127
155
|
const nodes = [
|
|
@@ -189,6 +217,11 @@ export function initDocument(prefix, name) {
|
|
|
189
217
|
*
|
|
190
218
|
* Wires must_follow to previous sibling change node at the same level.
|
|
191
219
|
* Default name: "Task N".
|
|
220
|
+
* @param doc - The SysProM document.
|
|
221
|
+
* @param prefix - Plan prefix.
|
|
222
|
+
* @param name - Name for the new item.
|
|
223
|
+
* @param parentId - Parent task ID.
|
|
224
|
+
* @returns The result.
|
|
192
225
|
*/
|
|
193
226
|
export function addTask(doc, prefix, name, parentId) {
|
|
194
227
|
const protImpl = findNode(doc, `${prefix}-PROT-IMPL`);
|
|
@@ -247,6 +280,12 @@ export function addTask(doc, prefix, name, parentId) {
|
|
|
247
280
|
}
|
|
248
281
|
/**
|
|
249
282
|
* Helper function to recursively add a task to a parent change node's subsystem.
|
|
283
|
+
* @param doc - The SysProM document.
|
|
284
|
+
* @param protImpl - Implementation protocol node.
|
|
285
|
+
* @param prefix - Plan prefix.
|
|
286
|
+
* @param parentId - Parent task ID.
|
|
287
|
+
* @param name - Name for the new item.
|
|
288
|
+
* @returns The result.
|
|
250
289
|
*/
|
|
251
290
|
function addTaskToParent(doc, protImpl, prefix, parentId, name) {
|
|
252
291
|
// Find the parent change node in the subsystem tree
|
|
@@ -376,6 +415,8 @@ function addTaskToParent(doc, protImpl, prefix, parentId, name) {
|
|
|
376
415
|
* - All items in node.plan must have done === true AND at least one item must exist
|
|
377
416
|
* If subsystem has change children:
|
|
378
417
|
* - All children must be recursively done AND own plan items (if any) must be done
|
|
418
|
+
* @param node - The node to check.
|
|
419
|
+
* @returns The result.
|
|
379
420
|
*/
|
|
380
421
|
export function isTaskDone(node) {
|
|
381
422
|
// If the node has a subsystem with change children, check those recursively
|
|
@@ -404,6 +445,8 @@ export function isTaskDone(node) {
|
|
|
404
445
|
*
|
|
405
446
|
* Sums plan[] items from this node and recursively from all change nodes in
|
|
406
447
|
* subsystem (and their subsystems).
|
|
448
|
+
* @param node - The node to check.
|
|
449
|
+
* @returns The result.
|
|
407
450
|
*/
|
|
408
451
|
export function countTasks(node) {
|
|
409
452
|
let total = 0;
|
|
@@ -429,6 +472,9 @@ export function countTasks(node) {
|
|
|
429
472
|
/**
|
|
430
473
|
* Inspect a document and return workflow completeness for a given prefix.
|
|
431
474
|
* Never throws — missing nodes are reported as "not defined".
|
|
475
|
+
* @param doc - The SysProM document.
|
|
476
|
+
* @param prefix - Plan prefix.
|
|
477
|
+
* @returns The result.
|
|
432
478
|
*/
|
|
433
479
|
export function planStatus(doc, prefix) {
|
|
434
480
|
const constitution = findNode(doc, `${prefix}-CONST`);
|
|
@@ -527,6 +573,9 @@ export function planStatus(doc, prefix) {
|
|
|
527
573
|
/**
|
|
528
574
|
* Return per-task completion data.
|
|
529
575
|
* Tasks (change nodes) are discovered from PROT-IMPL.subsystem, sorted topologically.
|
|
576
|
+
* @param doc - The SysProM document.
|
|
577
|
+
* @param prefix - Plan prefix.
|
|
578
|
+
* @returns The result.
|
|
530
579
|
*/
|
|
531
580
|
export function planProgress(doc, prefix) {
|
|
532
581
|
const protImpl = findNode(doc, `${prefix}-PROT-IMPL`);
|
|
@@ -568,6 +617,10 @@ export function planProgress(doc, prefix) {
|
|
|
568
617
|
*
|
|
569
618
|
* Additionally for phase N > 1:
|
|
570
619
|
* - All tasks in phase N-1 must be done
|
|
620
|
+
* @param doc - The SysProM document.
|
|
621
|
+
* @param prefix - Plan prefix.
|
|
622
|
+
* @param phase - Phase number (1-indexed).
|
|
623
|
+
* @returns Gate check result with readiness flag and issues.
|
|
571
624
|
*/
|
|
572
625
|
export function checkGate(doc, prefix, phase) {
|
|
573
626
|
if (phase < 1) {
|