@moikapy/origen-zero 0.1.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 +169 -0
- package/dist/chunk-6RAZN3WM.js +232 -0
- package/dist/chunk-6RAZN3WM.js.map +1 -0
- package/dist/chunk-DE5JDJKT.js +194 -0
- package/dist/chunk-DE5JDJKT.js.map +1 -0
- package/dist/chunk-J5UPC5XT.js +115 -0
- package/dist/chunk-J5UPC5XT.js.map +1 -0
- package/dist/chunk-PJFVSOEI.js +65 -0
- package/dist/chunk-PJFVSOEI.js.map +1 -0
- package/dist/chunk-QUQPQFU6.js +223 -0
- package/dist/chunk-QUQPQFU6.js.map +1 -0
- package/dist/chunk-SDOZC7ZI.js +161 -0
- package/dist/chunk-SDOZC7ZI.js.map +1 -0
- package/dist/compiler.d.ts +42 -0
- package/dist/compiler.js +10 -0
- package/dist/compiler.js.map +1 -0
- package/dist/http-compiler.d.ts +40 -0
- package/dist/http-compiler.js +8 -0
- package/dist/http-compiler.js.map +1 -0
- package/dist/index.d.ts +151 -0
- package/dist/index.js +190 -0
- package/dist/index.js.map +1 -0
- package/dist/tools.d.ts +46 -0
- package/dist/tools.js +13 -0
- package/dist/tools.js.map +1 -0
- package/dist/types-Dc-cDRjG.d.ts +200 -0
- package/dist/wasi-runtime.d.ts +41 -0
- package/dist/wasi-runtime.js +7 -0
- package/dist/wasi-runtime.js.map +1 -0
- package/dist/wasm-tool.d.ts +54 -0
- package/dist/wasm-tool.js +10 -0
- package/dist/wasm-tool.js.map +1 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# @moikapy/origen-zero
|
|
2
|
+
|
|
3
|
+
Bridge package connecting [Origen](https://www.npmjs.com/package/@moikapy/origen) agents to the [ZeroLang](https://zerolang.ai) compiler and runtime.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
Origen agents write tool logic in TypeScript. ZeroLang is a **systems language designed for agents** — structured compiler output, explicit effects, repair metadata, and JSON diagnostics are first-class. This package bridges the two:
|
|
8
|
+
|
|
9
|
+
- **Define tools in Zero** — Write `.0` files, compile them, get structured diagnostics before registration
|
|
10
|
+
- **Register as OrigenTools** — Zero functions become first-class Origen tools
|
|
11
|
+
- **Interactive compiler tools** — `zero_check`, `zero_graph`, `zero_size`, `zero_fix` as Origen tools
|
|
12
|
+
- **Self-modify** — Write, check, fix, and register tools during a single conversation session
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @moikapy/origen-zero
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Prerequisites:**
|
|
21
|
+
- `@moikapy/origen` ^0.6.0 (peer dependency)
|
|
22
|
+
- Zero CLI installed and available on `$PATH` — [install guide](https://zerolang.ai)
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Register a Compiled Zero Binary as OrigenTool
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { createZeroTool } from "@moikapy/origen-zero/tools";
|
|
30
|
+
import { streamOrigen } from "@moikapy/origen";
|
|
31
|
+
|
|
32
|
+
const lookupTool = createZeroTool({
|
|
33
|
+
functionName: "lookup",
|
|
34
|
+
description: "Look up a record by ID",
|
|
35
|
+
executablePath: "./bin/lookup",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const config = {
|
|
39
|
+
appName: "MyAgent",
|
|
40
|
+
tools: [lookupTool],
|
|
41
|
+
getD1: async () => myD1,
|
|
42
|
+
};
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Interactive Compiler Tools (LLM Calls Zero CLI)
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { createZeroCompilerTools } from "@moikapy/origen-zero/tools";
|
|
49
|
+
|
|
50
|
+
const compilerTools = createZeroCompilerTools();
|
|
51
|
+
// Returns: [zero_check, zero_graph, zero_size, zero_fix]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Write, Check, Fix, Register — Full Loop
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { compileAndRegister } from "@moikapy/origen-zero/tools";
|
|
58
|
+
|
|
59
|
+
const result = await compileAndRegister({
|
|
60
|
+
path: "math.0",
|
|
61
|
+
content: sourceCode,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if ("tools" in result) {
|
|
65
|
+
// ✅ Compiled — result.tools are ready
|
|
66
|
+
} else {
|
|
67
|
+
// ❌ Errors — return to LLM for self-repair
|
|
68
|
+
console.log(result.errors);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Direct Compiler Access
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { ZeroCompiler } from "@moikapy/origen-zero/compiler";
|
|
76
|
+
|
|
77
|
+
const compiler = new ZeroCompiler({ binaryPath: "zero", timeout: 10000 });
|
|
78
|
+
|
|
79
|
+
// Check for errors
|
|
80
|
+
const result = await compiler.check("fun main() {}" /* ... */);
|
|
81
|
+
if (result.ok) { /* clean */ }
|
|
82
|
+
|
|
83
|
+
// Get dependency graph
|
|
84
|
+
const graph = await compiler.graph("./src/math.0");
|
|
85
|
+
|
|
86
|
+
// Get size estimates
|
|
87
|
+
const sizes = await compiler.size("./src/math.0");
|
|
88
|
+
|
|
89
|
+
// Build WASM for Workers
|
|
90
|
+
const build = await compiler.build("./src/math.0", { emit: "wasm", target: "wasm32-web", out: "./dist/math" });
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## API
|
|
94
|
+
|
|
95
|
+
### `ZeroCompiler`
|
|
96
|
+
|
|
97
|
+
| Method | Description | Zero CLI |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| `check(source)` | Check for errors, return diagnostics | `zero check --json` |
|
|
100
|
+
| `graph(source)` | Get dependency graph | `zero graph --json` |
|
|
101
|
+
| `size(source)` | Get function size estimates | `zero size --json` |
|
|
102
|
+
| `fix(source)` | Get repair suggestions | `zero fix --plan --json` |
|
|
103
|
+
| `build(source, opts?)` | Compile to native executable | `zero build` |
|
|
104
|
+
| `explain(code)` | Human-readable diagnostic explanation | `zero explain` |
|
|
105
|
+
|
|
106
|
+
### Tool Registration
|
|
107
|
+
|
|
108
|
+
| Function | Description |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `createZeroTool(config)` | Register a compiled Zero function as an OrigenTool |
|
|
111
|
+
| `createZeroToolsFromProgram(path, opts?)` | Discover and register all public functions |
|
|
112
|
+
| `compileAndRegister(source, opts?)` | Write → compile → verify → register in one call |
|
|
113
|
+
|
|
114
|
+
### Interactive Compiler Tools
|
|
115
|
+
|
|
116
|
+
| Tool Name | Description |
|
|
117
|
+
|---|---|
|
|
118
|
+
| `zero_check` | Check Zero source for errors |
|
|
119
|
+
| `zero_graph` | Show dependency graph |
|
|
120
|
+
| `zero_size` | Show function size estimates |
|
|
121
|
+
| `zero_fix` | Suggest repairs for errors |
|
|
122
|
+
|
|
123
|
+
## Error Types
|
|
124
|
+
|
|
125
|
+
| Error | When |
|
|
126
|
+
|---|---|
|
|
127
|
+
| `ZeroCompilerNotFoundError` | `zero` binary not on PATH |
|
|
128
|
+
| `ZeroCheckFailedError` | Source has diagnostics |
|
|
129
|
+
| `ZeroBuildFailedError` | Build produces no output |
|
|
130
|
+
| `ZeroTimeoutError` | CLI invocation exceeds timeout |
|
|
131
|
+
| `ZeroExecutionError` | Compiled binary exits non-zero |
|
|
132
|
+
|
|
133
|
+
### WASM Execution (Workers-ready)
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { createZeroWASMTool } from "@moikapy/origen-zero/wasm-tool";
|
|
137
|
+
import { readFileSync } from "node:fs";
|
|
138
|
+
|
|
139
|
+
// Load pre-compiled WASM module
|
|
140
|
+
const wasmBytes = readFileSync("./dist/my-tool.wasm");
|
|
141
|
+
|
|
142
|
+
// In Workers — WASM runs in-process, no subprocess or HTTP needed
|
|
143
|
+
const tool = createZeroWASMTool({
|
|
144
|
+
functionName: "main",
|
|
145
|
+
description: "My Zero tool",
|
|
146
|
+
wasmBytes,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Execute: Zero program writes to stdout, tool captures the output
|
|
150
|
+
const result = await tool.execute({ input: "hello" });
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Build the WASM module from Zero source:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
zero build --emit wasm --target wasm32-web src/my-tool.0 --out dist/my-tool
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Execution Modes
|
|
160
|
+
|
|
161
|
+
| Mode | Transport | Works In | When |
|
|
162
|
+
|---|---|---|---|
|
|
163
|
+
| `subprocess` | execFile() | Node.js, Bun | Native binaries |
|
|
164
|
+
| `http` | fetch() | Workers, Node, browser | Remote Zero service |
|
|
165
|
+
| `wasm` | WebAssembly.instantiate() | Workers, Node, browser | Pre-compiled .wasm |
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var ZeroError = class extends Error {
|
|
3
|
+
constructor(message, code, diagnostics) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.diagnostics = diagnostics;
|
|
7
|
+
this.name = "ZeroError";
|
|
8
|
+
}
|
|
9
|
+
code;
|
|
10
|
+
diagnostics;
|
|
11
|
+
};
|
|
12
|
+
var ZeroCompilerNotFoundError = class extends ZeroError {
|
|
13
|
+
constructor(binaryPath) {
|
|
14
|
+
super(
|
|
15
|
+
`Zero CLI not found at "${binaryPath}". Install Zero CLI or configure binaryPath.`,
|
|
16
|
+
"ZERO_NOT_FOUND"
|
|
17
|
+
);
|
|
18
|
+
this.name = "ZeroCompilerNotFoundError";
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var ZeroCheckFailedError = class extends ZeroError {
|
|
22
|
+
constructor(diagnostics) {
|
|
23
|
+
super(
|
|
24
|
+
`Zero check failed with ${diagnostics.length} diagnostic(s):
|
|
25
|
+
${diagnostics.map((d) => ` [${d.code}] ${d.severity}: ${d.message} (line ${d.line})`).join("\n")}`,
|
|
26
|
+
"ZERO_CHECK_FAILED",
|
|
27
|
+
diagnostics
|
|
28
|
+
);
|
|
29
|
+
this.name = "ZeroCheckFailedError";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var ZeroBuildFailedError = class extends ZeroError {
|
|
33
|
+
constructor(diagnostics) {
|
|
34
|
+
super(
|
|
35
|
+
`Zero build failed with ${diagnostics.length} diagnostic(s)`,
|
|
36
|
+
"ZERO_BUILD_FAILED",
|
|
37
|
+
diagnostics
|
|
38
|
+
);
|
|
39
|
+
this.name = "ZeroBuildFailedError";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var ZeroTimeoutError = class extends ZeroError {
|
|
43
|
+
constructor(command, timeout) {
|
|
44
|
+
super(
|
|
45
|
+
`Zero CLI command "${command}" timed out after ${timeout}ms`,
|
|
46
|
+
"ZERO_TIMEOUT"
|
|
47
|
+
);
|
|
48
|
+
this.name = "ZeroTimeoutError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var ZeroHTTPError = class extends ZeroError {
|
|
52
|
+
constructor(status, url, body) {
|
|
53
|
+
super(
|
|
54
|
+
`Zero compiler service returned ${status} from ${url}: ${body}`,
|
|
55
|
+
"ZERO_HTTP_ERROR"
|
|
56
|
+
);
|
|
57
|
+
this.status = status;
|
|
58
|
+
this.url = url;
|
|
59
|
+
this.name = "ZeroHTTPError";
|
|
60
|
+
}
|
|
61
|
+
status;
|
|
62
|
+
url;
|
|
63
|
+
};
|
|
64
|
+
var ZeroExecutionError = class extends ZeroError {
|
|
65
|
+
constructor(exitCode, stderr) {
|
|
66
|
+
super(
|
|
67
|
+
`Zero binary exited with code ${exitCode}: ${stderr}`,
|
|
68
|
+
"ZERO_EXECUTION_ERROR"
|
|
69
|
+
);
|
|
70
|
+
this.exitCode = exitCode;
|
|
71
|
+
this.stderr = stderr;
|
|
72
|
+
this.name = "ZeroExecutionError";
|
|
73
|
+
}
|
|
74
|
+
exitCode;
|
|
75
|
+
stderr;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// src/parser.ts
|
|
79
|
+
import { z } from "zod";
|
|
80
|
+
var DIAGNOSTIC_CODE_PATTERN = /^[A-Z]{3}\d{3}$/;
|
|
81
|
+
var ZeroDiagnosticSchema = z.object({
|
|
82
|
+
code: z.string().regex(DIAGNOSTIC_CODE_PATTERN, {
|
|
83
|
+
message: "Diagnostic code must match XXX### pattern (e.g., NAM003)"
|
|
84
|
+
}),
|
|
85
|
+
severity: z.enum(["error", "warning", "info"]),
|
|
86
|
+
message: z.string(),
|
|
87
|
+
line: z.number().int().positive(),
|
|
88
|
+
column: z.number().int().positive().optional(),
|
|
89
|
+
repair: z.object({
|
|
90
|
+
id: z.string(),
|
|
91
|
+
suggestion: z.string().optional()
|
|
92
|
+
}).optional()
|
|
93
|
+
});
|
|
94
|
+
var ZeroCheckResultSchema = z.object({
|
|
95
|
+
ok: z.boolean(),
|
|
96
|
+
diagnostics: z.array(ZeroDiagnosticSchema),
|
|
97
|
+
raw: z.record(z.string(), z.unknown())
|
|
98
|
+
});
|
|
99
|
+
var ZeroGraphResultSchema = z.object({
|
|
100
|
+
ok: z.boolean(),
|
|
101
|
+
graph: z.record(z.string(), z.array(z.string())),
|
|
102
|
+
raw: z.record(z.string(), z.unknown())
|
|
103
|
+
});
|
|
104
|
+
var ZeroSizeResultSchema = z.object({
|
|
105
|
+
ok: z.boolean(),
|
|
106
|
+
sizes: z.record(z.string(), z.number()),
|
|
107
|
+
raw: z.record(z.string(), z.unknown())
|
|
108
|
+
});
|
|
109
|
+
var ZeroFixSuggestionSchema = z.object({
|
|
110
|
+
id: z.string(),
|
|
111
|
+
diagnosticCode: z.string(),
|
|
112
|
+
safety: z.string(),
|
|
113
|
+
summary: z.string(),
|
|
114
|
+
appliesEdits: z.boolean()
|
|
115
|
+
});
|
|
116
|
+
var ZeroFixResultSchema = z.object({
|
|
117
|
+
ok: z.boolean(),
|
|
118
|
+
fixes: z.array(ZeroFixSuggestionSchema),
|
|
119
|
+
raw: z.record(z.string(), z.unknown())
|
|
120
|
+
});
|
|
121
|
+
function parseDiagnostic(d) {
|
|
122
|
+
return {
|
|
123
|
+
code: String(d.code ?? "UNK000"),
|
|
124
|
+
severity: ["error", "warning", "info"].includes(d.severity) ? d.severity : "error",
|
|
125
|
+
message: String(d.message ?? ""),
|
|
126
|
+
line: Number(d.line ?? 0) || 0,
|
|
127
|
+
column: d.column ? Number(d.column) : void 0,
|
|
128
|
+
repair: d.repair ? {
|
|
129
|
+
id: String(d.repair.id ?? ""),
|
|
130
|
+
suggestion: d.repair.suggestion ? String(d.repair.suggestion) : void 0
|
|
131
|
+
} : void 0
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function parseCheckOutput(raw) {
|
|
135
|
+
const json = JSON.parse(raw);
|
|
136
|
+
return {
|
|
137
|
+
ok: json.ok ?? false,
|
|
138
|
+
diagnostics: (json.diagnostics ?? []).map(parseDiagnostic),
|
|
139
|
+
raw: json
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function parseGraphOutput(raw) {
|
|
143
|
+
const json = JSON.parse(raw);
|
|
144
|
+
const diagnostics = json.diagnostics ?? [];
|
|
145
|
+
const hasErrors = diagnostics.some((d) => d.severity === "error");
|
|
146
|
+
return {
|
|
147
|
+
ok: !hasErrors,
|
|
148
|
+
symbols: (json.symbols ?? []).map((s) => ({
|
|
149
|
+
name: String(s.name ?? ""),
|
|
150
|
+
module: String(s.module ?? ""),
|
|
151
|
+
kind: String(s.kind ?? ""),
|
|
152
|
+
public: Boolean(s.public),
|
|
153
|
+
effects: Array.isArray(s.effects) ? s.effects.map(String) : []
|
|
154
|
+
})),
|
|
155
|
+
functions: (json.functions ?? []).map((f) => ({
|
|
156
|
+
name: String(f.name ?? ""),
|
|
157
|
+
kind: String(f.kind ?? ""),
|
|
158
|
+
public: Boolean(f.public),
|
|
159
|
+
params: Number(f.params ?? 0),
|
|
160
|
+
returnType: String(f.returnType ?? ""),
|
|
161
|
+
raises: Boolean(f.raises),
|
|
162
|
+
effects: Array.isArray(f.effects) ? f.effects.map(String) : [],
|
|
163
|
+
allocationBehavior: String(f.allocationBehavior ?? ""),
|
|
164
|
+
targetSupport: (() => {
|
|
165
|
+
const ts = f.targetSupport;
|
|
166
|
+
return ts ? { status: String(ts.status ?? ""), missingCapabilities: Array.isArray(ts.missingCapabilities) ? ts.missingCapabilities.map(String) : [] } : { status: "unknown", missingCapabilities: [] };
|
|
167
|
+
})()
|
|
168
|
+
})),
|
|
169
|
+
raw: json
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function parseSizeOutput(raw) {
|
|
173
|
+
const json = JSON.parse(raw);
|
|
174
|
+
const diagnostics = json.diagnostics ?? [];
|
|
175
|
+
const hasErrors = diagnostics.some((d) => d.severity === "error");
|
|
176
|
+
const pr = json.portableRuntime;
|
|
177
|
+
return {
|
|
178
|
+
ok: !hasErrors,
|
|
179
|
+
portableRuntime: pr ? {
|
|
180
|
+
target: String(pr.target ?? ""),
|
|
181
|
+
runtimeKind: String(pr.runtimeKind ?? ""),
|
|
182
|
+
portable: Boolean(pr.portable),
|
|
183
|
+
imports: {
|
|
184
|
+
functionCount: Number(pr.imports?.functionCount ?? 0),
|
|
185
|
+
functions: Array.isArray(pr.imports?.functions) ? pr.imports.functions.map(String) : [],
|
|
186
|
+
module: pr.imports?.module ?? null
|
|
187
|
+
},
|
|
188
|
+
memoryFloor: pr.memoryFloor ? { floorBytes: Number(pr.memoryFloor.floorBytes ?? 0), minimumPages: Number(pr.memoryFloor.minimumPages ?? 0) } : void 0,
|
|
189
|
+
capabilityRestrictions: pr.capabilityRestrictions ?? void 0
|
|
190
|
+
} : void 0,
|
|
191
|
+
raw: json
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function parseFixOutput(raw) {
|
|
195
|
+
const json = JSON.parse(raw);
|
|
196
|
+
const fixes = (json.fixes ?? []).map(
|
|
197
|
+
(f) => ({
|
|
198
|
+
id: String(f.id ?? ""),
|
|
199
|
+
diagnosticCode: String(f.diagnosticCode ?? f.code ?? ""),
|
|
200
|
+
safety: String(f.safety ?? "requires-human-review"),
|
|
201
|
+
summary: String(f.summary ?? f.message ?? ""),
|
|
202
|
+
appliesEdits: Boolean(f.appliesEdits ?? false)
|
|
203
|
+
})
|
|
204
|
+
);
|
|
205
|
+
return {
|
|
206
|
+
ok: json.ok ?? false,
|
|
207
|
+
fixes,
|
|
208
|
+
raw: json
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export {
|
|
213
|
+
ZeroError,
|
|
214
|
+
ZeroCompilerNotFoundError,
|
|
215
|
+
ZeroCheckFailedError,
|
|
216
|
+
ZeroBuildFailedError,
|
|
217
|
+
ZeroTimeoutError,
|
|
218
|
+
ZeroHTTPError,
|
|
219
|
+
ZeroExecutionError,
|
|
220
|
+
ZeroDiagnosticSchema,
|
|
221
|
+
ZeroCheckResultSchema,
|
|
222
|
+
ZeroGraphResultSchema,
|
|
223
|
+
ZeroSizeResultSchema,
|
|
224
|
+
ZeroFixSuggestionSchema,
|
|
225
|
+
ZeroFixResultSchema,
|
|
226
|
+
parseDiagnostic,
|
|
227
|
+
parseCheckOutput,
|
|
228
|
+
parseGraphOutput,
|
|
229
|
+
parseSizeOutput,
|
|
230
|
+
parseFixOutput
|
|
231
|
+
};
|
|
232
|
+
//# sourceMappingURL=chunk-6RAZN3WM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/parser.ts"],"sourcesContent":["/**\n * @moikapy/origen-zero — Error hierarchy\n *\n * All errors extend ZeroError for consistent catch patterns.\n */\n\n/** Base error for all origen-zero errors. */\nexport class ZeroError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly diagnostics?: ZeroDiagnostic[],\n ) {\n super(message);\n this.name = \"ZeroError\";\n }\n}\n\n/** Thrown when the `zero` binary cannot be found on PATH or configured path. */\nexport class ZeroCompilerNotFoundError extends ZeroError {\n constructor(binaryPath: string) {\n super(\n `Zero CLI not found at \"${binaryPath}\". Install Zero CLI or configure binaryPath.`,\n \"ZERO_NOT_FOUND\",\n );\n this.name = \"ZeroCompilerNotFoundError\";\n }\n}\n\n/** Thrown when a Zero source file has diagnostic errors/warnings. */\nexport class ZeroCheckFailedError extends ZeroError {\n constructor(diagnostics: ZeroDiagnostic[]) {\n super(\n `Zero check failed with ${diagnostics.length} diagnostic(s):\\n${diagnostics.map((d) => ` [${d.code}] ${d.severity}: ${d.message} (line ${d.line})`).join(\"\\n\")}`,\n \"ZERO_CHECK_FAILED\",\n diagnostics,\n );\n this.name = \"ZeroCheckFailedError\";\n }\n}\n\n/** Thrown when `zero build` fails (produces no output binary). */\nexport class ZeroBuildFailedError extends ZeroError {\n constructor(diagnostics: ZeroDiagnostic[]) {\n super(\n `Zero build failed with ${diagnostics.length} diagnostic(s)`,\n \"ZERO_BUILD_FAILED\",\n diagnostics,\n );\n this.name = \"ZeroBuildFailedError\";\n }\n}\n\n/** Thrown when a Zero CLI invocation exceeds the configured timeout. */\nexport class ZeroTimeoutError extends ZeroError {\n constructor(command: string, timeout: number) {\n super(\n `Zero CLI command \"${command}\" timed out after ${timeout}ms`,\n \"ZERO_TIMEOUT\",\n );\n this.name = \"ZeroTimeoutError\";\n }\n}\n\n/** Thrown when a Zero HTTP compiler request fails. */\nexport class ZeroHTTPError extends ZeroError {\n constructor(\n public readonly status: number,\n public readonly url: string,\n body: string,\n ) {\n super(\n `Zero compiler service returned ${status} from ${url}: ${body}`,\n \"ZERO_HTTP_ERROR\",\n );\n this.name = \"ZeroHTTPError\";\n }\n}\n\n/** Thrown when a compiled Zero binary returns a non-zero exit code. */\nexport class ZeroExecutionError extends ZeroError {\n constructor(\n public readonly exitCode: number,\n public readonly stderr: string,\n ) {\n super(\n `Zero binary exited with code ${exitCode}: ${stderr}`,\n \"ZERO_EXECUTION_ERROR\",\n );\n this.name = \"ZeroExecutionError\";\n }\n}\n\n// Re-export ZeroDiagnostic from types so consumers don't need to import both\nimport type { ZeroDiagnostic } from \"./types.js\";\nexport type { ZeroDiagnostic } from \"./types.js\";","/**\n * @moikapy/origen-zero — Zero CLI output parser\n *\n * Parses JSON output from `zero check --json`, `zero graph --json`,\n * `zero size --json`, and `zero fix --plan --json` into typed structures.\n */\n\nimport { z } from \"zod\";\nimport type {\n ZeroDiagnostic,\n ZeroCheckResult,\n ZeroGraphResult,\n ZeroSizeResult,\n ZeroFixResult,\n ZeroFixSuggestion,\n} from \"./types.js\";\n\n// ── Zod Schemas ─────────────────────────────────────────────────────────\n\n/** Diagnostic code pattern: three uppercase letters + three digits. */\nconst DIAGNOSTIC_CODE_PATTERN = /^[A-Z]{3}\\d{3}$/;\n\nexport const ZeroDiagnosticSchema = z.object({\n code: z.string().regex(DIAGNOSTIC_CODE_PATTERN, {\n message: \"Diagnostic code must match XXX### pattern (e.g., NAM003)\",\n }),\n severity: z.enum([\"error\", \"warning\", \"info\"]),\n message: z.string(),\n line: z.number().int().positive(),\n column: z.number().int().positive().optional(),\n repair: z\n .object({\n id: z.string(),\n suggestion: z.string().optional(),\n })\n .optional(),\n});\n\nexport const ZeroCheckResultSchema = z.object({\n ok: z.boolean(),\n diagnostics: z.array(ZeroDiagnosticSchema),\n raw: z.record(z.string(), z.unknown()),\n});\n\nexport const ZeroGraphResultSchema = z.object({\n ok: z.boolean(),\n graph: z.record(z.string(), z.array(z.string())),\n raw: z.record(z.string(), z.unknown()),\n});\n\nexport const ZeroSizeResultSchema = z.object({\n ok: z.boolean(),\n sizes: z.record(z.string(), z.number()),\n raw: z.record(z.string(), z.unknown()),\n});\n\nexport const ZeroFixSuggestionSchema = z.object({\n id: z.string(),\n diagnosticCode: z.string(),\n safety: z.string(),\n summary: z.string(),\n appliesEdits: z.boolean(),\n});\n\nexport const ZeroFixResultSchema = z.object({\n ok: z.boolean(),\n fixes: z.array(ZeroFixSuggestionSchema),\n raw: z.record(z.string(), z.unknown()),\n});\n\n// ── Parsers ──────────────────────────────────────────────────────────────\n\n/** Parse a single diagnostic from raw JSON. */\nexport function parseDiagnostic(d: Record<string, unknown>): ZeroDiagnostic {\n return {\n code: String(d.code ?? \"UNK000\"),\n severity: ([\"error\", \"warning\", \"info\"].includes(d.severity as string)\n ? d.severity\n : \"error\") as ZeroDiagnostic[\"severity\"],\n message: String(d.message ?? \"\"),\n line: Number(d.line ?? 0) || 0,\n column: d.column ? Number(d.column) : undefined,\n repair: d.repair\n ? {\n id: String((d.repair as Record<string, unknown>).id ?? \"\"),\n suggestion: (d.repair as Record<string, unknown>).suggestion\n ? String((d.repair as Record<string, unknown>).suggestion)\n : undefined,\n }\n : undefined,\n };\n}\n\n/** Parse `zero check --json` output into a typed ZeroCheckResult. */\nexport function parseCheckOutput(raw: string): ZeroCheckResult {\n const json = JSON.parse(raw);\n return {\n ok: json.ok ?? false,\n diagnostics: (json.diagnostics ?? []).map(parseDiagnostic),\n raw: json,\n };\n}\n\n/** Parse `zero graph --json` output into a typed ZeroGraphResult. */\nexport function parseGraphOutput(raw: string): ZeroGraphResult {\n const json = JSON.parse(raw);\n const diagnostics = json.diagnostics ?? [];\n const hasErrors = diagnostics.some((d: any) => d.severity === \"error\");\n return {\n ok: !hasErrors,\n symbols: (json.symbols ?? []).map((s: Record<string, unknown>) => ({\n name: String(s.name ?? \"\"),\n module: String(s.module ?? \"\"),\n kind: String(s.kind ?? \"\"),\n public: Boolean(s.public),\n effects: Array.isArray(s.effects) ? s.effects.map(String) : [],\n })),\n functions: (json.functions ?? []).map((f: Record<string, unknown>) => ({\n name: String(f.name ?? \"\"),\n kind: String(f.kind ?? \"\"),\n public: Boolean(f.public),\n params: Number(f.params ?? 0),\n returnType: String(f.returnType ?? \"\"),\n raises: Boolean(f.raises),\n effects: Array.isArray(f.effects) ? f.effects.map(String) : [],\n allocationBehavior: String(f.allocationBehavior ?? \"\"),\n targetSupport: (() => {\n const ts = f.targetSupport as Record<string, unknown> | undefined;\n return ts\n ? { status: String(ts.status ?? \"\"), missingCapabilities: Array.isArray(ts.missingCapabilities) ? ts.missingCapabilities.map(String) : [] }\n : { status: \"unknown\", missingCapabilities: [] };\n })(),\n })),\n raw: json,\n };\n}\n\n/** Parse `zero size --json` output into a typed ZeroSizeResult. */\nexport function parseSizeOutput(raw: string): ZeroSizeResult {\n const json = JSON.parse(raw);\n const diagnostics = json.diagnostics ?? [];\n const hasErrors = diagnostics.some((d: any) => d.severity === \"error\");\n const pr = json.portableRuntime;\n return {\n ok: !hasErrors,\n portableRuntime: pr\n ? {\n target: String(pr.target ?? \"\"),\n runtimeKind: String(pr.runtimeKind ?? \"\"),\n portable: Boolean(pr.portable),\n imports: {\n functionCount: Number(pr.imports?.functionCount ?? 0),\n functions: Array.isArray(pr.imports?.functions) ? pr.imports.functions.map(String) : [],\n module: pr.imports?.module ?? null,\n },\n memoryFloor: pr.memoryFloor\n ? { floorBytes: Number(pr.memoryFloor.floorBytes ?? 0), minimumPages: Number(pr.memoryFloor.minimumPages ?? 0) }\n : undefined,\n capabilityRestrictions: pr.capabilityRestrictions ?? undefined,\n }\n : undefined,\n raw: json,\n };\n}\n\n/** Parse `zero fix --plan --json` output into a typed ZeroFixResult. */\nexport function parseFixOutput(raw: string): ZeroFixResult {\n const json = JSON.parse(raw);\n const fixes: ZeroFixSuggestion[] = (json.fixes ?? []).map(\n (f: Record<string, unknown>) => ({\n id: String(f.id ?? \"\"),\n diagnosticCode: String(f.diagnosticCode ?? f.code ?? \"\"),\n safety: String(f.safety ?? \"requires-human-review\"),\n summary: String(f.summary ?? f.message ?? \"\"),\n appliesEdits: Boolean(f.appliesEdits ?? false),\n }),\n );\n return {\n ok: json.ok ?? false,\n fixes,\n raw: json,\n };\n}"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ZeroBuildFailedError,
|
|
3
|
+
ZeroCompilerNotFoundError,
|
|
4
|
+
ZeroTimeoutError,
|
|
5
|
+
parseCheckOutput,
|
|
6
|
+
parseFixOutput,
|
|
7
|
+
parseGraphOutput,
|
|
8
|
+
parseSizeOutput
|
|
9
|
+
} from "./chunk-6RAZN3WM.js";
|
|
10
|
+
|
|
11
|
+
// src/compiler.ts
|
|
12
|
+
import { execFile } from "child_process";
|
|
13
|
+
import { mkdir, writeFile, rm } from "fs/promises";
|
|
14
|
+
import { join } from "path";
|
|
15
|
+
var DEFAULT_BINARY = "zero";
|
|
16
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
17
|
+
var TEMP_DIR = ".zero-origen/tmp";
|
|
18
|
+
var ZERO_EXIT_ERRORS = 1;
|
|
19
|
+
var ZERO_EXIT_INTERNAL = 2;
|
|
20
|
+
var ZeroCompiler = class {
|
|
21
|
+
binaryPath;
|
|
22
|
+
workingDir;
|
|
23
|
+
timeout;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.binaryPath = config?.binaryPath ?? DEFAULT_BINARY;
|
|
26
|
+
this.workingDir = config?.workingDir ?? process.cwd();
|
|
27
|
+
this.timeout = config?.timeout ?? DEFAULT_TIMEOUT;
|
|
28
|
+
}
|
|
29
|
+
// ── Public API ──────────────────────────────────────────────────────
|
|
30
|
+
/** Check a Zero file or package for errors. Returns structured diagnostics. */
|
|
31
|
+
async check(source) {
|
|
32
|
+
const filePath = await this.writeSource(source);
|
|
33
|
+
try {
|
|
34
|
+
const stdout = await this.exec(["check", "--json", filePath]);
|
|
35
|
+
return parseCheckOutput(stdout);
|
|
36
|
+
} finally {
|
|
37
|
+
await this.cleanup(filePath);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Get the dependency graph for a Zero package. */
|
|
41
|
+
async graph(source) {
|
|
42
|
+
const filePath = await this.writeSource(source);
|
|
43
|
+
try {
|
|
44
|
+
const stdout = await this.exec(["graph", "--json", filePath]);
|
|
45
|
+
return parseGraphOutput(stdout);
|
|
46
|
+
} finally {
|
|
47
|
+
await this.cleanup(filePath);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Get size estimates for functions in a Zero file. */
|
|
51
|
+
async size(source) {
|
|
52
|
+
const filePath = await this.writeSource(source);
|
|
53
|
+
try {
|
|
54
|
+
const stdout = await this.exec(["size", "--json", filePath]);
|
|
55
|
+
return parseSizeOutput(stdout);
|
|
56
|
+
} finally {
|
|
57
|
+
await this.cleanup(filePath);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Get repair suggestions for a Zero program. */
|
|
61
|
+
async fix(source) {
|
|
62
|
+
const filePath = await this.writeSource(source);
|
|
63
|
+
try {
|
|
64
|
+
const stdout = await this.exec(["fix", "--plan", "--json", filePath]);
|
|
65
|
+
return parseFixOutput(stdout);
|
|
66
|
+
} finally {
|
|
67
|
+
await this.cleanup(filePath);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Build a Zero file to a native executable. */
|
|
71
|
+
async build(source, options) {
|
|
72
|
+
const filePath = await this.writeSource(source);
|
|
73
|
+
const args = ["build", "--json", "--emit", options?.emit ?? "exe"];
|
|
74
|
+
if (options?.target) {
|
|
75
|
+
args.push("--target", options.target);
|
|
76
|
+
}
|
|
77
|
+
if (options?.out) {
|
|
78
|
+
args.push("--out", options.out);
|
|
79
|
+
}
|
|
80
|
+
args.push(filePath);
|
|
81
|
+
try {
|
|
82
|
+
const stdout = await this.exec(args);
|
|
83
|
+
const json = JSON.parse(stdout);
|
|
84
|
+
return {
|
|
85
|
+
ok: true,
|
|
86
|
+
outputPath: json.artifactPath ?? options?.out,
|
|
87
|
+
diagnostics: []
|
|
88
|
+
};
|
|
89
|
+
} catch (err) {
|
|
90
|
+
if (err instanceof ZeroCompilerNotFoundError) throw err;
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
diagnostics: []
|
|
94
|
+
};
|
|
95
|
+
} finally {
|
|
96
|
+
await this.cleanup(filePath);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Get a human-readable explanation for a diagnostic code. */
|
|
100
|
+
async explain(diagnosticCode) {
|
|
101
|
+
const stdout = await this.exec(["explain", diagnosticCode]);
|
|
102
|
+
return stdout.trim();
|
|
103
|
+
}
|
|
104
|
+
// ── Internal ────────────────────────────────────────────────────────
|
|
105
|
+
/** Resolve source to a file path. If inline content, write to temp dir. */
|
|
106
|
+
async writeSource(source) {
|
|
107
|
+
if (typeof source !== "string") {
|
|
108
|
+
if (source.content !== void 0) {
|
|
109
|
+
const tmpPath2 = join(this.workingDir, TEMP_DIR, source.path);
|
|
110
|
+
await mkdir(join(this.workingDir, TEMP_DIR), { recursive: true });
|
|
111
|
+
await writeFile(tmpPath2, source.content, "utf-8");
|
|
112
|
+
return tmpPath2;
|
|
113
|
+
}
|
|
114
|
+
return source.path;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const stat = await import("fs/promises").then((fs) => fs.stat(source));
|
|
118
|
+
if (stat.isFile()) return source;
|
|
119
|
+
} catch {
|
|
120
|
+
}
|
|
121
|
+
const tmpPath = join(this.workingDir, TEMP_DIR, `check-${Date.now()}.0`);
|
|
122
|
+
await mkdir(join(this.workingDir, TEMP_DIR), { recursive: true });
|
|
123
|
+
await writeFile(tmpPath, source, "utf-8");
|
|
124
|
+
return tmpPath;
|
|
125
|
+
}
|
|
126
|
+
/** Clean up temp files (best effort — ignore errors). */
|
|
127
|
+
async cleanup(filePath) {
|
|
128
|
+
if (filePath.includes(TEMP_DIR)) {
|
|
129
|
+
await rm(filePath, { force: true }).catch(() => {
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Execute the Zero CLI binary with the given arguments.
|
|
135
|
+
* Returns stdout on success (exit code 0).
|
|
136
|
+
* Throws ZeroCompilerNotFoundError if the binary isn't found.
|
|
137
|
+
* Throws ZeroTimeoutError if the invocation exceeds the timeout.
|
|
138
|
+
*/
|
|
139
|
+
exec(args) {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const timeout = setTimeout(() => {
|
|
142
|
+
killed = true;
|
|
143
|
+
reject(new ZeroTimeoutError(`${this.binaryPath} ${args.join(" ")}`, this.timeout));
|
|
144
|
+
}, this.timeout);
|
|
145
|
+
let killed = false;
|
|
146
|
+
execFile(
|
|
147
|
+
this.binaryPath,
|
|
148
|
+
args,
|
|
149
|
+
{
|
|
150
|
+
cwd: this.workingDir,
|
|
151
|
+
maxBuffer: 1024 * 1024
|
|
152
|
+
// 1MB
|
|
153
|
+
},
|
|
154
|
+
(error, stdout, stderr) => {
|
|
155
|
+
clearTimeout(timeout);
|
|
156
|
+
if (killed) return;
|
|
157
|
+
if (error) {
|
|
158
|
+
if (error.code === "ENOENT") {
|
|
159
|
+
reject(new ZeroCompilerNotFoundError(this.binaryPath));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const exitCode = error.code ?? error.status;
|
|
163
|
+
if (exitCode === ZERO_EXIT_ERRORS && stdout) {
|
|
164
|
+
resolve(stdout);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (exitCode === ZERO_EXIT_INTERNAL) {
|
|
168
|
+
reject(
|
|
169
|
+
new ZeroBuildFailedError([
|
|
170
|
+
{
|
|
171
|
+
code: "ZERO_INTERNAL",
|
|
172
|
+
severity: "error",
|
|
173
|
+
message: stderr || error.message,
|
|
174
|
+
line: 0
|
|
175
|
+
}
|
|
176
|
+
])
|
|
177
|
+
);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
reject(error);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
resolve(stdout);
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export {
|
|
191
|
+
TEMP_DIR,
|
|
192
|
+
ZeroCompiler
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=chunk-DE5JDJKT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/compiler.ts"],"sourcesContent":["/**\n * @moikapy/origen-zero — ZeroCompiler class\n *\n * Wraps the Zero CLI binary, invoking it as a subprocess with --json flags\n * and parsing the structured output into typed results.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { mkdir, writeFile, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type {\n ZeroCompilerLike,\n ZeroCompilerConfig,\n ZeroSourceFile,\n ZeroCheckResult,\n ZeroGraphResult,\n ZeroSizeResult,\n ZeroFixResult,\n ZeroBuildResult,\n ZeroBuildOptions,\n} from \"./types.js\";\nimport {\n parseCheckOutput,\n parseGraphOutput,\n parseSizeOutput,\n parseFixOutput,\n} from \"./parser.js\";\nimport {\n ZeroCompilerNotFoundError,\n ZeroTimeoutError,\n ZeroBuildFailedError,\n} from \"./errors.js\";\n\n// ── Defaults ────────────────────────────────────────────────────────────\n\nconst DEFAULT_BINARY = \"zero\";\nconst DEFAULT_TIMEOUT = 30_000;\n\n/** Temp directory for Zero compilation artifacts. Shared across modules. */\nexport const TEMP_DIR = \".zero-origen/tmp\";\nconst ZERO_EXIT_OK = 0;\nconst ZERO_EXIT_ERRORS = 1;\nconst ZERO_EXIT_INTERNAL = 2;\n\n// ── ZeroCompiler ────────────────────────────────────────────────────────\n\nexport class ZeroCompiler implements ZeroCompilerLike {\n private readonly binaryPath: string;\n private readonly workingDir: string;\n private readonly timeout: number;\n\n constructor(config?: ZeroCompilerConfig) {\n this.binaryPath = config?.binaryPath ?? DEFAULT_BINARY;\n this.workingDir = config?.workingDir ?? process.cwd();\n this.timeout = config?.timeout ?? DEFAULT_TIMEOUT;\n }\n\n // ── Public API ──────────────────────────────────────────────────────\n\n /** Check a Zero file or package for errors. Returns structured diagnostics. */\n async check(source: string | ZeroSourceFile): Promise<ZeroCheckResult> {\n const filePath = await this.writeSource(source);\n try {\n const stdout = await this.exec([\"check\", \"--json\", filePath]);\n return parseCheckOutput(stdout);\n } finally {\n await this.cleanup(filePath);\n }\n }\n\n /** Get the dependency graph for a Zero package. */\n async graph(source: string | ZeroSourceFile): Promise<ZeroGraphResult> {\n const filePath = await this.writeSource(source);\n try {\n const stdout = await this.exec([\"graph\", \"--json\", filePath]);\n return parseGraphOutput(stdout);\n } finally {\n await this.cleanup(filePath);\n }\n }\n\n /** Get size estimates for functions in a Zero file. */\n async size(source: string | ZeroSourceFile): Promise<ZeroSizeResult> {\n const filePath = await this.writeSource(source);\n try {\n const stdout = await this.exec([\"size\", \"--json\", filePath]);\n return parseSizeOutput(stdout);\n } finally {\n await this.cleanup(filePath);\n }\n }\n\n /** Get repair suggestions for a Zero program. */\n async fix(source: string | ZeroSourceFile): Promise<ZeroFixResult> {\n const filePath = await this.writeSource(source);\n try {\n const stdout = await this.exec([\"fix\", \"--plan\", \"--json\", filePath]);\n return parseFixOutput(stdout);\n } finally {\n await this.cleanup(filePath);\n }\n }\n\n /** Build a Zero file to a native executable. */\n async build(\n source: string | ZeroSourceFile,\n options?: ZeroBuildOptions,\n ): Promise<ZeroBuildResult> {\n const filePath = await this.writeSource(source);\n const args = [\"build\", \"--json\", \"--emit\", options?.emit ?? \"exe\"];\n\n if (options?.target) {\n args.push(\"--target\", options.target);\n }\n\n if (options?.out) {\n args.push(\"--out\", options.out);\n }\n\n args.push(filePath);\n\n try {\n const stdout = await this.exec(args);\n // Build produces structured JSON output\n const json = JSON.parse(stdout);\n return {\n ok: true,\n outputPath: json.artifactPath ?? options?.out,\n diagnostics: [],\n };\n } catch (err) {\n if (err instanceof ZeroCompilerNotFoundError) throw err;\n // Build errors may include diagnostics in stderr or structured output\n return {\n ok: false,\n diagnostics: [],\n };\n } finally {\n await this.cleanup(filePath);\n }\n }\n\n /** Get a human-readable explanation for a diagnostic code. */\n async explain(diagnosticCode: string): Promise<string> {\n const stdout = await this.exec([\"explain\", diagnosticCode]);\n return stdout.trim();\n }\n\n // ── Internal ────────────────────────────────────────────────────────\n\n /** Resolve source to a file path. If inline content, write to temp dir. */\n private async writeSource(source: string | ZeroSourceFile): Promise<string> {\n // If it's a ZeroSourceFile with explicit content, write to temp\n if (typeof source !== \"string\") {\n if (source.content !== undefined) {\n const tmpPath = join(this.workingDir, TEMP_DIR, source.path);\n await mkdir(join(this.workingDir, TEMP_DIR), { recursive: true });\n await writeFile(tmpPath, source.content, \"utf-8\");\n return tmpPath;\n }\n // Content is undefined — read from disk at source.path\n return source.path;\n }\n\n // String: check if it's a file path that exists on disk\n try {\n const stat = await import(\"node:fs/promises\").then((fs) => fs.stat(source));\n if (stat.isFile()) return source; // It's a real file path\n } catch {\n // Not a file — treat as inline source\n }\n\n // Inline source — write to temp file\n const tmpPath = join(this.workingDir, TEMP_DIR, `check-${Date.now()}.0`);\n await mkdir(join(this.workingDir, TEMP_DIR), { recursive: true });\n await writeFile(tmpPath, source, \"utf-8\");\n return tmpPath;\n }\n\n /** Clean up temp files (best effort — ignore errors). */\n private async cleanup(filePath: string): Promise<void> {\n if (filePath.includes(TEMP_DIR)) {\n await rm(filePath, { force: true }).catch(() => {});\n }\n }\n\n /**\n * Execute the Zero CLI binary with the given arguments.\n * Returns stdout on success (exit code 0).\n * Throws ZeroCompilerNotFoundError if the binary isn't found.\n * Throws ZeroTimeoutError if the invocation exceeds the timeout.\n */\n private exec(args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n killed = true;\n reject(new ZeroTimeoutError(`${this.binaryPath} ${args.join(\" \")}`, this.timeout));\n }, this.timeout);\n\n let killed = false;\n\n execFile(\n this.binaryPath,\n args,\n {\n cwd: this.workingDir,\n maxBuffer: 1024 * 1024, // 1MB\n },\n (error, stdout, stderr) => {\n clearTimeout(timeout);\n if (killed) return;\n\n if (error) {\n // ENOENT means binary not found\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n reject(new ZeroCompilerNotFoundError(this.binaryPath));\n return;\n }\n // Exit code 1 means errors in the source – check both code (Node 25+) and status (older)\n const exitCode = (error as NodeJS.ErrnoException & { code?: number; status?: number }).code\n ?? (error as NodeJS.ErrnoException & { status?: number }).status;\n if (exitCode === ZERO_EXIT_ERRORS && stdout) {\n resolve(stdout);\n return;\n }\n // Exit code 2 means internal error\n if (exitCode === ZERO_EXIT_INTERNAL) {\n reject(\n new ZeroBuildFailedError([\n {\n code: \"ZERO_INTERNAL\",\n severity: \"error\",\n message: stderr || error.message,\n line: 0,\n },\n ]),\n );\n return;\n }\n reject(error);\n return;\n }\n\n resolve(stdout);\n },\n );\n });\n }\n}"],"mappings":"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","names":["tmpPath"]}
|