@oddessentials/odd-docs 2.0.3 → 2.0.5
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 +166 -104
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
# odd-docs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@oddessentials/odd-docs)
|
|
4
|
+
[](https://nodejs.org)
|
|
5
|
+
[](./LICENSE)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
> **License Notice:** This project is source-available under the [Odd Essentials License (OEL)](./LICENSE). Commercial use requires a separate license. See [LICENSE](./LICENSE) for full terms.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
2. **Indirectly**, when invoked by an MCP host (such as `oddessentials-mcp`)
|
|
9
|
+
`odd-docs` is a documentation generation utility within the **oddessentials-mcp** ecosystem. It produces deterministic, structured documentation for MCP-compatible tools, servers, or repositories by inspecting manifests, schemas, and related metadata.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
It can be used in two distinct execution modes:
|
|
12
|
+
|
|
13
|
+
1. **Manual CLI execution**
|
|
14
|
+
2. **MCP-managed execution (via an MCP host such as oddessentials-mcp)**
|
|
15
|
+
|
|
16
|
+
Although both modes generate documentation automatically, they differ fundamentally in **execution ownership, filesystem control, and persistence guarantees**. This README documents both paths explicitly.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Requirements
|
|
21
|
+
|
|
22
|
+
- **Node.js ≥22.0.0** (see [.nvmrc](./.nvmrc))
|
|
23
|
+
- npm or npx
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Show version
|
|
31
|
+
npx @oddessentials/odd-docs --version
|
|
32
|
+
|
|
33
|
+
# Generate documentation for the current directory
|
|
34
|
+
npx @oddessentials/odd-docs generate .
|
|
35
|
+
|
|
36
|
+
# Validate without generating
|
|
37
|
+
npx @oddessentials/odd-docs validate .
|
|
38
|
+
|
|
39
|
+
# Start a local preview server
|
|
40
|
+
npx @oddessentials/odd-docs serve .
|
|
41
|
+
```
|
|
11
42
|
|
|
12
43
|
---
|
|
13
44
|
|
|
@@ -15,25 +46,25 @@ These two modes differ significantly in how execution, file access, and persiste
|
|
|
15
46
|
|
|
16
47
|
At a high level, `odd-docs`:
|
|
17
48
|
|
|
18
|
-
- Reads MCP-style manifests and
|
|
49
|
+
- Reads MCP-style manifests and schema definitions
|
|
19
50
|
- Builds an internal documentation representation
|
|
20
51
|
- Emits human-readable documentation (Markdown and/or HTML)
|
|
21
52
|
- Optionally validates documentation inputs
|
|
22
53
|
- Can serve generated documentation locally for inspection
|
|
23
54
|
|
|
24
|
-
|
|
55
|
+
`odd-docs` is intentionally **non-interactive** and **deterministic**: given the same inputs, it produces the same outputs.
|
|
25
56
|
|
|
26
57
|
---
|
|
27
58
|
|
|
28
59
|
## Installation (manual usage)
|
|
29
60
|
|
|
30
|
-
|
|
61
|
+
For standalone usage, install via npm:
|
|
31
62
|
|
|
32
63
|
```bash
|
|
33
64
|
npm install -g @oddessentials/odd-docs
|
|
34
65
|
```
|
|
35
66
|
|
|
36
|
-
Or run
|
|
67
|
+
Or run without installing:
|
|
37
68
|
|
|
38
69
|
```bash
|
|
39
70
|
npx @oddessentials/odd-docs --help
|
|
@@ -41,9 +72,18 @@ npx @oddessentials/odd-docs --help
|
|
|
41
72
|
|
|
42
73
|
---
|
|
43
74
|
|
|
44
|
-
##
|
|
75
|
+
## Global Options
|
|
45
76
|
|
|
46
|
-
|
|
77
|
+
```bash
|
|
78
|
+
odd-docs --version, -V # Show version number
|
|
79
|
+
odd-docs --help # Show help for any command
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## CLI Commands
|
|
85
|
+
|
|
86
|
+
### Command structure
|
|
47
87
|
|
|
48
88
|
```bash
|
|
49
89
|
odd-docs <command> <path> [options]
|
|
@@ -57,182 +97,204 @@ odd-docs <command> <path> [options]
|
|
|
57
97
|
|
|
58
98
|
---
|
|
59
99
|
|
|
60
|
-
###
|
|
100
|
+
### generate
|
|
101
|
+
|
|
102
|
+
Generate documentation for an MCP repository.
|
|
61
103
|
|
|
62
104
|
```bash
|
|
63
|
-
odd-docs generate <repo-path>
|
|
105
|
+
odd-docs generate <repo-path> [options]
|
|
64
106
|
```
|
|
65
107
|
|
|
66
|
-
|
|
108
|
+
**Options:**
|
|
67
109
|
|
|
68
|
-
|
|
69
|
-
|
|
110
|
+
| Option | Default | Description |
|
|
111
|
+
| ----------------------- | ---------------- | -------------------------------------- |
|
|
112
|
+
| `-f, --format <format>` | `md` | Output format: `md`, `html`, or `both` |
|
|
113
|
+
| `-o, --output <dir>` | `docs/generated` | Output directory for generated files |
|
|
114
|
+
| `--introspect <url>` | — | MCP server URL for live introspection |
|
|
70
115
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
--format md|html|both
|
|
75
|
-
--output <directory>
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Example:
|
|
116
|
+
**Example:**
|
|
79
117
|
|
|
80
118
|
```bash
|
|
81
119
|
odd-docs generate . --format both --output docs/generated
|
|
82
120
|
```
|
|
83
121
|
|
|
84
|
-
Outputs
|
|
122
|
+
**Outputs:**
|
|
85
123
|
|
|
86
124
|
- One or more `.md` and/or `.html` files
|
|
87
125
|
- A machine-readable intermediate representation (IR) JSON file
|
|
88
126
|
|
|
89
|
-
|
|
127
|
+
**Exit codes:**
|
|
128
|
+
|
|
129
|
+
- `0` — Success
|
|
130
|
+
- `1` — Error (missing manifest, invalid schema, etc.)
|
|
131
|
+
|
|
132
|
+
When run manually, **all generated files persist on disk** until you remove them.
|
|
90
133
|
|
|
91
134
|
---
|
|
92
135
|
|
|
93
|
-
###
|
|
136
|
+
### validate
|
|
137
|
+
|
|
138
|
+
Validate documentation inputs without writing output files.
|
|
94
139
|
|
|
95
140
|
```bash
|
|
96
|
-
odd-docs validate <repo-path>
|
|
141
|
+
odd-docs validate <repo-path> [options]
|
|
97
142
|
```
|
|
98
143
|
|
|
99
|
-
|
|
144
|
+
**Options:**
|
|
145
|
+
|
|
146
|
+
| Option | Description |
|
|
147
|
+
| -------------- | --------------------------------------------- |
|
|
148
|
+
| `-s, --strict` | Fail on unknown safety-affecting capabilities |
|
|
149
|
+
|
|
150
|
+
**Validation checks:**
|
|
100
151
|
|
|
101
152
|
- Required manifest fields
|
|
102
153
|
- Schema presence and consistency
|
|
103
154
|
- Capability declarations
|
|
104
155
|
- Structural correctness
|
|
105
156
|
|
|
106
|
-
|
|
107
|
-
|
|
157
|
+
**Exit codes:**
|
|
158
|
+
|
|
159
|
+
- `0` — Validation passed
|
|
160
|
+
- `1` — Validation failed or error encountered
|
|
161
|
+
|
|
162
|
+
Suitable for CI pipelines.
|
|
108
163
|
|
|
109
164
|
---
|
|
110
165
|
|
|
111
|
-
###
|
|
166
|
+
### serve
|
|
167
|
+
|
|
168
|
+
Start a local development server for generated documentation.
|
|
112
169
|
|
|
113
170
|
```bash
|
|
114
|
-
odd-docs serve <repo-path>
|
|
171
|
+
odd-docs serve <repo-path> [options]
|
|
115
172
|
```
|
|
116
173
|
|
|
117
|
-
|
|
174
|
+
**Options:**
|
|
175
|
+
|
|
176
|
+
| Option | Default | Description |
|
|
177
|
+
| -------------------------- | ---------------- | --------------------------------------------------------------- |
|
|
178
|
+
| `-p, --port <port>` | `3000` | Port to listen on |
|
|
179
|
+
| `-H, --host <host>` | `localhost` | Host to bind (localhost for safety) |
|
|
180
|
+
| `-o, --output <dir>` | `docs/generated` | Documentation output directory |
|
|
181
|
+
| `--no-watch` | — | Disable file watching |
|
|
182
|
+
| `--watch-mode <mode>` | `auto` | Watch mode: `auto` or `poll` (use `poll` for Docker/NFS) |
|
|
183
|
+
| `--reload <mode>` | `ws` | Reload mechanism: `ws`, `sse`, `poll`, `none` |
|
|
184
|
+
| `--no-open` | — | Do not open browser on start |
|
|
185
|
+
| `--introspect <target>` | — | MCP target: `http://host:port` or `stdio:<cmd>` |
|
|
186
|
+
| `--enable-mutations` | — | Enable mutation API endpoints (requires token) |
|
|
187
|
+
| `--mutation-token <token>` | — | Token for mutation endpoints (or `ODD_DOCS_MUTATION_TOKEN` env) |
|
|
188
|
+
|
|
189
|
+
**Behavior:**
|
|
118
190
|
|
|
119
|
-
- Generates documentation
|
|
120
|
-
- Starts a local HTTP server
|
|
121
|
-
-
|
|
191
|
+
- Generates documentation if it does not already exist
|
|
192
|
+
- Starts a local HTTP server for viewing the docs
|
|
193
|
+
- Watches source files and regenerates on change (unless `--no-watch`)
|
|
194
|
+
- Auto-switches to SSE for non-localhost bindings (safer for K8s)
|
|
122
195
|
|
|
123
|
-
|
|
196
|
+
**Exit codes:**
|
|
124
197
|
|
|
125
|
-
-
|
|
126
|
-
-
|
|
198
|
+
- `0` — Clean shutdown (SIGINT/SIGTERM)
|
|
199
|
+
- `1` — Error starting server
|
|
127
200
|
|
|
128
|
-
This mode is intended for
|
|
201
|
+
This mode is intended for local development and inspection.
|
|
129
202
|
|
|
130
203
|
---
|
|
131
204
|
|
|
132
|
-
## Temporary directories (manual
|
|
205
|
+
## Temporary directories (manual execution)
|
|
133
206
|
|
|
134
207
|
When running manually:
|
|
135
208
|
|
|
136
|
-
- `odd-docs` operates directly on the paths you provide
|
|
137
|
-
-
|
|
138
|
-
-
|
|
209
|
+
- `odd-docs` operates directly on the filesystem paths you provide
|
|
210
|
+
- Output directories are explicitly chosen by the user
|
|
211
|
+
- Generated documentation is **not** automatically deleted
|
|
139
212
|
|
|
140
|
-
|
|
213
|
+
Any temporary directories used internally during processing are scoped to execution only and do not affect output persistence.
|
|
141
214
|
|
|
142
|
-
**
|
|
215
|
+
**Persistence is fully under user control** in manual mode.
|
|
143
216
|
|
|
144
217
|
---
|
|
145
218
|
|
|
146
|
-
##
|
|
219
|
+
## MCP-managed execution (oddessentials-mcp)
|
|
147
220
|
|
|
148
|
-
When `odd-docs` is
|
|
149
|
-
|
|
150
|
-
Instead:
|
|
221
|
+
When invoked by an MCP host, `odd-docs` is not run directly by the user. Instead:
|
|
151
222
|
|
|
152
223
|
- The MCP host launches `odd-docs` as a managed tool
|
|
153
224
|
- Inputs are staged into an isolated workspace
|
|
154
|
-
- Outputs are collected as artifacts
|
|
155
|
-
- Execution
|
|
225
|
+
- Outputs are collected as MCP artifacts
|
|
226
|
+
- Execution occurs in a sandboxed environment
|
|
156
227
|
|
|
157
|
-
This
|
|
228
|
+
This execution model intentionally restricts filesystem access and lifetime.
|
|
158
229
|
|
|
159
230
|
---
|
|
160
231
|
|
|
161
232
|
## Temporary directories (MCP-managed execution)
|
|
162
233
|
|
|
163
|
-
When
|
|
234
|
+
When run under MCP control:
|
|
164
235
|
|
|
165
|
-
- A
|
|
166
|
-
- Repository files are copied or mounted into
|
|
167
|
-
-
|
|
168
|
-
-
|
|
236
|
+
- A temporary working directory is created by the MCP host
|
|
237
|
+
- Repository files are copied or mounted into this directory
|
|
238
|
+
- Generated documentation is written inside this directory
|
|
239
|
+
- The directory is **deleted immediately after execution completes**
|
|
169
240
|
|
|
170
|
-
###
|
|
241
|
+
### Persistence warning
|
|
171
242
|
|
|
172
|
-
When
|
|
243
|
+
When executed via MCP:
|
|
173
244
|
|
|
174
|
-
-
|
|
175
|
-
- There is no supported flag to
|
|
176
|
-
-
|
|
177
|
-
-
|
|
245
|
+
- The temporary directory **cannot be persisted**
|
|
246
|
+
- There is no supported flag or configuration to retain it
|
|
247
|
+
- Directory lifecycle is fully owned by the MCP host
|
|
248
|
+
- Cleanup occurs even after successful execution
|
|
178
249
|
|
|
179
|
-
If
|
|
250
|
+
If persistent documentation files are required, they must be:
|
|
180
251
|
|
|
181
|
-
-
|
|
182
|
-
-
|
|
252
|
+
- Retrieved from MCP artifact outputs, or
|
|
253
|
+
- Generated via manual CLI execution
|
|
183
254
|
|
|
184
|
-
|
|
255
|
+
Relying on MCP-managed temporary directories for persistence is unsupported.
|
|
185
256
|
|
|
186
257
|
---
|
|
187
258
|
|
|
188
|
-
##
|
|
189
|
-
|
|
190
|
-
The MCP execution model intentionally:
|
|
259
|
+
## Execution model comparison
|
|
191
260
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
261
|
+
| Aspect | Manual CLI execution | MCP-managed execution |
|
|
262
|
+
| ------------------------ | ------------------------ | ---------------------------- |
|
|
263
|
+
| Who launches the process | User | MCP host |
|
|
264
|
+
| Filesystem access | User-controlled paths | Isolated temporary workspace |
|
|
265
|
+
| Output persistence | Persistent | Ephemeral |
|
|
266
|
+
| Output retrieval | Direct filesystem access | MCP artifacts |
|
|
267
|
+
| Execution isolation | Minimal | Strong |
|
|
195
268
|
|
|
196
|
-
|
|
197
|
-
|
|
269
|
+
Both modes generate documentation automatically.
|
|
270
|
+
They differ in **who owns execution and filesystem lifecycle**.
|
|
198
271
|
|
|
199
272
|
---
|
|
200
273
|
|
|
201
|
-
##
|
|
202
|
-
|
|
203
|
-
### Use manual CLI mode if you:
|
|
204
|
-
|
|
205
|
-
- Want files written directly into your repository
|
|
206
|
-
- Need persistent documentation outputs
|
|
207
|
-
- Are developing or iterating on docs locally
|
|
274
|
+
## Summary
|
|
208
275
|
|
|
209
|
-
|
|
276
|
+
- `odd-docs` generates deterministic documentation from MCP metadata
|
|
277
|
+
- Manual execution prioritizes direct filesystem access and persistence
|
|
278
|
+
- MCP-managed execution prioritizes isolation and controlled lifecycles
|
|
279
|
+
- Temporary directories created under MCP control are always ephemeral
|
|
210
280
|
|
|
211
|
-
|
|
212
|
-
- Want documentation as artifacts, not files
|
|
213
|
-
- Are operating inside the oddessentials ecosystem
|
|
281
|
+
Choose the execution mode based on **ownership and persistence requirements**, not on automation level.
|
|
214
282
|
|
|
215
283
|
---
|
|
216
284
|
|
|
217
|
-
##
|
|
285
|
+
## License
|
|
218
286
|
|
|
219
|
-
|
|
287
|
+
This project is source-available under the [Odd Essentials License (OEL)](./LICENSE).
|
|
220
288
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
- Act as a documentation CMS
|
|
224
|
-
- Guarantee persistence when run under MCP
|
|
289
|
+
**Commercial use is prohibited** without a separate license from Odd Essentials, LLC.
|
|
290
|
+
See [LICENSE](./LICENSE) for full terms.
|
|
225
291
|
|
|
226
292
|
---
|
|
227
293
|
|
|
228
|
-
##
|
|
229
|
-
|
|
230
|
-
- `odd-docs` is deterministic, non-interactive, and filesystem-conscious
|
|
231
|
-
- Manual usage gives you full control and persistence
|
|
232
|
-
- MCP usage is sandboxed and ephemeral by design
|
|
233
|
-
- Temporary directories under MCP **cannot be persisted**
|
|
234
|
-
|
|
235
|
-
If you need persistence, run it manually.
|
|
236
|
-
If you need safety and automation, use MCP.
|
|
294
|
+
## Resources
|
|
237
295
|
|
|
238
|
-
|
|
296
|
+
- [Contributing](./CONTRIBUTING.md)
|
|
297
|
+
- [Code of Conduct](./CODE_OF_CONDUCT.md)
|
|
298
|
+
- [Changelog](./CHANGELOG.md)
|
|
299
|
+
- [Deployment Guide](./docs/deployment.md)
|
|
300
|
+
- [Specification](./docs/spec.md)
|
package/dist/cli/index.js
CHANGED
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/commands/generate.ts","../../src/core/parser/manifestParser.ts","../../src/core/ir/builder.ts","../../src/core/parser/schemaParser.ts","../../src/core/renderer/markdownRenderer.ts","../../src/core/renderer/htmlRenderer.ts","../../src/cli/commands/validate.ts","../../src/core/capabilities.ts","../../src/core/ir/validator.ts","../../src/cli/commands/serve.ts","../../src/server/index.ts","../../src/server/fileServer.ts","../../src/server/livereload.ts","../../src/server/api.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createRequire } from 'node:module';\nimport { generate } from './commands/generate.js';\nimport { validate } from './commands/validate.js';\nimport { serve } from './commands/serve.js';\n\n// Use createRequire for cross-platform compatibility with npx\n// This approach works reliably when the package is installed via npm/npx\nconst require = createRequire(import.meta.url);\nconst packageJson = require('../../package.json') as { version: string };\n\n// Handle --version explicitly before commander for reliable npx output\n// Commander's .version() output may not be captured properly by npx\nif (process.argv.includes('--version') || process.argv.includes('-V')) {\n console.log(packageJson.version);\n process.exit(0);\n}\n\nconst program = new Command();\n\nprogram.name('odd-docs').description('MCP-native documentation generator');\n\nprogram\n .command('generate')\n .description('Generate documentation for an MCP repo')\n .argument('<repo-path>', 'Path to the repository')\n .option('-f, --format <format>', 'Output format: md, html, or both', 'md')\n .option('-o, --output <dir>', 'Output directory')\n .option('--introspect <url>', 'MCP server URL for live introspection')\n .action(async (repoPath: string, options) => {\n try {\n await generate(repoPath, {\n format: options.format,\n output: options.output,\n introspect: options.introspect,\n });\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\nprogram\n .command('validate')\n .description('Validate documentation inputs for an MCP repo')\n .argument('<repo-path>', 'Path to the repository')\n .option('-s, --strict', 'Fail on unknown safety-affecting capabilities')\n .action(async (repoPath: string, options) => {\n try {\n const valid = await validate(repoPath, { strict: options.strict });\n process.exit(valid ? 0 : 1);\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\nprogram\n .command('serve')\n .description('Start a local dev server for generated documentation')\n .argument('<repo-path>', 'Path to the repository')\n .option('-p, --port <port>', 'Port to listen on', '3000')\n .option('-H, --host <host>', 'Host to bind (default: localhost for safety)', 'localhost')\n .option('-o, --output <dir>', 'Documentation output directory')\n .option('--no-watch', 'Disable file watching')\n .option('--watch-mode <mode>', 'Watch mode: auto or poll (use poll for Docker/NFS)', 'auto')\n .option('--reload <mode>', 'Reload mechanism: ws, sse, poll, none', 'ws')\n .option('--no-open', 'Do not open browser on start')\n .option('--introspect <target>', 'MCP target: http://host:port or stdio:<cmd>')\n .option('--enable-mutations', 'Enable mutation API endpoints (requires token)')\n .option('--mutation-token <token>', 'Token for mutation endpoints (or ODD_DOCS_MUTATION_TOKEN)')\n .action(async (repoPath: string, options) => {\n try {\n await serve(repoPath, {\n port: parseInt(options.port, 10),\n host: options.host,\n output: options.output,\n watch: options.watch,\n watchMode: options.watchMode,\n reload: options.reload,\n open: options.open,\n introspect: options.introspect,\n enableMutations: options.enableMutations,\n mutationToken: options.mutationToken,\n });\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import { writeFile, mkdir } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { parseManifest } from '../../core/parser/manifestParser.js';\nimport { buildDocIR } from '../../core/ir/builder.js';\nimport { renderMarkdown } from '../../core/renderer/markdownRenderer.js';\nimport { renderHTML } from '../../core/renderer/htmlRenderer.js';\n\nexport interface GenerateOptions {\n format?: 'md' | 'html' | 'both';\n output?: string;\n introspect?: string;\n}\n\nexport async function generate(repoPath: string, options: GenerateOptions = {}): Promise<void> {\n const absPath = resolve(repoPath);\n const format = options.format ?? 'md';\n const outputDir = options.output ? resolve(options.output) : join(absPath, 'docs', 'generated');\n\n console.log(`Generating documentation for: ${absPath}`);\n\n // Parse manifest\n const manifestResult = await parseManifest(absPath);\n console.log(` Entity: ${manifestResult.entity.id}@${manifestResult.entity.version}`);\n\n // Build Doc IR\n const ir = buildDocIR(manifestResult);\n console.log(` Determinism key: ${ir.determinismKey}`);\n\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n // Render formats\n if (format === 'md' || format === 'both') {\n const markdown = renderMarkdown(ir);\n const mdPath = join(outputDir, `${ir.entity.id}.md`);\n await writeFile(mdPath, markdown, 'utf-8');\n console.log(` ✓ Markdown: ${mdPath}`);\n }\n\n if (format === 'html' || format === 'both') {\n const html = renderHTML(ir);\n const htmlPath = join(outputDir, `${ir.entity.id}.html`);\n await writeFile(htmlPath, html, 'utf-8');\n console.log(` ✓ HTML: ${htmlPath}`);\n }\n\n // Write IR for debugging/caching\n const irPath = join(outputDir, `${ir.entity.id}.ir.json`);\n await writeFile(irPath, JSON.stringify(ir, null, 2), 'utf-8');\n console.log(` ✓ Doc IR: ${irPath}`);\n\n console.log('Done!');\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DocIR, Capability, SchemaSection } from '../ir/types.js';\n\ninterface ToolManifest {\n tool_id: string;\n version: string;\n description?: string;\n execution_mode?: 'IN_PROCESS' | 'RUNNER';\n parameters?: Record<string, unknown>;\n capabilities?: {\n network?: string[];\n filesystem?: string[];\n secrets?: string[];\n };\n timeout_ms?: number;\n resource_limits?: {\n memory_mb?: number;\n cpu_cores?: number;\n };\n deprecation?: {\n deprecated_at: string;\n sunset_date: string;\n migration_url?: string;\n };\n}\n\nexport interface ManifestParseResult {\n entity: DocIR['entity'];\n inputs: SchemaSection;\n constraints?: DocIR['constraints'];\n lifecycle?: DocIR['lifecycle'];\n}\n\n/**\n * Parse an MCP tool manifest file into partial Doc IR\n */\nexport async function parseManifest(repoPath: string): Promise<ManifestParseResult> {\n const manifestPath = join(repoPath, 'manifest.json');\n\n let content: string;\n try {\n content = await readFile(manifestPath, 'utf-8');\n } catch {\n throw new Error(`Manifest not found: ${manifestPath}`);\n }\n\n let manifest: ToolManifest;\n try {\n manifest = JSON.parse(content) as ToolManifest;\n } catch {\n throw new Error(`Invalid JSON in manifest: ${manifestPath}`);\n }\n\n // Validate required fields\n if (!manifest.tool_id) {\n throw new Error('Manifest missing required field: tool_id');\n }\n if (!manifest.version) {\n throw new Error('Manifest missing required field: version');\n }\n\n // Build capabilities array\n const capabilities: Capability[] = [];\n if (manifest.capabilities) {\n for (const [type, values] of Object.entries(manifest.capabilities)) {\n if (Array.isArray(values) && values.length > 0) {\n capabilities.push({ type, values, provenance: 'manifest' });\n }\n }\n }\n\n const result: ManifestParseResult = {\n entity: {\n type: 'tool',\n id: manifest.tool_id,\n version: manifest.version,\n description: manifest.description,\n },\n inputs: {\n schema: manifest.parameters,\n provenance: 'manifest',\n },\n };\n\n // Add constraints if present\n if (capabilities.length > 0 || manifest.timeout_ms || manifest.resource_limits) {\n result.constraints = {\n capabilities: capabilities.length > 0 ? capabilities : undefined,\n timeoutMs: manifest.timeout_ms,\n resourceLimits: manifest.resource_limits\n ? {\n memoryMb: manifest.resource_limits.memory_mb,\n cpuCores: manifest.resource_limits.cpu_cores,\n }\n : undefined,\n };\n }\n\n // Add lifecycle if deprecation present\n if (manifest.deprecation) {\n result.lifecycle = {\n version: manifest.version,\n deprecation: {\n deprecatedAt: manifest.deprecation.deprecated_at,\n sunsetDate: manifest.deprecation.sunset_date,\n migrationUrl: manifest.deprecation.migration_url,\n },\n };\n }\n\n return result;\n}\n","import { createHash } from 'node:crypto';\nimport type { DocIR } from './types.js';\nimport { enrichSchemaSection } from '../parser/schemaParser.js';\nimport type { ManifestParseResult } from '../parser/manifestParser.js';\n\n/**\n * Build a complete Doc IR from parsed sources\n */\nexport function buildDocIR(manifest: ManifestParseResult): DocIR {\n const enrichedInputs = enrichSchemaSection(manifest.inputs);\n\n const ir: DocIR = {\n version: '1.0.0',\n generatedAt: new Date().toISOString(),\n determinismKey: '', // Computed below\n entity: manifest.entity,\n inputs: enrichedInputs,\n constraints: manifest.constraints,\n lifecycle: manifest.lifecycle,\n provenance: {\n entity: 'manifest',\n inputs: 'manifest',\n },\n };\n\n // Compute determinism key\n ir.determinismKey = computeDeterminismKey(ir);\n\n return ir;\n}\n\n/**\n * Compute SHA-256 determinism key for caching and diffing\n */\nexport function computeDeterminismKey(ir: Omit<DocIR, 'determinismKey' | 'generatedAt'>): string {\n const canonical = JSON.stringify({\n entity: ir.entity,\n inputs: ir.inputs,\n constraints: ir.constraints,\n lifecycle: ir.lifecycle,\n });\n\n const hash = createHash('sha256').update(canonical).digest('hex');\n return `sha256:${hash}`;\n}\n","import type { Parameter, SchemaSection } from '../ir/types.js';\n\ninterface JSONSchema {\n type?: string;\n properties?: Record<string, JSONSchema>;\n required?: string[];\n description?: string;\n default?: unknown;\n enum?: unknown[];\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n items?: JSONSchema;\n $ref?: string;\n}\n\n/**\n * Parse JSON Schema into a list of parameters for documentation\n */\nexport function parseSchema(schema: Record<string, unknown> | undefined): Parameter[] {\n if (!schema) return [];\n\n const jsonSchema = schema as JSONSchema;\n const parameters: Parameter[] = [];\n const required = new Set(jsonSchema.required ?? []);\n\n if (jsonSchema.properties) {\n for (const [name, propSchema] of Object.entries(jsonSchema.properties)) {\n parameters.push(parseProperty(name, propSchema, required.has(name)));\n }\n }\n\n return parameters;\n}\n\nfunction parseProperty(name: string, schema: JSONSchema, isRequired: boolean): Parameter {\n const param: Parameter = {\n name,\n type: resolveType(schema),\n required: isRequired,\n };\n\n if (schema.description) {\n param.description = schema.description;\n }\n\n if (schema.default !== undefined) {\n param.default = schema.default;\n }\n\n if (schema.enum) {\n param.enum = schema.enum;\n }\n\n // Build constraints string\n const constraints = buildConstraints(schema);\n if (constraints) {\n param.constraints = constraints;\n }\n\n return param;\n}\n\nfunction resolveType(schema: JSONSchema): string {\n if (schema.$ref) {\n // Extract type name from $ref\n const refParts = schema.$ref.split('/');\n return refParts[refParts.length - 1];\n }\n\n if (schema.enum) {\n return 'enum';\n }\n\n if (schema.type === 'array' && schema.items) {\n return `${resolveType(schema.items)}[]`;\n }\n\n return schema.type ?? 'unknown';\n}\n\nfunction buildConstraints(schema: JSONSchema): string | undefined {\n const parts: string[] = [];\n\n if (schema.minimum !== undefined) {\n parts.push(`min: ${schema.minimum}`);\n }\n if (schema.maximum !== undefined) {\n parts.push(`max: ${schema.maximum}`);\n }\n if (schema.minLength !== undefined) {\n parts.push(`minLength: ${schema.minLength}`);\n }\n if (schema.maxLength !== undefined) {\n parts.push(`maxLength: ${schema.maxLength}`);\n }\n if (schema.pattern) {\n parts.push(`pattern: ${schema.pattern}`);\n }\n\n return parts.length > 0 ? parts.join(', ') : undefined;\n}\n\n/**\n * Enrich a SchemaSection with parsed parameters\n */\nexport function enrichSchemaSection(section: SchemaSection): SchemaSection {\n return {\n ...section,\n parameters: parseSchema(section.schema),\n };\n}\n","import type { DocIR, Parameter, ProvenanceSource } from '../ir/types.js';\n\n/**\n * Render Doc IR to Markdown\n */\nexport function renderMarkdown(ir: DocIR): string {\n const lines: string[] = [];\n\n // Header\n lines.push(`# ${ir.entity.id}`);\n lines.push('');\n lines.push(`**Version:** ${ir.entity.version} `);\n lines.push(`**Type:** ${ir.entity.type} `);\n if (ir.entity.description) {\n lines.push('');\n lines.push(ir.entity.description);\n }\n lines.push('');\n\n // Overview\n if (ir.overview) {\n lines.push('## Overview');\n lines.push('');\n if (ir.overview.intent) {\n lines.push(`**Intent:** ${ir.overview.intent}`);\n lines.push('');\n }\n if (ir.overview.useCases?.length) {\n lines.push('### Use Cases');\n lines.push('');\n for (const useCase of ir.overview.useCases) {\n lines.push(`- ${useCase}`);\n }\n lines.push('');\n }\n if (ir.overview.sideEffects?.length) {\n lines.push('### Side Effects');\n lines.push('');\n for (const effect of ir.overview.sideEffects) {\n lines.push(\n `- **${effect.type}**: ${effect.description} ${provenanceBadge(effect.provenance)}`\n );\n }\n lines.push('');\n }\n }\n\n // Inputs\n if (ir.inputs?.parameters?.length) {\n lines.push('## Inputs');\n lines.push('');\n lines.push(provenanceBadge(ir.inputs.provenance));\n lines.push('');\n lines.push(renderParameterTable(ir.inputs.parameters));\n lines.push('');\n }\n\n // Outputs\n if (ir.outputs?.parameters?.length) {\n lines.push('## Outputs');\n lines.push('');\n lines.push(provenanceBadge(ir.outputs.provenance));\n lines.push('');\n lines.push(renderParameterTable(ir.outputs.parameters));\n lines.push('');\n }\n\n // Constraints\n if (ir.constraints) {\n lines.push('## Constraints');\n lines.push('');\n if (ir.constraints.capabilities?.length) {\n lines.push('### Capabilities');\n lines.push('');\n for (const cap of ir.constraints.capabilities) {\n const values = cap.values?.join(', ') ?? 'enabled';\n lines.push(`- **${cap.type}**: ${values} ${provenanceBadge(cap.provenance)}`);\n }\n lines.push('');\n }\n if (ir.constraints.timeoutMs) {\n lines.push(`**Timeout:** ${ir.constraints.timeoutMs}ms`);\n lines.push('');\n }\n if (ir.constraints.resourceLimits) {\n lines.push('### Resource Limits');\n lines.push('');\n if (ir.constraints.resourceLimits.memoryMb) {\n lines.push(`- Memory: ${ir.constraints.resourceLimits.memoryMb} MB`);\n }\n if (ir.constraints.resourceLimits.cpuCores) {\n lines.push(`- CPU: ${ir.constraints.resourceLimits.cpuCores} cores`);\n }\n lines.push('');\n }\n }\n\n // Errors\n if (ir.errors?.length) {\n lines.push('## Errors');\n lines.push('');\n lines.push('| Code | Description | Recovery |');\n lines.push('|------|-------------|----------|');\n for (const err of ir.errors) {\n lines.push(`| \\`${err.code}\\` | ${err.description ?? ''} | ${err.recovery ?? ''} |`);\n }\n lines.push('');\n }\n\n // Lifecycle\n if (ir.lifecycle?.deprecation) {\n lines.push('## Lifecycle');\n lines.push('');\n lines.push('> [!WARNING]');\n lines.push(`> This tool is deprecated as of ${ir.lifecycle.deprecation.deprecatedAt}.`);\n lines.push(`> Sunset date: ${ir.lifecycle.deprecation.sunsetDate}`);\n if (ir.lifecycle.deprecation.migrationUrl) {\n lines.push(`> Migration guide: ${ir.lifecycle.deprecation.migrationUrl}`);\n }\n lines.push('');\n }\n\n // Examples\n if (ir.narrative?.examples?.length) {\n lines.push('## Examples');\n lines.push('');\n for (const example of ir.narrative.examples) {\n if (example.title) {\n lines.push(`### ${example.title}`);\n lines.push('');\n }\n if (example.description) {\n lines.push(example.description);\n lines.push('');\n }\n if (example.input) {\n lines.push('**Input:**');\n lines.push('```json');\n lines.push(JSON.stringify(example.input, null, 2));\n lines.push('```');\n lines.push('');\n }\n if (example.output) {\n lines.push('**Output:**');\n lines.push('```json');\n lines.push(JSON.stringify(example.output, null, 2));\n lines.push('```');\n lines.push('');\n }\n }\n }\n\n // Notes\n if (ir.narrative?.notes?.length) {\n lines.push('## Notes');\n lines.push('');\n lines.push('*[author notes]*');\n lines.push('');\n for (const note of ir.narrative.notes) {\n lines.push(note);\n lines.push('');\n }\n }\n\n // Footer\n lines.push('---');\n lines.push('');\n lines.push(`*Generated at ${ir.generatedAt}* `);\n lines.push(`*Determinism key: \\`${ir.determinismKey}\\`*`);\n\n return lines.join('\\n');\n}\n\nfunction renderParameterTable(params: Parameter[]): string {\n const lines: string[] = [];\n lines.push('| Name | Type | Required | Default | Description |');\n lines.push('|------|------|----------|---------|-------------|');\n\n for (const param of params) {\n const required = param.required ? '✓' : '';\n const defaultVal = param.default !== undefined ? `\\`${JSON.stringify(param.default)}\\`` : '';\n const desc = param.description ?? '';\n lines.push(`| \\`${param.name}\\` | \\`${param.type}\\` | ${required} | ${defaultVal} | ${desc} |`);\n }\n\n return lines.join('\\n');\n}\n\nfunction provenanceBadge(source?: ProvenanceSource): string {\n if (!source) return '';\n const badges: Record<ProvenanceSource, string> = {\n introspection: '`[from introspection]`',\n manifest: '`[from schema]`',\n overlay: '`[from overlay]`',\n narrative: '`[author notes]`',\n };\n return badges[source] ?? '';\n}\n","import { marked } from 'marked';\nimport type { DocIR } from '../ir/types.js';\nimport { renderMarkdown } from './markdownRenderer.js';\n\n/**\n * Render Doc IR to static HTML\n */\nexport function renderHTML(ir: DocIR): string {\n // First render to markdown, then convert to HTML\n const markdown = renderMarkdown(ir);\n const htmlContent = marked.parse(markdown) as string;\n\n return `<!DOCTYPE html>\n<html lang=\"en\" data-theme=\"light\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"description\" content=\"${escapeHtml(ir.entity.description ?? `Documentation for ${ir.entity.id}`)}\">\n <title>${escapeHtml(ir.entity.id)} - odd-docs</title>\n <style>\n${getThemeStyles()}\n </style>\n</head>\n<body>\n <div class=\"container\">\n <header>\n <nav class=\"breadcrumb\">\n <a href=\"index.html\">Home</a> / <span>${escapeHtml(ir.entity.id)}</span>\n </nav>\n </header>\n <main class=\"content\">\n${htmlContent}\n </main>\n <footer>\n <p class=\"meta\">\n Generated by <a href=\"https://github.com/oddessentials/odd-docs\">odd-docs</a> at ${ir.generatedAt}\n </p>\n <p class=\"determinism\">\n <code>${ir.determinismKey}</code>\n </p>\n </footer>\n </div>\n <script>\n${getThemeScript()}\n </script>\n</body>\n</html>`;\n}\n\n/**\n * Generate index page for multiple docs\n */\nexport function renderIndexHTML(docs: DocIR[]): string {\n const items = docs\n .map(\n (ir) => `\n <li>\n <a href=\"${ir.entity.id}.html\">\n <strong>${escapeHtml(ir.entity.id)}</strong>\n <span class=\"version\">v${ir.entity.version}</span>\n </a>\n <p>${escapeHtml(ir.entity.description ?? '')}</p>\n </li>`\n )\n .join('\\n');\n\n return `<!DOCTYPE html>\n<html lang=\"en\" data-theme=\"light\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Documentation - odd-docs</title>\n <style>\n${getThemeStyles()}\n </style>\n</head>\n<body>\n <div class=\"container\">\n <header>\n <h1>Documentation</h1>\n </header>\n <main class=\"content\">\n <ul class=\"doc-list\">\n${items}\n </ul>\n </main>\n <footer>\n <p class=\"meta\">Generated by <a href=\"https://github.com/oddessentials/odd-docs\">odd-docs</a></p>\n </footer>\n </div>\n <script>\n${getThemeScript()}\n </script>\n</body>\n</html>`;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nfunction getThemeStyles(): string {\n return `\n /* CSS Variables for theming */\n :root {\n /* Colors - neutral palette */\n --color-bg: #ffffff;\n --color-bg-secondary: #f8f9fa;\n --color-text: #1a1a2e;\n --color-text-muted: #6c757d;\n --color-border: #dee2e6;\n --color-link: #0066cc;\n --color-link-hover: #004499;\n --color-accent: #0066cc;\n --color-success: #28a745;\n --color-warning: #ffc107;\n --color-error: #dc3545;\n \n /* Typography */\n --font-sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n --font-mono: 'SF Mono', Monaco, 'Cascadia Code', monospace;\n --font-size-base: 16px;\n --line-height: 1.6;\n \n /* Spacing */\n --space-xs: 0.25rem;\n --space-sm: 0.5rem;\n --space-md: 1rem;\n --space-lg: 1.5rem;\n --space-xl: 2rem;\n \n /* Layout */\n --max-width: 800px;\n --border-radius: 4px;\n }\n \n [data-theme=\"dark\"] {\n --color-bg: #1a1a2e;\n --color-bg-secondary: #16213e;\n --color-text: #e8e8e8;\n --color-text-muted: #a0a0a0;\n --color-border: #3a3a5e;\n --color-link: #66b3ff;\n --color-link-hover: #99ccff;\n }\n \n /* Reset */\n *, *::before, *::after {\n box-sizing: border-box;\n }\n \n body {\n margin: 0;\n padding: 0;\n font-family: var(--font-sans);\n font-size: var(--font-size-base);\n line-height: var(--line-height);\n color: var(--color-text);\n background: var(--color-bg);\n }\n \n /* Container */\n .container {\n max-width: var(--max-width);\n margin: 0 auto;\n padding: var(--space-lg);\n }\n \n /* Typography */\n h1, h2, h3, h4, h5, h6 {\n margin-top: var(--space-xl);\n margin-bottom: var(--space-md);\n line-height: 1.3;\n }\n \n h1 { font-size: 2rem; }\n h2 { font-size: 1.5rem; border-bottom: 1px solid var(--color-border); padding-bottom: var(--space-sm); }\n h3 { font-size: 1.25rem; }\n \n p { margin: var(--space-md) 0; }\n \n a {\n color: var(--color-link);\n text-decoration: none;\n }\n \n a:hover {\n color: var(--color-link-hover);\n text-decoration: underline;\n }\n \n /* Code */\n code {\n font-family: var(--font-mono);\n font-size: 0.9em;\n background: var(--color-bg-secondary);\n padding: var(--space-xs) var(--space-sm);\n border-radius: var(--border-radius);\n }\n \n pre {\n background: var(--color-bg-secondary);\n padding: var(--space-md);\n border-radius: var(--border-radius);\n overflow-x: auto;\n }\n \n pre code {\n background: none;\n padding: 0;\n }\n \n /* Tables */\n table {\n width: 100%;\n border-collapse: collapse;\n margin: var(--space-md) 0;\n }\n \n th, td {\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n text-align: left;\n }\n \n th {\n background: var(--color-bg-secondary);\n font-weight: 600;\n }\n \n /* Provenance badges */\n code[class*=\"from\"] {\n font-size: 0.75em;\n color: var(--color-text-muted);\n background: transparent;\n }\n \n /* Blockquotes (for warnings/notes) */\n blockquote {\n margin: var(--space-md) 0;\n padding: var(--space-md);\n border-left: 4px solid var(--color-warning);\n background: var(--color-bg-secondary);\n }\n \n blockquote p:first-child { margin-top: 0; }\n blockquote p:last-child { margin-bottom: 0; }\n \n /* Lists */\n ul, ol {\n padding-left: var(--space-lg);\n }\n \n li { margin: var(--space-sm) 0; }\n \n /* Doc list (index page) */\n .doc-list {\n list-style: none;\n padding: 0;\n }\n \n .doc-list li {\n padding: var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--border-radius);\n margin-bottom: var(--space-md);\n }\n \n .doc-list a {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n }\n \n .doc-list .version {\n color: var(--color-text-muted);\n font-size: 0.875em;\n }\n \n .doc-list p {\n margin: var(--space-sm) 0 0;\n color: var(--color-text-muted);\n }\n \n /* Header */\n header {\n margin-bottom: var(--space-lg);\n }\n \n .breadcrumb {\n font-size: 0.875em;\n color: var(--color-text-muted);\n }\n \n .breadcrumb a {\n color: inherit;\n }\n \n /* Footer */\n footer {\n margin-top: var(--space-xl);\n padding-top: var(--space-lg);\n border-top: 1px solid var(--color-border);\n font-size: 0.875em;\n color: var(--color-text-muted);\n }\n \n .determinism code {\n font-size: 0.75em;\n }\n \n /* Theme toggle */\n .theme-toggle {\n position: fixed;\n top: var(--space-md);\n right: var(--space-md);\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--border-radius);\n background: var(--color-bg);\n cursor: pointer;\n font-size: 0.875em;\n }\n \n /* Responsive */\n @media (max-width: 600px) {\n .container { padding: var(--space-md); }\n h1 { font-size: 1.5rem; }\n h2 { font-size: 1.25rem; }\n table { font-size: 0.875em; }\n }\n `;\n}\n\nfunction getThemeScript(): string {\n return `\n // Theme toggle\n const toggle = document.createElement('button');\n toggle.className = 'theme-toggle';\n toggle.textContent = '🌙';\n toggle.onclick = () => {\n const html = document.documentElement;\n const isDark = html.dataset.theme === 'dark';\n html.dataset.theme = isDark ? 'light' : 'dark';\n toggle.textContent = isDark ? '🌙' : '☀️';\n localStorage.setItem('theme', html.dataset.theme);\n };\n document.body.appendChild(toggle);\n \n // Restore saved theme\n const saved = localStorage.getItem('theme');\n if (saved) {\n document.documentElement.dataset.theme = saved;\n toggle.textContent = saved === 'dark' ? '☀️' : '🌙';\n } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {\n document.documentElement.dataset.theme = 'dark';\n toggle.textContent = '☀️';\n }\n `;\n}\n","import { resolve } from 'node:path';\nimport { parseManifest } from '../../core/parser/manifestParser.js';\nimport { buildDocIR } from '../../core/ir/builder.js';\nimport { validateDocIR, formatValidationResult } from '../../core/ir/validator.js';\n\nexport interface ValidateOptions {\n strict?: boolean;\n}\n\nexport async function validate(repoPath: string, options: ValidateOptions = {}): Promise<boolean> {\n const absPath = resolve(repoPath);\n\n console.log(`Validating: ${absPath}`);\n console.log(`Mode: ${options.strict ? 'strict' : 'normal'}`);\n console.log('');\n\n try {\n // Parse manifest\n const manifestResult = await parseManifest(absPath);\n\n // Build Doc IR\n const ir = buildDocIR(manifestResult);\n\n // Validate\n const result = validateDocIR(ir, { strict: options.strict });\n\n // Format and print result\n console.log(formatValidationResult(result, absPath));\n\n return result.valid;\n } catch (error) {\n console.error('✗ Validation failed');\n console.error('');\n console.error(`Error: ${error instanceof Error ? error.message : error}`);\n return false;\n }\n}\n","/**\n * Known capabilities allowlist\n * Safety-affecting capabilities trigger stricter validation\n */\n\nexport const KNOWN_CAPABILITIES = [\n 'network',\n 'filesystem',\n 'secrets',\n 'exec',\n 'subprocess',\n 'database',\n 'queue',\n] as const;\n\nexport type KnownCapability = (typeof KNOWN_CAPABILITIES)[number];\n\n/**\n * Capabilities that imply safety-critical operations\n * Unknown capabilities matching these patterns fail in --strict mode\n */\nexport const SAFETY_AFFECTING_PATTERNS = ['network', 'exec', 'subprocess', 'write', 'delete'];\n\nexport function isKnownCapability(capability: string): capability is KnownCapability {\n return KNOWN_CAPABILITIES.includes(capability as KnownCapability);\n}\n\nexport function isSafetyAffecting(capability: string): boolean {\n return SAFETY_AFFECTING_PATTERNS.some((pattern) =>\n capability.toLowerCase().includes(pattern.toLowerCase())\n );\n}\n","import type { DocIR, ProvenanceSource } from '../ir/types.js';\nimport { isKnownCapability, isSafetyAffecting } from '../capabilities.js';\n\nexport type ValidationSeverity = 'error' | 'warning';\n\nexport interface ValidationIssue {\n severity: ValidationSeverity;\n code: string;\n message: string;\n path?: string;\n provenance?: ProvenanceSource;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n issues: ValidationIssue[];\n}\n\nexport interface ValidateOptions {\n strict?: boolean;\n}\n\n/**\n * Validate Doc IR for completeness and consistency\n */\nexport function validateDocIR(ir: DocIR, options: ValidateOptions = {}): ValidationResult {\n const issues: ValidationIssue[] = [];\n\n // Required field checks\n if (!ir.entity.id) {\n issues.push({\n severity: 'error',\n code: 'MISSING_TOOL_ID',\n message: 'Tool ID is required',\n path: 'entity.id',\n });\n }\n\n if (!ir.entity.version) {\n issues.push({\n severity: 'error',\n code: 'MISSING_VERSION',\n message: 'Version is required',\n path: 'entity.version',\n });\n }\n\n if (!ir.inputs?.schema && !ir.inputs?.parameters?.length) {\n issues.push({\n severity: 'error',\n code: 'MISSING_PARAMETERS_SCHEMA',\n message: 'Parameters schema is required',\n path: 'inputs',\n });\n }\n\n // Capability validation\n if (ir.constraints?.capabilities) {\n for (const cap of ir.constraints.capabilities) {\n if (!isKnownCapability(cap.type)) {\n const isSafety = isSafetyAffecting(cap.type);\n issues.push({\n severity: options.strict && isSafety ? 'error' : 'warning',\n code: 'UNKNOWN_CAPABILITY',\n message: `Unknown capability: ${cap.type}${isSafety ? ' (safety-affecting)' : ''}`,\n path: `constraints.capabilities.${cap.type}`,\n provenance: cap.provenance,\n });\n }\n }\n }\n\n // Structural contradiction checks\n issues.push(...checkStructuralContradictions(ir));\n\n const hasErrors = issues.some((i) => i.severity === 'error');\n\n return {\n valid: !hasErrors,\n issues,\n };\n}\n\n/**\n * Check for structural contradictions between sources\n */\nfunction checkStructuralContradictions(ir: DocIR): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n // Check if narrative mentions parameters not in schema\n if (ir.narrative?.notes && ir.inputs?.parameters) {\n const schemaParams = new Set(ir.inputs.parameters.map((p) => p.name.toLowerCase()));\n\n for (const note of ir.narrative.notes) {\n // Match patterns like \"parameter X\" or \"the X parameter\"\n const paramMentions = note.match(/(?:parameter|param)\\s+[`\"']?(\\w+)[`\"']?/gi) ?? [];\n const theParamMentions = note.match(/the\\s+[`\"']?(\\w+)[`\"']?\\s+parameter/gi) ?? [];\n\n for (const match of [...paramMentions, ...theParamMentions]) {\n const paramName = match.replace(/.*?[`\"']?(\\w+)[`\"']?.*/i, '$1').toLowerCase();\n if (paramName && !schemaParams.has(paramName) && paramName !== 'parameter') {\n issues.push({\n severity: 'error',\n code: 'NARRATIVE_REFERENCES_UNDEFINED_PARAM',\n message: `Narrative references parameter \"${paramName}\" not in schema`,\n path: 'narrative.notes',\n provenance: 'narrative',\n });\n }\n }\n }\n }\n\n // Check if examples use parameters not in schema\n if (ir.narrative?.examples && ir.inputs?.parameters) {\n const schemaParams = new Set(ir.inputs.parameters.map((p) => p.name));\n\n for (const example of ir.narrative.examples) {\n if (example.input && typeof example.input === 'object') {\n for (const key of Object.keys(example.input as Record<string, unknown>)) {\n if (!schemaParams.has(key)) {\n issues.push({\n severity: 'warning',\n code: 'EXAMPLE_USES_UNDEFINED_PARAM',\n message: `Example uses parameter \"${key}\" not in schema`,\n path: `narrative.examples.${example.title ?? 'unnamed'}`,\n provenance: 'narrative',\n });\n }\n }\n }\n }\n }\n\n // Check for side effect / capability contradictions\n if (ir.overview?.sideEffects && ir.constraints?.capabilities) {\n const capTypes = new Set(ir.constraints.capabilities.map((c) => c.type));\n\n for (const effect of ir.overview.sideEffects) {\n // Map side effect types to capability types\n const expectedCap = mapSideEffectToCapability(effect.type);\n if (expectedCap && !capTypes.has(expectedCap)) {\n issues.push({\n severity: 'error',\n code: 'SIDE_EFFECT_CAPABILITY_MISMATCH',\n message: `Side effect \"${effect.type}\" requires capability \"${expectedCap}\" which is not declared`,\n path: `overview.sideEffects.${effect.type}`,\n provenance: effect.provenance,\n });\n }\n }\n }\n\n return issues;\n}\n\nfunction mapSideEffectToCapability(effectType: string): string | null {\n const mapping: Record<string, string> = {\n filesystem: 'filesystem',\n network: 'network',\n secrets: 'secrets',\n exec: 'exec',\n subprocess: 'subprocess',\n database: 'database',\n queue: 'queue',\n };\n return mapping[effectType] ?? null;\n}\n\n/**\n * Format validation result for CLI output\n */\nexport function formatValidationResult(result: ValidationResult, repoPath: string): string {\n const lines: string[] = [];\n\n lines.push(`Validating: ${repoPath}`);\n lines.push('');\n\n if (result.valid) {\n lines.push('✓ Validation passed');\n } else {\n lines.push('✗ Validation failed');\n }\n lines.push('');\n\n const errors = result.issues.filter((i) => i.severity === 'error');\n const warnings = result.issues.filter((i) => i.severity === 'warning');\n\n if (errors.length > 0) {\n lines.push(`Errors (${errors.length}):`);\n for (const issue of errors) {\n lines.push(` ✗ [${issue.code}] ${issue.message}`);\n if (issue.path) {\n lines.push(` at ${issue.path}`);\n }\n }\n lines.push('');\n }\n\n if (warnings.length > 0) {\n lines.push(`Warnings (${warnings.length}):`);\n for (const issue of warnings) {\n lines.push(` ⚠ [${issue.code}] ${issue.message}`);\n if (issue.path) {\n lines.push(` at ${issue.path}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n","/**\n * Serve Command\n *\n * Start a local development server for generated documentation.\n * Enforces safe defaults per deployment stance:\n * - localhost binding\n * - mutations disabled\n * - SSE auto-switch for non-localhost\n */\n\nimport { existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { OddDocsServer, type ServeOptions } from '../../server/index.js';\nimport { generate } from './generate.js';\n\nexport interface ServeCommandOptions {\n port?: number;\n host?: string;\n output?: string;\n watch?: boolean;\n watchMode?: 'auto' | 'poll';\n reload?: 'ws' | 'sse' | 'poll' | 'none';\n open?: boolean;\n introspect?: string;\n enableMutations?: boolean;\n mutationToken?: string;\n}\n\n/**\n * Serve documentation with live reload\n */\nexport async function serve(repoPath: string, options: ServeCommandOptions = {}): Promise<void> {\n const resolvedPath = resolve(repoPath);\n\n // Determine output directory\n const outputDir = options.output\n ? resolve(options.output)\n : join(resolvedPath, 'docs', 'generated');\n\n // Check if docs exist, generate if not\n if (!existsSync(outputDir)) {\n console.log('[odd-docs] Documentation not found, generating...');\n await generate(repoPath, { output: outputDir, format: 'html' });\n }\n\n // Determine reload mode\n let reloadMode: 'ws' | 'sse' | 'poll' | 'none' = options.reload ?? 'ws';\n\n // Use poll mode if explicitly requested via env or option\n if (options.watchMode === 'poll' || process.env.CHOKIDAR_USEPOLLING === '1') {\n reloadMode = 'poll';\n console.log('[odd-docs] Using poll-based watching (CPU intensive)');\n }\n\n const host = options.host ?? 'localhost';\n const port = options.port ?? 3000;\n\n // Auto-switch to SSE for non-localhost (safer for K8s)\n if (host !== 'localhost' && options.reload === undefined) {\n reloadMode = 'sse';\n console.log('[odd-docs] Using SSE for non-localhost binding');\n }\n\n // Create and start server\n const serverOptions: Partial<ServeOptions> & { outputDir: string } = {\n outputDir,\n host,\n port,\n watch: options.watch !== false,\n reloadMode,\n enableMutations: options.enableMutations ?? false,\n mutationToken: options.mutationToken,\n };\n\n const server = new OddDocsServer(serverOptions);\n\n // Handle shutdown\n const shutdown = async () => {\n console.log('\\n[odd-docs] Shutting down...');\n await server.stop();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n try {\n await server.start();\n\n // Open browser if requested\n if (options.open !== false && host === 'localhost') {\n const url = `http://${host}:${port}`;\n try {\n const { default: open } = await import('open');\n await open(url);\n } catch {\n console.log(`[odd-docs] Open browser manually: ${url}`);\n }\n }\n } catch (error) {\n console.error('[odd-docs] Failed to start server:', error);\n process.exit(1);\n }\n}\n","/**\n * OddDocs Server\n *\n * HTTP server wrapper for serving generated documentation.\n * Enforces safe defaults: localhost binding, no mutations without explicit opt-in.\n */\n\nimport { createServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { FileServer } from './fileServer.js';\nimport { LiveReload } from './livereload.js';\nimport { ApiHandler, type ServerState } from './api.js';\n\nexport interface ServeOptions {\n /** Port to listen on. Default: 3000 */\n port: number;\n /** Host to bind. Default: 'localhost' (safe) */\n host: string;\n /** Documentation output directory */\n outputDir: string;\n /** Enable file watching for live reload. Default: true */\n watch: boolean;\n /** Reload mechanism. Default: 'ws' for localhost, 'sse' for 0.0.0.0 */\n reloadMode: 'ws' | 'sse' | 'poll' | 'none';\n /** Enable mutation API endpoints. Default: false */\n enableMutations: boolean;\n /** Token for mutation endpoints. Required if enableMutations=true */\n mutationToken?: string;\n /** Request timeout in ms. Default: 30000 */\n requestTimeout: number;\n}\n\nexport const DEFAULT_OPTIONS: Omit<ServeOptions, 'outputDir'> = {\n port: 3000,\n host: 'localhost',\n watch: true,\n reloadMode: 'ws',\n enableMutations: false,\n requestTimeout: 30000,\n};\n\nexport class OddDocsServer {\n private server: Server | null = null;\n private fileServer: FileServer;\n private liveReload: LiveReload | null = null;\n private apiHandler: ApiHandler;\n private options: ServeOptions;\n private state: ServerState;\n\n constructor(options: Partial<ServeOptions> & { outputDir: string }) {\n // Apply defaults\n this.options = {\n ...DEFAULT_OPTIONS,\n ...options,\n // Auto-switch to SSE for non-localhost binding (safer for K8s)\n reloadMode:\n options.reloadMode ??\n (options.host && options.host !== 'localhost' ? 'sse' : DEFAULT_OPTIONS.reloadMode),\n };\n\n // Environment overrides\n this.options.host = process.env.ODD_DOCS_HOST ?? this.options.host;\n this.options.port = parseInt(process.env.ODD_DOCS_PORT ?? String(this.options.port), 10);\n this.options.mutationToken = process.env.ODD_DOCS_MUTATION_TOKEN ?? this.options.mutationToken;\n\n this.state = {\n lastGenerateSuccess: true,\n lastGenerateTime: new Date().toISOString(),\n outputDirAccessible: true,\n introspectionConnected: false,\n };\n\n this.fileServer = new FileServer(this.options.outputDir);\n this.apiHandler = new ApiHandler(this.state, this.options);\n }\n\n async start(): Promise<void> {\n // Validate mutation token if mutations enabled\n if (this.options.enableMutations && !this.options.mutationToken) {\n throw new Error(\n 'Mutation token required when --enable-mutations is set. ' +\n 'Set ODD_DOCS_MUTATION_TOKEN or --mutation-token'\n );\n }\n\n this.server = createServer((req, res) => this.handleRequest(req, res));\n\n // Set timeout\n this.server.timeout = this.options.requestTimeout;\n\n // Start live reload if enabled\n if (this.options.watch && this.options.reloadMode !== 'none') {\n this.liveReload = new LiveReload({\n outputDir: this.options.outputDir,\n mode: this.options.reloadMode,\n server: this.server,\n });\n await this.liveReload.start();\n }\n\n return new Promise((resolve, reject) => {\n this.server!.listen(this.options.port, this.options.host, () => {\n console.log(\n `[odd-docs] Server started at http://${this.options.host}:${this.options.port}`\n );\n console.log(`[odd-docs] Serving: ${this.options.outputDir}`);\n if (this.liveReload) {\n console.log(`[odd-docs] Live reload: ${this.options.reloadMode}`);\n }\n resolve();\n });\n\n this.server!.on('error', reject);\n });\n }\n\n async stop(): Promise<void> {\n if (this.liveReload) {\n await this.liveReload.stop();\n }\n if (this.server) {\n return new Promise((resolve) => {\n this.server!.close(() => resolve());\n });\n }\n }\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url ?? '/';\n\n try {\n // API routes\n if (url.startsWith('/api/')) {\n await this.apiHandler.handle(req, res);\n return;\n }\n\n // Live reload endpoints\n if (this.liveReload && url === '/__livereload') {\n await this.liveReload.handleRequest(req, res);\n return;\n }\n\n // Static file serving\n await this.fileServer.serve(req, res);\n } catch (error) {\n console.error('[odd-docs] Request error:', error);\n res.statusCode = 500;\n res.end('Internal Server Error');\n }\n }\n\n updateState(updates: Partial<ServerState>): void {\n Object.assign(this.state, updates);\n }\n}\n","/**\n * File Server\n *\n * Static file serving with security protections.\n * - Path traversal protection via realpath + relative check\n * - MIME type detection\n * - ETag/304 support\n * - Max response size cap\n */\n\nimport { createReadStream, statSync } from 'node:fs';\nimport { realpath } from 'node:fs/promises';\nimport { join, extname, relative, isAbsolute } from 'node:path';\nimport { createHash } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\nconst MAX_RESPONSE_SIZE = 50 * 1024 * 1024; // 50MB\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.md': 'text/markdown; charset=utf-8',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n};\n\nexport class FileServer {\n private rootDir: string;\n private resolvedRoot: string | null = null;\n\n constructor(rootDir: string) {\n this.rootDir = rootDir;\n }\n\n async serve(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n let pathname = decodeURIComponent(url.pathname);\n\n // Default to index.html\n if (pathname === '/' || pathname.endsWith('/')) {\n pathname = join(pathname, 'index.html');\n }\n\n // Resolve and validate path\n const filePath = await this.resolvePath(pathname);\n if (!filePath) {\n res.statusCode = 403;\n res.end('Forbidden: Path traversal blocked');\n return;\n }\n\n // Check file exists and get stats\n let stats;\n try {\n stats = statSync(filePath);\n } catch {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n if (!stats.isFile()) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n // Check size limit\n if (stats.size > MAX_RESPONSE_SIZE) {\n res.statusCode = 413;\n res.end('File too large');\n return;\n }\n\n // ETag handling\n const etag = this.computeETag(filePath, stats.mtime, stats.size);\n const ifNoneMatch = req.headers['if-none-match'];\n if (ifNoneMatch === etag) {\n res.statusCode = 304;\n res.end();\n return;\n }\n\n // Set headers\n const ext = extname(filePath).toLowerCase();\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n\n res.setHeader('Content-Type', contentType);\n res.setHeader('Content-Length', stats.size);\n res.setHeader('ETag', etag);\n res.setHeader('Cache-Control', 'no-cache');\n\n // Stream file\n const stream = createReadStream(filePath);\n stream.pipe(res);\n stream.on('error', () => {\n res.statusCode = 500;\n res.end('Error reading file');\n });\n }\n\n /**\n * Resolve path with traversal protection\n */\n private async resolvePath(pathname: string): Promise<string | null> {\n // Ensure we have the real root path\n if (!this.resolvedRoot) {\n try {\n this.resolvedRoot = await realpath(this.rootDir);\n } catch {\n return null;\n }\n }\n\n // Construct target path\n const targetPath = join(this.rootDir, pathname);\n\n // Resolve to real path (follows symlinks, canonicalizes)\n let resolvedTarget: string;\n try {\n resolvedTarget = await realpath(targetPath);\n } catch {\n return null;\n }\n\n // Check containment: resolved path must be within root\n const rel = relative(this.resolvedRoot, resolvedTarget);\n if (rel.startsWith('..') || isAbsolute(rel)) {\n // Path escapes root directory\n console.warn(`[odd-docs] Path traversal blocked: ${pathname}`);\n return null;\n }\n\n return resolvedTarget;\n }\n\n private computeETag(path: string, mtime: Date, size: number): string {\n const hash = createHash('md5')\n .update(`${path}:${mtime.getTime()}:${size}`)\n .digest('hex')\n .slice(0, 16);\n return `\"${hash}\"`;\n }\n}\n","/**\n * Live Reload\n *\n * File watching and live reload for development.\n * Supports multiple mechanisms: WebSocket, SSE, Polling.\n * WS is dev-only default; SSE is K8s-safe.\n */\n\nimport { watch, type FSWatcher } from 'node:fs';\nimport type { Server, IncomingMessage, ServerResponse } from 'node:http';\n\nexport interface LiveReloadOptions {\n outputDir: string;\n mode: 'ws' | 'sse' | 'poll' | 'none';\n server: Server;\n pollInterval?: number; // for poll mode, ms\n}\n\ntype ReloadMode = 'ws' | 'sse' | 'poll' | 'none';\n\nexport class LiveReload {\n private options: LiveReloadOptions;\n private watcher: FSWatcher | null = null;\n private sseClients: Set<ServerResponse> = new Set();\n private lastChangeTime: number = Date.now();\n private debounceTimer: NodeJS.Timeout | null = null;\n\n constructor(options: LiveReloadOptions) {\n this.options = {\n pollInterval: 5000,\n ...options,\n };\n }\n\n async start(): Promise<void> {\n // Start file watcher with debounce\n const usePolling = process.env.CHOKIDAR_USEPOLLING === '1' || this.options.mode === 'poll';\n\n this.watcher = watch(\n this.options.outputDir,\n { recursive: true, persistent: true },\n (_eventType, filename) => {\n if (filename) {\n this.onFileChange(filename);\n }\n }\n );\n\n if (usePolling) {\n console.log('[odd-docs] Using poll-based file watching');\n }\n\n console.log(`[odd-docs] Live reload started (mode: ${this.options.mode})`);\n }\n\n async stop(): Promise<void> {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n }\n if (this.watcher) {\n this.watcher.close();\n }\n // Close SSE connections\n for (const client of this.sseClients) {\n client.end();\n }\n this.sseClients.clear();\n }\n\n private onFileChange(filename: string): void {\n // Debounce rapid changes\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n }\n this.debounceTimer = setTimeout(() => {\n this.lastChangeTime = Date.now();\n console.log(`[odd-docs] Change detected: ${filename}`);\n this.notifyClients();\n }, 100);\n }\n\n private notifyClients(): void {\n const message = JSON.stringify({ type: 'reload', time: this.lastChangeTime });\n\n // Notify SSE clients\n for (const client of this.sseClients) {\n client.write(`data: ${message}\\n\\n`);\n }\n }\n\n async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const mode = this.options.mode;\n\n if (mode === 'sse') {\n // SSE endpoint\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n res.setHeader('X-Accel-Buffering', 'no'); // For nginx\n\n res.write(': ping\\n\\n');\n this.sseClients.add(res);\n\n req.on('close', () => {\n this.sseClients.delete(res);\n });\n } else if (mode === 'poll') {\n // Poll endpoint - return last change time\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ lastChange: this.lastChangeTime }));\n } else {\n // Not supported in this mode\n res.statusCode = 404;\n res.end('Live reload not available in this mode');\n }\n }\n\n /**\n * Get client-side script for live reload\n */\n static getClientScript(mode: ReloadMode, pollInterval: number = 5000): string {\n if (mode === 'none') return '';\n\n if (mode === 'sse') {\n return `\n<script>\n(function() {\n const es = new EventSource('/__livereload');\n es.onmessage = function(e) {\n const data = JSON.parse(e.data);\n if (data.type === 'reload') {\n console.log('[odd-docs] Reloading...');\n location.reload();\n }\n };\n es.onerror = function() {\n console.log('[odd-docs] SSE connection lost, will retry...');\n };\n})();\n</script>`;\n }\n\n if (mode === 'poll') {\n return `\n<script>\n(function() {\n let lastChange = 0;\n setInterval(async () => {\n try {\n const res = await fetch('/__livereload');\n const data = await res.json();\n if (lastChange && data.lastChange > lastChange) {\n console.log('[odd-docs] Reloading...');\n location.reload();\n }\n lastChange = data.lastChange;\n } catch (e) {}\n }, ${pollInterval});\n})();\n</script>`;\n }\n\n // WebSocket (ws mode) - requires separate ws server\n return `\n<script>\n(function() {\n const ws = new WebSocket('ws://' + location.host + '/__ws');\n ws.onmessage = function(e) {\n const data = JSON.parse(e.data);\n if (data.type === 'reload') {\n console.log('[odd-docs] Reloading...');\n location.reload();\n }\n };\n ws.onclose = function() {\n console.log('[odd-docs] WebSocket closed, will retry in 3s...');\n setTimeout(() => location.reload(), 3000);\n };\n})();\n</script>`;\n }\n}\n","/**\n * API Handler\n *\n * REST API endpoints for programmatic access.\n * Implements K8s-compatible health semantics.\n * Mutation endpoints require explicit opt-in + token.\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { ServeOptions } from './index.js';\n\nconst MAX_IR_SIZE = 10 * 1024 * 1024; // 10MB\n\nexport interface ServerState {\n lastGenerateSuccess: boolean;\n lastGenerateTime: string;\n outputDirAccessible: boolean;\n introspectionConnected: boolean;\n lastIntrospectionTime?: string;\n}\n\nexport class ApiHandler {\n private state: ServerState;\n private options: ServeOptions;\n\n constructor(state: ServerState, options: ServeOptions) {\n this.state = state;\n this.options = options;\n }\n\n async handle(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const path = url.pathname;\n const method = req.method ?? 'GET';\n\n // Route to handlers\n switch (path) {\n case '/api/health':\n return this.handleHealth(res);\n case '/api/ready':\n return this.handleReady(res);\n case '/api/introspection':\n return this.handleIntrospection(res);\n case '/api/docs':\n return this.handleDocs(res);\n case '/api/ir':\n return this.handleIR(res);\n case '/api/capabilities':\n return this.handleCapabilities(res);\n case '/api/regenerate':\n if (method === 'POST') {\n return this.handleRegenerate(req, res);\n }\n return this.methodNotAllowed(res);\n default:\n return this.notFound(res);\n }\n }\n\n /**\n * GET /api/health - Liveness probe\n * Returns 200 if process is running\n */\n private handleHealth(res: ServerResponse): void {\n this.json(res, {\n status: 'ok',\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * GET /api/ready - Readiness probe\n * Returns 200 if last generate succeeded and output is accessible\n */\n private handleReady(res: ServerResponse): void {\n const ready = this.state.lastGenerateSuccess && this.state.outputDirAccessible;\n\n if (!ready) {\n res.statusCode = 503;\n }\n\n this.json(res, {\n ready,\n lastGenerateSuccess: this.state.lastGenerateSuccess,\n lastGenerateTime: this.state.lastGenerateTime,\n outputDirAccessible: this.state.outputDirAccessible,\n });\n }\n\n /**\n * GET /api/introspection - Introspection status\n */\n private handleIntrospection(res: ServerResponse): void {\n this.json(res, {\n connected: this.state.introspectionConnected,\n lastPollTime: this.state.lastIntrospectionTime ?? null,\n });\n }\n\n /**\n * GET /api/docs - List documentation sections\n */\n private handleDocs(res: ServerResponse): void {\n // TODO: Implement actual doc listing\n this.json(res, {\n sections: [],\n message: 'Not implemented yet',\n });\n }\n\n /**\n * GET /api/ir - Full IR dump (capped at 10MB)\n */\n private handleIR(res: ServerResponse): void {\n // TODO: Implement actual IR retrieval\n const ir = { tools: [], prompts: [], resources: [] };\n const irJson = JSON.stringify(ir);\n\n if (irJson.length > MAX_IR_SIZE) {\n this.json(res, {\n truncated: true,\n message: `IR exceeds ${MAX_IR_SIZE / 1024 / 1024}MB limit`,\n partial: null,\n });\n return;\n }\n\n res.setHeader('Content-Type', 'application/json');\n res.end(irJson);\n }\n\n /**\n * GET /api/capabilities - Tool capabilities summary\n */\n private handleCapabilities(res: ServerResponse): void {\n this.json(res, {\n serve: {\n host: this.options.host,\n port: this.options.port,\n reloadMode: this.options.reloadMode,\n mutationsEnabled: this.options.enableMutations,\n },\n });\n }\n\n /**\n * POST /api/regenerate - Trigger manual regeneration\n * Requires --enable-mutations and valid token\n */\n private handleRegenerate(req: IncomingMessage, res: ServerResponse): void {\n // Check if mutations are enabled\n if (!this.options.enableMutations) {\n res.statusCode = 403;\n this.json(res, {\n error: 'Mutations disabled',\n message: 'Start server with --enable-mutations to use this endpoint',\n });\n return;\n }\n\n // Validate token\n const token = req.headers['x-mutation-token'];\n if (token !== this.options.mutationToken) {\n res.statusCode = 401;\n this.json(res, {\n error: 'Unauthorized',\n message: 'Invalid or missing X-Mutation-Token header',\n });\n return;\n }\n\n // TODO: Trigger actual regeneration\n this.json(res, {\n status: 'queued',\n message: 'Regeneration triggered',\n timestamp: new Date().toISOString(),\n });\n }\n\n private json(res: ServerResponse, data: unknown): void {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(data, null, 2));\n }\n\n private notFound(res: ServerResponse): void {\n res.statusCode = 404;\n this.json(res, { error: 'Not Found' });\n }\n\n private methodNotAllowed(res: ServerResponse): void {\n res.statusCode = 405;\n this.json(res, { error: 'Method Not Allowed' });\n }\n}\n"],"mappings":";AAAA,SAAS,eAAe;AACxB,SAAS,qBAAqB;;;ACD9B,SAAS,WAAW,aAAa;AACjC,SAAS,QAAAA,OAAM,eAAe;;;ACD9B,SAAS,gBAAgB;AACzB,SAAS,YAAY;AAoCrB,eAAsB,cAAc,UAAgD;AAClF,QAAM,eAAe,KAAK,UAAU,eAAe;AAEnD,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS,cAAc,OAAO;AAAA,EAChD,QAAQ;AACN,UAAM,IAAI,MAAM,uBAAuB,YAAY,EAAE;AAAA,EACvD;AAEA,MAAI;AACJ,MAAI;AACF,eAAW,KAAK,MAAM,OAAO;AAAA,EAC/B,QAAQ;AACN,UAAM,IAAI,MAAM,6BAA6B,YAAY,EAAE;AAAA,EAC7D;AAGA,MAAI,CAAC,SAAS,SAAS;AACrB,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACA,MAAI,CAAC,SAAS,SAAS;AACrB,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAGA,QAAM,eAA6B,CAAC;AACpC,MAAI,SAAS,cAAc;AACzB,eAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,SAAS,YAAY,GAAG;AAClE,UAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,SAAS,GAAG;AAC9C,qBAAa,KAAK,EAAE,MAAM,QAAQ,YAAY,WAAW,CAAC;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAA8B;AAAA,IAClC,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,IAAI,SAAS;AAAA,MACb,SAAS,SAAS;AAAA,MAClB,aAAa,SAAS;AAAA,IACxB;AAAA,IACA,QAAQ;AAAA,MACN,QAAQ,SAAS;AAAA,MACjB,YAAY;AAAA,IACd;AAAA,EACF;AAGA,MAAI,aAAa,SAAS,KAAK,SAAS,cAAc,SAAS,iBAAiB;AAC9E,WAAO,cAAc;AAAA,MACnB,cAAc,aAAa,SAAS,IAAI,eAAe;AAAA,MACvD,WAAW,SAAS;AAAA,MACpB,gBAAgB,SAAS,kBACrB;AAAA,QACE,UAAU,SAAS,gBAAgB;AAAA,QACnC,UAAU,SAAS,gBAAgB;AAAA,MACrC,IACA;AAAA,IACN;AAAA,EACF;AAGA,MAAI,SAAS,aAAa;AACxB,WAAO,YAAY;AAAA,MACjB,SAAS,SAAS;AAAA,MAClB,aAAa;AAAA,QACX,cAAc,SAAS,YAAY;AAAA,QACnC,YAAY,SAAS,YAAY;AAAA,QACjC,cAAc,SAAS,YAAY;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AChHA,SAAS,kBAAkB;;;ACqBpB,SAAS,YAAY,QAA0D;AACpF,MAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,QAAM,aAAa;AACnB,QAAM,aAA0B,CAAC;AACjC,QAAM,WAAW,IAAI,IAAI,WAAW,YAAY,CAAC,CAAC;AAElD,MAAI,WAAW,YAAY;AACzB,eAAW,CAAC,MAAM,UAAU,KAAK,OAAO,QAAQ,WAAW,UAAU,GAAG;AACtE,iBAAW,KAAK,cAAc,MAAM,YAAY,SAAS,IAAI,IAAI,CAAC,CAAC;AAAA,IACrE;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,MAAc,QAAoB,YAAgC;AACvF,QAAM,QAAmB;AAAA,IACvB;AAAA,IACA,MAAM,YAAY,MAAM;AAAA,IACxB,UAAU;AAAA,EACZ;AAEA,MAAI,OAAO,aAAa;AACtB,UAAM,cAAc,OAAO;AAAA,EAC7B;AAEA,MAAI,OAAO,YAAY,QAAW;AAChC,UAAM,UAAU,OAAO;AAAA,EACzB;AAEA,MAAI,OAAO,MAAM;AACf,UAAM,OAAO,OAAO;AAAA,EACtB;AAGA,QAAM,cAAc,iBAAiB,MAAM;AAC3C,MAAI,aAAa;AACf,UAAM,cAAc;AAAA,EACtB;AAEA,SAAO;AACT;AAEA,SAAS,YAAY,QAA4B;AAC/C,MAAI,OAAO,MAAM;AAEf,UAAM,WAAW,OAAO,KAAK,MAAM,GAAG;AACtC,WAAO,SAAS,SAAS,SAAS,CAAC;AAAA,EACrC;AAEA,MAAI,OAAO,MAAM;AACf,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,SAAS,WAAW,OAAO,OAAO;AAC3C,WAAO,GAAG,YAAY,OAAO,KAAK,CAAC;AAAA,EACrC;AAEA,SAAO,OAAO,QAAQ;AACxB;AAEA,SAAS,iBAAiB,QAAwC;AAChE,QAAM,QAAkB,CAAC;AAEzB,MAAI,OAAO,YAAY,QAAW;AAChC,UAAM,KAAK,QAAQ,OAAO,OAAO,EAAE;AAAA,EACrC;AACA,MAAI,OAAO,YAAY,QAAW;AAChC,UAAM,KAAK,QAAQ,OAAO,OAAO,EAAE;AAAA,EACrC;AACA,MAAI,OAAO,cAAc,QAAW;AAClC,UAAM,KAAK,cAAc,OAAO,SAAS,EAAE;AAAA,EAC7C;AACA,MAAI,OAAO,cAAc,QAAW;AAClC,UAAM,KAAK,cAAc,OAAO,SAAS,EAAE;AAAA,EAC7C;AACA,MAAI,OAAO,SAAS;AAClB,UAAM,KAAK,YAAY,OAAO,OAAO,EAAE;AAAA,EACzC;AAEA,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAC/C;AAKO,SAAS,oBAAoB,SAAuC;AACzE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY,YAAY,QAAQ,MAAM;AAAA,EACxC;AACF;;;ADzGO,SAAS,WAAW,UAAsC;AAC/D,QAAM,iBAAiB,oBAAoB,SAAS,MAAM;AAE1D,QAAM,KAAY;AAAA,IAChB,SAAS;AAAA,IACT,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,gBAAgB;AAAA;AAAA,IAChB,QAAQ,SAAS;AAAA,IACjB,QAAQ;AAAA,IACR,aAAa,SAAS;AAAA,IACtB,WAAW,SAAS;AAAA,IACpB,YAAY;AAAA,MACV,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,EACF;AAGA,KAAG,iBAAiB,sBAAsB,EAAE;AAE5C,SAAO;AACT;AAKO,SAAS,sBAAsB,IAA2D;AAC/F,QAAM,YAAY,KAAK,UAAU;AAAA,IAC/B,QAAQ,GAAG;AAAA,IACX,QAAQ,GAAG;AAAA,IACX,aAAa,GAAG;AAAA,IAChB,WAAW,GAAG;AAAA,EAChB,CAAC;AAED,QAAM,OAAO,WAAW,QAAQ,EAAE,OAAO,SAAS,EAAE,OAAO,KAAK;AAChE,SAAO,UAAU,IAAI;AACvB;;;AEvCO,SAAS,eAAe,IAAmB;AAChD,QAAM,QAAkB,CAAC;AAGzB,QAAM,KAAK,KAAK,GAAG,OAAO,EAAE,EAAE;AAC9B,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,gBAAgB,GAAG,OAAO,OAAO,IAAI;AAChD,QAAM,KAAK,aAAa,GAAG,OAAO,IAAI,IAAI;AAC1C,MAAI,GAAG,OAAO,aAAa;AACzB,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,GAAG,OAAO,WAAW;AAAA,EAClC;AACA,QAAM,KAAK,EAAE;AAGb,MAAI,GAAG,UAAU;AACf,UAAM,KAAK,aAAa;AACxB,UAAM,KAAK,EAAE;AACb,QAAI,GAAG,SAAS,QAAQ;AACtB,YAAM,KAAK,eAAe,GAAG,SAAS,MAAM,EAAE;AAC9C,YAAM,KAAK,EAAE;AAAA,IACf;AACA,QAAI,GAAG,SAAS,UAAU,QAAQ;AAChC,YAAM,KAAK,eAAe;AAC1B,YAAM,KAAK,EAAE;AACb,iBAAW,WAAW,GAAG,SAAS,UAAU;AAC1C,cAAM,KAAK,KAAK,OAAO,EAAE;AAAA,MAC3B;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AACA,QAAI,GAAG,SAAS,aAAa,QAAQ;AACnC,YAAM,KAAK,kBAAkB;AAC7B,YAAM,KAAK,EAAE;AACb,iBAAW,UAAU,GAAG,SAAS,aAAa;AAC5C,cAAM;AAAA,UACJ,OAAO,OAAO,IAAI,OAAO,OAAO,WAAW,IAAI,gBAAgB,OAAO,UAAU,CAAC;AAAA,QACnF;AAAA,MACF;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AAGA,MAAI,GAAG,QAAQ,YAAY,QAAQ;AACjC,UAAM,KAAK,WAAW;AACtB,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,gBAAgB,GAAG,OAAO,UAAU,CAAC;AAChD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,qBAAqB,GAAG,OAAO,UAAU,CAAC;AACrD,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,MAAI,GAAG,SAAS,YAAY,QAAQ;AAClC,UAAM,KAAK,YAAY;AACvB,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,gBAAgB,GAAG,QAAQ,UAAU,CAAC;AACjD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,qBAAqB,GAAG,QAAQ,UAAU,CAAC;AACtD,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,MAAI,GAAG,aAAa;AAClB,UAAM,KAAK,gBAAgB;AAC3B,UAAM,KAAK,EAAE;AACb,QAAI,GAAG,YAAY,cAAc,QAAQ;AACvC,YAAM,KAAK,kBAAkB;AAC7B,YAAM,KAAK,EAAE;AACb,iBAAW,OAAO,GAAG,YAAY,cAAc;AAC7C,cAAM,SAAS,IAAI,QAAQ,KAAK,IAAI,KAAK;AACzC,cAAM,KAAK,OAAO,IAAI,IAAI,OAAO,MAAM,IAAI,gBAAgB,IAAI,UAAU,CAAC,EAAE;AAAA,MAC9E;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AACA,QAAI,GAAG,YAAY,WAAW;AAC5B,YAAM,KAAK,gBAAgB,GAAG,YAAY,SAAS,IAAI;AACvD,YAAM,KAAK,EAAE;AAAA,IACf;AACA,QAAI,GAAG,YAAY,gBAAgB;AACjC,YAAM,KAAK,qBAAqB;AAChC,YAAM,KAAK,EAAE;AACb,UAAI,GAAG,YAAY,eAAe,UAAU;AAC1C,cAAM,KAAK,aAAa,GAAG,YAAY,eAAe,QAAQ,KAAK;AAAA,MACrE;AACA,UAAI,GAAG,YAAY,eAAe,UAAU;AAC1C,cAAM,KAAK,UAAU,GAAG,YAAY,eAAe,QAAQ,QAAQ;AAAA,MACrE;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AAGA,MAAI,GAAG,QAAQ,QAAQ;AACrB,UAAM,KAAK,WAAW;AACtB,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,mCAAmC;AAC9C,UAAM,KAAK,mCAAmC;AAC9C,eAAW,OAAO,GAAG,QAAQ;AAC3B,YAAM,KAAK,OAAO,IAAI,IAAI,QAAQ,IAAI,eAAe,EAAE,MAAM,IAAI,YAAY,EAAE,IAAI;AAAA,IACrF;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,MAAI,GAAG,WAAW,aAAa;AAC7B,UAAM,KAAK,cAAc;AACzB,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,cAAc;AACzB,UAAM,KAAK,mCAAmC,GAAG,UAAU,YAAY,YAAY,GAAG;AACtF,UAAM,KAAK,kBAAkB,GAAG,UAAU,YAAY,UAAU,EAAE;AAClE,QAAI,GAAG,UAAU,YAAY,cAAc;AACzC,YAAM,KAAK,sBAAsB,GAAG,UAAU,YAAY,YAAY,EAAE;AAAA,IAC1E;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,MAAI,GAAG,WAAW,UAAU,QAAQ;AAClC,UAAM,KAAK,aAAa;AACxB,UAAM,KAAK,EAAE;AACb,eAAW,WAAW,GAAG,UAAU,UAAU;AAC3C,UAAI,QAAQ,OAAO;AACjB,cAAM,KAAK,OAAO,QAAQ,KAAK,EAAE;AACjC,cAAM,KAAK,EAAE;AAAA,MACf;AACA,UAAI,QAAQ,aAAa;AACvB,cAAM,KAAK,QAAQ,WAAW;AAC9B,cAAM,KAAK,EAAE;AAAA,MACf;AACA,UAAI,QAAQ,OAAO;AACjB,cAAM,KAAK,YAAY;AACvB,cAAM,KAAK,SAAS;AACpB,cAAM,KAAK,KAAK,UAAU,QAAQ,OAAO,MAAM,CAAC,CAAC;AACjD,cAAM,KAAK,KAAK;AAChB,cAAM,KAAK,EAAE;AAAA,MACf;AACA,UAAI,QAAQ,QAAQ;AAClB,cAAM,KAAK,aAAa;AACxB,cAAM,KAAK,SAAS;AACpB,cAAM,KAAK,KAAK,UAAU,QAAQ,QAAQ,MAAM,CAAC,CAAC;AAClD,cAAM,KAAK,KAAK;AAChB,cAAM,KAAK,EAAE;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAGA,MAAI,GAAG,WAAW,OAAO,QAAQ;AAC/B,UAAM,KAAK,UAAU;AACrB,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,kBAAkB;AAC7B,UAAM,KAAK,EAAE;AACb,eAAW,QAAQ,GAAG,UAAU,OAAO;AACrC,YAAM,KAAK,IAAI;AACf,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AAGA,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,iBAAiB,GAAG,WAAW,KAAK;AAC/C,QAAM,KAAK,uBAAuB,GAAG,cAAc,KAAK;AAExD,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,qBAAqB,QAA6B;AACzD,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,oDAAoD;AAC/D,QAAM,KAAK,oDAAoD;AAE/D,aAAW,SAAS,QAAQ;AAC1B,UAAM,WAAW,MAAM,WAAW,WAAM;AACxC,UAAM,aAAa,MAAM,YAAY,SAAY,KAAK,KAAK,UAAU,MAAM,OAAO,CAAC,OAAO;AAC1F,UAAM,OAAO,MAAM,eAAe;AAClC,UAAM,KAAK,OAAO,MAAM,IAAI,UAAU,MAAM,IAAI,QAAQ,QAAQ,MAAM,UAAU,MAAM,IAAI,IAAI;AAAA,EAChG;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,gBAAgB,QAAmC;AAC1D,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,SAA2C;AAAA,IAC/C,eAAe;AAAA,IACf,UAAU;AAAA,IACV,SAAS;AAAA,IACT,WAAW;AAAA,EACb;AACA,SAAO,OAAO,MAAM,KAAK;AAC3B;;;ACrMA,SAAS,cAAc;AAOhB,SAAS,WAAW,IAAmB;AAE5C,QAAM,WAAW,eAAe,EAAE;AAClC,QAAM,cAAc,OAAO,MAAM,QAAQ;AAEzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,sCAK6B,WAAW,GAAG,OAAO,eAAe,qBAAqB,GAAG,OAAO,EAAE,EAAE,CAAC;AAAA,WACnG,WAAW,GAAG,OAAO,EAAE,CAAC;AAAA;AAAA,EAEjC,eAAe,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDAO8B,WAAW,GAAG,OAAO,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,EAItE,WAAW;AAAA;AAAA;AAAA;AAAA,2FAI8E,GAAG,WAAW;AAAA;AAAA;AAAA,gBAGzF,GAAG,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/B,eAAe,CAAC;AAAA;AAAA;AAAA;AAIlB;AAkDA,SAAS,WAAW,KAAqB;AACvC,SAAO,IACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AAEA,SAAS,iBAAyB;AAChC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsOT;AAEA,SAAS,iBAAyB;AAChC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBT;;;AL/VA,eAAsB,SAAS,UAAkB,UAA2B,CAAC,GAAkB;AAC7F,QAAM,UAAU,QAAQ,QAAQ;AAChC,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,YAAY,QAAQ,SAAS,QAAQ,QAAQ,MAAM,IAAIC,MAAK,SAAS,QAAQ,WAAW;AAE9F,UAAQ,IAAI,iCAAiC,OAAO,EAAE;AAGtD,QAAM,iBAAiB,MAAM,cAAc,OAAO;AAClD,UAAQ,IAAI,aAAa,eAAe,OAAO,EAAE,IAAI,eAAe,OAAO,OAAO,EAAE;AAGpF,QAAM,KAAK,WAAW,cAAc;AACpC,UAAQ,IAAI,sBAAsB,GAAG,cAAc,EAAE;AAGrD,QAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAG1C,MAAI,WAAW,QAAQ,WAAW,QAAQ;AACxC,UAAM,WAAW,eAAe,EAAE;AAClC,UAAM,SAASA,MAAK,WAAW,GAAG,GAAG,OAAO,EAAE,KAAK;AACnD,UAAM,UAAU,QAAQ,UAAU,OAAO;AACzC,YAAQ,IAAI,sBAAiB,MAAM,EAAE;AAAA,EACvC;AAEA,MAAI,WAAW,UAAU,WAAW,QAAQ;AAC1C,UAAM,OAAO,WAAW,EAAE;AAC1B,UAAM,WAAWA,MAAK,WAAW,GAAG,GAAG,OAAO,EAAE,OAAO;AACvD,UAAM,UAAU,UAAU,MAAM,OAAO;AACvC,YAAQ,IAAI,kBAAa,QAAQ,EAAE;AAAA,EACrC;AAGA,QAAM,SAASA,MAAK,WAAW,GAAG,GAAG,OAAO,EAAE,UAAU;AACxD,QAAM,UAAU,QAAQ,KAAK,UAAU,IAAI,MAAM,CAAC,GAAG,OAAO;AAC5D,UAAQ,IAAI,oBAAe,MAAM,EAAE;AAEnC,UAAQ,IAAI,OAAO;AACrB;;;AMpDA,SAAS,WAAAC,gBAAe;;;ACKjB,IAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQO,IAAM,4BAA4B,CAAC,WAAW,QAAQ,cAAc,SAAS,QAAQ;AAErF,SAAS,kBAAkB,YAAmD;AACnF,SAAO,mBAAmB,SAAS,UAA6B;AAClE;AAEO,SAAS,kBAAkB,YAA6B;AAC7D,SAAO,0BAA0B;AAAA,IAAK,CAAC,YACrC,WAAW,YAAY,EAAE,SAAS,QAAQ,YAAY,CAAC;AAAA,EACzD;AACF;;;ACNO,SAAS,cAAc,IAAW,UAA2B,CAAC,GAAqB;AACxF,QAAM,SAA4B,CAAC;AAGnC,MAAI,CAAC,GAAG,OAAO,IAAI;AACjB,WAAO,KAAK;AAAA,MACV,UAAU;AAAA,MACV,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,GAAG,OAAO,SAAS;AACtB,WAAO,KAAK;AAAA,MACV,UAAU;AAAA,MACV,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,GAAG,QAAQ,UAAU,CAAC,GAAG,QAAQ,YAAY,QAAQ;AACxD,WAAO,KAAK;AAAA,MACV,UAAU;AAAA,MACV,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAGA,MAAI,GAAG,aAAa,cAAc;AAChC,eAAW,OAAO,GAAG,YAAY,cAAc;AAC7C,UAAI,CAAC,kBAAkB,IAAI,IAAI,GAAG;AAChC,cAAM,WAAW,kBAAkB,IAAI,IAAI;AAC3C,eAAO,KAAK;AAAA,UACV,UAAU,QAAQ,UAAU,WAAW,UAAU;AAAA,UACjD,MAAM;AAAA,UACN,SAAS,uBAAuB,IAAI,IAAI,GAAG,WAAW,wBAAwB,EAAE;AAAA,UAChF,MAAM,4BAA4B,IAAI,IAAI;AAAA,UAC1C,YAAY,IAAI;AAAA,QAClB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,SAAO,KAAK,GAAG,8BAA8B,EAAE,CAAC;AAEhD,QAAM,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,aAAa,OAAO;AAE3D,SAAO;AAAA,IACL,OAAO,CAAC;AAAA,IACR;AAAA,EACF;AACF;AAKA,SAAS,8BAA8B,IAA8B;AACnE,QAAM,SAA4B,CAAC;AAGnC,MAAI,GAAG,WAAW,SAAS,GAAG,QAAQ,YAAY;AAChD,UAAM,eAAe,IAAI,IAAI,GAAG,OAAO,WAAW,IAAI,CAAC,MAAM,EAAE,KAAK,YAAY,CAAC,CAAC;AAElF,eAAW,QAAQ,GAAG,UAAU,OAAO;AAErC,YAAM,gBAAgB,KAAK,MAAM,2CAA2C,KAAK,CAAC;AAClF,YAAM,mBAAmB,KAAK,MAAM,uCAAuC,KAAK,CAAC;AAEjF,iBAAW,SAAS,CAAC,GAAG,eAAe,GAAG,gBAAgB,GAAG;AAC3D,cAAM,YAAY,MAAM,QAAQ,2BAA2B,IAAI,EAAE,YAAY;AAC7E,YAAI,aAAa,CAAC,aAAa,IAAI,SAAS,KAAK,cAAc,aAAa;AAC1E,iBAAO,KAAK;AAAA,YACV,UAAU;AAAA,YACV,MAAM;AAAA,YACN,SAAS,mCAAmC,SAAS;AAAA,YACrD,MAAM;AAAA,YACN,YAAY;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,GAAG,WAAW,YAAY,GAAG,QAAQ,YAAY;AACnD,UAAM,eAAe,IAAI,IAAI,GAAG,OAAO,WAAW,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAEpE,eAAW,WAAW,GAAG,UAAU,UAAU;AAC3C,UAAI,QAAQ,SAAS,OAAO,QAAQ,UAAU,UAAU;AACtD,mBAAW,OAAO,OAAO,KAAK,QAAQ,KAAgC,GAAG;AACvE,cAAI,CAAC,aAAa,IAAI,GAAG,GAAG;AAC1B,mBAAO,KAAK;AAAA,cACV,UAAU;AAAA,cACV,MAAM;AAAA,cACN,SAAS,2BAA2B,GAAG;AAAA,cACvC,MAAM,sBAAsB,QAAQ,SAAS,SAAS;AAAA,cACtD,YAAY;AAAA,YACd,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,GAAG,UAAU,eAAe,GAAG,aAAa,cAAc;AAC5D,UAAM,WAAW,IAAI,IAAI,GAAG,YAAY,aAAa,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAEvE,eAAW,UAAU,GAAG,SAAS,aAAa;AAE5C,YAAM,cAAc,0BAA0B,OAAO,IAAI;AACzD,UAAI,eAAe,CAAC,SAAS,IAAI,WAAW,GAAG;AAC7C,eAAO,KAAK;AAAA,UACV,UAAU;AAAA,UACV,MAAM;AAAA,UACN,SAAS,gBAAgB,OAAO,IAAI,0BAA0B,WAAW;AAAA,UACzE,MAAM,wBAAwB,OAAO,IAAI;AAAA,UACzC,YAAY,OAAO;AAAA,QACrB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,0BAA0B,YAAmC;AACpE,QAAM,UAAkC;AAAA,IACtC,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,OAAO;AAAA,EACT;AACA,SAAO,QAAQ,UAAU,KAAK;AAChC;AAKO,SAAS,uBAAuB,QAA0B,UAA0B;AACzF,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,eAAe,QAAQ,EAAE;AACpC,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,OAAO;AAChB,UAAM,KAAK,0BAAqB;AAAA,EAClC,OAAO;AACL,UAAM,KAAK,0BAAqB;AAAA,EAClC;AACA,QAAM,KAAK,EAAE;AAEb,QAAM,SAAS,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO;AACjE,QAAM,WAAW,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS;AAErE,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,KAAK,WAAW,OAAO,MAAM,IAAI;AACvC,eAAW,SAAS,QAAQ;AAC1B,YAAM,KAAK,aAAQ,MAAM,IAAI,KAAK,MAAM,OAAO,EAAE;AACjD,UAAI,MAAM,MAAM;AACd,cAAM,KAAK,UAAU,MAAM,IAAI,EAAE;AAAA,MACnC;AAAA,IACF;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,KAAK,aAAa,SAAS,MAAM,IAAI;AAC3C,eAAW,SAAS,UAAU;AAC5B,YAAM,KAAK,aAAQ,MAAM,IAAI,KAAK,MAAM,OAAO,EAAE;AACjD,UAAI,MAAM,MAAM;AACd,cAAM,KAAK,UAAU,MAAM,IAAI,EAAE;AAAA,MACnC;AAAA,IACF;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;AF1MA,eAAsB,SAAS,UAAkB,UAA2B,CAAC,GAAqB;AAChG,QAAM,UAAUC,SAAQ,QAAQ;AAEhC,UAAQ,IAAI,eAAe,OAAO,EAAE;AACpC,UAAQ,IAAI,SAAS,QAAQ,SAAS,WAAW,QAAQ,EAAE;AAC3D,UAAQ,IAAI,EAAE;AAEd,MAAI;AAEF,UAAM,iBAAiB,MAAM,cAAc,OAAO;AAGlD,UAAM,KAAK,WAAW,cAAc;AAGpC,UAAM,SAAS,cAAc,IAAI,EAAE,QAAQ,QAAQ,OAAO,CAAC;AAG3D,YAAQ,IAAI,uBAAuB,QAAQ,OAAO,CAAC;AAEnD,WAAO,OAAO;AAAA,EAChB,SAAS,OAAO;AACd,YAAQ,MAAM,0BAAqB;AACnC,YAAQ,MAAM,EAAE;AAChB,YAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,KAAK,EAAE;AACxE,WAAO;AAAA,EACT;AACF;;;AG1BA,SAAS,kBAAkB;AAC3B,SAAS,QAAAC,OAAM,WAAAC,gBAAe;;;ACJ9B,SAAS,oBAA4E;;;ACGrF,SAAS,kBAAkB,gBAAgB;AAC3C,SAAS,gBAAgB;AACzB,SAAS,QAAAC,OAAM,SAAS,UAAU,kBAAkB;AACpD,SAAS,cAAAC,mBAAkB;AAG3B,IAAM,oBAAoB,KAAK,OAAO;AAEtC,IAAM,aAAqC;AAAA,EACzC,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AACV;AAEO,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA,eAA8B;AAAA,EAEtC,YAAY,SAAiB;AAC3B,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,MAAM,KAAsB,KAAoC;AACpE,UAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI,QAAQ,IAAI,EAAE;AAChE,QAAI,WAAW,mBAAmB,IAAI,QAAQ;AAG9C,QAAI,aAAa,OAAO,SAAS,SAAS,GAAG,GAAG;AAC9C,iBAAWD,MAAK,UAAU,YAAY;AAAA,IACxC;AAGA,UAAM,WAAW,MAAM,KAAK,YAAY,QAAQ;AAChD,QAAI,CAAC,UAAU;AACb,UAAI,aAAa;AACjB,UAAI,IAAI,mCAAmC;AAC3C;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,cAAQ,SAAS,QAAQ;AAAA,IAC3B,QAAQ;AACN,UAAI,aAAa;AACjB,UAAI,IAAI,WAAW;AACnB;AAAA,IACF;AAEA,QAAI,CAAC,MAAM,OAAO,GAAG;AACnB,UAAI,aAAa;AACjB,UAAI,IAAI,WAAW;AACnB;AAAA,IACF;AAGA,QAAI,MAAM,OAAO,mBAAmB;AAClC,UAAI,aAAa;AACjB,UAAI,IAAI,gBAAgB;AACxB;AAAA,IACF;AAGA,UAAM,OAAO,KAAK,YAAY,UAAU,MAAM,OAAO,MAAM,IAAI;AAC/D,UAAM,cAAc,IAAI,QAAQ,eAAe;AAC/C,QAAI,gBAAgB,MAAM;AACxB,UAAI,aAAa;AACjB,UAAI,IAAI;AACR;AAAA,IACF;AAGA,UAAM,MAAM,QAAQ,QAAQ,EAAE,YAAY;AAC1C,UAAM,cAAc,WAAW,GAAG,KAAK;AAEvC,QAAI,UAAU,gBAAgB,WAAW;AACzC,QAAI,UAAU,kBAAkB,MAAM,IAAI;AAC1C,QAAI,UAAU,QAAQ,IAAI;AAC1B,QAAI,UAAU,iBAAiB,UAAU;AAGzC,UAAM,SAAS,iBAAiB,QAAQ;AACxC,WAAO,KAAK,GAAG;AACf,WAAO,GAAG,SAAS,MAAM;AACvB,UAAI,aAAa;AACjB,UAAI,IAAI,oBAAoB;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YAAY,UAA0C;AAElE,QAAI,CAAC,KAAK,cAAc;AACtB,UAAI;AACF,aAAK,eAAe,MAAM,SAAS,KAAK,OAAO;AAAA,MACjD,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,aAAaA,MAAK,KAAK,SAAS,QAAQ;AAG9C,QAAI;AACJ,QAAI;AACF,uBAAiB,MAAM,SAAS,UAAU;AAAA,IAC5C,QAAQ;AACN,aAAO;AAAA,IACT;AAGA,UAAM,MAAM,SAAS,KAAK,cAAc,cAAc;AACtD,QAAI,IAAI,WAAW,IAAI,KAAK,WAAW,GAAG,GAAG;AAE3C,cAAQ,KAAK,sCAAsC,QAAQ,EAAE;AAC7D,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,YAAY,MAAc,OAAa,MAAsB;AACnE,UAAM,OAAOC,YAAW,KAAK,EAC1B,OAAO,GAAG,IAAI,IAAI,MAAM,QAAQ,CAAC,IAAI,IAAI,EAAE,EAC3C,OAAO,KAAK,EACZ,MAAM,GAAG,EAAE;AACd,WAAO,IAAI,IAAI;AAAA,EACjB;AACF;;;AChJA,SAAS,aAA6B;AAY/B,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA,UAA4B;AAAA,EAC5B,aAAkC,oBAAI,IAAI;AAAA,EAC1C,iBAAyB,KAAK,IAAI;AAAA,EAClC,gBAAuC;AAAA,EAE/C,YAAY,SAA4B;AACtC,SAAK,UAAU;AAAA,MACb,cAAc;AAAA,MACd,GAAG;AAAA,IACL;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAE3B,UAAM,aAAa,QAAQ,IAAI,wBAAwB,OAAO,KAAK,QAAQ,SAAS;AAEpF,SAAK,UAAU;AAAA,MACb,KAAK,QAAQ;AAAA,MACb,EAAE,WAAW,MAAM,YAAY,KAAK;AAAA,MACpC,CAAC,YAAY,aAAa;AACxB,YAAI,UAAU;AACZ,eAAK,aAAa,QAAQ;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAEA,QAAI,YAAY;AACd,cAAQ,IAAI,2CAA2C;AAAA,IACzD;AAEA,YAAQ,IAAI,yCAAyC,KAAK,QAAQ,IAAI,GAAG;AAAA,EAC3E;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,eAAe;AACtB,mBAAa,KAAK,aAAa;AAAA,IACjC;AACA,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,MAAM;AAAA,IACrB;AAEA,eAAW,UAAU,KAAK,YAAY;AACpC,aAAO,IAAI;AAAA,IACb;AACA,SAAK,WAAW,MAAM;AAAA,EACxB;AAAA,EAEQ,aAAa,UAAwB;AAE3C,QAAI,KAAK,eAAe;AACtB,mBAAa,KAAK,aAAa;AAAA,IACjC;AACA,SAAK,gBAAgB,WAAW,MAAM;AACpC,WAAK,iBAAiB,KAAK,IAAI;AAC/B,cAAQ,IAAI,+BAA+B,QAAQ,EAAE;AACrD,WAAK,cAAc;AAAA,IACrB,GAAG,GAAG;AAAA,EACR;AAAA,EAEQ,gBAAsB;AAC5B,UAAM,UAAU,KAAK,UAAU,EAAE,MAAM,UAAU,MAAM,KAAK,eAAe,CAAC;AAG5E,eAAW,UAAU,KAAK,YAAY;AACpC,aAAO,MAAM,SAAS,OAAO;AAAA;AAAA,CAAM;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,KAAsB,KAAoC;AAC5E,UAAM,OAAO,KAAK,QAAQ;AAE1B,QAAI,SAAS,OAAO;AAElB,UAAI,UAAU,gBAAgB,mBAAmB;AACjD,UAAI,UAAU,iBAAiB,UAAU;AACzC,UAAI,UAAU,cAAc,YAAY;AACxC,UAAI,UAAU,qBAAqB,IAAI;AAEvC,UAAI,MAAM,YAAY;AACtB,WAAK,WAAW,IAAI,GAAG;AAEvB,UAAI,GAAG,SAAS,MAAM;AACpB,aAAK,WAAW,OAAO,GAAG;AAAA,MAC5B,CAAC;AAAA,IACH,WAAW,SAAS,QAAQ;AAE1B,UAAI,UAAU,gBAAgB,kBAAkB;AAChD,UAAI,IAAI,KAAK,UAAU,EAAE,YAAY,KAAK,eAAe,CAAC,CAAC;AAAA,IAC7D,OAAO;AAEL,UAAI,aAAa;AACjB,UAAI,IAAI,wCAAwC;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,gBAAgB,MAAkB,eAAuB,KAAc;AAC5E,QAAI,SAAS,OAAQ,QAAO;AAE5B,QAAI,SAAS,OAAO;AAClB,aAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBT;AAEA,QAAI,SAAS,QAAQ;AACnB,aAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAcN,YAAY;AAAA;AAAA;AAAA,IAGf;AAGA,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBT;AACF;;;AC1KA,IAAM,cAAc,KAAK,OAAO;AAUzB,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA;AAAA,EAER,YAAY,OAAoB,SAAuB;AACrD,SAAK,QAAQ;AACb,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,OAAO,KAAsB,KAAoC;AACrE,UAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI,QAAQ,IAAI,EAAE;AAChE,UAAM,OAAO,IAAI;AACjB,UAAM,SAAS,IAAI,UAAU;AAG7B,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,eAAO,KAAK,aAAa,GAAG;AAAA,MAC9B,KAAK;AACH,eAAO,KAAK,YAAY,GAAG;AAAA,MAC7B,KAAK;AACH,eAAO,KAAK,oBAAoB,GAAG;AAAA,MACrC,KAAK;AACH,eAAO,KAAK,WAAW,GAAG;AAAA,MAC5B,KAAK;AACH,eAAO,KAAK,SAAS,GAAG;AAAA,MAC1B,KAAK;AACH,eAAO,KAAK,mBAAmB,GAAG;AAAA,MACpC,KAAK;AACH,YAAI,WAAW,QAAQ;AACrB,iBAAO,KAAK,iBAAiB,KAAK,GAAG;AAAA,QACvC;AACA,eAAO,KAAK,iBAAiB,GAAG;AAAA,MAClC;AACE,eAAO,KAAK,SAAS,GAAG;AAAA,IAC5B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAa,KAA2B;AAC9C,SAAK,KAAK,KAAK;AAAA,MACb,QAAQ;AAAA,MACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,KAA2B;AAC7C,UAAM,QAAQ,KAAK,MAAM,uBAAuB,KAAK,MAAM;AAE3D,QAAI,CAAC,OAAO;AACV,UAAI,aAAa;AAAA,IACnB;AAEA,SAAK,KAAK,KAAK;AAAA,MACb;AAAA,MACA,qBAAqB,KAAK,MAAM;AAAA,MAChC,kBAAkB,KAAK,MAAM;AAAA,MAC7B,qBAAqB,KAAK,MAAM;AAAA,IAClC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,KAA2B;AACrD,SAAK,KAAK,KAAK;AAAA,MACb,WAAW,KAAK,MAAM;AAAA,MACtB,cAAc,KAAK,MAAM,yBAAyB;AAAA,IACpD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAW,KAA2B;AAE5C,SAAK,KAAK,KAAK;AAAA,MACb,UAAU,CAAC;AAAA,MACX,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAS,KAA2B;AAE1C,UAAM,KAAK,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAAG,WAAW,CAAC,EAAE;AACnD,UAAM,SAAS,KAAK,UAAU,EAAE;AAEhC,QAAI,OAAO,SAAS,aAAa;AAC/B,WAAK,KAAK,KAAK;AAAA,QACb,WAAW;AAAA,QACX,SAAS,cAAc,cAAc,OAAO,IAAI;AAAA,QAChD,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,QAAI,UAAU,gBAAgB,kBAAkB;AAChD,QAAI,IAAI,MAAM;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,KAA2B;AACpD,SAAK,KAAK,KAAK;AAAA,MACb,OAAO;AAAA,QACL,MAAM,KAAK,QAAQ;AAAA,QACnB,MAAM,KAAK,QAAQ;AAAA,QACnB,YAAY,KAAK,QAAQ;AAAA,QACzB,kBAAkB,KAAK,QAAQ;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAiB,KAAsB,KAA2B;AAExE,QAAI,CAAC,KAAK,QAAQ,iBAAiB;AACjC,UAAI,aAAa;AACjB,WAAK,KAAK,KAAK;AAAA,QACb,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAGA,UAAM,QAAQ,IAAI,QAAQ,kBAAkB;AAC5C,QAAI,UAAU,KAAK,QAAQ,eAAe;AACxC,UAAI,aAAa;AACjB,WAAK,KAAK,KAAK;AAAA,QACb,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAGA,SAAK,KAAK,KAAK;AAAA,MACb,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EAEQ,KAAK,KAAqB,MAAqB;AACrD,QAAI,UAAU,gBAAgB,kBAAkB;AAChD,QAAI,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,EACvC;AAAA,EAEQ,SAAS,KAA2B;AAC1C,QAAI,aAAa;AACjB,SAAK,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AAAA,EACvC;AAAA,EAEQ,iBAAiB,KAA2B;AAClD,QAAI,aAAa;AACjB,SAAK,KAAK,KAAK,EAAE,OAAO,qBAAqB,CAAC;AAAA,EAChD;AACF;;;AHlKO,IAAM,kBAAmD;AAAA,EAC9D,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,gBAAgB;AAClB;AAEO,IAAM,gBAAN,MAAoB;AAAA,EACjB,SAAwB;AAAA,EACxB;AAAA,EACA,aAAgC;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,SAAwD;AAElE,SAAK,UAAU;AAAA,MACb,GAAG;AAAA,MACH,GAAG;AAAA;AAAA,MAEH,YACE,QAAQ,eACP,QAAQ,QAAQ,QAAQ,SAAS,cAAc,QAAQ,gBAAgB;AAAA,IAC5E;AAGA,SAAK,QAAQ,OAAO,QAAQ,IAAI,iBAAiB,KAAK,QAAQ;AAC9D,SAAK,QAAQ,OAAO,SAAS,QAAQ,IAAI,iBAAiB,OAAO,KAAK,QAAQ,IAAI,GAAG,EAAE;AACvF,SAAK,QAAQ,gBAAgB,QAAQ,IAAI,2BAA2B,KAAK,QAAQ;AAEjF,SAAK,QAAQ;AAAA,MACX,qBAAqB;AAAA,MACrB,mBAAkB,oBAAI,KAAK,GAAE,YAAY;AAAA,MACzC,qBAAqB;AAAA,MACrB,wBAAwB;AAAA,IAC1B;AAEA,SAAK,aAAa,IAAI,WAAW,KAAK,QAAQ,SAAS;AACvD,SAAK,aAAa,IAAI,WAAW,KAAK,OAAO,KAAK,OAAO;AAAA,EAC3D;AAAA,EAEA,MAAM,QAAuB;AAE3B,QAAI,KAAK,QAAQ,mBAAmB,CAAC,KAAK,QAAQ,eAAe;AAC/D,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAEA,SAAK,SAAS,aAAa,CAAC,KAAK,QAAQ,KAAK,cAAc,KAAK,GAAG,CAAC;AAGrE,SAAK,OAAO,UAAU,KAAK,QAAQ;AAGnC,QAAI,KAAK,QAAQ,SAAS,KAAK,QAAQ,eAAe,QAAQ;AAC5D,WAAK,aAAa,IAAI,WAAW;AAAA,QAC/B,WAAW,KAAK,QAAQ;AAAA,QACxB,MAAM,KAAK,QAAQ;AAAA,QACnB,QAAQ,KAAK;AAAA,MACf,CAAC;AACD,YAAM,KAAK,WAAW,MAAM;AAAA,IAC9B;AAEA,WAAO,IAAI,QAAQ,CAACC,UAAS,WAAW;AACtC,WAAK,OAAQ,OAAO,KAAK,QAAQ,MAAM,KAAK,QAAQ,MAAM,MAAM;AAC9D,gBAAQ;AAAA,UACN,uCAAuC,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ,IAAI;AAAA,QAC/E;AACA,gBAAQ,IAAI,uBAAuB,KAAK,QAAQ,SAAS,EAAE;AAC3D,YAAI,KAAK,YAAY;AACnB,kBAAQ,IAAI,2BAA2B,KAAK,QAAQ,UAAU,EAAE;AAAA,QAClE;AACA,QAAAA,SAAQ;AAAA,MACV,CAAC;AAED,WAAK,OAAQ,GAAG,SAAS,MAAM;AAAA,IACjC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,YAAY;AACnB,YAAM,KAAK,WAAW,KAAK;AAAA,IAC7B;AACA,QAAI,KAAK,QAAQ;AACf,aAAO,IAAI,QAAQ,CAACA,aAAY;AAC9B,aAAK,OAAQ,MAAM,MAAMA,SAAQ,CAAC;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAc,cAAc,KAAsB,KAAoC;AACpF,UAAM,MAAM,IAAI,OAAO;AAEvB,QAAI;AAEF,UAAI,IAAI,WAAW,OAAO,GAAG;AAC3B,cAAM,KAAK,WAAW,OAAO,KAAK,GAAG;AACrC;AAAA,MACF;AAGA,UAAI,KAAK,cAAc,QAAQ,iBAAiB;AAC9C,cAAM,KAAK,WAAW,cAAc,KAAK,GAAG;AAC5C;AAAA,MACF;AAGA,YAAM,KAAK,WAAW,MAAM,KAAK,GAAG;AAAA,IACtC,SAAS,OAAO;AACd,cAAQ,MAAM,6BAA6B,KAAK;AAChD,UAAI,aAAa;AACjB,UAAI,IAAI,uBAAuB;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,YAAY,SAAqC;AAC/C,WAAO,OAAO,KAAK,OAAO,OAAO;AAAA,EACnC;AACF;;;AD3HA,eAAsB,MAAM,UAAkB,UAA+B,CAAC,GAAkB;AAC9F,QAAM,eAAeC,SAAQ,QAAQ;AAGrC,QAAM,YAAY,QAAQ,SACtBA,SAAQ,QAAQ,MAAM,IACtBC,MAAK,cAAc,QAAQ,WAAW;AAG1C,MAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,YAAQ,IAAI,mDAAmD;AAC/D,UAAM,SAAS,UAAU,EAAE,QAAQ,WAAW,QAAQ,OAAO,CAAC;AAAA,EAChE;AAGA,MAAI,aAA6C,QAAQ,UAAU;AAGnE,MAAI,QAAQ,cAAc,UAAU,QAAQ,IAAI,wBAAwB,KAAK;AAC3E,iBAAa;AACb,YAAQ,IAAI,sDAAsD;AAAA,EACpE;AAEA,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,OAAO,QAAQ,QAAQ;AAG7B,MAAI,SAAS,eAAe,QAAQ,WAAW,QAAW;AACxD,iBAAa;AACb,YAAQ,IAAI,gDAAgD;AAAA,EAC9D;AAGA,QAAM,gBAA+D;AAAA,IACnE;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,QAAQ,UAAU;AAAA,IACzB;AAAA,IACA,iBAAiB,QAAQ,mBAAmB;AAAA,IAC5C,eAAe,QAAQ;AAAA,EACzB;AAEA,QAAM,SAAS,IAAI,cAAc,aAAa;AAG9C,QAAM,WAAW,YAAY;AAC3B,YAAQ,IAAI,+BAA+B;AAC3C,UAAM,OAAO,KAAK;AAClB,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,GAAG,UAAU,QAAQ;AAC7B,UAAQ,GAAG,WAAW,QAAQ;AAE9B,MAAI;AACF,UAAM,OAAO,MAAM;AAGnB,QAAI,QAAQ,SAAS,SAAS,SAAS,aAAa;AAClD,YAAM,MAAM,UAAU,IAAI,IAAI,IAAI;AAClC,UAAI;AACF,cAAM,EAAE,SAAS,KAAK,IAAI,MAAM,OAAO,MAAM;AAC7C,cAAM,KAAK,GAAG;AAAA,MAChB,QAAQ;AACN,gBAAQ,IAAI,qCAAqC,GAAG,EAAE;AAAA,MACxD;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,sCAAsC,KAAK;AACzD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;;;AV/FA,IAAMC,WAAU,cAAc,YAAY,GAAG;AAC7C,IAAM,cAAcA,SAAQ,oBAAoB;AAIhD,IAAI,QAAQ,KAAK,SAAS,WAAW,KAAK,QAAQ,KAAK,SAAS,IAAI,GAAG;AACrE,UAAQ,IAAI,YAAY,OAAO;AAC/B,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QAAQ,KAAK,UAAU,EAAE,YAAY,oCAAoC;AAEzE,QACG,QAAQ,UAAU,EAClB,YAAY,wCAAwC,EACpD,SAAS,eAAe,wBAAwB,EAChD,OAAO,yBAAyB,oCAAoC,IAAI,EACxE,OAAO,sBAAsB,kBAAkB,EAC/C,OAAO,sBAAsB,uCAAuC,EACpE,OAAO,OAAO,UAAkB,YAAY;AAC3C,MAAI;AACF,UAAM,SAAS,UAAU;AAAA,MACvB,QAAQ,QAAQ;AAAA,MAChB,QAAQ,QAAQ;AAAA,MAChB,YAAY,QAAQ;AAAA,IACtB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AACtE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QACG,QAAQ,UAAU,EAClB,YAAY,+CAA+C,EAC3D,SAAS,eAAe,wBAAwB,EAChD,OAAO,gBAAgB,+CAA+C,EACtE,OAAO,OAAO,UAAkB,YAAY;AAC3C,MAAI;AACF,UAAM,QAAQ,MAAM,SAAS,UAAU,EAAE,QAAQ,QAAQ,OAAO,CAAC;AACjE,YAAQ,KAAK,QAAQ,IAAI,CAAC;AAAA,EAC5B,SAAS,OAAO;AACd,YAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AACtE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QACG,QAAQ,OAAO,EACf,YAAY,sDAAsD,EAClE,SAAS,eAAe,wBAAwB,EAChD,OAAO,qBAAqB,qBAAqB,MAAM,EACvD,OAAO,qBAAqB,gDAAgD,WAAW,EACvF,OAAO,sBAAsB,gCAAgC,EAC7D,OAAO,cAAc,uBAAuB,EAC5C,OAAO,uBAAuB,sDAAsD,MAAM,EAC1F,OAAO,mBAAmB,yCAAyC,IAAI,EACvE,OAAO,aAAa,8BAA8B,EAClD,OAAO,yBAAyB,6CAA6C,EAC7E,OAAO,sBAAsB,gDAAgD,EAC7E,OAAO,4BAA4B,2DAA2D,EAC9F,OAAO,OAAO,UAAkB,YAAY;AAC3C,MAAI;AACF,UAAM,MAAM,UAAU;AAAA,MACpB,MAAM,SAAS,QAAQ,MAAM,EAAE;AAAA,MAC/B,MAAM,QAAQ;AAAA,MACd,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ;AAAA,MACf,WAAW,QAAQ;AAAA,MACnB,QAAQ,QAAQ;AAAA,MAChB,MAAM,QAAQ;AAAA,MACd,YAAY,QAAQ;AAAA,MACpB,iBAAiB,QAAQ;AAAA,MACzB,eAAe,QAAQ;AAAA,IACzB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AACtE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QAAQ,MAAM;","names":["join","join","resolve","resolve","join","resolve","join","createHash","resolve","resolve","join","require"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/commands/generate.ts","../../src/core/parser/manifestParser.ts","../../src/core/ir/builder.ts","../../src/core/parser/schemaParser.ts","../../src/core/renderer/markdownRenderer.ts","../../src/core/renderer/htmlRenderer.ts","../../src/cli/commands/validate.ts","../../src/core/capabilities.ts","../../src/core/ir/validator.ts","../../src/cli/commands/serve.ts","../../src/server/index.ts","../../src/server/fileServer.ts","../../src/server/livereload.ts","../../src/server/api.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { createRequire } from 'node:module';\nimport { generate } from './commands/generate.js';\nimport { validate } from './commands/validate.js';\nimport { serve } from './commands/serve.js';\n\n// Use createRequire for cross-platform compatibility with npx\n// This approach works reliably when the package is installed via npm/npx\nconst require = createRequire(import.meta.url);\nconst packageJson = require('../../package.json') as { version: string };\n\n// Handle --version explicitly before commander for reliable npx output\n// Commander's .version() output may not be captured properly by npx\nif (process.argv.includes('--version') || process.argv.includes('-V')) {\n console.log(packageJson.version);\n process.exit(0);\n}\n\nconst program = new Command();\n\nprogram.name('odd-docs').description('MCP-native documentation generator');\n\nprogram\n .command('generate')\n .description('Generate documentation for an MCP repo')\n .argument('<repo-path>', 'Path to the repository')\n .option('-f, --format <format>', 'Output format: md, html, or both', 'md')\n .option('-o, --output <dir>', 'Output directory')\n .option('--introspect <url>', 'MCP server URL for live introspection')\n .action(async (repoPath: string, options) => {\n try {\n await generate(repoPath, {\n format: options.format,\n output: options.output,\n introspect: options.introspect,\n });\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\nprogram\n .command('validate')\n .description('Validate documentation inputs for an MCP repo')\n .argument('<repo-path>', 'Path to the repository')\n .option('-s, --strict', 'Fail on unknown safety-affecting capabilities')\n .action(async (repoPath: string, options) => {\n try {\n const valid = await validate(repoPath, { strict: options.strict });\n process.exit(valid ? 0 : 1);\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\nprogram\n .command('serve')\n .description('Start a local dev server for generated documentation')\n .argument('<repo-path>', 'Path to the repository')\n .option('-p, --port <port>', 'Port to listen on', '3000')\n .option('-H, --host <host>', 'Host to bind (default: localhost for safety)', 'localhost')\n .option('-o, --output <dir>', 'Documentation output directory')\n .option('--no-watch', 'Disable file watching')\n .option('--watch-mode <mode>', 'Watch mode: auto or poll (use poll for Docker/NFS)', 'auto')\n .option('--reload <mode>', 'Reload mechanism: ws, sse, poll, none', 'ws')\n .option('--no-open', 'Do not open browser on start')\n .option('--introspect <target>', 'MCP target: http://host:port or stdio:<cmd>')\n .option('--enable-mutations', 'Enable mutation API endpoints (requires token)')\n .option('--mutation-token <token>', 'Token for mutation endpoints (or ODD_DOCS_MUTATION_TOKEN)')\n .action(async (repoPath: string, options) => {\n try {\n await serve(repoPath, {\n port: parseInt(options.port, 10),\n host: options.host,\n output: options.output,\n watch: options.watch,\n watchMode: options.watchMode,\n reload: options.reload,\n open: options.open,\n introspect: options.introspect,\n enableMutations: options.enableMutations,\n mutationToken: options.mutationToken,\n });\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import { writeFile, mkdir } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { parseManifest } from '../../core/parser/manifestParser.js';\nimport { buildDocIR } from '../../core/ir/builder.js';\nimport { renderMarkdown } from '../../core/renderer/markdownRenderer.js';\nimport { renderHTML } from '../../core/renderer/htmlRenderer.js';\n\nexport interface GenerateOptions {\n format?: 'md' | 'html' | 'both';\n output?: string;\n introspect?: string;\n}\n\nexport async function generate(repoPath: string, options: GenerateOptions = {}): Promise<void> {\n const absPath = resolve(repoPath);\n const format = options.format ?? 'md';\n const outputDir = options.output ? resolve(options.output) : join(absPath, 'docs', 'generated');\n\n console.log(`Generating documentation for: ${absPath}`);\n\n // Parse manifest\n const manifestResult = await parseManifest(absPath);\n console.log(` Entity: ${manifestResult.entity.id}@${manifestResult.entity.version}`);\n\n // Build Doc IR\n const ir = buildDocIR(manifestResult);\n console.log(` Determinism key: ${ir.determinismKey}`);\n\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n // Render formats\n if (format === 'md' || format === 'both') {\n const markdown = renderMarkdown(ir);\n const mdPath = join(outputDir, `${ir.entity.id}.md`);\n await writeFile(mdPath, markdown, 'utf-8');\n console.log(` ✓ Markdown: ${mdPath}`);\n }\n\n if (format === 'html' || format === 'both') {\n const html = renderHTML(ir);\n const htmlPath = join(outputDir, `${ir.entity.id}.html`);\n await writeFile(htmlPath, html, 'utf-8');\n console.log(` ✓ HTML: ${htmlPath}`);\n }\n\n // Write IR for debugging/caching\n const irPath = join(outputDir, `${ir.entity.id}.ir.json`);\n await writeFile(irPath, JSON.stringify(ir, null, 2), 'utf-8');\n console.log(` ✓ Doc IR: ${irPath}`);\n\n console.log('Done!');\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DocIR, Capability, SchemaSection } from '../ir/types.js';\n\ninterface ToolManifest {\n tool_id: string;\n version: string;\n description?: string;\n execution_mode?: 'IN_PROCESS' | 'RUNNER';\n parameters?: Record<string, unknown>;\n capabilities?: {\n network?: string[];\n filesystem?: string[];\n secrets?: string[];\n };\n timeout_ms?: number;\n resource_limits?: {\n memory_mb?: number;\n cpu_cores?: number;\n };\n deprecation?: {\n deprecated_at: string;\n sunset_date: string;\n migration_url?: string;\n };\n}\n\nexport interface ManifestParseResult {\n entity: DocIR['entity'];\n inputs: SchemaSection;\n constraints?: DocIR['constraints'];\n lifecycle?: DocIR['lifecycle'];\n}\n\n/**\n * Parse an MCP tool manifest file into partial Doc IR\n */\nexport async function parseManifest(repoPath: string): Promise<ManifestParseResult> {\n const manifestPath = join(repoPath, 'manifest.json');\n\n let content: string;\n try {\n content = await readFile(manifestPath, 'utf-8');\n } catch {\n throw new Error(`Manifest not found: ${manifestPath}`);\n }\n\n let manifest: ToolManifest;\n try {\n manifest = JSON.parse(content) as ToolManifest;\n } catch {\n throw new Error(`Invalid JSON in manifest: ${manifestPath}`);\n }\n\n // Validate required fields\n if (!manifest.tool_id) {\n throw new Error('Manifest missing required field: tool_id');\n }\n if (!manifest.version) {\n throw new Error('Manifest missing required field: version');\n }\n\n // Build capabilities array\n const capabilities: Capability[] = [];\n if (manifest.capabilities) {\n for (const [type, values] of Object.entries(manifest.capabilities)) {\n if (Array.isArray(values) && values.length > 0) {\n capabilities.push({ type, values, provenance: 'manifest' });\n }\n }\n }\n\n const result: ManifestParseResult = {\n entity: {\n type: 'tool',\n id: manifest.tool_id,\n version: manifest.version,\n description: manifest.description,\n },\n inputs: {\n schema: manifest.parameters,\n provenance: 'manifest',\n },\n };\n\n // Add constraints if present\n if (capabilities.length > 0 || manifest.timeout_ms || manifest.resource_limits) {\n result.constraints = {\n capabilities: capabilities.length > 0 ? capabilities : undefined,\n timeoutMs: manifest.timeout_ms,\n resourceLimits: manifest.resource_limits\n ? {\n memoryMb: manifest.resource_limits.memory_mb,\n cpuCores: manifest.resource_limits.cpu_cores,\n }\n : undefined,\n };\n }\n\n // Add lifecycle if deprecation present\n if (manifest.deprecation) {\n result.lifecycle = {\n version: manifest.version,\n deprecation: {\n deprecatedAt: manifest.deprecation.deprecated_at,\n sunsetDate: manifest.deprecation.sunset_date,\n migrationUrl: manifest.deprecation.migration_url,\n },\n };\n }\n\n return result;\n}\n","import { createHash } from 'node:crypto';\nimport type { DocIR } from './types.js';\nimport { enrichSchemaSection } from '../parser/schemaParser.js';\nimport type { ManifestParseResult } from '../parser/manifestParser.js';\n\n/**\n * Build a complete Doc IR from parsed sources\n */\nexport function buildDocIR(manifest: ManifestParseResult): DocIR {\n const enrichedInputs = enrichSchemaSection(manifest.inputs);\n\n const ir: DocIR = {\n version: '1.0.0',\n generatedAt: new Date().toISOString(),\n determinismKey: '', // Computed below\n entity: manifest.entity,\n inputs: enrichedInputs,\n constraints: manifest.constraints,\n lifecycle: manifest.lifecycle,\n provenance: {\n entity: 'manifest',\n inputs: 'manifest',\n },\n };\n\n // Compute determinism key\n ir.determinismKey = computeDeterminismKey(ir);\n\n return ir;\n}\n\n/**\n * Compute SHA-256 determinism key for caching and diffing\n */\nexport function computeDeterminismKey(ir: Omit<DocIR, 'determinismKey' | 'generatedAt'>): string {\n const canonical = JSON.stringify({\n entity: ir.entity,\n inputs: ir.inputs,\n constraints: ir.constraints,\n lifecycle: ir.lifecycle,\n });\n\n const hash = createHash('sha256').update(canonical).digest('hex');\n return `sha256:${hash}`;\n}\n","import type { Parameter, SchemaSection } from '../ir/types.js';\n\ninterface JSONSchema {\n type?: string;\n properties?: Record<string, JSONSchema>;\n required?: string[];\n description?: string;\n default?: unknown;\n enum?: unknown[];\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n items?: JSONSchema;\n $ref?: string;\n}\n\n/**\n * Parse JSON Schema into a list of parameters for documentation\n */\nexport function parseSchema(schema: Record<string, unknown> | undefined): Parameter[] {\n if (!schema) return [];\n\n const jsonSchema = schema as JSONSchema;\n const parameters: Parameter[] = [];\n const required = new Set(jsonSchema.required ?? []);\n\n if (jsonSchema.properties) {\n for (const [name, propSchema] of Object.entries(jsonSchema.properties)) {\n parameters.push(parseProperty(name, propSchema, required.has(name)));\n }\n }\n\n return parameters;\n}\n\nfunction parseProperty(name: string, schema: JSONSchema, isRequired: boolean): Parameter {\n const param: Parameter = {\n name,\n type: resolveType(schema),\n required: isRequired,\n };\n\n if (schema.description) {\n param.description = schema.description;\n }\n\n if (schema.default !== undefined) {\n param.default = schema.default;\n }\n\n if (schema.enum) {\n param.enum = schema.enum;\n }\n\n // Build constraints string\n const constraints = buildConstraints(schema);\n if (constraints) {\n param.constraints = constraints;\n }\n\n return param;\n}\n\nfunction resolveType(schema: JSONSchema): string {\n if (schema.$ref) {\n // Extract type name from $ref\n const refParts = schema.$ref.split('/');\n return refParts[refParts.length - 1];\n }\n\n if (schema.enum) {\n return 'enum';\n }\n\n if (schema.type === 'array' && schema.items) {\n return `${resolveType(schema.items)}[]`;\n }\n\n return schema.type ?? 'unknown';\n}\n\nfunction buildConstraints(schema: JSONSchema): string | undefined {\n const parts: string[] = [];\n\n if (schema.minimum !== undefined) {\n parts.push(`min: ${schema.minimum}`);\n }\n if (schema.maximum !== undefined) {\n parts.push(`max: ${schema.maximum}`);\n }\n if (schema.minLength !== undefined) {\n parts.push(`minLength: ${schema.minLength}`);\n }\n if (schema.maxLength !== undefined) {\n parts.push(`maxLength: ${schema.maxLength}`);\n }\n if (schema.pattern) {\n parts.push(`pattern: ${schema.pattern}`);\n }\n\n return parts.length > 0 ? parts.join(', ') : undefined;\n}\n\n/**\n * Enrich a SchemaSection with parsed parameters\n */\nexport function enrichSchemaSection(section: SchemaSection): SchemaSection {\n return {\n ...section,\n parameters: parseSchema(section.schema),\n };\n}\n","import type { DocIR, Parameter, ProvenanceSource } from '../ir/types.js';\n\n/**\n * Render Doc IR to Markdown\n */\nexport function renderMarkdown(ir: DocIR): string {\n const lines: string[] = [];\n\n // Header\n lines.push(`# ${ir.entity.id}`);\n lines.push('');\n lines.push(`**Version:** ${ir.entity.version} `);\n lines.push(`**Type:** ${ir.entity.type} `);\n if (ir.entity.description) {\n lines.push('');\n lines.push(ir.entity.description);\n }\n lines.push('');\n\n // Overview\n if (ir.overview) {\n lines.push('## Overview');\n lines.push('');\n if (ir.overview.intent) {\n lines.push(`**Intent:** ${ir.overview.intent}`);\n lines.push('');\n }\n if (ir.overview.useCases?.length) {\n lines.push('### Use Cases');\n lines.push('');\n for (const useCase of ir.overview.useCases) {\n lines.push(`- ${useCase}`);\n }\n lines.push('');\n }\n if (ir.overview.sideEffects?.length) {\n lines.push('### Side Effects');\n lines.push('');\n for (const effect of ir.overview.sideEffects) {\n lines.push(\n `- **${effect.type}**: ${effect.description} ${provenanceBadge(effect.provenance)}`\n );\n }\n lines.push('');\n }\n }\n\n // Inputs\n if (ir.inputs?.parameters?.length) {\n lines.push('## Inputs');\n lines.push('');\n lines.push(provenanceBadge(ir.inputs.provenance));\n lines.push('');\n lines.push(renderParameterTable(ir.inputs.parameters));\n lines.push('');\n }\n\n // Outputs\n if (ir.outputs?.parameters?.length) {\n lines.push('## Outputs');\n lines.push('');\n lines.push(provenanceBadge(ir.outputs.provenance));\n lines.push('');\n lines.push(renderParameterTable(ir.outputs.parameters));\n lines.push('');\n }\n\n // Constraints\n if (ir.constraints) {\n lines.push('## Constraints');\n lines.push('');\n if (ir.constraints.capabilities?.length) {\n lines.push('### Capabilities');\n lines.push('');\n for (const cap of ir.constraints.capabilities) {\n const values = cap.values?.join(', ') ?? 'enabled';\n lines.push(`- **${cap.type}**: ${values} ${provenanceBadge(cap.provenance)}`);\n }\n lines.push('');\n }\n if (ir.constraints.timeoutMs) {\n lines.push(`**Timeout:** ${ir.constraints.timeoutMs}ms`);\n lines.push('');\n }\n if (ir.constraints.resourceLimits) {\n lines.push('### Resource Limits');\n lines.push('');\n if (ir.constraints.resourceLimits.memoryMb) {\n lines.push(`- Memory: ${ir.constraints.resourceLimits.memoryMb} MB`);\n }\n if (ir.constraints.resourceLimits.cpuCores) {\n lines.push(`- CPU: ${ir.constraints.resourceLimits.cpuCores} cores`);\n }\n lines.push('');\n }\n }\n\n // Errors\n if (ir.errors?.length) {\n lines.push('## Errors');\n lines.push('');\n lines.push('| Code | Description | Recovery |');\n lines.push('|------|-------------|----------|');\n for (const err of ir.errors) {\n lines.push(`| \\`${err.code}\\` | ${err.description ?? ''} | ${err.recovery ?? ''} |`);\n }\n lines.push('');\n }\n\n // Lifecycle\n if (ir.lifecycle?.deprecation) {\n lines.push('## Lifecycle');\n lines.push('');\n lines.push('> [!WARNING]');\n lines.push(`> This tool is deprecated as of ${ir.lifecycle.deprecation.deprecatedAt}.`);\n lines.push(`> Sunset date: ${ir.lifecycle.deprecation.sunsetDate}`);\n if (ir.lifecycle.deprecation.migrationUrl) {\n lines.push(`> Migration guide: ${ir.lifecycle.deprecation.migrationUrl}`);\n }\n lines.push('');\n }\n\n // Examples\n if (ir.narrative?.examples?.length) {\n lines.push('## Examples');\n lines.push('');\n for (const example of ir.narrative.examples) {\n if (example.title) {\n lines.push(`### ${example.title}`);\n lines.push('');\n }\n if (example.description) {\n lines.push(example.description);\n lines.push('');\n }\n if (example.input) {\n lines.push('**Input:**');\n lines.push('```json');\n lines.push(JSON.stringify(example.input, null, 2));\n lines.push('```');\n lines.push('');\n }\n if (example.output) {\n lines.push('**Output:**');\n lines.push('```json');\n lines.push(JSON.stringify(example.output, null, 2));\n lines.push('```');\n lines.push('');\n }\n }\n }\n\n // Notes\n if (ir.narrative?.notes?.length) {\n lines.push('## Notes');\n lines.push('');\n lines.push('*[author notes]*');\n lines.push('');\n for (const note of ir.narrative.notes) {\n lines.push(note);\n lines.push('');\n }\n }\n\n // Footer\n lines.push('---');\n lines.push('');\n lines.push(`*Generated at ${ir.generatedAt}* `);\n lines.push(`*Determinism key: \\`${ir.determinismKey}\\`*`);\n\n return lines.join('\\n');\n}\n\nfunction renderParameterTable(params: Parameter[]): string {\n const lines: string[] = [];\n lines.push('| Name | Type | Required | Default | Description |');\n lines.push('|------|------|----------|---------|-------------|');\n\n for (const param of params) {\n const required = param.required ? '✓' : '';\n const defaultVal = param.default !== undefined ? `\\`${JSON.stringify(param.default)}\\`` : '';\n const desc = param.description ?? '';\n lines.push(`| \\`${param.name}\\` | \\`${param.type}\\` | ${required} | ${defaultVal} | ${desc} |`);\n }\n\n return lines.join('\\n');\n}\n\nfunction provenanceBadge(source?: ProvenanceSource): string {\n if (!source) return '';\n const badges: Record<ProvenanceSource, string> = {\n introspection: '`[from introspection]`',\n manifest: '`[from schema]`',\n overlay: '`[from overlay]`',\n narrative: '`[author notes]`',\n };\n return badges[source] ?? '';\n}\n","import { marked } from 'marked';\nimport type { DocIR } from '../ir/types.js';\nimport { renderMarkdown } from './markdownRenderer.js';\n\n/**\n * Render Doc IR to static HTML\n */\nexport function renderHTML(ir: DocIR): string {\n // First render to markdown, then convert to HTML\n const markdown = renderMarkdown(ir);\n const htmlContent = marked.parse(markdown) as string;\n\n return `<!DOCTYPE html>\n<html lang=\"en\" data-theme=\"light\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"description\" content=\"${escapeHtml(ir.entity.description ?? `Documentation for ${ir.entity.id}`)}\">\n <title>${escapeHtml(ir.entity.id)} - odd-docs</title>\n <style>\n${getThemeStyles()}\n </style>\n</head>\n<body>\n <div class=\"container\">\n <header>\n <nav class=\"breadcrumb\">\n <a href=\"index.html\">Home</a> / <span>${escapeHtml(ir.entity.id)}</span>\n </nav>\n </header>\n <main class=\"content\">\n${htmlContent}\n </main>\n <footer>\n <p class=\"meta\">\n Generated by <a href=\"https://github.com/oddessentials/odd-docs\">odd-docs</a> at ${ir.generatedAt}\n </p>\n <p class=\"determinism\">\n <code>${ir.determinismKey}</code>\n </p>\n </footer>\n </div>\n <script>\n${getThemeScript()}\n </script>\n</body>\n</html>`;\n}\n\n/**\n * Generate index page for multiple docs\n */\nexport function renderIndexHTML(docs: DocIR[]): string {\n const items = docs\n .map(\n (ir) => `\n <li>\n <a href=\"${ir.entity.id}.html\">\n <strong>${escapeHtml(ir.entity.id)}</strong>\n <span class=\"version\">v${ir.entity.version}</span>\n </a>\n <p>${escapeHtml(ir.entity.description ?? '')}</p>\n </li>`\n )\n .join('\\n');\n\n return `<!DOCTYPE html>\n<html lang=\"en\" data-theme=\"light\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Documentation - odd-docs</title>\n <style>\n${getThemeStyles()}\n </style>\n</head>\n<body>\n <div class=\"container\">\n <header>\n <h1>Documentation</h1>\n </header>\n <main class=\"content\">\n <ul class=\"doc-list\">\n${items}\n </ul>\n </main>\n <footer>\n <p class=\"meta\">Generated by <a href=\"https://github.com/oddessentials/odd-docs\">odd-docs</a></p>\n </footer>\n </div>\n <script>\n${getThemeScript()}\n </script>\n</body>\n</html>`;\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nfunction getThemeStyles(): string {\n return `\n /* CSS Variables for theming */\n :root {\n /* Colors - neutral palette */\n --color-bg: #ffffff;\n --color-bg-secondary: #f8f9fa;\n --color-text: #1a1a2e;\n --color-text-muted: #6c757d;\n --color-border: #dee2e6;\n --color-link: #0066cc;\n --color-link-hover: #004499;\n --color-accent: #0066cc;\n --color-success: #28a745;\n --color-warning: #ffc107;\n --color-error: #dc3545;\n \n /* Typography */\n --font-sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n --font-mono: 'SF Mono', Monaco, 'Cascadia Code', monospace;\n --font-size-base: 16px;\n --line-height: 1.6;\n \n /* Spacing */\n --space-xs: 0.25rem;\n --space-sm: 0.5rem;\n --space-md: 1rem;\n --space-lg: 1.5rem;\n --space-xl: 2rem;\n \n /* Layout */\n --max-width: 800px;\n --border-radius: 4px;\n }\n \n [data-theme=\"dark\"] {\n --color-bg: #1a1a2e;\n --color-bg-secondary: #16213e;\n --color-text: #e8e8e8;\n --color-text-muted: #a0a0a0;\n --color-border: #3a3a5e;\n --color-link: #66b3ff;\n --color-link-hover: #99ccff;\n }\n \n /* Reset */\n *, *::before, *::after {\n box-sizing: border-box;\n }\n \n body {\n margin: 0;\n padding: 0;\n font-family: var(--font-sans);\n font-size: var(--font-size-base);\n line-height: var(--line-height);\n color: var(--color-text);\n background: var(--color-bg);\n }\n \n /* Container */\n .container {\n max-width: var(--max-width);\n margin: 0 auto;\n padding: var(--space-lg);\n }\n \n /* Typography */\n h1, h2, h3, h4, h5, h6 {\n margin-top: var(--space-xl);\n margin-bottom: var(--space-md);\n line-height: 1.3;\n }\n \n h1 { font-size: 2rem; }\n h2 { font-size: 1.5rem; border-bottom: 1px solid var(--color-border); padding-bottom: var(--space-sm); }\n h3 { font-size: 1.25rem; }\n \n p { margin: var(--space-md) 0; }\n \n a {\n color: var(--color-link);\n text-decoration: none;\n }\n \n a:hover {\n color: var(--color-link-hover);\n text-decoration: underline;\n }\n \n /* Code */\n code {\n font-family: var(--font-mono);\n font-size: 0.9em;\n background: var(--color-bg-secondary);\n padding: var(--space-xs) var(--space-sm);\n border-radius: var(--border-radius);\n }\n \n pre {\n background: var(--color-bg-secondary);\n padding: var(--space-md);\n border-radius: var(--border-radius);\n overflow-x: auto;\n }\n \n pre code {\n background: none;\n padding: 0;\n }\n \n /* Tables */\n table {\n width: 100%;\n border-collapse: collapse;\n margin: var(--space-md) 0;\n }\n \n th, td {\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n text-align: left;\n }\n \n th {\n background: var(--color-bg-secondary);\n font-weight: 600;\n }\n \n /* Provenance badges */\n code[class*=\"from\"] {\n font-size: 0.75em;\n color: var(--color-text-muted);\n background: transparent;\n }\n \n /* Blockquotes (for warnings/notes) */\n blockquote {\n margin: var(--space-md) 0;\n padding: var(--space-md);\n border-left: 4px solid var(--color-warning);\n background: var(--color-bg-secondary);\n }\n \n blockquote p:first-child { margin-top: 0; }\n blockquote p:last-child { margin-bottom: 0; }\n \n /* Lists */\n ul, ol {\n padding-left: var(--space-lg);\n }\n \n li { margin: var(--space-sm) 0; }\n \n /* Doc list (index page) */\n .doc-list {\n list-style: none;\n padding: 0;\n }\n \n .doc-list li {\n padding: var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--border-radius);\n margin-bottom: var(--space-md);\n }\n \n .doc-list a {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n }\n \n .doc-list .version {\n color: var(--color-text-muted);\n font-size: 0.875em;\n }\n \n .doc-list p {\n margin: var(--space-sm) 0 0;\n color: var(--color-text-muted);\n }\n \n /* Header */\n header {\n margin-bottom: var(--space-lg);\n }\n \n .breadcrumb {\n font-size: 0.875em;\n color: var(--color-text-muted);\n }\n \n .breadcrumb a {\n color: inherit;\n }\n \n /* Footer */\n footer {\n margin-top: var(--space-xl);\n padding-top: var(--space-lg);\n border-top: 1px solid var(--color-border);\n font-size: 0.875em;\n color: var(--color-text-muted);\n }\n \n .determinism code {\n font-size: 0.75em;\n }\n \n /* Theme toggle */\n .theme-toggle {\n position: fixed;\n top: var(--space-md);\n right: var(--space-md);\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--border-radius);\n background: var(--color-bg);\n cursor: pointer;\n font-size: 0.875em;\n }\n \n /* Responsive */\n @media (max-width: 600px) {\n .container { padding: var(--space-md); }\n h1 { font-size: 1.5rem; }\n h2 { font-size: 1.25rem; }\n table { font-size: 0.875em; }\n }\n `;\n}\n\nfunction getThemeScript(): string {\n return `\n // Theme toggle\n const toggle = document.createElement('button');\n toggle.className = 'theme-toggle';\n toggle.textContent = '🌙';\n toggle.onclick = () => {\n const html = document.documentElement;\n const isDark = html.dataset.theme === 'dark';\n html.dataset.theme = isDark ? 'light' : 'dark';\n toggle.textContent = isDark ? '🌙' : '☀️';\n localStorage.setItem('theme', html.dataset.theme);\n };\n document.body.appendChild(toggle);\n \n // Restore saved theme\n const saved = localStorage.getItem('theme');\n if (saved) {\n document.documentElement.dataset.theme = saved;\n toggle.textContent = saved === 'dark' ? '☀️' : '🌙';\n } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {\n document.documentElement.dataset.theme = 'dark';\n toggle.textContent = '☀️';\n }\n `;\n}\n","import { resolve } from 'node:path';\nimport { parseManifest } from '../../core/parser/manifestParser.js';\nimport { buildDocIR } from '../../core/ir/builder.js';\nimport { validateDocIR, formatValidationResult } from '../../core/ir/validator.js';\n\nexport interface ValidateOptions {\n strict?: boolean;\n}\n\nexport async function validate(repoPath: string, options: ValidateOptions = {}): Promise<boolean> {\n const absPath = resolve(repoPath);\n\n console.log(`Validating: ${absPath}`);\n console.log(`Mode: ${options.strict ? 'strict' : 'normal'}`);\n console.log('');\n\n try {\n // Parse manifest\n const manifestResult = await parseManifest(absPath);\n\n // Build Doc IR\n const ir = buildDocIR(manifestResult);\n\n // Validate\n const result = validateDocIR(ir, { strict: options.strict });\n\n // Format and print result\n console.log(formatValidationResult(result, absPath));\n\n return result.valid;\n } catch (error) {\n console.error('✗ Validation failed');\n console.error('');\n console.error(`Error: ${error instanceof Error ? error.message : error}`);\n return false;\n }\n}\n","/**\n * Known capabilities allowlist\n * Safety-affecting capabilities trigger stricter validation\n */\n\nexport const KNOWN_CAPABILITIES = [\n 'network',\n 'filesystem',\n 'secrets',\n 'exec',\n 'subprocess',\n 'database',\n 'queue',\n] as const;\n\nexport type KnownCapability = (typeof KNOWN_CAPABILITIES)[number];\n\n/**\n * Capabilities that imply safety-critical operations\n * Unknown capabilities matching these patterns fail in --strict mode\n */\nexport const SAFETY_AFFECTING_PATTERNS = ['network', 'exec', 'subprocess', 'write', 'delete'];\n\nexport function isKnownCapability(capability: string): capability is KnownCapability {\n return KNOWN_CAPABILITIES.includes(capability as KnownCapability);\n}\n\nexport function isSafetyAffecting(capability: string): boolean {\n return SAFETY_AFFECTING_PATTERNS.some((pattern) =>\n capability.toLowerCase().includes(pattern.toLowerCase())\n );\n}\n","import type { DocIR, ProvenanceSource } from '../ir/types.js';\nimport { isKnownCapability, isSafetyAffecting } from '../capabilities.js';\n\nexport type ValidationSeverity = 'error' | 'warning';\n\nexport interface ValidationIssue {\n severity: ValidationSeverity;\n code: string;\n message: string;\n path?: string;\n provenance?: ProvenanceSource;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n issues: ValidationIssue[];\n}\n\nexport interface ValidateOptions {\n strict?: boolean;\n}\n\n/**\n * Validate Doc IR for completeness and consistency\n */\nexport function validateDocIR(ir: DocIR, options: ValidateOptions = {}): ValidationResult {\n const issues: ValidationIssue[] = [];\n\n // Required field checks\n if (!ir.entity.id) {\n issues.push({\n severity: 'error',\n code: 'MISSING_TOOL_ID',\n message: 'Tool ID is required',\n path: 'entity.id',\n });\n }\n\n if (!ir.entity.version) {\n issues.push({\n severity: 'error',\n code: 'MISSING_VERSION',\n message: 'Version is required',\n path: 'entity.version',\n });\n }\n\n if (!ir.inputs?.schema && !ir.inputs?.parameters?.length) {\n issues.push({\n severity: 'error',\n code: 'MISSING_PARAMETERS_SCHEMA',\n message: 'Parameters schema is required',\n path: 'inputs',\n });\n }\n\n // Capability validation\n if (ir.constraints?.capabilities) {\n for (const cap of ir.constraints.capabilities) {\n if (!isKnownCapability(cap.type)) {\n const isSafety = isSafetyAffecting(cap.type);\n issues.push({\n severity: options.strict && isSafety ? 'error' : 'warning',\n code: 'UNKNOWN_CAPABILITY',\n message: `Unknown capability: ${cap.type}${isSafety ? ' (safety-affecting)' : ''}`,\n path: `constraints.capabilities.${cap.type}`,\n provenance: cap.provenance,\n });\n }\n }\n }\n\n // Structural contradiction checks\n issues.push(...checkStructuralContradictions(ir));\n\n const hasErrors = issues.some((i) => i.severity === 'error');\n\n return {\n valid: !hasErrors,\n issues,\n };\n}\n\n/**\n * Check for structural contradictions between sources\n */\nfunction checkStructuralContradictions(ir: DocIR): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n // Check if narrative mentions parameters not in schema\n if (ir.narrative?.notes && ir.inputs?.parameters) {\n const schemaParams = new Set(ir.inputs.parameters.map((p) => p.name.toLowerCase()));\n\n for (const note of ir.narrative.notes) {\n // Match patterns like \"parameter X\" or \"the X parameter\"\n const paramMentions = note.match(/(?:parameter|param)\\s+[`\"']?(\\w+)[`\"']?/gi) ?? [];\n const theParamMentions = note.match(/the\\s+[`\"']?(\\w+)[`\"']?\\s+parameter/gi) ?? [];\n\n for (const match of [...paramMentions, ...theParamMentions]) {\n const paramName = match.replace(/.*?[`\"']?(\\w+)[`\"']?.*/i, '$1').toLowerCase();\n if (paramName && !schemaParams.has(paramName) && paramName !== 'parameter') {\n issues.push({\n severity: 'error',\n code: 'NARRATIVE_REFERENCES_UNDEFINED_PARAM',\n message: `Narrative references parameter \"${paramName}\" not in schema`,\n path: 'narrative.notes',\n provenance: 'narrative',\n });\n }\n }\n }\n }\n\n // Check if examples use parameters not in schema\n if (ir.narrative?.examples && ir.inputs?.parameters) {\n const schemaParams = new Set(ir.inputs.parameters.map((p) => p.name));\n\n for (const example of ir.narrative.examples) {\n if (example.input && typeof example.input === 'object') {\n for (const key of Object.keys(example.input as Record<string, unknown>)) {\n if (!schemaParams.has(key)) {\n issues.push({\n severity: 'warning',\n code: 'EXAMPLE_USES_UNDEFINED_PARAM',\n message: `Example uses parameter \"${key}\" not in schema`,\n path: `narrative.examples.${example.title ?? 'unnamed'}`,\n provenance: 'narrative',\n });\n }\n }\n }\n }\n }\n\n // Check for side effect / capability contradictions\n if (ir.overview?.sideEffects && ir.constraints?.capabilities) {\n const capTypes = new Set(ir.constraints.capabilities.map((c) => c.type));\n\n for (const effect of ir.overview.sideEffects) {\n // Map side effect types to capability types\n const expectedCap = mapSideEffectToCapability(effect.type);\n if (expectedCap && !capTypes.has(expectedCap)) {\n issues.push({\n severity: 'error',\n code: 'SIDE_EFFECT_CAPABILITY_MISMATCH',\n message: `Side effect \"${effect.type}\" requires capability \"${expectedCap}\" which is not declared`,\n path: `overview.sideEffects.${effect.type}`,\n provenance: effect.provenance,\n });\n }\n }\n }\n\n return issues;\n}\n\nfunction mapSideEffectToCapability(effectType: string): string | null {\n const mapping: Record<string, string> = {\n filesystem: 'filesystem',\n network: 'network',\n secrets: 'secrets',\n exec: 'exec',\n subprocess: 'subprocess',\n database: 'database',\n queue: 'queue',\n };\n return mapping[effectType] ?? null;\n}\n\n/**\n * Format validation result for CLI output\n */\nexport function formatValidationResult(result: ValidationResult, repoPath: string): string {\n const lines: string[] = [];\n\n lines.push(`Validating: ${repoPath}`);\n lines.push('');\n\n if (result.valid) {\n lines.push('✓ Validation passed');\n } else {\n lines.push('✗ Validation failed');\n }\n lines.push('');\n\n const errors = result.issues.filter((i) => i.severity === 'error');\n const warnings = result.issues.filter((i) => i.severity === 'warning');\n\n if (errors.length > 0) {\n lines.push(`Errors (${errors.length}):`);\n for (const issue of errors) {\n lines.push(` ✗ [${issue.code}] ${issue.message}`);\n if (issue.path) {\n lines.push(` at ${issue.path}`);\n }\n }\n lines.push('');\n }\n\n if (warnings.length > 0) {\n lines.push(`Warnings (${warnings.length}):`);\n for (const issue of warnings) {\n lines.push(` ⚠ [${issue.code}] ${issue.message}`);\n if (issue.path) {\n lines.push(` at ${issue.path}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n","/**\n * Serve Command\n *\n * Start a local development server for generated documentation.\n * Enforces safe defaults per deployment stance:\n * - localhost binding\n * - mutations disabled\n * - SSE auto-switch for non-localhost\n */\n\nimport { existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { OddDocsServer, type ServeOptions } from '../../server/index.js';\nimport { generate } from './generate.js';\n\nexport interface ServeCommandOptions {\n port?: number;\n host?: string;\n output?: string;\n watch?: boolean;\n watchMode?: 'auto' | 'poll';\n reload?: 'ws' | 'sse' | 'poll' | 'none';\n open?: boolean;\n introspect?: string;\n enableMutations?: boolean;\n mutationToken?: string;\n}\n\n/**\n * Serve documentation with live reload\n */\nexport async function serve(repoPath: string, options: ServeCommandOptions = {}): Promise<void> {\n const resolvedPath = resolve(repoPath);\n\n // Determine output directory\n const outputDir = options.output\n ? resolve(options.output)\n : join(resolvedPath, 'docs', 'generated');\n\n // Check if docs exist, generate if not\n if (!existsSync(outputDir)) {\n console.log('[odd-docs] Documentation not found, generating...');\n await generate(repoPath, { output: outputDir, format: 'html' });\n }\n\n // Determine reload mode\n let reloadMode: 'ws' | 'sse' | 'poll' | 'none' = options.reload ?? 'ws';\n\n // Use poll mode if explicitly requested via env or option\n if (options.watchMode === 'poll' || process.env.CHOKIDAR_USEPOLLING === '1') {\n reloadMode = 'poll';\n console.log('[odd-docs] Using poll-based watching (CPU intensive)');\n }\n\n const host = options.host ?? 'localhost';\n const port = options.port ?? 3000;\n\n // Auto-switch to SSE for non-localhost (safer for K8s)\n if (host !== 'localhost' && options.reload === undefined) {\n reloadMode = 'sse';\n console.log('[odd-docs] Using SSE for non-localhost binding');\n }\n\n // Create and start server\n const serverOptions: Partial<ServeOptions> & { outputDir: string } = {\n outputDir,\n host,\n port,\n watch: options.watch !== false,\n reloadMode,\n enableMutations: options.enableMutations ?? false,\n mutationToken: options.mutationToken,\n };\n\n const server = new OddDocsServer(serverOptions);\n\n // Handle shutdown\n const shutdown = async () => {\n console.log('\\n[odd-docs] Shutting down...');\n await server.stop();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n try {\n await server.start();\n\n // Open browser if requested\n if (options.open !== false && host === 'localhost') {\n const url = `http://${host}:${port}`;\n try {\n const { default: open } = await import('open');\n await open(url);\n } catch {\n console.log(`[odd-docs] Open browser manually: ${url}`);\n }\n }\n } catch (error) {\n console.error('[odd-docs] Failed to start server:', error);\n process.exit(1);\n }\n}\n","/**\n * OddDocs Server\n *\n * HTTP server wrapper for serving generated documentation.\n * Enforces safe defaults: localhost binding, no mutations without explicit opt-in.\n */\n\nimport { createServer, type Server, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { FileServer } from './fileServer.js';\nimport { LiveReload } from './livereload.js';\nimport { ApiHandler, type ServerState } from './api.js';\n\nexport interface ServeOptions {\n /** Port to listen on. Default: 3000 */\n port: number;\n /** Host to bind. Default: 'localhost' (safe) */\n host: string;\n /** Documentation output directory */\n outputDir: string;\n /** Enable file watching for live reload. Default: true */\n watch: boolean;\n /** Reload mechanism. Default: 'ws' for localhost, 'sse' for 0.0.0.0 */\n reloadMode: 'ws' | 'sse' | 'poll' | 'none';\n /** Enable mutation API endpoints. Default: false */\n enableMutations: boolean;\n /** Token for mutation endpoints. Required if enableMutations=true */\n mutationToken?: string;\n /** Request timeout in ms. Default: 30000 */\n requestTimeout: number;\n}\n\nexport const DEFAULT_OPTIONS: Omit<ServeOptions, 'outputDir'> = {\n port: 3000,\n host: 'localhost',\n watch: true,\n reloadMode: 'ws',\n enableMutations: false,\n requestTimeout: 30000,\n};\n\nexport class OddDocsServer {\n private server: Server | null = null;\n private fileServer: FileServer;\n private liveReload: LiveReload | null = null;\n private apiHandler: ApiHandler;\n private options: ServeOptions;\n private state: ServerState;\n\n constructor(options: Partial<ServeOptions> & { outputDir: string }) {\n // Apply defaults\n this.options = {\n ...DEFAULT_OPTIONS,\n ...options,\n // Auto-switch to SSE for non-localhost binding (safer for K8s)\n reloadMode:\n options.reloadMode ??\n (options.host && options.host !== 'localhost' ? 'sse' : DEFAULT_OPTIONS.reloadMode),\n };\n\n // Environment overrides\n this.options.host = process.env.ODD_DOCS_HOST ?? this.options.host;\n this.options.port = parseInt(process.env.ODD_DOCS_PORT ?? String(this.options.port), 10);\n this.options.mutationToken = process.env.ODD_DOCS_MUTATION_TOKEN ?? this.options.mutationToken;\n\n this.state = {\n lastGenerateSuccess: true,\n lastGenerateTime: new Date().toISOString(),\n outputDirAccessible: true,\n introspectionConnected: false,\n };\n\n this.fileServer = new FileServer(this.options.outputDir);\n this.apiHandler = new ApiHandler(this.state, this.options);\n }\n\n async start(): Promise<void> {\n // Validate mutation token if mutations enabled\n if (this.options.enableMutations && !this.options.mutationToken) {\n throw new Error(\n 'Mutation token required when --enable-mutations is set. ' +\n 'Set ODD_DOCS_MUTATION_TOKEN or --mutation-token'\n );\n }\n\n this.server = createServer((req, res) => this.handleRequest(req, res));\n\n // Set timeout\n this.server.timeout = this.options.requestTimeout;\n\n // Start live reload if enabled\n if (this.options.watch && this.options.reloadMode !== 'none') {\n this.liveReload = new LiveReload({\n outputDir: this.options.outputDir,\n mode: this.options.reloadMode,\n server: this.server,\n });\n await this.liveReload.start();\n }\n\n return new Promise((resolve, reject) => {\n this.server!.listen(this.options.port, this.options.host, () => {\n console.log(\n `[odd-docs] Server started at http://${this.options.host}:${this.options.port}`\n );\n console.log(`[odd-docs] Serving: ${this.options.outputDir}`);\n if (this.liveReload) {\n console.log(`[odd-docs] Live reload: ${this.options.reloadMode}`);\n }\n resolve();\n });\n\n this.server!.on('error', reject);\n });\n }\n\n async stop(): Promise<void> {\n if (this.liveReload) {\n await this.liveReload.stop();\n }\n if (this.server) {\n return new Promise((resolve) => {\n this.server!.close(() => resolve());\n });\n }\n }\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url ?? '/';\n\n try {\n // API routes\n if (url.startsWith('/api/')) {\n await this.apiHandler.handle(req, res);\n return;\n }\n\n // Live reload endpoints\n if (this.liveReload && url === '/__livereload') {\n await this.liveReload.handleRequest(req, res);\n return;\n }\n\n // Static file serving\n await this.fileServer.serve(req, res);\n } catch (error) {\n console.error('[odd-docs] Request error:', error);\n res.statusCode = 500;\n res.end('Internal Server Error');\n }\n }\n\n updateState(updates: Partial<ServerState>): void {\n Object.assign(this.state, updates);\n }\n}\n","/**\n * File Server\n *\n * Static file serving with security protections.\n * - Path traversal protection via realpath + relative check\n * - MIME type detection\n * - ETag/304 support\n * - Max response size cap\n */\n\nimport { createReadStream, statSync } from 'node:fs';\nimport { realpath } from 'node:fs/promises';\nimport { join, extname, relative, isAbsolute } from 'node:path';\nimport { createHash } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\nconst MAX_RESPONSE_SIZE = 50 * 1024 * 1024; // 50MB\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.md': 'text/markdown; charset=utf-8',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n};\n\nexport class FileServer {\n private rootDir: string;\n private resolvedRoot: string | null = null;\n\n constructor(rootDir: string) {\n this.rootDir = rootDir;\n }\n\n async serve(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n let pathname = decodeURIComponent(url.pathname);\n\n // Default to index.html\n if (pathname === '/' || pathname.endsWith('/')) {\n pathname = join(pathname, 'index.html');\n }\n\n // Resolve and validate path\n const filePath = await this.resolvePath(pathname);\n if (!filePath) {\n res.statusCode = 403;\n res.end('Forbidden: Path traversal blocked');\n return;\n }\n\n // Check file exists and get stats\n let stats;\n try {\n stats = statSync(filePath);\n } catch {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n if (!stats.isFile()) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n // Check size limit\n if (stats.size > MAX_RESPONSE_SIZE) {\n res.statusCode = 413;\n res.end('File too large');\n return;\n }\n\n // ETag handling\n const etag = this.computeETag(filePath, stats.mtime, stats.size);\n const ifNoneMatch = req.headers['if-none-match'];\n if (ifNoneMatch === etag) {\n res.statusCode = 304;\n res.end();\n return;\n }\n\n // Set headers\n const ext = extname(filePath).toLowerCase();\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n\n res.setHeader('Content-Type', contentType);\n res.setHeader('Content-Length', stats.size);\n res.setHeader('ETag', etag);\n res.setHeader('Cache-Control', 'no-cache');\n\n // Stream file\n const stream = createReadStream(filePath);\n stream.pipe(res);\n stream.on('error', () => {\n res.statusCode = 500;\n res.end('Error reading file');\n });\n }\n\n /**\n * Resolve path with traversal protection\n */\n private async resolvePath(pathname: string): Promise<string | null> {\n // Ensure we have the real root path\n if (!this.resolvedRoot) {\n try {\n this.resolvedRoot = await realpath(this.rootDir);\n } catch {\n return null;\n }\n }\n\n // Construct target path\n const targetPath = join(this.rootDir, pathname);\n\n // Resolve to real path (follows symlinks, canonicalizes)\n let resolvedTarget: string;\n try {\n resolvedTarget = await realpath(targetPath);\n } catch {\n return null;\n }\n\n // Check containment: resolved path must be within root\n const rel = relative(this.resolvedRoot, resolvedTarget);\n if (rel.startsWith('..') || isAbsolute(rel)) {\n // Path escapes root directory\n console.warn(`[odd-docs] Path traversal blocked: ${pathname}`);\n return null;\n }\n\n return resolvedTarget;\n }\n\n private computeETag(path: string, mtime: Date, size: number): string {\n const hash = createHash('md5')\n .update(`${path}:${mtime.getTime()}:${size}`)\n .digest('hex')\n .slice(0, 16);\n return `\"${hash}\"`;\n }\n}\n","/**\n * Live Reload\n *\n * File watching and live reload for development.\n * Supports multiple mechanisms: WebSocket, SSE, Polling.\n * WS is dev-only default; SSE is K8s-safe.\n */\n\nimport { watch, type FSWatcher } from 'node:fs';\nimport type { Server, IncomingMessage, ServerResponse } from 'node:http';\n\nexport interface LiveReloadOptions {\n outputDir: string;\n mode: 'ws' | 'sse' | 'poll' | 'none';\n server: Server;\n pollInterval?: number; // for poll mode, ms\n}\n\ntype ReloadMode = 'ws' | 'sse' | 'poll' | 'none';\n\nexport class LiveReload {\n private options: LiveReloadOptions;\n private watcher: FSWatcher | null = null;\n private sseClients: Set<ServerResponse> = new Set();\n private lastChangeTime: number = Date.now();\n private debounceTimer: NodeJS.Timeout | null = null;\n\n constructor(options: LiveReloadOptions) {\n this.options = {\n pollInterval: 5000,\n ...options,\n };\n }\n\n async start(): Promise<void> {\n // Start file watcher with debounce\n const usePolling = process.env.CHOKIDAR_USEPOLLING === '1' || this.options.mode === 'poll';\n\n this.watcher = watch(\n this.options.outputDir,\n { recursive: true, persistent: true },\n (_eventType, filename) => {\n if (filename) {\n this.onFileChange(filename);\n }\n }\n );\n\n if (usePolling) {\n console.log('[odd-docs] Using poll-based file watching');\n }\n\n console.log(`[odd-docs] Live reload started (mode: ${this.options.mode})`);\n }\n\n async stop(): Promise<void> {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n }\n if (this.watcher) {\n this.watcher.close();\n }\n // Close SSE connections\n for (const client of this.sseClients) {\n client.end();\n }\n this.sseClients.clear();\n }\n\n private onFileChange(filename: string): void {\n // Debounce rapid changes\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n }\n this.debounceTimer = setTimeout(() => {\n this.lastChangeTime = Date.now();\n console.log(`[odd-docs] Change detected: ${filename}`);\n this.notifyClients();\n }, 100);\n }\n\n private notifyClients(): void {\n const message = JSON.stringify({ type: 'reload', time: this.lastChangeTime });\n\n // Notify SSE clients\n for (const client of this.sseClients) {\n client.write(`data: ${message}\\n\\n`);\n }\n }\n\n async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const mode = this.options.mode;\n\n if (mode === 'sse') {\n // SSE endpoint\n res.setHeader('Content-Type', 'text/event-stream');\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Connection', 'keep-alive');\n res.setHeader('X-Accel-Buffering', 'no'); // For nginx\n\n res.write(': ping\\n\\n');\n this.sseClients.add(res);\n\n req.on('close', () => {\n this.sseClients.delete(res);\n });\n } else if (mode === 'poll') {\n // Poll endpoint - return last change time\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ lastChange: this.lastChangeTime }));\n } else {\n // Not supported in this mode\n res.statusCode = 404;\n res.end('Live reload not available in this mode');\n }\n }\n\n /**\n * Get client-side script for live reload\n */\n static getClientScript(mode: ReloadMode, pollInterval: number = 5000): string {\n if (mode === 'none') return '';\n\n if (mode === 'sse') {\n return `\n<script>\n(function() {\n const es = new EventSource('/__livereload');\n es.onmessage = function(e) {\n const data = JSON.parse(e.data);\n if (data.type === 'reload') {\n console.log('[odd-docs] Reloading...');\n location.reload();\n }\n };\n es.onerror = function() {\n console.log('[odd-docs] SSE connection lost, will retry...');\n };\n})();\n</script>`;\n }\n\n if (mode === 'poll') {\n return `\n<script>\n(function() {\n let lastChange = 0;\n setInterval(async () => {\n try {\n const res = await fetch('/__livereload');\n const data = await res.json();\n if (lastChange && data.lastChange > lastChange) {\n console.log('[odd-docs] Reloading...');\n location.reload();\n }\n lastChange = data.lastChange;\n } catch (e) {}\n }, ${pollInterval});\n})();\n</script>`;\n }\n\n // WebSocket (ws mode) - requires separate ws server\n return `\n<script>\n(function() {\n const ws = new WebSocket('ws://' + location.host + '/__ws');\n ws.onmessage = function(e) {\n const data = JSON.parse(e.data);\n if (data.type === 'reload') {\n console.log('[odd-docs] Reloading...');\n location.reload();\n }\n };\n ws.onclose = function() {\n console.log('[odd-docs] WebSocket closed, will retry in 3s...');\n setTimeout(() => location.reload(), 3000);\n };\n})();\n</script>`;\n }\n}\n","/**\n * API Handler\n *\n * REST API endpoints for programmatic access.\n * Implements K8s-compatible health semantics.\n * Mutation endpoints require explicit opt-in + token.\n */\n\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { ServeOptions } from './index.js';\n\nconst MAX_IR_SIZE = 10 * 1024 * 1024; // 10MB\n\nexport interface ServerState {\n lastGenerateSuccess: boolean;\n lastGenerateTime: string;\n outputDirAccessible: boolean;\n introspectionConnected: boolean;\n lastIntrospectionTime?: string;\n}\n\nexport class ApiHandler {\n private state: ServerState;\n private options: ServeOptions;\n\n constructor(state: ServerState, options: ServeOptions) {\n this.state = state;\n this.options = options;\n }\n\n async handle(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const path = url.pathname;\n const method = req.method ?? 'GET';\n\n // Route to handlers\n switch (path) {\n case '/api/health':\n return this.handleHealth(res);\n case '/api/ready':\n return this.handleReady(res);\n case '/api/introspection':\n return this.handleIntrospection(res);\n case '/api/docs':\n return this.handleDocs(res);\n case '/api/ir':\n return this.handleIR(res);\n case '/api/capabilities':\n return this.handleCapabilities(res);\n case '/api/regenerate':\n if (method === 'POST') {\n return this.handleRegenerate(req, res);\n }\n return this.methodNotAllowed(res);\n default:\n return this.notFound(res);\n }\n }\n\n /**\n * GET /api/health - Liveness probe\n * Returns 200 if process is running\n */\n private handleHealth(res: ServerResponse): void {\n this.json(res, {\n status: 'ok',\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * GET /api/ready - Readiness probe\n * Returns 200 if last generate succeeded and output is accessible\n */\n private handleReady(res: ServerResponse): void {\n const ready = this.state.lastGenerateSuccess && this.state.outputDirAccessible;\n\n if (!ready) {\n res.statusCode = 503;\n }\n\n this.json(res, {\n ready,\n lastGenerateSuccess: this.state.lastGenerateSuccess,\n lastGenerateTime: this.state.lastGenerateTime,\n outputDirAccessible: this.state.outputDirAccessible,\n });\n }\n\n /**\n * GET /api/introspection - Introspection status\n */\n private handleIntrospection(res: ServerResponse): void {\n this.json(res, {\n connected: this.state.introspectionConnected,\n lastPollTime: this.state.lastIntrospectionTime ?? null,\n });\n }\n\n /**\n * GET /api/docs - List documentation sections\n */\n private handleDocs(res: ServerResponse): void {\n // TODO: Implement actual doc listing\n this.json(res, {\n sections: [],\n message: 'Not implemented yet',\n });\n }\n\n /**\n * GET /api/ir - Full IR dump (capped at 10MB)\n */\n private handleIR(res: ServerResponse): void {\n // TODO: Implement actual IR retrieval\n const ir = { tools: [], prompts: [], resources: [] };\n const irJson = JSON.stringify(ir);\n\n if (irJson.length > MAX_IR_SIZE) {\n this.json(res, {\n truncated: true,\n message: `IR exceeds ${MAX_IR_SIZE / 1024 / 1024}MB limit`,\n partial: null,\n });\n return;\n }\n\n res.setHeader('Content-Type', 'application/json');\n res.end(irJson);\n }\n\n /**\n * GET /api/capabilities - Tool capabilities summary\n */\n private handleCapabilities(res: ServerResponse): void {\n this.json(res, {\n serve: {\n host: this.options.host,\n port: this.options.port,\n reloadMode: this.options.reloadMode,\n mutationsEnabled: this.options.enableMutations,\n },\n });\n }\n\n /**\n * POST /api/regenerate - Trigger manual regeneration\n * Requires --enable-mutations and valid token\n */\n private handleRegenerate(req: IncomingMessage, res: ServerResponse): void {\n // Check if mutations are enabled\n if (!this.options.enableMutations) {\n res.statusCode = 403;\n this.json(res, {\n error: 'Mutations disabled',\n message: 'Start server with --enable-mutations to use this endpoint',\n });\n return;\n }\n\n // Validate token\n const token = req.headers['x-mutation-token'];\n if (token !== this.options.mutationToken) {\n res.statusCode = 401;\n this.json(res, {\n error: 'Unauthorized',\n message: 'Invalid or missing X-Mutation-Token header',\n });\n return;\n }\n\n // TODO: Trigger actual regeneration\n this.json(res, {\n status: 'queued',\n message: 'Regeneration triggered',\n timestamp: new Date().toISOString(),\n });\n }\n\n private json(res: ServerResponse, data: unknown): void {\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(data, null, 2));\n }\n\n private notFound(res: ServerResponse): void {\n res.statusCode = 404;\n this.json(res, { error: 'Not Found' });\n }\n\n private methodNotAllowed(res: ServerResponse): void {\n res.statusCode = 405;\n this.json(res, { error: 'Method Not Allowed' });\n }\n}\n"],"mappings":"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","names":["join","join","resolve","resolve","join","resolve","join","createHash","resolve","resolve","join","require"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oddessentials/odd-docs",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "MCP-native documentation generator for clients, servers, and tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"clean": "rimraf dist",
|
|
23
23
|
"ci": "npm run lint && npm run format:check && npm run typecheck && npm run build && npm run test",
|
|
24
24
|
"release:dry-run": "semantic-release --dry-run",
|
|
25
|
-
"prepare": "husky"
|
|
25
|
+
"prepare": "husky",
|
|
26
|
+
"postinstall": "git config core.hooksPath .husky || true"
|
|
26
27
|
},
|
|
27
28
|
"keywords": [
|
|
28
29
|
"mcp",
|
|
@@ -59,6 +60,7 @@
|
|
|
59
60
|
"@commitlint/cli": "^19.0.0",
|
|
60
61
|
"@commitlint/config-conventional": "^19.0.0",
|
|
61
62
|
"@semantic-release/changelog": "^6.0.3",
|
|
63
|
+
"@semantic-release/exec": "^7.1.0",
|
|
62
64
|
"@semantic-release/git": "^10.0.1",
|
|
63
65
|
"@semantic-release/github": "^12.0.2",
|
|
64
66
|
"@types/node": "^22.0.0",
|