aisp-validator 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +65 -174
  2. package/bin/cli.js +173 -19
  3. package/package.json +1 -1
  4. package/src/index.js +120 -23
package/README.md CHANGED
@@ -1,52 +1,36 @@
1
1
  # AISP Validator
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/aisp-validator.svg)](https://www.npmjs.com/package/aisp-validator)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
5
 
6
- **Validate AI Symbolic Protocol (AISP) 5.1 documents** with <2% ambiguity using a lightweight <10KB WASM kernel.
6
+ **Validate AISP 5.1 documents** — AI Symbolic Protocol with <2% ambiguity.
7
7
 
8
- AISP is a formal specification language designed for AI-to-AI communication, providing precise, unambiguous specifications that eliminate interpretation errors.
9
-
10
- ## Installation
8
+ ## Install
11
9
 
12
10
  ```bash
13
11
  npm install aisp-validator
14
12
  ```
15
13
 
16
- Or run directly with npx:
17
-
18
- ```bash
19
- npx aisp-validator validate your-spec.aisp
20
- ```
21
-
22
- ## Quick Start
23
-
24
- ### CLI Usage
14
+ ## CLI Usage
25
15
 
26
16
  ```bash
27
17
  # Validate a document
28
18
  npx aisp-validator validate spec.aisp
29
19
 
30
- # Get quality tier (◊⁺⁺, ◊⁺, ◊, ◊⁻, ⊘)
31
- npx aisp-validator tier spec.aisp
32
-
33
- # Get density score
34
- npx aisp-validator density spec.aisp
35
-
36
- # Debug - detailed density breakdown
37
- npx aisp-validator debug spec.aisp
20
+ # Detailed output with JSON
21
+ npx aisp-validator validate spec.aisp --long
22
+ npx aisp-validator validate spec.aisp --json
38
23
  ```
39
24
 
40
- **Example output:**
25
+ **Output:**
41
26
  ```
42
27
  ✓ VALID
43
28
  Tier: ◊⁺⁺ Platinum
44
29
  Semantic (δ): 1.000
45
30
  Pure (ρ): 1.857
46
- Ambiguity: 0.010
47
31
  ```
48
32
 
49
- ### Node.js
33
+ ## Node.js Usage
50
34
 
51
35
  ```javascript
52
36
  import AISP from 'aisp-validator';
@@ -54,193 +38,100 @@ import AISP from 'aisp-validator';
54
38
  await AISP.init();
55
39
 
56
40
  const result = AISP.validate(`
57
- 𝔸1.0.example@2026-01-15
41
+ 𝔸1.0.example@2026-01-16
58
42
  γ≔test
59
43
 
60
44
  ⟦Ω:Meta⟧{ ∀D:Ambig(D)<0.02 }
61
45
  ⟦Σ:Types⟧{ T≜ℕ }
62
46
  ⟦Γ:Rules⟧{ ∀x:T:x≥0 }
63
47
  ⟦Λ:Funcs⟧{ f≜λx.x }
64
- ⟦Ε⟧⟨δ≜0.75;φ≜100;τ≜◊⁺⁺⟩
48
+ ⟦Ε⟧⟨δ≜0.75;τ≜◊⁺⁺⟩
65
49
  `);
66
50
 
67
- console.log(result);
68
- // {
69
- // valid: true,
70
- // tier: '◊⁺⁺',
71
- // tierName: 'Platinum',
72
- // delta: 0.82,
73
- // pureDensity: 1.85,
74
- // ambiguity: 0.01
75
- // }
51
+ console.log(result.valid); // true
52
+ console.log(result.tier); // '◊⁺⁺'
53
+ console.log(result.tierName); // 'Platinum'
54
+ console.log(result.delta); // 0.82
76
55
  ```
77
56
 
78
- ### Browser
57
+ ## Browser Usage
79
58
 
80
59
  ```html
81
60
  <script type="module">
82
61
  import AISP from 'aisp-validator/browser';
83
62
 
84
63
  await AISP.init('/path/to/aisp.wasm');
85
-
86
- const result = AISP.validate(documentSource);
87
- console.log(result.tier); // '◊⁺⁺'
64
+ const result = AISP.validate(source);
88
65
  </script>
89
66
  ```
90
67
 
91
- ## API Reference
92
-
93
- ### `AISP.init(wasmPath?)`
94
- Initialize the WASM kernel. Must be called once before validation.
95
-
96
- ### `AISP.validate(source)`
97
- Validate an AISP document. Returns:
98
- ```javascript
99
- {
100
- valid: boolean, // true if document passes validation
101
- tier: string, // '⊘' | '◊⁻' | '◊' | '◊⁺' | '◊⁺⁺'
102
- tierName: string, // 'Reject' | 'Bronze' | 'Silver' | 'Gold' | 'Platinum'
103
- tierValue: number, // 0-4 (numeric tier)
104
- delta: number, // Semantic density δ [0, 1]
105
- pureDensity: number, // Pure density ρ (symbols/tokens)
106
- ambiguity: number, // [0, 1], must be <0.02
107
- errorCode: number // 0 = success
108
- }
109
- ```
110
-
111
- ### `AISP.debug(source)`
112
- Get detailed density breakdown for debugging.
113
-
114
- ### `AISP.isValid(source)`
115
- Quick check: returns `true` if valid.
116
-
117
- ### `AISP.getTier(source)`
118
- Returns tier symbol: `'◊⁺⁺'`, `'◊⁺'`, `'◊'`, `'◊⁻'`, or `'⊘'`
119
-
120
- ### `AISP.getDensity(source)`
121
- Returns semantic density score (δ) between 0 and 1.
122
-
123
- ### `AISP.validateFile(path)` (Node.js only)
124
- Validate a file by path.
125
-
126
- ### `AISP.debugFile(path)` (Node.js only)
127
- Debug a file by path.
128
-
129
68
  ## Quality Tiers
130
69
 
131
- | Tier | Symbol | Threshold | Use Case |
132
- |------|--------|-----------|----------|
133
- | **Platinum** | ◊⁺⁺ | δ ≥ 0.75 | Production deployment |
134
- | **Gold** | ◊⁺ | δ ≥ 0.60 | Staging/pre-production |
135
- | **Silver** | ◊ | δ ≥ 0.40 | Development/testing |
136
- | **Bronze** | ◊⁻ | δ ≥ 0.20 | Draft/review |
137
- | **Reject** | ⊘ | δ < 0.20 | Insufficient quality |
70
+ | Tier | Symbol | δ Threshold | Description |
71
+ |------|--------|-------------|-------------|
72
+ | Platinum | ◊⁺⁺ | ≥ 0.75 | Production ready |
73
+ | Gold | ◊⁺ | ≥ 0.60 | Pre-production |
74
+ | Silver | ◊ | ≥ 0.40 | Development |
75
+ | Bronze | ◊⁻ | ≥ 0.20 | Draft |
76
+ | Reject | ⊘ | < 0.20 | Invalid |
138
77
 
139
- ## Density Metrics
78
+ ## Required Blocks
140
79
 
141
- ### Semantic Density (δ)
142
- Measures specification completeness:
143
- ```
144
- δ = (blockScore × 0.4) + (bindingScore × 0.6)
145
- ```
146
- - **blockScore**: Required blocks present (⟦Ω⟧, ⟦Σ⟧, ⟦Γ⟧, ⟦Λ⟧, ⟦Ε⟧)
147
- - **bindingScore**: Semantic operators (≜, ≔, ∀, ∃, λ, ⇒, ∈, etc.)
80
+ Every AISP document needs 5 blocks:
148
81
 
149
- ### Pure Density (ρ)
150
- Measures symbol concentration:
151
- ```
152
- ρ = |AISP_symbols| ÷ |non_ws_tokens|
153
- ```
154
-
155
- ## Required AISP Blocks
156
-
157
- Every valid AISP document must include these 5 blocks:
158
-
159
- | Block | Name | Purpose |
160
- |-------|------|---------|
161
- | `⟦Ω⟧` | Meta | Metadata and constraints |
162
- | `⟦Σ⟧` | Types | Type definitions |
163
- | `⟦Γ⟧` | Rules | Inference rules |
164
- | `⟦Λ⟧` | Funcs | Function definitions |
165
- | `⟦Ε⟧` | Evidence | Quality metrics |
166
-
167
- ## Example AISP Document
168
-
169
- ```aisp
170
- 𝔸5.1.tic-tac-toe@2026-01-15
171
- γ≔game-spec
82
+ | Block | Purpose |
83
+ |-------|---------|
84
+ | `⟦Ω⟧` | Meta/Foundation |
85
+ | `⟦Σ⟧` | Types/Glossary |
86
+ | `⟦Γ⟧` | Rules/Inference |
87
+ | `⟦Λ⟧` | Functions |
88
+ | `⟦Ε⟧` | Evidence |
172
89
 
173
- ⟦Ω:Meta⟧{
174
- ∀D∈AISP:Ambig(D)<0.02
175
- Target≜AI-Agents
176
- }
90
+ ## API
177
91
 
178
- ⟦Σ:Types⟧{
179
- Player≜{X,O}
180
- Cell≜{Empty,X,O}
181
- Board≜Cell[9]
182
- }
92
+ | Method | Returns | Description |
93
+ |--------|---------|-------------|
94
+ | `AISP.init()` | Promise | Initialize WASM (call once) |
95
+ | `AISP.validate(src)` | Object | Full validation result |
96
+ | `AISP.isValid(src)` | boolean | Quick valid check |
97
+ | `AISP.getTier(src)` | string | Tier symbol only |
98
+ | `AISP.getDensity(src)` | number | Semantic density δ |
99
+ | `AISP.validateFile(path)` | Object | Validate file (Node.js) |
183
100
 
184
- ⟦Γ:Rules⟧{
185
- ∀move:ValidMove(board,pos)⇔board[pos]=Empty
186
- ∀win:WinCondition⇔∃line∈Lines:∀c∈line:c=player
187
- }
101
+ ### Validation Result
188
102
 
189
- ⟦Λ:Funcs⟧{
190
- makeMove≜λ(board,pos,player).board[pos]←player
191
- checkWin≜λboard.∃p∈Player:WinCondition(board,p)
103
+ ```javascript
104
+ {
105
+ valid: true, // Document passes validation
106
+ tier: '◊⁺⁺', // Quality tier symbol
107
+ tierName: 'Platinum', // Tier name
108
+ tierValue: 4, // Numeric (0-4)
109
+ delta: 0.82, // Semantic density [0,1]
110
+ pureDensity: 1.85, // Symbol concentration
111
+ ambiguity: 0.01, // Must be <0.02
112
+ errorCode: 0 // 0 = success
192
113
  }
193
-
194
- ⟦Ε⟧⟨δ≜0.75;φ≜100;τ≜◊⁺⁺⟩
195
114
  ```
196
115
 
197
- ## Building from Source
198
-
199
- The validator includes full Rust source code:
200
-
201
- ```bash
202
- # Prerequisites
203
- rustup target add wasm32-unknown-unknown
204
- cargo install wasm-opt # or: npm install -g binaryen
205
-
206
- # Build WASM kernel
207
- cd wasm
208
- ./build.sh
209
-
210
- # Output: aisp.wasm (<10KB)
211
- ```
212
-
213
- ## Architecture
214
-
215
- - **WASM Kernel**: Zero-allocation Rust core (<10KB)
216
- - **Type System**: Based on dependent type theory
217
- - **Symbol Table**: AISP Σ_512 glossary (50+ formal symbols)
218
- - **Validation**: Structural + semantic analysis
219
-
220
116
  ## What is AISP?
221
117
 
222
- **AI Symbolic Protocol (AISP)** is a formal specification language designed for precise AI-to-AI communication. Key benefits:
118
+ **AI Symbolic Protocol** is a formal specification language for AI-to-AI communication:
223
119
 
224
- - **<2% Ambiguity**: Eliminates interpretation errors
225
- - **Formal Semantics**: Based on type theory and logic
226
- - **Machine-Readable**: Designed for AI agents
227
- - **Human-Auditable**: Clear structure for review
228
-
229
- Learn more:
230
- - [AI Guide](https://github.com/bar181/aisp-open-core/blob/main/AI_GUIDE.md) - Complete AISP specification
231
- - [Human Guide](https://github.com/bar181/aisp-open-core/blob/main/HUMAN_GUIDE.md) - Human-readable introduction
232
- - [Reference (Rosetta Stone)](https://github.com/bar181/aisp-open-core/blob/main/reference.md) - Symbol glossary
120
+ - **<2% Ambiguity** Eliminates interpretation errors
121
+ - **Formal Semantics** Based on type theory
122
+ - **Machine-Readable** Designed for AI agents
123
+ - **Human-Auditable** Clear structure for review
233
124
 
234
125
  ## Links
235
126
 
236
- - **GitHub**: [github.com/bar181/aisp-open-core](https://github.com/bar181/aisp-open-core)
237
- - **npm**: [npmjs.com/package/aisp-validator](https://www.npmjs.com/package/aisp-validator)
238
- - **Issues**: [Report bugs](https://github.com/bar181/aisp-open-core/issues)
127
+ - [AI Guide](https://github.com/bar181/aisp-open-core/blob/main/AI_GUIDE.md) — Full AISP 5.1 spec
128
+ - [Human Guide](https://github.com/bar181/aisp-open-core/blob/main/HUMAN_GUIDE.md) — Introduction
129
+ - [GitHub](https://github.com/bar181/aisp-open-core)
239
130
 
240
- ## License
131
+ ## Author
241
132
 
242
- MIT License - see [LICENSE](https://github.com/bar181/aisp-open-core/blob/main/validator/LICENSE)
133
+ Bradley Ross [GitHub @bar181](https://github.com/bar181)
243
134
 
244
- ---
135
+ ## License
245
136
 
246
- **Made for AI agents, auditable by humans.**
137
+ MIT
package/bin/cli.js CHANGED
@@ -1,18 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * AISP Validator CLI
4
- * Usage: aisp-validator <command> [file]
4
+ * Usage: aisp-validator <command> [file] [options]
5
5
  */
6
6
 
7
- import AISP from '../src/index.js';
8
- import { readFile } from 'fs/promises';
7
+ import AISP, { SUPPORTED_EXTENSIONS, SIZE_LIMITS } from '../src/index.js';
8
+ import { readFile, stat } from 'fs/promises';
9
9
  import { existsSync } from 'fs';
10
+ import { extname, basename } from 'path';
11
+
12
+ const VERSION = '0.3.0';
10
13
 
11
14
  const HELP = `
12
- AISP Validator v0.2.2 - Validate AISP 5.1 documents
15
+ AISP Validator v${VERSION} - Validate AISP 5.1 documents
13
16
 
14
17
  Usage:
15
- aisp-validator <command> [file]
18
+ aisp-validator <command> [file] [options]
16
19
  aisp-validator [file] Shorthand for validate
17
20
 
18
21
  Commands:
@@ -20,8 +23,18 @@ Commands:
20
23
  tier <file> Get quality tier (⊘ to ◊⁺⁺)
21
24
  density <file> Get density score (δ)
22
25
  debug <file> Show detailed density breakdown
26
+ long <file> Long-format output with full details
23
27
  help Show this help message
24
28
 
29
+ Options:
30
+ --long, -l Long-format output (detailed)
31
+ --json, -j JSON output
32
+ --max-size <n> Maximum document size in KB (default: 64)
33
+ --strict Force WASM validation (max 1KB)
34
+
35
+ Supported File Types:
36
+ ${SUPPORTED_EXTENSIONS.join(', ')}
37
+
25
38
  Quality Tiers:
26
39
  ◊⁺⁺ Platinum δ ≥ 0.75
27
40
  ◊⁺ Gold δ ≥ 0.60
@@ -41,8 +54,108 @@ Examples:
41
54
  npx aisp-validator validate spec.aisp
42
55
  npx aisp-validator tier spec.aisp
43
56
  npx aisp-validator debug spec.aisp
57
+ npx aisp-validator long spec.md --max-size 128
58
+ npx aisp-validator validate spec.aisp --json
44
59
  `;
45
60
 
61
+ /**
62
+ * Parse CLI arguments
63
+ */
64
+ function parseArgs(args) {
65
+ const result = {
66
+ command: 'validate',
67
+ file: null,
68
+ options: {
69
+ long: false,
70
+ json: false,
71
+ strict: false,
72
+ maxSize: SIZE_LIMITS.DEFAULT_MAX / 1024
73
+ }
74
+ };
75
+
76
+ const commands = ['validate', 'tier', 'density', 'debug', 'long', 'help'];
77
+ let i = 0;
78
+
79
+ while (i < args.length) {
80
+ const arg = args[i];
81
+
82
+ if (arg === '--long' || arg === '-l') {
83
+ result.options.long = true;
84
+ } else if (arg === '--json' || arg === '-j') {
85
+ result.options.json = true;
86
+ } else if (arg === '--strict') {
87
+ result.options.strict = true;
88
+ } else if (arg === '--max-size' && args[i + 1]) {
89
+ result.options.maxSize = parseInt(args[++i], 10) || 64;
90
+ } else if (commands.includes(arg)) {
91
+ result.command = arg;
92
+ } else if (!arg.startsWith('-') && !result.file) {
93
+ result.file = arg;
94
+ }
95
+ i++;
96
+ }
97
+
98
+ // 'long' command implies long format
99
+ if (result.command === 'long') {
100
+ result.options.long = true;
101
+ result.command = 'validate';
102
+ }
103
+
104
+ return result;
105
+ }
106
+
107
+ /**
108
+ * Check if file extension is supported
109
+ */
110
+ function isExtensionSupported(file) {
111
+ const ext = extname(file).toLowerCase();
112
+ // Also allow files without extension (assume AISP)
113
+ return ext === '' || SUPPORTED_EXTENSIONS.includes(ext);
114
+ }
115
+
116
+ /**
117
+ * Format long output
118
+ */
119
+ function formatLong(file, result, debug, fileSize) {
120
+ const lines = [];
121
+ lines.push(`\n${'═'.repeat(60)}`);
122
+ lines.push(`AISP Document Validation Report`);
123
+ lines.push(`${'═'.repeat(60)}`);
124
+ lines.push(`\nFile: ${basename(file)}`);
125
+ lines.push(`Size: ${(fileSize / 1024).toFixed(2)} KB`);
126
+ lines.push(`Mode: ${result.mode || 'wasm'}`);
127
+ lines.push(`\n${'─'.repeat(40)}`);
128
+ lines.push(`RESULT: ${result.valid ? '✓ VALID' : '✗ INVALID'}`);
129
+ lines.push(`${'─'.repeat(40)}`);
130
+ lines.push(`\nQuality Tier: ${result.tier} ${result.tierName}`);
131
+ lines.push(`\nMetrics:`);
132
+ lines.push(` Semantic Density (δ): ${result.delta.toFixed(4)}`);
133
+ lines.push(` Pure Density (ρ): ${result.pureDensity.toFixed(4)}`);
134
+ lines.push(` Ambiguity: ${result.ambiguity.toFixed(4)}`);
135
+
136
+ if (debug) {
137
+ lines.push(`\n${'─'.repeat(40)}`);
138
+ lines.push(`Semantic Score Breakdown:`);
139
+ lines.push(` Block Score: ${(debug.blockScore * 100).toFixed(1)}% (weight: 40%)`);
140
+ lines.push(` Binding Score: ${(debug.bindingScore * 100).toFixed(1)}% (weight: 60%)`);
141
+ lines.push(`\nBlocks Found: ${debug.breakdown.blocksFound}/${debug.breakdown.blocksRequired}`);
142
+ lines.push(` Required: ⟦Ω⟧, ⟦Σ⟧, ⟦Γ⟧, ⟦Λ⟧, ⟦Ε⟧`);
143
+ lines.push(`\nSemantic Operators: ${debug.breakdown.totalBindings}`);
144
+ lines.push(` ≜ definitions: ${debug.breakdown.definitions}`);
145
+ lines.push(` ≔ assignments: ${debug.breakdown.assignments}`);
146
+ lines.push(` ∀∃ quantifiers: ${debug.breakdown.quantifiers}`);
147
+ lines.push(` λ lambdas: ${debug.breakdown.lambdas}`);
148
+ lines.push(` ⇒⇔ implications: ${debug.breakdown.implications}`);
149
+ lines.push(` ∈⊆∩∪ set ops: ${debug.breakdown.setOps}`);
150
+ lines.push(`\nPure Density:`);
151
+ lines.push(` AISP Symbols: ${debug.breakdown.symbolCount}`);
152
+ lines.push(` Total Tokens: ${debug.breakdown.tokenCount}`);
153
+ }
154
+
155
+ lines.push(`\n${'═'.repeat(60)}`);
156
+ return lines.join('\n');
157
+ }
158
+
46
159
  async function main() {
47
160
  const args = process.argv.slice(2);
48
161
 
@@ -52,22 +165,15 @@ async function main() {
52
165
  }
53
166
 
54
167
  if (args[0] === '--version' || args[0] === '-v') {
55
- console.log('aisp-validator v0.2.2');
168
+ console.log(`aisp-validator v${VERSION}`);
56
169
  process.exit(0);
57
170
  }
58
171
 
59
- let command = args[0];
60
- let file = args[1];
61
-
62
- // If first arg is a file (no command), default to validate
63
- if (command && !['validate', 'tier', 'density', 'debug'].includes(command)) {
64
- file = command;
65
- command = 'validate';
66
- }
172
+ const { command, file, options } = parseArgs(args);
67
173
 
68
174
  if (!file) {
69
175
  console.error('Error: No file specified');
70
- console.log('Usage: aisp-validator <command> <file>');
176
+ console.log('Usage: aisp-validator <command> <file> [options]');
71
177
  process.exit(1);
72
178
  }
73
179
 
@@ -76,19 +182,51 @@ async function main() {
76
182
  process.exit(1);
77
183
  }
78
184
 
185
+ // Check file extension
186
+ if (!isExtensionSupported(file)) {
187
+ console.warn(`Warning: File extension not in supported list: ${SUPPORTED_EXTENSIONS.join(', ')}`);
188
+ console.warn('Continuing with validation...\n');
189
+ }
190
+
79
191
  try {
80
- await AISP.init();
192
+ // Initialize with max size option
193
+ await AISP.init({ maxDocSize: options.maxSize * 1024 });
194
+
81
195
  const content = await readFile(file, 'utf-8');
196
+ const fileStats = await stat(file);
197
+ const fileSize = fileStats.size;
82
198
 
83
199
  switch (command) {
84
200
  case 'validate': {
85
- const result = AISP.validate(content);
201
+ const result = AISP.validate(content, { strict: options.strict });
202
+ const debug = options.long ? AISP.debug(content) : null;
203
+
204
+ // JSON output
205
+ if (options.json) {
206
+ const output = {
207
+ file: basename(file),
208
+ fileSize,
209
+ ...result,
210
+ ...(debug ? { breakdown: debug.breakdown } : {})
211
+ };
212
+ console.log(JSON.stringify(output, null, 2));
213
+ process.exit(result.valid ? 0 : 1);
214
+ }
215
+
216
+ // Long format output
217
+ if (options.long) {
218
+ console.log(formatLong(file, result, debug, fileSize));
219
+ process.exit(result.valid ? 0 : 1);
220
+ }
221
+
222
+ // Standard output
86
223
  if (result.valid) {
87
224
  console.log(`✓ VALID`);
88
225
  console.log(` Tier: ${result.tier} ${result.tierName}`);
89
226
  console.log(` Semantic (δ): ${result.delta.toFixed(3)}`);
90
227
  console.log(` Pure (ρ): ${result.pureDensity.toFixed(3)}`);
91
228
  console.log(` Ambiguity: ${result.ambiguity.toFixed(3)}`);
229
+ if (result.mode) console.log(` Mode: ${result.mode}`);
92
230
  process.exit(0);
93
231
  } else {
94
232
  console.log(`✗ INVALID`);
@@ -105,20 +243,36 @@ async function main() {
105
243
 
106
244
  case 'tier': {
107
245
  const result = AISP.validate(content);
108
- console.log(`${result.tier} ${result.tierName}`);
246
+ if (options.json) {
247
+ console.log(JSON.stringify({ tier: result.tier, tierName: result.tierName, tierValue: result.tierValue }));
248
+ } else {
249
+ console.log(`${result.tier} ${result.tierName}`);
250
+ }
109
251
  break;
110
252
  }
111
253
 
112
254
  case 'density': {
113
255
  const result = AISP.validate(content);
114
- console.log(result.delta.toFixed(4));
256
+ if (options.json) {
257
+ console.log(JSON.stringify({ delta: result.delta, pureDensity: result.pureDensity }));
258
+ } else {
259
+ console.log(result.delta.toFixed(4));
260
+ }
115
261
  break;
116
262
  }
117
263
 
118
264
  case 'debug': {
119
265
  const debug = AISP.debug(content);
266
+
267
+ if (options.json) {
268
+ console.log(JSON.stringify(debug, null, 2));
269
+ break;
270
+ }
271
+
120
272
  console.log(`\nAISP Density Debug`);
121
273
  console.log(`==================`);
274
+ console.log(`\nFile: ${basename(file)}`);
275
+ console.log(`Size: ${(fileSize / 1024).toFixed(2)} KB`);
122
276
  console.log(`\nTier: ${debug.tier} ${debug.tierName}`);
123
277
  console.log(`Semantic (δ): ${debug.delta.toFixed(3)}`);
124
278
  console.log(`Pure (ρ): ${debug.pureDensity.toFixed(3)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aisp-validator",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "AISP 5.1 document validator - validates AI Symbolic Protocol specifications with <2% ambiguity",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -131,20 +131,48 @@ function getTierFromDelta(delta) {
131
131
  return { tier: '⊘', tierValue: 0, tierName: 'Reject' };
132
132
  }
133
133
 
134
+ /**
135
+ * Supported file extensions for AISP documents
136
+ */
137
+ const SUPPORTED_EXTENSIONS = ['.aisp', '.md', '.txt', '.spec', '.aisp5'];
138
+
139
+ /**
140
+ * Default and max document size limits
141
+ */
142
+ const SIZE_LIMITS = {
143
+ DEFAULT_MAX: 64 * 1024, // 64KB default
144
+ ABSOLUTE_MAX: 1024 * 1024, // 1MB absolute max
145
+ WASM_MAX: 1024 // WASM kernel limit
146
+ };
147
+
134
148
  const AISP = {
135
149
  _instance: null,
136
150
  _memory: null,
137
151
  _allocPtr: 0x1000,
138
152
  _initialized: false,
153
+ _maxDocSize: SIZE_LIMITS.DEFAULT_MAX,
139
154
 
140
155
  /**
141
156
  * Initialize AISP kernel
142
- * @param {string} [wasmPath] - Optional path to aisp.wasm
157
+ * @param {string|object} [options] - Path to aisp.wasm or options object
158
+ * @param {string} [options.wasmPath] - Path to aisp.wasm
159
+ * @param {number} [options.maxDocSize] - Maximum document size in bytes (default: 64KB)
143
160
  * @returns {Promise<number>} 0 on success
144
161
  */
145
- async init(wasmPath) {
162
+ async init(options) {
146
163
  if (this._initialized) return 0;
147
164
 
165
+ // Handle both string (legacy) and object (new) options
166
+ let wasmPath;
167
+ if (typeof options === 'string') {
168
+ wasmPath = options;
169
+ } else if (options && typeof options === 'object') {
170
+ wasmPath = options.wasmPath;
171
+ if (options.maxDocSize) {
172
+ this._maxDocSize = Math.min(options.maxDocSize, SIZE_LIMITS.ABSOLUTE_MAX);
173
+ }
174
+ }
175
+
148
176
  const path = wasmPath || join(__dirname, '..', 'wasm', 'aisp.wasm');
149
177
  const bytes = await readFile(path);
150
178
 
@@ -165,12 +193,22 @@ const AISP = {
165
193
  return this._instance.aisp_init();
166
194
  },
167
195
 
196
+ /**
197
+ * Set maximum document size
198
+ * @param {number} size - Maximum size in bytes
199
+ */
200
+ setMaxDocSize(size) {
201
+ this._maxDocSize = Math.min(size, SIZE_LIMITS.ABSOLUTE_MAX);
202
+ },
203
+
168
204
  /**
169
205
  * Validate AISP document
170
206
  * @param {string} source - AISP source code
207
+ * @param {object} [options] - Validation options
208
+ * @param {boolean} [options.strict] - Use strict WASM validation (limited to 1KB)
171
209
  * @returns {object} Validation result
172
210
  */
173
- validate(source) {
211
+ validate(source, options = {}) {
174
212
  if (!this._instance) {
175
213
  throw new Error('AISP not initialized. Call init() first.');
176
214
  }
@@ -178,41 +216,100 @@ const AISP = {
178
216
  const encoder = new TextEncoder();
179
217
  const bytes = encoder.encode(source);
180
218
 
181
- const ptr = 0x1000;
182
- if (bytes.length > 1024) {
183
- return { valid: false, error: 'Document too large (max 1KB)' };
184
- }
185
-
186
- this._memory = new Uint8Array(this._instance.memory.buffer);
187
- this._memory.set(bytes, ptr);
188
-
189
- const docId = this._instance.aisp_parse(ptr, bytes.length);
190
- if (docId < 0) {
219
+ // Check size against configurable limit
220
+ if (bytes.length > this._maxDocSize) {
191
221
  return {
192
222
  valid: false,
193
- error: `Parse error at offset ${this._instance.aisp_error_offset()}`,
194
- errorCode: this._instance.aisp_error_code()
223
+ error: `Document too large (${bytes.length} bytes, max ${this._maxDocSize} bytes)`,
224
+ errorCode: -4
195
225
  };
196
226
  }
197
227
 
198
- const parseResult = this._instance.aisp_validate(docId);
199
-
200
- // Use semantic density calculation instead of WASM density
228
+ // Use semantic density calculation (works for all sizes)
201
229
  const densityResult = calculateSemanticDensity(source);
202
230
  const tierResult = getTierFromDelta(densityResult.delta);
203
231
 
232
+ // For documents within WASM limit, use WASM validation
233
+ if (bytes.length <= SIZE_LIMITS.WASM_MAX && options.strict !== false) {
234
+ const ptr = 0x1000;
235
+ this._memory = new Uint8Array(this._instance.memory.buffer);
236
+ this._memory.set(bytes, ptr);
237
+
238
+ const docId = this._instance.aisp_parse(ptr, bytes.length);
239
+ if (docId < 0) {
240
+ return {
241
+ valid: false,
242
+ error: `Parse error at offset ${this._instance.aisp_error_offset()}`,
243
+ errorCode: this._instance.aisp_error_code(),
244
+ tier: tierResult.tier,
245
+ tierValue: tierResult.tierValue,
246
+ tierName: tierResult.tierName,
247
+ delta: densityResult.delta,
248
+ pureDensity: densityResult.pureDensity
249
+ };
250
+ }
251
+
252
+ const parseResult = this._instance.aisp_validate(docId);
253
+
254
+ return {
255
+ valid: parseResult === 0,
256
+ tier: tierResult.tier,
257
+ tierValue: tierResult.tierValue,
258
+ tierName: tierResult.tierName,
259
+ delta: densityResult.delta,
260
+ pureDensity: densityResult.pureDensity,
261
+ ambiguity: this._instance.aisp_ambig(docId),
262
+ errorCode: parseResult,
263
+ mode: 'wasm'
264
+ };
265
+ }
266
+
267
+ // For larger documents, use pure JS validation
268
+ const jsValidation = this._validatePureJS(source, densityResult);
269
+
204
270
  return {
205
- valid: parseResult === 0,
271
+ valid: jsValidation.valid,
206
272
  tier: tierResult.tier,
207
273
  tierValue: tierResult.tierValue,
208
274
  tierName: tierResult.tierName,
209
275
  delta: densityResult.delta,
210
276
  pureDensity: densityResult.pureDensity,
211
- ambiguity: this._instance.aisp_ambig(docId),
212
- errorCode: parseResult
277
+ ambiguity: jsValidation.ambiguity,
278
+ errorCode: jsValidation.valid ? 0 : -3,
279
+ mode: 'js',
280
+ docSize: bytes.length
213
281
  };
214
282
  },
215
283
 
284
+ /**
285
+ * Pure JavaScript validation for larger documents
286
+ * @private
287
+ */
288
+ _validatePureJS(source, densityResult) {
289
+ // Check for AISP header
290
+ if (!source.trim().startsWith('𝔸')) {
291
+ return { valid: false, ambiguity: 1.0, error: 'Missing AISP header (𝔸)' };
292
+ }
293
+
294
+ // Check for required blocks
295
+ const requiredBlocks = ['⟦Ω', '⟦Σ', '⟦Γ', '⟦Λ', '⟦Ε'];
296
+ const missingBlocks = requiredBlocks.filter(b => !source.includes(b));
297
+
298
+ if (missingBlocks.length > 0) {
299
+ return {
300
+ valid: false,
301
+ ambiguity: 0.5,
302
+ error: `Missing required blocks: ${missingBlocks.join(', ')}`
303
+ };
304
+ }
305
+
306
+ // Valid if all required blocks present and density >= 0.20 (Bronze tier minimum)
307
+ const valid = densityResult.delta >= 0.20;
308
+ const ambiguity = valid ? 0.01 : 0.5;
309
+
310
+ return { valid, ambiguity };
311
+ },
312
+
216
313
  /**
217
314
  * Get detailed density breakdown for debugging
218
315
  * @param {string} source - AISP source
@@ -290,5 +387,5 @@ const AISP = {
290
387
  };
291
388
 
292
389
  export default AISP;
293
- export const { init, validate, isValid, getDensity, getTier, validateFile, debug, debugFile } = AISP;
294
- export { calculateSemanticDensity, calculatePureDensity, getTierFromDelta, AISP_SYMBOLS };
390
+ export const { init, validate, isValid, getDensity, getTier, validateFile, debug, debugFile, setMaxDocSize } = AISP;
391
+ export { calculateSemanticDensity, calculatePureDensity, getTierFromDelta, AISP_SYMBOLS, SUPPORTED_EXTENSIONS, SIZE_LIMITS };