@rse/specbook 1.5.2 → 1.6.1

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 (63) hide show
  1. package/LICENSE.txt +201 -0
  2. package/README.md +288 -43
  3. package/dst/specbook-api.d.ts +23 -3
  4. package/dst/specbook-api.js +133 -59
  5. package/dst/specbook-cli.js +93 -26
  6. package/dst/specbook-cmd-describe.js +4 -4
  7. package/dst/specbook-cmd-export-schema.d.ts +8 -0
  8. package/dst/specbook-cmd-export-schema.js +441 -0
  9. package/dst/specbook-cmd-export.js +23 -6
  10. package/dst/specbook-cmd-init-sample.d.ts +4 -0
  11. package/dst/specbook-cmd-init-sample.js +322 -0
  12. package/dst/specbook-cmd-init.d.ts +1 -0
  13. package/dst/specbook-cmd-init.js +42 -10
  14. package/dst/specbook-cmd-lint.js +46 -48
  15. package/dst/specbook-cmd-query.d.ts +30 -0
  16. package/dst/specbook-cmd-query.js +165 -0
  17. package/dst/specbook-config.d.ts +9 -1
  18. package/dst/specbook-config.js +135 -10
  19. package/dst/specbook-coverage.js +2 -2
  20. package/dst/specbook-diagram.d.ts +7 -5
  21. package/dst/specbook-diagram.js +546 -143
  22. package/dst/specbook-export-ast.d.ts +1 -1
  23. package/dst/specbook-export-ast.js +11 -8
  24. package/dst/specbook-export-code.js +3 -3
  25. package/dst/specbook-export-common.d.ts +1 -1
  26. package/dst/specbook-export-common.js +3 -2
  27. package/dst/specbook-export-diagram.d.ts +1 -1
  28. package/dst/specbook-export-diagram.js +25 -7
  29. package/dst/specbook-export-html-fold.d.ts +16 -6
  30. package/dst/specbook-export-html-fold.js +65 -44
  31. package/dst/specbook-export-html-render.js +107 -26
  32. package/dst/specbook-export-html-search.js +18 -20
  33. package/dst/specbook-export-html-template.js +38 -9
  34. package/dst/specbook-export-html-widget.d.ts +2 -0
  35. package/dst/specbook-export-html-widget.js +219 -19
  36. package/dst/specbook-export-html.css +208 -38
  37. package/dst/specbook-export-html.js +96 -53
  38. package/dst/specbook-export-md.d.ts +2 -1
  39. package/dst/specbook-export-md.js +7 -8
  40. package/dst/specbook-export-pdf.js +1 -1
  41. package/dst/specbook-files.d.ts +2 -0
  42. package/dst/specbook-files.js +41 -0
  43. package/dst/specbook-format-meta.yaml +401 -0
  44. package/dst/specbook-format-pm.yaml +1240 -0
  45. package/dst/specbook-format-schema.d.ts +33 -3
  46. package/dst/specbook-format-schema.js +49 -3
  47. package/dst/specbook-format.md +427 -47
  48. package/dst/specbook-format.yaml +524 -228
  49. package/dst/specbook-ignore.js +2 -2
  50. package/dst/specbook-link.d.ts +4 -0
  51. package/dst/specbook-link.js +61 -6
  52. package/dst/specbook-mcp.js +103 -19
  53. package/dst/specbook-parse-semantic.d.ts +1 -0
  54. package/dst/specbook-parse-semantic.js +11 -4
  55. package/dst/specbook-parse-syntax.d.ts +1 -0
  56. package/dst/specbook-parse-syntax.js +1 -1
  57. package/dst/specbook-parse.d.ts +1 -1
  58. package/dst/specbook-parse.js +3 -3
  59. package/dst/specbook-project.d.ts +2 -0
  60. package/dst/specbook-project.js +15 -5
  61. package/dst/specbook-remote.d.ts +28 -0
  62. package/dst/specbook-remote.js +429 -0
  63. package/package.json +32 -20
package/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
 
2
- <img src="https://raw.githubusercontent.com/rse/specbook/master/etc/specbook-logo-blue-light.svg" width="400" align="right" alt=""/>
2
+ <img src="https://raw.githubusercontent.com/rse/specbook/master/etc/specbook-logo-blue-light.svg"
3
+ width="400" align="right" alt=""/>
3
4
 
4
5
  SpecBook
5
6
  ========
@@ -8,8 +9,13 @@ SpecBook
8
9
 
