wicked-crew-api-types 0.39.0 → 0.69.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/index.d.ts +2397 -70
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -84,7 +84,25 @@ export interface AuditEntry {
|
|
|
84
84
|
[k: string]: unknown;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* `GET /audit`'s query (api-types 0.43.0 adds `since`). Every filter is optional and they
|
|
89
|
+
* compose (AND); an empty value is absent. A malformed `limit` or `since` answers 400.
|
|
90
|
+
*/
|
|
91
|
+
export interface AuditQuery {
|
|
92
|
+
runId?: string;
|
|
93
|
+
action?: string;
|
|
94
|
+
/** Max entries returned, newest first. Default 200, capped at 1000. */
|
|
95
|
+
limit?: number;
|
|
96
|
+
/**
|
|
97
|
+
* Inclusive lower bound on {@link AuditEntry.ts} (unix MILLIS): keep entries with
|
|
98
|
+
* `ts >= since`. Applied before `limit`. The "while you were away" read: a skin passes the
|
|
99
|
+
* operator's last-visit instant and gets what happened since, including `system` actors'
|
|
100
|
+
* actions (the stall watchdog's `run.stall.*` entries).
|
|
101
|
+
*/
|
|
102
|
+
since?: number;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** `GET /audit` — newest first, filterable by {@link AuditQuery} (`?runId=` / `?action=` / `?limit=` / `?since=`). */
|
|
88
106
|
export interface AuditPage {
|
|
89
107
|
entries: AuditEntry[];
|
|
90
108
|
}
|
|
@@ -111,7 +129,15 @@ export type EntityMode = 'shared' | 'isolated';
|
|
|
111
129
|
/** Human-confirm gate policy. serde: `None`→"none", `All`→"all", `Before(n)`→{ before: n }. */
|
|
112
130
|
export type HumanConfirm = 'none' | 'all' | { before: number };
|
|
113
131
|
|
|
114
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* Why a CLI was assigned to a unit (`RoutingInfo`, internally tagged on `method`).
|
|
134
|
+
*
|
|
135
|
+
* `teamed` (wicked-core#590 S5) is what every seated unit of a new run carries: the engine no
|
|
136
|
+
* longer convenes a council to route, it picks the first eligible seat the unit's skills admit, in
|
|
137
|
+
* roster order (`winner`), and the evaluator ≠ creator fence then moves a review/test unit off a
|
|
138
|
+
* builder seat (`evaluator_distinct`, whose `was` is the teamed pick). `council` and `degraded` are
|
|
139
|
+
* no longer produced; they stay because a recorded run's units carry them.
|
|
140
|
+
*/
|
|
115
141
|
export type RoutingInfo =
|
|
116
142
|
/**
|
|
117
143
|
* `seated` is the seats CONVENED — the denominator `returned` must be read against.
|
|
@@ -135,7 +161,8 @@ export type RoutingInfo =
|
|
|
135
161
|
}
|
|
136
162
|
| { method: 'degraded'; reason: string }
|
|
137
163
|
| { method: 'evaluator_distinct'; winner: string; was: string }
|
|
138
|
-
| { method: 'tool' }
|
|
164
|
+
| { method: 'tool' }
|
|
165
|
+
| { method: 'teamed'; winner: string };
|
|
139
166
|
|
|
140
167
|
/**
|
|
141
168
|
* `GET /health` (api-types 0.37.0 — the shape was previously undeclared here; `status`,
|
|
@@ -157,6 +184,8 @@ export type RoutingInfo =
|
|
|
157
184
|
export interface HealthResponse {
|
|
158
185
|
status: string;
|
|
159
186
|
version: string;
|
|
187
|
+
/** The engine actor's answer (`"ok"`), or `"busy"` when the actor did not answer within ~1 s
|
|
188
|
+
* (crew#471): the daemon serves while the engine is occupied — a large launch is planning. */
|
|
160
189
|
ping: string;
|
|
161
190
|
capabilities?: HealthCapabilities;
|
|
162
191
|
/**
|
|
@@ -280,12 +309,18 @@ export interface AgentSession {
|
|
|
280
309
|
*
|
|
281
310
|
* - `'delivered'` — a PR was opened for this run (by the deliver phase, or post-hoc via
|
|
282
311
|
* `POST /runs/:id/deliver`); `deliverUrl` carries the PR URL.
|
|
312
|
+
* - `'pushed'` — (api-types 0.69.0, N1) the run's branch was PUSHED and that is the whole
|
|
313
|
+
* delivery: no pull request could be opened because the origin is not a GitHub host gh can
|
|
314
|
+
* resolve (a local path, SSH, GitLab, ADO, Gitea…). `deliverBranch` + `deliverRemote` say
|
|
315
|
+
* what is where. Nothing is left to lift, so no post-hoc deliver is offered (`POST
|
|
316
|
+
* /runs/:id/deliver` answers 409); opening the pull/merge request is the forge's, by hand.
|
|
283
317
|
* - `'stranded'` — reviewable work nobody lifted, reached two ways: a COMPLETED repo-scoped
|
|
284
318
|
* run with no recorded PR whose worktree still exists on disk AND carries work (derived
|
|
285
319
|
* honestly for OLD runs too — records written before this field existed strand the same
|
|
286
|
-
* way); OR (crew#418) a run whose deliver phase hit a LIFT collision — a rebase conflict
|
|
287
|
-
*
|
|
288
|
-
*
|
|
320
|
+
* way); OR (crew#418) a run whose deliver phase hit a LIFT collision — a rebase conflict
|
|
321
|
+
* (a push the remote REFUSED no longer strands: since 0.69.0 it parks the run at the
|
|
322
|
+
* engine's deliver-refusal gate, N4) — which the daemon reinterprets from the engine's
|
|
323
|
+
* `failed` to `completed`+`stranded`: its work is committed on the `wicked/<id>` branch (the engine
|
|
289
324
|
* reaps the now-clean worktree, but never the branch), recoverable via `POST /runs/:id/
|
|
290
325
|
* deliver`, which stands a throwaway worktree back up from that branch to lift it.
|
|
291
326
|
* - `'vacuous'` — a COMPLETED repo-scoped run whose surviving worktree carries NO
|
|
@@ -308,7 +343,7 @@ export interface AgentSession {
|
|
|
308
343
|
* FAILURE of a deliver phase is not spelled here; it is `units[].status === 'rejected'`
|
|
309
344
|
* plus `denial_reason` (crew#318's message), both already on the list wire.
|
|
310
345
|
*/
|
|
311
|
-
delivery?: 'delivered' | 'stranded' | 'vacuous' | 'none';
|
|
346
|
+
delivery?: 'delivered' | 'pushed' | 'stranded' | 'vacuous' | 'none';
|
|
312
347
|
/**
|
|
313
348
|
* The delivered PR's URL (crew#393; api-types 0.18.0) — present exactly when
|
|
314
349
|
* `delivery === 'delivered'`; absent otherwise (absence is the one spelling, never `null`).
|
|
@@ -319,6 +354,13 @@ export interface AgentSession {
|
|
|
319
354
|
* idempotent against the existing branch) and `'none'` after it is cleaned up.
|
|
320
355
|
*/
|
|
321
356
|
deliverUrl?: string;
|
|
357
|
+
/** The pushed run branch (api-types 0.69.0, N1) — present exactly when `delivery === 'pushed'`. */
|
|
358
|
+
deliverBranch?: string;
|
|
359
|
+
/**
|
|
360
|
+
* The remote the branch was pushed to (api-types 0.69.0, N1), with any URL userinfo removed —
|
|
361
|
+
* present exactly when `delivery === 'pushed'`. May be a filesystem path (a local bare origin).
|
|
362
|
+
*/
|
|
363
|
+
deliverRemote?: string;
|
|
322
364
|
/**
|
|
323
365
|
* The campaign this AD-HOC run was attached to at launch (`LaunchRunBody.campaignId`;
|
|
324
366
|
* wicked-studio#27, api-types 0.19.0) — daemon-joined at DTO assembly on `GET /runs` and
|
|
@@ -410,6 +452,15 @@ export interface AgentSession {
|
|
|
410
452
|
/** Wave 6 (F-7R2-006): the seats BENCHED for this run — never convened, never a failover or
|
|
411
453
|
* judge target. Absent (never `[]`) when none / on an older engine. */
|
|
412
454
|
benched_seats?: BenchedSeat[];
|
|
455
|
+
/**
|
|
456
|
+
* The run's APPROVED INTENT AMENDMENTS, in the order a human decided them (wicked-core#555;
|
|
457
|
+
* additive, engine ≥ the core-ts release after 0.7.30) — the `amend_intent` arm of a gate
|
|
458
|
+
* ({@link GateDecision.action}). Each amendment is appended to every unit at or after the
|
|
459
|
+
* gate's cursor, so the acceptance list each LATER EVALUATOR is handed changed with the
|
|
460
|
+
* decision. Render them beside the run's original intent: this is what was withdrawn or
|
|
461
|
+
* changed, and when. ABSENT (never `[]`) on an unamended run and on an older engine.
|
|
462
|
+
*/
|
|
463
|
+
intent_amendments?: IntentAmendment[];
|
|
413
464
|
/** crew#661: the declared skills this run's phases ran WITHOUT (the published skills snapshot did not
|
|
414
465
|
* hold them when the launching subsystem armed) — the run proceeded DEGRADED, and says so here.
|
|
415
466
|
* ABSENT (never `[]`) when the run launched fully armed, and on a daemon before this field. */
|
|
@@ -441,6 +492,78 @@ export interface AgentSession {
|
|
|
441
492
|
* this field.
|
|
442
493
|
*/
|
|
443
494
|
chat_grounded?: boolean;
|
|
495
|
+
/**
|
|
496
|
+
* The engine's plan state (wicked-core `TeamPlanState`, DES-TEAMING-002 §8.4-§8.6; api-types
|
|
497
|
+
* 0.46.0 types the engine field) — present on a run launched from a PLAN or a PRESET, ABSENT on
|
|
498
|
+
* every other run (a registered def, the free-text planner) and on a team run before its launch
|
|
499
|
+
* is scored. Engine-computed; typed here only as far as a skin reads it. Read the run's kind from
|
|
500
|
+
* {@link AgentSession.run_identity}, which is resolved from this.
|
|
501
|
+
*/
|
|
502
|
+
team_plan?: TeamPlanState;
|
|
503
|
+
/**
|
|
504
|
+
* What this run IS (seam X2; api-types 0.46.0) — daemon-resolved at DTO assembly on BOTH
|
|
505
|
+
* `GET /runs` and `GET /runs/:id` from the engine's own record (the plan state above, else the
|
|
506
|
+
* launch's recorded `sessionStarted`), never from the run's phase sequence. Always present on a
|
|
507
|
+
* 0.46.0+ daemon; ABSENT from an older one. `system` replaces a skin's own list of system
|
|
508
|
+
* workflow ids.
|
|
509
|
+
*/
|
|
510
|
+
run_identity?: RunIdentity;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* The fields of the engine's `TeamPlanState` a skin reads (the engine sends more — every field is
|
|
515
|
+
* engine-computed and additive).
|
|
516
|
+
*/
|
|
517
|
+
export interface TeamPlanState {
|
|
518
|
+
/** The last plan rev assigned (accepted or held). `0` = none yet. */
|
|
519
|
+
rev: number;
|
|
520
|
+
/** The last ACCEPTED plan rev. `0` = no plan accepted yet. */
|
|
521
|
+
accepted_rev: number;
|
|
522
|
+
/** The preset the launch named. ABSENT on a user plan. */
|
|
523
|
+
preset?: string;
|
|
524
|
+
/**
|
|
525
|
+
* (wicked-core#633, DES-TEAMING-002 X1; api-types 0.47.0) PRESENT while the run's PA is scoping
|
|
526
|
+
* its launch plan — a creator plan or preset that declared no `touch` set. Until the `pa-scope`
|
|
527
|
+
* unit's boundary decides the plan, the run's only unit is `pa-scope` (plan rev 1): what the run
|
|
528
|
+
* will contain is not known yet. ABSENT once the plan is scoped (or when none needed scoping).
|
|
529
|
+
*/
|
|
530
|
+
scope?: TeamPlanScopeHold;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/** The launch plan the PA is scoping (the engine's `ScopeHold`). */
|
|
534
|
+
export interface TeamPlanScopeHold {
|
|
535
|
+
/** The launch plan as authored (the preset's steps or the user's plan), without `pa-scope`. */
|
|
536
|
+
plan: { steps: TeamPlanStep[] } & Record<string, unknown>;
|
|
537
|
+
/** The run has no repo: the PA rates the risk (`RISK`) instead of declaring a touch set. */
|
|
538
|
+
unbound: boolean;
|
|
539
|
+
/** The scope step's `SCOPE` / `RISK` lines once its turn folds; ABSENT until then. */
|
|
540
|
+
answer?: { ord: number; attempt: number; by: string; lines: string };
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* What a run is (seam X2; api-types 0.46.0), resolved by the daemon from the engine's record.
|
|
545
|
+
*
|
|
546
|
+
* - `'preset'` — launched from a preset; `name` is the preset.
|
|
547
|
+
* - `'user_plan'` — launched from a user-composed plan (the engine's per-run `<run>:plan-<rev>`
|
|
548
|
+
* def); `name` is `null`.
|
|
549
|
+
* - `'workflow'` — launched on a registered workflow def; `name` is its id (a crew-composed
|
|
550
|
+
* per-run delivery/floor def reads as its base).
|
|
551
|
+
* - `'free_text'` — no workflow and no plan: the free-text planner; `name` is `null`.
|
|
552
|
+
* - `'unknown'` — the daemon has no record of what the launch named (a run predating the
|
|
553
|
+
* engine's event log, or an engine without the log read); `name` is `null`.
|
|
554
|
+
*/
|
|
555
|
+
export interface RunIdentity {
|
|
556
|
+
kind: 'preset' | 'user_plan' | 'workflow' | 'free_text' | 'unknown';
|
|
557
|
+
/** The preset or workflow name — `null` unless `kind` is `'preset'` or `'workflow'`. */
|
|
558
|
+
name: string | null;
|
|
559
|
+
/** `kind === 'user_plan'`, spelled out. */
|
|
560
|
+
user_plan: boolean;
|
|
561
|
+
/**
|
|
562
|
+
* A machine-owned run (chat, onboarding, the interactive document and video seams, …): skins keep
|
|
563
|
+
* it off delivery surfaces. Keyed by `name` against the daemon's ONE list — the same list that
|
|
564
|
+
* stamps `WorkflowDef.is_system` on `GET /workflows`.
|
|
565
|
+
*/
|
|
566
|
+
system: boolean;
|
|
444
567
|
}
|
|
445
568
|
|
|
446
569
|
/** An ordered unit of work within a run (`WorkUnit`). */
|
|
@@ -485,6 +608,34 @@ export interface WorkUnit {
|
|
|
485
608
|
* planned before the field existed, and on an older engine.
|
|
486
609
|
*/
|
|
487
610
|
base_skill_ref?: string | null;
|
|
611
|
+
/**
|
|
612
|
+
* The phase-catalog entry this unit instantiates (`build`, `review`, …) when it was planned from
|
|
613
|
+
* a catalog-composed plan — a preset or a user plan (wicked-core `WorkUnit.catalog`,
|
|
614
|
+
* DES-TEAMING-002 T3; api-types 0.46.0 types the engine field). ABSENT on every other unit.
|
|
615
|
+
*/
|
|
616
|
+
catalog?: string;
|
|
617
|
+
/** TRUE on a unit of a TEAM run (planned from the per-run plan def); ABSENT otherwise. Engine field. */
|
|
618
|
+
team_run?: boolean;
|
|
619
|
+
/**
|
|
620
|
+
* TRUE when this unit's phase declared `requires_capture_report` (wicked-core#535 / BC-80) —
|
|
621
|
+
* carried from the def at plan time. ABSENT on every other unit and on an older engine.
|
|
622
|
+
*/
|
|
623
|
+
requires_capture_report?: boolean;
|
|
624
|
+
/**
|
|
625
|
+
* What the capture phase REPORTED, read from its output marker by the gate fold
|
|
626
|
+
* (wicked-core#535 / BC-80): `derived` learnings, `submitted` proposals, `failed` submissions.
|
|
627
|
+
* Present once a capture unit emitted a well-formed marker — whether it passed or denied, so the
|
|
628
|
+
* counts are readable beside the denial. ABSENT on every other unit, on a capture unit whose
|
|
629
|
+
* marker was MISSING (that denies; the denial is the record), and on an older engine.
|
|
630
|
+
*/
|
|
631
|
+
capture_report?: CaptureReport;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/** The counts a capture phase reported (`WorkUnit.capture_report`; wicked-core#535). */
|
|
635
|
+
export interface CaptureReport {
|
|
636
|
+
derived: number;
|
|
637
|
+
submitted: number;
|
|
638
|
+
failed: number;
|
|
488
639
|
}
|
|
489
640
|
|
|
490
641
|
/** A run plus its ordered units (`SessionView`) — the shape `GET /runs` returns. */
|
|
@@ -617,9 +768,29 @@ export interface RosterSeat {
|
|
|
617
768
|
* while every ballot failed. Absent = the probe decided (and since 0.36.0 the probe itself needs
|
|
618
769
|
* a credential-SHAPED file, never mere presence).
|
|
619
770
|
*/
|
|
620
|
-
auth_source?: 'seat-stderr';
|
|
621
|
-
/** Present with `auth_source: 'seat-stderr'
|
|
771
|
+
auth_source?: 'seat-stderr' | 'probe';
|
|
772
|
+
/** Present with `auth_source: 'seat-stderr'`, and with `probe` when it read signed out: the
|
|
773
|
+
* seat's own words, bounded. */
|
|
622
774
|
auth_evidence?: string;
|
|
775
|
+
/**
|
|
776
|
+
* Present with `auth_source: 'probe'` (crew#630): ISO-8601 of the seat's own auth-status check
|
|
777
|
+
* (`claude auth status`, `codex login status`) under the seat's configuration home, which then
|
|
778
|
+
* decided `auth` and `signed_in` over the credential file. The daemon re-checks in the
|
|
779
|
+
* background (a signed-in answer after 5 minutes, any other after 30 s). A probed seat whose
|
|
780
|
+
* check has not answered yet reads `unknown`, never `signed_in` off its file.
|
|
781
|
+
*/
|
|
782
|
+
probed_at?: string;
|
|
783
|
+
/**
|
|
784
|
+
* How far `auth` was VERIFIED (crew#645): `live` — the seat answered an authenticated request, or
|
|
785
|
+
* refused one for want of a credential (a status command reads the stored login, so an expired
|
|
786
|
+
* OAuth login still reads signed in there; the daemon makes one short live request when it says
|
|
787
|
+
* signed in); `status` — only the status command answered (the live request could not tell);
|
|
788
|
+
* `unverified` — nothing asked the seat (it has no status command, or its check has not answered
|
|
789
|
+
* or could not tell). Optional on the wire: a daemon before it sends none.
|
|
790
|
+
*/
|
|
791
|
+
login_check?: 'live' | 'status' | 'unverified';
|
|
792
|
+
/** Present unless `login_check` is `live`: why, in the operator's words ("login unverified — …"). */
|
|
793
|
+
login_note?: string;
|
|
623
794
|
/** Present when `auth` is `not_required`: the free tier the seat answers on. */
|
|
624
795
|
free_tier?: string;
|
|
625
796
|
/**
|
|
@@ -650,9 +821,33 @@ export interface RosterSeat {
|
|
|
650
821
|
* a reader must tolerate absence today.
|
|
651
822
|
*/
|
|
652
823
|
council_bench?: RosterSeatCouncilBench;
|
|
824
|
+
/**
|
|
825
|
+
* (core#581) Present on a seat whose ACP config pins `verified_version`, once the daemon's
|
|
826
|
+
* probe has answered: the build the seat's input-governance admission was proven against and
|
|
827
|
+
* what the binary reports now. `matched: false` with `governanceClaimed: true` means the engine
|
|
828
|
+
* fails the seat's ACP governance closed at every spawn.
|
|
829
|
+
*/
|
|
830
|
+
version_pin?: SeatVersionPin;
|
|
653
831
|
[k: string]: unknown;
|
|
654
832
|
}
|
|
655
833
|
|
|
834
|
+
/**
|
|
835
|
+
* One pinned seat's `--version` reading (core#581): `RosterSeat.version_pin` and
|
|
836
|
+
* `AcpCliDiagnostics.versionPin`. Read the way the engine's spawn-time check reads it: the pin
|
|
837
|
+
* matches only the first line of `--version`, trimmed; `observed` is the first non-empty line,
|
|
838
|
+
* `null` when the binary did not answer.
|
|
839
|
+
*/
|
|
840
|
+
export interface SeatVersionPin {
|
|
841
|
+
cli: string;
|
|
842
|
+
binary: string;
|
|
843
|
+
pinned: string;
|
|
844
|
+
observed: string | null;
|
|
845
|
+
matched: boolean;
|
|
846
|
+
governanceClaimed: boolean;
|
|
847
|
+
/** The operator-facing reason when a governed seat's pin does not hold; else `null`. */
|
|
848
|
+
disclosure: string | null;
|
|
849
|
+
}
|
|
850
|
+
|
|
656
851
|
/** `RosterSeat.council_bench` (api-types 0.35.0).
|
|
657
852
|
* @deprecated ABSENT from crew 0.7.36 (see {@link RosterSeat.council_bench}); removed one minor later. */
|
|
658
853
|
export interface RosterSeatCouncilBench {
|
|
@@ -670,6 +865,62 @@ export interface RosterSeatCouncilBench {
|
|
|
670
865
|
window_ms: number;
|
|
671
866
|
}
|
|
672
867
|
|
|
868
|
+
/**
|
|
869
|
+
* `GET /roster/record?days=N` (api-types 0.52.0): each seat's record over the last N days (default 7,
|
|
870
|
+
* max 30), folded from the runs' durable event logs (studio's weekly 1:1 per agent). Nothing new is
|
|
871
|
+
* stored; the window is by event time. A unit's seat is `unitDistributed.cli` (moved by
|
|
872
|
+
* `unitReassigned.newCli`), else the unit row's `assigned_cli`. 503 when the engine has no event-log
|
|
873
|
+
* read binding (a missing binding is not an empty week).
|
|
874
|
+
*/
|
|
875
|
+
export interface SeatRecordResponse {
|
|
876
|
+
days: number;
|
|
877
|
+
/** Window start, unix MILLIS. */
|
|
878
|
+
since: number;
|
|
879
|
+
/** Window end (the read time), unix MILLIS. */
|
|
880
|
+
until: number;
|
|
881
|
+
/** Runs whose event log was read. */
|
|
882
|
+
runsRead: number;
|
|
883
|
+
/** True when the daemon's per-read run cap cut the read (the oldest runs in the window were skipped). */
|
|
884
|
+
truncated: boolean;
|
|
885
|
+
/** Seats with any record in the window, by key. A roster seat absent here had no units and no bench. */
|
|
886
|
+
seats: SeatRecord[];
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
/** One seat's week (`SeatRecordResponse.seats[]`). */
|
|
890
|
+
export interface SeatRecord {
|
|
891
|
+
/** The roster key. */
|
|
892
|
+
cli: string;
|
|
893
|
+
/** Distinct units the seat was dispatched on in the window. */
|
|
894
|
+
units: number;
|
|
895
|
+
/** Units of this seat with a gate evaluation in the window. */
|
|
896
|
+
gated: number;
|
|
897
|
+
/** Of `gated`: the FIRST evaluation passed (`gateEvaluated.combined` and no `denial`). */
|
|
898
|
+
firstPass: number;
|
|
899
|
+
/** Units the seat ran first that were dispatched again (a retry or a send-back) or given a `unitReworkAmended`. */
|
|
900
|
+
rework: number;
|
|
901
|
+
/** Distinct units that went quiet (`workerStalled`, engine or daemon watchdog) while the seat ran them. */
|
|
902
|
+
stalls: number;
|
|
903
|
+
/** Runs in the window whose `benched_seats` names the seat. */
|
|
904
|
+
benched: number;
|
|
905
|
+
/** Bench reason → runs. */
|
|
906
|
+
benchReasons: Record<string, number>;
|
|
907
|
+
/** Summed `cliUsage.costUsd` where a price was known; `null` when no usage frame carried one (never `0` for "unknown"). */
|
|
908
|
+
costUsd: number | null;
|
|
909
|
+
/** Usage frames that carried a price. */
|
|
910
|
+
costedUsage: number;
|
|
911
|
+
/** Phase (`phase_ref`, else `stage`) → the same counts, so a move can name the phase. */
|
|
912
|
+
byPhase: Record<string, SeatPhaseRecord>;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/** One phase's slice of a {@link SeatRecord}. */
|
|
916
|
+
export interface SeatPhaseRecord {
|
|
917
|
+
units: number;
|
|
918
|
+
gated: number;
|
|
919
|
+
firstPass: number;
|
|
920
|
+
rework: number;
|
|
921
|
+
stalls: number;
|
|
922
|
+
}
|
|
923
|
+
|
|
673
924
|
/** A seat's auth reading (`RosterSeat.auth`; api-types 0.35.0). */
|
|
674
925
|
export type SeatAuth = 'signed_in' | 'signed_out' | 'not_required' | 'unknown';
|
|
675
926
|
|
|
@@ -765,8 +1016,39 @@ export interface GateDecision {
|
|
|
765
1016
|
* `unitDispatched{attempt: last + 1}`); requires `approve: false` — a disagreement between
|
|
766
1017
|
* `action` and `approve` answers 400, a gate with no creator phase before it 409. An older
|
|
767
1018
|
* daemon's strict schema rejects the key with a 400 — omit it against such servers.
|
|
1019
|
+
*
|
|
1020
|
+
* The ESCALATION arms (additive; wicked-core#469 / #467, engine ≥ the core-ts release after
|
|
1021
|
+
* 0.7.30): all require `approve: true` and take no `amend` / `amendScope` / `plan` (a 400
|
|
1022
|
+
* otherwise). `'extend'` | `'targeted'` | `'accept_partial'` answer the escalation gate of a
|
|
1023
|
+
* repo-checks floor that did not finish (`gateEscalated.denialSource: 'repo_checks_timeout'`):
|
|
1024
|
+
* the engine re-runs the floor on the tree as it stands — the seat does not run again — with
|
|
1025
|
+
* every check under 2× its bound, with the repo's declared `test_targeted` in place of the full
|
|
1026
|
+
* test set (no targeted command ⇒ the test set is waived), or with the checks that did not
|
|
1027
|
+
* finish waived; the re-run goes through the ordinary gate and waived checks are named in
|
|
1028
|
+
* `gateEvaluated.floorNote`. `'accept_suggestion'` answers an evaluator's worktree-guard denial
|
|
1029
|
+
* whose edit was restored and pinned (`gateEscalated.suggestionRef`): the engine applies the
|
|
1030
|
+
* pinned edit and rewinds to the creator (`unitReworkAmended{scope: 'accept_suggestion'}`).
|
|
1031
|
+
* The engine refuses each at any other gate — a 409 — and the gate stays open.
|
|
1032
|
+
*
|
|
1033
|
+
* `'amend_intent'` (additive; wicked-core#555, engine ≥ the core-ts release after 0.7.30)
|
|
1034
|
+
* approves the gate AND AMENDS THE RUN'S INTENT: `amend` carries what the acceptance list now
|
|
1035
|
+
* says (required, non-empty), `approve: true`, and no `amendScope` — the scope IS every unit at
|
|
1036
|
+
* or after the cursor, which is what makes it reach the LATER EVALUATOR. Before it, nothing
|
|
1037
|
+
* amended the list an evaluator is handed, so a mid-run descope could only end in a relaunch.
|
|
1038
|
+
* The engine appends the text to those units' descriptions, records it on the run
|
|
1039
|
+
* (`AgentSession.intent_amendments`) and emits `intentAmended`. Refused at a plan or team gate,
|
|
1040
|
+
* and with empty text — a 409 with the gate left open.
|
|
768
1041
|
*/
|
|
769
|
-
action?:
|
|
1042
|
+
action?:
|
|
1043
|
+
| 'approve'
|
|
1044
|
+
| 'request_changes'
|
|
1045
|
+
| 'reject'
|
|
1046
|
+
| 'edit_plan'
|
|
1047
|
+
| 'extend'
|
|
1048
|
+
| 'targeted'
|
|
1049
|
+
| 'accept_partial'
|
|
1050
|
+
| 'accept_suggestion'
|
|
1051
|
+
| 'amend_intent';
|
|
770
1052
|
/**
|
|
771
1053
|
* Where an approve's `amend` lands (api-types 0.38.0, additive; same release as `action`).
|
|
772
1054
|
* Absent = `'cursor'` (today: the gated unit's description). `'creator'` — the first creator
|
|
@@ -775,6 +1057,38 @@ export interface GateDecision {
|
|
|
775
1057
|
* Identical text already present on the target is not appended twice.
|
|
776
1058
|
*/
|
|
777
1059
|
amendScope?: 'cursor' | 'creator';
|
|
1060
|
+
/**
|
|
1061
|
+
* Approve a `plan_approval` gate WITH AN EDIT (DES-TEAMING-002 §8.6, seam T3; additive; needs an
|
|
1062
|
+
* engine whose addon carries `Core.supportsPlanLaunch`). The edited plan: the engine publishes
|
|
1063
|
+
* `plan.proposed{by:"human", kind:"edit"}`, floor-fills it (phases below the floor are ADDED,
|
|
1064
|
+
* never refused) and accepts it as the next `plan_rev` — or refuses it (`plan.refused`) and
|
|
1065
|
+
* re-opens the gate under a new `gate_id`, answering `awaiting_human`. Requires `approve: true`
|
|
1066
|
+
* and `action` omitted or `'edit_plan'`; `amend` / `amendScope` do not apply. A plain approve
|
|
1067
|
+
* (no `plan`) releases the held plan as it is; `approve: false` rejects (cancels).
|
|
1068
|
+
*/
|
|
1069
|
+
plan?: LaunchPlan;
|
|
1070
|
+
/**
|
|
1071
|
+
* The gate this decision answers — the unit `ord` its open gate paused before, as `GET
|
|
1072
|
+
* /runs/:id/gate` served it (api-types 0.44.0, additive). When present the daemon compares it to
|
|
1073
|
+
* the run's open gate and answers **409** `{ error, code: 'gate_changed', openOrd }` on a
|
|
1074
|
+
* mismatch, confirming nothing: the gate was answered elsewhere or replaced while the decision
|
|
1075
|
+
* waited (a skin's undo window). When the daemon cannot tell which gate is open it answers
|
|
1076
|
+
* **409** `{ error, code: 'gate_unknown' }` — refresh the gate and decide again. Absent = today's
|
|
1077
|
+
* behaviour (no gate check).
|
|
1078
|
+
*/
|
|
1079
|
+
ord?: number;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* A USER-COMPOSED plan (DES-TEAMING-002 §8.4, seam T3): ordered `steps[]` over the phase catalog,
|
|
1084
|
+
* the predicted `touch` set (the intent score's input: a plan with a creator step and no `touch`
|
|
1085
|
+
* scores 100, "no declared scope") and an optional MANUAL-mode floor `override` (refused in auto
|
|
1086
|
+
* mode). A step's `id` defaults to its catalog id. The ENGINE validates every key.
|
|
1087
|
+
*/
|
|
1088
|
+
export interface LaunchPlan {
|
|
1089
|
+
steps: Array<{ catalog: string; id?: string | undefined; [k: string]: unknown }>;
|
|
1090
|
+
touch?: string[];
|
|
1091
|
+
override?: TeamPlanOverride;
|
|
778
1092
|
}
|
|
779
1093
|
|
|
780
1094
|
/**
|
|
@@ -1012,7 +1326,9 @@ export interface CoreEvent {
|
|
|
1012
1326
|
library?: string;
|
|
1013
1327
|
transform?: string;
|
|
1014
1328
|
known?: boolean;
|
|
1015
|
-
detail
|
|
1329
|
+
/** `adviceDelivered` (wicked-core#602, api-types 0.40.0) spells an absent detail `null`, never an
|
|
1330
|
+
* absent key — widened to admit that `null`; every other producer still sends a string. */
|
|
1331
|
+
detail?: string | null;
|
|
1016
1332
|
[k: string]: unknown;
|
|
1017
1333
|
}
|
|
1018
1334
|
|
|
@@ -1089,6 +1405,22 @@ export type WorkerStallEscalatedFrame = {
|
|
|
1089
1405
|
escalations?: number;
|
|
1090
1406
|
/** outcome `failed`: bounded excerpt of what the recovery call threw. */
|
|
1091
1407
|
error?: string;
|
|
1408
|
+
/**
|
|
1409
|
+
* Why the watchdog did not do a plain reassign (crew#638 / #581 / #580; additive, absent on older
|
|
1410
|
+
* daemons): `tool_unit` — the cursor is the engine's own command, nothing to fail over to;
|
|
1411
|
+
* `evaluating` — the worker returned and its gate evaluation is in flight, a reassign would start
|
|
1412
|
+
* a second creator; `evaluator_distinct` — every other seat is one evaluator ≠ creator forbids
|
|
1413
|
+
* (see `avoided`), so the unit was left for a human; `no_output` (outcome `exhausted`) — the
|
|
1414
|
+
* reassigned seat produced nothing past a startup banner.
|
|
1415
|
+
*/
|
|
1416
|
+
reason?: 'tool_unit' | 'evaluating' | 'evaluator_distinct' | 'no_output';
|
|
1417
|
+
/**
|
|
1418
|
+
* The seats the failover pick excluded under evaluator ≠ creator (crew#638; additive): a
|
|
1419
|
+
* creator cursor avoids the run's evaluator seats, an evaluator cursor the seats that built its
|
|
1420
|
+
* work, an `evaluator_distinct`-routed unit the seat it was routed away from. Present on an `ok`
|
|
1421
|
+
* reassign that skipped one and on a `reason: 'evaluator_distinct'` notify; absent otherwise.
|
|
1422
|
+
*/
|
|
1423
|
+
avoided?: string[];
|
|
1092
1424
|
};
|
|
1093
1425
|
|
|
1094
1426
|
export interface RecordedEvent extends CoreEvent {
|
|
@@ -1900,6 +2232,58 @@ export type WorkerToolCallDeniedEvent = {
|
|
|
1900
2232
|
remedy: string;
|
|
1901
2233
|
};
|
|
1902
2234
|
|
|
2235
|
+
/**
|
|
2236
|
+
* DES-TEAMING-001 §5.2 / §7 (wicked-core#602, S3; api-types 0.40.0) — what became of HIGH monitor
|
|
2237
|
+
* advice for one attempt of a unit. The one mid-turn carrier is the ACP adapter's
|
|
2238
|
+
* `_session/steering` request, always sent with `idleBehavior: "promptRequired"` so a steer that
|
|
2239
|
+
* lands after the turn settled never starts a detached turn.
|
|
2240
|
+
*
|
|
2241
|
+
* - `carrier: 'acp_steering'` + `outcome: 'injected'` — the steer reached the running turn.
|
|
2242
|
+
* - `outcome: 'turn_ended'` — the adapter answered `promptRequired` (the turn had settled; nothing
|
|
2243
|
+
* was started), or the turn ended with the steer unanswered. The advice goes to the gate.
|
|
2244
|
+
* - `outcome: 'refused'` — the adapter answered a JSON-RPC error (in `detail`); the turn continues.
|
|
2245
|
+
* - `outcome: 'not_delivered'` — the advice never rode a steer: `carrier: 'none'` when the unit's
|
|
2246
|
+
* carrier has no mid-turn channel (wrapped, PTY, an ACP adapter not advertising steering), or
|
|
2247
|
+
* `'acp_steering'` when the turn ended before the next tool-call boundary. `detail` says which.
|
|
2248
|
+
*
|
|
2249
|
+
* Every key is always present; `detail` is `null` when there is nothing to add. Spelled exactly as
|
|
2250
|
+
* wicked-core's `CoreEvent::to_json` emits it. `type` alias on purpose (relays through the
|
|
2251
|
+
* `CoreEvent`-typed seams unchanged).
|
|
2252
|
+
*/
|
|
2253
|
+
export type AdviceDeliveredEvent = {
|
|
2254
|
+
type: 'adviceDelivered';
|
|
2255
|
+
session: string;
|
|
2256
|
+
ord: number;
|
|
2257
|
+
attempt: number;
|
|
2258
|
+
/** `f-` + 16 lowercase hex per finding; one steer may carry several. */
|
|
2259
|
+
findingIds: string[];
|
|
2260
|
+
carrier: 'acp_steering' | 'none' | (string & {});
|
|
2261
|
+
outcome: 'injected' | 'turn_ended' | 'refused' | 'not_delivered' | (string & {});
|
|
2262
|
+
detail: string | null;
|
|
2263
|
+
};
|
|
2264
|
+
|
|
2265
|
+
/**
|
|
2266
|
+
* DES-TEAMING-001 §5.3 / §7 (wicked-core#602, S3; api-types 0.40.0) — the worker's answer to one
|
|
2267
|
+
* DELIVERED finding, read from its final output line `ADVICE <id>: ACCEPT|DECLINE — <reason>` (the
|
|
2268
|
+
* last line per id wins). The worker may decline and must say why: `reason` (≤2 KB) is its
|
|
2269
|
+
* evidence, and may be `""` — a refusal with no evidence is recorded as exactly that. A delivered
|
|
2270
|
+
* finding with no line emits nothing here and is `unanswered` in the team ledger. The gate, not the
|
|
2271
|
+
* monitor, decides.
|
|
2272
|
+
*/
|
|
2273
|
+
export type WorkerAdviceResponseEvent = {
|
|
2274
|
+
type: 'workerAdviceResponse';
|
|
2275
|
+
session: string;
|
|
2276
|
+
ord: number;
|
|
2277
|
+
attempt: number;
|
|
2278
|
+
findingId: string;
|
|
2279
|
+
disposition: 'accepted' | 'declined' | (string & {});
|
|
2280
|
+
reason: string;
|
|
2281
|
+
};
|
|
2282
|
+
|
|
2283
|
+
/** The S3 team-advice events as a discriminated union for consumers that narrow on `type`; they
|
|
2284
|
+
* also flow through the permissive {@link CoreEvent}. */
|
|
2285
|
+
export type TeamAdviceEvent = AdviceDeliveredEvent | WorkerAdviceResponseEvent;
|
|
2286
|
+
|
|
1903
2287
|
export type GateEvidenceEvent =
|
|
1904
2288
|
| EvaluatorMutatedWorktreeEvent
|
|
1905
2289
|
| RepoChecksEvaluatedEvent
|
|
@@ -1935,10 +2319,12 @@ export interface UnitReworkAmendedEvent {
|
|
|
1935
2319
|
* 0.7.27): `'cursor'` — the gated unit, today's approve-with-steer (`GateDecision.amendScope`
|
|
1936
2320
|
* absent or `'cursor'`); `'creator'` — the first creator phase at/after the cursor
|
|
1937
2321
|
* (`amendScope: 'creator'`); `'request_changes'` — the creator phase the gate rewound to, and
|
|
1938
|
-
* `amendment` then carries the evaluator's full findings + the operator's note
|
|
1939
|
-
*
|
|
2322
|
+
* `amendment` then carries the evaluator's full findings + the operator's note;
|
|
2323
|
+
* `'accept_suggestion'` (wicked-core#467) — the same rewind after the operator adopted the
|
|
2324
|
+
* evaluator's pinned edit, and `amendment` names it. ABSENT on an engine before the field — read
|
|
2325
|
+
* as `'cursor'`.
|
|
1940
2326
|
*/
|
|
1941
|
-
scope?: 'cursor' | 'creator' | 'request_changes';
|
|
2327
|
+
scope?: 'cursor' | 'creator' | 'request_changes' | 'accept_suggestion';
|
|
1942
2328
|
}
|
|
1943
2329
|
|
|
1944
2330
|
/** P2 — a worker's ApplyStepResult arrived and output is ready to be gated. Fires before GateDecided.
|
|
@@ -2006,9 +2392,12 @@ export interface UnitDistributedEvent {
|
|
|
2006
2392
|
ord: number;
|
|
2007
2393
|
/** The roster key of the assigned seat. */
|
|
2008
2394
|
cli: string;
|
|
2009
|
-
/** How the seat was chosen: the
|
|
2010
|
-
* evaluator ≠ creator reassignment, or a deterministic tool
|
|
2011
|
-
|
|
2395
|
+
/** How the seat was chosen: `'teamed'` — the deterministic pick, no council (wicked-core#590 S5;
|
|
2396
|
+
* every seated unit of a new run) — an evaluator ≠ creator reassignment, or a deterministic tool
|
|
2397
|
+
* execution. `'council'` / `'degraded'` are no longer emitted by a new run and stay for recorded
|
|
2398
|
+
* frames. On `'teamed'` the council-only fields (`agreementPct`, `returned`, `seated`, `dissent`)
|
|
2399
|
+
* are `null`. Consumers must render an unrecognised method as "routed", never as a council. */
|
|
2400
|
+
routingMethod: 'council' | 'degraded' | 'evaluator_distinct' | 'tool' | 'teamed';
|
|
2012
2401
|
agreementPct: number | null;
|
|
2013
2402
|
/** Ballots that came back. Read against `seated`. */
|
|
2014
2403
|
returned: number | null;
|
|
@@ -2046,13 +2435,23 @@ export interface UnitDistributedEvent {
|
|
|
2046
2435
|
*/
|
|
2047
2436
|
distinctnessFallback?: 'creator_seat' | 'same_cli_instance' | null;
|
|
2048
2437
|
/** @deprecated api-types 0.36.0 — the engine emits `routingMethod`; removed in 0.37. */
|
|
2049
|
-
routing_method?: 'council' | 'degraded' | 'evaluator_distinct' | 'tool';
|
|
2438
|
+
routing_method?: 'council' | 'degraded' | 'evaluator_distinct' | 'tool' | 'teamed';
|
|
2050
2439
|
/** @deprecated api-types 0.36.0 — the engine emits `agreementPct`; removed in 0.37. */
|
|
2051
2440
|
agreement_pct?: number | null;
|
|
2052
2441
|
/** @deprecated api-types 0.36.0 — the engine emits `degradedReason`; removed in 0.37. */
|
|
2053
2442
|
degraded_reason?: string | null;
|
|
2054
2443
|
}
|
|
2055
2444
|
|
|
2445
|
+
/** One APPROVED INTENT AMENDMENT (`AgentSession.intent_amendments`; wicked-core#555). */
|
|
2446
|
+
export interface IntentAmendment {
|
|
2447
|
+
/** The human's own words — what the run's acceptance list now says. */
|
|
2448
|
+
text: string;
|
|
2449
|
+
/** The gate's cursor unit `ord`: the first unit the amendment reached. */
|
|
2450
|
+
ord: number;
|
|
2451
|
+
/** When it was decided, unix millis. */
|
|
2452
|
+
at: number;
|
|
2453
|
+
}
|
|
2454
|
+
|
|
2056
2455
|
/** One seat the wave-6 engine BENCHED for a run (`AgentSession.benched_seats`, F-7R2-006): never
|
|
2057
2456
|
* convened, never a failover or judge target, named in `unitDistributed.degradedReason`. */
|
|
2058
2457
|
export interface BenchedSeat {
|
|
@@ -2552,6 +2951,30 @@ export interface SkillsManifestResponse {
|
|
|
2552
2951
|
* `recorded.reasons` is `null` for a row written before per-reason portability (0.34.0). */
|
|
2553
2952
|
drift?: SnapshotRowDrift[];
|
|
2554
2953
|
} | null;
|
|
2954
|
+
/**
|
|
2955
|
+
* The wicked-garden plugin INSTALLED on this host right now (wicked-studio#388) — so a surface
|
|
2956
|
+
* can say when the daemon's baseline, and therefore every snapshot published from it, is behind
|
|
2957
|
+
* the operator's install. `null` = no plugin is installed (the unseeded case the 503 covers);
|
|
2958
|
+
* absent on a daemon older than the release carrying it. Compare `installed.baseline` with
|
|
2959
|
+
* `manifest.baseline`: different = Refresh baseline, then Publish.
|
|
2960
|
+
*/
|
|
2961
|
+
installed?: InstalledPlugin | null;
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2964
|
+
/** `SkillsManifestResponse.installed` — the live plugin's identity (wicked-studio#388). */
|
|
2965
|
+
export interface InstalledPlugin {
|
|
2966
|
+
source: { kind: SkillSourceKind; path: string; plugin_version: string };
|
|
2967
|
+
/** HEAD sha for a `checkout` source; `null` otherwise (or when git could not answer). */
|
|
2968
|
+
git_sha: string | null;
|
|
2969
|
+
/**
|
|
2970
|
+
* The content hash of the INSTALLED bundle, comparable with `SkillManifest.baseline` — the same
|
|
2971
|
+
* identity `POST /skills/refresh-baseline` decides on, never the version string (two installs of
|
|
2972
|
+
* one version with different bytes are two baselines). `null` when the bundle could not be read,
|
|
2973
|
+
* and then `unreadable` says why: a comparison crew could not make is stated, not reported as
|
|
2974
|
+
* agreement.
|
|
2975
|
+
*/
|
|
2976
|
+
baseline: string | null;
|
|
2977
|
+
unreadable: string | null;
|
|
2555
2978
|
}
|
|
2556
2979
|
|
|
2557
2980
|
/** The identity of a portability-rule table (api-types 0.36.0, F-083): its version and the
|
|
@@ -3181,6 +3604,14 @@ export interface TestingReconResponse {
|
|
|
3181
3604
|
/** Present only when the fan was campaign-registered with a `projectId` and filing a sibling
|
|
3182
3605
|
* into the project failed — the runs are LIVE; re-attach via POST /projects/:id/members. */
|
|
3183
3606
|
projectAttachError?: string;
|
|
3607
|
+
/**
|
|
3608
|
+
* `true` on a **202**: the engine was still launching the fan when the daemon answered (crew#471 —
|
|
3609
|
+
* it plans every node's units before it replies, which held the POST for minutes). The `runIds`
|
|
3610
|
+
* are final (deterministic node ids) and can be followed now; the trail entries and project
|
|
3611
|
+
* filing land when the engine answers, and a late refusal is audited as `campaign.launch_failed`.
|
|
3612
|
+
* Absent on a 201.
|
|
3613
|
+
*/
|
|
3614
|
+
launching?: true;
|
|
3184
3615
|
}
|
|
3185
3616
|
|
|
3186
3617
|
// ── The governed test-authoring launch (wave 6; api-types 0.36.0) ──────────────────────────────
|
|
@@ -3355,6 +3786,21 @@ export interface LaunchRunBody {
|
|
|
3355
3786
|
repoRef?: string;
|
|
3356
3787
|
/** Built-in workflow id (`feature` | `bug` | `migration`); omit for free-text single-unit mode. */
|
|
3357
3788
|
workflow?: string;
|
|
3789
|
+
/**
|
|
3790
|
+
* A USER-COMPOSED plan (DES-TEAMING-002 §8.4, seam T3; additive; needs an engine whose addon
|
|
3791
|
+
* carries `Core.supportsPlanLaunch` — an older one is refused with a 501, never run unplanned).
|
|
3792
|
+
* The ENGINE publishes `plan.proposed{by:"human"}` before any unit runs, scores and floor-fills
|
|
3793
|
+
* it, and holds it at a `plan_approval` gate (`awaiting_human{gate_kind:"plan_approval"}`) when
|
|
3794
|
+
* the approval matrix says so: always in manual mode, and in auto mode when high risk (band
|
|
3795
|
+
* 70-100 or destructive). Mutually exclusive with `workflow` (a plan or a preset).
|
|
3796
|
+
* A creator plan with NO `touch` set — and every creator preset — is scoped by the run's PA
|
|
3797
|
+
* first (wicked-core#633, X1): rev 1 is the read-only `pa-scope` step alone (unit ord 1), the
|
|
3798
|
+
* scored plan is rev 2 proposed by the PA seat (`plan.proposed{by:<PA seat>}`), and its
|
|
3799
|
+
* `plan_approval` gate, when one opens, is at ord 2. Declare `touch` to be scored at launch.
|
|
3800
|
+
* `deliver: "pr"` with a plan (api-types 0.42.0, T8) hands the engine the deliver step, which it
|
|
3801
|
+
* appends to the plan and puts in the floor; `deliver` omitted with a plan means `"none"`.
|
|
3802
|
+
*/
|
|
3803
|
+
plan?: LaunchPlan;
|
|
3358
3804
|
/**
|
|
3359
3805
|
* The project to file this run into (DES-PROJECT-001 §2.2). The `crew.run` membership is
|
|
3360
3806
|
* attached atomically with the launch record; an unknown or archived project fails the launch
|
|
@@ -3466,6 +3912,29 @@ export interface LaunchRunBody {
|
|
|
3466
3912
|
actor?: string;
|
|
3467
3913
|
}
|
|
3468
3914
|
|
|
3915
|
+
/**
|
|
3916
|
+
* One issue a launch's intent linked (`#N`, `owner/repo#N`, an issue URL) and whether the daemon
|
|
3917
|
+
* could read it (crew#627, additive). A governed worker cannot read GitHub, so for a workflow launch
|
|
3918
|
+
* the daemon reads each linked issue under its own identity (`gh issue view`, at most 5) and appends
|
|
3919
|
+
* the title, state, body and comments to the problem the engine plans from, inside a marked block.
|
|
3920
|
+
* `resolved: false` names why (`error`) — shown, never skipped.
|
|
3921
|
+
*/
|
|
3922
|
+
export interface LinkedIssue {
|
|
3923
|
+
ref: string;
|
|
3924
|
+
resolved: boolean;
|
|
3925
|
+
/** Present when `resolved`. */
|
|
3926
|
+
title?: string;
|
|
3927
|
+
/** Present when not `resolved`: why, in one line. */
|
|
3928
|
+
error?: string;
|
|
3929
|
+
}
|
|
3930
|
+
|
|
3931
|
+
/** The `POST /runs` 201 body. `linkedIssues` (crew#627, additive) is present when the intent of a
|
|
3932
|
+
* workflow launch named at least one issue; absent otherwise and on an older daemon. */
|
|
3933
|
+
export interface LaunchRunResponse {
|
|
3934
|
+
runId: string;
|
|
3935
|
+
linkedIssues?: LinkedIssue[];
|
|
3936
|
+
}
|
|
3937
|
+
|
|
3469
3938
|
/**
|
|
3470
3939
|
* Body for `PUT /runs/:id/guidance` (DES-UX-002 §7.2, CREW-UX-7; api-types 0.9.0) — upsert the
|
|
3471
3940
|
* run's ONE durable operator guidance note. `text: ''` CLEARS the note (the DTO field returns
|
|
@@ -3597,12 +4066,20 @@ export interface PhaseDef {
|
|
|
3597
4066
|
* run `cmd` directly. */
|
|
3598
4067
|
executor?: PhaseExecutor;
|
|
3599
4068
|
/** Per-phase agent instructions folded into the unit prompt by the engine (core PhaseDef.instructions,
|
|
3600
|
-
* Option<String>). Absent = no extra instruction. Mirrors of core drop-ins that carry it
|
|
3601
|
-
*
|
|
4069
|
+
* Option<String>). Absent = no extra instruction. Mirrors of core drop-ins that carry it MUST
|
|
4070
|
+
* reproduce it verbatim or the runtime def diverges from core's — FINDING-011. */
|
|
3602
4071
|
instructions?: string | null;
|
|
3603
4072
|
gate_type: GateType | null;
|
|
3604
4073
|
gate: GateSpec;
|
|
3605
4074
|
executes_code: boolean;
|
|
4075
|
+
/**
|
|
4076
|
+
* The phase must REPORT what it captured (wicked-core#535 / BC-80; additive, engine ≥ the
|
|
4077
|
+
* release carrying it — an older engine's strict def parser refuses the key). Its output must
|
|
4078
|
+
* carry `wicked-capture-report {"derived": N, "submitted": M, "failed": K}`; a missing marker, a
|
|
4079
|
+
* failed submission and proposals derived but never submitted each deny the unit into the human
|
|
4080
|
+
* gate. An honest `0/0/0` passes. Absent/false ⇒ not parsed (every phase but `capture`).
|
|
4081
|
+
*/
|
|
4082
|
+
requires_capture_report?: boolean;
|
|
3606
4083
|
verified_evidence: boolean;
|
|
3607
4084
|
required_deliverables: string[];
|
|
3608
4085
|
depends_on: string[];
|
|
@@ -3629,6 +4106,29 @@ export interface WorkflowDef {
|
|
|
3629
4106
|
base_skill_ref?: string | null;
|
|
3630
4107
|
}
|
|
3631
4108
|
|
|
4109
|
+
/** A drop-in workflow definition the ENGINE refused, with the engine's own reason (wicked-crew#718). */
|
|
4110
|
+
export interface RefusedWorkflow {
|
|
4111
|
+
/** The def's id, as its file named it. */
|
|
4112
|
+
id: string;
|
|
4113
|
+
/**
|
|
4114
|
+
* wicked-core's refusal, verbatim — e.g. `gate evaluates nothing: write-a-note — the phase
|
|
4115
|
+
* declares executes_code but pins no validator and has no human gate, so its gate would approve
|
|
4116
|
+
* with nothing checked.`
|
|
4117
|
+
*/
|
|
4118
|
+
reason: string;
|
|
4119
|
+
}
|
|
4120
|
+
|
|
4121
|
+
/**
|
|
4122
|
+
* `GET /workflows` (wicked-crew#718). `workflows` is what the ENGINE accepted — the only defs a
|
|
4123
|
+
* launch can name. `unavailable` is the drop-ins it refused, with its reason, so a def that cannot
|
|
4124
|
+
* be launched is NAMED rather than offered and then 400'd `unknown workflow`. Absent on a daemon
|
|
4125
|
+
* older than the release carrying it (read it as `[]`).
|
|
4126
|
+
*/
|
|
4127
|
+
export interface WorkflowsResponse {
|
|
4128
|
+
workflows: WorkflowDef[];
|
|
4129
|
+
unavailable?: RefusedWorkflow[];
|
|
4130
|
+
}
|
|
4131
|
+
|
|
3632
4132
|
/** Top-level requirements_graph.json artifact (schema 1.0.0). */
|
|
3633
4133
|
export interface DomainGraph {
|
|
3634
4134
|
metadata: { schema_version: string; migration_mode: string; source?: string };
|
|
@@ -3702,6 +4202,24 @@ export interface CodeGraphData {
|
|
|
3702
4202
|
totals?: { nodes: number; edges: number; files: number };
|
|
3703
4203
|
}
|
|
3704
4204
|
|
|
4205
|
+
/**
|
|
4206
|
+
* `GET /api/v1/repos/:id/deliver-target` (R3) — where a delivering launch on this repo would push,
|
|
4207
|
+
* read by the same origin preflight the deliver gate card uses (crew#730). `sentence` is the gate's
|
|
4208
|
+
* own target sentence for a run not yet started ("the run branch"); show it verbatim.
|
|
4209
|
+
* - `github` — a github.com origin; `githubRepo` is its `owner/repo` on github.com or
|
|
4210
|
+
* ssh.github.com, and `null` on another `*.github.com` host (gist, api);
|
|
4211
|
+
* - `local` — a filesystem path or `file://` URL: no pull request can be opened against it;
|
|
4212
|
+
* - `other` — another host: a pull request opens only if gh resolves it as a GitHub host;
|
|
4213
|
+
* - `none` — the checkout has no `origin` remote: the push will fail;
|
|
4214
|
+
* - `unknown` — the origin could not be read; the sentence claims nothing either way.
|
|
4215
|
+
*/
|
|
4216
|
+
export interface DeliverTargetResponse {
|
|
4217
|
+
repo: string;
|
|
4218
|
+
origin: 'github' | 'local' | 'other' | 'none' | 'unknown';
|
|
4219
|
+
githubRepo: string | null;
|
|
4220
|
+
sentence: string;
|
|
4221
|
+
}
|
|
4222
|
+
|
|
3705
4223
|
/**
|
|
3706
4224
|
* `GET /repos/:id/graph` → 200 (api-types 0.35.0, F-2R2-005). `graph: null` = the repo's code
|
|
3707
4225
|
* graph has not been built (nothing at its registered graph path) — and `reason` says WHY, so a
|
|
@@ -3781,6 +4299,18 @@ export interface SystemSettings {
|
|
|
3781
4299
|
* `base_skill_refused`); the finding is an `error`.
|
|
3782
4300
|
*/
|
|
3783
4301
|
baseSkillPolicy?: 'warn' | 'require';
|
|
4302
|
+
/**
|
|
4303
|
+
* The DELIVER IDENTITY (crew#549; additive): the GitHub login the deliver phase must push as.
|
|
4304
|
+
* The deliver script reads `gh api user` AND asks git which credential it would use for the
|
|
4305
|
+
* remote's host, and REFUSES — before anything is staged, committed or pushed — when either
|
|
4306
|
+
* disagrees with this login (or, with nothing configured, when those two disagree with each
|
|
4307
|
+
* other). `''`/absent ⇒ the `GH_ACCOUNT` env var decides, and unset there means the phase
|
|
4308
|
+
* pushes as whatever login gh holds, said aloud on the gate card.
|
|
4309
|
+
*
|
|
4310
|
+
* A LOGIN ONLY — never a token. The credential itself stays in gh's keyring or in the daemon's
|
|
4311
|
+
* `GH_TOKEN`; `GET /settings` returns this login and no secret ever.
|
|
4312
|
+
*/
|
|
4313
|
+
deliverIdentityLogin?: string;
|
|
3784
4314
|
/**
|
|
3785
4315
|
* The stall watchdog's DETECTION threshold (crew#287; api-types 0.18.0 — previously a
|
|
3786
4316
|
* daemon-local extension): minutes a run in `executing` may go without ANY engine event on the
|
|
@@ -3926,6 +4456,60 @@ export interface ElicitationResponse {
|
|
|
3926
4456
|
content?: { response: string };
|
|
3927
4457
|
}
|
|
3928
4458
|
|
|
4459
|
+
// ── Presets (DES-TEAMING-002 §8.4, seam C2) — saved phase selections ──────────
|
|
4460
|
+
|
|
4461
|
+
/**
|
|
4462
|
+
* One plan step: the catalog entry it instantiates (`understand`, `build`, …), its phase id,
|
|
4463
|
+
* and the step fields the catalog lets a step set (`gate`, `validator_pin`, `depends_on`, …).
|
|
4464
|
+
* The engine validates it (`plan::compose`); unknown keys are refused there.
|
|
4465
|
+
*/
|
|
4466
|
+
export interface PresetStep {
|
|
4467
|
+
catalog: string;
|
|
4468
|
+
id: string;
|
|
4469
|
+
[k: string]: unknown;
|
|
4470
|
+
}
|
|
4471
|
+
|
|
4472
|
+
/**
|
|
4473
|
+
* A preset (`GET /presets`, `PUT /presets/:name`): a named phase selection stored in the core
|
|
4474
|
+
* store. A launch's `workflow` names one (`POST /runs {workflow}`); a project-scoped preset
|
|
4475
|
+
* shadows a global one of the same name for that project. Built-ins carry
|
|
4476
|
+
* `created_by: "builtin"` and cannot be deleted.
|
|
4477
|
+
*/
|
|
4478
|
+
export interface Preset {
|
|
4479
|
+
name: string;
|
|
4480
|
+
/** `"global"` or `"project:<id>"`. */
|
|
4481
|
+
scope: string;
|
|
4482
|
+
steps: PresetStep[];
|
|
4483
|
+
/** `"builtin"` for a seeded built-in; otherwise the writing surface. */
|
|
4484
|
+
created_by: string;
|
|
4485
|
+
/** Unix millis. */
|
|
4486
|
+
updated_at: number;
|
|
4487
|
+
/**
|
|
4488
|
+
* A machine-owned preset (`chat`, `onboarding`, …): keep it off delivery surfaces and the work-mode
|
|
4489
|
+
* selector. The preset's half of the one name-keyed classification that stamps
|
|
4490
|
+
* `WorkflowDef.is_system` and `run_identity.system` (DES-TEAMING-002 §11.3). The daemon stamps it
|
|
4491
|
+
* on every preset it serves (api-types 0.48.0); absent from an older daemon.
|
|
4492
|
+
*/
|
|
4493
|
+
system?: boolean;
|
|
4494
|
+
[k: string]: unknown;
|
|
4495
|
+
}
|
|
4496
|
+
|
|
4497
|
+
/** `PUT /presets/:name` body. `projectId` absent ⇒ a global preset. */
|
|
4498
|
+
export interface PutPresetBody {
|
|
4499
|
+
steps: PresetStep[];
|
|
4500
|
+
projectId?: string;
|
|
4501
|
+
}
|
|
4502
|
+
|
|
4503
|
+
/** `GET /presets` (`?projectId=`) — the presets a launch in that project sees, by name. */
|
|
4504
|
+
export interface PresetListResponse {
|
|
4505
|
+
presets: Preset[];
|
|
4506
|
+
}
|
|
4507
|
+
|
|
4508
|
+
/** `GET /presets/:name`, `PUT /presets/:name`. */
|
|
4509
|
+
export interface PresetResponse {
|
|
4510
|
+
preset: Preset;
|
|
4511
|
+
}
|
|
4512
|
+
|
|
3929
4513
|
// ── Projects (DES-PROJECT-001) — the experience-plane keystone ─────────────────
|
|
3930
4514
|
|
|
3931
4515
|
/** Project lifecycle: `active ⇄ archived`, no hard delete (ADR §1.3). */
|
|
@@ -4561,6 +5145,60 @@ export type ChatSeatRefusedFrame = {
|
|
|
4561
5145
|
project_id?: string;
|
|
4562
5146
|
};
|
|
4563
5147
|
|
|
5148
|
+
// ── Chat citations (crew#561, F-RC1-117; api-types 0.67.0) ───────────────────
|
|
5149
|
+
//
|
|
5150
|
+
// A seat's answer cites paths, `path:line` / `path:symbol` refs and commit SHAs, and nothing used
|
|
5151
|
+
// to check them: on the RC1 Phase 6 re-run 2 of 26 cited SHAs existed in no repo and three line
|
|
5152
|
+
// refs were off, rendered as plain text a reader could not tell apart from the real ones. The
|
|
5153
|
+
// daemon verifies each citation against the very read roots it handed the seats and publishes the
|
|
5154
|
+
// verdicts; the seat's TEXT is never edited — a skin MARKS it from these items.
|
|
5155
|
+
|
|
5156
|
+
/** What class of thing a citation is. */
|
|
5157
|
+
export type ChatCitationKind = 'path' | 'line' | 'symbol' | 'sha';
|
|
5158
|
+
|
|
5159
|
+
/**
|
|
5160
|
+
* The verdict on one citation.
|
|
5161
|
+
* - `verified` — it exists, exactly as cited;
|
|
5162
|
+
* - `corrected` — it exists, but not where the reply said (`resolved` is the real place);
|
|
5163
|
+
* - `unverified` — it is not in the chat's scope (the fabricated-SHA case);
|
|
5164
|
+
* - `unchecked` — the bounded pass did not reach it. NOT a claim either way.
|
|
5165
|
+
*/
|
|
5166
|
+
export type ChatCitationStatus = 'verified' | 'corrected' | 'unverified' | 'unchecked';
|
|
5167
|
+
|
|
5168
|
+
/** One citation as verified. `raw` is the token EXACTLY as it appears in the reply, so a skin can
|
|
5169
|
+
* find it in the rendered text without re-parsing. */
|
|
5170
|
+
export interface ChatCitationItem {
|
|
5171
|
+
raw: string;
|
|
5172
|
+
kind: ChatCitationKind;
|
|
5173
|
+
status: ChatCitationStatus;
|
|
5174
|
+
/** Where the thing actually is: `alpha/src/foo.ts:2069` for a corrected line ref, the repo name
|
|
5175
|
+
* for a SHA, the defining line for a symbol. Absent when there is nothing to add. */
|
|
5176
|
+
resolved?: string;
|
|
5177
|
+
/** Why, in one short phrase — a skin's hover text. */
|
|
5178
|
+
note?: string;
|
|
5179
|
+
}
|
|
5180
|
+
|
|
5181
|
+
/**
|
|
5182
|
+
* DAEMON-SYNTHETIC (like {@link ChatSeatRefusedFrame}): ONE frame per terminal `chatReply` of a
|
|
5183
|
+
* chat that has read roots, broadcast AFTER that reply (verification never delays an answer) and
|
|
5184
|
+
* stamped with the reply's own `turn_id`. ABSENT — never empty — when the reply cites nothing, when
|
|
5185
|
+
* the chat has no read roots to verify against, and for a not-ok reply (a refusal or eviction line
|
|
5186
|
+
* cites nothing a reader would paste). The counts match `items`; `unverifiable` counts `unverified`
|
|
5187
|
+
* only, so `unchecked` is never read as a fabrication.
|
|
5188
|
+
*/
|
|
5189
|
+
export type ChatCitationsFrame = {
|
|
5190
|
+
type: 'chatCitations';
|
|
5191
|
+
chat: string;
|
|
5192
|
+
cliKey: string;
|
|
5193
|
+
turn_id?: string;
|
|
5194
|
+
verified: number;
|
|
5195
|
+
unverifiable: number;
|
|
5196
|
+
corrected: number;
|
|
5197
|
+
unchecked: number;
|
|
5198
|
+
items: ChatCitationItem[];
|
|
5199
|
+
project_id?: string;
|
|
5200
|
+
};
|
|
5201
|
+
|
|
4564
5202
|
/** One live chat on `GET /chats` (FINDING-027 gap 4; scope fields with crew#502). */
|
|
4565
5203
|
export interface ChatSummary {
|
|
4566
5204
|
chatId: string;
|
|
@@ -4604,7 +5242,25 @@ export interface ChatUsage {
|
|
|
4604
5242
|
*/
|
|
4605
5243
|
export type ChatTranscriptRecord =
|
|
4606
5244
|
| { at: number; turnId: string; kind: 'user'; text: string; seats: string[] }
|
|
4607
|
-
| { at: number; turnId: string; kind: 'seat'; cliKey: string; text: string; ok: boolean; usage: ChatUsage | null }
|
|
5245
|
+
| { at: number; turnId: string; kind: 'seat'; cliKey: string; text: string; ok: boolean; usage: ChatUsage | null }
|
|
5246
|
+
/**
|
|
5247
|
+
* The citation verdicts of the `seat` record with the same `turnId` + `cliKey` (api-types 0.68.0,
|
|
5248
|
+
* crew#561) — a SEPARATE record because the transcript is append-only and verification finishes
|
|
5249
|
+
* after the reply is stored. A reader folds it onto that reply; a skin that does not know this
|
|
5250
|
+
* kind ignores it (the `kind` discriminant is the extension point). Present only for a reply that
|
|
5251
|
+
* cited something; the live frame is {@link ChatCitationsFrame}, with the same fields.
|
|
5252
|
+
*/
|
|
5253
|
+
| {
|
|
5254
|
+
at: number;
|
|
5255
|
+
turnId: string;
|
|
5256
|
+
kind: 'citations';
|
|
5257
|
+
cliKey: string;
|
|
5258
|
+
verified: number;
|
|
5259
|
+
unverifiable: number;
|
|
5260
|
+
corrected: number;
|
|
5261
|
+
unchecked: number;
|
|
5262
|
+
items: ChatCitationItem[];
|
|
5263
|
+
};
|
|
4608
5264
|
|
|
4609
5265
|
/** `GET /chats/:id` → 200. */
|
|
4610
5266
|
export interface ChatDetailResponse {
|
|
@@ -4979,8 +5635,12 @@ export interface Campaign {
|
|
|
4979
5635
|
* `delivery === 'delivered'`.
|
|
4980
5636
|
*/
|
|
4981
5637
|
export interface CampaignNodeDelivery {
|
|
4982
|
-
delivery: 'delivered' | 'stranded' | 'vacuous' | 'none';
|
|
5638
|
+
delivery: 'delivered' | 'pushed' | 'stranded' | 'vacuous' | 'none';
|
|
4983
5639
|
deliverUrl?: string;
|
|
5640
|
+
/** Present exactly when `delivery === 'pushed'` (api-types 0.69.0, N1). */
|
|
5641
|
+
deliverBranch?: string;
|
|
5642
|
+
/** Present exactly when `delivery === 'pushed'`; userinfo removed. */
|
|
5643
|
+
deliverRemote?: string;
|
|
4984
5644
|
}
|
|
4985
5645
|
|
|
4986
5646
|
/**
|
|
@@ -4993,8 +5653,12 @@ export interface CampaignNodeDelivery {
|
|
|
4993
5653
|
export interface AttachedRunView {
|
|
4994
5654
|
runId: string;
|
|
4995
5655
|
status: SessionStatus;
|
|
4996
|
-
delivery: 'delivered' | 'stranded' | 'vacuous' | 'none';
|
|
5656
|
+
delivery: 'delivered' | 'pushed' | 'stranded' | 'vacuous' | 'none';
|
|
4997
5657
|
deliverUrl?: string;
|
|
5658
|
+
/** Present exactly when `delivery === 'pushed'` (api-types 0.69.0, N1). */
|
|
5659
|
+
deliverBranch?: string;
|
|
5660
|
+
/** Present exactly when `delivery === 'pushed'`; userinfo removed. */
|
|
5661
|
+
deliverRemote?: string;
|
|
4998
5662
|
}
|
|
4999
5663
|
|
|
5000
5664
|
/**
|
|
@@ -5182,6 +5846,9 @@ export interface AcpCliDiagnostics {
|
|
|
5182
5846
|
lastStartedTs: number | null;
|
|
5183
5847
|
/** Epoch ms of the newest `acpFallback`, or `null` when none recorded. */
|
|
5184
5848
|
lastFallbackTs: number | null;
|
|
5849
|
+
/** (core#581) The seat's ACP version pin, probed now — present only for a pinned seat, which
|
|
5850
|
+
* lists here even with no ACP events yet (zero counts). */
|
|
5851
|
+
versionPin?: SeatVersionPin;
|
|
5185
5852
|
}
|
|
5186
5853
|
|
|
5187
5854
|
/** The ACP fold of `GET /diagnostics` — keyed by `cliKey` (`claude`, `pi`, `codex`, …). */
|
|
@@ -5298,6 +5965,36 @@ export interface DiagnosticsGovernance {
|
|
|
5298
5965
|
findings: DiagnosticsGovernanceFinding[];
|
|
5299
5966
|
}
|
|
5300
5967
|
|
|
5968
|
+
/** `POST /governance/deadletters/replay` body (api-types 0.51.0): replay THIS daemon's dead-letter
|
|
5969
|
+
* outbox into its own governance store. `dryRun: true` folds the outbox and moves nothing. */
|
|
5970
|
+
export interface GovernanceReplayBody {
|
|
5971
|
+
dryRun?: boolean;
|
|
5972
|
+
}
|
|
5973
|
+
|
|
5974
|
+
/** `POST /governance/deadletters/replay` answer (api-types 0.51.0) — the `governance replay` CLI's
|
|
5975
|
+
* outcome. A dry run carries `fold` (what the outbox holds) and `blocker`: why a real replay could
|
|
5976
|
+
* not run on this daemon (in-memory store, an engine without the binding), `null` when it can. A
|
|
5977
|
+
* real replay reports what landed (`replayed`), what an earlier replay had already landed
|
|
5978
|
+
* (`alreadyPresent`, `null` on an engine that does not say) and what did not (`failed` — those
|
|
5979
|
+
* entries are back on the live outbox and stay dead letters). 409: no governance store / a replay
|
|
5980
|
+
* already running / a blocker; 501: the engine cannot replay. */
|
|
5981
|
+
export interface GovernanceReplayOutcome {
|
|
5982
|
+
outbox: string;
|
|
5983
|
+
store: { path: string; source: DiagnosticsGovernanceStoreSource };
|
|
5984
|
+
/** Where a real replay archived the drained outbox; `null` on a dry run. */
|
|
5985
|
+
archive: string | null;
|
|
5986
|
+
read: number;
|
|
5987
|
+
replayed: number;
|
|
5988
|
+
alreadyPresent: number | null;
|
|
5989
|
+
failed: number;
|
|
5990
|
+
dryRun: boolean;
|
|
5991
|
+
/** The same-event conflation caveat the CLI prints, or `null`. */
|
|
5992
|
+
note: string | null;
|
|
5993
|
+
/** Dry run only: the outbox fold (the `/diagnostics` dead-letter block minus the legacy pointer). */
|
|
5994
|
+
fold?: Omit<DiagnosticsGovernanceDeadletters, 'legacyOutbox'>;
|
|
5995
|
+
blocker: string | null;
|
|
5996
|
+
}
|
|
5997
|
+
|
|
5301
5998
|
/** The skills seam's state as `GET /diagnostics` reports it (skills keystone, api-types 0.28.0). */
|
|
5302
5999
|
export type DiagnosticsSkillsState = 'published' | 'fallback' | 'blocked' | 'config-error' | 'disabled';
|
|
5303
6000
|
|
|
@@ -5604,55 +6301,240 @@ export interface PolicyLandingResult {
|
|
|
5604
6301
|
* predating the policy→steering landing (forward-additive, DES-MEM-FACETED-001 §5.2).
|
|
5605
6302
|
*/
|
|
5606
6303
|
export type ApproveProposalResponse =
|
|
5607
|
-
| { outcome: 'promoted'; active_id: string }
|
|
6304
|
+
| { outcome: 'promoted'; active_id: string; edited?: ProposalEdit }
|
|
5608
6305
|
| { outcome: 'handed_off'; payload: unknown; landing?: PolicyLandingResult };
|
|
5609
6306
|
|
|
5610
|
-
/**
|
|
5611
|
-
|
|
5612
|
-
|
|
6307
|
+
/**
|
|
6308
|
+
* `POST /proposals/:id/approve` body (api-types 0.49.0) — present only for an accept WITH an edit;
|
|
6309
|
+
* no body (or `{}`) is the plain approve. estate has no proposal edit, so the daemon submits the
|
|
6310
|
+
* edited copy to the same queue (`payload.edited_from = <id>`), approves it, then rejects the
|
|
6311
|
+
* original. Memory proposals only (400 otherwise; 404 when `id` is not pending; 409 while another
|
|
6312
|
+
* accept of the same `id` is in flight).
|
|
6313
|
+
*/
|
|
6314
|
+
export interface ApproveProposalBody {
|
|
6315
|
+
/** The edited memory text (replaces `payload.content`). */
|
|
6316
|
+
content?: string;
|
|
6317
|
+
/** `"pattern"`: the copy drops its `project`/`repo` facets, so it may be recalled on ANY project
|
|
6318
|
+
* (the human act that lets a pattern cross projects; refused on anything but a captured memory, `payload.capture: "memory"`).
|
|
6319
|
+
* `"project"`: it stays scoped to its project — gaining the proposing run's project as its
|
|
6320
|
+
* `project` facet when the worker filed none (400 when no project files that run). An accept
|
|
6321
|
+
* that changes nothing the store keeps approves the original as filed (no copy, no `edited`). */
|
|
6322
|
+
reach?: 'project' | 'pattern';
|
|
5613
6323
|
}
|
|
5614
6324
|
|
|
5615
|
-
// ── Memory management (governed-knowledge surface, DES-MEM-FACETED-001, api-types 0.22.0) ──────
|
|
5616
|
-
//
|
|
5617
|
-
// The studio's surface for managing the memories that ALREADY exist in the operator store — the
|
|
5618
|
-
// counterpart to the proposal queue (which decides learnings not yet stored). Backed by the estate
|
|
5619
|
-
// MCP memory tools (memory.recall / memory.coverage / memory.erase) exposed over crew's /api/v1.
|
|
5620
|
-
// The granularity is estate's, surfaced honestly: browse is query-based (no "list all"), and
|
|
5621
|
-
// retire is SUBTREE-scoped (no per-id delete).
|
|
5622
|
-
|
|
5623
6325
|
/**
|
|
5624
|
-
*
|
|
5625
|
-
*
|
|
5626
|
-
*
|
|
5627
|
-
*
|
|
5628
|
-
*
|
|
5629
|
-
* `Proposal.facets`); `score` is the recall relevance score, absent when estate omits it.
|
|
6326
|
+
* `POST /proposals` body (api-types 0.54.0) — a skin files ONE preference into the review queue
|
|
6327
|
+
* (studio's takes: "prefers takes like X", filed when a person picks one of two candidate outputs).
|
|
6328
|
+
* The daemon files it as `kind_type: "memory"` with `payload {content, tier: "semantic",
|
|
6329
|
+
* capture: "preference", source?}`; the kind is never the caller's (unknown keys are a 400).
|
|
6330
|
+
* Nothing is learned until the person accepts it on `/proposals`.
|
|
5630
6331
|
*/
|
|
5631
|
-
export interface
|
|
5632
|
-
/**
|
|
5633
|
-
id: string;
|
|
5634
|
-
/** The memory body. */
|
|
6332
|
+
export interface FileProposalBody {
|
|
6333
|
+
/** The preference in words (1–4000 chars, trimmed). */
|
|
5635
6334
|
content: string;
|
|
5636
|
-
/**
|
|
5637
|
-
|
|
5638
|
-
/**
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
*
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
6335
|
+
/** Becomes the `project` facet, so the preference is recalled on that project only. */
|
|
6336
|
+
project?: string;
|
|
6337
|
+
/** Where the pick was made, e.g. `doc:<docId>@v3` (kept on the payload). */
|
|
6338
|
+
source?: string;
|
|
6339
|
+
}
|
|
6340
|
+
|
|
6341
|
+
/** `POST /proposals` → 201: the pending proposal's id. */
|
|
6342
|
+
export interface FileProposalResponse {
|
|
6343
|
+
id: string;
|
|
6344
|
+
}
|
|
6345
|
+
|
|
6346
|
+
/** An accept-with-edit's trail: the original proposal (now rejected) and the approved copy. */
|
|
6347
|
+
export interface ProposalEdit {
|
|
6348
|
+
from: string;
|
|
6349
|
+
to: string;
|
|
6350
|
+
/** The copy was approved but rejecting the original failed: it is still pending, for the person
|
|
6351
|
+
* to reject. Absent when the original was rejected. */
|
|
6352
|
+
originalPending?: true;
|
|
6353
|
+
}
|
|
6354
|
+
|
|
6355
|
+
// ── Capture (Studio OS behaviour 8, api-types 0.49.0) ─────────────────────────────
|
|
6356
|
+
|
|
6357
|
+
/** One dropped text file (a transcript, meeting notes). */
|
|
6358
|
+
export interface CaptureTextFile {
|
|
6359
|
+
name: string;
|
|
6360
|
+
text: string;
|
|
6361
|
+
}
|
|
6362
|
+
|
|
6363
|
+
/** One dropped photo, read by a vision-capable seat. `mediaType` is image/png, image/jpeg,
|
|
6364
|
+
* image/gif or image/webp. */
|
|
6365
|
+
export interface CaptureImageFile {
|
|
6366
|
+
name: string;
|
|
6367
|
+
mediaType: string;
|
|
6368
|
+
dataBase64: string;
|
|
6369
|
+
}
|
|
6370
|
+
|
|
6371
|
+
/**
|
|
6372
|
+
* `POST /projects/:id/capture` body: notes and/or files (at least one). The daemon lands them in a
|
|
6373
|
+
* per-run inbox and launches a repo-less run filed to the project (through `POST /runs`, so its
|
|
6374
|
+
* refusals are that route's). The run's output is proposals in the `/proposals` queue — each with
|
|
6375
|
+
* `kind_type: "memory"` (or `"policy:<type>"` for a rule), `payload.capture` = `intent` |
|
|
6376
|
+
* `decision` | `memory` | `rule`, `provenance.run_id` = the returned `runId`, and `facets.project`
|
|
6377
|
+
* unless the team marked a memory `payload.reach: "pattern"` (the user decides on accept).
|
|
6378
|
+
*/
|
|
6379
|
+
export interface CaptureBody {
|
|
6380
|
+
notes?: string;
|
|
6381
|
+
files?: Array<CaptureTextFile | CaptureImageFile>;
|
|
6382
|
+
}
|
|
6383
|
+
|
|
6384
|
+
/** `POST /projects/:id/capture` → 201. */
|
|
6385
|
+
export interface CaptureResponse {
|
|
6386
|
+
runId: string;
|
|
6387
|
+
}
|
|
6388
|
+
|
|
6389
|
+
// ── The Demo experience (wicked-studio#373, api-types 0.61.0) ────────────────────────────────
|
|
6390
|
+
|
|
6391
|
+
/**
|
|
6392
|
+
* `POST /projects/:id/demo` body: the app to film, who the demo is for and what to show. The daemon
|
|
6393
|
+
* mints the run's demo root, writes the brief there and launches the built-in `demo` preset (the
|
|
6394
|
+
* wicked-garden demo skill's plan → record → review) through `POST /runs`, so its refusals are that
|
|
6395
|
+
* route's. The demo root is the run's only extra write root; a caller never names it.
|
|
6396
|
+
*/
|
|
6397
|
+
export interface DemoLaunchBody {
|
|
6398
|
+
/** The running app (http or https). The recorder is read-only against it. */
|
|
6399
|
+
url: string;
|
|
6400
|
+
audience: string;
|
|
6401
|
+
show: string;
|
|
6402
|
+
/** The roster to seat the team from, as `POST /runs` takes it. Omit for the daemon's roster. */
|
|
6403
|
+
clisJson?: string;
|
|
6404
|
+
}
|
|
6405
|
+
|
|
6406
|
+
/** `POST /projects/:id/demo` → 201. */
|
|
6407
|
+
export interface DemoLaunchResponse {
|
|
6408
|
+
runId: string;
|
|
6409
|
+
}
|
|
6410
|
+
|
|
6411
|
+
/** `PUT /runs/:id/demo/script` body: the presenter's edit of `script.md` (plan gate only; ≤ 256 KB). */
|
|
6412
|
+
export interface DemoScriptBody {
|
|
6413
|
+
content: string;
|
|
6414
|
+
}
|
|
6415
|
+
|
|
6416
|
+
/**
|
|
6417
|
+
* Where a demo run stands. `preparing` covers the PA's scope step and any phase the floor added before
|
|
6418
|
+
* `plan`; `team_gate` is the team plan's approval gate (`plan_approval`: the run holds a plan rev past
|
|
6419
|
+
* the accepted one), which opens before `plan` runs and is answered like any gate; `plan_gate` and `review_gate` are the run's human gates (answered through `POST /runs/:id/gate`:
|
|
6420
|
+
* approve, or `action: 'request_changes'` with the note as `amend` — at the plan gate it re-runs `plan`,
|
|
6421
|
+
* at the review gate it rewinds to `record`). The review gate is the one after `review` passed, or the
|
|
6422
|
+
* engine's escalation gate when the review did not pass (`review.rejected`).
|
|
6423
|
+
*/
|
|
6424
|
+
export type DemoStage =
|
|
6425
|
+
| 'preparing'
|
|
6426
|
+
| 'team_gate'
|
|
6427
|
+
| 'planning'
|
|
6428
|
+
| 'plan_gate'
|
|
6429
|
+
| 'recording'
|
|
6430
|
+
| 'reviewing'
|
|
6431
|
+
| 'review_gate'
|
|
6432
|
+
| 'done'
|
|
6433
|
+
| 'failed';
|
|
6434
|
+
|
|
6435
|
+
/** One chapter of the plan's `chapters.json`, with whether its segment has been recorded. */
|
|
6436
|
+
export interface DemoChapter {
|
|
6437
|
+
/** `NN-slug` — the segment key record.mjs re-records by. */
|
|
6438
|
+
key: string;
|
|
6439
|
+
title: string;
|
|
6440
|
+
blurb: string;
|
|
6441
|
+
tags: string[];
|
|
6442
|
+
resets: string[];
|
|
6443
|
+
recorded: boolean;
|
|
6444
|
+
}
|
|
6445
|
+
|
|
6446
|
+
/** A chapter marker of the stitched MP4 (record.mjs's `chapters.md`). */
|
|
6447
|
+
export interface DemoMarker {
|
|
6448
|
+
/** `m:ss`. */
|
|
6449
|
+
at: string;
|
|
6450
|
+
sec: number;
|
|
6451
|
+
title: string;
|
|
6452
|
+
}
|
|
6453
|
+
|
|
6454
|
+
/** One finding of the reviewer's verdict block. */
|
|
6455
|
+
export interface DemoFinding {
|
|
6456
|
+
at: string;
|
|
6457
|
+
chapter: string;
|
|
6458
|
+
issue: string;
|
|
6459
|
+
verdict: 're-encode' | 're-record' | 'fix-app';
|
|
6460
|
+
}
|
|
6461
|
+
|
|
6462
|
+
/** `GET /runs/:id/demo` → 200 (404 for a run that is not a demo run). */
|
|
6463
|
+
export interface DemoView {
|
|
6464
|
+
runId: string;
|
|
6465
|
+
/** From the brief the daemon wrote. */
|
|
6466
|
+
url: string | null;
|
|
6467
|
+
audience: string | null;
|
|
6468
|
+
stage: DemoStage;
|
|
6469
|
+
/** `script.md` — the presenter script (null until `plan` writes it). */
|
|
6470
|
+
script: string | null;
|
|
6471
|
+
chapters: DemoChapter[];
|
|
6472
|
+
markers: DemoMarker[];
|
|
6473
|
+
/** Root-relative paths for `GET /runs/:id/demo/file?path=`. */
|
|
6474
|
+
sheets: Array<{ name: 'chapters' | 'joins' | 'end'; path: string }>;
|
|
6475
|
+
video: { path: string; bytes: number } | null;
|
|
6476
|
+
/** From the recorder's `recording.json`: true only when every stitched segment was recorded read-only;
|
|
6477
|
+
* null before a stitch (or from a recorder without the guard). */
|
|
6478
|
+
recording: { readOnly: boolean | null };
|
|
6479
|
+
/**
|
|
6480
|
+
* The reviewer's last output and its parsed verdict block (empty until `review` has finished).
|
|
6481
|
+
* `rejected`: the engine judged the review NOT PASS, so the review gate is its escalation gate — a
|
|
6482
|
+
* failed review cannot be accepted: approve re-runs the reviewer, `request_changes` sends the note back
|
|
6483
|
+
* to `record`, reject cancels the run.
|
|
6484
|
+
*/
|
|
6485
|
+
review: { verdict: 'accept' | 'changes' | null; findings: DemoFinding[]; text: string | null; rejected: boolean };
|
|
6486
|
+
/** The seats that recorded and reviewed — evaluator ≠ creator puts them apart. */
|
|
6487
|
+
seats: { recorder: string | null; reviewer: string | null };
|
|
6488
|
+
/** The script says which data is synthetic. */
|
|
6489
|
+
syntheticLabelled: boolean;
|
|
6490
|
+
}
|
|
6491
|
+
|
|
6492
|
+
/** `POST /proposals/:id/reject` → 200. */
|
|
6493
|
+
export interface RejectProposalResponse {
|
|
6494
|
+
ok: true;
|
|
6495
|
+
}
|
|
6496
|
+
|
|
6497
|
+
// ── Memory management (governed-knowledge surface, DES-MEM-FACETED-001, api-types 0.22.0) ──────
|
|
6498
|
+
//
|
|
6499
|
+
// The studio's surface for managing the memories that ALREADY exist in the operator store — the
|
|
6500
|
+
// counterpart to the proposal queue (which decides learnings not yet stored). Backed by the estate
|
|
6501
|
+
// MCP memory tools (memory.recall / memory.coverage / memory.erase) exposed over crew's /api/v1.
|
|
6502
|
+
// The granularity is estate's, surfaced honestly: browse is query-based (no "list all"), and
|
|
6503
|
+
// retire is SUBTREE-scoped (no per-id delete).
|
|
6504
|
+
|
|
6505
|
+
/**
|
|
6506
|
+
* One memory as browsed from the store (`GET /memory`, from estate `memory.recall`).
|
|
6507
|
+
*
|
|
6508
|
+
* estate `memory.recall` is query-based and token-budgeted — there is NO "list all" — and returns
|
|
6509
|
+
* `{ memory_id, scope, content, tier, score }` per item. It does NOT surface per-item `facets`, so
|
|
6510
|
+
* `facets` is presently always `{}` (kept in the shape for forward-compatibility and to mirror
|
|
6511
|
+
* `Proposal.facets`); `score` is the recall relevance score, absent when estate omits it.
|
|
6512
|
+
*/
|
|
6513
|
+
export interface MemoryItem {
|
|
6514
|
+
/** Stable memory-node id (estate `memory_id`). */
|
|
6515
|
+
id: string;
|
|
6516
|
+
/** The memory body. */
|
|
6517
|
+
content: string;
|
|
6518
|
+
/** Tier: `working` | `episodic` | `semantic` | `procedural` | `archival`. */
|
|
6519
|
+
tier: string;
|
|
6520
|
+
/** The memory's own hierarchical scope path (slash-separated `kind:id` segments; `""` = root). */
|
|
6521
|
+
scope: string;
|
|
6522
|
+
/** Orthogonal facets (axis → value) the memory is tagged with. Populated by estate `memory.list`
|
|
6523
|
+
* (the management browse) — this is what powers the surface's facet filter. `{}` for an
|
|
6524
|
+
* unfaceted memory (and for a `memory.recall`-sourced item, which carries no facets). */
|
|
6525
|
+
facets: Record<string, string>;
|
|
6526
|
+
/** Relevance score — only present on a `memory.recall` item; `memory.list` (the browse) is not
|
|
6527
|
+
* relevance-ranked, so it is absent there. */
|
|
6528
|
+
score?: number;
|
|
6529
|
+
/**
|
|
6530
|
+
* Unix-SECONDS timestamp of when this memory FIRST entered the store — the "added" time the
|
|
6531
|
+
* governance surface sorts + date-filters on (api-types 0.23.0). Populated from estate
|
|
6532
|
+
* `memory.list`, which returns `created_at` per item; ABSENT — never fabricated — on a memory
|
|
6533
|
+
* whose creation time the store did not report (and on a `memory.recall`-sourced item, which
|
|
6534
|
+
* carries none). Additive: absence is the one spelling of "unknown", so a `since`/`until` filter
|
|
6535
|
+
* cannot assert an undated memory in range.
|
|
6536
|
+
*/
|
|
6537
|
+
created_at?: number;
|
|
5656
6538
|
}
|
|
5657
6539
|
|
|
5658
6540
|
/**
|
|
@@ -5708,16 +6590,1461 @@ export interface MemoryCoverageResponse {
|
|
|
5708
6590
|
}
|
|
5709
6591
|
|
|
5710
6592
|
/**
|
|
5711
|
-
* `POST /memory/retire` body.
|
|
5712
|
-
*
|
|
5713
|
-
*
|
|
5714
|
-
*
|
|
6593
|
+
* `POST /memory/retire` body. This retire is SUBTREE-scoped: estate `memory.erase` hard-deletes
|
|
6594
|
+
* EVERY memory whose scope equals or descends from `scope_prefix`. `scope_prefix` is required and
|
|
6595
|
+
* must be non-empty (estate refuses a total wipe) — the surface must show the operator the whole
|
|
6596
|
+
* subtree it will remove. To remove ONE row, use {@link RetireMemoryItemBody}.
|
|
5715
6597
|
*/
|
|
5716
6598
|
export interface RetireMemoryBody {
|
|
5717
6599
|
scope_prefix: string;
|
|
5718
6600
|
}
|
|
5719
6601
|
|
|
5720
|
-
/**
|
|
6602
|
+
/**
|
|
6603
|
+
* `POST /memory/retire-item` body (studio#206; api-types 0.60.0): exactly ONE memory, by the
|
|
6604
|
+
* `memory_id` `GET /memory` listed. 404 when no memory has that id; 501 `estate_upgrade_required`
|
|
6605
|
+
* when the estate predates erase-by-id (wicked-estate#188) — nothing is deleted then.
|
|
6606
|
+
*/
|
|
6607
|
+
export interface RetireMemoryItemBody {
|
|
6608
|
+
memory_id: string;
|
|
6609
|
+
}
|
|
6610
|
+
|
|
6611
|
+
/** `POST /memory/retire` / `POST /memory/retire-item` → 200. How many memories were deleted
|
|
6612
|
+
* (always 1 for `retire-item`). */
|
|
5721
6613
|
export interface RetireMemoryResponse {
|
|
5722
6614
|
erased: number;
|
|
5723
6615
|
}
|
|
6616
|
+
|
|
6617
|
+
// ── Team events on the bus (DES-TEAMING-002 §6, wicked-core T1; api-types 0.41.0) ──────────────
|
|
6618
|
+
//
|
|
6619
|
+
// The `wicked.team.*` facts wicked-core publishes on the cross-product bus (`domain`
|
|
6620
|
+
// `wicked-core`, `subdomain` `core.team`), one owner per type (DES-002 §7: E engine, S supervisor,
|
|
6621
|
+
// R attempt runner). Crew publishes none of them: it relays and reads. Mirrors wicked-core
|
|
6622
|
+
// `src/team/events.rs`; `packages/crew/tests/team-events.test.ts` pins every type against the
|
|
6623
|
+
// engine's own round-trip fixtures by value. Payload keys are snake_case and every key is
|
|
6624
|
+
// present (an absent value is `null`), except a plan step's optional fields, which a plan omits
|
|
6625
|
+
// when unset. The embedded {@link TeamLedger} keeps DES-001 §7's camelCase.
|
|
6626
|
+
|
|
6627
|
+
/** The 25 `wicked.team.<noun>.<verb>` event types. */
|
|
6628
|
+
export type TeamEventType =
|
|
6629
|
+
| 'wicked.team.path.started'
|
|
6630
|
+
| 'wicked.team.path.scored'
|
|
6631
|
+
| 'wicked.team.plan.proposed'
|
|
6632
|
+
| 'wicked.team.plan.revised'
|
|
6633
|
+
| 'wicked.team.plan.accepted'
|
|
6634
|
+
| 'wicked.team.plan.refused'
|
|
6635
|
+
| 'wicked.team.member.joined'
|
|
6636
|
+
| 'wicked.team.member.left'
|
|
6637
|
+
| 'wicked.team.step.claimed'
|
|
6638
|
+
| 'wicked.team.checkpoint.reached'
|
|
6639
|
+
| 'wicked.team.finding.raised'
|
|
6640
|
+
| 'wicked.team.advice.delivered'
|
|
6641
|
+
| 'wicked.team.advice.answered'
|
|
6642
|
+
| 'wicked.team.help.requested'
|
|
6643
|
+
| 'wicked.team.help.answered'
|
|
6644
|
+
| 'wicked.team.change.requested'
|
|
6645
|
+
| 'wicked.team.step.completed'
|
|
6646
|
+
| 'wicked.team.step.reviewed'
|
|
6647
|
+
| 'wicked.team.finding.settled'
|
|
6648
|
+
| 'wicked.team.council.called'
|
|
6649
|
+
| 'wicked.team.council.ruled'
|
|
6650
|
+
| 'wicked.team.ledger.folded'
|
|
6651
|
+
| 'wicked.team.gate.opened'
|
|
6652
|
+
| 'wicked.team.gate.decided'
|
|
6653
|
+
| 'wicked.team.path.ended';
|
|
6654
|
+
|
|
6655
|
+
/** The fields every team payload carries. */
|
|
6656
|
+
export interface TeamEnvelope {
|
|
6657
|
+
run_id: string;
|
|
6658
|
+
ord: number | null;
|
|
6659
|
+
attempt: number | null;
|
|
6660
|
+
/**
|
|
6661
|
+
* Who acted: a seated CLI instance (the PA, a member or the authoring monitor, e.g.
|
|
6662
|
+
* `'claude#1'`, `'claude#2'`, `'codex'`), `'engine'`, `'human'` or `'council:<task id>'`.
|
|
6663
|
+
*/
|
|
6664
|
+
by: string;
|
|
6665
|
+
/** Epoch milliseconds at the producer. */
|
|
6666
|
+
at: number;
|
|
6667
|
+
/** The row this one answers, e.g. `'finding.raised#4'`. */
|
|
6668
|
+
re: string | null;
|
|
6669
|
+
}
|
|
6670
|
+
|
|
6671
|
+
/** A plan step: a catalog entry plus the step fields a plan may set (omitted when unset). */
|
|
6672
|
+
export interface TeamPlanStep {
|
|
6673
|
+
catalog: string;
|
|
6674
|
+
id: string;
|
|
6675
|
+
instructions?: string;
|
|
6676
|
+
owner?: 'pa' | 'team' | (string & {});
|
|
6677
|
+
depends_on?: string[];
|
|
6678
|
+
/** A raised gate, as the workflow's externally tagged `GateSpec`. */
|
|
6679
|
+
gate?: unknown;
|
|
6680
|
+
added_by?: 'plan' | 'floor' | (string & {});
|
|
6681
|
+
floor_reason?: string;
|
|
6682
|
+
late?: boolean;
|
|
6683
|
+
}
|
|
6684
|
+
|
|
6685
|
+
export interface TeamPlanOverride {
|
|
6686
|
+
remove: string[];
|
|
6687
|
+
reason: string;
|
|
6688
|
+
}
|
|
6689
|
+
|
|
6690
|
+
export type TeamPathStartedPayload = TeamEnvelope & {
|
|
6691
|
+
cli: string;
|
|
6692
|
+
selection: 'chosen' | 'random' | (string & {});
|
|
6693
|
+
roster: string[];
|
|
6694
|
+
request: string;
|
|
6695
|
+
workflow: string | null;
|
|
6696
|
+
plan: boolean;
|
|
6697
|
+
};
|
|
6698
|
+
|
|
6699
|
+
export type TeamPathScoredPayload = TeamEnvelope & {
|
|
6700
|
+
/** `'intent:<proposal_id>'` | `'diff:<ord>:<attempt>:<rescore_seq>'`. */
|
|
6701
|
+
score_source: string;
|
|
6702
|
+
basis: 'intent' | 'diff' | (string & {});
|
|
6703
|
+
score: number;
|
|
6704
|
+
deterministic: number;
|
|
6705
|
+
reasons: string[];
|
|
6706
|
+
model: { add: number; rationale: string } | null;
|
|
6707
|
+
signals: {
|
|
6708
|
+
changed_symbols: number;
|
|
6709
|
+
dependents: number;
|
|
6710
|
+
products: number;
|
|
6711
|
+
contract_change: boolean;
|
|
6712
|
+
test_gap: number;
|
|
6713
|
+
critical: boolean;
|
|
6714
|
+
destructive: boolean;
|
|
6715
|
+
truncated: boolean;
|
|
6716
|
+
} | null;
|
|
6717
|
+
plan: { monitors: number; depth: string; post_hoc_reviewer: boolean; post_hoc_other_cli: boolean };
|
|
6718
|
+
tree: string | null;
|
|
6719
|
+
};
|
|
6720
|
+
|
|
6721
|
+
export type TeamPlanProposedPayload = TeamEnvelope & {
|
|
6722
|
+
proposal_id: string;
|
|
6723
|
+
base_rev: number | null;
|
|
6724
|
+
kind: 'initial' | 'change' | 'edit' | (string & {});
|
|
6725
|
+
preset: string | null;
|
|
6726
|
+
steps: TeamPlanStep[];
|
|
6727
|
+
monitors: { asked: number };
|
|
6728
|
+
asks: string[];
|
|
6729
|
+
touch: string[];
|
|
6730
|
+
override: TeamPlanOverride | null;
|
|
6731
|
+
rationale: string;
|
|
6732
|
+
};
|
|
6733
|
+
|
|
6734
|
+
export type TeamPlanRevisedPayload = TeamEnvelope & {
|
|
6735
|
+
plan_rev: number;
|
|
6736
|
+
proposal_id: string | null;
|
|
6737
|
+
reason: 'floor_raised' | 'pa_added' | 'member_request' | (string & {});
|
|
6738
|
+
from_band: string;
|
|
6739
|
+
to_band: string;
|
|
6740
|
+
high_risk: boolean;
|
|
6741
|
+
added: TeamPlanStep[];
|
|
6742
|
+
};
|
|
6743
|
+
|
|
6744
|
+
export type TeamPlanAcceptedPayload = TeamEnvelope & {
|
|
6745
|
+
plan_rev: number;
|
|
6746
|
+
workflow_id: string;
|
|
6747
|
+
band: string;
|
|
6748
|
+
high_risk: boolean;
|
|
6749
|
+
mode: 'auto' | 'manual' | (string & {});
|
|
6750
|
+
steps: TeamPlanStep[];
|
|
6751
|
+
override: TeamPlanOverride | null;
|
|
6752
|
+
proposal_id: string | null;
|
|
6753
|
+
};
|
|
6754
|
+
|
|
6755
|
+
export type TeamPlanRefusedPayload = TeamEnvelope & {
|
|
6756
|
+
proposal_id: string;
|
|
6757
|
+
base_rev: number | null;
|
|
6758
|
+
reason: string;
|
|
6759
|
+
};
|
|
6760
|
+
|
|
6761
|
+
export type TeamMemberJoinedPayload = TeamEnvelope & {
|
|
6762
|
+
member_id: string;
|
|
6763
|
+
open_seq: number;
|
|
6764
|
+
seat: string;
|
|
6765
|
+
role: 'monitor' | (string & {});
|
|
6766
|
+
status: 'attached' | 'failed' | (string & {});
|
|
6767
|
+
reason: string;
|
|
6768
|
+
error: string | null;
|
|
6769
|
+
};
|
|
6770
|
+
|
|
6771
|
+
export type TeamMemberLeftPayload = TeamEnvelope & {
|
|
6772
|
+
member_id: string;
|
|
6773
|
+
open_seq: number;
|
|
6774
|
+
seat: string;
|
|
6775
|
+
status: 'completed' | 'budget_exhausted' | 'failed' | 'timed_out' | (string & {});
|
|
6776
|
+
batches: number;
|
|
6777
|
+
error: string | null;
|
|
6778
|
+
};
|
|
6779
|
+
|
|
6780
|
+
export type TeamStepClaimedPayload = TeamEnvelope & {
|
|
6781
|
+
step_id: string;
|
|
6782
|
+
role: string;
|
|
6783
|
+
kind: string;
|
|
6784
|
+
phase: string;
|
|
6785
|
+
criterion: string;
|
|
6786
|
+
baseline_tree: string | null;
|
|
6787
|
+
repo: { workdir: string; git_dir: string } | null;
|
|
6788
|
+
code_graph_db: string | null;
|
|
6789
|
+
};
|
|
6790
|
+
|
|
6791
|
+
export type TeamCheckpointReachedPayload = TeamEnvelope & {
|
|
6792
|
+
seq: number;
|
|
6793
|
+
tool_call_id: string;
|
|
6794
|
+
kind: string;
|
|
6795
|
+
title: string;
|
|
6796
|
+
status: 'completed' | 'failed' | (string & {});
|
|
6797
|
+
paths: string[];
|
|
6798
|
+
};
|
|
6799
|
+
|
|
6800
|
+
export type TeamFindingRaisedPayload = TeamEnvelope & {
|
|
6801
|
+
raise_seq: number;
|
|
6802
|
+
finding_id: string;
|
|
6803
|
+
member_id: string;
|
|
6804
|
+
line_key: string | null;
|
|
6805
|
+
anchor: string | null;
|
|
6806
|
+
anchor_source: 'graph' | 'hunk' | 'none' | (string & {}) | null;
|
|
6807
|
+
severity: 'high' | 'medium' | (string & {});
|
|
6808
|
+
path: string;
|
|
6809
|
+
line: number;
|
|
6810
|
+
evidence: string;
|
|
6811
|
+
claim: string;
|
|
6812
|
+
suggestion: string | null;
|
|
6813
|
+
tree: string;
|
|
6814
|
+
in_diff: boolean;
|
|
6815
|
+
corroborated_by: string[];
|
|
6816
|
+
};
|
|
6817
|
+
|
|
6818
|
+
export type TeamAdviceDeliveredPayload = TeamEnvelope & {
|
|
6819
|
+
raise_seq: number;
|
|
6820
|
+
finding_id: string;
|
|
6821
|
+
/** The steer id | `'boundary:<step_id>:<attempt>'` | `'end:<attempt>'`. */
|
|
6822
|
+
delivery_id: string;
|
|
6823
|
+
steer_id: string | null;
|
|
6824
|
+
channel: 'acp_steering' | 'boundary' | 'none' | (string & {});
|
|
6825
|
+
outcome: 'injected' | 'turn_ended' | 'refused' | 'not_delivered' | (string & {});
|
|
6826
|
+
detail: string | null;
|
|
6827
|
+
};
|
|
6828
|
+
|
|
6829
|
+
export type TeamAdviceAnsweredPayload = TeamEnvelope & {
|
|
6830
|
+
raise_seq: number;
|
|
6831
|
+
/** `'<step_id>:<attempt>'`. */
|
|
6832
|
+
answered_in: string;
|
|
6833
|
+
finding_id: string;
|
|
6834
|
+
disposition: 'accepted' | 'declined' | (string & {});
|
|
6835
|
+
reason: string;
|
|
6836
|
+
};
|
|
6837
|
+
|
|
6838
|
+
export type TeamHelpRequestedPayload = TeamEnvelope & {
|
|
6839
|
+
help_id: string;
|
|
6840
|
+
help_seq: number;
|
|
6841
|
+
question: string;
|
|
6842
|
+
context: string;
|
|
6843
|
+
};
|
|
6844
|
+
|
|
6845
|
+
export type TeamHelpAnsweredPayload = TeamEnvelope & {
|
|
6846
|
+
help_id: string;
|
|
6847
|
+
answer_id: string;
|
|
6848
|
+
answer: string;
|
|
6849
|
+
evidence: string[];
|
|
6850
|
+
};
|
|
6851
|
+
|
|
6852
|
+
export type TeamChangeRequestedPayload = TeamEnvelope & {
|
|
6853
|
+
change_id: string;
|
|
6854
|
+
change_seq: number;
|
|
6855
|
+
steps: TeamPlanStep[];
|
|
6856
|
+
reason: string;
|
|
6857
|
+
};
|
|
6858
|
+
|
|
6859
|
+
export type TeamStepCompletedPayload = TeamEnvelope & {
|
|
6860
|
+
step_id: string;
|
|
6861
|
+
status: 'ok' | 'failed' | 'cancelled' | 'elicitation_failed' | 'timed_out' | (string & {});
|
|
6862
|
+
tree: string | null;
|
|
6863
|
+
output_bytes: number;
|
|
6864
|
+
output_ref: string;
|
|
6865
|
+
};
|
|
6866
|
+
|
|
6867
|
+
export type TeamStepReviewedPayload = TeamEnvelope & {
|
|
6868
|
+
step_id: string;
|
|
6869
|
+
verdict: 'accepted' | 'rejected' | (string & {});
|
|
6870
|
+
to: 'member' | 'pa' | (string & {}) | null;
|
|
6871
|
+
reason: string;
|
|
6872
|
+
};
|
|
6873
|
+
|
|
6874
|
+
export type TeamFindingSettledPayload = TeamEnvelope & {
|
|
6875
|
+
raise_seq: number;
|
|
6876
|
+
finding_id: string;
|
|
6877
|
+
status: 'held' | 'withdrawn' | 'superseded' | (string & {});
|
|
6878
|
+
reason: string;
|
|
6879
|
+
final_line: number | null;
|
|
6880
|
+
};
|
|
6881
|
+
|
|
6882
|
+
export type TeamCouncilCalledPayload = TeamEnvelope & {
|
|
6883
|
+
/** `'finding:<raise_seq>'` | `'step:<step_id>:<attempt>'`. */
|
|
6884
|
+
subject: string;
|
|
6885
|
+
finding_id: string | null;
|
|
6886
|
+
trigger: 'unresolved_high' | 'member_step' | (string & {});
|
|
6887
|
+
question: string;
|
|
6888
|
+
positions: { by: string; position: string; reason: string }[];
|
|
6889
|
+
evidence: string;
|
|
6890
|
+
excluded_seats: string[];
|
|
6891
|
+
transcript: number[];
|
|
6892
|
+
};
|
|
6893
|
+
|
|
6894
|
+
export type TeamCouncilRuledPayload = TeamEnvelope & {
|
|
6895
|
+
subject: string;
|
|
6896
|
+
verdict: 'yes' | 'no' | 'no_verdict' | (string & {});
|
|
6897
|
+
reason: 'no_quorum' | 'seats_benched' | 'error' | 'timeout' | 'cap' | (string & {}) | null;
|
|
6898
|
+
task_id: string | null;
|
|
6899
|
+
consensus: boolean;
|
|
6900
|
+
agreement_pct: number;
|
|
6901
|
+
dissent: string[];
|
|
6902
|
+
returned: number;
|
|
6903
|
+
seated: number;
|
|
6904
|
+
};
|
|
6905
|
+
|
|
6906
|
+
/** DES-001 §7 `teamLedger.findings[]` (camelCase). */
|
|
6907
|
+
export interface TeamLedgerFinding {
|
|
6908
|
+
findingId: string;
|
|
6909
|
+
monitorId: string;
|
|
6910
|
+
seat: string;
|
|
6911
|
+
severity: 'high' | 'medium' | (string & {});
|
|
6912
|
+
path: string;
|
|
6913
|
+
line: number;
|
|
6914
|
+
evidence: string;
|
|
6915
|
+
claim: string;
|
|
6916
|
+
suggestion: string | null;
|
|
6917
|
+
tree: string;
|
|
6918
|
+
inDiff: boolean;
|
|
6919
|
+
finalLine: number | null;
|
|
6920
|
+
corroboratedBy: string[];
|
|
6921
|
+
delivery: 'injected' | 'not_delivered' | (string & {});
|
|
6922
|
+
status: 'accepted' | 'declined' | 'withdrawn' | 'unanswered' | 'superseded' | (string & {});
|
|
6923
|
+
workerReason: string | null;
|
|
6924
|
+
monitorReply: { kind: 'hold' | 'withdraw' | (string & {}); reason: string } | null;
|
|
6925
|
+
dispute: {
|
|
6926
|
+
verdict: 'yes' | 'no' | 'no_verdict' | (string & {});
|
|
6927
|
+
agreementPct: number | null;
|
|
6928
|
+
dissent: number | null;
|
|
6929
|
+
seats: string[];
|
|
6930
|
+
reason: string | null;
|
|
6931
|
+
} | null;
|
|
6932
|
+
/**
|
|
6933
|
+
* (T6, api-types 0.42.0) The enclosing location the finding id is minted over (git's funcname
|
|
6934
|
+
* heuristic). Omitted when file-level.
|
|
6935
|
+
*/
|
|
6936
|
+
anchor?: string;
|
|
6937
|
+
/** (T6, api-types 0.42.0) The attempt that first raised it, when it was carried into a redriven attempt. Omitted otherwise. */
|
|
6938
|
+
carriedFromAttempt?: number;
|
|
6939
|
+
}
|
|
6940
|
+
|
|
6941
|
+
/**
|
|
6942
|
+
* (T6, DES-002 §8.8; api-types 0.42.0) The PA's review of a member's step, as the attempt that
|
|
6943
|
+
* carried the review recorded it.
|
|
6944
|
+
*/
|
|
6945
|
+
export interface TeamStepReview {
|
|
6946
|
+
stepId: string;
|
|
6947
|
+
/** The member attempt the review is about. */
|
|
6948
|
+
reviewedAttempt: number;
|
|
6949
|
+
verdict: 'accepted' | 'rejected' | (string & {});
|
|
6950
|
+
to: 'member' | 'pa' | (string & {}) | null;
|
|
6951
|
+
reason: string;
|
|
6952
|
+
/** On a rejection: `true` the member held (`HOLD`), `false` it accepted, `null` no answer on record. */
|
|
6953
|
+
held: boolean | null;
|
|
6954
|
+
memberReason: string | null;
|
|
6955
|
+
/** The one-off council a hold convened. */
|
|
6956
|
+
dispute: TeamLedgerFinding['dispute'];
|
|
6957
|
+
}
|
|
6958
|
+
|
|
6959
|
+
/** DES-001 §7 `teamLedger` without its envelope: the fold of one attempt's team stream. */
|
|
6960
|
+
export interface TeamLedger {
|
|
6961
|
+
finalPass: 'completed' | 'timed_out' | 'skipped' | 'stream_gap' | (string & {});
|
|
6962
|
+
renderedToJudge: boolean;
|
|
6963
|
+
teamPause: boolean;
|
|
6964
|
+
monitors: {
|
|
6965
|
+
monitorId: string;
|
|
6966
|
+
seat: string;
|
|
6967
|
+
batches: number;
|
|
6968
|
+
status: 'completed' | 'budget_exhausted' | 'failed' | 'timed_out' | (string & {});
|
|
6969
|
+
error: string | null;
|
|
6970
|
+
}[];
|
|
6971
|
+
findings: TeamLedgerFinding[];
|
|
6972
|
+
rejected: { malformed: number; belowBar: number; unconfirmed: number; duplicate: number };
|
|
6973
|
+
/** (T6, api-types 0.42.0) The PA's reviews of member steps this attempt carried. Omitted when none. */
|
|
6974
|
+
stepReviews?: TeamStepReview[];
|
|
6975
|
+
}
|
|
6976
|
+
|
|
6977
|
+
export type TeamLedgerFoldedPayload = TeamEnvelope & {
|
|
6978
|
+
final_pass: 'completed' | 'timed_out' | 'skipped' | 'stream_gap' | (string & {});
|
|
6979
|
+
ledger: TeamLedger;
|
|
6980
|
+
transport: 'bus' | 'none' | (string & {});
|
|
6981
|
+
transcript: {
|
|
6982
|
+
from_event_id: number;
|
|
6983
|
+
to_event_id: number;
|
|
6984
|
+
count: number;
|
|
6985
|
+
truncated: boolean;
|
|
6986
|
+
events: { event_id: number; event_type: string; payload: unknown }[];
|
|
6987
|
+
};
|
|
6988
|
+
};
|
|
6989
|
+
|
|
6990
|
+
/** `gate.opened`'s kind-specific fields, discriminated on `kind`. */
|
|
6991
|
+
export type TeamGateOpenedPayload = TeamEnvelope & { gate_id: string } & (
|
|
6992
|
+
| { kind: 'unit_review'; ledger_ref: string | null; ledger_source: 'folded' | 'synthesized' | 'no_bus' | (string & {}) }
|
|
6993
|
+
| {
|
|
6994
|
+
kind: 'plan_approval';
|
|
6995
|
+
reviewing_ord: number;
|
|
6996
|
+
plan_rev: number;
|
|
6997
|
+
band: string;
|
|
6998
|
+
high_risk: boolean;
|
|
6999
|
+
mode: 'auto' | 'manual' | (string & {});
|
|
7000
|
+
reason: 'manual_mode' | 'high_risk' | 'into_high_risk' | 'override' | (string & {});
|
|
7001
|
+
diff: { from_rev: number | null; added: string[] };
|
|
7002
|
+
}
|
|
7003
|
+
| { kind: 'team_dispute'; finding_ids: string[] }
|
|
7004
|
+
| { kind: 'team_transport'; fact: string; reason: string }
|
|
7005
|
+
);
|
|
7006
|
+
|
|
7007
|
+
export type TeamGateDecidedPayload = TeamEnvelope & {
|
|
7008
|
+
gate_id: string;
|
|
7009
|
+
kind: 'unit_review' | 'plan_approval' | 'team_dispute' | 'team_transport' | (string & {});
|
|
7010
|
+
decision:
|
|
7011
|
+
| 'allow'
|
|
7012
|
+
| 'deny'
|
|
7013
|
+
| 'paused'
|
|
7014
|
+
| 'human_approved'
|
|
7015
|
+
| 'human_amended'
|
|
7016
|
+
| 'human_rejected'
|
|
7017
|
+
| (string & {});
|
|
7018
|
+
combined: boolean | null;
|
|
7019
|
+
team_pause: boolean;
|
|
7020
|
+
unresolved: string[];
|
|
7021
|
+
};
|
|
7022
|
+
|
|
7023
|
+
export type TeamPathEndedPayload = TeamEnvelope & {
|
|
7024
|
+
status: 'completed' | 'failed' | 'cancelled' | (string & {});
|
|
7025
|
+
};
|
|
7026
|
+
|
|
7027
|
+
/** Each team event type's payload. */
|
|
7028
|
+
export interface TeamEventPayloads {
|
|
7029
|
+
'wicked.team.path.started': TeamPathStartedPayload;
|
|
7030
|
+
'wicked.team.path.scored': TeamPathScoredPayload;
|
|
7031
|
+
'wicked.team.plan.proposed': TeamPlanProposedPayload;
|
|
7032
|
+
'wicked.team.plan.revised': TeamPlanRevisedPayload;
|
|
7033
|
+
'wicked.team.plan.accepted': TeamPlanAcceptedPayload;
|
|
7034
|
+
'wicked.team.plan.refused': TeamPlanRefusedPayload;
|
|
7035
|
+
'wicked.team.member.joined': TeamMemberJoinedPayload;
|
|
7036
|
+
'wicked.team.member.left': TeamMemberLeftPayload;
|
|
7037
|
+
'wicked.team.step.claimed': TeamStepClaimedPayload;
|
|
7038
|
+
'wicked.team.checkpoint.reached': TeamCheckpointReachedPayload;
|
|
7039
|
+
'wicked.team.finding.raised': TeamFindingRaisedPayload;
|
|
7040
|
+
'wicked.team.advice.delivered': TeamAdviceDeliveredPayload;
|
|
7041
|
+
'wicked.team.advice.answered': TeamAdviceAnsweredPayload;
|
|
7042
|
+
'wicked.team.help.requested': TeamHelpRequestedPayload;
|
|
7043
|
+
'wicked.team.help.answered': TeamHelpAnsweredPayload;
|
|
7044
|
+
'wicked.team.change.requested': TeamChangeRequestedPayload;
|
|
7045
|
+
'wicked.team.step.completed': TeamStepCompletedPayload;
|
|
7046
|
+
'wicked.team.step.reviewed': TeamStepReviewedPayload;
|
|
7047
|
+
'wicked.team.finding.settled': TeamFindingSettledPayload;
|
|
7048
|
+
'wicked.team.council.called': TeamCouncilCalledPayload;
|
|
7049
|
+
'wicked.team.council.ruled': TeamCouncilRuledPayload;
|
|
7050
|
+
'wicked.team.ledger.folded': TeamLedgerFoldedPayload;
|
|
7051
|
+
'wicked.team.gate.opened': TeamGateOpenedPayload;
|
|
7052
|
+
'wicked.team.gate.decided': TeamGateDecidedPayload;
|
|
7053
|
+
'wicked.team.path.ended': TeamPathEndedPayload;
|
|
7054
|
+
}
|
|
7055
|
+
|
|
7056
|
+
/** One team bus row, discriminated on `event_type`. */
|
|
7057
|
+
export type TeamBusEvent = {
|
|
7058
|
+
[K in TeamEventType]: { event_type: K; payload: TeamEventPayloads[K] };
|
|
7059
|
+
}[TeamEventType];
|
|
7060
|
+
|
|
7061
|
+
// ── The crew team surface (DES-TEAMING-002 T8; api-types 0.42.0) ─────────────────────────────
|
|
7062
|
+
//
|
|
7063
|
+
// Commands go through the API, facts go on the bus (§4.0). Crew RELAYS the engine's
|
|
7064
|
+
// `wicked.team.*` rows onto `/ws`, READS them back per run, and POSTs commands to the engine. It
|
|
7065
|
+
// publishes no team row.
|
|
7066
|
+
|
|
7067
|
+
/**
|
|
7068
|
+
* A `/ws` frame carrying one `wicked.team.*` bus row, relayed verbatim (the `interactiveEvent`
|
|
7069
|
+
* pattern). `project_id` is set when the run's membership files it, as on every other frame.
|
|
7070
|
+
*/
|
|
7071
|
+
export interface TeamEventFrame {
|
|
7072
|
+
type: 'teamEvent';
|
|
7073
|
+
/** The whole bus row as wicked-bus delivers it. */
|
|
7074
|
+
event: TeamBusEvent & { event_id: number; [k: string]: unknown };
|
|
7075
|
+
project_id?: string;
|
|
7076
|
+
}
|
|
7077
|
+
|
|
7078
|
+
/** One `wicked.team.*` bus row as `GET /runs/:id/team` returns it. */
|
|
7079
|
+
export type TeamRow = TeamBusEvent & {
|
|
7080
|
+
event_id: number;
|
|
7081
|
+
/** wicked-bus `emitted_at` (Unix millis). */
|
|
7082
|
+
emitted_at: number;
|
|
7083
|
+
/**
|
|
7084
|
+
* Set on a `wicked.team.ledger.folded` row the unit's gate did NOT read: a `gate.opened
|
|
7085
|
+
* {kind:"unit_review"}` for the same ord and attempt names another ledger (`ledger_ref` null,
|
|
7086
|
+
* a synthesized ledger). `gate.opened.ledger_ref` is the only authority on what the gate read.
|
|
7087
|
+
*/
|
|
7088
|
+
unused?: true;
|
|
7089
|
+
};
|
|
7090
|
+
|
|
7091
|
+
/**
|
|
7092
|
+
* One unit's team state in {@link RunTeamResponse}: the engine's persisted snapshot
|
|
7093
|
+
* (`Core.runTeam`; the last five fields are `null` until the unit's attempt folded) plus the
|
|
7094
|
+
* unit's bus rows.
|
|
7095
|
+
*/
|
|
7096
|
+
export interface RunTeamUnit {
|
|
7097
|
+
ord: number;
|
|
7098
|
+
/** `null` until the unit dispatched. */
|
|
7099
|
+
transport: 'bus' | 'none' | (string & {}) | null;
|
|
7100
|
+
reason: string | null;
|
|
7101
|
+
/** Where the gate's ledger came from: folded by the supervisor, synthesized by the worker on the final-pass timeout, or local (no bus). */
|
|
7102
|
+
ledgerSource: 'folded' | 'synthesized' | 'no_bus' | (string & {}) | null;
|
|
7103
|
+
/** The supervisor row the gate read (`"ledger.folded#<ord>:<attempt>"`); `null` for a synthesized or local ledger. */
|
|
7104
|
+
ledgerRef: string | null;
|
|
7105
|
+
finalPass: 'completed' | 'timed_out' | 'skipped' | 'stream_gap' | (string & {}) | null;
|
|
7106
|
+
/** An unresolved HIGH (or an incomplete record) stands without a council YES: the run pauses `team_dispute`. */
|
|
7107
|
+
teamPause: boolean | null;
|
|
7108
|
+
/** How many findings the attempt's ledger holds. */
|
|
7109
|
+
findings: number | null;
|
|
7110
|
+
/** The unit's bus rows (`payload.ord` = this ord), every attempt, ordered by `event_id`. Empty when the bus has none. */
|
|
7111
|
+
rows: TeamRow[];
|
|
7112
|
+
/**
|
|
7113
|
+
* The folded ledger the gate read (the `ledger.folded` row `ledgerRef` names), or `null`: not
|
|
7114
|
+
* folded yet, synthesized or local (read `UnitEvidence.team` on the evidence route), or the bus
|
|
7115
|
+
* no longer has the row (the snapshot fields above still stand).
|
|
7116
|
+
*/
|
|
7117
|
+
ledger: TeamLedger | null;
|
|
7118
|
+
}
|
|
7119
|
+
|
|
7120
|
+
/**
|
|
7121
|
+
* `GET /runs/:id/team`. The run's team transport and per-unit team state. A run that is not a team
|
|
7122
|
+
* run (free text, a registered def: bug, chat, onboarding, …) answers `teamed: false`,
|
|
7123
|
+
* `transport: null` and `units: []` — nothing to render, and no outage.
|
|
7124
|
+
*/
|
|
7125
|
+
export interface RunTeamResponse {
|
|
7126
|
+
runId: string;
|
|
7127
|
+
/** Whether the run is a team run at all. `false` ⇒ `transport` and `reason` are `null`. */
|
|
7128
|
+
teamed: boolean;
|
|
7129
|
+
/**
|
|
7130
|
+
* For a team run: `"bus"`; `"none"` (the teamed run fell back to no team transport: render the
|
|
7131
|
+
* "team transport unavailable" banner with `reason`); `"pending"` (not decided yet);
|
|
7132
|
+
* `"unavailable"` (this daemon has no bus: the run is paused `team_transport` until the operator
|
|
7133
|
+
* answers it). `null` for a run that is not a team run.
|
|
7134
|
+
*/
|
|
7135
|
+
transport: 'bus' | 'none' | 'pending' | 'unavailable' | (string & {}) | null;
|
|
7136
|
+
reason: string | null;
|
|
7137
|
+
/** The first bus event id of the run's stream. */
|
|
7138
|
+
streamFloor: number | null;
|
|
7139
|
+
planRev: number | null;
|
|
7140
|
+
/** The required fact the run waits on (its event type), if any. */
|
|
7141
|
+
pending: string | null;
|
|
7142
|
+
/** The run is terminal and its end is on record (a run that is not a team run: its status is terminal). */
|
|
7143
|
+
ended: boolean;
|
|
7144
|
+
units: RunTeamUnit[];
|
|
7145
|
+
/** The run-level rows (`payload.ord` null: `path.*`, `plan.*`), ordered by `event_id`. */
|
|
7146
|
+
rows: TeamRow[];
|
|
7147
|
+
}
|
|
7148
|
+
|
|
7149
|
+
/**
|
|
7150
|
+
* `POST /runs/:id/plan` body: a plan edit. At a `plan_approval` gate the edit IS the gate answer
|
|
7151
|
+
* (the engine proposes, floor-fills and accepts it, or refuses it and re-opens the gate) and the
|
|
7152
|
+
* route answers `{ status }`. Anywhere else on a live planned run (running, or paused at another
|
|
7153
|
+
* gate) it is a MID-RUN edit (`Core.proposePlan`): `plan.steps` are the steps to ADD, held and
|
|
7154
|
+
* applied at the run's next step boundary — its author approved it, so no gate opens — and the
|
|
7155
|
+
* route answers {@link PlanProposalResponse}. A mid-run edit carries no `touch` / `override`.
|
|
7156
|
+
*/
|
|
7157
|
+
export interface EditPlanBody {
|
|
7158
|
+
plan: LaunchPlan;
|
|
7159
|
+
/**
|
|
7160
|
+
* The caller's id for this edit: the engine's idempotency key for a mid-run edit, so a retried
|
|
7161
|
+
* POST carrying the same id proposes once (`duplicate: true`). Omitted ⇒ the daemon mints a
|
|
7162
|
+
* fresh UUID for that POST, so an omitted-id retry is a SECOND edit — send one to retry safely.
|
|
7163
|
+
* A gate edit is keyed on its gate, not on this id.
|
|
7164
|
+
*/
|
|
7165
|
+
requestId?: string;
|
|
7166
|
+
}
|
|
7167
|
+
|
|
7168
|
+
/** `POST /runs/:id/plan` at a `plan_approval` gate: the run's status after the gate answer. */
|
|
7169
|
+
export interface EditPlanGateResponse {
|
|
7170
|
+
status: SessionStatus;
|
|
7171
|
+
}
|
|
7172
|
+
|
|
7173
|
+
/**
|
|
7174
|
+
* `POST /runs/:id/plan` mid-run: the engine's `PlanProposal` (`Core.proposePlan`), what the held
|
|
7175
|
+
* edit does to the run — read off the dry run it was validated by, since the author's own edit
|
|
7176
|
+
* opens no gate. Refusals (a plan awaiting approval — edit it at the gate —, a started deliver
|
|
7177
|
+
* step, a finished or unplanned run, an edit the revision refuses) answer 409 with the engine
|
|
7178
|
+
* reason.
|
|
7179
|
+
*/
|
|
7180
|
+
export interface PlanProposalResponse {
|
|
7181
|
+
/** The `plan.proposed` id the edit is published under. */
|
|
7182
|
+
proposal_id: string;
|
|
7183
|
+
/** `true`: this `requestId` was already taken — nothing new is held or published. */
|
|
7184
|
+
duplicate: boolean;
|
|
7185
|
+
/** The floor band of the rev the edit makes (`"40-69"`, …); `null` for a duplicate. */
|
|
7186
|
+
band: string | null;
|
|
7187
|
+
/** §8.5's high-risk rule on that rev: `true` = the edit moved the run into high risk. `null` for a duplicate. */
|
|
7188
|
+
high_risk: boolean | null;
|
|
7189
|
+
/** The floor phase types (catalog ids) the edit adds; empty for a duplicate. */
|
|
7190
|
+
floor_added: string[];
|
|
7191
|
+
}
|
|
7192
|
+
|
|
7193
|
+
/** `POST /runs/:id/plan`: a gate answer (`status`) or a mid-run proposal (`proposal_id`). */
|
|
7194
|
+
export type EditPlanResponse = EditPlanGateResponse | PlanProposalResponse;
|
|
7195
|
+
|
|
7196
|
+
/** `POST /team/outbox/replay`: the engine's replay of `<state home>/team-outbox.ndjson`. */
|
|
7197
|
+
export interface TeamOutboxReplayReport {
|
|
7198
|
+
/** `[idempotency key, bus event id]` of every fact that reached the bus, in publish order. */
|
|
7199
|
+
published: Array<[string, number]>;
|
|
7200
|
+
superseded: number;
|
|
7201
|
+
invalid: number;
|
|
7202
|
+
remaining: number;
|
|
7203
|
+
/** `[run id, reason]` per lane that stopped. */
|
|
7204
|
+
failures: Array<[string, string]>;
|
|
7205
|
+
}
|
|
7206
|
+
|
|
7207
|
+
/** One phase type of the engine's catalog (`GET /catalog`, `Core.catalog`), in catalog order —
|
|
7208
|
+
* the row studio's phase picker renders. */
|
|
7209
|
+
export interface CatalogEntry {
|
|
7210
|
+
id: string;
|
|
7211
|
+
kind: StageKindPhase;
|
|
7212
|
+
role: PhaseRole;
|
|
7213
|
+
gate: GateSpec;
|
|
7214
|
+
gate_type: GateType | null;
|
|
7215
|
+
executes_code: boolean;
|
|
7216
|
+
/** `"tool"`: a step of this entry supplies its own command (`deliver`); else `"agent"`. */
|
|
7217
|
+
executor: 'agent' | 'tool';
|
|
7218
|
+
validator_pin: string | null;
|
|
7219
|
+
/** The entry carries a validator pin (a step may not remove or swap it). */
|
|
7220
|
+
pinned: boolean;
|
|
7221
|
+
/** That pin is the evidence floor. */
|
|
7222
|
+
evidence_floor: boolean;
|
|
7223
|
+
/**
|
|
7224
|
+
* The entry declares re-verified evidence: a step of it is an acceptance requirement of the run
|
|
7225
|
+
* that contains it (`test`, `domain_coverage`). ABSENT from an engine before the flag (api-types
|
|
7226
|
+
* 0.46.0) — the daemon then fails a plan run's acceptance closed rather than guess.
|
|
7227
|
+
*/
|
|
7228
|
+
verified_evidence?: boolean;
|
|
7229
|
+
skill_ref: string | null;
|
|
7230
|
+
/** The entry's one-line description; `null` when it has none. */
|
|
7231
|
+
description: string | null;
|
|
7232
|
+
}
|
|
7233
|
+
|
|
7234
|
+
/** `GET /catalog`. */
|
|
7235
|
+
export interface CatalogResponse {
|
|
7236
|
+
entries: CatalogEntry[];
|
|
7237
|
+
}
|
|
7238
|
+
|
|
7239
|
+
/** `POST /plans/preview` body: a draft plan, previewed as the `POST /runs {plan}` launch with the
|
|
7240
|
+
* same fields would decide it. */
|
|
7241
|
+
export interface PlanPreviewBody {
|
|
7242
|
+
plan: LaunchPlan;
|
|
7243
|
+
/** Only matters to a preset name, so it does not change a plan's preview. */
|
|
7244
|
+
projectId?: string;
|
|
7245
|
+
/** The launch's gate mode (`humanConfirm` on `POST /runs`); absent = auto. */
|
|
7246
|
+
humanConfirm?: string;
|
|
7247
|
+
/** The registered repo the launch would run on: a behavioural `touch` set is scored against its
|
|
7248
|
+
* code graph at the base the launch would start from (read locally, no fetch). An unregistered
|
|
7249
|
+
* repo is a 400. Absent ⇒ the fail-closed score (`graph: "unavailable"`). */
|
|
7250
|
+
repoRef?: string;
|
|
7251
|
+
/** The launch's delivery (`deliver` on `POST /runs`): `"pr"` hands the engine the launch's
|
|
7252
|
+
* deliver step, so the preview's floor carries `deliver` as the launch's would. Absent or
|
|
7253
|
+
* `"none"` ⇒ no deliver step (a plan launch's own default). */
|
|
7254
|
+
deliver?: 'pr' | 'none';
|
|
7255
|
+
}
|
|
7256
|
+
|
|
7257
|
+
/**
|
|
7258
|
+
* `POST /plans/preview`: the engine's `PlanPreview` (`Core.previewPlan`) — what the launch would
|
|
7259
|
+
* compute (precheck, intent score, floor fill, approval matrix, planning checks), persisting and
|
|
7260
|
+
* publishing nothing. A refusal (the launch's own, an unregistered repo) is a 400.
|
|
7261
|
+
*/
|
|
7262
|
+
export interface PlanPreviewResponse {
|
|
7263
|
+
/** The intent score (§8.2), its deterministic part, one reason per contribution. */
|
|
7264
|
+
score: number;
|
|
7265
|
+
deterministic: number;
|
|
7266
|
+
reasons: string[];
|
|
7267
|
+
/** The destructive signal the floor fill reads. */
|
|
7268
|
+
destructive: boolean;
|
|
7269
|
+
/** The floor band the score lands in (`"40-69"`, `"70-100"`, …). */
|
|
7270
|
+
band: string;
|
|
7271
|
+
high_risk: boolean;
|
|
7272
|
+
/** The floor phase types the plan owes, in order. The steps the floor ADDED are the `steps`
|
|
7273
|
+
* with `added_by: "floor"`. */
|
|
7274
|
+
floor: string[];
|
|
7275
|
+
/** The floor override as recorded (manual mode only). */
|
|
7276
|
+
floor_override: TeamPlanOverride | null;
|
|
7277
|
+
/** The floor-filled steps; each carries `added_by`, and `floor_reason` when the floor added it. */
|
|
7278
|
+
steps: TeamPlanStep[];
|
|
7279
|
+
/** The def the run would plan from (`compose` of `steps`). */
|
|
7280
|
+
def: WorkflowDef;
|
|
7281
|
+
/** `true` ⇒ the launch would pause at a `plan_approval` gate before its first unit. */
|
|
7282
|
+
pauses: boolean;
|
|
7283
|
+
pause_reason: 'manual_mode' | 'high_risk' | 'override' | (string & {}) | null;
|
|
7284
|
+
/** `"ready"`: the score read the repo's code graph. `"not_needed"`: a docs-only touch set (or no
|
|
7285
|
+
* creator and no touch set). `"unavailable"`: the fail-closed score (no repo, no or a stale
|
|
7286
|
+
* graph — `reasons` says which). `"pending_pa_scope"` (wicked-core#633, DES-TEAMING-002 X1;
|
|
7287
|
+
* api-types 0.47.0): a creator plan with no `touch` set — the launch runs the PA's read-only
|
|
7288
|
+
* `pa-scope` step first and scores the plan from its answer, so `score`, `band` and the floor
|
|
7289
|
+
* shown are the baseline's with `pa-scope` first, NOT the plan's final risk, and `pauses` is
|
|
7290
|
+
* manual mode's alone (an auto-mode launch may still pause once the PA's scope lands high). */
|
|
7291
|
+
graph: 'ready' | 'not_needed' | 'unavailable' | 'pending_pa_scope';
|
|
7292
|
+
}
|
|
7293
|
+
|
|
7294
|
+
// ── Standing orders (Studio OS behaviour 10; api-types 0.50.0) ─────────────────────────────────
|
|
7295
|
+
|
|
7296
|
+
/**
|
|
7297
|
+
* A standing order's structured rule — parsed from plain words by a seat and CONFIRMED by the
|
|
7298
|
+
* operator before it is stored. `trigger.phase` is the phase the gate reviews (the reviewed unit's
|
|
7299
|
+
* `phase_ref`) or `*`. The invariant: `approve` never answers the deliver gate, a plan approval,
|
|
7300
|
+
* an escalation, a failure or a triage gate, and never a finding (the create route refuses a rule
|
|
7301
|
+
* that approves `deliver`, `plan_approval` or a finding with a 400 `order_refused`).
|
|
7302
|
+
*/
|
|
7303
|
+
export interface StandingOrderRule {
|
|
7304
|
+
scope: { kind: 'all' } | { kind: 'project'; projectId: string };
|
|
7305
|
+
/** `band` (api-types 0.53.0, optional): the order matches only a run whose accepted plan landed in
|
|
7306
|
+
* that band (`"0-19"`, …); a run with no scored plan never matches a band-scoped order.
|
|
7307
|
+
* `preset` (api-types 0.56.0, optional): only a run launched from that preset (`team_plan.preset`).
|
|
7308
|
+
* `phase: "plan_approval"` with `action: "approve"` is a TRUST RECEIPT (0.56.0): accepted only
|
|
7309
|
+
* with `band: "0-19"`, a `preset` and a `project` scope, and it answers a run's plan gate only
|
|
7310
|
+
* when that open gate itself reports band 0-19 and no high risk. `deliver` is never approvable. */
|
|
7311
|
+
trigger: { kind: 'gate'; phase: string; band?: string | undefined; preset?: string | undefined } | { kind: 'finding'; severity: 'high' | 'medium' | '*' };
|
|
7312
|
+
action: 'approve' | 'hold' | 'notify';
|
|
7313
|
+
activeWhen: 'away' | 'always';
|
|
7314
|
+
}
|
|
7315
|
+
|
|
7316
|
+
export interface StandingOrder {
|
|
7317
|
+
id: string;
|
|
7318
|
+
/** The operator's own words. */
|
|
7319
|
+
text: string;
|
|
7320
|
+
rule: StandingOrderRule;
|
|
7321
|
+
/** Unix millis. */
|
|
7322
|
+
createdAt: number;
|
|
7323
|
+
}
|
|
7324
|
+
|
|
7325
|
+
/** An outbound message a `notify` order wanted sent. Only ever QUEUED — the daemon sends nothing. */
|
|
7326
|
+
export interface QueuedStandingMessage {
|
|
7327
|
+
id: string;
|
|
7328
|
+
orderId: string;
|
|
7329
|
+
orderText: string;
|
|
7330
|
+
runId: string | null;
|
|
7331
|
+
text: string;
|
|
7332
|
+
/** Unix millis. */
|
|
7333
|
+
at: number;
|
|
7334
|
+
status: 'queued';
|
|
7335
|
+
}
|
|
7336
|
+
|
|
7337
|
+
/** `GET /standing-orders`, and the answer to `PUT /standing-orders/away`. */
|
|
7338
|
+
export interface StandingOrdersState {
|
|
7339
|
+
away: boolean;
|
|
7340
|
+
/** Unix millis the flag turned on; `null` while present. */
|
|
7341
|
+
awaySince: number | null;
|
|
7342
|
+
orders: StandingOrder[];
|
|
7343
|
+
outbox: QueuedStandingMessage[];
|
|
7344
|
+
}
|
|
7345
|
+
|
|
7346
|
+
/** `PUT /standing-orders/away`. */
|
|
7347
|
+
export interface StandingAwayBody {
|
|
7348
|
+
away: boolean;
|
|
7349
|
+
}
|
|
7350
|
+
|
|
7351
|
+
/** `POST /standing-orders/parse` — the plain words one seat reads. */
|
|
7352
|
+
export interface ParseStandingOrderBody {
|
|
7353
|
+
text: string;
|
|
7354
|
+
}
|
|
7355
|
+
|
|
7356
|
+
/** `POST /standing-orders/parse`'s 200: the rule to show back for confirmation. `refused` is set
|
|
7357
|
+
* when storing it would be refused (the invariant), in plain words. A 422 carries the seat's own
|
|
7358
|
+
* `answer` when it could not produce a rule; 409 = no seat can take a turn; 502 = the seat failed. */
|
|
7359
|
+
export interface ParsedStandingOrder {
|
|
7360
|
+
rule: StandingOrderRule;
|
|
7361
|
+
seat: string;
|
|
7362
|
+
refused?: string;
|
|
7363
|
+
}
|
|
7364
|
+
|
|
7365
|
+
/** `POST /standing-orders` — the confirmed rule. 201 `{ order }`. */
|
|
7366
|
+
export interface CreateStandingOrderBody {
|
|
7367
|
+
text: string;
|
|
7368
|
+
rule: StandingOrderRule;
|
|
7369
|
+
}
|
|
7370
|
+
|
|
7371
|
+
// ── Decided-gate history (api-types 0.53.0) ────────────────────────────────────────────────────
|
|
7372
|
+
|
|
7373
|
+
/**
|
|
7374
|
+
* One decided gate — `GET /gates/decided?since=<unix ms>` (newest first, at most 1000). One row per
|
|
7375
|
+
* `gate.decided` audit line, joined to the engine's gate row for the same `(run, ord)` and to the
|
|
7376
|
+
* run. What a skin needs for a seat's track record on a step, and for the preview of a proposed
|
|
7377
|
+
* standing order (`phase` and `orderApprovable` are the order evaluator's own readings).
|
|
7378
|
+
*/
|
|
7379
|
+
export interface DecidedGate {
|
|
7380
|
+
runId: string;
|
|
7381
|
+
/** The unit the gate paused before; `null` when the decision named none (a plan edit). */
|
|
7382
|
+
ord: number | null;
|
|
7383
|
+
/** Unix millis. */
|
|
7384
|
+
decidedAt: number;
|
|
7385
|
+
decision: 'approve' | 'request_changes' | 'reject' | 'edit_plan';
|
|
7386
|
+
/** Who decided: a person's actor id, or `standing-order:<id>`. */
|
|
7387
|
+
actor: string;
|
|
7388
|
+
/** A standing order decided it (the actor is `standing-order:<id>`). */
|
|
7389
|
+
byOrder: boolean;
|
|
7390
|
+
/** The engine's gate kind (`def`, `run_level`, `terminal`, `deliver`, `plan_approval`, …); `null` when unknown. */
|
|
7391
|
+
gateKind: string | null;
|
|
7392
|
+
/** The phase an order's trigger matches (`intake`, or the reviewed unit's phase); `null` when unknown. */
|
|
7393
|
+
phase: string | null;
|
|
7394
|
+
projectId: string | null;
|
|
7395
|
+
/** The band the run's accepted plan landed in; `null` for an unscored run. */
|
|
7396
|
+
band: string | null;
|
|
7397
|
+
/** The unit whose work the gate judged (the newest creator before the gate) and its seat; `null` when none. */
|
|
7398
|
+
creator: { seat: string; phase: string | null; ord: number } | null;
|
|
7399
|
+
/** A standing order could have approved this gate (a phase-review gate of a run that lands no doctrine). */
|
|
7400
|
+
orderApprovable: boolean;
|
|
7401
|
+
}
|
|
7402
|
+
|
|
7403
|
+
/** `GET /gates/decided`'s 200. A malformed `since` answers 400. */
|
|
7404
|
+
export interface DecidedGatesResponse {
|
|
7405
|
+
gates: DecidedGate[];
|
|
7406
|
+
}
|
|
7407
|
+
|
|
7408
|
+
// ── Freeze deliveries (api-types 0.55.0) ───────────────────────────────────────────────────────
|
|
7409
|
+
|
|
7410
|
+
/**
|
|
7411
|
+
* `GET|PUT /deliveries/freeze` — the one switch that holds every deliver gate. While `frozen`, an
|
|
7412
|
+
* approve of a gate that would run a deliver unit answers 409 `{code: "deliveries_frozen"}` and
|
|
7413
|
+
* `POST /runs/:id/deliver` refuses the same way; the gate stays open, so unfreezing lets the same
|
|
7414
|
+
* approve through. A run launched with `deliverGate: "auto"` has no gate and is not held.
|
|
7415
|
+
* Audited as `deliveries.frozen {reason?}` / `deliveries.unfrozen`; a restart keeps the freeze.
|
|
7416
|
+
*/
|
|
7417
|
+
export interface DeliveryFreezeState {
|
|
7418
|
+
frozen: boolean;
|
|
7419
|
+
/** ISO time it was turned on; `null` while thawed. */
|
|
7420
|
+
since: string | null;
|
|
7421
|
+
/** The actor id that turned it on; `null` while thawed. */
|
|
7422
|
+
by: string | null;
|
|
7423
|
+
reason: string | null;
|
|
7424
|
+
}
|
|
7425
|
+
|
|
7426
|
+
/** `PUT /deliveries/freeze`. `reason` (1–500 chars) is kept only when freezing. */
|
|
7427
|
+
export interface PutDeliveryFreezeBody {
|
|
7428
|
+
frozen: boolean;
|
|
7429
|
+
reason?: string;
|
|
7430
|
+
}
|
|
7431
|
+
|
|
7432
|
+
// ── MCP tools registry (DES-MCP-TOOLS-001 §5, §8, slice S2; api-types 0.58.0) ─────────────────
|
|
7433
|
+
|
|
7434
|
+
/**
|
|
7435
|
+
* How crew reaches an upstream: an MCP server over stdio or streamable HTTP, or a plain REST API
|
|
7436
|
+
* wrapped as tools from its OpenAPI document (`rest`, api-types 0.64.0).
|
|
7437
|
+
*/
|
|
7438
|
+
export type McpUpstreamKind = 'mcp-stdio' | 'mcp-http' | 'rest';
|
|
7439
|
+
/**
|
|
7440
|
+
* A tool's class, from its own `tools/list` annotations (never from a carrier): `read` when
|
|
7441
|
+
* `readOnlyHint` is true; else `destructive` unless `destructiveHint` is false; else `write`. A tool
|
|
7442
|
+
* with no annotations, or with neither `readOnlyHint` nor `destructiveHint`, is `write`. An
|
|
7443
|
+
* operator's `classOverride` wins.
|
|
7444
|
+
*/
|
|
7445
|
+
export type McpToolClass = 'read' | 'write' | 'destructive';
|
|
7446
|
+
/**
|
|
7447
|
+
* `registered`: the schema the operator saved is the one the server lists. `unregistered`: the
|
|
7448
|
+
* schema changed, or the server added the tool after the save; it is denied until previewed and
|
|
7449
|
+
* saved again. `gone`: the server no longer lists it (kept so old records resolve).
|
|
7450
|
+
*/
|
|
7451
|
+
export type McpToolStatus = 'registered' | 'unregistered' | 'gone';
|
|
7452
|
+
/** `failing` after 3 consecutive failed probes; `never` = no probe has succeeded yet. */
|
|
7453
|
+
export type McpHealthState = 'ok' | 'failing' | 'never';
|
|
7454
|
+
/** `none` = the server needs no secret; `missing` = its reference resolves to nothing. */
|
|
7455
|
+
export type McpAuthState = 'none' | 'set' | 'missing';
|
|
7456
|
+
|
|
7457
|
+
/** The spec's tool annotations, only the fields it defines. */
|
|
7458
|
+
export interface McpToolAnnotations {
|
|
7459
|
+
title?: string;
|
|
7460
|
+
readOnlyHint?: boolean;
|
|
7461
|
+
destructiveHint?: boolean;
|
|
7462
|
+
idempotentHint?: boolean;
|
|
7463
|
+
openWorldHint?: boolean;
|
|
7464
|
+
}
|
|
7465
|
+
|
|
7466
|
+
/**
|
|
7467
|
+
* Where a server's secret comes from and where crew injects it. The registry stores this
|
|
7468
|
+
* reference only, never a value. `ref` is `keychain:wicked-mcp/<name>` (written by
|
|
7469
|
+
* `PUT /mcp/servers/:name/secret`) or `env:<NAME>` (the daemon's env). An `mcp-stdio` server gets
|
|
7470
|
+
* the value in env variable `env`; an `mcp-http` or `rest` server in header `header`, after `prefix`.
|
|
7471
|
+
*/
|
|
7472
|
+
export interface McpAuthConfig {
|
|
7473
|
+
ref: string;
|
|
7474
|
+
env?: string;
|
|
7475
|
+
header?: string;
|
|
7476
|
+
prefix?: string;
|
|
7477
|
+
}
|
|
7478
|
+
|
|
7479
|
+
/**
|
|
7480
|
+
* `POST /mcp/servers/preview`. `mcp-stdio` takes `command` (+ `args`); `mcp-http` takes `url`.
|
|
7481
|
+
* `rest` takes `url`, the base URL every call of the API is pinned to (its scheme, host and port,
|
|
7482
|
+
* and its path as a prefix), plus its OpenAPI 3 document: `openapiUrl` (fetched by crew) or
|
|
7483
|
+
* `openapi` (the document itself, pasted), never both. `operations` picks which operations become
|
|
7484
|
+
* tools (by `operationId` or tool name); absent = all of them.
|
|
7485
|
+
*/
|
|
7486
|
+
export interface McpServerConfigBody {
|
|
7487
|
+
/** 1–63 of `a-z 0-9 _ -`; the `<server>` of the subject `mcp:<server>/<tool>`. */
|
|
7488
|
+
name: string;
|
|
7489
|
+
kind: McpUpstreamKind;
|
|
7490
|
+
command?: string;
|
|
7491
|
+
args?: string[];
|
|
7492
|
+
url?: string;
|
|
7493
|
+
auth?: McpAuthConfig | null;
|
|
7494
|
+
/** `rest` only: where crew fetches the OpenAPI 3 document (JSON or YAML). */
|
|
7495
|
+
openapiUrl?: string;
|
|
7496
|
+
/** `rest` only: the OpenAPI 3 document itself (instead of `openapiUrl`); at most 1 MB as JSON. */
|
|
7497
|
+
openapi?: Record<string, unknown>;
|
|
7498
|
+
/** `rest` only: the operations to wrap, by `operationId` or tool name; absent = all. */
|
|
7499
|
+
operations?: string[];
|
|
7500
|
+
/**
|
|
7501
|
+
* The secret VALUE this server's keychain entry will hold (wicked-crew#719). The preview is
|
|
7502
|
+
* probed with it and it is held with the preview; `POST /mcp/servers` writes it to the OS store
|
|
7503
|
+
* as part of the save, so the secret and the registry row commit together — studio used to write
|
|
7504
|
+
* the keychain itself first, and a failure between the two writes left a keychain entry with no
|
|
7505
|
+
* server, or a server whose secret never landed. Requires `auth.ref` =
|
|
7506
|
+
* `keychain:wicked-mcp/<name>`; `501` when the platform has no OS secret store. It is in no
|
|
7507
|
+
* response, log, audit entry or file.
|
|
7508
|
+
*/
|
|
7509
|
+
secret?: string;
|
|
7510
|
+
}
|
|
7511
|
+
|
|
7512
|
+
/**
|
|
7513
|
+
* How a `rest` tool turns its arguments into one HTTP request (api-types 0.64.0). The arguments are
|
|
7514
|
+
* an ALLOWLIST: an argument that no map names is dropped, never sent (its name is disclosed in the
|
|
7515
|
+
* result's `_meta["wicked/rest"].droppedArgs`). The request goes only to the server's base URL: a
|
|
7516
|
+
* request that would leave its scheme, host, port or base path, or a redirect to another host, is
|
|
7517
|
+
* refused before (or instead of) being followed, and recorded as a `guard_error`.
|
|
7518
|
+
*/
|
|
7519
|
+
export interface McpRestMapping {
|
|
7520
|
+
method: 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
7521
|
+
/** The OpenAPI path, e.g. `/issues/{id}`; joined onto the base URL's path. */
|
|
7522
|
+
pathTemplate: string;
|
|
7523
|
+
/** argument → `{variable}` of `pathTemplate`. */
|
|
7524
|
+
pathMap: Record<string, string>;
|
|
7525
|
+
/** argument → query parameter. */
|
|
7526
|
+
queryMap: Record<string, string>;
|
|
7527
|
+
/** argument → request header (never the auth header, `Host`, `Cookie` or a hop-by-hop header). */
|
|
7528
|
+
headerMap: Record<string, string>;
|
|
7529
|
+
/** argument → top-level key of the JSON request body; `null` when the body is one argument or none. */
|
|
7530
|
+
bodyMap: Record<string, string> | null;
|
|
7531
|
+
/** The argument that is the whole JSON request body; `null` when the body is mapped by key or absent. */
|
|
7532
|
+
bodyArg: string | null;
|
|
7533
|
+
/** Every argument that is sent: the union of the maps and `bodyArg`. */
|
|
7534
|
+
argAllowlist: string[];
|
|
7535
|
+
timeoutMs: number;
|
|
7536
|
+
}
|
|
7537
|
+
|
|
7538
|
+
export interface McpHealth {
|
|
7539
|
+
state: McpHealthState;
|
|
7540
|
+
consecutiveFailures: number;
|
|
7541
|
+
checkedAt: string | null;
|
|
7542
|
+
/** The last probe's error, with any secret scrubbed out. */
|
|
7543
|
+
lastError: string | null;
|
|
7544
|
+
}
|
|
7545
|
+
|
|
7546
|
+
export interface McpTool {
|
|
7547
|
+
name: string;
|
|
7548
|
+
/** A `rest` tool's request mapping (api-types 0.64.0); `null` for an MCP server's tool. */
|
|
7549
|
+
rest?: McpRestMapping | null;
|
|
7550
|
+
/** The policy token: `mcp:<server>/<tool>`. */
|
|
7551
|
+
subject: string;
|
|
7552
|
+
description: string | null;
|
|
7553
|
+
annotations: McpToolAnnotations | null;
|
|
7554
|
+
inputSchema: Record<string, unknown> | null;
|
|
7555
|
+
derivedClass: McpToolClass;
|
|
7556
|
+
classOverride: McpToolClass | null;
|
|
7557
|
+
/** `classOverride ?? derivedClass`: what a policy sees. */
|
|
7558
|
+
class: McpToolClass;
|
|
7559
|
+
enabled: boolean;
|
|
7560
|
+
status: McpToolStatus;
|
|
7561
|
+
/** The saved schema's hash; `null` = never saved. */
|
|
7562
|
+
schemaHash: string | null;
|
|
7563
|
+
/** The hash the last probe saw. */
|
|
7564
|
+
observedSchemaHash: string;
|
|
7565
|
+
}
|
|
7566
|
+
|
|
7567
|
+
export interface McpServer {
|
|
7568
|
+
name: string;
|
|
7569
|
+
kind: McpUpstreamKind;
|
|
7570
|
+
command: string | null;
|
|
7571
|
+
args: string[];
|
|
7572
|
+
url: string | null;
|
|
7573
|
+
auth: McpAuthConfig | null;
|
|
7574
|
+
/** `rest` only (api-types 0.64.0): the OpenAPI URL, `null` when the document was pasted. */
|
|
7575
|
+
openapiUrl?: string | null;
|
|
7576
|
+
/** `rest` only: the operations that were picked; `null` = all. */
|
|
7577
|
+
operations?: string[] | null;
|
|
7578
|
+
authState: McpAuthState;
|
|
7579
|
+
enabled: boolean;
|
|
7580
|
+
health: McpHealth;
|
|
7581
|
+
registeredAt: string;
|
|
7582
|
+
updatedAt: string;
|
|
7583
|
+
tools: McpTool[];
|
|
7584
|
+
/** Over the tools that are not `gone`. */
|
|
7585
|
+
counts: { total: number; enabled: number; registered: number; read: number; write: number; destructive: number };
|
|
7586
|
+
}
|
|
7587
|
+
|
|
7588
|
+
/**
|
|
7589
|
+
* A server configured in a CLI's own home, by name only (never its command, URL or env).
|
|
7590
|
+
* `origin: 'worker'` is a server in a seat's worker home, which no wicked-handed server may be.
|
|
7591
|
+
*/
|
|
7592
|
+
export interface McpDiscoveredServer {
|
|
7593
|
+
name: string;
|
|
7594
|
+
cli: string;
|
|
7595
|
+
origin: 'operator' | 'worker';
|
|
7596
|
+
/** The config file, relative to `~` or `<worker home>`. */
|
|
7597
|
+
source: string;
|
|
7598
|
+
/** Whether a registered server has the same name. */
|
|
7599
|
+
managed: boolean;
|
|
7600
|
+
}
|
|
7601
|
+
|
|
7602
|
+
/** `GET /mcp/servers`. */
|
|
7603
|
+
export interface McpServersResponse {
|
|
7604
|
+
servers: McpServer[];
|
|
7605
|
+
discovered: McpDiscoveredServer[];
|
|
7606
|
+
}
|
|
7607
|
+
|
|
7608
|
+
/** The difference between the registered tools and a probe, by tool name. */
|
|
7609
|
+
export interface McpToolDiff {
|
|
7610
|
+
added: string[];
|
|
7611
|
+
removed: string[];
|
|
7612
|
+
changed: string[];
|
|
7613
|
+
unchanged: string[];
|
|
7614
|
+
}
|
|
7615
|
+
|
|
7616
|
+
export interface McpPreviewTool {
|
|
7617
|
+
name: string;
|
|
7618
|
+
/** A `rest` tool's request mapping (api-types 0.64.0); `null` for an MCP server's tool. */
|
|
7619
|
+
rest?: McpRestMapping | null;
|
|
7620
|
+
subject: string;
|
|
7621
|
+
description: string | null;
|
|
7622
|
+
annotations: McpToolAnnotations | null;
|
|
7623
|
+
inputSchema: Record<string, unknown> | null;
|
|
7624
|
+
class: McpToolClass;
|
|
7625
|
+
schemaHash: string;
|
|
7626
|
+
}
|
|
7627
|
+
|
|
7628
|
+
/**
|
|
7629
|
+
* `POST /mcp/servers/preview`'s 200. Save it with `POST /mcp/servers {previewHash}` before
|
|
7630
|
+
* `expiresAt`. `diff` compares with the registered server of the same name, `null` when none.
|
|
7631
|
+
* A server that does not answer is a 502 `probe_failed`.
|
|
7632
|
+
*/
|
|
7633
|
+
export interface McpPreviewResponse {
|
|
7634
|
+
previewHash: string;
|
|
7635
|
+
expiresAt: string;
|
|
7636
|
+
server: {
|
|
7637
|
+
name: string;
|
|
7638
|
+
kind: McpUpstreamKind;
|
|
7639
|
+
command: string | null;
|
|
7640
|
+
args: string[];
|
|
7641
|
+
url: string | null;
|
|
7642
|
+
auth: McpAuthConfig | null;
|
|
7643
|
+
openapiUrl?: string | null;
|
|
7644
|
+
operations?: string[] | null;
|
|
7645
|
+
};
|
|
7646
|
+
serverInfo: { name: string; version: string } | null;
|
|
7647
|
+
tools: McpPreviewTool[];
|
|
7648
|
+
diff: McpToolDiff | null;
|
|
7649
|
+
/** `rest` only (api-types 0.64.0): operations that could not be wrapped, each with why. */
|
|
7650
|
+
skipped?: string[];
|
|
7651
|
+
/**
|
|
7652
|
+
* Each tool's decision per phase role × seat × mode under the current policies and approvals,
|
|
7653
|
+
* judged as if this preview were saved now (api-types 0.63.0); see `withdrawOnSave`. `null` when
|
|
7654
|
+
* the engine cannot preview.
|
|
7655
|
+
*/
|
|
7656
|
+
policies?: McpPolicyPreviewResponse | null;
|
|
7657
|
+
}
|
|
7658
|
+
|
|
7659
|
+
/** `POST /mcp/servers`. No `previewHash`, or one that is unknown or expired, is a 409. */
|
|
7660
|
+
export interface SaveMcpServerBody {
|
|
7661
|
+
previewHash?: string;
|
|
7662
|
+
}
|
|
7663
|
+
|
|
7664
|
+
/** `PATCH /mcp/servers/:name`. */
|
|
7665
|
+
export interface PatchMcpServerBody {
|
|
7666
|
+
enabled: boolean;
|
|
7667
|
+
}
|
|
7668
|
+
|
|
7669
|
+
/** `PATCH /mcp/tools/:subject` (subject URL-encoded). At least one field. */
|
|
7670
|
+
export interface PatchMcpToolBody {
|
|
7671
|
+
enabled?: boolean;
|
|
7672
|
+
classOverride?: McpToolClass | null;
|
|
7673
|
+
}
|
|
7674
|
+
|
|
7675
|
+
/** `POST /mcp/servers/:name/test`'s 200: a failed probe is `ok: false` and counts toward `failing`. */
|
|
7676
|
+
export interface McpServerTestResponse {
|
|
7677
|
+
ok: boolean;
|
|
7678
|
+
error: string | null;
|
|
7679
|
+
/** `null` when the probe failed. */
|
|
7680
|
+
diff: McpToolDiff | null;
|
|
7681
|
+
server: McpServer;
|
|
7682
|
+
}
|
|
7683
|
+
|
|
7684
|
+
/** `PUT /mcp/servers/:name/secret`: one line, 8–8192 characters. */
|
|
7685
|
+
export interface PutMcpSecretBody {
|
|
7686
|
+
value: string;
|
|
7687
|
+
}
|
|
7688
|
+
|
|
7689
|
+
/** The value is never echoed; `ref` goes into the server's `auth.ref`. 501 = no OS secret store. */
|
|
7690
|
+
export interface McpSecretResponse {
|
|
7691
|
+
ref: string;
|
|
7692
|
+
set: true;
|
|
7693
|
+
}
|
|
7694
|
+
|
|
7695
|
+
// ── MCP broker call path (DES-MCP-TOOLS-001 §6, §8 `POST /mcp/call`; slice S3) ─────────────────
|
|
7696
|
+
|
|
7697
|
+
/** `POST /mcp/call`: what the garden shim sends. `token` is the worker's `WICKED_MCP_TOKEN`. */
|
|
7698
|
+
export interface McpCallBody {
|
|
7699
|
+
token: string;
|
|
7700
|
+
/** `mcp:<server>/<tool>`. */
|
|
7701
|
+
subject: string;
|
|
7702
|
+
/** The tool's arguments (a JSON object); absent = `{}`. */
|
|
7703
|
+
args?: Record<string, unknown>;
|
|
7704
|
+
}
|
|
7705
|
+
|
|
7706
|
+
/** How a brokered call ended. Every outcome but `ok` means the result was not handed back. */
|
|
7707
|
+
export type McpCallOutcome =
|
|
7708
|
+
/** The call ran; `result` is the scrubbed upstream result (it may itself be a tool error, `isError`). */
|
|
7709
|
+
| 'ok'
|
|
7710
|
+
/** Refused by a policy or an engine gate before anything ran (403). The worker continues. */
|
|
7711
|
+
| 'denied'
|
|
7712
|
+
/** Waits for the operator's approval (first use of a server, or the run's mode) (409). */
|
|
7713
|
+
| 'pending_approval'
|
|
7714
|
+
/** The call ran, but the output policy withheld its result (403). */
|
|
7715
|
+
| 'withheld'
|
|
7716
|
+
/** The unit's call budget is spent (429). */
|
|
7717
|
+
| 'budget_exhausted'
|
|
7718
|
+
/** The tool failed 5 times in a row and is refused for 60 s (503). */
|
|
7719
|
+
| 'breaker_open'
|
|
7720
|
+
/** The upstream failed (502) or timed out (504). */
|
|
7721
|
+
| 'upstream_error'
|
|
7722
|
+
/**
|
|
7723
|
+
* The call could not be judged, scrubbed or recorded, or (a `rest` tool) its request would have
|
|
7724
|
+
* left the API's pinned host (`status.errorClass` `rest_host_escape`): refused, fail closed (500).
|
|
7725
|
+
*/
|
|
7726
|
+
| 'guard_error';
|
|
7727
|
+
|
|
7728
|
+
/** Who decided a call: an engine gate (`engine:mcp-*`), a steering rule, or the broker itself. */
|
|
7729
|
+
export type McpDecisionBy = string;
|
|
7730
|
+
|
|
7731
|
+
/** `POST /mcp/call`'s answer, on every status. Never carries a secret; `result` only on `ok`. */
|
|
7732
|
+
export interface McpCallResponse {
|
|
7733
|
+
outcome: McpCallOutcome;
|
|
7734
|
+
subject: string;
|
|
7735
|
+
/** The call record's span id (`GET /mcp/usage` and the run's Governance panel resolve it). */
|
|
7736
|
+
callId: string | null;
|
|
7737
|
+
/** The scrubbed `tools/call` result — only when `outcome` is `ok`. */
|
|
7738
|
+
result?: Record<string, unknown>;
|
|
7739
|
+
/** The rules or gates that decided (deny, ask, withheld). */
|
|
7740
|
+
ruleIds: string[];
|
|
7741
|
+
/** Why the result is not handed back; absent on `ok`. */
|
|
7742
|
+
reason?: string;
|
|
7743
|
+
/** What the worker can do instead. */
|
|
7744
|
+
remedy?: string;
|
|
7745
|
+
/** `pending_approval` only: the subject the operator is asked to approve. */
|
|
7746
|
+
pending_approval?: string;
|
|
7747
|
+
/** `denied` / `withheld`: the call was refused (the unit continues). */
|
|
7748
|
+
denied?: true;
|
|
7749
|
+
}
|
|
7750
|
+
|
|
7751
|
+
export type McpCallDecision = 'allow' | 'ask' | 'deny' | 'guard_error';
|
|
7752
|
+
|
|
7753
|
+
/**
|
|
7754
|
+
* One call record (`<state home>/mcp/calls.ndjson`), OTel span shaped. Arguments and results are
|
|
7755
|
+
* NEVER captured: only the subject, the decision, timings and the byte count.
|
|
7756
|
+
*/
|
|
7757
|
+
export interface McpCallRecord {
|
|
7758
|
+
/** The run id, or `null` when the token resolved to no unit (a guard error before judging). */
|
|
7759
|
+
traceId: string | null;
|
|
7760
|
+
spanId: string;
|
|
7761
|
+
/** The unit, `<ord>:<attempt>`; `null` with `traceId`. */
|
|
7762
|
+
parentSpanId: string | null;
|
|
7763
|
+
name: 'mcp.tool.call';
|
|
7764
|
+
start: string;
|
|
7765
|
+
end: string;
|
|
7766
|
+
ms: number;
|
|
7767
|
+
status: { code: 'ok' | 'error'; errorClass: string | null };
|
|
7768
|
+
decision: { decision: McpCallDecision; by: McpDecisionBy; ruleIds: string[]; claimId: string | null };
|
|
7769
|
+
outcome: McpCallOutcome;
|
|
7770
|
+
attrs: {
|
|
7771
|
+
'mcp.subject': string;
|
|
7772
|
+
'mcp.class': McpToolClass | null;
|
|
7773
|
+
'mcp.kind': McpUpstreamKind | null;
|
|
7774
|
+
'wicked.seat': string | null;
|
|
7775
|
+
'wicked.phase': string | null;
|
|
7776
|
+
'wicked.carrier': 'shim';
|
|
7777
|
+
'bytes.out': number;
|
|
7778
|
+
retries: number;
|
|
7779
|
+
};
|
|
7780
|
+
}
|
|
7781
|
+
|
|
7782
|
+
/** The `/ws` frame each call record rides (additive CoreEvent contract: skins that don't know it ignore it). */
|
|
7783
|
+
export interface McpCallCompletedFrame {
|
|
7784
|
+
type: 'mcpCallCompleted';
|
|
7785
|
+
record: McpCallRecord;
|
|
7786
|
+
}
|
|
7787
|
+
|
|
7788
|
+
// ── The unit's tool list (DES-MCP-TOOLS-001 §8, slice S4; api-types 0.65.0) ─────────────────────
|
|
7789
|
+
|
|
7790
|
+
/**
|
|
7791
|
+
* `POST /mcp/tools`: what the garden shim's `list` sends. The token travels in the body, never the
|
|
7792
|
+
* query string, so it stays out of request logs.
|
|
7793
|
+
*/
|
|
7794
|
+
export interface McpToolsBody {
|
|
7795
|
+
token: string;
|
|
7796
|
+
}
|
|
7797
|
+
|
|
7798
|
+
/** One tool the token's unit may try, judged now with no arguments. A certain deny is left out. */
|
|
7799
|
+
export interface McpVisibleTool {
|
|
7800
|
+
/** `mcp:<server>/<tool>`. */
|
|
7801
|
+
subject: string;
|
|
7802
|
+
class: McpToolClass;
|
|
7803
|
+
/** `allow` = a call runs; `ask` = it waits for the operator's approval. */
|
|
7804
|
+
decision: 'allow' | 'ask';
|
|
7805
|
+
ruleIds: string[];
|
|
7806
|
+
/** Why a call would ask. */
|
|
7807
|
+
reason?: string;
|
|
7808
|
+
/** The tool's description, from the server's `tools/list`. */
|
|
7809
|
+
description: string | null;
|
|
7810
|
+
/** The tool's argument JSON schema, from `tools/list`. */
|
|
7811
|
+
inputSchema: Record<string, unknown> | null;
|
|
7812
|
+
}
|
|
7813
|
+
|
|
7814
|
+
/** `POST /mcp/tools`'s answer: the unit the token is bound to and its tools. */
|
|
7815
|
+
export interface McpToolsResponse {
|
|
7816
|
+
unit: { runId: string; ord: number; attempt: number; phase: string; seat: string };
|
|
7817
|
+
tools: McpVisibleTool[];
|
|
7818
|
+
}
|
|
7819
|
+
|
|
7820
|
+
// ── MCP policies: the preview matrix and approvals (DES-MCP-TOOLS-001 §4.5, §4.7, §8, slice S6; api-types 0.63.0) ──
|
|
7821
|
+
|
|
7822
|
+
/** A policy decision: `ask` = the call waits for the operator's approval (it does not run). */
|
|
7823
|
+
export type McpDecision = 'allow' | 'ask' | 'deny';
|
|
7824
|
+
/**
|
|
7825
|
+
* The phase role a matrix row stands for: `creator` = a creator phase with full write posture;
|
|
7826
|
+
* `evaluator` = an evaluator phase (read-only); `recon` = a neutral phase with a read-only posture.
|
|
7827
|
+
*/
|
|
7828
|
+
export type McpPhaseRole = 'creator' | 'evaluator' | 'recon';
|
|
7829
|
+
/** The run's mode (studio's launch autonomy): Gate every step / Gate by risk / Auto. */
|
|
7830
|
+
export type McpRunMode = 'ask' | 'balanced' | 'autonomous';
|
|
7831
|
+
|
|
7832
|
+
/** One matrix cell: what a call from a unit of this shape would get now. Nothing is recorded. */
|
|
7833
|
+
export interface McpPolicyCell {
|
|
7834
|
+
role: McpPhaseRole;
|
|
7835
|
+
seat: string;
|
|
7836
|
+
mode: McpRunMode;
|
|
7837
|
+
phaseId?: string;
|
|
7838
|
+
decision: McpDecision;
|
|
7839
|
+
/** The class the engine judged (the tool's override, else its annotations; none = `write`). */
|
|
7840
|
+
class: McpToolClass;
|
|
7841
|
+
/** The rules that decided: `engine:*` gates first, then steering rule ids (each a Steering row). */
|
|
7842
|
+
ruleIds: string[];
|
|
7843
|
+
obligations: string[];
|
|
7844
|
+
reason: string | null;
|
|
7845
|
+
}
|
|
7846
|
+
|
|
7847
|
+
/** Whether a tool is approved in each ledger, and by which token (`server` = `mcp:<server>`). */
|
|
7848
|
+
export interface McpApprovalState {
|
|
7849
|
+
/** `MCP-FIRST-USE`: the first use of a server asks in every mode until approved. */
|
|
7850
|
+
firstUse: 'server' | 'tool' | null;
|
|
7851
|
+
/** `MCP-POSTURE-WRITE`: in balanced mode a write asks until approved. */
|
|
7852
|
+
write: 'server' | 'tool' | null;
|
|
7853
|
+
}
|
|
7854
|
+
|
|
7855
|
+
export interface McpPolicyPreviewTool {
|
|
7856
|
+
subject: string;
|
|
7857
|
+
server: string;
|
|
7858
|
+
tool: string;
|
|
7859
|
+
class: McpToolClass;
|
|
7860
|
+
status: McpToolStatus;
|
|
7861
|
+
/** The server and the tool are both enabled. */
|
|
7862
|
+
enabled: boolean;
|
|
7863
|
+
/** What the broker sends the engine: enabled and `registered`; otherwise D-5 denies it. */
|
|
7864
|
+
registered: boolean;
|
|
7865
|
+
approval: McpApprovalState;
|
|
7866
|
+
/** One per role × seat × mode, in `roles`, `seats`, `modes` order. */
|
|
7867
|
+
cells: McpPolicyCell[];
|
|
7868
|
+
}
|
|
7869
|
+
|
|
7870
|
+
/** `POST /mcp/policies/preview`. Every field narrows; none = every tool, role, seat and mode. */
|
|
7871
|
+
export interface McpPolicyPreviewBody {
|
|
7872
|
+
/** One tool: `mcp:<server>/<tool>`. */
|
|
7873
|
+
subject?: string;
|
|
7874
|
+
server?: string;
|
|
7875
|
+
phaseRole?: McpPhaseRole;
|
|
7876
|
+
seat?: string;
|
|
7877
|
+
mode?: McpRunMode;
|
|
7878
|
+
/** A workflow phase id a policy may name (`review`, `build`, ...). */
|
|
7879
|
+
phaseId?: string;
|
|
7880
|
+
}
|
|
7881
|
+
|
|
7882
|
+
/** `POST /mcp/policies/preview`'s 200, and `McpPreviewResponse.policies`. */
|
|
7883
|
+
export interface McpPolicyPreviewResponse {
|
|
7884
|
+
roles: McpPhaseRole[];
|
|
7885
|
+
seats: string[];
|
|
7886
|
+
modes: McpRunMode[];
|
|
7887
|
+
phaseId: string | null;
|
|
7888
|
+
/**
|
|
7889
|
+
* Server previews only (`[]` elsewhere): the approvals saving this preview withdraws, because a
|
|
7890
|
+
* saved tool's schema changed. The cells are judged under the CURRENT approvals, so a tool listed
|
|
7891
|
+
* here (or every tool, when `mcp:<server>` is listed) asks again after the save.
|
|
7892
|
+
*/
|
|
7893
|
+
withdrawOnSave: string[];
|
|
7894
|
+
tools: McpPolicyPreviewTool[];
|
|
7895
|
+
}
|
|
7896
|
+
|
|
7897
|
+
/** An approved subject and the ledgers that hold it. */
|
|
7898
|
+
export interface McpApproval {
|
|
7899
|
+
subject: string;
|
|
7900
|
+
scope: 'server' | 'tool';
|
|
7901
|
+
firstUse: boolean;
|
|
7902
|
+
write: boolean;
|
|
7903
|
+
}
|
|
7904
|
+
|
|
7905
|
+
/** A registered, enabled tool that would ask in balanced mode, and why. */
|
|
7906
|
+
export interface McpPendingApproval {
|
|
7907
|
+
subject: string;
|
|
7908
|
+
server: string;
|
|
7909
|
+
tool: string;
|
|
7910
|
+
class: McpToolClass;
|
|
7911
|
+
needs: Array<'first-use' | 'write'>;
|
|
7912
|
+
}
|
|
7913
|
+
|
|
7914
|
+
export interface McpLedgerState {
|
|
7915
|
+
id: string;
|
|
7916
|
+
/** `false` = the mcp-defaults pack was not seeded; approvals are refused (503). */
|
|
7917
|
+
present: boolean;
|
|
7918
|
+
/** A retired first-use ledger still asks: the engine reads it either way. */
|
|
7919
|
+
retired: boolean;
|
|
7920
|
+
}
|
|
7921
|
+
|
|
7922
|
+
/** `GET /mcp/approvals`. */
|
|
7923
|
+
export interface McpApprovalsResponse {
|
|
7924
|
+
approved: McpApproval[];
|
|
7925
|
+
pending: McpPendingApproval[];
|
|
7926
|
+
ledgers: { firstUse: McpLedgerState; write: McpLedgerState };
|
|
7927
|
+
}
|
|
7928
|
+
|
|
7929
|
+
/**
|
|
7930
|
+
* `POST /mcp/approvals`, an audited edit of the ledger rules' `excludes`. `mcp:<server>` approves
|
|
7931
|
+
* the server's FIRST USE (`MCP-FIRST-USE`); its write tools still ask in balanced mode.
|
|
7932
|
+
* `mcp:<server>/<tool>` approves that tool's first use and its writes (`MCP-POSTURE-WRITE` too).
|
|
7933
|
+
* An approval never lifts an engine gate or an explicit deny rule.
|
|
7934
|
+
*/
|
|
7935
|
+
export interface McpApprovalBody {
|
|
7936
|
+
subject: string;
|
|
7937
|
+
}
|
|
7938
|
+
|
|
7939
|
+
/** `POST /mcp/approvals` and `DELETE /mcp/approvals/:subject`: the ledger rules the edit changed. */
|
|
7940
|
+
export interface McpApprovalResponse {
|
|
7941
|
+
subject: string;
|
|
7942
|
+
approved: boolean;
|
|
7943
|
+
rulesChanged: string[];
|
|
7944
|
+
}
|
|
7945
|
+
|
|
7946
|
+
// ── MCP usage: the fold over the call records (DES-MCP-TOOLS-001 §7 Usage, §8 `GET /mcp/usage`; slice S7; api-types 0.66.0) ──
|
|
7947
|
+
|
|
7948
|
+
/** Every call record in a window, split by the broker's decision. */
|
|
7949
|
+
export interface McpDecisionCounts {
|
|
7950
|
+
allow: number;
|
|
7951
|
+
ask: number;
|
|
7952
|
+
deny: number;
|
|
7953
|
+
guard_error: number;
|
|
7954
|
+
}
|
|
7955
|
+
|
|
7956
|
+
/**
|
|
7957
|
+
* The numbers a set of call records folds to. `ran` counts the calls the broker let through
|
|
7958
|
+
* (`decision: allow`); the error rate and the latency percentiles are over those calls only, since
|
|
7959
|
+
* a denied or asked call never reached an upstream. Percentiles are nearest-rank: the value at
|
|
7960
|
+
* position `ceil(q * n)` of the sorted durations. `null` = no call ran.
|
|
7961
|
+
*/
|
|
7962
|
+
export interface McpUsageStats {
|
|
7963
|
+
calls: number;
|
|
7964
|
+
decisions: McpDecisionCounts;
|
|
7965
|
+
ran: number;
|
|
7966
|
+
/** Ran calls whose status is `error` (an upstream failure or a tool error, `isError`). */
|
|
7967
|
+
errors: number;
|
|
7968
|
+
errorRate: number | null;
|
|
7969
|
+
p50Ms: number | null;
|
|
7970
|
+
p95Ms: number | null;
|
|
7971
|
+
p99Ms: number | null;
|
|
7972
|
+
}
|
|
7973
|
+
|
|
7974
|
+
/** One tool's row of the per-tool table. */
|
|
7975
|
+
export interface McpUsageTool extends McpUsageStats {
|
|
7976
|
+
subject: string;
|
|
7977
|
+
server: string;
|
|
7978
|
+
tool: string;
|
|
7979
|
+
/** The class the engine judged on the newest record; `null` = never judged (a guard error). */
|
|
7980
|
+
class: McpToolClass | null;
|
|
7981
|
+
/** The seats that called it, sorted. */
|
|
7982
|
+
seats: string[];
|
|
7983
|
+
lastCall: string;
|
|
7984
|
+
}
|
|
7985
|
+
|
|
7986
|
+
/** One server's totals: its row's "last used" and "calls over the window". */
|
|
7987
|
+
export interface McpUsageServer {
|
|
7988
|
+
server: string;
|
|
7989
|
+
calls: number;
|
|
7990
|
+
decisions: McpDecisionCounts;
|
|
7991
|
+
lastCall: string;
|
|
7992
|
+
}
|
|
7993
|
+
|
|
7994
|
+
/** The drill-down: one tool × seat × run. `runId: null` = calls the broker refused before judging. */
|
|
7995
|
+
export interface McpUsageRun {
|
|
7996
|
+
subject: string;
|
|
7997
|
+
seat: string | null;
|
|
7998
|
+
runId: string | null;
|
|
7999
|
+
calls: number;
|
|
8000
|
+
decisions: McpDecisionCounts;
|
|
8001
|
+
/** Ran calls whose status is `error`, as in {@link McpUsageStats}. */
|
|
8002
|
+
errors: number;
|
|
8003
|
+
lastCall: string;
|
|
8004
|
+
}
|
|
8005
|
+
|
|
8006
|
+
/**
|
|
8007
|
+
* A tool chain: `from` then `to`, two consecutive calls of one unit attempt (by start time), with
|
|
8008
|
+
* different subjects. `count` = how often; `runs` = in how many runs.
|
|
8009
|
+
*/
|
|
8010
|
+
export interface McpUsageChain {
|
|
8011
|
+
from: string;
|
|
8012
|
+
to: string;
|
|
8013
|
+
count: number;
|
|
8014
|
+
runs: number;
|
|
8015
|
+
}
|
|
8016
|
+
|
|
8017
|
+
/** One UTC day the window touches (its first day is partial), days with no calls included. */
|
|
8018
|
+
export interface McpUsageDay {
|
|
8019
|
+
day: string;
|
|
8020
|
+
calls: number;
|
|
8021
|
+
decisions: McpDecisionCounts;
|
|
8022
|
+
}
|
|
8023
|
+
|
|
8024
|
+
/**
|
|
8025
|
+
* `GET /mcp/usage?days&subject&seat&decision`. `days` is 1-30 (default 7); the window is the last
|
|
8026
|
+
* `days` × 24 h. Every filter narrows every section, except `chains`: a chain is folded from the
|
|
8027
|
+
* unit's calls under the seat and decision filters, then kept when either end is `subject`.
|
|
8028
|
+
* Records older than 30 days are folded into `calls-daily.ndjson` and are not in any window.
|
|
8029
|
+
*/
|
|
8030
|
+
export interface McpUsageResponse {
|
|
8031
|
+
days: number;
|
|
8032
|
+
since: string;
|
|
8033
|
+
until: string;
|
|
8034
|
+
filters: { subject: string | null; seat: string | null; decision: McpCallDecision | null };
|
|
8035
|
+
totals: McpUsageStats;
|
|
8036
|
+
/** Most calls first, then by subject. */
|
|
8037
|
+
tools: McpUsageTool[];
|
|
8038
|
+
/** Most calls first, then by name. */
|
|
8039
|
+
servers: McpUsageServer[];
|
|
8040
|
+
/** Newest first, at most 200. */
|
|
8041
|
+
runs: McpUsageRun[];
|
|
8042
|
+
/** Most frequent first, at most 20. */
|
|
8043
|
+
chains: McpUsageChain[];
|
|
8044
|
+
/** Oldest first. */
|
|
8045
|
+
daily: McpUsageDay[];
|
|
8046
|
+
/** The seats seen in the window before any filter (the seat filter's options), sorted. */
|
|
8047
|
+
seats: string[];
|
|
8048
|
+
/** Lines of `calls.ndjson` that did not parse as a call record. */
|
|
8049
|
+
skipped: number;
|
|
8050
|
+
}
|