wicked-crew-api-types 0.38.0 → 0.40.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 +289 -14
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -111,7 +111,15 @@ export type EntityMode = 'shared' | 'isolated';
111
111
  /** Human-confirm gate policy. serde: `None`→"none", `All`→"all", `Before(n)`→{ before: n }. */
112
112
  export type HumanConfirm = 'none' | 'all' | { before: number };
113
113
 
114
- /** Why a CLI was assigned to a unit (`RoutingInfo`, internally tagged on `method`). */
114
+ /**
115
+ * Why a CLI was assigned to a unit (`RoutingInfo`, internally tagged on `method`).
116
+ *
117
+ * `teamed` (wicked-core#590 S5) is what every seated unit of a new run carries: the engine no
118
+ * longer convenes a council to route, it picks the first eligible seat the unit's skills admit, in
119
+ * roster order (`winner`), and the evaluator ≠ creator fence then moves a review/test unit off a
120
+ * builder seat (`evaluator_distinct`, whose `was` is the teamed pick). `council` and `degraded` are
121
+ * no longer produced; they stay because a recorded run's units carry them.
122
+ */
115
123
  export type RoutingInfo =
116
124
  /**
117
125
  * `seated` is the seats CONVENED — the denominator `returned` must be read against.
@@ -135,7 +143,8 @@ export type RoutingInfo =
135
143
  }
136
144
  | { method: 'degraded'; reason: string }
137
145
  | { method: 'evaluator_distinct'; winner: string; was: string }
138
- | { method: 'tool' };
146
+ | { method: 'tool' }
147
+ | { method: 'teamed'; winner: string };
139
148
 
140
149
  /**
141
150
  * `GET /health` (api-types 0.37.0 — the shape was previously undeclared here; `status`,
@@ -191,6 +200,17 @@ export interface HealthCapabilities {
191
200
  * the field — read as `false`: do not send `revisesPr` to such a daemon.
192
201
  */
193
202
  revisesPr?: boolean;
203
+ /**
204
+ * `LaunchRunBody.chatId` is accepted (crew#619; crew ≥ 0.7.39). ABSENT on a daemon before
205
+ * the field — read as `false`: do not send `chatId` to such a daemon.
206
+ */
207
+ chatIdOnLaunch?: boolean;
208
+ /**
209
+ * `InteractiveDocCreateRequest.clisJson` (and the same field on demo/video and testing bodies)
210
+ * is accepted (crew#631; crew ≥ 0.7.40). ABSENT on a daemon before the field — omit `clisJson`
211
+ * on such a daemon.
212
+ */
213
+ seatChipOnCreate?: boolean;
194
214
  }
195
215
 
196
216
  /** One `GET /health.warnings[]` entry (additive; wicked-core#411 / wicked-crew#497). */
@@ -399,6 +419,37 @@ export interface AgentSession {
399
419
  /** Wave 6 (F-7R2-006): the seats BENCHED for this run — never convened, never a failover or
400
420
  * judge target. Absent (never `[]`) when none / on an older engine. */
401
421
  benched_seats?: BenchedSeat[];
422
+ /** crew#661: the declared skills this run's phases ran WITHOUT (the published skills snapshot did not
423
+ * hold them when the launching subsystem armed) — the run proceeded DEGRADED, and says so here.
424
+ * ABSENT (never `[]`) when the run launched fully armed, and on a daemon before this field. */
425
+ skill_gaps?: RunSkillGap[];
426
+ /**
427
+ * The surface that triggered this launch (crew#632; crew ≥ 0.7.40): `'studio'` (web UI),
428
+ * `'cli'` (wicked-crew CLI), or `'api'` (programmatic). ABSENT when the launch did not include
429
+ * the field (an older daemon or a caller that omitted it).
430
+ */
431
+ channel?: 'studio' | 'cli' | 'api';
432
+ /**
433
+ * An opaque caller-supplied identifier for the user or system that triggered the launch
434
+ * (crew#632; crew ≥ 0.7.40). ABSENT when the launch did not name one. Use `AgentSession.actor`
435
+ * (the authenticated crew actor) for the identity of WHO launched; `launch_actor` is an
436
+ * ADDITIONAL annotation the caller may attach (e.g. a CI job name or a studio tab id).
437
+ */
438
+ launch_actor?: string;
439
+ /**
440
+ * The number of warm seats in the chat this run was promoted from (crew#641/#642, item 5).
441
+ * ABSENT — never `null` — when the run was not promoted from a chat (`chatId` absent at launch)
442
+ * or on a daemon predating this field. A value of `1` means the intent was authored by a single
443
+ * model that could not disagree with itself.
444
+ */
445
+ chat_seat_count?: number;
446
+ /**
447
+ * Whether the chat this run was promoted from was graph-grounded at launch (crew#641/#642,
448
+ * item 5). `true` = at least one repo graph was bound and held entities; `false` = ungrounded.
449
+ * ABSENT — never `null` — when the run was not promoted from a chat or on a daemon predating
450
+ * this field.
451
+ */
452
+ chat_grounded?: boolean;
402
453
  }