9
10
  [specbook.tools](https://specbook.tools)
10
11
 
11
- [![github (author stars)](https://img.shields.io/github/stars/rse?logo=github&label=author%20stars&color=%233377aa)](https://github.com/rse)
12
- [![github (author followers)](https://img.shields.io/github/followers/rse?label=author%20followers&logo=github&color=%234477aa)](https://github.com/rse)
12
+ [![github (author stars)][badge-stars]](https://github.com/rse)
13
+ [![github (author followers)][badge-followers]](https://github.com/rse)
14
+
15
+ [badge-stars]:
16
+ https://img.shields.io/github/stars/rse?logo=github&label=author%20stars&color=%233377aa
17
+ [badge-followers]:
18
+ https://img.shields.io/github/followers/rse?label=author%20followers&logo=github&color=%234477aa
13
19
 
14
20
  About
15
21
  -----
@@ -19,7 +25,8 @@ format* which can be configured for the specifications of particular
19
25
  contexts through a YAML-based *schema configuration*. SpecBook allows
20
26
  specifications to be *initialized*, *linted*, *exported* (JSON, JSON5,
21
27
  YAML, TOON, HTML, PDF, and normalized Markdown), *previewed* (HTML, live
22
- in the browser), and *described* to LLMs.
28
+ in the browser), *queried* (ASTq selectors on the AST), and *described*
29
+ to LLMs.
23
30
 
24
31
  **SpecBook** ships with an API class with methods `<xxx>()`, a
25
32
  CLI with commands `specbook <xxx>`, and an MCP service with tools
@@ -29,7 +36,7 @@ CLI with commands `specbook <xxx>`, and an MCP service with tools
29
36
 
30
37
  - **Hierarchical Object Model**:
31
38
  A specification is a tree of typed objects, each with a kind and
32
- name, an optional id, optional properties, optional description, and
39
+ name, an optional id, optional properties, an optional description, and
33
40
  optional child objects. The allowed object hierarchy is defined per
34
41
  context by the YAML schema configuration.
35
42
 
@@ -41,7 +48,7 @@ CLI with commands `specbook <xxx>`, and an MCP service with tools
41
48
 
42
49
  - **Wiki-Style Object Linking**:
43
50
  Objects can hierarchically reference each other through Wiki-style
44
- `[[xxx]]` references, which are resolved against the locally-unique
51
+ `[[xxx]]` references, which are resolved against the locally unique
45
52
  ids and names of all objects. In the HTML and PDF exports they become
46
53
  navigable links onto precise anchors.
47
54
 
@@ -58,9 +65,10 @@ CLI with commands `specbook <xxx>`, and an MCP service with tools
58
65
  demands is reported as a warning only. A bundled standard schema
59
66
  configuration applies if no particular one is given.
60
67
 
61
- - **Object Model Diagram Visualisation**:
62
- Object kinds can declare "graph", "hub", or "grid" diagrams in the
63
- schema, whose nodes and edges are automatically derived from the
68
+ - **Object Model Diagram Visualization**:
69
+ Object kinds can declare one or more "graph", "hub", "grid", "state",
70
+ "layer", "slice", "tree", "matrix", "sequence", "petri", or "gantt" diagrams in
71
+ the schema, whose nodes and edges are automatically derived from the
64
72
  object model and its references. The diagrams are rendered with the
65
73
  sibling project [Gradia](https://github.com/rse/gradia), which is
66
74
  specialized in rendering object models.
@@ -84,11 +92,15 @@ CLI with commands `specbook <xxx>`, and an MCP service with tools
84
92
  a table-of-contents (also as a slide-in side panel for quick navigation),
85
93
  a diagram-of-contents, a fuzzy full-text search, embedded images,
86
94
  embedded Mermaid and D2 diagrams (inline or as files, in the theme colors),
87
- embedded PDF pages,
95
+ embedded PDF pages, syntax-highlighted code listings (fenced or as
96
+ files, with line numbers and marked lines),
88
97
  reference coverage tables (e.g. the share of the use cases, scenarios,
89
98
  requirements, and rules the test cases verify), a
90
99
  scroll progress meter (which also scrolls back to the top on click),
91
100
  diagram maximization (into the viewport or the fullscreen),
101
+ folding of the diagrams and over-long table cells, an artifact
102
+ filter (which shows only the objects the selected artifacts reach
103
+ through their references),
92
104
  description popups (which show the schema and corpus description of
93
105
  an object kind, property, or object instance on hover), and a
94
106
  light/dark theme toggle. It is intended for the day-to-day online
@@ -108,7 +120,8 @@ CLI with commands `specbook <xxx>`, and an MCP service with tools
108
120
  The title object of the specification drives the entire document:
109
121
  its title, subtitle, author, version, and logo fill the title page
110
122
  (with an optional light/dark variant of the logo), its language
111
- selects the smart typography quote style, its color tone seeds the
123
+ selects the smart typography quote style and the translation of the
124
+ rationale keyword (like `BECAUSE (weil)`), its color tone seeds the
112
125
  theme color spreads of both the light and the dark theme, and its
113
126
  character set subsets the embedded fonts down to the actually needed
114
127
  glyphs.
@@ -138,40 +151,67 @@ Commands:
138
151
  $ specbook init \
139
152
  [-v|--verbose [<level>]] \
140
153
  [-c|--config <schema-yaml-file>] \
141
- [-b|--basedir <spec-md-file-basedir>]
154
+ [-b|--basedir <spec-md-file-basedir>] \
155
+ [-F|--fetch <mode>] \
156
+ [-s|--sample]
142
157
 
143
158
  $ specbook lint \
144
159
  [-v|--verbose [<level>]] \
145
160
  [-c|--config <schema-yaml-file>] \
146
- [-b|--basedir <spec-md-file-basedir>]
161
+ [-b|--basedir <spec-md-file-basedir>] \
162
+ [-F|--fetch <mode>] \
163
+ [-g|--gitignore]
147
164
 
148
165
  $ specbook export \
149
166
  [-v|--verbose [<level>]] \
150
167
  [-c|--config <schema-yaml-file>] \
151
168
  [-b|--basedir <spec-md-file-basedir>] \
152
- [-o|--output [<format>:]<output-file>] \
169
+ [-F|--fetch <mode>] \
170
+ [-g|--gitignore] \
171
+ [-S|--schema] \
172
+ [-o|--output [<format>:]<output-file>] [...] \
153
173
  [-w|--watch] \
154
- [-O|--omit <aspect>[,...]] \
155
- [...]
174
+ [-O|--omit <aspect>[,...]]
156
175
 
157
176
  $ specbook preview \
158
177
  [-v|--verbose [<level>]] \
159
178
  [-c|--config <schema-yaml-file>] \
160
179
  [-b|--basedir <spec-md-file-basedir>] \
180
+ [-F|--fetch <mode>] \
181
+ [-g|--gitignore] \
182
+ [-S|--schema] \
161
183
  [-O|--omit <aspect>[,...]] \
162
184
  [-a|--addr <ip-addr>] \
163
185
  [-p|--port <tcp-port>]
164
186
 
187
+ $ specbook query \
188
+ [-v|--verbose [<level>]] \
189
+ [-c|--config <schema-yaml-file>] \
190
+ [-b|--basedir <spec-md-file-basedir>] \
191
+ [-F|--fetch <mode>] \
192
+ [-g|--gitignore] \
193
+ [-S|--schema] \
194
+ [-P|--param <name>=<value>] [...] \
195
+ [-f|--format <format>] \
196
+ [-o|--output [<format>:]<output-file>] \
197
+ <selector>
198
+
165
199
  $ specbook describe \
166
200
  [-v|--verbose [<level>]] \
167
201
  [-c|--config <schema-yaml-file>] \
168
202
  [-b|--basedir <spec-md-file-basedir>] \
203
+ [-F|--fetch <mode>] \
169
204
  [-e|--embed] \
170
205
  [-z|--compress [<level>]] \
171
206
  [-f|--format <format>] \
172
207
  [-p|--part <part>] \
173
208
  [-o|--output <output-file>]
174
209
 
210
+ $ specbook search \
211
+ [-v|--verbose [<level>]] \
212
+ [-F|--fetch <mode>] \
213
+ [<term> ...]
214
+
175
215
  $ specbook mcp \
176
216
  [-v|--verbose [<level>]]
177
217
  ```
@@ -180,7 +220,8 @@ Options:
180
220
 
181
221
  - `-v|--verbose [<level>]`:
182
222
  Enable verbose logging of processing information to `stderr` at the
183
- given verbosity level: `0` (the default) logs the notices only, `1`
223
+ given verbosity level: `0` (the default) logs the warnings and the
224
+ environment problems only, `1`
184
225
  (the bare flag) also the regular processing information, `2` also
185
226
  the reference coverage ratios, and `3` also the unreferenced objects
186
227
  of a reference coverage.
@@ -188,12 +229,11 @@ Options:
188
229
  - `-c|--config <schema-yaml-file>`:
189
230
  The YAML schema configuration (default: the `config` entry of the
190
231
  project configuration file `.specbook.yaml`, else the bundled standard
191
- schema configuration `specbook-format.yaml`) determines the specification:
192
- exactly the artifact files its `file` fields reference are loaded and
193
- parsed; all other Markdown files below the base directory are ignored.
194
- A referenced file which is absent is reported, unless all of its
195
- artifacts are `optional`, and so is an artifact absent from its present
196
- file, unless it is `optional` itself. Both `lint` and `export` report
232
+ schema configuration `specbook-format.yaml`) determines the artifacts
233
+ of the specification, while its `file` fields drive `init` only: every
234
+ `.md` file below the base directory is loaded and parsed, whatever its
235
+ name. A base directory without any `.md` file is reported, and so is an
236
+ artifact absent from all of them, unless it is `optional`. Both `lint` and `export` report
197
237
  all diagnostics and fail on any error among them (a warning, like a
198
238
  lapse of the reference coverage a `referenced` object kind demands,
199
239
  is reported only), so a partial or invalid specification is never
@@ -204,7 +244,11 @@ Options:
204
244
  The option accepts glob patterns and can be given multiple times: the
205
245
  matching files (in the order of the patterns and alphabetically within
206
246
  a pattern, where the literal `std` names the bundled standard schema
207
- configuration, and where a pattern matching no file is an error) are
247
+ configuration, the literal `meta` the bundled meta one, which
248
+ describes a schema configuration itself, and the literal `pm` the
249
+ bundled project management one, which plans the delivery of a
250
+ solution in a handbook beside its specification, and where a pattern matching
251
+ no file is an error) are
208
252
  merged in order into one effective schema configuration, the later
209
253
  files into the earlier ones. The objects merge deeply, while the
210
254
  elements of the lists are matched by identity (artifacts by `kind`
@@ -213,12 +257,61 @@ Options:
213
257
  counterpart, an unmatched one is appended. Every file has to be valid
214
258
  YAML on its own, while the merged result alone is validated against
215
259
  the schema of the configuration.
260
+ Instead of a local file, the option also accepts a *remote reference*
261
+ (see "Remote References" below): `npm:<pkg>[@<range>][/<path>]`,
262
+ `github:<user>/<repo>[/<path>][#<ref>]`, or an `http://` or `https://`
263
+ URL of a single file, which is fetched into the download cache and then merged
264
+ exactly like a local file.
216
265
 
217
266
  - `-b|--basedir <spec-md-file-basedir>`:
218
267
  The base directory (default: the `basedir` entry of the project
219
- configuration file `.specbook.yaml`, else `.`) is the directory the
220
- referenced artifact files are resolved against, and generated
221
- specification Markdown files are placed inside it, too.
268
+ configuration file `.specbook.yaml`, else `.`) is the directory
269
+ whose `.md` files (recursively, except below `.`-prefixed entries)
270
+ make up the specification, and generated specification Markdown
271
+ files are placed inside it, too. A normalized Markdown export written
272
+ into it is refused, as it would be parsed as a specification file.
273
+
274
+ - `-F|--fetch <mode>`:
275
+ When to fetch the remote references of the schema configuration
276
+ through the network: `never` (the download cache only, where a
277
+ reference which is not cached is an error), `auto` (the default:
278
+ whenever the download cache lacks a reference or it is no longer
279
+ fresh), or `always` (ignoring the download cache).
280
+
281
+ - `-g|--gitignore` (`lint`, `export`, `preview`, and `query` only):
282
+ Set aside every specification file the Git exclude rules (the global
283
+ excludes file, the repository-local `info/exclude`, and the
284
+ `.gitignore` files, with Git's own precedence) exclude from its
285
+ project, as it is no part of the project: silently if all of its
286
+ artifacts are optional, else as the error `artifact file excluded by
287
+ Git`. A base directory outside any Git working tree excludes nothing.
288
+
289
+ - `-S|--schema` (`export`, `preview`, and `query` only):
290
+ Export (or preview, or query) the *effective schema configuration itself* --
291
+ the one `-c|--config` selects, merged out of its local, bundled, or
292
+ remote files -- as a SpecBook document, instead of the specification
293
+ below the base directory (which is not applicable then, so an
294
+ explicit `-b|--basedir` is an error, and `--watch` and `preview`
295
+ observe the configuration files only). The document is generated in
296
+ memory against the bundled meta schema configuration (`meta`) and
297
+ rendered like any other specification, in every export format: a
298
+ title page with the configuration references, the SpecBook version,
299
+ and the counts of the artifact kinds, artifacts, object kinds, and
300
+ reference relationships, an artifact-level overview graph as the
301
+ "Diagram of Contents", and one top-level `ARTIFACT-KIND` artifact per
302
+ artifact kind (with a graph of its artifacts and object kinds),
303
+ every artifact and object kind
304
+ (with its file, name pattern, optionality, `referenced`/`coverage`
305
+ patterns, `automaton`, `badge`, `multiple`, `diagram`, and `format`
306
+ configuration, its
307
+ description and literature references, and a hub diagram of its
308
+ references, every artifact also with a Mermaid UML class diagram of
309
+ it and its object kinds, omittable via `-O diagram:code` and left out
310
+ without relationships), and every property (with its value constraint and
311
+ flags, a reference-valued one additionally naming its target
312
+ artifacts and object kinds and its cardinality, and acting as an edge
313
+ of the diagrams). When several configuration files are merged, every
314
+ object also names the files contributing it.
222
315
 
223
316
  - `-o|--output [<format>:]<output-file>` (`export` only):
224
317
  The output file (`-` for stdout) is required and can be given multiple times.
@@ -230,8 +323,9 @@ Options:
230
323
 
231
324
  - `-w|--watch` (`export` only):
232
325
  Keep the outputs in sync with their sources: after the regular export,
233
- the YAML schema configuration files, the referenced artifact files, and
234
- all assets they embed are observed, and every change re-exports the
326
+ the YAML schema configuration files, the specification files, all
327
+ assets they embed, and the base directory itself (for added and removed
328
+ `.md` files) are observed, and every change re-exports the
235
329
  specification once the sources stayed silent for one second. A failed
236
330
  re-export is reported and leaves the observe loop intact, so a
237
331
  transiently invalid specification (or configuration) does not end the
@@ -244,9 +338,12 @@ Options:
244
338
  Omit content aspects (comma-separated, repeatable) from the HTML and
245
339
  PDF outputs at generation time, instead of just leaving them foldable
246
340
  in the browser. The aspects match the folding controls of the HTML
247
- export: `diagram:graph`, `diagram:hub`, `diagram:grid`,
248
- `diagram:code` (Mermaid/D2), and `diagram:image` (images and PDF pages) omit all
249
- diagrams of a type, `diagram:1` (alias: `diagram`), `diagram:2`, and
341
+ export: `diagram:graph`, `diagram:hub`, `diagram:grid`, `diagram:state`,
342
+ `diagram:layer`, `diagram:slice`, `diagram:tree`, `diagram:matrix`,
343
+ `diagram:sequence`, `diagram:petri`, `diagram:gantt`, `diagram:code`
344
+ (Mermaid/D2), `diagram:image` (images and PDF pages), and
345
+ `diagram:listing` (code listings) omit all diagrams of a type,
346
+ `diagram:1` (alias: `diagram`), `diagram:2`, and
250
347
  `diagram:3` omit all diagrams from an object tree nesting level on
251
348
  (level 1 hence all, including the "Diagram of Contents" page), and
252
349
  `text:long` cuts every table cell whose estimated number of text
@@ -272,6 +369,28 @@ Options:
272
369
  the connection state: its plug icon carries the search highlight
273
370
  color while disconnected and blinks for 2s after every update.
274
371
 
372
+ - `-P|--param <name>=<value>`, `<selector>` (`query` only):
373
+ Query the specification (strictly validated like `export`) with the
374
+ XPath-like selector of [ASTq](https://github.com/rse/astq) and write
375
+ the matched nodes as an array (their subtrees included, the embedded
376
+ file contents dropped), where `-P|--param` (repeatable) gives the
377
+ value of a `{name}` parameter of the selector.
378
+ The root node is of type `specification`, its children are of type
379
+ `artifact` (attributes `created`, `modified`, and `file`), and the
380
+ objects below are typed by their kind (attributes `kind`, `id`,
381
+ `anchor`, `paren`, `name`, `primary`, `description`, `rationale`,
382
+ `elaboration`, and one per property key), e.g.
383
+ `specbook query "// USE-CASE [ @ACTOR == '[[ROLE:attendee]]' ]"`. The
384
+ query function `refs()` yields the objects the references of an object
385
+ resolve to, e.g. `specbook query "// REQUIREMENT [ count(refs()) == 0 ]"`.
386
+
387
+ - `-f|--format <format>`, `-o|--output [<format>:]<output-file>` (`query` only):
388
+ The output file (default: `-` for stdout) receives the matched nodes
389
+ in the format `json`, `json5`, `yaml`, or `toon`, where an explicit
390
+ `-f|--format` wins and the format is otherwise inferred exactly like
391
+ for an `export` output (a `<format>:` prefix, else the filename
392
+ extension, while plain `-` defaults to JSON).
393
+
275
394
  - `-o|--output <output-file>` (`describe` only):
276
395
  The output file (default: `-` for stdout) receives the described
277
396
  Markdown document.
@@ -287,7 +406,8 @@ Options:
287
406
  raw file content), so the configuration costs fewer tokens: `0`
288
407
  emits it verbatim, `1` re-emits it with 2-space indentation, unwrapped
289
408
  lines, and without comments, `2` additionally leaves out its `refs`,
290
- `diagram`, and `format` fields, and `3` additionally leaves out its
409
+ `badge`, `multiple`, `diagram`, and `format` fields, and `3`
410
+ additionally leaves out its
291
411
  `desc` fields of objects and properties. The MCP tool `specbook_describe` defaults to
292
412
  `2` instead, as its consumer is an LLM.
293
413
 
@@ -317,8 +437,8 @@ basedir: docs/spec
317
437
  ```
318
438
 
319
439
  The entry `config` is a single file or glob pattern or a list of them
320
- (exactly like the repeatable `-c|--config`, including the literal
321
- `std`), and the entry `basedir` is a directory. Relative paths resolve
440
+ (exactly like the repeatable `-c|--config`, including the literals
441
+ `std`, `meta`, and `pm`), and the entry `basedir` is a directory. Relative paths resolve
322
442
  against the directory of the `.specbook.yaml` itself, the file is
323
443
  validated (an unknown entry or a wrongly typed value fails the command),
324
444
  and both an explicitly supplied option and its environment variable
@@ -326,7 +446,12 @@ win over its entry.
326
446
 
327
447
  `specbook init` creates such a file in the current working directory
328
448
  (unless one already applies), so the options of the initialization
329
- stick for all subsequent commands.
449
+ stick for all subsequent commands. With `-s|--sample` it scaffolds a
450
+ small sample into the created artifact files instead of the bare
451
+ headings -- one object per allowed object kind, with every configured
452
+ property carrying a placeholder value satisfying the schema and the
453
+ first sentence of the schema description of the kind as its statement
454
+ -- so the format is learnable from the generated files alone.
330
455
 
331
456
  The default value of every CLI option `--xxx` can be overridden
332
457
  by a corresponding `SPECBOOK_XXX` environment variable (e.g.
@@ -345,11 +470,102 @@ an executable path and any other one as a Playwright channel name
345
470
  `chrome-dev`, `chrome-canary`, `msedge`, `msedge-beta`, `msedge-dev`,
346
471
  or `msedge-canary`). The variable itself has no default value: when it
347
472
  is unset, the downloaded Playwright Chromium is used (the equivalent of
348
- `chromium`) and only if that one is absent a system-installed *Google
473
+ `chromium`) and, only if that one is absent, a system-installed *Google
349
474
  Chrome* (the equivalent of `chrome`). An explicitly configured browser
350
475
  failing to launch fails the export instead of falling back onto another
351
476
  browser.
352
477
 
478
+ ### API
479
+
480
+ Third-party scripts generating foreign documents out of a specification
481
+ load it (strictly validated like `export`) and query its AST through the
482
+ very same ASTq selectors as `specbook query`, retrieving the *original*
483
+ AST nodes:
484
+
485
+ ```ts
486
+ import { SpecBook, type SpecObject } from "@rse/specbook"
487
+
488
+ const specbook = new SpecBook()
489
+ const document = await specbook.load({ basedir: "docs/spec" })
490
+
491
+ /* register a custom query function (beside the built-in "refs()") */
492
+ document.func("contains", (_adapter, _node, list, item) =>
493
+ Array.isArray(list) && list.includes(item))
494
+
495
+ /* emit the roles with the use cases referencing them as Markdown */
496
+ for (const role of document.query("// ROLE") as SpecObject[]) {
497
+ console.log(`## ${document.plain(role.name)}\n`)
498
+ for (const useCase of document.query("// USE-CASE [ contains(refs(), {role}) ]",
499
+ { role }) as SpecObject[])
500
+ console.log(`- ${document.plain(useCase.name)}`)
501
+ }
502
+ ```
503
+
504
+ The `SpecBookDocument` returned by `load()` (options like `lint`, plus
505
+ `schema`) carries the `specification`, its `config`, and the warning
506
+ `diagnostics`, and provides `query(selector, params?)`, `parent(node)`
507
+ (the AST nodes carrying no parent references), `func(name, fn)`, and the
508
+ text helpers `plain(text, from?)` and `html(text, from?)`, which render
509
+ a Markdown text (a description part or property value) into plain text
510
+ resp. an HTML fragment, replacing every `[[...]]` reference by the name
511
+ of its target object.
512
+
513
+ Remote References
514
+ -----------------
515
+
516
+ Useful schema configurations should not stay buried in individual
517
+ project repositories. SpecBook hence resolves *remote references*
518
+ wherever a schema configuration is expected (`-c|--config`, the `config`
519
+ entry of `.specbook.yaml`, `SPECBOOK_CONFIG`):
520
+
521
+ - `npm:<pkg>[@<range>][/<path>]`: a package of the npm registry (the
522
+ package perhaps scoped, the version a semver range or dist-tag,
523
+ default `latest`), resolved and fetched through the npm registry
524
+ client itself, so the `registry`, the scoped `@scope:registry`, and
525
+ the `//host/:_authToken` credentials of your `.npmrc` files (and the
526
+ `npm_config_*` environment variables) are honored, while none of the
527
+ scripts of the package is ever run.
528
+
529
+ - `github:<user>/<repo>[/<path>][#<ref>]`: a GitHub repository at a
530
+ branch, tag, or commit (default: `HEAD`), fetched as its tarball,
531
+ where `GITHUB_TOKEN` (or `SPECBOOK_GITHUB_TOKEN`) authenticates the
532
+ private repositories.
533
+
534
+ - `http[s]://<host>[:<port>]/<path>/<file>`: a single schema
535
+ configuration file.
536
+
537
+ The `<path>` inside a package names a schema configuration file, a glob
538
+ pattern of such files, or a named building block of the
539
+ `"specbook": { "schema": { "<name>": "<file>", ... } }` map of the
540
+ `package.json` of the package. An absent path resolves through the
541
+ `"specbook": { "schema": "<file>" }` entry of the `package.json`, then
542
+ through the `config` entries of the `.specbook.yaml` of the package
543
+ (whose remote entries resolve transitively, a cycle being an error),
544
+ and finally through its `index.yaml`. A package may
545
+ declare the SpecBook versions it supports through
546
+ `"engines": { "specbook": "<range>" }` of its `package.json`, which is
547
+ checked. The artifacts several schema configuration files define (and
548
+ hence merge) are reported at verbosity level `2`, and unconditionally
549
+ if two remote files collide, as such a merge is hardly intended.
550
+
551
+ The downloads are cached under `SPECBOOK_CACHE` (default: the native
552
+ cache location of the platform, like `~/Library/Caches/specbook` on
553
+ macOS, `%LOCALAPPDATA%\specbook\Cache` on Windows, and
554
+ `$XDG_CACHE_HOME/specbook` or `~/.cache/specbook` elsewhere): an exact
555
+ npm version or a commit hash is immutable and stays cached forever,
556
+ while a floating reference (a range, a branch, a tag, a URL) is
557
+ fetched again after five minutes. With `-F|--fetch never` (or
558
+ `SPECBOOK_FETCH=never`), only the cache is consulted, and a reference
559
+ which is not cached is an error, while `-F|--fetch always` fetches every
560
+ reference again.
561
+
562
+ To share a schema configuration of your own, publish it as a plain npm
563
+ package carrying the keyword `specbook-schema` (or push it to a GitHub
564
+ repository carrying the same topic), so `specbook search [<term> ...]`
565
+ (and the MCP tool `specbook_search`) finds it, right after the bundled
566
+ schema configurations `std`, `meta`, and `pm`, which it always
567
+ lists first (and which are all it lists under `--fetch never`).
568
+
353
569
  Agent Skill
354
570
  -----------
355
571
 
@@ -364,10 +580,13 @@ $ claude plugin install specbook@specbook
364
580
 
365
581
  ```text
366
582
  /specbook [-c|--config <yaml-file>] [-b|--basedir <basedir>] [<query>]
367
- /specbook init [-c|--config <yaml-file>] [-b|--basedir <basedir>]
368
- /specbook lint [-c|--config <yaml-file>] [-b|--basedir <basedir>] [-g|--gitignore]
369
- /specbook export [-c|--config <yaml-file>] [-b|--basedir <basedir>] [-g|--gitignore]
370
- [-O|--omit <aspect>[,...]] [-o|--output [<format>:]<output-file>] [...]
583
+ /specbook init [-c|--config <yaml-file>] [-b|--basedir <basedir>] [-F|--fetch <mode>]
584
+ [-s|--sample]
585
+ /specbook lint [-c|--config <yaml-file>] [-b|--basedir <basedir>] [-F|--fetch <mode>]
586
+ [-g|--gitignore]
587
+ /specbook export [-c|--config <yaml-file>] [-b|--basedir <basedir>] [-F|--fetch <mode>]
588
+ [-g|--gitignore] [-O|--omit <aspect>[,...]]
589
+ [-o|--output [<format>:]<output-file>] [...]
371
590
  /specbook edit [-c|--config <yaml-file>] [-b|--basedir <basedir>] [-g|--grill]
372
591
  [-r|--grill-rounds <n>] [-v|--verify] [-l|--loop] [<query>]
373
592
  ```
@@ -395,7 +614,7 @@ query (`--loop`). All commands leave an absent `--config` and
395
614
  Example: Simple
396
615
  ---------------
397
616
 
398
- Check out the *simple* specification of simple
617
+ Check out the *simple* specification of a simple
399
618
  example data model:
400
619
 
401
620
  ### Sources
@@ -446,6 +665,32 @@ $ specbook export -v \
446
665
 
447
666
  ![screenshot-broadcast-print](etc/screenshot-broadcast-print.png)
448
667
 
668
+ Example: Project Management
669
+ ---------------------------
670
+
671
+ Check out the *project management handbook* of the Broadcast
672
+ project, based on **SpecBook**'s built-in "pm" schema, which plans the
673
+ delivery of a solution (the project charter with its objectives,
674
+ constraints, assumptions, and budget, the team, the deliverables, the
675
+ work breakdown, the project plan as a Gantt chart, the risks and
676
+ opportunities, the governance, and the change log of the issues) in a
677
+ handbook of its own beside the specification:
678
+
679
+ ### Sources
680
+
681
+ - [Specification](smp/pm/)
682
+ - [Schema](src/specbook-format-schema.d/)
683
+
684
+ ### Generation
685
+
686
+ ```bash
687
+ $ specbook export -v \
688
+ -c pm \
689
+ -b smp/pm \
690
+ -o smp/pm.html \
691
+ -o smp/pm.pdf
692
+ ```
693
+
449
694
  See Also
450
695
  --------
451
696
 
@@ -458,7 +703,7 @@ Support
458
703
  **SpecBook** is developed in the experience context of industrial Software
459
704
  Engineering at the [*msg group*](https://www.msg.group) and in the
460
705
  educational context of the *Software Engineering Academy (SEA)*. **SpecBook**
461
- development is supported by *msg Research* and *Software Engineering
706
+ development is supported by *msg Research* and the *Software Engineering
462
707
  Academy (SEA)*.
463
708
 
464
709
  License
@@ -1,7 +1,9 @@
1
1
  import { projectFile } from "./specbook-project.js";
2
+ import { version, standardConfig, metaConfig, pmConfig, cacheDir, fetchModes, parseFetchMode, type SearchHit, type FetchMode } from "./specbook-remote.js";
2
3
  import { renderDiagnostic, renderDiagnosticVerbose, type Diagnostic, type DiagnosticSeverity } from "./specbook-diagnostic.js";
3
4
  import { type LintResult } from "./specbook-cmd-lint.js";
4
5
  import { parseOutputSpec, formats, omitAspects, type ExportFormat } from "./specbook-cmd-export.js";
6
+ import { SpecBookDocument, renderNodes, queryFormats, parseQueryOutput, type SpecNode, type SpecQueryFunc, type SpecQueryAdapter, type QueryFormat } from "./specbook-cmd-query.js";
5
7
  import { previewAddr, previewPort } from "./specbook-cmd-preview.js";
6
8
  import { describeFormats, describeParts, parseDescribeFormat, parseDescribePart, compressLevels, parseCompressLevel, type DescribeFormat, type DescribePart, type CompressLevel } from "./specbook-cmd-describe.js";
7
9
  import { literal, renderVerbose, verbosities, verbosityOf, parseVerbosity, type Verbose, type VerboseLevel, type Verbosity } from "./specbook-verbose.js";
@@ -15,10 +17,10 @@ export { compressLevels, parseCompressLevel };
15
17
  export { type DescribeFormat, type DescribePart, type CompressLevel };
16
18
  export { renderDiagnostic, renderDiagnosticVerbose, type Diagnostic, type DiagnosticSeverity };
17
19
  export { type LintResult };
20
+ export { SpecBookDocument, renderNodes, queryFormats, parseQueryOutput, type SpecNode, type SpecQueryFunc, type SpecQueryAdapter, type QueryFormat };
21
+ export { version, standardConfig, metaConfig, pmConfig, cacheDir, fetchModes, parseFetchMode, type FetchMode, type SearchHit };
18
22
  export type { Spec, SpecArtifact, SpecObject, SpecDescription, SpecProperty } from "./specbook-format-spec.js";
19
23
  export type { Schema, SchemaObject, SchemaProperty } from "./specbook-format-schema.js";
20
- export declare const version: string;
21
- export declare const standardConfig: string;
22
24
  export type VerboseSink = (cmd: string, msg: string, level: VerboseLevel) => void;
23
25
  export interface SpecBookOptions {
24
26
  verbose?: VerboseSink;
@@ -27,16 +29,23 @@ export interface ProjectOptions {
27
29
  config?: string[];
28
30
  basedir?: string;
29
31
  cwd?: string;
32
+ fetch?: FetchMode;
30
33
  }
31
34
  export interface InitResult {
32
35
  files: string[];
33
36
  project?: string;
34
37
  }
38
+ export interface SearchRequest {
39
+ term?: string;
40
+ cwd?: string;
41
+ fetch?: FetchMode;
42
+ }
35
43
  export interface ExportRequest extends ProjectOptions {
36
44
  formats?: ExportFormat[];
37
45
  realtime?: boolean;
38
46
  omit?: string[];
39
47
  gitignore?: boolean;
48
+ schema?: boolean;
40
49
  rebase?: (string | undefined)[];
41
50
  }
42
51
  export interface WatchRequest extends ExportRequest {
@@ -48,14 +57,24 @@ export declare class SpecBook {
48
57
  constructor(options?: SpecBookOptions);
49
58
  private verboseOf;
50
59
  private project;
60
+ private remoteOptions;
51
61
  private configFiles;
52
62
  private requireConfig;
53
- init(options: ProjectOptions): Promise<InitResult>;
63
+ init(options: ProjectOptions & {
64
+ sample?: boolean;
65
+ }): Promise<InitResult>;
54
66
  lint(options: ProjectOptions & {
55
67
  gitignore?: boolean;
56
68
  }): Promise<LintResult>;
69
+ load(options: ProjectOptions & {
70
+ gitignore?: boolean;
71
+ schema?: boolean;
72
+ }): Promise<SpecBookDocument>;
73
+ search(options: SearchRequest): Promise<SearchHit[]>;
57
74
  private renderFormats;
58
75
  private rebaseOf;
76
+ private guardRebase;
77
+ private parseSource;
59
78
  export(options: ExportRequest): Promise<Buffer[]>;
60
79
  private observe;
61
80
  watch(options: WatchRequest): Promise<void>;
@@ -64,6 +83,7 @@ export declare class SpecBook {
64
83
  port?: number;
65
84
  omit?: string[];
66
85
  gitignore?: boolean;
86
+ schema?: boolean;
67
87
  }): Promise<void>;
68
88
  describe(options: ProjectOptions & {
69
89
  embed?: boolean;