sysprom 1.0.0 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +207 -0
  2. package/dist/schema.json +510 -0
  3. package/dist/src/canonical-json.d.ts +23 -0
  4. package/dist/src/canonical-json.js +120 -0
  5. package/dist/src/cli/commands/add.d.ts +22 -0
  6. package/dist/src/cli/commands/add.js +95 -0
  7. package/dist/src/cli/commands/check.d.ts +10 -0
  8. package/dist/src/cli/commands/check.js +33 -0
  9. package/dist/src/cli/commands/graph.d.ts +15 -0
  10. package/dist/src/cli/commands/graph.js +32 -0
  11. package/dist/src/cli/commands/init.d.ts +2 -0
  12. package/dist/src/cli/commands/init.js +44 -0
  13. package/dist/src/cli/commands/json2md.d.ts +2 -0
  14. package/dist/src/cli/commands/json2md.js +60 -0
  15. package/dist/src/cli/commands/md2json.d.ts +2 -0
  16. package/dist/src/cli/commands/md2json.js +29 -0
  17. package/dist/src/cli/commands/plan.d.ts +2 -0
  18. package/dist/src/cli/commands/plan.js +227 -0
  19. package/dist/src/cli/commands/query.d.ts +2 -0
  20. package/dist/src/cli/commands/query.js +275 -0
  21. package/dist/src/cli/commands/remove.d.ts +13 -0
  22. package/dist/src/cli/commands/remove.js +50 -0
  23. package/dist/src/cli/commands/rename.d.ts +14 -0
  24. package/dist/src/cli/commands/rename.js +34 -0
  25. package/dist/src/cli/commands/search.d.ts +11 -0
  26. package/dist/src/cli/commands/search.js +37 -0
  27. package/dist/src/cli/commands/speckit.d.ts +2 -0
  28. package/dist/src/cli/commands/speckit.js +318 -0
  29. package/dist/src/cli/commands/stats.d.ts +10 -0
  30. package/dist/src/cli/commands/stats.js +51 -0
  31. package/dist/src/cli/commands/task.d.ts +2 -0
  32. package/dist/src/cli/commands/task.js +162 -0
  33. package/dist/src/cli/commands/update.d.ts +2 -0
  34. package/dist/src/cli/commands/update.js +219 -0
  35. package/dist/src/cli/commands/validate.d.ts +10 -0
  36. package/dist/src/cli/commands/validate.js +30 -0
  37. package/dist/src/cli/define-command.d.ts +34 -0
  38. package/dist/src/cli/define-command.js +237 -0
  39. package/dist/src/cli/index.d.ts +2 -0
  40. package/dist/src/cli/index.js +3 -0
  41. package/dist/src/cli/program.d.ts +4 -0
  42. package/dist/src/cli/program.js +46 -0
  43. package/dist/src/cli/shared.d.ts +26 -0
  44. package/dist/src/cli/shared.js +41 -0
  45. package/dist/src/generate-schema.d.ts +1 -0
  46. package/dist/src/generate-schema.js +9 -0
  47. package/dist/src/index.d.ts +48 -0
  48. package/dist/src/index.js +99 -0
  49. package/dist/src/io.d.ts +22 -0
  50. package/dist/src/io.js +66 -0
  51. package/dist/src/json-to-md.d.ts +26 -0
  52. package/dist/src/json-to-md.js +498 -0
  53. package/dist/src/md-to-json.d.ts +22 -0
  54. package/dist/src/md-to-json.js +548 -0
  55. package/dist/src/operations/add-node.d.ts +887 -0
  56. package/dist/src/operations/add-node.js +21 -0
  57. package/dist/src/operations/add-plan-task.d.ts +594 -0
  58. package/dist/src/operations/add-plan-task.js +25 -0
  59. package/dist/src/operations/add-relationship.d.ts +635 -0
  60. package/dist/src/operations/add-relationship.js +25 -0
  61. package/dist/src/operations/check.d.ts +301 -0
  62. package/dist/src/operations/check.js +66 -0
  63. package/dist/src/operations/define-operation.d.ts +14 -0
  64. package/dist/src/operations/define-operation.js +21 -0
  65. package/dist/src/operations/graph.d.ts +303 -0
  66. package/dist/src/operations/graph.js +71 -0
  67. package/dist/src/operations/index.d.ts +38 -0
  68. package/dist/src/operations/index.js +45 -0
  69. package/dist/src/operations/init-document.d.ts +299 -0
  70. package/dist/src/operations/init-document.js +26 -0
  71. package/dist/src/operations/json-to-markdown.d.ts +298 -0
  72. package/dist/src/operations/json-to-markdown.js +13 -0
  73. package/dist/src/operations/mark-task-done.d.ts +594 -0
  74. package/dist/src/operations/mark-task-done.js +26 -0
  75. package/dist/src/operations/mark-task-undone.d.ts +594 -0
  76. package/dist/src/operations/mark-task-undone.js +26 -0
  77. package/dist/src/operations/markdown-to-json.d.ts +298 -0
  78. package/dist/src/operations/markdown-to-json.js +13 -0
  79. package/dist/src/operations/next-id.d.ts +322 -0
  80. package/dist/src/operations/next-id.js +29 -0
  81. package/dist/src/operations/node-history.d.ts +313 -0
  82. package/dist/src/operations/node-history.js +55 -0
  83. package/dist/src/operations/plan-add-task.d.ts +595 -0
  84. package/dist/src/operations/plan-add-task.js +18 -0
  85. package/dist/src/operations/plan-gate.d.ts +351 -0
  86. package/dist/src/operations/plan-gate.js +41 -0
  87. package/dist/src/operations/plan-init.d.ts +299 -0
  88. package/dist/src/operations/plan-init.js +17 -0
  89. package/dist/src/operations/plan-progress.d.ts +313 -0
  90. package/dist/src/operations/plan-progress.js +23 -0
  91. package/dist/src/operations/plan-status.d.ts +349 -0
  92. package/dist/src/operations/plan-status.js +41 -0
  93. package/dist/src/operations/query-node.d.ts +1065 -0
  94. package/dist/src/operations/query-node.js +27 -0
  95. package/dist/src/operations/query-nodes.d.ts +594 -0
  96. package/dist/src/operations/query-nodes.js +23 -0
  97. package/dist/src/operations/query-relationships.d.ts +343 -0
  98. package/dist/src/operations/query-relationships.js +27 -0
  99. package/dist/src/operations/remove-node.d.ts +895 -0
  100. package/dist/src/operations/remove-node.js +58 -0
  101. package/dist/src/operations/remove-relationship.d.ts +622 -0
  102. package/dist/src/operations/remove-relationship.js +26 -0
  103. package/dist/src/operations/rename.d.ts +594 -0
  104. package/dist/src/operations/rename.js +113 -0
  105. package/dist/src/operations/search.d.ts +593 -0
  106. package/dist/src/operations/search.js +39 -0
  107. package/dist/src/operations/speckit-diff.d.ts +330 -0
  108. package/dist/src/operations/speckit-diff.js +89 -0
  109. package/dist/src/operations/speckit-export.d.ts +300 -0
  110. package/dist/src/operations/speckit-export.js +17 -0
  111. package/dist/src/operations/speckit-import.d.ts +299 -0
  112. package/dist/src/operations/speckit-import.js +39 -0
  113. package/dist/src/operations/speckit-sync.d.ts +900 -0
  114. package/dist/src/operations/speckit-sync.js +116 -0
  115. package/dist/src/operations/state-at.d.ts +309 -0
  116. package/dist/src/operations/state-at.js +53 -0
  117. package/dist/src/operations/stats.d.ts +324 -0
  118. package/dist/src/operations/stats.js +85 -0
  119. package/dist/src/operations/task-list.d.ts +305 -0
  120. package/dist/src/operations/task-list.js +44 -0
  121. package/dist/src/operations/timeline.d.ts +312 -0
  122. package/dist/src/operations/timeline.js +46 -0
  123. package/dist/src/operations/trace-from-node.d.ts +1197 -0
  124. package/dist/src/operations/trace-from-node.js +36 -0
  125. package/dist/src/operations/update-metadata.d.ts +593 -0
  126. package/dist/src/operations/update-metadata.js +18 -0
  127. package/dist/src/operations/update-node.d.ts +957 -0
  128. package/dist/src/operations/update-node.js +24 -0
  129. package/dist/src/operations/update-plan-task.d.ts +595 -0
  130. package/dist/src/operations/update-plan-task.js +31 -0
  131. package/dist/src/operations/validate.d.ts +310 -0
  132. package/dist/src/operations/validate.js +82 -0
  133. package/dist/src/schema.d.ts +891 -0
  134. package/dist/src/schema.js +356 -0
  135. package/dist/src/speckit/generate.d.ts +7 -0
  136. package/dist/src/speckit/generate.js +546 -0
  137. package/dist/src/speckit/index.d.ts +4 -0
  138. package/dist/src/speckit/index.js +4 -0
  139. package/dist/src/speckit/parse.d.ts +11 -0
  140. package/dist/src/speckit/parse.js +712 -0
  141. package/dist/src/speckit/plan.d.ts +125 -0
  142. package/dist/src/speckit/plan.js +636 -0
  143. package/dist/src/speckit/project.d.ts +39 -0
  144. package/dist/src/speckit/project.js +141 -0
  145. package/dist/src/text.d.ts +23 -0
  146. package/dist/src/text.js +32 -0
  147. package/package.json +86 -8
  148. package/schema.json +510 -0
