@inharness-ai/claude4spec 1.0.18 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/.claude/skills/c4s-brief-implementer/SKILL.md +11 -0
  2. package/.claude/skills/c4s-spec-reader/SKILL.md +14 -0
  3. package/CHANGELOG.md +12 -0
  4. package/dist/bin/c4s/commands/tagged-list-mixed.js +2 -0
  5. package/dist/bin/c4s/commands/tagged-list-mixed.js.map +1 -1
  6. package/dist/client/assets/{arc-BoIjQ4Rl.js → arc-Y_Y7YYxJ.js} +1 -1
  7. package/dist/client/assets/{architectureDiagram-3BPJPVTR-BxBVRaEg.js → architectureDiagram-3BPJPVTR-BvfJSQGS.js} +1 -1
  8. package/dist/client/assets/{blockDiagram-GPEHLZMM-CUZNbllz.js → blockDiagram-GPEHLZMM-0ER_5Ga5.js} +1 -1
  9. package/dist/client/assets/{c4Diagram-AAUBKEIU-CvuTKwEz.js → c4Diagram-AAUBKEIU-CulSeIur.js} +1 -1
  10. package/dist/client/assets/channel-COuoa9K9.js +1 -0
  11. package/dist/client/assets/{chunk-2J33WTMH-CEO4c2pf.js → chunk-2J33WTMH-BR0UTxIH.js} +1 -1
  12. package/dist/client/assets/{chunk-4BX2VUAB-Bu8DCHu0.js → chunk-4BX2VUAB-C3CE1iTm.js} +1 -1
  13. package/dist/client/assets/{chunk-55IACEB6-DIN8FXXB.js → chunk-55IACEB6-WYG0SMCq.js} +1 -1
  14. package/dist/client/assets/{chunk-727SXJPM-DArSpufF.js → chunk-727SXJPM-CFxvH3KU.js} +1 -1
  15. package/dist/client/assets/{chunk-AQP2D5EJ-DvyQ3boK.js → chunk-AQP2D5EJ-CW3tCRq5.js} +1 -1
  16. package/dist/client/assets/{chunk-FMBD7UC4-DzYhHpnC.js → chunk-FMBD7UC4-DhWed3oG.js} +1 -1
  17. package/dist/client/assets/{chunk-ND2GUHAM-DocECmh1.js → chunk-ND2GUHAM-wKw1Twd3.js} +1 -1
  18. package/dist/client/assets/{chunk-QZHKN3VN-cUsgOLYm.js → chunk-QZHKN3VN-N2YJn9Rv.js} +1 -1
  19. package/dist/client/assets/classDiagram-4FO5ZUOK-BESpN0be.js +1 -0
  20. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BESpN0be.js +1 -0
  21. package/dist/client/assets/{cose-bilkent-S5V4N54A-BXlU_dXh.js → cose-bilkent-S5V4N54A-BwTia-tr.js} +1 -1
  22. package/dist/client/assets/{dagre-BM42HDAG-CmrHrBPK.js → dagre-BM42HDAG-qaDS43Ui.js} +1 -1
  23. package/dist/client/assets/{diagram-2AECGRRQ-CV4Tc8wQ.js → diagram-2AECGRRQ-D_kuEzAN.js} +1 -1
  24. package/dist/client/assets/{diagram-5GNKFQAL-BiBsPCGc.js → diagram-5GNKFQAL-BYj6JmFh.js} +1 -1
  25. package/dist/client/assets/{diagram-KO2AKTUF-DA09S_op.js → diagram-KO2AKTUF-C5GerpKU.js} +1 -1
  26. package/dist/client/assets/{diagram-LMA3HP47-DBaod99I.js → diagram-LMA3HP47-BCCWR_VJ.js} +1 -1
  27. package/dist/client/assets/{diagram-OG6HWLK6-ClJXH4o0.js → diagram-OG6HWLK6-zQ3cOHd6.js} +1 -1
  28. package/dist/client/assets/{erDiagram-TEJ5UH35-9ic-AAly.js → erDiagram-TEJ5UH35-CXGKcFZT.js} +1 -1
  29. package/dist/client/assets/{flowDiagram-I6XJVG4X-8UWNEpWY.js → flowDiagram-I6XJVG4X-CtZxh2DT.js} +1 -1
  30. package/dist/client/assets/{ganttDiagram-6RSMTGT7-ZMUkzsKr.js → ganttDiagram-6RSMTGT7-BUdwVJfD.js} +1 -1
  31. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-5MgsfBQ-.js → gitGraphDiagram-PVQCEYII-DAJUpS0c.js} +1 -1
  32. package/dist/client/assets/{index-B3XLrPs9.js → index-CSz40CWW.js} +1 -1
  33. package/dist/client/assets/{index-D7DH-SO5.js → index-g9hdRfKL.js} +1 -1
  34. package/dist/client/assets/{index-BSPNo0Xa.js → index-nd9N-ch1.js} +176 -179
  35. package/dist/client/assets/{infoDiagram-5YYISTIA-DnoyGZzF.js → infoDiagram-5YYISTIA-Dkqaeq-d.js} +1 -1
  36. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DXzuF94t.js → ishikawaDiagram-YF4QCWOH-BDZbcL20.js} +1 -1
  37. package/dist/client/assets/{journeyDiagram-JHISSGLW-AEPglDXi.js → journeyDiagram-JHISSGLW-DQ8LraKA.js} +1 -1
  38. package/dist/client/assets/{kanban-definition-UN3LZRKU-D0-kFv2f.js → kanban-definition-UN3LZRKU-CQOW2Mao.js} +1 -1
  39. package/dist/client/assets/{linear-CZwFXsxu.js → linear-B-ZW0b9t.js} +1 -1
  40. package/dist/client/assets/{mermaid.core-BikmxM36.js → mermaid.core-BdFxxBuE.js} +4 -4
  41. package/dist/client/assets/{mindmap-definition-RKZ34NQL-C95lTdDB.js → mindmap-definition-RKZ34NQL-CcsZCub_.js} +1 -1
  42. package/dist/client/assets/{pieDiagram-4H26LBE5-CMeXZFX8.js → pieDiagram-4H26LBE5-DpFgB1Qa.js} +1 -1
  43. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-D1dG1F2s.js → quadrantDiagram-W4KKPZXB-CItGhZSD.js} +1 -1
  44. package/dist/client/assets/{requirementDiagram-4Y6WPE33-RPNqJRNK.js → requirementDiagram-4Y6WPE33-CMfRtv6V.js} +1 -1
  45. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DQ4EB8Xb.js → sankeyDiagram-5OEKKPKP-LUqs9QQq.js} +1 -1
  46. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-Dn-VJOlP.js → sequenceDiagram-3UESZ5HK-BZt_Nz-I.js} +1 -1
  47. package/dist/client/assets/{stateDiagram-AJRCARHV-CCpprZJO.js → stateDiagram-AJRCARHV-DDCaA4Lh.js} +1 -1
  48. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DfEoRDHz.js +1 -0
  49. package/dist/client/assets/{timeline-definition-PNZ67QCA-h0cUr7kp.js → timeline-definition-PNZ67QCA-Chrt6eh8.js} +1 -1
  50. package/dist/client/assets/{vennDiagram-CIIHVFJN-BTZzKsPH.js → vennDiagram-CIIHVFJN-7L-WzZJY.js} +1 -1
  51. package/dist/client/assets/{wardley-L42UT6IY-D1eOaFAH.js → wardley-L42UT6IY-CTNWz-UZ.js} +1 -1
  52. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-wsnKkjjR.js → wardleyDiagram-YWT4CUSO-BIhHmbRz.js} +1 -1
  53. package/dist/client/assets/{xychartDiagram-2RQKCTM6-BCebuOGO.js → xychartDiagram-2RQKCTM6-eqxCYjS7.js} +1 -1
  54. package/dist/client/index.html +1 -1
  55. package/dist/server/db/migrations/040_diagram.sql +17 -0
  56. package/dist/server/domain/raw-entity-reader.d.ts +1 -1
  57. package/dist/server/domain/raw-entity-reader.js +5 -1
  58. package/dist/server/domain/raw-entity-reader.js.map +1 -1
  59. package/dist/server/entities/diagram/mcp-server.d.ts +10 -0
  60. package/dist/server/entities/diagram/mcp-server.js +141 -0
  61. package/dist/server/entities/diagram/mcp-server.js.map +1 -0
  62. package/dist/server/entities/diagram/plugin.d.ts +3 -0
  63. package/dist/server/entities/diagram/plugin.js +41 -0
  64. package/dist/server/entities/diagram/plugin.js.map +1 -0
  65. package/dist/server/entities/diagram/routes.d.ts +5 -0
  66. package/dist/server/entities/diagram/routes.js +83 -0
  67. package/dist/server/entities/diagram/routes.js.map +1 -0
  68. package/dist/server/entities/diagram/serializer.d.ts +11 -0
  69. package/dist/server/entities/diagram/serializer.js +147 -0
  70. package/dist/server/entities/diagram/serializer.js.map +1 -0
  71. package/dist/server/entities/diagram/services.d.ts +40 -0
  72. package/dist/server/entities/diagram/services.js +202 -0
  73. package/dist/server/entities/diagram/services.js.map +1 -0
  74. package/dist/server/entities/diagram/system-prompt.d.ts +2 -0
  75. package/dist/server/entities/diagram/system-prompt.js +15 -0
  76. package/dist/server/entities/diagram/system-prompt.js.map +1 -0
  77. package/dist/server/entities/diagram/validate.d.ts +9 -0
  78. package/dist/server/entities/diagram/validate.js +35 -0
  79. package/dist/server/entities/diagram/validate.js.map +1 -0
  80. package/dist/server/external-skills/brief-implementer-template.d.ts +1 -1
  81. package/dist/server/external-skills/brief-implementer-template.js +11 -0
  82. package/dist/server/external-skills/brief-implementer-template.js.map +1 -1
  83. package/dist/server/external-skills/spec-reader-template.d.ts +1 -1
  84. package/dist/server/external-skills/spec-reader-template.js +14 -0
  85. package/dist/server/external-skills/spec-reader-template.js.map +1 -1
  86. package/dist/server/mcp/c4s-reader.js +2 -0
  87. package/dist/server/mcp/c4s-reader.js.map +1 -1
  88. package/dist/server/serialization/registerAll.js +2 -0
  89. package/dist/server/serialization/registerAll.js.map +1 -1
  90. package/dist/server/serialization/writer.d.ts +2 -1
  91. package/dist/server/services/chat-context.js +5 -15
  92. package/dist/server/services/chat-context.js.map +1 -1
  93. package/dist/server/services/entity-indexer.js +4 -0
  94. package/dist/server/services/entity-indexer.js.map +1 -1
  95. package/dist/server/services/entity-store.js +9 -1
  96. package/dist/server/services/entity-store.js.map +1 -1
  97. package/dist/server/services/entity-writer.d.ts +2 -0
  98. package/dist/server/services/entity-writer.js +12 -0
  99. package/dist/server/services/entity-writer.js.map +1 -1
  100. package/dist/server/services/references.js +10 -0
  101. package/dist/server/services/references.js.map +1 -1
  102. package/dist/server/workspace/project-context.js +9 -0
  103. package/dist/server/workspace/project-context.js.map +1 -1
  104. package/dist/shared/entities.d.ts +43 -1
  105. package/dist/shared/entities.js.map +1 -1
  106. package/dist/shared/xml-tags.d.ts +3 -3
  107. package/dist/shared/xml-tags.js +10 -4
  108. package/dist/shared/xml-tags.js.map +1 -1
  109. package/package.json +1 -1
  110. package/dist/client/assets/channel-Ba45UACg.js +0 -1
  111. package/dist/client/assets/classDiagram-4FO5ZUOK-DigWu50-.js +0 -1
  112. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DigWu50-.js +0 -1
  113. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DZMO7v7d.js +0 -1
