@principal-ai/subsystems-react 0.50.0 → 0.51.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 (61) hide show
  1. package/dist/index.d.ts +8 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +5 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.d.ts +95 -0
  6. package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.d.ts.map +1 -0
  7. package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.js +340 -0
  8. package/dist/stories/Subsystem/C4Graph/c4Associations.fixture.js.map +1 -0
  9. package/dist/stories/Subsystem/C4Graph/c4Fixture.d.ts +4 -0
  10. package/dist/stories/Subsystem/C4Graph/c4Fixture.d.ts.map +1 -1
  11. package/dist/stories/Subsystem/C4Graph/c4Fixture.js +7334 -1
  12. package/dist/stories/Subsystem/C4Graph/c4Fixture.js.map +1 -1
  13. package/dist/stories/Subsystem/C4Graph/generateFixture.d.ts +2 -0
  14. package/dist/stories/Subsystem/C4Graph/generateFixture.d.ts.map +1 -0
  15. package/dist/stories/Subsystem/C4Graph/generateFixture.js +145 -0
  16. package/dist/stories/Subsystem/C4Graph/generateFixture.js.map +1 -0
  17. package/dist/subsystem/C4Graph.d.ts.map +1 -1
  18. package/dist/subsystem/C4Graph.js +16 -60
  19. package/dist/subsystem/C4Graph.js.map +1 -1
  20. package/dist/subsystem/C4NodeCard.d.ts +84 -0
  21. package/dist/subsystem/C4NodeCard.d.ts.map +1 -0
  22. package/dist/subsystem/C4NodeCard.js +229 -0
  23. package/dist/subsystem/C4NodeCard.js.map +1 -0
  24. package/dist/subsystem/DiagnosticToggle.d.ts +8 -1
  25. package/dist/subsystem/DiagnosticToggle.d.ts.map +1 -1
  26. package/dist/subsystem/DiagnosticToggle.js +40 -6
  27. package/dist/subsystem/DiagnosticToggle.js.map +1 -1
  28. package/dist/subsystem/c4Associations.d.ts +186 -0
  29. package/dist/subsystem/c4Associations.d.ts.map +1 -0
  30. package/dist/subsystem/c4Associations.js +284 -0
  31. package/dist/subsystem/c4Associations.js.map +1 -0
  32. package/dist/subsystem/model.d.ts +25 -1
  33. package/dist/subsystem/model.d.ts.map +1 -1
  34. package/dist/subsystem/model.js +15 -0
  35. package/dist/subsystem/model.js.map +1 -1
  36. package/dist/subsystem/nodes.d.ts.map +1 -1
  37. package/dist/subsystem/nodes.js +78 -7
  38. package/dist/subsystem/nodes.js.map +1 -1
  39. package/dist/subsystem/toC4.d.ts +119 -0
  40. package/dist/subsystem/toC4.d.ts.map +1 -1
  41. package/dist/subsystem/toC4.js +95 -5
  42. package/dist/subsystem/toC4.js.map +1 -1
  43. package/package.json +2 -2
  44. package/src/index.ts +39 -0
  45. package/src/stories/Subsystem/C4Graph/C4Associations.stories.tsx +273 -0
  46. package/src/stories/Subsystem/C4Graph/C4NodeGallery.stories.tsx +325 -0
  47. package/src/stories/Subsystem/C4Graph/c4Associations.fixture.ts +344 -0
  48. package/src/stories/Subsystem/C4Graph/c4Fixture.ts +7337 -4
  49. package/src/stories/Subsystem/C4Graph/generateFixture.ts +161 -0
  50. package/src/stories/Subsystem/ComponentGraph/Deprecated.stories.tsx +358 -0
  51. package/src/stories/Subsystem/ComponentGraph/Diagnostics.stories.tsx +27 -2
  52. package/src/stories/Subsystem/ComponentGraph/{Flows.stories.tsx → Trails.stories.tsx} +4 -4
  53. package/src/subsystem/C4Graph.tsx +51 -92
  54. package/src/subsystem/C4NodeCard.test.ts +196 -0
  55. package/src/subsystem/C4NodeCard.tsx +307 -0
  56. package/src/subsystem/DiagnosticToggle.tsx +58 -4
  57. package/src/subsystem/c4Associations.test.ts +484 -0
  58. package/src/subsystem/c4Associations.ts +398 -0
  59. package/src/subsystem/model.ts +34 -1
  60. package/src/subsystem/nodes.tsx +124 -5
  61. package/src/subsystem/toC4.ts +210 -5
