sysprom 1.17.0 → 1.19.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.
Files changed (76) hide show
  1. package/README.md +198 -87
  2. package/dist/schema.json +2 -1
  3. package/dist/src/cli/commands/graph.d.ts +15 -0
  4. package/dist/src/cli/commands/graph.js +51 -2
  5. package/dist/src/cli/commands/init.d.ts +1 -1
  6. package/dist/src/cli/commands/json2md.d.ts +30 -1
  7. package/dist/src/cli/commands/json2md.js +42 -1
  8. package/dist/src/cli/commands/md2json.d.ts +1 -1
  9. package/dist/src/cli/commands/sync.d.ts +1 -1
  10. package/dist/src/cli/define-command.d.ts +1 -1
  11. package/dist/src/cli/define-command.js +176 -156
  12. package/dist/src/endpoint-types.js +22 -7
  13. package/dist/src/json-to-md.d.ts +32 -2
  14. package/dist/src/json-to-md.js +145 -5
  15. package/dist/src/md-to-json.js +7 -0
  16. package/dist/src/operations/add-node.d.ts +12 -9
  17. package/dist/src/operations/add-plan-task.d.ts +8 -6
  18. package/dist/src/operations/add-relationship.d.ts +11 -8
  19. package/dist/src/operations/check.d.ts +4 -3
  20. package/dist/src/operations/define-operation.d.ts +1 -1
  21. package/dist/src/operations/graph-decision.d.ts +329 -0
  22. package/dist/src/operations/graph-decision.js +96 -0
  23. package/dist/src/operations/graph-dependency.d.ts +329 -0
  24. package/dist/src/operations/graph-dependency.js +121 -0
  25. package/dist/src/operations/graph-refinement.d.ts +329 -0
  26. package/dist/src/operations/graph-refinement.js +97 -0
  27. package/dist/src/operations/graph-shared.d.ts +116 -0
  28. package/dist/src/operations/graph-shared.js +257 -0
  29. package/dist/src/operations/graph.d.ts +20 -4
  30. package/dist/src/operations/graph.js +129 -36
  31. package/dist/src/operations/index.d.ts +3 -0
  32. package/dist/src/operations/index.js +3 -0
  33. package/dist/src/operations/infer-completeness.d.ts +4 -3
  34. package/dist/src/operations/infer-derived.d.ts +4 -3
  35. package/dist/src/operations/infer-impact.d.ts +28 -21
  36. package/dist/src/operations/infer-lifecycle.d.ts +4 -3
  37. package/dist/src/operations/init-document.d.ts +4 -3
  38. package/dist/src/operations/json-to-markdown.d.ts +28 -3
  39. package/dist/src/operations/json-to-markdown.js +11 -1
  40. package/dist/src/operations/mark-task-done.d.ts +8 -6
  41. package/dist/src/operations/mark-task-undone.d.ts +8 -6
  42. package/dist/src/operations/markdown-to-json.d.ts +4 -3
  43. package/dist/src/operations/next-id.d.ts +4 -3
  44. package/dist/src/operations/node-history.d.ts +4 -3
  45. package/dist/src/operations/plan-add-task.d.ts +8 -6
  46. package/dist/src/operations/plan-gate.d.ts +4 -3
  47. package/dist/src/operations/plan-init.d.ts +4 -3
  48. package/dist/src/operations/plan-progress.d.ts +4 -3
  49. package/dist/src/operations/plan-status.d.ts +4 -3
  50. package/dist/src/operations/query-node.d.ts +24 -17
  51. package/dist/src/operations/query-nodes.d.ts +8 -6
  52. package/dist/src/operations/query-relationships.d.ts +7 -5
  53. package/dist/src/operations/remove-node.d.ts +12 -9
  54. package/dist/src/operations/remove-relationship.d.ts +10 -7
  55. package/dist/src/operations/rename.d.ts +8 -6
  56. package/dist/src/operations/search.d.ts +8 -6
  57. package/dist/src/operations/speckit-diff.d.ts +4 -3
  58. package/dist/src/operations/speckit-export.d.ts +4 -3
  59. package/dist/src/operations/speckit-import.d.ts +4 -3
  60. package/dist/src/operations/speckit-sync.d.ts +12 -9
  61. package/dist/src/operations/state-at.d.ts +4 -3
  62. package/dist/src/operations/stats.d.ts +4 -3
  63. package/dist/src/operations/sync.d.ts +12 -9
  64. package/dist/src/operations/task-list.d.ts +4 -3
  65. package/dist/src/operations/timeline.d.ts +4 -3
  66. package/dist/src/operations/trace-from-node.d.ts +12 -9
  67. package/dist/src/operations/update-metadata.d.ts +8 -6
  68. package/dist/src/operations/update-node.d.ts +11 -8
  69. package/dist/src/operations/update-plan-task.d.ts +8 -6
  70. package/dist/src/operations/validate.d.ts +4 -3
  71. package/dist/src/schema.d.ts +15 -10
  72. package/dist/src/schema.js +3 -11
  73. package/dist/src/utils/define-schema.d.ts +17 -0
  74. package/dist/src/utils/define-schema.js +21 -0
  75. package/package.json +98 -93
  76. package/schema.json +2 -1
