@1agh/maude 1.3.1 → 1.4.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.
- package/apps/studio/annotation-edit-base.ts +36 -0
- package/apps/studio/annotations-layer.tsx +13 -2
- package/apps/studio/api.ts +8 -0
- package/apps/studio/canvas-lib.tsx +25 -10
- package/apps/studio/client/app.jsx +2 -0
- package/apps/studio/client/panels/TimelinePanel.jsx +75 -62
- package/apps/studio/client/photo-knobs.jsx +3 -3
- package/apps/studio/comments-overlay.tsx +86 -2
- package/apps/studio/context.ts +93 -1
- package/apps/studio/dist/client.bundle.js +524 -524
- package/apps/studio/dist/comment-mount.js +2 -2
- package/apps/studio/http.ts +4 -1
- package/apps/studio/server.ts +3 -0
- package/apps/studio/sync/accepted-link.ts +3 -0
- package/apps/studio/sync/file-plane.ts +15 -0
- package/apps/studio/sync/index.ts +32 -0
- package/apps/studio/sync/transaction-client.ts +3 -0
- package/apps/studio/whats-new.json +36 -0
- package/apps/studio/ws.ts +9 -2
- package/package.json +8 -8
- package/plugins/flow/.claude-plugin/config.schema.json +15 -2
- package/plugins/flow/README.md +1 -1
package/apps/studio/context.ts
CHANGED
|
@@ -329,6 +329,96 @@ function resolveRepoRoot(): string {
|
|
|
329
329
|
return process.cwd();
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
/** Where the sync runtime keeps what the linked project says about itself. */
|
|
333
|
+
export const PROJECT_CONFIG_CACHE_REL = '_state/project-config.json';
|
|
334
|
+
|
|
335
|
+
export interface ProjectConfig {
|
|
336
|
+
canvasGroups: { label: string; path: string }[];
|
|
337
|
+
designSystems: { name: string; path: string; tokensCssRel?: string }[];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* The project's own labels and design systems, as the hub reported them —
|
|
342
|
+
* UNTRUSTED (DDR-054): only short names and contained relative paths survive.
|
|
343
|
+
*/
|
|
344
|
+
export function sanitizeProjectConfig(raw: unknown): ProjectConfig | null {
|
|
345
|
+
if (!raw || typeof raw !== 'object') return null;
|
|
346
|
+
const r = raw as { canvasGroups?: unknown; designSystems?: unknown };
|
|
347
|
+
const groups = Array.isArray(r.canvasGroups) ? r.canvasGroups : [];
|
|
348
|
+
const systems = Array.isArray(r.designSystems) ? r.designSystems : [];
|
|
349
|
+
const canvasGroups = groups
|
|
350
|
+
.filter(
|
|
351
|
+
(g): g is { label: string; path: string } =>
|
|
352
|
+
!!g &&
|
|
353
|
+
typeof g === 'object' &&
|
|
354
|
+
typeof (g as { label?: unknown }).label === 'string' &&
|
|
355
|
+
(g as { label: string }).label.length > 0 &&
|
|
356
|
+
(g as { label: string }).label.length <= 64 &&
|
|
357
|
+
isContainedRel((g as { path?: unknown }).path)
|
|
358
|
+
)
|
|
359
|
+
.slice(0, 32)
|
|
360
|
+
.map((g) => ({ label: g.label, path: g.path.replace(/^\/+|\/+$/g, '') }));
|
|
361
|
+
const designSystems = systems
|
|
362
|
+
.filter(
|
|
363
|
+
(d): d is { name: string; path: string; tokensCssRel?: string } =>
|
|
364
|
+
!!d &&
|
|
365
|
+
typeof d === 'object' &&
|
|
366
|
+
typeof (d as { name?: unknown }).name === 'string' &&
|
|
367
|
+
/^[\w .-]{1,64}$/.test((d as { name: string }).name) &&
|
|
368
|
+
isContainedRel((d as { path?: unknown }).path) &&
|
|
369
|
+
((d as { tokensCssRel?: unknown }).tokensCssRel == null ||
|
|
370
|
+
isContainedRel((d as { tokensCssRel?: unknown }).tokensCssRel))
|
|
371
|
+
)
|
|
372
|
+
.slice(0, 16)
|
|
373
|
+
.map((d) => ({
|
|
374
|
+
name: d.name,
|
|
375
|
+
path: d.path.replace(/^\/+|\/+$/g, ''),
|
|
376
|
+
...(typeof d.tokensCssRel === 'string' ? { tokensCssRel: d.tokensCssRel } : {}),
|
|
377
|
+
}));
|
|
378
|
+
return { canvasGroups, designSystems };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* What the linked project says about itself that this copy's own config does
|
|
383
|
+
* not. A managed desktop copy is declared from group PATHS alone, so its
|
|
384
|
+
* groups had no labels ("system", never "Design system") and it knew no
|
|
385
|
+
* design systems: the project's design system never appeared on a teammate's
|
|
386
|
+
* desktop (plan T31/L16). This only FILLS IN — a label the local config chose
|
|
387
|
+
* and a local design system of the same name always win — and only for a
|
|
388
|
+
* group this copy already declares.
|
|
389
|
+
*/
|
|
390
|
+
function withProjectConfig(cfg: DevServerConfig, repoRoot: string): DevServerConfig {
|
|
391
|
+
if (!cfg.linkedHub) return cfg;
|
|
392
|
+
let project: ProjectConfig | null = null;
|
|
393
|
+
try {
|
|
394
|
+
const designRel = String(cfg.designRoot ?? '.design').replace(/^\/+|\/+$/g, '');
|
|
395
|
+
project = sanitizeProjectConfig(
|
|
396
|
+
JSON.parse(readFileSync(path.join(repoRoot, designRel, PROJECT_CONFIG_CACHE_REL), 'utf8'))
|
|
397
|
+
);
|
|
398
|
+
} catch {
|
|
399
|
+
return cfg;
|
|
400
|
+
}
|
|
401
|
+
if (!project) return cfg;
|
|
402
|
+
const labels = new Map(project.canvasGroups.map((g) => [g.path, g.label]));
|
|
403
|
+
const canvasGroups = (cfg.canvasGroups ?? []).map((g) => {
|
|
404
|
+
const p = String(g.path ?? '').replace(/^\/+|\/+$/g, '');
|
|
405
|
+
const label = labels.get(p);
|
|
406
|
+
return label && (!g.label || g.label === p) ? { ...g, label } : g;
|
|
407
|
+
});
|
|
408
|
+
const declared = new Set((cfg.designSystems ?? []).map((d) => d.name));
|
|
409
|
+
const groupPaths = canvasGroups.map((g) => String(g.path).replace(/^\/+|\/+$/g, ''));
|
|
410
|
+
const adopted = project.designSystems.filter(
|
|
411
|
+
(d) =>
|
|
412
|
+
!declared.has(d.name) && groupPaths.some((g) => d.path === g || d.path.startsWith(`${g}/`))
|
|
413
|
+
);
|
|
414
|
+
if (adopted.length === 0 && canvasGroups.every((g, i) => g === cfg.canvasGroups[i])) return cfg;
|
|
415
|
+
return {
|
|
416
|
+
...cfg,
|
|
417
|
+
canvasGroups,
|
|
418
|
+
...(adopted.length ? { designSystems: [...(cfg.designSystems ?? []), ...adopted] } : {}),
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
332
422
|
function loadConfig(repoRoot: string): DevServerConfig {
|
|
333
423
|
const configPath = path.join(repoRoot, '.design', 'config.json');
|
|
334
424
|
let raw: string;
|
|
@@ -339,7 +429,9 @@ function loadConfig(repoRoot: string): DevServerConfig {
|
|
|
339
429
|
}
|
|
340
430
|
try {
|
|
341
431
|
const parsed = JSON.parse(raw);
|
|
342
|
-
return normalizeConfig(
|
|
432
|
+
return normalizeConfig(
|
|
433
|
+
withProjectConfig({ ...DEFAULT_CONFIG, ...parsed, _source: '.design/config.json' }, repoRoot)
|
|
434
|
+
);
|
|
343
435
|
} catch (e) {
|
|
344
436
|
const msg = e instanceof Error ? e.message : String(e);
|
|
345
437
|
console.error(` warn: ${configPath} is not valid JSON: ${msg}. Using defaults.`);
|