@principal-ai/subsystems-react 0.21.1 → 0.23.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 (92) hide show
  1. package/dist/graphify/consolidated.d.ts +5 -24
  2. package/dist/graphify/consolidated.d.ts.map +1 -1
  3. package/dist/graphify/index.d.ts +1 -1
  4. package/dist/graphify/index.d.ts.map +1 -1
  5. package/dist/graphify/index.js.map +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/pierre/PierreFileView.d.ts +3 -1
  10. package/dist/pierre/PierreFileView.d.ts.map +1 -1
  11. package/dist/pierre/PierreFileView.js +13 -3
  12. package/dist/pierre/PierreFileView.js.map +1 -1
  13. package/dist/pierre/PierreSnippetView.d.ts.map +1 -1
  14. package/dist/pierre/PierreSnippetView.js +5 -26
  15. package/dist/pierre/PierreSnippetView.js.map +1 -1
  16. package/dist/pierre/PierreWalkthroughCodeView.d.ts +3 -1
  17. package/dist/pierre/PierreWalkthroughCodeView.d.ts.map +1 -1
  18. package/dist/pierre/PierreWalkthroughCodeView.js +65 -8
  19. package/dist/pierre/PierreWalkthroughCodeView.js.map +1 -1
  20. package/dist/pierre/constructColors.d.ts.map +1 -1
  21. package/dist/pierre/constructColors.js +0 -5
  22. package/dist/pierre/constructColors.js.map +1 -1
  23. package/dist/pierre/index.d.ts +1 -1
  24. package/dist/pierre/index.d.ts.map +1 -1
  25. package/dist/pierre/index.js +1 -1
  26. package/dist/pierre/index.js.map +1 -1
  27. package/dist/pierre/scrollAnchor.d.ts +2 -0
  28. package/dist/pierre/scrollAnchor.d.ts.map +1 -1
  29. package/dist/pierre/scrollAnchor.js +7 -0
  30. package/dist/pierre/scrollAnchor.js.map +1 -1
  31. package/dist/pierre/sliceSnippet.d.ts +6 -0
  32. package/dist/pierre/sliceSnippet.d.ts.map +1 -1
  33. package/dist/pierre/sliceSnippet.js +25 -0
  34. package/dist/pierre/sliceSnippet.js.map +1 -1
  35. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
  36. package/dist/stories/Subsystem/ComponentGraph/fixtures.js +0 -4
  37. package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
  38. package/dist/subsystem/FileDrawer.d.ts +7 -2
  39. package/dist/subsystem/FileDrawer.d.ts.map +1 -1
  40. package/dist/subsystem/FileDrawer.js +13 -9
  41. package/dist/subsystem/FileDrawer.js.map +1 -1
  42. package/dist/subsystem/SubsystemComponentGraph.d.ts +2 -0
  43. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  44. package/dist/subsystem/SubsystemComponentGraph.js +97 -8
  45. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  46. package/dist/subsystem/declarationRef.d.ts +6 -1
  47. package/dist/subsystem/declarationRef.d.ts.map +1 -1
  48. package/dist/subsystem/formatDeclaration.d.ts.map +1 -1
  49. package/dist/subsystem/formatDeclaration.js +0 -15
  50. package/dist/subsystem/formatDeclaration.js.map +1 -1
  51. package/dist/subsystem/model.d.ts +61 -22
  52. package/dist/subsystem/model.d.ts.map +1 -1
  53. package/dist/subsystem/model.js +185 -65
  54. package/dist/subsystem/model.js.map +1 -1
  55. package/dist/subsystem/nodes.d.ts +3 -4
  56. package/dist/subsystem/nodes.d.ts.map +1 -1
  57. package/dist/subsystem/nodes.js +5 -6
  58. package/dist/subsystem/nodes.js.map +1 -1
  59. package/dist/utils/elkLayout.d.ts +6 -4
  60. package/dist/utils/elkLayout.d.ts.map +1 -1
  61. package/dist/utils/elkLayout.js +144 -54
  62. package/dist/utils/elkLayout.js.map +1 -1
  63. package/package.json +3 -3
  64. package/src/graphify/consolidated.ts +4 -26
  65. package/src/graphify/index.ts +0 -2
  66. package/src/index.ts +0 -2
  67. package/src/pierre/PierreFileView.tsx +25 -2
  68. package/src/pierre/PierreSnippetView.tsx +5 -31
  69. package/src/pierre/PierreWalkthroughCodeView.tsx +110 -5
  70. package/src/pierre/constructColors.test.ts +1 -2
  71. package/src/pierre/constructColors.ts +0 -5
  72. package/src/pierre/index.ts +1 -1
  73. package/src/pierre/scrollAnchor.ts +13 -0
  74. package/src/pierre/sliceSnippet.test.ts +44 -1
  75. package/src/pierre/sliceSnippet.ts +28 -0
  76. package/src/stories/Subsystem/ComponentDeclarationAudit.stories.tsx +0 -31
  77. package/src/stories/Subsystem/ComponentGraph/Appearance.stories.tsx +2 -46
  78. package/src/stories/Subsystem/ComponentGraph/Captures.stories.tsx +9 -24
  79. package/src/stories/Subsystem/ComponentGraph/DetailPanel.stories.tsx +2 -2
  80. package/src/stories/Subsystem/ComponentGraph/Flows.stories.tsx +2 -1
  81. package/src/stories/Subsystem/ComponentGraph/Modules.stories.tsx +287 -0
  82. package/src/stories/Subsystem/ComponentGraph/Processes.stories.tsx +1 -1
  83. package/src/stories/Subsystem/ComponentGraph/Scenarios.stories.tsx +6 -6
  84. package/src/stories/Subsystem/ComponentGraph/fixtures.ts +0 -4
  85. package/src/subsystem/FileDrawer.tsx +19 -7
  86. package/src/subsystem/SubsystemComponentGraph.tsx +153 -7
  87. package/src/subsystem/declarationRef.ts +6 -1
  88. package/src/subsystem/formatDeclaration.ts +0 -19
  89. package/src/subsystem/model.test.ts +190 -9
  90. package/src/subsystem/model.ts +219 -77
  91. package/src/subsystem/nodes.tsx +6 -6
  92. package/src/utils/elkLayout.ts +148 -58