package/README.md CHANGED
@@ -23,51 +23,100 @@ Both `sysprom` and `spm` are available as commands — use `sysprom` for new pro
23
23
 
24
24
  ## CLI
25
25
 
26
- ```sh
26
+ ````sh
27
27
  # Convert between formats
28
28
  sysprom json2md --input .SysProM.json --output ./.SysProM
29
29
  sysprom md2json --input ./.SysProM --output output.SysProM.json
30
30
 
31
+ # Diagram and label options
32
+
33
+ The `graph` and `json2md` commands support options to control diagram layout and node label style used when generating Mermaid/DOT output.
34
+
35
+ Examples:
36
+
37
+ ```sh
38
+ # Generate a Mermaid graph with friendly labels (default)
39
+ sysprom graph --path .SysProM.json --format mermaid
40
+
41
+ # Compact node labels (IDs only) instead of `ID: Name`
42
+ sysprom graph --path .SysProM.json --format mermaid --label-mode compact
43
+
44
+ # Embed diagrams when converting JSON → Markdown, using compact labels
45
+ sysprom json2md --input .SysProM.json --output ./.SysProM --embed-diagrams --label-mode compact
46
+
47
+ # Control layout direction for graph (LR, TD, RL, BT)
48
+ sysprom graph --path .SysProM.json --format mermaid --layout LR
49
+ ````
50
+
51
+ Notes:
52
+
53
+ - `--label-mode friendly|compact` controls whether nodes show `ID: Name` (`friendly`) or just `ID` (`compact`).
54
+ - `--layout LR|TD|RL|BT` controls graph direction. `json2md` uses sensible per-diagram defaults (relationship/refinement/decision diagrams default to `TD`, dependency diagrams default to `LR`) but you can override when calling `graph` directly.
55
+ - `--label-mode friendly|compact` controls whether nodes show `ID: Name` (`friendly`) or just `ID` (`compact`).
56
+ - `--layout LR|TD|RL|BT` controls graph direction. `json2md` uses sensible per-diagram defaults (relationship/refinement/decision diagrams default to `TD`, dependency diagrams default to `LR`) but you can override when calling `graph` directly.
57
+ - `json2md` supports per-diagram layout overrides to control each embedded diagram independently:
58
+ - `--relationship-layout LR|TD|RL|BT` — override the layout used for the Relationship Graph.
59
+ - `--refinement-layout LR|TD|RL|BT` — override the layout used for the Refinement Chain.
60
+ - `--decision-layout LR|TD|RL|BT` — override the layout used for the Decision Map.
61
+ - `--dependency-layout LR|TD|RL|BT` — override the layout used for the Dependency Graph.
62
+
63
+ Examples:
64
+
65
+ ```sh
66
+ # Embed diagrams in multi-doc output but make dependency graph top-to-bottom (TD)
67
+ sysprom json2md --input .SysProM.json --output ./.SysProM --embed-diagrams --dependency-layout TD
68
+
69
+ # Override relationship and refinement layouts independently
70
+ sysprom json2md --input .SysProM.json --output ./.SysProM --embed-diagrams --relationship-layout LR --refinement-layout TD
71
+ ```
72
+
31
73
  # Validate and summarise (auto-detects .SysProM.json in current directory)
74
+
32
75
  sysprom validate
33
76
  sysprom stats
34
77
 
35
78
  # Query nodes and relationships
79
+
36
80
  sysprom query nodes --type decision
37
81
  sysprom query node D1
38
82
  sysprom query rels --from D1
39
83
  sysprom query trace I1
40
84
  sysprom query timeline
41
- sysprom query state-at 2026-03-22
85
+ sysprom query state-at <ISO-timestamp>
42
86
 
