@1agh/maude 0.27.0 → 0.28.1
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.
- package/cli/commands/design-link.test.mjs +46 -0
- package/cli/commands/design.mjs +69 -3
- package/cli/commands/design.test.mjs +97 -1
- package/cli/commands/doctor.mjs +110 -5
- package/cli/commands/doctor.test.mjs +52 -0
- package/cli/lib/cache.mjs +1 -1
- package/cli/lib/config-lint.mjs +1 -1
- package/cli/lib/copy-tree.mjs +1 -1
- package/cli/lib/design-link.mjs +39 -9
- package/cli/lib/flow-design-integration.test.mjs +1 -1
- package/cli/lib/gitignore-block.test.mjs +2 -2
- package/cli/lib/stack-detect.mjs +1 -1
- package/package.json +9 -9
- package/plugins/design/dev-server/activity.ts +256 -0
- package/plugins/design/dev-server/ai-banner.tsx +4 -0
- package/plugins/design/dev-server/annotations-context-toolbar.tsx +1 -1
- package/plugins/design/dev-server/annotations-layer.tsx +3 -3
- package/plugins/design/dev-server/api.ts +1 -1
- package/plugins/design/dev-server/artboard-activity-overlay.tsx +67 -0
- package/plugins/design/dev-server/bin/scenario-report.mjs +1 -1
- package/plugins/design/dev-server/bin/server-up.sh +102 -9
- package/plugins/design/dev-server/bin/visual-sanity.sh +19 -3
- package/plugins/design/dev-server/canvas-comment-mount.tsx +165 -10
- package/plugins/design/dev-server/canvas-cursors.ts +1 -1
- package/plugins/design/dev-server/canvas-lib.tsx +72 -36
- package/plugins/design/dev-server/canvas-shell.tsx +1 -1
- package/plugins/design/dev-server/collab/awareness-bridge.ts +1 -1
- package/plugins/design/dev-server/collab/index.ts +4 -4
- package/plugins/design/dev-server/collab/persistence.ts +1 -1
- package/plugins/design/dev-server/config.schema.json +2 -1
- package/plugins/design/dev-server/context-menu.tsx +1 -1
- package/plugins/design/dev-server/dist/client.bundle.js +19 -19
- package/plugins/design/dev-server/dist/comment-mount.js +84 -6
- package/plugins/design/dev-server/dist/runtime/lib0_decoding.js +1 -620
- package/plugins/design/dev-server/dist/runtime/lib0_encoding.js +1 -604
- package/plugins/design/dev-server/dist/runtime/motion.js +4 -4944
- package/plugins/design/dev-server/dist/runtime/motion_react.js +10 -10054
- package/plugins/design/dev-server/dist/runtime/pixi-js.js +2775 -52482
- package/plugins/design/dev-server/dist/runtime/react-dom.js +1 -231
- package/plugins/design/dev-server/dist/runtime/react-dom_client.js +9 -10357
- package/plugins/design/dev-server/dist/runtime/react.js +1 -535
- package/plugins/design/dev-server/dist/runtime/react_jsx-dev-runtime.js +1 -60
- package/plugins/design/dev-server/dist/runtime/react_jsx-runtime.js +1 -85
- package/plugins/design/dev-server/dist/runtime/y-protocols_awareness.js +1 -376
- package/plugins/design/dev-server/dist/runtime/y-protocols_sync.js +1 -100
- package/plugins/design/dev-server/dist/runtime/yjs.js +5 -6687
- package/plugins/design/dev-server/draw/brush.ts +3 -3
- package/plugins/design/dev-server/draw/index.ts +5 -5
- package/plugins/design/dev-server/draw/layout.ts +1 -1
- package/plugins/design/dev-server/draw/test/geometry.test.ts +1 -1
- package/plugins/design/dev-server/draw/test/layout.test.ts +1 -1
- package/plugins/design/dev-server/draw/test/primitives.test.ts +1 -1
- package/plugins/design/dev-server/draw/test/serialize.test.ts +1 -1
- package/plugins/design/dev-server/equal-spacing-handles.tsx +1 -1
- package/plugins/design/dev-server/examples/perf-100-artboards.tsx +1 -2
- package/plugins/design/dev-server/export-dialog.tsx +1 -1
- package/plugins/design/dev-server/exporters/html.ts +1 -1
- package/plugins/design/dev-server/exporters/index.ts +2 -2
- package/plugins/design/dev-server/exporters/pdf.ts +1 -1
- package/plugins/design/dev-server/exporters/png.ts +1 -1
- package/plugins/design/dev-server/exporters/pptx.ts +1 -1
- package/plugins/design/dev-server/exporters/svg.ts +1 -1
- package/plugins/design/dev-server/http.ts +1 -1
- package/plugins/design/dev-server/inspect.ts +31 -1
- package/plugins/design/dev-server/marquee-overlay.tsx +1 -1
- package/plugins/design/dev-server/participants-chrome.tsx +86 -1
- package/plugins/design/dev-server/server.ts +11 -2
- package/plugins/design/dev-server/sync/agent.ts +1 -1
- package/plugins/design/dev-server/sync/index.ts +29 -24
- package/plugins/design/dev-server/sync/materialize.ts +2 -2
- package/plugins/design/dev-server/sync/migrate-seed.ts +1 -1
- package/plugins/design/dev-server/sync/projection.ts +3 -3
- package/plugins/design/dev-server/test/activity.test.ts +195 -0
- package/plugins/design/dev-server/test/ai-activity.test.ts +1 -1
- package/plugins/design/dev-server/test/annotations-api.test.ts +1 -2
- package/plugins/design/dev-server/test/annotations-draw-modifiers.test.ts +2 -2
- package/plugins/design/dev-server/test/annotations-layer.test.ts +6 -6
- package/plugins/design/dev-server/test/annotations-roundtrip.test.ts +1 -1
- package/plugins/design/dev-server/test/artboard-activity-overlay.test.tsx +56 -0
- package/plugins/design/dev-server/test/boot-self-heal.test.ts +1 -1
- package/plugins/design/dev-server/test/canvas-cursors.test.ts +1 -1
- package/plugins/design/dev-server/test/canvas-edit.test.ts +1 -1
- package/plugins/design/dev-server/test/canvas-header.test.ts +1 -1
- package/plugins/design/dev-server/test/canvas-hmr-runtime.test.tsx +114 -0
- package/plugins/design/dev-server/test/canvas-lib-inline.test.ts +1 -1
- package/plugins/design/dev-server/test/canvas-lib-resolver.test.ts +1 -2
- package/plugins/design/dev-server/test/canvas-meta-api.test.ts +1 -2
- package/plugins/design/dev-server/test/canvas-origin-gate.test.ts +1 -2
- package/plugins/design/dev-server/test/collab-annotations-bridge.test.ts +1 -1
- package/plugins/design/dev-server/test/collab-bridge.test.ts +1 -1
- package/plugins/design/dev-server/test/collab-protocol.test.ts +2 -2
- package/plugins/design/dev-server/test/collab-room.test.ts +1 -1
- package/plugins/design/dev-server/test/collab-stress.test.ts +1 -1
- package/plugins/design/dev-server/test/comments-api.test.ts +1 -2
- package/plugins/design/dev-server/test/compile-entry.test.ts +1 -2
- package/plugins/design/dev-server/test/exporters/canva.test.ts +1 -2
- package/plugins/design/dev-server/test/exporters/history.test.ts +1 -2
- package/plugins/design/dev-server/test/exporters/pw-launch.test.ts +1 -1
- package/plugins/design/dev-server/test/exporters/scope.test.ts +1 -2
- package/plugins/design/dev-server/test/exporters/zip.test.ts +1 -2
- package/plugins/design/dev-server/test/git-lifecycle.test.ts +1 -2
- package/plugins/design/dev-server/test/handoff-static-frames.test.ts +1 -1
- package/plugins/design/dev-server/test/handoff.test.ts +1 -1
- package/plugins/design/dev-server/test/hmr-broadcast.test.ts +1 -1
- package/plugins/design/dev-server/test/input-router.test.ts +2 -2
- package/plugins/design/dev-server/test/locator.test.ts +1 -1
- package/plugins/design/dev-server/test/runtime-bundle.test.ts +1 -1
- package/plugins/design/dev-server/test/shared-doc-convergence.test.ts +1 -1
- package/plugins/design/dev-server/test/shared-doc-migrate.test.ts +2 -3
- package/plugins/design/dev-server/test/shared-doc-projection.test.ts +1 -1
- package/plugins/design/dev-server/test/snap-distance-pill.test.ts +1 -1
- package/plugins/design/dev-server/test/sync-agent.test.ts +2 -3
- package/plugins/design/dev-server/test/sync-atomic-write.test.ts +2 -3
- package/plugins/design/dev-server/test/sync-codec.test.ts +1 -1
- package/plugins/design/dev-server/test/sync-connection-state.test.ts +1 -1
- package/plugins/design/dev-server/test/sync-echo-guard.test.ts +1 -1
- package/plugins/design/dev-server/test/sync-fs-mirror.test.ts +1 -2
- package/plugins/design/dev-server/test/sync-hardening.test.ts +4 -5
- package/plugins/design/dev-server/test/sync-hubs-config.test.ts +1 -2
- package/plugins/design/dev-server/test/sync-meta-codec.test.ts +1 -1
- package/plugins/design/dev-server/test/sync-runtime.test.ts +37 -14
- package/plugins/design/dev-server/test/sync-status.test.ts +1 -1
- package/plugins/design/dev-server/test/sync-untrusted.test.ts +1 -2
- package/plugins/design/dev-server/test/undo-stack.test.ts +2 -2
- package/plugins/design/dev-server/test/use-agent-presence.test.tsx +117 -0
- package/plugins/design/dev-server/test/use-artboard-drag.test.ts +3 -3
- package/plugins/design/dev-server/test/use-canvas-activity.test.tsx +206 -0
- package/plugins/design/dev-server/test/use-selection-set.test.tsx +1 -1
- package/plugins/design/dev-server/test/use-snap-guides.test.ts +1 -1
- package/plugins/design/dev-server/test/use-undo-stack.test.tsx +2 -2
- package/plugins/design/dev-server/use-agent-presence.tsx +244 -0
- package/plugins/design/dev-server/use-annotation-resize.tsx +1 -5
- package/plugins/design/dev-server/use-annotation-selection.tsx +2 -6
- package/plugins/design/dev-server/use-annotations-visibility.tsx +1 -1
- package/plugins/design/dev-server/use-artboard-drag.tsx +1 -1
- package/plugins/design/dev-server/use-canvas-activity.tsx +252 -0
- package/plugins/design/dev-server/use-collab.tsx +3 -4
- package/plugins/design/dev-server/use-selection-set.tsx +1 -1
- package/plugins/design/dev-server/use-tool-mode.tsx +1 -1
- package/plugins/design/dev-server/use-undo-stack.tsx +4 -5
- package/plugins/design/dev-server/ws.ts +21 -2
- package/plugins/design/templates/_shell.html +108 -3
- package/plugins/design/templates/design-system-inspiration/SUB-AGENT-PROMPTS.md +18 -3
|
@@ -23,15 +23,15 @@
|
|
|
23
23
|
|
|
24
24
|
import type { Rect } from './geometry.ts';
|
|
25
25
|
import {
|
|
26
|
-
|
|
26
|
+
circle,
|
|
27
27
|
type DrawPrimitive,
|
|
28
28
|
type DrawStyle,
|
|
29
|
-
type Point,
|
|
30
|
-
circle,
|
|
31
29
|
fe,
|
|
32
30
|
filter,
|
|
33
31
|
group,
|
|
34
32
|
line,
|
|
33
|
+
type Point,
|
|
34
|
+
path,
|
|
35
35
|
} from './primitives.ts';
|
|
36
36
|
|
|
37
37
|
function fmt(n: number): string {
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
* React-free (DDR-067) — nothing here imports react / a `.tsx`.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
export * from './primitives.ts';
|
|
22
|
-
export * from './geometry.ts';
|
|
23
|
-
export * from './palette.ts';
|
|
24
|
-
export * from './composition.ts';
|
|
25
21
|
export * from './brush.ts';
|
|
22
|
+
export * from './composition.ts';
|
|
23
|
+
export * from './geometry.ts';
|
|
26
24
|
export * from './layout.ts';
|
|
27
|
-
export * from './serialize.ts';
|
|
28
25
|
export * from './optimize.ts';
|
|
26
|
+
export * from './palette.ts';
|
|
27
|
+
export * from './primitives.ts';
|
|
28
|
+
export * from './serialize.ts';
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { type Rect, routeConnector } from './geometry.ts';
|
|
18
|
-
import { type DrawPrimitive, type Point,
|
|
18
|
+
import { type DrawPrimitive, group, type Point, polyline, rect, snap, text } from './primitives.ts';
|
|
19
19
|
|
|
20
20
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
21
21
|
// Grid + modular scale
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test';
|
|
2
2
|
import type { Rect } from '../geometry.ts';
|
|
3
|
-
import { type LabelItem,
|
|
3
|
+
import { diagram, type LabelItem, modularScale, placeLabels, snapToGrid } from '../layout.ts';
|
|
4
4
|
import type { Point } from '../primitives.ts';
|
|
5
5
|
|
|
6
6
|
describe('grid + modular scale', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
import { path, circle, group, line, rect, text } from '../primitives.ts';
|
|
3
2
|
import type { DrawPrimitive } from '../primitives.ts';
|
|
3
|
+
import { circle, group, line, path, rect, text } from '../primitives.ts';
|
|
4
4
|
import { primitivesToNodes, toJsx, toSvg } from '../serialize.ts';
|
|
5
5
|
|
|
6
6
|
const SAMPLE: DrawPrimitive[] = [
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
import { useEffect, useRef, useState } from 'react';
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
|
+
detectEqualSpacing,
|
|
18
19
|
type EqualSpacingResult,
|
|
19
20
|
type SpacingAxis,
|
|
20
|
-
detectEqualSpacing,
|
|
21
21
|
} from './equal-spacing-detector.ts';
|
|
22
22
|
import { useSelectionSet } from './use-selection-set.tsx';
|
|
23
23
|
|
|
@@ -20,9 +20,8 @@
|
|
|
20
20
|
* Results land in .ai/decisions/DDR-024 + .ai/logs/phase-4-perf-<date>.md.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
import { useEffect } from 'react';
|
|
24
|
-
|
|
25
23
|
import { DCArtboard, DCSection, DesignCanvas } from '@maude/canvas-lib';
|
|
24
|
+
import { useEffect } from 'react';
|
|
26
25
|
|
|
27
26
|
const ARTBOARD_COUNT = 100;
|
|
28
27
|
const NODES_PER_ARTBOARD = 30;
|
|
@@ -13,10 +13,10 @@ import path from 'node:path';
|
|
|
13
13
|
import JSZip from 'jszip';
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
|
+
canvasShellUrl,
|
|
16
17
|
type ExportContext,
|
|
17
18
|
type ExportOptions,
|
|
18
19
|
type ExportResult,
|
|
19
|
-
canvasShellUrl,
|
|
20
20
|
} from './index.ts';
|
|
21
21
|
import type { Target } from './scope.ts';
|
|
22
22
|
|
|
@@ -13,7 +13,7 @@ import * as html from './html.ts';
|
|
|
13
13
|
import * as pdf from './pdf.ts';
|
|
14
14
|
import * as png from './png.ts';
|
|
15
15
|
import * as pptx from './pptx.ts';
|
|
16
|
-
import { type ResolveScopeArgs, type Scope, type Target
|
|
16
|
+
import { type ResolveScopeArgs, resolveScope, type Scope, type Target } from './scope.ts';
|
|
17
17
|
import * as svg from './svg.ts';
|
|
18
18
|
import * as zip from './zip.ts';
|
|
19
19
|
|
|
@@ -100,8 +100,8 @@ export async function runExport(args: {
|
|
|
100
100
|
return adapter.run(targets, args.options, args.ctx);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
export { resolveScope };
|
|
104
103
|
export type { Scope, Target };
|
|
104
|
+
export { resolveScope };
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
107
|
* Build the `_canvas-shell.html?canvas=…&tokens=…&components=…` URL the
|
|
@@ -15,10 +15,10 @@ import path from 'node:path';
|
|
|
15
15
|
import { PDFDocument } from 'pdf-lib';
|
|
16
16
|
|
|
17
17
|
import {
|
|
18
|
+
canvasShellUrl,
|
|
18
19
|
type ExportContext,
|
|
19
20
|
type ExportOptions,
|
|
20
21
|
type ExportResult,
|
|
21
|
-
canvasShellUrl,
|
|
22
22
|
} from './index.ts';
|
|
23
23
|
import type { Target } from './scope.ts';
|
|
24
24
|
|
|
@@ -14,10 +14,10 @@ import path from 'node:path';
|
|
|
14
14
|
import JSZip from 'jszip';
|
|
15
15
|
|
|
16
16
|
import {
|
|
17
|
+
canvasShellUrl,
|
|
17
18
|
type ExportContext,
|
|
18
19
|
type ExportOptions,
|
|
19
20
|
type ExportResult,
|
|
20
|
-
canvasShellUrl,
|
|
21
21
|
} from './index.ts';
|
|
22
22
|
import type { Target } from './scope.ts';
|
|
23
23
|
|
|
@@ -28,10 +28,10 @@ import PptxGenJS from 'pptxgenjs';
|
|
|
28
28
|
|
|
29
29
|
import { getBrowserBundle } from './_browser-bundles.ts';
|
|
30
30
|
import {
|
|
31
|
+
canvasShellUrl,
|
|
31
32
|
type ExportContext,
|
|
32
33
|
type ExportOptions,
|
|
33
34
|
type ExportResult,
|
|
34
|
-
canvasShellUrl,
|
|
35
35
|
} from './index.ts';
|
|
36
36
|
import type { Target } from './scope.ts';
|
|
37
37
|
|
|
@@ -14,10 +14,10 @@ import JSZip from 'jszip';
|
|
|
14
14
|
|
|
15
15
|
import { getBrowserBundle } from './_browser-bundles.ts';
|
|
16
16
|
import {
|
|
17
|
+
canvasShellUrl,
|
|
17
18
|
type ExportContext,
|
|
18
19
|
type ExportOptions,
|
|
19
20
|
type ExportResult,
|
|
20
|
-
canvasShellUrl,
|
|
21
21
|
} from './index.ts';
|
|
22
22
|
import type { Target } from './scope.ts';
|
|
23
23
|
|
|
@@ -19,7 +19,7 @@ import type { ActiveJsonShape } from './exporters/scope.ts';
|
|
|
19
19
|
import type { Inspect } from './inspect.ts';
|
|
20
20
|
import { canvasSlug, writeLocator } from './locator.ts';
|
|
21
21
|
import { DEV_SERVER_ROOT } from './paths.ts';
|
|
22
|
-
import {
|
|
22
|
+
import { getRuntimeBundle, packageForSlug, RUNTIME_PACKAGES, slugFor } from './runtime-bundle.ts';
|
|
23
23
|
|
|
24
24
|
// Real disk install root — never the virtual `/$bunfs/root` of compiled bins.
|
|
25
25
|
// See paths.ts for the resolution logic + Phase 19.1 / v0.18.1 rationale.
|
|
@@ -230,7 +230,37 @@ const INSPECTOR_SCRIPT = `
|
|
|
230
230
|
'.dgn-pin { position: absolute; top: 0; left: 0; z-index: 2147483646; width: 22px; height: 22px; padding: 0; border: 0; border-radius: 999px 999px 999px 4px; background: #facc15; color: #1c1917; font: 600 11px/22px var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace); text-align: center; cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,0.5), 0 0 0 1px rgba(0,0,0,0.4); transition: filter 120ms; transform-origin: bottom left; will-change: transform; }',
|
|
231
231
|
'.dgn-pin:hover { filter: brightness(1.1); outline: 2px solid rgba(0,0,0,0.3); }',
|
|
232
232
|
'.dgn-pin.resolved { background: #22c55e; color: #052e16; }',
|
|
233
|
-
'.dgn-pin.focused { box-shadow: 0 4px 12px rgba(0,0,0,0.6), 0 0 0 2px #fff; outline: 2px solid #fff; }'
|
|
233
|
+
'.dgn-pin.focused { box-shadow: 0 4px 12px rgba(0,0,0,0.6), 0 0 0 2px #fff; outline: 2px solid #fff; }',
|
|
234
|
+
/* Phase 13 / DDR-029 — canvas activity overlay. Single injection point so the
|
|
235
|
+
canvas iframe stays self-contained. Scoped with html ... so canvas-page
|
|
236
|
+
stylesheets can't clobber it. The "editing" motion is a light scan beam
|
|
237
|
+
(Phase 13.3) sweeping the whole artboard top→bottom — transform-only
|
|
238
|
+
(compositor), unmounts when the file goes idle (infinite-with-control,
|
|
239
|
+
flow:motion-rules §5); reduced-motion drops the beam to a static rim. The
|
|
240
|
+
rim border + glow are static boundary chrome. */
|
|
241
|
+
'html .dc-activity-rim { position: absolute; pointer-events: none; box-sizing: border-box; border: 2.5px solid var(--mdcc-activity, hsl(210 90% 58%)); border-radius: 5px; z-index: 6; opacity: 1; transition: opacity 200ms ease-out; }',
|
|
242
|
+
'html .dc-activity-rim[data-fading="true"] { opacity: 0; }',
|
|
243
|
+
'html .dc-activity-rim::after { content: ""; position: absolute; inset: -1px; border-radius: 6px; box-shadow: 0 0 0 1px var(--mdcc-activity, hsl(210 90% 58%)), 0 0 16px 2px var(--mdcc-activity, hsl(210 90% 58%)); opacity: 0.55; pointer-events: none; will-change: opacity; animation: dc-activity-glow var(--mdcc-activity-scan-ms, 2200ms) ease-in-out infinite; }',
|
|
244
|
+
'html .dc-activity-badge { position: absolute; top: 4px; right: 4px; z-index: 2; padding: 2px 8px; border-radius: 4px; background: var(--mdcc-activity, hsl(210 90% 58%)); color: #fff; font: 600 11px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; font-variant-numeric: tabular-nums; white-space: nowrap; box-shadow: 0 1px 4px rgba(0,0,0,0.45); }',
|
|
245
|
+
/* Phase 13.3 — the AGENT BORDER is the primary "editing" indicator: a clear
|
|
246
|
+
2.5px border in the agent color with a softly pulsing glow (::after,
|
|
247
|
+
opacity-only, compositor). Clipping lives on the wash (not the rim) so the
|
|
248
|
+
outward glow is not clipped. The dc-activity-scan wash is ONE full-artboard
|
|
249
|
+
wave: a single gradient with a SHARP bottom edge (full agent color) fading
|
|
250
|
+
up to transparent at the top (height = artboard). Its sharp edge enters at
|
|
251
|
+
the top and the whole wave travels straight down and off past the bottom
|
|
252
|
+
edge (translateY -100% → 100%), then the next wave enters from the top in a
|
|
253
|
+
loop. transform-only; linear so it flows at a steady pace. */
|
|
254
|
+
'html .dc-activity-scan { position: absolute; inset: 0; overflow: hidden; border-radius: 4px; pointer-events: none; z-index: 1; }',
|
|
255
|
+
'html .dc-activity-scan::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 135%; will-change: transform; background: linear-gradient(to top, color-mix(in oklab, var(--mdcc-activity, hsl(210 90% 58%)) 20%, transparent) 0%, transparent 100%); animation: dc-activity-wave var(--mdcc-activity-scan-ms, 3800ms) linear infinite; }',
|
|
256
|
+
'@keyframes dc-activity-glow { 0%, 100% { opacity: 0.4; } 50% { opacity: 0.85; } }',
|
|
257
|
+
'@keyframes dc-activity-wave { from { transform: translateY(-100%); } to { transform: translateY(100%); } }',
|
|
258
|
+
'@media (prefers-reduced-motion: reduce) { html .dc-activity-rim { transition: none; } html .dc-activity-rim::after { animation: none; opacity: 0.55; } html .dc-activity-scan { display: none; } }',
|
|
259
|
+
/* Phase 13.1 / DDR-077 — "holding last good render" toast, shown when an
|
|
260
|
+
agent edit produced a broken intermediate (build/render error) and the
|
|
261
|
+
canvas is held instead of flashing white. Amber = warn, distinct from the
|
|
262
|
+
blue activity rim. pointer-events:none so it never blocks the canvas. */
|
|
263
|
+
'html .dc-hmr-holding { position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 2147483646; pointer-events: none; max-width: 90vw; padding: 6px 12px; border-radius: 6px; background: hsl(38 92% 50% / 0.96); color: #1c1207; font: 600 12px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; box-shadow: 0 2px 10px rgba(0,0,0,0.45); }'
|
|
234
264
|
].join('\\n');
|
|
235
265
|
document.documentElement.appendChild(styleEl);
|
|
236
266
|
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
18
18
|
|
|
19
19
|
import { useViewportControllerContext } from './canvas-lib.tsx';
|
|
20
|
+
import { type AgentPresence, useAgentPresence } from './use-agent-presence.tsx';
|
|
20
21
|
import { type ForeignAwareness, useCollab, useForeignAwareness } from './use-collab.tsx';
|
|
21
22
|
|
|
22
23
|
const CHROME_CSS = `
|
|
@@ -110,6 +111,34 @@ const CHROME_CSS = `
|
|
|
110
111
|
@media (prefers-reduced-motion: reduce) {
|
|
111
112
|
.dc-participant { transition: none; }
|
|
112
113
|
}
|
|
114
|
+
/* Phase 13.2 / DDR-078 — agent presence avatar. Looks like a peer chip + a
|
|
115
|
+
subtle ✦ marker so an agent reads as distinct from a human collaborator. */
|
|
116
|
+
.dc-participant--agent { box-shadow: 0 1px 2px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04); }
|
|
117
|
+
.dc-participant-agent-marker {
|
|
118
|
+
position: absolute;
|
|
119
|
+
right: -3px;
|
|
120
|
+
bottom: -3px;
|
|
121
|
+
width: 13px;
|
|
122
|
+
height: 13px;
|
|
123
|
+
border-radius: 50%;
|
|
124
|
+
background: var(--maude-chrome-bg-0, #fff);
|
|
125
|
+
color: var(--maude-chrome-fg-0, #111);
|
|
126
|
+
display: inline-flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
font-size: 8px;
|
|
130
|
+
line-height: 1;
|
|
131
|
+
box-shadow: 0 0 0 1px rgba(0,0,0,0.14);
|
|
132
|
+
pointer-events: none;
|
|
133
|
+
}
|
|
134
|
+
.dc-participant-popover__sub {
|
|
135
|
+
font-size: 11px;
|
|
136
|
+
color: var(--maude-chrome-fg-2, #666);
|
|
137
|
+
margin-top: -4px;
|
|
138
|
+
margin-bottom: 6px;
|
|
139
|
+
white-space: normal;
|
|
140
|
+
max-width: 200px;
|
|
141
|
+
}
|
|
113
142
|
`.trim();
|
|
114
143
|
|
|
115
144
|
function ensureChromeStyles(): void {
|
|
@@ -192,10 +221,63 @@ function Avatar({ peer, isFollowing, onToggleFollow }: AvatarProps): JSX.Element
|
|
|
192
221
|
);
|
|
193
222
|
}
|
|
194
223
|
|
|
224
|
+
// Phase 13.2 / DDR-078 — an agent rendered as a presence peer. No "Follow"
|
|
225
|
+
// (an agent has no viewport to mirror); a ✦ marker + an "AI agent" popover
|
|
226
|
+
// subtitle distinguish it from a human collaborator.
|
|
227
|
+
function AgentAvatar({ agent }: { agent: AgentPresence }): JSX.Element {
|
|
228
|
+
const [open, setOpen] = useState(false);
|
|
229
|
+
const rootRef = useRef<HTMLDivElement | null>(null);
|
|
230
|
+
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
if (!open) return;
|
|
233
|
+
const onDocClick = (e: MouseEvent) => {
|
|
234
|
+
if (!rootRef.current) return;
|
|
235
|
+
if (!rootRef.current.contains(e.target as Node)) setOpen(false);
|
|
236
|
+
};
|
|
237
|
+
document.addEventListener('mousedown', onDocClick);
|
|
238
|
+
return () => document.removeEventListener('mousedown', onDocClick);
|
|
239
|
+
}, [open]);
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
<div
|
|
243
|
+
ref={rootRef}
|
|
244
|
+
className="dc-participant dc-participant--agent"
|
|
245
|
+
style={{ background: agent.color }}
|
|
246
|
+
onClick={() => setOpen((v) => !v)}
|
|
247
|
+
onKeyDown={(e) => {
|
|
248
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
249
|
+
e.preventDefault();
|
|
250
|
+
setOpen((v) => !v);
|
|
251
|
+
}
|
|
252
|
+
}}
|
|
253
|
+
// biome-ignore lint/a11y/useSemanticElements: matches the peer Avatar chip pattern.
|
|
254
|
+
role="button"
|
|
255
|
+
tabIndex={0}
|
|
256
|
+
title={`${agent.name} (AI agent)`}
|
|
257
|
+
aria-label={`${agent.name}, AI agent`}
|
|
258
|
+
aria-expanded={open}
|
|
259
|
+
>
|
|
260
|
+
{initialsFor(agent.name)}
|
|
261
|
+
<span className="dc-participant-agent-marker" aria-hidden>
|
|
262
|
+
✦
|
|
263
|
+
</span>
|
|
264
|
+
{open && (
|
|
265
|
+
// biome-ignore lint/a11y/useKeyWithClickEvents: stop-propagation wrapper; no actionable child.
|
|
266
|
+
// biome-ignore lint/a11y/useSemanticElements: popover wrapper carries no semantic role.
|
|
267
|
+
<div className="dc-participant-popover" onClick={(e) => e.stopPropagation()}>
|
|
268
|
+
<div className="dc-participant-popover__name">{agent.name}</div>
|
|
269
|
+
<div className="dc-participant-popover__sub">AI agent · {agent.author}</div>
|
|
270
|
+
</div>
|
|
271
|
+
)}
|
|
272
|
+
</div>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
195
276
|
export function ParticipantsChrome(): JSX.Element | null {
|
|
196
277
|
ensureChromeStyles();
|
|
197
278
|
const collab = useCollab();
|
|
198
279
|
const peers = useForeignAwareness();
|
|
280
|
+
const agent = useAgentPresence();
|
|
199
281
|
const controller = useViewportControllerContext();
|
|
200
282
|
|
|
201
283
|
const [followTarget, setFollowTarget] = useState<number | null>(null);
|
|
@@ -242,7 +324,9 @@ export function ParticipantsChrome(): JSX.Element | null {
|
|
|
242
324
|
controller.setViewport(v);
|
|
243
325
|
}, [controller, followTarget, peers]);
|
|
244
326
|
|
|
245
|
-
|
|
327
|
+
// Render whenever there's a human peer OR an active agent (so an agent shows
|
|
328
|
+
// even with no human collaborators connected).
|
|
329
|
+
if (peers.length === 0 && !agent) return null;
|
|
246
330
|
|
|
247
331
|
return (
|
|
248
332
|
<div className="dc-participants" aria-label="Active collaborators">
|
|
@@ -254,6 +338,7 @@ export function ParticipantsChrome(): JSX.Element | null {
|
|
|
254
338
|
onToggleFollow={onToggleFollow}
|
|
255
339
|
/>
|
|
256
340
|
))}
|
|
341
|
+
{agent ? <AgentAvatar key={agent.id} agent={agent} /> : null}
|
|
257
342
|
</div>
|
|
258
343
|
);
|
|
259
344
|
}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { spawn } from 'node:child_process';
|
|
18
18
|
|
|
19
|
+
import { createActivity } from './activity.ts';
|
|
19
20
|
import { createApi } from './api.ts';
|
|
20
21
|
import { bootSelfHeal } from './boot-self-heal.ts';
|
|
21
22
|
import { createAiActivity } from './collab/ai-activity.ts';
|
|
@@ -27,7 +28,7 @@ import { createHttp } from './http.ts';
|
|
|
27
28
|
import { createInspect } from './inspect.ts';
|
|
28
29
|
import { startHeapWatch } from './mem.ts';
|
|
29
30
|
import { createSyncRuntime } from './sync/index.ts';
|
|
30
|
-
import {
|
|
31
|
+
import { createWs, isLoopbackHost, parseCollabSlug, type WsData } from './ws.ts';
|
|
31
32
|
|
|
32
33
|
// Phase 19 / DDR-044 — covers the marketplace-cache-install gap where
|
|
33
34
|
// node_modules/ ships empty (git clone honors .gitignore). Auto-installs +
|
|
@@ -77,7 +78,10 @@ await inspect.load();
|
|
|
77
78
|
collab = createCollab(ctx, api);
|
|
78
79
|
const aiActivity = createAiActivity(ctx);
|
|
79
80
|
const gitLifecycle = createGitLifecycle(ctx, collab.registry);
|
|
80
|
-
|
|
81
|
+
// Phase 13 / DDR-029 — fs-watch-driven canvas activity overlay. Subscribes to
|
|
82
|
+
// `fs:any` and emits `activity:change`; ws.ts forwards it to canvas iframes.
|
|
83
|
+
const activity = createActivity(ctx);
|
|
84
|
+
const ws = createWs(ctx, api, inspect, collab, activity);
|
|
81
85
|
const http = createHttp(ctx, api, inspect, aiActivity);
|
|
82
86
|
const fsWatch = createFsWatch(ctx);
|
|
83
87
|
|
|
@@ -346,6 +350,11 @@ if (!process.env.NO_OPEN) {
|
|
|
346
350
|
async function shutdown() {
|
|
347
351
|
console.log('\n Stopping…');
|
|
348
352
|
fsWatch.stop();
|
|
353
|
+
try {
|
|
354
|
+
activity.stop();
|
|
355
|
+
} catch {
|
|
356
|
+
/* timer cleanup is best-effort */
|
|
357
|
+
}
|
|
349
358
|
try {
|
|
350
359
|
if (syncRuntime) await syncRuntime.stop();
|
|
351
360
|
} catch {
|
|
@@ -33,7 +33,6 @@ import type * as Y from 'yjs';
|
|
|
33
33
|
|
|
34
34
|
import { atomicWrite } from './atomic-write.ts';
|
|
35
35
|
import {
|
|
36
|
-
Y_SYNC_TYPES,
|
|
37
36
|
annotationsFromDoc,
|
|
38
37
|
applyAnnotationsToDoc,
|
|
39
38
|
applyCommentsToDoc,
|
|
@@ -45,6 +44,7 @@ import {
|
|
|
45
44
|
htmlFromDoc,
|
|
46
45
|
mergeSharedMetaIntoLocal,
|
|
47
46
|
metaFromDoc,
|
|
47
|
+
Y_SYNC_TYPES,
|
|
48
48
|
} from './codec.ts';
|
|
49
49
|
import { type EchoGuard, hashBytes } from './echo-guard.ts';
|
|
50
50
|
|
|
@@ -29,15 +29,15 @@ import type { Context } from '../context.ts';
|
|
|
29
29
|
import { type CanvasSyncAgent, createCanvasSyncAgent } from './agent.ts';
|
|
30
30
|
import {
|
|
31
31
|
type ConnectionMonitor,
|
|
32
|
-
type ProviderStatus,
|
|
33
32
|
createConnectionMonitor,
|
|
33
|
+
type ProviderStatus,
|
|
34
34
|
} from './connection-state.ts';
|
|
35
|
-
import { type EchoGuard
|
|
36
|
-
import { type FsReader
|
|
35
|
+
import { createEchoGuard, type EchoGuard } from './echo-guard.ts';
|
|
36
|
+
import { createFsReader, type FsReader } from './fs-mirror.ts';
|
|
37
37
|
import { getHubToken } from './hubs-config.ts';
|
|
38
38
|
import { migrateSeed } from './migrate-seed.ts';
|
|
39
|
-
import { type DocProjection
|
|
40
|
-
import { type SyncStatusStore
|
|
39
|
+
import { createDocProjection, type DocProjection } from './projection.ts';
|
|
40
|
+
import { createSyncStatusStore, type SyncStatusStore } from './status.ts';
|
|
41
41
|
import { writeUntrustedMarkers } from './untrusted.ts';
|
|
42
42
|
|
|
43
43
|
/** A minimum-surface stand-in for the HocuspocusProvider's runtime API. */
|
|
@@ -246,16 +246,17 @@ export function createSyncRuntime(
|
|
|
246
246
|
return;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
-
// DDR-
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
249
|
+
// DDR-079 — TSX sync defaults ON, so every linked non-loopback project that
|
|
250
|
+
// ships .tsx broadcasts the WebRTC/self-nav exfil residual (the sandbox
|
|
251
|
+
// contains execution but not that lane) to every synced canvas. The default
|
|
252
|
+
// traded a footgun (silent 0-syncable) for this surface, so the surface must
|
|
253
|
+
// be LOUD: a banner on every `serve` naming the count + the opt-outs. Fires
|
|
254
|
+
// unless explicitly opted out (`syncTsx: false`); loopback hubs (local dev)
|
|
255
|
+
// skip it — no remote exfil concern.
|
|
256
|
+
const tsxBodyCount = canvases.filter((c) => c.html.toLowerCase().endsWith('.tsx')).length;
|
|
257
|
+
if (linkedHub.syncTsx !== false && tsxBodyCount > 0 && !isLoopbackHubUrl(linkedHub.url)) {
|
|
257
258
|
console.warn(
|
|
258
|
-
`[sync]
|
|
259
|
+
`[sync] ${tsxBodyCount} TSX canvas BODIES will sync to ${linkedHub.url} (TSX sync is ON by default — DDR-079). The sandbox contains execution, but a WebRTC/self-nav exfil residual applies to every synced canvas — link only hubs you operate or trust. Opt out: linkedHub.syncTsx=false (whole project) or a canvas .meta.json "syncable": false (one canvas).`
|
|
259
260
|
);
|
|
260
261
|
}
|
|
261
262
|
|
|
@@ -612,12 +613,15 @@ export async function scanCanvases(ctx: Context): Promise<CanvasScan> {
|
|
|
612
613
|
// `.tsx` syncs — the per-canvas opt-in is inert without the sandbox, and
|
|
613
614
|
// decoupling them would re-open the CRITICAL F1 RCE (DDR-060, DDR-054 §F1).
|
|
614
615
|
const splitActive = !!ctx.canvasOrigin;
|
|
615
|
-
// DDR-072 —
|
|
616
|
-
//
|
|
617
|
-
//
|
|
618
|
-
//
|
|
619
|
-
//
|
|
620
|
-
|
|
616
|
+
// DDR-079 (supersedes DDR-072) — TSX sync defaults ON for a linked project.
|
|
617
|
+
// Absence of the flag = ON: a freshly-linked peer sees the project's TSX
|
|
618
|
+
// without a hidden per-project opt-in (the recurring "I linked but my teammate
|
|
619
|
+
// sees nothing" footgun). `linkedHub.syncTsx: false` is the explicit
|
|
620
|
+
// project-wide opt-out; a per-canvas `.meta.json "syncable": false` still wins
|
|
621
|
+
// for one canvas (see resolveSyncable). The Lock-2 sandbox coupling
|
|
622
|
+
// (`splitActive`) is UNTOUCHED — a `.tsx` still syncs ONLY when the cross-origin
|
|
623
|
+
// containment is active; decoupling them would re-open the F1 RCE (DDR-060).
|
|
624
|
+
const projectSyncTsx = ctx.cfg.linkedHub?.syncTsx !== false;
|
|
621
625
|
for (const group of ctx.cfg.canvasGroups) {
|
|
622
626
|
const groupAbs = path.join(ctx.paths.designRoot, group.path);
|
|
623
627
|
if (!existsSync(groupAbs)) continue;
|
|
@@ -636,7 +640,7 @@ export async function scanCanvases(ctx: Context): Promise<CanvasScan> {
|
|
|
636
640
|
}
|
|
637
641
|
|
|
638
642
|
/**
|
|
639
|
-
* T3 (9.1-B) + DDR-072 — resolve whether a `.tsx` body is syncable.
|
|
643
|
+
* T3 (9.1-B) + DDR-079 (was DDR-072) — resolve whether a `.tsx` body is syncable.
|
|
640
644
|
*
|
|
641
645
|
* Tri-state precedence:
|
|
642
646
|
* 1. The sibling `<name>.meta.json` `"syncable"` boolean ALWAYS wins when
|
|
@@ -644,9 +648,10 @@ export async function scanCanvases(ctx: Context): Promise<CanvasScan> {
|
|
|
644
648
|
* sidecar; deliberately NOT in the untrusted `/_api/canvas-meta` PATCH
|
|
645
649
|
* whitelist (api.ts), so a hostile canvas/hub cannot flip its own body into
|
|
646
650
|
* or out of the sync set.
|
|
647
|
-
* 2. Otherwise fall back to
|
|
651
|
+
* 2. Otherwise fall back to `projectSyncTsx` — which now defaults to TRUE
|
|
652
|
+
* (DDR-079); `linkedHub.syncTsx: false` is the explicit project-wide opt-out.
|
|
648
653
|
*
|
|
649
|
-
* Missing sidecar / parse error → no explicit verdict → the project default.
|
|
654
|
+
* Missing sidecar / parse error → no explicit verdict → the project default (on).
|
|
650
655
|
*/
|
|
651
656
|
function resolveSyncable(bodyAbs: string, projectSyncTsx: boolean): boolean {
|
|
652
657
|
const metaAbs = bodyAbs.replace(/\.(tsx|html)$/i, '.meta.json');
|
|
@@ -752,7 +757,7 @@ export function buildNoSyncablePayload(
|
|
|
752
757
|
): NoSyncablePayload {
|
|
753
758
|
const reason =
|
|
754
759
|
tsxCount > 0
|
|
755
|
-
? `${tsxCount} TSX canvas(es) found but none are syncable
|
|
760
|
+
? `${tsxCount} TSX canvas(es) found but none are syncable. TSX sync is ON by default (DDR-079), so this means it was opted OUT — either project-wide (.design/config.json linkedHub.syncTsx: false) or per canvas (.meta.json "syncable": false) — OR the cross-origin sandbox is off (MAUDE_CANVAS_ORIGIN_SPLIT=0 disables it, and TSX sync with it — DDR-060). Remove the opt-out / re-enable the sandbox to sync.`
|
|
756
761
|
: `no canvases found under ${designRoot}.`;
|
|
757
762
|
return {
|
|
758
763
|
linked: true,
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
import type * as Y from 'yjs';
|
|
23
23
|
import { Y_TYPES } from '../collab/persistence.ts';
|
|
24
|
-
import {
|
|
24
|
+
import { annotationsFromDoc, commentsFromDoc, Y_SYNC_TYPES } from './codec.ts';
|
|
25
25
|
|
|
26
26
|
export interface CanonicalMaterialization {
|
|
27
27
|
html: string;
|
|
@@ -59,4 +59,4 @@ export function materializeCanonical(doc: Y.Doc): string {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Re-export so a shadow-compare caller has the type names in one import.
|
|
62
|
-
export {
|
|
62
|
+
export { Y_SYNC_TYPES, Y_TYPES };
|
|
@@ -34,12 +34,12 @@ import type * as Y from 'yjs';
|
|
|
34
34
|
|
|
35
35
|
import { Y_TYPES } from '../collab/persistence.ts';
|
|
36
36
|
import {
|
|
37
|
-
Y_SYNC_TYPES,
|
|
38
37
|
applyAnnotationsToDoc,
|
|
39
38
|
applyCommentsToDoc,
|
|
40
39
|
applyCssToDoc,
|
|
41
40
|
applyHtmlToDoc,
|
|
42
41
|
applyMetaToDoc,
|
|
42
|
+
Y_SYNC_TYPES,
|
|
43
43
|
} from './codec.ts';
|
|
44
44
|
import { ORIGINS } from './origins.ts';
|
|
45
45
|
|
|
@@ -30,9 +30,6 @@ import type * as Y from 'yjs';
|
|
|
30
30
|
|
|
31
31
|
import { atomicWrite } from './atomic-write.ts';
|
|
32
32
|
import {
|
|
33
|
-
MAX_CSS_BYTES,
|
|
34
|
-
MAX_HTML_BYTES,
|
|
35
|
-
MAX_META_BYTES,
|
|
36
33
|
applyAnnotationsToDoc,
|
|
37
34
|
applyCommentsToDoc,
|
|
38
35
|
applyCssToDoc,
|
|
@@ -40,6 +37,9 @@ import {
|
|
|
40
37
|
applyMetaToDoc,
|
|
41
38
|
cssFromDoc,
|
|
42
39
|
htmlFromDoc,
|
|
40
|
+
MAX_CSS_BYTES,
|
|
41
|
+
MAX_HTML_BYTES,
|
|
42
|
+
MAX_META_BYTES,
|
|
43
43
|
mergeSharedMetaIntoLocal,
|
|
44
44
|
metaFromDoc,
|
|
45
45
|
} from './codec.ts';
|