@danielsimonjr/mathts-workbook 0.1.8 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +247 -117
- package/dist/chunk-3KTM2DZC.js +720 -0
- package/dist/chunk-TMVFG3I3.js +581 -0
- package/dist/cli.d.ts +39 -0
- package/dist/cli.js +1758 -79
- package/dist/index.d.ts +304 -9
- package/dist/index.js +35 -1
- package/dist/run-worker.d.ts +2 -0
- package/dist/run-worker.js +39 -0
- package/package.json +64 -62
- package/dist/chunk-L7UWFWMV.js +0 -269
package/README.md
CHANGED
|
@@ -1,117 +1,247 @@
|
|
|
1
|
-
# @danielsimonjr/mathts-workbook
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
# Run a workbook
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
#
|
|
20
|
-
mtsw run example.mtsw -
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
1
|
+
# @danielsimonjr/mathts-workbook
|
|
2
|
+
|
|
3
|
+
Headless runtime for MathTS scientific notebooks in the YAML-based `.mtsw` format. Load a workbook, run its cells in dependency order, and verify results — all from the terminal or programmatically.
|
|
4
|
+
|
|
5
|
+
> **Scope:** This is the headless v1 — a CLI and runtime. Code cells evaluate **MathTS expressions** (via the sandboxed expression engine), not arbitrary TypeScript. A desktop GUI is a separate, later project that builds on this runtime.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @danielsimonjr/mathts-workbook
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## CLI
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Run a workbook: executes cells in dependency order and prints per-cell results.
|
|
17
|
+
# Exits non-zero if any cell errors or any test assertion fails.
|
|
18
|
+
mtsw run example.mtsw
|
|
19
|
+
mtsw run example.mtsw -v # also print the execution event stream
|
|
20
|
+
mtsw run example.mtsw --json # machine-readable envelope on stdout
|
|
21
|
+
mtsw run example.mtsw -c gauss # run one cell + its transitive deps (stateless)
|
|
22
|
+
mtsw run example.mtsw --timeout 5000 # run in a worker; killed (exit 1) if it exceeds 5s
|
|
23
|
+
|
|
24
|
+
# Describe the structured document model (cells, outputs, dependency graph).
|
|
25
|
+
mtsw describe example.mtsw --json
|
|
26
|
+
|
|
27
|
+
# Validate structure: ids, dependency references, and cycles.
|
|
28
|
+
mtsw validate example.mtsw [--json]
|
|
29
|
+
|
|
30
|
+
# Print the dependency graph (human only; use `describe --json` for structured data).
|
|
31
|
+
mtsw graph example.mtsw # text adjacency
|
|
32
|
+
mtsw graph example.mtsw -f mermaid # Mermaid `graph TD`
|
|
33
|
+
|
|
34
|
+
# Engine introspection (for tooling / GUIs).
|
|
35
|
+
mtsw capabilities --json # version, supported cell types, feature flags
|
|
36
|
+
mtsw templates --json # available `new` templates
|
|
37
|
+
|
|
38
|
+
# Scaffold a new workbook (<name>.mtsw) from a template.
|
|
39
|
+
mtsw new my-notebook # basic template; refuses to overwrite
|
|
40
|
+
mtsw new my-notebook -t basic --force # overwrite an existing file
|
|
41
|
+
|
|
42
|
+
# Strip cell outputs (for git): prints to stdout, or -w to rewrite in place.
|
|
43
|
+
mtsw strip example.mtsw
|
|
44
|
+
mtsw strip example.mtsw -w
|
|
45
|
+
|
|
46
|
+
# Run and persist outputs back into the file (opt-in; never writes without --write).
|
|
47
|
+
mtsw run example.mtsw --write
|
|
48
|
+
|
|
49
|
+
# Edit cells (atomic, in-place; --json returns the updated doc, --dry-run previews).
|
|
50
|
+
mtsw cell add example.mtsw --type code --id gauss --content "n*(n+1)/2" --depends-on n
|
|
51
|
+
mtsw cell add example.mtsw --type code --id big --content-file body.txt # or - for stdin
|
|
52
|
+
mtsw cell edit example.mtsw gauss --content "n*(n-1)/2"
|
|
53
|
+
mtsw cell move example.mtsw gauss --before n # --before/--after <id> | --at <index>
|
|
54
|
+
mtsw cell rename example.mtsw n count # rewrites dependents' depends_on
|
|
55
|
+
mtsw cell rm example.mtsw n # refuses if cells depend on it
|
|
56
|
+
mtsw cell rm example.mtsw n --force # removes + detaches dependents
|
|
57
|
+
|
|
58
|
+
# Introspection + metadata.
|
|
59
|
+
mtsw functions --json # functions/constants cells can call (autocomplete)
|
|
60
|
+
mtsw meta get example.mtsw # show workbook metadata
|
|
61
|
+
mtsw meta set example.mtsw --title "My Notebook" --author Ada --tags physics,demo
|
|
62
|
+
|
|
63
|
+
# Scaffold a workbook (templates: basic | empty | chart; -o writes to any path).
|
|
64
|
+
mtsw new notebook # notebook.mtsw in the CWD (basic template)
|
|
65
|
+
mtsw new draft --empty -o docs/draft.mtsw # blank workbook at an explicit path
|
|
66
|
+
mtsw new demo -t chart # a line-chart example workbook
|
|
67
|
+
|
|
68
|
+
# Build a whole .mtsw from a JSON/YAML document (the inverse of `describe --json`).
|
|
69
|
+
echo '{"cells":[{"id":"a","type":"code","content":"6 * 7"}]}' | mtsw import -o out.mtsw
|
|
70
|
+
mtsw import doc.json --json # validates (ids/deps/cycles); stdout if no -o
|
|
71
|
+
|
|
72
|
+
# Render to a self-contained HTML document (runs first, then renders).
|
|
73
|
+
mtsw export example.mtsw -o example.html # one offline file; stdout if no -o
|
|
74
|
+
mtsw export example.mtsw --no-run # render cached outputs without executing
|
|
75
|
+
mtsw export example.mtsw --json # envelope: { data: { path, bytes } }
|
|
76
|
+
|
|
77
|
+
# Other export formats: --format tex|pdf|json|ipynb (html is the default).
|
|
78
|
+
mtsw export example.mtsw --format ipynb -o example.ipynb # Jupyter notebook (nbformat v4)
|
|
79
|
+
|
|
80
|
+
# Persistent session for a GUI/tooling: JSON-RPC 2.0 over stdio (NDJSON).
|
|
81
|
+
mtsw serve
|
|
82
|
+
# -> {"jsonrpc":"2.0","id":1,"method":"open","params":{"path":"example.mtsw"}}
|
|
83
|
+
# <- {"jsonrpc":"2.0","id":1,"result":{...describe doc...}}
|
|
84
|
+
# -> {"jsonrpc":"2.0","id":2,"method":"run"} # streams cell/event notifications
|
|
85
|
+
# methods: open/describe/validate/graph/run/cell.*/meta.*/save/capabilities/functions/shutdown
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**`export` (self-contained HTML).** `mtsw export <file> --format html` renders a
|
|
89
|
+
notebook to a single offline `.html` with **no external requests**: markdown prose,
|
|
90
|
+
**equations typeset as MathML** (rendered natively by modern browsers — Chromium ≥109,
|
|
91
|
+
Firefox, Safari), code cells with their embedded outputs, ✓/✗ test badges, and (as of
|
|
92
|
+
the chart slice) inline SVG plots. All rendering is MathTS-native — the generators
|
|
93
|
+
(`toMathML`/`toHTML`/`toCSS`, plus `markdownToHtml`) live in the `expression` package
|
|
94
|
+
alongside the node `.toTex()`/`.toHTML()` serializers, with **zero external
|
|
95
|
+
dependencies**. Equation cells contain MathTS expression syntax (e.g.
|
|
96
|
+
`c = 1 / sqrt(eps0 * mu0)`), not raw LaTeX; they are display-only and rendered via
|
|
97
|
+
`toMathML`. By default `export` runs the workbook first (use `--no-run` for cached
|
|
98
|
+
outputs); a whole-run failure such as a dependency cycle fails loudly rather than
|
|
99
|
+
emitting a misleading document.
|
|
100
|
+
|
|
101
|
+
**`export --format ipynb` (Jupyter notebook).** Renders the same run report to a
|
|
102
|
+
structurally conformant **nbformat v4** JSON document: `markdown` cells map to
|
|
103
|
+
notebook markdown cells; every other cell type (`code`, `equation`, `test`, `data`,
|
|
104
|
+
`visualization`) maps to a notebook code cell, with a computed result becoming an
|
|
105
|
+
`execute_result` output (`data['text/plain']`), an error becoming an `error` output,
|
|
106
|
+
and a chart becoming a `display_data` output (inline SVG). Shares the same
|
|
107
|
+
run-then-render pipeline as `--format html`/`tex` (including `--no-run`, `--json`,
|
|
108
|
+
`-o`).
|
|
109
|
+
|
|
110
|
+
**`run --timeout <ms>` (kill-able worker-thread run).** By default, cell execution runs
|
|
111
|
+
in-process with no time budget — a runaway cell (e.g. an unbounded computation) hangs
|
|
112
|
+
the process. `--timeout` runs the whole workbook in a `worker_threads` Worker and
|
|
113
|
+
forcibly terminates it if it exceeds the budget, exiting 1 with a clear
|
|
114
|
+
`workbook execution exceeded <ms>ms and was terminated` message; termination kills the
|
|
115
|
+
worker outright, so it interrupts even a synchronous, CPU-bound runaway. It always runs
|
|
116
|
+
the entire workbook to completion-or-termination, so it's incompatible with `-c`/`-v`.
|
|
117
|
+
The same primitive is available programmatically as `runWorkbookWithTimeout(source, {
|
|
118
|
+
timeoutMs })` (throws `WorkbookTimeoutError` on timeout); cell outputs come back
|
|
119
|
+
pre-formatted to strings (via `formatResult`), since engine class instances (Complex,
|
|
120
|
+
matrices, …) don't survive the worker's `postMessage`.
|
|
121
|
+
|
|
122
|
+
**`serve` (persistent session).** One long-lived process holds the workbook in memory with a per-cell result cache and a **stale set**: a `cell.*` edit marks that cell and its transitive dependents stale, and a `run` re-executes **only** the stale cells (reusing cached outputs for the rest) — the incremental latency win a GUI needs. Requests are processed strictly in order; `run` streams `cell/event` notifications (flushed before that run's response in v1, not mid-run). Edits stay in memory until `save`. Single-document per process; concurrent writers are last-write-wins.
|
|
123
|
+
|
|
124
|
+
**Editing notes.** Cell edits are validity-preserving: an op that would create a duplicate/invalid id, a missing dependency, or a **dependency cycle** is rejected and the file is left byte-for-byte unchanged. Editing a cell clears its (now-stale) persisted output; `--at N` is the cell's final 0-based index; `--force` detaches dependents (clearing their outputs) but does not rewrite cell _content_, so a dependent that still references the removed id by name will error at run. Concurrent editors are last-write-wins (an optimistic-lock guard arrives with the `serve` session).
|
|
125
|
+
|
|
126
|
+
Diagnostics and errors are written to stderr; results (including `--json`) go to stdout, so the exit code can be used in scripts independently of the output.
|
|
127
|
+
|
|
128
|
+
**Machine contract (`--json`).** Every `--json` command emits one envelope on stdout:
|
|
129
|
+
`{ schemaVersion: {major,minor}, command, ok, data, problems }`. The envelope is
|
|
130
|
+
emitted even on failure (and is cycle/BigInt-safe, so it never crashes on
|
|
131
|
+
pathological data); the exit code mirrors `ok` for shells, but tooling/GUIs
|
|
132
|
+
should read `ok` and treat a missing/unparseable envelope as the only transport
|
|
133
|
+
error. Compatibility rule: ignore unknown fields when `major` matches; refuse on
|
|
134
|
+
a `major` mismatch. `run --cell <id>` is stateless (it recomputes the target's
|
|
135
|
+
transitive deps each call; `run --cell --write` persists only the executed
|
|
136
|
+
cells). This is the contract a GUI binds to; a persistent `serve` mode (streaming
|
|
137
|
+
events, incremental re-execution) is planned.
|
|
138
|
+
|
|
139
|
+
**Saving / round-trip.** `serializeWorkbook` (and the write commands above) round-trips a workbook through the parser: structure is preserved exactly, and persisted `output` values round-trip best-effort (plain numbers/strings/arrays/objects exactly; exotic types to their plain shape). All writes are **atomic** (temp file + rename). Note that any write path is parse→serialize and therefore **drops YAML comments and re-orders keys** — a CST-preserving in-place rewrite is a future enhancement.
|
|
140
|
+
|
|
141
|
+
## Programmatic API
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { parseWorkbook, createExecutor, formatResult } from '@danielsimonjr/mathts-workbook';
|
|
145
|
+
|
|
146
|
+
const content = `
|
|
147
|
+
version: "1.0"
|
|
148
|
+
metadata:
|
|
149
|
+
title: "My Workbook"
|
|
150
|
+
runtime:
|
|
151
|
+
engine: mathts
|
|
152
|
+
execution: reactive
|
|
153
|
+
cells:
|
|
154
|
+
- code: "n * (n + 1) / 2"
|
|
155
|
+
id: gaussSum
|
|
156
|
+
depends_on: [n]
|
|
157
|
+
- code: "10"
|
|
158
|
+
id: n
|
|
159
|
+
- test: "gaussSum == 55"
|
|
160
|
+
id: checkGauss
|
|
161
|
+
depends_on: [gaussSum]
|
|
162
|
+
`;
|
|
163
|
+
|
|
164
|
+
const result = parseWorkbook(content);
|
|
165
|
+
if (result.success && result.workbook) {
|
|
166
|
+
const report = await createExecutor(result.workbook).runReport();
|
|
167
|
+
for (const cell of report.cells) {
|
|
168
|
+
console.log(cell.id, cell.status, formatResult(cell.output));
|
|
169
|
+
}
|
|
170
|
+
console.log('ok:', report.ok);
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`runReport()` is continue-on-error and returns a structured `RunResult` (it never throws on a cell failure, and refuses a workbook with a dependency cycle). The older `runAll()` remains available as an event-stream API that throws on the first cell error.
|
|
175
|
+
|
|
176
|
+
## Workbook format (.mtsw)
|
|
177
|
+
|
|
178
|
+
```yaml
|
|
179
|
+
version: '1.0'
|
|
180
|
+
metadata:
|
|
181
|
+
title: 'Example'
|
|
182
|
+
author: 'Your Name'
|
|
183
|
+
|
|
184
|
+
runtime:
|
|
185
|
+
engine: mathts
|
|
186
|
+
execution: reactive # reactive | sequential | manual
|
|
187
|
+
|
|
188
|
+
cells:
|
|
189
|
+
- markdown: |
|
|
190
|
+
# Introduction
|
|
191
|
+
id: intro
|
|
192
|
+
|
|
193
|
+
- code: '{ pi: 3.14159, e: 2.71828 }'
|
|
194
|
+
id: constants
|
|
195
|
+
|
|
196
|
+
- test: 'constants.pi > 3.14'
|
|
197
|
+
id: checkPi
|
|
198
|
+
depends_on: [constants]
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Each cell is a YAML mapping with **exactly one** type key (`code`, `markdown`, `data`, `test`, …) whose value is the cell content, plus:
|
|
202
|
+
|
|
203
|
+
- **`id`** (required) — must be a valid identifier (`[A-Za-z_][A-Za-z0-9_]*`); ids are how cells are referenced.
|
|
204
|
+
- **`depends_on`** (optional) — a list of cell ids this cell depends on.
|
|
205
|
+
|
|
206
|
+
### Dependencies & scope
|
|
207
|
+
|
|
208
|
+
A dependency's result is injected into a cell's evaluation scope as a variable named by the dependency's id. To expose several values, return an object literal and read it with property access:
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
cells:
|
|
212
|
+
- code: '{ n: 2, m: 3 }'
|
|
213
|
+
id: pair
|
|
214
|
+
- code: 'pair.n + pair.m' # -> 5
|
|
215
|
+
id: total
|
|
216
|
+
depends_on: [pair]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Scope is **direct-only (non-transitive)**: a cell sees only the cells in its own `depends_on`, not their dependencies. To use a transitive value, list it explicitly.
|
|
220
|
+
|
|
221
|
+
### Test cells
|
|
222
|
+
|
|
223
|
+
A `test` cell's expression must evaluate to a **boolean**: `true` passes, `false` fails, and a non-boolean result is reported as an error (use an explicit comparison). A failing test makes `mtsw run` exit non-zero — workbooks can verify themselves.
|
|
224
|
+
|
|
225
|
+
## Cell types (v1)
|
|
226
|
+
|
|
227
|
+
| Type | Status | Description |
|
|
228
|
+
| -------------------------------------------------- | ------ | ------------------------------------------------------ |
|
|
229
|
+
| `markdown` | ✅ | Documentation (passed through verbatim) |
|
|
230
|
+
| `code` | ✅ | MathTS expression script; last value is the result |
|
|
231
|
+
| `data` | ✅ | Structured YAML, parsed (hardened) into a value |
|
|
232
|
+
| `test` | ✅ | Boolean assertion (`true` = pass) |
|
|
233
|
+
| `tensor` / `equation` / `visualization` / `export` | ⏳ | Reserved; not executed in v1 (reported as unsupported) |
|
|
234
|
+
|
|
235
|
+
## Execution modes
|
|
236
|
+
|
|
237
|
+
- **reactive** — emits stale events for dependents when a cell re-runs
|
|
238
|
+
- **sequential** — top-to-bottom (dependency) order
|
|
239
|
+
- **manual** — explicit trigger only
|
|
240
|
+
|
|
241
|
+
## Security
|
|
242
|
+
|
|
243
|
+
Code and test cells execute only through the MathTS sandboxed expression engine — no `eval`, `Function`, or `vm`. YAML (both the document and `data`-cell payloads) is parsed with a hardened core-schema configuration and a prototype-pollution guard.
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
MIT
|