43
87
  # Add nodes (ID auto-generated from type prefix if --id omitted)
88
+
44
89
  sysprom add invariant --name "New Rule" --description "Must hold"
45
90
  sysprom add decision --name "Choose X" \
46
- --option "OPT-A:Use framework X" --option "OPT-B:Use framework Y" \
47
- --selected OPT-A --rationale "Lower migration effort"
91
+ --option "OPT-A:Use framework X" --option "OPT-B:Use framework Y" \
92
+ --selected OPT-A --rationale "Lower migration effort"
48
93
 
49
94
  # Remove nodes
95
+
50
96
  sysprom remove INV23
51
97
 
52
98
  # Update nodes, relationships, and metadata
99
+
53
100
  sysprom update node D1 --status deprecated
54
101
  sysprom update add-rel D1 affects EL5
55
102
  sysprom update remove-rel D1 affects EL5
56
103
  sysprom update meta --fields version=2
57
104
 
58
105
  # Inference operations (deterministic graph analysis)
59
- sysprom infer completeness # Score node completeness (0-1)
60
- sysprom infer lifecycle # Infer lifecycle phases
61
- sysprom infer impact I1 # Trace impact from node
62
- sysprom infer derived # Compute transitive closure
63
- sysprom infer all # Run all analyses
64
- ```
106
+
107
+ sysprom infer completeness # Score node completeness (0-1)
108
+ sysprom infer lifecycle # Infer lifecycle phases
109
+ sysprom infer impact I1 # Trace impact from node
110
+ sysprom infer derived # Compute transitive closure
111
+ sysprom infer all # Run all analyses
112
+
113
+ ````
65
114
 
66
115
  All commands auto-detect the document — they search the current directory for `.SysProM.json`, `.SysProM.md`, or `.SysProM/` (in that priority order), then fall back to `.spm.json`, `.spm.md`, or `.spm/`. Use `--path` to specify an explicit path. Note: `spm` is an alias for `sysprom` for backwards compatibility.
67
116
 
68
117
  ## MCP Server
69
118
 
70
- SysProM includes an MCP (Model Context Protocol) server exposing 15 tools over stdio transport. Any MCP-compatible agent — Cursor, Windsurf, VS Code Copilot, Cline, or custom clients — can use it.
119
+ SysProM includes an MCP (Model Context Protocol) server exposing tools over stdio transport. Any MCP-compatible agent — Cursor, Windsurf, VS Code Copilot, Cline, or custom clients — can use it.
71
120
 
72
121
  ### Configuration
73
122
 
@@ -82,7 +131,7 @@ Add the following to your MCP client's configuration (e.g. `.cursor/mcp.json`, `
82
131
  }
83
132
  }
84
133
  }
85
- ```
134
+ ````
86
135
 
87
136
  Or via the CLI subcommand (equivalent):
88
137
 
@@ -92,23 +141,23 @@ sysprom mcp # starts the MCP server on stdio
92
141
 
93
142
  ### Available Tools
94
143
 
95
- | Tool | Description |
96
- |------|-------------|
97
- | `validate` | Validate a SysProM document and return issues |
98
- | `stats` | Return document statistics |
99
- | `query-nodes` | Query nodes by type, status, or text |
100
- | `query-node` | Retrieve a single node by ID |
101
- | `query-relationships` | Query relationships by source, target, or type |
102
- | `trace` | Trace refinement chains from a node |
103
- | `add-node` | Add a new node to the document |
104
- | `remove-node` | Remove a node by ID |
105
- | `update-node` | Update fields on an existing node |
106
- | `add-relationship` | Add a relationship between nodes |
107
- | `remove-relationship` | Remove a relationship |
108
- | `infer-completeness` | Score node completeness (0-1) based on refinement relationships |
109
- | `infer-lifecycle` | Infer lifecycle phase from status and lifecycle fields |
110
- | `infer-impact` | Trace impact propagation from a starting node |
111
- | `infer-derived` | Compute transitive closure and inverse relationships |
144
+ | Tool | Description |
145
+ | --------------------- | --------------------------------------------------------------- |
146
+ | `validate` | Validate a SysProM document and return issues |
147
+ | `stats` | Return document statistics |
148
+ | `query-nodes` | Query nodes by type, status, or text |
149
+ | `query-node` | Retrieve a single node by ID |
150
+ | `query-relationships` | Query relationships by source, target, or type |
151
+ | `trace` | Trace refinement chains from a node |
152
+ | `add-node` | Add a new node to the document |
153
+ | `remove-node` | Remove a node by ID |
154
+ | `update-node` | Update fields on an existing node |
155
+ | `add-relationship` | Add a relationship between nodes |
156
+ | `remove-relationship` | Remove a relationship |
157
+ | `infer-completeness` | Score node completeness (0-1) based on refinement relationships |
158
+ | `infer-lifecycle` | Infer lifecycle phase from status and lifecycle fields |
159
+ | `infer-impact` | Trace impact propagation from a starting node |
160
+ | `infer-derived` | Compute transitive closure and inverse relationships |
112
161
 
113
162
  All tools accept a `path` parameter to specify the SysProM document location.
114
163
 
@@ -116,50 +165,50 @@ All tools accept a `path` parameter to specify the SysProM document location.
116
165
 
117
166
  ```ts