403
454
 
404
455
  /** An ordered unit of work within a run (`WorkUnit`). */
@@ -885,7 +936,7 @@ export interface CoreEvent {
885
936
  seatConstraint?: string | null;
886
937
  /** `unitDistributed` (wicked-core#461): the evaluator ≠ creator fallback as a field — see
887
938
  * `UnitDistributedEvent.distinctnessFallback`. */
888
- distinctnessFallback?: 'creator_seat' | null;
939
+ distinctnessFallback?: 'creator_seat' | 'same_cli_instance' | null;
889
940
  /** `gateEvaluated` (wave 6, F-7R2-005): `true` when NOTHING gated the unit — render as UNGATED. */
890
941
  ungated?: boolean;
891
942
  /** `gateEvaluated` (wave 6): why, when `ungated`. */
@@ -970,7 +1021,9 @@ export interface CoreEvent {
970
1021
  library?: string;
971
1022
  transform?: string;
972
1023
  known?: boolean;
973
- detail?: string;
1024
+ /** `adviceDelivered` (wicked-core#602, api-types 0.40.0) spells an absent detail `null`, never an
1025
+ * absent key — widened to admit that `null`; every other producer still sends a string. */
1026
+ detail?: string | null;
974
1027
  [k: string]: unknown;
975
1028
  }
976
1029
 
@@ -1858,6 +1911,58 @@ export type WorkerToolCallDeniedEvent = {
1858
1911
  remedy: string;
1859
1912
  };
1860
1913
 
1914
+ /**
1915
+ * DES-TEAMING-001 §5.2 / §7 (wicked-core#602, S3; api-types 0.40.0) — what became of HIGH monitor
1916
+ * advice for one attempt of a unit. The one mid-turn carrier is the ACP adapter's
1917
+ * `_session/steering` request, always sent with `idleBehavior: "promptRequired"` so a steer that
1918
+ * lands after the turn settled never starts a detached turn.
1919
+ *
1920
+ * - `carrier: 'acp_steering'` + `outcome: 'injected'` — the steer reached the running turn.
1921
+ * - `outcome: 'turn_ended'` — the adapter answered `promptRequired` (the turn had settled; nothing
1922
+ * was started), or the turn ended with the steer unanswered. The advice goes to the gate.
1923
+ * - `outcome: 'refused'` — the adapter answered a JSON-RPC error (in `detail`); the turn continues.
1924
+ * - `outcome: 'not_delivered'` — the advice never rode a steer: `carrier: 'none'` when the unit's
1925
+ * carrier has no mid-turn channel (wrapped, PTY, an ACP adapter not advertising steering), or
1926
+ * `'acp_steering'` when the turn ended before the next tool-call boundary. `detail` says which.
1927
+ *
1928
+ * Every key is always present; `detail` is `null` when there is nothing to add. Spelled exactly as
1929
+ * wicked-core's `CoreEvent::to_json` emits it. `type` alias on purpose (relays through the
1930
+ * `CoreEvent`-typed seams unchanged).
1931
+ */
1932
+ export type AdviceDeliveredEvent = {
1933
+ type: 'adviceDelivered';
1934
+ session: string;
1935
+ ord: number;
1936
+ attempt: number;
1937
+ /** `f-` + 16 lowercase hex per finding; one steer may carry several. */
1938
+ findingIds: string[];
1939
+ carrier: 'acp_steering' | 'none' | (string & {});
1940
+ outcome: 'injected' | 'turn_ended' | 'refused' | 'not_delivered' | (string & {});
1941
+ detail: string | null;
1942
+ };
1943
+
1944
+ /**
1945
+ * DES-TEAMING-001 §5.3 / §7 (wicked-core#602, S3; api-types 0.40.0) — the worker's answer to one
1946
+ * DELIVERED finding, read from its final output line `ADVICE <id>: ACCEPT|DECLINE — <reason>` (the
1947
+ * last line per id wins). The worker may decline and must say why: `reason` (≤2 KB) is its
1948
+ * evidence, and may be `""` — a refusal with no evidence is recorded as exactly that. A delivered
1949
+ * finding with no line emits nothing here and is `unanswered` in the team ledger. The gate, not the
1950
+ * monitor, decides.
1951
+ */
1952
+ export type WorkerAdviceResponseEvent = {
1953
+ type: 'workerAdviceResponse';
1954
+ session: string;
1955
+ ord: number;
1956
+ attempt: number;
1957
+ findingId: string;
1958
+ disposition: 'accepted' | 'declined' | (string & {});
1959
+ reason: string;
1960
+ };
1961
+
1962
+ /** The S3 team-advice events as a discriminated union for consumers that narrow on `type`; they
1963
+ * also flow through the permissive {@link CoreEvent}. */
1964
+ export type TeamAdviceEvent = AdviceDeliveredEvent | WorkerAdviceResponseEvent;
1965
+
1861
1966
  export type GateEvidenceEvent =
1862
1967
  | EvaluatorMutatedWorktreeEvent
1863
1968
  | RepoChecksEvaluatedEvent
@@ -1964,9 +2069,12 @@ export interface UnitDistributedEvent {
1964
2069
  ord: number;
1965
2070
  /** The roster key of the assigned seat. */
1966
2071
  cli: string;
1967
- /** How the seat was chosen: the council verdict, a degrade to the first candidate, an
1968
- * evaluator ≠ creator reassignment, or a deterministic tool execution. */
1969
- routingMethod: 'council' | 'degraded' | 'evaluator_distinct' | 'tool';
2072
+ /** How the seat was chosen: `'teamed'` — the deterministic pick, no council (wicked-core#590 S5;
2073
+ * every seated unit of a new run) — an evaluator ≠ creator reassignment, or a deterministic tool
2074
+ * execution. `'council'` / `'degraded'` are no longer emitted by a new run and stay for recorded
2075
+ * frames. On `'teamed'` the council-only fields (`agreementPct`, `returned`, `seated`, `dissent`)
2076
+ * are `null`. Consumers must render an unrecognised method as "routed", never as a council. */
2077
+ routingMethod: 'council' | 'degraded' | 'evaluator_distinct' | 'tool' | 'teamed';
1970
2078
  agreementPct: number | null;
1971
2079
  /** Ballots that came back. Read against `seated`. */
1972
2080
  returned: number | null;
@@ -1995,10 +2103,16 @@ export interface UnitDistributedEvent {
1995
2103
  * never absent — the `seatConstraint` rule) from the wicked-core release carrying #461 on, but an
1996
2104
  * older engine does not send it at all, and this contract must read frames from both. Consumers
1997
2105
  * guard with `== null`, never `=== undefined`.
2106
+ *
2107
+ * `'same_cli_instance'` (wicked-core#591/#595): the unit IS on a seat distinct from every builder
2108
+ * seat, but that seat runs the SAME cli as a builder (`claude#2` grading `claude#1`) — instance
2109
+ * distinctness removes the creator's context, not the model's blind spots, so it is a degraded
2110
+ * gate and disclosed. `'creator_seat'` dominates when both would apply. Consumers must treat an
2111
+ * unrecognised value as a disclosure too, never as "distinct".
1998
2112
  */
1999
- distinctnessFallback?: 'creator_seat' | null;
2113
+ distinctnessFallback?: 'creator_seat' | 'same_cli_instance' | null;
2000
2114
  /** @deprecated api-types 0.36.0 — the engine emits `routingMethod`; removed in 0.37. */
2001
- routing_method?: 'council' | 'degraded' | 'evaluator_distinct' | 'tool';
2115
+ routing_method?: 'council' | 'degraded' | 'evaluator_distinct' | 'tool' | 'teamed';
2002
2116
  /** @deprecated api-types 0.36.0 — the engine emits `agreementPct`; removed in 0.37. */
2003
2117
  agreement_pct?: number | null;
2004
2118
  /** @deprecated api-types 0.36.0 — the engine emits `degradedReason`; removed in 0.37. */
@@ -3361,6 +3475,15 @@ export interface LaunchRunBody {
3361
3475
  * launch schema rejects the key with a 400.
3362
3476
  */
3363
3477
  revisesPr?: number;
3478
+ /**
3479
+ * Promote-from-chat linkage (crew#619; api-types 0.39.0, additive): the id of the chat this
3480
+ * run was promoted from. When present, the daemon retains that chat's conversation transcript
3481
+ * on disk for the run's lifetime, so the Continue-in-Build prefill is always reproducible
3482
+ * even if the chat is idle-reclaimed before the run finishes. Optional; omit when the launch
3483
+ * is not promoted from a chat. Check `GET /health.capabilities.chatIdOnLaunch` before sending —
3484
+ * an older daemon's strict launch schema rejects the key with a 400.
3485
+ */
3486
+ chatId?: string;
3364
3487
  /**
3365
3488
  * Retry lineage (DES-UX-001 §8.3, CREW-UX-3; api-types 0.8.0): the id of the run this
3366
3489
  * launch retries. Must name an EXISTING run id — an unknown id fails the launch (400 with
@@ -3392,6 +3515,21 @@ export interface LaunchRunBody {
3392
3515
  * `AgentSession.group_label`. Mutually exclusive with `campaignId` (both ⇒ 400).
3393
3516
  */
3394
3517
  groupLabel?: string;
3518
+ /**
3519
+ * The surface that triggered this launch (crew#632; additive). `'studio'` (web UI), `'cli'`
3520
+ * (wicked-crew CLI), or `'api'` (programmatic caller). Persisted in the `run.launched` audit
3521
+ * entry and echoed as `AgentSession.channel`. Absent ⇒ origin unknown. Check
3522
+ * `GET /health.capabilities.seatChipOnCreate` to confirm the daemon accepts the field before
3523
+ * sending — an older daemon's strict schema rejects unknown keys with a 400.
3524
+ */
3525
+ channel?: 'studio' | 'cli' | 'api';
3526
+ /**
3527
+ * An opaque caller-supplied identifier for the user or system that triggered the launch
3528
+ * (crew#632; additive). Persisted in the `run.launched` audit entry and echoed as
3529
+ * `AgentSession.launch_actor`. Absent ⇒ caller omitted it. Subject to the same daemon-version
3530
+ * guard as `channel` above.
3531
+ */
3532
+ actor?: string;
3395
3533
  }
3396
3534
 
3397
3535
  /**
@@ -4043,6 +4181,18 @@ export interface InteractiveDocCreateRequest {
4043
4181
  repo_ref?: string;
4044
4182
  /** SEVERAL subject repositories (at most 8); the union with `repo_ref`, de-duplicated. */
4045
4183
  repo_refs?: string[];
4184
+ /**
4185
+ * Per-doc council roster override (crew#631; crew ≥ 0.7.40 — check `GET /health` capabilities
4186
+ * `seatChipOnCreate` before sending). JSON-serialised `AgenticCli[]`; defaults to the daemon's
4187
+ * full roster when absent. Seat keys not present in `GET /roster` → 400.
4188
+ */
4189
+ clisJson?: string;
4190
+ /** Launch channel (crew#632). Persisted to the run's `run.launched` audit entry and served on
4191
+ * run DTOs as `channel`. ABSENT when the caller does not know the channel. */
4192
+ channel?: 'studio' | 'cli' | 'api';
4193
+ /** Launch actor (crew#632). Free-form string (≤ 256 chars) identifying the human or service
4194
+ * that triggered the launch. ABSENT when unknown. */
4195
+ actor?: string;
4046
4196
  }
4047
4197
 
4048
4198
  /**
@@ -4288,10 +4438,32 @@ export interface ChatOpenBody {
4288
4438
  /** File the chat into a project (`crew.chat` membership, attached on open) — and, when no
4289
4439
  * `repoRefs` are given, scope it to every registered `crew.repo` member of that project. */
4290
4440
  projectId?: string;
4441
+ /**
4442
+ * The scope the caller NAMES (api-types 0.39.0, studio#323 R4). Omitted ⇒ the legacy inference
4443
+ * above (`repoRefs` ⇒ `repos`, else `projectId` ⇒ `project`, else `none`) — unchanged for older
4444
+ * skins. Named, the daemon resolves exactly that kind or refuses with 400:
4445
+ * - `system` — the platform itself (daemon, seats, runs, config): NO repository and no code
4446
+ * graph. The seats have no live read of the daemon; what they know of it is what
4447
+ * the message carries. Takes no `repoRefs`; `projectId` only files the chat.
4448
+ * - `everything` — EVERY repository registered with the daemon, across all projects, as read
4449
+ * roots — never an enumerated list (no 1–32 cap). No single code graph spans
4450
+ * them, so none is bound. Takes no `repoRefs`; `projectId` only files the chat.
4451
+ * - `project` — requires `projectId`; takes no `repoRefs` (name `repo` to narrow).
4452
+ * - `repo` — requires `repoRefs`; `repos` is the same kind in its legacy spelling.
4453
+ * - `none` — the legacy unscoped chat; takes neither `projectId` nor `repoRefs`.
4454
+ */
4455
+ scopeKind?: ChatScopeRequestKind;
4291
4456
  }
4292
4457
 
4293
- /** How a chat's scope was chosen (crew#502). */
4294
- export type ChatScopeKind = 'project' | 'repos' | 'none';
4458
+ /** The scope a `POST /chats` caller may name (api-types 0.39.0, studio#323 R4). */
4459
+ export type ChatScopeRequestKind = 'system' | 'everything' | 'project' | 'repo' | 'repos' | 'none';
4460
+
4461
+ /**
4462
+ * How a chat's scope was chosen (crew#502). `system` and `everything` (api-types 0.39.0,
4463
+ * studio#323 R4) come back only for a request that named them (`ChatOpenBody.scopeKind`); a named
4464
+ * `repo` comes back as `repos`, the kind for an explicit repo list.
4465
+ */
4466
+ export type ChatScopeKind = 'system' | 'everything' | 'project' | 'repos' | 'none';
4295
4467
 
4296
4468
  /** One repository a chat's seats may read. */
4297
4469
  export interface ChatScopeRepo {
@@ -4310,7 +4482,7 @@ export interface ChatScope {
4310
4482
  kind: ChatScopeKind;
4311
4483
  /** The project the chat is filed into, when any. */
4312
4484
  projectId?: string;
4313
- /** The repositories in scope (read-only). Empty for `kind: 'none'`. */
4485
+ /** The repositories in scope (read-only). Empty for `kind: 'none'` and `kind: 'system'`. */
4314
4486
  repos: ChatScopeRepo[];
4315
4487
  /** The seats' working directory: the chat's private scratch root under the OS temp dir. */
4316
4488
  cwd: string;
@@ -4356,6 +4528,47 @@ export interface ChatSeatRefusal {
4356
4528
  source?: ChatRefusalSource;
4357
4529
  }
4358
4530
 
4531
+ /**
4532
+ * Single-seat degradation disclosure (crew#641/#650): present on `POST /chats` → 201 and on
4533
+ * `POST /chats/:id/messages` → 202 whenever exactly ONE seat is warm — refusals or not, since a
4534
+ * one-seat chat cannot disagree with itself either way. Named here so callers do not have to reason
4535
+ * about the `refused[]` array. The root cause is tracked as wicked-core#563.
4536
+ */
4537
+ export interface ChatSingleSeatDegradation {
4538
+ degraded: true;
4539
+ /** The one warm seat key (e.g. `"claude"`). */
4540
+ warmed: string;
4541
+ /**
4542
+ * The seats currently ON RECORD as refused, with each reason and source — EVIDENCE, not the
4543
+ * trigger. It describes the daemon's RECORD (what the open, or the last `POST /chats/:id/seats`,
4544
+ * observed); `warmed` describes the roster NOW, and the two are different moments.
4545
+ *
4546
+ * `[]` with `refusalsKnown: true` therefore means **no refusal is on record** — NOT "no seat was
4547
+ * ever refused": a seat re-seated through `POST /chats/:id/seats` is removed from the record when
4548
+ * it warms, and a seat RELEASED mid-session (it blew its turn budget) was never refused at all,
4549
+ * yet either can leave a chat with one warm seat and an empty record. `[]` with `refusalsKnown:
4550
+ * false` means the record is GONE — see that field.
4551
+ */
4552
+ refused: ChatSeatRefusal[];
4553
+ /**
4554
+ * Whether `refused` is the record this daemon actually holds (crew#650, review follow-up). `true`
4555
+ * on every 201 (the daemon just opened the chat) and on a 202 for a chat it still holds. `false`
4556
+ * on a 202 for a chat this daemon did not open — the engine keeps a warm session across a restart,
4557
+ * the daemon's in-memory scope index does not — where `refused: []` means THE RECORD IS GONE, not
4558
+ * that nothing was refused, and `message` says so instead of asserting either way. Absent on a
4559
+ * daemon predating this field, where `[]` was ambiguous.
4560
+ */
4561
+ refusalsKnown?: boolean;
4562
+ /**
4563
+ * Human-readable summary naming the degradation, its cause, and wicked-core#563. It states only
4564
+ * what the answering route witnessed: the 201 performed the open, so it may say the chat was
4565
+ * opened with a single seat; a 202 knows the roster NOW and the refusal record and says nothing
4566
+ * about how the chat came to look this way — the one warm seat may be the survivor of a two-seat
4567
+ * chat whose other seat was released.
4568
+ */
4569
+ message: string;
4570
+ }
4571
+
4359
4572
  /** `POST /chats` → 201. */
4360
4573
  export interface ChatOpenResponse {
4361
4574
  chatId: string;
@@ -4367,6 +4580,33 @@ export interface ChatOpenResponse {
4367
4580
  /** Every seat that was asked for or defaulted and is NOT in `seats` as warm, with its reason
4368
4581
  * (api-types 0.35.0). Empty when every seat warmed; absent on a daemon predating the field. */
4369
4582
  refused?: ChatSeatRefusal[];
4583
+ /**
4584
+ * crew#641/#650: present whenever exactly ONE seat is warm — the chat cannot disagree with
4585
+ * itself, which is equally true when nothing was refused (a chat opened with one seat on
4586
+ * purpose). ABSENT only when two or more seats are warm. Absent on a daemon predating this
4587
+ * field; a daemon between #641 and #650 emitted it only when `refused` was non-empty.
4588
+ */
4589
+ singleSeat?: ChatSingleSeatDegradation;
4590
+ }
4591
+
4592
+ /** `POST /chats/:id/messages` → 202. */
4593
+ export interface ChatMessageResponse {
4594
+ /** The seats the engine delivered the message to (warm seat keys). */
4595
+ seats: string[];
4596
+ /** The turn id stamped on every `chatDelta` / `chatReply` frame for this message. Absent on a
4597
+ * daemon predating the turn index (crew ≥ 0.7.35). */
4598
+ turnId?: string;
4599
+ /**
4600
+ * crew#641/#650: re-stated on every turn when the chat has exactly one WARM seat — decided from
4601
+ * the warm roster, never from the seats this turn reached, and never from whether refusals are
4602
+ * still on record (a restarted daemon has none and the chat is still single-seated). ABSENT when
4603
+ * two or more seats are warm. Absent on a daemon predating this field.
4604
+ *
4605
+ * This is a statement about NOW. It never describes how the chat was opened — the single warm seat
4606
+ * may be the survivor of a multi-seat chat whose other seats were refused, re-seated or released —
4607
+ * and only `POST /chats` → 201, which performed the open, says anything about that moment.
4608
+ */
4609
+ singleSeat?: ChatSingleSeatDegradation;
4370
4610
  }
4371
4611
 
4372
4612
  /**
@@ -5151,7 +5391,9 @@ export interface DiagnosticsSkillsFinding {
5151
5391
  * the configured BASE skill (`SystemSettings.baseSkillRef`) is not in the current generation —
5152
5392
  * a `warning` under `baseSkillPolicy: 'warn'` (runs proceed without the discipline directive),
5153
5393
  * an `error` under `'require'` (the engine refuses every launch at intake); cleared by a publish
5154
- * that hands it. Also carried as `DiagnosticsSkills.baseSkill.finding`. */
5394
+ * that hands it. Also carried as `DiagnosticsSkills.baseSkill.finding`; `skills.phase-skill`
5395
+ * (`warning`, crew#661) = a subsystem's phases declare a skill the published snapshot did not hold
5396
+ * when it armed, so they run without it — one per `DiagnosticsSkills.phaseSkillGaps` entry. */
5155
5397
  kind:
5156
5398
  | 'skills.fallback'
5157
5399
  | 'skills.blocked'
@@ -5159,7 +5401,8 @@ export interface DiagnosticsSkillsFinding {
5159
5401
  | 'skills.source'
5160
5402
  | 'skills.manifest'
5161
5403
  | 'skills.stale-rules'
5162
- | 'skills.base-skill';
5404
+ | 'skills.base-skill'
5405
+ | 'skills.phase-skill';
5163
5406
  severity: 'warning' | 'error';
5164
5407
  message: string;
5165
5408
  }
@@ -5193,8 +5436,40 @@ export interface DiagnosticsSkills {
5193
5436
  * when the setting is off or the seam is `disabled`. A daemon before this field omits the key
5194
5437
  * (read it as `null`). */
5195
5438
  baseSkill: BaseSkillPosture | null;
5439
+ /** Subsystems whose phases run WITHOUT a skill their workflow declares (crew#661; additive) — one
5440
+ * entry per subsystem, judged when that seam ARMED (the decision holds until the daemon restarts).
5441
+ * Each entry also rides `findings` as a `skills.phase-skill` warning. `[]` when every armed seam
5442
+ * holds its skill; ABSENT on a daemon before this field (read it as unknown, not as `[]`). */
5443
+ phaseSkillGaps?: DiagnosticsPhaseSkillGap[];
5196
5444
  }
5197
5445
 
5446
+ /**
5447
+ * One subsystem whose phases declare a skill the published snapshot did not hold when the subsystem
5448
+ * armed (crew#661) — today the interactive seams' `wicked-garden-draft` quality floor. The phases
5449
+ * run DEGRADED (no `skill_ref`, no quality floor) and every run launched on it says so in
5450
+ * `AgentSession.skill_gaps`; the engine would refuse a `skill_ref` its snapshot lacks, so the seam
5451
+ * cannot simply stamp it.
5452
+ */
5453
+ export interface DiagnosticsPhaseSkillGap {
5454
+ /** The subsystem (`interactive-draft` / `interactive-edit` / `interactive-chat`). */
5455
+ subsystem: string;
5456
+ /** The workflow id the subsystem launches. */
5457
+ workflow: string;
5458
+ /** The agent phases that declare the skill and run without it. */
5459
+ phases: string[];
5460
+ /** The declared skill (`wicked-garden-draft`). */
5461
+ skill: string;
5462
+ /** The published skills generation judged at arm time, or `null` when none was published. */
5463
+ gen: number | null;
5464
+ /** Epoch ms of the arm-time judgement. */
5465
+ armedAt: number;
5466
+ /** The fix: republish the skills snapshot from a wicked-garden that carries the skill, then restart. */
5467
+ remedy: string;
5468
+ }
5469
+
5470
+ /** A skill gap a run LAUNCHED with (`AgentSession.skill_gaps[]`, crew#661) — the arm-time gap without its timestamp. */
5471
+ export type RunSkillGap = Omit<DiagnosticsPhaseSkillGap, 'armedAt'>;
5472
+
5198
5473
  /**
5199
5474
  * The BASE skill in force for the next launch (crew#554 — the launcher half of wicked-core#468).
5200
5475
  * The engine leads EVERY agent unit's prompt with one role-keyed directive naming this skill and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-crew-api-types",
3
- "version": "0.38.0",
3
+ "version": "0.40.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",