cohorte 2.10.1 → 3.0.0-dev.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/README.md +7 -0
- package/assets/manifest.json +193 -0
- package/assets/migrations/config/README.md +12 -0
- package/assets/migrations/state/0001_init.sql +154 -0
- package/assets/prompts/README.md +11 -0
- package/assets/prompts/agents/fixer.md +7 -0
- package/assets/prompts/agents/implementer.md +12 -0
- package/assets/prompts/agents/reviewer.md +8 -0
- package/assets/prompts/agents/security-reviewer.md +7 -0
- package/assets/prompts/phases/build.md +5 -0
- package/assets/prompts/phases/review.md +5 -0
- package/assets/prompts/phases/test.md +5 -0
- package/assets/prompts/system.md +11 -0
- package/assets/schemas/agent-output.schema.json +225 -0
- package/assets/schemas/auth-status.schema.json +87 -0
- package/assets/schemas/command-result.schema.json +192 -0
- package/assets/schemas/commands.schema.json +952 -0
- package/assets/schemas/config.schema.json +2259 -0
- package/assets/schemas/doctor-report.schema.json +104 -0
- package/assets/schemas/events.schema.json +8514 -0
- package/assets/schemas/fake-script.schema.json +549 -0
- package/assets/schemas/inspect.schema.json +3133 -0
- package/assets/schemas/manifest.schema.json +79 -0
- package/assets/schemas/ownership.schema.json +52 -0
- package/assets/schemas/policy-verdict.schema.json +282 -0
- package/assets/schemas/project-model.schema.json +783 -0
- package/assets/schemas/project-status.schema.json +217 -0
- package/assets/schemas/reconcile-plan.schema.json +154 -0
- package/assets/schemas/run-diff.schema.json +177 -0
- package/assets/schemas/run-snapshot-manifest.schema.json +2104 -0
- package/assets/schemas/run-state.schema.json +1755 -0
- package/assets/schemas/runtime-capabilities.schema.json +1545 -0
- package/assets/schemas/sandbox-capabilities.schema.json +116 -0
- package/assets/schemas/skill.schema.json +87 -0
- package/assets/schemas/spec.schema.json +202 -0
- package/assets/schemas/tool-catalogue.schema.json +655 -0
- package/assets/schemas/trust-record.schema.json +38 -0
- package/assets/skills/README.md +9 -0
- package/assets/skills/inspect-surface.md +4 -0
- package/dist/agent-host.mjs +2187 -0
- package/dist/agent-host.mjs.map +1 -0
- package/dist/bundle-manifest.json +104 -0
- package/dist/chunks/__host-DgGPyco9.mjs +18 -0
- package/dist/chunks/__host-DgGPyco9.mjs.map +1 -0
- package/dist/chunks/approve-Cv135UqI.mjs +19 -0
- package/dist/chunks/approve-Cv135UqI.mjs.map +1 -0
- package/dist/chunks/auth-BT5oVp76.mjs +132 -0
- package/dist/chunks/auth-BT5oVp76.mjs.map +1 -0
- package/dist/chunks/auth-CYOh60KG.mjs +93 -0
- package/dist/chunks/auth-CYOh60KG.mjs.map +1 -0
- package/dist/chunks/brainstorm-BwKA6yZP.mjs +7 -0
- package/dist/chunks/brainstorm-BwKA6yZP.mjs.map +1 -0
- package/dist/chunks/cancel-KV_cpsqS.mjs +15 -0
- package/dist/chunks/cancel-KV_cpsqS.mjs.map +1 -0
- package/dist/chunks/canonical-C8UxeEmB.mjs +57 -0
- package/dist/chunks/canonical-C8UxeEmB.mjs.map +1 -0
- package/dist/chunks/catalogue-BvwSrM_j.mjs +1549 -0
- package/dist/chunks/catalogue-BvwSrM_j.mjs.map +1 -0
- package/dist/chunks/compose-Dvxunpto.mjs +7307 -0
- package/dist/chunks/compose-Dvxunpto.mjs.map +1 -0
- package/dist/chunks/config-DefHA2Lw.mjs +96 -0
- package/dist/chunks/config-DefHA2Lw.mjs.map +1 -0
- package/dist/chunks/contract-BkMjU1kR.mjs +295 -0
- package/dist/chunks/contract-BkMjU1kR.mjs.map +1 -0
- package/dist/chunks/contract-bQ9FJl4N.mjs +123 -0
- package/dist/chunks/contract-bQ9FJl4N.mjs.map +1 -0
- package/dist/chunks/deny-ClTxSvHJ.mjs +15 -0
- package/dist/chunks/deny-ClTxSvHJ.mjs.map +1 -0
- package/dist/chunks/diff-Qw0II0sj.mjs +101 -0
- package/dist/chunks/diff-Qw0II0sj.mjs.map +1 -0
- package/dist/chunks/discover-eS01-me1.mjs +21 -0
- package/dist/chunks/discover-eS01-me1.mjs.map +1 -0
- package/dist/chunks/doctor-B-H2UK5e.mjs +222 -0
- package/dist/chunks/doctor-B-H2UK5e.mjs.map +1 -0
- package/dist/chunks/fix-D4Tj8RVA.mjs +18 -0
- package/dist/chunks/fix-D4Tj8RVA.mjs.map +1 -0
- package/dist/chunks/gc-BBXlBF5w.mjs +161 -0
- package/dist/chunks/gc-BBXlBF5w.mjs.map +1 -0
- package/dist/chunks/init-BUnzIkeE.mjs +63 -0
- package/dist/chunks/init-BUnzIkeE.mjs.map +1 -0
- package/dist/chunks/inspect-Buby4cQD.mjs +22 -0
- package/dist/chunks/inspect-Buby4cQD.mjs.map +1 -0
- package/dist/chunks/logs-Giq5sUau.mjs +25 -0
- package/dist/chunks/logs-Giq5sUau.mjs.map +1 -0
- package/dist/chunks/migrate-DybihKzZ.mjs +33 -0
- package/dist/chunks/migrate-DybihKzZ.mjs.map +1 -0
- package/dist/chunks/models-Btp6X2YZ.mjs +24 -0
- package/dist/chunks/models-Btp6X2YZ.mjs.map +1 -0
- package/dist/chunks/pause-BASBfKLO.mjs +16 -0
- package/dist/chunks/pause-BASBfKLO.mjs.map +1 -0
- package/dist/chunks/policy-DUIgzF3W.mjs +139 -0
- package/dist/chunks/policy-DUIgzF3W.mjs.map +1 -0
- package/dist/chunks/providers-Dx78imKj.mjs +19 -0
- package/dist/chunks/providers-Dx78imKj.mjs.map +1 -0
- package/dist/chunks/reconcile-Bhy3IIYo.mjs +50 -0
- package/dist/chunks/reconcile-Bhy3IIYo.mjs.map +1 -0
- package/dist/chunks/render-DyZr5Lgi.mjs +53 -0
- package/dist/chunks/render-DyZr5Lgi.mjs.map +1 -0
- package/dist/chunks/resume-GJQRb2Eb.mjs +15 -0
- package/dist/chunks/resume-GJQRb2Eb.mjs.map +1 -0
- package/dist/chunks/retry-CLrUem1H.mjs +15 -0
- package/dist/chunks/retry-CLrUem1H.mjs.map +1 -0
- package/dist/chunks/review-BDdjb6kB.mjs +17 -0
- package/dist/chunks/review-BDdjb6kB.mjs.map +1 -0
- package/dist/chunks/run-CgTWYlcd.mjs +82 -0
- package/dist/chunks/run-CgTWYlcd.mjs.map +1 -0
- package/dist/chunks/run-tool-C3rAv4XF.mjs +26 -0
- package/dist/chunks/run-tool-C3rAv4XF.mjs.map +1 -0
- package/dist/chunks/scan-8Gy_B6kI.mjs +122 -0
- package/dist/chunks/scan-8Gy_B6kI.mjs.map +1 -0
- package/dist/chunks/schema-C9QbUW4H.mjs +578 -0
- package/dist/chunks/schema-C9QbUW4H.mjs.map +1 -0
- package/dist/chunks/send-BdnJ85Nz.mjs +19 -0
- package/dist/chunks/send-BdnJ85Nz.mjs.map +1 -0
- package/dist/chunks/ship-DTuLGoaJ.mjs +19 -0
- package/dist/chunks/ship-DTuLGoaJ.mjs.map +1 -0
- package/dist/chunks/shutdown-BM92Iyv2.mjs +15 -0
- package/dist/chunks/shutdown-BM92Iyv2.mjs.map +1 -0
- package/dist/chunks/skip-DZG5kpcH.mjs +18 -0
- package/dist/chunks/skip-DZG5kpcH.mjs.map +1 -0
- package/dist/chunks/spec-Bq0P3jVh.mjs +20 -0
- package/dist/chunks/spec-Bq0P3jVh.mjs.map +1 -0
- package/dist/chunks/src-CId6kMsY.mjs +1689 -0
- package/dist/chunks/src-CId6kMsY.mjs.map +1 -0
- package/dist/chunks/src-CfAOde7C.mjs +5403 -0
- package/dist/chunks/src-CfAOde7C.mjs.map +1 -0
- package/dist/chunks/src-CmFjh4M0.mjs +928 -0
- package/dist/chunks/src-CmFjh4M0.mjs.map +1 -0
- package/dist/chunks/src-Cu3TxNob.mjs +783 -0
- package/dist/chunks/src-Cu3TxNob.mjs.map +1 -0
- package/dist/chunks/src-DcU4IXMe.mjs +117 -0
- package/dist/chunks/src-DcU4IXMe.mjs.map +1 -0
- package/dist/chunks/src-s7YRvk0t.mjs +2116 -0
- package/dist/chunks/src-s7YRvk0t.mjs.map +1 -0
- package/dist/chunks/status-SMjiOMYy.mjs +29 -0
- package/dist/chunks/status-SMjiOMYy.mjs.map +1 -0
- package/dist/chunks/tail-BuhT-2PH.mjs +25 -0
- package/dist/chunks/tail-BuhT-2PH.mjs.map +1 -0
- package/dist/chunks/update-BXIppsbi.mjs +16 -0
- package/dist/chunks/update-BXIppsbi.mjs.map +1 -0
- package/dist/cli.mjs +175 -0
- package/dist/cli.mjs.map +1 -0
- package/package.json +17 -32
- package/CHANGELOG.md +0 -1461
- package/bin/cli.js +0 -817
- package/bin/report.js +0 -141
- package/core/adapter/render.js +0 -415
- package/core/agents/implementer.template.md +0 -142
- package/core/agents/profile-reader.md +0 -50
- package/core/agents/release.md +0 -58
- package/core/agents/review.md +0 -179
- package/core/commands/cohorte-align-ds.md +0 -33
- package/core/commands/cohorte-audit.md +0 -58
- package/core/commands/cohorte-brainstorm.md +0 -70
- package/core/commands/cohorte-build.md +0 -219
- package/core/commands/cohorte-doctor.md +0 -194
- package/core/commands/cohorte-fix.md +0 -80
- package/core/commands/cohorte-fleet.md +0 -103
- package/core/commands/cohorte-init-pipeline.md +0 -31
- package/core/commands/cohorte-intake.md +0 -92
- package/core/commands/cohorte-patch.md +0 -118
- package/core/commands/cohorte-refactor.md +0 -59
- package/core/commands/cohorte-retro.md +0 -85
- package/core/commands/cohorte-review.md +0 -270
- package/core/commands/cohorte-ship.md +0 -122
- package/core/commands/cohorte-spec.md +0 -101
- package/core/commands/cohorte-update-pipeline.md +0 -165
- package/core/hooks/gate.py +0 -588
- package/core/runtimes/claude.json +0 -74
- package/core/runtimes/codex.json +0 -85
- package/core/runtimes/cursor.json +0 -76
- package/core/runtimes/gemini.json +0 -76
- package/core/runtimes/opencode.json +0 -73
- package/core/templates/agent-handoff.md +0 -34
- package/core/templates/brainstorm-return.md +0 -36
- package/core/templates/decisions.template.md +0 -42
- package/core/templates/design-brief.md +0 -44
- package/core/templates/patch.template.md +0 -86
- package/core/templates/pr-body.md +0 -25
- package/core/templates/review-feedback.md +0 -38
- package/core/templates/spec.template.md +0 -87
- package/core/templates/steps/init-pipeline/01-detect-stack.md +0 -44
- package/core/templates/steps/init-pipeline/02-interview-gaps.md +0 -55
- package/core/templates/steps/init-pipeline/03-draft-profile.md +0 -10
- package/core/templates/steps/init-pipeline/04-write-render.md +0 -145
- package/core/templates/steps/init-pipeline/05-report.md +0 -12
- package/core/workflows/audit.js +0 -240
- package/core/workflows/loop.js +0 -641
- package/core/workflows/refactor.js +0 -276
- package/core/workflows/review.js +0 -456
- package/install.ps1 +0 -103
- package/install.sh +0 -114
- package/lib/doctor.js +0 -534
- package/lib/runtime.js +0 -139
- package/lib/versions.js +0 -149
- package/lib/yaml.js +0 -129
- package/profile/PIPELINE.template.md +0 -259
- package/profile/SCHEMA.md +0 -735
- package/profile/cohorte.config.template.yaml +0 -43
- package/scripts/assert-gate-hook.mjs +0 -75
- package/scripts/kanban-move.sh +0 -313
- package/scripts/metrics/collect.mjs +0 -531
- package/scripts/metrics/prices.json +0 -42
- package/scripts/new-feature.sh.template +0 -98
- package/scripts/preflight.sh +0 -124
- package/scripts/remove-feature.sh.template +0 -56
- package/scripts/test-adapter.mjs +0 -437
- package/scripts/test-gate.mjs +0 -443
- package/scripts/test-kanban.mjs +0 -304
- package/scripts/test-lib.mjs +0 -356
- package/scripts/test-metrics.mjs +0 -156
- package/scripts/test-workflows.mjs +0 -758
- package/scripts/validate-core.mjs +0 -325
|
@@ -0,0 +1,2116 @@
|
|
|
1
|
+
import { t as canonicalJson } from "./canonical-C8UxeEmB.mjs";
|
|
2
|
+
import { B as ErrorInfo, C as PhaseRunId, D as SurfaceId, E as SpecId, O as ToolCallId, S as IsoInstant, T as Sha256, V as JsonValueSchema, _ as CommandId, b as FindingId, d as ModelRef, f as MonetaryCost, g as ArtifactId, h as ApprovalId, i as Redaction, l as AuthMode, m as AgentId, n as QuotaInfo, o as err, p as ThinkingLevel, r as TokenUsage, s as ok, t as BudgetCounters, u as ModelCapability, v as EffectId, w as RunId, y as EventId } from "./src-Cu3TxNob.mjs";
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
import { Compile } from "typebox/compile";
|
|
5
|
+
//#region ../../packages/protocol/src/open-enum.ts
|
|
6
|
+
/** The keyword a PUBLISHED schema carries instead of `enum`: the values this version knows, as documentation. */
|
|
7
|
+
const OPEN_ENUM_KEYWORD = "x-cohorte-known";
|
|
8
|
+
const checked = (values, what) => {
|
|
9
|
+
if (values.length === 0) throw new RangeError(`${what}: at least one value is required`);
|
|
10
|
+
if (new Set(values).size !== values.length) throw new RangeError(`${what}: duplicate value in [${values.join(", ")}]`);
|
|
11
|
+
return [...values];
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* OPEN enums (values may be added in a minor): strict compile -> enum [...known];
|
|
15
|
+
* published schema -> { type: 'string', 'x-cohorte-known': [...] } (compile.ts does the rewrite).
|
|
16
|
+
* The authored form carries BOTH keywords: `enum` is what the writer-side validator enforces, the marker is what
|
|
17
|
+
* tells the generator that this enum, unlike a closed one, must lose its `enum` when published.
|
|
18
|
+
*/
|
|
19
|
+
function OpenEnum(known, opts = {}) {
|
|
20
|
+
const values = checked(known, "OpenEnum");
|
|
21
|
+
return Type.Unsafe({
|
|
22
|
+
type: "string",
|
|
23
|
+
enum: values,
|
|
24
|
+
[OPEN_ENUM_KEYWORD]: [...values],
|
|
25
|
+
...opts
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** A CLOSED string enum: adding a value is a MAJOR. One `enum` keyword rather than an `anyOf` of constants. */
|
|
29
|
+
function ClosedEnum(values, opts = {}) {
|
|
30
|
+
return Type.Unsafe({
|
|
31
|
+
type: "string",
|
|
32
|
+
enum: checked(values, "ClosedEnum"),
|
|
33
|
+
...opts
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/** The known values of an authored or published open enum; undefined for anything else. */
|
|
37
|
+
function knownValuesOf(schema) {
|
|
38
|
+
if (typeof schema !== "object" || schema === null) return void 0;
|
|
39
|
+
const known = schema[OPEN_ENUM_KEYWORD];
|
|
40
|
+
return Array.isArray(known) && known.every((value) => typeof value === "string") ? known : void 0;
|
|
41
|
+
}
|
|
42
|
+
const PipelineProfile = OpenEnum([
|
|
43
|
+
"feature",
|
|
44
|
+
"bugfix",
|
|
45
|
+
"review"
|
|
46
|
+
]);
|
|
47
|
+
const ACTIVE_PIPELINE_STATES = [
|
|
48
|
+
"BRAINSTORM",
|
|
49
|
+
"SPEC",
|
|
50
|
+
"PREFLIGHT",
|
|
51
|
+
"BUILD",
|
|
52
|
+
"TEST",
|
|
53
|
+
"REVIEW",
|
|
54
|
+
"FIX",
|
|
55
|
+
"SHIP"
|
|
56
|
+
];
|
|
57
|
+
/** spec 11.1 + the two states spec 10.1 names */
|
|
58
|
+
const SUSPENDED_STATES = [
|
|
59
|
+
"PAUSED",
|
|
60
|
+
"WAITING_APPROVAL",
|
|
61
|
+
"AUTH_REQUIRED",
|
|
62
|
+
"QUOTA_EXCEEDED"
|
|
63
|
+
];
|
|
64
|
+
/** FAILED: recoverable checkpoint (spec 24). BLOCKED: human inspection mandatory. */
|
|
65
|
+
const HALTED_STATES = ["FAILED", "BLOCKED"];
|
|
66
|
+
const TERMINAL_STATES = ["COMPLETED", "CANCELLED"];
|
|
67
|
+
const PIPELINE_STATES = [
|
|
68
|
+
"IDLE",
|
|
69
|
+
...ACTIVE_PIPELINE_STATES,
|
|
70
|
+
...SUSPENDED_STATES,
|
|
71
|
+
...HALTED_STATES,
|
|
72
|
+
...TERMINAL_STATES
|
|
73
|
+
];
|
|
74
|
+
const ActivePipelineState = ClosedEnum(ACTIVE_PIPELINE_STATES);
|
|
75
|
+
ClosedEnum(SUSPENDED_STATES);
|
|
76
|
+
const HaltedState = ClosedEnum(HALTED_STATES);
|
|
77
|
+
ClosedEnum(TERMINAL_STATES);
|
|
78
|
+
const PipelineState = ClosedEnum(PIPELINE_STATES);
|
|
79
|
+
const TransitionReason = ClosedEnum([
|
|
80
|
+
"start",
|
|
81
|
+
"ready",
|
|
82
|
+
"built",
|
|
83
|
+
"tests-pass",
|
|
84
|
+
"tests-fail",
|
|
85
|
+
"review-approved",
|
|
86
|
+
"review-findings",
|
|
87
|
+
"review-delivered",
|
|
88
|
+
"fixed",
|
|
89
|
+
"shipped",
|
|
90
|
+
"needs-human",
|
|
91
|
+
"approval-resolved",
|
|
92
|
+
"pause-command",
|
|
93
|
+
"resume-command",
|
|
94
|
+
"cancel-command",
|
|
95
|
+
"retry-command",
|
|
96
|
+
"skip-command",
|
|
97
|
+
"auth-required",
|
|
98
|
+
"auth-restored",
|
|
99
|
+
"quota-exceeded",
|
|
100
|
+
"quota-reset",
|
|
101
|
+
"stop-rule",
|
|
102
|
+
"security-violation",
|
|
103
|
+
"unexpected-error"
|
|
104
|
+
]);
|
|
105
|
+
const StopReason = ClosedEnum([
|
|
106
|
+
"review-clean",
|
|
107
|
+
"iteration-limit",
|
|
108
|
+
"budget-exhausted",
|
|
109
|
+
"timeout",
|
|
110
|
+
"identical-failure",
|
|
111
|
+
"no-progress",
|
|
112
|
+
"policy-violation",
|
|
113
|
+
"approval-required",
|
|
114
|
+
"unexpected-repo-change",
|
|
115
|
+
"runtime-incompatible",
|
|
116
|
+
"auth-required",
|
|
117
|
+
"quota-exceeded",
|
|
118
|
+
"paused",
|
|
119
|
+
"cancelled",
|
|
120
|
+
"agent-dead",
|
|
121
|
+
"unreviewed",
|
|
122
|
+
"internal-error",
|
|
123
|
+
"check-environment"
|
|
124
|
+
]);
|
|
125
|
+
const AgentState = ClosedEnum([
|
|
126
|
+
"declared",
|
|
127
|
+
"planned",
|
|
128
|
+
"spawning",
|
|
129
|
+
"running",
|
|
130
|
+
"waiting",
|
|
131
|
+
"paused",
|
|
132
|
+
"completed",
|
|
133
|
+
"failed",
|
|
134
|
+
"retrying",
|
|
135
|
+
"escalated",
|
|
136
|
+
"cancelled"
|
|
137
|
+
]);
|
|
138
|
+
const NodeStatus = ClosedEnum([
|
|
139
|
+
"pending",
|
|
140
|
+
"running",
|
|
141
|
+
"completed",
|
|
142
|
+
"failed",
|
|
143
|
+
"paused",
|
|
144
|
+
"waiting-approval",
|
|
145
|
+
"cancelled",
|
|
146
|
+
"skipped",
|
|
147
|
+
"blocked"
|
|
148
|
+
]);
|
|
149
|
+
/** The eleven roles of spec 8, and `verifier`: the id is reserved, the adversarial cross-check is off in V3.0 (2.9). */
|
|
150
|
+
const COHORTE_ROLES = [
|
|
151
|
+
"discoverer",
|
|
152
|
+
"brainstormer",
|
|
153
|
+
"architect",
|
|
154
|
+
"spec-author",
|
|
155
|
+
"implementer",
|
|
156
|
+
"tester",
|
|
157
|
+
"reviewer",
|
|
158
|
+
"security-reviewer",
|
|
159
|
+
"fixer",
|
|
160
|
+
"release-manager",
|
|
161
|
+
"reconciler",
|
|
162
|
+
"verifier"
|
|
163
|
+
];
|
|
164
|
+
OpenEnum(COHORTE_ROLES);
|
|
165
|
+
/** Closed: for data Cohorte itself authors and switches over (the escalation ladder). */
|
|
166
|
+
const KnownCohorteRole = ClosedEnum(COHORTE_ROLES);
|
|
167
|
+
const Severity = ClosedEnum([
|
|
168
|
+
"critical",
|
|
169
|
+
"major",
|
|
170
|
+
"minor",
|
|
171
|
+
"info"
|
|
172
|
+
]);
|
|
173
|
+
const Actor = Type.Object({
|
|
174
|
+
kind: ClosedEnum([
|
|
175
|
+
"human",
|
|
176
|
+
"client",
|
|
177
|
+
"system"
|
|
178
|
+
]),
|
|
179
|
+
id: Type.String(),
|
|
180
|
+
transport: OpenEnum(["cli"])
|
|
181
|
+
});
|
|
182
|
+
const GuardOutcome = Type.Object({
|
|
183
|
+
id: Type.String(),
|
|
184
|
+
ok: Type.Boolean(),
|
|
185
|
+
detail: Type.Optional(Type.String())
|
|
186
|
+
});
|
|
187
|
+
const StopRecord = Type.Object({
|
|
188
|
+
reason: StopReason,
|
|
189
|
+
detail: Type.String(),
|
|
190
|
+
resumable: Type.Boolean(),
|
|
191
|
+
resumeRequires: Type.Optional(OpenEnum([
|
|
192
|
+
"approval",
|
|
193
|
+
"auth-login",
|
|
194
|
+
"quota-reset",
|
|
195
|
+
"budget-raise",
|
|
196
|
+
"human-ack",
|
|
197
|
+
"repo-repair",
|
|
198
|
+
"reinstall-pinned-version",
|
|
199
|
+
"environment-repair"
|
|
200
|
+
]))
|
|
201
|
+
});
|
|
202
|
+
const EscalationStep = Type.Union([
|
|
203
|
+
Type.Object({
|
|
204
|
+
kind: Type.Literal("model-tier"),
|
|
205
|
+
role: KnownCohorteRole,
|
|
206
|
+
from: ModelCapability,
|
|
207
|
+
to: ModelCapability
|
|
208
|
+
}),
|
|
209
|
+
Type.Object({
|
|
210
|
+
kind: Type.Literal("role"),
|
|
211
|
+
from: KnownCohorteRole,
|
|
212
|
+
to: KnownCohorteRole
|
|
213
|
+
}),
|
|
214
|
+
Type.Object({ kind: Type.Literal("human") })
|
|
215
|
+
]);
|
|
216
|
+
/** Data: used by config AND by `escalation.applied`. Defaults: sameFailureCount 2, maxPerRun 2. */
|
|
217
|
+
const EscalationPolicy = Type.Object({
|
|
218
|
+
sameFailureCount: Type.Integer({ minimum: 1 }),
|
|
219
|
+
ladder: Type.Array(EscalationStep),
|
|
220
|
+
maxPerRun: Type.Integer({ minimum: 0 })
|
|
221
|
+
});
|
|
222
|
+
/**
|
|
223
|
+
* DESIGN 2.3.3. Declared HERE and re-exported by refs.ts: CheckResult needs it, and refs.ts needs the states and the
|
|
224
|
+
* profile of this file. Schemas are values, so an import cycle between the two files would read a const before it is set.
|
|
225
|
+
*/
|
|
226
|
+
const ArtifactRef = Type.Object({
|
|
227
|
+
artifactId: ArtifactId,
|
|
228
|
+
kind: OpenEnum([
|
|
229
|
+
"diff",
|
|
230
|
+
"file",
|
|
231
|
+
"log",
|
|
232
|
+
"report",
|
|
233
|
+
"agent-output",
|
|
234
|
+
"transcript",
|
|
235
|
+
"context",
|
|
236
|
+
"prompt",
|
|
237
|
+
"patch"
|
|
238
|
+
]),
|
|
239
|
+
path: Type.String(),
|
|
240
|
+
sha256: Sha256,
|
|
241
|
+
bytes: Type.Integer({ minimum: 0 })
|
|
242
|
+
});
|
|
243
|
+
const CheckResult = Type.Object({
|
|
244
|
+
name: Type.String(),
|
|
245
|
+
status: ClosedEnum([
|
|
246
|
+
"passed",
|
|
247
|
+
"failed",
|
|
248
|
+
"errored",
|
|
249
|
+
"skipped"
|
|
250
|
+
]),
|
|
251
|
+
argv: Type.Array(Type.String()),
|
|
252
|
+
exitCode: Type.Optional(Type.Integer()),
|
|
253
|
+
durationMs: Type.Number({ minimum: 0 }),
|
|
254
|
+
treeDigest: Type.String(),
|
|
255
|
+
output: Type.Optional(ArtifactRef)
|
|
256
|
+
});
|
|
257
|
+
//#endregion
|
|
258
|
+
//#region ../../packages/protocol/src/agent-output.ts
|
|
259
|
+
const AGENT_OUTPUT_MAX_SUMMARY = 2e3;
|
|
260
|
+
const confidence = () => Type.Number({
|
|
261
|
+
minimum: 0,
|
|
262
|
+
maximum: 1
|
|
263
|
+
});
|
|
264
|
+
const lineNumber = () => Type.Integer({ minimum: 1 });
|
|
265
|
+
const Finding = Type.Object({
|
|
266
|
+
/** assigned by Cohorte */
|
|
267
|
+
id: Type.Optional(FindingId),
|
|
268
|
+
severity: Severity,
|
|
269
|
+
kind: ClosedEnum([
|
|
270
|
+
"spec-violation",
|
|
271
|
+
"security",
|
|
272
|
+
"quality",
|
|
273
|
+
"complexity",
|
|
274
|
+
"check-failure"
|
|
275
|
+
]),
|
|
276
|
+
rule: Type.String(),
|
|
277
|
+
location: Type.Optional(Type.Object({
|
|
278
|
+
file: Type.String(),
|
|
279
|
+
line: Type.Optional(lineNumber()),
|
|
280
|
+
endLine: Type.Optional(lineNumber()),
|
|
281
|
+
symbol: Type.Optional(Type.String())
|
|
282
|
+
})),
|
|
283
|
+
reproduction: Type.Optional(Type.String()),
|
|
284
|
+
expected: Type.String(),
|
|
285
|
+
actual: Type.String(),
|
|
286
|
+
confidence: confidence(),
|
|
287
|
+
suggestedFix: Type.Optional(Type.String()),
|
|
288
|
+
scope: ClosedEnum(["in-scope", "deferred"]),
|
|
289
|
+
outOfScopeReason: Type.Optional(Type.String())
|
|
290
|
+
});
|
|
291
|
+
const AgentOutput = Type.Object({
|
|
292
|
+
status: ClosedEnum([
|
|
293
|
+
"completed",
|
|
294
|
+
"failed",
|
|
295
|
+
"blocked",
|
|
296
|
+
"needs-input"
|
|
297
|
+
]),
|
|
298
|
+
summary: Type.String({ maxLength: AGENT_OUTPUT_MAX_SUMMARY }),
|
|
299
|
+
artifacts: Type.Array(Type.Object({
|
|
300
|
+
path: Type.String(),
|
|
301
|
+
kind: ClosedEnum([
|
|
302
|
+
"diff",
|
|
303
|
+
"file",
|
|
304
|
+
"test",
|
|
305
|
+
"report",
|
|
306
|
+
"contract"
|
|
307
|
+
]),
|
|
308
|
+
/** ignored; Cohorte recomputes. A plain string on purpose: a wrong digest from a model must not fail its output. */
|
|
309
|
+
sha256: Type.Optional(Type.String())
|
|
310
|
+
})),
|
|
311
|
+
findings: Type.Array(Finding, { maxItems: 30 }),
|
|
312
|
+
/** claims; TEST is the truth */
|
|
313
|
+
checks: Type.Array(Type.Object({
|
|
314
|
+
name: Type.String(),
|
|
315
|
+
status: ClosedEnum([
|
|
316
|
+
"passed",
|
|
317
|
+
"failed",
|
|
318
|
+
"skipped",
|
|
319
|
+
"not-run"
|
|
320
|
+
]),
|
|
321
|
+
command: Type.Optional(Type.String())
|
|
322
|
+
})),
|
|
323
|
+
questions: Type.Array(Type.String()),
|
|
324
|
+
confidence: confidence(),
|
|
325
|
+
assumptions: Type.Optional(Type.Array(Type.Object({
|
|
326
|
+
gap: Type.String(),
|
|
327
|
+
decision: Type.String()
|
|
328
|
+
}))),
|
|
329
|
+
remediationAddressed: Type.Optional(Type.Array(Type.Object({
|
|
330
|
+
findingId: Type.String(),
|
|
331
|
+
how: Type.String()
|
|
332
|
+
})))
|
|
333
|
+
});
|
|
334
|
+
const count$4 = () => Type.Integer({ minimum: 0 });
|
|
335
|
+
/** Computed by core, never read from a model (2.9 rule 5). */
|
|
336
|
+
const ReviewResult = Type.Object({
|
|
337
|
+
verdict: ClosedEnum([
|
|
338
|
+
"approved",
|
|
339
|
+
"findings",
|
|
340
|
+
"needs-human"
|
|
341
|
+
]),
|
|
342
|
+
kept: Type.Array(Finding),
|
|
343
|
+
refuted: Type.Array(Finding),
|
|
344
|
+
deferred: Type.Array(Finding),
|
|
345
|
+
needsInvestigation: Type.Array(Finding),
|
|
346
|
+
blocking: count$4(),
|
|
347
|
+
blockingItems: Type.Array(Type.String()),
|
|
348
|
+
/** sha256(items)[0:16]; '' when there is nothing to fix */
|
|
349
|
+
fingerprint: Type.String({ pattern: "^(?:[0-9a-f]{16})?$" }),
|
|
350
|
+
unreviewed: Type.Array(SurfaceId),
|
|
351
|
+
clean: Type.Boolean(),
|
|
352
|
+
counts: Type.Object({
|
|
353
|
+
critical: count$4(),
|
|
354
|
+
major: count$4(),
|
|
355
|
+
minor: count$4(),
|
|
356
|
+
info: count$4()
|
|
357
|
+
})
|
|
358
|
+
});
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region ../../packages/protocol/src/refs.ts
|
|
361
|
+
const count$3 = () => Type.Integer({ minimum: 0 });
|
|
362
|
+
const PhaseRef = Type.Object({
|
|
363
|
+
phaseRunId: PhaseRunId,
|
|
364
|
+
state: ActivePipelineState,
|
|
365
|
+
iteration: count$3()
|
|
366
|
+
});
|
|
367
|
+
/** `role` is a plain string here (DESIGN 2.3.3): a reader must be able to show an agent whose role it does not know. */
|
|
368
|
+
const AgentRef = Type.Object({
|
|
369
|
+
agentId: AgentId,
|
|
370
|
+
role: Type.String(),
|
|
371
|
+
surface: Type.Optional(SurfaceId),
|
|
372
|
+
incarnation: count$3(),
|
|
373
|
+
attempt: count$3()
|
|
374
|
+
});
|
|
375
|
+
/** R8: optional wherever it appears, and opaque. A client never needs it. */
|
|
376
|
+
const RuntimeRef = Type.Object({
|
|
377
|
+
runtime: Type.String(),
|
|
378
|
+
version: Type.String(),
|
|
379
|
+
sessionId: Type.String(),
|
|
380
|
+
transcriptRef: Type.String()
|
|
381
|
+
});
|
|
382
|
+
const FileTouch = Type.Object({
|
|
383
|
+
/** worktree-relative, POSIX */
|
|
384
|
+
path: Type.String(),
|
|
385
|
+
op: ClosedEnum([
|
|
386
|
+
"read",
|
|
387
|
+
"create",
|
|
388
|
+
"modify",
|
|
389
|
+
"delete"
|
|
390
|
+
]),
|
|
391
|
+
beforeSha256: Type.Optional(Sha256),
|
|
392
|
+
afterSha256: Type.Optional(Sha256),
|
|
393
|
+
bytes: Type.Optional(count$3())
|
|
394
|
+
});
|
|
395
|
+
const SandboxReport = Type.Object({
|
|
396
|
+
level: OpenEnum(["L0-process", "L1-os"]),
|
|
397
|
+
backend: OpenEnum([
|
|
398
|
+
"none",
|
|
399
|
+
"seatbelt",
|
|
400
|
+
"bubblewrap"
|
|
401
|
+
]),
|
|
402
|
+
filesystem: OpenEnum([
|
|
403
|
+
"enforced",
|
|
404
|
+
"partial",
|
|
405
|
+
"advisory"
|
|
406
|
+
]),
|
|
407
|
+
network: OpenEnum([
|
|
408
|
+
"enforced-off",
|
|
409
|
+
"partial",
|
|
410
|
+
"unenforced"
|
|
411
|
+
])
|
|
412
|
+
});
|
|
413
|
+
const RunPlan = Type.Object({
|
|
414
|
+
profile: PipelineProfile,
|
|
415
|
+
runtime: Type.Object({
|
|
416
|
+
id: Type.String(),
|
|
417
|
+
version: Type.String()
|
|
418
|
+
}),
|
|
419
|
+
/** 2.10.1: WHO consented to every security-loosening key of the project file */
|
|
420
|
+
trust: Type.Object({
|
|
421
|
+
policySha256: Sha256,
|
|
422
|
+
loosenedKeys: Type.Array(Type.String()),
|
|
423
|
+
grantedBy: OpenEnum([
|
|
424
|
+
"none-needed",
|
|
425
|
+
"user-config",
|
|
426
|
+
"cli-flag",
|
|
427
|
+
"trust-record"
|
|
428
|
+
])
|
|
429
|
+
}),
|
|
430
|
+
models: Type.Array(Type.Object({
|
|
431
|
+
role: Type.String(),
|
|
432
|
+
requested: ModelRef,
|
|
433
|
+
thinking: ThinkingLevel,
|
|
434
|
+
authMode: AuthMode,
|
|
435
|
+
billing: ClosedEnum(["plan-limits", "metered"]),
|
|
436
|
+
reason: Type.String()
|
|
437
|
+
})),
|
|
438
|
+
apiBillingEnabled: Type.Boolean(),
|
|
439
|
+
/** non-empty => the plan printed to the human names per-token billing */
|
|
440
|
+
meteredProviders: Type.Array(Type.String()),
|
|
441
|
+
sandbox: SandboxReport,
|
|
442
|
+
sandboxRequire: ClosedEnum(["native", "best-effort"]),
|
|
443
|
+
brainIsolation: ClosedEnum(["os", "process"]),
|
|
444
|
+
budgets: Type.Object({
|
|
445
|
+
run: BudgetCounters,
|
|
446
|
+
perPhase: BudgetCounters,
|
|
447
|
+
perAgent: BudgetCounters,
|
|
448
|
+
perProvider: Type.Record(Type.String(), BudgetCounters),
|
|
449
|
+
perTool: Type.Record(Type.String(), BudgetCounters)
|
|
450
|
+
}),
|
|
451
|
+
network: Type.Object({ provisioning: Type.Boolean() }),
|
|
452
|
+
promptOverrides: Type.Array(Type.String()),
|
|
453
|
+
unattended: Type.Boolean()
|
|
454
|
+
});
|
|
455
|
+
/** R6 — everything a human needs without reading a transcript */
|
|
456
|
+
const ApprovalRequest = Type.Object({
|
|
457
|
+
approvalId: ApprovalId,
|
|
458
|
+
kind: OpenEnum([
|
|
459
|
+
"tool",
|
|
460
|
+
"shared-path",
|
|
461
|
+
"ship",
|
|
462
|
+
"budget",
|
|
463
|
+
"loop-stalled",
|
|
464
|
+
"contract-change",
|
|
465
|
+
"spec-not-ready",
|
|
466
|
+
"review-leftovers",
|
|
467
|
+
"unowned-path",
|
|
468
|
+
"api-billing",
|
|
469
|
+
"blocked-ack",
|
|
470
|
+
"provision-network"
|
|
471
|
+
]),
|
|
472
|
+
agent: Type.Optional(AgentRef),
|
|
473
|
+
phase: Type.Optional(PhaseRef),
|
|
474
|
+
tool: Type.Optional(Type.String()),
|
|
475
|
+
/** sealed */
|
|
476
|
+
args: Type.Optional(JsonValueSchema),
|
|
477
|
+
affectedPaths: Type.Array(Type.String()),
|
|
478
|
+
/** sealed; agent-controlled text: clients MUST render it through the sanitiser of 2.3.6 */
|
|
479
|
+
preview: Type.Object({
|
|
480
|
+
kind: ClosedEnum([
|
|
481
|
+
"diff",
|
|
482
|
+
"command",
|
|
483
|
+
"text"
|
|
484
|
+
]),
|
|
485
|
+
text: Type.String()
|
|
486
|
+
}),
|
|
487
|
+
/** only for the `approval_request` tool: the answers the agent offered; `approve.answer` must be one of them */
|
|
488
|
+
options: Type.Optional(Type.Array(Type.String())),
|
|
489
|
+
ruleId: Type.String(),
|
|
490
|
+
reason: Type.String(),
|
|
491
|
+
asks: Type.Array(Type.Object({
|
|
492
|
+
stage: Type.String(),
|
|
493
|
+
ruleId: Type.String(),
|
|
494
|
+
reason: Type.String()
|
|
495
|
+
})),
|
|
496
|
+
allowedDecisions: Type.Array(ClosedEnum([
|
|
497
|
+
"allow-once",
|
|
498
|
+
"allow-for-run",
|
|
499
|
+
"deny"
|
|
500
|
+
])),
|
|
501
|
+
/** what the decision is bound to (4.5): the target's beforeSha256 (write/patch) or the slot's treeDigest (command) */
|
|
502
|
+
preStateSha256: Type.Optional(Sha256),
|
|
503
|
+
expiresAt: Type.Optional(IsoInstant),
|
|
504
|
+
unattended: ClosedEnum(["deny", "wait"]),
|
|
505
|
+
/** literal "cohorte approve <id>" */
|
|
506
|
+
cli: Type.String()
|
|
507
|
+
});
|
|
508
|
+
const ResumeReport = Type.Object({
|
|
509
|
+
takeover: Type.Boolean(),
|
|
510
|
+
hostId: Type.String(),
|
|
511
|
+
fencingToken: count$3(),
|
|
512
|
+
locks: Type.Object({
|
|
513
|
+
rebuilt: Type.Array(Type.String()),
|
|
514
|
+
conflicts: Type.Array(Type.String())
|
|
515
|
+
}),
|
|
516
|
+
orphans: Type.Array(Type.Object({
|
|
517
|
+
agentId: Type.Optional(AgentId),
|
|
518
|
+
incarnation: Type.Optional(count$3()),
|
|
519
|
+
pid: count$3(),
|
|
520
|
+
kind: ClosedEnum(["brain", "command"]),
|
|
521
|
+
killed: Type.Boolean()
|
|
522
|
+
})),
|
|
523
|
+
worktrees: Type.Array(Type.Object({
|
|
524
|
+
slot: Type.String(),
|
|
525
|
+
path: Type.String(),
|
|
526
|
+
verdict: OpenEnum([
|
|
527
|
+
"ok",
|
|
528
|
+
"re-added",
|
|
529
|
+
"ledger-explained",
|
|
530
|
+
"quarantined-reset",
|
|
531
|
+
"unexplained-change",
|
|
532
|
+
"missing-branch"
|
|
533
|
+
])
|
|
534
|
+
})),
|
|
535
|
+
effects: Type.Array(Type.Object({
|
|
536
|
+
effectId: EffectId,
|
|
537
|
+
kind: Type.String(),
|
|
538
|
+
replayClass: ClosedEnum([
|
|
539
|
+
"idempotent",
|
|
540
|
+
"verifiable",
|
|
541
|
+
"at-most-once"
|
|
542
|
+
]),
|
|
543
|
+
verdict: OpenEnum([
|
|
544
|
+
"done",
|
|
545
|
+
"failed",
|
|
546
|
+
"re-executed",
|
|
547
|
+
"in-doubt",
|
|
548
|
+
"compensated"
|
|
549
|
+
])
|
|
550
|
+
})),
|
|
551
|
+
approvalsCarried: Type.Array(ApprovalId),
|
|
552
|
+
commandsApplied: Type.Array(CommandId),
|
|
553
|
+
inDoubt: Type.Array(EffectId),
|
|
554
|
+
/** 4.5 parked path */
|
|
555
|
+
approvedReplays: Type.Array(Type.Object({
|
|
556
|
+
approvalId: ApprovalId,
|
|
557
|
+
toolCallId: ToolCallId,
|
|
558
|
+
outcome: OpenEnum([
|
|
559
|
+
"executed",
|
|
560
|
+
"binding-changed",
|
|
561
|
+
"denied-by-gate"
|
|
562
|
+
])
|
|
563
|
+
}))
|
|
564
|
+
});
|
|
565
|
+
const Durability = ClosedEnum(["durable", "ephemeral"]);
|
|
566
|
+
const EnvelopeBase = Type.Object({
|
|
567
|
+
protocolVersion: Type.Literal("1.0"),
|
|
568
|
+
eventId: EventId,
|
|
569
|
+
/** durable: own gapless per-run sequence (1..n). ephemeral: sequence of the last COMMITTED durable event when it is STAMPED */
|
|
570
|
+
sequence: Type.Integer({ minimum: 0 }),
|
|
571
|
+
/** durable: 0. ephemeral: 1.. after that durable sequence */
|
|
572
|
+
sub: Type.Integer({ minimum: 0 }),
|
|
573
|
+
durability: Durability,
|
|
574
|
+
timestamp: IsoInstant,
|
|
575
|
+
runId: RunId,
|
|
576
|
+
/** narrowed per event */
|
|
577
|
+
type: Type.String({ minLength: 1 }),
|
|
578
|
+
source: ClosedEnum([
|
|
579
|
+
"cohorte",
|
|
580
|
+
"runtime",
|
|
581
|
+
"client",
|
|
582
|
+
"human"
|
|
583
|
+
]),
|
|
584
|
+
phase: Type.Optional(PhaseRef),
|
|
585
|
+
agent: Type.Optional(AgentRef),
|
|
586
|
+
/** eventId or commandId that caused this event */
|
|
587
|
+
causationId: Type.Optional(Type.String()),
|
|
588
|
+
/** one line, sealed; EventWriter replaces control characters by U+FFFD BEFORE validation */
|
|
589
|
+
summary: Type.String({
|
|
590
|
+
maxLength: 200,
|
|
591
|
+
pattern: "^[^\\u0000-\\u001f\\u007f-\\u009f]*$"
|
|
592
|
+
}),
|
|
593
|
+
severity: ClosedEnum([
|
|
594
|
+
"info",
|
|
595
|
+
"success",
|
|
596
|
+
"warning",
|
|
597
|
+
"error",
|
|
598
|
+
"progress"
|
|
599
|
+
]),
|
|
600
|
+
/** narrowed per event */
|
|
601
|
+
payload: Type.Unknown(),
|
|
602
|
+
redactions: Type.Array(Redaction)
|
|
603
|
+
});
|
|
604
|
+
/** Total order of a stream. */
|
|
605
|
+
function compareOrder(a, b) {
|
|
606
|
+
return a.sequence - b.sequence || a.sub - b.sub;
|
|
607
|
+
}
|
|
608
|
+
//#endregion
|
|
609
|
+
//#region ../../packages/protocol/src/compile.ts
|
|
610
|
+
const SCHEMA_DIALECT = "https://json-schema.org/draft/2020-12/schema";
|
|
611
|
+
const SCHEMA_MAPS = /* @__PURE__ */ new Set([
|
|
612
|
+
"properties",
|
|
613
|
+
"patternProperties",
|
|
614
|
+
"$defs",
|
|
615
|
+
"definitions",
|
|
616
|
+
"dependentSchemas"
|
|
617
|
+
]);
|
|
618
|
+
const SCHEMA_LISTS = /* @__PURE__ */ new Set([
|
|
619
|
+
"anyOf",
|
|
620
|
+
"oneOf",
|
|
621
|
+
"prefixItems"
|
|
622
|
+
]);
|
|
623
|
+
const SCHEMA_SINGLES = /* @__PURE__ */ new Set([
|
|
624
|
+
"items",
|
|
625
|
+
"additionalItems",
|
|
626
|
+
"additionalProperties",
|
|
627
|
+
"unevaluatedProperties",
|
|
628
|
+
"unevaluatedItems",
|
|
629
|
+
"not",
|
|
630
|
+
"if",
|
|
631
|
+
"then",
|
|
632
|
+
"else",
|
|
633
|
+
"contains",
|
|
634
|
+
"propertyNames"
|
|
635
|
+
]);
|
|
636
|
+
const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
637
|
+
/** TypeBox keeps its own bookkeeping under non-enumerable or `~`-prefixed keys: a JSON round trip leaves the JSON Schema. */
|
|
638
|
+
const plain = (schema) => JSON.parse(JSON.stringify(schema));
|
|
639
|
+
/** Post-order map over every SCHEMA of a document: `post` sees a node whose sub-schemas are already mapped. */
|
|
640
|
+
function mapSchemas(node, post, closable = true) {
|
|
641
|
+
if (!isObject(node)) return node;
|
|
642
|
+
const out = {};
|
|
643
|
+
for (const [keyword, value] of Object.entries(node)) if (SCHEMA_MAPS.has(keyword) && isObject(value)) out[keyword] = Object.fromEntries(Object.entries(value).map(([name, member]) => [name, mapSchemas(member, post)]));
|
|
644
|
+
else if ((SCHEMA_LISTS.has(keyword) || keyword === "items") && Array.isArray(value)) out[keyword] = value.map((member) => mapSchemas(member, post));
|
|
645
|
+
else if (keyword === "allOf" && Array.isArray(value)) out[keyword] = value.map((member) => mapSchemas(member, post, false));
|
|
646
|
+
else if (SCHEMA_SINGLES.has(keyword) && isObject(value)) out[keyword] = mapSchemas(value, post);
|
|
647
|
+
else out[keyword] = value;
|
|
648
|
+
return post(out, closable);
|
|
649
|
+
}
|
|
650
|
+
function rewrite(node, mode) {
|
|
651
|
+
return mapSchemas(node, (out, closable) => {
|
|
652
|
+
if (mode === "open") {
|
|
653
|
+
if (out.additionalProperties === false) delete out.additionalProperties;
|
|
654
|
+
if (knownValuesOf(out) !== void 0) delete out.enum;
|
|
655
|
+
} else if (closable && isObject(out.properties) && !("additionalProperties" in out)) out.additionalProperties = false;
|
|
656
|
+
return out;
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* TypeBox inlines a `Type.Cyclic` at EVERY use as `{ $defs: { X: { $id: 'X', … } }, $ref: 'X' }`. Its own compiler
|
|
661
|
+
* accepts the repetition; a second implementation (ajv) refuses two schemas with one `$id` in one document, and the
|
|
662
|
+
* published schema exists for second implementations (AC-07). So a published DOCUMENT carries each such definition
|
|
663
|
+
* once, under the root `$defs`, without its `$id`, and every reference becomes a pointer. Two different definitions
|
|
664
|
+
* under one name are an authoring error, never merged. The result is a whole document: embed authored schemas in a
|
|
665
|
+
* bigger one, not published ones (their pointers are relative to the root).
|
|
666
|
+
*/
|
|
667
|
+
function hoistDefinitions(document) {
|
|
668
|
+
const hoisted = {};
|
|
669
|
+
const hoist = (name, definition) => {
|
|
670
|
+
const { $id: _id, ...body } = definition;
|
|
671
|
+
const found = hoisted[name];
|
|
672
|
+
if (found !== void 0 && JSON.stringify(found) !== JSON.stringify(body)) throw new TypeError(`two different definitions are named ${JSON.stringify(name)} in one published schema`);
|
|
673
|
+
hoisted[name] = body;
|
|
674
|
+
};
|
|
675
|
+
const lifted = mapSchemas(document, (out) => {
|
|
676
|
+
if (!isObject(out.$defs)) return out;
|
|
677
|
+
const kept = {};
|
|
678
|
+
for (const [name, member] of Object.entries(out.$defs)) if (isObject(member) && member.$id === name) hoist(name, member);
|
|
679
|
+
else kept[name] = member;
|
|
680
|
+
if (Object.keys(kept).length > 0) out.$defs = kept;
|
|
681
|
+
else delete out.$defs;
|
|
682
|
+
return out;
|
|
683
|
+
});
|
|
684
|
+
if (!isObject(lifted) || Object.keys(hoisted).length === 0) return lifted;
|
|
685
|
+
const own = isObject(lifted.$defs) ? lifted.$defs : {};
|
|
686
|
+
for (const name of Object.keys(hoisted)) if (name in own) throw new TypeError(`two different definitions are named ${JSON.stringify(name)} in one published schema`);
|
|
687
|
+
return mapSchemas({
|
|
688
|
+
...lifted,
|
|
689
|
+
$defs: {
|
|
690
|
+
...own,
|
|
691
|
+
...hoisted
|
|
692
|
+
}
|
|
693
|
+
}, (out) => {
|
|
694
|
+
if (typeof out.$ref === "string" && Object.hasOwn(hoisted, out.$ref)) out.$ref = `#/$defs/${out.$ref}`;
|
|
695
|
+
return out;
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
/** Writer side. Closes every object that declares `properties`, whether or not its author remembered to. */
|
|
699
|
+
function toStrictSchema(schema) {
|
|
700
|
+
return rewrite(plain(schema), "strict");
|
|
701
|
+
}
|
|
702
|
+
function validatorOf(jsonSchema) {
|
|
703
|
+
const compiled = Compile(jsonSchema);
|
|
704
|
+
return (value) => {
|
|
705
|
+
if (compiled.Check(value)) return ok(value);
|
|
706
|
+
const issues = [];
|
|
707
|
+
for (const issue of compiled.Errors(value)) issues.push({
|
|
708
|
+
path: issue.instancePath,
|
|
709
|
+
keyword: issue.keyword,
|
|
710
|
+
message: issue.message
|
|
711
|
+
});
|
|
712
|
+
return err(issues);
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
const strictCache = /* @__PURE__ */ new WeakMap();
|
|
716
|
+
/** The STRICT validator of any authored schema: commands, documents, agent output. Compiled once per schema object. */
|
|
717
|
+
function compileSchema(schema) {
|
|
718
|
+
let found = strictCache.get(schema);
|
|
719
|
+
if (!found) {
|
|
720
|
+
found = validatorOf(toStrictSchema(schema));
|
|
721
|
+
strictCache.set(schema, found);
|
|
722
|
+
}
|
|
723
|
+
return found;
|
|
724
|
+
}
|
|
725
|
+
const rowOf = (events, type) => {
|
|
726
|
+
if (!Object.hasOwn(events, type)) throw new RangeError(`no event type ${JSON.stringify(type)} in this catalogue`);
|
|
727
|
+
return events[type];
|
|
728
|
+
};
|
|
729
|
+
/** Writer side: the payload of one event type, unknown keys rejected. Generic over the table, so a catalogue only adds rows. */
|
|
730
|
+
function compileStrict(events, type) {
|
|
731
|
+
return compileSchema(rowOf(events, type).payload);
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* The properties that make a base envelope the envelope of ONE row: the discriminant, the narrowed body and whatever
|
|
735
|
+
* the row pins (an event pins its durability). Shared by the strict and the open form, so the two cannot disagree.
|
|
736
|
+
*/
|
|
737
|
+
function narrowed(base, discriminant, type, body, bodySchema, pinned) {
|
|
738
|
+
if (!isObject(base) || !isObject(base.properties)) throw new TypeError("an envelope schema must be an object schema");
|
|
739
|
+
const properties = {
|
|
740
|
+
...base.properties,
|
|
741
|
+
[discriminant]: { const: type },
|
|
742
|
+
[body]: bodySchema
|
|
743
|
+
};
|
|
744
|
+
for (const [name, value] of Object.entries(pinned)) properties[name] = { const: value };
|
|
745
|
+
return {
|
|
746
|
+
...base,
|
|
747
|
+
properties
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
const envelopeCache = /* @__PURE__ */ new WeakMap();
|
|
751
|
+
/** Writer side: the WHOLE envelope of one event type — closed, its `type` and its durability pinned by the table. */
|
|
752
|
+
function compileStrictEnvelope(events, type) {
|
|
753
|
+
const row = rowOf(events, type);
|
|
754
|
+
let perTable = envelopeCache.get(events);
|
|
755
|
+
if (!perTable) {
|
|
756
|
+
perTable = /* @__PURE__ */ new Map();
|
|
757
|
+
envelopeCache.set(events, perTable);
|
|
758
|
+
}
|
|
759
|
+
let found = perTable.get(type);
|
|
760
|
+
if (!found) {
|
|
761
|
+
found = validatorOf(narrowed(toStrictSchema(EnvelopeBase), "type", type, "payload", toStrictSchema(row.payload), { durability: row.durability }));
|
|
762
|
+
perTable.set(type, found);
|
|
763
|
+
}
|
|
764
|
+
return found;
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* The published form of a table of types: the open base envelope, then a `oneOf` with one branch per KNOWN type and a
|
|
768
|
+
* catch-all branch for the types of a later minor. Exactly one branch matches any envelope, because the base requires
|
|
769
|
+
* the discriminant. Used for events here and for commands in commands.ts.
|
|
770
|
+
*/
|
|
771
|
+
function toOpenTableSchema(options) {
|
|
772
|
+
const base = rewrite(plain(options.base), "open");
|
|
773
|
+
if (!isObject(base)) throw new TypeError("an envelope schema must be an object schema");
|
|
774
|
+
const known = options.rows.map((row) => row.type);
|
|
775
|
+
const branches = options.rows.map((row) => {
|
|
776
|
+
const branch = narrowed({ properties: {} }, options.discriminant, row.type, options.body, rewrite(plain(row.body), "open"), row.pinned ?? {});
|
|
777
|
+
return {
|
|
778
|
+
title: row.type,
|
|
779
|
+
...branch
|
|
780
|
+
};
|
|
781
|
+
});
|
|
782
|
+
branches.push({
|
|
783
|
+
title: "a type added by a later minor version: readers MUST ignore it",
|
|
784
|
+
properties: { [options.discriminant]: { not: { enum: known } } }
|
|
785
|
+
});
|
|
786
|
+
return hoistDefinitions({
|
|
787
|
+
$schema: SCHEMA_DIALECT,
|
|
788
|
+
$id: options.$id,
|
|
789
|
+
title: options.title,
|
|
790
|
+
...base,
|
|
791
|
+
oneOf: branches
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
/** Generator side of DESIGN 2.3.2, over any events table. */
|
|
795
|
+
function toOpenJsonSchema(events, options = {}) {
|
|
796
|
+
return toOpenTableSchema({
|
|
797
|
+
$id: options.$id ?? "https://cohorte.dev/schemas/3/events.schema.json",
|
|
798
|
+
title: options.title ?? "Cohorte Protocol event envelope",
|
|
799
|
+
base: EnvelopeBase,
|
|
800
|
+
discriminant: "type",
|
|
801
|
+
body: "payload",
|
|
802
|
+
rows: Object.entries(events).map(([type, row]) => ({
|
|
803
|
+
type,
|
|
804
|
+
body: row.payload,
|
|
805
|
+
pinned: { durability: row.durability }
|
|
806
|
+
}))
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
/** The exact signatures of DESIGN 2.3.2, bound to one table: `bindCatalogue(EVENTS)` is all a catalogue has to write. */
|
|
810
|
+
function bindCatalogue(events) {
|
|
811
|
+
return {
|
|
812
|
+
compileStrict: (type) => compileStrict(events, type),
|
|
813
|
+
compileStrictEnvelope: (type) => compileStrictEnvelope(events, type),
|
|
814
|
+
toOpenJsonSchema: () => toOpenJsonSchema(events)
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
//#endregion
|
|
818
|
+
//#region ../../packages/protocol/src/events/declare.ts
|
|
819
|
+
const durable = (payload) => ({
|
|
820
|
+
payload,
|
|
821
|
+
durability: "durable"
|
|
822
|
+
});
|
|
823
|
+
const ephemeral = (payload) => ({
|
|
824
|
+
payload,
|
|
825
|
+
durability: "ephemeral"
|
|
826
|
+
});
|
|
827
|
+
const count$2 = () => Type.Integer({ minimum: 0 });
|
|
828
|
+
const milliseconds = () => Type.Number({ minimum: 0 });
|
|
829
|
+
/** `{ ref; sha; treeDigest }`: what a review looked at, and what an approval of it is bound to. */
|
|
830
|
+
const ReviewRef = Type.Object({
|
|
831
|
+
ref: Type.String(),
|
|
832
|
+
sha: Type.String(),
|
|
833
|
+
treeDigest: Type.String()
|
|
834
|
+
});
|
|
835
|
+
const REPLAY_CLASSES = [
|
|
836
|
+
"idempotent",
|
|
837
|
+
"verifiable",
|
|
838
|
+
"at-most-once"
|
|
839
|
+
];
|
|
840
|
+
//#endregion
|
|
841
|
+
//#region ../../packages/protocol/src/events/agent.ts
|
|
842
|
+
const AGENT_STATE_CHANGE_REASONS = [
|
|
843
|
+
"planned",
|
|
844
|
+
"spawned",
|
|
845
|
+
"tool-wait",
|
|
846
|
+
"approval-wait",
|
|
847
|
+
"quota-wait",
|
|
848
|
+
"peer-wait",
|
|
849
|
+
"paused",
|
|
850
|
+
"resumed",
|
|
851
|
+
"completed",
|
|
852
|
+
"failed",
|
|
853
|
+
"cancelled",
|
|
854
|
+
"retry",
|
|
855
|
+
"escalation",
|
|
856
|
+
"recovery",
|
|
857
|
+
"park",
|
|
858
|
+
"pause-expiry"
|
|
859
|
+
];
|
|
860
|
+
const MESSAGE_ROLES = [
|
|
861
|
+
"assistant",
|
|
862
|
+
"user",
|
|
863
|
+
"tool-result"
|
|
864
|
+
];
|
|
865
|
+
const MESSAGE_CHANNELS = [
|
|
866
|
+
"text",
|
|
867
|
+
"thinking",
|
|
868
|
+
"tool-input"
|
|
869
|
+
];
|
|
870
|
+
const MESSAGE_STOPS = [
|
|
871
|
+
"stop",
|
|
872
|
+
"length",
|
|
873
|
+
"tool-use",
|
|
874
|
+
"error",
|
|
875
|
+
"aborted"
|
|
876
|
+
];
|
|
877
|
+
const MESSAGE_DELIVERIES = ["steer", "follow-up"];
|
|
878
|
+
const MESSAGE_DELTA_MAX_LENGTH = 8192;
|
|
879
|
+
/**
|
|
880
|
+
* R9. The shapes of the context manifest (DESIGN 2.2.4), declared here a second time: protocol imports no other
|
|
881
|
+
* package than base (C4). Exported because `inspect { kind: 'context' }` returns this payload as it is.
|
|
882
|
+
*/
|
|
883
|
+
const ContextBuiltPayload = Type.Object({
|
|
884
|
+
agent: AgentRef,
|
|
885
|
+
manifestSha256: Sha256,
|
|
886
|
+
tokenEstimate: count$2(),
|
|
887
|
+
tokenLimit: count$2(),
|
|
888
|
+
entries: Type.Array(Type.Object({
|
|
889
|
+
id: Type.String(),
|
|
890
|
+
tier: ClosedEnum([
|
|
891
|
+
"system",
|
|
892
|
+
"doctrine",
|
|
893
|
+
"data",
|
|
894
|
+
"task",
|
|
895
|
+
"prior-results"
|
|
896
|
+
]),
|
|
897
|
+
trust: ClosedEnum([
|
|
898
|
+
"cohorte",
|
|
899
|
+
"human",
|
|
900
|
+
"untrusted-repository",
|
|
901
|
+
"agent-output"
|
|
902
|
+
]),
|
|
903
|
+
source: Type.Object({
|
|
904
|
+
kind: ClosedEnum([
|
|
905
|
+
"asset",
|
|
906
|
+
"project-file",
|
|
907
|
+
"artifact",
|
|
908
|
+
"event-summary",
|
|
909
|
+
"inline"
|
|
910
|
+
]),
|
|
911
|
+
ref: Type.String()
|
|
912
|
+
}),
|
|
913
|
+
sha256: Sha256,
|
|
914
|
+
bytes: count$2(),
|
|
915
|
+
tokenEstimate: count$2()
|
|
916
|
+
})),
|
|
917
|
+
reductions: Type.Array(Type.Object({
|
|
918
|
+
entryId: Type.String(),
|
|
919
|
+
strategy: ClosedEnum([
|
|
920
|
+
"excerpt",
|
|
921
|
+
"outline",
|
|
922
|
+
"summary-with-refs",
|
|
923
|
+
"dropped"
|
|
924
|
+
]),
|
|
925
|
+
fromBytes: count$2(),
|
|
926
|
+
toBytes: count$2()
|
|
927
|
+
})),
|
|
928
|
+
exclusions: Type.Array(Type.Object({
|
|
929
|
+
pattern: Type.String(),
|
|
930
|
+
reason: ClosedEnum([
|
|
931
|
+
"secret",
|
|
932
|
+
"outside-scope",
|
|
933
|
+
"size",
|
|
934
|
+
"binary"
|
|
935
|
+
])
|
|
936
|
+
})),
|
|
937
|
+
manifest: ArtifactRef
|
|
938
|
+
});
|
|
939
|
+
const AGENT_EVENTS = {
|
|
940
|
+
"agent.declared": durable(Type.Object({
|
|
941
|
+
agent: AgentRef,
|
|
942
|
+
parentAgentId: Type.Optional(AgentId),
|
|
943
|
+
owner: Type.String(),
|
|
944
|
+
ownedPaths: Type.Array(Type.String()),
|
|
945
|
+
grantsDigest: Sha256,
|
|
946
|
+
requestedModel: ModelRef,
|
|
947
|
+
thinking: ThinkingLevel,
|
|
948
|
+
routingReason: Type.String(),
|
|
949
|
+
budget: BudgetCounters
|
|
950
|
+
})),
|
|
951
|
+
"agent.spawned": durable(Type.Object({
|
|
952
|
+
agent: AgentRef,
|
|
953
|
+
worktree: Type.Optional(Type.Object({
|
|
954
|
+
slot: Type.String(),
|
|
955
|
+
path: Type.String(),
|
|
956
|
+
branch: Type.String(),
|
|
957
|
+
baseSha: Type.String()
|
|
958
|
+
})),
|
|
959
|
+
tools: Type.Array(Type.String()),
|
|
960
|
+
systemPromptSha256: Sha256,
|
|
961
|
+
effectiveSystemPromptSha256: Sha256,
|
|
962
|
+
authMode: AuthMode,
|
|
963
|
+
isolation: SandboxReport,
|
|
964
|
+
runtimeRef: Type.Optional(RuntimeRef)
|
|
965
|
+
})),
|
|
966
|
+
"agent.started": durable(Type.Object({
|
|
967
|
+
agent: AgentRef,
|
|
968
|
+
taskSha256: Sha256
|
|
969
|
+
})),
|
|
970
|
+
"agent.state.changed": durable(Type.Object({
|
|
971
|
+
agent: AgentRef,
|
|
972
|
+
from: AgentState,
|
|
973
|
+
to: AgentState,
|
|
974
|
+
reason: OpenEnum(AGENT_STATE_CHANGE_REASONS),
|
|
975
|
+
pausedAt: Type.Optional(ClosedEnum(["tool-boundary", "model-boundary"])),
|
|
976
|
+
attemptConsumed: Type.Boolean()
|
|
977
|
+
})),
|
|
978
|
+
"agent.completed": durable(Type.Object({
|
|
979
|
+
agent: AgentRef,
|
|
980
|
+
status: AgentOutput.properties.status,
|
|
981
|
+
summary: Type.String(),
|
|
982
|
+
confidence: Type.Number({
|
|
983
|
+
minimum: 0,
|
|
984
|
+
maximum: 1
|
|
985
|
+
}),
|
|
986
|
+
output: ArtifactRef,
|
|
987
|
+
artifacts: Type.Array(ArtifactRef),
|
|
988
|
+
findings: count$2(),
|
|
989
|
+
questions: Type.Array(Type.String()),
|
|
990
|
+
usage: BudgetCounters
|
|
991
|
+
})),
|
|
992
|
+
"agent.failed": durable(Type.Object({
|
|
993
|
+
agent: AgentRef,
|
|
994
|
+
error: ErrorInfo,
|
|
995
|
+
willRetry: Type.Boolean(),
|
|
996
|
+
nextIncarnation: Type.Optional(count$2())
|
|
997
|
+
})),
|
|
998
|
+
"agent.turn.started": ephemeral(Type.Object({ turn: count$2() })),
|
|
999
|
+
"agent.turn.completed": durable(Type.Object({
|
|
1000
|
+
turn: count$2(),
|
|
1001
|
+
toolCalls: count$2()
|
|
1002
|
+
})),
|
|
1003
|
+
/** R1 */
|
|
1004
|
+
"agent.message.started": ephemeral(Type.Object({
|
|
1005
|
+
messageId: Type.String(),
|
|
1006
|
+
role: ClosedEnum(MESSAGE_ROLES)
|
|
1007
|
+
})),
|
|
1008
|
+
"agent.message.delta": ephemeral(Type.Object({
|
|
1009
|
+
messageId: Type.String(),
|
|
1010
|
+
channel: ClosedEnum(MESSAGE_CHANNELS),
|
|
1011
|
+
contentIndex: count$2(),
|
|
1012
|
+
delta: Type.String({ maxLength: MESSAGE_DELTA_MAX_LENGTH })
|
|
1013
|
+
})),
|
|
1014
|
+
"agent.message.completed": durable(Type.Object({
|
|
1015
|
+
messageId: Type.String(),
|
|
1016
|
+
role: ClosedEnum(MESSAGE_ROLES),
|
|
1017
|
+
preview: Type.String({ maxLength: 512 }),
|
|
1018
|
+
textSha256: Sha256,
|
|
1019
|
+
bytes: count$2(),
|
|
1020
|
+
stop: Type.Optional(ClosedEnum(MESSAGE_STOPS))
|
|
1021
|
+
})),
|
|
1022
|
+
/** the runtime took a `send` (host note, nudge, or `agent.send`) into its queue */
|
|
1023
|
+
"agent.message.accepted": durable(Type.Object({
|
|
1024
|
+
agent: AgentRef,
|
|
1025
|
+
messageId: Type.String(),
|
|
1026
|
+
delivery: ClosedEnum(MESSAGE_DELIVERIES)
|
|
1027
|
+
})),
|
|
1028
|
+
/** non-fatal runtime diagnostics (unmapped stop reason, stale auth snapshot, degraded capability); `message` is sealed */
|
|
1029
|
+
"runtime.warning": durable(Type.Object({
|
|
1030
|
+
agent: Type.Optional(AgentRef),
|
|
1031
|
+
code: Type.String(),
|
|
1032
|
+
message: Type.String()
|
|
1033
|
+
})),
|
|
1034
|
+
"model.requested": durable(Type.Object({
|
|
1035
|
+
requestId: Type.String(),
|
|
1036
|
+
model: ModelRef,
|
|
1037
|
+
expectedAuthMode: AuthMode,
|
|
1038
|
+
contextSha256: Type.Optional(Sha256),
|
|
1039
|
+
attempt: count$2()
|
|
1040
|
+
})),
|
|
1041
|
+
"model.responded": durable(Type.Object({
|
|
1042
|
+
requestId: Type.String(),
|
|
1043
|
+
requestedModel: ModelRef,
|
|
1044
|
+
effectiveModel: Type.Object({
|
|
1045
|
+
provider: Type.String(),
|
|
1046
|
+
model: Type.String(),
|
|
1047
|
+
api: Type.Optional(Type.String()),
|
|
1048
|
+
baseUrl: Type.Optional(Type.String())
|
|
1049
|
+
}),
|
|
1050
|
+
authMode: AuthMode,
|
|
1051
|
+
authSource: ClosedEnum([
|
|
1052
|
+
"oauth",
|
|
1053
|
+
"api-key",
|
|
1054
|
+
"none"
|
|
1055
|
+
]),
|
|
1056
|
+
status: ClosedEnum(["ok", "error"]),
|
|
1057
|
+
httpStatus: Type.Optional(Type.Integer({
|
|
1058
|
+
minimum: 100,
|
|
1059
|
+
maximum: 599
|
|
1060
|
+
})),
|
|
1061
|
+
durationMs: milliseconds(),
|
|
1062
|
+
tokens: TokenUsage,
|
|
1063
|
+
monetaryCost: MonetaryCost,
|
|
1064
|
+
quota: QuotaInfo,
|
|
1065
|
+
attempt: count$2(),
|
|
1066
|
+
error: Type.Optional(ErrorInfo)
|
|
1067
|
+
})),
|
|
1068
|
+
"context.built": durable(ContextBuiltPayload),
|
|
1069
|
+
"escalation.applied": durable(Type.Object({
|
|
1070
|
+
agent: AgentRef,
|
|
1071
|
+
step: EscalationStep,
|
|
1072
|
+
because: Type.String()
|
|
1073
|
+
}))
|
|
1074
|
+
};
|
|
1075
|
+
const Lock = Type.Object({
|
|
1076
|
+
scope: ClosedEnum([
|
|
1077
|
+
"project",
|
|
1078
|
+
"zone",
|
|
1079
|
+
"run",
|
|
1080
|
+
"integration",
|
|
1081
|
+
"slot"
|
|
1082
|
+
]),
|
|
1083
|
+
key: Type.String(),
|
|
1084
|
+
mode: ClosedEnum(["shared", "exclusive"]),
|
|
1085
|
+
owner: Type.String(),
|
|
1086
|
+
fencingToken: Type.Optional(count$2())
|
|
1087
|
+
});
|
|
1088
|
+
const GIT_EVENTS = {
|
|
1089
|
+
"git.worktree.created": durable(Type.Object({
|
|
1090
|
+
slot: Type.String(),
|
|
1091
|
+
path: Type.String(),
|
|
1092
|
+
branch: Type.String(),
|
|
1093
|
+
baseSha: Type.String(),
|
|
1094
|
+
effectId: EffectId
|
|
1095
|
+
})),
|
|
1096
|
+
"git.worktree.provisioned": durable(Type.Object({
|
|
1097
|
+
slot: Type.String(),
|
|
1098
|
+
lockfileSha256: Sha256,
|
|
1099
|
+
network: Type.Boolean(),
|
|
1100
|
+
effectId: EffectId
|
|
1101
|
+
})),
|
|
1102
|
+
"git.worktree.quarantined": durable(Type.Object({
|
|
1103
|
+
slot: Type.String(),
|
|
1104
|
+
resetTo: Type.String(),
|
|
1105
|
+
patch: ArtifactRef,
|
|
1106
|
+
compensated: Type.Array(EffectId)
|
|
1107
|
+
})),
|
|
1108
|
+
"git.worktree.removed": durable(Type.Object({
|
|
1109
|
+
slot: Type.String(),
|
|
1110
|
+
path: Type.String()
|
|
1111
|
+
})),
|
|
1112
|
+
"git.commit.created": durable(Type.Object({
|
|
1113
|
+
slot: Type.String(),
|
|
1114
|
+
branch: Type.String(),
|
|
1115
|
+
sha: Type.String(),
|
|
1116
|
+
kind: ClosedEnum(["result", "checkpoint"]),
|
|
1117
|
+
treeDigest: Type.String(),
|
|
1118
|
+
paths: Type.Array(Type.String()),
|
|
1119
|
+
effectId: EffectId
|
|
1120
|
+
})),
|
|
1121
|
+
"git.merge.completed": durable(Type.Object({
|
|
1122
|
+
from: Type.String(),
|
|
1123
|
+
into: Type.String(),
|
|
1124
|
+
mergeSha: Type.String(),
|
|
1125
|
+
treeDigest: Type.String(),
|
|
1126
|
+
effectId: EffectId
|
|
1127
|
+
})),
|
|
1128
|
+
"git.merge.conflicted": durable(Type.Object({
|
|
1129
|
+
from: Type.String(),
|
|
1130
|
+
into: Type.String(),
|
|
1131
|
+
files: Type.Array(Type.String())
|
|
1132
|
+
})),
|
|
1133
|
+
"repo.change.detected": durable(Type.Object({
|
|
1134
|
+
slot: Type.String(),
|
|
1135
|
+
expected: Type.String(),
|
|
1136
|
+
actual: Type.String(),
|
|
1137
|
+
files: Type.Array(FileTouch)
|
|
1138
|
+
})),
|
|
1139
|
+
"lock.acquired": durable(Lock),
|
|
1140
|
+
"lock.released": durable(Lock),
|
|
1141
|
+
"lock.stolen": durable(Lock)
|
|
1142
|
+
};
|
|
1143
|
+
//#endregion
|
|
1144
|
+
//#region ../../packages/protocol/src/commands.ts
|
|
1145
|
+
/** `inspect { kind: 'artifact' }`: default 1 MiB, cap 3 MiB, so the document stays under a 4 MiB one-shot client. */
|
|
1146
|
+
const INSPECT_ARTIFACT_DEFAULT_BYTES = 1048576;
|
|
1147
|
+
const INSPECT_ARTIFACT_MAX_BYTES = 3145728;
|
|
1148
|
+
const count$1 = () => Type.Integer({ minimum: 0 });
|
|
1149
|
+
const COMMAND_AUTH_SCHEMES = ["hmac-sha256"];
|
|
1150
|
+
/**
|
|
1151
|
+
* Scheme-neutral, so an asymmetric signature (ADR-0022 "Revisit") is a MINOR. V3.0: value = hex
|
|
1152
|
+
* HMAC-SHA256(projectKey, canonicalCommandBody(envelope)). An unknown scheme VALIDATES under the open schema:
|
|
1153
|
+
* refusing it (`security/command-auth-invalid`) is the host's job, not the parser's.
|
|
1154
|
+
*/
|
|
1155
|
+
const CommandAuth = Type.Object({
|
|
1156
|
+
scheme: OpenEnum(COMMAND_AUTH_SCHEMES),
|
|
1157
|
+
value: Type.String({ minLength: 1 })
|
|
1158
|
+
});
|
|
1159
|
+
const StartPayload = Type.Object({
|
|
1160
|
+
profile: PipelineProfile,
|
|
1161
|
+
spec: Type.Optional(Type.Union([Type.Object({ id: SpecId }), Type.Object({ path: Type.String() })])),
|
|
1162
|
+
reviewTarget: Type.Optional(Type.Union([
|
|
1163
|
+
Type.Object({ ref: Type.String() }),
|
|
1164
|
+
Type.Object({
|
|
1165
|
+
base: Type.String(),
|
|
1166
|
+
head: Type.String()
|
|
1167
|
+
}),
|
|
1168
|
+
Type.Object({ runId: RunId })
|
|
1169
|
+
])),
|
|
1170
|
+
withFix: Type.Optional(Type.Boolean()),
|
|
1171
|
+
phases: Type.Optional(Type.Array(ActivePipelineState)),
|
|
1172
|
+
/** keyed by role */
|
|
1173
|
+
modelOverrides: Type.Optional(Type.Record(Type.String(), ModelRef)),
|
|
1174
|
+
runtime: Type.Optional(Type.String()),
|
|
1175
|
+
fakeScript: Type.Optional(Type.String()),
|
|
1176
|
+
unattended: Type.Boolean(),
|
|
1177
|
+
budgets: Type.Optional(BudgetCounters),
|
|
1178
|
+
sandboxRequire: Type.Optional(ClosedEnum(["native", "best-effort"])),
|
|
1179
|
+
/** 2.10.1: `--trust-project-config` travels in the SIGNED start command, so the host's re-check sees the consent the CLI saw */
|
|
1180
|
+
consent: Type.Optional(Type.Object({
|
|
1181
|
+
policySha256: Sha256,
|
|
1182
|
+
via: Type.Literal("cli-flag")
|
|
1183
|
+
}))
|
|
1184
|
+
});
|
|
1185
|
+
const InspectPayload = Type.Object({ target: Type.Union([
|
|
1186
|
+
Type.Object({
|
|
1187
|
+
kind: Type.Literal("agent"),
|
|
1188
|
+
agentId: AgentId
|
|
1189
|
+
}),
|
|
1190
|
+
Type.Object({
|
|
1191
|
+
kind: Type.Literal("context"),
|
|
1192
|
+
agentId: AgentId,
|
|
1193
|
+
incarnation: count$1()
|
|
1194
|
+
}),
|
|
1195
|
+
Type.Object({
|
|
1196
|
+
kind: Type.Literal("approval"),
|
|
1197
|
+
approvalId: ApprovalId
|
|
1198
|
+
}),
|
|
1199
|
+
Type.Object({
|
|
1200
|
+
kind: Type.Literal("effect"),
|
|
1201
|
+
effectId: EffectId
|
|
1202
|
+
}),
|
|
1203
|
+
Type.Object({ kind: Type.Literal("snapshot") }),
|
|
1204
|
+
Type.Object({ kind: Type.Literal("locks") }),
|
|
1205
|
+
Type.Object({
|
|
1206
|
+
kind: Type.Literal("diff"),
|
|
1207
|
+
surface: Type.Optional(SurfaceId)
|
|
1208
|
+
}),
|
|
1209
|
+
Type.Object({
|
|
1210
|
+
kind: Type.Literal("artifact"),
|
|
1211
|
+
artifactId: ArtifactId,
|
|
1212
|
+
maxBytes: Type.Optional(Type.Integer({
|
|
1213
|
+
minimum: 1,
|
|
1214
|
+
maximum: INSPECT_ARTIFACT_MAX_BYTES,
|
|
1215
|
+
default: INSPECT_ARTIFACT_DEFAULT_BYTES
|
|
1216
|
+
})),
|
|
1217
|
+
offset: Type.Optional(count$1())
|
|
1218
|
+
})
|
|
1219
|
+
]) });
|
|
1220
|
+
const reader = (payload, route) => ({
|
|
1221
|
+
payload,
|
|
1222
|
+
route,
|
|
1223
|
+
authenticated: false,
|
|
1224
|
+
emitsResultEvent: false
|
|
1225
|
+
});
|
|
1226
|
+
const mutating = (payload, route) => ({
|
|
1227
|
+
payload,
|
|
1228
|
+
route: route ?? "inbox",
|
|
1229
|
+
authenticated: true,
|
|
1230
|
+
emitsResultEvent: true
|
|
1231
|
+
});
|
|
1232
|
+
const COMMANDS = {
|
|
1233
|
+
start: mutating(StartPayload, "start"),
|
|
1234
|
+
/** no runId => ProjectStatusDocument (R4 "current pipeline") */
|
|
1235
|
+
status: reader(Type.Object({ runId: Type.Optional(RunId) }), "direct-read"),
|
|
1236
|
+
inspect: reader(InspectPayload, "direct-read"),
|
|
1237
|
+
tail: reader(Type.Object({
|
|
1238
|
+
sinceSequence: Type.Optional(count$1()),
|
|
1239
|
+
replay: Type.Optional(count$1()),
|
|
1240
|
+
follow: Type.Boolean(),
|
|
1241
|
+
ephemeral: Type.Boolean()
|
|
1242
|
+
}), "direct-read"),
|
|
1243
|
+
pause: mutating(Type.Object({ reason: Type.Optional(Type.String()) })),
|
|
1244
|
+
resume: mutating(Type.Object({
|
|
1245
|
+
acknowledge: Type.Optional(Type.Literal("blocked-inspected")),
|
|
1246
|
+
raiseBudgets: Type.Optional(BudgetCounters),
|
|
1247
|
+
takeover: Type.Optional(Type.Boolean())
|
|
1248
|
+
})),
|
|
1249
|
+
cancel: mutating(Type.Object({
|
|
1250
|
+
reason: Type.Optional(Type.String()),
|
|
1251
|
+
keepWorktrees: Type.Boolean()
|
|
1252
|
+
})),
|
|
1253
|
+
approve: mutating(Type.Object({
|
|
1254
|
+
approvalId: ApprovalId,
|
|
1255
|
+
scope: ClosedEnum(["once", "run"]),
|
|
1256
|
+
/** required when the request carries `options`; must be one of them; echoed in the tool result */
|
|
1257
|
+
answer: Type.Optional(Type.String()),
|
|
1258
|
+
note: Type.Optional(Type.String())
|
|
1259
|
+
})),
|
|
1260
|
+
deny: mutating(Type.Object({
|
|
1261
|
+
approvalId: ApprovalId,
|
|
1262
|
+
note: Type.Optional(Type.String())
|
|
1263
|
+
})),
|
|
1264
|
+
retry: mutating(Type.Object({ target: Type.Union([Type.Object({
|
|
1265
|
+
kind: Type.Literal("phase"),
|
|
1266
|
+
state: Type.Optional(ActivePipelineState)
|
|
1267
|
+
}), Type.Object({
|
|
1268
|
+
kind: Type.Literal("agent"),
|
|
1269
|
+
agentId: AgentId
|
|
1270
|
+
})]) })),
|
|
1271
|
+
/** only if policy.skip lists that phase */
|
|
1272
|
+
skip: mutating(Type.Object({
|
|
1273
|
+
phase: ActivePipelineState,
|
|
1274
|
+
justification: Type.String({ minLength: 1 })
|
|
1275
|
+
})),
|
|
1276
|
+
/** admin; rejected unless policy.admin.runTool; still goes through the full gate chain */
|
|
1277
|
+
"run-tool": mutating(Type.Object({
|
|
1278
|
+
agentId: Type.Optional(AgentId),
|
|
1279
|
+
tool: Type.String({ minLength: 1 }),
|
|
1280
|
+
input: JsonValueSchema,
|
|
1281
|
+
justification: Type.String({ minLength: 1 })
|
|
1282
|
+
})),
|
|
1283
|
+
/** V3.0: 'plan' only */
|
|
1284
|
+
reconcile: reader(Type.Object({ mode: ClosedEnum(["plan", "apply"]) }), "cli-local"),
|
|
1285
|
+
shutdown: mutating(Type.Object({ graceMs: count$1() })),
|
|
1286
|
+
/** R11: optional, policy.steer.enabled, default false */
|
|
1287
|
+
"agent.send": mutating(Type.Object({
|
|
1288
|
+
agentId: AgentId,
|
|
1289
|
+
text: Type.String(),
|
|
1290
|
+
delivery: ClosedEnum(["steer", "follow-up"])
|
|
1291
|
+
}))
|
|
1292
|
+
};
|
|
1293
|
+
const COMMAND_TYPES = Object.keys(COMMANDS);
|
|
1294
|
+
Type.Object({
|
|
1295
|
+
protocolVersion: Type.Literal("1.0"),
|
|
1296
|
+
/** client-generated; THE idempotency key. Same id + same body = same outcome; same id + other body = conflict/command-id-reuse */
|
|
1297
|
+
commandId: CommandId,
|
|
1298
|
+
/** narrowed per command */
|
|
1299
|
+
type: Type.String({ minLength: 1 }),
|
|
1300
|
+
runId: Type.Optional(RunId),
|
|
1301
|
+
issuedAt: IsoInstant,
|
|
1302
|
+
actor: Actor,
|
|
1303
|
+
/** optimistic guard: reject if the run moved past this sequence */
|
|
1304
|
+
expectedSequence: Type.Optional(count$1()),
|
|
1305
|
+
/** narrowed per command */
|
|
1306
|
+
payload: Type.Unknown(),
|
|
1307
|
+
auth: Type.Optional(CommandAuth)
|
|
1308
|
+
});
|
|
1309
|
+
/**
|
|
1310
|
+
* The envelope MINUS `auth`, as canonical JSON: exactly what the authenticator covers, and the only thing `security`
|
|
1311
|
+
* ever sees of a command (it signs bytes, not envelopes). Key order never matters; every other field does.
|
|
1312
|
+
*/
|
|
1313
|
+
function canonicalCommandBody(envelope) {
|
|
1314
|
+
const { auth: _auth, ...body } = envelope;
|
|
1315
|
+
return canonicalJson(body);
|
|
1316
|
+
}
|
|
1317
|
+
/** Controller exit codes. 4 is not an error: the inbox is durable, the command is accepted but still pending at `--wait` expiry. */
|
|
1318
|
+
const CONTROLLER_EXIT_CODES = {
|
|
1319
|
+
completed: 0,
|
|
1320
|
+
usage: 2,
|
|
1321
|
+
rejected: 3,
|
|
1322
|
+
pending: 4
|
|
1323
|
+
};
|
|
1324
|
+
//#endregion
|
|
1325
|
+
//#region ../../packages/protocol/src/events/governance.ts
|
|
1326
|
+
const APPROVAL_DECISIONS = [
|
|
1327
|
+
"allow-once",
|
|
1328
|
+
"allow-for-run",
|
|
1329
|
+
"deny",
|
|
1330
|
+
"expired",
|
|
1331
|
+
"superseded"
|
|
1332
|
+
];
|
|
1333
|
+
const BUDGET_LEVELS = [
|
|
1334
|
+
"run",
|
|
1335
|
+
"phase",
|
|
1336
|
+
"agent",
|
|
1337
|
+
"provider",
|
|
1338
|
+
"tool"
|
|
1339
|
+
];
|
|
1340
|
+
const BUDGET_THRESHOLDS = [
|
|
1341
|
+
50,
|
|
1342
|
+
80,
|
|
1343
|
+
100
|
|
1344
|
+
];
|
|
1345
|
+
const BUDGET_COUNTER_NAMES = [
|
|
1346
|
+
"tokens",
|
|
1347
|
+
"modelRequests",
|
|
1348
|
+
"toolCalls",
|
|
1349
|
+
"wallClockMs",
|
|
1350
|
+
"retries",
|
|
1351
|
+
"fixRounds",
|
|
1352
|
+
"contextTokens",
|
|
1353
|
+
"concurrentAgents",
|
|
1354
|
+
"estimatedQuotaPercent"
|
|
1355
|
+
];
|
|
1356
|
+
const AUTH_REQUIRED_CAUSES = [
|
|
1357
|
+
"absent",
|
|
1358
|
+
"expired",
|
|
1359
|
+
"refresh-failed",
|
|
1360
|
+
"revoked",
|
|
1361
|
+
"entitlement",
|
|
1362
|
+
"mode-mismatch",
|
|
1363
|
+
"ambient-source"
|
|
1364
|
+
];
|
|
1365
|
+
const RETRY_TARGET_KINDS = [
|
|
1366
|
+
"agent",
|
|
1367
|
+
"model-request",
|
|
1368
|
+
"tool",
|
|
1369
|
+
"phase"
|
|
1370
|
+
];
|
|
1371
|
+
const BudgetScope = Type.Object({
|
|
1372
|
+
level: ClosedEnum(BUDGET_LEVELS),
|
|
1373
|
+
id: Type.String()
|
|
1374
|
+
});
|
|
1375
|
+
/** A MINOR may add commands (2.3.2), so the `type` a command event names is open on the wire. */
|
|
1376
|
+
const CommandTypeName = OpenEnum(COMMAND_TYPES);
|
|
1377
|
+
/** Exported because `inspect { kind: 'approval' }` returns this payload as the decision (R6). */
|
|
1378
|
+
const ApprovalResolvedPayload = Type.Object({
|
|
1379
|
+
approvalId: ApprovalId,
|
|
1380
|
+
decision: ClosedEnum(APPROVAL_DECISIONS),
|
|
1381
|
+
actor: Actor,
|
|
1382
|
+
commandId: Type.Optional(CommandId),
|
|
1383
|
+
/** the authenticator of the approve / deny command, copied so that the decision stays verifiable from the journal */
|
|
1384
|
+
commandAuth: Type.Optional(CommandAuth),
|
|
1385
|
+
grantId: Type.Optional(Type.String()),
|
|
1386
|
+
/** one of `ApprovalRequest.options` */
|
|
1387
|
+
answer: Type.Optional(Type.String()),
|
|
1388
|
+
note: Type.Optional(Type.String())
|
|
1389
|
+
});
|
|
1390
|
+
const GOVERNANCE_EVENTS = {
|
|
1391
|
+
/** R6 */
|
|
1392
|
+
"approval.requested": durable(ApprovalRequest),
|
|
1393
|
+
"approval.resolved": durable(ApprovalResolvedPayload),
|
|
1394
|
+
/** coalesced: thresholds + at most 1 per 5 s per scope */
|
|
1395
|
+
"budget.updated": durable(Type.Object({
|
|
1396
|
+
scope: BudgetScope,
|
|
1397
|
+
consumed: BudgetCounters,
|
|
1398
|
+
limit: BudgetCounters,
|
|
1399
|
+
threshold: Type.Optional(Type.Unsafe({
|
|
1400
|
+
type: "integer",
|
|
1401
|
+
enum: [...BUDGET_THRESHOLDS]
|
|
1402
|
+
}))
|
|
1403
|
+
})),
|
|
1404
|
+
"budget.exceeded": durable(Type.Object({
|
|
1405
|
+
scope: BudgetScope,
|
|
1406
|
+
counter: ClosedEnum(BUDGET_COUNTER_NAMES),
|
|
1407
|
+
limit: Type.Number({ minimum: 0 }),
|
|
1408
|
+
consumed: Type.Number({ minimum: 0 })
|
|
1409
|
+
})),
|
|
1410
|
+
/** on change only */
|
|
1411
|
+
"quota.updated": durable(Type.Object({
|
|
1412
|
+
provider: Type.String(),
|
|
1413
|
+
authMode: AuthMode,
|
|
1414
|
+
quota: QuotaInfo
|
|
1415
|
+
})),
|
|
1416
|
+
"auth.required": durable(Type.Object({
|
|
1417
|
+
provider: Type.String(),
|
|
1418
|
+
cause: ClosedEnum(AUTH_REQUIRED_CAUSES),
|
|
1419
|
+
cli: Type.String()
|
|
1420
|
+
})),
|
|
1421
|
+
"retry.scheduled": durable(Type.Object({
|
|
1422
|
+
target: Type.Object({
|
|
1423
|
+
kind: ClosedEnum(RETRY_TARGET_KINDS),
|
|
1424
|
+
id: Type.String()
|
|
1425
|
+
}),
|
|
1426
|
+
attempt: count$2(),
|
|
1427
|
+
maxAttempts: count$2(),
|
|
1428
|
+
delayMs: milliseconds(),
|
|
1429
|
+
cause: ErrorInfo
|
|
1430
|
+
})),
|
|
1431
|
+
/** `actor` as normalised by the host (2.6.7). An accepted command was authenticated: `authVerified` has one value. */
|
|
1432
|
+
"command.accepted": durable(Type.Object({
|
|
1433
|
+
commandId: CommandId,
|
|
1434
|
+
type: CommandTypeName,
|
|
1435
|
+
actor: Actor,
|
|
1436
|
+
authVerified: Type.Literal(true),
|
|
1437
|
+
scheme: OpenEnum(COMMAND_AUTH_SCHEMES)
|
|
1438
|
+
})),
|
|
1439
|
+
"command.completed": durable(Type.Object({
|
|
1440
|
+
commandId: CommandId,
|
|
1441
|
+
type: CommandTypeName,
|
|
1442
|
+
result: JsonValueSchema
|
|
1443
|
+
})),
|
|
1444
|
+
"command.rejected": durable(Type.Object({
|
|
1445
|
+
commandId: CommandId,
|
|
1446
|
+
type: CommandTypeName,
|
|
1447
|
+
error: ErrorInfo
|
|
1448
|
+
}))
|
|
1449
|
+
};
|
|
1450
|
+
const RUN_EVENTS = {
|
|
1451
|
+
"pipeline.started": durable(Type.Object({
|
|
1452
|
+
profile: PipelineProfile,
|
|
1453
|
+
tableVersion: count$2(),
|
|
1454
|
+
spec: Type.Object({
|
|
1455
|
+
id: SpecId,
|
|
1456
|
+
sha256: Sha256,
|
|
1457
|
+
kind: ClosedEnum([
|
|
1458
|
+
"feature",
|
|
1459
|
+
"patch",
|
|
1460
|
+
"review"
|
|
1461
|
+
])
|
|
1462
|
+
}),
|
|
1463
|
+
snapshotDigest: Sha256,
|
|
1464
|
+
runtime: Type.Object({
|
|
1465
|
+
id: Type.String(),
|
|
1466
|
+
version: Type.String(),
|
|
1467
|
+
pinDigest: Type.String()
|
|
1468
|
+
}),
|
|
1469
|
+
plan: RunPlan,
|
|
1470
|
+
base: Type.Object({
|
|
1471
|
+
branch: Type.String(),
|
|
1472
|
+
sha: Type.String()
|
|
1473
|
+
}),
|
|
1474
|
+
integrationBranch: Type.String(),
|
|
1475
|
+
cohorteVersion: Type.String(),
|
|
1476
|
+
hostId: Type.String()
|
|
1477
|
+
})),
|
|
1478
|
+
"pipeline.completed": durable(Type.Object({
|
|
1479
|
+
stop: StopRecord,
|
|
1480
|
+
integration: Type.Object({
|
|
1481
|
+
branch: Type.String(),
|
|
1482
|
+
headSha: Type.String(),
|
|
1483
|
+
treeDigest: Type.String()
|
|
1484
|
+
}),
|
|
1485
|
+
totals: Type.Object({
|
|
1486
|
+
usage: BudgetCounters,
|
|
1487
|
+
tokens: TokenUsage,
|
|
1488
|
+
monetaryCost: MonetaryCost,
|
|
1489
|
+
fixRounds: count$2(),
|
|
1490
|
+
durationMs: milliseconds()
|
|
1491
|
+
})
|
|
1492
|
+
})),
|
|
1493
|
+
"pipeline.failed": durable(Type.Object({
|
|
1494
|
+
state: HaltedState,
|
|
1495
|
+
error: ErrorInfo,
|
|
1496
|
+
stop: StopRecord,
|
|
1497
|
+
checkpointSequence: count$2()
|
|
1498
|
+
})),
|
|
1499
|
+
"run.state.changed": durable(Type.Object({
|
|
1500
|
+
transitionId: Type.String(),
|
|
1501
|
+
defId: Type.String(),
|
|
1502
|
+
tableVersion: count$2(),
|
|
1503
|
+
from: PipelineState,
|
|
1504
|
+
to: PipelineState,
|
|
1505
|
+
reason: TransitionReason,
|
|
1506
|
+
actor: Actor,
|
|
1507
|
+
guards: Type.Array(GuardOutcome),
|
|
1508
|
+
idempotencyKey: Type.String(),
|
|
1509
|
+
resumeTo: Type.Optional(ActivePipelineState),
|
|
1510
|
+
stop: Type.Optional(StopRecord)
|
|
1511
|
+
})),
|
|
1512
|
+
"run.paused": durable(Type.Object({
|
|
1513
|
+
commandId: Type.Optional(CommandId),
|
|
1514
|
+
parkedAgents: Type.Array(AgentId),
|
|
1515
|
+
inFlightEffects: Type.Array(EffectId)
|
|
1516
|
+
})),
|
|
1517
|
+
"run.resumed": durable(Type.Object({
|
|
1518
|
+
commandId: Type.Optional(CommandId),
|
|
1519
|
+
mode: ClosedEnum([
|
|
1520
|
+
"unpause",
|
|
1521
|
+
"recovery",
|
|
1522
|
+
"retry"
|
|
1523
|
+
]),
|
|
1524
|
+
report: ResumeReport
|
|
1525
|
+
})),
|
|
1526
|
+
"run.cancelled": durable(Type.Object({
|
|
1527
|
+
commandId: Type.Optional(CommandId),
|
|
1528
|
+
reason: Type.String(),
|
|
1529
|
+
cancelledAgents: Type.Array(AgentId),
|
|
1530
|
+
worktreesKept: Type.Boolean()
|
|
1531
|
+
})),
|
|
1532
|
+
"run.host.attached": durable(Type.Object({
|
|
1533
|
+
hostId: Type.String(),
|
|
1534
|
+
pid: count$2(),
|
|
1535
|
+
cohorteVersion: Type.String(),
|
|
1536
|
+
fencingToken: count$2(),
|
|
1537
|
+
takeover: Type.Boolean()
|
|
1538
|
+
})),
|
|
1539
|
+
"run.host.detached": durable(Type.Object({
|
|
1540
|
+
hostId: Type.String(),
|
|
1541
|
+
cause: ClosedEnum([
|
|
1542
|
+
"exit",
|
|
1543
|
+
"signal",
|
|
1544
|
+
"lease-lost",
|
|
1545
|
+
"shutdown-command",
|
|
1546
|
+
"fatal"
|
|
1547
|
+
])
|
|
1548
|
+
})),
|
|
1549
|
+
"phase.started": durable(Type.Object({
|
|
1550
|
+
phase: PhaseRef,
|
|
1551
|
+
contractId: Type.String(),
|
|
1552
|
+
/** PhaseContract.version (DESIGN 2.5.2): a number */
|
|
1553
|
+
contractVersion: count$2(),
|
|
1554
|
+
planned: Type.Array(Type.Object({
|
|
1555
|
+
agentId: AgentId,
|
|
1556
|
+
role: Type.String(),
|
|
1557
|
+
surface: Type.Optional(SurfaceId)
|
|
1558
|
+
})),
|
|
1559
|
+
budget: BudgetCounters
|
|
1560
|
+
})),
|
|
1561
|
+
"phase.completed": durable(Type.Object({
|
|
1562
|
+
phase: PhaseRef,
|
|
1563
|
+
outcome: ClosedEnum([
|
|
1564
|
+
"passed",
|
|
1565
|
+
"failed",
|
|
1566
|
+
"needs-human",
|
|
1567
|
+
"skipped"
|
|
1568
|
+
]),
|
|
1569
|
+
outputs: Type.Array(ArtifactRef),
|
|
1570
|
+
checks: Type.Array(CheckResult),
|
|
1571
|
+
durationMs: milliseconds()
|
|
1572
|
+
})),
|
|
1573
|
+
"check.started": durable(Type.Object({
|
|
1574
|
+
name: Type.String(),
|
|
1575
|
+
argv: Type.Array(Type.String()),
|
|
1576
|
+
slot: Type.String()
|
|
1577
|
+
})),
|
|
1578
|
+
"check.completed": durable(CheckResult),
|
|
1579
|
+
error: durable(Type.Object({
|
|
1580
|
+
error: ErrorInfo,
|
|
1581
|
+
fatal: Type.Boolean()
|
|
1582
|
+
})),
|
|
1583
|
+
"checkpoint.created": durable(Type.Object({
|
|
1584
|
+
atSequence: count$2(),
|
|
1585
|
+
snapshotSha256: Sha256,
|
|
1586
|
+
chainHash: Type.String(),
|
|
1587
|
+
chainMac: Type.String(),
|
|
1588
|
+
cause: ClosedEnum([
|
|
1589
|
+
"phase-boundary",
|
|
1590
|
+
"interval",
|
|
1591
|
+
"pause",
|
|
1592
|
+
"shutdown",
|
|
1593
|
+
"pre-effect",
|
|
1594
|
+
"fatal"
|
|
1595
|
+
])
|
|
1596
|
+
}))
|
|
1597
|
+
};
|
|
1598
|
+
//#endregion
|
|
1599
|
+
//#region ../../packages/protocol/src/documents.ts
|
|
1600
|
+
const count = () => Type.Integer({ minimum: 0 });
|
|
1601
|
+
const documentVersion = () => Type.Literal(1);
|
|
1602
|
+
const protocolVersion = () => Type.Literal("1.0");
|
|
1603
|
+
const BILLING = ["plan-limits", "metered"];
|
|
1604
|
+
const ApprovalView = Type.Object({
|
|
1605
|
+
approvalId: ApprovalId,
|
|
1606
|
+
kind: Type.String(),
|
|
1607
|
+
agentId: Type.Optional(AgentId),
|
|
1608
|
+
/** sealed */
|
|
1609
|
+
what: Type.String({ maxLength: 512 }),
|
|
1610
|
+
since: IsoInstant,
|
|
1611
|
+
expiresAt: Type.Optional(IsoInstant),
|
|
1612
|
+
cli: Type.String()
|
|
1613
|
+
});
|
|
1614
|
+
const AgentNode = Type.Object({
|
|
1615
|
+
agentId: AgentId,
|
|
1616
|
+
role: Type.String(),
|
|
1617
|
+
surface: Type.Optional(SurfaceId),
|
|
1618
|
+
label: Type.String(),
|
|
1619
|
+
status: NodeStatus,
|
|
1620
|
+
lifecycle: AgentState,
|
|
1621
|
+
attempt: count(),
|
|
1622
|
+
incarnation: count(),
|
|
1623
|
+
model: Type.Object({
|
|
1624
|
+
requested: ModelRef,
|
|
1625
|
+
effective: Type.Optional(Type.Object({
|
|
1626
|
+
provider: Type.String(),
|
|
1627
|
+
model: Type.String()
|
|
1628
|
+
}))
|
|
1629
|
+
}),
|
|
1630
|
+
authMode: Type.Optional(AuthMode),
|
|
1631
|
+
worktree: Type.Optional(Type.String()),
|
|
1632
|
+
usage: BudgetCounters,
|
|
1633
|
+
summary: Type.Optional(Type.String()),
|
|
1634
|
+
lastError: Type.Optional(ErrorInfo),
|
|
1635
|
+
pendingApproval: Type.Optional(ApprovalId),
|
|
1636
|
+
/** R8: optional and opaque */
|
|
1637
|
+
runtimeRef: Type.Optional(RuntimeRef)
|
|
1638
|
+
});
|
|
1639
|
+
const PhaseNode = Type.Object({
|
|
1640
|
+
state: ActivePipelineState,
|
|
1641
|
+
label: Type.String(),
|
|
1642
|
+
status: NodeStatus,
|
|
1643
|
+
runs: Type.Array(Type.Object({
|
|
1644
|
+
phaseRunId: PhaseRunId,
|
|
1645
|
+
iteration: count(),
|
|
1646
|
+
status: NodeStatus,
|
|
1647
|
+
startedAt: Type.Optional(IsoInstant),
|
|
1648
|
+
endedAt: Type.Optional(IsoInstant),
|
|
1649
|
+
outcome: Type.Optional(Type.String()),
|
|
1650
|
+
agents: Type.Array(AgentNode),
|
|
1651
|
+
checks: Type.Array(CheckResult)
|
|
1652
|
+
}))
|
|
1653
|
+
});
|
|
1654
|
+
const RunNode = Type.Object({
|
|
1655
|
+
runId: RunId,
|
|
1656
|
+
profile: PipelineProfile,
|
|
1657
|
+
title: Type.String(),
|
|
1658
|
+
spec: Type.Object({
|
|
1659
|
+
id: SpecId,
|
|
1660
|
+
kind: Type.String(),
|
|
1661
|
+
sha256: Sha256
|
|
1662
|
+
}),
|
|
1663
|
+
state: PipelineState,
|
|
1664
|
+
status: NodeStatus,
|
|
1665
|
+
since: IsoInstant,
|
|
1666
|
+
resumeTo: Type.Optional(ActivePipelineState),
|
|
1667
|
+
stop: Type.Optional(StopRecord),
|
|
1668
|
+
lastError: Type.Optional(ErrorInfo),
|
|
1669
|
+
iteration: Type.Object({
|
|
1670
|
+
fixRounds: count(),
|
|
1671
|
+
maxFixRounds: count(),
|
|
1672
|
+
reviewRounds: count()
|
|
1673
|
+
}),
|
|
1674
|
+
host: Type.Object({
|
|
1675
|
+
hostId: Type.Optional(Type.String()),
|
|
1676
|
+
alive: Type.Boolean(),
|
|
1677
|
+
heartbeatAt: Type.Optional(IsoInstant),
|
|
1678
|
+
pid: Type.Optional(count())
|
|
1679
|
+
}),
|
|
1680
|
+
git: Type.Object({
|
|
1681
|
+
base: Type.Object({
|
|
1682
|
+
branch: Type.String(),
|
|
1683
|
+
sha: Type.String()
|
|
1684
|
+
}),
|
|
1685
|
+
integrationBranch: Type.String(),
|
|
1686
|
+
integrationHead: Type.Optional(Type.String()),
|
|
1687
|
+
approvedTreeDigest: Type.Optional(Type.String())
|
|
1688
|
+
}),
|
|
1689
|
+
plan: RunPlan,
|
|
1690
|
+
snapshotDigest: Sha256,
|
|
1691
|
+
startedAt: IsoInstant,
|
|
1692
|
+
endedAt: Type.Optional(IsoInstant)
|
|
1693
|
+
});
|
|
1694
|
+
/** `cohorte status <run> --json`, `inspect { kind: 'snapshot' }`, and the first line of every stream (R2). */
|
|
1695
|
+
const RunSnapshotDocument = Type.Object({
|
|
1696
|
+
documentVersion: documentVersion(),
|
|
1697
|
+
protocolVersion: protocolVersion(),
|
|
1698
|
+
cohorteVersion: Type.String(),
|
|
1699
|
+
generatedAt: IsoInstant,
|
|
1700
|
+
lastSequence: count(),
|
|
1701
|
+
run: RunNode,
|
|
1702
|
+
/** table order for the profile, not-yet-run phases as 'pending' */
|
|
1703
|
+
phases: Type.Array(PhaseNode),
|
|
1704
|
+
approvals: Type.Object({
|
|
1705
|
+
pending: Type.Array(ApprovalView),
|
|
1706
|
+
resolved: count()
|
|
1707
|
+
}),
|
|
1708
|
+
budgets: Type.Array(Type.Object({
|
|
1709
|
+
scope: Type.Object({
|
|
1710
|
+
level: Type.String(),
|
|
1711
|
+
id: Type.String()
|
|
1712
|
+
}),
|
|
1713
|
+
consumed: BudgetCounters,
|
|
1714
|
+
limit: BudgetCounters
|
|
1715
|
+
})),
|
|
1716
|
+
usage: Type.Object({
|
|
1717
|
+
tokens: TokenUsage,
|
|
1718
|
+
monetaryCost: MonetaryCost,
|
|
1719
|
+
byProvider: Type.Array(Type.Object({
|
|
1720
|
+
provider: Type.String(),
|
|
1721
|
+
authMode: AuthMode,
|
|
1722
|
+
billing: ClosedEnum(BILLING),
|
|
1723
|
+
tokens: TokenUsage,
|
|
1724
|
+
quota: QuotaInfo,
|
|
1725
|
+
accountLabel: Type.Optional(Type.String())
|
|
1726
|
+
}))
|
|
1727
|
+
}),
|
|
1728
|
+
locks: Type.Array(Type.Object({
|
|
1729
|
+
scope: Type.String(),
|
|
1730
|
+
key: Type.String(),
|
|
1731
|
+
mode: Type.String()
|
|
1732
|
+
})),
|
|
1733
|
+
inDoubtEffects: Type.Array(EffectId)
|
|
1734
|
+
});
|
|
1735
|
+
/**
|
|
1736
|
+
* One row of `ProjectStatusDocument.runs`: a PROJECTION of `RunSnapshotDocument.run`, never a second definition.
|
|
1737
|
+
*
|
|
1738
|
+
* KEEP THE EXPLICIT ANNOTATION. Biome 2.5.14 overflows its stack when it has to INFER the type of this pick, in every
|
|
1739
|
+
* file that names the const, and then exits 0 having linted nothing (docs/v3/requests/U0.02.md R1).
|
|
1740
|
+
*/
|
|
1741
|
+
const ProjectRunSummary = Type.Unsafe(Type.Pick(RunNode, [
|
|
1742
|
+
"runId",
|
|
1743
|
+
"profile",
|
|
1744
|
+
"title",
|
|
1745
|
+
"state",
|
|
1746
|
+
"status",
|
|
1747
|
+
"since",
|
|
1748
|
+
"startedAt",
|
|
1749
|
+
"endedAt",
|
|
1750
|
+
"stop"
|
|
1751
|
+
]));
|
|
1752
|
+
/** `cohorte status --json` without a run: the "current pipeline" of R4. */
|
|
1753
|
+
const ProjectStatusDocument = Type.Object({
|
|
1754
|
+
documentVersion: documentVersion(),
|
|
1755
|
+
protocolVersion: protocolVersion(),
|
|
1756
|
+
project: Type.Object({
|
|
1757
|
+
id: Type.String(),
|
|
1758
|
+
root: Type.String()
|
|
1759
|
+
}),
|
|
1760
|
+
runs: Type.Array(ProjectRunSummary),
|
|
1761
|
+
pendingApprovals: Type.Array(ApprovalView)
|
|
1762
|
+
});
|
|
1763
|
+
/** spec 17.1 "diffs"; `cohorte diff --json`. A patch is fetched with `inspect { kind: 'artifact' }`. */
|
|
1764
|
+
const RunDiffDocument = Type.Object({
|
|
1765
|
+
documentVersion: documentVersion(),
|
|
1766
|
+
runId: RunId,
|
|
1767
|
+
base: Type.Object({
|
|
1768
|
+
branch: Type.String(),
|
|
1769
|
+
sha: Type.String()
|
|
1770
|
+
}),
|
|
1771
|
+
head: Type.Object({
|
|
1772
|
+
branch: Type.String(),
|
|
1773
|
+
sha: Type.String(),
|
|
1774
|
+
treeDigest: Type.String()
|
|
1775
|
+
}),
|
|
1776
|
+
surfaces: Type.Array(Type.Object({
|
|
1777
|
+
surface: Type.Union([Type.Literal("shared"), SurfaceId]),
|
|
1778
|
+
files: Type.Array(FileTouch),
|
|
1779
|
+
stat: Type.Object({
|
|
1780
|
+
added: count(),
|
|
1781
|
+
removed: count()
|
|
1782
|
+
}),
|
|
1783
|
+
patch: ArtifactRef
|
|
1784
|
+
}))
|
|
1785
|
+
});
|
|
1786
|
+
/**
|
|
1787
|
+
* The artifact window is capped in BYTES by the command (`maxBytes` <= INSPECT_ARTIFACT_MAX_BYTES). `content` is
|
|
1788
|
+
* those bytes as utf8 (never more characters than bytes) or as base64 (4 characters per 3 bytes): the base64 length
|
|
1789
|
+
* of the byte cap bounds both.
|
|
1790
|
+
*/
|
|
1791
|
+
const INSPECT_ARTIFACT_MAX_CONTENT_LENGTH = 4 * Math.ceil(INSPECT_ARTIFACT_MAX_BYTES / 3);
|
|
1792
|
+
const inspectHeader = () => ({
|
|
1793
|
+
documentVersion: documentVersion(),
|
|
1794
|
+
protocolVersion: protocolVersion(),
|
|
1795
|
+
runId: RunId,
|
|
1796
|
+
lastSequence: count()
|
|
1797
|
+
});
|
|
1798
|
+
/** Keyed by the published file name: `schemas/<name>.schema.json` (DESIGN 7.5 AC-07 lists them). */
|
|
1799
|
+
const DOCUMENTS = {
|
|
1800
|
+
"run-state": RunSnapshotDocument,
|
|
1801
|
+
"project-status": ProjectStatusDocument,
|
|
1802
|
+
inspect: Type.Union([
|
|
1803
|
+
Type.Object({
|
|
1804
|
+
...inspectHeader(),
|
|
1805
|
+
kind: Type.Literal("agent"),
|
|
1806
|
+
agent: AgentNode,
|
|
1807
|
+
grantsDigest: Sha256,
|
|
1808
|
+
tools: Type.Array(Type.String()),
|
|
1809
|
+
incarnations: Type.Array(Type.Object({
|
|
1810
|
+
n: count(),
|
|
1811
|
+
state: Type.String(),
|
|
1812
|
+
startedAt: Type.Optional(IsoInstant),
|
|
1813
|
+
endedAt: Type.Optional(IsoInstant),
|
|
1814
|
+
stop: Type.Optional(Type.String()),
|
|
1815
|
+
reason: Type.Optional(Type.String())
|
|
1816
|
+
}))
|
|
1817
|
+
}),
|
|
1818
|
+
Type.Object({
|
|
1819
|
+
...inspectHeader(),
|
|
1820
|
+
kind: Type.Literal("context"),
|
|
1821
|
+
agentId: AgentId,
|
|
1822
|
+
incarnation: count(),
|
|
1823
|
+
context: ContextBuiltPayload
|
|
1824
|
+
}),
|
|
1825
|
+
Type.Object({
|
|
1826
|
+
...inspectHeader(),
|
|
1827
|
+
kind: Type.Literal("approval"),
|
|
1828
|
+
request: ApprovalRequest,
|
|
1829
|
+
status: Type.String(),
|
|
1830
|
+
decision: Type.Optional(ApprovalResolvedPayload)
|
|
1831
|
+
}),
|
|
1832
|
+
Type.Object({
|
|
1833
|
+
...inspectHeader(),
|
|
1834
|
+
kind: Type.Literal("effect"),
|
|
1835
|
+
effect: Type.Object({
|
|
1836
|
+
effectId: EffectId,
|
|
1837
|
+
kind: Type.String(),
|
|
1838
|
+
replayClass: Type.String(),
|
|
1839
|
+
state: Type.String(),
|
|
1840
|
+
toolCallId: Type.Optional(ToolCallId),
|
|
1841
|
+
slot: Type.Optional(Type.String()),
|
|
1842
|
+
request: JsonValueSchema,
|
|
1843
|
+
result: Type.Optional(JsonValueSchema),
|
|
1844
|
+
error: Type.Optional(ErrorInfo)
|
|
1845
|
+
})
|
|
1846
|
+
}),
|
|
1847
|
+
Type.Object({
|
|
1848
|
+
...inspectHeader(),
|
|
1849
|
+
kind: Type.Literal("snapshot"),
|
|
1850
|
+
document: RunSnapshotDocument
|
|
1851
|
+
}),
|
|
1852
|
+
Type.Object({
|
|
1853
|
+
...inspectHeader(),
|
|
1854
|
+
kind: Type.Literal("locks"),
|
|
1855
|
+
locks: Type.Array(Type.Object({
|
|
1856
|
+
scope: Type.String(),
|
|
1857
|
+
key: Type.String(),
|
|
1858
|
+
mode: Type.String(),
|
|
1859
|
+
owner: Type.String(),
|
|
1860
|
+
leaseExpiresAt: IsoInstant
|
|
1861
|
+
}))
|
|
1862
|
+
}),
|
|
1863
|
+
Type.Object({
|
|
1864
|
+
...inspectHeader(),
|
|
1865
|
+
kind: Type.Literal("diff"),
|
|
1866
|
+
diff: RunDiffDocument
|
|
1867
|
+
}),
|
|
1868
|
+
Type.Object({
|
|
1869
|
+
...inspectHeader(),
|
|
1870
|
+
kind: Type.Literal("artifact"),
|
|
1871
|
+
artifact: ArtifactRef,
|
|
1872
|
+
offset: count(),
|
|
1873
|
+
bytes: Type.Integer({
|
|
1874
|
+
minimum: 0,
|
|
1875
|
+
maximum: INSPECT_ARTIFACT_MAX_BYTES
|
|
1876
|
+
}),
|
|
1877
|
+
truncated: Type.Boolean(),
|
|
1878
|
+
encoding: ClosedEnum(["utf8", "base64"]),
|
|
1879
|
+
/** sealed at write time */
|
|
1880
|
+
content: Type.String({ maxLength: INSPECT_ARTIFACT_MAX_CONTENT_LENGTH })
|
|
1881
|
+
})
|
|
1882
|
+
]),
|
|
1883
|
+
"run-diff": RunDiffDocument,
|
|
1884
|
+
"command-result": Type.Object({
|
|
1885
|
+
documentVersion: documentVersion(),
|
|
1886
|
+
commandId: CommandId,
|
|
1887
|
+
/** open on the wire: a MINOR may add commands */
|
|
1888
|
+
type: OpenEnum(COMMAND_TYPES),
|
|
1889
|
+
status: ClosedEnum([
|
|
1890
|
+
"completed",
|
|
1891
|
+
"rejected",
|
|
1892
|
+
"pending"
|
|
1893
|
+
]),
|
|
1894
|
+
result: Type.Optional(JsonValueSchema),
|
|
1895
|
+
error: Type.Optional(ErrorInfo),
|
|
1896
|
+
lastSequence: Type.Optional(count())
|
|
1897
|
+
}),
|
|
1898
|
+
"doctor-report": Type.Object({
|
|
1899
|
+
documentVersion: documentVersion(),
|
|
1900
|
+
cohorteVersion: Type.String(),
|
|
1901
|
+
generatedAt: IsoInstant,
|
|
1902
|
+
ok: Type.Boolean(),
|
|
1903
|
+
checks: Type.Array(Type.Object({
|
|
1904
|
+
id: Type.String(),
|
|
1905
|
+
status: OpenEnum([
|
|
1906
|
+
"ok",
|
|
1907
|
+
"warning",
|
|
1908
|
+
"error",
|
|
1909
|
+
"skipped"
|
|
1910
|
+
]),
|
|
1911
|
+
summary: Type.String(),
|
|
1912
|
+
detail: Type.Optional(Type.String()),
|
|
1913
|
+
remediation: Type.Optional(Type.String())
|
|
1914
|
+
})),
|
|
1915
|
+
sandbox: JsonValueSchema,
|
|
1916
|
+
runtimeCapabilities: JsonValueSchema
|
|
1917
|
+
}),
|
|
1918
|
+
"auth-status": Type.Object({
|
|
1919
|
+
documentVersion: documentVersion(),
|
|
1920
|
+
generatedAt: IsoInstant,
|
|
1921
|
+
runtime: Type.Object({
|
|
1922
|
+
id: Type.String(),
|
|
1923
|
+
version: Type.String()
|
|
1924
|
+
}),
|
|
1925
|
+
providers: Type.Array(Type.Object({
|
|
1926
|
+
provider: Type.String(),
|
|
1927
|
+
state: Type.String(),
|
|
1928
|
+
subscription: Type.Boolean(),
|
|
1929
|
+
billing: ClosedEnum([...BILLING, "unknown"]),
|
|
1930
|
+
source: Type.Optional(Type.String()),
|
|
1931
|
+
accountLabel: Type.Optional(Type.String()),
|
|
1932
|
+
accountLabelNote: Type.Optional(Type.String()),
|
|
1933
|
+
caveat: Type.Optional(Type.String()),
|
|
1934
|
+
checkedAt: IsoInstant
|
|
1935
|
+
}))
|
|
1936
|
+
})
|
|
1937
|
+
};
|
|
1938
|
+
Object.keys(DOCUMENTS);
|
|
1939
|
+
//#endregion
|
|
1940
|
+
//#region ../../packages/protocol/src/events/stream.ts
|
|
1941
|
+
const STREAM_EVENTS = {
|
|
1942
|
+
/** synthetic first line of every stream: a late client gets this, then the durable events after `lastSequence` */
|
|
1943
|
+
snapshot: ephemeral(Type.Object({
|
|
1944
|
+
document: RunSnapshotDocument,
|
|
1945
|
+
lastSequence: count$2()
|
|
1946
|
+
})),
|
|
1947
|
+
/** every 15 s on `--follow` */
|
|
1948
|
+
heartbeat: ephemeral(Type.Object({
|
|
1949
|
+
hostAlive: Type.Boolean(),
|
|
1950
|
+
lastSequence: count$2()
|
|
1951
|
+
}))
|
|
1952
|
+
};
|
|
1953
|
+
//#endregion
|
|
1954
|
+
//#region ../../packages/protocol/src/events/tool.ts
|
|
1955
|
+
const TOOL_DENIAL_STAGES = [
|
|
1956
|
+
"liveness",
|
|
1957
|
+
"schema",
|
|
1958
|
+
"capability",
|
|
1959
|
+
"path",
|
|
1960
|
+
"command",
|
|
1961
|
+
"network",
|
|
1962
|
+
"budget",
|
|
1963
|
+
"approval"
|
|
1964
|
+
];
|
|
1965
|
+
const TOOL_REJECTION_CAUSES = [
|
|
1966
|
+
"unknown-tool",
|
|
1967
|
+
"invalid-input",
|
|
1968
|
+
"output-truncated"
|
|
1969
|
+
];
|
|
1970
|
+
const TOOL_DECISIONS = [
|
|
1971
|
+
"allow",
|
|
1972
|
+
"allow-once",
|
|
1973
|
+
"allow-for-run"
|
|
1974
|
+
];
|
|
1975
|
+
const FINDING_DISPOSITIONS = [
|
|
1976
|
+
"kept",
|
|
1977
|
+
"refuted",
|
|
1978
|
+
"deferred",
|
|
1979
|
+
"needs-investigation",
|
|
1980
|
+
"duplicate"
|
|
1981
|
+
];
|
|
1982
|
+
const FileAccess = Type.Object({
|
|
1983
|
+
toolCallId: ToolCallId,
|
|
1984
|
+
file: FileTouch,
|
|
1985
|
+
diffStat: Type.Optional(Type.Object({
|
|
1986
|
+
added: count$2(),
|
|
1987
|
+
removed: count$2()
|
|
1988
|
+
}))
|
|
1989
|
+
});
|
|
1990
|
+
const TOOL_EVENTS = {
|
|
1991
|
+
/** `args` is sealed */
|
|
1992
|
+
"tool.requested": durable(Type.Object({
|
|
1993
|
+
toolCallId: ToolCallId,
|
|
1994
|
+
tool: Type.String(),
|
|
1995
|
+
args: JsonValueSchema,
|
|
1996
|
+
argsSha256: Sha256
|
|
1997
|
+
})),
|
|
1998
|
+
"tool.denied": durable(Type.Object({
|
|
1999
|
+
toolCallId: ToolCallId,
|
|
2000
|
+
tool: Type.String(),
|
|
2001
|
+
stage: OpenEnum(TOOL_DENIAL_STAGES),
|
|
2002
|
+
ruleId: Type.String(),
|
|
2003
|
+
reason: Type.String(),
|
|
2004
|
+
overridable: Type.Boolean(),
|
|
2005
|
+
evaluatedRules: Type.Array(Type.String()),
|
|
2006
|
+
approvalId: Type.Optional(ApprovalId)
|
|
2007
|
+
})),
|
|
2008
|
+
/**
|
|
2009
|
+
* The ENGINE refused the call before the host saw it: no `toolCallId`, no gate, no rule ids — which is why it is
|
|
2010
|
+
* not a `tool.denied`. `message` is sealed.
|
|
2011
|
+
*/
|
|
2012
|
+
"tool.rejected": durable(Type.Object({
|
|
2013
|
+
engineToolCallId: Type.Optional(Type.String()),
|
|
2014
|
+
tool: Type.String(),
|
|
2015
|
+
cause: OpenEnum(TOOL_REJECTION_CAUSES),
|
|
2016
|
+
message: Type.String()
|
|
2017
|
+
})),
|
|
2018
|
+
"tool.started": durable(Type.Object({
|
|
2019
|
+
toolCallId: ToolCallId,
|
|
2020
|
+
tool: Type.String(),
|
|
2021
|
+
effectId: EffectId,
|
|
2022
|
+
decision: ClosedEnum(TOOL_DECISIONS),
|
|
2023
|
+
ruleId: Type.String(),
|
|
2024
|
+
grantId: Type.Optional(Type.String()),
|
|
2025
|
+
normalizedArgs: JsonValueSchema,
|
|
2026
|
+
replayClass: ClosedEnum(REPLAY_CLASSES),
|
|
2027
|
+
sandbox: SandboxReport,
|
|
2028
|
+
/** marks a host-side replay of an approved call (4.5) */
|
|
2029
|
+
replayOfApproval: Type.Optional(ApprovalId)
|
|
2030
|
+
})),
|
|
2031
|
+
"tool.progress": ephemeral(Type.Object({
|
|
2032
|
+
toolCallId: ToolCallId,
|
|
2033
|
+
text: Type.Optional(Type.String()),
|
|
2034
|
+
bytes: Type.Optional(count$2())
|
|
2035
|
+
})),
|
|
2036
|
+
"tool.completed": durable(Type.Object({
|
|
2037
|
+
toolCallId: ToolCallId,
|
|
2038
|
+
tool: Type.String(),
|
|
2039
|
+
effectId: EffectId,
|
|
2040
|
+
isError: Type.Boolean(),
|
|
2041
|
+
exitCode: Type.Optional(Type.Integer()),
|
|
2042
|
+
signal: Type.Optional(Type.String()),
|
|
2043
|
+
timedOut: Type.Boolean(),
|
|
2044
|
+
durationMs: milliseconds(),
|
|
2045
|
+
/** time the runtime waited for the host, from the delivery of the call */
|
|
2046
|
+
waitedMs: milliseconds(),
|
|
2047
|
+
output: Type.Object({
|
|
2048
|
+
sha256: Sha256,
|
|
2049
|
+
bytes: count$2(),
|
|
2050
|
+
truncated: Type.Boolean(),
|
|
2051
|
+
preview: Type.String(),
|
|
2052
|
+
artifact: Type.Optional(ArtifactRef)
|
|
2053
|
+
}),
|
|
2054
|
+
filesTouched: Type.Array(FileTouch),
|
|
2055
|
+
/** hits dropped by output filtering (2.7) */
|
|
2056
|
+
filteredPaths: Type.Optional(count$2()),
|
|
2057
|
+
replayed: Type.Boolean()
|
|
2058
|
+
})),
|
|
2059
|
+
"file.read": durable(FileAccess),
|
|
2060
|
+
"file.written": durable(FileAccess),
|
|
2061
|
+
"file.changed": durable(Type.Object({
|
|
2062
|
+
slot: Type.String(),
|
|
2063
|
+
files: Type.Array(FileTouch),
|
|
2064
|
+
detectedBy: ClosedEnum(["post-command-scan", "ledger-audit"]),
|
|
2065
|
+
attributedTo: Type.Optional(ToolCallId)
|
|
2066
|
+
})),
|
|
2067
|
+
"review.started": durable(Type.Object({
|
|
2068
|
+
phase: PhaseRef,
|
|
2069
|
+
reviewRef: ReviewRef,
|
|
2070
|
+
surfaces: Type.Array(SurfaceId),
|
|
2071
|
+
reviewers: Type.Array(AgentId)
|
|
2072
|
+
})),
|
|
2073
|
+
"review.finding": durable(Type.Object({
|
|
2074
|
+
finding: Finding,
|
|
2075
|
+
reviewer: AgentRef,
|
|
2076
|
+
disposition: ClosedEnum(FINDING_DISPOSITIONS)
|
|
2077
|
+
})),
|
|
2078
|
+
"review.completed": durable(Type.Object({
|
|
2079
|
+
verdict: ReviewResult.properties.verdict,
|
|
2080
|
+
blocking: count$2(),
|
|
2081
|
+
blockingItems: Type.Array(Type.String()),
|
|
2082
|
+
fingerprint: ReviewResult.properties.fingerprint,
|
|
2083
|
+
unreviewed: Type.Array(SurfaceId),
|
|
2084
|
+
counts: ReviewResult.properties.counts,
|
|
2085
|
+
clean: Type.Boolean()
|
|
2086
|
+
})),
|
|
2087
|
+
"review.approved": durable(Type.Object({
|
|
2088
|
+
reviewRef: ReviewRef,
|
|
2089
|
+
waivers: Type.Array(Type.Object({
|
|
2090
|
+
findingId: FindingId,
|
|
2091
|
+
approvalId: ApprovalId
|
|
2092
|
+
}))
|
|
2093
|
+
}))
|
|
2094
|
+
};
|
|
2095
|
+
//#endregion
|
|
2096
|
+
//#region ../../packages/protocol/src/catalogue.ts
|
|
2097
|
+
const EVENTS = {
|
|
2098
|
+
...RUN_EVENTS,
|
|
2099
|
+
...AGENT_EVENTS,
|
|
2100
|
+
...TOOL_EVENTS,
|
|
2101
|
+
...GOVERNANCE_EVENTS,
|
|
2102
|
+
...GIT_EVENTS,
|
|
2103
|
+
...STREAM_EVENTS
|
|
2104
|
+
};
|
|
2105
|
+
Object.keys(EVENTS).filter((type) => EVENTS[type].durability === "durable");
|
|
2106
|
+
const isEventType = (type) => Object.hasOwn(EVENTS, type);
|
|
2107
|
+
const isDurableEventType = (type) => isEventType(type) && EVENTS[type].durability === "durable";
|
|
2108
|
+
/**
|
|
2109
|
+
* `compileStrict(type)`, `compileStrictEnvelope(type)` and `toOpenJsonSchema()` with the exact signatures of
|
|
2110
|
+
* DESIGN 2.3.2, bound to EVENTS. The functions of the same names in compile.ts are generic over a table.
|
|
2111
|
+
*/
|
|
2112
|
+
const catalogue = bindCatalogue(EVENTS);
|
|
2113
|
+
//#endregion
|
|
2114
|
+
export { compileSchema as a, AgentOutput as c, EscalationPolicy as d, HALTED_STATES as f, ClosedEnum as g, TERMINAL_STATES as h, canonicalCommandBody as i, ACTIVE_PIPELINE_STATES as l, SUSPENDED_STATES as m, isDurableEventType as n, toStrictSchema as o, PipelineProfile as p, CONTROLLER_EXIT_CODES as r, compareOrder as s, catalogue as t, ActivePipelineState as u };
|
|
2115
|
+
|
|
2116
|
+
//# sourceMappingURL=src-s7YRvk0t.mjs.map
|