domain-knowledge-kit 0.2.15 → 0.2.19

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 (210) hide show
  1. package/README.md +4 -0
  2. package/dist/cli.js +24 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/features/agent/commands/init.d.ts +90 -1
  5. package/dist/features/agent/commands/init.d.ts.map +1 -1
  6. package/dist/features/agent/commands/init.js +328 -32
  7. package/dist/features/agent/commands/init.js.map +1 -1
  8. package/dist/features/agent/commands/prime.d.ts +11 -0
  9. package/dist/features/agent/commands/prime.d.ts.map +1 -1
  10. package/dist/features/agent/commands/prime.js +105 -8
  11. package/dist/features/agent/commands/prime.js.map +1 -1
  12. package/dist/features/agent/commands/update.d.ts +27 -0
  13. package/dist/features/agent/commands/update.d.ts.map +1 -0
  14. package/dist/features/agent/commands/update.js +316 -0
  15. package/dist/features/agent/commands/update.js.map +1 -0
  16. package/dist/features/agent/dkk-artifacts.d.ts +76 -0
  17. package/dist/features/agent/dkk-artifacts.d.ts.map +1 -0
  18. package/dist/features/agent/dkk-artifacts.js +328 -0
  19. package/dist/features/agent/dkk-artifacts.js.map +1 -0
  20. package/dist/features/agent/install-mode.d.ts +34 -0
  21. package/dist/features/agent/install-mode.d.ts.map +1 -0
  22. package/dist/features/agent/install-mode.js +78 -0
  23. package/dist/features/agent/install-mode.js.map +1 -0
  24. package/dist/features/agent/mcp-register.d.ts +20 -0
  25. package/dist/features/agent/mcp-register.d.ts.map +1 -0
  26. package/dist/features/agent/mcp-register.js +116 -0
  27. package/dist/features/agent/mcp-register.js.map +1 -0
  28. package/dist/features/agent/settings-prune.d.ts +29 -0
  29. package/dist/features/agent/settings-prune.d.ts.map +1 -0
  30. package/dist/features/agent/settings-prune.js +70 -0
  31. package/dist/features/agent/settings-prune.js.map +1 -0
  32. package/dist/features/agent/tests/settings-prune.test.d.ts +2 -0
  33. package/dist/features/agent/tests/settings-prune.test.d.ts.map +1 -0
  34. package/dist/features/agent/tests/settings-prune.test.js +118 -0
  35. package/dist/features/agent/tests/settings-prune.test.js.map +1 -0
  36. package/dist/features/federation/commands/consumers.d.ts +40 -0
  37. package/dist/features/federation/commands/consumers.d.ts.map +1 -0
  38. package/dist/features/federation/commands/consumers.js +126 -0
  39. package/dist/features/federation/commands/consumers.js.map +1 -0
  40. package/dist/features/federation/commands/peers-add.d.ts +14 -0
  41. package/dist/features/federation/commands/peers-add.d.ts.map +1 -0
  42. package/dist/features/federation/commands/peers-add.js +79 -0
  43. package/dist/features/federation/commands/peers-add.js.map +1 -0
  44. package/dist/features/federation/commands/peers-list.d.ts +8 -0
  45. package/dist/features/federation/commands/peers-list.d.ts.map +1 -0
  46. package/dist/features/federation/commands/peers-list.js +51 -0
  47. package/dist/features/federation/commands/peers-list.js.map +1 -0
  48. package/dist/features/federation/commands/peers-status.d.ts +8 -0
  49. package/dist/features/federation/commands/peers-status.d.ts.map +1 -0
  50. package/dist/features/federation/commands/peers-status.js +78 -0
  51. package/dist/features/federation/commands/peers-status.js.map +1 -0
  52. package/dist/features/federation/commands/pull.d.ts +18 -0
  53. package/dist/features/federation/commands/pull.d.ts.map +1 -0
  54. package/dist/features/federation/commands/pull.js +153 -0
  55. package/dist/features/federation/commands/pull.js.map +1 -0
  56. package/dist/features/federation/git-fetcher.d.ts +45 -0
  57. package/dist/features/federation/git-fetcher.d.ts.map +1 -0
  58. package/dist/features/federation/git-fetcher.js +70 -0
  59. package/dist/features/federation/git-fetcher.js.map +1 -0
  60. package/dist/features/federation/loader.d.ts +60 -0
  61. package/dist/features/federation/loader.d.ts.map +1 -0
  62. package/dist/features/federation/loader.js +193 -0
  63. package/dist/features/federation/loader.js.map +1 -0
  64. package/dist/features/federation/lock.d.ts +12 -0
  65. package/dist/features/federation/lock.d.ts.map +1 -0
  66. package/dist/features/federation/lock.js +48 -0
  67. package/dist/features/federation/lock.js.map +1 -0
  68. package/dist/features/federation/tests/git-fetcher.test.d.ts +2 -0
  69. package/dist/features/federation/tests/git-fetcher.test.d.ts.map +1 -0
  70. package/dist/features/federation/tests/git-fetcher.test.js +167 -0
  71. package/dist/features/federation/tests/git-fetcher.test.js.map +1 -0
  72. package/dist/features/federation/tests/loader.test.d.ts +2 -0
  73. package/dist/features/federation/tests/loader.test.d.ts.map +1 -0
  74. package/dist/features/federation/tests/loader.test.js +144 -0
  75. package/dist/features/federation/tests/loader.test.js.map +1 -0
  76. package/dist/features/federation/tests/phase5.test.d.ts +2 -0
  77. package/dist/features/federation/tests/phase5.test.d.ts.map +1 -0
  78. package/dist/features/federation/tests/phase5.test.js +137 -0
  79. package/dist/features/federation/tests/phase5.test.js.map +1 -0
  80. package/dist/features/federation/tests/schema-load.test.d.ts +2 -0
  81. package/dist/features/federation/tests/schema-load.test.d.ts.map +1 -0
  82. package/dist/features/federation/tests/schema-load.test.js +97 -0
  83. package/dist/features/federation/tests/schema-load.test.js.map +1 -0
  84. package/dist/features/federation/tests/validator.test.d.ts +2 -0
  85. package/dist/features/federation/tests/validator.test.d.ts.map +1 -0
  86. package/dist/features/federation/tests/validator.test.js +319 -0
  87. package/dist/features/federation/tests/validator.test.js.map +1 -0
  88. package/dist/features/mcp/commands/serve.d.ts +10 -0
  89. package/dist/features/mcp/commands/serve.d.ts.map +1 -0
  90. package/dist/features/mcp/commands/serve.js +12 -0
  91. package/dist/features/mcp/commands/serve.js.map +1 -0
  92. package/dist/features/mcp/server.d.ts +15 -0
  93. package/dist/features/mcp/server.d.ts.map +1 -0
  94. package/dist/features/mcp/server.js +438 -0
  95. package/dist/features/mcp/server.js.map +1 -0
  96. package/dist/features/pipeline/commands/validate.d.ts.map +1 -1
  97. package/dist/features/pipeline/commands/validate.js +7 -0
  98. package/dist/features/pipeline/commands/validate.js.map +1 -1
  99. package/dist/features/pipeline/indexer.d.ts +28 -2
  100. package/dist/features/pipeline/indexer.d.ts.map +1 -1
  101. package/dist/features/pipeline/indexer.js +82 -27
  102. package/dist/features/pipeline/indexer.js.map +1 -1
  103. package/dist/features/pipeline/validator.d.ts +10 -0
  104. package/dist/features/pipeline/validator.d.ts.map +1 -1
  105. package/dist/features/pipeline/validator.js +274 -27
  106. package/dist/features/pipeline/validator.js.map +1 -1
  107. package/dist/features/query/commands/list.d.ts +10 -0
  108. package/dist/features/query/commands/list.d.ts.map +1 -1
  109. package/dist/features/query/commands/list.js +1 -1
  110. package/dist/features/query/commands/list.js.map +1 -1
  111. package/dist/features/query/commands/locate.d.ts +1 -0
  112. package/dist/features/query/commands/locate.d.ts.map +1 -1
  113. package/dist/features/query/commands/locate.js +1 -1
  114. package/dist/features/query/commands/locate.js.map +1 -1
  115. package/dist/features/query/commands/search.d.ts.map +1 -1
  116. package/dist/features/query/commands/search.js +2 -0
  117. package/dist/features/query/commands/search.js.map +1 -1
  118. package/dist/features/query/commands/show.d.ts +15 -0
  119. package/dist/features/query/commands/show.d.ts.map +1 -1
  120. package/dist/features/query/commands/show.js +116 -58
  121. package/dist/features/query/commands/show.js.map +1 -1
  122. package/dist/features/query/commands/story.d.ts +70 -0
  123. package/dist/features/query/commands/story.d.ts.map +1 -1
  124. package/dist/features/query/commands/story.js +2 -2
  125. package/dist/features/query/commands/story.js.map +1 -1
  126. package/dist/features/query/commands/summary.d.ts +3 -0
  127. package/dist/features/query/commands/summary.d.ts.map +1 -1
  128. package/dist/features/query/commands/summary.js +1 -1
  129. package/dist/features/query/commands/summary.js.map +1 -1
  130. package/dist/features/query/searcher.d.ts +18 -1
  131. package/dist/features/query/searcher.d.ts.map +1 -1
  132. package/dist/features/query/searcher.js +11 -2
  133. package/dist/features/query/searcher.js.map +1 -1
  134. package/dist/features/scaffold/commands/new-domain.d.ts +22 -0
  135. package/dist/features/scaffold/commands/new-domain.d.ts.map +1 -1
  136. package/dist/features/scaffold/commands/new-domain.js +44 -28
  137. package/dist/features/scaffold/commands/new-domain.js.map +1 -1
  138. package/dist/features/scaffold/commands/service-init.d.ts +12 -0
  139. package/dist/features/scaffold/commands/service-init.d.ts.map +1 -0
  140. package/dist/features/scaffold/commands/service-init.js +69 -0
  141. package/dist/features/scaffold/commands/service-init.js.map +1 -0
  142. package/dist/shared/graph.d.ts +8 -0
  143. package/dist/shared/graph.d.ts.map +1 -1
  144. package/dist/shared/graph.js +180 -112
  145. package/dist/shared/graph.js.map +1 -1
  146. package/dist/shared/index.d.ts +4 -1
  147. package/dist/shared/index.d.ts.map +1 -1
  148. package/dist/shared/index.js +6 -1
  149. package/dist/shared/index.js.map +1 -1
  150. package/dist/shared/loader.d.ts +22 -0
  151. package/dist/shared/loader.d.ts.map +1 -1
  152. package/dist/shared/loader.js +31 -1
  153. package/dist/shared/loader.js.map +1 -1
  154. package/dist/shared/paths.d.ts +59 -7
  155. package/dist/shared/paths.d.ts.map +1 -1
  156. package/dist/shared/paths.js +93 -11
  157. package/dist/shared/paths.js.map +1 -1
  158. package/dist/shared/refs.d.ts +96 -0
  159. package/dist/shared/refs.d.ts.map +1 -0
  160. package/dist/shared/refs.js +182 -0
  161. package/dist/shared/refs.js.map +1 -0
  162. package/dist/shared/service-id.d.ts +11 -0
  163. package/dist/shared/service-id.d.ts.map +1 -0
  164. package/dist/shared/service-id.js +64 -0
  165. package/dist/shared/service-id.js.map +1 -0
  166. package/dist/shared/tests/paths.test.d.ts +2 -0
  167. package/dist/shared/tests/paths.test.d.ts.map +1 -0
  168. package/dist/shared/tests/paths.test.js +111 -0
  169. package/dist/shared/tests/paths.test.js.map +1 -0
  170. package/dist/shared/tests/refs.test.d.ts +2 -0
  171. package/dist/shared/tests/refs.test.d.ts.map +1 -0
  172. package/dist/shared/tests/refs.test.js +104 -0
  173. package/dist/shared/tests/refs.test.js.map +1 -0
  174. package/dist/shared/types/domain.d.ts +14 -0
  175. package/dist/shared/types/domain.d.ts.map +1 -1
  176. package/dist/shared/types/federation.d.ts +60 -0
  177. package/dist/shared/types/federation.d.ts.map +1 -0
  178. package/dist/shared/types/federation.js +12 -0
  179. package/dist/shared/types/federation.js.map +1 -0
  180. package/dist/version.d.ts +4 -0
  181. package/dist/version.d.ts.map +1 -0
  182. package/dist/version.js +15 -0
  183. package/dist/version.js.map +1 -0
  184. package/package.json +8 -5
  185. package/tools/dkk/claude/agents/dkk-domain-reviewer.md +69 -0
  186. package/tools/dkk/claude/commands/dkk-adr.md +11 -0
  187. package/tools/dkk/claude/commands/dkk-impact.md +34 -0
  188. package/tools/dkk/claude/commands/dkk-implement.md +12 -0
  189. package/tools/dkk/claude/commands/dkk-prime.md +6 -0
  190. package/tools/dkk/claude/commands/dkk-review.md +12 -0
  191. package/tools/dkk/claude/commands/dkk-story.md +12 -0
  192. package/tools/dkk/claude/hooks/post-edit-validate.mjs +68 -0
  193. package/tools/dkk/claude/hooks/pre-edit-block-generated.mjs +39 -0
  194. package/tools/dkk/claude/hooks/session-start-prime.mjs +20 -0
  195. package/tools/dkk/claude/hooks/stop-validate.mjs +67 -0
  196. package/tools/dkk/claude/settings.json +62 -0
  197. package/tools/dkk/claude/skills/dkk-adr-author/SKILL.md +54 -0
  198. package/tools/dkk/claude/skills/dkk-flow-implementer/SKILL.md +51 -0
  199. package/tools/dkk/claude/skills/dkk-story-analyst/SKILL.md +108 -0
  200. package/tools/dkk/schema/actors.schema.json +1 -1
  201. package/tools/dkk/schema/adr-frontmatter.schema.json +4 -4
  202. package/tools/dkk/schema/aggregate.schema.json +1 -1
  203. package/tools/dkk/schema/command.schema.json +1 -1
  204. package/tools/dkk/schema/event.schema.json +1 -1
  205. package/tools/dkk/schema/federation.schema.json +71 -0
  206. package/tools/dkk/schema/glossary.schema.json +1 -1
  207. package/tools/dkk/schema/index.schema.json +2 -2
  208. package/tools/dkk/schema/policy.schema.json +1 -1
  209. package/tools/dkk/schema/read-model.schema.json +1 -1
  210. package/tools/dkk/schema/service.schema.json +30 -0
