aisp-validator 0.2.1 → 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 +84 -83
- package/bin/cli.js +173 -19
- package/package.json +1 -1
- package/src/index.js +120 -23
package/README.md
CHANGED
|
@@ -1,23 +1,36 @@
|
|
|
1
1
|
# AISP Validator
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/aisp-validator)
|
|
4
|
+
[](LICENSE)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
**Validate AISP 5.1 documents** — AI Symbolic Protocol with <2% ambiguity.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
## Install
|
|
8
9
|
|
|
9
10
|
```bash
|
|
10
|
-
|
|
11
|
+
npm install aisp-validator
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## CLI Usage
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Validate a document
|
|
11
18
|
npx aisp-validator validate spec.aisp
|
|
12
19
|
|
|
13
|
-
#
|
|
14
|
-
npx aisp-validator
|
|
20
|
+
# Detailed output with JSON
|
|
21
|
+
npx aisp-validator validate spec.aisp --long
|
|
22
|
+
npx aisp-validator validate spec.aisp --json
|
|
23
|
+
```
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
**Output:**
|
|
26
|
+
```
|
|
27
|
+
✓ VALID
|
|
28
|
+
Tier: ◊⁺⁺ Platinum
|
|
29
|
+
Semantic (δ): 1.000
|
|
30
|
+
Pure (ρ): 1.857
|
|
18
31
|
```
|
|
19
32
|
|
|
20
|
-
|
|
33
|
+
## Node.js Usage
|
|
21
34
|
|
|
22
35
|
```javascript
|
|
23
36
|
import AISP from 'aisp-validator';
|
|
@@ -25,112 +38,100 @@ import AISP from 'aisp-validator';
|
|
|
25
38
|
await AISP.init();
|
|
26
39
|
|
|
27
40
|
const result = AISP.validate(`
|
|
28
|
-
𝔸1.0.example@2026-01-
|
|
41
|
+
𝔸1.0.example@2026-01-16
|
|
29
42
|
γ≔test
|
|
30
43
|
|
|
31
44
|
⟦Ω:Meta⟧{ ∀D:Ambig(D)<0.02 }
|
|
32
45
|
⟦Σ:Types⟧{ T≜ℕ }
|
|
33
46
|
⟦Γ:Rules⟧{ ∀x:T:x≥0 }
|
|
34
47
|
⟦Λ:Funcs⟧{ f≜λx.x }
|
|
35
|
-
⟦Ε⟧⟨δ≜0.75
|
|
48
|
+
⟦Ε⟧⟨δ≜0.75;τ≜◊⁺⁺⟩
|
|
36
49
|
`);
|
|
37
50
|
|
|
38
|
-
console.log(result);
|
|
39
|
-
//
|
|
51
|
+
console.log(result.valid); // true
|
|
52
|
+
console.log(result.tier); // '◊⁺⁺'
|
|
53
|
+
console.log(result.tierName); // 'Platinum'
|
|
54
|
+
console.log(result.delta); // 0.82
|
|
40
55
|
```
|
|
41
56
|
|
|
42
|
-
|
|
57
|
+
## Browser Usage
|
|
43
58
|
|
|
44
59
|
```html
|
|
45
60
|
<script type="module">
|
|
46
|
-
import AISP from '
|
|
47
|
-
|
|
48
|
-
await AISP.init('/wasm/aisp.wasm');
|
|
61
|
+
import AISP from 'aisp-validator/browser';
|
|
49
62
|
|
|
50
|
-
|
|
51
|
-
|
|
63
|
+
await AISP.init('/path/to/aisp.wasm');
|
|
64
|
+
const result = AISP.validate(source);
|
|
52
65
|
</script>
|
|
53
66
|
```
|
|
54
67
|
|
|
55
|
-
##
|
|
56
|
-
|
|
57
|
-
### `AISP.init(wasmPath?)`
|
|
58
|
-
Initialize the WASM kernel. Call once before validation.
|
|
59
|
-
|
|
60
|
-
### `AISP.validate(source)`
|
|
61
|
-
Validate an AISP document. Returns:
|
|
62
|
-
```javascript
|
|
63
|
-
{
|
|
64
|
-
valid: boolean, // true if valid
|
|
65
|
-
tier: string, // '⊘' | '◊⁻' | '◊' | '◊⁺' | '◊⁺⁺'
|
|
66
|
-
tierValue: number, // 0-4
|
|
67
|
-
delta: number, // density δ [0, 1]
|
|
68
|
-
ambiguity: number, // [0, 1], must be <0.02
|
|
69
|
-
errorCode: number // 0 = success
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### `AISP.isValid(source)`
|
|
74
|
-
Quick check: returns `true` if valid.
|
|
68
|
+
## Quality Tiers
|
|
75
69
|
|
|
76
|
-
|
|
77
|
-
|
|
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 |
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
Returns density score (δ) between 0 and 1.
|
|
78
|
+
## Required Blocks
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
Validate a file by path.
|
|
80
|
+
Every AISP document needs 5 blocks:
|
|
84
81
|
|
|
85
|
-
|
|
82
|
+
| Block | Purpose |
|
|
83
|
+
|-------|---------|
|
|
84
|
+
| `⟦Ω⟧` | Meta/Foundation |
|
|
85
|
+
| `⟦Σ⟧` | Types/Glossary |
|
|
86
|
+
| `⟦Γ⟧` | Rules/Inference |
|
|
87
|
+
| `⟦Λ⟧` | Functions |
|
|
88
|
+
| `⟦Ε⟧` | Evidence |
|
|
86
89
|
|
|
87
|
-
|
|
88
|
-
|------|--------|-----------|---------|
|
|
89
|
-
| Platinum | ◊⁺⁺ | δ ≥ 0.75 | Production-ready |
|
|
90
|
-
| Gold | ◊⁺ | δ ≥ 0.60 | High quality |
|
|
91
|
-
| Silver | ◊ | δ ≥ 0.40 | Acceptable |
|
|
92
|
-
| Bronze | ◊⁻ | δ ≥ 0.20 | Needs improvement |
|
|
93
|
-
| Reject | ⊘ | δ < 0.20 | Insufficient AISP |
|
|
90
|
+
## API
|
|
94
91
|
|
|
95
|
-
|
|
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) |
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
### Validation Result
|
|
98
102
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
|
113
|
+
}
|
|
114
|
+
```
|
|
104
115
|
|
|
105
|
-
##
|
|
116
|
+
## What is AISP?
|
|
106
117
|
|
|
107
|
-
|
|
108
|
-
# Prerequisites
|
|
109
|
-
rustup target add wasm32-unknown-unknown
|
|
110
|
-
npm install -g binaryen
|
|
118
|
+
**AI Symbolic Protocol** is a formal specification language for AI-to-AI communication:
|
|
111
119
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
|
115
124
|
|
|
116
|
-
|
|
117
|
-
```
|
|
125
|
+
## Links
|
|
118
126
|
|
|
119
|
-
|
|
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)
|
|
120
130
|
|
|
121
|
-
|
|
131
|
+
## Author
|
|
122
132
|
|
|
123
|
-
|
|
124
|
-
- **Type checking**: Based on lean-agentic
|
|
125
|
-
- **Symbol table**: AISP Σ_512 glossary
|
|
126
|
-
- **Density computation**: AISP symbol ratio
|
|
133
|
+
Bradley Ross — [GitHub @bar181](https://github.com/bar181)
|
|
127
134
|
|
|
128
135
|
## License
|
|
129
136
|
|
|
130
|
-
MIT
|
|
131
|
-
|
|
132
|
-
## Links
|
|
133
|
-
|
|
134
|
-
- [AISP 5.1 Specification](../AI_GUIDE.md)
|
|
135
|
-
- [Reference (Rosetta Stone)](../reference.md)
|
|
136
|
-
- [Repository](https://github.com/bar181/aisp-open-core)
|
|
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 };
|