@1agh/maude 0.60.7 → 1.0.2
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/apps/studio/acp/index.ts +1 -0
- package/apps/studio/ai-banner.tsx +1 -0
- package/apps/studio/annotations-context-toolbar.tsx +3 -1
- package/apps/studio/annotations-layer.tsx +33 -16
- package/apps/studio/api.ts +108 -18
- package/apps/studio/artboard-guides-overlay.tsx +5 -1
- package/apps/studio/assets-s3.ts +6 -1
- package/apps/studio/bin/_import-figma.mjs +8 -3
- package/apps/studio/build.ts +1 -1
- package/apps/studio/canvas-artifacts.ts +21 -0
- package/apps/studio/canvas-build.ts +14 -9
- package/apps/studio/canvas-comment-mount.tsx +27 -30
- package/apps/studio/canvas-icons.tsx +1 -1
- package/apps/studio/canvas-lib.tsx +94 -5
- package/apps/studio/canvas-list-watch.ts +14 -1
- package/apps/studio/canvas-shell.tsx +8 -0
- package/apps/studio/client/app.jsx +224 -45
- package/apps/studio/client/panels/GitPanel.jsx +121 -13
- package/apps/studio/client/panels/SettingsPanel.jsx +1 -1
- package/apps/studio/client/panels/SyncConsentDialog.jsx +182 -0
- package/apps/studio/client/panels/SyncPanel.jsx +595 -1
- package/apps/studio/client/styles/3-shell-maude.css +38 -0
- package/apps/studio/clip-ops.ts +8 -1
- package/apps/studio/cloud/endpoints.ts +265 -3
- package/apps/studio/collab/origins.ts +3 -1
- package/apps/studio/comments-overlay.tsx +5 -0
- package/apps/studio/config.schema.json +24 -0
- package/apps/studio/context-menu.tsx +40 -27
- package/apps/studio/context.ts +57 -8
- package/apps/studio/cursors-overlay.tsx +25 -13
- package/apps/studio/dist/client.bundle.js +686 -686
- package/apps/studio/dist/comment-mount.js +2 -2
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/exporters/jobs.ts +77 -15
- package/apps/studio/exporters/remote.ts +190 -0
- package/apps/studio/exporters/video-encode-lib.ts +10 -4
- package/apps/studio/figma/to-strokes.ts +11 -9
- package/apps/studio/gifenc.d.ts +51 -0
- package/apps/studio/git/log-format.ts +88 -0
- package/apps/studio/git/safe-rel.ts +96 -0
- package/apps/studio/git/service.ts +46 -27
- package/apps/studio/hmr-broadcast.ts +10 -0
- package/apps/studio/http.ts +384 -6
- package/apps/studio/participants-chrome.tsx +1 -0
- package/apps/studio/photo-store.ts +7 -0
- package/apps/studio/react-augment.d.ts +17 -0
- package/apps/studio/runtime-bundle.ts +6 -1
- package/apps/studio/server.ts +43 -8
- package/apps/studio/sync/agent.ts +70 -82
- package/apps/studio/sync/asset-push.ts +28 -71
- package/apps/studio/sync/autocommit.ts +106 -5
- package/apps/studio/sync/cell-file-events.ts +117 -0
- package/apps/studio/sync/cell-pairing.ts +20 -5
- package/apps/studio/sync/cell-write-nudge.ts +244 -0
- package/apps/studio/sync/codec.ts +155 -3
- package/apps/studio/sync/cold-start-apply.ts +211 -0
- package/apps/studio/sync/ctl-heal.ts +253 -0
- package/apps/studio/sync/ctl-provider.ts +217 -0
- package/apps/studio/sync/decide-file.ts +335 -0
- package/apps/studio/sync/file-ledger.ts +581 -0
- package/apps/studio/sync/file-membership.ts +32 -0
- package/apps/studio/sync/file-plane.ts +1400 -0
- package/apps/studio/sync/file-pull.ts +41 -4
- package/apps/studio/sync/hub-link.ts +16 -1
- package/apps/studio/sync/hub-listing.ts +46 -0
- package/apps/studio/sync/hubs-config.ts +16 -0
- package/apps/studio/sync/index.ts +915 -308
- package/apps/studio/sync/journal-client.ts +200 -0
- package/apps/studio/sync/migrate-seed.ts +99 -67
- package/apps/studio/sync/poke.ts +50 -0
- package/apps/studio/sync/projection.ts +13 -0
- package/apps/studio/sync/pull-budget.ts +86 -0
- package/apps/studio/sync/settings.ts +110 -0
- package/apps/studio/sync/status.ts +68 -0
- package/apps/studio/sync/trash.ts +243 -0
- package/apps/studio/sync/untrusted.ts +30 -10
- package/apps/studio/test/_helpers.ts +8 -0
- package/apps/studio/test/canvas-build.test.ts +63 -0
- package/apps/studio/test/canvas-list-watch.test.ts +17 -0
- package/apps/studio/test/canvas-move-api.test.ts +31 -0
- package/apps/studio/test/canvas-origin-gate.test.ts +12 -0
- package/apps/studio/test/canvas-shell-build-error.test.ts +49 -0
- package/apps/studio/test/cloud-history-hardening.test.ts +165 -0
- package/apps/studio/test/cloud-history-posture.test.ts +230 -0
- package/apps/studio/test/cloud-session-role.test.ts +30 -0
- package/apps/studio/test/cloud-shell-surfaces.test.ts +39 -0
- package/apps/studio/test/cold-start-apply.test.ts +303 -0
- package/apps/studio/test/collab-stress.test.ts +9 -1
- package/apps/studio/test/export-lane.test.ts +245 -0
- package/apps/studio/test/fixtures/video-comp-fixture.tsx +1 -1
- package/apps/studio/test/git-log-format.test.ts +95 -0
- package/apps/studio/test/git-safe-rel.test.ts +132 -0
- package/apps/studio/test/hmr-broadcast.test.ts +26 -0
- package/apps/studio/test/peer-selection-follows-camera.test.tsx +131 -0
- package/apps/studio/test/shared-doc-cell-pairing.test.ts +5 -2
- package/apps/studio/test/sync-agent.test.ts +78 -0
- package/apps/studio/test/sync-asset-push.test.ts +71 -108
- package/apps/studio/test/sync-autocommit.test.ts +80 -0
- package/apps/studio/test/sync-cell-write-nudge.test.ts +346 -0
- package/apps/studio/test/sync-ctl-channel.test.ts +508 -0
- package/apps/studio/test/sync-decide-file.test.ts +420 -0
- package/apps/studio/test/sync-file-ledger.test.ts +334 -0
- package/apps/studio/test/sync-file-membership.test.ts +17 -1
- package/apps/studio/test/sync-file-plane.test.ts +976 -0
- package/apps/studio/test/sync-hub-listing.test.ts +46 -0
- package/apps/studio/test/sync-meta-codec.test.ts +76 -0
- package/apps/studio/test/sync-move-retirement.test.ts +231 -0
- package/apps/studio/test/sync-panel-surface.test.ts +20 -0
- package/apps/studio/test/sync-path-pull.test.ts +67 -1
- package/apps/studio/test/sync-pull-budget.test.ts +169 -0
- package/apps/studio/test/sync-seed-defers-to-hub.test.ts +83 -0
- package/apps/studio/test/sync-settings-routes.test.ts +195 -0
- package/apps/studio/test/sync-settings.test.ts +151 -0
- package/apps/studio/test/sync-status.test.ts +69 -0
- package/apps/studio/test/sync-trash.test.ts +132 -0
- package/apps/studio/test/workspace-containment.test.ts +45 -9
- package/apps/studio/tsconfig.json +9 -10
- package/apps/studio/use-annotation-resize.tsx +14 -3
- package/apps/studio/use-collab.tsx +3 -1
- package/apps/studio/whats-new.json +90 -0
- package/apps/studio/workspace-mode.ts +110 -62
- package/apps/studio/ws.ts +22 -1
- package/cli/bin/claude-design-server.mjs +19 -0
- package/cli/commands/design.mjs +25 -6
- package/cli/commands/hub-workspace.mjs +243 -22
- package/cli/commands/hub-workspace.test.mjs +171 -0
- package/cli/commands/hub.mjs +71 -1
- package/cli/lib/design-link.mjs +186 -1
- package/cli/lib/design-ownership.mjs +330 -0
- package/cli/lib/design-ownership.test.mjs +329 -0
- package/cli/lib/hubs-config.mjs +21 -0
- package/cli/lib/hubs-config.test.mjs +47 -1
- package/cli/lib/workspace-plan.mjs +298 -5
- package/cli/lib/workspace-plan.test.mjs +215 -1
- package/package.json +10 -10
- package/plugins/design/templates/_shell.html +43 -2
- package/plugins/design/templates/design-system-inspiration/SUB-AGENT-PROMPTS.md +1 -1
- package/plugins/design/templates/design-system-inspiration/core/preview/_motion-readme.md.tpl +1 -1
- package/apps/studio/server.mjs +0 -1312
- package/apps/studio/sync/asset-pull.ts +0 -210
- package/apps/studio/sync/asset-push-worker.ts +0 -84
- package/apps/studio/sync/asset-sweep.ts +0 -262
- package/apps/studio/test/sync-asset-pull.test.ts +0 -161
- package/apps/studio/test/sync-asset-push-worker.test.ts +0 -183
- package/apps/studio/test/sync-asset-sweep.test.ts +0 -243
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
* deprecation log at dev-server boot.
|
|
78
78
|
*/
|
|
79
79
|
|
|
80
|
+
import type { Easing } from 'motion/react';
|
|
80
81
|
import {
|
|
81
82
|
AnimatePresence as _MotionAnimatePresence,
|
|
82
83
|
motion as _motionImpl,
|
|
@@ -226,7 +227,7 @@ const ZOOM_MIN = 0.02;
|
|
|
226
227
|
const ZOOM_MAX = 4.0;
|
|
227
228
|
const ZOOM_STEP_IN = 1.2;
|
|
228
229
|
const ZOOM_STEP_OUT = 1 / 1.2;
|
|
229
|
-
const WHEEL_ZOOM_K = 0.
|
|
230
|
+
const WHEEL_ZOOM_K = 0.0035; // larger = more sensitive wheel — tuned to match Figma/FigJam's zoom-per-notch feel
|
|
230
231
|
const SETTLE_MS = 500;
|
|
231
232
|
const PUBLISH_MS = 50;
|
|
232
233
|
|
|
@@ -257,7 +258,12 @@ type DcPerfCounters = {
|
|
|
257
258
|
instrumented?: boolean;
|
|
258
259
|
};
|
|
259
260
|
|
|
260
|
-
|
|
261
|
+
/** The numeric counters only — `instrumented` is a flag, not something to add 1 to. */
|
|
262
|
+
type DcPerfCounterKey = {
|
|
263
|
+
[K in keyof DcPerfCounters]-?: DcPerfCounters[K] extends number | undefined ? K : never;
|
|
264
|
+
}[keyof DcPerfCounters];
|
|
265
|
+
|
|
266
|
+
export function countRender(key: DcPerfCounterKey): void {
|
|
261
267
|
if (typeof window === 'undefined') return;
|
|
262
268
|
const perf = (window as unknown as { __dcPerf?: DcPerfCounters }).__dcPerf;
|
|
263
269
|
if (!perf) return;
|
|
@@ -2618,7 +2624,14 @@ function buildCanvasRectsManifest(): CanvasRectsManifest {
|
|
|
2618
2624
|
if (rect.width <= 0 || rect.height <= 0) continue;
|
|
2619
2625
|
const id = el.getAttribute('data-dc-screen');
|
|
2620
2626
|
if (!id) continue;
|
|
2621
|
-
|
|
2627
|
+
// `kind` is part of ArtboardRect and the manifest's consumers (canvas-rects
|
|
2628
|
+
// → the whiteboard toolkit, DDR-151) read it. It was being dropped here —
|
|
2629
|
+
// invisible until A2 put this file under a checker. Same element carries
|
|
2630
|
+
// `data-dc-kind`, always stamped by DCArtboard; 'digital' is its own default.
|
|
2631
|
+
const kindAttr = el.getAttribute('data-dc-kind');
|
|
2632
|
+
const kind: ArtboardKind =
|
|
2633
|
+
kindAttr === 'print' || kindAttr === 'web' || kindAttr === 'video' ? kindAttr : 'digital';
|
|
2634
|
+
artboards.push({ id, kind, ...toWorld(rect) });
|
|
2622
2635
|
}
|
|
2623
2636
|
|
|
2624
2637
|
const elements: CanvasRectsElement[] = [];
|
|
@@ -3021,6 +3034,39 @@ export function PhotoPreviewBridge() {
|
|
|
3021
3034
|
};
|
|
3022
3035
|
}, []);
|
|
3023
3036
|
|
|
3037
|
+
// A peer's photo edit arrived: the sidecar changed on disk, the shell heard
|
|
3038
|
+
// it on the HMR socket and re-dispatched it here. Re-fetch and re-apply —
|
|
3039
|
+
// deliberately OUTSIDE the hydration scan's once-per-asset `attempted` set,
|
|
3040
|
+
// which exists to stop mutation-driven fetch amplification and which is
|
|
3041
|
+
// exactly why a synced edit used to appear only after Cmd+R (the scan had
|
|
3042
|
+
// already spent this asset's one attempt on mount).
|
|
3043
|
+
useEffect(() => {
|
|
3044
|
+
const onRefreshed = (e: Event) => {
|
|
3045
|
+
const sha8 = (e as CustomEvent<{ sha8?: unknown }>).detail?.sha8;
|
|
3046
|
+
if (typeof sha8 !== 'string' || !/^[0-9a-f]{8}$/i.test(sha8)) return;
|
|
3047
|
+
// Resolve the full `assets/<sha8>.<ext>` ref from the live DOM — the
|
|
3048
|
+
// event carries only the hash (the sidecar name has no extension).
|
|
3049
|
+
let asset: string | null = null;
|
|
3050
|
+
for (const n of document.querySelectorAll('img, image')) {
|
|
3051
|
+
const ref = extractAssetRef(n);
|
|
3052
|
+
if (ref?.includes(`assets/${sha8}.`)) {
|
|
3053
|
+
asset = ref;
|
|
3054
|
+
break;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
if (!asset) return; // no photo on this canvas uses that asset
|
|
3058
|
+
fetch(`/_api/photo-edit?asset=${encodeURIComponent(asset)}`)
|
|
3059
|
+
.then((r) => (r.ok ? r.json() : null))
|
|
3060
|
+
.then((edit) => {
|
|
3061
|
+
// A deleted/reset edit applies as null → restores the original src.
|
|
3062
|
+
apply(asset as string, edit && !isDefaultEdit(edit) ? (edit as PhotoEdit) : null);
|
|
3063
|
+
})
|
|
3064
|
+
.catch(() => {});
|
|
3065
|
+
};
|
|
3066
|
+
document.addEventListener('maude:photo-edit-refreshed', onRefreshed);
|
|
3067
|
+
return () => document.removeEventListener('maude:photo-edit-refreshed', onRefreshed);
|
|
3068
|
+
}, [apply]);
|
|
3069
|
+
|
|
3024
3070
|
useEffect(() => {
|
|
3025
3071
|
const onMsg = (e: MessageEvent) => {
|
|
3026
3072
|
const m = e.data as { dgn?: string; asset?: unknown; edit?: unknown; busy?: unknown } | null;
|
|
@@ -4019,6 +4065,49 @@ export function easingFromToken(
|
|
|
4019
4065
|
return undefined;
|
|
4020
4066
|
}
|
|
4021
4067
|
|
|
4068
|
+
/**
|
|
4069
|
+
* The same token, in the shape MOTION accepts.
|
|
4070
|
+
*
|
|
4071
|
+
* `easingFromToken` returns CSS (`cubic-bezier(a, b, c, d)`), which is right for
|
|
4072
|
+
* a stylesheet and wrong for motion: its `Easing` is a named curve or a
|
|
4073
|
+
* four-number BezierDefinition, never a CSS string. Both MotionDemo call sites
|
|
4074
|
+
* were handing it the CSS form, so motion silently fell back to its own default
|
|
4075
|
+
* — a DS motion specimen was not demonstrating the DS's easing at all. Invisible
|
|
4076
|
+
* until A2 put this file under a checker.
|
|
4077
|
+
*
|
|
4078
|
+
* Named curves pass through; anything unparseable returns undefined, which is
|
|
4079
|
+
* the same "let motion decide" the bug produced, only deliberately.
|
|
4080
|
+
*/
|
|
4081
|
+
function motionEaseFromToken(token: string, easings: Record<string, string>): Easing | undefined {
|
|
4082
|
+
const css = easingFromToken(token, easings);
|
|
4083
|
+
if (!css) return undefined;
|
|
4084
|
+
const named = css.trim();
|
|
4085
|
+
if (
|
|
4086
|
+
named === 'linear' ||
|
|
4087
|
+
named === 'easeIn' ||
|
|
4088
|
+
named === 'easeOut' ||
|
|
4089
|
+
named === 'easeInOut' ||
|
|
4090
|
+
named === 'circIn' ||
|
|
4091
|
+
named === 'circOut' ||
|
|
4092
|
+
named === 'circInOut' ||
|
|
4093
|
+
named === 'backIn' ||
|
|
4094
|
+
named === 'backOut' ||
|
|
4095
|
+
named === 'backInOut' ||
|
|
4096
|
+
named === 'anticipate'
|
|
4097
|
+
) {
|
|
4098
|
+
return named;
|
|
4099
|
+
}
|
|
4100
|
+
// CSS keywords motion spells differently.
|
|
4101
|
+
if (named === 'ease-in') return 'easeIn';
|
|
4102
|
+
if (named === 'ease-out') return 'easeOut';
|
|
4103
|
+
if (named === 'ease-in-out') return 'easeInOut';
|
|
4104
|
+
const m = /^cubic-bezier\(([^)]*)\)$/.exec(named);
|
|
4105
|
+
if (!m || !m[1]) return undefined;
|
|
4106
|
+
const nums = m[1].split(',').map((n) => Number(n.trim()));
|
|
4107
|
+
if (nums.length !== 4 || nums.some((n) => !Number.isFinite(n))) return undefined;
|
|
4108
|
+
return [nums[0], nums[1], nums[2], nums[3]] as [number, number, number, number];
|
|
4109
|
+
}
|
|
4110
|
+
|
|
4022
4111
|
interface MotionDemoProps {
|
|
4023
4112
|
role: MotionRole;
|
|
4024
4113
|
loop?: MotionLoop;
|
|
@@ -4048,7 +4137,7 @@ export function MotionDemo({
|
|
|
4048
4137
|
const reduced = _useReducedMotion();
|
|
4049
4138
|
const durationMs = tokens.durations[cfg.durationToken] ?? cfg.fallbackMs;
|
|
4050
4139
|
const isSpring = cfg.easingToken === 'spring';
|
|
4051
|
-
const ease = isSpring ? undefined :
|
|
4140
|
+
const ease = isSpring ? undefined : motionEaseFromToken(cfg.easingToken, tokens.easings);
|
|
4052
4141
|
const repeat = reduced || loop === 'once' ? 0 : Number.POSITIVE_INFINITY;
|
|
4053
4142
|
const repeatType: 'reverse' | 'loop' = loop === 'always' ? 'reverse' : 'loop';
|
|
4054
4143
|
const animate = reduced ? undefined : cfg.keyframes;
|
|
@@ -4131,7 +4220,7 @@ export function TokenPlayback({
|
|
|
4131
4220
|
const tokens = useMotionTokens();
|
|
4132
4221
|
const reduced = _useReducedMotion();
|
|
4133
4222
|
const durationMs = tokens.durations[duration] ?? 220;
|
|
4134
|
-
const ease = easing === 'spring' ? undefined :
|
|
4223
|
+
const ease = easing === 'spring' ? undefined : motionEaseFromToken(easing, tokens.easings);
|
|
4135
4224
|
const [tick, setTick] = useState(0);
|
|
4136
4225
|
const fire = useCallback(() => {
|
|
4137
4226
|
if (!reduced) setTick((n) => n + 1);
|
|
@@ -47,10 +47,23 @@ export function isCanvasCandidate(rel: string, groupPaths: string[]): boolean {
|
|
|
47
47
|
const p = rel.replace(/\\/g, '/').replace(/^\/+/, '');
|
|
48
48
|
if (!p) return false;
|
|
49
49
|
const low = p.toLowerCase();
|
|
50
|
-
|
|
50
|
+
// A DIRECTORY IS A CANDIDATE TOO. Renaming or moving a folder OUTSIDE the app
|
|
51
|
+
// (Finder, `mv`, `git checkout` of a branch that renamed it) changes the path
|
|
52
|
+
// of every canvas inside it, but the only event that reaches here names the
|
|
53
|
+
// DIRECTORY — `ui/dbox2` — which has no `.tsx` on the end. Gating on the
|
|
54
|
+
// extension therefore ignored it, so the tree kept listing the old folder and,
|
|
55
|
+
// worse, the sync runtime kept a descriptor pointing at a path that no longer
|
|
56
|
+
// existed: the canvases in that folder silently stopped syncing until some
|
|
57
|
+
// unrelated write to a `.tsx` happened to nudge the same recompute.
|
|
58
|
+
// `snapshot()` is authoritative, so a directory that turns out to hold no
|
|
59
|
+
// canvases costs one recompute and emits nothing.
|
|
60
|
+
const last = p.slice(p.lastIndexOf('/') + 1);
|
|
61
|
+
const looksLikeDir = !last.includes('.');
|
|
62
|
+
if (!looksLikeDir && !low.endsWith('.tsx') && !low.endsWith('.html')) return false;
|
|
51
63
|
const segs = p.split('/');
|
|
52
64
|
for (const s of segs) {
|
|
53
65
|
if (!s) return false;
|
|
66
|
+
if (s === '..') return false; // the extension test used to be the guard here
|
|
54
67
|
if (s.startsWith('_')) return false;
|
|
55
68
|
if (SKIP_DIRS.has(s)) return false;
|
|
56
69
|
}
|
|
@@ -3005,6 +3005,14 @@ function CanvasRouter({
|
|
|
3005
3005
|
// Record onto the in-canvas undo stack so Cmd+Z reverts the rewrite. The
|
|
3006
3006
|
// edit already posted above (record, don't re-run do()). before/after are
|
|
3007
3007
|
// the trimmed bodies the edit-text endpoint persists.
|
|
3008
|
+
//
|
|
3009
|
+
// ONLY the record is gated on `file`. An earlier version of this guard
|
|
3010
|
+
// sat above the `postMessage` and returned out of the whole function —
|
|
3011
|
+
// which silently dropped THE EDIT ITSELF, not just an unusable undo
|
|
3012
|
+
// entry. `deriveFile` returning undefined must not cost the user their
|
|
3013
|
+
// typing; it costs them only a Cmd+Z step they could not have applied
|
|
3014
|
+
// anyway (a record with no canvas is one undo can never target).
|
|
3015
|
+
if (!file) return;
|
|
3008
3016
|
undoStackRef.current.record(
|
|
3009
3017
|
buildEditSourceRecord({
|
|
3010
3018
|
op: 'text',
|