replay-self-healing-cli 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/ERROR_CODES.md +68 -0
- package/LICENSE +21 -0
- package/README.md +284 -0
- package/bin/replay.mjs +2 -0
- package/package.json +43 -0
- package/schemas/replay-artifact.schema.json +107 -0
- package/schemas/runner-output.schema.json +108 -0
- package/src/cli.mjs +1680 -0
package/ERROR_CODES.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Error Codes
|
|
2
|
+
|
|
3
|
+
All CLI errors are emitted as JSON with:
|
|
4
|
+
|
|
5
|
+
- `code`
|
|
6
|
+
- `message`
|
|
7
|
+
- optional `path`
|
|
8
|
+
- optional `expected`
|
|
9
|
+
- optional `received`
|
|
10
|
+
- optional `howToFix`
|
|
11
|
+
- optional `example`
|
|
12
|
+
|
|
13
|
+
## CLI input errors
|
|
14
|
+
|
|
15
|
+
- `E_UNKNOWN_FLAG` unknown CLI flag
|
|
16
|
+
- `E_TIMEOUT_INVALID` invalid `--timeout-ms`
|
|
17
|
+
- `E_PROMPT_REQUIRED` prompt missing from args/stdin
|
|
18
|
+
- `E_CONTEXT_CONFLICT` both `--context` and `--context-file` set
|
|
19
|
+
- `E_CONTEXT_JSON_INVALID` invalid JSON in context
|
|
20
|
+
- `E_CONTEXT_SHAPE_INVALID` context is not object
|
|
21
|
+
- `E_CONTEXT_FILE_NOT_FOUND` context file missing
|
|
22
|
+
- `E_COMMAND_UNKNOWN` unsupported command
|
|
23
|
+
|
|
24
|
+
## Runner discovery/execution errors
|
|
25
|
+
|
|
26
|
+
- `E_RUNNER_NOT_FOUND` no default runner discovered
|
|
27
|
+
- `E_RUNNER_PATH_NOT_FOUND` explicit runner path missing
|
|
28
|
+
- `E_RUNNER_UNSUPPORTED_EXTENSION` unsupported runner extension (e.g. `.ts`)
|
|
29
|
+
- `E_RUNNER_NOT_EXECUTABLE` runner not executable when required
|
|
30
|
+
- `E_RUNNER_START_FAILED` process spawn failure
|
|
31
|
+
- `E_RUNNER_TIMEOUT` runner timed out
|
|
32
|
+
- `E_RUNNER_EXIT_NON_ZERO` runner process exited with non-zero code
|
|
33
|
+
|
|
34
|
+
## Runner output validation errors
|
|
35
|
+
|
|
36
|
+
- `E_RUNNER_EMPTY_STDOUT` runner wrote no stdout
|
|
37
|
+
- `E_RUNNER_INVALID_JSON` runner stdout not parseable JSON
|
|
38
|
+
- `E_RUNNER_OUTPUT_SHAPE` output is not JSON object
|
|
39
|
+
- `E_RUNNER_STATUS_INVALID` status is not `ok` or `error`
|
|
40
|
+
- `E_RUNNER_EVENTS_INVALID` events is not array
|
|
41
|
+
- `E_RUNNER_RESPONSE_MISSING` status `ok` but missing response string
|
|
42
|
+
|
|
43
|
+
## Artifact IO and validation errors
|
|
44
|
+
|
|
45
|
+
- `E_INPUT_PATH_NOT_FOUND` `--in` target missing
|
|
46
|
+
- `E_INPUT_FILE_NOT_JSON` `--in` file is not `.json`
|
|
47
|
+
- `E_INPUT_NOT_FILE_OR_DIR` `--in` target not file/dir
|
|
48
|
+
- `E_ARTIFACT_JSON_INVALID` invalid JSON artifact file
|
|
49
|
+
- `E_ARTIFACT_SHAPE_INVALID` artifact is not object
|
|
50
|
+
- `E_ARTIFACT_TYPE_INVALID` artifactType mismatch
|
|
51
|
+
- `E_SCHEMA_VERSION_UNSUPPORTED` schemaVersion mismatch
|
|
52
|
+
- `E_ARTIFACT_ID_INVALID` missing/invalid id
|
|
53
|
+
- `E_ARTIFACT_STATUS_INVALID` missing/invalid status
|
|
54
|
+
- `E_ARTIFACT_EVENTS_INVALID` missing/invalid events array
|
|
55
|
+
- `E_ARTIFACT_EVENT_INVALID` event item not object
|
|
56
|
+
- `E_ARTIFACT_EVENT_TYPE_INVALID` event.type invalid
|
|
57
|
+
- `E_ARTIFACT_EVENT_SEQ_INVALID` event.seq invalid
|
|
58
|
+
- `E_ARTIFACT_EVENT_TIMESTAMP_INVALID` event.timestamp invalid
|
|
59
|
+
- `E_HEALED_ARTIFACT_INVALID` healed artifact fails validation
|
|
60
|
+
|
|
61
|
+
## Heal rule errors
|
|
62
|
+
|
|
63
|
+
- `E_HEAL_RULES_INVALID_JSON` heal rules file invalid JSON
|
|
64
|
+
- `E_HEAL_RULES_SHAPE_INVALID` heal rules must be object
|
|
65
|
+
|
|
66
|
+
## Internal fallback
|
|
67
|
+
|
|
68
|
+
- `E_UNHANDLED` unexpected runtime failure
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# replay-self-healing-cli
|
|
2
|
+
|
|
3
|
+
Zero-dependency CLI to capture LLM runs as replay artifacts, auto-heal trace inconsistencies, and produce validation/report output.
|
|
4
|
+
|
|
5
|
+
## Why this exists
|
|
6
|
+
|
|
7
|
+
- Prompt-first UX: run one prompt and get replay artifacts immediately.
|
|
8
|
+
- Runner is user-defined: framework choice stays outside this tool.
|
|
9
|
+
- Self-healing: the CLI preserves raw output, repairs common trace issues, and logs every repair action.
|
|
10
|
+
- LLM-friendly errors: failures are always emitted as machine-readable JSON with fix guidance.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g replay-self-healing-cli
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or run locally from this folder:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install
|
|
22
|
+
node ./bin/replay.mjs help
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This package has **zero dependencies**.
|
|
26
|
+
|
|
27
|
+
## 30-second quickstart
|
|
28
|
+
|
|
29
|
+
1. Create a runner at `.replay/runner.mjs`:
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
#!/usr/bin/env node
|
|
33
|
+
import process from 'node:process';
|
|
34
|
+
|
|
35
|
+
let input = '';
|
|
36
|
+
for await (const chunk of process.stdin) {
|
|
37
|
+
input += chunk;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const request = JSON.parse(input);
|
|
41
|
+
const now = new Date().toISOString();
|
|
42
|
+
|
|
43
|
+
const output = {
|
|
44
|
+
status: 'ok',
|
|
45
|
+
framework: 'custom',
|
|
46
|
+
response: `Echo: ${request.prompt}`,
|
|
47
|
+
events: [
|
|
48
|
+
{ seq: 1, timestamp: now, type: 'run_started', runId: request.runId, payload: {} },
|
|
49
|
+
{
|
|
50
|
+
seq: 2,
|
|
51
|
+
timestamp: now,
|
|
52
|
+
type: 'assistant_message',
|
|
53
|
+
runId: request.runId,
|
|
54
|
+
payload: { response: `Echo: ${request.prompt}` }
|
|
55
|
+
},
|
|
56
|
+
{ seq: 3, timestamp: now, type: 'run_completed', runId: request.runId, payload: {} }
|
|
57
|
+
],
|
|
58
|
+
sources: [],
|
|
59
|
+
usage: { inputTokens: 0, outputTokens: 0, costUsd: 0 }
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
process.stdout.write(JSON.stringify(output));
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
2. Run:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
replay "What are my top holdings?"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
3. Output files are created automatically under:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
.replay/artifacts/YYYY-MM-DD/
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Command overview
|
|
78
|
+
|
|
79
|
+
### Capture (default)
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
replay "your prompt"
|
|
83
|
+
replay capture "your prompt"
|
|
84
|
+
echo "your prompt" | replay
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Optional flags:
|
|
88
|
+
|
|
89
|
+
- `--runner <path>` override runner discovery
|
|
90
|
+
- `--out <dir>` override output directory
|
|
91
|
+
- `--context '{"k":"v"}'` inline JSON context
|
|
92
|
+
- `--context-file ./context.json` JSON context file
|
|
93
|
+
- `--timeout-ms 120000` runner timeout
|
|
94
|
+
- `--no-heal` skip heal pass
|
|
95
|
+
|
|
96
|
+
### Validate artifacts
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
replay validate --in .replay/artifacts
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Re-heal existing artifacts
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
replay heal --in .replay/artifacts --out .replay/healed
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Report summary
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
replay report --in .replay/artifacts
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Runner discovery (implied defaults)
|
|
115
|
+
|
|
116
|
+
If `--runner` is not provided, the CLI checks in this order:
|
|
117
|
+
|
|
118
|
+
1. `REPLAY_RUNNER` env var
|
|
119
|
+
2. `.replay/runner.mjs`
|
|
120
|
+
3. `.replay/runner.js`
|
|
121
|
+
4. `.replay/runner.cjs`
|
|
122
|
+
5. `.replay/runner`
|
|
123
|
+
6. `package.json` script: `replay:runner`
|
|
124
|
+
|
|
125
|
+
## Runner input contract
|
|
126
|
+
|
|
127
|
+
Runner receives one JSON object via `stdin`:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"prompt": "What are my top holdings?",
|
|
132
|
+
"query": "What are my top holdings?",
|
|
133
|
+
"runId": "run_...",
|
|
134
|
+
"timestamp": "2026-03-01T12:00:00.000Z",
|
|
135
|
+
"context": {}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Runner output contract
|
|
140
|
+
|
|
141
|
+
Runner must print one JSON object to `stdout`.
|
|
142
|
+
|
|
143
|
+
Success:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"status": "ok",
|
|
148
|
+
"framework": "langchain",
|
|
149
|
+
"response": "AAPL is your largest holding.",
|
|
150
|
+
"events": [
|
|
151
|
+
{
|
|
152
|
+
"seq": 1,
|
|
153
|
+
"timestamp": "2026-03-01T12:00:00.000Z",
|
|
154
|
+
"type": "run_started",
|
|
155
|
+
"runId": "run_123",
|
|
156
|
+
"payload": {}
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
"sources": ["portfolio_db"],
|
|
160
|
+
"usage": {
|
|
161
|
+
"inputTokens": 100,
|
|
162
|
+
"outputTokens": 40,
|
|
163
|
+
"costUsd": 0.0021
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Failure:
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"status": "error",
|
|
173
|
+
"error": {
|
|
174
|
+
"code": "RUNNER_TOOL_TIMEOUT",
|
|
175
|
+
"message": "get_portfolio_summary timed out after 15s",
|
|
176
|
+
"retryable": true
|
|
177
|
+
},
|
|
178
|
+
"events": []
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Schema references:
|
|
183
|
+
|
|
184
|
+
- [schemas/runner-output.schema.json](./schemas/runner-output.schema.json)
|
|
185
|
+
- [schemas/replay-artifact.schema.json](./schemas/replay-artifact.schema.json)
|
|
186
|
+
|
|
187
|
+
## Self-healing behavior
|
|
188
|
+
|
|
189
|
+
The CLI always writes a raw artifact first, then heals into a replay artifact.
|
|
190
|
+
|
|
191
|
+
Healing currently includes:
|
|
192
|
+
|
|
193
|
+
- type alias mapping (`tool_end` -> `tool_completed`, etc.)
|
|
194
|
+
- missing `run_started` insertion
|
|
195
|
+
- missing terminal event insertion (`run_completed`/`run_failed`)
|
|
196
|
+
- non-object event payload normalization to `{}`
|
|
197
|
+
- sequence renumbering to strict monotonic order
|
|
198
|
+
- duplicate event dedupe (exact adjacent duplicates)
|
|
199
|
+
- synthetic `assistant_message` insertion from final response when missing
|
|
200
|
+
|
|
201
|
+
All applied repairs are written to `*.heal-log.json`.
|
|
202
|
+
|
|
203
|
+
### Custom heal rules
|
|
204
|
+
|
|
205
|
+
Optional file: `.replay/heal.rules.json`
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"version": "v1",
|
|
210
|
+
"eventAliases": {
|
|
211
|
+
"tool_end": "tool_completed",
|
|
212
|
+
"llm_message": "assistant_message"
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Artifact files
|
|
218
|
+
|
|
219
|
+
For each run:
|
|
220
|
+
|
|
221
|
+
- `*.raw.json` raw capture of runner process input/output
|
|
222
|
+
- `*.artifact.json` normalized artifact before healing
|
|
223
|
+
- `*.healed.json` healed replay artifact
|
|
224
|
+
- `*.heal-log.json` structured healing log
|
|
225
|
+
|
|
226
|
+
## Error model (LLM-friendly)
|
|
227
|
+
|
|
228
|
+
Errors are always JSON on `stderr`:
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"error": {
|
|
233
|
+
"code": "E_RUNNER_EVENTS_INVALID",
|
|
234
|
+
"message": "Runner output field `events` must be an array.",
|
|
235
|
+
"path": "$.events",
|
|
236
|
+
"expected": "array",
|
|
237
|
+
"received": "object",
|
|
238
|
+
"howToFix": "Return `events: []` when there are no events."
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
See full catalog: [ERROR_CODES.md](./ERROR_CODES.md)
|
|
244
|
+
|
|
245
|
+
## Publish checklist
|
|
246
|
+
|
|
247
|
+
1. Authenticate npm on this machine:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
npm login
|
|
251
|
+
# or: npm adduser
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
2. Confirm identity and package name availability:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
npm whoami
|
|
258
|
+
npm view replay-self-healing-cli version
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
3. Run pre-publish checks:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
node ./bin/replay.mjs help
|
|
265
|
+
REPLAY_RUNNER=./examples/runner.mjs node ./bin/replay.mjs "test prompt"
|
|
266
|
+
node ./bin/replay.mjs validate --in .replay/artifacts
|
|
267
|
+
npm pack --dry-run
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
4. Publish:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
npm publish
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
5. Verify:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npm view replay-self-healing-cli version
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## License
|
|
283
|
+
|
|
284
|
+
MIT
|
package/bin/replay.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "replay-self-healing-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Zero-dependency self-healing replay harness CLI for LLM runs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"replay": "bin/replay.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"src",
|
|
12
|
+
"schemas",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE",
|
|
15
|
+
"ERROR_CODES.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --test"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"llm",
|
|
22
|
+
"evals",
|
|
23
|
+
"replay",
|
|
24
|
+
"harness",
|
|
25
|
+
"cli",
|
|
26
|
+
"self-healing"
|
|
27
|
+
],
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=18.17.0"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/nathankoerschner/replay-self-healing-cli.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/nathankoerschner/replay-self-healing-cli/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/nathankoerschner/replay-self-healing-cli#readme",
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://replay-self-healing-cli.dev/schemas/replay-artifact.schema.json",
|
|
4
|
+
"title": "Replay Artifact",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"schemaVersion",
|
|
8
|
+
"artifactType",
|
|
9
|
+
"id",
|
|
10
|
+
"timestamp",
|
|
11
|
+
"prompt",
|
|
12
|
+
"query",
|
|
13
|
+
"status",
|
|
14
|
+
"events"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"schemaVersion": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"const": "1.0.0"
|
|
20
|
+
},
|
|
21
|
+
"artifactType": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"const": "replay"
|
|
24
|
+
},
|
|
25
|
+
"id": {
|
|
26
|
+
"type": "string"
|
|
27
|
+
},
|
|
28
|
+
"timestamp": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"format": "date-time"
|
|
31
|
+
},
|
|
32
|
+
"prompt": {
|
|
33
|
+
"type": "string"
|
|
34
|
+
},
|
|
35
|
+
"query": {
|
|
36
|
+
"type": "string"
|
|
37
|
+
},
|
|
38
|
+
"status": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"enum": ["ok", "error"]
|
|
41
|
+
},
|
|
42
|
+
"response": {
|
|
43
|
+
"type": "string"
|
|
44
|
+
},
|
|
45
|
+
"error": {
|
|
46
|
+
"type": "object"
|
|
47
|
+
},
|
|
48
|
+
"events": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"items": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"required": ["seq", "timestamp", "type", "runId", "payload"],
|
|
53
|
+
"properties": {
|
|
54
|
+
"seq": {
|
|
55
|
+
"type": "integer",
|
|
56
|
+
"minimum": 1
|
|
57
|
+
},
|
|
58
|
+
"timestamp": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"format": "date-time"
|
|
61
|
+
},
|
|
62
|
+
"type": {
|
|
63
|
+
"type": "string"
|
|
64
|
+
},
|
|
65
|
+
"runId": {
|
|
66
|
+
"type": "string"
|
|
67
|
+
},
|
|
68
|
+
"payload": {
|
|
69
|
+
"type": "object"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"toolCalls": {
|
|
75
|
+
"type": "array",
|
|
76
|
+
"items": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"required": ["toolName", "status", "durationMs"],
|
|
79
|
+
"properties": {
|
|
80
|
+
"toolName": {
|
|
81
|
+
"type": "string"
|
|
82
|
+
},
|
|
83
|
+
"status": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"enum": ["ok", "error"]
|
|
86
|
+
},
|
|
87
|
+
"durationMs": {
|
|
88
|
+
"type": "number",
|
|
89
|
+
"minimum": 0
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"timings": {
|
|
95
|
+
"type": "object"
|
|
96
|
+
},
|
|
97
|
+
"sources": {
|
|
98
|
+
"type": "array",
|
|
99
|
+
"items": {
|
|
100
|
+
"type": "string"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"usage": {
|
|
104
|
+
"type": "object"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://replay-self-healing-cli.dev/schemas/runner-output.schema.json",
|
|
4
|
+
"title": "Replay Runner Output",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["status", "events"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"status": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"enum": ["ok", "error"]
|
|
11
|
+
},
|
|
12
|
+
"framework": {
|
|
13
|
+
"type": "string"
|
|
14
|
+
},
|
|
15
|
+
"response": {
|
|
16
|
+
"type": "string"
|
|
17
|
+
},
|
|
18
|
+
"events": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"required": ["type"],
|
|
23
|
+
"properties": {
|
|
24
|
+
"runId": {
|
|
25
|
+
"type": "string"
|
|
26
|
+
},
|
|
27
|
+
"seq": {
|
|
28
|
+
"type": "integer",
|
|
29
|
+
"minimum": 1
|
|
30
|
+
},
|
|
31
|
+
"timestamp": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"format": "date-time"
|
|
34
|
+
},
|
|
35
|
+
"type": {
|
|
36
|
+
"type": "string"
|
|
37
|
+
},
|
|
38
|
+
"payload": {
|
|
39
|
+
"type": "object"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"sources": {
|
|
45
|
+
"type": "array",
|
|
46
|
+
"items": {
|
|
47
|
+
"type": "string"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"usage": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"properties": {
|
|
53
|
+
"inputTokens": {
|
|
54
|
+
"type": "number",
|
|
55
|
+
"minimum": 0
|
|
56
|
+
},
|
|
57
|
+
"outputTokens": {
|
|
58
|
+
"type": "number",
|
|
59
|
+
"minimum": 0
|
|
60
|
+
},
|
|
61
|
+
"costUsd": {
|
|
62
|
+
"type": "number",
|
|
63
|
+
"minimum": 0
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"error": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"properties": {
|
|
70
|
+
"code": {
|
|
71
|
+
"type": "string"
|
|
72
|
+
},
|
|
73
|
+
"message": {
|
|
74
|
+
"type": "string"
|
|
75
|
+
},
|
|
76
|
+
"retryable": {
|
|
77
|
+
"type": "boolean"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"allOf": [
|
|
83
|
+
{
|
|
84
|
+
"if": {
|
|
85
|
+
"properties": {
|
|
86
|
+
"status": {
|
|
87
|
+
"const": "ok"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"then": {
|
|
92
|
+
"required": ["response"]
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"if": {
|
|
97
|
+
"properties": {
|
|
98
|
+
"status": {
|
|
99
|
+
"const": "error"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"then": {
|
|
104
|
+
"required": ["error"]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|