@aionis/manifest 0.1.1
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/CHANGELOG.md +26 -0
- package/LICENSE +178 -0
- package/README.md +170 -0
- package/dist/ast/types.d.ts +34 -0
- package/dist/ast/types.js +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +122 -0
- package/dist/compile.d.ts +14 -0
- package/dist/compile.js +219 -0
- package/dist/contracts.d.ts +12610 -0
- package/dist/contracts.js +401 -0
- package/dist/diagnostics/types.d.ts +17 -0
- package/dist/diagnostics/types.js +1 -0
- package/dist/execute/localRuntime.d.ts +5 -0
- package/dist/execute/localRuntime.js +165 -0
- package/dist/execute/moduleRuntime.d.ts +25 -0
- package/dist/execute/moduleRuntime.js +352 -0
- package/dist/execute/types.d.ts +113 -0
- package/dist/execute/types.js +1 -0
- package/dist/execute-cli.d.ts +2 -0
- package/dist/execute-cli.js +112 -0
- package/dist/execute.d.ts +6 -0
- package/dist/execute.js +46 -0
- package/dist/graph/buildExecutionGraph.d.ts +8 -0
- package/dist/graph/buildExecutionGraph.js +69 -0
- package/dist/graph/types.d.ts +24 -0
- package/dist/graph/types.js +1 -0
- package/dist/handoff-store-cli.d.ts +2 -0
- package/dist/handoff-store-cli.js +139 -0
- package/dist/handoff-store.d.ts +103 -0
- package/dist/handoff-store.js +78 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +21 -0
- package/dist/ir/types.d.ts +92 -0
- package/dist/ir/types.js +1 -0
- package/dist/parser/parseAst.d.ts +3 -0
- package/dist/parser/parseAst.js +207 -0
- package/dist/parser/payload.d.ts +6 -0
- package/dist/parser/payload.js +211 -0
- package/dist/plan/buildExecutionPlan.d.ts +9 -0
- package/dist/plan/buildExecutionPlan.js +98 -0
- package/dist/plan/types.d.ts +44 -0
- package/dist/plan/types.js +1 -0
- package/dist/publish-cli.d.ts +2 -0
- package/dist/publish-cli.js +249 -0
- package/dist/publish.d.ts +148 -0
- package/dist/publish.js +190 -0
- package/dist/recover-cli.d.ts +2 -0
- package/dist/recover-cli.js +258 -0
- package/dist/recover.d.ts +489 -0
- package/dist/recover.js +290 -0
- package/dist/refs/resolveRefs.d.ts +13 -0
- package/dist/refs/resolveRefs.js +104 -0
- package/dist/registry/loadModuleRegistry.d.ts +28 -0
- package/dist/registry/loadModuleRegistry.js +97 -0
- package/dist/registry/types.d.ts +20 -0
- package/dist/registry/types.js +2 -0
- package/dist/resume-cli.d.ts +2 -0
- package/dist/resume-cli.js +379 -0
- package/dist/resume.d.ts +2076 -0
- package/dist/resume.js +452 -0
- package/dist/run-cli.d.ts +2 -0
- package/dist/run-cli.js +119 -0
- package/dist/run.d.ts +9 -0
- package/dist/run.js +43 -0
- package/dist/runtime-handoff-cli.d.ts +2 -0
- package/dist/runtime-handoff-cli.js +179 -0
- package/dist/runtime-handoff.d.ts +914 -0
- package/dist/runtime-handoff.js +383 -0
- package/dist/scanner/scanSource.d.ts +9 -0
- package/dist/scanner/scanSource.js +43 -0
- package/dist/schema/validateIrSchemas.d.ts +3 -0
- package/dist/schema/validateIrSchemas.js +64 -0
- package/dist/validate-module-cli.d.ts +2 -0
- package/dist/validate-module-cli.js +93 -0
- package/dist/validate-registry-cli.d.ts +2 -0
- package/dist/validate-registry-cli.js +82 -0
- package/dist/validate.d.ts +52 -0
- package/dist/validate.js +91 -0
- package/fixtures/duplicate-doc.aionis.md +19 -0
- package/fixtures/fenced-example.aionis.md +27 -0
- package/fixtures/malformed-payload.aionis.md +9 -0
- package/fixtures/npm-installed-module-registry.json +17 -0
- package/fixtures/standalone-module-registry.json +13 -0
- package/fixtures/standalone-runner-plan.json +51 -0
- package/fixtures/standalone-runner.aionis.md +29 -0
- package/fixtures/unresolved-ref.aionis.md +14 -0
- package/fixtures/valid-minimal.aionis.md +24 -0
- package/fixtures/valid-workflow.aionis.md +29 -0
- package/official-modules/copy-summary/CHANGELOG.md +6 -0
- package/official-modules/copy-summary/README.md +43 -0
- package/official-modules/copy-summary/index.mjs +41 -0
- package/official-modules/copy-summary/package.json +31 -0
- package/official-modules/json-transform/CHANGELOG.md +6 -0
- package/official-modules/json-transform/README.md +51 -0
- package/official-modules/json-transform/index.mjs +53 -0
- package/official-modules/json-transform/package.json +31 -0
- package/official-modules/research-claims/CHANGELOG.md +6 -0
- package/official-modules/research-claims/README.md +47 -0
- package/official-modules/research-claims/index.mjs +44 -0
- package/official-modules/research-claims/package.json +31 -0
- package/package.json +74 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { rangeFromOffsets } from "../scanner/scanSource.js";
|
|
2
|
+
import { parseAionisPayload } from "./payload.js";
|
|
3
|
+
function isFenceLine(line) {
|
|
4
|
+
return /^\s*```/.test(line);
|
|
5
|
+
}
|
|
6
|
+
function isHeadingLine(line) {
|
|
7
|
+
return /^#{1,6}\s+/.test(line);
|
|
8
|
+
}
|
|
9
|
+
function isDirectiveLine(line) {
|
|
10
|
+
return /^\s*@[A-Za-z][A-Za-z0-9_.-]*/.test(line);
|
|
11
|
+
}
|
|
12
|
+
function countNewlines(source, start, end) {
|
|
13
|
+
let count = 0;
|
|
14
|
+
for (let i = start; i < end; i += 1) {
|
|
15
|
+
if (source[i] === "\n")
|
|
16
|
+
count += 1;
|
|
17
|
+
}
|
|
18
|
+
return count;
|
|
19
|
+
}
|
|
20
|
+
function findDirectiveBlockEnd(source, braceStart) {
|
|
21
|
+
let depth = 0;
|
|
22
|
+
let quote = null;
|
|
23
|
+
let escaped = false;
|
|
24
|
+
for (let i = braceStart; i < source.length; i += 1) {
|
|
25
|
+
const char = source[i];
|
|
26
|
+
if (quote) {
|
|
27
|
+
if (escaped) {
|
|
28
|
+
escaped = false;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (char === "\\") {
|
|
32
|
+
escaped = true;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (char === quote) {
|
|
36
|
+
quote = null;
|
|
37
|
+
}
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (char === "\"" || char === "'") {
|
|
41
|
+
quote = char;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (char === "{") {
|
|
45
|
+
depth += 1;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (char === "}") {
|
|
49
|
+
depth -= 1;
|
|
50
|
+
if (depth === 0)
|
|
51
|
+
return i + 1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return -1;
|
|
55
|
+
}
|
|
56
|
+
function makeInvalidDirectiveDiagnostic(scan, start, end, message) {
|
|
57
|
+
return {
|
|
58
|
+
severity: "error",
|
|
59
|
+
code: "INVALID_PAYLOAD",
|
|
60
|
+
message,
|
|
61
|
+
loc: rangeFromOffsets(scan, start, end),
|
|
62
|
+
hint: "Directives must be followed by a balanced { ... } payload.",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function parseAst(scan) {
|
|
66
|
+
const lines = scan.source.split("\n");
|
|
67
|
+
const children = [];
|
|
68
|
+
const diagnostics = [];
|
|
69
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
70
|
+
const line = lines[lineIndex];
|
|
71
|
+
const lineStart = scan.lineStarts[lineIndex] ?? scan.source.length;
|
|
72
|
+
if (line.trim().length === 0) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (isFenceLine(line)) {
|
|
76
|
+
const startOffset = lineStart;
|
|
77
|
+
const fenceStart = line.trim();
|
|
78
|
+
const info = fenceStart.slice(3).trim() || undefined;
|
|
79
|
+
let endLineIndex = lineIndex;
|
|
80
|
+
while (endLineIndex + 1 < lines.length) {
|
|
81
|
+
endLineIndex += 1;
|
|
82
|
+
if (isFenceLine(lines[endLineIndex])) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const isClosed = endLineIndex !== lineIndex && isFenceLine(lines[endLineIndex]);
|
|
87
|
+
const endOffset = endLineIndex + 1 < scan.lineStarts.length ? scan.lineStarts[endLineIndex + 1] : scan.source.length;
|
|
88
|
+
const node = {
|
|
89
|
+
type: "CodeFenceNode",
|
|
90
|
+
fence: "```",
|
|
91
|
+
info,
|
|
92
|
+
content: lines.slice(lineIndex + 1, isClosed ? endLineIndex : endLineIndex + 1).join("\n"),
|
|
93
|
+
raw: scan.source.slice(startOffset, endOffset),
|
|
94
|
+
loc: rangeFromOffsets(scan, startOffset, endOffset),
|
|
95
|
+
};
|
|
96
|
+
children.push(node);
|
|
97
|
+
if (!isClosed) {
|
|
98
|
+
diagnostics.push({
|
|
99
|
+
severity: "warning",
|
|
100
|
+
code: "UNCLOSED_FENCE",
|
|
101
|
+
message: "Code fence reaches end of file without a closing delimiter.",
|
|
102
|
+
loc: node.loc,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
lineIndex = endLineIndex;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (isHeadingLine(line)) {
|
|
109
|
+
const match = /^(#{1,6})\s+(.*)$/.exec(line);
|
|
110
|
+
if (match) {
|
|
111
|
+
const node = {
|
|
112
|
+
type: "HeadingNode",
|
|
113
|
+
depth: match[1].length,
|
|
114
|
+
text: match[2],
|
|
115
|
+
raw: line,
|
|
116
|
+
loc: rangeFromOffsets(scan, lineStart, lineStart + line.length),
|
|
117
|
+
};
|
|
118
|
+
children.push(node);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (isDirectiveLine(line)) {
|
|
123
|
+
const match = /^(\s*)@([A-Za-z][A-Za-z0-9_.-]*)/.exec(line);
|
|
124
|
+
if (!match)
|
|
125
|
+
continue;
|
|
126
|
+
const directiveStart = lineStart + match[1].length;
|
|
127
|
+
const afterHead = directiveStart + 1 + match[2].length;
|
|
128
|
+
let payloadStart = afterHead;
|
|
129
|
+
while (payloadStart < scan.source.length && /\s/.test(scan.source[payloadStart])) {
|
|
130
|
+
payloadStart += 1;
|
|
131
|
+
}
|
|
132
|
+
if (scan.source[payloadStart] !== "{") {
|
|
133
|
+
const endOffset = lineStart + line.length;
|
|
134
|
+
const node = {
|
|
135
|
+
type: "DirectiveNode",
|
|
136
|
+
name: match[2],
|
|
137
|
+
payload: null,
|
|
138
|
+
raw: scan.source.slice(directiveStart, endOffset),
|
|
139
|
+
loc: rangeFromOffsets(scan, directiveStart, endOffset),
|
|
140
|
+
diagnostics: [
|
|
141
|
+
makeInvalidDirectiveDiagnostic(scan, directiveStart, endOffset, "Directive is missing an object payload."),
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
children.push(node);
|
|
145
|
+
diagnostics.push(...(node.diagnostics ?? []));
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const endOffset = findDirectiveBlockEnd(scan.source, payloadStart);
|
|
149
|
+
if (endOffset < 0) {
|
|
150
|
+
const node = {
|
|
151
|
+
type: "DirectiveNode",
|
|
152
|
+
name: match[2],
|
|
153
|
+
payload: null,
|
|
154
|
+
raw: scan.source.slice(directiveStart),
|
|
155
|
+
loc: rangeFromOffsets(scan, directiveStart, scan.source.length),
|
|
156
|
+
diagnostics: [
|
|
157
|
+
makeInvalidDirectiveDiagnostic(scan, directiveStart, scan.source.length, "Directive payload ends before its closing brace."),
|
|
158
|
+
],
|
|
159
|
+
};
|
|
160
|
+
children.push(node);
|
|
161
|
+
diagnostics.push(...(node.diagnostics ?? []));
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
const loc = rangeFromOffsets(scan, directiveStart, endOffset);
|
|
165
|
+
const payload = parseAionisPayload(scan.source.slice(payloadStart, endOffset), loc);
|
|
166
|
+
const node = {
|
|
167
|
+
type: "DirectiveNode",
|
|
168
|
+
name: match[2],
|
|
169
|
+
payload: payload.value,
|
|
170
|
+
raw: scan.source.slice(directiveStart, endOffset),
|
|
171
|
+
loc,
|
|
172
|
+
diagnostics: payload.diagnostics,
|
|
173
|
+
};
|
|
174
|
+
children.push(node);
|
|
175
|
+
diagnostics.push(...payload.diagnostics);
|
|
176
|
+
lineIndex += countNewlines(scan.source, directiveStart, endOffset);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const paragraphStart = lineStart;
|
|
180
|
+
let paragraphEndLine = lineIndex;
|
|
181
|
+
while (paragraphEndLine + 1 < lines.length) {
|
|
182
|
+
const next = lines[paragraphEndLine + 1];
|
|
183
|
+
if (next.trim().length === 0 ||
|
|
184
|
+
isFenceLine(next) ||
|
|
185
|
+
isHeadingLine(next) ||
|
|
186
|
+
isDirectiveLine(next)) {
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
paragraphEndLine += 1;
|
|
190
|
+
}
|
|
191
|
+
const paragraphEndOffset = paragraphEndLine + 1 < scan.lineStarts.length ? scan.lineStarts[paragraphEndLine + 1] : scan.source.length;
|
|
192
|
+
const node = {
|
|
193
|
+
type: "ParagraphNode",
|
|
194
|
+
text: lines.slice(lineIndex, paragraphEndLine + 1).join("\n").trim(),
|
|
195
|
+
raw: scan.source.slice(paragraphStart, paragraphEndOffset),
|
|
196
|
+
loc: rangeFromOffsets(scan, paragraphStart, paragraphEndOffset),
|
|
197
|
+
};
|
|
198
|
+
children.push(node);
|
|
199
|
+
lineIndex = paragraphEndLine;
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
type: "DocumentNode",
|
|
203
|
+
children,
|
|
204
|
+
diagnostics,
|
|
205
|
+
loc: rangeFromOffsets(scan, 0, scan.source.length),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
class PayloadSyntaxError extends Error {
|
|
2
|
+
index;
|
|
3
|
+
constructor(message, index) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "PayloadSyntaxError";
|
|
6
|
+
this.index = index;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
class PayloadParser {
|
|
10
|
+
text;
|
|
11
|
+
index = 0;
|
|
12
|
+
constructor(text) {
|
|
13
|
+
this.text = text;
|
|
14
|
+
}
|
|
15
|
+
parse() {
|
|
16
|
+
this.skipWhitespace();
|
|
17
|
+
const value = this.parseValue();
|
|
18
|
+
this.skipWhitespace();
|
|
19
|
+
if (!this.isAtEnd()) {
|
|
20
|
+
throw new PayloadSyntaxError("Unexpected trailing content in directive payload.", this.index);
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
parseValue() {
|
|
25
|
+
const char = this.peek();
|
|
26
|
+
if (char === "{")
|
|
27
|
+
return this.parseObject();
|
|
28
|
+
if (char === "[")
|
|
29
|
+
return this.parseArray();
|
|
30
|
+
if (char === "\"" || char === "'")
|
|
31
|
+
return this.parseString();
|
|
32
|
+
if (char === "-" || this.isDigit(char))
|
|
33
|
+
return this.parseNumber();
|
|
34
|
+
if (this.isIdentifierStart(char))
|
|
35
|
+
return this.parseLiteral();
|
|
36
|
+
throw new PayloadSyntaxError(`Unexpected token '${char ?? "EOF"}' in payload.`, this.index);
|
|
37
|
+
}
|
|
38
|
+
parseObject() {
|
|
39
|
+
this.expect("{");
|
|
40
|
+
this.skipWhitespace();
|
|
41
|
+
const out = {};
|
|
42
|
+
if (this.peek() === "}") {
|
|
43
|
+
this.index += 1;
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
while (!this.isAtEnd()) {
|
|
47
|
+
const key = this.parseKey();
|
|
48
|
+
this.skipWhitespace();
|
|
49
|
+
this.expect(":");
|
|
50
|
+
this.skipWhitespace();
|
|
51
|
+
out[key] = this.parseValue();
|
|
52
|
+
this.skipWhitespace();
|
|
53
|
+
if (this.peek() === ",") {
|
|
54
|
+
this.index += 1;
|
|
55
|
+
this.skipWhitespace();
|
|
56
|
+
}
|
|
57
|
+
if (this.peek() === "}") {
|
|
58
|
+
this.index += 1;
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
throw new PayloadSyntaxError("Expected closing brace for object payload.", this.index);
|
|
63
|
+
}
|
|
64
|
+
parseArray() {
|
|
65
|
+
this.expect("[");
|
|
66
|
+
this.skipWhitespace();
|
|
67
|
+
const out = [];
|
|
68
|
+
if (this.peek() === "]") {
|
|
69
|
+
this.index += 1;
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
while (!this.isAtEnd()) {
|
|
73
|
+
out.push(this.parseValue());
|
|
74
|
+
this.skipWhitespace();
|
|
75
|
+
if (this.peek() === ",") {
|
|
76
|
+
this.index += 1;
|
|
77
|
+
this.skipWhitespace();
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (this.peek() === "]") {
|
|
81
|
+
this.index += 1;
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
throw new PayloadSyntaxError("Expected ',' or ']' inside array payload.", this.index);
|
|
85
|
+
}
|
|
86
|
+
throw new PayloadSyntaxError("Expected closing bracket for array payload.", this.index);
|
|
87
|
+
}
|
|
88
|
+
parseKey() {
|
|
89
|
+
const char = this.peek();
|
|
90
|
+
if (char === "\"" || char === "'") {
|
|
91
|
+
return this.parseString();
|
|
92
|
+
}
|
|
93
|
+
if (!this.isIdentifierStart(char)) {
|
|
94
|
+
throw new PayloadSyntaxError("Expected an object key.", this.index);
|
|
95
|
+
}
|
|
96
|
+
const start = this.index;
|
|
97
|
+
this.index += 1;
|
|
98
|
+
while (!this.isAtEnd() && this.isIdentifierPart(this.peek())) {
|
|
99
|
+
this.index += 1;
|
|
100
|
+
}
|
|
101
|
+
return this.text.slice(start, this.index);
|
|
102
|
+
}
|
|
103
|
+
parseString() {
|
|
104
|
+
const quote = this.peek();
|
|
105
|
+
if (quote !== "\"" && quote !== "'") {
|
|
106
|
+
throw new PayloadSyntaxError("Expected a quoted string.", this.index);
|
|
107
|
+
}
|
|
108
|
+
this.index += 1;
|
|
109
|
+
let out = "";
|
|
110
|
+
while (!this.isAtEnd()) {
|
|
111
|
+
const char = this.text[this.index];
|
|
112
|
+
if (char === "\\") {
|
|
113
|
+
const next = this.text[this.index + 1];
|
|
114
|
+
if (next === undefined) {
|
|
115
|
+
throw new PayloadSyntaxError("String ends with a dangling escape.", this.index);
|
|
116
|
+
}
|
|
117
|
+
const escapes = {
|
|
118
|
+
"\"": "\"",
|
|
119
|
+
"'": "'",
|
|
120
|
+
"\\": "\\",
|
|
121
|
+
n: "\n",
|
|
122
|
+
r: "\r",
|
|
123
|
+
t: "\t",
|
|
124
|
+
};
|
|
125
|
+
out += escapes[next] ?? next;
|
|
126
|
+
this.index += 2;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (char === quote) {
|
|
130
|
+
this.index += 1;
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
out += char;
|
|
134
|
+
this.index += 1;
|
|
135
|
+
}
|
|
136
|
+
throw new PayloadSyntaxError("Expected closing quote for string.", this.index);
|
|
137
|
+
}
|
|
138
|
+
parseNumber() {
|
|
139
|
+
const match = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/.exec(this.text.slice(this.index));
|
|
140
|
+
if (!match) {
|
|
141
|
+
throw new PayloadSyntaxError("Invalid numeric literal.", this.index);
|
|
142
|
+
}
|
|
143
|
+
this.index += match[0].length;
|
|
144
|
+
return Number(match[0]);
|
|
145
|
+
}
|
|
146
|
+
parseLiteral() {
|
|
147
|
+
const start = this.index;
|
|
148
|
+
this.index += 1;
|
|
149
|
+
while (!this.isAtEnd() && this.isIdentifierPart(this.peek())) {
|
|
150
|
+
this.index += 1;
|
|
151
|
+
}
|
|
152
|
+
const literal = this.text.slice(start, this.index);
|
|
153
|
+
if (literal === "true")
|
|
154
|
+
return true;
|
|
155
|
+
if (literal === "false")
|
|
156
|
+
return false;
|
|
157
|
+
if (literal === "null")
|
|
158
|
+
return null;
|
|
159
|
+
throw new PayloadSyntaxError(`Unsupported bare literal '${literal}'. Use quoted strings for stability.`, start);
|
|
160
|
+
}
|
|
161
|
+
skipWhitespace() {
|
|
162
|
+
while (!this.isAtEnd() && /\s/.test(this.text[this.index])) {
|
|
163
|
+
this.index += 1;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
expect(char) {
|
|
167
|
+
if (this.peek() !== char) {
|
|
168
|
+
throw new PayloadSyntaxError(`Expected '${char}' but found '${this.peek() ?? "EOF"}'.`, this.index);
|
|
169
|
+
}
|
|
170
|
+
this.index += 1;
|
|
171
|
+
}
|
|
172
|
+
peek() {
|
|
173
|
+
return this.text[this.index];
|
|
174
|
+
}
|
|
175
|
+
isAtEnd() {
|
|
176
|
+
return this.index >= this.text.length;
|
|
177
|
+
}
|
|
178
|
+
isDigit(char) {
|
|
179
|
+
return !!char && /[0-9]/.test(char);
|
|
180
|
+
}
|
|
181
|
+
isIdentifierStart(char) {
|
|
182
|
+
return !!char && /[A-Za-z_]/.test(char);
|
|
183
|
+
}
|
|
184
|
+
isIdentifierPart(char) {
|
|
185
|
+
return !!char && /[A-Za-z0-9_.-]/.test(char);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
export function parseAionisPayload(raw, loc) {
|
|
189
|
+
try {
|
|
190
|
+
const parser = new PayloadParser(raw);
|
|
191
|
+
return {
|
|
192
|
+
value: parser.parse(),
|
|
193
|
+
diagnostics: [],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
const message = error instanceof Error ? error.message : "Unknown payload parse failure.";
|
|
198
|
+
return {
|
|
199
|
+
value: null,
|
|
200
|
+
diagnostics: [
|
|
201
|
+
{
|
|
202
|
+
severity: "error",
|
|
203
|
+
code: "INVALID_PAYLOAD",
|
|
204
|
+
message,
|
|
205
|
+
loc,
|
|
206
|
+
hint: "Check directive braces, quoted strings, and array separators.",
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Diagnostic } from "../diagnostics/types.js";
|
|
2
|
+
import type { ExecutionGraph } from "../graph/types.js";
|
|
3
|
+
import type { AionisManifestIR } from "../ir/types.js";
|
|
4
|
+
import { type ExecutionPlanV1 } from "./types.js";
|
|
5
|
+
export declare function buildExecutionPlanV1(args: {
|
|
6
|
+
ir: AionisManifestIR;
|
|
7
|
+
graph: ExecutionGraph | null;
|
|
8
|
+
diagnostics?: Diagnostic[];
|
|
9
|
+
}): ExecutionPlanV1;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { EXECUTION_PLAN_V1, } from "./types.js";
|
|
2
|
+
function mergeContextFrames(frames) {
|
|
3
|
+
const merged = {};
|
|
4
|
+
for (const frame of frames) {
|
|
5
|
+
for (const [key, value] of Object.entries(frame)) {
|
|
6
|
+
merged[key] = value;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return merged;
|
|
10
|
+
}
|
|
11
|
+
function buildExecutionId(step, index) {
|
|
12
|
+
if (step.output_ref)
|
|
13
|
+
return step.output_ref;
|
|
14
|
+
if (step.module)
|
|
15
|
+
return `run.${step.module}.${index + 1}`;
|
|
16
|
+
if (step.tool)
|
|
17
|
+
return `run.${step.tool}.${index + 1}`;
|
|
18
|
+
if (step.agent)
|
|
19
|
+
return `run.${step.agent}.${index + 1}`;
|
|
20
|
+
return `run.execution_${index + 1}`;
|
|
21
|
+
}
|
|
22
|
+
function buildExecutionStep(step, index) {
|
|
23
|
+
return {
|
|
24
|
+
execution_id: buildExecutionId(step, index),
|
|
25
|
+
module: step.module,
|
|
26
|
+
tool: step.tool,
|
|
27
|
+
agent: step.agent,
|
|
28
|
+
input: step.input,
|
|
29
|
+
input_ref: step.input_ref,
|
|
30
|
+
output_ref: step.output_ref,
|
|
31
|
+
depends_on: step.depends_on ?? [],
|
|
32
|
+
deterministic: step.deterministic,
|
|
33
|
+
loc: step.loc,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function collectExpectedOutputs(ir) {
|
|
37
|
+
const replayOutputs = ir.replay.flatMap((entry) => entry.expected_outputs ?? []);
|
|
38
|
+
if (replayOutputs.length > 0)
|
|
39
|
+
return replayOutputs;
|
|
40
|
+
return ir.executions
|
|
41
|
+
.map((execution) => execution.output_ref)
|
|
42
|
+
.filter((value) => typeof value === "string" && value.length > 0);
|
|
43
|
+
}
|
|
44
|
+
function collectRequiredCapabilities(ir) {
|
|
45
|
+
const capabilities = new Set();
|
|
46
|
+
if (ir.executions.length > 0) {
|
|
47
|
+
capabilities.add("direct_execution");
|
|
48
|
+
capabilities.add("module_registry");
|
|
49
|
+
}
|
|
50
|
+
for (const replay of ir.replay) {
|
|
51
|
+
if (replay.mode === "deterministic")
|
|
52
|
+
capabilities.add("deterministic_replay");
|
|
53
|
+
if (replay.mode === "assisted")
|
|
54
|
+
capabilities.add("assisted_replay");
|
|
55
|
+
if (replay.executable)
|
|
56
|
+
capabilities.add("state_persistence");
|
|
57
|
+
}
|
|
58
|
+
if (ir.memory.some((entry) => entry.writeback)) {
|
|
59
|
+
capabilities.add("memory_writeback");
|
|
60
|
+
}
|
|
61
|
+
return [...capabilities];
|
|
62
|
+
}
|
|
63
|
+
function buildDeterminism(ir) {
|
|
64
|
+
const primaryReplay = ir.replay[0];
|
|
65
|
+
const executable = ir.replay.some((entry) => entry.executable === true) || ir.executions.length > 0;
|
|
66
|
+
return {
|
|
67
|
+
executable,
|
|
68
|
+
replay_mode: primaryReplay?.mode,
|
|
69
|
+
requires_resume_support: ir.replay.some((entry) => entry.executable === true),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function buildExecutionPlanV1(args) {
|
|
73
|
+
const contextFrames = args.ir.context.map((entry) => entry.data);
|
|
74
|
+
const context = {
|
|
75
|
+
merged: mergeContextFrames(contextFrames),
|
|
76
|
+
frames: contextFrames,
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
plan_version: EXECUTION_PLAN_V1,
|
|
80
|
+
doc: args.ir.doc
|
|
81
|
+
? {
|
|
82
|
+
id: args.ir.doc.id,
|
|
83
|
+
version: args.ir.doc.version,
|
|
84
|
+
kind: args.ir.doc.kind,
|
|
85
|
+
title: args.ir.doc.title,
|
|
86
|
+
status: args.ir.doc.status,
|
|
87
|
+
tags: args.ir.doc.tags,
|
|
88
|
+
}
|
|
89
|
+
: null,
|
|
90
|
+
context,
|
|
91
|
+
executions: args.ir.executions.map(buildExecutionStep),
|
|
92
|
+
graph: args.graph,
|
|
93
|
+
expected_outputs: collectExpectedOutputs(args.ir),
|
|
94
|
+
required_capabilities: collectRequiredCapabilities(args.ir),
|
|
95
|
+
determinism: buildDeterminism(args.ir),
|
|
96
|
+
diagnostics: args.diagnostics ?? args.ir.diagnostics,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Diagnostic, SourceRange } from "../diagnostics/types.js";
|
|
2
|
+
import type { ExecutionGraph } from "../graph/types.js";
|
|
3
|
+
import type { AionisObject, ReplayIR } from "../ir/types.js";
|
|
4
|
+
export declare const EXECUTION_PLAN_V1: "execution_plan_v1";
|
|
5
|
+
export interface ExecutionPlanDocMeta {
|
|
6
|
+
id: string;
|
|
7
|
+
version: string;
|
|
8
|
+
kind?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
status?: string;
|
|
11
|
+
tags?: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface ExecutionPlanContext {
|
|
14
|
+
merged: AionisObject;
|
|
15
|
+
frames: AionisObject[];
|
|
16
|
+
}
|
|
17
|
+
export interface ExecutionPlanStep {
|
|
18
|
+
execution_id: string;
|
|
19
|
+
module?: string;
|
|
20
|
+
tool?: string;
|
|
21
|
+
agent?: string;
|
|
22
|
+
input?: AionisObject;
|
|
23
|
+
input_ref?: string;
|
|
24
|
+
output_ref?: string;
|
|
25
|
+
depends_on: string[];
|
|
26
|
+
deterministic?: boolean;
|
|
27
|
+
loc?: SourceRange;
|
|
28
|
+
}
|
|
29
|
+
export interface ExecutionPlanDeterminism {
|
|
30
|
+
executable: boolean;
|
|
31
|
+
replay_mode?: ReplayIR["mode"];
|
|
32
|
+
requires_resume_support: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface ExecutionPlanV1 {
|
|
35
|
+
plan_version: typeof EXECUTION_PLAN_V1;
|
|
36
|
+
doc: ExecutionPlanDocMeta | null;
|
|
37
|
+
context: ExecutionPlanContext;
|
|
38
|
+
executions: ExecutionPlanStep[];
|
|
39
|
+
graph: ExecutionGraph | null;
|
|
40
|
+
expected_outputs: string[];
|
|
41
|
+
required_capabilities: string[];
|
|
42
|
+
determinism: ExecutionPlanDeterminism;
|
|
43
|
+
diagnostics: Diagnostic[];
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const EXECUTION_PLAN_V1 = "execution_plan_v1";
|