wicked-crew-api-types 0.149.0 → 0.167.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.
Files changed (2) hide show
  1. package/index.d.ts +805 -12
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -353,6 +353,12 @@ export interface HealthCapabilities {
353
353
  * ABSENT on an older daemon: read as `false` and hide the switch.
354
354
  */
355
355
  powerMode?: boolean | undefined;
356
+ /**
357
+ * (api-types 0.156.0, DES-VOICE) Voice mode's routes are served: `GET /voice/status`, `POST|DELETE /voice/model`,
358
+ * `POST /voice/transcribe` and `GET|PUT /voice/dashboard`. Whether transcription can run NOW (the engine and
359
+ * the model are on this machine) is {@link VoiceStatus.ready}. ABSENT on an older daemon: read as `false`.
360
+ */
361
+ voice?: boolean;
356
362
  }
357
363
 
358
364
  // ── A run's working document (program DES-POWER-MODE §8.3, §9; api-types 0.148.0) ──────────────────
@@ -360,10 +366,12 @@ export interface HealthCapabilities {
360
366
  /** The working document's sections, in order. */
361
367
  export type WorkingDocSectionId = 'goal' | 'approach' | 'decisions' | 'constraints' | 'questions' | 'next';
362
368
 
363
- /** Who wrote a version: a person (the operator), a plugin's own generated lines, or crew (the first version). */
369
+ /** Who wrote a version: a person (the operator), a plugin's own generated lines, the power orchestrator's own notes
370
+ * (`agent`, id `agent:<seat>`: Approach and Decisions only, never a steer), or crew (the first version). */
364
371
  export type WorkingDocAuthor =
365
372
  | { kind: 'human'; id: string }
366
373
  | { kind: 'plugin'; id: string }
374
+ | { kind: 'agent'; id: string }
367
375
  | { kind: 'system'; id: 'crew' };
368
376
 
369
377
  /** One version of the working document, as crew attributed it. */
@@ -401,6 +409,9 @@ export interface WorkingDocSteer {
401
409
  error: string | null;
402
410
  supersededBy?: string | null;
403
411
  renewals?: number;
412
+ /** (0.161.0, DES-VOICE) The person said the edit and confirmed it on screen: the thread says "You (by voice)".
413
+ * ABSENT on a typed edit (and on an older daemon). It grants nothing. */
414
+ input?: 'voice';
404
415
  }
405
416
 
406
417
  /** `GET /runs/:id/working-doc` (and the body of `POST /runs/:id/working-doc`). */
@@ -412,15 +423,23 @@ export interface WorkingDocView {
412
423
  labels: Record<WorkingDocSectionId, string>;
413
424
  trail: WorkingDocTrailEntry[];
414
425
  steers: WorkingDocSteer[];
426
+ /** (0.151.0) `true` when crew itself writes the document's event-derived lines (Decisions answered, Open questions,
427
+ * Next) from the run's own log, as `plugin:wicked-phase-report@…`: a host plugin then writes none of its own and
428
+ * only renders and takes a person's edits. ABSENT on an older daemon — read as `false` (the plugin keeps writing). */
429
+ eventLines?: boolean;
415
430
  }
416
431
 
417
432
  /** `POST /runs/:id/working-doc/versions`. `author: 'operator'` only from a person; `author: 'plugin'` writes only the
418
- * plugin's own section (`decisions`). 409 `{head}` when the document moved since `base`. */
433
+ * plugin's own lines, under `decisions`, `questions` and `next` (never `goal`, `approach` or `constraints`: 403). A
434
+ * plugin's write never steers, in any section (`steer` is null). 409 `{head}` when the document moved since `base`. */
419
435
  export interface ProposeWorkingDocRequest {
420
436
  base: number;
421
437
  sections: Partial<Record<WorkingDocSectionId, string>>;
422
438
  author: 'operator' | 'plugin';
423
439
  plugin?: { id: string; version: string };
440
+ /** (0.161.0, DES-VOICE) The person said this edit and confirmed it on screen. On `author: 'operator'` only (400
441
+ * otherwise); kept on the steer ({@link WorkingDocSteer.input}) and the `run.steered.doc` audit line. */
442
+ input?: 'voice';
424
443
  }
425
444
 
426
445
  export interface ProposeWorkingDocResponse {
@@ -776,7 +795,46 @@ export type PowerActivityEvent = {
776
795
  subject: string | null;
777
796
  };
778
797
 
798
+ /** `/ws` frame: a seat's tool call started or finished, live from its stream as it happens (bus
799
+ * `wicked.run.tool.started` / `wicked.run.tool.finished`). Sent for claude, codex (`exec --json` items) and pi
800
+ * (`--mode json` tool executions); at most 24 frames per 2 s and 4000 per attempt, and a call shown starting is
801
+ * always shown finishing. `target` is a repo-relative path, a search, or a command with secrets cut, at most 160
802
+ * characters. (0.151.0) `state: 'working'` (bus `wicked.run.tool.working`) is a quiet seat's heartbeat, any seat,
803
+ * copilot included: after 15 s with no frame, one per 15 s while it stays quiet, `id` `working-<attempt>` (update one
804
+ * row), `kind: 'working'`, `tool` the seat, `target` `last output N s ago`, `durationMs` that silence. */
805
+ export type ToolActivityEvent = {
806
+ type: 'toolActivity';
807
+ session: string;
808
+ ord: number;
809
+ attempt: number;
810
+ at: number;
811
+ id: string;
812
+ state: 'started' | 'finished' | 'working';
813
+ kind: 'read' | 'search' | 'run' | 'test' | 'edit' | 'write' | 'skill' | 'task' | 'other' | 'working';
814
+ tool: string;
815
+ target: string | null;
816
+ ok: boolean | null;
817
+ durationMs: number | null;
818
+ };
819
+
820
+ /** `/ws` frame: new working notes from the power orchestrator's stream (bus `wicked.run.notes.recorded`): its
821
+ * approach when stated or restated, and each new decision with its reason. Crew writes them into the run's working
822
+ * document as `agent:<seat>`; they never steer. */
823
+ export type PowerWorkingNotesEvent = {
824
+ type: 'powerWorkingNotes';
825
+ session: string;
826
+ ord: number;
827
+ attempt: number;
828
+ turn: number;
829
+ seat: string;
830
+ at: number;
831
+ approach: string | null;
832
+ decisions: Array<{ text: string; why: string | null }>;
833
+ };
834
+
779
835
  export type PowerEvent =
836
+ | ToolActivityEvent
837
+ | PowerWorkingNotesEvent
780
838
  | PowerActivityEvent
781
839
  | PowerIntakePlannedEvent
782
840
  | RigorRescoredEvent
@@ -796,6 +854,10 @@ export type RunBusType =
796
854
  | 'wicked.run.handoff.stepped'
797
855
  | 'wicked.run.power.toggled'
798
856
  | 'wicked.run.activity.recorded'
857
+ | 'wicked.run.tool.started'
858
+ | 'wicked.run.tool.finished'
859
+ | 'wicked.run.tool.working'
860
+ | 'wicked.run.notes.recorded'
799
861
  | 'wicked.run.unit.started'
800
862
  | 'wicked.run.unit.finished'
801
863
  | 'wicked.run.checks.evaluated'
@@ -2366,6 +2428,20 @@ export interface GateDecision {
2366
2428
  * `POST /runs/:id/resume` or `/reassign`.
2367
2429
  */
2368
2430
  ord?: number;
2431
+ /**
2432
+ * (api-types 0.156.0, DES-VOICE) The person answered by voice: studio matched the spoken words to this
2433
+ * answer, showed it on screen and the person confirmed it, then the usual undo window ran. Recorded on the
2434
+ * `gate.decided` audit line and {@link DecidedGate.input}; it grants nothing a typed answer does not.
2435
+ */
2436
+ input?: 'voice';
2437
+ /**
2438
+ * (api-types 0.160.0, program DES-LEARN §3.1) On a steering-author propose gate: the drafted rule ids
2439
+ * (`SteeringDraftResponse.rules[].id`) the person keeps. Only those land; the rest are declined
2440
+ * (`SteeringLandingResult.declinedIds`, audited `governance.steering.declined`). Absent = every drafted
2441
+ * rule lands. With a plain approve only (400 otherwise); **409** `no_draft` on a gate with no readable
2442
+ * draft, **409** `draft_changed` when an id is not in the draft as it reads now (the gate stays open).
2443
+ */
2444
+ keepRules?: string[];
2369
2445
  }
2370
2446
 
2371
2447
  /**
@@ -2441,6 +2517,8 @@ export interface CoreEvent {
2441
2517
  seat?: string;
2442
2518
  /** `elicitationCreated`: an ordered set of valid responses; `null` / absent = free-text. */
2443
2519
  options?: string[] | null;
2520
+ /** `elicitationCreated` (api-types 0.158.0): a multi-select's bounds (`propType: "array"`). Absent otherwise. */
2521
+ multi?: ElicitationMulti;
2444
2522
  /**
2445
2523
  * `elicitationCreated` (C3; wicked-core-ts >= 0.7.35, api-types 0.83.0): the index into `options`
2446
2524
  * of the option the PRODUCER of the options recommends (the field's JSON Schema `default`).
@@ -2465,6 +2543,13 @@ export interface CoreEvent {
2465
2543
  /** `awaitingHuman{gateKind: 'consent'}` (core#820): why no write targets are listed (no dry run
2466
2544
  * ran before the gate, or it printed no plan); the gate is then a plain approve / reject. */
2467
2545
  writeTargetsMissing?: string;
2546
+ /**
2547
+ * `awaitingHuman{gateKind: 'repeat'}` (api-types 0.163.0, domain-graph-3): a loop step's ask —
2548
+ * its command's progress line ("Mapping wicked-crew · 3% → 23% · target 80% · page 21 · budget
2549
+ * reached …"). The ask's answers ride `choices` (`consent:<id>`…, `reject` = stop, the run ends
2550
+ * and what it did is kept), `choiceLabels` and `recommended`, as on a consent gate.
2551
+ */
2552
+ repeatLine?: string;
2468
2553
  /** PTY terminal frames (`terminalOpened`/`terminalOutput`/`terminalExited`): the terminal id. */
2469
2554
  id?: string;
2470
2555
  /**
@@ -2872,6 +2957,24 @@ export interface CliUsageEvent {
2872
2957
  costUsd: number | null;
2873
2958
  }
2874
2959
 
2960
+ /**
2961
+ * (0.155.0) `/ws` frame (and logged with the run): a working seat's running token TOTAL for one unit attempt, live from
2962
+ * its own stream (wicked-core: claude per assistant message, pi per `message_end`, codex per `turn.completed`). Fresh +
2963
+ * cache input, as {@link CliUsageEvent} counts it; sent when it changed, at most one per 3 s. `costUsd` only where the
2964
+ * seat's stream states one (pi), else `null`. The attempt's `cliUsage` at its end stays the record.
2965
+ */
2966
+ export interface UsageProgressEvent {
2967
+ type: 'usageProgress';
2968
+ session: string;
2969
+ ord: number;
2970
+ attempt: number;
2971
+ /** Unix ms. */
2972
+ at: number;
2973
+ inputTokens: number;
2974
+ outputTokens: number;
2975
+ costUsd: number | null;
2976
+ }
2977
+
2875
2978
  /** §3 B4 — the data files a unit's CLI touched. */
2876
2979
  export interface DataUsedEvent {
2877
2980
  type: 'dataUsed';
@@ -4039,6 +4142,23 @@ export interface WorkflowSelectedEvent {
4039
4142
  unitCount: number;
4040
4143
  }
4041
4144
 
4145
+ /**
4146
+ * (api-types 0.163.0, domain-graph-3) A loop step sent the run back for another pass: every unit
4147
+ * from `fromOrd` through `ord` was re-armed at a fresh attempt and the run goes on from `fromOrd`.
4148
+ * `pass` counts the passes the loop has sent back (1 after the first); `line` is the step's own
4149
+ * progress line ("Mapping wicked-crew · 3% → 12% → 19% · target 80% · page 4 · about 2 h left"),
4150
+ * possibly empty. One per loop rewind: a page that reaches the target, or stops at a budget ask
4151
+ * (whose `awaitingHuman.repeatLine` carries the line), emits none.
4152
+ */
4153
+ export type StepRepeatedEvent = {
4154
+ type: 'stepRepeated';
4155
+ session: string;
4156
+ ord: number;
4157
+ fromOrd: number;
4158
+ pass: number;
4159
+ line: string;
4160
+ };
4161
+
4042
4162
  /** P2 — a human approved a gate with an amendment text that was injected into the unit's description
4043
4163
  * before re-dispatch. Fires after the amendment is persisted, before Resumed. Only emitted when
4044
4164
  * the amendment text is non-empty. The canonical record for the HITL paper trail. */
@@ -4223,6 +4343,28 @@ export interface WorkerMessageInjectedEvent {
4223
4343
  message: string;
4224
4344
  /** `"all"` or the cli_key that was targeted. */
4225
4345
  target: string;
4346
+ /** (0.161.0, DES-VOICE) Stamped by crew when the note was sent with {@link InjectMessageRequest.input} `voice`
4347
+ * (on `/ws` and `GET /runs/:id/events`; also on the `workerMessageQueued` frame). Crew remembers spoken notes in
4348
+ * memory, so one sent before a daemon restart reads as typed here; its `run.injected` audit line keeps it. */
4349
+ input?: 'voice';
4350
+ }
4351
+
4352
+ /** `POST /runs/:id/cancel` (0.161.0): the body is optional; a bodiless cancel is unchanged. */
4353
+ export interface CancelRunRequest {
4354
+ /** Why the person stopped it (≤ 2000 characters), said or typed: kept on the `run.cancelled` audit line. */
4355
+ reason?: string;
4356
+ /** (DES-VOICE) The person said the stop and confirmed it on screen. A person's only (403 otherwise). */
4357
+ input?: 'voice';
4358
+ }
4359
+
4360
+ /** `POST /runs/:id/inject`: an operator note into the run's active worker(s). */
4361
+ export interface InjectMessageRequest {
4362
+ message: string;
4363
+ /** `"all"` (the default) or a CLI key. */
4364
+ target?: string;
4365
+ /** (0.161.0, DES-VOICE) The person said this note and confirmed it on screen. A person's only (403 for a worker or
4366
+ * plugin bearer); kept on the `run.injected` audit line and stamped on the note's frames. Grants nothing. */
4367
+ input?: 'voice';
4226
4368
  }
4227
4369
 
4228
4370
  /** A unit was stopped and re-dispatched to a different CLI (or re-routed via council). */
@@ -4484,6 +4626,91 @@ export interface SteeringLandingResult {
4484
4626
  alreadyLanded?: boolean;
4485
4627
  /** Present iff `outcome: "failed"` — the loud, operator-readable reason. */
4486
4628
  error?: string;
4629
+ /** (api-types 0.160.0) The drafted rules the approve's `keepRules` left out: never landed. */
4630
+ declinedIds?: string[];
4631
+ }
4632
+
4633
+ /**
4634
+ * `GET /governance/steering/author/:runId/draft` (api-types 0.160.0, program DES-LEARN §3.1): a
4635
+ * steering-author run's drafted rules, normalized exactly as the landing lands them. `ready` is true once
4636
+ * the propose step has run and the run waits at a gate; until then `rules` may be empty. 404 for an
4637
+ * unknown run or one that is not steering-author (`code: "not_steering_author"`).
4638
+ */
4639
+ export interface SteeringDraftResponse {
4640
+ runId: string;
4641
+ ready: boolean;
4642
+ rules: ConformanceRule[];
4643
+ source?: SteeringProposalSource;
4644
+ }
4645
+
4646
+ // ── Personality (api-types 0.160.0, program DES-LEARN §3.3) ──────────────────────────────────────
4647
+
4648
+ /** 0 = the left word, 2 = the right word: length short..thorough, warmth plain..warm, pushback goes
4649
+ * along..challenges, initiative asks first..just starts. */
4650
+ export type PersonaDial = 0 | 1 | 2;
4651
+ export type PersonaHabit = 'says-unchecked' | 'tables' | 'cites' | 'names';
4652
+
4653
+ /** `PUT /persona`'s `persona`: how the orchestrator talks. Tone only: never read by a gate, review, QE or rule. */
4654
+ export interface PersonaInput {
4655
+ /** 1..40 characters. */
4656
+ name: string;
4657
+ /** `#rrggbb`. */
4658
+ colour: string;
4659
+ dials: { length: PersonaDial; warmth: PersonaDial; pushback: PersonaDial; initiative: PersonaDial };
4660
+ habits: PersonaHabit[];
4661
+ /** At most 500 characters, about tone. */
4662
+ notes?: string;
4663
+ }
4664
+
4665
+ export interface Persona extends PersonaInput {
4666
+ /** 1 on the first save of a scope, one more on each save. */
4667
+ version: number;
4668
+ /** Unix ms. */
4669
+ updatedAt: number;
4670
+ }
4671
+
4672
+ /** `user`, or `project:<id>` for one project's override. */
4673
+ export type PersonaScope = 'user' | `project:${string}`;
4674
+
4675
+ /** `GET /persona`: the person's own, every project override, and the voice block each adds to what a chat
4676
+ * seat is told (the project's override, else the person's, rides every chat's scope statement). */
4677
+ export interface PersonaResponse {
4678
+ user: Persona | null;
4679
+ projects: Record<string, Persona>;
4680
+ voice: { user: string | null; projects: Record<string, string> };
4681
+ }
4682
+
4683
+ /** `PUT /persona` body: a person only (403 otherwise); 404 for an unknown project. */
4684
+ export interface PersonaPutBody {
4685
+ scope: PersonaScope;
4686
+ persona: PersonaInput;
4687
+ }
4688
+
4689
+ export interface PersonaSaved {
4690
+ scope: PersonaScope;
4691
+ persona: Persona;
4692
+ voice: string;
4693
+ }
4694
+
4695
+ /** `DELETE /persona?scope=project:<id>`: removes a project's override (a person only). */
4696
+ export interface PersonaRemoved {
4697
+ removed: true;
4698
+ scope: PersonaScope;
4699
+ }
4700
+
4701
+ // ── First run (api-types 0.160.0, program DES-LEARN §4) ──────────────────────────────────────────
4702
+
4703
+ /** `GET /setup/known` (operator trust): what studio shows before it asks. A fact that cannot be read is
4704
+ * `null` or empty, never guessed. */
4705
+ export interface SetupKnown {
4706
+ /** The global git identity; null when neither name nor email is set. */
4707
+ git: { name: string | null; email: string | null } | null;
4708
+ /** Tracked source files by language across the registered repositories (`git ls-files`), at most 6. */
4709
+ languages: Array<{ name: string; files: number; share: number }>;
4710
+ filesCounted: number;
4711
+ /** Git checkouts one level under the home's code folders and the registered repositories' folders,
4712
+ * not registered yet (at most 24). `path` is absolute: register with `POST /repos {name, rootPath}`. */
4713
+ nearby: Array<{ name: string; path: string }>;
4487
4714
  }
4488
4715
 
4489
4716
  // ── Skills — the daemon-owned garden plugin root, published as immutable snapshots (api-types 0.28.0) ──
@@ -6227,6 +6454,7 @@ export interface RepoGraphResponse {
6227
6454
  finding?: RepoFinding;
6228
6455
  }
6229
6456
 
6457
+ /** One row of `GET /repos/:id/git-history` (`?limit=` 1..500, default 20; newest first). */
6230
6458
  export interface GitCommit {
6231
6459
  sha: string;
6232
6460
  shortSha: string;
@@ -6279,6 +6507,29 @@ export interface SystemSettings {
6279
6507
  * Exported as `WICKED_COUNCIL_SPAWN_STAGGER_MS`, read per council. Absent = the default.
6280
6508
  */
6281
6509
  councilSpawnStaggerMs?: number;
6510
+ /**
6511
+ * (api-types 0.159.0, operator ruling 2026-10-31) The requirements graph's minimum coverage:
6512
+ * `minCoveragePct`, a whole percentage 1..100, default 80. A repository's requirements graph is
6513
+ * built, and shown labelled with its share, once REAL requirements (0.164.0: placeholders never
6514
+ * count) reach this share of its behaviour-bearing product code; below it the
6515
+ * `domain-extraction` run says "N% real requirements, minimum M%" and keeps the mapping for the
6516
+ * next run. The daemon exports it as
6517
+ * `WICKED_REQUIREMENTS_MIN_COVERAGE_PCT` at boot and on every change. Absent = the default.
6518
+ */
6519
+ requirementsGraph?: {
6520
+ minCoveragePct?: number;
6521
+ /**
6522
+ * (api-types 0.163.0, domain-graph-3) A domain-extraction run maps page after page until the
6523
+ * target; its budget per grant — `maxPages` (1..200, default 20) or `maxMinutes` (1..1440,
6524
+ * default 240), whichever is spent first — ends in an ask: map more, lower the target for the
6525
+ * repository, or stop. `pageSize` (50..2000, default 500) is how many behaviours one page
6526
+ * maps. Exported as `WICKED_DOMAIN_MAX_PAGES` / `WICKED_DOMAIN_MAX_MINUTES` /
6527
+ * `WICKED_DOMAIN_PAGE_SIZE`. Absent = the defaults.
6528
+ */
6529
+ maxPages?: number;
6530
+ maxMinutes?: number;
6531
+ pageSize?: number;
6532
+ };
6282
6533
  /*
6283
6534
  * There is NO skills setting (skills keystone, api-types 0.28.0). The daemon-owned skills root is
6284
6535
  * `<state home>/skills` — the directory holding `manifest.json`, `baseline/<hash>/`, `effective/`,
@@ -6472,6 +6723,74 @@ export interface SettingsResponse {
6472
6723
  }
6473
6724
 
6474
6725
  // ── Requirements management (server-side search + overrides; crew api/requirements.ts) ──
6726
+ /**
6727
+ * (0.159.0, operator ruling 2026-10-31 "validation by duplication") How many INDEPENDENT sources in
6728
+ * the repository support a requirement beyond the extractor's own statement, as `wicked-core
6729
+ * domain-graph` computed it: distinct callers (`callSites`), tests, docs that name it, and extractor
6730
+ * seats beyond the first. `validated` at 2 or more; otherwise `unconfirmed`, and `why` says what is
6731
+ * missing — show `why.text` on the item. `why.code` is one of `unindexed_file` (a file the code index
6732
+ * skipped names it, so its callers there are not counted), `dead_code`, `config_only`,
6733
+ * `single_caller`, `test_only`, `doc_only`, `extractors_only`.
6734
+ */
6735
+ export interface RequirementCorroboration {
6736
+ status: 'validated' | 'unconfirmed';
6737
+ sources: number;
6738
+ callSites: number;
6739
+ tests: number;
6740
+ docs: number;
6741
+ extraExtractors: number;
6742
+ why?: { code: string; text: string };
6743
+ }
6744
+
6745
+ /**
6746
+ * (0.164.0, operator decision 2026-11-01, wicked-core#1233) How much of a repository's product code
6747
+ * is REAL requirements, and the minimum the graph is held to (`SystemSettings.requirementsGraph
6748
+ * .minCoveragePct`): label it "23% real requirements · 4397 placeholders · minimum 80%".
6749
+ *
6750
+ * - `realPct` is the one number the minimum is checked against: `floor(real * 100 /
6751
+ * behaviorBearing)`, floored so it never reads above the minimum it was compared to; 100 when
6752
+ * `behaviorBearing` is 0 (nothing in product code to map). `real + placeholders + unmapped ===
6753
+ * behaviorBearing`; a label that breaks either is not sent.
6754
+ * - `real`: behaviours resolved to a stated, sourced business rule.
6755
+ * - `placeholders`: behaviours carrying only a risk-flagged placeholder (an empty statement, a rule
6756
+ * under the confidence threshold, one written unconfirmed). Shown in the graph as unconfirmed,
6757
+ * NEVER counted toward the minimum.
6758
+ * - `unmapped`: behaviours with nothing recorded yet.
6759
+ * - `behaviorBearing`: the denominator, product code only. `notProduct` counts the behaviour-kind
6760
+ * nodes left out because their file is a test, data, manifest or document file.
6761
+ *
6762
+ * Replaces 0.159.0's `mappedPct` / `mapped` / `resolved`, which counted placeholders as mapped (a
6763
+ * repository with 3 real requirements and 117 placeholders read "100% mapped").
6764
+ */
6765
+ export interface RequirementsCoverage {
6766
+ realPct: number;
6767
+ minPct: number;
6768
+ behaviorBearing: number;
6769
+ real: number;
6770
+ placeholders: number;
6771
+ unmapped: number;
6772
+ notProduct: number;
6773
+ }
6774
+
6775
+ /**
6776
+ * (0.165.0) The graph a requirements page lists, as it was built. When `behind`, the header (`coverage`, the store
6777
+ * now) does not count what the list holds: say so. When this `coverage.real` is below the header's: "2,202 real
6778
+ * requirements mapped since the last graph build; build the graph to list them". With `coverage` null: "built
6779
+ * before real requirements were counted; build the graph to list the N real requirements mapped now". Otherwise
6780
+ * (only another count moved, or `real` fell): "the repository changed since this graph was built".
6781
+ */
6782
+ export interface RequirementsGraphBuild {
6783
+ /** The build's generation in the store (1 = the first build; 0 = a graph persisted before the engine kept a
6784
+ * build record). */
6785
+ generation: number;
6786
+ /** The label the build persisted; `null` when it carried none or an older engine's `mapped_pct` label. */
6787
+ coverage: RequirementsCoverage | null;
6788
+ /** True when any count of the build's label differs from the page's `coverage` (or the label is null), or
6789
+ * (0.167.0) when the engine judged every listed row and the counted rows' verdicts are not the header's real and
6790
+ * placeholders. False says the counts agree, not that every statement is unchanged. */
6791
+ behind: boolean;
6792
+ }
6793
+
6475
6794
  export interface RequirementSummary {
6476
6795
  key: string;
6477
6796
  domain: string;
@@ -6483,6 +6802,20 @@ export interface RequirementSummary {
6483
6802
  risk: boolean;
6484
6803
  riskSource: 'operator' | 'data' | null;
6485
6804
  edited: boolean;
6805
+ /** (0.159.0) Validated or unconfirmed (with why). `null` on a graph built before the field;
6806
+ * ABSENT from an older daemon. */
6807
+ corroboration?: RequirementCorroboration | null;
6808
+ /** (0.166.0) The engine would not count it a real requirement (a validated requirement, or a business rule at or
6809
+ * above the resolve threshold, 0.75): a placeholder, unconfirmed whatever its corroboration says. (0.167.0) The
6810
+ * engine's own verdict when it gives one, else read off the document. ABSENT from an older daemon. */
6811
+ placeholder?: boolean;
6812
+ /** (0.167.0) The coverage share does not count this row, and why: its unit is not a behaviour (`structural`, a
6813
+ * TypeScript shape or signature), is outside product code (`not_product`), or is no longer indexed (`unindexed`).
6814
+ * Such a row is neither a real requirement nor a placeholder of the header's (its `placeholder` says only whether
6815
+ * a rule was stated there), sorts after them, and carries
6816
+ * `corroboration: null` (a type has no callers; "dead code" would be wrong). `null` when it counts or the engine
6817
+ * does not say; ABSENT from an older daemon. */
6818
+ uncounted?: 'structural' | 'not_product' | 'unindexed' | null;
6486
6819
  }
6487
6820
 
6488
6821
  export interface RequirementDetail extends RequirementSummary {
@@ -6508,12 +6841,55 @@ export interface RequirementsPage {
6508
6841
  source: 'store' | 'artifact';
6509
6842
  /**
6510
6843
  * Keys in `requirements_overrides.json` that matched NO requirement in the corpus. Operator
6511
- * edits are keyed by SymbolId (store) or `domain::reqId` (artifact); an estate id-scheme
6512
- * migration re-mints method/field SymbolIds, so overrides keyed by the old ids stop matching and
6513
- * would otherwise vanish silently. Non-zero means edits exist that no row is showing — re-run
6514
- * the annotation workflow, then re-apply or delete the stale keys.
6844
+ * edits are keyed by `domain::reqId` whatever the source (older daemons serving `'store'` keyed
6845
+ * them by SymbolId). The engine keeps a requirement's id across builds, so a key stops matching
6846
+ * when its requirement is retired or its domain regrouped. Non-zero means edits exist that no
6847
+ * row is showing — re-apply or delete the stale keys.
6515
6848
  */
6516
6849
  orphanedOverrides?: number;
6850
+ /** (0.159.0; real requirements since 0.164.0) The graph's coverage label; `null` when absent, an
6851
+ * older engine's `mapped_pct` label, or one its counts do not support; ABSENT from an older
6852
+ * daemon. */
6853
+ coverage?: RequirementsCoverage | null;
6854
+ /**
6855
+ * (0.165.0) Which build the rows are. The list is the last graph BUILD; `coverage` counts the store NOW,
6856
+ * which moves on when a run maps more without building (stopped at its repeat ask, or below the minimum,
6857
+ * where the build refuses). `null` when the engine does not say; ABSENT from an older daemon.
6858
+ */
6859
+ graphBuild?: RequirementsGraphBuild | null;
6860
+ /** (0.159.0) How many requirements of the whole corpus are validated / unconfirmed. (0.167.0) Rows the share does
6861
+ * not count are in neither. */
6862
+ corroboration?: { validated: number; unconfirmed: number };
6863
+ /**
6864
+ * (0.167.0) Rows of the whole corpus the coverage share does not count (items with `uncounted`), split stated /
6865
+ * placeholder: why the list holds more rows than the header. When this is not `null` and `graphBuild.behind` is
6866
+ * false, the rows that are neither placeholders nor uncounted number exactly `coverage.real`. `null` when the engine
6867
+ * did not judge every row (an older engine, a build before it recorded each row's unit, a malformed verdict): those
6868
+ * rows are read off the document, and there is no such claim. ABSENT from an older daemon.
6869
+ */
6870
+ uncounted?: { stated: number; placeholders: number } | null;
6871
+ /** (0.167.0) How many rows of the whole corpus are in each category, so a client can leave out an empty filter.
6872
+ * ABSENT from an older daemon. */
6873
+ categories?: { functional: number; configData: number };
6874
+ }
6875
+
6876
+ /**
6877
+ * `GET /repos/:id/requirements` 404 when the repository's `requirements_graph.json` has not been
6878
+ * generated (0.154.0). A state, not a refusal: `code` is the discriminator a client matches on, and
6879
+ * `workflow` names the preset that generates the graph (its last step runs `wicked-core domain-graph`).
6880
+ * Any other 404 on the route (an unknown repo) carries no `code`.
6881
+ */
6882
+ export interface RequirementsNotGenerated {
6883
+ error: string;
6884
+ code: 'notGenerated';
6885
+ workflow: string;
6886
+ /**
6887
+ * (api-types 0.163.0, domain-graph-3; real requirements since 0.164.0) How far the repository
6888
+ * is, against its target ("23% real requirements · 4397 placeholders · target 80%"): present
6889
+ * when the repository has a store to count.
6890
+ * `minPct` is the target in force (the repository's own when lowered, else the daemon's).
6891
+ */
6892
+ coverage?: RequirementsCoverage;
6517
6893
  }
6518
6894
 
6519
6895
  export interface RequirementPatch {
@@ -6571,14 +6947,130 @@ export interface ElicitationInfo {
6571
6947
  ord?: number;
6572
6948
  attempt?: number;
6573
6949
  seat?: string;
6950
+ /**
6951
+ * (api-types 0.158.0, guided asks) The person may pick SEVERAL of `options`: at least `min`, at most `max`
6952
+ * (both always set, `1 <= min <= max <= options.length`). Answer it with `content: {values}`; the engine records
6953
+ * the picks as a JSON array in `options` order. ABSENT on a single-choice or free-text question and on an older
6954
+ * daemon.
6955
+ */
6956
+ multi?: ElicitationMulti;
6574
6957
  receivedAt: string;
6575
6958
  }
6576
6959
 
6577
- /** `POST /runs/:id/elicitation` body. `content` is required for accept, absent otherwise. */
6960
+ /** (api-types 0.158.0) How many of a multi-select elicitation's options an answer picks. */
6961
+ export interface ElicitationMulti {
6962
+ min: number;
6963
+ max: number;
6964
+ }
6965
+
6966
+ /**
6967
+ * `POST /runs/:id/elicitation` body. `content` is required for accept, absent otherwise: `{response}` answers a
6968
+ * free-text or single-choice question (one of `options`); `{values}` (api-types 0.158.0) answers a multi-select one
6969
+ * ({@link ElicitationInfo.multi}): distinct entries of `options`, `min..=max` of them. Crew answers 400 to `values` on
6970
+ * a question that is not multi-select, and to `response` on one that is.
6971
+ */
6578
6972
  export interface ElicitationResponse {
6579
6973
  elicitationId: string;
6580
6974
  action: 'accept' | 'decline' | 'cancel';
6581
- content?: { response: string };
6975
+ content?: { response: string } | { values: string[] };
6976
+ }
6977
+
6978
+ // ── Guided asks (api-types 0.158.0; design DES-GUIDED-CHAT) ─────────────────────────────────────────────────────
6979
+ //
6980
+ // ONE typed shape for every question a person answers inline: an engine gate, a seat's or MCP server's elicitation,
6981
+ // a power-mode pause, a plugin's proposal, a studio setup step. It is a RENDERING contract: the wire shapes that
6982
+ // exist stay as they are and map onto it (GateInfo.choices + recommended + gateKind → `choose`; ElicitationInfo
6983
+ // options/multi → `choose` / `pick` / `text`), and every answer still goes through its host's own route
6984
+ // (`POST /runs/:id/gate` with a GateDecision, `POST /runs/:id/elicitation`, …). Governance is the host's: an ask
6985
+ // never widens who may answer, and a gate's ask is always `answeredBy: 'person'`.
6986
+
6987
+ /** The six ways a person answers. */
6988
+ export type AskKind =
6989
+ /** Yes / no (two options; picking one is the answer). */
6990
+ | 'confirm'
6991
+ /** Choose one of 2..n options. */
6992
+ | 'choose'
6993
+ /** Pick several (`multi` bounds). */
6994
+ | 'pick'
6995
+ /** Short text. */
6996
+ | 'text'
6997
+ /** A point on a scale (named steps, or a number range). */
6998
+ | 'scale'
6999
+ /** Confirm, with a required reason (a danger move: stop, reject, skip QE, override). */
7000
+ | 'confirm_reason';
7001
+
7002
+ /** Which route answers the ask. */
7003
+ export type AskHost = 'gate' | 'elicitation' | 'chat' | 'learn' | 'plugin' | 'power';
7004
+
7005
+ /** One option of a `confirm` / `choose` / `pick` / `confirm_reason` ask. */
7006
+ export interface AskOption {
7007
+ /** Stable within the ask. */
7008
+ id: string;
7009
+ /** What the person reads (and the voice vocabulary). */
7010
+ label: string;
7011
+ /** One line under the label. */
7012
+ sub?: string;
7013
+ /** What happens if this option is taken, shown while it is hovered or selected ("If you choose this: …"). */
7014
+ consequence?: string;
7015
+ /** The wire answer: a gate action token, an elicitation option, a pause decision. */
7016
+ token: string;
7017
+ tone?: 'primary' | 'neutral' | 'danger';
7018
+ /** The engine's (or producer's) recommendation: marked, and preselected unless the host says otherwise. */
7019
+ recommended?: boolean;
7020
+ /** Taking it asks for a reason first (kept with the record). */
7021
+ needsReason?: boolean;
7022
+ /** Shown but not choosable; the string says why ("Frozen: nothing merges there"). */
7023
+ disabled?: string;
7024
+ /** A small tag ("default", "current release"). */
7025
+ meta?: string;
7026
+ }
7027
+
7028
+ /** A named-step scale, or a number range. */
7029
+ export type AskScale =
7030
+ | { steps: string[]; consequences?: string[] }
7031
+ | { min: number; max: number; step: number; labels: [string, string] };
7032
+
7033
+ export interface Ask {
7034
+ /** Gate: `<runId>:<ord>`; elicitation: its `elicitationId`; otherwise the host's own id. */
7035
+ id: string;
7036
+ host: AskHost;
7037
+ /** Who asks, in words ("Codex asks", "The engine asks"). */
7038
+ from: { kind: 'engine' | 'seat' | 'plugin' | 'studio'; id: string; label: string };
7039
+ /** One sentence, a question. */
7040
+ prompt: string;
7041
+ /** One line under the question. */
7042
+ detail?: string;
7043
+ kind: AskKind;
7044
+ options?: AskOption[];
7045
+ /** `pick`: how many (defaults: 1 and every option). */
7046
+ multi?: { min?: number; max?: number };
7047
+ /** Preselected: an option id (`choose` / `confirm`), option ids (`pick`), a step index or value (`scale`). */
7048
+ default?: string | string[] | number;
7049
+ scale?: AskScale;
7050
+ text?: { placeholder?: string; maxChars?: number; optional?: boolean };
7051
+ /** A follow-up shown in the same card once the first part is answered (pick the steps, then say what). */
7052
+ then?: Ask;
7053
+ /** A gate is always `'person'`. */
7054
+ answeredBy: 'person' | 'any';
7055
+ /** The answer waits this long, with Undo, before it is sent (a gate: 10 000). */
7056
+ undoMs?: number;
7057
+ /** The answered line: `{label}`, `{labels}` and `{text}` are filled ("You chose: {label}"). */
7058
+ record: string;
7059
+ }
7060
+
7061
+ /** What a person answered: the host turns it into its own wire body. */
7062
+ export interface AskAnswer {
7063
+ askId: string;
7064
+ /** `confirm` / `choose` / `confirm_reason`: the option taken. */
7065
+ option?: string;
7066
+ /** `pick`: the options picked, in the ask's order. */
7067
+ options?: string[];
7068
+ /** `text`, and a `then` text. */
7069
+ text?: string;
7070
+ /** `scale`: the step index or value. */
7071
+ value?: number;
7072
+ /** A `needsReason` option's reason. */
7073
+ reason?: string;
6582
7074
  }
6583
7075
 
6584
7076
  // ── Inventory claims (wicked-crew#721) — whether each enumerating step's list is complete ──
@@ -6611,6 +7103,116 @@ export interface RunInventoryUnit {
6611
7103
  claims: InventoryClaim[];
6612
7104
  }
6613
7105
 
7106
+ /**
7107
+ * `GET /runs/:id/learnings` — what a run proposed to the approve queue (run learnings, crew src/learnings).
7108
+ * Every learning is a `memory` proposal attributed to the run (`provenance.run_id`); nothing is used until a
7109
+ * person approves it on the Memory page. `distilling` is true while the run's distil seat (one cheap seat
7110
+ * that did not build the run) is still reading its evidence.
7111
+ */
7112
+ export interface RunLearningsResponse {
7113
+ runId: string;
7114
+ proposed: number;
7115
+ pending: number;
7116
+ approved: number;
7117
+ rejected: number;
7118
+ distilling: boolean;
7119
+ items: Array<{
7120
+ /** The proposal id (approve or reject it through `/proposals/:id/*`). */
7121
+ id: string;
7122
+ state: string;
7123
+ /** `gotcha` | `decision` | `pattern` | `steering`, as filed. */
7124
+ capture: string | null;
7125
+ content: string;
7126
+ /** Who worded it: `crew` (from the run's record) or the distil seat. */
7127
+ agent: string | null;
7128
+ /** Unix seconds. */
7129
+ createdAt: number | null;
7130
+ }>;
7131
+ }
7132
+
7133
+ /** (0.155.0) The in-flight check's verdict on a working step. */
7134
+ export type UnitInspectVerdict = 'progressing' | 'looping' | 'stuck' | 'wasteful';
7135
+ /** (0.155.0) The one action a check recommends; the person chooses, nothing is done for them. */
7136
+ export type UnitInspectAction = 'let_run' | 'steer' | 'stop';
7137
+
7138
+ /** (0.155.0) Crew's own deterministic reading of a working step's newest attempt (crew src/inspect/reading.ts). */
7139
+ export interface UnitInspectReading {
7140
+ ord: number;
7141
+ attempt: number;
7142
+ startedAt: number | null;
7143
+ elapsedMs: number | null;
7144
+ calls: number;
7145
+ openCalls: Array<{ tool: string; target: string | null; forMs: number }>;
7146
+ byKind: Record<string, number>;
7147
+ edits: Array<{ path: string; count: number }>;
7148
+ said: { deltas: number; chars: number; lastAt: number | null; newest: string | null };
7149
+ usage: { inputTokens: number; outputTokens: number; costUsd: number | null; source: 'live' | 'final' } | null;
7150
+ lastSignAt: number | null;
7151
+ verdict: UnitInspectVerdict;
7152
+ evidence: string[];
7153
+ doing: string | null;
7154
+ action: UnitInspectAction;
7155
+ note: string | null;
7156
+ }
7157
+
7158
+ /**
7159
+ * (0.155.0) One "Is this going well?" check on a working step (`POST /runs/:id/units/:ord/inspect`). A seat that is not
7160
+ * the step's own reads the step's record (one read-only `inspect-unit` run, bounded by time and budget) and answers;
7161
+ * when none can, or it fails, times out or reaches its budget, `source: 'crew'` and `why` says so and the answer is
7162
+ * crew's own reading. It never steers, stops or edits the run it looks at.
7163
+ */
7164
+ export interface UnitInspection {
7165
+ id: string;
7166
+ runId: string;
7167
+ ord: number;
7168
+ attempt: number;
7169
+ state: 'checking' | 'done';
7170
+ /** The actor id who asked. */
7171
+ requestedBy: string;
7172
+ /** Unix ms. */
7173
+ requestedAt: number;
7174
+ finishedAt: number | null;
7175
+ /** The step's own seat. */
7176
+ workerSeat: string | null;
7177
+ /** The seat that checked (never the step's own); null when none could. */
7178
+ seat: string | null;
7179
+ /** The check's own run (workflow `inspect-unit`); null when none was launched. */
7180
+ checkRunId: string | null;
7181
+ source: 'seat' | 'crew' | null;
7182
+ why: string | null;
7183
+ verdict: UnitInspectVerdict | null;
7184
+ /** What the step is doing, one sentence. */
7185
+ doing: string | null;
7186
+ /** Roughly how far along it is (the seat's estimate), one sentence. */
7187
+ progress: string | null;
7188
+ evidence: string[];
7189
+ action: UnitInspectAction | null;
7190
+ /** For `action: 'steer'`: the note it suggests sending the step's seat (the person may edit it before sending). */
7191
+ note: string | null;
7192
+ reading: UnitInspectReading;
7193
+ /** What the check itself spent, when its seat reported it. */
7194
+ cost: { inputTokens: number; outputTokens: number; costUsd: number | null } | null;
7195
+ }
7196
+
7197
+ /** (0.155.0) `POST /runs/:id/units/:ord/inspect` → 202. 403 for anyone but a human operator; 409 `not_working` when the
7198
+ * step is not working now. A check already running on the step is answered as it is. */
7199
+ export interface UnitInspectionResponse {
7200
+ inspection: UnitInspection;
7201
+ }
7202
+
7203
+ /** (0.155.0) `GET /runs/:id/units/:ord/inspections`: the step's checks, newest first. */
7204
+ export interface UnitInspectionsResponse {
7205
+ inspections: UnitInspection[];
7206
+ }
7207
+
7208
+ /** (0.155.0) `/ws` frame: a check started, its budget moved, or it answered. */
7209
+ export interface UnitInspectionEvent {
7210
+ type: 'unitInspection';
7211
+ session: string;
7212
+ ord: number;
7213
+ inspection: UnitInspection;
7214
+ }
7215
+
6614
7216
  /**
6615
7217
  * `GET /runs/:id/inventory` (404 for an unknown run). `complete` is true only when at least one
6616
7218
  * unit claimed an inventory, every claim is `full` and every finished unit's output was readable;
@@ -7355,7 +7957,8 @@ export interface ChatScope {
7355
7957
  * 0.35.0, F-2R2-008) names the UI action that would change a `bound: false` outcome, when one
7356
7958
  * would: `projects.graph.refresh` = build the project graph from the project page. */
7357
7959
  graph: { bound: boolean; reason: string; repoLabel?: string; action?: ProjectGraphAction };
7358
- /** `crew.repo` members of the project whose registry record is gone — named, not readable. */
7960
+ /** `crew.repo` members of the project whose registry record is gone — named, not readable. (0.155.0) Also
7961
+ * any repo in scope (project or `everything`) whose folder is missing (`repo_folder_missing`). */
7359
7962
  dangling: string[];
7360
7963
  }
7361
7964
 
@@ -8436,8 +9039,26 @@ export interface DiagnosticsResponse {
8436
9039
  * — see `DiagnosticsVault`. `null` on a route set booted without an engine adapter; ABSENT on an
8437
9040
  * older daemon. */
8438
9041
  vault?: DiagnosticsVault | null;
9042
+ /** (crew#1147) The engine's repo-checks floor cache usage (`Core.floorCacheUsage`): `path` is shown as
9043
+ * `~/...`, never a home path; `repos` is largest first. The engine walks the cache, so the daemon
9044
+ * caches this answer for 60 s. `{ error }` when the engine has no worker home; `null` on an addon
9045
+ * without the static; ABSENT on an older daemon. */
9046
+ floorCache?: DiagnosticsFloorCache | null;
8439
9047
  }
8440
9048
 
9049
+ /** `DiagnosticsResponse.floorCache` (crew#1147). Every `path` is `~/...`. */
9050
+ export type DiagnosticsFloorCache =
9051
+ | {
9052
+ path: string;
9053
+ bytes: number;
9054
+ totalCapBytes: number;
9055
+ repoCapBytes: number;
9056
+ idleTtlSecs: number;
9057
+ repos: Array<{ name: string; bytes: number; leaves: number }>;
9058
+ logs: { path: string; bytes: number; capBytes: number };
9059
+ }
9060
+ | { error: string };
9061
+
8441
9062
  /**
8442
9063
  * (api-types 0.130.0, crew#1068) `DiagnosticsResponse.vault`: what the daemon exported to the engine
8443
9064
  * as `WICKED_VAULT_BIN` at boot. `shipped` = crew's own `wicked-vault` dependency's bin (an absolute
@@ -8909,8 +9530,33 @@ export type SystemLevel = 'green' | 'yellow' | 'red';
8909
9530
  /** The existing action an attention item or row offers (the snapshot itself is read-only):
8910
9531
  * `sign_in` — the CLI's sign-in (`POST /seats/:cli/login…` / the Agents page); `recheck` — read
8911
9532
  * the snapshot again (every probe runs fresh per read); `open_gate` — the run's open gate;
8912
- * `open_run` — the run. */
8913
- export type SystemActionKind = 'sign_in' | 'recheck' | 'open_gate' | 'open_run';
9533
+ * `open_run` — the run. (0.162.0) `rebuild_seat_images` — `POST /system/seat-images/rebuild`
9534
+ * (the `seat_images` row: missing or unheld seat images); a skin that does not know a kind shows
9535
+ * the item without its button. */
9536
+ export type SystemActionKind = 'sign_in' | 'recheck' | 'open_gate' | 'open_run' | 'rebuild_seat_images';
9537
+
9538
+ /** (0.162.0) `POST /api/v1/system/seat-images/rebuild` (a person only: 403 `{ error }` for an agent
9539
+ * or plugin bearer) → 202 once the engine process started; 409 while a rebuild runs; 503 on the
9540
+ * host floor, when crew cannot reach or start the engine binary, when the engine's seat image
9541
+ * status does not answer, when the roster cannot be read, or when no roster seat has an engine seat
9542
+ * image (`started: false` with why). A running rebuild is 409 before anything else is asked. The rebuild runs `wicked-core seat-image build <roster seats>` in the background (minutes;
9543
+ * it also holds an operator's own image); its progress reads on the `seat_images` row
9544
+ * (`details.rebuild`). */
9545
+ export interface RebuildSeatImagesResponse {
9546
+ started: boolean;
9547
+ /** Why it did not start; absent when it did. */
9548
+ reason?: string;
9549
+ rebuild: {
9550
+ running: boolean;
9551
+ startedAt: string;
9552
+ finishedAt: string | null;
9553
+ rc: number | null;
9554
+ tail: string[];
9555
+ /** The last output line that reads as a failure; `null` when none. */
9556
+ error: string | null;
9557
+ clis: string[];
9558
+ } | null;
9559
+ }
8914
9560
 
8915
9561
  /** Where an item points. A skin maps it to its own route; crew never spells a studio URL. */
8916
9562
  export type SystemTarget =
@@ -9203,7 +9849,21 @@ export type SystemInfraKey =
9203
9849
  | 'stores'
9204
9850
  | 'seat_floor'
9205
9851
  | 'disk'
9206
- | 'load';
9852
+ | 'load'
9853
+ /** (0.155.0) The registered repositories' folders: `down` while any is missing (moved or deleted),
9854
+ * naming each with its path; `details.missing` lists `{ id, name, path }`. ABSENT before. */
9855
+ | 'repos'
9856
+ /** (0.162.0) The container seats' images (wicked-core `seat-image status`): `down` when a missing
9857
+ * seat image cannot be built (the operator's base is gone with no recipe, or an operator image is
9858
+ * missing) or the runtime VM disk is at 92 % or more; `degraded` when roster images are missing
9859
+ * (the next unit builds each first), not yet held against a runtime's image cleanup, the base is
9860
+ * missing, or the VM disk is at 75 % or more (a kubelet deletes unheld images from 85 %);
9861
+ * `unknown` when the engine, the roster or the disk could not be read. `details`: `images`
9862
+ * (`base`, `baseRecipe`, `holdSupported`, `floor`, `seats[]` with `present`/`held`/
9863
+ * `operatorImage`), `disk` (`totalBytes`, `availBytes`, `usedPct`), `missing`, `unheld`,
9864
+ * `imageGcHighPct`, `rebuild` (a running or the last rebuild, its output's last lines live).
9865
+ * `off` on the host floor. ABSENT before. */
9866
+ | 'seat_images';
9207
9867
 
9208
9868
  export interface SystemInfraRow {
9209
9869
  key: SystemInfraKey;
@@ -11095,6 +11755,8 @@ export interface DecidedGate {
11095
11755
  creator: { seat: string; phase: string | null; ord: number } | null;
11096
11756
  /** A standing order could have approved this gate (a phase-review gate of a run that lands no doctrine). */
11097
11757
  orderApprovable: boolean;
11758
+ /** (api-types 0.156.0) Answered by voice and confirmed on screen ({@link GateDecision.input}); absent otherwise. */
11759
+ input?: 'voice';
11098
11760
  }
11099
11761
 
11100
11762
  /** `GET /gates/decided`'s 200. A malformed `since` answers 400. */
@@ -12100,6 +12762,23 @@ export interface EditorControl {
12100
12762
  maxChars?: number;
12101
12763
  }
12102
12764
 
12765
+ /**
12766
+ * How an editor looks on studio's Plugins page (program DES-LEARN §2; api-types 0.157.0). Every image is a `data:` URL
12767
+ * (`image/svg+xml`, `image/png` or `image/webp`, base64) the registry read from the editor's own files, bounded (icon
12768
+ * 16 KB, preview 200 KB) and never through a link: no path and no remote URL is on the wire. Each field is optional;
12769
+ * a file that is missing, too big or not the image its name says is left out (the editor is still served).
12770
+ */
12771
+ export interface EditorVisuals {
12772
+ /** Drawn on `color`, at about 18 px. */
12773
+ icon?: string;
12774
+ /** `#rrggbb`. */
12775
+ color?: string;
12776
+ /** A 16:9 picture of the editor at work; a `dark` one is used on a dark theme (else `light`). */
12777
+ preview?: { light?: string; dark?: string };
12778
+ /** The editor offers a live preview on its own sample (reserved: studio draws one for run plugins today). */
12779
+ live?: boolean;
12780
+ }
12781
+
12103
12782
  /**
12104
12783
  * One registered editor, as Settings → Editors renders it. No path is on the wire: the bundle is
12105
12784
  * fetched at `entry_url` (`GET /editors/:id/:version/entry`, the §8.2 headers, re-hashed per serve).
@@ -12132,6 +12811,11 @@ export interface EditorView {
12132
12811
  /** `studio-bundle`: first-party, shipped with studio. `pack`: a third-party pack the operator installed. */
12133
12812
  source: 'studio-bundle' | 'pack';
12134
12813
  entry_url: string;
12814
+ /** Its one line for the Plugins page (at most 160 characters). Absent when the manifest has none, and from a daemon
12815
+ * that predates the field (api-types 0.157.0). */
12816
+ description?: string;
12817
+ /** Its icon, colour and preview (api-types 0.157.0). Absent when it declares none that read. */
12818
+ visuals?: EditorVisuals;
12135
12819
  }
12136
12820
 
12137
12821
  /** `GET /editors` (operator+). */
@@ -13013,3 +13697,112 @@ export interface DefaultEvalDetail {
13013
13697
  report: DefaultEvalReport;
13014
13698
  cases: DefaultEvalCase[];
13015
13699
  }
13700
+
13701
+ // ── Voice mode, phase 1 (program DES-VOICE; api-types 0.156.0) ─────────────────────────────────────────
13702
+
13703
+ /**
13704
+ * `GET /voice/status` (and the answer of `POST|DELETE /voice/model`). Speech to text runs on THIS machine:
13705
+ * whisper.cpp's CLI plus one model file. Every voice route is the human operator's alone, on loopback
13706
+ * (403 `human_operator_only` / `voice_loopback_only`).
13707
+ */
13708
+ export interface VoiceStatus {
13709
+ /** Audio is transcribed on this machine and never sent anywhere. Always `true` in phase 1. */
13710
+ local: true;
13711
+ /** The engine and the model are both here: `POST /voice/transcribe` can run. */
13712
+ ready: boolean;
13713
+ engine: {
13714
+ name: 'whisper.cpp';
13715
+ found: boolean;
13716
+ /** Where the CLI was found; `null` when it was not. */
13717
+ path: string | null;
13718
+ /** How to install (or upgrade) it on this platform, when it is missing or too old; else `null`. */
13719
+ install: string | null;
13720
+ /** (api-types 0.158.0) The version it reports (`--version`); `null` when not found, or too old to report one. */
13721
+ version: string | null;
13722
+ /** (api-types 0.158.0) New enough for voice (1.8.0 or later, reporting `--version`): a stdin transcription prints
13723
+ * its text and writes no file. An older engine is refused with 409 `voice_engine_outdated`, before any audio. */
13724
+ supported: boolean;
13725
+ };
13726
+ model: {
13727
+ /** `base.en`. */
13728
+ name: string;
13729
+ present: boolean;
13730
+ /** The model file's size; `null` when absent. */
13731
+ bytes: number | null;
13732
+ /** What the consent says before anything is fetched. */
13733
+ approxBytes: number;
13734
+ /** Where it is fetched from (`huggingface.co/ggerganov/whisper.cpp`). */
13735
+ source: string;
13736
+ /** A download in progress, or the last one's failure; `null` when none. */
13737
+ download: {
13738
+ state: 'running' | 'failed';
13739
+ receivedBytes: number;
13740
+ totalBytes: number | null;
13741
+ startedAt: string;
13742
+ error: string | null;
13743
+ } | null;
13744
+ };
13745
+ }
13746
+
13747
+ /** `POST /voice/model`: the person's consent to fetch the model (202 = started; 200 = already here; 409
13748
+ * `voice_download_running`). Audited `voice.model.download_started`. `DELETE /voice/model` removes it. */
13749
+ export interface PostVoiceModelBody {
13750
+ consent: true;
13751
+ }
13752
+
13753
+ /**
13754
+ * `POST /voice/transcribe` with an `audio/wav` body (16 kHz mono 16-bit, at most 8 MiB). The audio is held in
13755
+ * memory for the call and dropped: never stored, logged or audited. Errors carry `code`:
13756
+ * `voice_engine_missing` / `voice_engine_outdated` / `voice_model_missing` (409), `voice_audio_invalid` (400/415),
13757
+ * `voice_audio_too_large` (413), `voice_busy` (429: one runs and one waits), `voice_timeout` (504), `voice_failed` (500).
13758
+ */
13759
+ export interface VoiceTranscribeResponse {
13760
+ /** The words, one line; empty when nothing was said. */
13761
+ text: string;
13762
+ ms: number;
13763
+ model: string;
13764
+ }
13765
+
13766
+ /** A section a widget registers in the `voice-dashboard` panel slot (the `panels[]` shape of a run plugin). */
13767
+ export interface VoicePanelDecl {
13768
+ slot: 'voice-dashboard';
13769
+ id: string;
13770
+ title: string;
13771
+ /** 1-99, lower first. */
13772
+ order: number;
13773
+ }
13774
+
13775
+ /**
13776
+ * A USER-MADE dashboard widget: a declarative plugin (no code, nothing framed) that shows one field of
13777
+ * `GET /system` or `GET /diagnostics` as a number or a chart. `metric.path` is a field path:
13778
+ * `infra[key=load].details.load1`, `runs.length`, `toReview`.
13779
+ */
13780
+ export interface VoiceWidgetManifest {
13781
+ /** `user.<slug>`. */
13782
+ id: string;
13783
+ title: string;
13784
+ version: 1;
13785
+ kind: 'metric';
13786
+ panels: [VoicePanelDecl];
13787
+ metric: {
13788
+ source: 'system' | 'diagnostics';
13789
+ path: string;
13790
+ display: 'number' | 'chart';
13791
+ unit?: string;
13792
+ };
13793
+ createdAt?: string;
13794
+ }
13795
+
13796
+ /** `GET /voice/dashboard`: this person's dashboard (keyed by actor id). `layout: null` = never saved. */
13797
+ export interface VoiceDashboard {
13798
+ /** Widget ids in order: `builtin.<id>` or a user widget's `user.<slug>`. */
13799
+ layout: string[] | null;
13800
+ widgets: VoiceWidgetManifest[];
13801
+ updatedAt: string | null;
13802
+ }
13803
+
13804
+ /** `PUT /voice/dashboard` (at most 24 on the layout, 16 user widgets; every `user.*` on the layout is in `widgets`). */
13805
+ export interface PutVoiceDashboardBody {
13806
+ layout: string[];
13807
+ widgets: VoiceWidgetManifest[];
13808
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-crew-api-types",
3
- "version": "0.149.0",
3
+ "version": "0.167.0",
4
4
  "description": "The wire contract of the wicked-crew daemon's /api/v1 REST surface and /ws CoreEvent frames \u2014 types only, zero runtime",
5
5
  "type": "module",
6
6
  "types": "./index.d.ts",