sysprom 1.17.0 → 1.18.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 +145 -75
  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 +13 -6
  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
@@ -0,0 +1,329 @@
1
+ import * as z from "zod";
2
+ /** Generate a dependency graph showing how nodes depend on, constrain, and require each other. */
3
+ export declare const graphDependencyOp: import("./define-operation.js").DefinedOperation<z.ZodObject<{
4
+ doc: z.ZodObject<{
5
+ $schema: z.ZodOptional<z.ZodString>;
6
+ metadata: z.ZodOptional<z.ZodObject<{
7
+ title: z.ZodOptional<z.ZodString>;
8
+ doc_type: z.ZodOptional<z.ZodString>;
9
+ scope: z.ZodOptional<z.ZodString>;
10
+ status: z.ZodOptional<z.ZodString>;
11
+ version: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodInt]>>;
12
+ }, z.core.$loose> & {
13
+ is(value: unknown): value is {
14
+ [x: string]: unknown;
15
+ title?: string | undefined;
16
+ doc_type?: string | undefined;
17
+ scope?: string | undefined;
18
+ status?: string | undefined;
19
+ version?: string | number | undefined;
20
+ };
21
+ }>;
22
+ nodes: z.ZodArray<z.ZodObject<{
23
+ id: z.ZodString;
24
+ type: z.ZodEnum<{
25
+ intent: "intent";
26
+ concept: "concept";
27
+ capability: "capability";
28
+ element: "element";
29
+ realisation: "realisation";
30
+ invariant: "invariant";
31
+ principle: "principle";
32
+ policy: "policy";
33
+ protocol: "protocol";
34
+ stage: "stage";
35
+ role: "role";
36
+ gate: "gate";
37
+ mode: "mode";
38
+ artefact: "artefact";
39
+ artefact_flow: "artefact_flow";
40
+ decision: "decision";
41
+ change: "change";
42
+ view: "view";
43
+ milestone: "milestone";
44
+ version: "version";
45
+ }> & {
46
+ is(value: unknown): value is "intent" | "concept" | "capability" | "element" | "realisation" | "invariant" | "principle" | "policy" | "protocol" | "stage" | "role" | "gate" | "mode" | "artefact" | "artefact_flow" | "decision" | "change" | "view" | "milestone" | "version";
47
+ };
48
+ name: z.ZodString;
49
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
50
+ is(value: unknown): value is string | string[];
51
+ }>;
52
+ status: z.ZodOptional<z.ZodEnum<{
53
+ deprecated: "deprecated";
54
+ proposed: "proposed";
55
+ accepted: "accepted";
56
+ active: "active";
57
+ implemented: "implemented";
58
+ adopted: "adopted";
59
+ defined: "defined";
60
+ introduced: "introduced";
61
+ in_progress: "in_progress";
62
+ complete: "complete";
63
+ consolidated: "consolidated";
64
+ experimental: "experimental";
65
+ retired: "retired";
66
+ superseded: "superseded";
67
+ abandoned: "abandoned";
68
+ deferred: "deferred";
69
+ }> & {
70
+ is(value: unknown): value is "deprecated" | "proposed" | "accepted" | "active" | "implemented" | "adopted" | "defined" | "introduced" | "in_progress" | "complete" | "consolidated" | "experimental" | "retired" | "superseded" | "abandoned" | "deferred";
71
+ }>;
72
+ lifecycle: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>>;
73
+ context: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
74
+ is(value: unknown): value is string | string[];
75
+ }>;
76
+ options: z.ZodOptional<z.ZodArray<z.ZodObject<{
77
+ id: z.ZodString;
78
+ description: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
79
+ is(value: unknown): value is string | string[];
80
+ };
81
+ }, z.core.$loose> & {
82
+ is(value: unknown): value is {
83
+ [x: string]: unknown;
84
+ id: string;
85
+ description: string | string[];
86
+ };
87
+ }>>;
88
+ selected: z.ZodOptional<z.ZodString>;
89
+ rationale: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
90
+ is(value: unknown): value is string | string[];
91
+ }>;
92
+ scope: z.ZodOptional<z.ZodArray<z.ZodString>>;
93
+ operations: z.ZodOptional<z.ZodArray<z.ZodObject<{
94
+ type: z.ZodEnum<{
95
+ link: "link";
96
+ add: "add";
97
+ update: "update";
98
+ remove: "remove";
99
+ }>;
100
+ target: z.ZodOptional<z.ZodString>;
101
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
102
+ is(value: unknown): value is string | string[];
103
+ }>;
104
+ }, z.core.$loose> & {
105
+ is(value: unknown): value is {
106
+ [x: string]: unknown;
107
+ type: "link" | "add" | "update" | "remove";
108
+ target?: string | undefined;
109
+ description?: string | string[] | undefined;
110
+ };
111
+ }>>;
112
+ plan: z.ZodOptional<z.ZodArray<z.ZodObject<{
113
+ description: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
114
+ is(value: unknown): value is string | string[];
115
+ };
116
+ done: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
117
+ }, z.core.$loose> & {
118
+ is(value: unknown): value is {
119
+ [x: string]: unknown;
120
+ description: string | string[];
121
+ done?: boolean | undefined;
122
+ };
123
+ }>>;
124
+ propagation: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
125
+ includes: z.ZodOptional<z.ZodArray<z.ZodString>>;
126
+ input: z.ZodOptional<z.ZodString>;
127
+ output: z.ZodOptional<z.ZodString>;
128
+ external_references: z.ZodOptional<z.ZodArray<z.ZodObject<{
129
+ role: z.ZodEnum<{
130
+ output: "output";
131
+ input: "input";
132
+ context: "context";
133
+ evidence: "evidence";
134
+ source: "source";
135
+ standard: "standard";
136
+ prior_art: "prior_art";
137
+ }> & {
138
+ is(value: unknown): value is "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
139
+ };
140
+ identifier: z.ZodString;
141
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
142
+ is(value: unknown): value is string | string[];
143
+ }>;
144
+ node_id: z.ZodOptional<z.ZodString>;
145
+ internalised: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
146
+ is(value: unknown): value is string | string[];
147
+ }>;
148
+ }, z.core.$strip> & {
149
+ is(value: unknown): value is {
150
+ role: "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
151
+ identifier: string;
152
+ description?: string | string[] | undefined;
153
+ node_id?: string | undefined;
154
+ internalised?: string | string[] | undefined;
155
+ };
156
+ }>>;
157
+ readonly subsystem: z.ZodOptional<z.ZodObject</*elided*/ any, z.core.$strip>>;
158
+ }, z.core.$loose>>;
159
+ relationships: z.ZodOptional<z.ZodArray<z.ZodObject<{
160
+ from: z.ZodString;
161
+ to: z.ZodString;
162
+ type: z.ZodEnum<{
163
+ refines: "refines";
164
+ realises: "realises";
165
+ implements: "implements";
166
+ depends_on: "depends_on";
167
+ constrained_by: "constrained_by";
168
+ affects: "affects";
169
+ supersedes: "supersedes";
170
+ must_preserve: "must_preserve";
171
+ performs: "performs";
172
+ part_of: "part_of";
173
+ precedes: "precedes";
174
+ must_follow: "must_follow";
175
+ blocks: "blocks";
176
+ routes_to: "routes_to";
177
+ governed_by: "governed_by";
178
+ modifies: "modifies";
179
+ triggered_by: "triggered_by";
180
+ applies_to: "applies_to";
181
+ produces: "produces";
182
+ consumes: "consumes";
183
+ transforms_into: "transforms_into";
184
+ selects: "selects";
185
+ requires: "requires";
186
+ disables: "disables";
187
+ influence: "influence";
188
+ justifies: "justifies";
189
+ }> & {
190
+ is(value: unknown): value is "refines" | "realises" | "implements" | "depends_on" | "constrained_by" | "affects" | "supersedes" | "must_preserve" | "performs" | "part_of" | "precedes" | "must_follow" | "blocks" | "routes_to" | "governed_by" | "modifies" | "triggered_by" | "applies_to" | "produces" | "consumes" | "transforms_into" | "selects" | "requires" | "disables" | "influence" | "justifies";
191
+ };
192
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
193
+ is(value: unknown): value is string | string[];
194
+ }>;
195
+ polarity: z.ZodOptional<z.ZodEnum<{
196
+ positive: "positive";
197
+ negative: "negative";
198
+ neutral: "neutral";
199
+ uncertain: "uncertain";
200
+ }> & {
201
+ is(value: unknown): value is "positive" | "negative" | "neutral" | "uncertain";
202
+ }>;
203
+ strength: z.ZodOptional<z.ZodNumber>;
204
+ }, z.core.$loose> & {
205
+ is(value: unknown): value is {
206
+ [x: string]: unknown;
207
+ from: string;
208
+ to: string;
209
+ type: "refines" | "realises" | "implements" | "depends_on" | "constrained_by" | "affects" | "supersedes" | "must_preserve" | "performs" | "part_of" | "precedes" | "must_follow" | "blocks" | "routes_to" | "governed_by" | "modifies" | "triggered_by" | "applies_to" | "produces" | "consumes" | "transforms_into" | "selects" | "requires" | "disables" | "influence" | "justifies";
210
+ description?: string | string[] | undefined;
211
+ polarity?: "positive" | "negative" | "neutral" | "uncertain" | undefined;
212
+ strength?: number | undefined;
213
+ };
214
+ }>>;
215
+ external_references: z.ZodOptional<z.ZodArray<z.ZodObject<{
216
+ role: z.ZodEnum<{
217
+ output: "output";
218
+ input: "input";
219
+ context: "context";
220
+ evidence: "evidence";
221
+ source: "source";
222
+ standard: "standard";
223
+ prior_art: "prior_art";
224
+ }> & {
225
+ is(value: unknown): value is "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
226
+ };
227
+ identifier: z.ZodString;
228
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
229
+ is(value: unknown): value is string | string[];
230
+ }>;
231
+ node_id: z.ZodOptional<z.ZodString>;
232
+ internalised: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
233
+ is(value: unknown): value is string | string[];
234
+ }>;
235
+ }, z.core.$strip> & {
236
+ is(value: unknown): value is {
237
+ role: "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
238
+ identifier: string;
239
+ description?: string | string[] | undefined;
240
+ node_id?: string | undefined;
241
+ internalised?: string | string[] | undefined;
242
+ };
243
+ }>>;
244
+ }, z.core.$strip> & {
245
+ is(value: unknown): value is {
246
+ nodes: {
247
+ [x: string]: unknown;
248
+ id: string;
249
+ type: "intent" | "concept" | "capability" | "element" | "realisation" | "invariant" | "principle" | "policy" | "protocol" | "stage" | "role" | "gate" | "mode" | "artefact" | "artefact_flow" | "decision" | "change" | "view" | "milestone" | "version";
250
+ name: string;
251
+ description?: string | string[] | undefined;
252
+ status?: "deprecated" | "proposed" | "accepted" | "active" | "implemented" | "adopted" | "defined" | "introduced" | "in_progress" | "complete" | "consolidated" | "experimental" | "retired" | "superseded" | "abandoned" | "deferred" | undefined;
253
+ lifecycle?: Record<string, string | boolean> | undefined;
254
+ context?: string | string[] | undefined;
255
+ options?: {
256
+ [x: string]: unknown;
257
+ id: string;
258
+ description: string | string[];
259
+ }[] | undefined;
260
+ selected?: string | undefined;
261
+ rationale?: string | string[] | undefined;
262
+ scope?: string[] | undefined;
263
+ operations?: {
264
+ [x: string]: unknown;
265
+ type: "link" | "add" | "update" | "remove";
266
+ target?: string | undefined;
267
+ description?: string | string[] | undefined;
268
+ }[] | undefined;
269
+ plan?: {
270
+ [x: string]: unknown;
271
+ description: string | string[];
272
+ done?: boolean | undefined;
273
+ }[] | undefined;
274
+ propagation?: Record<string, boolean> | undefined;
275
+ includes?: string[] | undefined;
276
+ input?: string | undefined;
277
+ output?: string | undefined;
278
+ external_references?: {
279
+ role: "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
280
+ identifier: string;
281
+ description?: string | string[] | undefined;
282
+ node_id?: string | undefined;
283
+ internalised?: string | string[] | undefined;
284
+ }[] | undefined;
285
+ subsystem?: /*elided*/ any | undefined;
286
+ }[];
287
+ $schema?: string | undefined;
288
+ metadata?: {
289
+ [x: string]: unknown;
290
+ title?: string | undefined;
291
+ doc_type?: string | undefined;
292
+ scope?: string | undefined;
293
+ status?: string | undefined;
294
+ version?: string | number | undefined;
295
+ } | undefined;
296
+ relationships?: {
297
+ [x: string]: unknown;
298
+ from: string;
299
+ to: string;
300
+ type: "refines" | "realises" | "implements" | "depends_on" | "constrained_by" | "affects" | "supersedes" | "must_preserve" | "performs" | "part_of" | "precedes" | "must_follow" | "blocks" | "routes_to" | "governed_by" | "modifies" | "triggered_by" | "applies_to" | "produces" | "consumes" | "transforms_into" | "selects" | "requires" | "disables" | "influence" | "justifies";
301
+ description?: string | string[] | undefined;
302
+ polarity?: "positive" | "negative" | "neutral" | "uncertain" | undefined;
303
+ strength?: number | undefined;
304
+ }[] | undefined;
305
+ external_references?: {
306
+ role: "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
307
+ identifier: string;
308
+ description?: string | string[] | undefined;
309
+ node_id?: string | undefined;
310
+ internalised?: string | string[] | undefined;
311
+ }[] | undefined;
312
+ };
313
+ };
314
+ format: z.ZodDefault<z.ZodEnum<{
315
+ dot: "dot";
316
+ mermaid: "mermaid";
317
+ }>>;
318
+ seedIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
319
+ layout: z.ZodDefault<z.ZodEnum<{
320
+ TD: "TD";
321
+ BT: "BT";
322
+ RL: "RL";
323
+ LR: "LR";
324
+ }>>;
325
+ labelMode: z.ZodDefault<z.ZodEnum<{
326
+ friendly: "friendly";
327
+ compact: "compact";
328
+ }>>;
329
+ }, z.core.$strip>, z.ZodString>;
@@ -0,0 +1,121 @@
1
+ import * as z from "zod";
2
+ import { defineOperation } from "./define-operation.js";
3
+ import { SysProMDocument } from "../schema.js";
4
+ import { sanitiseMermaidId, mermaidShapeForNode, renderMermaidNode, renderMermaidClassDefs, mermaidClassForNode, dotNodeAttrsWithMode, renderRelationshipLabel, } from "./graph-shared.js";
5
+ const DEPENDENCY_REL_TYPES = new Set([
6
+ "depends_on",
7
+ "constrained_by",
8
+ "requires",
9
+ "blocks",
10
+ "governed_by",
11
+ ]);
12
+ function collectDependencyGraph(doc, seedIds) {
13
+ const rels = (doc.relationships ?? []).filter((r) => DEPENDENCY_REL_TYPES.has(r.type));
14
+ if (seedIds && seedIds.length > 0) {
15
+ const reachable = new Set(seedIds);
16
+ let changed = true;
17
+ while (changed) {
18
+ changed = false;
19
+ for (const r of rels) {
20
+ if (reachable.has(r.from) && !reachable.has(r.to)) {
21
+ reachable.add(r.to);
22
+ changed = true;
23
+ }
24
+ if (reachable.has(r.to) && !reachable.has(r.from)) {
25
+ reachable.add(r.from);
26
+ changed = true;
27
+ }
28
+ }
29
+ }
30
+ const filteredRels = rels.filter((r) => reachable.has(r.from) && reachable.has(r.to));
31
+ const nodes = doc.nodes.filter((n) => reachable.has(n.id));
32
+ return { nodes, rels: filteredRels };
33
+ }
34
+ const nodeIds = new Set(rels.flatMap((r) => [r.from, r.to]));
35
+ const nodes = doc.nodes.filter((n) => nodeIds.has(n.id));
36
+ return { nodes, rels };
37
+ }
38
+ function generateDependencyMermaid(nodes, rels, labelMode) {
39
+ const lines = [];
40
+ lines.push("graph LR");
41
+ for (const def of renderMermaidClassDefs()) {
42
+ lines.push(` ${def}`);
43
+ }
44
+ lines.push("");
45
+ for (const node of nodes) {
46
+ const shape = mermaidShapeForNode(node);
47
+ const cls = mermaidClassForNode(node);
48
+ lines.push(` ${renderMermaidNode(node.id, node.name, shape, labelMode)}:::${cls}`);
49
+ }
50
+ lines.push("");
51
+ for (const rel of rels) {
52
+ const fromId = sanitiseMermaidId(rel.from);
53
+ const toId = sanitiseMermaidId(rel.to);
54
+ const style = rel.type === "blocks"
55
+ ? "-.->|blocked|"
56
+ : rel.type === "requires"
57
+ ? "==>|required|"
58
+ : `-->|${rel.type}|`;
59
+ const label = renderRelationshipLabel(rel);
60
+ if (rel.type === "blocks") {
61
+ lines.push(` ${toId} ${style} ${fromId}`);
62
+ }
63
+ else {
64
+ lines.push(` ${fromId} ${style}${label ? `|${label}| ` : " "}${toId}`);
65
+ }
66
+ }
67
+ return lines.join("\n");
68
+ }
69
+ function generateDependencyDot(nodes, rels, layout, labelMode) {
70
+ const lines = [];
71
+ lines.push("digraph Dependencies {");
72
+ const rankdir = layout === "TD"
73
+ ? "TB"
74
+ : layout === "BT"
75
+ ? "BT"
76
+ : layout === "RL"
77
+ ? "RL"
78
+ : "LR";
79
+ lines.push(` rankdir=${rankdir};`);
80
+ lines.push(" node [style=filled];");
81
+ for (const node of nodes) {
82
+ lines.push(` "${node.id}" ${dotNodeAttrsWithMode(node, labelMode)};`);
83
+ }
84
+ for (const rel of rels) {
85
+ const attrs = [`label="${renderRelationshipLabel(rel)}"`];
86
+ if (rel.type === "blocks") {
87
+ attrs.push("style=dashed", "color=red");
88
+ lines.push(` "${rel.to}" -> "${rel.from}" [${attrs.join(" ")}];`);
89
+ }
90
+ else {
91
+ if (rel.type === "requires")
92
+ attrs.push("penwidth=2");
93
+ lines.push(` "${rel.from}" -> "${rel.to}" [${attrs.join(" ")}];`);
94
+ }
95
+ }
96
+ lines.push("}");
97
+ return lines.join("\n");
98
+ }
99
+ /** Generate a dependency graph showing how nodes depend on, constrain, and require each other. */
100
+ export const graphDependencyOp = defineOperation({
101
+ name: "graphDependency",
102
+ description: "Generate a dependency graph showing depends_on, constrained_by, requires, blocks, and governed_by relationships.",
103
+ input: z.object({
104
+ doc: SysProMDocument,
105
+ format: z.enum(["mermaid", "dot"]).default("mermaid"),
106
+ seedIds: z.array(z.string()).optional(),
107
+ layout: z.enum(["LR", "TD", "RL", "BT"]).default("LR"),
108
+ labelMode: z.enum(["friendly", "compact"]).default("friendly"),
109
+ }),
110
+ output: z.string(),
111
+ fn({ doc, format, seedIds, layout, labelMode }) {
112
+ const { nodes, rels } = collectDependencyGraph(doc, seedIds);
113
+ if (format === "dot") {
114
+ return generateDependencyDot(nodes, rels, layout, labelMode);
115
+ }
116
+ const mermaid = generateDependencyMermaid(nodes, rels, labelMode);
117
+ const mermaidLines = mermaid.split("\n");
118
+ mermaidLines[0] = `graph ${layout}`;
119
+ return mermaidLines.join("\n");
120
+ },
121
+ });