@@ -8,7 +8,29 @@
8
8
  * context.yml, events/, commands/, aggregates/, policies/, read-models/
9
9
  *
10
10
  * Errors if `.dkk/domain/` already exists (use `--force` to overwrite).
11
+ *
12
+ * The scaffold logic is also exported as `scaffoldDomain()` so `dkk init`
13
+ * can bootstrap the same structure during project initialization.
11
14
  */
12
15
  import type { Command as Cmd } from "commander";
16
+ export type ScaffoldDomainStatus = "created" | "skipped" | "replaced";
17
+ export interface ScaffoldDomainResult {
18
+ status: ScaffoldDomainStatus;
19
+ path: string;
20
+ }
21
+ /**
22
+ * Scaffold `.dkk/domain/` with sample content.
23
+ *
24
+ * - If the directory does not exist, creates it (`status: "created"`).
25
+ * - If it exists and `force` is false, leaves it untouched (`status: "skipped"`).
26
+ * - If it exists and `force` is true, removes it entirely first, then
27
+ * creates a fresh scaffold (`status: "replaced"`).
28
+ */
29
+ export declare function scaffoldDomain(opts?: {
30
+ root?: string;
31
+ force?: boolean;
32
+ }): ScaffoldDomainResult;
33
+ /** Files created by a successful scaffold — used by callers that print their own report. */
34
+ export declare const SCAFFOLD_DOMAIN_FILES: readonly string[];
13
35
  export declare function registerNewDomain(program: Cmd): void;
