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.
- package/README.md +65 -174
- package/bin/cli.js +173 -19
- package/package.json +1 -1
- package/src/index.js +120 -23
package/README.md
CHANGED
|
@@ -1,52 +1,36 @@
|
|
|
1
1
|
# AISP Validator
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/aisp-validator)
|
|
4
|
-
[](
|
|
4
|
+
[](LICENSE)
|
|
5
5
|
|
|
6
|
-
**Validate
|
|
6
|
+
**Validate AISP 5.1 documents** — AI Symbolic Protocol with <2% ambiguity.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## Installation
|
|
8
|
+
## Install
|
|
11
9
|
|
|
12
10
|
```bash
|
|
13
11
|
npm install aisp-validator
|
|
14
12
|
```
|
|
15
13
|
|
|
16
|
-
|
|
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
|
-
#
|
|
31
|
-
npx aisp-validator
|
|
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
|
-
**
|
|
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
|
-
|
|
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-
|
|
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
|
|
48
|
+
⟦Ε⟧⟨δ≜0.75;τ≜◊⁺⁺⟩
|
|
65
49
|
`);
|
|
66
50
|
|
|
67
|
-
console.log(result);
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
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
|
-
|
|
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 |
|
|
132
|
-
|
|
133
|
-
|
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
|
|
|
137
|
-
|
|
|
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
|
-
##
|
|
78
|
+
## Required Blocks
|
|
140
79
|
|
|
141
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
174
|
-
∀D∈AISP:Ambig(D)<0.02
|
|
175
|
-
Target≜AI-Agents
|
|
176
|
-
}
|
|
90
|
+
## API
|
|
177
91
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
185
|
-
∀move:ValidMove(board,pos)⇔board[pos]=Empty
|
|
186
|
-
∀win:WinCondition⇔∃line∈Lines:∀c∈line:c=player
|
|
187
|
-
}
|
|
101
|
+
### Validation Result
|
|
188
102
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
|
118
|
+
**AI Symbolic Protocol** is a formal specification language for AI-to-AI communication:
|
|
223
119
|
|
|
224
|
-
- **<2% Ambiguity
|
|
225
|
-
- **Formal Semantics
|
|
226
|
-
- **Machine-Readable
|
|
227
|
-
- **Human-Auditable
|
|
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
|
-
-
|
|
237
|
-
-
|
|
238
|
-
-
|
|
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
|
-
##
|
|
131
|
+
## Author
|
|
241
132
|
|
|
242
|
-
|
|
133
|
+
Bradley Ross — [GitHub @bar181](https://github.com/bar181)
|
|
243
134
|
|
|
244
|
-
|
|
135
|
+
## License
|
|
245
136
|
|
|
246
|
-
|
|
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
|
|
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(
|
|
168
|
+
console.log(`aisp-validator v${VERSION}`);
|
|
56
169
|
process.exit(0);
|
|
57
170
|
}
|
|
58
171
|
|
|
59
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
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} [
|
|
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(
|
|
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
|
-
|
|
182
|
-
if (bytes.length >
|
|
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: `
|
|
194
|
-
errorCode:
|
|
223
|
+
error: `Document too large (${bytes.length} bytes, max ${this._maxDocSize} bytes)`,
|
|
224
|
+
errorCode: -4
|
|
195
225
|
};
|
|
196
226
|
}
|
|
197
227
|
|
|
198
|
-
|
|
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:
|
|
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:
|
|
212
|
-
errorCode:
|
|
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 };
|