@1agh/maude 0.22.2 → 0.24.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 (125) hide show
  1. package/README.md +34 -1
  2. package/cli/bin/maude.mjs +3 -0
  3. package/cli/commands/cache.mjs +181 -0
  4. package/cli/commands/cache.test.mjs +166 -0
  5. package/cli/commands/design-link.test.mjs +84 -2
  6. package/cli/commands/design.mjs +95 -4
  7. package/cli/commands/design.test.mjs +56 -0
  8. package/cli/commands/help.mjs +34 -0
  9. package/cli/commands/hub.mjs +255 -30
  10. package/cli/commands/hub.test.mjs +135 -10
  11. package/cli/commands/init.mjs +3 -0
  12. package/cli/commands/preflight.mjs +11 -0
  13. package/cli/commands/preflight.test.mjs +46 -0
  14. package/cli/commands/scenario-report.mjs +45 -0
  15. package/cli/lib/cache.mjs +407 -0
  16. package/cli/lib/cache.test.mjs +303 -0
  17. package/cli/lib/design-link.mjs +222 -11
  18. package/cli/lib/flow-design-integration.test.mjs +165 -0
  19. package/cli/lib/gitignore-block.mjs +90 -0
  20. package/cli/lib/gitignore-block.test.mjs +123 -0
  21. package/cli/lib/hubs-config.mjs +42 -4
  22. package/cli/lib/plugin-cli-reachability.test.mjs +56 -0
  23. package/cli/lib/preflight.mjs +41 -10
  24. package/package.json +8 -8
  25. package/plugins/design/dev-server/ai-banner.tsx +2 -2
  26. package/plugins/design/dev-server/annotations-context-toolbar.tsx +349 -112
  27. package/plugins/design/dev-server/annotations-layer.tsx +906 -137
  28. package/plugins/design/dev-server/api.ts +109 -4
  29. package/plugins/design/dev-server/bin/preflight.sh +21 -10
  30. package/plugins/design/dev-server/bin/prep.sh +211 -0
  31. package/plugins/design/dev-server/bin/scenario-report.mjs +209 -0
  32. package/plugins/design/dev-server/bin/screenshot.sh +18 -1
  33. package/plugins/design/dev-server/bin/smoke.sh +94 -11
  34. package/plugins/design/dev-server/build.ts +69 -3
  35. package/plugins/design/dev-server/canvas-comment-mount.tsx +384 -0
  36. package/plugins/design/dev-server/canvas-cursors.ts +125 -0
  37. package/plugins/design/dev-server/canvas-icons.tsx +130 -0
  38. package/plugins/design/dev-server/canvas-lib.tsx +47 -27
  39. package/plugins/design/dev-server/canvas-meta.schema.json +20 -0
  40. package/plugins/design/dev-server/canvas-shell.tsx +358 -245
  41. package/plugins/design/dev-server/client/app.jsx +191 -21
  42. package/plugins/design/dev-server/client/styles/3-shell.css +10 -0
  43. package/plugins/design/dev-server/collab/awareness-bridge.ts +77 -0
  44. package/plugins/design/dev-server/collab/index.ts +87 -9
  45. package/plugins/design/dev-server/collab/persistence.ts +34 -3
  46. package/plugins/design/dev-server/collab/registry.ts +131 -2
  47. package/plugins/design/dev-server/collab/room.ts +21 -8
  48. package/plugins/design/dev-server/config.schema.json +20 -0
  49. package/plugins/design/dev-server/context-menu.tsx +167 -23
  50. package/plugins/design/dev-server/context.ts +31 -0
  51. package/plugins/design/dev-server/contextual-toolbar.tsx +7 -7
  52. package/plugins/design/dev-server/dist/client.bundle.js +144 -22
  53. package/plugins/design/dev-server/dist/comment-mount.js +1868 -0
  54. package/plugins/design/dev-server/dist/styles.css +16 -0
  55. package/plugins/design/dev-server/dom-selection.ts +156 -0
  56. package/plugins/design/dev-server/equal-spacing-handles.tsx +1 -1
  57. package/plugins/design/dev-server/export-dialog.tsx +19 -17
  58. package/plugins/design/dev-server/fs-watch.ts +1 -0
  59. package/plugins/design/dev-server/hmr-broadcast.ts +51 -20
  60. package/plugins/design/dev-server/http.ts +260 -20
  61. package/plugins/design/dev-server/input-router.tsx +125 -64
  62. package/plugins/design/dev-server/participants-chrome.tsx +10 -10
  63. package/plugins/design/dev-server/server.ts +141 -1
  64. package/plugins/design/dev-server/sync/agent.ts +418 -0
  65. package/plugins/design/dev-server/sync/atomic-write.ts +103 -0
  66. package/plugins/design/dev-server/sync/codec.ts +324 -0
  67. package/plugins/design/dev-server/sync/connection-state.ts +203 -0
  68. package/plugins/design/dev-server/sync/echo-guard.ts +108 -0
  69. package/plugins/design/dev-server/sync/fs-mirror.ts +160 -0
  70. package/plugins/design/dev-server/sync/hubs-config.ts +87 -0
  71. package/plugins/design/dev-server/sync/index.ts +918 -0
  72. package/plugins/design/dev-server/sync/materialize.ts +62 -0
  73. package/plugins/design/dev-server/sync/migrate-seed.ts +163 -0
  74. package/plugins/design/dev-server/sync/origins.ts +57 -0
  75. package/plugins/design/dev-server/sync/projection.ts +368 -0
  76. package/plugins/design/dev-server/sync/status.ts +115 -0
  77. package/plugins/design/dev-server/sync/untrusted.ts +153 -0
  78. package/plugins/design/dev-server/test/_helpers.ts +6 -2
  79. package/plugins/design/dev-server/test/annotations-layer.test.ts +231 -0
  80. package/plugins/design/dev-server/test/annotations-roundtrip.test.ts +276 -0
  81. package/plugins/design/dev-server/test/canvas-cursors.test.ts +73 -0
  82. package/plugins/design/dev-server/test/canvas-origin-gate.test.ts +76 -0
  83. package/plugins/design/dev-server/test/collab-awareness-bridge.test.ts +223 -0
  84. package/plugins/design/dev-server/test/collab-reseed-guard.test.ts +78 -0
  85. package/plugins/design/dev-server/test/collab-room.test.ts +21 -10
  86. package/plugins/design/dev-server/test/comment-mount.test.ts +87 -0
  87. package/plugins/design/dev-server/test/csp-canvas-shell.test.ts +46 -0
  88. package/plugins/design/dev-server/test/fixtures/phase-20-annotations.svg +1 -0
  89. package/plugins/design/dev-server/test/hmr-classify.test.ts +70 -0
  90. package/plugins/design/dev-server/test/input-router.test.ts +21 -0
  91. package/plugins/design/dev-server/test/sanitize-annotation-svg.test.ts +100 -0
  92. package/plugins/design/dev-server/test/shared-doc-convergence.test.ts +265 -0
  93. package/plugins/design/dev-server/test/shared-doc-foundation.test.ts +63 -0
  94. package/plugins/design/dev-server/test/shared-doc-migrate.test.ts +160 -0
  95. package/plugins/design/dev-server/test/shared-doc-projection.test.ts +238 -0
  96. package/plugins/design/dev-server/test/sync-agent.test.ts +278 -0
  97. package/plugins/design/dev-server/test/sync-atomic-write.test.ts +63 -0
  98. package/plugins/design/dev-server/test/sync-codec.test.ts +165 -0
  99. package/plugins/design/dev-server/test/sync-connection-state.test.ts +146 -0
  100. package/plugins/design/dev-server/test/sync-echo-guard.test.ts +96 -0
  101. package/plugins/design/dev-server/test/sync-fs-mirror.test.ts +182 -0
  102. package/plugins/design/dev-server/test/sync-hardening.test.ts +520 -0
  103. package/plugins/design/dev-server/test/sync-hubs-config.test.ts +130 -0
  104. package/plugins/design/dev-server/test/sync-meta-codec.test.ts +123 -0
  105. package/plugins/design/dev-server/test/sync-runtime.test.ts +812 -0
  106. package/plugins/design/dev-server/test/sync-status.test.ts +80 -0
  107. package/plugins/design/dev-server/test/sync-untrusted.test.ts +104 -0
  108. package/plugins/design/dev-server/test/use-collab.test.ts +0 -0
  109. package/plugins/design/dev-server/test/use-tool-mode.test.tsx +38 -10
  110. package/plugins/design/dev-server/tool-palette.tsx +18 -16
  111. package/plugins/design/dev-server/undo-hud.tsx +4 -4
  112. package/plugins/design/dev-server/undo-stack.ts +20 -4
  113. package/plugins/design/dev-server/use-annotation-resize.tsx +16 -5
  114. package/plugins/design/dev-server/use-collab.tsx +157 -13
  115. package/plugins/design/dev-server/use-selection-set.tsx +12 -0
  116. package/plugins/design/dev-server/use-tool-mode.tsx +27 -12
  117. package/plugins/design/dev-server/ws.ts +40 -1
  118. package/plugins/design/templates/_shell.html +63 -5
  119. package/plugins/design/templates/canvas.tsx.template +13 -0
  120. package/plugins/design/templates/design-system-inspiration/SUB-AGENT-PROMPTS.md +15 -7
  121. package/plugins/flow/.claude-plugin/config.schema.json +5 -0
  122. package/plugins/flow/templates/ai-skeleton/README.md +1 -1
  123. package/plugins/flow/templates/ai-skeleton/gitignore +10 -0
  124. package/plugins/flow/templates/ai-skeleton/scenarios/README.md +3 -1
  125. package/plugins/flow/templates/ai-skeleton/workflows.config.json +2 -1
