@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 CHANGED
@@ -1,13 +1,44 @@
1
1
  # odd-docs
2
2
 
3
- `odd-docs` is a documentation generation utility that lives inside the **oddessentials-mcp** ecosystem. Its purpose is to generate deterministic, structured documentation for MCP-compatible tools, servers, or repositories by inspecting manifests, schemas, and related metadata.
3
+ [![npm version](https://img.shields.io/npm/v/@oddessentials/odd-docs.svg)](https://www.npmjs.com/package/@oddessentials/odd-docs)
4
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D22.0.0-brightgreen)](https://nodejs.org)
5
+ [![License: OEL](https://img.shields.io/badge/license-OEL-blue)](./LICENSE)
4
6
 
5
- It can be used in two distinct ways:
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
- 1. **Manually**, as a standalone CLI tool
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
- These two modes differ significantly in how execution, file access, and persistence work. This README documents both paths explicitly.
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 schemas from a repository
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
- It is intentionally **non-interactive** and **deterministic**: given the same inputs, it produces the same outputs.
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
- If you are using `odd-docs` outside of an MCP host, install it via npm:
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 it without installing:
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
- ## Manual CLI usage
75
+ ## Global Options
45
76
 
46
- ### Basic command structure
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
- ### Generating documentation
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
- By default, this:
108
+ **Options:**
67
109
 
68
- - Reads documentation inputs from `<repo-path>`
69
- - Writes generated output to a documentation directory inside the repository
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
- Common options include:
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 typically include:
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
- These outputs **persist on disk** when running manually.
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
- ### Validating documentation inputs
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
- Validation checks include (non-exhaustive):
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
- Validation **does not write output files**.
107
- It exits non-zero if errors are found, making it suitable for CI.
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
- ### Serving documentation locally
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
- This:
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 (if not already generated)
120
- - Starts a local HTTP server to view the docs
121
- - Optionally watches for file changes
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
- By default:
196
+ **Exit codes:**
124
197
 
125
- - Host: `localhost`
126
- - Port: `3000`
198
+ - `0` — Clean shutdown (SIGINT/SIGTERM)
199
+ - `1` — Error starting server
127
200
 
128
- This mode is intended for **local development only**.
201
+ This mode is intended for local development and inspection.
129
202
 
130
203
  ---
131
204
 
132
- ## Temporary directories (manual usage)
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
- - Generated documentation is written to real directories you control
138
- - **Nothing is automatically deleted**
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
- If a temporary directory is used internally (e.g. during processing), it is scoped to the execution and does not affect your outputs.
213
+ Any temporary directories used internally during processing are scoped to execution only and do not affect output persistence.
141
214
 
142
- **You control persistence entirely** by choosing output paths.
215
+ **Persistence is fully under user control** in manual mode.
143
216
 
144
217
  ---
145
218
 
146
- ## Usage via MCP (oddessentials-mcp)
219
+ ## MCP-managed execution (oddessentials-mcp)
147
220
 
148
- When `odd-docs` is used through **oddessentials-mcp**, you do **not** run the CLI yourself.
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 happens in a sandboxed environment
225
+ - Outputs are collected as MCP artifacts
226
+ - Execution occurs in a sandboxed environment
156
227
 
157
- This has important implications.
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 invoked by an MCP host:
234
+ When run under MCP control:
164
235
 
165
- - A **temporary working directory** is created automatically
166
- - Repository files are copied or mounted into that directory
167
- - Documentation output is written **inside that temporary directory**
168
- - After execution completes, the directory is **deleted**
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
- ### ⚠️ Persistence warning (important)
241
+ ### Persistence warning
171
242
 
172
- When running under MCP control:
243
+ When executed via MCP:
173
244
 
174
- - **You cannot persist the temporary directory**
175
- - There is no supported flag to “keep” it
176
- - The directory lifecycle is owned by the MCP host
177
- - Files are removed even after successful execution
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 you need persistent documentation files:
250
+ If persistent documentation files are required, they must be:
180
251
 
181
- - Retrieve them from the MCP artifact output
182
- - Or run `odd-docs` manually outside of MCP
252
+ - Retrieved from MCP artifact outputs, or
253
+ - Generated via manual CLI execution
183
254
 
184
- Attempting to rely on MCP temp directories for persistence is unsupported and unsafe.
255
+ Relying on MCP-managed temporary directories for persistence is unsupported.
185
256
 
186
257
  ---
187
258
 
188
- ## Why this design exists
189
-
190
- The MCP execution model intentionally:
259
+ ## Execution model comparison
191
260
 
192
- - Isolates tools from the host system
193
- - Prevents unintended filesystem access
194
- - Ensures repeatable, side-effect-free runs
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
- `odd-docs` follows this model strictly.
197
- Persistence is handled **by the MCP host**, not by `odd-docs` itself.
269
+ Both modes generate documentation automatically.
270
+ They differ in **who owns execution and filesystem lifecycle**.
198
271
 
199
272
  ---
200
273
 
201
- ## When to use which mode
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
- ### Use MCP-managed mode if you:
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
- - Are generating docs as part of an automated pipeline
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
- ## Non-goals
285
+ ## License
218
286
 
219
- `odd-docs` does **not**:
287
+ This project is source-available under the [Odd Essentials License (OEL)](./LICENSE).
220
288
 
221
- - Edit your source files
222
- - Maintain long-lived state
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
- ## Summary
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
- Both are valid — just not interchangeable.
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
@@ -1,3 +1,5 @@
1
+ #!/usr/bin/env node
2
+
1
3
  // src/cli/index.ts
2
4
  import { Command } from "commander";
3
5
  import { createRequire } from "module";
@@ -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, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\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"]}
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, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\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",
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",