@@ -0,0 +1,141 @@
1
+ import { createMcpServer, mcpTool } from '@inharness-ai/agent-adapters';
2
+ import { z } from 'zod';
3
+ import { validateDiagramSource } from './validate.js';
4
+ import { DomainError } from '../../services/tags.js';
5
+ const formatSchema = z.enum(['mermaid', 'd2']);
6
+ export function createDiagramToolsServer(deps) {
7
+ const ok = (payload) => ({
8
+ content: [{ type: 'text', text: JSON.stringify(payload) }],
9
+ });
10
+ const fail = (err) => {
11
+ const code = err instanceof DomainError ? err.code : 'INTERNAL';
12
+ const message = err instanceof Error ? err.message : String(err);
13
+ return {
14
+ content: [{ type: 'text', text: JSON.stringify({ error: message, code }) }],
15
+ isError: true,
16
+ };
17
+ };
18
+ const createDiagram = mcpTool('create_diagram', 'Create a new diagram entity. The DSL `source` is the source of truth (rendered live on pages). ' +
19
+ 'A page references the diagram via a self-closing `<diagram slug="…" caption="…"/>` tag — `caption` is a ' +
20
+ 'per-reference attribute, NOT stored here. Slug: explicit `slug` | slugify(`caption`) | diagram-<nanoid>. ' +
21
+ '`source` is validated with mermaid.parse() → warnings only, never blocks.', {
22
+ source: z.string().optional().describe('DSL body (mermaid). May be empty (placeholder).'),
23
+ format: formatSchema.optional().describe("Diagram language (default 'mermaid')."),
24
+ caption: z
25
+ .string()
26
+ .optional()
27
+ .describe('Transient — seeds the slug only (slugify(caption)); NOT persisted on the entity.'),
28
+ slug: z.string().optional().describe('Explicit slug; collisions get a -2/-3 suffix.'),
29
+ tags: z.array(z.string()).optional().describe('Tag slugs; non-existent tags are auto-created.'),
30
+ }, async (args) => {
31
+ try {
32
+ const input = {
33
+ source: args.source,
34
+ format: args.format,
35
+ caption: args.caption,
36
+ slug: args.slug,
37
+ tags: args.tags,
38
+ };
39
+ const diagram = deps.diagramService.create(input, 'agent');
40
+ const warnings = await validateDiagramSource(diagram.format, diagram.source);
41
+ deps.ws.broadcast({ kind: 'entity:changed', entityType: 'diagram', slug: diagram.slug });
42
+ return ok({
43
+ id: diagram.slug,
44
+ slug: diagram.slug,
45
+ type: 'diagram',
46
+ ...(warnings.length ? { warnings } : {}),
47
+ });
48
+ }
49
+ catch (err) {
50
+ return fail(err);
51
+ }
52
+ });
53
+ const getDiagram = mcpTool('get_diagram', 'Get a diagram by slug (format, source, tags).', { slug: z.string() }, async (args) => {
54
+ const diagram = deps.diagramService.getBySlug(String(args.slug));
55
+ if (!diagram)
56
+ return fail(new DomainError('NOT_FOUND', `diagram '${args.slug}' not found`));
57
+ return ok(diagram);
58
+ });
59
+ const updateDiagram = mcpTool('update_diagram', 'Update a diagram (partial). Slug is stable; rename only via newSlug (auto-propagates page references). ' +
60
+ '`source` is validated with mermaid.parse() → warnings only, never blocks.', {
61
+ slug: z.string(),
62
+ data: z
63
+ .object({
64
+ source: z.string().optional(),
65
+ format: formatSchema.optional(),
66
+ })
67
+ .describe('Partial fields to update.'),
68
+ newSlug: z.string().optional().describe('Explicit slug rename.'),
69
+ }, async (args) => {
70
+ try {
71
+ const data = args.data;
72
+ const input = {
73
+ source: data.source,
74
+ format: data.format,
75
+ newSlug: args.newSlug,
76
+ };
77
+ const { diagram, previousSlug } = deps.diagramService.update(String(args.slug), input, 'agent');
78
+ if (diagram.slug !== previousSlug) {
79
+ await deps.referencesService.propagateSlugChange('diagram', previousSlug, diagram.slug);
80
+ }
81
+ const warnings = await validateDiagramSource(diagram.format, diagram.source);
82
+ deps.ws.broadcast({ kind: 'entity:changed', entityType: 'diagram', slug: diagram.slug });
83
+ return ok({ slug: diagram.slug, updated: true, ...(warnings.length ? { warnings } : {}) });
84
+ }
85
+ catch (err) {
86
+ return fail(err);
87
+ }
88
+ });
89
+ const deleteDiagram = mcpTool('delete_diagram', 'Delete a diagram. Returns pages with now-broken `<diagram/>` references.', { slug: z.string() }, async (args) => {
90
+ try {
91
+ const slug = String(args.slug);
92
+ const refs = await deps.referencesService.findReferences('diagram', slug);
93
+ deps.diagramService.remove(slug, 'agent', refs.map((r) => ({
94
+ pagePath: r.pagePath,
95
+ tagType: r.tagType,
96
+ line: r.line,
97
+ slug,
98
+ type: 'diagram',
99
+ })));
100
+ deps.ws.broadcast({ kind: 'entity:changed', entityType: 'diagram', slug });
101
+ return ok({
102
+ deleted: true,
103
+ brokenReferences: refs.map((r) => ({ pagePath: r.pagePath, count: 1 })),
104
+ });
105
+ }
106
+ catch (err) {
107
+ return fail(err);
108
+ }
109
+ });
110
+ const listDiagrams = mcpTool('list_diagrams', 'List diagrams with optional tag/search filtering. Returns slug, format, tags and a total.', {
111
+ tags: z.array(z.string()).optional(),
112
+ tagFilter: z.enum(['and', 'or']).optional(),
113
+ search: z.string().optional(),
114
+ limit: z.number().optional(),
115
+ offset: z.number().optional(),
116
+ }, async (args) => {
117
+ try {
118
+ const query = {
119
+ tags: args.tags,
120
+ tagFilter: args.tagFilter,
121
+ search: args.search,
122
+ limit: args.limit,
123
+ offset: args.offset,
124
+ };
125
+ const diagrams = deps.diagramService.list(query);
126
+ const total = deps.diagramService.count(query);
127
+ return ok({
128
+ diagrams: diagrams.map((d) => ({ slug: d.slug, format: d.format, tags: d.tags })),
129
+ total,
130
+ });
131
+ }
132
+ catch (err) {
133
+ return fail(err);
134
+ }
135
+ });
136
+ return createMcpServer({
137
+ name: 'diagram-tools',
138
+ tools: [createDiagram, getDiagram, updateDiagram, deleteDiagram, listDiagrams],
139
+ });
140
+ }
141
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../../../src/server/entities/diagram/mcp-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { BackendModule, PluginRegistry } from '../../core/plugin-host/types.js';
2
+ export declare const diagramBackendModule: BackendModule;
3
+ export declare function onRegister(registry: PluginRegistry): void;
@@ -0,0 +1,41 @@
1
+ import { nanoid } from 'nanoid';
2
+ import { slugify } from '../../services/slug.js';
3
+ import { diagramSerializer } from './serializer.js';
4
+ import { diagramSystemPrompt } from './system-prompt.js';
5
+ import { diagramsRouter } from './routes.js';
6
+ import { DiagramService } from './services.js';
7
+ import { createDiagramToolsServer } from './mcp-server.js';
8
+ export const diagramBackendModule = {
9
+ type: 'diagram',
10
+ table: 'diagram',
11
+ label: 'Diagram',
12
+ labelPlural: 'Diagrams',
13
+ // After design-system (60) — diagrams sit at the end of ELEMENTS.
14
+ displayOrder: 70,
15
+ pathPrefix: '/diagrams',
16
+ // Decyzja #1: explicit slug | slugify(caption) | diagram-<nanoid(8)>.
17
+ // The service does the authoritative generation (with collision suffixing);
18
+ // this manifest helper mirrors the fallback for generic callers.
19
+ slugFrom: (data) => {
20
+ const d = (data ?? {});
21
+ return d.slug?.trim() || (d.caption ? slugify(d.caption) : `diagram-${nanoid(8)}`);
22
+ },
23
+ serializer: diagramSerializer,
24
+ systemPrompt: diagramSystemPrompt,
25
+ backend: {
26
+ mount(ctx) {
27
+ const service = new DiagramService(ctx.db, ctx.tagsService, ctx.versionService, ctx.entityStore);
28
+ ctx.app.use(`${diagramBackendModule.pathPrefix}`, diagramsRouter(service, ctx.referencesService, ctx.ws));
29
+ ctx.registerMcpServer(`${diagramBackendModule.type}-tools`, () => createDiagramToolsServer({
30
+ diagramService: service,
31
+ referencesService: ctx.referencesService,
32
+ ws: ctx.ws,
33
+ }));
34
+ ctx.registerEntityService(diagramBackendModule.type, service);
35
+ },
36
+ },
37
+ };
38
+ export function onRegister(registry) {
39
+ registry.registerEntityModule(diagramBackendModule);
40
+ }
41
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../src/server/entities/diagram/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,MAAM,CAAC,MAAM,oBAAoB,GAAkB;IACjD,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,SAAS;IAChB,WAAW,EAAE,UAAU;IACvB,kEAAkE;IAClE,YAAY,EAAE,EAAE;IAChB,UAAU,EAAE,WAAW;IACvB,sEAAsE;IACtE,4EAA4E;IAC5E,iEAAiE;IACjE,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;QACjB,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAwC,CAAC;QAC9D,OAAO,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,UAAU,EAAE,iBAA8C;IAC1D,YAAY,EAAE,mBAAmB;IACjC,OAAO,EAAE;QACP,KAAK,CAAC,GAAG;YACP,MAAM,OAAO,GAAG,IAAI,cAAc,CAChC,GAAG,CAAC,EAAE,EACN,GAAG,CAAC,WAAW,EACf,GAAG,CAAC,cAAc,EAClB,GAAG,CAAC,WAAW,CAChB,CAAC;YACF,GAAG,CAAC,GAAG,CAAC,GAAG,CACT,GAAG,oBAAoB,CAAC,UAAU,EAAE,EACpC,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,iBAAiB,EAAE,GAAG,CAAC,EAAE,CAAC,CACvD,CAAC;YACF,GAAG,CAAC,iBAAiB,CACnB,GAAG,oBAAoB,CAAC,IAAI,QAAQ,EACpC,GAAG,EAAE,CACH,wBAAwB,CAAC;gBACvB,cAAc,EAAE,OAAO;gBACvB,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;gBACxC,EAAE,EAAE,GAAG,CAAC,EAAE;aACX,CAAC,CACL,CAAC;YACF,GAAG,CAAC,qBAAqB,CAAC,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAChE,CAAC;KACF;CACF,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,QAAwB;IACjD,QAAQ,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Router } from 'express';
2
+ import type { DiagramService } from './services.js';
3
+ import type { ReferencesService } from '../../services/references.js';
4
+ import type { WsEmitter } from '../../ws/project-emitter.js';
5
+ export declare function diagramsRouter(service: DiagramService, references: ReferencesService, ws: WsEmitter): Router;
@@ -0,0 +1,83 @@
1
+ import { Router } from 'express';
2
+ import { validateDiagramSource } from './validate.js';
3
+ import { errorHandler } from '../../routes/errors.js';
4
+ export function diagramsRouter(service, references, ws) {
5
+ const router = Router();
6
+ router.get('/', (req, res, next) => {
7
+ try {
8
+ const q = req.query;
9
+ const tags = typeof q.tags === 'string' ? q.tags.split(',').filter(Boolean) : undefined;
10
+ const filter = q.tagFilter === 'and' || q.tagFilter === 'or' ? q.tagFilter : undefined;
11
+ const query = {
12
+ tags,
13
+ tagFilter: filter,
14
+ search: typeof q.search === 'string' ? q.search : undefined,
15
+ limit: q.limit ? Number(q.limit) : undefined,
16
+ offset: q.offset ? Number(q.offset) : undefined,
17
+ };
18
+ res.json({ diagrams: service.list(query) });
19
+ }
20
+ catch (err) {
21
+ next(err);
22
+ }
23
+ });
24
+ router.post('/', async (req, res, next) => {
25
+ try {
26
+ const body = req.body;
27
+ const diagram = service.create(body, 'user');
28
+ const warnings = await validateDiagramSource(diagram.format, diagram.source);
29
+ ws.broadcast({ kind: 'entity:changed', entityType: 'diagram', slug: diagram.slug });
30
+ res.status(201).json({ ...diagram, warnings });
31
+ }
32
+ catch (err) {
33
+ next(err);
34
+ }
35
+ });
36
+ router.get('/:slug', (req, res, next) => {
37
+ try {
38
+ const diagram = service.getBySlug(req.params.slug);
39
+ if (!diagram)
40
+ return res.status(404).json({ error: { code: 'NOT_FOUND', message: 'diagram not found' } });
41
+ res.json(diagram);
42
+ }
43
+ catch (err) {
44
+ next(err);
45
+ }
46
+ });
47
+ router.patch('/:slug', async (req, res, next) => {
48
+ try {
49
+ const body = req.body;
50
+ const { diagram, previousSlug } = service.update(req.params.slug, body, 'user');
51
+ if (diagram.slug !== previousSlug) {
52
+ await references.propagateSlugChange('diagram', previousSlug, diagram.slug);
53
+ }
54
+ const warnings = await validateDiagramSource(diagram.format, diagram.source);
55
+ ws.broadcast({ kind: 'entity:changed', entityType: 'diagram', slug: diagram.slug });
56
+ res.json({ ...diagram, warnings });
57
+ }
58
+ catch (err) {
59
+ next(err);
60
+ }
61
+ });
62
+ router.delete('/:slug', async (req, res, next) => {
63
+ try {
64
+ const slug = req.params.slug;
65
+ const broken = await references.findReferences('diagram', slug);
66
+ const result = service.remove(slug, 'user', broken.map((b) => ({
67
+ pagePath: b.pagePath,
68
+ tagType: b.tagType,
69
+ line: b.line,
70
+ slug,
71
+ type: 'diagram',
72
+ })));
73
+ ws.broadcast({ kind: 'entity:changed', entityType: 'diagram', slug });
74
+ res.json(result);
75
+ }
76
+ catch (err) {
77
+ next(err);
78
+ }
79
+ });
80
+ router.use(errorHandler);
81
+ return router;
82
+ }
83
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../../src/server/entities/diagram/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { RawEntity } from '../../domain/raw-entity-reader.js';
2
+ import type { EntitySerializer } from '../../serialization/types.js';
3
+ import type { DiagramFormat } from '../../../shared/entities.js';
4
+ export interface DiagramSnapshot {
5
+ slug: string;
6
+ format: DiagramFormat;
7
+ /** Literal DSL body, kept verbatim (no trim). May be empty. */
8
+ source: string;
9
+ tags: string[];
10
+ }
11
+ export declare const diagramSerializer: EntitySerializer<RawEntity>;
@@ -0,0 +1,147 @@
1
+ function readFormat(value) {
2
+ return value === 'd2' ? 'd2' : 'mermaid';
3
+ }
4
+ function readSource(value) {
5
+ // `source` is stored verbatim; coerce defensively (a JSON-shaped source could
6
+ // be hydrated into a non-string by the generic reader — mermaid DSL never is).
7
+ return typeof value === 'string' ? value : '';
8
+ }
9
+ // ─── view helpers ────────────────────────────────────────────────────────────
10
+ function baseSingle(entity) {
11
+ return {
12
+ type: 'diagram',
13
+ slug: entity.slug,
14
+ format: readFormat(entity.data.format),
15
+ source: readSource(entity.data.source),
16
+ tags: entity.tags,
17
+ };
18
+ }
19
+ function trimItem(entity) {
20
+ const source = readSource(entity.data.source);
21
+ return {
22
+ type: 'diagram',
23
+ slug: entity.slug,
24
+ format: readFormat(entity.data.format),
25
+ sourceLines: source ? source.split('\n').length : 0,
26
+ tags: entity.tags,
27
+ };
28
+ }
29
+ // ─── snapshot / restore / diff ──────────────────────────────────────────────
30
+ function buildSnapshot(entity) {
31
+ return {
32
+ slug: entity.slug,
33
+ format: readFormat(entity.data.format),
34
+ source: readSource(entity.data.source),
35
+ tags: [...entity.tags].sort(),
36
+ };
37
+ }
38
+ function coerce(raw) {
39
+ const r = (raw ?? {});
40
+ return {
41
+ slug: String(r.slug ?? ''),
42
+ format: readFormat(r.format),
43
+ source: readSource(r.source),
44
+ tags: Array.isArray(r.tags) ? r.tags : [],
45
+ };
46
+ }
47
+ function diagramRestore(data, ctx) {
48
+ const snap = coerce(data);
49
+ const result = ctx.writer.upsertDiagram(snap.slug, { slug: snap.slug, format: snap.format, source: snap.source }, ctx.actor);
50
+ ctx.writer.syncTags('diagram', snap.slug, snap.tags);
51
+ return {
52
+ op: result.op,
53
+ entity: result.entity,
54
+ ...(result.warnings && result.warnings.length ? { warnings: result.warnings } : {}),
55
+ };
56
+ }
57
+ function diagramDiff(a, b, slug) {
58
+ if (a == null && b == null)
59
+ return { type: 'diagram', slug, op: 'noop' };
60
+ if (a == null)
61
+ return { type: 'diagram', slug, op: 'created' };
62
+ if (b == null)
63
+ return { type: 'diagram', slug, op: 'deleted' };
64
+ const sa = coerce(a);
65
+ const sb = coerce(b);
66
+ const changes = {};
67
+ if (sa.format !== sb.format)
68
+ changes.format_changed = { from: sa.format, to: sb.format };
69
+ if (sa.source !== sb.source)
70
+ changes.source_changed = true;
71
+ const tagAdded = sb.tags.filter((t) => !sa.tags.includes(t));
72
+ const tagRemoved = sa.tags.filter((t) => !sb.tags.includes(t));
73
+ if (tagAdded.length)
74
+ changes.tag_added = tagAdded;
75
+ if (tagRemoved.length)
76
+ changes.tag_removed = tagRemoved;
77
+ if (Object.keys(changes).length === 0)
78
+ return { type: 'diagram', slug, op: 'noop' };
79
+ return { type: 'diagram', slug, op: 'modified', changes };
80
+ }
81
+ // ─── schemas ─────────────────────────────────────────────────────────────────
82
+ const SINGLE_ELEMENT_SCHEMA = {
83
+ type: 'object',
84
+ required: ['type', 'slug', 'format', 'source', 'tags'],
85
+ properties: {
86
+ type: { const: 'diagram' },
87
+ slug: { type: 'string' },
88
+ format: { type: 'string' },
89
+ source: { type: 'string' },
90
+ tags: { type: 'array', items: { type: 'string' } },
91
+ },
92
+ };
93
+ const LIST_ITEM_SCHEMA = {
94
+ type: 'object',
95
+ required: ['type', 'slug', 'format', 'sourceLines', 'tags'],
96
+ properties: {
97
+ type: { const: 'diagram' },
98
+ slug: { type: 'string' },
99
+ format: { type: 'string' },
100
+ sourceLines: { type: 'number' },
101
+ tags: { type: 'array', items: { type: 'string' } },
102
+ },
103
+ };
104
+ const INLINE_MENTION_SCHEMA = {
105
+ type: 'object',
106
+ required: ['type', 'slug', 'label', 'href'],
107
+ properties: {
108
+ type: { const: 'diagram' },
109
+ slug: { type: 'string' },
110
+ label: { type: 'string' },
111
+ href: { type: 'string' },
112
+ },
113
+ };
114
+ export const diagramSerializer = {
115
+ type: 'diagram',
116
+ version: '1.0.0',
117
+ inlineMention: (entity) => ({
118
+ type: 'diagram',
119
+ slug: entity.slug,
120
+ label: entity.slug,
121
+ href: `/diagrams/${entity.slug}`,
122
+ }),
123
+ singleElement: (entity) => baseSingle(entity),
124
+ elementListItem: (entity) => trimItem(entity),
125
+ taggedListItem: (entity) => trimItem(entity),
126
+ detail: (entity, ctx) => {
127
+ const base = baseSingle(entity);
128
+ const references = ctx.reader.findSectionReferences('diagram', entity.slug).map((r) => ({
129
+ anchor: r.anchor,
130
+ pagePath: r.pagePath,
131
+ headingText: r.headingText,
132
+ relation: r.relation,
133
+ }));
134
+ return { ...base, _references: references };
135
+ },
136
+ schema: (view) => {
137
+ if (view === 'single_element' || view === 'detail')
138
+ return SINGLE_ELEMENT_SCHEMA;
139
+ if (view === 'inline_mention')
140
+ return INLINE_MENTION_SCHEMA;
141
+ return LIST_ITEM_SCHEMA;
142
+ },
143
+ snapshot: (entity) => buildSnapshot(entity),
144
+ restore: diagramRestore,
145
+ diff: diagramDiff,
146
+ };
147
+ //# sourceMappingURL=serializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../../../../src/server/entities/diagram/serializer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { BrokenReference, ChangedBy, Diagram, DiagramCreateInput, DiagramDeleteResult, DiagramListQuery, DiagramUpdateInput } from '../../../shared/entities.js';
3
+ import type { TagsService } from '../../services/tags.js';
4
+ import type { VersionService } from '../../services/versions.js';
5
+ import type { EntityStore } from '../../services/entity-store.js';
6
+ /**
7
+ * M29 write options — mirror the other entity services. `capture: false`
8
+ * suppresses the entity_version capture (index-rebuild path); `writeFile: false`
9
+ * skips the JSON file persist (the file is what the rebuild reads).
10
+ */
11
+ export interface MutateOpts {
12
+ capture?: boolean;
13
+ writeFile?: boolean;
14
+ }
15
+ export declare class DiagramService {
16
+ private db;
17
+ private tags;
18
+ private versions;
19
+ private store;
20
+ constructor(db: Database.Database, tags: TagsService, versions: VersionService, store: EntityStore);
21
+ /** Resolve a free slug, appending `-2`, `-3`, … on collision. */
22
+ private uniqueSlug;
23
+ private generateSlug;
24
+ create(input: DiagramCreateInput, actor: ChangedBy, opts?: MutateOpts): Diagram;
25
+ list(query?: DiagramListQuery): Diagram[];
26
+ count(query?: DiagramListQuery): number;
27
+ getBySlug(slug: string): Diagram | null;
28
+ update(slug: string, input: DiagramUpdateInput, actor: ChangedBy, opts?: MutateOpts): {
29
+ diagram: Diagram;
30
+ previousSlug: string;
31
+ };
32
+ /** Idempotent UPSERT for M17 restore. CREATE if missing, UPDATE otherwise; preserves slug. */
33
+ upsert(slug: string, input: DiagramCreateInput, actor: ChangedBy, opts?: MutateOpts): {
34
+ diagram: Diagram;
35
+ op: 'created' | 'updated';
36
+ };
37
+ remove(slug: string, actor: ChangedBy, brokenReferences?: BrokenReference[], opts?: MutateOpts): DiagramDeleteResult;
38
+ private getBySlugInternal;
39
+ private hydrate;
40
+ }