118
167
  import {
119
- // Schema and types
120
- sysproMDocument,
121
- node,
122
- nodeType,
123
- relationshipType,
124
- type SysProMDocument,
125
- type Node,
126
- type Relationship,
127
-
128
- // Conversion
129
- jsonToMarkdown,
130
- jsonToMarkdownSingle,
131
- jsonToMarkdownMultiDoc,
132
- markdownToJson,
133
-
134
- // Validation and query
135
- validate,
136
- stats,
137
- queryNodes,
138
- queryNode,
139
- queryRelationships,
140
- traceFromNode,
141
-
142
- // Mutation
143
- addNode,
144
- removeNode,
145
- updateNode,
146
- addRelationship,
147
- removeRelationship,
148
- updateMetadata,
149
-
150
- // Inference
151
- inferCompletenessOp,
152
- inferLifecycleOp,
153
- inferImpactOp,
154
- inferDerivedOp,
155
-
156
- // File I/O
157
- loadDocument,
158
- saveDocument,
159
-
160
- // Utilities
161
- canonicalise,
162
- toJSONSchema,
168
+ // Schema and types
169
+ sysproMDocument,
170
+ node,
171
+ nodeType,
172
+ relationshipType,
173
+ type SysProMDocument,
174
+ type Node,
175
+ type Relationship,
176
+
177
+ // Conversion
178
+ jsonToMarkdown,
179
+ jsonToMarkdownSingle,
180
+ jsonToMarkdownMultiDoc,
181
+ markdownToJson,
182
+
183
+ // Validation and query
184
+ validate,
185
+ stats,
186
+ queryNodes,
187
+ queryNode,
188
+ queryRelationships,
189
+ traceFromNode,
190
+
191
+ // Mutation
192
+ addNode,
193
+ removeNode,
194
+ updateNode,
195
+ addRelationship,
196
+ removeRelationship,
197
+ updateMetadata,
198
+
199
+ // Inference
200
+ inferCompletenessOp,
201
+ inferLifecycleOp,
202
+ inferImpactOp,
203
+ inferDerivedOp,
204
+
205
+ // File I/O
206
+ loadDocument,
207
+ saveDocument,
208
+
209
+ // Utilities
210
+ canonicalise,
211
+ toJSONSchema,
163
212
  } from "sysprom";
164
213
 
165
214
  // Validate
@@ -172,18 +221,71 @@ const decisions = queryNodes(doc, { type: "decision" });
172
221
  const trace = traceFromNode(doc, "I1");
173
222
 
174
223
  // Mutate
175
- const updated = addNode(doc, { id: "INV23", type: "invariant", name: "New Rule" });
176
- const withRel = addRelationship(updated, { from: "D1", to: "INV23", type: "must_preserve" });
224
+ const updated = addNode(doc, {
225
+ id: "INV23",
226
+ type: "invariant",
227
+ name: "New Rule",
228
+ });
229
+ const withRel = addRelationship(updated, {
230
+ from: "D1",
231
+ to: "INV23",
232
+ type: "must_preserve",
233
+ });
177
234
 
178
235
  // Type guards