@@ -39,8 +39,6 @@ export function generateDeclarationString(component: SubsystemComponent): string
39
39
  case 'type_alias':
40
40
  case 'enum':
41
41
  return generateType(name, component.construct, declaration);
42
- case 'module':
43
- return generateModule(declaration);
44
42
  case 'store':
45
43
  return generateStore(name, declaration);
46
44
  case 'external':
@@ -175,23 +173,6 @@ function generateType(
175
173
  }
176
174
  }
177
175
 
178
- function generateModule(declaration?: GraphifyComponentDetail): string {
179
- const mod = declaration?.kind === 'module' ? declaration : undefined;
180
- if (!mod) return 'module {}';
181
-
182
- const parts: string[] = [];
183
-
184
- for (const imp of mod.imports ?? []) {
185
- parts.push(`import '${imp.name}';`);
186
- }
187
-
188
- if ((mod.exports ?? []).length > 0) {
189
- parts.push(`export { ${mod.exports!.join(', ')} };`);
190
- }
191
-
192
- return parts.join('\n') || `module {}`;
193
- }
194
-
195
176
  /**
196
177
  * A store renders as its retained state — ambient `declare const` lines for
197
178
  * the state members, never a class/method stub. The node's name labels the
@@ -4,7 +4,9 @@ import {
4
4
  convertSubsystemToEdges,
5
5
  convertSubsystemToGroups,
6
6
  getSubsystemRegions,
7
+ getSubsystemModuleRegions,
7
8
  processGroupNodeId,
9
+ moduleGroupNodeId,
8
10
  buildSubsystemGraph,
9
11
  deriveNameFromSymbol,
10
12
  constructBadgeLabel,
@@ -94,10 +96,10 @@ describe('subsystem graph model', () => {
94
96
  });
95
97
 
96
98
  test('deriveNameFromSymbol is consistent per kind', () => {
97
- // brace-bodied constructs wear {}; classes render bare; module uses the symbol as-is.
99
+ // brace-bodied constructs wear {}; classes render bare.
98
100
  expect(deriveNameFromSymbol('SessionReader', 'class')).toBe('SessionReader');
99
101
  expect(deriveNameFromSymbol('SessionRecord', 'type_alias')).toBe('SessionRecord {}');
100
- expect(deriveNameFromSymbol('transcript', 'module')).toBe('transcript');
102
+ expect(deriveNameFromSymbol('transcript', 'function')).toBe('transcript()');
101
103
  // falls back to existing name when no symbol (class stays bare).
102
104
  expect(deriveNameFromSymbol(undefined, 'class', 'SessionReader')).toBe('SessionReader');
103
105
  expect(deriveNameFromSymbol('', 'external', 'principal-studio-host')).toBe('principal-studio-host');
@@ -187,13 +189,13 @@ describe('subsystem graph model', () => {
187
189
  expect(rightBadgeLabel({ role: 'service', proposed: true })).toBe('proposed');
188
190
  });
189
191
 
190
- test('deriveNameFromSymbol falls back to file basename for modules', () => {
191
- expect(deriveNameFromSymbol(undefined, 'module', undefined, 'transcript.ts')).toBe('transcript');
192
- expect(deriveNameFromSymbol(undefined, 'module', undefined, 'src/event-processors/index.ts')).toBe('index');
193
- // Symbol wins over file basename.
194
- expect(deriveNameFromSymbol('CodexRolloutRecord', 'module', undefined, 'transcript.ts')).toBe('CodexRolloutRecord');
195
- // File basename wins over a supplied name for modules (derivation precedence).
196
- expect(deriveNameFromSymbol(undefined, 'module', 'MyModule', 'x.ts')).toBe('x');
192
+ test('deriveNameFromSymbol falls back to existing name when no symbol', () => {
193
+ expect(deriveNameFromSymbol(undefined, 'class', undefined, 'transcript.ts')).toBe('untitled');
194
+ expect(deriveNameFromSymbol(undefined, 'function', 'MyFn', 'x.ts')).toBe('MyFn()');
195
+ // Symbol wins over a supplied name.
196
+ expect(deriveNameFromSymbol('CodexRolloutRecord', 'function', undefined, 'transcript.ts')).toBe(
197
+ 'CodexRolloutRecord()',
198
+ );
197
199
  });
198
200
 
199
201
  test('formatPurl renders the human identity', () => {
@@ -216,9 +218,49 @@ describe('subsystem graph model', () => {
216
218
  ],
217
219
  });
218
220
  expect(regions.map((r) => r.key)).toEqual(['app/host', 'app/renderer']);
221
+ expect(regions.every((r) => r.kind === 'process')).toBe(true);
219
222
  expect(regions[0]!.memberIds).toEqual(['a', 'b']);
220
223
  });
221
224
 
225
+ test('getSubsystemModuleRegions groups by module, skipping module-less nodes', () => {
226
+ const regions = getSubsystemModuleRegions({
227
+ components: [
228
+ { id: 'a', name: 'a', construct: 'function', file: 'transcript.ts', purl: 'pkg:github/acme/app', module: 'src/session/transcript.ts' },
229
+ { id: 'b', name: 'b', construct: 'type_alias', file: 'transcript.ts', purl: 'pkg:github/acme/app', module: 'src/session/transcript.ts' },
230
+ { id: 'c', name: 'c', construct: 'function', file: 'paths.ts', purl: 'pkg:github/acme/app', module: 'src/session/paths.ts' },
231
+ { id: 'd', name: 'd', construct: 'function', file: 'other.ts', purl: 'pkg:github/acme/app' },
232
+ ],
233
+ });
234
+ expect(regions.map((r) => r.key)).toEqual([
235
+ 'src/session/transcript.ts',
236
+ 'src/session/paths.ts',
237
+ ]);
238
+ expect(regions.every((r) => r.kind === 'module')).toBe(true);
239
+ expect(regions[0]!.memberIds).toEqual(['a', 'b']);
240
+ });
241
+
242
+ test('convertSubsystemToNodes prefers module parentId over process', () => {
243
+ const nodes = convertSubsystemToNodes({
244
+ components: [
245
+ {
246
+ id: 'a',
247
+ name: 'a',
248
+ construct: 'function',
249
+ file: 'a.ts',
250
+ purl: 'pkg:github/acme/app',
251
+ process: 'app/host',
252
+ module: 'src/a.ts',
253
+ },
254
+ { id: 'd', name: 'd', construct: 'function', file: 'd.ts', purl: 'pkg:github/acme/app' },
255
+ ],
256
+ relations: [],
257
+ });
258
+ expect((nodes.find((n) => n.id === 'a') as { parentId?: string }).parentId).toBe(
259
+ moduleGroupNodeId('src/a.ts'),
260
+ );
261
+ expect((nodes.find((n) => n.id === 'd') as { parentId?: string }).parentId).toBeUndefined();
262
+ });
263
+
222
264
  test('convertSubsystemToNodes stamps parentId for process members only', () => {
223
265
  const nodes = convertSubsystemToNodes({
224
266
  components: [
@@ -245,6 +287,103 @@ describe('subsystem graph model', () => {
245
287
  expect(groups[0]!.type).toBe('subsystem-group');
246
288
  });
247
289
 
290
+ test('convertSubsystemToGroups nests module frames under a shared process', () => {
291
+ const groups = convertSubsystemToGroups({
292
+ components: [
293
+ {
294
+ id: 'a',
295
+ name: 'a',
296
+ construct: 'function',
297
+ file: 'a.ts',
298
+ purl: 'pkg:github/acme/app',
299
+ process: 'app/host',
300
+ module: 'src/a.ts',
301
+ },
302
+ {
303
+ id: 'b',
304
+ name: 'b',
305
+ construct: 'function',
306
+ file: 'a.ts',
307
+ purl: 'pkg:github/acme/app',
308
+ process: 'app/host',
309
+ module: 'src/a.ts',
310
+ },
311
+ ],
312
+ });
313
+ expect(groups.map((g) => g.id).sort()).toEqual(
314
+ [moduleGroupNodeId('src/a.ts'), processGroupNodeId('app/host')].sort(),
315
+ );
316
+ const mod = groups.find((g) => g.id === moduleGroupNodeId('src/a.ts'));
317
+ expect((mod as { parentId?: string }).parentId).toBe(processGroupNodeId('app/host'));
318
+ const proc = groups.find((g) => g.id === processGroupNodeId('app/host'));
319
+ expect((proc as { parentId?: string }).parentId).toBeUndefined();
320
+ });
321
+
322
+ test('buildSubsystemGraph nests module frames inside process frames', async () => {
323
+ const { nodes, regions } = await buildSubsystemGraph({
324
+ components: [
325
+ {
326
+ id: 'boot',
327
+ name: 'boot',
328
+ construct: 'function',
329
+ file: 'main.ts',
330
+ purl: 'pkg:github/acme/app',
331
+ process: 'app/host',
332
+ module: 'src/main.ts',
333
+ symbol: 'boot',
334
+ },
335
+ {
336
+ id: 'create',
337
+ name: 'createHost',
338
+ construct: 'function',
339
+ file: 'main.ts',
340
+ purl: 'pkg:github/acme/app',
341
+ process: 'app/host',
342
+ module: 'src/main.ts',
343
+ symbol: 'createHost',
344
+ },
345
+ {
346
+ id: 'write',
347
+ name: 'writeSession',
348
+ construct: 'function',
349
+ file: 'store.ts',
350
+ purl: 'pkg:github/acme/app',
351
+ process: 'app/host',
352
+ module: 'src/store.ts',
353
+ symbol: 'writeSession',
354
+ },
355
+ {
356
+ id: 'store',
357
+ name: 'SessionStore',
358
+ construct: 'store',
359
+ file: 'store.ts',
360
+ purl: 'pkg:github/acme/app',
361
+ process: 'app/host',
362
+ module: 'src/store.ts',
363
+ symbol: 'SessionStore',
364
+ },
365
+ ],
366
+ relations: [],
367
+ });
368
+ expect(regions.map((r) => r.key).sort()).toEqual(
369
+ ['app/host', 'src/main.ts', 'src/store.ts'].sort(),
370
+ );
371
+ const processNode = nodes.find((n) => n.id === processGroupNodeId('app/host'));
372
+ const mainMod = nodes.find((n) => n.id === moduleGroupNodeId('src/main.ts'));
373
+ const storeMod = nodes.find((n) => n.id === moduleGroupNodeId('src/store.ts'));
374
+ expect(processNode).toBeDefined();
375
+ expect(mainMod).toBeDefined();
376
+ expect(storeMod).toBeDefined();
377
+ expect((mainMod as { parentId?: string }).parentId).toBe(processGroupNodeId('app/host'));
378
+ expect((storeMod as { parentId?: string }).parentId).toBe(processGroupNodeId('app/host'));
379
+ expect((nodes.find((n) => n.id === 'boot') as { parentId?: string }).parentId).toBe(
380
+ moduleGroupNodeId('src/main.ts'),
381
+ );
382
+ expect((nodes.find((n) => n.id === 'store') as { parentId?: string }).parentId).toBe(
383
+ moduleGroupNodeId('src/store.ts'),
384
+ );
385
+ });
386
+
248
387
  test('buildSubsystemGraph drops singleton process frames (no parentId, no group)', async () => {
249
388
  const { nodes, regions } = await buildSubsystemGraph({
250
389
  components: [
@@ -264,6 +403,48 @@ describe('subsystem graph model', () => {
264
403
  expect(nodes.find((n) => n.id === processGroupNodeId('app/lonely'))).toBeUndefined();
265
404
  });
266
405
 
406
+ test('buildSubsystemGraph frames multi-member modules', async () => {
407
+ const { nodes, regions } = await buildSubsystemGraph({
408
+ components: [
409
+ {
410
+ id: 'rec',
411
+ name: 'CodexRolloutRecord',
412
+ construct: 'type_alias',
413
+ file: 'transcript.ts',
414
+ purl: 'pkg:github/acme/app',
415
+ module: 'src/session/transcript.ts',
416
+ symbol: 'CodexRolloutRecord',
417
+ },
418
+ {
419
+ id: 'parse',
420
+ name: 'parseTranscript',
421
+ construct: 'function',
422
+ file: 'transcript.ts',
423
+ purl: 'pkg:github/acme/app',
424
+ module: 'src/session/transcript.ts',
425
+ symbol: 'parseTranscript',
426
+ },
427
+ {
428
+ id: 'solo',
429
+ name: 'lonely',
430
+ construct: 'function',
431
+ file: 'solo.ts',
432
+ purl: 'pkg:github/acme/app',
433
+ module: 'src/solo.ts',
434
+ symbol: 'lonely',
435
+ },
436
+ ],
437
+ relations: [],
438
+ });
439
+ expect(regions.map((r) => r.key)).toEqual(['src/session/transcript.ts']);
440
+ expect(regions[0]!.kind).toBe('module');
441
+ expect((nodes.find((n) => n.id === 'rec') as { parentId?: string }).parentId).toBe(
442
+ moduleGroupNodeId('src/session/transcript.ts'),
443
+ );
444
+ expect((nodes.find((n) => n.id === 'solo') as { parentId?: string }).parentId).toBeUndefined();
445
+ expect(nodes.find((n) => n.id === moduleGroupNodeId('src/session/transcript.ts'))).toBeDefined();
446
+ });
447
+
267
448
  test('subsystemGraphLayoutKey ignores declarationRef-only changes', () => {
268
449
  const base = doc;
269
450
  const withRef = {