@danielsimonjr/mathts-workbook 0.1.7 → 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.
package/README.md CHANGED
@@ -1,117 +1,222 @@
1
- # @danielsimonjr/mathts-workbook
2
-
3
- Scientific workbook runtime for MathTS with reactive YAML-based notebooks (`.mtsw` format).
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @danielsimonjr/mathts-workbook
9
- ```
10
-
11
- ## Usage
12
-
13
- ### CLI
14
-
15
- ```bash
16
- # Run a workbook
17
- mtsw run example.mtsw
18
-
19
- # Run specific cell
20
- mtsw run example.mtsw -c compute
21
-
22
- # Validate structure
23
- mtsw validate example.mtsw
24
-
25
- # Show dependency graph
26
- mtsw graph example.mtsw
27
-
28
- # Create from template (basic | tensor-physics | data-science)
29
- mtsw new my-workbook -t tensor-physics
30
- ```
31
-
32
- > Note: `mtsw watch` and `mtsw export` appear in the CLI help text but are not yet implemented.
33
-
34
- ### Programmatic API
35
-
36
- ```typescript
37
- import { parseWorkbook, createExecutor } from '@danielsimonjr/mathts-workbook';
38
-
39
- const content = `
40
- version: "1.0"
41
- metadata:
42
- title: "My Workbook"
43
- runtime:
44
- engine: mathts
45
- execution: reactive
46
- cells:
47
- - code: |
48
- const x = 42;
49
- export { x };
50
- id: compute
51
- `;
52
-
53
- const result = parseWorkbook(content);
54
- if (result.success && result.workbook) {
55
- const executor = createExecutor(result.workbook);
56
-
57
- executor.on((event) => {
58
- console.log(event.type, event.cellId);
59
- });
60
-
61
- await executor.runAll();
62
- }
63
- ```
64
-
65
- ## Workbook Format (.mtsw)
66
-
67
- ```yaml
68
- version: '1.0'
69
- metadata:
70
- title: 'Matrix Analysis'
71
- author: 'Your Name'
72
-
73
- runtime:
74
- engine: mathts
75
- execution: reactive # reactive | sequential | manual
76
-
77
- cells:
78
- - markdown: |
79
- # Introduction
80
- id: intro
81
-
82
- - code: |
83
- import { Matrix } from '@danielsimonjr/mathts-matrix';
84
- const A = Matrix.random(3, 3);
85
- export { A };
86
- id: create-matrix
87
-
88
- - code: |
89
- import { A } from '#create-matrix';
90
- const det = A.determinant();
91
- console.log('Determinant:', det);
92
- id: compute
93
- depends_on: [create-matrix]
94
- ```
95
-
96
- ## Cell Types
97
-
98
- | Type | Description |
99
- | --------------- | --------------------------------- |
100
- | `markdown` | Documentation with LaTeX math |
101
- | `code` | TypeScript/JavaScript execution |
102
- | `tensor` | Einstein notation for tensor math |
103
- | `equation` | LaTeX equations with labels |
104
- | `visualization` | Three.js/D3/Plotly rendering |
105
- | `data` | YAML/JSON/CSV data |
106
- | `test` | Assertions with timeout |
107
- | `export` | Publication output |
108
-
109
- ## Execution Modes
110
-
111
- - **reactive** - Auto-rerun when dependencies change
112
- - **sequential** - Top-to-bottom execution
113
- - **manual** - Explicit trigger only
114
-
115
- ## License
116
-
117
- MIT
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
+
23
+ # Describe the structured document model (cells, outputs, dependency graph).
24
+ mtsw describe example.mtsw --json
25
+
26
+ # Validate structure: ids, dependency references, and cycles.
27
+ mtsw validate example.mtsw [--json]
28
+
29
+ # Print the dependency graph (human only; use `describe --json` for structured data).
30
+ mtsw graph example.mtsw # text adjacency
31
+ mtsw graph example.mtsw -f mermaid # Mermaid `graph TD`
32
+
33
+ # Engine introspection (for tooling / GUIs).
34
+ mtsw capabilities --json # version, supported cell types, feature flags
35
+ mtsw templates --json # available `new` templates
36
+
37
+ # Scaffold a new workbook (<name>.mtsw) from a template.
38
+ mtsw new my-notebook # basic template; refuses to overwrite
39
+ mtsw new my-notebook -t basic --force # overwrite an existing file
40
+
41
+ # Strip cell outputs (for git): prints to stdout, or -w to rewrite in place.
42
+ mtsw strip example.mtsw
43
+ mtsw strip example.mtsw -w
44
+
45
+ # Run and persist outputs back into the file (opt-in; never writes without --write).
46
+ mtsw run example.mtsw --write
47
+
48
+ # Edit cells (atomic, in-place; --json returns the updated doc, --dry-run previews).
49
+ mtsw cell add example.mtsw --type code --id gauss --content "n*(n+1)/2" --depends-on n
50
+ mtsw cell add example.mtsw --type code --id big --content-file body.txt # or - for stdin
51
+ mtsw cell edit example.mtsw gauss --content "n*(n-1)/2"
52
+ mtsw cell move example.mtsw gauss --before n # --before/--after <id> | --at <index>
53
+ mtsw cell rename example.mtsw n count # rewrites dependents' depends_on
54
+ mtsw cell rm example.mtsw n # refuses if cells depend on it
55
+ mtsw cell rm example.mtsw n --force # removes + detaches dependents
56
+
57
+ # Introspection + metadata.
58
+ mtsw functions --json # functions/constants cells can call (autocomplete)
59
+ mtsw meta get example.mtsw # show workbook metadata
60
+ mtsw meta set example.mtsw --title "My Notebook" --author Ada --tags physics,demo
61
+
62
+ # Scaffold a workbook (templates: basic | empty | chart; -o writes to any path).
63
+ mtsw new notebook # notebook.mtsw in the CWD (basic template)
64
+ mtsw new draft --empty -o docs/draft.mtsw # blank workbook at an explicit path
65
+ mtsw new demo -t chart # a line-chart example workbook
66
+
67
+ # Build a whole .mtsw from a JSON/YAML document (the inverse of `describe --json`).
68
+ echo '{"cells":[{"id":"a","type":"code","content":"6 * 7"}]}' | mtsw import -o out.mtsw
69
+ mtsw import doc.json --json # validates (ids/deps/cycles); stdout if no -o
70
+
71
+ # Render to a self-contained HTML document (runs first, then renders).
72
+ mtsw export example.mtsw -o example.html # one offline file; stdout if no -o
73
+ mtsw export example.mtsw --no-run # render cached outputs without executing
74
+ mtsw export example.mtsw --json # envelope: { data: { path, bytes } }
75
+
76
+ # Persistent session for a GUI/tooling: JSON-RPC 2.0 over stdio (NDJSON).
77
+ mtsw serve
78
+ # -> {"jsonrpc":"2.0","id":1,"method":"open","params":{"path":"example.mtsw"}}
79
+ # <- {"jsonrpc":"2.0","id":1,"result":{...describe doc...}}
80
+ # -> {"jsonrpc":"2.0","id":2,"method":"run"} # streams cell/event notifications
81
+ # methods: open/describe/validate/graph/run/cell.*/meta.*/save/capabilities/functions/shutdown
82
+ ```
83
+
84
+ **`export` (self-contained HTML).** `mtsw export <file> --format html` renders a
85
+ notebook to a single offline `.html` with **no external requests**: markdown prose,
86
+ **equations typeset as MathML** (rendered natively by modern browsers — Chromium ≥109,
87
+ Firefox, Safari), code cells with their embedded outputs, ✓/✗ test badges, and (as of
88
+ the chart slice) inline SVG plots. All rendering is MathTS-native the generators
89
+ (`toMathML`/`toHTML`/`toCSS`, plus `markdownToHtml`) live in the `expression` package
90
+ alongside the node `.toTex()`/`.toHTML()` serializers, with **zero external
91
+ dependencies**. Equation cells contain MathTS expression syntax (e.g.
92
+ `c = 1 / sqrt(eps0 * mu0)`), not raw LaTeX; they are display-only and rendered via
93
+ `toMathML`. By default `export` runs the workbook first (use `--no-run` for cached
94
+ outputs); a whole-run failure such as a dependency cycle fails loudly rather than
95
+ emitting a misleading document.
96
+
97
+ **`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.
98
+
99
+ **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).
100
+
101
+ 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.
102
+
103
+ **Machine contract (`--json`).** Every `--json` command emits one envelope on stdout:
104
+ `{ schemaVersion: {major,minor}, command, ok, data, problems }`. The envelope is
105
+ emitted even on failure (and is cycle/BigInt-safe, so it never crashes on
106
+ pathological data); the exit code mirrors `ok` for shells, but tooling/GUIs
107
+ should read `ok` and treat a missing/unparseable envelope as the only transport
108
+ error. Compatibility rule: ignore unknown fields when `major` matches; refuse on
109
+ a `major` mismatch. `run --cell <id>` is stateless (it recomputes the target's
110
+ transitive deps each call; `run --cell --write` persists only the executed
111
+ cells). This is the contract a GUI binds to; a persistent `serve` mode (streaming
112
+ events, incremental re-execution) is planned.
113
+
114
+ **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.
115
+
116
+ ## Programmatic API
117
+
118
+ ```typescript
119
+ import { parseWorkbook, createExecutor, formatResult } from '@danielsimonjr/mathts-workbook';
120
+
121
+ const content = `
122
+ version: "1.0"
123
+ metadata:
124
+ title: "My Workbook"
125
+ runtime:
126
+ engine: mathts
127
+ execution: reactive
128
+ cells:
129
+ - code: "n * (n + 1) / 2"
130
+ id: gaussSum
131
+ depends_on: [n]
132
+ - code: "10"
133
+ id: n
134
+ - test: "gaussSum == 55"
135
+ id: checkGauss
136
+ depends_on: [gaussSum]
137
+ `;
138
+
139
+ const result = parseWorkbook(content);
140
+ if (result.success && result.workbook) {
141
+ const report = await createExecutor(result.workbook).runReport();
142
+ for (const cell of report.cells) {
143
+ console.log(cell.id, cell.status, formatResult(cell.output));
144
+ }
145
+ console.log('ok:', report.ok);
146
+ }
147
+ ```
148
+
149
+ `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.
150
+
151
+ ## Workbook format (.mtsw)
152
+
153
+ ```yaml
154
+ version: '1.0'
155
+ metadata:
156
+ title: 'Example'
157
+ author: 'Your Name'
158
+
159
+ runtime:
160
+ engine: mathts
161
+ execution: reactive # reactive | sequential | manual
162
+
163
+ cells:
164
+ - markdown: |
165
+ # Introduction
166
+ id: intro
167
+
168
+ - code: '{ pi: 3.14159, e: 2.71828 }'
169
+ id: constants
170
+
171
+ - test: 'constants.pi > 3.14'
172
+ id: checkPi
173
+ depends_on: [constants]
174
+ ```
175
+
176
+ Each cell is a YAML mapping with **exactly one** type key (`code`, `markdown`, `data`, `test`, …) whose value is the cell content, plus:
177
+
178
+ - **`id`** (required) — must be a valid identifier (`[A-Za-z_][A-Za-z0-9_]*`); ids are how cells are referenced.
179
+ - **`depends_on`** (optional) — a list of cell ids this cell depends on.
180
+
181
+ ### Dependencies & scope
182
+
183
+ 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:
184
+
185
+ ```yaml
186
+ cells:
187
+ - code: '{ n: 2, m: 3 }'
188
+ id: pair
189
+ - code: 'pair.n + pair.m' # -> 5
190
+ id: total
191
+ depends_on: [pair]
192
+ ```
193
+
194
+ 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.
195
+
196
+ ### Test cells
197
+
198
+ 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.
199
+
200
+ ## Cell types (v1)
201
+
202
+ | Type | Status | Description |
203
+ | ---------- | ------ | ------------------------------------------------------------ |
204
+ | `markdown` | ✅ | Documentation (passed through verbatim) |
205
+ | `code` | ✅ | MathTS expression script; last value is the result |
206
+ | `data` | ✅ | Structured YAML, parsed (hardened) into a value |
207
+ | `test` | ✅ | Boolean assertion (`true` = pass) |
208
+ | `tensor` / `equation` / `visualization` / `export` | ⏳ | Reserved; not executed in v1 (reported as unsupported) |
209
+
210
+ ## Execution modes
211
+
212
+ - **reactive** — emits stale events for dependents when a cell re-runs
213
+ - **sequential** — top-to-bottom (dependency) order
214
+ - **manual** — explicit trigger only
215
+
216
+ ## Security
217
+
218
+ 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.
219
+
220
+ ## License
221
+
222
+ MIT