@glyphlab/diagram-core 0.1.0 → 0.2.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/{chunk-XCRPIPPL.js → chunk-KZD7D662.js} +24 -6
- package/{chunk-XCRPIPPL.js.map → chunk-KZD7D662.js.map} +1 -1
- package/index.d.ts +3 -3
- package/index.js +40 -6
- package/index.js.map +1 -1
- package/package.json +5 -5
- package/{repository-C4DyvGsM.d.ts → repository-n7clVcr3.d.ts} +195 -7
- package/testing.js +1 -1
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/checklist.ts","../src/membership.ts","../src/plan.ts","../src/editGeometry.ts","../src/geometry.ts","../src/ops.ts","../src/controller.ts","../src/repository.ts","../src/highlights.ts","../src/codeRefs.ts","../src/linkCheck.ts","../src/repoRules.ts"],"sourcesContent":["// The Systems design questions a node can answer. The answers are kept on the node (`systemsDesign`, by question id), so they are\n// saved with the design and the agent can read and write them.\nexport interface ChecklistItem { id: string; label: string; question: string }\nexport interface ChecklistGroup { title: string; items: ChecklistItem[] }\n\nexport const DESIGN_CHECKLIST: ChecklistGroup[] = [\n { title: 'The Two Endpoints', items: [\n { id: 'client', label: 'Client', question: 'Who or what initiates the request?' },\n { id: 'server', label: 'Server', question: 'Who or what processes the request?' },\n ] },\n { title: 'The Four Package Characteristics', items: [\n { id: 'size', label: 'Package Size', question: 'How much data is transmitted per request?' },\n { id: 'frequency', label: 'Package Frequency', question: 'How often are requests sent?' },\n { id: 'latency', label: 'Package Latency', question: 'How quickly must requests be processed?' },\n { id: 'retention', label: 'Package Retention', question: 'How long must the data remain relevant or be stored?' },\n ] },\n { title: 'The Three Cs', items: [\n { id: 'connection', label: 'Connection', question: 'How do clients and servers communicate? Are connections persistent or temporary?' },\n { id: 'capacity', label: 'Capacity', question: 'How much traffic, concurrency, and throughput must the system support?' },\n { id: 'consistency', label: 'Consistency & Idempotency', question: 'How consistent must the data be? How are retries and duplicate requests handled safely?' },\n ] },\n { title: 'The Final Four', items: [\n { id: 'protocol', label: 'Protocol', question: 'What communication protocols are used (HTTP, WebSocket, gRPC, etc.)?' },\n { id: 'errors', label: 'Error Handling', question: 'How are failures, timeouts, retries, and recovery handled?' },\n { id: 'security', label: 'Security', question: 'How are authentication, authorization, encryption, and data protection implemented?' },\n { id: 'telemetry', label: 'Telemetry', question: 'How are logs, metrics, traces, and system health monitored?' },\n ] },\n]\n\nexport const CHECKLIST_TOTAL = DESIGN_CHECKLIST.reduce((n, g) => n + g.items.length, 0)\n\nexport const CHECKLIST_IDS: readonly string[] = DESIGN_CHECKLIST.flatMap((g) => g.items.map((i) => i.id))\nexport const CHECKLIST_ANSWER_MAX = 200\n","import type { GroupDef, NodeDef } from './types'\n\n// A group does not store its members: whatever is drawn inside its box belongs to it. A node is\n// inside when its centre is, and another group is inside when its whole box is. Keeping this\n// derived means the saved diagram needs nothing extra, and dragging a node out of a box takes\n// it out of the group.\nexport function membersOf(group: GroupDef, nodes: NodeDef[], groups: GroupDef[]): { nodes: NodeDef[]; groups: GroupDef[] } {\n const inside = (x: number, y: number) => x >= group.x && x <= group.x + group.w && y >= group.y && y <= group.y + group.h\n return {\n nodes: nodes.filter((n) => inside(n.x + n.w / 2, n.y + n.h / 2)),\n groups: groups.filter(\n (g) => g.id !== group.id && g.x >= group.x && g.y >= group.y && g.x + g.w <= group.x + group.w && g.y + g.h <= group.y + group.h,\n ),\n }\n}\n","import { membersOf } from './membership'\nimport type { DiagramOp } from './ops'\nimport { CHECKLIST_ANSWER_MAX, CHECKLIST_IDS } from './checklist'\nimport type { EdgeDef, GroupDef, NodeDef } from './types'\n\n// The part of the app that edits a diagram, kept pure: given what the diagram is and a batch of\n// operations, say what it becomes (or why that is not possible). Nothing here touches a store,\n// so every rule can be tested on its own, and a batch is all-or-nothing by construction.\n\nexport interface Snapshot {\n nodes: NodeDef[]\n edges: EdgeDef[]\n groups: GroupDef[]\n}\n\n// A change to a snapshot: entities to put in (new or replaced) and ids to take out. Applying a\n// patch touches only the entities named in it, so undoing a change does not undo unrelated\n// edits (a node the user dragged afterwards, say).\nexport interface Patch {\n nodes: { upsert: NodeDef[]; remove: string[] }\n edges: { upsert: EdgeDef[]; remove: string[] }\n groups: { upsert: GroupDef[]; remove: string[] }\n}\n\nexport type PlanResult =\n | { ok: true; next: Snapshot; patch: Patch; inverse: Patch; applied: number }\n | { ok: false; message: string; opIndex?: number }\n\nexport const LIMITS = { maxNodes: 300, maxEdges: 600, maxGroups: 50, title: 120, body: 20_000, label: 200 } as const\n\nconst ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/\nconst DEFAULT_SIZE = { w: 280, h: 150 }\nconst ROW_GAP = 30\nconst GROUP_BOTTOM_PADDING = 20\n// An empty group, before it is sized.\nconst EMPTY_GROUP = { w: 360, h: 240 }\nconst GROUP_PADDING = 24\nconst GROUP_TITLE_SPACE = 40\n\nfunction diffById<T extends { id: string }>(before: T[], after: T[]): { upsert: T[]; remove: string[] } {\n const beforeById = new Map(before.map((e) => [e.id, e]))\n const afterIds = new Set(after.map((e) => e.id))\n return {\n upsert: after.filter((e) => JSON.stringify(beforeById.get(e.id)) !== JSON.stringify(e)),\n remove: before.filter((e) => !afterIds.has(e.id)).map((e) => e.id),\n }\n}\n\n// What turns `before` into `after`.\nexport function diffSnapshots(before: Snapshot, after: Snapshot): Patch {\n return {\n nodes: diffById(before.nodes, after.nodes),\n edges: diffById(before.edges, after.edges),\n groups: diffById(before.groups, after.groups),\n }\n}\n\nfunction applyTo<T extends { id: string }>(items: T[], change: { upsert: T[]; remove: string[] }): T[] {\n const removed = new Set(change.remove)\n const replacements = new Map(change.upsert.map((e) => [e.id, e]))\n const kept = items.filter((e) => !removed.has(e.id)).map((e) => replacements.get(e.id) ?? e)\n const known = new Set(items.map((e) => e.id))\n return [...kept, ...change.upsert.filter((e) => !known.has(e.id))]\n}\n\nexport function applyPatch(snapshot: Snapshot, patch: Patch): Snapshot {\n const nodes = applyTo(snapshot.nodes, patch.nodes)\n const nodeIds = new Set(nodes.map((n) => n.id))\n return {\n nodes,\n // An edge whose end is gone cannot exist.\n edges: applyTo(snapshot.edges, patch.edges).filter((e) => nodeIds.has(e.from) && nodeIds.has(e.to)),\n groups: applyTo(snapshot.groups, patch.groups),\n }\n}\n\nexport function isEmptyPatch(patch: Patch): boolean {\n return Object.values(patch).every((c) => c.upsert.length === 0 && c.remove.length === 0)\n}\n\nfunction slug(text: string): string {\n const base = text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40)\n return base || 'item'\n}\n\nfunction uniqueId(base: string, taken: Set<string>): string {\n if (!taken.has(base)) return base\n for (let n = 2; ; n++) {\n const candidate = `${base}-${n}`\n if (!taken.has(candidate)) return candidate\n }\n}\n\nclass PlanError extends Error {}\n\n// A colour is set, or taken off with null; left out, it stays.\nfunction setColor(item: { color?: string }, color: string | null | undefined) {\n if (color === null) delete item.color\n else if (color !== undefined) item.color = color\n}\nconst fail = (message: string): never => {\n throw new PlanError(message)\n}\n\n// Puts a new node under the others in the column of the node added last. If that node is inside a box (a group), the box grows\n// to keep the new one inside.\nfunction place(draft: Snapshot, size: { w: number; h: number }) {\n const last = draft.nodes[draft.nodes.length - 1]\n if (!last) return { x: 0, y: ROW_GAP }\n\n const column = draft.nodes.filter((n) => n.x === last.x)\n const y = Math.max(...column.map((n) => n.y + n.h)) + ROW_GAP\n const home = draft.groups.find((g) => last.x >= g.x && last.x < g.x + g.w && last.y >= g.y && last.y < g.y + g.h)\n if (home) {\n const needed = y + size.h + GROUP_BOTTOM_PADDING - home.y\n if (needed > home.h) draft.groups = draft.groups.map((g) => (g.id === home.id ? { ...g, h: needed } : g))\n }\n return { x: last.x, y }\n}\n\n// The smallest a node or group may be resized to, so it cannot collapse out of sight.\nexport const MIN_NODE = { w: 160, h: 80 } as const\nexport const MIN_GROUP = { w: 120, h: 80 } as const\n\nfunction checkSize(what: string, w: number | undefined, h: number | undefined, min: { w: number; h: number }) {\n if (w !== undefined && w < min.w) fail(`The ${what} cannot be narrower than ${min.w}.`)\n if (h !== undefined && h < min.h) fail(`The ${what} cannot be shorter than ${min.h}.`)\n}\n\n// Only the fields that were given.\nfunction geometry(g: { x?: number; y?: number; w?: number; h?: number }) {\n return Object.fromEntries(Object.entries(g).filter(([, v]) => v !== undefined)) as Partial<{ x: number; y: number; w: number; h: number }>\n}\n\nfunction checkText(label: string, value: string, max: number) {\n if (value.length > max) fail(`${label} is too long (${value.length} characters; the limit is ${max}).`)\n}\n\n// The answers must be to known questions and short. Empty answers are left out.\nfunction checkAnswers(answers: Record<string, string>) {\n for (const [key, value] of Object.entries(answers)) {\n if (!CHECKLIST_IDS.includes(key)) fail(`\"${key}\" is not a Systems design question. Use: ${CHECKLIST_IDS.join(', ')}.`)\n checkText(`The answer for \"${key}\"`, value, CHECKLIST_ANSWER_MAX)\n }\n}\n\nconst MAX_LINKS = 20\n// A link points inside the project: a relative path, with no \"..\", and a hash that is hex.\nfunction checkLinks(links: NodeDef['links']) {\n if (!links) return\n if (links.length > MAX_LINKS) fail(`A node can have at most ${MAX_LINKS} links.`)\n for (const link of links) {\n if (link.path.startsWith('/') || link.path.split('/').includes('..')) fail(`The link path \"${link.path}\" must be relative to the project root, without \"..\".`)\n checkText('The link path', link.path, 500)\n if (link.symbol !== undefined) checkText('The link symbol', link.symbol, 500)\n if (link.hash !== undefined && !/^[0-9a-f]{6,64}$/.test(link.hash)) fail(`The link hash \"${link.hash}\" must be lowercase hex (6 to 64 characters).`)\n }\n}\n\nfunction node(draft: Snapshot, id: string): NodeDef {\n return draft.nodes.find((n) => n.id === id) ?? fail(`There is no node \"${id}\". Use getDiagram to see the ids.`)\n}\n\n// A node named by its id, or (for what the assistant has just created and has no id for yet) by its\n// title, when exactly one node has it. A title that fits several nodes is refused rather than guessed.\nexport function findNodeRef(nodes: NodeDef[], ref: string): { node: NodeDef } | { error: 'missing' | 'ambiguous' } {\n const byId = nodes.find((n) => n.id === ref)\n if (byId) return { node: byId }\n for (const same of [(n: NodeDef) => n.title === ref, (n: NodeDef) => n.title.toLowerCase() === ref.toLowerCase()]) {\n const found = nodes.filter(same)\n if (found.length === 1) return { node: found[0] }\n if (found.length > 1) return { error: 'ambiguous' }\n }\n return { error: 'missing' }\n}\n\nfunction nodeRef(draft: Snapshot, ref: string): NodeDef {\n const found = findNodeRef(draft.nodes, ref)\n if ('node' in found) return found.node\n if (found.error === 'ambiguous') return fail(`More than one node is titled \"${ref}\". Use the node's id.`)\n return fail(`There is no node \"${ref}\". Use getDiagram to see the ids.`)\n}\n\nfunction group(draft: Snapshot, id: string): GroupDef {\n return draft.groups.find((g) => g.id === id) ?? fail(`There is no group \"${id}\". Use getDiagram to see the ids.`)\n}\n\nfunction edge(draft: Snapshot, id: string): EdgeDef {\n return draft.edges.find((e) => e.id === id) ?? fail(`There is no edge \"${id}\". Use getDiagram to see the ids.`)\n}\n\nfunction applyOp(draft: Snapshot, op: DiagramOp) {\n switch (op.op) {\n case 'createLane': {\n const lanes = draft.groups.filter((g) => g.lane)\n const orientation = op.lane.orientation ?? lanes[0]?.lane?.orientation ?? 'horizontal'\n if (!op.lane.title.trim()) fail('A swimlane title cannot be empty.')\n if (lanes.some((g) => g.lane?.orientation !== orientation)) fail('Use arrangeLanes to change the orientation of all swimlanes together.')\n const x = orientation === 'horizontal' ? Math.min(0, ...lanes.map((g) => g.x)) : Math.max(0, ...lanes.map((g) => g.x + g.w))\n const y = orientation === 'vertical' ? Math.min(0, ...lanes.map((g) => g.y)) : Math.max(0, ...lanes.map((g) => g.y + g.h))\n checkText('The lane description', op.lane.body, LIMITS.body)\n applyOp(draft, { op: 'createGroup', group: {\n ...op.lane, nodeIds: [], x: op.lane.x ?? x, y: op.lane.y ?? y,\n w: op.lane.w ?? (orientation === 'horizontal' ? Math.max(960, ...lanes.map((g) => g.w)) : 400),\n h: op.lane.h ?? (orientation === 'vertical' ? Math.max(720, ...lanes.map((g) => g.h)) : 280),\n } })\n draft.groups = draft.groups.map((g, index) => index === draft.groups.length - 1 ? { ...g, lane: { body: op.lane.body, orientation } } : g)\n return\n }\n case 'updateLane': {\n const current = group(draft, op.id)\n if (!current.lane) fail(`\"${op.id}\" is not a swimlane.`)\n const { body, ...patch } = op.patch\n if (patch.title !== undefined && !patch.title.trim()) fail('A swimlane title cannot be empty.')\n if (body !== undefined) checkText('The lane description', body, LIMITS.body)\n if (Object.values(patch).some((value) => value !== undefined)) applyOp(draft, { op: 'updateGroup', id: op.id, patch })\n else if (body === undefined) fail('The lane update changes nothing.')\n if (body !== undefined) draft.groups = draft.groups.map((g) => g.id === op.id && g.lane ? { ...g, lane: { ...g.lane, body } } : g)\n return\n }\n case 'deleteLane': {\n if (!group(draft, op.id).lane) fail(`\"${op.id}\" is not a swimlane.`)\n applyOp(draft, { op: 'deleteGroup', id: op.id })\n return\n }\n case 'arrangeLanes': {\n const lanes = draft.groups.filter((g) => g.lane).sort((a, b) => (a.lane?.orientation === 'vertical' ? a.x - b.x : a.y - b.y))\n if (lanes.length === 0) fail('There are no swimlanes to arrange.')\n const ids = op.laneIds ?? lanes.map((g) => g.id)\n if (ids.length !== lanes.length || new Set(ids).size !== lanes.length || ids.some((id) => !lanes.some((g) => g.id === id))) {\n fail('laneIds must contain every swimlane id exactly once.')\n }\n const ordered = ids.map((id) => group(draft, id))\n const x = Math.min(...lanes.map((g) => g.x))\n const y = Math.min(...lanes.map((g) => g.y))\n // A lane carries its nodes and any plain group drawn inside it; other lanes are never inside a lane.\n const plainGroups = draft.groups.filter((g) => !g.lane)\n const contents = (g: GroupDef) => {\n const members = membersOf(g, draft.nodes, plainGroups)\n return [...members.nodes, ...members.groups]\n }\n const sized = ordered.map((g) => {\n if (g.lane?.orientation === op.orientation) return g\n const boxes = contents(g)\n return { ...g,\n w: op.orientation === 'horizontal' ? Math.max(960, g.w) : Math.max(400, ...boxes.map((b) => b.x + b.w - g.x + 24)),\n h: op.orientation === 'vertical' ? Math.max(720, g.h) : Math.max(280, ...boxes.map((b) => b.y + b.h - g.y + 24)),\n }\n })\n const width = Math.max(...sized.map((g) => g.w))\n const height = Math.max(...sized.map((g) => g.h))\n let offset = 0\n const positions = new Map(sized.map((g) => {\n const next = { ...g, x: x + (op.orientation === 'vertical' ? offset : 0), y: y + (op.orientation === 'horizontal' ? offset : 0),\n w: op.orientation === 'horizontal' ? width : g.w, h: op.orientation === 'vertical' ? height : g.h,\n lane: { body: g.lane!.body, orientation: op.orientation } }\n offset += op.orientation === 'horizontal' ? next.h : next.w\n return [g.id, next]\n }))\n // Nodes and groups have separate ids, so each kind gets its own map of offsets.\n const nodeMoves = new Map<string, { dx: number; dy: number }>()\n const groupMoves = new Map<string, { dx: number; dy: number }>()\n for (const g of lanes) {\n const next = positions.get(g.id)!\n const move = { dx: next.x - g.x, dy: next.y - g.y }\n const members = membersOf(g, draft.nodes, plainGroups)\n for (const n of members.nodes) if (!nodeMoves.has(n.id)) nodeMoves.set(n.id, move)\n for (const b of members.groups) if (!groupMoves.has(b.id)) groupMoves.set(b.id, move)\n }\n const moved = <T extends { id: string; x: number; y: number }>(moves: Map<string, { dx: number; dy: number }>, b: T): T => {\n const move = moves.get(b.id)\n return move ? { ...b, x: b.x + move.dx, y: b.y + move.dy } : b\n }\n draft.nodes = draft.nodes.map((n) => moved(nodeMoves, n))\n draft.groups = draft.groups.map((g) => positions.get(g.id) ?? moved(groupMoves, g))\n return\n }\n case 'createNode': {\n const { node: spec } = op\n checkText('The title', spec.title, LIMITS.title)\n checkText('The body', spec.body, LIMITS.body)\n if (spec.decisions !== undefined) checkText('The decisions', spec.decisions, LIMITS.body)\n if (spec.systemsDesign) checkAnswers(spec.systemsDesign)\n checkLinks(spec.links)\n if (draft.nodes.length >= LIMITS.maxNodes) fail(`The diagram already has the maximum of ${LIMITS.maxNodes} nodes.`)\n\n const taken = new Set(draft.nodes.map((n) => n.id))\n if (spec.id !== undefined && !ID_PATTERN.test(spec.id)) {\n fail(`\"${spec.id}\" is not a valid id. Use letters, digits, \"-\" and \"_\", starting with a letter or digit.`)\n }\n if (spec.id !== undefined && taken.has(spec.id)) fail(`A node with id \"${spec.id}\" already exists.`)\n const id = spec.id ?? uniqueId(slug(spec.title), taken)\n\n const size = { ...DEFAULT_SIZE }\n let at = spec.x !== undefined && spec.y !== undefined ? { x: spec.x, y: spec.y } : spec.laneId !== undefined ? { x: 0, y: 0 } : place(draft, size)\n if (spec.laneId !== undefined) {\n const lane = group(draft, spec.laneId)\n if (!lane.lane) fail(`\"${spec.laneId}\" is not a swimlane.`)\n const members = membersOf(lane, draft.nodes, []).nodes\n at = {\n x: Math.max(lane.x + 24, spec.x ?? lane.x + 24),\n y: Math.max(lane.y + 96, spec.y ?? Math.max(lane.y + 96, ...members.map((n) => n.y + n.h + 24))),\n }\n draft.groups = draft.groups.map((g) => g.id === lane.id ? { ...g, w: Math.max(g.w, at.x + size.w + 24 - g.x), h: Math.max(g.h, at.y + size.h + 24 - g.y) } : g)\n }\n draft.nodes = [...draft.nodes, { id, title: spec.title, body: spec.body, ...(spec.decisions?.trim() && { decisions: spec.decisions }), ...(spec.systemsDesign && Object.values(spec.systemsDesign).some((v) => v.trim()) && { systemsDesign: Object.fromEntries(Object.entries(spec.systemsDesign).filter(([, v]) => v.trim())) }), ...(spec.links && spec.links.length > 0 && { links: spec.links }), ...(spec.color !== undefined && { color: spec.color }), ...at, ...size }]\n return\n }\n\n case 'updateNode': {\n const current = node(draft, op.id)\n const { title, body, decisions, systemsDesign, links, color, x, y, w, h } = op.patch\n if (Object.values(op.patch).every((v) => v === undefined)) fail(`The update to \"${op.id}\" changes nothing.`)\n if (title !== undefined) checkText('The title', title, LIMITS.title)\n if (body !== undefined) checkText('The body', body, LIMITS.body)\n if (decisions !== undefined) checkText('The decisions', decisions, LIMITS.body)\n if (systemsDesign) checkAnswers(systemsDesign)\n checkLinks(links)\n checkSize(`node \"${op.id}\"`, w, h, MIN_NODE)\n\n const next: NodeDef = { ...current, ...(title !== undefined && { title }), ...(body !== undefined && { body }) }\n if (decisions !== undefined) {\n if (decisions.trim()) next.decisions = decisions\n else delete next.decisions\n }\n if (systemsDesign) {\n const merged = { ...next.systemsDesign, ...systemsDesign }\n for (const [key, value] of Object.entries(merged)) if (!value.trim()) delete merged[key]\n if (Object.keys(merged).length > 0) next.systemsDesign = merged\n else delete next.systemsDesign\n }\n if (links) {\n if (links.length > 0) next.links = links\n else delete next.links\n }\n setColor(next, color)\n Object.assign(next, geometry({ x, y, w, h }))\n draft.nodes = draft.nodes.map((n) => (n.id === op.id ? next : n))\n return\n }\n\n case 'deleteNode': {\n node(draft, op.id)\n draft.nodes = draft.nodes.filter((n) => n.id !== op.id)\n // Its edges go with it.\n draft.edges = draft.edges.filter((e) => e.from !== op.id && e.to !== op.id)\n return\n }\n\n case 'createGroup': {\n const { group: spec } = op\n checkText('The title', spec.title, LIMITS.title)\n if (draft.groups.length >= LIMITS.maxGroups) fail(`The diagram already has the maximum of ${LIMITS.maxGroups} groups.`)\n const members = [...new Set(spec.nodeIds.map((ref) => nodeRef(draft, ref).id))].map((id) => node(draft, id))\n if (members.length === 0 && (spec.x === undefined || spec.y === undefined)) fail('A group needs nodes to go around, or a position (x and y) for an empty box.')\n checkSize('group', spec.w, spec.h, MIN_GROUP)\n const taken = new Set(draft.groups.map((g) => g.id))\n if (spec.id !== undefined && !ID_PATTERN.test(spec.id)) fail(`\"${spec.id}\" is not a valid id.`)\n if (spec.id !== undefined && taken.has(spec.id)) fail(`A group with id \"${spec.id}\" already exists.`)\n const id = spec.id ?? uniqueId(slug(spec.title), taken)\n\n if (members.length === 0) {\n draft.groups = [\n ...draft.groups,\n { id, title: spec.title, ...(spec.color !== undefined && { color: spec.color }), x: spec.x!, y: spec.y!, w: spec.w ?? EMPTY_GROUP.w, h: spec.h ?? EMPTY_GROUP.h },\n ]\n return\n }\n\n // The box is drawn around its nodes; moving nodes later does not move it.\n const left = Math.min(...members.map((n) => n.x)) - GROUP_PADDING\n const top = Math.min(...members.map((n) => n.y)) - GROUP_TITLE_SPACE\n const right = Math.max(...members.map((n) => n.x + n.w)) + GROUP_PADDING\n const bottom = Math.max(...members.map((n) => n.y + n.h)) + GROUP_PADDING\n draft.groups = [\n ...draft.groups,\n { id, title: spec.title, ...(spec.color !== undefined && { color: spec.color }), x: left, y: top, w: right - left, h: bottom - top },\n ]\n return\n }\n\n case 'updateGroup': {\n const current = group(draft, op.id)\n const { title, color, x, y, w, h } = op.patch\n if (Object.values(op.patch).every((v) => v === undefined)) fail(`The update to group \"${op.id}\" changes nothing.`)\n if (title !== undefined) checkText('The title', title, LIMITS.title)\n checkSize(`group \"${op.id}\"`, w, h, MIN_GROUP)\n\n // Changing only the position moves the group: what is inside it goes along. Giving a size resizes the box alone.\n const dx = w === undefined && h === undefined && x !== undefined ? x - current.x : 0\n const dy = w === undefined && h === undefined && y !== undefined ? y - current.y : 0\n const carried = dx !== 0 || dy !== 0 ? membersOf(current, draft.nodes, draft.groups) : { nodes: [], groups: [] }\n const carriedNodes = new Set(carried.nodes.map((n) => n.id))\n const carriedGroups = new Set(carried.groups.map((g) => g.id))\n draft.nodes = draft.nodes.map((n) => (carriedNodes.has(n.id) ? { ...n, x: n.x + dx, y: n.y + dy } : n))\n draft.groups = draft.groups.map((g) => {\n if (g.id === current.id) {\n const next = { ...g, ...(title !== undefined && { title }), ...geometry({ x, y, w, h }) }\n setColor(next, color)\n return next\n }\n return carriedGroups.has(g.id) ? { ...g, x: g.x + dx, y: g.y + dy } : g\n })\n return\n }\n\n case 'deleteGroup': {\n group(draft, op.id)\n draft.groups = draft.groups.filter((g) => g.id !== op.id)\n return\n }\n\n case 'createEdge': {\n const { edge: spec } = op\n checkText('The label', spec.label, LIMITS.label)\n if (draft.edges.length >= LIMITS.maxEdges) fail(`The diagram already has the maximum of ${LIMITS.maxEdges} edges.`)\n // Ends may be named by id or by title, so an edge can follow the nodes created earlier in the same batch.\n const from = nodeRef(draft, spec.from).id\n const to = nodeRef(draft, spec.to).id\n if (from === to) fail('An edge cannot start and end at the same node.')\n if (draft.edges.some((e) => e.from === from && e.to === to && e.label === spec.label)) {\n fail(`There is already an edge from \"${from}\" to \"${to}\" labelled \"${spec.label}\".`)\n }\n\n const taken = new Set(draft.edges.map((e) => e.id))\n if (spec.id !== undefined && !ID_PATTERN.test(spec.id)) fail(`\"${spec.id}\" is not a valid id.`)\n if (spec.id !== undefined && taken.has(spec.id)) fail(`An edge with id \"${spec.id}\" already exists.`)\n const id = spec.id ?? uniqueId(`${slug(from)}-${slug(to)}`, taken)\n\n draft.edges = [\n ...draft.edges,\n {\n id,\n from,\n to,\n label: spec.label,\n ...(spec.dashed !== undefined && { dashed: spec.dashed }),\n ...(spec.optional !== undefined && { optional: spec.optional }),\n ...(spec.color !== undefined && { color: spec.color }),\n },\n ]\n return\n }\n\n case 'updateEdge': {\n const current = edge(draft, op.id)\n const { label, dashed, optional, color } = op.patch\n if (Object.values(op.patch).every((v) => v === undefined)) fail(`The update to \"${op.id}\" changes nothing.`)\n if (label !== undefined) checkText('The label', label, LIMITS.label)\n draft.edges = draft.edges.map((e) => {\n if (e.id !== current.id) return e\n const next = { ...e, ...(label !== undefined && { label }), ...(dashed !== undefined && { dashed }), ...(optional !== undefined && { optional }) }\n setColor(next, color)\n return next\n })\n return\n }\n\n case 'deleteEdge': {\n edge(draft, op.id)\n draft.edges = draft.edges.filter((e) => e.id !== op.id)\n return\n }\n }\n}\n\n// Applies the operations in order to a copy. If any one is invalid, nothing is applied and the\n// reason names the operation, so the model can fix that one and try again.\nexport function planChanges(snapshot: Snapshot, ops: DiagramOp[]): PlanResult {\n const draft: Snapshot = { nodes: [...snapshot.nodes], edges: [...snapshot.edges], groups: [...snapshot.groups] }\n\n for (let i = 0; i < ops.length; i++) {\n try {\n applyOp(draft, ops[i])\n } catch (error) {\n if (error instanceof PlanError) return { ok: false, message: `Change ${i + 1} (${ops[i].op}): ${error.message}`, opIndex: i }\n throw error\n }\n }\n\n const patch = diffSnapshots(snapshot, draft)\n return { ok: true, next: draft, patch, inverse: diffSnapshots(draft, snapshot), applied: ops.length }\n}\n","import { MIN_GROUP, MIN_NODE } from './plan'\n\nexport type Handle = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw'\nexport type EditMode = 'move' | Handle\nexport type EditKind = 'node' | 'group'\n\nexport interface Rect {\n x: number\n y: number\n w: number\n h: number\n}\n\nexport const HANDLES: Handle[] = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w']\n\nexport const minSize = (kind: EditKind) => (kind === 'node' ? MIN_NODE : MIN_GROUP)\n\n// The rectangle after dragging by (dx, dy) world units. A resize never goes below the minimum,\n// and the edge opposite the one being dragged stays where it is.\nexport function dragRect(start: Rect, mode: EditMode, dx: number, dy: number, min: { w: number; h: number }): Rect {\n if (mode === 'move') return { ...start, x: Math.round(start.x + dx), y: Math.round(start.y + dy) }\n\n let { x, y, w, h } = start\n if (mode.includes('e')) w = Math.max(min.w, start.w + dx)\n if (mode.includes('w')) {\n w = Math.max(min.w, start.w - dx)\n x = start.x + start.w - w\n }\n if (mode.includes('s')) h = Math.max(min.h, start.h + dy)\n if (mode.includes('n')) {\n h = Math.max(min.h, start.h - dy)\n y = start.y + start.h - h\n }\n return { x: Math.round(x), y: Math.round(y), w: Math.round(w), h: Math.round(h) }\n}\n\n// Only what differs, so the change touches nothing it does not have to.\nexport function rectPatch(before: Rect, after: Rect): Partial<Rect> {\n const patch: Partial<Rect> = {}\n for (const key of ['x', 'y', 'w', 'h'] as const) if (before[key] !== after[key]) patch[key] = after[key]\n return patch\n}\n","import type { Bounds, EdgeDef, GroupDef, NodeDef } from './types'\n\nexport interface EdgeGeometry {\n d: string\n lx: number\n ly: number\n}\n\nfunction cubicAt(t: number, p0: number, p1: number, p2: number, p3: number) {\n const u = 1 - t\n return u * u * u * p0 + 3 * u * u * t * p1 + 3 * u * t * t * p2 + t * t * t * p3\n}\n\n// Right edge to left edge when the target is in a later column, the reverse for\n// earlier columns, and a bulge out the right side when both nodes share a column.\nexport function edgeGeometry(a: NodeDef, b: NodeDef): EdgeGeometry {\n const y1 = a.y + a.h / 2\n const y2 = b.y + b.h / 2\n let x1: number, x2: number, c1x: number, c2x: number\n\n if (b.x > a.x + a.w - 1) {\n x1 = a.x + a.w\n x2 = b.x\n const dx = Math.max(60, (x2 - x1) / 2)\n c1x = x1 + dx\n c2x = x2 - dx\n } else if (b.x + b.w < a.x + 1) {\n x1 = a.x\n x2 = b.x + b.w\n const dx = Math.max(60, (x1 - x2) / 2)\n c1x = x1 - dx\n c2x = x2 + dx\n } else {\n x1 = a.x + a.w\n x2 = b.x + b.w\n c1x = x1 + 90\n c2x = x2 + 90\n }\n\n return {\n d: `M ${x1} ${y1} C ${c1x} ${y1}, ${c2x} ${y2}, ${x2} ${y2}`,\n lx: cubicAt(0.5, x1, c1x, c2x, x2),\n ly: cubicAt(0.5, y1, y1, y2, y2),\n }\n}\n\nexport function labelWidth(edge: EdgeDef) {\n return edge.label.length * 6.2 + 16\n}\n\n// The area the diagram covers: groups are optional, so nodes count too.\nexport function diagramBounds(groups: GroupDef[], nodes: NodeDef[]): Bounds {\n return [...groups, ...nodes].reduce(\n (acc, g) => ({ w: Math.max(acc.w, g.x + g.w), h: Math.max(acc.h, g.y + g.h) }),\n { w: 0, h: 0 },\n )\n}\n","import { z } from 'zod'\nimport { colorSchema } from './colors'\nimport { linkSchema, orientationSchema } from './format'\n\n// The operations that change a diagram: the one vocabulary for people and for agents. A batch of them is planned (plan.ts), applied\n// as a whole or not at all, and answered with the exact inverse. The descriptions are what a model reads.\n\nconst colorHelp = 'A colour: a name (red, orange, yellow, green, teal, blue, purple, pink, gray), which follows the light or dark theme, or a fixed #rrggbb. Leave out for the default.'\n// In an update, null takes the colour off.\nconst colorPatch = colorSchema.nullable().optional().describe(`${colorHelp} null removes it.`)\n\nconst decisionsHelp = 'Optional Markdown decision log for this node, kept apart from the body: why this was chosen (for example Lambda over Fargate, ECS or Kubernetes) and the alternatives and trade-offs that were considered. Leave out when there is nothing to record.'\n\nconst systemsDesignHelp = 'Optional answers to the Systems design questions, as an object of question id to a short answer. Ids: client, server, size, frequency, latency, retention, connection, capacity, consistency, protocol, errors, security, telemetry. An answer is at most 200 characters.'\n\nconst linksHelp = 'Optional code this node describes: a list of { repo?, path, symbol?, lines?: [from, to], hash? }. repo is a repo id from the project workspace (omit it for the default repo) and path is relative to that repo, or to the project root when the project has no repos. Every repo in the workspace has a GitHub remote, so a link can open on GitHub; a repo id the workspace does not list is refused; hash is the first 12 characters of the SHA-256 of the linked lines, taken now, so a later check can tell the code changed. At most 20 per node.'\n\nconst nodeDraft = z.object({\n id: z.string().optional().describe('Leave out to have one generated.'),\n title: z.string().min(1),\n color: colorSchema.optional().describe(colorHelp),\n body: z.string().describe('Markdown.'),\n decisions: z.string().optional().describe(decisionsHelp),\n systemsDesign: z.record(z.string(), z.string()).optional().describe(systemsDesignHelp),\n links: z.array(linkSchema).optional().describe(linksHelp),\n x: z.number().optional(),\n y: z.number().optional(),\n laneId: z.string().optional().describe('Place this node inside this swimlane, expanding the lane if needed.'),\n})\n\n// Position and size on the canvas. Nodes may not be smaller than 160x80 and groups not smaller than 120x80.\n// Giving a group only x and/or y moves it together with the nodes (and groups) drawn inside it; giving w or h resizes the box alone.\nconst geometryPatch = { x: z.number().optional(), y: z.number().optional(), w: z.number().positive().optional(), h: z.number().positive().optional() }\n\nexport const diagramOpSchema = z.discriminatedUnion('op', [\n z.object({\n op: z.literal('createLane'),\n lane: z.object({\n id: z.string().optional(),\n title: z.string().min(1),\n body: z.string().default(''),\n orientation: orientationSchema.optional(),\n color: colorSchema.optional(),\n ...geometryPatch,\n }),\n }),\n z.object({\n op: z.literal('updateLane'), id: z.string(),\n patch: z.object({ title: z.string().min(1).optional(), body: z.string().optional(), color: colorPatch, ...geometryPatch }),\n }),\n z.object({ op: z.literal('deleteLane'), id: z.string() }),\n z.object({\n op: z.literal('arrangeLanes'),\n orientation: orientationSchema,\n laneIds: z.array(z.string()).optional().describe('Every lane id exactly once, in the desired order. Omit to keep the current spatial order.'),\n }),\n z.object({ op: z.literal('createNode'), node: nodeDraft }),\n z.object({\n op: z.literal('updateNode'),\n id: z.string(),\n patch: z.object({\n title: z.string().min(1).optional(),\n body: z.string().optional(),\n decisions: z.string().optional().describe(`${decisionsHelp} An empty string removes the decision log.`),\n systemsDesign: z.record(z.string(), z.string()).optional().describe(`${systemsDesignHelp} Only the ids given change; an empty string clears that answer.`),\n links: z.array(linkSchema).optional().describe(`${linksHelp} Replaces the node's whole list; [] removes every link.`),\n color: colorPatch,\n ...geometryPatch,\n }),\n }),\n z.object({ op: z.literal('deleteNode'), id: z.string() }),\n z.object({\n op: z.literal('createEdge'),\n edge: z.object({\n id: z.string().optional(),\n from: z.string().describe('A node id, or the title of a node (including one created earlier in this same batch).'),\n to: z.string().describe('A node id, or the title of a node (including one created earlier in this same batch).'),\n label: z.string(),\n dashed: z.boolean().optional(),\n optional: z.boolean().optional(),\n color: colorSchema.optional().describe(colorHelp),\n }),\n }),\n z.object({\n op: z.literal('updateEdge'),\n id: z.string(),\n patch: z.object({ label: z.string().optional(), dashed: z.boolean().optional(), optional: z.boolean().optional(), color: colorPatch }),\n }),\n z.object({ op: z.literal('deleteEdge'), id: z.string() }),\n z.object({\n op: z.literal('createGroup'),\n group: z.object({\n id: z.string().optional().describe('Leave out to have one generated.'),\n title: z.string().min(1),\n nodeIds: z.array(z.string()).default([]).describe('The nodes to draw a labelled box around, by id or by title. Leave empty for an empty box at x, y.'),\n color: colorSchema.optional().describe(colorHelp),\n ...geometryPatch,\n }),\n }),\n z.object({ op: z.literal('updateGroup'), id: z.string(), patch: z.object({ title: z.string().min(1).optional(), color: colorPatch, ...geometryPatch }) }),\n z.object({ op: z.literal('deleteGroup'), id: z.string() }),\n])\n\n\nexport type DiagramOp = z.infer<typeof diagramOpSchema>\n","import { createStore } from 'zustand/vanilla'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { DIAGRAM_SCHEMA_VERSION } from './format'\nimport type { DiagramOp } from './ops'\nimport { applyPatch, diffSnapshots, isEmptyPatch, planChanges } from './plan'\nimport type { Patch, Snapshot } from './plan'\nimport type { DiagramData, DiagramFile, EdgeDef, GroupDef, NodeDef } from './types'\n\n// The diagram's state and the one way to change it. A host (the Glyph app, another app, a test, a server) gets a controller, reads\n// from it, and changes it only through `apply`: so a mouse, a keyboard shortcut and an AI agent all take the same path, and all get the\n// same checks and the same exact inverse. The controller has no UI and no storage and keeps no history: a host that wants undo keeps the\n// `inverse` of each change (`onChange`) and sends it back with `applyPatch`.\n\nexport interface NodeState {\n byId: Record<string, NodeDef>\n ids: string[]\n setNodes: (nodes: NodeDef[]) => void\n addNode: (node: NodeDef) => void\n updateNode: (id: string, patch: Partial<Omit<NodeDef, 'id'>>) => void\n removeNode: (id: string) => void\n}\n\nexport interface EdgeState {\n byId: Record<string, EdgeDef>\n ids: string[]\n setEdges: (edges: EdgeDef[]) => void\n addEdge: (edge: EdgeDef) => void\n updateEdge: (id: string, patch: Partial<Omit<EdgeDef, 'id'>>) => void\n removeEdge: (id: string) => void\n // Returns the removed edge ids so callers can clear a stale selection.\n removeEdgesOfNode: (nodeId: string) => string[]\n}\n\nexport interface GroupState {\n byId: Record<string, GroupDef>\n ids: string[]\n setGroups: (groups: GroupDef[]) => void\n addGroup: (group: GroupDef) => void\n updateGroup: (id: string, patch: Partial<Omit<GroupDef, 'id'>>) => void\n removeGroup: (id: string) => void\n}\n\n// What the diagram is, apart from its contents. The revision counts accepted changes (an undo counts too), so an agent, and any proposal it\n// makes, can tell whether the diagram has moved on since it looked.\nexport interface MetaState {\n name: string\n description?: string\n type?: DiagramFile['type']\n revision: number\n setMeta: (meta: { name: string; description?: string; type?: DiagramFile['type']; revision?: number }) => void\n bumpRevision: () => number\n}\n\n// The stores a renderer subscribes to, one per kind so a component re-renders only for the kind it shows. A change from outside goes through\n// `apply`; writing to a store directly is only for a live preview that is rolled back (a drag in progress).\nexport interface DiagramStores {\n nodes: StoreApi<NodeState>\n edges: StoreApi<EdgeState>\n groups: StoreApi<GroupState>\n meta: StoreApi<MetaState>\n}\n\nexport interface DiagramSnapshot extends Snapshot {\n name: string\n description?: string\n type?: DiagramFile['type']\n revision: number\n}\n\nexport interface ApplyRequest {\n ops: DiagramOp[]\n // A short description, for a history list or an approval card.\n summary: string\n // Who made the change: 'user', 'agent', or anything the host tells apart.\n source: string\n // The revision the author looked at. A mismatch means the diagram moved on and nothing is applied.\n expectedRevision?: number\n // The host's own id for the change (a tool call id, say); one is made when it is left out.\n id?: string\n}\n\nexport type ApplyResult =\n | {\n ok: true\n revision: number\n // How many operations were in the batch.\n applied: number\n // False when the batch changed nothing (the revision did not move and no event was sent).\n changed: boolean\n patch: Patch\n // What undoes it exactly: only the things it touched. Send it to `applyPatch`.\n inverse: Patch\n }\n | { ok: false; error: 'stale-revision' | 'invalid'; message: string; currentRevision: number }\n\nexport interface ChangeEvent {\n id: string\n revision: number\n summary: string\n source: string\n at: number\n patch: Patch\n inverse: Patch\n}\n\nexport interface DiagramController {\n readonly stores: DiagramStores\n // The whole diagram as plain data. The same object is returned until something changes, so it works with React's useSyncExternalStore.\n getSnapshot(): DiagramSnapshot\n // Called once after each change or load (not once per store write).\n subscribe(listener: () => void): () => void\n // The one way to change a diagram. A batch is applied as a whole or not at all, and moves the revision once.\n apply(request: ApplyRequest): ApplyResult\n // Applies a patch the host kept (an inverse, for undo) as a change of its own: the revision moves on.\n applyPatch(patch: Patch, meta: { summary: string; source: string; id?: string }): ApplyResult\n // Called for each accepted change that changed something, with what a history, an autosave or an approval list needs.\n onChange(listener: (event: ChangeEvent) => void): () => void\n // Called after a whole diagram is put in (a different one is shown).\n onLoad(listener: () => void): () => void\n // Replaces the contents. Not a change: it has no inverse and sends no ChangeEvent.\n load(diagram: DiagramData & { name?: string; description?: string }, revision?: number): void\n // The diagram as a file; pass it to serializeDiagram() to save it.\n export(meta?: { name?: string; description?: string; schemaVersion?: number }): DiagramFile\n // Runs several store writes and tells subscribers once, afterwards.\n batch(fn: () => void): void\n}\n\nfunction collection<T extends { id: string }>(set: (partial: Partial<{ byId: Record<string, T>; ids: string[] }>) => void) {\n return {\n replace: (items: T[]) => set({ byId: Object.fromEntries(items.map((i) => [i.id, i])), ids: items.map((i) => i.id) }),\n }\n}\n\nfunction makeStores(): DiagramStores {\n const nodes = createStore<NodeState>()((set) => ({\n byId: {},\n ids: [],\n setNodes: (items) => collection<NodeDef>(set).replace(items),\n addNode: (node) =>\n set((s) => ({\n byId: { ...s.byId, [node.id]: node },\n ids: s.ids.includes(node.id) ? s.ids : [...s.ids, node.id],\n })),\n updateNode: (id, patch) =>\n set((s) => {\n const current = s.byId[id]\n if (!current) return s\n return { byId: { ...s.byId, [id]: { ...current, ...patch } } }\n }),\n removeNode: (id) =>\n set((s) => {\n if (!s.byId[id]) return s\n const { [id]: _removed, ...byId } = s.byId\n return { byId, ids: s.ids.filter((i) => i !== id) }\n }),\n }))\n\n const edges = createStore<EdgeState>()((set, get) => ({\n byId: {},\n ids: [],\n setEdges: (items) => collection<EdgeDef>(set).replace(items),\n addEdge: (edge) =>\n set((s) => ({\n byId: { ...s.byId, [edge.id]: edge },\n ids: s.ids.includes(edge.id) ? s.ids : [...s.ids, edge.id],\n })),\n updateEdge: (id, patch) =>\n set((s) => {\n const current = s.byId[id]\n if (!current) return s\n return { byId: { ...s.byId, [id]: { ...current, ...patch } } }\n }),\n removeEdge: (id) =>\n set((s) => {\n if (!s.byId[id]) return s\n const { [id]: _removed, ...byId } = s.byId\n return { byId, ids: s.ids.filter((i) => i !== id) }\n }),\n removeEdgesOfNode: (nodeId) => {\n const { byId, ids } = get()\n const removed = ids.filter((id) => byId[id].from === nodeId || byId[id].to === nodeId)\n if (removed.length === 0) return removed\n const drop = new Set(removed)\n set({\n byId: Object.fromEntries(Object.entries(byId).filter(([id]) => !drop.has(id))),\n ids: ids.filter((id) => !drop.has(id)),\n })\n return removed\n },\n }))\n\n const groups = createStore<GroupState>()((set) => ({\n byId: {},\n ids: [],\n setGroups: (items) => collection<GroupDef>(set).replace(items),\n addGroup: (group) =>\n set((s) => ({\n byId: { ...s.byId, [group.id]: group },\n ids: s.ids.includes(group.id) ? s.ids : [...s.ids, group.id],\n })),\n updateGroup: (id, patch) =>\n set((s) => {\n const current = s.byId[id]\n if (!current) return s\n return { byId: { ...s.byId, [id]: { ...current, ...patch } } }\n }),\n removeGroup: (id) =>\n set((s) => {\n if (!s.byId[id]) return s\n const { [id]: _removed, ...byId } = s.byId\n return { byId, ids: s.ids.filter((i) => i !== id) }\n }),\n }))\n\n const meta = createStore<MetaState>()((set, get) => ({\n name: 'Untitled diagram',\n description: undefined,\n revision: 0,\n setMeta: ({ name, description, type, revision = 0 }) => set({ name, description, type, revision }),\n bumpRevision: () => {\n const next = get().revision + 1\n set({ revision: next })\n return next\n },\n }))\n\n return { nodes, edges, groups, meta }\n}\n\nlet counter = 1\n\nexport function createDiagramController(initial?: DiagramData & { name?: string; description?: string; revision?: number }): DiagramController {\n const stores = makeStores()\n const listeners = new Set<() => void>()\n const changeListeners = new Set<(event: ChangeEvent) => void>()\n const loadListeners = new Set<() => void>()\n\n let snapshot: DiagramSnapshot | null = null\n let depth = 0\n let dirty = false\n const notify = () => {\n for (const listener of [...listeners]) listener()\n }\n // Any write to any store (a commit, a load, or a live preview) ends up here.\n const touched = () => {\n snapshot = null\n if (depth > 0) dirty = true\n else notify()\n }\n for (const store of [stores.nodes, stores.edges, stores.groups, stores.meta]) (store as StoreApi<unknown>).subscribe(touched)\n\n const batch = (fn: () => void) => {\n depth++\n try {\n fn()\n } finally {\n depth--\n if (depth === 0 && dirty) {\n dirty = false\n notify()\n }\n }\n }\n\n const getSnapshot = (): DiagramSnapshot => {\n if (snapshot) return snapshot\n const nodes = stores.nodes.getState()\n const edges = stores.edges.getState()\n const groups = stores.groups.getState()\n const meta = stores.meta.getState()\n snapshot = {\n name: meta.name,\n description: meta.description,\n ...(meta.type && { type: meta.type }),\n revision: meta.revision,\n nodes: nodes.ids.map((id) => nodes.byId[id]),\n edges: edges.ids.map((id) => edges.byId[id]),\n groups: groups.ids.map((id) => groups.byId[id]),\n }\n return snapshot\n }\n\n // Positions of things a change did not touch are whatever they are now: the snapshot was just read from the stores.\n const commit = (next: Snapshot) => {\n batch(() => {\n stores.groups.getState().setGroups(next.groups)\n stores.nodes.getState().setNodes(next.nodes)\n stores.edges.getState().setEdges(next.edges)\n })\n }\n\n const empty: Patch = { nodes: { upsert: [], remove: [] }, edges: { upsert: [], remove: [] }, groups: { upsert: [], remove: [] } }\n\n const run = (planned: ReturnType<typeof planChanges>, request: { summary: string; source: string; id?: string }, applied: number): ApplyResult => {\n const currentRevision = stores.meta.getState().revision\n if (!planned.ok) return { ok: false, error: 'invalid', message: planned.message, currentRevision }\n // A batch that changes nothing is not a change.\n if (isEmptyPatch(planned.patch)) return { ok: true, revision: currentRevision, applied, changed: false, patch: empty, inverse: empty }\n\n let revision = currentRevision\n batch(() => {\n commit(planned.next)\n revision = stores.meta.getState().bumpRevision()\n })\n const event: ChangeEvent = {\n id: request.id ?? `change-${Date.now().toString(36)}-${counter++}`,\n revision,\n summary: request.summary,\n source: request.source,\n at: Date.now(),\n patch: planned.patch,\n inverse: planned.inverse,\n }\n for (const listener of [...changeListeners]) listener(event)\n return { ok: true, revision, applied, changed: true, patch: planned.patch, inverse: planned.inverse }\n }\n\n const controller: DiagramController = {\n stores,\n getSnapshot,\n subscribe(listener) {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n },\n apply(request) {\n const meta = stores.meta.getState()\n if (request.expectedRevision !== undefined && request.expectedRevision !== meta.revision) {\n return {\n ok: false,\n error: 'stale-revision',\n message: `The diagram is at revision ${meta.revision}, but this change was made against revision ${request.expectedRevision}. Read it again and retry.`,\n currentRevision: meta.revision,\n }\n }\n return run(planChanges(getSnapshot(), request.ops), request, request.ops.length)\n },\n applyPatch(patch, meta) {\n const before = getSnapshot()\n const next = applyPatch(before, patch)\n // What undoes this exactly is what turns the result back into what it was.\n return run({ ok: true, next, patch, inverse: diffSnapshots(next, before), applied: 1 }, meta, 1)\n },\n onChange(listener) {\n changeListeners.add(listener)\n return () => void changeListeners.delete(listener)\n },\n onLoad(listener) {\n loadListeners.add(listener)\n return () => void loadListeners.delete(listener)\n },\n load(diagram, revision = 0) {\n batch(() => {\n // The revision and type always come from what is loaded; a diagram without a name keeps the current one.\n const meta = stores.meta.getState()\n meta.setMeta({ name: diagram.name || meta.name, description: diagram.description, type: diagram.type, revision })\n stores.groups.getState().setGroups(diagram.groups)\n stores.nodes.getState().setNodes(diagram.nodes)\n stores.edges.getState().setEdges(diagram.edges)\n })\n for (const listener of [...loadListeners]) listener()\n },\n export(meta) {\n const snap = getSnapshot()\n return {\n schemaVersion: (meta?.schemaVersion ?? DIAGRAM_SCHEMA_VERSION) as DiagramFile['schemaVersion'],\n name: meta?.name ?? snap.name,\n ...(snap.type && { type: snap.type }),\n ...((meta?.description ?? snap.description) !== undefined && { description: meta?.description ?? snap.description }),\n groups: snap.groups,\n nodes: snap.nodes,\n edges: snap.edges,\n }\n },\n batch,\n }\n\n if (initial) controller.load(initial, initial.revision ?? 0)\n return controller\n}\n","import type { DiagramController } from './controller'\nimport { readDiagram } from './format'\nimport type { DiagramFile } from './types'\nimport { describeVersionError } from './versioning'\n\n// Where a diagram comes from and goes to. The host supplies one of these; the controller never knows which: memory, the browser's\n// storage, a database, a REST service. A diagram is kept as the versioned file (see format.ts) with the revision it was saved at.\n\nexport interface StoredDiagram {\n file: DiagramFile\n revision: number\n}\n\nexport interface SaveMeta {\n // The revision this save is.\n revision: number\n // The revision the author last loaded or saved: null for a diagram that was never saved. A repository refuses the save when the stored\n // one is different, so a save never overwrites somebody else's work unseen.\n baseRevision: number | null\n}\n\nexport interface DiagramRepository {\n // null when there is no diagram with that id.\n load(id: string): Promise<StoredDiagram | null>\n // Rejects with a RepositoryConflictError when baseRevision is not the stored revision.\n save(id: string, file: DiagramFile, meta: SaveMeta): Promise<void>\n // Optional: tells the host when someone else changes the diagram (a live or shared source). Returns how to stop.\n subscribe?(id: string, onRemoteChange: (stored: StoredDiagram) => void): () => void\n}\n\nexport class RepositoryConflictError extends Error {\n readonly storedRevision: number | null\n constructor(id: string, storedRevision: number | null) {\n super(`“${id}” was changed somewhere else (it is at revision ${storedRevision ?? 'none'}). Load it again before saving.`)\n this.name = 'RepositoryConflictError'\n this.storedRevision = storedRevision\n }\n}\n\nconst conflicts = (stored: number | null, base: number | null) => stored !== base\n\n// ---- adapters ----\n\n// Kept in memory: tests, demos, and hosts that save somewhere else themselves.\nexport function memoryRepository(initial: Record<string, StoredDiagram> = {}): DiagramRepository {\n const kept = new Map(Object.entries(initial).map(([id, stored]) => [id, structuredClone(stored)]))\n return {\n async load(id) {\n const stored = kept.get(id)\n return stored ? structuredClone(stored) : null\n },\n async save(id, file, meta) {\n const stored = kept.get(id)?.revision ?? null\n if (conflicts(stored, meta.baseRevision)) throw new RepositoryConflictError(id, stored)\n kept.set(id, structuredClone({ file, revision: meta.revision }))\n },\n }\n}\n\n// Kept in a Storage (the browser's localStorage, or anything shaped like it).\nexport function storageRepository(storage: Pick<Storage, 'getItem' | 'setItem'>, prefix = 'diagram:'): DiagramRepository {\n return {\n async load(id) {\n const raw = storage.getItem(prefix + id)\n if (raw === null) return null\n let parsed: { file?: unknown; revision?: unknown }\n try {\n parsed = JSON.parse(raw) as typeof parsed\n } catch {\n throw new Error(`The saved diagram “${id}” is damaged.`)\n }\n const read = readDiagram(parsed.file)\n if (!read.ok) throw new Error(`The saved diagram “${id}” could not be read: ${describeVersionError(read.error)}`)\n return { file: read.value, revision: typeof parsed.revision === 'number' ? parsed.revision : 0 }\n },\n async save(id, file, meta) {\n const raw = storage.getItem(prefix + id)\n let stored: number | null = null\n if (raw !== null) {\n try {\n const revision = (JSON.parse(raw) as { revision?: unknown }).revision\n stored = typeof revision === 'number' ? revision : 0\n } catch {\n stored = null\n }\n }\n if (conflicts(stored, meta.baseRevision)) throw new RepositoryConflictError(id, stored)\n storage.setItem(prefix + id, JSON.stringify({ file, revision: meta.revision }))\n },\n }\n}\n\n// Kept by a REST service: GET {base}/{id} answers 200 with {file, revision} or 404, and PUT {base}/{id} takes {file, revision, baseRevision} and\n// answers 409 when baseRevision is not the stored one.\nexport function httpRepository(options: { baseUrl: string; fetch?: typeof fetch; headers?: Record<string, string> }): DiagramRepository {\n const call = options.fetch ?? ((...args: Parameters<typeof fetch>) => fetch(...args))\n const url = (id: string) => `${options.baseUrl.replace(/\\/+$/, '')}/${encodeURIComponent(id)}`\n return {\n async load(id) {\n const response = await call(url(id), { headers: { accept: 'application/json', ...options.headers } })\n if (response.status === 404) return null\n if (!response.ok) throw new Error(`Could not load “${id}” (${response.status}).`)\n const body = (await response.json()) as { file?: unknown; revision?: unknown }\n const read = readDiagram(body.file)\n if (!read.ok) throw new Error(`“${id}” could not be read: ${describeVersionError(read.error)}`)\n return { file: read.value, revision: typeof body.revision === 'number' ? body.revision : 0 }\n },\n async save(id, file, meta) {\n const response = await call(url(id), {\n method: 'PUT',\n headers: { 'content-type': 'application/json', ...options.headers },\n body: JSON.stringify({ file, revision: meta.revision, baseRevision: meta.baseRevision }),\n })\n if (response.status === 409) {\n const body = (await response.json().catch(() => ({}))) as { revision?: unknown }\n throw new RepositoryConflictError(id, typeof body.revision === 'number' ? body.revision : null)\n }\n if (!response.ok) throw new Error(`Could not save “${id}” (${response.status}).`)\n },\n }\n}\n\n// ---- binding a controller to a repository ----\n\nexport interface Binding {\n // Puts the stored diagram into the controller (false when there is none). Also what resumes saving after a conflict.\n load(): Promise<boolean>\n // Saves now if there is anything unsaved, and resolves when it is done: true when everything is saved (or there was nothing to save), false\n // when the save failed or met somebody else's change.\n flush(): Promise<boolean>\n dispose(): void\n}\n\nexport interface BindOptions {\n id: string\n // How long after a change to wait before saving, so a burst of changes is one save.\n debounceMs?: number\n // A save or a load failed. Saving is tried again at the next change.\n onError?: (error: Error) => void\n // The stored diagram changed somewhere else. Saving stops until `load()` is called.\n onConflict?: (error: RepositoryConflictError) => void\n}\n\n// Loads a diagram into a controller and keeps it saved: each accepted change schedules a save (a burst is one), saves run one at a time,\n// and a save that meets somebody else's change stops instead of overwriting it.\nexport function bindRepository(controller: DiagramController, repository: DiagramRepository, options: BindOptions): Binding {\n const { id, debounceMs = 300 } = options\n let baseRevision: number | null = null\n let timer: ReturnType<typeof setTimeout> | undefined\n let unsaved = false\n let stopped = false\n let chain: Promise<unknown> = Promise.resolve()\n\n const save = (): Promise<boolean> => {\n const step = chain.then(async () => {\n if (stopped) return false\n if (!unsaved) return true\n unsaved = false\n const revision = controller.getSnapshot().revision\n try {\n await repository.save(id, controller.export(), { revision, baseRevision })\n baseRevision = revision\n return true\n } catch (error) {\n unsaved = true\n if (error instanceof RepositoryConflictError) {\n stopped = true\n options.onConflict?.(error)\n } else options.onError?.(error instanceof Error ? error : new Error(String(error)))\n return false\n }\n })\n chain = step\n return step\n }\n\n const schedule = () => {\n unsaved = true\n if (timer) clearTimeout(timer)\n timer = setTimeout(() => void save(), debounceMs)\n }\n\n const off = controller.onChange(schedule)\n const offRemote = repository.subscribe?.(id, (stored) => {\n controller.load(stored.file, stored.revision)\n baseRevision = stored.revision\n unsaved = false\n })\n\n return {\n async load() {\n try {\n const stored = await repository.load(id)\n if (!stored) {\n baseRevision = null\n stopped = false\n return false\n }\n controller.load(stored.file, stored.revision)\n baseRevision = stored.revision\n unsaved = false\n stopped = false\n return true\n } catch (error) {\n options.onError?.(error instanceof Error ? error : new Error(String(error)))\n return false\n }\n },\n async flush() {\n if (timer) clearTimeout(timer)\n timer = undefined\n return save()\n },\n dispose() {\n if (timer) clearTimeout(timer)\n off()\n offRemote?.()\n },\n }\n}\n","// Visual emphasis a diagram can show on its nodes and edges. It says nothing about why: a scenario playing, a search, a review could all\n// drive it. It is plain data, so whatever produces it (the scenario player) and whatever draws it (a canvas) agree on it here and import\n// nothing of each other.\n\nexport const NODE_HIGHLIGHTS = ['active', 'visited', 'success', 'failure', 'blocked'] as const\nexport const EDGE_HIGHLIGHTS = ['active', 'visited'] as const\n\nexport type NodeHighlight = (typeof NODE_HIGHLIGHTS)[number]\nexport type EdgeHighlight = (typeof EDGE_HIGHLIGHTS)[number]\n\nexport interface Highlights {\n nodes: Record<string, NodeHighlight>\n edges: Record<string, EdgeHighlight>\n // Fade everything that is not highlighted, so the highlighted part stands out.\n dimmed?: boolean\n}\n","import type { NodeDef } from './format'\n\n// A file named in a node's Markdown, written as inline code: `path/to/file.ts`, `path/to/file.ts:42`, `path/to/file.ts:42-60`, and with the\n// repo it is in first when the project has several: `website:lib/api.ts:90`. Pure, so the editor, the website and the planner share it.\n\nexport interface CodeRef {\n repo?: string\n path: string\n start?: number\n end?: number\n}\n\n// An optional repo id and \":\", then a path of letters, digits and . _ - @ / ending in a file name with an extension, then an optional :line[-line].\n// A repo id has no \".\" or \"/\", so `lib/a.ts:9` and `a.ts:9` never read as a repo.\nconst REF = /^(?:([A-Za-z0-9][A-Za-z0-9_-]{0,39}):)?((?:[A-Za-z0-9_@.-]+\\/)*[A-Za-z0-9_@-][A-Za-z0-9_@.-]*\\.[A-Za-z0-9]+)(?::(\\d{1,6})(?:-(\\d{1,6}))?)?$/\n\nexport function parseCodeRef(text: string): CodeRef | null {\n const match = REF.exec(text.trim())\n if (!match) return null\n const [, repo, path, a, b] = match\n if (path.split('/').some((s) => s === '..' || s === '.')) return null\n const base = repo === undefined ? { path } : { repo, path }\n if (a === undefined) return base\n const start = Number(a)\n const end = b === undefined ? undefined : Number(b)\n if (start < 1 || (end !== undefined && end < start)) return null\n return end === undefined || end === start ? { ...base, start } : { ...base, start, end }\n}\n\nexport function describeCodeRef(ref: CodeRef): string {\n const lines = ref.start === undefined ? '' : ref.end === undefined ? `:${ref.start}` : `:${ref.start}-${ref.end}`\n return `${ref.repo ? `${ref.repo}:` : ''}${ref.path}${lines}`\n}\n\n// The code references in some Markdown: inline code spans only, never inside a fenced block.\nexport function markdownCodeRefs(markdown: string): CodeRef[] {\n const refs: CodeRef[] = []\n for (const match of markdown.replace(/^(```|~~~)[\\s\\S]*?^\\1/gm, '').matchAll(/`([^`\\n]+)`/g)) {\n const ref = parseCodeRef(match[1])\n if (ref) refs.push(ref)\n }\n return refs\n}\n\nexport interface UncoveredRef {\n nodeId: string\n title: string\n ref: CodeRef\n}\n\n// Files a node's Markdown (body and decisions) names that none of its `links` lists. The Code tab and the drift check read only `links`, so\n// such a file is clickable but invisible to both. A reference with no repo matches a link in any repo; one with a repo needs that repo\n// (a link with none counts as the default repo, which only the host knows, so it matches too).\nexport function uncoveredRefs(nodes: (Pick<NodeDef, 'id' | 'title' | 'decisions' | 'links'> & Partial<Pick<NodeDef, 'body'>>)[]): UncoveredRef[] {\n const out: UncoveredRef[] = []\n for (const node of nodes) {\n const seen = new Set<string>()\n for (const ref of [...markdownCodeRefs(node.body ?? ''), ...markdownCodeRefs(node.decisions ?? '')]) {\n const key = `${ref.repo ?? ''}:${ref.path}`\n if (seen.has(key)) continue\n seen.add(key)\n const covered = (node.links ?? []).some((l) => l.path === ref.path && (ref.repo === undefined || l.repo === undefined || l.repo === ref.repo))\n if (!covered) out.push({ nodeId: node.id, title: node.title, ref })\n }\n }\n return out\n}\n","import type { NodeDef } from './format'\nimport { uncoveredRefs } from './codeRefs'\nimport type { UncoveredRef } from './codeRefs'\n\n// Checks the code links on nodes against the code as it is now. It only reports: it never changes a link, and it reads no files itself\n// (the host passes their text), so the same check runs in the desktop app, in a script and on a server. The result says \"possibly stale\",\n// never \"verified\": a matching hash means the linked lines are unchanged, not that the node's text is still true.\n\nexport type LinkStatus = 'ok' | 'changed' | 'moved' | 'missing' | 'unchecked'\n\n// Worst first. A node shows the worst status among its links.\nexport const LINK_STATUS_ORDER: LinkStatus[] = ['missing', 'changed', 'moved', 'unchecked', 'ok']\n\nexport interface LinkReport {\n nodeId: string\n title: string\n // Position in the node's `links`.\n index: number\n // The repo the path is in, when the link names one.\n repo?: string\n path: string\n symbol?: string\n lines?: [number, number]\n status: LinkStatus\n expectedHash?: string\n actualHash?: string\n // For `moved`: where the same lines are now, so the link can be re-pointed.\n newLines?: [number, number]\n message: string\n}\n\nexport interface LinkCheck {\n summary: Record<LinkStatus, number>\n // Only links that are not ok.\n problems: LinkReport[]\n // The worst status of each node that has links. A node with none is left out: nothing can be said about it.\n nodes: Record<string, LinkStatus>\n // Paths the check needed that the host could not supply, so their links are reported `unchecked`.\n unread: string[]\n // Files a node's Markdown names that none of its links lists (see uncoveredRefs). Only for nodes whose body was passed in.\n uncovered: UncoveredRef[]\n}\n\n// What a file is called in `FileTexts` and `unread`: `repo:path` when the link names a repo, else the bare path. Two repos can hold the same\n// path (both of ours have packages/diagram-core/src/format.ts), so a repo-qualified link must never be looked up by its path alone.\nexport const linkKey = (link: { repo?: string; path: string }) => (link.repo ? `${link.repo}:${link.path}` : link.path)\n\n// The text of each file by `linkKey`, or null when it does not exist. A key left out was not read.\nexport type FileTexts = Record<string, string | null | undefined>\n\nconst HASH_LENGTH = 12\nconst MAX_SCAN_LINES = 20000\n\nconst hex = (bytes: ArrayBuffer) => [...new Uint8Array(bytes)].map((b) => b.toString(16).padStart(2, '0')).join('')\n\n// The hash a link stores: the first 12 hex characters of the SHA-256 of the linked lines, each followed by a newline\n// (the same as `sed -n 'A,Bp' file | shasum -a 256`).\nexport async function hashLines(lines: string[]): Promise<string> {\n const data = new TextEncoder().encode(lines.join('\\n') + '\\n')\n return hex(await globalThis.crypto.subtle.digest('SHA-256', data)).slice(0, HASH_LENGTH)\n}\n\nconst splitLines = (text: string) => {\n const lines = text.split('\\n')\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()\n return lines.map((l) => (l.endsWith('\\r') ? l.slice(0, -1) : l))\n}\n\nconst escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\nconst hasSymbol = (text: string, symbol: string) => new RegExp(`(?<![\\\\w$])${escapeRegExp(symbol)}(?![\\\\w$])`).test(text)\n\n// The files (by `linkKey`) the links of these nodes name, so a host knows which to read.\nexport function linkedPaths(nodes: Pick<NodeDef, 'links'>[]): string[] {\n return [...new Set(nodes.flatMap((n) => (n.links ?? []).map(linkKey)))]\n}\n\nexport async function checkLinks(nodes: (Pick<NodeDef, 'id' | 'title' | 'links'> & Partial<Pick<NodeDef, 'body' | 'decisions'>>)[], files: FileTexts, options: { nodeId?: string } = {}): Promise<LinkCheck> {\n const summary: Record<LinkStatus, number> = { ok: 0, changed: 0, moved: 0, missing: 0, unchecked: 0 }\n const problems: LinkReport[] = []\n const worst: Record<string, LinkStatus> = {}\n const unread = new Set<string>()\n const lineCache = new Map<string, string[]>()\n const linesOf = (path: string, text: string) => {\n let lines = lineCache.get(path)\n if (!lines) lineCache.set(path, (lines = splitLines(text)))\n return lines\n }\n\n for (const node of nodes) {\n if (options.nodeId !== undefined && node.id !== options.nodeId) continue\n for (const [index, link] of (node.links ?? []).entries()) {\n const base = { nodeId: node.id, title: node.title, index, ...(link.repo && { repo: link.repo }), path: link.path, ...(link.symbol && { symbol: link.symbol }), ...(link.lines && { lines: link.lines }) }\n const done = (status: LinkStatus, message: string, extra: Partial<LinkReport> = {}) => {\n summary[status]++\n if (status !== 'ok') problems.push({ ...base, status, message, ...(link.hash && { expectedHash: link.hash }), ...extra })\n if (!worst[node.id] || LINK_STATUS_ORDER.indexOf(status) < LINK_STATUS_ORDER.indexOf(worst[node.id])) worst[node.id] = status\n }\n\n const key = linkKey(link)\n const text = files[key]\n if (text === undefined) {\n unread.add(key)\n done('unchecked', `${key} was not read, so this link could not be checked.`)\n continue\n }\n if (text === null) {\n done('missing', `${key} does not exist. It may have been renamed or deleted.`)\n continue\n }\n if (link.symbol && !hasSymbol(text, link.symbol)) {\n done('missing', `${key} no longer contains \"${link.symbol}\".`)\n continue\n }\n if (!link.lines || !link.hash) {\n done('unchecked', `${key} exists${link.symbol ? ` and contains \"${link.symbol}\"` : ''}, but the link has no ${link.lines ? 'hash' : 'lines'} to compare.`)\n continue\n }\n\n const [from, to] = link.lines\n const lines = linesOf(key, text)\n const expected = link.hash.toLowerCase()\n const matches = (hash: string) => hash.startsWith(expected) || expected.startsWith(hash)\n const actual = to <= lines.length ? await hashLines(lines.slice(from - 1, to)) : undefined\n if (actual && matches(actual)) {\n done('ok', '')\n continue\n }\n\n // The lines may only have shifted (code added above): look for the same text elsewhere in the file.\n const size = to - from + 1\n let shifted: [number, number] | undefined\n if (lines.length <= MAX_SCAN_LINES) {\n for (let start = 1; start + size - 1 <= lines.length && !shifted; start++) {\n if (start === from) continue\n if (matches(await hashLines(lines.slice(start - 1, start - 1 + size)))) shifted = [start, start + size - 1]\n }\n }\n if (shifted) done('moved', `The same lines are now at ${key}:${shifted[0]}${shifted[1] !== shifted[0] ? `-${shifted[1]}` : ''}.`, { newLines: shifted, ...(actual && { actualHash: actual }) })\n else done('changed', `${key}:${from}${to !== from ? `-${to}` : ''} no longer matches the hash taken when the link was made. The node is possibly stale.`, actual ? { actualHash: actual } : {})\n }\n }\n const covered = nodes.filter((n) => (options.nodeId === undefined || n.id === options.nodeId) && (n.body !== undefined || n.decisions !== undefined))\n return { summary, problems, nodes: worst, unread: [...unread], uncovered: uncoveredRefs(covered) }\n}\n","import type { DiagramFile } from './format'\n\n// Code links must be able to open on GitHub, so nothing is left to be guessed. Two checks share this rule: one for a design being edited\n// (its links must name repos the project's workspace knows), and one for a design being published (every repo its links use is listed in\n// `repos` with a GitHub remote and a commit).\n\n/** Where a repo is on GitHub, written one way only: github.com/owner/repo. */\nexport const GITHUB_REMOTE = /^github\\.com\\/[\\w.-]+\\/[\\w.-]+$/\n\ntype LinkedNode = { links?: { repo?: string; path?: string }[] }\ntype KnownRepo = { id: string; remote?: string; default?: boolean }\n\n/** The repo a link belongs to: the one it names, or the default repo when it names none (undefined when there is none to pick). */\nexport function linkRepo<R extends KnownRepo>(link: { repo?: string }, known: R[]): R | undefined {\n return link.repo ? known.find((item) => item.id === link.repo) : (known.find((item) => item.default) ?? known[0])\n}\n\n/** A path inside a repo's folder: relative, no \"..\", no empty parts. */\nexport const isRepoRelativePath = (path: string) => path.length > 0 && !/^([/\\\\]|[A-Za-z]:)/.test(path) && !path.split(/[/\\\\]/).some((part) => part === '..' || part === '')\n\n/**\n * While editing: the problems in the links of these nodes, given the repos of the project's workspace (`.glyph/workspace.json`, where each\n * has a folder and a GitHub remote). A link must resolve both ways: its repo (the one it names, or the default when it names none; with\n * several repos it must name one) is listed and has a remote written as github.com/owner/repo, so it can open on the web, and its path stays\n * inside that repo's folder, so it can open on disk. The remote is only checked to be defined, never looked up. That the file exists is\n * checked where the disk can be read. With no repos known, no link is allowed.\n */\nexport function workspaceLinkIssues(nodes: LinkedNode[], known: KnownRepo[]): string[] {\n const issues = new Set<string>()\n const ids = known.map((repo) => repo.id).join(', ')\n for (const node of nodes) for (const link of node.links ?? []) {\n if (!known.length) { issues.add('links: this project lists no repos in .glyph/workspace.json, so a link has nowhere to resolve'); continue }\n if (!link.repo && known.length > 1) { issues.add(`links: with several repos, every link must name its repo (${ids})`); continue }\n const repo = linkRepo(link, known)\n if (!repo) issues.add(`links: repo \"${link.repo}\" is not in the workspace; use one of ${ids}`)\n else if (!repo.remote || !GITHUB_REMOTE.test(repo.remote)) issues.add(`links: repo \"${repo.id}\" has no GitHub remote in the workspace; add \"remote\": \"github.com/owner/repo\"`)\n if (link.path !== undefined && !isRepoRelativePath(link.path)) issues.add(`links: path \"${link.path}\" must be a file inside the repo: relative, with no \"..\"`)\n }\n return [...issues].slice(0, 5)\n}\n\n/**\n * When publishing: every repo the links point into is listed in `repos` with a remote written as github.com/owner/repo and a commit `sha` (or at\n * least a `branch`). A link with no `repo` belongs to the only repo listed, so with several repos each link must name its own.\n */\nexport function publishedRepoIssues(diagram: Pick<DiagramFile, 'nodes' | 'repos'>): string[] {\n const issues: string[] = []\n const repos = diagram.repos ?? {}\n const ids = Object.keys(repos)\n const used = new Set<string>()\n let unnamed = false\n for (const node of diagram.nodes) for (const link of node.links ?? []) { if (link.repo) used.add(link.repo); else unnamed = true }\n if (unnamed && ids.length === 1) used.add(ids[0])\n if (unnamed && ids.length !== 1) {\n issues.push(ids.length === 0\n ? 'repos: this design has code links, so list each repo it links into, for example \"repos\": { \"website\": { \"remote\": \"github.com/you/app\", \"sha\": \"<commit>\" } }'\n : 'links: with several repos, every link must name its repo')\n }\n for (const id of used) {\n const repo = repos[id]\n if (!repo) issues.push(`repos.${id}: a link names this repo, but it is not listed in repos`)\n else if (!repo.remote || !GITHUB_REMOTE.test(repo.remote)) issues.push(`repos.${id}.remote: write the GitHub address as github.com/owner/repo`)\n else if (!repo.sha && !repo.branch) issues.push(`repos.${id}: give the commit \"sha\" the links were written against (or at least a \"branch\")`)\n }\n return issues.slice(0, 5)\n}\n"],"mappings":"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","names":["group","id","edge","node","edge","group","node","checkLinks","node","node"]}
|
|
1
|
+
{"version":3,"sources":["../src/checklist.ts","../src/membership.ts","../src/plan.ts","../src/editGeometry.ts","../src/geometry.ts","../src/ops.ts","../src/controller.ts","../src/repository.ts","../src/highlights.ts","../src/codeRefs.ts","../src/linkCheck.ts","../src/repoRules.ts"],"sourcesContent":["// The Systems design questions a node can answer. The answers are kept on the node (`systemsDesign`, by question id), so they are\n// saved with the design and the agent can read and write them.\nexport interface ChecklistItem { id: string; label: string; question: string }\nexport interface ChecklistGroup { title: string; items: ChecklistItem[] }\n\nexport const DESIGN_CHECKLIST: ChecklistGroup[] = [\n { title: 'The Two Endpoints', items: [\n { id: 'client', label: 'Client', question: 'Who or what initiates the request?' },\n { id: 'server', label: 'Server', question: 'Who or what processes the request?' },\n ] },\n { title: 'The Four Package Characteristics', items: [\n { id: 'size', label: 'Package Size', question: 'How much data is transmitted per request?' },\n { id: 'frequency', label: 'Package Frequency', question: 'How often are requests sent?' },\n { id: 'latency', label: 'Package Latency', question: 'How quickly must requests be processed?' },\n { id: 'retention', label: 'Package Retention', question: 'How long must the data remain relevant or be stored?' },\n ] },\n { title: 'The Three Cs', items: [\n { id: 'connection', label: 'Connection', question: 'How do clients and servers communicate? Are connections persistent or temporary?' },\n { id: 'capacity', label: 'Capacity', question: 'How much traffic, concurrency, and throughput must the system support?' },\n { id: 'consistency', label: 'Consistency & Idempotency', question: 'How consistent must the data be? How are retries and duplicate requests handled safely?' },\n ] },\n { title: 'The Final Four', items: [\n { id: 'protocol', label: 'Protocol', question: 'What communication protocols are used (HTTP, WebSocket, gRPC, etc.)?' },\n { id: 'errors', label: 'Error Handling', question: 'How are failures, timeouts, retries, and recovery handled?' },\n { id: 'security', label: 'Security', question: 'How are authentication, authorization, encryption, and data protection implemented?' },\n { id: 'telemetry', label: 'Telemetry', question: 'How are logs, metrics, traces, and system health monitored?' },\n ] },\n]\n\nexport const CHECKLIST_TOTAL = DESIGN_CHECKLIST.reduce((n, g) => n + g.items.length, 0)\n\nexport const CHECKLIST_IDS: readonly string[] = DESIGN_CHECKLIST.flatMap((g) => g.items.map((i) => i.id))\nexport const CHECKLIST_ANSWER_MAX = 200\n","import type { GroupDef, NodeDef } from './types'\n\n// A group does not store its members: whatever is drawn inside its box belongs to it. A node is\n// inside when its centre is, and another group is inside when its whole box is. Keeping this\n// derived means the saved diagram needs nothing extra, and dragging a node out of a box takes\n// it out of the group.\nexport function membersOf(group: GroupDef, nodes: NodeDef[], groups: GroupDef[]): { nodes: NodeDef[]; groups: GroupDef[] } {\n const inside = (x: number, y: number) => x >= group.x && x <= group.x + group.w && y >= group.y && y <= group.y + group.h\n return {\n nodes: nodes.filter((n) => inside(n.x + n.w / 2, n.y + n.h / 2)),\n groups: groups.filter(\n (g) => g.id !== group.id && g.x >= group.x && g.y >= group.y && g.x + g.w <= group.x + group.w && g.y + g.h <= group.y + group.h,\n ),\n }\n}\n","import { membersOf } from './membership'\nimport type { DiagramOp } from './ops'\nimport { CHECKLIST_ANSWER_MAX, CHECKLIST_IDS } from './checklist'\nimport type { EdgeDef, GroupDef, NodeDef } from './types'\n\n// The part of the app that edits a diagram, kept pure: given what the diagram is and a batch of\n// operations, say what it becomes (or why that is not possible). Nothing here touches a store,\n// so every rule can be tested on its own, and a batch is all-or-nothing by construction.\n\nexport interface Snapshot {\n nodes: NodeDef[]\n edges: EdgeDef[]\n groups: GroupDef[]\n}\n\n// A change to a snapshot: entities to put in (new or replaced) and ids to take out. Applying a\n// patch touches only the entities named in it, so undoing a change does not undo unrelated\n// edits (a node the user dragged afterwards, say).\nexport interface Patch {\n nodes: { upsert: NodeDef[]; remove: string[] }\n edges: { upsert: EdgeDef[]; remove: string[] }\n groups: { upsert: GroupDef[]; remove: string[] }\n}\n\nexport type PlanResult =\n | { ok: true; next: Snapshot; patch: Patch; inverse: Patch; applied: number }\n | { ok: false; message: string; opIndex?: number }\n\nexport const LIMITS = { maxNodes: 300, maxEdges: 600, maxGroups: 50, title: 120, body: 20_000, label: 200 } as const\n\nconst ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/\nconst DEFAULT_SIZE = { w: 280, h: 150 }\nconst ROW_GAP = 30\nconst GROUP_BOTTOM_PADDING = 20\n// An empty group, before it is sized.\nconst EMPTY_GROUP = { w: 360, h: 240 }\nconst GROUP_PADDING = 24\nconst GROUP_TITLE_SPACE = 40\n\nfunction diffById<T extends { id: string }>(before: T[], after: T[]): { upsert: T[]; remove: string[] } {\n const beforeById = new Map(before.map((e) => [e.id, e]))\n const afterIds = new Set(after.map((e) => e.id))\n return {\n upsert: after.filter((e) => JSON.stringify(beforeById.get(e.id)) !== JSON.stringify(e)),\n remove: before.filter((e) => !afterIds.has(e.id)).map((e) => e.id),\n }\n}\n\n// What turns `before` into `after`.\nexport function diffSnapshots(before: Snapshot, after: Snapshot): Patch {\n return {\n nodes: diffById(before.nodes, after.nodes),\n edges: diffById(before.edges, after.edges),\n groups: diffById(before.groups, after.groups),\n }\n}\n\nfunction applyTo<T extends { id: string }>(items: T[], change: { upsert: T[]; remove: string[] }): T[] {\n const removed = new Set(change.remove)\n const replacements = new Map(change.upsert.map((e) => [e.id, e]))\n const kept = items.filter((e) => !removed.has(e.id)).map((e) => replacements.get(e.id) ?? e)\n const known = new Set(items.map((e) => e.id))\n return [...kept, ...change.upsert.filter((e) => !known.has(e.id))]\n}\n\nexport function applyPatch(snapshot: Snapshot, patch: Patch): Snapshot {\n const nodes = applyTo(snapshot.nodes, patch.nodes)\n const nodeIds = new Set(nodes.map((n) => n.id))\n return {\n nodes,\n // An edge whose end is gone cannot exist.\n edges: applyTo(snapshot.edges, patch.edges).filter((e) => nodeIds.has(e.from) && nodeIds.has(e.to)),\n groups: applyTo(snapshot.groups, patch.groups),\n }\n}\n\nexport function isEmptyPatch(patch: Patch): boolean {\n return Object.values(patch).every((c) => c.upsert.length === 0 && c.remove.length === 0)\n}\n\nfunction slug(text: string): string {\n const base = text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40)\n return base || 'item'\n}\n\nfunction uniqueId(base: string, taken: Set<string>): string {\n if (!taken.has(base)) return base\n for (let n = 2; ; n++) {\n const candidate = `${base}-${n}`\n if (!taken.has(candidate)) return candidate\n }\n}\n\nclass PlanError extends Error {}\n\n// A colour is set, or taken off with null; left out, it stays.\nfunction setColor(item: { color?: string }, color: string | null | undefined) {\n if (color === null) delete item.color\n else if (color !== undefined) item.color = color\n}\nconst fail = (message: string): never => {\n throw new PlanError(message)\n}\n\n// Puts a new node under the others in the column of the node added last. If that node is inside a box (a group), the box grows\n// to keep the new one inside.\nfunction place(draft: Snapshot, size: { w: number; h: number }) {\n const last = draft.nodes[draft.nodes.length - 1]\n if (!last) return { x: 0, y: ROW_GAP }\n\n const column = draft.nodes.filter((n) => n.x === last.x)\n const y = Math.max(...column.map((n) => n.y + n.h)) + ROW_GAP\n const home = draft.groups.find((g) => last.x >= g.x && last.x < g.x + g.w && last.y >= g.y && last.y < g.y + g.h)\n if (home) {\n const needed = y + size.h + GROUP_BOTTOM_PADDING - home.y\n if (needed > home.h) draft.groups = draft.groups.map((g) => (g.id === home.id ? { ...g, h: needed } : g))\n }\n return { x: last.x, y }\n}\n\n// The smallest a node or group may be resized to, so it cannot collapse out of sight.\nexport const MIN_NODE = { w: 160, h: 80 } as const\nexport const MIN_GROUP = { w: 120, h: 80 } as const\n\nfunction checkSize(what: string, w: number | undefined, h: number | undefined, min: { w: number; h: number }) {\n if (w !== undefined && w < min.w) fail(`The ${what} cannot be narrower than ${min.w}.`)\n if (h !== undefined && h < min.h) fail(`The ${what} cannot be shorter than ${min.h}.`)\n}\n\n// Only the fields that were given.\nfunction geometry(g: { x?: number; y?: number; w?: number; h?: number }) {\n return Object.fromEntries(Object.entries(g).filter(([, v]) => v !== undefined)) as Partial<{ x: number; y: number; w: number; h: number }>\n}\n\nfunction checkText(label: string, value: string, max: number) {\n if (value.length > max) fail(`${label} is too long (${value.length} characters; the limit is ${max}).`)\n}\n\n// The answers must be to known questions and short. Empty answers are left out.\nfunction checkAnswers(answers: Record<string, string>) {\n for (const [key, value] of Object.entries(answers)) {\n if (!CHECKLIST_IDS.includes(key)) fail(`\"${key}\" is not a Systems design question. Use: ${CHECKLIST_IDS.join(', ')}.`)\n checkText(`The answer for \"${key}\"`, value, CHECKLIST_ANSWER_MAX)\n }\n}\n\nconst MAX_LINKS = 20\n// A link points inside the project: a relative path, with no \"..\", and a hash that is hex.\nfunction checkLinks(links: NodeDef['links']) {\n if (!links) return\n if (links.length > MAX_LINKS) fail(`A node can have at most ${MAX_LINKS} links.`)\n for (const link of links) {\n if (link.path.startsWith('/') || link.path.split('/').includes('..')) fail(`The link path \"${link.path}\" must be relative to the project root, without \"..\".`)\n checkText('The link path', link.path, 500)\n if (link.symbol !== undefined) checkText('The link symbol', link.symbol, 500)\n if (link.hash !== undefined && !/^[0-9a-f]{6,64}$/.test(link.hash)) fail(`The link hash \"${link.hash}\" must be lowercase hex (6 to 64 characters).`)\n }\n}\n\nfunction node(draft: Snapshot, id: string): NodeDef {\n return draft.nodes.find((n) => n.id === id) ?? fail(`There is no node \"${id}\". Use getDiagram to see the ids.`)\n}\n\n// A node named by its id, or (for what the assistant has just created and has no id for yet) by its\n// title, when exactly one node has it. A title that fits several nodes is refused rather than guessed.\nexport function findNodeRef(nodes: NodeDef[], ref: string): { node: NodeDef } | { error: 'missing' | 'ambiguous' } {\n const byId = nodes.find((n) => n.id === ref)\n if (byId) return { node: byId }\n for (const same of [(n: NodeDef) => n.title === ref, (n: NodeDef) => n.title.toLowerCase() === ref.toLowerCase()]) {\n const found = nodes.filter(same)\n if (found.length === 1) return { node: found[0] }\n if (found.length > 1) return { error: 'ambiguous' }\n }\n return { error: 'missing' }\n}\n\nfunction nodeRef(draft: Snapshot, ref: string): NodeDef {\n const found = findNodeRef(draft.nodes, ref)\n if ('node' in found) return found.node\n if (found.error === 'ambiguous') return fail(`More than one node is titled \"${ref}\". Use the node's id.`)\n return fail(`There is no node \"${ref}\". Use getDiagram to see the ids.`)\n}\n\nfunction group(draft: Snapshot, id: string): GroupDef {\n return draft.groups.find((g) => g.id === id) ?? fail(`There is no group \"${id}\". Use getDiagram to see the ids.`)\n}\n\nfunction edge(draft: Snapshot, id: string): EdgeDef {\n return draft.edges.find((e) => e.id === id) ?? fail(`There is no edge \"${id}\". Use getDiagram to see the ids.`)\n}\n\nfunction applyOp(draft: Snapshot, op: DiagramOp) {\n switch (op.op) {\n case 'createLane': {\n const lanes = draft.groups.filter((g) => g.lane)\n const orientation = op.lane.orientation ?? lanes[0]?.lane?.orientation ?? 'horizontal'\n if (!op.lane.title.trim()) fail('A swimlane title cannot be empty.')\n if (lanes.some((g) => g.lane?.orientation !== orientation)) fail('Use arrangeLanes to change the orientation of all swimlanes together.')\n const x = orientation === 'horizontal' ? Math.min(0, ...lanes.map((g) => g.x)) : Math.max(0, ...lanes.map((g) => g.x + g.w))\n const y = orientation === 'vertical' ? Math.min(0, ...lanes.map((g) => g.y)) : Math.max(0, ...lanes.map((g) => g.y + g.h))\n checkText('The lane description', op.lane.body, LIMITS.body)\n applyOp(draft, { op: 'createGroup', group: {\n ...op.lane, nodeIds: [], x: op.lane.x ?? x, y: op.lane.y ?? y,\n w: op.lane.w ?? (orientation === 'horizontal' ? Math.max(960, ...lanes.map((g) => g.w)) : 400),\n h: op.lane.h ?? (orientation === 'vertical' ? Math.max(720, ...lanes.map((g) => g.h)) : 280),\n } })\n draft.groups = draft.groups.map((g, index) => index === draft.groups.length - 1 ? { ...g, lane: { body: op.lane.body, orientation } } : g)\n return\n }\n case 'updateLane': {\n const current = group(draft, op.id)\n if (!current.lane) fail(`\"${op.id}\" is not a swimlane.`)\n const { body, ...patch } = op.patch\n if (patch.title !== undefined && !patch.title.trim()) fail('A swimlane title cannot be empty.')\n if (body !== undefined) checkText('The lane description', body, LIMITS.body)\n if (Object.values(patch).some((value) => value !== undefined)) applyOp(draft, { op: 'updateGroup', id: op.id, patch })\n else if (body === undefined) fail('The lane update changes nothing.')\n if (body !== undefined) draft.groups = draft.groups.map((g) => g.id === op.id && g.lane ? { ...g, lane: { ...g.lane, body } } : g)\n return\n }\n case 'deleteLane': {\n if (!group(draft, op.id).lane) fail(`\"${op.id}\" is not a swimlane.`)\n applyOp(draft, { op: 'deleteGroup', id: op.id })\n return\n }\n case 'arrangeLanes': {\n const lanes = draft.groups.filter((g) => g.lane).sort((a, b) => (a.lane?.orientation === 'vertical' ? a.x - b.x : a.y - b.y))\n if (lanes.length === 0) fail('There are no swimlanes to arrange.')\n const ids = op.laneIds ?? lanes.map((g) => g.id)\n if (ids.length !== lanes.length || new Set(ids).size !== lanes.length || ids.some((id) => !lanes.some((g) => g.id === id))) {\n fail('laneIds must contain every swimlane id exactly once.')\n }\n const ordered = ids.map((id) => group(draft, id))\n const x = Math.min(...lanes.map((g) => g.x))\n const y = Math.min(...lanes.map((g) => g.y))\n // A lane carries its nodes and any plain group drawn inside it; other lanes are never inside a lane.\n const plainGroups = draft.groups.filter((g) => !g.lane)\n const contents = (g: GroupDef) => {\n const members = membersOf(g, draft.nodes, plainGroups)\n return [...members.nodes, ...members.groups]\n }\n const sized = ordered.map((g) => {\n if (g.lane?.orientation === op.orientation) return g\n const boxes = contents(g)\n return { ...g,\n w: op.orientation === 'horizontal' ? Math.max(960, g.w) : Math.max(400, ...boxes.map((b) => b.x + b.w - g.x + 24)),\n h: op.orientation === 'vertical' ? Math.max(720, g.h) : Math.max(280, ...boxes.map((b) => b.y + b.h - g.y + 24)),\n }\n })\n const width = Math.max(...sized.map((g) => g.w))\n const height = Math.max(...sized.map((g) => g.h))\n let offset = 0\n const positions = new Map(sized.map((g) => {\n const next = { ...g, x: x + (op.orientation === 'vertical' ? offset : 0), y: y + (op.orientation === 'horizontal' ? offset : 0),\n w: op.orientation === 'horizontal' ? width : g.w, h: op.orientation === 'vertical' ? height : g.h,\n lane: { body: g.lane!.body, orientation: op.orientation } }\n offset += op.orientation === 'horizontal' ? next.h : next.w\n return [g.id, next]\n }))\n // Nodes and groups have separate ids, so each kind gets its own map of offsets.\n const nodeMoves = new Map<string, { dx: number; dy: number }>()\n const groupMoves = new Map<string, { dx: number; dy: number }>()\n for (const g of lanes) {\n const next = positions.get(g.id)!\n const move = { dx: next.x - g.x, dy: next.y - g.y }\n const members = membersOf(g, draft.nodes, plainGroups)\n for (const n of members.nodes) if (!nodeMoves.has(n.id)) nodeMoves.set(n.id, move)\n for (const b of members.groups) if (!groupMoves.has(b.id)) groupMoves.set(b.id, move)\n }\n const moved = <T extends { id: string; x: number; y: number }>(moves: Map<string, { dx: number; dy: number }>, b: T): T => {\n const move = moves.get(b.id)\n return move ? { ...b, x: b.x + move.dx, y: b.y + move.dy } : b\n }\n draft.nodes = draft.nodes.map((n) => moved(nodeMoves, n))\n draft.groups = draft.groups.map((g) => positions.get(g.id) ?? moved(groupMoves, g))\n return\n }\n case 'createNode': {\n const { node: spec } = op\n checkText('The title', spec.title, LIMITS.title)\n checkText('The body', spec.body, LIMITS.body)\n if (spec.decisions !== undefined) checkText('The decisions', spec.decisions, LIMITS.body)\n if (spec.systemsDesign) checkAnswers(spec.systemsDesign)\n checkLinks(spec.links)\n if (draft.nodes.length >= LIMITS.maxNodes) fail(`The diagram already has the maximum of ${LIMITS.maxNodes} nodes.`)\n\n const taken = new Set(draft.nodes.map((n) => n.id))\n if (spec.id !== undefined && !ID_PATTERN.test(spec.id)) {\n fail(`\"${spec.id}\" is not a valid id. Use letters, digits, \"-\" and \"_\", starting with a letter or digit.`)\n }\n if (spec.id !== undefined && taken.has(spec.id)) fail(`A node with id \"${spec.id}\" already exists.`)\n const id = spec.id ?? uniqueId(slug(spec.title), taken)\n\n const size = { ...DEFAULT_SIZE }\n let at = spec.x !== undefined && spec.y !== undefined ? { x: spec.x, y: spec.y } : spec.laneId !== undefined ? { x: 0, y: 0 } : place(draft, size)\n if (spec.laneId !== undefined) {\n const lane = group(draft, spec.laneId)\n if (!lane.lane) fail(`\"${spec.laneId}\" is not a swimlane.`)\n const members = membersOf(lane, draft.nodes, []).nodes\n at = {\n x: Math.max(lane.x + 24, spec.x ?? lane.x + 24),\n y: Math.max(lane.y + 96, spec.y ?? Math.max(lane.y + 96, ...members.map((n) => n.y + n.h + 24))),\n }\n draft.groups = draft.groups.map((g) => g.id === lane.id ? { ...g, w: Math.max(g.w, at.x + size.w + 24 - g.x), h: Math.max(g.h, at.y + size.h + 24 - g.y) } : g)\n }\n draft.nodes = [...draft.nodes, { id, title: spec.title, body: spec.body, ...(spec.decisions?.trim() && { decisions: spec.decisions }), ...(spec.systemsDesign && Object.values(spec.systemsDesign).some((v) => v.trim()) && { systemsDesign: Object.fromEntries(Object.entries(spec.systemsDesign).filter(([, v]) => v.trim())) }), ...(spec.links && spec.links.length > 0 && { links: spec.links }), ...(spec.color !== undefined && { color: spec.color }), ...at, ...size }]\n return\n }\n\n case 'updateNode': {\n const current = node(draft, op.id)\n const { title, body, decisions, systemsDesign, links, color, x, y, w, h } = op.patch\n if (Object.values(op.patch).every((v) => v === undefined)) fail(`The update to \"${op.id}\" changes nothing.`)\n if (title !== undefined) checkText('The title', title, LIMITS.title)\n if (body !== undefined) checkText('The body', body, LIMITS.body)\n if (decisions !== undefined) checkText('The decisions', decisions, LIMITS.body)\n if (systemsDesign) checkAnswers(systemsDesign)\n checkLinks(links)\n checkSize(`node \"${op.id}\"`, w, h, MIN_NODE)\n\n const next: NodeDef = { ...current, ...(title !== undefined && { title }), ...(body !== undefined && { body }) }\n if (decisions !== undefined) {\n if (decisions.trim()) next.decisions = decisions\n else delete next.decisions\n }\n if (systemsDesign) {\n const merged = { ...next.systemsDesign, ...systemsDesign }\n for (const [key, value] of Object.entries(merged)) if (!value.trim()) delete merged[key]\n if (Object.keys(merged).length > 0) next.systemsDesign = merged\n else delete next.systemsDesign\n }\n if (links) {\n if (links.length > 0) next.links = links\n else delete next.links\n }\n setColor(next, color)\n Object.assign(next, geometry({ x, y, w, h }))\n draft.nodes = draft.nodes.map((n) => (n.id === op.id ? next : n))\n return\n }\n\n case 'deleteNode': {\n node(draft, op.id)\n draft.nodes = draft.nodes.filter((n) => n.id !== op.id)\n // Its edges go with it.\n draft.edges = draft.edges.filter((e) => e.from !== op.id && e.to !== op.id)\n return\n }\n\n case 'createGroup': {\n const { group: spec } = op\n checkText('The title', spec.title, LIMITS.title)\n if (draft.groups.length >= LIMITS.maxGroups) fail(`The diagram already has the maximum of ${LIMITS.maxGroups} groups.`)\n const members = [...new Set(spec.nodeIds.map((ref) => nodeRef(draft, ref).id))].map((id) => node(draft, id))\n if (members.length === 0 && (spec.x === undefined || spec.y === undefined)) fail('A group needs nodes to go around, or a position (x and y) for an empty box.')\n checkSize('group', spec.w, spec.h, MIN_GROUP)\n const taken = new Set(draft.groups.map((g) => g.id))\n if (spec.id !== undefined && !ID_PATTERN.test(spec.id)) fail(`\"${spec.id}\" is not a valid id.`)\n if (spec.id !== undefined && taken.has(spec.id)) fail(`A group with id \"${spec.id}\" already exists.`)\n const id = spec.id ?? uniqueId(slug(spec.title), taken)\n\n if (members.length === 0) {\n draft.groups = [\n ...draft.groups,\n { id, title: spec.title, ...(spec.color !== undefined && { color: spec.color }), x: spec.x!, y: spec.y!, w: spec.w ?? EMPTY_GROUP.w, h: spec.h ?? EMPTY_GROUP.h },\n ]\n return\n }\n\n // The box is drawn around its nodes; moving nodes later does not move it.\n const left = Math.min(...members.map((n) => n.x)) - GROUP_PADDING\n const top = Math.min(...members.map((n) => n.y)) - GROUP_TITLE_SPACE\n const right = Math.max(...members.map((n) => n.x + n.w)) + GROUP_PADDING\n const bottom = Math.max(...members.map((n) => n.y + n.h)) + GROUP_PADDING\n draft.groups = [\n ...draft.groups,\n { id, title: spec.title, ...(spec.color !== undefined && { color: spec.color }), x: left, y: top, w: right - left, h: bottom - top },\n ]\n return\n }\n\n case 'updateGroup': {\n const current = group(draft, op.id)\n const { title, color, x, y, w, h } = op.patch\n if (Object.values(op.patch).every((v) => v === undefined)) fail(`The update to group \"${op.id}\" changes nothing.`)\n if (title !== undefined) checkText('The title', title, LIMITS.title)\n checkSize(`group \"${op.id}\"`, w, h, MIN_GROUP)\n\n // Changing only the position moves the group: what is inside it goes along. Giving a size resizes the box alone.\n const dx = w === undefined && h === undefined && x !== undefined ? x - current.x : 0\n const dy = w === undefined && h === undefined && y !== undefined ? y - current.y : 0\n const carried = dx !== 0 || dy !== 0 ? membersOf(current, draft.nodes, draft.groups) : { nodes: [], groups: [] }\n const carriedNodes = new Set(carried.nodes.map((n) => n.id))\n const carriedGroups = new Set(carried.groups.map((g) => g.id))\n draft.nodes = draft.nodes.map((n) => (carriedNodes.has(n.id) ? { ...n, x: n.x + dx, y: n.y + dy } : n))\n draft.groups = draft.groups.map((g) => {\n if (g.id === current.id) {\n const next = { ...g, ...(title !== undefined && { title }), ...geometry({ x, y, w, h }) }\n setColor(next, color)\n return next\n }\n return carriedGroups.has(g.id) ? { ...g, x: g.x + dx, y: g.y + dy } : g\n })\n return\n }\n\n case 'deleteGroup': {\n group(draft, op.id)\n draft.groups = draft.groups.filter((g) => g.id !== op.id)\n return\n }\n\n case 'createEdge': {\n const { edge: spec } = op\n checkText('The label', spec.label, LIMITS.label)\n if (draft.edges.length >= LIMITS.maxEdges) fail(`The diagram already has the maximum of ${LIMITS.maxEdges} edges.`)\n // Ends may be named by id or by title, so an edge can follow the nodes created earlier in the same batch.\n const from = nodeRef(draft, spec.from).id\n const to = nodeRef(draft, spec.to).id\n if (from === to) fail('An edge cannot start and end at the same node.')\n if (draft.edges.some((e) => e.from === from && e.to === to && e.label === spec.label)) {\n fail(`There is already an edge from \"${from}\" to \"${to}\" labelled \"${spec.label}\".`)\n }\n\n const taken = new Set(draft.edges.map((e) => e.id))\n if (spec.id !== undefined && !ID_PATTERN.test(spec.id)) fail(`\"${spec.id}\" is not a valid id.`)\n if (spec.id !== undefined && taken.has(spec.id)) fail(`An edge with id \"${spec.id}\" already exists.`)\n const id = spec.id ?? uniqueId(`${slug(from)}-${slug(to)}`, taken)\n\n draft.edges = [\n ...draft.edges,\n {\n id,\n from,\n to,\n label: spec.label,\n ...(spec.dashed !== undefined && { dashed: spec.dashed }),\n ...(spec.optional !== undefined && { optional: spec.optional }),\n ...(spec.color !== undefined && { color: spec.color }),\n ...(spec.width !== undefined && { width: spec.width }),\n ...(spec.arrow !== undefined && { arrow: spec.arrow }),\n },\n ]\n return\n }\n\n case 'updateEdge': {\n const current = edge(draft, op.id)\n const { label, dashed, optional, color, width, arrow } = op.patch\n if (Object.values(op.patch).every((v) => v === undefined)) fail(`The update to \"${op.id}\" changes nothing.`)\n if (label !== undefined) checkText('The label', label, LIMITS.label)\n draft.edges = draft.edges.map((e) => {\n if (e.id !== current.id) return e\n const next = { ...e, ...(label !== undefined && { label }), ...(dashed !== undefined && { dashed }), ...(optional !== undefined && { optional }) }\n setColor(next, color)\n // null clears the setting, so the file holds no key for the default.\n if (width === null) delete next.width\n else if (width !== undefined) next.width = width\n if (arrow === null) delete next.arrow\n else if (arrow !== undefined) next.arrow = arrow\n return next\n })\n return\n }\n\n case 'deleteEdge': {\n edge(draft, op.id)\n draft.edges = draft.edges.filter((e) => e.id !== op.id)\n return\n }\n }\n}\n\n// Applies the operations in order to a copy. If any one is invalid, nothing is applied and the\n// reason names the operation, so the model can fix that one and try again.\nexport function planChanges(snapshot: Snapshot, ops: DiagramOp[]): PlanResult {\n const draft: Snapshot = { nodes: [...snapshot.nodes], edges: [...snapshot.edges], groups: [...snapshot.groups] }\n\n for (let i = 0; i < ops.length; i++) {\n try {\n applyOp(draft, ops[i])\n } catch (error) {\n if (error instanceof PlanError) return { ok: false, message: `Change ${i + 1} (${ops[i].op}): ${error.message}`, opIndex: i }\n throw error\n }\n }\n\n const patch = diffSnapshots(snapshot, draft)\n return { ok: true, next: draft, patch, inverse: diffSnapshots(draft, snapshot), applied: ops.length }\n}\n","import { MIN_GROUP, MIN_NODE } from './plan'\n\nexport type Handle = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw'\nexport type EditMode = 'move' | Handle\nexport type EditKind = 'node' | 'group'\n\nexport interface Rect {\n x: number\n y: number\n w: number\n h: number\n}\n\nexport const HANDLES: Handle[] = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w']\n\nexport const minSize = (kind: EditKind) => (kind === 'node' ? MIN_NODE : MIN_GROUP)\n\n// The rectangle after dragging by (dx, dy) world units. A resize never goes below the minimum,\n// and the edge opposite the one being dragged stays where it is.\nexport function dragRect(start: Rect, mode: EditMode, dx: number, dy: number, min: { w: number; h: number }): Rect {\n if (mode === 'move') return { ...start, x: Math.round(start.x + dx), y: Math.round(start.y + dy) }\n\n let { x, y, w, h } = start\n if (mode.includes('e')) w = Math.max(min.w, start.w + dx)\n if (mode.includes('w')) {\n w = Math.max(min.w, start.w - dx)\n x = start.x + start.w - w\n }\n if (mode.includes('s')) h = Math.max(min.h, start.h + dy)\n if (mode.includes('n')) {\n h = Math.max(min.h, start.h - dy)\n y = start.y + start.h - h\n }\n return { x: Math.round(x), y: Math.round(y), w: Math.round(w), h: Math.round(h) }\n}\n\n// Only what differs, so the change touches nothing it does not have to.\nexport function rectPatch(before: Rect, after: Rect): Partial<Rect> {\n const patch: Partial<Rect> = {}\n for (const key of ['x', 'y', 'w', 'h'] as const) if (before[key] !== after[key]) patch[key] = after[key]\n return patch\n}\n","import type { Bounds, EdgeDef, GroupDef, NodeDef } from './types'\n\nexport interface EdgeGeometry {\n d: string\n lx: number\n ly: number\n}\n\nfunction cubicAt(t: number, p0: number, p1: number, p2: number, p3: number) {\n const u = 1 - t\n return u * u * u * p0 + 3 * u * u * t * p1 + 3 * u * t * t * p2 + t * t * t * p3\n}\n\n// Right edge to left edge when the target is in a later column, the reverse for\n// earlier columns, and a bulge out the right side when both nodes share a column.\nexport function edgeGeometry(a: NodeDef, b: NodeDef): EdgeGeometry {\n const y1 = a.y + a.h / 2\n const y2 = b.y + b.h / 2\n let x1: number, x2: number, c1x: number, c2x: number\n\n if (b.x > a.x + a.w - 1) {\n x1 = a.x + a.w\n x2 = b.x\n const dx = Math.max(60, (x2 - x1) / 2)\n c1x = x1 + dx\n c2x = x2 - dx\n } else if (b.x + b.w < a.x + 1) {\n x1 = a.x\n x2 = b.x + b.w\n const dx = Math.max(60, (x1 - x2) / 2)\n c1x = x1 - dx\n c2x = x2 + dx\n } else {\n x1 = a.x + a.w\n x2 = b.x + b.w\n c1x = x1 + 90\n c2x = x2 + 90\n }\n\n return {\n d: `M ${x1} ${y1} C ${c1x} ${y1}, ${c2x} ${y2}, ${x2} ${y2}`,\n lx: cubicAt(0.5, x1, c1x, c2x, x2),\n ly: cubicAt(0.5, y1, y1, y2, y2),\n }\n}\n\nexport function labelWidth(edge: EdgeDef) {\n return edge.label.length * 6.2 + 16\n}\n\n// The area the diagram covers: groups are optional, so nodes count too.\nexport function diagramBounds(groups: GroupDef[], nodes: NodeDef[]): Bounds {\n return [...groups, ...nodes].reduce(\n (acc, g) => ({ w: Math.max(acc.w, g.x + g.w), h: Math.max(acc.h, g.y + g.h) }),\n { w: 0, h: 0 },\n )\n}\n","import { z } from 'zod'\nimport { colorSchema } from './colors'\nimport { edgeArrowSchema, edgeWidthSchema, linkSchema, orientationSchema } from './format'\n\n// The operations that change a diagram: the one vocabulary for people and for agents. A batch of them is planned (plan.ts), applied\n// as a whole or not at all, and answered with the exact inverse. The descriptions are what a model reads.\n\nconst colorHelp = 'A colour: a name (red, orange, yellow, green, teal, blue, purple, pink, gray), which follows the light or dark theme, or a fixed #rrggbb. Leave out for the default.'\n// In an update, null takes the colour off.\nconst colorPatch = colorSchema.nullable().optional().describe(`${colorHelp} null removes it.`)\n\nconst decisionsHelp = 'Optional Markdown decision log for this node, kept apart from the body: why this was chosen (for example Lambda over Fargate, ECS or Kubernetes) and the alternatives and trade-offs that were considered. Leave out when there is nothing to record.'\n\nconst systemsDesignHelp = 'Optional answers to the Systems design questions, as an object of question id to a short answer. Ids: client, server, size, frequency, latency, retention, connection, capacity, consistency, protocol, errors, security, telemetry. An answer is at most 200 characters.'\n\nconst linksHelp = 'Optional code this node describes: a list of { repo?, path, symbol?, lines?: [from, to], hash? }. repo is a repo id from the project workspace (omit it for the default repo) and path is relative to that repo, or to the project root when the project has no repos. Every repo in the workspace has a GitHub remote, so a link can open on GitHub; a repo id the workspace does not list is refused; hash is the first 12 characters of the SHA-256 of the linked lines, taken now, so a later check can tell the code changed. At most 20 per node.'\n\nconst nodeDraft = z.object({\n id: z.string().optional().describe('Leave out to have one generated.'),\n title: z.string().min(1),\n color: colorSchema.optional().describe(colorHelp),\n body: z.string().describe('Markdown.'),\n decisions: z.string().optional().describe(decisionsHelp),\n systemsDesign: z.record(z.string(), z.string()).optional().describe(systemsDesignHelp),\n links: z.array(linkSchema).optional().describe(linksHelp),\n x: z.number().optional(),\n y: z.number().optional(),\n laneId: z.string().optional().describe('Place this node inside this swimlane, expanding the lane if needed.'),\n})\n\n// Position and size on the canvas. Nodes may not be smaller than 160x80 and groups not smaller than 120x80.\n// Giving a group only x and/or y moves it together with the nodes (and groups) drawn inside it; giving w or h resizes the box alone.\nconst geometryPatch = { x: z.number().optional(), y: z.number().optional(), w: z.number().positive().optional(), h: z.number().positive().optional() }\n\nexport const diagramOpSchema = z.discriminatedUnion('op', [\n z.object({\n op: z.literal('createLane'),\n lane: z.object({\n id: z.string().optional(),\n title: z.string().min(1),\n body: z.string().default(''),\n orientation: orientationSchema.optional(),\n color: colorSchema.optional(),\n ...geometryPatch,\n }),\n }),\n z.object({\n op: z.literal('updateLane'), id: z.string(),\n patch: z.object({ title: z.string().min(1).optional(), body: z.string().optional(), color: colorPatch, ...geometryPatch }),\n }),\n z.object({ op: z.literal('deleteLane'), id: z.string() }),\n z.object({\n op: z.literal('arrangeLanes'),\n orientation: orientationSchema,\n laneIds: z.array(z.string()).optional().describe('Every lane id exactly once, in the desired order. Omit to keep the current spatial order.'),\n }),\n z.object({ op: z.literal('createNode'), node: nodeDraft }),\n z.object({\n op: z.literal('updateNode'),\n id: z.string(),\n patch: z.object({\n title: z.string().min(1).optional(),\n body: z.string().optional(),\n decisions: z.string().optional().describe(`${decisionsHelp} An empty string removes the decision log.`),\n systemsDesign: z.record(z.string(), z.string()).optional().describe(`${systemsDesignHelp} Only the ids given change; an empty string clears that answer.`),\n links: z.array(linkSchema).optional().describe(`${linksHelp} Replaces the node's whole list; [] removes every link.`),\n color: colorPatch,\n ...geometryPatch,\n }),\n }),\n z.object({ op: z.literal('deleteNode'), id: z.string() }),\n z.object({\n op: z.literal('createEdge'),\n edge: z.object({\n id: z.string().optional(),\n from: z.string().describe('A node id, or the title of a node (including one created earlier in this same batch).'),\n to: z.string().describe('A node id, or the title of a node (including one created earlier in this same batch).'),\n label: z.string(),\n dashed: z.boolean().optional(),\n optional: z.boolean().optional(),\n color: colorSchema.optional().describe(colorHelp),\n width: edgeWidthSchema.optional().describe('Line thickness: \"thin\" or \"thick\". Leave out for the usual thickness.'),\n arrow: edgeArrowSchema.optional().describe('Which end has an arrow head: \"end\" (at the \"to\" node, the default), \"start\" (at the \"from\" node), \"both\" or \"none\". It only changes the drawing; the edge still runs from \"from\" to \"to\".'),\n }),\n }),\n z.object({\n op: z.literal('updateEdge'),\n id: z.string(),\n patch: z.object({\n label: z.string().optional(),\n dashed: z.boolean().optional(),\n optional: z.boolean().optional(),\n color: colorPatch,\n width: edgeWidthSchema.nullable().optional().describe('\"thin\" or \"thick\"; null returns to the usual thickness.'),\n arrow: edgeArrowSchema.nullable().optional().describe('\"end\", \"start\", \"both\" or \"none\"; null returns to the default (end).'),\n }),\n }),\n z.object({ op: z.literal('deleteEdge'), id: z.string() }),\n z.object({\n op: z.literal('createGroup'),\n group: z.object({\n id: z.string().optional().describe('Leave out to have one generated.'),\n title: z.string().min(1),\n nodeIds: z.array(z.string()).default([]).describe('The nodes to draw a labelled box around, by id or by title. Leave empty for an empty box at x, y.'),\n color: colorSchema.optional().describe(colorHelp),\n ...geometryPatch,\n }),\n }),\n z.object({ op: z.literal('updateGroup'), id: z.string(), patch: z.object({ title: z.string().min(1).optional(), color: colorPatch, ...geometryPatch }) }),\n z.object({ op: z.literal('deleteGroup'), id: z.string() }),\n])\n\n\nexport type DiagramOp = z.infer<typeof diagramOpSchema>\n","import { createStore } from 'zustand/vanilla'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { DIAGRAM_SCHEMA_VERSION } from './format'\nimport type { DiagramOp } from './ops'\nimport { applyPatch, diffSnapshots, isEmptyPatch, planChanges } from './plan'\nimport type { Patch, Snapshot } from './plan'\nimport type { DiagramData, DiagramFile, EdgeDef, GroupDef, NodeDef } from './types'\n\n// The diagram's state and the one way to change it. A host (the cakeslice app, another app, a test, a server) gets a controller, reads\n// from it, and changes it only through `apply`: so a mouse, a keyboard shortcut and an AI agent all take the same path, and all get the\n// same checks and the same exact inverse. The controller has no UI and no storage and keeps no history: a host that wants undo keeps the\n// `inverse` of each change (`onChange`) and sends it back with `applyPatch`.\n\nexport interface NodeState {\n byId: Record<string, NodeDef>\n ids: string[]\n setNodes: (nodes: NodeDef[]) => void\n addNode: (node: NodeDef) => void\n updateNode: (id: string, patch: Partial<Omit<NodeDef, 'id'>>) => void\n removeNode: (id: string) => void\n}\n\nexport interface EdgeState {\n byId: Record<string, EdgeDef>\n ids: string[]\n setEdges: (edges: EdgeDef[]) => void\n addEdge: (edge: EdgeDef) => void\n updateEdge: (id: string, patch: Partial<Omit<EdgeDef, 'id'>>) => void\n removeEdge: (id: string) => void\n // Returns the removed edge ids so callers can clear a stale selection.\n removeEdgesOfNode: (nodeId: string) => string[]\n}\n\nexport interface GroupState {\n byId: Record<string, GroupDef>\n ids: string[]\n setGroups: (groups: GroupDef[]) => void\n addGroup: (group: GroupDef) => void\n updateGroup: (id: string, patch: Partial<Omit<GroupDef, 'id'>>) => void\n removeGroup: (id: string) => void\n}\n\n// What the diagram is, apart from its contents. The revision counts accepted changes (an undo counts too), so an agent, and any proposal it\n// makes, can tell whether the diagram has moved on since it looked.\nexport interface MetaState {\n name: string\n description?: string\n type?: DiagramFile['type']\n revision: number\n setMeta: (meta: { name: string; description?: string; type?: DiagramFile['type']; revision?: number }) => void\n bumpRevision: () => number\n}\n\n// The stores a renderer subscribes to, one per kind so a component re-renders only for the kind it shows. A change from outside goes through\n// `apply`; writing to a store directly is only for a live preview that is rolled back (a drag in progress).\nexport interface DiagramStores {\n nodes: StoreApi<NodeState>\n edges: StoreApi<EdgeState>\n groups: StoreApi<GroupState>\n meta: StoreApi<MetaState>\n}\n\nexport interface DiagramSnapshot extends Snapshot {\n name: string\n description?: string\n type?: DiagramFile['type']\n revision: number\n}\n\nexport interface ApplyRequest {\n ops: DiagramOp[]\n // A short description, for a history list or an approval card.\n summary: string\n // Who made the change: 'user', 'agent', or anything the host tells apart.\n source: string\n // The revision the author looked at. A mismatch means the diagram moved on and nothing is applied.\n expectedRevision?: number\n // The host's own id for the change (a tool call id, say); one is made when it is left out.\n id?: string\n}\n\nexport type ApplyResult =\n | {\n ok: true\n revision: number\n // How many operations were in the batch.\n applied: number\n // False when the batch changed nothing (the revision did not move and no event was sent).\n changed: boolean\n patch: Patch\n // What undoes it exactly: only the things it touched. Send it to `applyPatch`.\n inverse: Patch\n }\n | { ok: false; error: 'stale-revision' | 'invalid'; message: string; currentRevision: number }\n\nexport interface ChangeEvent {\n id: string\n revision: number\n summary: string\n source: string\n at: number\n patch: Patch\n inverse: Patch\n}\n\nexport interface DiagramController {\n readonly stores: DiagramStores\n // The whole diagram as plain data. The same object is returned until something changes, so it works with React's useSyncExternalStore.\n getSnapshot(): DiagramSnapshot\n // Called once after each change or load (not once per store write).\n subscribe(listener: () => void): () => void\n // The one way to change a diagram. A batch is applied as a whole or not at all, and moves the revision once.\n apply(request: ApplyRequest): ApplyResult\n // Applies a patch the host kept (an inverse, for undo) as a change of its own: the revision moves on.\n applyPatch(patch: Patch, meta: { summary: string; source: string; id?: string }): ApplyResult\n // Called for each accepted change that changed something, with what a history, an autosave or an approval list needs.\n onChange(listener: (event: ChangeEvent) => void): () => void\n // Called after a whole diagram is put in (a different one is shown).\n onLoad(listener: () => void): () => void\n // Replaces the contents. Not a change: it has no inverse and sends no ChangeEvent.\n load(diagram: DiagramData & { name?: string; description?: string }, revision?: number): void\n // The diagram as a file; pass it to serializeDiagram() to save it.\n export(meta?: { name?: string; description?: string; schemaVersion?: number }): DiagramFile\n // Runs several store writes and tells subscribers once, afterwards.\n batch(fn: () => void): void\n // Refuses `apply` and `applyPatch` with this message (null lifts it), for a diagram someone else is editing. A change whose source is\n // REMOTE_SOURCE still goes through: it is the other person's edit arriving.\n setReadOnly(message: string | null): void\n readonly readOnly: string | null\n}\n\nexport const REMOTE_SOURCE = 'remote'\n\nfunction collection<T extends { id: string }>(set: (partial: Partial<{ byId: Record<string, T>; ids: string[] }>) => void) {\n return {\n replace: (items: T[]) => set({ byId: Object.fromEntries(items.map((i) => [i.id, i])), ids: items.map((i) => i.id) }),\n }\n}\n\nfunction makeStores(): DiagramStores {\n const nodes = createStore<NodeState>()((set) => ({\n byId: {},\n ids: [],\n setNodes: (items) => collection<NodeDef>(set).replace(items),\n addNode: (node) =>\n set((s) => ({\n byId: { ...s.byId, [node.id]: node },\n ids: s.ids.includes(node.id) ? s.ids : [...s.ids, node.id],\n })),\n updateNode: (id, patch) =>\n set((s) => {\n const current = s.byId[id]\n if (!current) return s\n return { byId: { ...s.byId, [id]: { ...current, ...patch } } }\n }),\n removeNode: (id) =>\n set((s) => {\n if (!s.byId[id]) return s\n const { [id]: _removed, ...byId } = s.byId\n return { byId, ids: s.ids.filter((i) => i !== id) }\n }),\n }))\n\n const edges = createStore<EdgeState>()((set, get) => ({\n byId: {},\n ids: [],\n setEdges: (items) => collection<EdgeDef>(set).replace(items),\n addEdge: (edge) =>\n set((s) => ({\n byId: { ...s.byId, [edge.id]: edge },\n ids: s.ids.includes(edge.id) ? s.ids : [...s.ids, edge.id],\n })),\n updateEdge: (id, patch) =>\n set((s) => {\n const current = s.byId[id]\n if (!current) return s\n return { byId: { ...s.byId, [id]: { ...current, ...patch } } }\n }),\n removeEdge: (id) =>\n set((s) => {\n if (!s.byId[id]) return s\n const { [id]: _removed, ...byId } = s.byId\n return { byId, ids: s.ids.filter((i) => i !== id) }\n }),\n removeEdgesOfNode: (nodeId) => {\n const { byId, ids } = get()\n const removed = ids.filter((id) => byId[id].from === nodeId || byId[id].to === nodeId)\n if (removed.length === 0) return removed\n const drop = new Set(removed)\n set({\n byId: Object.fromEntries(Object.entries(byId).filter(([id]) => !drop.has(id))),\n ids: ids.filter((id) => !drop.has(id)),\n })\n return removed\n },\n }))\n\n const groups = createStore<GroupState>()((set) => ({\n byId: {},\n ids: [],\n setGroups: (items) => collection<GroupDef>(set).replace(items),\n addGroup: (group) =>\n set((s) => ({\n byId: { ...s.byId, [group.id]: group },\n ids: s.ids.includes(group.id) ? s.ids : [...s.ids, group.id],\n })),\n updateGroup: (id, patch) =>\n set((s) => {\n const current = s.byId[id]\n if (!current) return s\n return { byId: { ...s.byId, [id]: { ...current, ...patch } } }\n }),\n removeGroup: (id) =>\n set((s) => {\n if (!s.byId[id]) return s\n const { [id]: _removed, ...byId } = s.byId\n return { byId, ids: s.ids.filter((i) => i !== id) }\n }),\n }))\n\n const meta = createStore<MetaState>()((set, get) => ({\n name: 'Untitled diagram',\n description: undefined,\n revision: 0,\n setMeta: ({ name, description, type, revision = 0 }) => set({ name, description, type, revision }),\n bumpRevision: () => {\n const next = get().revision + 1\n set({ revision: next })\n return next\n },\n }))\n\n return { nodes, edges, groups, meta }\n}\n\nlet counter = 1\n\nexport function createDiagramController(initial?: DiagramData & { name?: string; description?: string; revision?: number }): DiagramController {\n const stores = makeStores()\n const listeners = new Set<() => void>()\n const changeListeners = new Set<(event: ChangeEvent) => void>()\n const loadListeners = new Set<() => void>()\n\n let snapshot: DiagramSnapshot | null = null\n let readOnly: string | null = null\n let depth = 0\n let dirty = false\n const notify = () => {\n for (const listener of [...listeners]) listener()\n }\n // Any write to any store (a commit, a load, or a live preview) ends up here.\n const touched = () => {\n snapshot = null\n if (depth > 0) dirty = true\n else notify()\n }\n for (const store of [stores.nodes, stores.edges, stores.groups, stores.meta]) (store as StoreApi<unknown>).subscribe(touched)\n\n const batch = (fn: () => void) => {\n depth++\n try {\n fn()\n } finally {\n depth--\n if (depth === 0 && dirty) {\n dirty = false\n notify()\n }\n }\n }\n\n const getSnapshot = (): DiagramSnapshot => {\n if (snapshot) return snapshot\n const nodes = stores.nodes.getState()\n const edges = stores.edges.getState()\n const groups = stores.groups.getState()\n const meta = stores.meta.getState()\n snapshot = {\n name: meta.name,\n description: meta.description,\n ...(meta.type && { type: meta.type }),\n revision: meta.revision,\n nodes: nodes.ids.map((id) => nodes.byId[id]),\n edges: edges.ids.map((id) => edges.byId[id]),\n groups: groups.ids.map((id) => groups.byId[id]),\n }\n return snapshot\n }\n\n // Positions of things a change did not touch are whatever they are now: the snapshot was just read from the stores.\n const commit = (next: Snapshot) => {\n batch(() => {\n stores.groups.getState().setGroups(next.groups)\n stores.nodes.getState().setNodes(next.nodes)\n stores.edges.getState().setEdges(next.edges)\n })\n }\n\n const empty: Patch = { nodes: { upsert: [], remove: [] }, edges: { upsert: [], remove: [] }, groups: { upsert: [], remove: [] } }\n\n const run = (planned: ReturnType<typeof planChanges>, request: { summary: string; source: string; id?: string }, applied: number): ApplyResult => {\n const currentRevision = stores.meta.getState().revision\n if (!planned.ok) return { ok: false, error: 'invalid', message: planned.message, currentRevision }\n // A batch that changes nothing is not a change.\n if (isEmptyPatch(planned.patch)) return { ok: true, revision: currentRevision, applied, changed: false, patch: empty, inverse: empty }\n\n let revision = currentRevision\n batch(() => {\n commit(planned.next)\n revision = stores.meta.getState().bumpRevision()\n })\n const event: ChangeEvent = {\n id: request.id ?? `change-${Date.now().toString(36)}-${counter++}`,\n revision,\n summary: request.summary,\n source: request.source,\n at: Date.now(),\n patch: planned.patch,\n inverse: planned.inverse,\n }\n for (const listener of [...changeListeners]) listener(event)\n return { ok: true, revision, applied, changed: true, patch: planned.patch, inverse: planned.inverse }\n }\n\n const controller: DiagramController = {\n stores,\n getSnapshot,\n subscribe(listener) {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n },\n get readOnly() {\n return readOnly\n },\n setReadOnly(message) {\n readOnly = message\n },\n apply(request) {\n if (readOnly && request.source !== REMOTE_SOURCE) return { ok: false, error: 'invalid', message: readOnly, currentRevision: stores.meta.getState().revision }\n const meta = stores.meta.getState()\n if (request.expectedRevision !== undefined && request.expectedRevision !== meta.revision) {\n return {\n ok: false,\n error: 'stale-revision',\n message: `The diagram is at revision ${meta.revision}, but this change was made against revision ${request.expectedRevision}. Read it again and retry.`,\n currentRevision: meta.revision,\n }\n }\n return run(planChanges(getSnapshot(), request.ops), request, request.ops.length)\n },\n applyPatch(patch, meta) {\n if (readOnly && meta.source !== REMOTE_SOURCE) return { ok: false, error: 'invalid', message: readOnly, currentRevision: stores.meta.getState().revision }\n const before = getSnapshot()\n const next = applyPatch(before, patch)\n // What undoes this exactly is what turns the result back into what it was.\n return run({ ok: true, next, patch, inverse: diffSnapshots(next, before), applied: 1 }, meta, 1)\n },\n onChange(listener) {\n changeListeners.add(listener)\n return () => void changeListeners.delete(listener)\n },\n onLoad(listener) {\n loadListeners.add(listener)\n return () => void loadListeners.delete(listener)\n },\n load(diagram, revision = 0) {\n batch(() => {\n // The revision and type always come from what is loaded; a diagram without a name keeps the current one.\n const meta = stores.meta.getState()\n meta.setMeta({ name: diagram.name || meta.name, description: diagram.description, type: diagram.type, revision })\n stores.groups.getState().setGroups(diagram.groups)\n stores.nodes.getState().setNodes(diagram.nodes)\n stores.edges.getState().setEdges(diagram.edges)\n })\n for (const listener of [...loadListeners]) listener()\n },\n export(meta) {\n const snap = getSnapshot()\n return {\n schemaVersion: (meta?.schemaVersion ?? DIAGRAM_SCHEMA_VERSION) as DiagramFile['schemaVersion'],\n name: meta?.name ?? snap.name,\n ...(snap.type && { type: snap.type }),\n ...((meta?.description ?? snap.description) !== undefined && { description: meta?.description ?? snap.description }),\n groups: snap.groups,\n nodes: snap.nodes,\n edges: snap.edges,\n }\n },\n batch,\n }\n\n if (initial) controller.load(initial, initial.revision ?? 0)\n return controller\n}\n","import type { DiagramController } from './controller'\nimport { readDiagram } from './format'\nimport type { DiagramFile } from './types'\nimport { describeVersionError } from './versioning'\n\n// Where a diagram comes from and goes to. The host supplies one of these; the controller never knows which: memory, the browser's\n// storage, a database, a REST service. A diagram is kept as the versioned file (see format.ts) with the revision it was saved at.\n\nexport interface StoredDiagram {\n file: DiagramFile\n revision: number\n}\n\nexport interface SaveMeta {\n // The revision this save is.\n revision: number\n // The revision the author last loaded or saved: null for a diagram that was never saved. A repository refuses the save when the stored\n // one is different, so a save never overwrites somebody else's work unseen.\n baseRevision: number | null\n}\n\nexport interface DiagramRepository {\n // null when there is no diagram with that id.\n load(id: string): Promise<StoredDiagram | null>\n // Rejects with a RepositoryConflictError when baseRevision is not the stored revision.\n save(id: string, file: DiagramFile, meta: SaveMeta): Promise<void>\n // Optional: tells the host when someone else changes the diagram (a live or shared source). Returns how to stop.\n subscribe?(id: string, onRemoteChange: (stored: StoredDiagram) => void): () => void\n}\n\nexport class RepositoryConflictError extends Error {\n readonly storedRevision: number | null\n constructor(id: string, storedRevision: number | null) {\n super(`“${id}” was changed somewhere else (it is at revision ${storedRevision ?? 'none'}). Load it again before saving.`)\n this.name = 'RepositoryConflictError'\n this.storedRevision = storedRevision\n }\n}\n\nconst conflicts = (stored: number | null, base: number | null) => stored !== base\n\n// ---- adapters ----\n\n// Kept in memory: tests, demos, and hosts that save somewhere else themselves.\nexport function memoryRepository(initial: Record<string, StoredDiagram> = {}): DiagramRepository {\n const kept = new Map(Object.entries(initial).map(([id, stored]) => [id, structuredClone(stored)]))\n return {\n async load(id) {\n const stored = kept.get(id)\n return stored ? structuredClone(stored) : null\n },\n async save(id, file, meta) {\n const stored = kept.get(id)?.revision ?? null\n if (conflicts(stored, meta.baseRevision)) throw new RepositoryConflictError(id, stored)\n kept.set(id, structuredClone({ file, revision: meta.revision }))\n },\n }\n}\n\n// Kept in a Storage (the browser's localStorage, or anything shaped like it).\nexport function storageRepository(storage: Pick<Storage, 'getItem' | 'setItem'>, prefix = 'diagram:'): DiagramRepository {\n return {\n async load(id) {\n const raw = storage.getItem(prefix + id)\n if (raw === null) return null\n let parsed: { file?: unknown; revision?: unknown }\n try {\n parsed = JSON.parse(raw) as typeof parsed\n } catch {\n throw new Error(`The saved diagram “${id}” is damaged.`)\n }\n const read = readDiagram(parsed.file)\n if (!read.ok) throw new Error(`The saved diagram “${id}” could not be read: ${describeVersionError(read.error)}`)\n return { file: read.value, revision: typeof parsed.revision === 'number' ? parsed.revision : 0 }\n },\n async save(id, file, meta) {\n const raw = storage.getItem(prefix + id)\n let stored: number | null = null\n if (raw !== null) {\n try {\n const revision = (JSON.parse(raw) as { revision?: unknown }).revision\n stored = typeof revision === 'number' ? revision : 0\n } catch {\n stored = null\n }\n }\n if (conflicts(stored, meta.baseRevision)) throw new RepositoryConflictError(id, stored)\n storage.setItem(prefix + id, JSON.stringify({ file, revision: meta.revision }))\n },\n }\n}\n\n// Kept by a REST service: GET {base}/{id} answers 200 with {file, revision} or 404, and PUT {base}/{id} takes {file, revision, baseRevision} and\n// answers 409 when baseRevision is not the stored one.\nexport function httpRepository(options: { baseUrl: string; fetch?: typeof fetch; headers?: Record<string, string> }): DiagramRepository {\n const call = options.fetch ?? ((...args: Parameters<typeof fetch>) => fetch(...args))\n const url = (id: string) => `${options.baseUrl.replace(/\\/+$/, '')}/${encodeURIComponent(id)}`\n return {\n async load(id) {\n const response = await call(url(id), { headers: { accept: 'application/json', ...options.headers } })\n if (response.status === 404) return null\n if (!response.ok) throw new Error(`Could not load “${id}” (${response.status}).`)\n const body = (await response.json()) as { file?: unknown; revision?: unknown }\n const read = readDiagram(body.file)\n if (!read.ok) throw new Error(`“${id}” could not be read: ${describeVersionError(read.error)}`)\n return { file: read.value, revision: typeof body.revision === 'number' ? body.revision : 0 }\n },\n async save(id, file, meta) {\n const response = await call(url(id), {\n method: 'PUT',\n headers: { 'content-type': 'application/json', ...options.headers },\n body: JSON.stringify({ file, revision: meta.revision, baseRevision: meta.baseRevision }),\n })\n if (response.status === 409) {\n const body = (await response.json().catch(() => ({}))) as { revision?: unknown }\n throw new RepositoryConflictError(id, typeof body.revision === 'number' ? body.revision : null)\n }\n if (!response.ok) throw new Error(`Could not save “${id}” (${response.status}).`)\n },\n }\n}\n\n// ---- binding a controller to a repository ----\n\nexport interface Binding {\n // Puts the stored diagram into the controller (false when there is none). Also what resumes saving after a conflict.\n load(): Promise<boolean>\n // Saves now if there is anything unsaved, and resolves when it is done: true when everything is saved (or there was nothing to save), false\n // when the save failed or met somebody else's change.\n flush(): Promise<boolean>\n dispose(): void\n}\n\nexport interface BindOptions {\n id: string\n // How long after a change to wait before saving, so a burst of changes is one save.\n debounceMs?: number\n // A save or a load failed. Saving is tried again at the next change.\n onError?: (error: Error) => void\n // The stored diagram changed somewhere else. Saving stops until `load()` is called.\n onConflict?: (error: RepositoryConflictError) => void\n}\n\n// Loads a diagram into a controller and keeps it saved: each accepted change schedules a save (a burst is one), saves run one at a time,\n// and a save that meets somebody else's change stops instead of overwriting it.\nexport function bindRepository(controller: DiagramController, repository: DiagramRepository, options: BindOptions): Binding {\n const { id, debounceMs = 300 } = options\n let baseRevision: number | null = null\n let timer: ReturnType<typeof setTimeout> | undefined\n let unsaved = false\n let stopped = false\n let chain: Promise<unknown> = Promise.resolve()\n\n const save = (): Promise<boolean> => {\n const step = chain.then(async () => {\n if (stopped) return false\n if (!unsaved) return true\n unsaved = false\n const revision = controller.getSnapshot().revision\n try {\n await repository.save(id, controller.export(), { revision, baseRevision })\n baseRevision = revision\n return true\n } catch (error) {\n unsaved = true\n if (error instanceof RepositoryConflictError) {\n stopped = true\n options.onConflict?.(error)\n } else options.onError?.(error instanceof Error ? error : new Error(String(error)))\n return false\n }\n })\n chain = step\n return step\n }\n\n const schedule = () => {\n unsaved = true\n if (timer) clearTimeout(timer)\n timer = setTimeout(() => void save(), debounceMs)\n }\n\n const off = controller.onChange(schedule)\n const offRemote = repository.subscribe?.(id, (stored) => {\n controller.load(stored.file, stored.revision)\n baseRevision = stored.revision\n unsaved = false\n })\n\n return {\n async load() {\n try {\n const stored = await repository.load(id)\n if (!stored) {\n baseRevision = null\n stopped = false\n return false\n }\n controller.load(stored.file, stored.revision)\n baseRevision = stored.revision\n unsaved = false\n stopped = false\n return true\n } catch (error) {\n options.onError?.(error instanceof Error ? error : new Error(String(error)))\n return false\n }\n },\n async flush() {\n if (timer) clearTimeout(timer)\n timer = undefined\n return save()\n },\n dispose() {\n if (timer) clearTimeout(timer)\n off()\n offRemote?.()\n },\n }\n}\n","// Visual emphasis a diagram can show on its nodes and edges. It says nothing about why: a scenario playing, a search, a review could all\n// drive it. It is plain data, so whatever produces it (the scenario player) and whatever draws it (a canvas) agree on it here and import\n// nothing of each other.\n\nexport const NODE_HIGHLIGHTS = ['active', 'visited', 'success', 'failure', 'blocked'] as const\nexport const EDGE_HIGHLIGHTS = ['active', 'visited'] as const\n\nexport type NodeHighlight = (typeof NODE_HIGHLIGHTS)[number]\nexport type EdgeHighlight = (typeof EDGE_HIGHLIGHTS)[number]\n\nexport interface Highlights {\n nodes: Record<string, NodeHighlight>\n edges: Record<string, EdgeHighlight>\n // Fade everything that is not highlighted, so the highlighted part stands out.\n dimmed?: boolean\n}\n","import type { NodeDef } from './format'\n\n// A file named in a node's Markdown, written as inline code: `path/to/file.ts`, `path/to/file.ts:42`, `path/to/file.ts:42-60`, and with the\n// repo it is in first when the project has several: `website:lib/api.ts:90`. Pure, so the editor, the website and the planner share it.\n\nexport interface CodeRef {\n repo?: string\n path: string\n start?: number\n end?: number\n}\n\n// An optional repo id and \":\", then a path of letters, digits and . _ - @ / ending in a file name with an extension, then an optional :line[-line].\n// A repo id has no \".\" or \"/\", so `lib/a.ts:9` and `a.ts:9` never read as a repo.\nconst REF = /^(?:([A-Za-z0-9][A-Za-z0-9_-]{0,39}):)?((?:[A-Za-z0-9_@.-]+\\/)*[A-Za-z0-9_@-][A-Za-z0-9_@.-]*\\.[A-Za-z0-9]+)(?::(\\d{1,6})(?:-(\\d{1,6}))?)?$/\n\nexport function parseCodeRef(text: string): CodeRef | null {\n const match = REF.exec(text.trim())\n if (!match) return null\n const [, repo, path, a, b] = match\n if (path.split('/').some((s) => s === '..' || s === '.')) return null\n const base = repo === undefined ? { path } : { repo, path }\n if (a === undefined) return base\n const start = Number(a)\n const end = b === undefined ? undefined : Number(b)\n if (start < 1 || (end !== undefined && end < start)) return null\n return end === undefined || end === start ? { ...base, start } : { ...base, start, end }\n}\n\nexport function describeCodeRef(ref: CodeRef): string {\n const lines = ref.start === undefined ? '' : ref.end === undefined ? `:${ref.start}` : `:${ref.start}-${ref.end}`\n return `${ref.repo ? `${ref.repo}:` : ''}${ref.path}${lines}`\n}\n\n// The code references in some Markdown: inline code spans only, never inside a fenced block.\nexport function markdownCodeRefs(markdown: string): CodeRef[] {\n const refs: CodeRef[] = []\n for (const match of markdown.replace(/^(```|~~~)[\\s\\S]*?^\\1/gm, '').matchAll(/`([^`\\n]+)`/g)) {\n const ref = parseCodeRef(match[1])\n if (ref) refs.push(ref)\n }\n return refs\n}\n\nexport interface UncoveredRef {\n nodeId: string\n title: string\n ref: CodeRef\n}\n\n// Files a node's Markdown (body and decisions) names that none of its `links` lists. The Code tab and the drift check read only `links`, so\n// such a file is clickable but invisible to both. A reference with no repo matches a link in any repo; one with a repo needs that repo\n// (a link with none counts as the default repo, which only the host knows, so it matches too).\nexport function uncoveredRefs(nodes: (Pick<NodeDef, 'id' | 'title' | 'decisions' | 'links'> & Partial<Pick<NodeDef, 'body'>>)[]): UncoveredRef[] {\n const out: UncoveredRef[] = []\n for (const node of nodes) {\n const seen = new Set<string>()\n for (const ref of [...markdownCodeRefs(node.body ?? ''), ...markdownCodeRefs(node.decisions ?? '')]) {\n const key = `${ref.repo ?? ''}:${ref.path}`\n if (seen.has(key)) continue\n seen.add(key)\n const covered = (node.links ?? []).some((l) => l.path === ref.path && (ref.repo === undefined || l.repo === undefined || l.repo === ref.repo))\n if (!covered) out.push({ nodeId: node.id, title: node.title, ref })\n }\n }\n return out\n}\n","import type { NodeDef } from './format'\nimport { uncoveredRefs } from './codeRefs'\nimport type { UncoveredRef } from './codeRefs'\n\n// Checks the code links on nodes against the code as it is now. It only reports: it never changes a link, and it reads no files itself\n// (the host passes their text), so the same check runs in the desktop app, in a script and on a server. The result says \"possibly stale\",\n// never \"verified\": a matching hash means the linked lines are unchanged, not that the node's text is still true.\n\nexport type LinkStatus = 'ok' | 'changed' | 'moved' | 'missing' | 'unchecked'\n\n// Worst first. A node shows the worst status among its links.\nexport const LINK_STATUS_ORDER: LinkStatus[] = ['missing', 'changed', 'moved', 'unchecked', 'ok']\n\nexport interface LinkReport {\n nodeId: string\n title: string\n // Position in the node's `links`.\n index: number\n // The repo the path is in, when the link names one.\n repo?: string\n path: string\n symbol?: string\n lines?: [number, number]\n status: LinkStatus\n expectedHash?: string\n actualHash?: string\n // For `moved`: where the same lines are now, so the link can be re-pointed.\n newLines?: [number, number]\n message: string\n}\n\nexport interface LinkCheck {\n summary: Record<LinkStatus, number>\n // Only links that are not ok.\n problems: LinkReport[]\n // The worst status of each node that has links. A node with none is left out: nothing can be said about it.\n nodes: Record<string, LinkStatus>\n // Paths the check needed that the host could not supply, so their links are reported `unchecked`.\n unread: string[]\n // Files a node's Markdown names that none of its links lists (see uncoveredRefs). Only for nodes whose body was passed in.\n uncovered: UncoveredRef[]\n}\n\n// What a file is called in `FileTexts` and `unread`: `repo:path` when the link names a repo, else the bare path. Two repos can hold the same\n// path (both of ours have packages/diagram-core/src/format.ts), so a repo-qualified link must never be looked up by its path alone.\nexport const linkKey = (link: { repo?: string; path: string }) => (link.repo ? `${link.repo}:${link.path}` : link.path)\n\n// The text of each file by `linkKey`, or null when it does not exist. A key left out was not read.\nexport type FileTexts = Record<string, string | null | undefined>\n\nconst HASH_LENGTH = 12\nconst MAX_SCAN_LINES = 20000\n\nconst hex = (bytes: ArrayBuffer) => [...new Uint8Array(bytes)].map((b) => b.toString(16).padStart(2, '0')).join('')\n\n// The hash a link stores: the first 12 hex characters of the SHA-256 of the linked lines, each followed by a newline\n// (the same as `sed -n 'A,Bp' file | shasum -a 256`).\nexport async function hashLines(lines: string[]): Promise<string> {\n const data = new TextEncoder().encode(lines.join('\\n') + '\\n')\n return hex(await globalThis.crypto.subtle.digest('SHA-256', data)).slice(0, HASH_LENGTH)\n}\n\nconst splitLines = (text: string) => {\n const lines = text.split('\\n')\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()\n return lines.map((l) => (l.endsWith('\\r') ? l.slice(0, -1) : l))\n}\n\nconst escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\nconst hasSymbol = (text: string, symbol: string) => new RegExp(`(?<![\\\\w$])${escapeRegExp(symbol)}(?![\\\\w$])`).test(text)\n\n// The files (by `linkKey`) the links of these nodes name, so a host knows which to read.\nexport function linkedPaths(nodes: Pick<NodeDef, 'links'>[]): string[] {\n return [...new Set(nodes.flatMap((n) => (n.links ?? []).map(linkKey)))]\n}\n\nexport async function checkLinks(nodes: (Pick<NodeDef, 'id' | 'title' | 'links'> & Partial<Pick<NodeDef, 'body' | 'decisions'>>)[], files: FileTexts, options: { nodeId?: string } = {}): Promise<LinkCheck> {\n const summary: Record<LinkStatus, number> = { ok: 0, changed: 0, moved: 0, missing: 0, unchecked: 0 }\n const problems: LinkReport[] = []\n const worst: Record<string, LinkStatus> = {}\n const unread = new Set<string>()\n const lineCache = new Map<string, string[]>()\n const linesOf = (path: string, text: string) => {\n let lines = lineCache.get(path)\n if (!lines) lineCache.set(path, (lines = splitLines(text)))\n return lines\n }\n\n for (const node of nodes) {\n if (options.nodeId !== undefined && node.id !== options.nodeId) continue\n for (const [index, link] of (node.links ?? []).entries()) {\n const base = { nodeId: node.id, title: node.title, index, ...(link.repo && { repo: link.repo }), path: link.path, ...(link.symbol && { symbol: link.symbol }), ...(link.lines && { lines: link.lines }) }\n const done = (status: LinkStatus, message: string, extra: Partial<LinkReport> = {}) => {\n summary[status]++\n if (status !== 'ok') problems.push({ ...base, status, message, ...(link.hash && { expectedHash: link.hash }), ...extra })\n if (!worst[node.id] || LINK_STATUS_ORDER.indexOf(status) < LINK_STATUS_ORDER.indexOf(worst[node.id])) worst[node.id] = status\n }\n\n const key = linkKey(link)\n const text = files[key]\n if (text === undefined) {\n unread.add(key)\n done('unchecked', `${key} was not read, so this link could not be checked.`)\n continue\n }\n if (text === null) {\n done('missing', `${key} does not exist. It may have been renamed or deleted.`)\n continue\n }\n if (link.symbol && !hasSymbol(text, link.symbol)) {\n done('missing', `${key} no longer contains \"${link.symbol}\".`)\n continue\n }\n if (!link.lines || !link.hash) {\n done('unchecked', `${key} exists${link.symbol ? ` and contains \"${link.symbol}\"` : ''}, but the link has no ${link.lines ? 'hash' : 'lines'} to compare.`)\n continue\n }\n\n const [from, to] = link.lines\n const lines = linesOf(key, text)\n const expected = link.hash.toLowerCase()\n const matches = (hash: string) => hash.startsWith(expected) || expected.startsWith(hash)\n const actual = to <= lines.length ? await hashLines(lines.slice(from - 1, to)) : undefined\n if (actual && matches(actual)) {\n done('ok', '')\n continue\n }\n\n // The lines may only have shifted (code added above): look for the same text elsewhere in the file.\n const size = to - from + 1\n let shifted: [number, number] | undefined\n if (lines.length <= MAX_SCAN_LINES) {\n for (let start = 1; start + size - 1 <= lines.length && !shifted; start++) {\n if (start === from) continue\n if (matches(await hashLines(lines.slice(start - 1, start - 1 + size)))) shifted = [start, start + size - 1]\n }\n }\n if (shifted) done('moved', `The same lines are now at ${key}:${shifted[0]}${shifted[1] !== shifted[0] ? `-${shifted[1]}` : ''}.`, { newLines: shifted, ...(actual && { actualHash: actual }) })\n else done('changed', `${key}:${from}${to !== from ? `-${to}` : ''} no longer matches the hash taken when the link was made. The node is possibly stale.`, actual ? { actualHash: actual } : {})\n }\n }\n const covered = nodes.filter((n) => (options.nodeId === undefined || n.id === options.nodeId) && (n.body !== undefined || n.decisions !== undefined))\n return { summary, problems, nodes: worst, unread: [...unread], uncovered: uncoveredRefs(covered) }\n}\n","import type { DiagramFile } from './format'\n\n// Code links must be able to open on GitHub, so nothing is left to be guessed. Two checks share this rule: one for a design being edited\n// (its links must name repos the project's workspace knows), and one for a design being published (every repo its links use is listed in\n// `repos` with a GitHub remote and a commit).\n\n/** Where a repo is on GitHub, written one way only: github.com/owner/repo. */\nexport const GITHUB_REMOTE = /^github\\.com\\/[\\w.-]+\\/[\\w.-]+$/\n\ntype LinkedNode = { links?: { repo?: string; path?: string }[] }\ntype KnownRepo = { id: string; remote?: string; default?: boolean }\n\n/** The repo a link belongs to: the one it names, or the default repo when it names none (undefined when there is none to pick). */\nexport function linkRepo<R extends KnownRepo>(link: { repo?: string }, known: R[]): R | undefined {\n return link.repo ? known.find((item) => item.id === link.repo) : (known.find((item) => item.default) ?? known[0])\n}\n\n/** A path inside a repo's folder: relative, no \"..\", no empty parts. */\nexport const isRepoRelativePath = (path: string) => path.length > 0 && !/^([/\\\\]|[A-Za-z]:)/.test(path) && !path.split(/[/\\\\]/).some((part) => part === '..' || part === '')\n\n/**\n * While editing: the problems in the links of these nodes, given the repos of the project's workspace (`.cakeslice/workspace.json`, where each\n * has a folder and a GitHub remote). A link must resolve both ways: its repo (the one it names, or the default when it names none; with\n * several repos it must name one) is listed and has a remote written as github.com/owner/repo, so it can open on the web, and its path stays\n * inside that repo's folder, so it can open on disk. The remote is only checked to be defined, never looked up. That the file exists is\n * checked where the disk can be read. With no repos known, no link is allowed.\n */\nexport function workspaceLinkIssues(nodes: LinkedNode[], known: KnownRepo[]): string[] {\n const issues = new Set<string>()\n const ids = known.map((repo) => repo.id).join(', ')\n for (const node of nodes) for (const link of node.links ?? []) {\n if (!known.length) { issues.add('links: this project lists no repos in .cakeslice/workspace.json, so a link has nowhere to resolve'); continue }\n if (!link.repo && known.length > 1) { issues.add(`links: with several repos, every link must name its repo (${ids})`); continue }\n const repo = linkRepo(link, known)\n if (!repo) issues.add(`links: repo \"${link.repo}\" is not in the workspace; use one of ${ids}`)\n else if (!repo.remote || !GITHUB_REMOTE.test(repo.remote)) issues.add(`links: repo \"${repo.id}\" has no GitHub remote in the workspace; add \"remote\": \"github.com/owner/repo\"`)\n if (link.path !== undefined && !isRepoRelativePath(link.path)) issues.add(`links: path \"${link.path}\" must be a file inside the repo: relative, with no \"..\"`)\n }\n return [...issues].slice(0, 5)\n}\n\n/**\n * When publishing: every repo the links point into is listed in `repos` with a remote written as github.com/owner/repo and a commit `sha` (or at\n * least a `branch`). A link with no `repo` belongs to the only repo listed, so with several repos each link must name its own.\n */\nexport function publishedRepoIssues(diagram: Pick<DiagramFile, 'nodes' | 'repos'>): string[] {\n const issues: string[] = []\n const repos = diagram.repos ?? {}\n const ids = Object.keys(repos)\n const used = new Set<string>()\n let unnamed = false\n for (const node of diagram.nodes) for (const link of node.links ?? []) { if (link.repo) used.add(link.repo); else unnamed = true }\n if (unnamed && ids.length === 1) used.add(ids[0])\n if (unnamed && ids.length !== 1) {\n issues.push(ids.length === 0\n ? 'repos: this design has code links, so list each repo it links into, for example \"repos\": { \"website\": { \"remote\": \"github.com/you/app\", \"sha\": \"<commit>\" } }'\n : 'links: with several repos, every link must name its repo')\n }\n for (const id of used) {\n const repo = repos[id]\n if (!repo) issues.push(`repos.${id}: a link names this repo, but it is not listed in repos`)\n else if (!repo.remote || !GITHUB_REMOTE.test(repo.remote)) issues.push(`repos.${id}.remote: write the GitHub address as github.com/owner/repo`)\n else if (!repo.sha && !repo.branch) issues.push(`repos.${id}: give the commit \"sha\" the links were written against (or at least a \"branch\")`)\n }\n return issues.slice(0, 5)\n}\n"],"mappings":"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","names":["group","id","edge","node","edge","group","node","checkLinks","node","node"]}
|