@@ -1 +1 @@
1
- {"version":3,"file":"toC4.d.ts","sourceRoot":"","sources":["../../src/subsystem/toC4.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAE1E,4DAA4D;AAC5D,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC;AAEjF,+EAA+E;AAC/E,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,WAAW,CAAC;AAE/C,mDAAmD;AACnD,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,qEAAqE;IACrE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,wEAAwE;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wEAAwE;AACxE,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,+DAA+D;AAC/D,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC1C;AAKD,+DAA+D;AAC/D,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAElE;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,GAAG,EAAE,sBAAsB,GAAG,MAAM,GAAG,SAAS,CAM7E;AAaD;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,sBAAsB,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CA6IpF"}
1
+ {"version":3,"file":"toC4.d.ts","sourceRoot":"","sources":["../../src/subsystem/toC4.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,40 @@ const UNASSIGNED = '(unassigned)';
25
25
  export function isGroundedComponent(c) {
26
26
  return c.construct !== 'external' && c.construct !== 'custom_entity';
27
27
  }
28
+ /**
29
+ * Index confirmed associations by the derived keys they claim.
30
+ *
31
+ * First writer wins on a contested key so the result does not depend on array
32
+ * order, and the loser is reported so the conflict is visible rather than
33
+ * silently dropped.
34
+ */
35
+ export function indexAssociations(associations) {
36
+ const byKey = new Map();
37
+ const contested = [];
38
+ if (!associations)
39
+ return { byKey, contested };
40
+ // Stable order: accepted before proposed, so a confirmed decision outranks a
41
+ // speculative one for the same key.
42
+ const ordered = [...associations].sort((a, b) => {
43
+ const rank = (s) => (s === 'accepted' ? 0 : s === 'proposed' ? 1 : 2);
44
+ return rank(a.state) - rank(b.state) || a.id.localeCompare(b.id);
45
+ });
46
+ for (const a of ordered) {
47
+ for (const key of a.sourceKeys) {
48
+ const existing = byKey.get(key);
49
+ if (existing && existing.id !== a.id) {
50
+ contested.push({ key, kept: existing.id, dropped: a.id });
51
+ continue;
52
+ }
53
+ byKey.set(key, a);
54
+ }
55
+ }
56
+ return { byKey, contested };
57
+ }
58
+ /** True when a resolved association means this box should not be drawn. */
59
+ function isSuppressed(a) {
60
+ return a?.state === 'rejected';
61
+ }
28
62
  /** `owner/name` from a purl, trimmed of scheme and fragment. */
29
63
  export function labelFromPurl(purl) {
30
64
  const base = purl.replace(/^external:/, '').split('#')[0]?.trim() ?? '';
@@ -60,6 +94,12 @@ export function toC4(doc, options = {}) {
60
94
  const view = options.view ?? 'container';
61
95
  const repoKey = options.repoKey ?? deriveRepoKey(doc) ?? 'system';
62
96
  const systemId = `system:${repoKey}`;
97
+ const { byKey: assocByKey } = indexAssociations(options.associations);
98
+ // Id -> association, so a container frame can be labelled from its
99
+ // association even when no node exists for it (component view).
100
+ const assocById = new Map();
101
+ for (const a of options.associations ?? [])
102
+ assocById.set(a.id, a);
63
103
  const system = {
64
104
  id: systemId,
65
105
  kind: 'system',
@@ -73,12 +113,32 @@ export function toC4(doc, options = {}) {
73
113
  const ownerOf = new Map();
74
114
  const containerNodeId = (key) => `container:${key}`;
75
115
  const componentNodeId = (alias) => `component:${alias}`;
116
+ /**
117
+ * Resolve one derived container key into the box that should carry it.
118
+ *
119
+ * An accepted association wins: its id becomes the node id, so every key it
120
+ * claims rolls into one node (that is the dedup), and its label / type /
121
+ * technology / description become the node's presentation. A rejected one
122
+ * means the box is not drawn at all. Unclaimed keys keep the raw derived
123
+ * behaviour, so the projection is still useful with zero associations.
124
+ */
125
+ const resolveContainer = (key) => {
126
+ const assoc = assocByKey.get(key);
127
+ if (assoc && assoc.level === 'container') {
128
+ return { id: assoc.id, label: assoc.label, assoc };
129
+ }
130
+ if (view === 'component') {
131
+ return { id: containerNodeId(key), label: key === UNASSIGNED ? 'Unassigned' : key, assoc: undefined };
132
+ }
133
+ return { id: containerNodeId(key), label: key === UNASSIGNED ? 'Unassigned' : key, assoc: undefined };
134
+ };
76
135
  for (const c of doc.components) {
77
136
  let id;
78
137
  let kind;
79
138
  let label;
80
139
  let parentId;
81
140
  let key;
141
+ let assoc;
82
142
  if (c.construct === 'external') {
83
143
  key = externalKey(c);
84
144
  id = `external:${key}`;
@@ -93,17 +153,25 @@ export function toC4(doc, options = {}) {
93
153
  }
94
154
  else if (view === 'component') {
95
155
  key = containerKey(c);
156
+ const resolved = resolveContainer(key);
157
+ if (isSuppressed(resolved.assoc))
158
+ continue;
96
159
  id = componentNodeId(c.alias);
97
160
  kind = 'component';
98
161
  label = c.name;
99
- parentId = containerNodeId(key);
162
+ parentId = resolved.id;
163
+ assoc = undefined; // the component itself has no association
100
164
  }
101
165
  else {
102
166
  key = containerKey(c);
103
- id = containerNodeId(key);
167
+ const resolved = resolveContainer(key);
168
+ if (isSuppressed(resolved.assoc))
169
+ continue;
170
+ id = resolved.id;
104
171
  kind = 'container';
105
- label = key === UNASSIGNED ? 'Unassigned' : key;
172
+ label = resolved.label;
106
173
  parentId = systemId;
174
+ assoc = resolved.assoc;
107
175
  }
108
176
  ownerOf.set(c.alias, id);
109
177
  let node = nodes.get(id);
@@ -117,7 +185,12 @@ export function toC4(doc, options = {}) {
117
185
  members: [],
118
186
  constructs: [],
119
187
  isStore: false,
188
+ // A merged box is built from several derived keys. Track them as a
189
+ // set so the confirm UI can show what was folded together — without
190
+ // this, the accumulation would run once per member, not per key.
191
+ ...(assoc && assoc.sourceKeys.length > 1 ? { sourceKeys: [...assoc.sourceKeys] } : {}),
120
192
  ...(kind === 'component' ? { component: c } : {}),
193
+ ...(assoc ? { decoration: toDecoration(assoc) } : {}),
121
194
  };
122
195
  nodes.set(id, node);
123
196
  }
@@ -133,6 +206,9 @@ export function toC4(doc, options = {}) {
133
206
  }
134
207
  // --- Groups (compound frames) ------------------------------------------
135
208
  const groups = [];
209
+ const labelForContainerId = (id) => nodes.get(id)?.label ??
210
+ assocById.get(id)?.label ??
211
+ (id.startsWith('container:') ? id.slice('container:'.length) : id);
136
212
  if (view === 'container') {
137
213
  const containerIds = [...nodes.values()].filter((n) => n.kind === 'container').map((n) => n.id);
138
214
  if (containerIds.length > 0) {
@@ -150,8 +226,7 @@ export function toC4(doc, options = {}) {
150
226
  }
151
227
  const containerIds = [];
152
228
  for (const [id, memberIds] of byContainer) {
153
- const label = id.slice('container:'.length);
154
- groups.push({ id, kind: 'container', label: label === UNASSIGNED ? 'Unassigned' : label, parentId: systemId, memberIds });
229
+ groups.push({ id, kind: 'container', label: labelForContainerId(id), parentId: systemId, memberIds });
155
230
  containerIds.push(id);
156
231
  }
157
232
  if (containerIds.length > 0) {
@@ -163,6 +238,10 @@ export function toC4(doc, options = {}) {
163
238
  const addEdge = (bucket, source, target, kind, mechanism) => {
164
239
  if (!source || !target || source === target)
165
240
  return;
241
+ // An endpoint whose box was rejected has no owner; the edge cannot be
242
+ // drawn, so drop it rather than inventing a dangling arrow.
243
+ if (!nodes.has(source) || !nodes.has(target))
244
+ return;
166
245
  const key = `${source}\0${target}`;
167
246
  let edge = bucket.get(key);
168
247
  if (!edge) {
@@ -189,4 +268,15 @@ export function toC4(doc, options = {}) {
189
268
  edges,
190
269
  };
191
270
  }
271
+ /** Project an association down to the attributes a node carries. */
272
+ function toDecoration(a) {
273
+ return {
274
+ id: a.id,
275
+ label: a.label,
276
+ type: a.type,
277
+ technology: a.technology,
278
+ description: a.description,
279
+ state: a.state,
280
+ };
281
+ }
192
282
  //# sourceMappingURL=toC4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toC4.js","sourceRoot":"","sources":["../../src/subsystem/toC4.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAsEH,MAAM,aAAa,GAAG,UAAU,CAAC;AACjC,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC,+DAA+D;AAC/D,MAAM,UAAU,mBAAmB,CAAC,CAAqB;IACvD,OAAO,CAAC,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC,CAAC,SAAS,KAAK,eAAe,CAAC;AACvE,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC;AACnD,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,aAAa,CAAC,GAA2B;IACvD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE;QAC9B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,CAAC,CAAC;KACtE;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kFAAkF;AAClF,SAAS,WAAW,CAAC,CAAqB;IACxC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,IAAI,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,mBAAmB;QAAE,OAAO,IAAI,CAAC;IAChF,OAAO,SAAS,CAAC,CAAC,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,YAAY,CAAC,CAAqB;IACzC,OAAO,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,UAAU,CAAC;AACzC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,GAA2B,EAAE,UAAuB,EAAE;IACzE,MAAM,IAAI,GAAW,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC;IACjD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC;IAClE,MAAM,QAAQ,GAAG,UAAU,OAAO,EAAE,CAAC;IAErC,MAAM,MAAM,GAAW;QACrB,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,OAAO,CAAC,WAAW,IAAI,aAAa,CAAC,OAAO,CAAC;QACpD,GAAG,EAAE,OAAO;QACZ,OAAO,EAAE,EAAE;QACX,UAAU,EAAE,EAAE;QACd,OAAO,EAAE,KAAK;KACf,CAAC;IAEF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE1C,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,aAAa,GAAG,EAAE,CAAC;IAC5D,MAAM,eAAe,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,aAAa,KAAK,EAAE,CAAC;IAEhE,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE;QAC9B,IAAI,EAAU,CAAC;QACf,IAAI,IAAY,CAAC;QACjB,IAAI,KAAa,CAAC;QAClB,IAAI,QAA4B,CAAC;QACjC,IAAI,GAAuB,CAAC;QAE5B,IAAI,CAAC,CAAC,SAAS,KAAK,UAAU,EAAE;YAC9B,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YACrB,EAAE,GAAG,YAAY,GAAG,EAAE,CAAC;YACvB,IAAI,GAAG,UAAU,CAAC;YAClB,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;SAChE;aAAM,IAAI,CAAC,CAAC,SAAS,KAAK,eAAe,EAAE;YAC1C,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC;YACd,EAAE,GAAG,SAAS,CAAC,CAAC,KAAK,EAAE,CAAC;YACxB,IAAI,GAAG,OAAO,CAAC;YACf,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC;SAChB;aAAM,IAAI,IAAI,KAAK,WAAW,EAAE;YAC/B,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YACtB,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC9B,IAAI,GAAG,WAAW,CAAC;YACnB,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC;YACf,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;SACjC;aAAM;YACL,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YACtB,EAAE,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,GAAG,WAAW,CAAC;YACnB,KAAK,GAAG,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC;YAChD,QAAQ,GAAG,QAAQ,CAAC;SACrB;QAED,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAEzB,IAAI,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,IAAI,EAAE;YACT,IAAI,GAAG;gBACL,EAAE;gBACF,IAAI;gBACJ,KAAK;gBACL,QAAQ;gBACR,GAAG;gBACH,OAAO,EAAE,EAAE;gBACX,UAAU,EAAE,EAAE;gBACd,OAAO,EAAE,KAAK;gBACd,GAAG,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAClD,CAAC;YACF,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;SACrB;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;YAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC9E,IAAI,CAAC,CAAC,SAAS,KAAK,OAAO;YAAE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACjD,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;YAC/B,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;SACjE;KACF;IAED,0EAA0E;IAC1E,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,IAAI,IAAI,KAAK,WAAW,EAAE;QACxB,MAAM,YAAY,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAChG,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;SAC7F;KACF;SAAM;QACL,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE;YAC9B,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,CAAC,QAAQ;gBAAE,SAAS;YACpD,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAChB,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;SACnC;QACD,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,KAAK,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,WAAW,EAAE;YACzC,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YAC1H,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SACvB;QACD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;SAC7F;KACF;IAED,2EAA2E;IAC3E,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE5C,MAAM,OAAO,GAAG,CACd,MAA2B,EAC3B,MAA0B,EAC1B,MAA0B,EAC1B,IAAoB,EACpB,SAAiB,EACjB,EAAE;QACF,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO;QACpD,MAAM,GAAG,GAAG,GAAG,MAAM,KAAK,MAAM,EAAE,CAAC;QACnC,IAAI,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE;YACT,IAAI,GAAG,EAAE,EAAE,EAAE,GAAG,IAAI,IAAI,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YAC3F,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;SACvB;QACD,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5E,CAAC,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE;QAChC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE;YAC7B,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;SACjF;KACF;IAED,MAAM,KAAK,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAEtE,OAAO;QACL,IAAI;QACJ,MAAM;QACN,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC;QAC7D,MAAM;QACN,KAAK;KACN,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"toC4.js","sourceRoot":"","sources":["../../src/subsystem/toC4.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@principal-ai/subsystems-react",
3
- "version": "0.50.0",
4
- "description": "React UI for Subsystem Models — graph, Pierre code views, and session-event feeds",
3
+ "version": "0.51.0",
4
+ "description": "React UI for Subsystem Models \u2014 graph, Pierre code views, and session-event feeds",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
package/src/index.ts CHANGED
@@ -239,6 +239,45 @@ export type {
239
239
  SubsystemSignatureClaim,
240
240
  SubsystemSignatureParameter,
241
241
  } from './subsystem/model';
242
+ // --- C4 projection + the confirmed association layer ------------------
243
+ export { C4Graph } from './subsystem/C4Graph';
244
+ export type { C4GraphProps } from './subsystem/C4Graph';
245
+ export { C4NodeCard, nodeStyle, nodeSubtitle, nodeTag, nodeMissing, NODE_W, NODE_H } from './subsystem/C4NodeCard';
246
+ export type { C4NodeCardProps, NodeStyle } from './subsystem/C4NodeCard';
247
+ export {
248
+ toC4,
249
+ isGroundedComponent,
250
+ labelFromPurl,
251
+ deriveRepoKey,
252
+ indexAssociations,
253
+ } from './subsystem/toC4';
254
+ export type {
255
+ C4Kind,
256
+ C4View,
257
+ C4Node,
258
+ C4Group,
259
+ C4Edge,
260
+ C4Model,
261
+ C4Decoration,
262
+ C4ElementType,
263
+ C4Association,
264
+ C4AssociationState,
265
+ ToC4Options,
266
+ } from './subsystem/toC4';
267
+ export {
268
+ deriveConcerns,
269
+ suggestMerges,
270
+ buildAssociations,
271
+ mergeAssociations,
272
+ associationWeight,
273
+ summarizeAssociations,
274
+ } from './subsystem/c4Associations';
275
+ export type {
276
+ C4AssociationSet,
277
+ C4AssociationReason,
278
+ C4ConcernKind,
279
+ C4MemberView,
280
+ } from './subsystem/c4Associations';
242
281
  export {
243
282
  constructBadgeLabel,
244
283
  constructBadgeColor,
@@ -0,0 +1,273 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import '@xyflow/react/dist/style.css';
3
+ import type { Meta, StoryObj } from '@storybook/react';
4
+ import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
5
+ import { C4Graph } from '../../../subsystem/C4Graph';
6
+ import { toC4, type C4View } from '../../../subsystem/toC4';
7
+ import type { C4Association } from '../../../subsystem/toC4';
8
+ import { summarizeAssociations, mergeAssociations } from '../../../subsystem/c4Associations';
9
+ import { c4FixtureModel, c4MemberCounts } from './c4Fixture';
10
+ import { c4Associations, C4_MERGE_CANDIDATES, C4_CONCERNS } from './c4Associations.fixture';
11
+
12
+ const MEMBER_COUNTS = new Map(Object.entries(c4MemberCounts));
13
+
14
+ const meta = {
15
+ title: 'Subsystem/C4Graph/C4Associations',
16
+ component: C4Graph,
17
+ parameters: { layout: 'fullscreen' },
18
+ tags: ['autodocs'],
19
+ decorators: [
20
+ (Story) => (
21
+ <ThemeProvider theme={defaultEditorTheme}>
22
+ <Story />
23
+ </ThemeProvider>
24
+ ),
25
+ ],
26
+ } satisfies Meta<typeof C4Graph>;
27
+
28
+ export default meta;
29
+ type Story = StoryObj<typeof meta>;
30
+
31
+ /**
32
+ * C4 associations — the confirmed layer over a raw derivation.
33
+ *
34
+ * `toC4()` alone rolls components up into boxes keyed by `process`. That
35
+ * derivation is a guess: two keys may be the same deployable, a library may be
36
+ * pretending to be a container, and a store may not be a C4 data store at all.
37
+ *
38
+ * This story starts from a real composite of 40 stored models and lets you act
39
+ * on the 13 proposed associations:
40
+ *
41
+ * accept the box goes solid — it is part of the architecture
42
+ * reject the box disappears, and so do the edges into it
43
+ * merge two keys collapse into one box
44
+ *
45
+ * Try `merge host` first: it takes `subsystems-studio/host` (113 components)
46
+ * and `principal-studio/host` (1 component) and folds them into one container.
47
+ */
48
+
49
+ function Demo({ initialAccepted = [] as string[] }: { initialAccepted?: string[] }) {
50
+ const [view, setView] = useState<C4View>('container');
51
+ const [selected, setSelected] = useState<string | null>(null);
52
+ const [state, setState] = useState<Record<string, C4Association['state']>>(() =>
53
+ Object.fromEntries(initialAccepted.map((id) => [id, 'accepted' as const])),
54
+ );
55
+ /** Roles the user has merged. Folds the candidates into one association each. */
56
+ const [mergedRoles, setMergedRoles] = useState<string[]>([]);
57
+
58
+ const associations = useMemo<C4Association[]>(() => {
59
+ let set: C4Association[] = c4Associations;
60
+ for (const role of mergedRoles) {
61
+ const candidate = C4_MERGE_CANDIDATES.find((c) => c.role === role);
62
+ if (!candidate) continue;
63
+ // The evidence-heavy side survives automatically — see mergeAssociations.
64
+ set = mergeAssociations(set, candidate.keys, undefined, MEMBER_COUNTS);
65
+ }
66
+ // Apply the user's accept/reject last, over the merged set.
67
+ return set.map((a) => ({ ...a, state: state[a.id] ?? a.state }));
68
+ }, [state, mergedRoles]);
69
+
70
+ const model = useMemo(
71
+ () => toC4(c4FixtureModel, { view, systemLabel: 'Subsystem Modeling', associations }),
72
+ [view, associations],
73
+ );
74
+
75
+ const stats = useMemo(() => summarizeAssociations(model, associations), [model, associations]);
76
+
77
+ const concernsFor = (id: string) => {
78
+ const a = associations.find((x) => x.id === id);
79
+ if (!a) return [];
80
+ return C4_CONCERNS.filter((c) => a.sourceKeys.includes(c.target));
81
+ };
82
+
83
+ const decide = (id: string, next: C4Association['state']) =>
84
+ setState((prev) => ({ ...prev, [id]: next }));
85
+
86
+ const reset = () => {
87
+ setState({});
88
+ setMergedRoles([]);
89
+ };
90
+
91
+ const button = (label: string, value: C4View) => (
92
+ <button
93
+ type="button"
94
+ onClick={() => setView(value)}
95
+ style={{
96
+ fontFamily: 'monospace',
97
+ fontSize: 12,
98
+ padding: '2px 10px',
99
+ borderRadius: 4,
100
+ cursor: 'pointer',
101
+ border: '1px solid #555',
102
+ background: view === value ? '#1D9E75' : 'transparent',
103
+ color: view === value ? '#020B12' : '#ddd',
104
+ }}
105
+ >
106
+ {label}
107
+ </button>
108
+ );
109
+
110
+ const act = (label: string, onClick: () => void) => (
111
+ <button
112
+ type="button"
113
+ onClick={onClick}
114
+ style={{
115
+ fontFamily: 'monospace',
116
+ fontSize: 11,
117
+ padding: '2px 8px',
118
+ borderRadius: 4,
119
+ cursor: 'pointer',
120
+ border: '1px solid #555',
121
+ background: 'transparent',
122
+ color: '#ddd',
123
+ }}
124
+ >
125
+ {label}
126
+ </button>
127
+ );
128
+
129
+ return (
130
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column', background: '#12141a' }}>
131
+ <div style={{ flex: 1, minHeight: 0, position: 'relative' }}>
132
+ <C4Graph model={model} title="Subsystem Modeling" onSelectNode={setSelected} />
133
+ </div>
134
+
135
+ <div
136
+ style={{
137
+ maxHeight: 280,
138
+ overflowY: 'auto',
139
+ padding: '8px 12px',
140
+ display: 'flex',
141
+ gap: 18,
142
+ fontFamily: 'monospace',
143
+ fontSize: 12,
144
+ color: '#aaa',
145
+ borderTop: '1px solid #333',
146
+ }}
147
+ >
148
+ <div style={{ minWidth: 210 }}>
149
+ <div style={{ display: 'flex', gap: 6, marginBottom: 8 }}>
150
+ {button('container', 'container')}
151
+ {button('component', 'component')}
152
+ </div>
153
+ <div>
154
+ {stats.confirmed} confirmed · {stats.proposed} proposed
155
+ </div>
156
+ <div>{stats.rejected} rejected · {stats.mergedAway} keys merged away</div>
157
+ <div style={{ color: stats.missingTechnology > 0 ? '#e8a33a' : '#5a5' }}>
158
+ {stats.missingTechnology} containers missing technology
159
+ </div>
160
+ <div>{stats.needsDecision} still need a decision</div>
161
+ <div style={{ marginTop: 8 }}>{act('reset', reset)}</div>
162
+ </div>
163
+
164
+ {/* The merge question, with one click to try it. */}
165
+ <div style={{ minWidth: 300, maxWidth: 340 }}>
166
+ <div style={{ color: '#ddd', marginBottom: 4 }}>MERGE CANDIDATES</div>
167
+ {C4_MERGE_CANDIDATES.map((c) => {
168
+ const done = mergedRoles.includes(c.role);
169
+ // Show which side the evidence will keep, before you click.
170
+ const heaviest = c.keys.reduce((a, b) =>
171
+ (c4MemberCounts[b] ?? 0) > (c4MemberCounts[a] ?? 0) ? b : a,
172
+ );
173
+ return (
174
+ <div key={c.role} style={{ marginBottom: 8 }}>
175
+ {c.keys.map((k) => (
176
+ <div
177
+ key={k}
178
+ style={{
179
+ color: done && k === heaviest ? '#5a5' : '#888',
180
+ lineHeight: 1.35,
181
+ fontWeight: done && k === heaviest ? 600 : 400,
182
+ }}
183
+ >
184
+ {k} · {c4MemberCounts[k] ?? 0}
185
+ </div>
186
+ ))}
187
+ <div style={{ display: 'flex', gap: 6, alignItems: 'center', marginTop: 3 }}>
188
+ {done ? (
189
+ <>
190
+ <span style={{ color: '#5a5' }}>merged — kept {heaviest.split('/').pop()}</span>
191
+ {act('undo', () => setMergedRoles((prev) => prev.filter((r) => r !== c.role)))}
192
+ </>
193
+ ) : (
194
+ act(`merge ${c.role}`, () => setMergedRoles((prev) => [...prev, c.role]))
195
+ )}
196
+ </div>
197
+ </div>
198
+ );
199
+ })}
200
+ </div>
201
+
202
+ {/* Per-association review. This is the surface a real confirm UI would use. */}
203
+ <div style={{ flex: 1, minWidth: 380 }}>
204
+ <div style={{ color: '#ddd', marginBottom: 4 }}>
205
+ ASSOCIATIONS · {associations.length}
206
+ </div>
207
+ {associations.map((a) => {
208
+ const s = state[a.id] ?? a.state;
209
+ const concerns = concernsFor(a.id);
210
+ const missing: string[] = [];
211
+ if (!a.technology) missing.push('technology');
212
+ if (!a.description) missing.push('description');
213
+ return (
214
+ <div
215
+ key={a.id}
216
+ style={{
217
+ display: 'flex',
218
+ gap: 10,
219
+ alignItems: 'flex-start',
220
+ padding: '4px 0',
221
+ borderBottom: '1px solid #222',
222
+ opacity: s === 'rejected' ? 0.45 : 1,
223
+ }}
224
+ >
225
+ <div style={{ flex: 1, minWidth: 0 }}>
226
+ <div style={{ color: '#ddd' }}>
227
+ {a.label}
228
+ <span style={{ color: s === 'accepted' ? '#5a5' : s === 'proposed' ? '#e8a33a' : '#888' }}>
229
+ {' '}
230
+ · {s} · {a.type}
231
+ </span>
232
+ </div>
233
+ <div style={{ color: '#777', fontSize: 11 }}>
234
+ keys: {a.sourceKeys.join(', ')}
235
+ {a.technology ? ` · tech: ${a.technology}` : ''}
236
+ {missing.length > 0 ? ` · needs ${missing.join(' + ')}` : ''}
237
+ </div>
238
+ {concerns.length > 0 && (
239
+ <div style={{ color: '#c96', fontSize: 11, lineHeight: 1.35 }}>
240
+ {concerns.map((c) => (
241
+ <div key={c.kind + c.target}>⚠ {c.message}</div>
242
+ ))}
243
+ </div>
244
+ )}
245
+ </div>
246
+ <div style={{ display: 'flex', gap: 4 }}>
247
+ {act('accept', () => decide(a.id, 'accepted'))}
248
+ {act('reject', () => decide(a.id, 'rejected'))}
249
+ </div>
250
+ </div>
251
+ );
252
+ })}
253
+ </div>
254
+
255
+ <div style={{ minWidth: 130, fontSize: 11, color: '#777' }}>
256
+ <div>selected: {selected ?? '(none)'}</div>
257
+ <div style={{ marginTop: 6 }}>solid = confirmed</div>
258
+ <div>dashed = proposed</div>
259
+ <div>muted = unconfirmed</div>
260
+ </div>
261
+ </div>
262
+ </div>
263
+ );
264
+ }
265
+
266
+ export const Associations: Story = {
267
+ render: () => <Demo />,
268
+ };
269
+
270
+ /** Start from a half-confirmed state so the visual difference is obvious. */
271
+ export const PartiallyConfirmed: Story = {
272
+ render: () => <Demo initialAccepted={['container:subsystems-studio/host', 'container:subsystems-studio/renderer']} />,
273
+ };