@@ -0,0 +1,356 @@
1
+ import * as z from "zod";
2
+ // ---------------------------------------------------------------------------
3
+ // defineSchema — attaches a .is() type guard to any Zod schema
4
+ // ---------------------------------------------------------------------------
5
+ function defineSchema(schema) {
6
+ return Object.assign(schema, {
7
+ is(value) {
8
+ return schema.safeParse(value).success;
9
+ },
10
+ });
11
+ }
12
+ // ---------------------------------------------------------------------------
13
+ // Text type — allows a string or an array of lines
14
+ // ---------------------------------------------------------------------------
15
+ export const Text = defineSchema(z.union([z.string(), z.array(z.string())]));
16
+ // ---------------------------------------------------------------------------
17
+ // Extensible string types
18
+ // ---------------------------------------------------------------------------
19
+ // ---------------------------------------------------------------------------
20
+ // Labelled enum helper — define labels once, derive everything else
21
+ // ---------------------------------------------------------------------------
22
+ function typedKeys(obj) {
23
+ const keys = [];
24
+ for (const key in obj) {
25
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
26
+ keys.push(key);
27
+ }
28
+ }
29
+ if (keys.length === 0)
30
+ throw new Error("labelledEnum requires at least one entry");
31
+ return [keys[0], ...keys.slice(1)];
32
+ }
33
+ function invertRecord(record) {
34
+ const result = {};
35
+ for (const key in record) {
36
+ if (Object.prototype.hasOwnProperty.call(record, key)) {
37
+ result[record[key]] = key;
38
+ }
39
+ }
40
+ return result;
41
+ }
42
+ function labelledEnum(labels) {
43
+ const keys = typedKeys(labels);
44
+ const schema = defineSchema(z.enum(keys));
45
+ const reverse = invertRecord(labels);
46
+ return { schema, labels, reverse, keys };
47
+ }
48
+ // ---------------------------------------------------------------------------
49
+ // Node types
50
+ // ---------------------------------------------------------------------------
51
+ const nodeTypeDef = labelledEnum({
52
+ intent: "Intent",
53
+ concept: "Concepts",
54
+ capability: "Capabilities",
55
+ element: "Elements",
56
+ realisation: "Realisations",
57
+ invariant: "Invariants",
58
+ principle: "Principles",
59
+ policy: "Policies",
60
+ protocol: "Protocols",
61
+ stage: "Stages",
62
+ role: "Roles",
63
+ gate: "Gates",
64
+ mode: "Modes",
65
+ artefact: "Artefacts",
66
+ artefact_flow: "Artefact Flows",
67
+ decision: "Decisions",
68
+ change: "Changes",
69
+ view: "Views",
70
+ milestone: "Milestones",
71
+ version: "Versions",
72
+ });
73
+ export const NodeType = nodeTypeDef.schema;
74
+ export const NODE_TYPE_LABELS = nodeTypeDef.labels;
75
+ export const NODE_LABEL_TO_TYPE = nodeTypeDef.reverse;
76
+ // ---------------------------------------------------------------------------
77
+ // Node statuses
78
+ // ---------------------------------------------------------------------------
79
+ export const NODE_STATUSES = [
80
+ "proposed",
81
+ "accepted",
82
+ "active",
83
+ "implemented",
84
+ "adopted",
85
+ "defined",
86
+ "introduced",
87
+ "in_progress",
88
+ "complete",
89
+ "consolidated",
90
+ "experimental",
91
+ "deprecated",
92
+ "retired",
93
+ "superseded",
94
+ "abandoned",
95
+ "deferred",
96
+ ];
97
+ export const NodeStatus = defineSchema(z.enum(NODE_STATUSES));
98
+ // ---------------------------------------------------------------------------
99
+ // Relationship types
100
+ // ---------------------------------------------------------------------------
101
+ const relationshipTypeDef = labelledEnum({
102
+ refines: "Refines",
103
+ realises: "Realises",
104
+ implements: "Implements",
105
+ depends_on: "Depends on",
106
+ constrained_by: "Constrained by",
107
+ affects: "Affects",
108
+ supersedes: "Supersedes",
109
+ must_preserve: "Must preserve",
110
+ performs: "Performs",
111
+ part_of: "Part of",
112
+ precedes: "Precedes",
113
+ must_follow: "Must follow",
114
+ blocks: "Blocks",
115
+ routes_to: "Routes to",
116
+ governed_by: "Governed by",
117
+ modifies: "Modifies",
118
+ triggered_by: "Triggered by",
119
+ applies_to: "Applies to",
120
+ produces: "Produces",
121
+ consumes: "Consumes",
122
+ transforms_into: "Transforms into",
123
+ selects: "Selects",
124
+ requires: "Requires",
125
+ disables: "Disables",
126
+ });
127
+ export const RelationshipType = relationshipTypeDef.schema;
128
+ export const RELATIONSHIP_TYPE_LABELS = relationshipTypeDef.labels;
129
+ export const RELATIONSHIP_LABEL_TO_TYPE = relationshipTypeDef.reverse;
130
+ // ---------------------------------------------------------------------------
131
+ // External reference roles
132
+ // ---------------------------------------------------------------------------
133
+ const externalReferenceRoleDef = labelledEnum({
134
+ input: "Input",
135
+ output: "Output",
136
+ context: "Context",
137
+ evidence: "Evidence",
138
+ source: "Source",
139
+ standard: "Standard",
140
+ prior_art: "Prior art",
141
+ });
142
+ export const ExternalReferenceRole = externalReferenceRoleDef.schema;
143
+ export const EXTERNAL_REFERENCE_ROLE_LABELS = externalReferenceRoleDef.labels;
144
+ export const EXTERNAL_REFERENCE_LABEL_TO_ROLE = externalReferenceRoleDef.reverse;
145
+ // ---------------------------------------------------------------------------
146
+ // Leaf schemas
147
+ // ---------------------------------------------------------------------------
148
+ export const Option = defineSchema(z
149
+ .looseObject({
150
+ id: z.string(),
151
+ description: Text,
152
+ })
153
+ .describe("An alternative considered as part of a decision."));
154
+ export const Operation = defineSchema(z
155
+ .looseObject({
156
+ type: z.enum(["add", "update", "remove", "link"]),
157
+ target: z.string().describe("ID of the affected node.").optional(),
158
+ description: Text.optional(),
159
+ })
160
+ .describe("An atomic operation within a change."));
161
+ export const Task = defineSchema(z
162
+ .looseObject({
163
+ description: Text,
164
+ done: z.boolean().default(false).optional(),
165
+ })
166
+ .describe("A single task within a change's execution plan."));
167
+ export const ExternalReference = defineSchema(z
168
+ .object({
169
+ role: ExternalReferenceRole,
170
+ identifier: z
171
+ .string()
172
+ .describe("Serialisation-specific identifier (URI, file path, DOI, etc.)."),
173
+ description: Text.optional(),
174
+ node_id: z
175
+ .string()
176
+ .describe("ID of the node this reference belongs to. Used when the reference is declared at graph level rather than inline on the node.")
177
+ .optional(),
178
+ internalised: Text.describe("Inline content captured from the external resource. When present, the node is self-contained and does not depend on the external identifier being resolvable.").optional(),
179
+ })
180
+ .describe("A reference to a resource outside the SysProM graph."));
181
+ export const Metadata = defineSchema(z
182
+ .looseObject({
183
+ title: z.string().optional(),
184
+ doc_type: z
185
+ .string()
186
+ .describe("Document type. Use 'sysprom' for the root entry point. Subsystems and features may use other values.")
187
+ .optional(),
188
+ scope: z
189
+ .string()
190
+ .describe("The scope of this document (e.g. system, feature, component).")
191
+ .optional(),
192
+ status: z.string().optional(),
193
+ version: z.union([z.string(), z.int()]).optional(),
194
+ })
195
+ .describe("Document-level metadata. Analogous to front matter in Markdown."));
196
+ export const Relationship = defineSchema(z
197
+ .looseObject({
198
+ from: z.string().describe("Source node ID."),
199
+ to: z.string().describe("Target node ID."),
200
+ type: RelationshipType,
201
+ description: Text.optional(),
202
+ })
203
+ .describe("A typed, directed connection between two nodes."));
204
+ // ---------------------------------------------------------------------------
205
+ // Recursive schemas — defined raw, then wrapped with defineSchema after both
206
+ // exist so TypeScript can resolve the circular type inference.
207
+ // ---------------------------------------------------------------------------
208
+ const SysProMDocumentSchema = z
209
+ .object({
210
+ $schema: z
211
+ .string()
212
+ .describe("Schema URI for self-identification.")
213
+ .optional(),
214
+ metadata: Metadata.optional(),
215
+ get nodes() {
216
+ return z.array(NodeSchema).describe("All nodes in the graph.");
217
+ },
218
+ relationships: z
219
+ .array(Relationship)
220
+ .describe("Typed, directed connections between nodes.")
221
+ .optional(),
222
+ external_references: z
223
+ .array(ExternalReference)
224
+ .describe("References to resources outside the graph, declared at system level.")
225
+ .optional(),
226
+ })
227
+ .meta({
228
+ id: "SysProM",
229
+ title: "SysProM: System Provenance Model",
230
+ description: "JSON Schema for SysProM — a recursive, decision-driven model for recording system provenance.",
231
+ });
232
+ const NodeSchema = z
233
+ .looseObject({
234
+ id: z.string().describe("Unique identifier for this node."),
235
+ type: NodeType,
236
+ name: z.string().describe("Human-readable name."),
237
+ description: Text.optional(),
238
+ status: NodeStatus.optional(),
239
+ lifecycle: z
240
+ .record(z.string(), z.union([z.boolean(), z.string()]))
241
+ .describe("Map of lifecycle state names to completion status. Values may be boolean or an ISO date string indicating when the state was reached.")
242
+ .optional(),
243
+ context: Text.describe("Background context explaining why this node exists or why a decision was needed.").optional(),
244
+ options: z
245
+ .array(Option)
246
+ .describe("Alternatives considered. Applicable to decision nodes.")
247
+ .optional(),
248
+ selected: z
249
+ .string()
250
+ .describe("ID of the chosen option. Applicable to decision nodes.")
251
+ .optional(),
252
+ rationale: Text.describe("Reasoning for the choice. Applicable to decision nodes.").optional(),
253
+ scope: z
254
+ .array(z.string())
255
+ .describe("IDs of nodes affected by this change. Applicable to change nodes.")
256
+ .optional(),
257
+ operations: z
258
+ .array(Operation)
259
+ .describe("Operations performed. Applicable to change nodes.")
260
+ .optional(),
261
+ plan: z
262
+ .array(Task)
263
+ .describe("Execution plan as a sequence of tasks. Applicable to change nodes.")
264
+ .optional(),
265
+ propagation: z
266
+ .record(z.string(), z.boolean())
267
+ .describe("Layer propagation status. Applicable to change nodes.")
268
+ .optional(),
269
+ includes: z
270
+ .array(z.string())
271
+ .describe("IDs of nodes included in this projection. Applicable to view nodes.")
272
+ .optional(),
273
+ input: z
274
+ .string()
275
+ .describe("ID of the input artefact. Applicable to artefact_flow nodes.")
276
+ .optional(),
277
+ output: z
278
+ .string()
279
+ .describe("ID of the output artefact. Applicable to artefact_flow nodes.")
280
+ .optional(),
281
+ external_references: z
282
+ .array(ExternalReference)
283
+ .describe("External resources related to this node.")
284
+ .optional(),
285
+ get subsystem() {
286
+ return SysProMDocumentSchema.optional();
287
+ },
288
+ })
289
+ .describe("A uniquely identifiable entity within the system.");
290
+ // Attach .is() type guards after both schemas are declared
291
+ export const SysProMDocument = defineSchema(SysProMDocumentSchema);
292
+ export const Node = defineSchema(NodeSchema);
293
+ // ---------------------------------------------------------------------------
294
+ // Domain constants
295
+ // ---------------------------------------------------------------------------
296
+ /** Which node types belong in which document file. */
297
+ export const NODE_FILE_MAP = {
298
+ INTENT: ["intent", "concept", "capability"],
299
+ INVARIANTS: ["invariant", "principle", "policy"],
300
+ STATE: [
301
+ "element",
302
+ "realisation",
303
+ "protocol",
304
+ "stage",
305
+ "role",
306
+ "gate",
307
+ "mode",
308
+ "artefact",
309
+ "artefact_flow",
310
+ ],
311
+ DECISIONS: ["decision"],
312
+ CHANGES: ["change"],
313
+ };
314
+ /** Conventional ID prefix for each node type. */
315
+ export const NODE_ID_PREFIX = {
316
+ intent: "I",
317
+ concept: "CN",
318
+ capability: "CP",
319
+ element: "EL",
320
+ realisation: "R",
321
+ invariant: "INV",
322
+ principle: "PR",
323
+ policy: "POL",
324
+ protocol: "PROT",
325
+ stage: "STG",
326
+ role: "ROLE",
327
+ gate: "GATE",
328
+ mode: "MODE",
329
+ artefact: "ART",
330
+ artefact_flow: "AF",
331
+ decision: "D",
332
+ change: "CH",
333
+ view: "V",
334
+ milestone: "MS",
335
+ version: "VER",
336
+ };
337
+ // ---------------------------------------------------------------------------
338
+ // Generate JSON Schema
339
+ // ---------------------------------------------------------------------------
340
+ function isRecord(value) {
341
+ return typeof value === "object" && value !== null && !Array.isArray(value);
342
+ }
343
+ /** Generate the JSON Schema representation of the SysProM document schema. */
344
+ export function toJSONSchema() {
345
+ const generated = z.toJSONSchema(SysProMDocument, {
346
+ target: "draft-2020-12",
347
+ });
348
+ if (!isRecord(generated)) {
349
+ throw new Error("toJSONSchema did not return an object");
350
+ }
351
+ return {
352
+ $schema: "https://json-schema.org/draft/2020-12/schema",
353
+ $id: "https://sysprom.org/schema.json",
354
+ ...generated,
355
+ };
356
+ }
@@ -0,0 +1,7 @@
1
+ import type { SysProMDocument } from "../schema.js";
2
+ export declare function generateConstitution(doc: SysProMDocument, prefix: string): string;
3
+ export declare function generateSpec(doc: SysProMDocument, prefix: string): string;
4
+ export declare function generatePlan(doc: SysProMDocument, prefix: string): string;
5
+ export declare function generateTasks(doc: SysProMDocument, prefix: string): string;
6
+ export declare function generateChecklist(doc: SysProMDocument, prefix: string): string;
7
+ export declare function generateSpecKitProject(doc: SysProMDocument, outputDir: string, prefix: string): void;