wicked-crew-api-types 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/index.d.ts +1148 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# wicked-crew-api-types
|
|
2
|
+
|
|
3
|
+
The **wire contract** of the wicked-crew daemon: one definition of every shape that crosses the
|
|
4
|
+
`/api/v1` REST surface and the `/ws` CoreEvent stream. Both sides compile against it —
|
|
5
|
+
|
|
6
|
+
- the daemon's route layer, via `packages/crew/src/core/types.ts` (a re-export), and
|
|
7
|
+
- the [wicked-studio](https://github.com/mikeparcewski/wicked-studio) SPA, via its
|
|
8
|
+
`src/api/types.ts` (likewise a re-export)
|
|
9
|
+
|
|
10
|
+
— replacing the hand-copied mirror the studio used to carry (task #84). Published to npm as
|
|
11
|
+
[`wicked-crew-api-types`](https://www.npmjs.com/package/wicked-crew-api-types) so out-of-repo
|
|
12
|
+
clients (studio first among them) can pin the contract as a normal dependency; crew's in-repo
|
|
13
|
+
consumers keep the workspace reference.
|
|
14
|
+
|
|
15
|
+
## Rules
|
|
16
|
+
|
|
17
|
+
- **Wire shapes only.** Engine-internal types (`LaunchRunInput`, `RepoOnboardRef`, runtime
|
|
18
|
+
constants) stay in the daemon.
|
|
19
|
+
- **Zero runtime.** This is a `.d.ts`-only package: no JavaScript, nothing to build. Consumers
|
|
20
|
+
declare it as a devDependency (the published `wicked-crew` tarball never depends on it at
|
|
21
|
+
runtime). Import it with `import type` only — the `exports` map offers just a `types`
|
|
22
|
+
condition, so a value import fails loudly.
|
|
23
|
+
- **Forward-additive.** Optional/index-signature fields keep the shapes additive: a newer daemon
|
|
24
|
+
that adds fields still parses in an older studio (DES-STUDIO-001 §5.1).
|
|
25
|
+
|
|
26
|
+
## Drift guard
|
|
27
|
+
|
|
28
|
+
`packages/crew/tests/wire-contract.test.ts` holds compile-time assertions, run by
|
|
29
|
+
`npm run -w packages/crew typecheck` (and CI): every response type the daemon produces must satisfy
|
|
30
|
+
this contract, and every request body the contract allows must be accepted by the daemon's zod
|
|
31
|
+
schemas. Change the wire shape in one place and the typecheck fails everywhere it matters.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,1148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wicked-crew-api-types — the wire contract of the wicked-crew daemon.
|
|
3
|
+
*
|
|
4
|
+
* One definition of every shape that crosses the daemon's HTTP/WS boundary:
|
|
5
|
+
* the `/api/v1` JSON responses and request bodies, and the CoreEvent frames
|
|
6
|
+
* delivered verbatim over `/ws`. BOTH sides compile against this package —
|
|
7
|
+
* the daemon's route layer (via `packages/crew/src/core/types.ts`, which
|
|
8
|
+
* re-exports it) and the studio SPA (via `packages/studio/src/api/types.ts`,
|
|
9
|
+
* likewise a re-export) — replacing the hand-copied mirror the studio used to
|
|
10
|
+
* carry, which could drift from the daemon silently (task #84).
|
|
11
|
+
*
|
|
12
|
+
* Rules of this package:
|
|
13
|
+
* - WIRE SHAPES ONLY. Engine-internal types (`LaunchRunInput`,
|
|
14
|
+
* `RepoOnboardRef`, runtime constants) stay in `packages/crew/src/core/types.ts`.
|
|
15
|
+
* - ZERO RUNTIME. This is a `.d.ts`-only package with no JavaScript; import it
|
|
16
|
+
* with `import type` exclusively. The `exports` map deliberately offers only
|
|
17
|
+
* a `types` condition, so a value import fails loudly at resolution time.
|
|
18
|
+
* - FORWARD-ADDITIVE. Optional/index-signature fields keep the shapes additive:
|
|
19
|
+
* a newer daemon that adds fields still parses in an older studio, and new
|
|
20
|
+
* CoreEvent variants pass through event switches untouched (DES-STUDIO-001
|
|
21
|
+
* §5.1). No `any` at the boundary — unknown-typed fields are narrowed at use.
|
|
22
|
+
*
|
|
23
|
+
* The shapes mirror wicked-core's serde representation (wicked-core/src/domain.rs,
|
|
24
|
+
* repo.rs, scope.rs) — the daemon passes most of them through verbatim.
|
|
25
|
+
* Drift guard: `packages/crew/tests/wire-contract.test.ts` fails to compile if
|
|
26
|
+
* the daemon's produced types stop satisfying this contract.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Run-level lifecycle status (`SessionStatus`, snake_case serde token). */
|
|
30
|
+
export type SessionStatus =
|
|
31
|
+
| 'planning'
|
|
32
|
+
| 'distributing'
|
|
33
|
+
| 'executing'
|
|
34
|
+
| 'awaiting_human'
|
|
35
|
+
| 'completed'
|
|
36
|
+
| 'cancelled'
|
|
37
|
+
| 'failed';
|
|
38
|
+
|
|
39
|
+
/** Per-unit lifecycle status (`UnitStatus`). */
|
|
40
|
+
export type UnitStatus = 'pending' | 'distributed' | 'done' | 'rejected';
|
|
41
|
+
|
|
42
|
+
/** The methodology stage badge on a unit (`StageKind`). */
|
|
43
|
+
export type StageKind = 'recon' | 'build' | 'review' | 'test';
|
|
44
|
+
|
|
45
|
+
/** Collection-scope mode (`EntityMode`). */
|
|
46
|
+
export type EntityMode = 'shared' | 'isolated';
|
|
47
|
+
|
|
48
|
+
/** Human-confirm gate policy. serde: `None`→"none", `All`→"all", `Before(n)`→{ before: n }. */
|
|
49
|
+
export type HumanConfirm = 'none' | 'all' | { before: number };
|
|
50
|
+
|
|
51
|
+
/** Why a CLI was assigned to a unit (`RoutingInfo`, internally tagged on `method`). */
|
|
52
|
+
export type RoutingInfo =
|
|
53
|
+
/**
|
|
54
|
+
* `seated` is the seats CONVENED — the denominator `returned` must be read against.
|
|
55
|
+
* Unknown on a run recorded by an engine older than the quorum fix; unknown means exactly that,
|
|
56
|
+
* never "equal to `returned`" (FINDING-026 D).
|
|
57
|
+
*
|
|
58
|
+
* `number | null` AND optional because unknown arrives in both shapes and neither is under this
|
|
59
|
+
* file's control: the engine serializes the artifact's `Option<u32>` as an explicit `null` (no
|
|
60
|
+
* `skip_serializing_if`, so the routing artifact and the event stream agree on one spelling of
|
|
61
|
+
* unknown), while a payload from before the field existed at all simply has no key. Read it with
|
|
62
|
+
* `== null`, which covers both — `=== undefined` silently misses the null case, which is the one
|
|
63
|
+
* the live API actually sends.
|
|
64
|
+
*/
|
|
65
|
+
| {
|
|
66
|
+
method: 'council';
|
|
67
|
+
winner: string;
|
|
68
|
+
agreement_pct: number;
|
|
69
|
+
returned: number;
|
|
70
|
+
seated?: number | null;
|
|
71
|
+
dissent: number;
|
|
72
|
+
}
|
|
73
|
+
| { method: 'degraded'; reason: string }
|
|
74
|
+
| { method: 'evaluator_distinct'; winner: string; was: string }
|
|
75
|
+
| { method: 'tool' };
|
|
76
|
+
|
|
77
|
+
/** A run (`AgentSession`). */
|
|
78
|
+
export interface AgentSession {
|
|
79
|
+
id: string;
|
|
80
|
+
workflow_id: string;
|
|
81
|
+
problem: string;
|
|
82
|
+
entity_mode: EntityMode;
|
|
83
|
+
collection_scope: string | null;
|
|
84
|
+
clis: string[];
|
|
85
|
+
status: SessionStatus;
|
|
86
|
+
human_confirm: HumanConfirm;
|
|
87
|
+
unit_ix: number;
|
|
88
|
+
attempt: number;
|
|
89
|
+
workdir: string | null;
|
|
90
|
+
repo_ref: string | null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** An ordered unit of work within a run (`WorkUnit`). */
|
|
94
|
+
export interface WorkUnit {
|
|
95
|
+
id: string;
|
|
96
|
+
session_id: string;
|
|
97
|
+
ord: number;
|
|
98
|
+
description: string;
|
|
99
|
+
stage: StageKind;
|
|
100
|
+
assigned_cli: string | null;
|
|
101
|
+
assigned_invocation: string | null;
|
|
102
|
+
council_task_ref: string | null;
|
|
103
|
+
routing: RoutingInfo | null;
|
|
104
|
+
denial_reason: string | null;
|
|
105
|
+
phase_ref: string | null;
|
|
106
|
+
conformance_ref: string | null;
|
|
107
|
+
phase_status: string | null;
|
|
108
|
+
collection_scope: string | null;
|
|
109
|
+
status: UnitStatus;
|
|
110
|
+
skill_ref?: string | null;
|
|
111
|
+
/** The command this unit runs directly (Tool-executor phases). `null`/absent for Agent units. */
|
|
112
|
+
tool_cmd?: string[] | null;
|
|
113
|
+
/** Evaluator≠creator role. Present on def-driven units; absent on legacy/free-text. */
|
|
114
|
+
role?: PhaseRole;
|
|
115
|
+
/** Gate policy for this phase. Present on def-driven units; absent on legacy/free-text. */
|
|
116
|
+
gate?: GateSpec | string;
|
|
117
|
+
/** True when a pinned deterministic validator is attached to this unit. */
|
|
118
|
+
has_validator_pin?: boolean;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** A run plus its ordered units (`SessionView`) — the shape `GET /runs` returns. */
|
|
122
|
+
export interface SessionView {
|
|
123
|
+
session: AgentSession;
|
|
124
|
+
units: WorkUnit[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** A registered git repository (`RepoEntry`). */
|
|
128
|
+
export interface RepoEntry {
|
|
129
|
+
id: string;
|
|
130
|
+
name: string;
|
|
131
|
+
root_path: string;
|
|
132
|
+
default_branch: string;
|
|
133
|
+
registered_at: number;
|
|
134
|
+
/** Remote git URL the repo was cloned from (undefined for locally-registered repos). */
|
|
135
|
+
git_url?: string;
|
|
136
|
+
/**
|
|
137
|
+
* ABSOLUTE path of this repo's code graph, resolved by the engine (wicked-core#170).
|
|
138
|
+
*
|
|
139
|
+
* Optional in the TYPE, mandatory in practice: an addon predating the field omits it, and
|
|
140
|
+
* `codeGraphDb()` in the daemon's `repoPaths.ts` is where that turns into a loud error. Never
|
|
141
|
+
* join this path yourself — six independent spellings is what FINDING-069 was.
|
|
142
|
+
*/
|
|
143
|
+
code_graph_db?: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** The run id of the onboarding run launched when a repo was registered (`GET /repos/:id/onboard`). */
|
|
147
|
+
export interface OnboardRef {
|
|
148
|
+
runId: string | null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* A council seat (`AgenticCli`) as returned by `GET /roster`. Only the fields
|
|
153
|
+
* the launch form uses are named; the index signature keeps the (large) rest of
|
|
154
|
+
* the seat intact so it round-trips verbatim into `clisJson` on launch.
|
|
155
|
+
*/
|
|
156
|
+
export interface RosterSeat {
|
|
157
|
+
key: string;
|
|
158
|
+
display_name: string;
|
|
159
|
+
binary: string;
|
|
160
|
+
enabled_for_council: boolean;
|
|
161
|
+
category?: string;
|
|
162
|
+
[k: string]: unknown;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** The daemon's cached open-gate record (`GET /runs/:id/gate`, DES-STUDIO-001 §3.3). */
|
|
166
|
+
export interface GateInfo {
|
|
167
|
+
runId: string;
|
|
168
|
+
ord: number;
|
|
169
|
+
prompt: string;
|
|
170
|
+
lifecycle: string;
|
|
171
|
+
receivedAt: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Approve / reject payload for the steering gate (`POST /runs/:id/gate`). */
|
|
175
|
+
export interface GateDecision {
|
|
176
|
+
approve: boolean;
|
|
177
|
+
amend?: string;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* A CoreEvent frame as delivered verbatim over `/ws` — a tagged-JSON object
|
|
182
|
+
* discriminated on `type` (wicked-core-ts `event_to_json`). The named optional
|
|
183
|
+
* fields cover the frames the daemon and the studio inspect; the index
|
|
184
|
+
* signature keeps the shape additive-safe so new variants pass through
|
|
185
|
+
* untouched (DES-STUDIO-001 §2.1, §5.1).
|
|
186
|
+
*/
|
|
187
|
+
export interface CoreEvent {
|
|
188
|
+
type: string;
|
|
189
|
+
session?: string;
|
|
190
|
+
ord?: number;
|
|
191
|
+
prompt?: string;
|
|
192
|
+
chunk?: string;
|
|
193
|
+
allow?: boolean;
|
|
194
|
+
cli?: string;
|
|
195
|
+
description?: string;
|
|
196
|
+
problem?: string;
|
|
197
|
+
message?: string;
|
|
198
|
+
/** `elicitationCreated` (DES-002): the id minted by the actor for this elicitation round. */
|
|
199
|
+
elicitationId?: string;
|
|
200
|
+
/** `elicitationCreated`: an ordered set of valid responses; `null` / absent = free-text. */
|
|
201
|
+
options?: string[] | null;
|
|
202
|
+
/** PTY terminal frames (`terminalOpened`/`terminalOutput`/`terminalExited`): the terminal id. */
|
|
203
|
+
id?: string;
|
|
204
|
+
/**
|
|
205
|
+
* A monotonic counter — but of WHAT depends on where the event came from, and the two never
|
|
206
|
+
* appear together, so there is exactly one right reading per event:
|
|
207
|
+
*
|
|
208
|
+
* - **live `/ws` frame** — `terminalOutput` only, and it counts within that one terminal
|
|
209
|
+
* (`actor.rs` `TerminalState::next_seq`). Two terminals both start at 0; comparing their `seq`
|
|
210
|
+
* values means nothing.
|
|
211
|
+
* - **entry from `runEvents`** — the durable log's own envelope counter, process-wide and stamped
|
|
212
|
+
* at emit (`event_log.rs` `SEQ`), which is what `read_run` sorts on. It totals-orders a run,
|
|
213
|
+
* which `ts` alone cannot: a burst from one actor turn shares a millisecond.
|
|
214
|
+
*
|
|
215
|
+
* They cannot collide, because `terminalOutput` is classed high-volume and is **never written to
|
|
216
|
+
* the log** — so no payload ever carries both meanings. What that does forbid is merging the two
|
|
217
|
+
* sources and sorting the result on this field: a live per-terminal 3 is not comparable to a
|
|
218
|
+
* replayed envelope 4700. Sort a replay by `seq`; order live frames by arrival, per terminal id.
|
|
219
|
+
*/
|
|
220
|
+
seq?: number;
|
|
221
|
+
/** Capture time, epoch millis. Present ONLY on entries replayed from the durable event log
|
|
222
|
+
* (`runEvents` / `GET /runs/:id/events`); live `/ws` frames are not stamped, because for those
|
|
223
|
+
* the arrival IS the time. */
|
|
224
|
+
ts?: number;
|
|
225
|
+
/** `terminalOutput`: raw PTY bytes, base64-encoded (decode → send to the owning socket). */
|
|
226
|
+
bytesB64?: string;
|
|
227
|
+
/** `terminalOpened`: the working directory the PTY was opened in. */
|
|
228
|
+
cwd?: string;
|
|
229
|
+
// ── DES-STUDIO-COCKPIT-001 §3 B-events (Phase B insight wires) ──
|
|
230
|
+
/** `unitDispatched`/`cliUsage`: 0-based dispatch attempt (`>0` = a re-dispatch / rework). */
|
|
231
|
+
attempt?: number;
|
|
232
|
+
/** `cliUsage`: prompt/input tokens for the unit run. */
|
|
233
|
+
inputTokens?: number;
|
|
234
|
+
/** `cliUsage`: completion/output tokens for the unit run. */
|
|
235
|
+
outputTokens?: number;
|
|
236
|
+
/** `cliUsage`: dollar cost when the CLI reports it (claude) or a price table resolves it; else `null`. */
|
|
237
|
+
costUsd?: number | null;
|
|
238
|
+
/** `dataUsed`: the data files the unit's CLI touched (`tool_use` file paths). */
|
|
239
|
+
files?: string[];
|
|
240
|
+
/** `gateEvaluated`: the gated criterion — `null` when the phase was UNGATED (no deterministic floor). */
|
|
241
|
+
criterion?: string | null;
|
|
242
|
+
/** `gateEvaluated`: `true` iff a pinned validator gated this unit (else the phase is ungated). */
|
|
243
|
+
hasDeterministicFloor?: boolean;
|
|
244
|
+
/** `gateEvaluated`: whether the deterministic (layer-1) floor passed (vacuous when no floor). */
|
|
245
|
+
deterministicPass?: boolean;
|
|
246
|
+
/** `gateEvaluated`: the agent (layer-2) judge's verdict when one ran, else `null`. */
|
|
247
|
+
agentVerdict?: string | null;
|
|
248
|
+
/** `gateEvaluated`: the agent judge's reasoning when one ran, else `null`. */
|
|
249
|
+
agentReasoning?: string | null;
|
|
250
|
+
/** `gateEvaluated`: the evaluator≠creator second-pass result — `null` when that layer did not run. */
|
|
251
|
+
evaluatorPass?: boolean | null;
|
|
252
|
+
/**
|
|
253
|
+
* `gateEvaluated`: policy ids the second pass applied. EMPTY alongside `evaluatorPass: true`
|
|
254
|
+
* means nothing applied, so the pass is a vacuous default-allow rather than an enforced
|
|
255
|
+
* approval (FINDING-025). The layer-3 analogue of `hasDeterministicFloor`.
|
|
256
|
+
*/
|
|
257
|
+
evaluatorPolicies?: string[];
|
|
258
|
+
/** `gateEvaluated`: the WINNING denial's reason when `combined === false`, else `null`. */
|
|
259
|
+
denialReason?: string | null;
|
|
260
|
+
/** `gateEvaluated`: the final deny-dominant decision over all layers (mirrors `gateDecided.allow`). */
|
|
261
|
+
combined?: boolean;
|
|
262
|
+
// sessionStarted enrichment fields (snake_case — serde wire names)
|
|
263
|
+
workflow_id?: string | null;
|
|
264
|
+
cli_count?: number;
|
|
265
|
+
governed?: boolean;
|
|
266
|
+
entity_mode?: string;
|
|
267
|
+
// workflowSelected (EVT-001) — camelCase per event_to_json
|
|
268
|
+
workflowId?: string;
|
|
269
|
+
unitCount?: number;
|
|
270
|
+
// unitReworkAmended (EVT-012)
|
|
271
|
+
amendment?: string;
|
|
272
|
+
updatedDescription?: string;
|
|
273
|
+
// unitOutputCaptured (EVT-013)
|
|
274
|
+
outputBytes?: number;
|
|
275
|
+
stepStatus?: 'ok' | 'failed' | 'cancelled';
|
|
276
|
+
// unitPlanned enrichment fields — the wire spelling is camelCase (event_to_json);
|
|
277
|
+
// the snake_case variants are kept for older daemons.
|
|
278
|
+
stage?: string;
|
|
279
|
+
skill_ref?: string | null;
|
|
280
|
+
skillRef?: string | null;
|
|
281
|
+
has_validator_pin?: boolean;
|
|
282
|
+
hasValidatorPin?: boolean;
|
|
283
|
+
executor_type?: string;
|
|
284
|
+
executorType?: string;
|
|
285
|
+
// unitDistributed enrichment fields
|
|
286
|
+
routing_method?: string;
|
|
287
|
+
agreement_pct?: number | null;
|
|
288
|
+
returned?: number | null;
|
|
289
|
+
dissent?: number | null;
|
|
290
|
+
degraded_reason?: string | null;
|
|
291
|
+
// councilConvened / councilDeliberated / councilVoted (live deliberation) — camelCase
|
|
292
|
+
// per event_to_json
|
|
293
|
+
clis?: string[];
|
|
294
|
+
consensus?: boolean;
|
|
295
|
+
agreementPct?: number;
|
|
296
|
+
votes?: number;
|
|
297
|
+
/** councilDeliberated: the completed ballot number (1-based). */
|
|
298
|
+
round?: number;
|
|
299
|
+
/** councilDeliberated: the approval bar the council must reach, as a percent. */
|
|
300
|
+
neededPct?: number;
|
|
301
|
+
/**
|
|
302
|
+
* councilSeatFailed: the seat's exit code, when it ran far enough to have one.
|
|
303
|
+
*
|
|
304
|
+
* The branch itself arrives on the shared `kind` field — `spawn_failed`, `non_zero_exit`,
|
|
305
|
+
* `timed_out`, `pty_unsupported`, `invocation_empty`, `workdir_unavailable`,
|
|
306
|
+
* `prompt_write_failed`, `wait_failed`, `unreported`. Every seat that does not vote reports
|
|
307
|
+
* one; without it the council's quorum shrinks silently.
|
|
308
|
+
*/
|
|
309
|
+
exitCode?: number | null;
|
|
310
|
+
/** councilSeatFailed: bounded capture of what the seat wrote to stderr (≤4 KiB). */
|
|
311
|
+
stderr?: string;
|
|
312
|
+
/** councilSeatFailed: how long the seat burned before failing — separates a spawn error from a timeout. */
|
|
313
|
+
latencyMs?: number;
|
|
314
|
+
/** workerStalled: silent seconds before the stall event fired. */
|
|
315
|
+
stalledSecs?: number;
|
|
316
|
+
/** failureTriaged: the triage judge's decision. */
|
|
317
|
+
decision?: string;
|
|
318
|
+
/** failureTriaged: the judge's bounded reasoning. */
|
|
319
|
+
analysis?: string;
|
|
320
|
+
// assumptionRecorded (external-transform convention) — camelCase per event_to_json
|
|
321
|
+
kind?: string;
|
|
322
|
+
library?: string;
|
|
323
|
+
transform?: string;
|
|
324
|
+
known?: boolean;
|
|
325
|
+
detail?: string;
|
|
326
|
+
[k: string]: unknown;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* A frame read back from core's DURABLE per-run event log (`GET /runs/:id/events`):
|
|
331
|
+
* the same tagged object the live stream carries, plus the two fields the log
|
|
332
|
+
* adds when it records one.
|
|
333
|
+
*
|
|
334
|
+
* Same shape as the live frame on purpose — one mapping in core
|
|
335
|
+
* (`CoreEvent::to_json`) serializes both, so an event named here is the event
|
|
336
|
+
* named live, and a bundle assembled after a run cannot describe it in different
|
|
337
|
+
* words than the operator watched it happen in. (FINDING-014)
|
|
338
|
+
*/
|
|
339
|
+
export interface RecordedEvent extends CoreEvent {
|
|
340
|
+
/** Capture time, epoch millis — when core emitted the frame, not when it was read. */
|
|
341
|
+
ts: number;
|
|
342
|
+
/**
|
|
343
|
+
* Monotonic ordering across THIS RUN's whole event trail, so frames sharing a `ts` are still
|
|
344
|
+
* ordered.
|
|
345
|
+
*
|
|
346
|
+
* Not the same `seq` as `CoreEvent`'s, which counts chunks within one terminal's output. This one
|
|
347
|
+
* is required and spans every frame of the run; that one is optional and scoped to a stream. The
|
|
348
|
+
* name is inherited from the wire and narrowed here rather than renamed, because the wire is what
|
|
349
|
+
* `runEvents` returns.
|
|
350
|
+
*/
|
|
351
|
+
seq: number;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* DES-STUDIO-COCKPIT-001 §3 B-events — the 4 tagged-JSON insight frames, as a discriminated
|
|
356
|
+
* union for consumers that narrow on `type`. Each mirrors a wicked-core `CoreEvent` variant
|
|
357
|
+
* (`event_to_json`, camelCase). They also flow through the permissive {@link CoreEvent} above; the
|
|
358
|
+
* union just gives Phase-B panels exact field types.
|
|
359
|
+
*/
|
|
360
|
+
export type InsightEvent =
|
|
361
|
+
| UnitDispatchedEvent
|
|
362
|
+
| CliUsageEvent
|
|
363
|
+
| DataUsedEvent
|
|
364
|
+
| GateEvaluatedEvent;
|
|
365
|
+
|
|
366
|
+
/** §3 B2 — a unit was dispatched (initial + each re-dispatch); `attempt>0` = rework. */
|
|
367
|
+
export interface UnitDispatchedEvent {
|
|
368
|
+
type: 'unitDispatched';
|
|
369
|
+
session: string;
|
|
370
|
+
ord: number;
|
|
371
|
+
attempt: number;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** §3 B3 — token/cost burn for one unit run. `costUsd` is `null` when no cost is known. */
|
|
375
|
+
export interface CliUsageEvent {
|
|
376
|
+
type: 'cliUsage';
|
|
377
|
+
session: string;
|
|
378
|
+
ord: number;
|
|
379
|
+
attempt: number;
|
|
380
|
+
inputTokens: number;
|
|
381
|
+
outputTokens: number;
|
|
382
|
+
costUsd: number | null;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/** §3 B4 — the data files a unit's CLI touched. */
|
|
386
|
+
export interface DataUsedEvent {
|
|
387
|
+
type: 'dataUsed';
|
|
388
|
+
session: string;
|
|
389
|
+
ord: number;
|
|
390
|
+
files: string[];
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/** §3 B1 — the gate's decision depth, emitted alongside `gateDecided`. */
|
|
394
|
+
export interface GateEvaluatedEvent {
|
|
395
|
+
type: 'gateEvaluated';
|
|
396
|
+
session: string;
|
|
397
|
+
ord: number;
|
|
398
|
+
criterion: string | null;
|
|
399
|
+
hasDeterministicFloor: boolean;
|
|
400
|
+
deterministicPass: boolean;
|
|
401
|
+
agentVerdict: string | null;
|
|
402
|
+
agentReasoning: string | null;
|
|
403
|
+
evaluatorPass: boolean | null;
|
|
404
|
+
denialReason: string | null;
|
|
405
|
+
combined: boolean;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** Foundation wave: session started with enriched context. */
|
|
409
|
+
export interface SessionStartedEvent {
|
|
410
|
+
type: 'sessionStarted';
|
|
411
|
+
session: string;
|
|
412
|
+
problem: string;
|
|
413
|
+
workflow_id: string | null;
|
|
414
|
+
cli_count: number;
|
|
415
|
+
governed: boolean;
|
|
416
|
+
entity_mode: 'shared' | 'isolated';
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// ── P1 observability events ─────────────────────────────────────────────────
|
|
420
|
+
|
|
421
|
+
/** P1 — a worker failure halted this unit; `detail` is a bounded excerpt of raw output. */
|
|
422
|
+
export interface StepFailedEvent {
|
|
423
|
+
type: 'stepFailed';
|
|
424
|
+
session: string;
|
|
425
|
+
ord: number;
|
|
426
|
+
attempt: number;
|
|
427
|
+
detail: string;
|
|
428
|
+
failureKind: string;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** P1 — the engine restarted and is re-dispatching this unit; `attempt` is the NEW attempt number. */
|
|
432
|
+
export interface CrashRecoveryRedriveEvent {
|
|
433
|
+
type: 'crashRecoveryRedrive';
|
|
434
|
+
session: string;
|
|
435
|
+
ord: number;
|
|
436
|
+
attempt: number;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** P1 — a PTY worker session opened for the run; `terminalId` matches the terminal event stream. */
|
|
440
|
+
export interface WorkerSessionStartedEvent {
|
|
441
|
+
type: 'workerSessionStarted';
|
|
442
|
+
session: string;
|
|
443
|
+
terminalId: string;
|
|
444
|
+
cliKey: string;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** P1 — an ACP persistent session opened for a CLI; `acpSessionId` is the protocol session handle. */
|
|
448
|
+
export interface AcpSessionStartedEvent {
|
|
449
|
+
type: 'acpSessionStarted';
|
|
450
|
+
session: string;
|
|
451
|
+
cliKey: string;
|
|
452
|
+
acpSessionId: string;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** P1 — ACP unavailable or failed for a CLI; the run continues with single-shot fallback. */
|
|
456
|
+
export interface AcpFallbackEvent {
|
|
457
|
+
type: 'acpFallback';
|
|
458
|
+
session: string;
|
|
459
|
+
cliKey: string;
|
|
460
|
+
reason: string;
|
|
461
|
+
fallbackKind: string;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// ── P2 observability events ─────────────────────────────────────────────────
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* P2 — one prior unit's context contributed to a cross-CLI injection.
|
|
468
|
+
* Mirrors `wicked_core::InjectedContext`: identity + size only, no raw content.
|
|
469
|
+
*/
|
|
470
|
+
export interface InjectedContextRecord {
|
|
471
|
+
ord: number;
|
|
472
|
+
label: string;
|
|
473
|
+
outputBytes: number;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/** P2 — an existing PTY session was reused for a subsequent unit in the same run (EVT-003). */
|
|
477
|
+
export interface WorkerSessionReusedEvent {
|
|
478
|
+
type: 'workerSessionReused';
|
|
479
|
+
session: string;
|
|
480
|
+
terminalId: string;
|
|
481
|
+
ord: number;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* P2 — a PTY worker session closed (EVT-004).
|
|
486
|
+
* `reason`: `"run_complete"` (normal end-of-run) | `"error"` (PTY write failure).
|
|
487
|
+
*/
|
|
488
|
+
export interface WorkerSessionClosedEvent {
|
|
489
|
+
type: 'workerSessionClosed';
|
|
490
|
+
session: string;
|
|
491
|
+
terminalId: string;
|
|
492
|
+
reason: 'run_complete' | 'error';
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* P2 — prior cross-CLI unit outputs were injected into a unit's context before dispatch (EVT-007).
|
|
497
|
+
* Carries identity + byte-size only — raw output content is not included.
|
|
498
|
+
*/
|
|
499
|
+
export interface UnitContextInjectedEvent {
|
|
500
|
+
type: 'unitContextInjected';
|
|
501
|
+
session: string;
|
|
502
|
+
ord: number;
|
|
503
|
+
recipientCli: string;
|
|
504
|
+
priorUnits: InjectedContextRecord[];
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// ── P2 governance-deep observability events (wicked-core#89) ────────────────
|
|
508
|
+
|
|
509
|
+
/** P2 — governance hook fired for a tool call; records the per-call allow/deny decision. */
|
|
510
|
+
export interface GovernanceHookFiredEvent {
|
|
511
|
+
type: 'governanceHookFired';
|
|
512
|
+
session: string;
|
|
513
|
+
ord: number;
|
|
514
|
+
attempt: number;
|
|
515
|
+
toolName: string;
|
|
516
|
+
decision: 'allow' | 'deny';
|
|
517
|
+
denyingPolicy: string | null;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/** P2 — a pinned deterministic validator was attached; confirms the governance floor is armed. */
|
|
521
|
+
export interface ValidationPinAttachedEvent {
|
|
522
|
+
type: 'validationPinAttached';
|
|
523
|
+
session: string;
|
|
524
|
+
ord: number;
|
|
525
|
+
pin: string;
|
|
526
|
+
criterion: string;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/** P2 — a HumanConfirmIf gate escalated to human review. */
|
|
530
|
+
export interface GateEscalatedEvent {
|
|
531
|
+
type: 'gateEscalated';
|
|
532
|
+
session: string;
|
|
533
|
+
ord: number;
|
|
534
|
+
condition: string;
|
|
535
|
+
verdictSummary: string;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/** P2 — a tool-executor command was dispatched (non-agent unit). */
|
|
539
|
+
export interface ToolExecutorDispatchedEvent {
|
|
540
|
+
type: 'toolExecutorDispatched';
|
|
541
|
+
session: string;
|
|
542
|
+
ord: number;
|
|
543
|
+
cmd: string[];
|
|
544
|
+
workdir: string | null;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/** P2 — governance context was confirmed armed for a unit. */
|
|
548
|
+
export interface GovernanceContextArmedEvent {
|
|
549
|
+
type: 'governanceContextArmed';
|
|
550
|
+
session: string;
|
|
551
|
+
ord: number;
|
|
552
|
+
attempt: number;
|
|
553
|
+
path: 'wrapped_cli' | 'acp';
|
|
554
|
+
dbPath: string;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/** P2 — a unit the workflow declared GOVERNED ran with its tool calls unchecked, because the CLI it
|
|
558
|
+
* was routed to has no gate-hook adapter (injection is claude-only). Distinct from a unit that was
|
|
559
|
+
* never governed at all: both report `governed: false` on unitOutputCaptured, and only this event
|
|
560
|
+
* separates "not asked for" from "asked for and not applied" (FINDING-063). */
|
|
561
|
+
export interface GovernanceUnenforcedEvent {
|
|
562
|
+
type: 'governanceUnenforced';
|
|
563
|
+
session: string;
|
|
564
|
+
ord: number;
|
|
565
|
+
attempt: number;
|
|
566
|
+
cli: string;
|
|
567
|
+
reason: string;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// ── P2 decisions-full observability events (wicked-core EVT-001/012/013) ────
|
|
571
|
+
|
|
572
|
+
/** P2 — a structured workflow def was selected; fires once per session, after SessionStarted and before
|
|
573
|
+
* the first UnitPlanned. Not emitted for free-text runs. `unitCount` is the number of phases. */
|
|
574
|
+
export interface WorkflowSelectedEvent {
|
|
575
|
+
type: 'workflowSelected';
|
|
576
|
+
session: string;
|
|
577
|
+
workflowId: string;
|
|
578
|
+
unitCount: number;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/** P2 — a human approved a gate with an amendment text that was injected into the unit's description
|
|
582
|
+
* before re-dispatch. Fires after the amendment is persisted, before Resumed. Only emitted when
|
|
583
|
+
* the amendment text is non-empty. The canonical record for the HITL paper trail. */
|
|
584
|
+
export interface UnitReworkAmendedEvent {
|
|
585
|
+
type: 'unitReworkAmended';
|
|
586
|
+
session: string;
|
|
587
|
+
ord: number;
|
|
588
|
+
/** The raw amendment text supplied by the operator. */
|
|
589
|
+
amendment: string;
|
|
590
|
+
/** The unit's description after the amendment was injected. */
|
|
591
|
+
updatedDescription: string;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/** P2 — a worker's ApplyStepResult arrived and output is ready to be gated. Fires before GateDecided.
|
|
595
|
+
* `outputBytes` is the byte length of the worker's output; `stepStatus` is "ok"/"failed"/"cancelled";
|
|
596
|
+
* `governed` reflects whether the runner armed input governance for this unit. */
|
|
597
|
+
export interface UnitOutputCapturedEvent {
|
|
598
|
+
type: 'unitOutputCaptured';
|
|
599
|
+
session: string;
|
|
600
|
+
ord: number;
|
|
601
|
+
attempt: number;
|
|
602
|
+
/** Byte length of the worker's raw output — distinguishes 0-byte from 8 MB truncated. */
|
|
603
|
+
outputBytes: number;
|
|
604
|
+
stepStatus: 'ok' | 'failed' | 'cancelled';
|
|
605
|
+
governed: boolean;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/** Foundation wave: a unit was planned with full phase metadata. */
|
|
609
|
+
export interface UnitPlannedEvent {
|
|
610
|
+
type: 'unitPlanned';
|
|
611
|
+
session: string;
|
|
612
|
+
ord: number;
|
|
613
|
+
description: string;
|
|
614
|
+
stage: StageKind;
|
|
615
|
+
role: PhaseRole;
|
|
616
|
+
gate: 'auto' | 'human_confirm' | 'human_confirm_if';
|
|
617
|
+
skill_ref: string | null;
|
|
618
|
+
has_validator_pin: boolean;
|
|
619
|
+
executor_type: 'agent' | 'tool';
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/** Foundation wave: a unit was distributed with full routing detail. */
|
|
623
|
+
export interface UnitDistributedEvent {
|
|
624
|
+
type: 'unitDistributed';
|
|
625
|
+
session: string;
|
|
626
|
+
ord: number;
|
|
627
|
+
cli: string;
|
|
628
|
+
routing_method: 'council' | 'degraded' | 'evaluator_distinct' | 'tool';
|
|
629
|
+
agreement_pct: number | null;
|
|
630
|
+
returned: number | null;
|
|
631
|
+
dissent: number | null;
|
|
632
|
+
degraded_reason: string | null;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// ── Worker injection + reassignment events (core#93) ──────────────────────────
|
|
636
|
+
|
|
637
|
+
/** An operator message was injected into active worker sessions mid-run. */
|
|
638
|
+
export interface WorkerMessageInjectedEvent {
|
|
639
|
+
type: 'workerMessageInjected';
|
|
640
|
+
session: string;
|
|
641
|
+
message: string;
|
|
642
|
+
/** `"all"` or the cli_key that was targeted. */
|
|
643
|
+
target: string;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/** A unit was stopped and re-dispatched to a different CLI (or re-routed via council). */
|
|
647
|
+
export interface UnitReassignedEvent {
|
|
648
|
+
type: 'unitReassigned';
|
|
649
|
+
session: string;
|
|
650
|
+
ord: number;
|
|
651
|
+
attempt: number;
|
|
652
|
+
previousCli: string;
|
|
653
|
+
/** `null` means the council was re-convened and its choice is the new assignment. */
|
|
654
|
+
newCli: string | null;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// ── Governance types (crew#40/42/43) ───────────────────────────────────────────
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* A registered governance policy (`wicked-governance::Policy`).
|
|
661
|
+
* `effect`: `deny` | `allow_with_conditions` | `allow`.
|
|
662
|
+
* `severity`: `high` | `medium` | `low`.
|
|
663
|
+
*/
|
|
664
|
+
export interface GovernancePolicy {
|
|
665
|
+
id: string;
|
|
666
|
+
kind: string;
|
|
667
|
+
applies_to: string[];
|
|
668
|
+
effect: 'deny' | 'allow_with_conditions' | 'allow';
|
|
669
|
+
trigger: { contains?: string };
|
|
670
|
+
obligations: string[];
|
|
671
|
+
criteria: string;
|
|
672
|
+
severity: 'high' | 'medium' | 'low';
|
|
673
|
+
rule: string;
|
|
674
|
+
/**
|
|
675
|
+
* Withdrawn from enforcement (FINDING-038). Still listed — the record survives so past decisions
|
|
676
|
+
* citing it stay explicable — but it can no longer decide a gate. Absent on policies written
|
|
677
|
+
* before the field existed, which read as active.
|
|
678
|
+
*/
|
|
679
|
+
retired?: boolean;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* A prescriptive conformance rule (`wicked-governance::ConformanceRule`).
|
|
684
|
+
* `rule_type`: `pattern` | `policy`. `severity`: `info` | `warn` | `error` | `critical`.
|
|
685
|
+
*/
|
|
686
|
+
export interface ConformanceRule {
|
|
687
|
+
id: string;
|
|
688
|
+
rule_type: 'pattern' | 'policy';
|
|
689
|
+
statement: string;
|
|
690
|
+
severity: 'info' | 'warn' | 'error' | 'critical';
|
|
691
|
+
confidence: number;
|
|
692
|
+
targets: { language?: string; layer?: string; framework?: string };
|
|
693
|
+
symbol_ref?: string;
|
|
694
|
+
compliance?: { framework: string; control_id: string };
|
|
695
|
+
provenance: { source: string; ref?: string; source_kinds: string[] };
|
|
696
|
+
/** Withdrawn from recall. Same contract as {@link GovernancePolicy.retired}. */
|
|
697
|
+
retired?: boolean;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/** Facet query for `GET /governance/rules/preview`. All fields are optional. */
|
|
701
|
+
export interface RulePreviewQuery {
|
|
702
|
+
language?: string;
|
|
703
|
+
layer?: string;
|
|
704
|
+
framework?: string;
|
|
705
|
+
severity?: string;
|
|
706
|
+
rule_type?: string;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// ── Governance claims (crew#40/43) ─────────────────────────────────────────────
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* A recorded governance decision from the conformance store (`wicked-apps-core::ConformanceClaim`).
|
|
713
|
+
* `decision` values: `allow` | `deny` | `allow_with_conditions`.
|
|
714
|
+
*/
|
|
715
|
+
export interface GovernanceClaim {
|
|
716
|
+
claim_id: string;
|
|
717
|
+
scope: string;
|
|
718
|
+
phase: string;
|
|
719
|
+
policy_ids: string[];
|
|
720
|
+
decision: 'allow' | 'deny' | 'allow_with_conditions';
|
|
721
|
+
obligations: string[];
|
|
722
|
+
evaluated_context_ref: string;
|
|
723
|
+
criteria: string;
|
|
724
|
+
evaluator_identity: string;
|
|
725
|
+
/** Unix-seconds timestamp. */
|
|
726
|
+
evaluated_at: number;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/** The launch-run request body (`POST /runs`). */
|
|
730
|
+
export interface LaunchRunBody {
|
|
731
|
+
problem: string;
|
|
732
|
+
sessionId?: string;
|
|
733
|
+
clisJson?: string;
|
|
734
|
+
entityMode?: EntityMode;
|
|
735
|
+
humanConfirm?: string;
|
|
736
|
+
repoRef?: string;
|
|
737
|
+
/** Built-in workflow id (`feature` | `bug` | `migration`); omit for free-text single-unit mode. */
|
|
738
|
+
workflow?: string;
|
|
739
|
+
/**
|
|
740
|
+
* The project to file this run into (DES-PROJECT-001 §2.2). The `crew.run` membership is
|
|
741
|
+
* attached atomically with the launch record; an unknown or archived project fails the launch
|
|
742
|
+
* (4xx) — never a silent unfiled run. Omit for an unfiled run (the synthesized `default`).
|
|
743
|
+
*/
|
|
744
|
+
projectId?: string;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// ── Governance types (crew#40/41) ──────────────────────────────────────────────
|
|
748
|
+
|
|
749
|
+
/** Per-app breakdown within a `CoverageReport`. */
|
|
750
|
+
export interface CoveragePerApp {
|
|
751
|
+
app: string;
|
|
752
|
+
behavior_bearing: number;
|
|
753
|
+
resolved: number;
|
|
754
|
+
risk_flagged: number;
|
|
755
|
+
unaccounted: number;
|
|
756
|
+
coverage: number;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/** A behavior-bearing node without a coverage annotation (a coverage hole). */
|
|
760
|
+
export interface UnaccountedNode {
|
|
761
|
+
symbol_id: string;
|
|
762
|
+
name?: string;
|
|
763
|
+
kind?: string;
|
|
764
|
+
file?: string;
|
|
765
|
+
app?: string;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Front-half coverage gate report (`wicked-governance::CoverageReport`).
|
|
770
|
+
* `null` when the graph store has no nodes.
|
|
771
|
+
*/
|
|
772
|
+
export interface CoverageReport {
|
|
773
|
+
total: number;
|
|
774
|
+
behavior_bearing: number;
|
|
775
|
+
resolved: number;
|
|
776
|
+
risk_flagged: number;
|
|
777
|
+
unaccounted: number;
|
|
778
|
+
coverage: number;
|
|
779
|
+
resolved_rate: number;
|
|
780
|
+
mean_confidence: number;
|
|
781
|
+
resolve_threshold: number;
|
|
782
|
+
per_app: CoveragePerApp[];
|
|
783
|
+
unaccounted_nodes: UnaccountedNode[];
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/** One entry of a repo's code-graph summary — a node kind and how many the graph holds (#122). */
|
|
787
|
+
export interface GraphKind {
|
|
788
|
+
kind: string;
|
|
789
|
+
count: number;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// ── Workflow viewer + domain-model browser types (crew#44) ──────────────────
|
|
793
|
+
|
|
794
|
+
/** Gate position in the value→strategy→execution ladder. */
|
|
795
|
+
export type GateType = 'value' | 'strategy' | 'execution';
|
|
796
|
+
|
|
797
|
+
/** Human-confirm spec for a phase gate (serde flattened from Rust enum). */
|
|
798
|
+
export type GateSpec =
|
|
799
|
+
| 'auto'
|
|
800
|
+
| { human_confirm: { unconditional: boolean } }
|
|
801
|
+
| { human_confirm_if: 'verdict_not_pass' };
|
|
802
|
+
|
|
803
|
+
/** Evaluator≠creator role for a phase. */
|
|
804
|
+
export type PhaseRole = 'neutral' | 'creator' | 'evaluator';
|
|
805
|
+
|
|
806
|
+
/** Methodology stage for a phase (same tokens as {@link StageKind}). */
|
|
807
|
+
export type StageKindPhase = 'recon' | 'build' | 'review' | 'test';
|
|
808
|
+
|
|
809
|
+
/** How a phase executes — agent (council-routed CLI) or tool (direct command). */
|
|
810
|
+
export type PhaseExecutor =
|
|
811
|
+
| { type: 'agent' }
|
|
812
|
+
| { type: 'tool'; cmd: string[] };
|
|
813
|
+
|
|
814
|
+
/** One ordered phase of a workflow — pure data. */
|
|
815
|
+
export interface PhaseDef {
|
|
816
|
+
id: string;
|
|
817
|
+
kind: StageKindPhase;
|
|
818
|
+
/** How the phase executes. Omitted = Agent (engine default). Tool phases bypass the council and
|
|
819
|
+
* run `cmd` directly. */
|
|
820
|
+
executor?: PhaseExecutor;
|
|
821
|
+
/** Per-phase agent instructions folded into the unit prompt by the engine (core PhaseDef.instructions,
|
|
822
|
+
* Option<String>). Absent = no extra instruction. Mirrors of core drop-ins that carry it (e.g.
|
|
823
|
+
* survey-repo) MUST reproduce it verbatim or the runtime def diverges from core's — FINDING-011. */
|
|
824
|
+
instructions?: string | null;
|
|
825
|
+
gate_type: GateType | null;
|
|
826
|
+
gate: GateSpec;
|
|
827
|
+
executes_code: boolean;
|
|
828
|
+
verified_evidence: boolean;
|
|
829
|
+
required_deliverables: string[];
|
|
830
|
+
depends_on: string[];
|
|
831
|
+
role: PhaseRole;
|
|
832
|
+
skill_ref: string | null;
|
|
833
|
+
allowed_skills: string[];
|
|
834
|
+
validator_pin: string | null;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/** A workflow — id + ordered phases. */
|
|
838
|
+
export interface WorkflowDef {
|
|
839
|
+
id: string;
|
|
840
|
+
phases: PhaseDef[];
|
|
841
|
+
/** True for built-in workflows that have dedicated entry points and must not appear in the work-mode selector. */
|
|
842
|
+
is_system?: boolean;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/** Top-level requirements_graph.json artifact (schema 1.0.0). */
|
|
846
|
+
export interface DomainGraph {
|
|
847
|
+
metadata: { schema_version: string; migration_mode: string; source?: string };
|
|
848
|
+
domains: Record<string, DomainGraphDomain>;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/** A capability domain in the requirements graph. */
|
|
852
|
+
export interface DomainGraphDomain {
|
|
853
|
+
description?: string;
|
|
854
|
+
cluster_id?: number;
|
|
855
|
+
requirements: Record<string, DomainGraphRequirement>;
|
|
856
|
+
entities: Record<string, { description?: string }>;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/** A requirement in a domain. */
|
|
860
|
+
export interface DomainGraphRequirement {
|
|
861
|
+
title: string;
|
|
862
|
+
description: string;
|
|
863
|
+
status?: string;
|
|
864
|
+
disposition?: string;
|
|
865
|
+
business_rules: Array<{ id: string; statement: string; confidence: number; provenance: { source: string } }>;
|
|
866
|
+
validations: Array<{ id: string; statement: string; confidence?: number }>;
|
|
867
|
+
error_paths: Array<{ id: string; statement: string }>;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/** Coverage stats from `wicked-core coverage --json` — present when code is indexed but domain not yet annotated. */
|
|
871
|
+
export interface DomainCoverage {
|
|
872
|
+
coverage: number;
|
|
873
|
+
total: number;
|
|
874
|
+
behavior_bearing: number;
|
|
875
|
+
resolved: number;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/** The open-terminal request body (`POST /terminals`, DES-TERMINAL-001 §6). */
|
|
879
|
+
export interface OpenTerminalBody {
|
|
880
|
+
/** Working directory the PTY opens in. */
|
|
881
|
+
cwd: string;
|
|
882
|
+
/** Command to run; omit for the user's login shell. */
|
|
883
|
+
cmd?: string[];
|
|
884
|
+
cols: number;
|
|
885
|
+
rows: number;
|
|
886
|
+
/**
|
|
887
|
+
* Omit for the safe governed default; `false` is the loud, opt-in UNGOVERNED
|
|
888
|
+
* operator shell (surfaced as ungoverned in the UI, DES-TERMINAL-001 §7).
|
|
889
|
+
*/
|
|
890
|
+
governed?: boolean;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/** Symbol-level code graph from estate (GET /repos/:id/graph). */
|
|
894
|
+
export interface CodeGraphNode {
|
|
895
|
+
id: string; // estate symbol ID (primary key)
|
|
896
|
+
name: string; // short display name (function/class/type name)
|
|
897
|
+
kind: string; // function | class | struct | interface | type_alias | method | enum
|
|
898
|
+
file: string; // source file path
|
|
899
|
+
inDeg: number; // incoming call/import count (hotspot indicator)
|
|
900
|
+
outDeg: number; // outgoing call/import count
|
|
901
|
+
lang: string; // language (typescript, rust, python, etc.)
|
|
902
|
+
}
|
|
903
|
+
export interface CodeGraphEdge { src: string; tgt: string; }
|
|
904
|
+
export interface CodeGraphData {
|
|
905
|
+
nodes: CodeGraphNode[];
|
|
906
|
+
edges: CodeGraphEdge[];
|
|
907
|
+
stats: { nodeCount: number; edgeCount: number; fileCount: number };
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
export interface GitCommit {
|
|
911
|
+
sha: string;
|
|
912
|
+
shortSha: string;
|
|
913
|
+
message: string;
|
|
914
|
+
author: string;
|
|
915
|
+
date: string;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
export interface GitContributor {
|
|
919
|
+
commits: number;
|
|
920
|
+
name: string;
|
|
921
|
+
email: string;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/** Daemon-persisted system settings (~/.config/wicked-core/settings.json). */
|
|
925
|
+
export interface SystemSettings {
|
|
926
|
+
/** Max nodes returned by wicked-estate graph-view (default 150). */
|
|
927
|
+
graphNodeLimit: number;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// ── Requirements management (server-side search + overrides; crew api/requirements.ts) ──
|
|
931
|
+
export interface RequirementSummary {
|
|
932
|
+
key: string;
|
|
933
|
+
domain: string;
|
|
934
|
+
reqId: string;
|
|
935
|
+
title: string;
|
|
936
|
+
category: 'functional' | 'config-data';
|
|
937
|
+
statement: string;
|
|
938
|
+
status: string;
|
|
939
|
+
risk: boolean;
|
|
940
|
+
riskSource: 'operator' | 'data' | null;
|
|
941
|
+
edited: boolean;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
export interface RequirementDetail extends RequirementSummary {
|
|
945
|
+
description: string;
|
|
946
|
+
notes: string;
|
|
947
|
+
sourceTitle: string;
|
|
948
|
+
ruleCount: number;
|
|
949
|
+
componentCount: number;
|
|
950
|
+
validationCount: number;
|
|
951
|
+
errorPathCount: number;
|
|
952
|
+
businessRules: unknown[];
|
|
953
|
+
legacyComponents: unknown[];
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
export interface RequirementsPage {
|
|
957
|
+
total: number;
|
|
958
|
+
corpus: number;
|
|
959
|
+
offset: number;
|
|
960
|
+
limit: number;
|
|
961
|
+
items: RequirementSummary[];
|
|
962
|
+
/** Which source served the corpus: the live estate store, or the evidence-gated
|
|
963
|
+
* `requirements_graph.json` snapshot, which can lag it by hours (FINDING-065). */
|
|
964
|
+
source: 'store' | 'artifact';
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
export interface RequirementPatch {
|
|
968
|
+
title?: string;
|
|
969
|
+
notes?: string;
|
|
970
|
+
status?: 'active' | 'deprecated' | 'review';
|
|
971
|
+
risk?: boolean;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// ── Blast radius (wicked-estate blast-radius --json via crew) ──
|
|
975
|
+
export interface BlastRadius {
|
|
976
|
+
target: string;
|
|
977
|
+
dependents: Array<{ id: string; name: string; kind: string; file: string; line: number }>;
|
|
978
|
+
/** Unresolved call-sites referencing the target — absence of dependents never means "safe". */
|
|
979
|
+
unresolved: number;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/** An open elicitation as `GET /runs/:id/elicitation` returns it (DES-002). */
|
|
983
|
+
export interface ElicitationInfo {
|
|
984
|
+
runId: string;
|
|
985
|
+
elicitationId: string;
|
|
986
|
+
message: string;
|
|
987
|
+
/** Ordered set of valid responses; `null` means free-text. */
|
|
988
|
+
options: string[] | null;
|
|
989
|
+
receivedAt: string;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
/** `POST /runs/:id/elicitation` body. `content` is required for accept, absent otherwise. */
|
|
993
|
+
export interface ElicitationResponse {
|
|
994
|
+
elicitationId: string;
|
|
995
|
+
action: 'accept' | 'decline' | 'cancel';
|
|
996
|
+
content?: { response: string };
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// ── Projects (DES-PROJECT-001) — the experience-plane keystone ─────────────────
|
|
1000
|
+
|
|
1001
|
+
/** Project lifecycle: `active ⇄ archived`, no hard delete (ADR §1.3). */
|
|
1002
|
+
export type ProjectLifecycle = 'active' | 'archived';
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* A named, control-plane-owned container whose members are work units from any
|
|
1006
|
+
* plane (`GET /projects`, `GET /projects/:id`). Mirrors wicked-core's serde
|
|
1007
|
+
* shape (`project.rs`) — Rust `Option` fields arrive as `null`, never absent.
|
|
1008
|
+
* The synthesized `default` project ("Unfiled") appears in lists with
|
|
1009
|
+
* `id: "default"`, `scope: ""`, and zero timestamps; it rejects PATCH/attach.
|
|
1010
|
+
*/
|
|
1011
|
+
export interface Project {
|
|
1012
|
+
/** `proj_<sortable>` — minted by control at create; or the reserved `default`. */
|
|
1013
|
+
id: string;
|
|
1014
|
+
name: string;
|
|
1015
|
+
description: string | null;
|
|
1016
|
+
status: ProjectLifecycle;
|
|
1017
|
+
/** The estate scope path of this project's record (`project:<id>`; `""` for `default`). */
|
|
1018
|
+
scope: string;
|
|
1019
|
+
/** Unix millis. */
|
|
1020
|
+
created_at: number;
|
|
1021
|
+
/** Unix millis. */
|
|
1022
|
+
updated_at: number;
|
|
1023
|
+
[k: string]: unknown;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
/**
|
|
1027
|
+
* A typed, opaque membership reference (ADR §1.2). `member_kind` is the open
|
|
1028
|
+
* `<product>.<noun>` grammar (`crew.run`, `crew.chat`, `crew.repo`,
|
|
1029
|
+
* `crew.workflow`, `interactive.doc`, reserved `studio.session`).
|
|
1030
|
+
*/
|
|
1031
|
+
export interface ProjectMember {
|
|
1032
|
+
/** Derived from `(project_id, member_kind, member_ref)` — the UNIQUE constraint. */
|
|
1033
|
+
id: string;
|
|
1034
|
+
project_id: string;
|
|
1035
|
+
member_kind: string;
|
|
1036
|
+
/** Opaque to the engine; `crew.*` refs are checked at the API layer at attach time. */
|
|
1037
|
+
member_ref: string;
|
|
1038
|
+
/** Skin hints (doc root, display title, …) as JSON text; `null` when none. */
|
|
1039
|
+
meta: string | null;
|
|
1040
|
+
/** Unix millis. */
|
|
1041
|
+
attached_at: number;
|
|
1042
|
+
/** The attaching surface: `studio` | `interactive` | `cli` | `api`. */
|
|
1043
|
+
attached_by: string;
|
|
1044
|
+
[k: string]: unknown;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
/** `GET /projects/:id` — detail + members (ADR §5.2). */
|
|
1048
|
+
export interface ProjectDetail {
|
|
1049
|
+
project: Project;
|
|
1050
|
+
members: ProjectMember[];
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/** `POST /projects` body. */
|
|
1054
|
+
export interface CreateProjectBody {
|
|
1055
|
+
/** 1–120 chars; unique among ACTIVE projects (409 on collision). */
|
|
1056
|
+
name: string;
|
|
1057
|
+
description?: string;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/** `PATCH /projects/:id` body — rename / describe / archive / restore. */
|
|
1061
|
+
export interface UpdateProjectBody {
|
|
1062
|
+
name?: string;
|
|
1063
|
+
/** `""` clears the description. */
|
|
1064
|
+
description?: string;
|
|
1065
|
+
status?: ProjectLifecycle;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/** `POST /projects/:id/members` body. */
|
|
1069
|
+
export interface AttachMemberBody {
|
|
1070
|
+
/** `<product>.<noun>` (open grammar). */
|
|
1071
|
+
kind: string;
|
|
1072
|
+
ref: string;
|
|
1073
|
+
/** Skin hints, carried opaquely. */
|
|
1074
|
+
meta?: Record<string, unknown>;
|
|
1075
|
+
/** The attaching surface; defaults to `api`. */
|
|
1076
|
+
attachedBy?: 'studio' | 'interactive' | 'cli' | 'api';
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* One normalized entry of the merged project activity feed
|
|
1081
|
+
* (`GET /projects/:id/activity`, ADR §5.2): core events of member runs/chats
|
|
1082
|
+
* ∪ bus `wicked.interactive.*` events carrying this `project_id`.
|
|
1083
|
+
*/
|
|
1084
|
+
export interface ActivityEntry {
|
|
1085
|
+
/** Stable entry id (`crew:<run>:<seq>` | `bus:<event_id>`) — the cursor tiebreaker. */
|
|
1086
|
+
id: string;
|
|
1087
|
+
/** Unix millis. */
|
|
1088
|
+
ts: number;
|
|
1089
|
+
source: 'crew' | 'interactive';
|
|
1090
|
+
/** The event type (`awaitingHuman`, `wicked.interactive.version.created`, …). */
|
|
1091
|
+
kind: string;
|
|
1092
|
+
/** The member the entry belongs to (run id, doc name). */
|
|
1093
|
+
ref: string;
|
|
1094
|
+
summary: string;
|
|
1095
|
+
/** The original frame/payload, verbatim. */
|
|
1096
|
+
raw: unknown;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/** `GET /projects/:id/activity` — newest-first, cursor-paginated on `(ts, id)`. */
|
|
1100
|
+
export interface ActivityPage {
|
|
1101
|
+
projectId: string;
|
|
1102
|
+
entries: ActivityEntry[];
|
|
1103
|
+
/** Opaque; pass back as `?cursor=`. `null` ⇒ no older entries. */
|
|
1104
|
+
nextCursor: string | null;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* A durable interaction request (DES-PROJECT-001 §5.3) as the engine persists
|
|
1109
|
+
* it — written in the same transaction as the run's `awaiting_human`
|
|
1110
|
+
* transition, resolved in the same transaction as the gate decision. The
|
|
1111
|
+
* prompt inbox (`GET /projects/:id/prompts`) returns the OPEN ones across the
|
|
1112
|
+
* project's member runs.
|
|
1113
|
+
*/
|
|
1114
|
+
export interface InteractionRequest {
|
|
1115
|
+
/** `ir_<derived>` — stable across re-pauses of the same `(run, kind, ord)`. */
|
|
1116
|
+
id: string;
|
|
1117
|
+
/** The owning run. */
|
|
1118
|
+
session_id: string;
|
|
1119
|
+
kind: 'gate' | 'elicitation';
|
|
1120
|
+
/** The unit ordinal the gate pauses before; `null` when not unit-bound. */
|
|
1121
|
+
ord: number | null;
|
|
1122
|
+
/** The already-run unit the gate reviews, when attributable. */
|
|
1123
|
+
reviewing_ord: number | null;
|
|
1124
|
+
prompt: string;
|
|
1125
|
+
status: 'open' | 'answered' | 'expired' | 'cancelled';
|
|
1126
|
+
/** The decision payload (JSON text, e.g. `{"approve":true,"amend":null}`) once resolved. */
|
|
1127
|
+
answer: string | null;
|
|
1128
|
+
/** Unix millis. */
|
|
1129
|
+
created_at: number;
|
|
1130
|
+
/** Unix millis; `null` while open. */
|
|
1131
|
+
resolved_at: number | null;
|
|
1132
|
+
[k: string]: unknown;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/** `GET /projects/:id/prompts` — the open prompt inbox across member runs. */
|
|
1136
|
+
export interface ProjectPrompts {
|
|
1137
|
+
projectId: string;
|
|
1138
|
+
prompts: InteractionRequest[];
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
/** `POST /chats` body (gains `projectId` with DES-PROJECT-001). */
|
|
1142
|
+
export interface ChatOpenBody {
|
|
1143
|
+
chatId?: string;
|
|
1144
|
+
clis?: string[];
|
|
1145
|
+
repoRef?: string;
|
|
1146
|
+
/** File the chat into a project (`crew.chat` membership, attached on open). */
|
|
1147
|
+
projectId?: string;
|
|
1148
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wicked-crew-api-types",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The wire contract of the wicked-crew daemon's /api/v1 REST surface and /ws CoreEvent frames — types only, zero runtime",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"types": "./index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./index.d.ts"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"index.d.ts"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/mikeparcewski/wicked-crew.git",
|
|
18
|
+
"directory": "packages/crew-api-types"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/mikeparcewski/wicked-crew/tree/main/packages/crew-api-types#readme",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/mikeparcewski/wicked-crew/issues"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"wicked-crew",
|
|
26
|
+
"api-types",
|
|
27
|
+
"wire-contract",
|
|
28
|
+
"typescript"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"typecheck": "tsc -p tsconfig.json"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"typescript": "^5.5.0"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22.0.0"
|
|
41
|
+
},
|
|
42
|
+
"license": "MIT"
|
|
43
|
+
}
|