dsh-model-everything 0.0.0-stage → 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.
Files changed (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.en-US.md +332 -0
  3. package/README.md +332 -3
  4. package/cordis.patch.yml +20 -0
  5. package/examples/README.md +48 -0
  6. package/examples/control-dispatcher.json +113 -0
  7. package/examples/control-dispatcher.overbudget.json +113 -0
  8. package/examples/ecommerce-data-model.json +185 -0
  9. package/examples/order-state-machine.after.json +116 -0
  10. package/examples/order-state-machine.before.json +101 -0
  11. package/examples/user-migration.after.json +29 -0
  12. package/examples/user-migration.before.json +29 -0
  13. package/gate/locale/en.json +6 -0
  14. package/gate/locale/zh.json +6 -0
  15. package/gate/package.json +5 -0
  16. package/lib/baseline.js +249 -0
  17. package/lib/compose-tool.js +80 -0
  18. package/lib/concurrency-tool.js +40 -0
  19. package/lib/concurrency.js +206 -0
  20. package/lib/data-engine.js +1141 -0
  21. package/lib/data-tool.js +87 -0
  22. package/lib/design-engine.js +1149 -0
  23. package/lib/design-tool.js +63 -0
  24. package/lib/engine.js +4343 -0
  25. package/lib/export-tool.js +78 -0
  26. package/lib/exporters.js +434 -0
  27. package/lib/gate.js +274 -0
  28. package/lib/granularity.js +237 -0
  29. package/lib/index.js +237 -0
  30. package/lib/json-value.js +18 -0
  31. package/lib/model-file.js +48 -0
  32. package/lib/option-shape.js +62 -0
  33. package/lib/report-diff-tool.js +63 -0
  34. package/lib/report-view.js +433 -0
  35. package/lib/structure-tool.js +91 -0
  36. package/lib/structure.js +711 -0
  37. package/lib/tool.js +94 -0
  38. package/lib/types/baseline.d.ts +65 -0
  39. package/lib/types/compose-tool.d.ts +7 -0
  40. package/lib/types/concurrency-tool.d.ts +8 -0
  41. package/lib/types/concurrency.d.ts +37 -0
  42. package/lib/types/data-engine.d.ts +211 -0
  43. package/lib/types/data-tool.d.ts +10 -0
  44. package/lib/types/design-engine.d.ts +215 -0
  45. package/lib/types/design-tool.d.ts +11 -0
  46. package/lib/types/engine.d.ts +494 -0
  47. package/lib/types/export-tool.d.ts +7 -0
  48. package/lib/types/exporters.d.ts +37 -0
  49. package/lib/types/gate.d.ts +91 -0
  50. package/lib/types/granularity.d.ts +106 -0
  51. package/lib/types/index.d.ts +45 -0
  52. package/lib/types/json-value.d.ts +21 -0
  53. package/lib/types/model-file.d.ts +7 -0
  54. package/lib/types/option-shape.d.ts +22 -0
  55. package/lib/types/report-diff-tool.d.ts +8 -0
  56. package/lib/types/report-view.d.ts +50 -0
  57. package/lib/types/structure-tool.d.ts +10 -0
  58. package/lib/types/structure.d.ts +152 -0
  59. package/lib/types/tool.d.ts +11 -0
  60. package/lib/types/uml-communication.d.ts +109 -0
  61. package/lib/types/uml-composite.d.ts +107 -0
  62. package/lib/types/uml-interaction-overview.d.ts +91 -0
  63. package/lib/types/uml-profile.d.ts +112 -0
  64. package/lib/types/uml-structure.d.ts +53 -0
  65. package/lib/types/uml-syntax.d.ts +296 -0
  66. package/lib/types/uml-timing.d.ts +152 -0
  67. package/lib/types/uml-tool.d.ts +12 -0
  68. package/lib/types/uml-usecase.d.ts +58 -0
  69. package/lib/types/uml.d.ts +303 -0
  70. package/lib/uml-communication.js +353 -0
  71. package/lib/uml-composite.js +442 -0
  72. package/lib/uml-interaction-overview.js +277 -0
  73. package/lib/uml-profile.js +373 -0
  74. package/lib/uml-structure.js +306 -0
  75. package/lib/uml-syntax.js +545 -0
  76. package/lib/uml-timing.js +974 -0
  77. package/lib/uml-tool.js +213 -0
  78. package/lib/uml-usecase.js +532 -0
  79. package/lib/uml.js +2110 -0
  80. package/locale/en.json +6 -0
  81. package/locale/zh.json +6 -0
  82. package/package.json +128 -6
  83. package/skills/model-everything/SKILL.md +450 -0
  84. package/skills/model-everything/references/dsh-model-schema.md +437 -0
  85. package/skills/model-everything/references/gap-routing-guide.md +42 -0
  86. package/skills/model-everything/references/hash-spec.md +152 -0
  87. package/skills/model-everything/references/logic-verification-guide.md +422 -0
  88. package/skills/model-everything-datamodel/SKILL.md +130 -0
  89. package/skills/model-everything-datamodel/references/data-model-guide.md +84 -0
  90. package/skills/model-everything-datamodel/references/data-model-schema.md +128 -0
  91. package/skills/model-everything-design/SKILL.md +115 -0
  92. package/skills/model-everything-interleaving/SKILL.md +63 -0
  93. package/skills/model-everything-interleaving/SKILL.zh-CN.md +60 -0
  94. package/skills/model-everything-interleaving/references/concurrency-risk-guide.md +63 -0
  95. package/skills/model-everything-report-reading/SKILL.md +137 -0
  96. package/skills/model-everything-report-reading/references/reading-a-report.md +166 -0
  97. package/skills/model-everything-report-reading/references/reading-a-report.mmd +59 -0
  98. package/skills/model-everything-structure/SKILL.md +96 -0
  99. package/skills/model-everything-structure/references/structure-review-guide.md +201 -0
  100. package/skills/model-everything-uml/SKILL.md +60 -0
  101. package/skills/model-everything-uml/references/uml-modeling-guide.md +551 -0
  102. package/src/baseline.ts +288 -0
  103. package/src/compose-tool.ts +82 -0
  104. package/src/concurrency-tool.ts +44 -0
  105. package/src/concurrency.ts +254 -0
  106. package/src/data-engine.ts +1208 -0
  107. package/src/data-tool.ts +91 -0
  108. package/src/design-engine.ts +1263 -0
  109. package/src/design-tool.ts +68 -0
  110. package/src/engine.ts +4564 -0
  111. package/src/export-tool.ts +81 -0
  112. package/src/exporters.ts +399 -0
  113. package/src/gate.ts +330 -0
  114. package/src/granularity.ts +312 -0
  115. package/src/index.ts +289 -0
  116. package/src/json-value.ts +20 -0
  117. package/src/model-file.ts +49 -0
  118. package/src/option-shape.ts +64 -0
  119. package/src/report-diff-tool.ts +67 -0
  120. package/src/report-view.ts +483 -0
  121. package/src/structure-tool.ts +93 -0
  122. package/src/structure.ts +786 -0
  123. package/src/tool.ts +103 -0
  124. package/src/uml-communication.ts +428 -0
  125. package/src/uml-composite.ts +520 -0
  126. package/src/uml-interaction-overview.ts +321 -0
  127. package/src/uml-profile.ts +439 -0
  128. package/src/uml-structure.ts +317 -0
  129. package/src/uml-syntax.ts +764 -0
  130. package/src/uml-timing.ts +1106 -0
  131. package/src/uml-tool.ts +230 -0
  132. package/src/uml-usecase.ts +566 -0
  133. package/src/uml.ts +2139 -0
@@ -0,0 +1,230 @@
1
+ import { defineTool } from '@deepseek-ai/dsh-tools'
2
+ import { createHash } from 'node:crypto'
3
+ import type { JsonValue } from './json-value.js'
4
+ import { REPORT_SCHEMAS, DEFAULT_HASH_SPEC, valueHash, refusalVerdict, verdictOf, verdictOfFindings, type VerdictSummary } from './engine.js'
5
+ import {
6
+ renderUml, parseUml, parseFindings, reviewUml, explainLabels, checkUmlIntent, UmlError, UML_DIAGRAMS,
7
+ type UmlDiagram, type UmlFinding, type UmlIntent, type UmlNotation, type UmlParseResult,
8
+ } from './uml.js'
9
+ import { renderReportText } from './report-view.js'
10
+
11
+ /**
12
+ * The UML front end as four tools, one per job.
13
+ *
14
+ * The split follows the jobs a caller actually has: draw a diagram from a model, read a
15
+ * diagram into a model, audit a diagram or a model, and read the label contract the parser
16
+ * accepts. Bundling them behind one action parameter made every caller read four jobs to
17
+ * find one, and made the tool description a summary of all four.
18
+ *
19
+ * The family list is not written here. It is read from the engine (`UML_DIAGRAMS`), so adding
20
+ * a UML diagram type is a change in the engine and its family module and touches no tool:
21
+ * the schema, the enum and every description follow from the table.
22
+ */
23
+
24
+ /** Every family the front end knows, in the engine's order. A new family is one edit there. */
25
+ const FAMILIES = [...UML_DIAGRAMS]
26
+
27
+ export const UML_RENDER_TOOL_NAME = 'uml_render'
28
+ export const UML_PARSE_TOOL_NAME = 'uml_parse'
29
+ export const UML_REVIEW_TOOL_NAME = 'uml_review'
30
+ export const UML_LABELS_TOOL_NAME = 'uml_explain_labels'
31
+
32
+ const reportViewParameter = {
33
+ type: 'string',
34
+ enum: ['digest', 'full'],
35
+ description: 'digest (default) prints the diagram or the report body; full prints the structured result as JSON.',
36
+ } as const
37
+
38
+ const notationParameter = {
39
+ type: 'string',
40
+ enum: ['auto', 'mermaid', 'plantuml'],
41
+ description: 'Diagram language. Default auto: detected from the text where there is text, mermaid where a model is drawn.',
42
+ } as const
43
+
44
+ const kindParameter = {
45
+ type: 'string',
46
+ enum: FAMILIES,
47
+ description: 'UML diagram family. Default state. A family the chosen notation cannot express is refused with the reason, never approximated silently.',
48
+ } as const
49
+
50
+ const intentParameter = {
51
+ type: 'string',
52
+ enum: ['present', 'verify', 'fidelity'],
53
+ description: 'What the artifact is for, declared up front: present = a human will read it; verify = it must be readable as a model by the verification engine; fidelity = the render-and-reparse proof is the point. A view that cannot serve the declared intent is refused before any work, with errorCode UML_INTENT_UNSERVABLE, UML_VIEW_UNREPRESENTABLE or UML_INTENT_MISMATCH. Omit it and nothing changes.',
54
+ } as const
55
+
56
+ const reportOutput = {
57
+ schema: { type: 'json', description: 'The result: diagram source, a family model, or a modelling review report with findings, round-trip fidelity and next steps.' },
58
+ render(args: Record<string, unknown>, value: unknown) {
59
+ // A rendered diagram is source text: the body prints it verbatim, once.
60
+ return [{ type: 'text' as const, text: renderReportText(value, { full: args.reportView === 'full' }) }]
61
+ },
62
+ } as const
63
+
64
+ /** Draw a model as diagram source. */
65
+ export const umlRenderTool = defineTool({
66
+ name: UML_RENDER_TOOL_NAME,
67
+ description:
68
+ 'Turn a model into UML diagram source a human can read, in the notation that can draw that family. It does not judge the model: `uml_review` audits the modelling, `uml_parse` reads a diagram someone else drew. Takes a LogicModelV1 state machine, or the model of another family (use case, class, object, package, component, deployment), and returns Mermaid or PlantUML text that draws it. Use it to turn a verified machine into a diagram a reader can check, or to produce a diagram someone can edit. It never invents structure the model does not have: a construct the notation cannot carry becomes a warning. PlantUML activity is refused instead of approximated, and a family the notation has no view for is refused with the reason. Declare `intent` to have a view that cannot serve the declared purpose refused before any work.',
69
+ parameters: {
70
+ model: { type: 'json', required: true, description: 'The model to draw: a LogicModelV1 (state machine) or a family model such as a use case or structure model.' },
71
+ notation: notationParameter,
72
+ kind: kindParameter,
73
+ maxSteps: { type: 'integer', description: 'Cap on the sequence trace length when rendering kind=sequence. Default 60.' },
74
+ intent: intentParameter,
75
+ reportView: reportViewParameter,
76
+ },
77
+ output: reportOutput,
78
+ timeoutMs: 10_000,
79
+ isConcurrencySafe: () => true,
80
+ async execute(args) {
81
+ try {
82
+ if (args.model === undefined) return errorResult('uml_render needs a model: a LogicModelV1 or a family model object')
83
+ const notation = (args.notation === undefined || args.notation === 'auto' ? 'mermaid' : args.notation) as UmlNotation
84
+ const result = renderUml(args.model, notation, (args.kind ?? 'state') as UmlDiagram, args.maxSteps as number | undefined, args.intent as UmlIntent | undefined)
85
+ return {
86
+ ok: true,
87
+ ran: true,
88
+ ...verdictOf(0, result.warnings.length),
89
+ schema: REPORT_SCHEMAS.umlRender,
90
+ action: 'render',
91
+ notation: result.notation,
92
+ kind: result.diagram,
93
+ diagram: result.primary,
94
+ hashes: { diagram: createHash('sha256').update(result.primary).digest('hex') },
95
+ warnings: result.warnings,
96
+ } as unknown as JsonValue
97
+ } catch (error) {
98
+ return refusal(error)
99
+ }
100
+ },
101
+ })
102
+
103
+ /** Read diagram text into the model of the family it declares. */
104
+ export const umlParseTool = defineTool({
105
+ name: UML_PARSE_TOOL_NAME,
106
+ description:
107
+ 'Read UML diagram text into the model of the family it declares, so a hand-drawn diagram can be checked or diffed. It only reads what the notation states: `uml_review` judges the modelling, and a family the notation cannot carry is refused by name. Mermaid and PlantUML are both accepted, and the family is detected from the text: a state machine or activity diagram becomes a LogicModelV1 the verification engine can run, while a use case, class, object, package, component or deployment diagram becomes that family model. Read the verdict, not ok: a diagram whose family has no module in this build is refused with errorCode UML_NOT_A_STATE_DIAGRAM, and the refusal names the family it found. A sequence diagram is refused as well, because a trace cannot reconstruct a machine, and so is text that is not a UML diagram at all.',
108
+ parameters: {
109
+ diagram: { type: 'string', required: true, description: 'The UML source text to read.' },
110
+ notation: notationParameter,
111
+ intent: intentParameter,
112
+ reportView: reportViewParameter,
113
+ },
114
+ output: reportOutput,
115
+ timeoutMs: 10_000,
116
+ isConcurrencySafe: () => true,
117
+ async execute(args) {
118
+ try {
119
+ if (args.diagram === undefined) return errorResult('uml_parse needs diagram text (Mermaid or PlantUML)')
120
+ checkUmlIntent(args.intent as UmlIntent | undefined, 'parse')
121
+ const result = parseUml(args.diagram, (args.notation ?? 'auto') as UmlNotation | 'auto')
122
+ // The parser notes are the parse verdict: an ignored line is information the model does not carry, so
123
+ // ok: true only ever means the parser ran. They stay in `warnings` - the channel the schema reference names and
124
+ // the render side uses - and the body prints them, which is where the old contradiction lived: the verdict
125
+ // counted them while the roster said `FINDINGS none`.
126
+ const findings = parseFindings(result)
127
+ return {
128
+ ok: true,
129
+ ran: true,
130
+ ...parseVerdict(result, findings),
131
+ schema: REPORT_SCHEMAS.umlParse,
132
+ action: 'parse',
133
+ notation: result.notation,
134
+ kind: result.diagram,
135
+ family: result.family,
136
+ model: result.model,
137
+ labels: result.labels,
138
+ findings,
139
+ discardedConstructs: result.discardedConstructs,
140
+ discardedEdges: result.discardedEdges,
141
+ hashes: { hashSpec: DEFAULT_HASH_SPEC, modelHash: valueHash(result.model), diagram: createHash('sha256').update(args.diagram).digest('hex') },
142
+ warnings: result.warnings,
143
+ } as unknown as JsonValue
144
+ } catch (error) {
145
+ return refusal(error)
146
+ }
147
+ },
148
+ })
149
+
150
+ /** Audit the modelling: the diagram, the model, or the two against each other. */
151
+ export const umlReviewTool = defineTool({
152
+ name: UML_REVIEW_TOOL_NAME,
153
+ description:
154
+ 'Audit UML modelling, and report what a reader would get wrong. Give it a model (is this machine well modelled?), a diagram (what does this diagram actually say?), or both (does the diagram carry the model it is presented with?). It reports structural defects such as unreachable states, dead ends, ambiguous or non-exhaustive branches, isolated nodes and cycles, plus documentation gaps and the fidelity check that re-renders the model and reads it back. Read the verdict, not ok. A family diagram gets its own family checks: use case defects, or the dependency-graph checks for a structure diagram. This audits the modelling; behaviour needs model_verify.',
155
+ parameters: {
156
+ model: { type: 'json', description: 'The model to review: a LogicModelV1 or a family model. Provide it, the diagram, or both.' },
157
+ diagram: { type: 'string', description: 'UML source text to review. Provide it, the model, or both.' },
158
+ notation: notationParameter,
159
+ kind: kindParameter,
160
+ roundTrip: { type: 'boolean', description: 'Render and re-read the model to prove the diagram carries it. Default true.' },
161
+ maxSteps: { type: 'integer', description: 'Cap on the sequence trace used for the fidelity check.' },
162
+ intent: intentParameter,
163
+ reportView: reportViewParameter,
164
+ },
165
+ output: reportOutput,
166
+ timeoutMs: 10_000,
167
+ isConcurrencySafe: () => true,
168
+ async execute(args) {
169
+ try {
170
+ if (args.model === undefined && args.diagram === undefined) return errorResult('uml_review needs a model, diagram text, or both')
171
+ const report = reviewUml({
172
+ model: args.model,
173
+ diagram: args.diagram,
174
+ notation: (args.notation ?? 'auto') as UmlNotation | 'auto',
175
+ diagramKind: (args.kind ?? 'state') as UmlDiagram,
176
+ roundTrip: args.roundTrip as boolean | undefined,
177
+ maxSteps: args.maxSteps as number | undefined,
178
+ intent: args.intent as UmlIntent | undefined,
179
+ })
180
+ return report as unknown as JsonValue
181
+ } catch (error) {
182
+ return refusal(error)
183
+ }
184
+ },
185
+ })
186
+
187
+ /** Print the label and comment contract the parser accepts. */
188
+ export const umlExplainLabelsTool = defineTool({
189
+ name: UML_LABELS_TOOL_NAME,
190
+ description:
191
+ 'Print the label and comment conventions the UML parser accepts, for one notation: the accepted label spellings, the form the renderer writes, the directives that pin what the notation cannot spell, and which lines are ignored. No diagram is needed. Use it when a hand-written diagram reports label drift or ignored lines and the reason is not obvious from the source. It reads no diagram and judges no modelling: `uml_parse` reads a diagram, and `uml_review` audits one.',
192
+ parameters: {
193
+ notation: notationParameter,
194
+ reportView: reportViewParameter,
195
+ },
196
+ output: reportOutput,
197
+ timeoutMs: 10_000,
198
+ isConcurrencySafe: () => true,
199
+ async execute(args) {
200
+ const notation = (args.notation === undefined || args.notation === 'auto' ? 'mermaid' : args.notation) as UmlNotation
201
+ return {
202
+ ok: true,
203
+ ran: true,
204
+ ...verdictOf(0, 0),
205
+ schema: REPORT_SCHEMAS.umlExplainLabels,
206
+ action: 'explain-labels',
207
+ ...explainLabels(notation),
208
+ } as unknown as JsonValue
209
+ },
210
+ })
211
+
212
+ /** The parse verdict counts parser notes as warnings: an ignored line is information the model does not carry. */
213
+ function parseVerdict(result: UmlParseResult, findings: UmlFinding[]): VerdictSummary {
214
+ const errors = findings.filter((finding) => finding.severity === 'error').length
215
+ const warnings = findings.filter((finding) => finding.severity === 'warning').length + result.warnings.length
216
+ const firstCode = findings.find((finding) => finding.severity === 'error')?.code ?? findings.find((finding) => finding.severity === 'warning')?.code
217
+ return verdictOf(errors, warnings, firstCode)
218
+ }
219
+
220
+ /** A front-end refusal travels as a failed result, with the code that says why. */
221
+ function refusal(error: unknown): JsonValue {
222
+ const message = error instanceof Error ? error.message : String(error)
223
+ return errorResult(message, error instanceof UmlError ? error.code : undefined)
224
+ }
225
+
226
+ function errorResult(message: string, errorCode = 'UML_INPUT'): JsonValue {
227
+ // Carries the refusal schema. Every other family's refusal carries one, and a reader who decides "what am I
228
+ // holding" from `schema` got nothing from this one - it was the only refusal shaped differently.
229
+ return { ok: false, ran: false, ...refusalVerdict(message), schema: REPORT_SCHEMAS.umlRefusal, errorCode, error: message } as unknown as JsonValue
230
+ }