14
36
  //# sourceMappingURL=new-domain.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"new-domain.d.ts","sourceRoot":"","sources":["../../../../src/features/scaffold/commands/new-domain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,WAAW,CAAC;AA0DhD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI,CA6DpD"}
1
+ {"version":3,"file":"new-domain.d.ts","sourceRoot":"","sources":["../../../../src/features/scaffold/commands/new-domain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,WAAW,CAAC;AA0DhD,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAEtE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,oBAAoB,CA0BlG;AAED,4FAA4F;AAC5F,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAOlD,CAAC;AAIF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI,CAmCpD"}
@@ -45,6 +45,45 @@ emits:
45
45
  events:
46
46
  - SampleCreated
47
47
  `;
48
+ /**
49
+ * Scaffold `.dkk/domain/` with sample content.
50
+ *
51
+ * - If the directory does not exist, creates it (`status: "created"`).
52
+ * - If it exists and `force` is false, leaves it untouched (`status: "skipped"`).
53
+ * - If it exists and `force` is true, removes it entirely first, then
54
+ * creates a fresh scaffold (`status: "replaced"`).
55
+ */
56
+ export function scaffoldDomain(opts = {}) {
57
+ const dir = domainDir(opts.root);
58
+ if (existsSync(dir) && !opts.force) {
59
+ return { status: "skipped", path: dir };
60
+ }
61
+ const replaced = existsSync(dir) && (opts.force ?? false);
62
+ if (replaced) {
63
+ rmSync(dir, { recursive: true, force: true });
64
+ }
65
+ const contextsBase = join(dir, "contexts", "sample");
66
+ const subDirs = ["events", "commands", "aggregates", "policies", "read-models"];
67
+ for (const sub of subDirs) {
68
+ mkdirSync(join(contextsBase, sub), { recursive: true });
69
+ }
70
+ writeFileSync(join(dir, "index.yml"), INDEX_YML, "utf-8");
71
+ writeFileSync(join(dir, "actors.yml"), ACTORS_YML, "utf-8");
72
+ writeFileSync(join(contextsBase, "context.yml"), CONTEXT_YML, "utf-8");
73
+ writeFileSync(join(contextsBase, "events", "SampleCreated.yml"), SAMPLE_EVENT, "utf-8");
74
+ writeFileSync(join(contextsBase, "commands", "CreateSample.yml"), SAMPLE_COMMAND, "utf-8");
75
+ writeFileSync(join(contextsBase, "aggregates", "Sample.yml"), SAMPLE_AGGREGATE, "utf-8");
76
+ return { status: replaced ? "replaced" : "created", path: dir };
77
+ }
78
+ /** Files created by a successful scaffold — used by callers that print their own report. */
79
+ export const SCAFFOLD_DOMAIN_FILES = [
80
+ "index.yml",
81
+ "actors.yml",
82
+ "contexts/sample/context.yml",
83
+ "contexts/sample/events/SampleCreated.yml",
84
+ "contexts/sample/commands/CreateSample.yml",
85
+ "contexts/sample/aggregates/Sample.yml",
86
+ ];
48
87
  // ── Registration ──────────────────────────────────────────────────────
49
88
  export function registerNewDomain(program) {
50
89
  program
@@ -56,44 +95,21 @@ export function registerNewDomain(program) {
56
95
  .option("--minify", "Minify JSON")
57
96
  .action((opts) => {
58
97
  const dir = domainDir(opts.root);
59
- // Guard: refuse to overwrite unless --force
60
98
  if (existsSync(dir) && !opts.force) {
61
99
  console.error(`Error: ${dir} already exists. Use --force to replace it entirely.`);
62
100
  process.exit(1);
63
101
  }
64
- // --force: remove the entire domain directory so the scaffold is applied
65
- // to a clean slate (no silent merging of pre-existing content).
66
- if (existsSync(dir) && opts.force) {
67
- rmSync(dir, { recursive: true, force: true });
68
- }
69
- // Create directory structure
70
- const contextsBase = join(dir, "contexts", "sample");
71
- const subDirs = ["events", "commands", "aggregates", "policies", "read-models"];
72
- for (const sub of subDirs) {
73
- mkdirSync(join(contextsBase, sub), { recursive: true });
74
- }
75
- // Write files
76
- writeFileSync(join(dir, "index.yml"), INDEX_YML, "utf-8");
77
- writeFileSync(join(dir, "actors.yml"), ACTORS_YML, "utf-8");
78
- writeFileSync(join(contextsBase, "context.yml"), CONTEXT_YML, "utf-8");
79
- writeFileSync(join(contextsBase, "events", "SampleCreated.yml"), SAMPLE_EVENT, "utf-8");
80
- writeFileSync(join(contextsBase, "commands", "CreateSample.yml"), SAMPLE_COMMAND, "utf-8");
81
- writeFileSync(join(contextsBase, "aggregates", "Sample.yml"), SAMPLE_AGGREGATE, "utf-8");
102
+ const result = scaffoldDomain({ root: opts.root, force: opts.force });
82
103
  if (opts.json) {
83
104
  console.log(JSON.stringify({
84
- path: dir,
85
- success: true
105
+ path: result.path,
106
+ success: true,
86
107
  }, null, opts.minify ? 0 : 2));
87
108
  return;
88
109
  }
89
110
  console.log("Created .dkk/domain/ with sample content:");
90
- console.log(" index.yml");
91
- console.log(" actors.yml");
92
- console.log(" contexts/sample/");
93
- console.log(" context.yml");
94
- console.log(" events/SampleCreated.yml");
95
- console.log(" commands/CreateSample.yml");
96
- console.log(" aggregates/Sample.yml");
111
+ for (const f of SCAFFOLD_DOMAIN_FILES)
112
+ console.log(` ${f}`);
97
113
  console.log("\nRun `dkk render` to validate and generate documentation.");
98
114
  });
99
115
  }
@@ -1 +1 @@
1
- {"version":3,"file":"new-domain.js","sourceRoot":"","sources":["../../../../src/features/scaffold/commands/new-domain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"new-domain.js","sourceRoot":"","sources":["../../../../src/features/scaffold/commands/new-domain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `dkk service init` command — declare this repo as a federated service.
3
+ *
4
+ * Writes `.dkk/service.yml` with the given name and exported contexts.
5
+ * This is the foundation for cross-repo references: peer repos can
6
+ * now address items in this service as `<name>:<context>.<Item>`.
7
+ *
8
+ * Errors if `.dkk/service.yml` already exists (use `--force` to replace).
9
+ */
10
+ import type { Command as Cmd } from "commander";
11
+ export declare function registerServiceInit(program: Cmd): void;
12
+ //# sourceMappingURL=service-init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-init.d.ts","sourceRoot":"","sources":["../../../../src/features/scaffold/commands/service-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,WAAW,CAAC;AAYhD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI,CA+EtD"}
@@ -0,0 +1,69 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { serviceFile } from "../../../shared/paths.js";
4
+ import { stringifyYaml } from "../../../shared/yaml.js";
5
+ /** Validate name is kebab-case per schema: ^[a-z][a-z0-9-]*$ */
6
+ function isValidKebab(name) {
7
+ return /^[a-z][a-z0-9-]*$/.test(name);
8
+ }
9
+ export function registerServiceInit(program) {
10
+ const service = program
11
+ .command("service")
12
+ .description("Service identity and federation commands");
13
+ service
14
+ .command("init")
15
+ .description("Declare this repo as a federated service (writes .dkk/service.yml)")
16
+ .requiredOption("--name <name>", "Kebab-case service name (e.g. ordering)")
17
+ .option("--export <context...>", "Bounded-context names to export for federation (repeat or comma-separate)")
18
+ .option("--description <text>", "Optional human-readable description")
19
+ .option("-r, --root <path>", "Override repository root")
20
+ .option("--force", "Overwrite an existing service.yml")
21
+ .option("--json", "Output as JSON")
22
+ .option("--minify", "Minify JSON output")
23
+ .action((opts) => {
24
+ // Validate name
25
+ if (!isValidKebab(opts.name)) {
26
+ console.error(`Error: Service name "${opts.name}" is invalid. Use kebab-case (e.g. "ordering" or "order-management").`);
27
+ process.exit(1);
28
+ }
29
+ // Normalize --export: commander gives an array, but each entry may
30
+ // also be a comma-separated list (user-friendly: --export a,b,c).
31
+ const rawExports = opts.export ?? [];
32
+ const exports = [];
33
+ for (const entry of rawExports) {
34
+ for (const ctx of entry.split(",")) {
35
+ const trimmed = ctx.trim();
36
+ if (trimmed.length === 0)
37
+ continue;
38
+ if (!isValidKebab(trimmed)) {
39
+ console.error(`Error: Export "${trimmed}" is not kebab-case.`);
40
+ process.exit(1);
41
+ }
42
+ if (!exports.includes(trimmed))
43
+ exports.push(trimmed);
44
+ }
45
+ }
46
+ const path = serviceFile(opts.root);
47
+ if (existsSync(path) && !opts.force) {
48
+ console.error(`Error: ${path} already exists. Use --force to overwrite.`);
49
+ process.exit(1);
50
+ }
51
+ const manifest = {
52
+ name: opts.name,
53
+ exports,
54
+ };
55
+ if (opts.description)
56
+ manifest.description = opts.description;
57
+ mkdirSync(dirname(path), { recursive: true });
58
+ const header = "# Service identity for federation. See `dkk service --help`.\n";
59
+ writeFileSync(path, header + stringifyYaml(manifest), "utf-8");
60
+ if (opts.json) {
61
+ console.log(JSON.stringify({ path, name: opts.name, exports }, null, opts.minify ? 0 : 2));
62
+ return;
63
+ }
64
+ console.log(`Created ${path}`);
65
+ console.log(` name: ${opts.name}`);
66
+ console.log(` exports: [${exports.join(", ")}]`);
67
+ });
68
+ }
69
+ //# sourceMappingURL=service-init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-init.js","sourceRoot":"","sources":["../../../../src/features/scaffold/commands/service-init.ts"],"names":[],"mappings":"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"}
@@ -47,6 +47,14 @@ export declare class DomainGraph {
47
47
  private constructor();
48
48
  /**
49
49
  * Build a domain graph from a loaded {@link DomainModel}.
50
+ *
51
+ * Federation-aware: the local model is walked first, then each peer
52
+ * model in `model.peers` is walked with its service name as a prefix.
53
+ * Local node ids keep the bare grammar (`<ctx>.<Name>`, `actor.X`,
54
+ * `adr-NNNN`, `flow.X`, `context.X`); peer node ids are prefixed
55
+ * with `<peerService>:` so a local policy referencing
56
+ * `ordering:ordering.OrderCancelled` connects through to the peer's
57
+ * node by name.
50
58
  */
51
59
  static from(model: DomainModel): DomainGraph;
52
60
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/shared/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAsD,MAAM,mBAAmB,CAAC;AAMzG,iDAAiD;AACjD,MAAM,MAAM,QAAQ,GAChB,SAAS,GACT,OAAO,GACP,SAAS,GACT,QAAQ,GACR,WAAW,GACX,YAAY,GACZ,OAAO,GACP,KAAK,GACL,UAAU,GACV,MAAM,CAAC;AAEX,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,yEAAyE;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,4CAA4C;AAC5C,MAAM,WAAW,SAAS;IACxB,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;CACf;AAqBD;;;;GAIG;AACH,qBAAa,WAAW;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC/C,iBAAiB;IACjB,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IAErC,sDAAsD;IACtD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA2B;IAE/C,OAAO;IAYP;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW;IAsL5C;;;;;;;;OAQG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,GAAG,CAAC,MAAM,CAAC;IAwB3D;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAI1C;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;CAG7B"}
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/shared/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAsD,MAAM,mBAAmB,CAAC;AAOzG,iDAAiD;AACjD,MAAM,MAAM,QAAQ,GAChB,SAAS,GACT,OAAO,GACP,SAAS,GACT,QAAQ,GACR,WAAW,GACX,YAAY,GACZ,OAAO,GACP,KAAK,GACL,UAAU,GACV,MAAM,CAAC;AAEX,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,yEAAyE;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,4CAA4C;AAC5C,MAAM,WAAW,SAAS;IACxB,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;CACf;AAqBD;;;;GAIG;AACH,qBAAa,WAAW;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC/C,iBAAiB;IACjB,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IAErC,sDAAsD;IACtD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA2B;IAE/C,OAAO;IAYP;;;;;;;;;;OAUG;IACH,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW;IAyO5C;;;;;;;;OAQG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,GAAG,CAAC,MAAM,CAAC;IAwB3D;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAI1C;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;CAG7B"}
@@ -10,6 +10,7 @@
10
10
  * performs a breadth-first traversal up to a specified depth.
11
11
  */
12
12
  import { forEachItem, itemAdrRefs } from "./item-visitor.js";
13
+ import { parseRef, qualifyItemRef, qualifyActorRef } from "./refs.js";
13
14
  // ── Helpers ───────────────────────────────────────────────────────────
14
15
  /** Build scoped id for a context-local item. */
15
16
  function scopedId(context, name) {
@@ -44,6 +45,14 @@ export class DomainGraph {
44
45
  // ── Factory ───────────────────────────────────────────────────────
45
46
  /**
46
47
  * Build a domain graph from a loaded {@link DomainModel}.
48
+ *
49
+ * Federation-aware: the local model is walked first, then each peer
50
+ * model in `model.peers` is walked with its service name as a prefix.
51
+ * Local node ids keep the bare grammar (`<ctx>.<Name>`, `actor.X`,
52
+ * `adr-NNNN`, `flow.X`, `context.X`); peer node ids are prefixed
53
+ * with `<peerService>:` so a local policy referencing
54
+ * `ordering:ordering.OrderCancelled` connects through to the peer's
55
+ * node by name.
47
56
  */
48
57
  static from(model) {
49
58
  const nodes = new Map();
@@ -74,136 +83,195 @@ export class DomainGraph {
74
83
  adj.get(from)?.add(to);
75
84
  adj.get(to)?.add(from);
76
85
  }
77
- /** Wire adr_refs for any item. */
78
- function wireAdrRefs(itemId, adrRefs) {
86
+ /** Wire adr_refs for any item. Adds the peer prefix when refs are bare. */
87
+ function wireAdrRefs(itemId, adrRefs, prefix) {
79
88
  if (!adrRefs)
80
89
  return;
81
90
  for (const ref of adrRefs) {
82
- // ADR node might not exist yet if the ADR file wasn't present;
83
- // we still create a placeholder node so the edge is recorded.
84
- ensureNode(ref, "adr", ref);
85
- addEdge(itemId, ref, "adr_ref");
91
+ // Author-qualified refs (already contain `:`) stay as-is; bare
92
+ // refs are prefixed with this walk's service prefix.
93
+ const nodeRefId = ref.includes(":") || !prefix ? ref : `${prefix}${ref}`;
94
+ ensureNode(nodeRefId, "adr", nodeRefId);
95
+ addEdge(itemId, nodeRefId, "adr_ref");
86
96
  }
87
97
  }
88
- // ── Actors ────────────────────────────────────────────────────
89
- for (const actor of model.actors) {
90
- const id = ensureNode(actorId(actor.name), "actor", actor.name);
91
- wireAdrRefs(id, actor.adr_refs);
92
- }
93
- // ── Bounded contexts & their items ────────────────────────────
94
- for (const [ctxName, ctx] of model.contexts) {
95
- const ctxId = ensureNode(`context.${ctxName}`, "context", ctxName);
96
- wireAdrRefs(ctxId, undefined); // contexts don't have adr_refs currently
97
- // Visit all item types: create node, add contains edge, wire ADR refs,
98
- // then apply type-specific relationship wiring.
99
- forEachItem(ctx, (type, name, item) => {
100
- const nodeKind = type;
101
- const id = ensureNode(scopedId(ctxName, name), nodeKind, name, ctxName);
102
- addEdge(ctxId, id, "contains");
103
- wireAdrRefs(id, itemAdrRefs(item));
104
- // Type-specific relationship wiring
105
- switch (type) {
106
- case "event": {
107
- const evt = item;
108
- if (evt.raised_by) {
109
- const aggId = ensureNode(scopedId(ctxName, evt.raised_by), "aggregate", evt.raised_by, ctxName);
110
- addEdge(aggId, id, "emits");
98
+ /**
99
+ * Walk one model (local or peer). When `walkPrefix` is set to
100
+ * `"<peerName>:"`, every node id created inside this walk is
101
+ * prefixed accordingly, so local + peer namespaces stay disjoint.
102
+ */
103
+ function walkOne(m, walkPrefix) {
104
+ // ── Actors ────────────────────────────────────────────────────
105
+ for (const actor of m.actors) {
106
+ const id = ensureNode(`${walkPrefix}${actorId(actor.name)}`, "actor", actor.name);
107
+ wireAdrRefs(id, actor.adr_refs, walkPrefix);
108
+ }
109
+ // ── Bounded contexts & their items ────────────────────────────
110
+ for (const [ctxName, ctx] of m.contexts) {
111
+ const ctxId = ensureNode(`${walkPrefix}context.${ctxName}`, "context", ctxName);
112
+ wireAdrRefs(ctxId, undefined, walkPrefix);
113
+ forEachItem(ctx, (type, name, item) => {
114
+ const nodeKind = type;
115
+ const id = ensureNode(`${walkPrefix}${scopedId(ctxName, name)}`, nodeKind, name, ctxName);
116
+ addEdge(ctxId, id, "contains");
117
+ wireAdrRefs(id, itemAdrRefs(item), walkPrefix);
118
+ switch (type) {
119
+ case "event": {
120
+ const evt = item;
121
+ if (evt.raised_by) {
122
+ const res = qualifyItemRef(evt.raised_by, walkPrefix, ctxName);
123
+ const aggId = ensureNode(res.id, "aggregate", res.name, res.context);
124
+ addEdge(aggId, id, "emits");
125
+ }
126
+ break;
111
127
  }
112
- break;
113
- }
114
- case "command": {
115
- const cmd = item;
116
- if (cmd.handled_by) {
117
- const aggId = ensureNode(scopedId(ctxName, cmd.handled_by), "aggregate", cmd.handled_by, ctxName);
118
- addEdge(aggId, id, "handles");
128
+ case "command": {
129
+ const cmd = item;
130
+ if (cmd.handled_by) {
131
+ const res = qualifyItemRef(cmd.handled_by, walkPrefix, ctxName);
132
+ const aggId = ensureNode(res.id, "aggregate", res.name, res.context);
133
+ addEdge(aggId, id, "handles");
134
+ }
135
+ if (cmd.actor) {
136
+ const a = qualifyActorRef(cmd.actor, walkPrefix);
137
+ const aId = ensureNode(a.id, "actor", a.name);
138
+ addEdge(aId, id, "initiates");
139
+ }
140
+ break;
119
141
  }
120
- if (cmd.actor) {
121
- const aId = ensureNode(actorId(cmd.actor), "actor", cmd.actor);
122
- addEdge(aId, id, "initiates");
142
+ case "policy": {
143
+ const pol = item;
144
+ for (const trigger of pol.when?.events ?? []) {
145
+ const res = qualifyItemRef(trigger, walkPrefix, ctxName);
146
+ const evtId = ensureNode(res.id, "event", res.name, res.context);
147
+ addEdge(evtId, id, "triggers");
148
+ }
149
+ for (const emitted of pol.then?.commands ?? []) {
150
+ const res = qualifyItemRef(emitted, walkPrefix, ctxName);
151
+ const cmdId = ensureNode(res.id, "command", res.name, res.context);
152
+ addEdge(id, cmdId, "emits");
153
+ }
154
+ break;
123
155
  }
124
- break;
125
- }
126
- case "policy": {
127
- const pol = item;
128
- for (const trigger of pol.when?.events ?? []) {
129
- const evtId = ensureNode(scopedId(ctxName, trigger), "event", trigger, ctxName);
130
- addEdge(evtId, id, "triggers");
156
+ case "aggregate": {
157
+ const agg = item;
158
+ for (const h of agg.handles?.commands ?? []) {
159
+ const res = qualifyItemRef(h, walkPrefix, ctxName);
160
+ const cmdId = ensureNode(res.id, "command", res.name, res.context);
161
+ addEdge(id, cmdId, "handles");
162
+ }
163
+ for (const e of agg.emits?.events ?? []) {
164
+ const res = qualifyItemRef(e, walkPrefix, ctxName);
165
+ const evtId = ensureNode(res.id, "event", res.name, res.context);
166
+ addEdge(id, evtId, "emits");
167
+ }
168
+ break;
131
169
  }
132
- for (const emitted of pol.then?.commands ?? []) {
133
- const cmdId = ensureNode(scopedId(ctxName, emitted), "command", emitted, ctxName);
134
- addEdge(id, cmdId, "emits");
170
+ case "read_model": {
171
+ const rm = item;
172
+ for (const sub of rm.subscribes_to ?? []) {
173
+ const res = qualifyItemRef(sub, walkPrefix, ctxName);
174
+ const evtId = ensureNode(res.id, "event", res.name, res.context);
175
+ addEdge(id, evtId, "subscribes_to");
176
+ }
177
+ for (const user of rm.used_by ?? []) {
178
+ const a = qualifyActorRef(user, walkPrefix);
179
+ const aId = ensureNode(a.id, "actor", a.name);
180
+ addEdge(id, aId, "used_by");
181
+ }
182
+ break;
135
183
  }
136
- break;
184
+ case "glossary":
185
+ // Glossary items have no type-specific relationship wiring.
186
+ break;
137
187
  }
138
- case "aggregate": {
139
- const agg = item;
140
- for (const h of agg.handles?.commands ?? []) {
141
- const cmdId = ensureNode(scopedId(ctxName, h), "command", h, ctxName);
142
- addEdge(id, cmdId, "handles");
143
- }
144
- for (const e of agg.emits?.events ?? []) {
145
- const evtId = ensureNode(scopedId(ctxName, e), "event", e, ctxName);
146
- addEdge(id, evtId, "emits");
147
- }
148
- break;
188
+ });
189
+ }
190
+ // ── ADRs ──────────────────────────────────────────────────────
191
+ for (const [adrIdRaw, adr] of m.adrs) {
192
+ const adrNodeId = `${walkPrefix}${adrIdRaw}`;
193
+ ensureNode(adrNodeId, "adr", adr.title);
194
+ // domain_refs domain items. Use parseRef to split correctly
195
+ // for both bare and service-prefixed forms.
196
+ for (const ref of adr.domain_refs ?? []) {
197
+ const parsed = parseRef(ref);
198
+ if (parsed?.kind === "item" && parsed.service) {
199
+ // Explicit peer ref — keep as-is.
200
+ const id = `${parsed.service}:${parsed.context}.${parsed.name}`;
201
+ ensureNode(id, "aggregate", parsed.name, parsed.context);
202
+ addEdge(adrNodeId, id, "domain_ref");
149
203
  }
150
- case "read_model": {
151
- const rm = item;
152
- for (const sub of rm.subscribes_to ?? []) {
153
- const evtId = ensureNode(scopedId(ctxName, sub), "event", sub, ctxName);
154
- addEdge(id, evtId, "subscribes_to");
155
- }
156
- for (const user of rm.used_by ?? []) {
157
- const aId = ensureNode(actorId(user), "actor", user);
158
- addEdge(id, aId, "used_by");
159
- }
160
- break;
204
+ else if (parsed?.kind === "item") {
205
+ // Bare ref — prefix with this walk's service.
206
+ const id = `${walkPrefix}${parsed.context}.${parsed.name}`;
207
+ ensureNode(id, "aggregate", parsed.name, parsed.context);
208
+ addEdge(adrNodeId, id, "domain_ref");
209
+ }
210
+ else {
211
+ // Unparseable record edge against the raw form so
212
+ // visibility is preserved even though the node is dangling.
213
+ ensureNode(ref, "aggregate", ref);
214
+ addEdge(adrNodeId, ref, "domain_ref");
161
215
  }
162
- case "glossary":
163
- // Glossary items have no type-specific relationship wiring.
164
- break;
165
216
  }
166
- });
167
- }
168
- // ── ADRs ──────────────────────────────────────────────────────
169
- for (const [adrId, adr] of model.adrs) {
170
- ensureNode(adrId, "adr", adr.title);
171
- // domain_refs → domain items
172
- for (const ref of adr.domain_refs ?? []) {
173
- // ref is in "context.Name" format — ensure node exists
174
- const dotIdx = ref.indexOf(".");
175
- if (dotIdx > 0) {
176
- const ctx = ref.slice(0, dotIdx);
177
- const name = ref.slice(dotIdx + 1);
178
- // We don't know the item kind from the ref alone; default to
179
- // a generic node that will be reconciled if it was already created.
180
- ensureNode(ref, "aggregate", name, ctx);
217
+ // superseded_by → another ADR
218
+ if (adr.superseded_by) {
219
+ const parsed = parseRef(adr.superseded_by);
220
+ const targetId = parsed?.kind === "adr"
221
+ ? parsed.service
222
+ ? `${parsed.service}:${parsed.id}`
223
+ : `${walkPrefix}${parsed.id}`
224
+ : adr.superseded_by;
225
+ ensureNode(targetId, "adr", targetId);
226
+ addEdge(adrNodeId, targetId, "superseded_by");
181
227
  }
182
- addEdge(adrId, ref, "domain_ref");
183
228
  }
184
- // superseded_by another ADR
185
- if (adr.superseded_by) {
186
- ensureNode(adr.superseded_by, "adr", adr.superseded_by);
187
- addEdge(adrId, adr.superseded_by, "superseded_by");
229
+ // ── Flows ─────────────────────────────────────────────────────
230
+ for (const flow of m.index.flows ?? []) {
231
+ const fId = ensureNode(`${walkPrefix}${flowId(flow.name)}`, "flow", flow.name);
232
+ let prevStepId;
233
+ for (const step of flow.steps) {
234
+ const raw = step.ref;
235
+ const parsed = parseRef(raw);
236
+ let stepId;
237
+ let ctx;
238
+ let name;
239
+ if (parsed?.kind === "item" && parsed.service) {
240
+ stepId = `${parsed.service}:${parsed.context}.${parsed.name}`;
241
+ ctx = parsed.context;
242
+ name = parsed.name;
243
+ }
244
+ else if (parsed?.kind === "item") {
245
+ stepId = `${walkPrefix}${parsed.context}.${parsed.name}`;
246
+ ctx = parsed.context;
247
+ name = parsed.name;
248
+ }
249
+ else {
250
+ stepId = raw;
251
+ const dot = raw.indexOf(".");
252
+ ctx = dot > 0 ? raw.slice(0, dot) : undefined;
253
+ name = dot > 0 ? raw.slice(dot + 1) : raw;
254
+ }
255
+ const kind = step.type === "read_model" ? "read_model" : step.type;
256
+ ensureNode(stepId, kind, name, ctx);
257
+ addEdge(fId, stepId, "flow_step");
258
+ if (prevStepId) {
259
+ addEdge(prevStepId, stepId, "flow_next");
260
+ }
261
+ prevStepId = stepId;
262
+ }
188
263
  }
189
264
  }
190
- // ── Flows ─────────────────────────────────────────────────────
191
- for (const flow of model.index.flows ?? []) {
192
- const fId = ensureNode(flowId(flow.name), "flow", flow.name);
193
- let prevStepId;
194
- for (const step of flow.steps) {
195
- const ref = step.ref;
196
- const dotIdx = ref.indexOf(".");
197
- const ctx = dotIdx > 0 ? ref.slice(0, dotIdx) : undefined;
198
- const name = dotIdx > 0 ? ref.slice(dotIdx + 1) : ref;
199
- const kind = step.type === "read_model" ? "read_model" : step.type;
200
- ensureNode(ref, kind, name, ctx);
201
- addEdge(fId, ref, "flow_step");
202
- // Link consecutive flow steps
203
- if (prevStepId) {
204
- addEdge(prevStepId, ref, "flow_next");
205
- }
206
- prevStepId = ref;
265
+ // Local walk (no prefix).
266
+ walkOne(model, "");
267
+ // Peer walks, one prefix per peer.
268
+ for (const [peerName, peerModel] of model.peers ?? []) {
269
+ try {
270
+ walkOne(peerModel, `${peerName}:`);
271
+ }
272
+ catch (err) {
273
+ const msg = err instanceof Error ? err.message : String(err);
274
+ console.warn(`dkk: skipped graphing peer "${peerName}": ${msg}`);
207
275
  }
208
276
  }
209
277
  return new DomainGraph(nodes, edges, adj);