@danielsimonjr/mathts-workbook 0.1.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.
package/README.md ADDED
@@ -0,0 +1,121 @@
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
+ # Watch for changes
23
+ mtsw watch example.mtsw
24
+
25
+ # Validate structure
26
+ mtsw validate example.mtsw
27
+
28
+ # Show dependency graph
29
+ mtsw graph example.mtsw
30
+
31
+ # Create from template
32
+ mtsw new my-workbook -t tensor-physics
33
+
34
+ # Export
35
+ mtsw export example.mtsw -f html
36
+ ```
37
+
38
+ ### Programmatic API
39
+
40
+ ```typescript
41
+ import { parseWorkbook, createExecutor } from '@danielsimonjr/mathts-workbook';
42
+
43
+ const content = `
44
+ version: "1.0"
45
+ metadata:
46
+ title: "My Workbook"
47
+ runtime:
48
+ engine: mathts
49
+ execution: reactive
50
+ cells:
51
+ - code: |
52
+ const x = 42;
53
+ export { x };
54
+ id: compute
55
+ `;
56
+
57
+ const result = parseWorkbook(content);
58
+ if (result.success && result.workbook) {
59
+ const executor = createExecutor(result.workbook);
60
+
61
+ executor.on((event) => {
62
+ console.log(event.type, event.cellId);
63
+ });
64
+
65
+ await executor.runAll();
66
+ }
67
+ ```
68
+
69
+ ## Workbook Format (.mtsw)
70
+
71
+ ```yaml
72
+ version: "1.0"
73
+ metadata:
74
+ title: "Matrix Analysis"
75
+ author: "Your Name"
76
+
77
+ runtime:
78
+ engine: mathts
79
+ execution: reactive # reactive | sequential | manual
80
+
81
+ cells:
82
+ - markdown: |
83
+ # Introduction
84
+ id: intro
85
+
86
+ - code: |
87
+ import { Matrix } from '@danielsimonjr/mathts-matrix';
88
+ const A = Matrix.random(3, 3);
89
+ export { A };
90
+ id: create-matrix
91
+
92
+ - code: |
93
+ import { A } from '#create-matrix';
94
+ const det = A.determinant();
95
+ console.log('Determinant:', det);
96
+ id: compute
97
+ depends_on: [create-matrix]
98
+ ```
99
+
100
+ ## Cell Types
101
+
102
+ | Type | Description |
103
+ |------|-------------|
104
+ | `markdown` | Documentation with LaTeX math |
105
+ | `code` | TypeScript/JavaScript execution |
106
+ | `tensor` | Einstein notation for tensor math |
107
+ | `equation` | LaTeX equations with labels |
108
+ | `visualization` | Three.js/D3/Plotly rendering |
109
+ | `data` | YAML/JSON/CSV data |
110
+ | `test` | Assertions with timeout |
111
+ | `export` | Publication output |
112
+
113
+ ## Execution Modes
114
+
115
+ - **reactive** - Auto-rerun when dependencies change
116
+ - **sequential** - Top-to-bottom execution
117
+ - **manual** - Explicit trigger only
118
+
119
+ ## License
120
+
121
+ MIT
@@ -0,0 +1,273 @@
1
+ // src/parser.ts
2
+ function parseWorkbook(content) {
3
+ try {
4
+ const errors = [];
5
+ const warnings = [];
6
+ if (!content.trim()) {
7
+ return {
8
+ success: false,
9
+ errors: ["Empty workbook content"]
10
+ };
11
+ }
12
+ const workbook = {
13
+ version: "1.0",
14
+ metadata: {
15
+ title: "Untitled Workbook"
16
+ },
17
+ runtime: {
18
+ engine: "mathts",
19
+ execution: "reactive"
20
+ },
21
+ cells: []
22
+ };
23
+ if (warnings.length > 0 || errors.length > 0) {
24
+ return {
25
+ success: errors.length === 0,
26
+ workbook: errors.length === 0 ? workbook : void 0,
27
+ errors: errors.length > 0 ? errors : void 0,
28
+ warnings: warnings.length > 0 ? warnings : void 0
29
+ };
30
+ }
31
+ return {
32
+ success: true,
33
+ workbook
34
+ };
35
+ } catch (error) {
36
+ return {
37
+ success: false,
38
+ errors: [`Parse error: ${error instanceof Error ? error.message : String(error)}`]
39
+ };
40
+ }
41
+ }
42
+ function serializeWorkbook(_workbook) {
43
+ throw new Error("serializeWorkbook not yet implemented");
44
+ }
45
+ function stripOutputs(workbook) {
46
+ return {
47
+ ...workbook,
48
+ cells: workbook.cells.map((cell) => ({
49
+ ...cell,
50
+ output: void 0,
51
+ error: void 0
52
+ }))
53
+ };
54
+ }
55
+
56
+ // src/graph.ts
57
+ function buildDependencyGraph(cells) {
58
+ const nodes = /* @__PURE__ */ new Map();
59
+ for (const cell of cells) {
60
+ nodes.set(cell.id, {
61
+ id: cell.id,
62
+ dependencies: cell.dependsOn ?? [],
63
+ dependents: []
64
+ });
65
+ }
66
+ for (const cell of cells) {
67
+ for (const depId of cell.dependsOn ?? []) {
68
+ const depNode = nodes.get(depId);
69
+ if (depNode) {
70
+ depNode.dependents.push(cell.id);
71
+ }
72
+ }
73
+ }
74
+ const executionOrder = topologicalSort(nodes);
75
+ return { nodes, executionOrder };
76
+ }
77
+ function topologicalSort(nodes) {
78
+ const visited = /* @__PURE__ */ new Set();
79
+ const result = [];
80
+ function visit(id) {
81
+ if (visited.has(id)) return;
82
+ visited.add(id);
83
+ const node = nodes.get(id);
84
+ if (node) {
85
+ for (const depId of node.dependencies) {
86
+ visit(depId);
87
+ }
88
+ }
89
+ result.push(id);
90
+ }
91
+ for (const id of nodes.keys()) {
92
+ visit(id);
93
+ }
94
+ return result;
95
+ }
96
+ function getDependents(graph, cellId) {
97
+ const result = [];
98
+ const visited = /* @__PURE__ */ new Set();
99
+ function collect(id) {
100
+ const node = graph.nodes.get(id);
101
+ if (!node) return;
102
+ for (const depId of node.dependents) {
103
+ if (!visited.has(depId)) {
104
+ visited.add(depId);
105
+ result.push(depId);
106
+ collect(depId);
107
+ }
108
+ }
109
+ }
110
+ collect(cellId);
111
+ return result;
112
+ }
113
+
114
+ // src/executor.ts
115
+ var WorkbookExecutor = class {
116
+ workbook;
117
+ graph;
118
+ outputs = /* @__PURE__ */ new Map();
119
+ handlers = [];
120
+ constructor(workbook) {
121
+ this.workbook = workbook;
122
+ this.graph = buildDependencyGraph(workbook.cells);
123
+ }
124
+ /**
125
+ * Subscribe to execution events
126
+ */
127
+ on(handler) {
128
+ this.handlers.push(handler);
129
+ return () => {
130
+ const index = this.handlers.indexOf(handler);
131
+ if (index >= 0) {
132
+ this.handlers.splice(index, 1);
133
+ }
134
+ };
135
+ }
136
+ /**
137
+ * Emit an event to all handlers
138
+ */
139
+ emit(event) {
140
+ for (const handler of this.handlers) {
141
+ handler(event);
142
+ }
143
+ }
144
+ /**
145
+ * Run all cells in order
146
+ */
147
+ async runAll() {
148
+ for (const cellId of this.graph.executionOrder) {
149
+ await this.runCell(cellId);
150
+ }
151
+ this.emit({
152
+ type: "workbook:complete",
153
+ timestamp: Date.now()
154
+ });
155
+ }
156
+ /**
157
+ * Run a specific cell
158
+ */
159
+ async runCell(cellId) {
160
+ const cell = this.workbook.cells.find((c) => c.id === cellId);
161
+ if (!cell) {
162
+ throw new Error(`Cell not found: ${cellId}`);
163
+ }
164
+ this.emit({
165
+ type: "cell:start",
166
+ cellId,
167
+ timestamp: Date.now()
168
+ });
169
+ try {
170
+ const output = await this.executeCell(cell);
171
+ this.outputs.set(cellId, output);
172
+ this.emit({
173
+ type: "cell:success",
174
+ cellId,
175
+ output,
176
+ timestamp: Date.now()
177
+ });
178
+ if (this.workbook.runtime.execution === "reactive") {
179
+ const dependents = getDependents(this.graph, cellId);
180
+ for (const depId of dependents) {
181
+ this.emit({
182
+ type: "cell:stale",
183
+ cellId: depId,
184
+ timestamp: Date.now()
185
+ });
186
+ }
187
+ }
188
+ return output;
189
+ } catch (error) {
190
+ const errorMessage = error instanceof Error ? error.message : String(error);
191
+ this.emit({
192
+ type: "cell:error",
193
+ cellId,
194
+ error: errorMessage,
195
+ timestamp: Date.now()
196
+ });
197
+ throw error;
198
+ }
199
+ }
200
+ /**
201
+ * Execute a single cell
202
+ */
203
+ async executeCell(cell) {
204
+ switch (cell.type) {
205
+ case "code":
206
+ return this.executeCode(cell);
207
+ case "markdown":
208
+ return cell.content;
209
+ // Markdown is pass-through
210
+ case "data":
211
+ return this.executeData(cell);
212
+ default:
213
+ throw new Error(`Unsupported cell type: ${cell.type}`);
214
+ }
215
+ }
216
+ /**
217
+ * Execute a code cell by evaluating its content with scope from dependency outputs.
218
+ *
219
+ * Uses the Function constructor to evaluate expressions. Cell dependencies
220
+ * are injected as named variables in the evaluation scope, allowing cells
221
+ * to reference outputs of earlier cells by their id.
222
+ */
223
+ async executeCode(cell) {
224
+ const scope = {};
225
+ if (cell.dependsOn) {
226
+ for (const depId of cell.dependsOn) {
227
+ const output = this.outputs.get(depId);
228
+ if (output !== void 0) {
229
+ scope[depId] = output;
230
+ }
231
+ }
232
+ }
233
+ const scopeKeys = Object.keys(scope);
234
+ const scopeValues = scopeKeys.map((k) => scope[k]);
235
+ try {
236
+ const fn = new Function(...scopeKeys, `return (${cell.content});`);
237
+ return fn(...scopeValues);
238
+ } catch {
239
+ const fn = new Function(...scopeKeys, cell.content);
240
+ return fn(...scopeValues);
241
+ }
242
+ }
243
+ /**
244
+ * Execute a data cell
245
+ */
246
+ async executeData(cell) {
247
+ return cell.content;
248
+ }
249
+ /**
250
+ * Get output from a previous cell
251
+ */
252
+ getOutput(cellId) {
253
+ return this.outputs.get(cellId);
254
+ }
255
+ };
256
+ function createExecutor(workbook) {
257
+ return new WorkbookExecutor(workbook);
258
+ }
259
+
260
+ // src/index.ts
261
+ var VERSION = "0.1.0";
262
+
263
+ export {
264
+ parseWorkbook,
265
+ serializeWorkbook,
266
+ stripOutputs,
267
+ buildDependencyGraph,
268
+ topologicalSort,
269
+ getDependents,
270
+ WorkbookExecutor,
271
+ createExecutor,
272
+ VERSION
273
+ };
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createExecutor,
4
+ parseWorkbook
5
+ } from "./chunk-64JBL36K.js";
6
+
7
+ // src/cli.ts
8
+ var HELP = `
9
+ mtsw - MathTS Workbook CLI
10
+
11
+ Usage:
12
+ mtsw run <file> Execute a workbook
13
+ mtsw run <file> -c <cell> Run specific cell
14
+ mtsw run <file> -v Verbose output
15
+ mtsw watch <file> Watch and re-run on changes
16
+ mtsw validate <file> Validate workbook structure
17
+ mtsw graph <file> Show dependency graph
18
+ mtsw graph <file> -f mermaid Export as Mermaid diagram
19
+ mtsw strip <file> Strip outputs (for git)
20
+ mtsw new <name> Create new workbook
21
+ mtsw new <name> -t <template> Use template (basic|tensor-physics|data-science)
22
+ mtsw export <file> -f <fmt> Export to format (html|pdf|ipynb|latex)
23
+
24
+ Options:
25
+ -h, --help Show this help
26
+ -v, --verbose Verbose output
27
+ -V, --version Show version
28
+ `;
29
+ async function main() {
30
+ const args = process.argv.slice(2);
31
+ if (args.length === 0 || args.includes("-h") || args.includes("--help")) {
32
+ console.log(HELP);
33
+ process.exit(0);
34
+ }
35
+ if (args.includes("-V") || args.includes("--version")) {
36
+ console.log("mtsw version 0.1.0");
37
+ process.exit(0);
38
+ }
39
+ const command = args[0];
40
+ switch (command) {
41
+ case "run":
42
+ await runCommand(args.slice(1));
43
+ break;
44
+ case "validate":
45
+ await validateCommand(args.slice(1));
46
+ break;
47
+ case "graph":
48
+ await graphCommand(args.slice(1));
49
+ break;
50
+ case "new":
51
+ await newCommand(args.slice(1));
52
+ break;
53
+ default:
54
+ console.error(`Unknown command: ${command}`);
55
+ console.log(HELP);
56
+ process.exit(1);
57
+ }
58
+ }
59
+ async function runCommand(args) {
60
+ const file = args[0];
61
+ if (!file) {
62
+ console.error("Usage: mtsw run <file>");
63
+ process.exit(1);
64
+ }
65
+ console.log(`Running workbook: ${file}`);
66
+ const content = "";
67
+ const result = parseWorkbook(content);
68
+ if (!result.success) {
69
+ console.error("Parse errors:", result.errors);
70
+ process.exit(1);
71
+ }
72
+ if (result.workbook) {
73
+ const executor = createExecutor(result.workbook);
74
+ executor.on((event) => {
75
+ console.log(`[${event.type}] ${event.cellId ?? ""}`);
76
+ });
77
+ await executor.runAll();
78
+ }
79
+ }
80
+ async function validateCommand(args) {
81
+ const file = args[0];
82
+ if (!file) {
83
+ console.error("Usage: mtsw validate <file>");
84
+ process.exit(1);
85
+ }
86
+ console.log(`Validating: ${file}`);
87
+ }
88
+ async function graphCommand(args) {
89
+ const file = args[0];
90
+ if (!file) {
91
+ console.error("Usage: mtsw graph <file>");
92
+ process.exit(1);
93
+ }
94
+ console.log(`Dependency graph for: ${file}`);
95
+ }
96
+ async function newCommand(args) {
97
+ const name = args[0];
98
+ if (!name) {
99
+ console.error("Usage: mtsw new <name>");
100
+ process.exit(1);
101
+ }
102
+ console.log(`Creating new workbook: ${name}.mtsw`);
103
+ }
104
+ main().catch((error) => {
105
+ console.error("Error:", error);
106
+ process.exit(1);
107
+ });
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Workbook type definitions
3
+ */
4
+ /**
5
+ * Supported cell types
6
+ */
7
+ type CellType = 'markdown' | 'code' | 'tensor' | 'equation' | 'visualization' | 'data' | 'test' | 'export';
8
+ /**
9
+ * Execution modes
10
+ */
11
+ type ExecutionMode = 'reactive' | 'sequential' | 'manual';
12
+ /**
13
+ * Workbook metadata
14
+ */
15
+ interface WorkbookMetadata {
16
+ title?: string;
17
+ author?: string;
18
+ description?: string;
19
+ tags?: string[];
20
+ created?: string;
21
+ modified?: string;
22
+ }
23
+ /**
24
+ * Runtime configuration
25
+ */
26
+ interface RuntimeConfig {
27
+ engine: 'mathts' | 'custom';
28
+ execution: ExecutionMode;
29
+ timeout?: number;
30
+ }
31
+ /**
32
+ * Individual cell in a workbook
33
+ */
34
+ interface Cell {
35
+ id: string;
36
+ type: CellType;
37
+ content: string;
38
+ dependsOn?: string[];
39
+ output?: unknown;
40
+ error?: string;
41
+ metadata?: Record<string, unknown>;
42
+ }
43
+ /**
44
+ * Complete workbook structure
45
+ */
46
+ interface Workbook {
47
+ version: string;
48
+ metadata: WorkbookMetadata;
49
+ runtime: RuntimeConfig;
50
+ cells: Cell[];
51
+ }
52
+ /**
53
+ * Parse result with validation
54
+ */
55
+ interface ParseResult {
56
+ success: boolean;
57
+ workbook?: Workbook;
58
+ errors?: string[];
59
+ warnings?: string[];
60
+ }
61
+ /**
62
+ * Workbook execution events
63
+ */
64
+ interface WorkbookEvent {
65
+ type: 'cell:start' | 'cell:success' | 'cell:error' | 'cell:stale' | 'workbook:complete';
66
+ cellId?: string;
67
+ output?: unknown;
68
+ error?: string;
69
+ timestamp: number;
70
+ }
71
+ /**
72
+ * Dependency graph node
73
+ */
74
+ interface DependencyNode {
75
+ id: string;
76
+ dependencies: string[];
77
+ dependents: string[];
78
+ }
79
+ /**
80
+ * Dependency graph
81
+ */
82
+ interface DependencyGraph {
83
+ nodes: Map<string, DependencyNode>;
84
+ executionOrder: string[];
85
+ }
86
+
87
+ /**
88
+ * Workbook YAML parser
89
+ */
90
+
91
+ /**
92
+ * Parse a workbook from YAML content
93
+ */
94
+ declare function parseWorkbook(content: string): ParseResult;
95
+ /**
96
+ * Serialize a workbook to YAML
97
+ */
98
+ declare function serializeWorkbook(_workbook: Workbook): string;
99
+ /**
100
+ * Strip outputs from workbook (for git)
101
+ */
102
+ declare function stripOutputs(workbook: Workbook): Workbook;
103
+
104
+ /**
105
+ * Dependency graph management
106
+ */
107
+
108
+ /**
109
+ * Build dependency graph from cells
110
+ */
111
+ declare function buildDependencyGraph(cells: Cell[]): DependencyGraph;
112
+ /**
113
+ * Topological sort for execution order
114
+ */
115
+ declare function topologicalSort(nodes: Map<string, DependencyNode>): string[];
116
+ /**
117
+ * Get all cells that depend on a given cell
118
+ */
119
+ declare function getDependents(graph: DependencyGraph, cellId: string): string[];
120
+
121
+ /**
122
+ * Workbook executor
123
+ */
124
+
125
+ /**
126
+ * Event handler type
127
+ */
128
+ type EventHandler = (event: WorkbookEvent) => void;
129
+ /**
130
+ * Workbook executor with reactive execution support
131
+ */
132
+ declare class WorkbookExecutor {
133
+ private workbook;
134
+ private graph;
135
+ private outputs;
136
+ private handlers;
137
+ constructor(workbook: Workbook);
138
+ /**
139
+ * Subscribe to execution events
140
+ */
141
+ on(handler: EventHandler): () => void;
142
+ /**
143
+ * Emit an event to all handlers
144
+ */
145
+ private emit;
146
+ /**
147
+ * Run all cells in order
148
+ */
149
+ runAll(): Promise<void>;
150
+ /**
151
+ * Run a specific cell
152
+ */
153
+ runCell(cellId: string): Promise<unknown>;
154
+ /**
155
+ * Execute a single cell
156
+ */
157
+ private executeCell;
158
+ /**
159
+ * Execute a code cell by evaluating its content with scope from dependency outputs.
160
+ *
161
+ * Uses the Function constructor to evaluate expressions. Cell dependencies
162
+ * are injected as named variables in the evaluation scope, allowing cells
163
+ * to reference outputs of earlier cells by their id.
164
+ */
165
+ private executeCode;
166
+ /**
167
+ * Execute a data cell
168
+ */
169
+ private executeData;
170
+ /**
171
+ * Get output from a previous cell
172
+ */
173
+ getOutput(cellId: string): unknown;
174
+ }
175
+ /**
176
+ * Create an executor for a workbook
177
+ */
178
+ declare function createExecutor(workbook: Workbook): WorkbookExecutor;
179
+
180
+ /**
181
+ * @danielsimonjr/mathts-workbook - Scientific workbook runtime
182
+ * @packageDocumentation
183
+ */
184
+
185
+ declare const VERSION = "0.1.0";
186
+
187
+ export { type Cell, type CellType, type ExecutionMode, type ParseResult, type RuntimeConfig, VERSION, type Workbook, type WorkbookEvent, WorkbookExecutor, type WorkbookMetadata, buildDependencyGraph, createExecutor, getDependents, parseWorkbook, serializeWorkbook, stripOutputs, topologicalSort };
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ import {
2
+ VERSION,
3
+ WorkbookExecutor,
4
+ buildDependencyGraph,
5
+ createExecutor,
6
+ getDependents,
7
+ parseWorkbook,
8
+ serializeWorkbook,
9
+ stripOutputs,
10
+ topologicalSort
11
+ } from "./chunk-64JBL36K.js";
12
+ export {
13
+ VERSION,
14
+ WorkbookExecutor,
15
+ buildDependencyGraph,
16
+ createExecutor,
17
+ getDependents,
18
+ parseWorkbook,
19
+ serializeWorkbook,
20
+ stripOutputs,
21
+ topologicalSort
22
+ };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@danielsimonjr/mathts-workbook",
3
+ "version": "0.1.1",
4
+ "description": "Scientific workbook runtime for MathTS (.mtsw format)",
5
+ "author": "Daniel Simon Jr.",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "bin": {
12
+ "mtsw": "./dist/cli.js"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "import": "./dist/index.js",
17
+ "types": "./dist/index.d.ts"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup src/index.ts src/cli.ts --format esm --dts --clean",
26
+ "dev": "tsup src/index.ts src/cli.ts --format esm --dts --watch",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest",
29
+ "test:coverage": "vitest run --coverage",
30
+ "typecheck": "tsc --noEmit",
31
+ "lint": "eslint src --ext .ts",
32
+ "lint:fix": "eslint src --ext .ts --fix",
33
+ "clean": "rm -rf dist",
34
+ "build:prod": "tsup src/index.ts src/cli.ts --format esm --dts --clean --minify --treeshake"
35
+ },
36
+ "dependencies": {
37
+ "@danielsimonjr/mathts-core": "*",
38
+ "yaml": "^2.3.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^25.5.2",
42
+ "tsup": "^8.0.0",
43
+ "typescript": "^5.3.0",
44
+ "vitest": "^2.0.0"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "https://github.com/danielsimonjr/mathts",
52
+ "directory": "packages/workbook"
53
+ },
54
+ "keywords": [
55
+ "notebook",
56
+ "workbook",
57
+ "scientific-computing",
58
+ "reactive",
59
+ "yaml"
60
+ ]
61
+ }