@@ -0,0 +1,123 @@
1
+ // Gap 2 — .meta.json shared-layout sync codec.
2
+ //
3
+ // Artboard layout must propagate as a file diff (one machine moves an artboard →
4
+ // the other's .meta.json layout converges), while each user's pan/zoom
5
+ // (`viewport`) and the security opt-in (`syncable`) stay strictly local. These
6
+ // tests pin that split: applyMetaToDoc stores only the shared subset, and
7
+ // mergeSharedMetaIntoLocal layers it back without trampling local-only keys.
8
+
9
+ import { describe, expect, test } from 'bun:test';
10
+ import * as Y from 'yjs';
11
+
12
+ import {
13
+ META_LOCAL_KEYS,
14
+ applyCssToDoc,
15
+ applyMetaToDoc,
16
+ cssFromDoc,
17
+ mergeSharedMetaIntoLocal,
18
+ metaFromDoc,
19
+ } from '../sync/codec.ts';
20
+
21
+ describe('Gap 2 — meta codec: shared layout syncs, per-user keys stay local', () => {
22
+ test('applyMetaToDoc stores ONLY the shared subset (viewport/last_modified/syncable stripped)', () => {
23
+ const doc = new Y.Doc();
24
+ const full = JSON.stringify({
25
+ title: 'Kanban',
26
+ layout: { 'ab-1': { x: 10, y: 20 } },
27
+ viewport: { x: 999, y: 888, zoom: 0.5 },
28
+ last_modified: '2026-01-01T00:00:00Z',
29
+ syncable: true,
30
+ });
31
+ expect(applyMetaToDoc(doc, full)).toBe(true);
32
+
33
+ const shared = JSON.parse(metaFromDoc(doc) as string);
34
+ expect(shared.title).toBe('Kanban');
35
+ expect(shared.layout).toEqual({ 'ab-1': { x: 10, y: 20 } });
36
+ // The three per-machine keys never enter the synced doc.
37
+ expect(shared.viewport).toBeUndefined();
38
+ expect(shared.last_modified).toBeUndefined();
39
+ expect(shared.syncable).toBeUndefined();
40
+ });
41
+
42
+ test('applyMetaToDoc is a NO-OP when only per-user keys differ (no churn from panning)', () => {
43
+ const doc = new Y.Doc();
44
+ applyMetaToDoc(doc, JSON.stringify({ title: 'X', viewport: { x: 1 } }));
45
+ // Same shared content, different viewport → must not register a change,
46
+ // otherwise every pan would emit a sync op.
47
+ expect(applyMetaToDoc(doc, JSON.stringify({ title: 'X', viewport: { x: 2 } }))).toBe(false);
48
+ });
49
+
50
+ test('mergeSharedMetaIntoLocal takes shared layout, PRESERVES local viewport + syncable', () => {
51
+ const shared = JSON.stringify({ title: 'Kanban', layout: { 'ab-1': { x: 10, y: 20 } } });
52
+ const local = JSON.stringify({
53
+ title: 'Kanban (stale)',
54
+ layout: { 'ab-1': { x: 0, y: 0 } },
55
+ viewport: { x: 42, y: 7, zoom: 1.5 },
56
+ syncable: false,
57
+ last_modified: 'local-ts',
58
+ });
59
+ const merged = JSON.parse(mergeSharedMetaIntoLocal(local, shared) as string);
60
+ expect(merged.layout).toEqual({ 'ab-1': { x: 10, y: 20 } }); // shared layout won
61
+ expect(merged.title).toBe('Kanban'); // shared title won
62
+ expect(merged.viewport).toEqual({ x: 42, y: 7, zoom: 1.5 }); // LOCAL viewport kept
63
+ expect(merged.syncable).toBe(false); // LOCAL opt-in kept (security invariant)
64
+ expect(merged.last_modified).toBe('local-ts'); // local timestamp kept
65
+ });
66
+
67
+ test('round-trip: artboard move on A reaches B without touching B viewport / syncable', () => {
68
+ const aDoc = new Y.Doc();
69
+ applyMetaToDoc(
70
+ aDoc,
71
+ JSON.stringify({
72
+ title: 'K',
73
+ layout: { 'ab-1': { x: 100, y: 200 } },
74
+ viewport: { zoom: 0.5 },
75
+ syncable: true,
76
+ })
77
+ );
78
+ const shared = metaFromDoc(aDoc) as string;
79
+
80
+ const bLocal = JSON.stringify({
81
+ title: 'K',
82
+ layout: { 'ab-1': { x: 0, y: 0 } },
83
+ viewport: { zoom: 2.0 },
84
+ syncable: false,
85
+ });
86
+ const bMerged = JSON.parse(mergeSharedMetaIntoLocal(bLocal, shared) as string);
87
+ expect(bMerged.layout['ab-1']).toEqual({ x: 100, y: 200 }); // A's move landed on B
88
+ expect(bMerged.viewport).toEqual({ zoom: 2.0 }); // B's camera untouched
89
+ expect(bMerged.syncable).toBe(false); // B's opt-in untouched
90
+ });
91
+
92
+ test('a freshly-cloned peer with no local viewport just takes the shared subset', () => {
93
+ const merged = JSON.parse(
94
+ mergeSharedMetaIntoLocal('{}', JSON.stringify({ title: 'K', layout: { a: 1 } })) as string
95
+ );
96
+ expect(merged).toEqual({ title: 'K', layout: { a: 1 } });
97
+ });
98
+
99
+ test('META_LOCAL_KEYS pins the never-synced set', () => {
100
+ expect([...META_LOCAL_KEYS].sort()).toEqual(['last_modified', 'syncable', 'viewport']);
101
+ });
102
+
103
+ test('mergeSharedMetaIntoLocal returns null on an unparseable shared payload', () => {
104
+ expect(mergeSharedMetaIntoLocal('{}', 'not json')).toBeNull();
105
+ });
106
+ });
107
+
108
+ describe('Gap 3 — css codec (opaque wholesale text)', () => {
109
+ test('applyCssToDoc round-trips the css string', () => {
110
+ const doc = new Y.Doc();
111
+ expect(cssFromDoc(doc)).toBeNull();
112
+ const css = '.ka-card { color: red; }\n';
113
+ expect(applyCssToDoc(doc, css)).toBe(true);
114
+ expect(cssFromDoc(doc)).toBe(css);
115
+ });
116
+
117
+ test('applyCssToDoc is a no-op when unchanged (loop-safe)', () => {
118
+ const doc = new Y.Doc();
119
+ applyCssToDoc(doc, '.x{}');
120
+ expect(applyCssToDoc(doc, '.x{}')).toBe(false);
121
+ expect(applyCssToDoc(doc, '.x{ color: blue }')).toBe(true);
122
+ });
123
+ });