179
- if (sysproMDocument.is(data)) { /* data is SysProMDocument */ }
180
- if (node.is(thing)) { /* thing is Node */ }
236
+ if (sysproMDocument.is(data)) {
237
+ /* data is SysProMDocument */
238
+ }
239
+ if (node.is(thing)) {
240
+ /* thing is Node */
241
+ }
181
242
  ```
182
243
 
183
244
  ## What is SysProM?
184
245
 
185
246
  SysProM models systems as directed graphs across abstraction layers — intent, concept, capability, structure, and realisation — with explicit decisions, changes, and invariants. It is domain-agnostic, format-agnostic, and recursively composable.
186
247
 
248
+ ## System Provenance Profile
249
+
250
+ For product repositories, use SysProM to model the specification, design, and implementation of the system being built.
251
+
252
+ Recommended node usage:
253
+
254
+ - `intent`: user outcomes, business goals, and product promises
255
+ - `concept`: domain concepts, behavioural boundaries, and system rules
256
+ - `capability`: user-visible or externally meaningful system behaviours
257
+ - `element`: architectural components, services, stores, queues, and UI surfaces
258
+ - `realisation`: implementation units such as packages, modules, handlers, schemas, and jobs
259
+ - `protocol`: workflows and lifecycle paths such as review, publish, sync, or ingestion flows
260
+ - `artefact`: API contracts, documents, prompts, tests, migrations, and generated outputs
261
+ - `decision`: selected trade-offs and architectural choices
262
+ - `change`: implementation slices or delivery units
263
+ - `role`: human or system actors
264
+ - `view`: curated slices such as specification, architecture, implementation, and operations
265
+
266
+ Recommended trace chain:
267
+
268
+ ```text
269
+ intent -> concept -> capability -> element -> realisation -> artefact
270
+ ```
271
+
272
+ Recommended relationship usage:
273
+
274
+ - `refines`: tighten intent into concepts and concepts into capabilities
275
+ - `part_of`: decompose concepts, protocols, capabilities, and architecture structures
276
+ - `realises`: connect design structures to implementation structures
277
+ - `produces`: connect capabilities or stages to the artefacts they generate
278
+ - `performs`: connect roles to capabilities, stages, protocols, and operational concepts
279
+ - `governed_by` / `constrained_by`: express rules, policies, and invariants on design and implementation
280
+ - `implements` / `modifies`: connect delivery changes to the nodes they implement or alter
281
+ - `affects` + `must_preserve`: connect decisions to impacted areas and their protected invariants
282
+
283
+ Recommended implementation provenance:
284
+
285
+ - use `external_references` on `realisation` nodes to point to code paths, packages, handlers, or schemas
286
+ - use `external_references` on `artefact` nodes to point to API definitions, test files, migrations, docs, PRs, and generated outputs
287
+ - use `status`, `scope`, and decision/change links so the graph can answer both “what is the design?” and “what has actually been built?”
288
+
187
289
  ## How SysProM Compares
188
290
 
189
291
  <table>
@@ -302,7 +404,7 @@ sysprom md2json --input ./.SysProM --output .SysProM.json
302
404
 
303
405
  ## Claude Code Plugin
304
406
 
305
- SysProM is available as a Claude Code plugin with 28 skills for managing provenance documents. The plugin is defined in `.claude-plugin/marketplace.json` with skills in `.claude/skills/`.
407
+ SysProM is available as a Claude Code plugin with skills for managing provenance documents. The plugin is defined in `.claude-plugin/marketplace.json` with skills in `.claude/skills/`.
306
408
 
307
409
  ### Install from Marketplace
308
410
 
@@ -322,49 +424,58 @@ When working on the SysProM repo itself, skills in `.claude/skills/` are auto-di
322
424
 
323
425
  ### Skills by Category
324
426
 
325
- **Node Creation (4 skills)**
427
+ **Node Creation**
428
+
326
429
  - `add-decision` — Create decision nodes with context, options, rationale, and invariant links
327
430
  - `add-change` — Create change nodes with scope, operations, and task tracking
328
431
  - `add-invariant` — Create invariant nodes representing system rules and constraints
329
432
  - `add-node` — Generic node creation for any SysProM type
330
433
 
331
- **Node Modification (3 skills)**
434
+ **Node Modification**
435
+
332
436
  - `update-node` — Modify node fields, status, lifecycle, context, or rationale
333
437
  - `remove-node` — Delete nodes with safety flags (hard delete, recursive, repair)
334
438
  - `rename-node` — Rename node IDs across all references
335
439
 
336
- **Relationships (2 skills)**
440
+ **Relationships**
441
+
337
442
  - `add-relationship` — Create relationships between nodes with specific types
338
443
  - `remove-relationship` — Delete relationships
339
444
 
340
- **Query & Analysis (5 skills)**
445
+ **Query & Analysis**
446
+
341
447
  - `query-nodes` — Search nodes by type, status, text, or ID
342
448
  - `query-relationships` — Query relationships by source, target, or type
343
449
  - `trace-node` — Trace refinement chains through abstraction layers
344
450
  - `check-document` — Validate document structure and report issues
345
451
  - `stats` — Show document statistics and composition metrics
346
452
 
347
- **Visualisation (1 skill)**
453
+ **Visualisation**
454
+
348
455
  - `graph` — Generate Mermaid or DOT graphs with filtering
349
456
 
350
- **Format Conversion (4 skills)**
457
+ **Format Conversion**
458
+
351
459
  - `init-document` — Create new SysProM documents with metadata
352
460
  - `json-to-markdown` — Convert JSON to Markdown format
353
461
  - `markdown-to-json` — Convert Markdown to JSON format
354
462
  - `sync-formats` — Bidirectional sync between JSON and Markdown
355
463
 
356
- **Spec-Kit Integration (4 skills)**
464
+ **Spec-Kit Integration**
465
+
357
466
  - `speckit-import` — Import Spec-Kit features as SysProM nodes
358
467
  - `speckit-export` — Export SysProM nodes to Spec-Kit format
359
468
  - `speckit-sync` — Bidirectional sync with Spec-Kit specifications
360
469
  - `speckit-diff` — Show differences between SysProM and Spec-Kit
361
470
 
362
- **Task Management (3 skills)**
471
+ **Task Management**
472
+
363
473
  - `task-list` — List tasks in a change node with progress
364
474
  - `task-add` — Add tasks to a change
365
475
  - `task-mark-done` — Mark tasks as complete
366
476
 
367
- **Plan Management (2 skills)**
477
+ **Plan Management**
478
+
368
479
  - `plan-init` — Initialise plans with phases and gates
369
480
  - `plan-status` — Show plan progress and phase gates
370
481
 
package/dist/schema.json CHANGED
@@ -504,7 +504,8 @@
504
504
  "selects",
505
505
  "requires",
506
506
  "disables",
507
- "influence"
507
+ "influence",
508
+ "justifies"
508
509
  ],
509
510
  "type": "string"
510
511
  }
@@ -9,6 +9,21 @@ declare const optsSchema: z.ZodObject<{
9
9
  mermaid: "mermaid";
10
10
  }>>;
11
11
  type: z.ZodOptional<z.ZodString>;
12
+ nodeTypes: z.ZodOptional<z.ZodString>;
13
+ nodeIds: z.ZodOptional<z.ZodString>;
14
+ relTypes: z.ZodOptional<z.ZodString>;
15
+ layout: z.ZodOptional<z.ZodEnum<{
16
+ TD: "TD";
17
+ BT: "BT";
18
+ RL: "RL";
19
+ LR: "LR";
20
+ }>>;
21
+ labelMode: z.ZodOptional<z.ZodEnum<{
22
+ friendly: "friendly";
23
+ compact: "compact";
24
+ }>>;
25
+ cluster: z.ZodOptional<z.ZodBoolean>;
26
+ connectedOnly: z.ZodOptional<z.ZodBoolean>;
12
27
  }, z.core.$strip>;
13
28
  export declare const graphCommand: CommandDef<typeof noArgs, typeof optsSchema>;
14
29
  export {};
@@ -1,9 +1,41 @@
1
+ /// <reference types="node" />
1
2
  import * as z from "zod";
2
3
  import { graphOp } from "../../operations/index.js";
3
4
  import { readOpts, loadDoc } from "../shared.js";
4
5
  const optsSchema = readOpts.extend({
5
6
  format: z.enum(["mermaid", "dot"]).optional().describe("Output format"),
6
- type: z.string().optional().describe("Filter by relationship type"),
7
+ type: z
8
+ .string()
9
+ .optional()
10
+ .describe("Filter by relationship type (backward compatible)"),
11
+ nodeTypes: z
12
+ .string()
13
+ .optional()
14
+ .describe("Filter by node types (comma-separated)"),
15
+ nodeIds: z
16
+ .string()
17
+ .optional()
18
+ .describe("Filter by node IDs (comma-separated)"),
19
+ relTypes: z
20
+ .string()
21
+ .optional()
22
+ .describe("Filter by relationship types (comma-separated)"),
23
+ layout: z
24
+ .enum(["LR", "TD", "RL", "BT"])
25
+ .optional()
26
+ .describe("Graph layout direction"),
27
+ labelMode: z
28
+ .enum(["friendly", "compact"])
29
+ .optional()
30
+ .describe('Node label mode: "friendly" shows `id: name`, "compact" shows `id`'),
31
+ cluster: z
32
+ .boolean()
33
+ .optional()
34
+ .describe("Group nodes by category in subgraphs"),
35
+ connectedOnly: z
36
+ .boolean()
37
+ .optional()
38
+ .describe("Only show nodes that have relationships"),
7
39
  });
8
40
  export const graphCommand = {
9
41
  name: "graph",
@@ -13,15 +45,32 @@ export const graphCommand = {
13
45
  action(_args, opts) {
14
46
  try {
15
47
  const { doc } = loadDoc(opts.path);
48
+ const nodeTypes = opts.nodeTypes
49
+ ? opts.nodeTypes.split(",").map((s) => s.trim())
50
+ : undefined;
51
+ const nodeIds = opts.nodeIds
52
+ ? opts.nodeIds.split(",").map((s) => s.trim())
53
+ : undefined;
54
+ const relTypes = opts.relTypes
55
+ ? opts.relTypes.split(",").map((s) => s.trim())
56
+ : undefined;
16
57
  const output = graphOp({
17
58
  doc,
18
59
  format: opts.format ?? "mermaid",
19
60
  typeFilter: opts.type,
61
+ nodeTypes,
62
+ nodeIds,
63
+ relTypes,
64
+ layout: opts.layout ?? "TD",
65
+ cluster: opts.cluster ?? true,
66
+ labelMode: opts.labelMode ?? "friendly",
67
+ connectedOnly: opts.connectedOnly ?? false,
20
68
  });
21
69
  console.log(output);
22
70
  }
23
71
  catch (err) {
24
- console.error(err instanceof Error ? err.message : String(err));
72
+ const message = err instanceof Error ? err.message : String(err);
73
+ console.error(message);
25
74
  process.exit(1);
26
75
  }
27
76
  },
@@ -10,5 +10,5 @@ declare const optsSchema: z.ZodObject<{
10
10
  dir: "dir";
11
11
  }>>;
12
12
  }, z.core.$strict>;
13
- export declare const initCommand: CommandDef<z.ZodObject<z.ZodRawShape>, typeof optsSchema>;
13
+ export declare const initCommand: CommandDef<z.ZodObject, typeof optsSchema>;
14
14
  export {};
@@ -4,6 +4,35 @@ declare const optsSchema: z.ZodObject<{
4
4
  input: z.ZodString;
5
5
  output: z.ZodString;
6
6
  singleFile: z.ZodOptional<z.ZodBoolean>;
7
+ embedDiagrams: z.ZodOptional<z.ZodBoolean>;
8
+ labelMode: z.ZodOptional<z.ZodEnum<{
9
+ friendly: "friendly";
10
+ compact: "compact";
11
+ }>>;
12
+ relationshipLayout: z.ZodOptional<z.ZodEnum<{
13
+ TD: "TD";
14
+ BT: "BT";
15
+ RL: "RL";
16
+ LR: "LR";
17
+ }>>;
18
+ refinementLayout: z.ZodOptional<z.ZodEnum<{
19
+ TD: "TD";
20
+ BT: "BT";
21
+ RL: "RL";
22
+ LR: "LR";
23
+ }>>;
24
+ decisionLayout: z.ZodOptional<z.ZodEnum<{
25
+ TD: "TD";
26
+ BT: "BT";
27
+ RL: "RL";
28
+ LR: "LR";
29
+ }>>;
30
+ dependencyLayout: z.ZodOptional<z.ZodEnum<{
31
+ TD: "TD";
32
+ BT: "BT";
33
+ RL: "RL";
34
+ LR: "LR";
35
+ }>>;
7
36
  }, z.core.$strict>;
8
- export declare const json2mdCommand: CommandDef<z.ZodObject<z.ZodRawShape>, typeof optsSchema>;
37
+ export declare const json2mdCommand: CommandDef<z.ZodObject, typeof optsSchema>;
9
38
  export {};
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import * as z from "zod";
2
3
  import { readFileSync } from "node:fs";
3
4
  import { resolve } from "node:path";
@@ -12,6 +13,30 @@ const optsSchema = z
12
13
  .boolean()
13
14
  .optional()
14
15
  .describe("Force single-file output format"),
16
+ embedDiagrams: z
17
+ .boolean()
18
+ .optional()
19
+ .describe("Embed Mermaid diagrams in the output"),
20
+ labelMode: z
21
+ .enum(["friendly", "compact"])
22
+ .optional()
23
+ .describe("Node label mode for embedded diagrams"),
24
+ relationshipLayout: z
25
+ .enum(["LR", "TD", "RL", "BT"])
26
+ .optional()
27
+ .describe("Override layout for relationship diagrams"),
28
+ refinementLayout: z
29
+ .enum(["LR", "TD", "RL", "BT"])
30
+ .optional()
31
+ .describe("Override layout for refinement diagrams"),
32
+ decisionLayout: z
33
+ .enum(["LR", "TD", "RL", "BT"])
34
+ .optional()
35
+ .describe("Override layout for decision diagrams"),
36
+ dependencyLayout: z
37
+ .enum(["LR", "TD", "RL", "BT"])
38
+ .optional()
39
+ .describe("Override layout for dependency diagrams"),
15
40
  })
16
41
  .strict();
17
42
  export const json2mdCommand = {
@@ -23,6 +48,7 @@ export const json2mdCommand = {
23
48
  const inputPath = resolve(opts.input);
24
49
  const outputPath = resolve(opts.output);
25
50
  const raw = JSON.parse(readFileSync(inputPath, "utf8"));
51
+ // Use the attached type guard for clearer intent and narrower runtime checks
26
52
  if (!SysProMDocument.is(raw)) {
27
53
  const result = SysProMDocument.safeParse(raw);
28
54
  if (!result.success) {
@@ -36,7 +62,22 @@ export const json2mdCommand = {
36
62
  const form = opts.singleFile || outputPath.endsWith(".md")
37
63
  ? "single-file"
38
64
  : "multi-doc";
39
- jsonToMarkdown(raw, outputPath, { form });
65
+ // Forward per-diagram layout overrides via environment-like flags.
66
+ // We accept flags on the command line for common diagram layouts but also
67
+ // preserve sensible per-diagram defaults in jsonToMarkdown when not set.
68
+ // For now we expose a single --label-mode flag and keep per-diagram layout
69
+ // defaults internal; a future enhancement could expose per-diagram
70
+ // flags such as --relationship-layout, --dependency-layout, etc.
71
+ jsonToMarkdown(raw, outputPath, {
72
+ form,
73
+ embedDiagrams: opts.embedDiagrams,
74
+ // forward labelMode for embedded diagrams (default friendly)
75
+ labelMode: opts.labelMode ?? "friendly",
76
+ relationshipLayout: opts.relationshipLayout,
77
+ refinementLayout: opts.refinementLayout,
78
+ decisionLayout: opts.decisionLayout,
79
+ dependencyLayout: opts.dependencyLayout,
80
+ });
40
81
  if (form === "single-file") {
41
82
  console.log(`Written to ${outputPath}`);
42
83
  }
@@ -4,5 +4,5 @@ declare const optsSchema: z.ZodObject<{
4
4
  input: z.ZodString;
5
5
  output: z.ZodString;
6
6
  }, z.core.$strict>;
7
- export declare const md2jsonCommand: CommandDef<z.ZodObject<z.ZodRawShape>, typeof optsSchema>;
7
+ export declare const md2jsonCommand: CommandDef<z.ZodObject, typeof optsSchema>;
8
8
  export {};
@@ -23,5 +23,5 @@ declare const syncOpts: z.ZodObject<{
23
23
  dryRun: z.ZodOptional<z.ZodBoolean>;
24
24
  report: z.ZodOptional<z.ZodBoolean>;
25
25
  }, z.core.$strict>;
26
- export declare const syncCommandDef: CommandDef<z.ZodObject<z.ZodRawShape>, typeof syncOpts>;
26
+ export declare const syncCommandDef: CommandDef<z.ZodObject, typeof syncOpts>;
27
27
  export {};
@@ -1,7 +1,7 @@
1
1
  import * as z from "zod";
2
2
  import { Command } from "commander";
3
3
  /** Definition of a CLI command — name, description, Zod schemas for args/opts, optional subcommands, and action handler. */
4
- export interface CommandDef<TArgs extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>, TOpts extends z.ZodObject<z.ZodRawShape> = z.ZodObject<z.ZodRawShape>> {
4
+ export interface CommandDef<TArgs extends z.ZodObject = z.ZodObject, TOpts extends z.ZodObject = z.ZodObject> {
5
5
  name: string;
6
6
  description: string;
7
7
  args?: TArgs;