@agent-delivery-harness/cli 0.2.0 → 0.5.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/LICENSE +104 -201
- package/NOTICE +1 -1
- package/package.json +4 -4
- package/src/boundary.ts +77 -61
- package/src/command-activity.ts +75 -0
- package/src/commands/admit.ts +106 -0
- package/src/commands/check.ts +13 -2
- package/src/commands/emit-review-evidence.ts +38 -0
- package/src/commands/emit.ts +80 -12
- package/src/commands/gate.ts +33 -8
- package/src/commands/maintain.ts +1 -0
- package/src/commands/managed.ts +1 -0
- package/src/commands/prepare.ts +123 -22
- package/src/commands/record.ts +98 -3
- package/src/commands/resume.ts +53 -0
- package/src/commands/review-context.ts +19 -0
- package/src/commands/runs.ts +415 -30
- package/src/commands/save-context.ts +51 -0
- package/src/commands/submit-evidence.ts +46 -7
- package/src/commands/verify.ts +29 -8
- package/src/declared-checks.ts +50 -0
- package/src/index.ts +14 -1
- package/src/main.ts +20 -47
- package/src/ordinary-context.ts +99 -0
- package/src/provider-rails.ts +23 -704
- package/src/record-retention.ts +325 -0
- package/src/review-evidence.ts +284 -0
- package/src/run-archive-commands.ts +164 -0
- package/src/run-archive.ts +127 -0
- package/src/run-artifact-commands.ts +163 -0
- package/src/run-attachments.ts +112 -0
- package/src/run-export.ts +164 -0
- package/src/run-live.ts +102 -0
- package/src/run-projection.ts +129 -11
- package/src/run-server.ts +394 -149
- package/src/run-surface.ts +81 -8
- package/src/run-view-command.ts +77 -0
- package/src/run-view-html.ts +138 -0
- package/src/run-view-record.ts +119 -0
- package/src/run-view.ts +343 -0
package/src/run-view.ts
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/** One operational readout for terminal, JSON and HTML; no admission decisions. */
|
|
2
|
+
import type { RunEvent } from "@agent-delivery-harness/kernel";
|
|
3
|
+
import {
|
|
4
|
+
projectRunProgress,
|
|
5
|
+
projectCosts,
|
|
6
|
+
costLabel,
|
|
7
|
+
} from "./run-projection.ts";
|
|
8
|
+
export interface RunViewItem {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
readonly fields: readonly { label: string; value: string }[];
|
|
12
|
+
readonly artifactId?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface RunViewSection {
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly title: string;
|
|
17
|
+
readonly empty: string;
|
|
18
|
+
readonly items: readonly RunViewItem[];
|
|
19
|
+
}
|
|
20
|
+
export interface RunView {
|
|
21
|
+
readonly spec: "run-view/1";
|
|
22
|
+
readonly historical: boolean;
|
|
23
|
+
readonly asOf: string;
|
|
24
|
+
readonly authority: string;
|
|
25
|
+
readonly sections: readonly RunViewSection[];
|
|
26
|
+
}
|
|
27
|
+
const value = (v: unknown): string =>
|
|
28
|
+
v === undefined
|
|
29
|
+
? "Unreported"
|
|
30
|
+
: typeof v === "string"
|
|
31
|
+
? v
|
|
32
|
+
: JSON.stringify(v);
|
|
33
|
+
const item = (
|
|
34
|
+
id: string,
|
|
35
|
+
label: string,
|
|
36
|
+
fields: Record<string, unknown>,
|
|
37
|
+
artifactId?: string,
|
|
38
|
+
): RunViewItem => ({
|
|
39
|
+
id,
|
|
40
|
+
label,
|
|
41
|
+
fields: Object.entries(fields).map(([label, v]) => ({
|
|
42
|
+
label,
|
|
43
|
+
value: value(v),
|
|
44
|
+
})),
|
|
45
|
+
...(artifactId === undefined ? {} : { artifactId }),
|
|
46
|
+
});
|
|
47
|
+
export function projectRunView(
|
|
48
|
+
events: readonly RunEvent[],
|
|
49
|
+
options: {
|
|
50
|
+
readonly now: string;
|
|
51
|
+
readonly historical?: boolean;
|
|
52
|
+
readonly freshnessWindowMs?: number;
|
|
53
|
+
},
|
|
54
|
+
): RunView {
|
|
55
|
+
const p = projectRunProgress(events, options.now, options.freshnessWindowMs);
|
|
56
|
+
const historical = options.historical === true;
|
|
57
|
+
const costs = projectCosts(events);
|
|
58
|
+
const runCost = costs.run as Record<string, unknown>;
|
|
59
|
+
const attempts = p.activities.flatMap((a) => a.attempts);
|
|
60
|
+
const current = attempts.filter((a) => !a.superseded);
|
|
61
|
+
const sections: RunViewSection[] = [
|
|
62
|
+
{
|
|
63
|
+
id: "waiting",
|
|
64
|
+
title: "Waiting and required action",
|
|
65
|
+
empty: "No current waiting observation. Unreported waits remain unknown.",
|
|
66
|
+
items: p.waits
|
|
67
|
+
.filter((w) => w.current && !w.resolvedAt)
|
|
68
|
+
.map((w) =>
|
|
69
|
+
item(w.waitId, w.reason, {
|
|
70
|
+
Owner: w.owner,
|
|
71
|
+
"Human action required":
|
|
72
|
+
w.waitingOn === "human"
|
|
73
|
+
? "Yes — human"
|
|
74
|
+
: w.waitingOn === "unknown"
|
|
75
|
+
? "Unknown"
|
|
76
|
+
: `No — ${w.waitingOn}`,
|
|
77
|
+
"Next action": w.nextAction,
|
|
78
|
+
Scope: w.scope,
|
|
79
|
+
Attempt: w.attemptId,
|
|
80
|
+
Observed: w.startedAt,
|
|
81
|
+
Freshness: historical
|
|
82
|
+
? "Historical observation"
|
|
83
|
+
: !Number.isFinite(Date.parse(w.startedAt))
|
|
84
|
+
? "unknown"
|
|
85
|
+
: Date.parse(options.now) - Date.parse(w.startedAt) >
|
|
86
|
+
(options.freshnessWindowMs ?? 300000)
|
|
87
|
+
? "stale"
|
|
88
|
+
: "recent",
|
|
89
|
+
Candidate: w.candidateTreeSha,
|
|
90
|
+
}),
|
|
91
|
+
),
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: "work",
|
|
95
|
+
title: "Current work",
|
|
96
|
+
empty: attempts.length === 0
|
|
97
|
+
? "No activity observations; execution status unknown."
|
|
98
|
+
: "No active work in the latest observations. Retained attempts appear in history.",
|
|
99
|
+
items: current
|
|
100
|
+
.filter(
|
|
101
|
+
(a) => !["completed", "failed", "interrupted"].includes(a.state),
|
|
102
|
+
)
|
|
103
|
+
.map((a) =>
|
|
104
|
+
item(a.attemptId, a.activityId, {
|
|
105
|
+
Owner: a.owner,
|
|
106
|
+
Phase: a.phase,
|
|
107
|
+
State: `${a.state} (reported)`,
|
|
108
|
+
Freshness: historical ? "Historical observation" : a.freshness,
|
|
109
|
+
"Last observed": a.lastObservedAt,
|
|
110
|
+
"Elapsed since start": a.startedAt
|
|
111
|
+
? `${Math.max(0, Math.floor((Date.parse(options.now) - Date.parse(a.startedAt)) / 1000))}s`
|
|
112
|
+
: "Unknown — start not observed",
|
|
113
|
+
"Next step": a.nextStep,
|
|
114
|
+
Candidate: a.candidateTreeSha,
|
|
115
|
+
"Lifecycle history": a.lifecycleIncomplete
|
|
116
|
+
? "Incomplete"
|
|
117
|
+
: "Observed",
|
|
118
|
+
}),
|
|
119
|
+
),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: "reviews",
|
|
123
|
+
title: "Reviewer attempts and history",
|
|
124
|
+
empty: "No reviewer attempt observations.",
|
|
125
|
+
items: attempts
|
|
126
|
+
.filter((a) => a.lensId !== undefined || a.phase === "review")
|
|
127
|
+
.map((a) =>
|
|
128
|
+
item(a.attemptId, a.lensId ?? a.activityId, {
|
|
129
|
+
Attempt: a.attemptId,
|
|
130
|
+
Round: a.round,
|
|
131
|
+
"Round ID": a.roundId,
|
|
132
|
+
Owner: a.owner,
|
|
133
|
+
State: a.state,
|
|
134
|
+
History: a.superseded
|
|
135
|
+
? "Superseded attempt"
|
|
136
|
+
: "Latest observed attempt",
|
|
137
|
+
Verdict: a.verdict,
|
|
138
|
+
Cost: costLabel(a.cost),
|
|
139
|
+
Candidate: a.candidateTreeSha,
|
|
140
|
+
}),
|
|
141
|
+
),
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: "findings",
|
|
145
|
+
title: "Current unresolved findings",
|
|
146
|
+
empty:
|
|
147
|
+
p.findingsCoverage === "unreported"
|
|
148
|
+
? "Unknown — detailed finding observations were not recorded."
|
|
149
|
+
: "No unresolved findings in latest reported observations; this is not approval.",
|
|
150
|
+
items: p.currentFindings
|
|
151
|
+
.filter((f) => f.payload["state"] === "unresolved")
|
|
152
|
+
.map((f) =>
|
|
153
|
+
item(String(f.payload["findingId"]), String(f.payload["findingId"]), {
|
|
154
|
+
Severity: f.payload["severity"],
|
|
155
|
+
State: "Unresolved (reported)",
|
|
156
|
+
Report: f.payload["reportId"],
|
|
157
|
+
Attempt: f.payload["attemptId"],
|
|
158
|
+
Candidate: f.payload["candidateTreeSha"],
|
|
159
|
+
}),
|
|
160
|
+
),
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "evidence",
|
|
164
|
+
title: "Evidence and candidate",
|
|
165
|
+
empty: "No evidence observations. Applicability unknown.",
|
|
166
|
+
items: events
|
|
167
|
+
.filter((e) =>
|
|
168
|
+
[
|
|
169
|
+
"gate.reported",
|
|
170
|
+
"command.completed",
|
|
171
|
+
"review.round.closed",
|
|
172
|
+
].includes(e.kind),
|
|
173
|
+
)
|
|
174
|
+
.map((e) =>
|
|
175
|
+
item(String(e.seq), e.kind, {
|
|
176
|
+
"Reported at": e.at,
|
|
177
|
+
Candidate: e.candidateTreeSha ?? e.payload["candidateTreeSha"],
|
|
178
|
+
Observation: e.payload,
|
|
179
|
+
Authority:
|
|
180
|
+
"Reported only — Applicability unknown; no verification is run by this view",
|
|
181
|
+
}),
|
|
182
|
+
),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: "reports",
|
|
186
|
+
title: "Retained reports",
|
|
187
|
+
empty: "No report references recorded.",
|
|
188
|
+
items: p.reports.map((r) =>
|
|
189
|
+
item(
|
|
190
|
+
String(r.payload["reportId"]),
|
|
191
|
+
String(r.payload["role"]),
|
|
192
|
+
{
|
|
193
|
+
Report: r.payload["reportId"],
|
|
194
|
+
Availability: r.payload["availability"],
|
|
195
|
+
Reason: r.payload["reason"],
|
|
196
|
+
"Originating report": r.payload["originatingReportId"],
|
|
197
|
+
Lens: r.payload["lensId"],
|
|
198
|
+
Attempt: r.payload["attemptId"],
|
|
199
|
+
Candidate: r.payload["candidateTreeSha"],
|
|
200
|
+
History: r.current
|
|
201
|
+
? "Latest observed attempt"
|
|
202
|
+
: "Historical or incomplete binding",
|
|
203
|
+
},
|
|
204
|
+
typeof r.payload["artifactId"] === "string"
|
|
205
|
+
? r.payload["artifactId"]
|
|
206
|
+
: undefined,
|
|
207
|
+
),
|
|
208
|
+
),
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: "finish",
|
|
212
|
+
title: "Declared finish line",
|
|
213
|
+
empty: "Finish steps unreported; delivery completion unknown.",
|
|
214
|
+
items: [],
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: "cost",
|
|
218
|
+
title: "Reported cost",
|
|
219
|
+
empty: "Cost unreported.",
|
|
220
|
+
items: [
|
|
221
|
+
{
|
|
222
|
+
id: "review-cost",
|
|
223
|
+
label: "Review totals",
|
|
224
|
+
fields: [
|
|
225
|
+
...item("review-cost", "Review totals", {
|
|
226
|
+
Coverage: costs.review.coverage,
|
|
227
|
+
"Unreported round entries": costs.review.unreportedEntries,
|
|
228
|
+
...(costs.review.totals.length === 0
|
|
229
|
+
? { Measurement: "Unreported" }
|
|
230
|
+
: {}),
|
|
231
|
+
}).fields,
|
|
232
|
+
...costs.review.totals.map((total) => ({
|
|
233
|
+
label: `${total.reportedBy} · ${total.unit}`,
|
|
234
|
+
value:
|
|
235
|
+
total.total === null
|
|
236
|
+
? "Unavailable — reported sum exceeds numeric range"
|
|
237
|
+
: `${total.total} ${total.unit}`,
|
|
238
|
+
})),
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
item("run-cost", "Run total", {
|
|
242
|
+
Coverage: runCost["coverage"],
|
|
243
|
+
Measurement: costLabel(runCost),
|
|
244
|
+
"Reported by": runCost["reportedBy"],
|
|
245
|
+
Accounting:
|
|
246
|
+
"Run totals can include review and attempt costs. These totals are shown separately and are not added together.",
|
|
247
|
+
}),
|
|
248
|
+
...attempts.filter((a) => a.cost !== undefined).map((a) => {
|
|
249
|
+
const cost = a.cost as Record<string, unknown>;
|
|
250
|
+
return item(`attempt-cost-${a.attemptId}`, `Attempt cost · ${a.activityId}`, {
|
|
251
|
+
Attempt: a.attemptId,
|
|
252
|
+
Owner: a.owner,
|
|
253
|
+
Phase: a.phase,
|
|
254
|
+
State: `${a.state} (reported)`,
|
|
255
|
+
History: a.superseded ? "Superseded attempt" : "Latest observed attempt",
|
|
256
|
+
Candidate: a.candidateTreeSha,
|
|
257
|
+
Coverage: cost["coverage"],
|
|
258
|
+
Measurement: costLabel(a.cost),
|
|
259
|
+
"Reported by": cost["reportedBy"],
|
|
260
|
+
Accounting: "Reported attempt measurement; not added to run or review totals, which may overlap.",
|
|
261
|
+
});
|
|
262
|
+
}),
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
id: "activity-history",
|
|
267
|
+
title: "Activity history",
|
|
268
|
+
empty: "No completed, failed, interrupted or superseded activity observations.",
|
|
269
|
+
items: attempts
|
|
270
|
+
.filter((a) => a.superseded || ["completed", "failed", "interrupted"].includes(a.state))
|
|
271
|
+
.map((a) => item(a.attemptId, a.activityId, {
|
|
272
|
+
Attempt: a.attemptId,
|
|
273
|
+
Owner: a.owner,
|
|
274
|
+
Phase: a.phase,
|
|
275
|
+
State: `${a.state} (reported)`,
|
|
276
|
+
History: a.superseded ? "Superseded attempt" : "Latest observed attempt",
|
|
277
|
+
Freshness: historical ? "Historical observation" : a.freshness,
|
|
278
|
+
"Last observed": a.lastObservedAt,
|
|
279
|
+
Candidate: a.candidateTreeSha,
|
|
280
|
+
"Lifecycle history": a.lifecycleIncomplete ? "Incomplete" : "Observed",
|
|
281
|
+
Cost: costLabel(a.cost),
|
|
282
|
+
})),
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
id: "finding-history",
|
|
286
|
+
title: "Finding history",
|
|
287
|
+
empty: "No detailed finding history.",
|
|
288
|
+
items: p.findings.map((f) =>
|
|
289
|
+
item(String(f.seq), String(f.payload["findingId"]), {
|
|
290
|
+
State: f.payload["state"],
|
|
291
|
+
Severity: f.payload["severity"],
|
|
292
|
+
Attempt: f.payload["attemptId"],
|
|
293
|
+
Candidate: f.payload["candidateTreeSha"],
|
|
294
|
+
"Deferred issue": f.payload["deferredIssueId"],
|
|
295
|
+
Observed: f.at,
|
|
296
|
+
}),
|
|
297
|
+
),
|
|
298
|
+
},
|
|
299
|
+
];
|
|
300
|
+
const reviewSection = sections.find((s) => s.id === "reviews")!;
|
|
301
|
+
sections[2] = {
|
|
302
|
+
...reviewSection,
|
|
303
|
+
items: [
|
|
304
|
+
...events
|
|
305
|
+
.filter((e) => e.kind === "review.round.opened")
|
|
306
|
+
.map((e) =>
|
|
307
|
+
item(`round-${e.seq}`, "Declared review round", {
|
|
308
|
+
Round: e.payload["round"],
|
|
309
|
+
"Round ID": e.payload["roundId"],
|
|
310
|
+
Bound: e.payload["bound"],
|
|
311
|
+
Grace: e.payload["grace"],
|
|
312
|
+
Reopens: e.payload["reopensRoundId"],
|
|
313
|
+
Candidate: e.payload["candidateTreeSha"],
|
|
314
|
+
}),
|
|
315
|
+
),
|
|
316
|
+
...reviewSection.items,
|
|
317
|
+
],
|
|
318
|
+
};
|
|
319
|
+
const finish = new Map<string, (typeof p.finishSteps)[number]>();
|
|
320
|
+
for (const step of p.finishSteps)
|
|
321
|
+
finish.set(String(step.payload["stepId"]), step);
|
|
322
|
+
sections[6] = {
|
|
323
|
+
id: "finish",
|
|
324
|
+
title: "Declared finish line",
|
|
325
|
+
empty: "Finish steps unreported; delivery completion unknown.",
|
|
326
|
+
items: [...finish.values()].map((s) =>
|
|
327
|
+
item(String(s.payload["stepId"]), String(s.payload["name"]), {
|
|
328
|
+
State: s.payload["state"],
|
|
329
|
+
Owner: s.payload["owner"],
|
|
330
|
+
Reason: s.payload["reason"],
|
|
331
|
+
Candidate: s.payload["candidateTreeSha"],
|
|
332
|
+
}),
|
|
333
|
+
),
|
|
334
|
+
};
|
|
335
|
+
return {
|
|
336
|
+
spec: "run-view/1",
|
|
337
|
+
historical,
|
|
338
|
+
asOf: options.now,
|
|
339
|
+
authority:
|
|
340
|
+
"Self-attested observations. Applicability unknown; no permission or candidate approval is granted.",
|
|
341
|
+
sections,
|
|
342
|
+
};
|
|
343
|
+
}
|