@rse/specbook 0.9.5 → 0.9.7
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/README.md +108 -328
- package/dst/specbook-api.d.ts +13 -20
- package/dst/specbook-api.js +43 -39
- package/dst/specbook-cli.js +42 -55
- package/dst/specbook-cmd-describe.d.ts +5 -2
- package/dst/specbook-cmd-describe.js +30 -91
- package/dst/specbook-cmd-export.d.ts +3 -3
- package/dst/specbook-cmd-export.js +23 -19
- package/dst/specbook-cmd-init.d.ts +3 -3
- package/dst/specbook-cmd-init.js +38 -15
- package/dst/specbook-cmd-lint.d.ts +5 -6
- package/dst/specbook-cmd-lint.js +61 -24
- package/dst/specbook-config.d.ts +2 -2
- package/dst/specbook-config.js +82 -73
- package/dst/specbook-diagnostic.js +4 -1
- package/dst/specbook-diagram.d.ts +6 -5
- package/dst/specbook-diagram.js +94 -104
- package/dst/specbook-export-ast.d.ts +3 -3
- package/dst/specbook-export-ast.js +1 -1
- package/dst/specbook-export-common.d.ts +11 -9
- package/dst/specbook-export-common.js +34 -22
- package/dst/specbook-export-html-search.js +10 -14
- package/dst/specbook-export-html.css +37 -32
- package/dst/specbook-export-html.d.ts +4 -4
- package/dst/specbook-export-html.js +153 -107
- package/dst/specbook-export-logo-dark.svg +35 -0
- package/dst/specbook-export-logo-light.svg +35 -0
- package/dst/specbook-export-md.d.ts +3 -3
- package/dst/specbook-export-md.js +50 -24
- package/dst/specbook-export-pdf.d.ts +4 -2
- package/dst/specbook-export-pdf.js +48 -38
- package/dst/{specbook-struct-schema.d.ts → specbook-format-schema.d.ts} +3 -2
- package/dst/{specbook-struct-schema.js → specbook-format-schema.js} +8 -4
- package/dst/specbook-format-spec.d.ts +31 -0
- package/dst/{specbook-struct-spec.js → specbook-format-spec.js} +10 -10
- package/dst/specbook-format.md +750 -0
- package/dst/specbook-link.d.ts +3 -2
- package/dst/specbook-link.js +7 -4
- package/dst/specbook-mcp.d.ts +2 -1
- package/dst/specbook-mcp.js +30 -62
- package/dst/specbook-parse-common.d.ts +5 -3
- package/dst/specbook-parse-common.js +8 -0
- package/dst/specbook-parse-semantic.d.ts +6 -4
- package/dst/specbook-parse-semantic.js +98 -106
- package/dst/specbook-parse-syntax.d.ts +2 -2
- package/dst/specbook-parse-syntax.js +175 -144
- package/dst/specbook-parse-value.d.ts +1 -1
- package/dst/specbook-parse-value.js +6 -3
- package/dst/specbook-parse.d.ts +4 -7
- package/dst/specbook-parse.js +28 -35
- package/dst/specbook-verbose.d.ts +2 -0
- package/dst/specbook-verbose.js +17 -0
- package/package.json +3 -7
- package/dst/specbook-cmd-edit.d.ts +0 -9
- package/dst/specbook-cmd-edit.js +0 -74
- package/dst/specbook-cmd-import.d.ts +0 -9
- package/dst/specbook-cmd-import.js +0 -78
- package/dst/specbook-export-logo.svg +0 -35
- package/dst/specbook-llm.d.ts +0 -13
- package/dst/specbook-llm.js +0 -51
- package/dst/specbook-struct-spec.d.ts +0 -31
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
<img src="https://raw.githubusercontent.com/rse/specbook/master/etc/specbook-logo.svg" width="400" align="right" alt=""/>
|
|
2
|
+
<img src="https://raw.githubusercontent.com/rse/specbook/master/etc/specbook-logo-blue-light.svg" width="400" align="right" alt=""/>
|
|
3
3
|
|
|
4
4
|
SpecBook
|
|
5
5
|
========
|
|
@@ -13,22 +13,76 @@ About
|
|
|
13
13
|
format* which can be configured for the specifications of particular
|
|
14
14
|
contexts through a YAML-based *schema configuration*. SpecBook allows
|
|
15
15
|
specifications to be *initialized*, *linted*, *exported* (JSON, JSON5,
|
|
16
|
-
YAML, TOON, HTML, PDF, and normalized Markdown), *described* to
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
YAML, TOON, HTML, PDF, and normalized Markdown), and *described* to
|
|
17
|
+
LLMs.
|
|
18
|
+
|
|
19
|
+
**SpecBook** ships with an API class with methods `<xxx>()`, a
|
|
20
|
+
CLI with commands `specbook <xxx>`, and an MCP service with tools
|
|
21
|
+
`specbook_<xxx>()`.
|
|
20
22
|
|
|
21
23
|
**SpecBook** provides the following distinct features:
|
|
22
24
|
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
- **Hierarchical Object Model**:
|
|
26
|
+
A specification is a tree of typed objects, each with a kind and
|
|
27
|
+
name, an optional id, optional properties, optional description, and
|
|
28
|
+
optional child objects. The allowed object hierarchy is defined per
|
|
29
|
+
context by the YAML schema configuration.
|
|
30
|
+
|
|
31
|
+
- **Versatile Object to Markdown Mapping**:
|
|
32
|
+
Objects are authored as plain Markdown headings, property lists,
|
|
33
|
+
and description prose. The objects can be mapped to nested sections
|
|
34
|
+
("complex" format) or a compact bullet point lists ("concise" and
|
|
35
|
+
"group" format).
|
|
36
|
+
|
|
37
|
+
- **Wiki-Style Object Linking**:
|
|
38
|
+
Objects can hierarchically reference each other through Wiki-style
|
|
39
|
+
`[[xxx]]` references, which are resolved against the locally-unique
|
|
40
|
+
ids and names of all objects. In the HTML and PDF exports they become
|
|
41
|
+
navigable links onto precise anchors.
|
|
42
|
+
|
|
43
|
+
- **Strict Validation with Custom Schema**:
|
|
44
|
+
The YAML schema configuration strictly defines the allowed object
|
|
45
|
+
kinds, hierarchies, and properties, whose values are constrained by an
|
|
46
|
+
expression language (regex, enum, tags, list, and reference). Violations
|
|
47
|
+
are reported as file- and line-precise diagnostics.
|
|
48
|
+
|
|
49
|
+
- **Object Model Diagram Visualisation**:
|
|
50
|
+
Object kinds can declare "graph", "hub", or "grid" diagrams in the
|
|
51
|
+
schema, whose nodes and edges are automatically derived from the
|
|
52
|
+
object model and its references. The diagrams are rendered with the
|
|
53
|
+
sibling project [Gradia](https://github.com/rse/gradia), which is
|
|
54
|
+
specialized on rendering object models.
|
|
55
|
+
|
|
56
|
+
- **CLI, MCP, and API Interface**:
|
|
57
|
+
All commands are implemented once in the API class `SpecBook`, on
|
|
58
|
+
which both the CLI and the MCP service are just thin wrappers.
|
|
59
|
+
This way, humans, scripts, and AI agents use exactly the same
|
|
60
|
+
functionality.
|
|
61
|
+
|
|
62
|
+
- **AST Exports for AI/LLMs**:
|
|
63
|
+
The parsed specification Abstract Syntax Tree (AST) can be exported in
|
|
64
|
+
JSON, JSON5, YAML, or TOON format for machine consumption. Together
|
|
65
|
+
with the `describe` command, which explains the models and formats,
|
|
66
|
+
this enables LLMs to both read and write specifications.
|
|
67
|
+
|
|
68
|
+
- **HTML Export for Developers**:
|
|
69
|
+
The HTML export is a self-contained single document with a
|
|
70
|
+
table-of-contents, full-text search, embedded images, and a light/dark
|
|
71
|
+
theme toggle. It is intended for the day-to-day online reading during
|
|
72
|
+
development. The HTML export can map all object kinds to nested
|
|
73
|
+
sections or compact tables, or an automatic mixture which collapses
|
|
74
|
+
only the deepest level into tables.
|
|
75
|
+
|
|
76
|
+
- **PDF Export for Customers**:
|
|
77
|
+
The PDF export prints the HTML rendering via Chromium and post-processes
|
|
78
|
+
it with page numbers, headers/footers, and a hierarchical PDF outline.
|
|
79
|
+
It is intended as a polished, paginated offline document for handing
|
|
80
|
+
over to customers.
|
|
81
|
+
|
|
82
|
+
Overview Poster
|
|
83
|
+
---------------
|
|
84
|
+
|
|
85
|
+
[](etc/poster.pdf)
|
|
32
86
|
|
|
33
87
|
Rendering Example
|
|
34
88
|
-----------------
|
|
@@ -45,308 +99,31 @@ Rendering Example
|
|
|
45
99
|
|
|
46
100
|

|
|
47
101
|
|
|
48
|
-
Specification Format
|
|
49
|
-
--------------------
|
|
50
|
-
|
|
51
|
-
### Artifact Files
|
|
52
|
-
|
|
53
|
-
A specification consists of Markdown *artifact* files, which are
|
|
54
|
-
scanned recursively from a base directory. Every file has to start with
|
|
55
|
-
a frontmatter block carrying the `Created:` and `Modified:` timestamps
|
|
56
|
-
(format `yyyy-LL-dd HH:mm`):
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
---
|
|
60
|
-
Created: 2026-06-18 10:18
|
|
61
|
-
Modified: 2026-06-18 10:18
|
|
62
|
-
---
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Every level 1 heading opens a new *artifact*, so usually each file
|
|
66
|
-
carries exactly one. Both ATX headings (`# <text/>`, `## <text/>`, ...)
|
|
67
|
-
and Setext headings (`<text/>` underlined with `===` or `---`) are
|
|
68
|
-
supported.
|
|
69
|
-
|
|
70
|
-
### Object Model
|
|
71
|
-
|
|
72
|
-
An artifact carries a tree of *objects*. Every object has a mandatory
|
|
73
|
-
*kind* (e.g. `ENTITY`), a mandatory *name*, a unique anchor *id*
|
|
74
|
-
(explicitly given or derived from the name), an optional *primary*
|
|
75
|
-
marker, optional *properties* (key/value pairs), an optional
|
|
76
|
-
*description* statement with an optional rationale, and optional *child*
|
|
77
|
-
objects. Which kinds, properties, and nestings are allowed is defined by
|
|
78
|
-
the schema configuration (see below); object kinds and property keys are
|
|
79
|
-
case-sensitive and have to be written exactly as configured. Backquotes
|
|
80
|
-
in names and property values are preserved as code markup for rendering,
|
|
81
|
-
but are ignored when matching names, references, and constraints.
|
|
82
|
-
|
|
83
|
-
Three concrete syntaxes exist:
|
|
84
|
-
|
|
85
|
-
### Complex Format
|
|
86
|
-
|
|
87
|
-
Usually used on object hierarchy levels 1-3 (`#`, `##`, `###`). A
|
|
88
|
-
heading opens the object, an optional unordered list carries its
|
|
89
|
-
properties, and the remaining content up to the next heading is its
|
|
90
|
-
description:
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
# <kind/>: <name/> (<id/>)
|
|
94
|
-
|
|
95
|
-
- <key/>: <value/>
|
|
96
|
-
- [...]
|
|
97
|
-
|
|
98
|
-
<statement/>, BECAUSE <rationale/>.
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
The heading level directly reflects the nesting level: a `##` object
|
|
102
|
-
becomes a child of the preceding `#` object, a `###` object a child of
|
|
103
|
-
the preceding `##` object, etc. Skipping a level (a heading without a
|
|
104
|
-
parent object on the level above) is an error.
|
|
105
|
-
|
|
106
|
-
### Concise Format
|
|
107
|
-
|
|
108
|
-
Usually used on level 4 and deeper. A single unordered list item carries
|
|
109
|
-
the entire object as `;`-separated segments -- the `<kind/>: <name/>`
|
|
110
|
-
head, the `<key/>: <value/>` properties, and the trailing description --
|
|
111
|
-
and may wrap over multiple (indented) lines:
|
|
112
|
-
|
|
113
|
-
```
|
|
114
|
-
- <kind/>: <name/>; <key/>: <value/>; [...];
|
|
115
|
-
<statement/>, BECAUSE <rationale/>.
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
A list item is recognized as a Concise Format object (instead of a
|
|
119
|
-
property of the enclosing object) by carrying at least one `;` on its
|
|
120
|
-
first line. Every segment of the form `<key/>: <value/>` becomes a
|
|
121
|
-
property (unless it contains a ` BECAUSE `), all remaining segments are
|
|
122
|
-
joined into the description. Child objects nest as indented list items
|
|
123
|
-
below their parent item, where key/value items become properties and
|
|
124
|
-
concise items become child objects of that parent:
|
|
125
|
-
|
|
126
|
-
```
|
|
127
|
-
- <kind/>: <name/>; <key/>: <value/>;
|
|
128
|
-
<statement/>, BECAUSE <rationale/>.
|
|
129
|
-
- <kind/>: <name/>; <key/>: <value/>;
|
|
130
|
-
<statement/>, BECAUSE <rationale/>.
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Grouped Format
|
|
134
|
-
|
|
135
|
-
A heading carrying just a *kind* and no `<kind/>: <name/>` pair opens a
|
|
136
|
-
*grouping container* instead of an object. The list items below it are
|
|
137
|
-
Concise Format items whose kind comes from that heading, so they start
|
|
138
|
-
with the (optionally backquoted) name directly:
|
|
139
|
-
|
|
140
|
-
```
|
|
141
|
-
### <kinds/>
|
|
142
|
-
|
|
143
|
-
- `<name/>`; <key/>: <value/>; [...];
|
|
144
|
-
<statement/>, BECAUSE <rationale/>.
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
The heading kind is singularized by stripping one trailing `S`, so both
|
|
148
|
-
`### STATES` and `### STATE` group objects of kind `STATE`. The grouped
|
|
149
|
-
objects become children of the object the heading is nested under. An
|
|
150
|
-
unquoted name must not contain a `:` (else the item would look like a
|
|
151
|
-
key/value pair) -- backquote it in this case.
|
|
152
|
-
|
|
153
|
-
When **SpecBook** itself generates specification Markdown, it emits
|
|
154
|
-
the Complex Format on levels 1-3 and the Concise Format from level 4
|
|
155
|
-
upwards. When **SpecBook** edits existing files, it mirrors the format
|
|
156
|
-
each existing object already uses.
|
|
157
|
-
|
|
158
|
-
### Names, Anchors, and Ids
|
|
159
|
-
|
|
160
|
-
In all formats, the `<name/>` may carry trailing decorations, in any
|
|
161
|
-
order:
|
|
162
|
-
|
|
163
|
-
- `{{<id/>}}`: the explicit Wiki-style anchor, setting the object id
|
|
164
|
-
(e.g. `## ENTITY: Attendee Browser {{attendee}}`).
|
|
165
|
-
|
|
166
|
-
- `(*)`: the *primary* marker, flagging the object as primary (e.g.
|
|
167
|
-
the primary attributes of an entity).
|
|
168
|
-
|
|
169
|
-
- `(<token/>)`: a parenthesized token with three possible roles: on
|
|
170
|
-
level 1 it becomes the artifact id (e.g. `# SPEC: Data Model (DM)`);
|
|
171
|
-
on deeper levels it is either accepted as the value of a still
|
|
172
|
-
missing configured property whose constraint it matches (e.g.
|
|
173
|
-
`### SCENARIO: Successful Token Login (Main)` satisfying an
|
|
174
|
-
`enum(Main,Alternative,Exceptional)` property), or else acts as the
|
|
175
|
-
implicit anchor id.
|
|
176
|
-
|
|
177
|
-
- `<a id="<id/>"></a>`: an HTML anchor at the very end of a heading,
|
|
178
|
-
as an alternative to `{{<id/>}}` (emitted by **SpecBook** itself
|
|
179
|
-
when exporting normalized Markdown).
|
|
180
|
-
|
|
181
|
-
When no explicit id is given, the id is derived by slugifying the name
|
|
182
|
-
(lowercased, with non-alphanumeric character runs dashed). An explicit
|
|
183
|
-
`{{<id/>}}` anchor always takes precedence over a `(<token/>)` id. When
|
|
184
|
-
the schema configures a fixed `id` for an object, it has to be
|
|
185
|
-
explicitly written in the input, via either `{{<id/>}}` or `(<id/>)`.
|
|
186
|
-
|
|
187
|
-
### Properties
|
|
188
|
-
|
|
189
|
-
In the Complex Format, each property is an unordered list item of the
|
|
190
|
-
form `<key/>: <value/>`, whose value may continue on the following
|
|
191
|
-
indented lines of the item (joined with spaces). In the Concise Format,
|
|
192
|
-
each property is a `<key/>: <value/>` segment. A property key may carry
|
|
193
|
-
a trailing parenthesized annotation (e.g. `WHEN (Context)`), which is
|
|
194
|
-
kept for rendering but ignored when matching the key against the schema.
|
|
195
|
-
|
|
196
|
-
A multi-token convenience exists for pattern-constrained properties:
|
|
197
|
-
when a property value fails its (regex or enum) constraint as a whole,
|
|
198
|
-
but consists of multiple whitespace-separated tokens of which one
|
|
199
|
-
matches the property's own constraint, that token is kept as the value
|
|
200
|
-
and the remaining tokens are distributed (case-insensitively) across the
|
|
201
|
-
other still unset pattern-constrained properties of the object. Tokens
|
|
202
|
-
assignable to no property are reported as errors.
|
|
203
|
-
|
|
204
|
-
### Descriptions and Rationales
|
|
205
|
-
|
|
206
|
-
The description of a Complex Format object is all block content below
|
|
207
|
-
its heading (up to the next heading) except the property list:
|
|
208
|
-
paragraphs, blockquotes, ordered lists (e.g. scenario steps), and
|
|
209
|
-
fenced code blocks. A fenced code block
|
|
210
|
-
of language `gradia` is skipped, as it is the derived diagram which
|
|
211
|
-
**SpecBook** itself emits into exported Markdown and which must not
|
|
212
|
-
become authored content on a re-parse. In the Concise Format, the
|
|
213
|
-
description is formed by the non-property segments of the item.
|
|
214
|
-
|
|
215
|
-
A description is split into its *statement* and *rationale* at the first
|
|
216
|
-
`, BECAUSE ` (or `, **BECAUSE** `) occurrence:
|
|
217
|
-
|
|
218
|
-
```
|
|
219
|
-
The event is created and configured but not visible to attendees,
|
|
220
|
-
BECAUSE an event needs a private setup phase.
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
### Wiki-Style References
|
|
224
|
-
|
|
225
|
-
A `[[<reference/>]]` anywhere in a name, property value, description, or
|
|
226
|
-
rationale is a Wiki-style reference to another object, which is checked
|
|
227
|
-
for unique resolvability and rendered as a hyperlink in the HTML/PDF
|
|
228
|
-
exports. A reference is a `.`-separated path of segments, where each
|
|
229
|
-
segment matches a single object as:
|
|
230
|
-
|
|
231
|
-
- `<id/>`: the object id or explicit anchor (e.g. `[[attendee]]`)
|
|
232
|
-
- `<name/>`: the object name (e.g. `[[Attendee Browser]]`)
|
|
233
|
-
- `<kind/>:<name-or-id/>`: kind-qualified (e.g. `[[ENTITY:Event]]`)
|
|
234
|
-
- `<kind/>:*` or `*`: wildcards (for match sets, see below)
|
|
235
|
-
|
|
236
|
-
Each part can be double-quoted to allow spaces, dots, and colons inside
|
|
237
|
-
it (e.g. `[["Vue.js"]]`, whose dot would otherwise be taken as a path
|
|
238
|
-
separator). A multi-segment path matches object chains connected by
|
|
239
|
-
direct parent-to-child steps, where the leading segments up to the root
|
|
240
|
-
may be omitted (e.g. `[[FV.relay]]` matches the object `relay` directly
|
|
241
|
-
below the artifact with id `FV`).
|
|
242
|
-
|
|
243
|
-
A reference has to resolve to exactly one object: a single-segment
|
|
244
|
-
reference tries the variants (1) id/anchor, (2) name, and (3)
|
|
245
|
-
`<kind/>:<name-or-id/>` in order, where the first variant yielding any
|
|
246
|
-
matches decides; several matches are an ambiguity and zero matches an
|
|
247
|
-
unresolvable reference, both reported by the linter. Wildcard references
|
|
248
|
-
resolve into match *sets* and are used in the schema configuration to
|
|
249
|
-
constrain reference-valued properties (e.g. `[[PERSONA:*]]` or
|
|
250
|
-
`[[DM.ENTITY:*]]`).
|
|
251
|
-
|
|
252
|
-
### Image Embeddings
|
|
253
|
-
|
|
254
|
-
A Markdown image `` inside a description or property
|
|
255
|
-
value embeds a local image file, resolved relative to the artifact file:
|
|
256
|
-
SVG files are inlined as-is; PNG/JPEG files are embedded as base64
|
|
257
|
-
`data:` URLs. URLs and other file types are left untouched.
|
|
258
|
-
|
|
259
|
-
### Normalization
|
|
260
|
-
|
|
261
|
-
The semantic phase validates the parsed objects against the schema
|
|
262
|
-
configuration (unknown kinds and properties, missing required properties
|
|
263
|
-
and child kinds, and violated value constraints are reported with
|
|
264
|
-
file/line-precise diagnostics) and then normalizes the specification:
|
|
265
|
-
artifacts, child objects, and properties are stably reordered along the
|
|
266
|
-
schema definition, so the exports always present them in their
|
|
267
|
-
configured canonical order.
|
|
268
|
-
|
|
269
|
-
Schema Configuration
|
|
270
|
-
--------------------
|
|
271
|
-
|
|
272
|
-
The YAML schema configuration (see
|
|
273
|
-
[`ase.specbook.yaml`](smp/ase.specbook.yaml) for a comprehensive
|
|
274
|
-
example) defines which domain-specific objects are allowed: the artifact
|
|
275
|
-
kinds with their `file` mapping on the first level, the object kinds of
|
|
276
|
-
the deeper levels, and their properties with optional value constraints:
|
|
277
|
-
regular expressions `/xxx/`, object references `[[xxx]]`, enumerations
|
|
278
|
-
`enum(xxx,yyy)`, tag sets `tags(xxx,yyy)`, and lists `list(xxx[, ...])`
|
|
279
|
-
of such alternatives. The `file` field is only allowed on the first
|
|
280
|
-
(artifact) level.
|
|
281
|
-
|
|
282
|
-
An object kind can additionally carry a `diagram` field, which derives a
|
|
283
|
-
[Gradia](https://github.com/rse/gradia) diagram for every object of that
|
|
284
|
-
kind. Its `type` selects the diagram shape (`graph`, `hub`, or `grid`),
|
|
285
|
-
`nodes` and `edges` select the participating objects through
|
|
286
|
-
comma-separated `[[xxx]]` reference patterns (`nodes` defaults to the
|
|
287
|
-
object itself plus all objects below it), `center` names the object a
|
|
288
|
-
`hub` is projected onto (default: `self`), `onlyConnected` drops the
|
|
289
|
-
edge-less nodes of a `graph`, `collapse` (default: `true`) omits a
|
|
290
|
-
degenerated diagram consisting of a single node only, `qualified` labels
|
|
291
|
-
every node with its object kind, `properties` lists the property names
|
|
292
|
-
whose values are attached to the nodes as key/value annotations (with
|
|
293
|
-
every `[[xxx]]` reference stripped to its target object name), and
|
|
294
|
-
`config` passes arbitrary Gradia rendering options (e.g.
|
|
295
|
-
`grid-columns-max: 5`) through to the diagram.
|
|
296
|
-
|
|
297
|
-
The edges are derived from the `[[xxx]]` references of the node objects
|
|
298
|
-
-- from their property values only, or, with `links: all`, from their
|
|
299
|
-
descriptions as well. As the *nesting* of the objects carries no such
|
|
300
|
-
reference, `hierarchy: true` additionally derives a containment edge
|
|
301
|
-
from every node object to each of its child objects which is part of the
|
|
302
|
-
node set. This is what turns a parent object into the hub of its own
|
|
303
|
-
children, as the `TIER` objects of the sample schema configuration
|
|
304
|
-
demonstrate:
|
|
305
|
-
|
|
306
|
-
```yaml
|
|
307
|
-
- kind: TIER
|
|
308
|
-
diagram:
|
|
309
|
-
type: hub
|
|
310
|
-
center: self
|
|
311
|
-
hierarchy: true
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
A `grid` is edge-less by definition and hence accepts neither `edges`
|
|
315
|
-
nor `hierarchy`.
|
|
316
|
-
|
|
317
|
-
An object kind can furthermore carry a `format` field, which controls
|
|
318
|
-
how the HTML/PDF export renders the child objects of every object of
|
|
319
|
-
that kind. Its `type` selects the rendering: `complex` (nested
|
|
320
|
-
sections), `concise` (compact per-kind tables), or the default `auto`,
|
|
321
|
-
which collapses only the deepest level into tables. Below a `concise`
|
|
322
|
-
object, unconfigured children implicitly stay `concise` and render as
|
|
323
|
-
sub-tables inside the description cells, while an explicitly configured
|
|
324
|
-
`type` is always honored, even a `complex` rendering pressed into a
|
|
325
|
-
cell. `maxTableColumns` (default: `4`) bounds the columns of the compact
|
|
326
|
-
tables below the object (wider groups chunk their properties into
|
|
327
|
-
embedded per-object tables), and `withUnusedProps` (default: `false`)
|
|
328
|
-
unconditionally renders the defined but unused properties of that kind,
|
|
329
|
-
as empty property table lines or table columns. Objects collapsed into
|
|
330
|
-
tables carry no headings and hence leave the table of contents and the
|
|
331
|
-
PDF outline.
|
|
332
|
-
|
|
333
102
|
Usage
|
|
334
103
|
-----
|
|
335
104
|
|
|
336
105
|
### CLI
|
|
337
106
|
|
|
338
107
|
```
|
|
339
|
-
$ specbook init [-v]
|
|
340
|
-
$ specbook lint [-v]
|
|
341
|
-
$ specbook export [-v]
|
|
342
|
-
$ specbook describe [-v] [-c <yaml-file>] [-o <markdown-file>]
|
|
343
|
-
$ specbook import [-v] [-c <yaml-file>] [-b <basedir>] <input-files...>
|
|
344
|
-
$ specbook edit [-v] [-c <yaml-file>] [-b <basedir>] <query>
|
|
108
|
+
$ specbook init [-v] -c <yaml-file> [-b <basedir>]
|
|
109
|
+
$ specbook lint [-v] -c <yaml-file> [-b <basedir>]
|
|
110
|
+
$ specbook export [-v] -c <yaml-file> [-b <basedir>] [-o [<format>:]<output-file>] [...]
|
|
111
|
+
$ specbook describe [-v] [-c <yaml-file>] [-b <basedir>] [-e] [-o <markdown-file>]
|
|
345
112
|
$ specbook mcp [-v]
|
|
346
113
|
```
|
|
347
114
|
|
|
348
|
-
The
|
|
349
|
-
|
|
115
|
+
The YAML schema configuration `-c`/`--config` is mandatory for `init`,
|
|
116
|
+
`lint`, and `export`, as it determines the specification: exactly the
|
|
117
|
+
artifact files its `file` fields reference are loaded and parsed, all
|
|
118
|
+
other Markdown files below the base directory are ignored. A referenced
|
|
119
|
+
file which is absent is reported, unless all of its artifacts are
|
|
120
|
+
`optional`, and so is an artifact absent from its present file, unless
|
|
121
|
+
it is `optional` itself. Both `lint` and `export` report all
|
|
122
|
+
diagnostics and fail on any of them, so a partial or invalid
|
|
123
|
+
specification is never exported.
|
|
124
|
+
|
|
125
|
+
The base directory `-b`/`--basedir` (default: `.`) is the directory the
|
|
126
|
+
referenced artifact files are resolved against, and generated
|
|
350
127
|
specification Markdown files are placed inside it, too.
|
|
351
128
|
|
|
352
129
|
The export output option `-o`/`--output` (default: `-` for stdout) can
|
|
@@ -355,41 +132,44 @@ occur multiple times. The format (`json`, `json5`, `yaml`, `toon`,
|
|
|
355
132
|
it is explicitly given as a `<format>:` prefix, and plain `-` (stdout)
|
|
356
133
|
defaults to JSON.
|
|
357
134
|
|
|
135
|
+
The `describe` command outputs the description of the SpecBook models
|
|
136
|
+
and formats. If the configuration file `-c`/`--config` or the base
|
|
137
|
+
directory `-b`/`--basedir` is given, it additionally appends a *SpecBook
|
|
138
|
+
Project Instantiation* section which points to these artifacts of the
|
|
139
|
+
particular project. With `-e`/`--embed` the YAML schema configuration is
|
|
140
|
+
embedded verbatim instead of just being referenced, so the resulting
|
|
141
|
+
document describes the specification format of the project entirely on
|
|
142
|
+
its own.
|
|
143
|
+
|
|
358
144
|
The default value of every CLI option `--xxx` can be overridden by a
|
|
359
145
|
corresponding `SPECBOOK_XXX` environment variable (e.g.
|
|
360
146
|
`SPECBOOK_BASEDIR`, `SPECBOOK_CONFIG`, `SPECBOOK_OUTPUT`,
|
|
361
|
-
`SPECBOOK_VERBOSE`), while an explicitly supplied option always wins.
|
|
147
|
+
`SPECBOOK_VERBOSE`), while an explicitly supplied option always wins. A
|
|
148
|
+
`SPECBOOK_CONFIG` value also satisfies the otherwise mandatory
|
|
149
|
+
`-c`/`--config` option.
|
|
362
150
|
|
|
363
151
|
### API
|
|
364
152
|
|
|
365
153
|
```ts
|
|
366
|
-
import { SpecBook } from "@rse/specbook"
|
|
154
|
+
import { SpecBook, renderVerbose } from "@rse/specbook"
|
|
367
155
|
|
|
368
|
-
const specbook = new SpecBook({
|
|
369
|
-
|
|
156
|
+
const specbook = new SpecBook({
|
|
157
|
+
verbose: (cmd, msg) => console.error(`specbook: ${cmd}: ${renderVerbose(msg)}`)
|
|
158
|
+
})
|
|
159
|
+
const result = await specbook.lint({
|
|
160
|
+
config: "smp/ase.specbook.yaml",
|
|
161
|
+
basedir: "smp/broadcast"
|
|
162
|
+
})
|
|
370
163
|
```
|
|
371
164
|
|
|
372
165
|
### MCP
|
|
373
166
|
|
|
374
|
-
Run `specbook mcp` to serve the tools `specbook_init`,
|
|
375
|
-
`
|
|
376
|
-
`specbook_import`, and `specbook_edit` over stdio.
|
|
377
|
-
|
|
378
|
-
### AI Configuration
|
|
379
|
-
|
|
380
|
-
The commands `import` and `edit` use an LLM. The environment variables
|
|
381
|
-
`SPECBOOK_AI_PROVIDER` (`anthropic`, `openai`, `openrouter`, or
|
|
382
|
-
`ollama`) and
|
|
383
|
-
`SPECBOOK_AI_MODEL` provide the defaults, which the CLI options
|
|
384
|
-
`--provider`/`--model` (respectively the MCP/API parameters `provider`/
|
|
385
|
-
`model`) override. The provider API keys come from the standard
|
|
386
|
-
environment variables (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
|
|
387
|
-
`OPENROUTER_API_KEY`), while `ollama` needs no key and uses the local
|
|
388
|
-
Ollama service.
|
|
167
|
+
Run `specbook mcp` to serve the tools `specbook_init`, `specbook_lint`,
|
|
168
|
+
`specbook_export`, and `specbook_describe` over stdio.
|
|
389
169
|
|
|
390
170
|
License
|
|
391
171
|
-------
|
|
392
172
|
|
|
393
|
-
Copyright © 2026 Dr. Ralf S. Engelschall
|
|
394
|
-
Licensed under Apache 2.0
|
|
173
|
+
Copyright © 2026 [Dr. Ralf S. Engelschall](http://engelschall.com/)<br/>
|
|
174
|
+
Licensed under [Apache 2.0](https://spdx.org/licenses/Apache-2.0)
|
|
395
175
|
|
package/dst/specbook-api.d.ts
CHANGED
|
@@ -1,47 +1,40 @@
|
|
|
1
1
|
import { renderDiagnostic, renderDiagnosticVerbose, type Diagnostic } from "./specbook-diagnostic.js";
|
|
2
2
|
import { type LintResult } from "./specbook-cmd-lint.js";
|
|
3
3
|
import { parseOutputSpec, formats, type ExportFormat } from "./specbook-cmd-export.js";
|
|
4
|
+
import { literal, renderVerbose } from "./specbook-verbose.js";
|
|
5
|
+
export { literal, renderVerbose };
|
|
4
6
|
export { formats, parseOutputSpec, type ExportFormat };
|
|
5
7
|
export { renderDiagnostic, renderDiagnosticVerbose, type Diagnostic };
|
|
6
8
|
export { type LintResult };
|
|
7
|
-
export type {
|
|
8
|
-
export type {
|
|
9
|
+
export type { Spec, SpecArtifact, SpecObject, SpecDescription, SpecProperty } from "./specbook-format-spec.js";
|
|
10
|
+
export type { Schema, SchemaObject, SchemaProperty } from "./specbook-format-schema.js";
|
|
9
11
|
export declare const version: string;
|
|
12
|
+
export type VerboseSink = (cmd: string, msg: string) => void;
|
|
10
13
|
export interface SpecBookOptions {
|
|
11
|
-
verbose?:
|
|
14
|
+
verbose?: VerboseSink;
|
|
12
15
|
}
|
|
13
16
|
export declare class SpecBook {
|
|
14
17
|
private verbose;
|
|
15
18
|
constructor(options?: SpecBookOptions);
|
|
19
|
+
private verboseOf;
|
|
20
|
+
private requireConfigFile;
|
|
16
21
|
private requireConfig;
|
|
17
22
|
init(options: {
|
|
18
|
-
config
|
|
23
|
+
config: string;
|
|
19
24
|
basedir?: string;
|
|
20
25
|
}): Promise<string[]>;
|
|
21
26
|
lint(options: {
|
|
22
|
-
config
|
|
27
|
+
config: string;
|
|
23
28
|
basedir?: string;
|
|
24
29
|
}): Promise<LintResult>;
|
|
25
30
|
export(options: {
|
|
26
|
-
config
|
|
31
|
+
config: string;
|
|
27
32
|
basedir?: string;
|
|
28
33
|
formats?: ExportFormat[];
|
|
29
34
|
}): Promise<Buffer[]>;
|
|
30
35
|
describe(options: {
|
|
31
36
|
config?: string;
|
|
32
|
-
}): Promise<string>;
|
|
33
|
-
import(options: {
|
|
34
|
-
config?: string;
|
|
35
37
|
basedir?: string;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
model?: string;
|
|
39
|
-
}): Promise<string[]>;
|
|
40
|
-
edit(options: {
|
|
41
|
-
config?: string;
|
|
42
|
-
basedir?: string;
|
|
43
|
-
query: string;
|
|
44
|
-
provider?: string;
|
|
45
|
-
model?: string;
|
|
46
|
-
}): Promise<string[]>;
|
|
38
|
+
embed?: boolean;
|
|
39
|
+
}): Promise<string>;
|
|
47
40
|
}
|