wicked-crew-api-types 0.31.0 → 0.33.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 +423 -13
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -341,8 +341,31 @@ export interface RepoEntry {
341
341
  * Optional in the TYPE, mandatory in practice: an addon predating the field omits it, and
342
342
  * `codeGraphDb()` in the daemon's `repoPaths.ts` is where that turns into a loud error. Never
343
343
  * join this path yourself — six independent spellings is what FINDING-069 was.
344
+ *
345
+ * Since wicked-core#406 the path is `<daemon state home>/repo-graphs/<key>/estate.db` — never
346
+ * inside `root_path`; a checkout's in-tree `.codegraph/` is reported in `findings`, not adopted.
344
347
  */
345
348
  code_graph_db?: string;
349
+ /**
350
+ * Diagnostics about the checkout the engine wants shown on the repo card (wicked-core#406) —
351
+ * derived by the engine on every read like `code_graph_db`, never authoritative in the record.
352
+ * An empty array for a clean checkout; optional in the TYPE only because an addon predating the
353
+ * field omits it. Today's codes: `in_tree_code_graph_ignored` (the checkout carries a
354
+ * `.codegraph/` an older engine indexed in-tree — ignored; `path` names the directory and
355
+ * `message` says how to clear it) and `code_graph_root_unresolvable` (no repo-graph root
356
+ * resolves for this daemon, so `code_graph_db` is empty).
357
+ */
358
+ findings?: RepoFinding[];
359
+ }
360
+
361
+ /** One engine diagnostic on a registered repo (`RepoEntry.findings[]`; wicked-core#406). */
362
+ export interface RepoFinding {
363
+ /** Stable machine code (`snake_case`) a consumer switches on. */
364
+ code: string;
365
+ /** Operator-facing explanation: what was found, why it is ignored, how to clear it. */
366
+ message: string;
367
+ /** The filesystem path the finding is about, or `null` when it has none. */
368
+ path: string | null;
346
369
  }
347
370
 
348
371
  /** The run id of the onboarding run launched when a repo was registered (`GET /repos/:id/onboard`). */
@@ -567,6 +590,12 @@ export interface CoreEvent {
567
590
  denialReason?: string | null;
568
591
  /** `gateEvaluated`: the final deny-dominant decision over all layers (mirrors `gateDecided.allow`). */
569
592
  combined?: boolean;
593
+ /** `gateEvaluated` (wicked-core#431, api-types 0.33.0): WHO rendered `agentVerdict` — the council seat key
594
+ * the layer-2 judge ran under; `null` when no judge ran, and on the bus-mediated path. */
595
+ judgeCli?: string | null;
596
+ /** `gateEvaluated` (wicked-core#431): whether that judge was identity-distinct from the work's author
597
+ * (`true` = the rotation pick, `false` = the single default runner); `null` when no judge ran. */
598
+ judgeDistinct?: boolean | null;
570
599
  // sessionStarted enrichment fields (snake_case — serde wire names)
571
600
  workflow_id?: string | null;
572
601
  cli_count?: number;
@@ -665,7 +694,10 @@ export interface CoreEvent {
665
694
  /** campaignNodeStarted / campaignNodeAwaitingHuman: the node's attempt-keyed Run id. */
666
695
  runId?: string;
667
696
  // assumptionRecorded (external-transform convention) — camelCase per event_to_json
668
- kind?: string;
697
+ /** `assumptionRecorded`: the assumption kind; `councilSeatFailed`: the failure branch;
698
+ * `evaluatorToolCallDenied` (wicked-core#431, api-types 0.33.0): the ACP `toolCall.kind` — `null`
699
+ * when the agent sent none. Widened to admit that `null`; every other producer still sends a string. */
700
+ kind?: string | null;
669
701
  library?: string;
670
702
  transform?: string;
671
703
  known?: boolean;
@@ -846,7 +878,11 @@ export interface UnitDenial {
846
878
 
847
879
  /** §3 B1 — the gate's decision depth, emitted alongside `gateDecided`. `denial` is the structured
848
880
  * twin of `denialReason`: `null` when the gate approved, else the winning layer (deny-dominates) —
849
- * `worktree_guard` and `repo_checks` are the two wicked-core F-036/F-039 layers. */
881
+ * `worktree_guard` and `repo_checks` are the two wicked-core F-036/F-039 layers. `judgeCli` /
882
+ * `judgeDistinct` (wicked-core#431 / F-3R2-007, api-types 0.33.0) name WHO rendered `agentVerdict`,
883
+ * so evaluator ≠ creator is auditable from the event stream alone (compare with the unit's
884
+ * `unitDistributed.cli`). Both keys are ALWAYS present: `null` when no judge ran (`agentVerdict`
885
+ * is `null` too) and on the bus-mediated evaluator path, where the seat is not reported back. */
850
886
  export interface GateEvaluatedEvent {
851
887
  type: 'gateEvaluated';
852
888
  session: string;
@@ -862,6 +898,13 @@ export interface GateEvaluatedEvent {
862
898
  denialReason: string | null;
863
899
  denial: UnitDenial | null;
864
900
  combined: boolean;
901
+ /** The council seat key the layer-2 judge ran under (`codex`, `pi`, …) — WHO rendered
902
+ * `agentVerdict`. `null` when no judge ran, and on the bus-mediated path. */
903
+ judgeCli: string | null;
904
+ /** Whether that judge seat was IDENTITY-DISTINCT from the work's author: `true` for the rotation
905
+ * pick, `false` when the judge fell back to the single default runner (prompt-only independence).
906
+ * `null` when no judge ran or the seat is unknown. */
907
+ judgeDistinct: boolean | null;
865
908
  }
866
909
 
867
910
  /** Foundation wave: session started with enriched context. */
@@ -911,13 +954,36 @@ export interface AcpSessionStartedEvent {
911
954
  acpSessionId: string;
912
955
  }
913
956
 
914
- /** P1 — ACP unavailable or failed for a CLI; the run continues with single-shot fallback. */
957
+ /**
958
+ * `acpFallback.fallbackKind` — WHY a unit left the ACP carrier for the wrapped (single-shot) one:
959
+ * - `binary_unavailable` / `session_died` / `auth_required` — the ACP session could not be had; the
960
+ * run continues single-shot (a FAILURE of the seat's transport or account, counted by seat health);
961
+ * - `governance_requires_wrapped` — a governed unit on a seat whose ACP adapter cannot enforce input
962
+ * governance is routed to the wrapped carrier by design (crew#276);
963
+ * - `read_only_requires_wrapped` (wicked-core#431 / F-3R2-009, api-types 0.33.0) — an
964
+ * `executes_code: false` unit (an evaluator, a recon rung, a review) on an ACP seat NOT admitted to
965
+ * input governance (pi-acp, codex-acp) is routed to the wrapped carrier BEFORE any ACP turn, where
966
+ * the read-only lever is an argv fact (`--sandbox read-only` / `--exclude-tools edit,write`). No
967
+ * per-call {@link EvaluatorToolCallDeniedEvent} exists on that route — consumers must not wait for one.
968
+ * The two `*_requires_wrapped` kinds are deliberate routing, not failures — never a seat-health signal.
969
+ * Open-ended (`string & {}`) so a newer engine's kind parses in an older consumer.
970
+ */
971
+ export type AcpFallbackKind =
972
+ | 'binary_unavailable'
973
+ | 'session_died'
974
+ | 'auth_required'
975
+ | 'governance_requires_wrapped'
976
+ | 'read_only_requires_wrapped'
977
+ | (string & {});
978
+
979
+ /** P1 — ACP unavailable or failed for a CLI, or the unit was deliberately routed off ACP; the run
980
+ * continues on the wrapped carrier. `fallbackKind` says which (see {@link AcpFallbackKind}). */
915
981
  export interface AcpFallbackEvent {
916
982
  type: 'acpFallback';
917
983
  session: string;
918
984
  cliKey: string;
919
985
  reason: string;
920
- fallbackKind: string;
986
+ fallbackKind: AcpFallbackKind;
921
987
  }
922
988
 
923
989
  // ── P2 observability events ─────────────────────────────────────────────────
@@ -1066,6 +1132,17 @@ export type EvaluatorMutatedWorktreeEvent = {
1066
1132
  afterTree: string;
1067
1133
  headMoved: boolean;
1068
1134
  changed: WorktreeChangedPath[];
1135
+ /** wicked-core#431 / F-3R2-010 (api-types 0.33.0): whether the engine RESTORED the creator's tree
1136
+ * (`beforeTree`) in the worktree right after detecting the mutation — so the retry a human
1137
+ * approves runs against the VERIFIED tree, never against the evaluator's edit. When `true` a
1138
+ * {@link WorktreeRestoredEvent} follows with the discarded paths, the gate's `denialReason` says the
1139
+ * edit was discarded, and the `awaitingHuman` prompt reads "… its edit was discarded and the
1140
+ * creator's verified tree restored. Approve to retry the phase against the restored tree …" (the
1141
+ * pre-0.33.0 prompt was "confirm to retry the phase"; a card that matched the old text must
1142
+ * re-check). `false` = the restore failed or was not attempted — `restoreError` says why — and the
1143
+ * denial keeps the manual `git read-tree` remedy. */
1144
+ restored: boolean;
1145
+ restoreError: string | null;
1069
1146
  };
1070
1147
 
1071
1148
  /** One repository check the engine ran in the run's worktree (wicked-core F-039). */
@@ -1073,7 +1150,11 @@ export interface RepoCheckRun {
1073
1150
  /** `install` | `typecheck` | `lint` | `test` | `cargo-test`. */
1074
1151
  name: string;
1075
1152
  argv: string[];
1076
- /** Provenance an operator can verify: `package.json scripts.test`, `Cargo.toml`, … */
1153
+ /** Provenance an operator can verify: `package.json scripts.test`, `Cargo.toml`, … For the `install`
1154
+ * step the lockfile and WHY it ran: `package-lock.json (node_modules absent)`, `pnpm-lock.yaml (…)`,
1155
+ * `yarn.lock (…)`, `package.json (…, no lockfile)` — and, since wicked-core#431 / #433, `… (forced:
1156
+ * lockfile drift)` when the deliver lift moved a lockfile/manifest between the old base and the
1157
+ * remote tip and the re-verify re-installed (frozen lockfile, `--ignore-scripts`) before the checks. */
1077
1158
  source: string;
1078
1159
  /** The process exit code; `null` when it produced none (timed out / could not spawn). */
1079
1160
  exitCode: number | null;
@@ -1113,7 +1194,17 @@ export interface RepoCheckRun {
1113
1194
  * true`): no manifest at all, or a readable `package.json` with no string `typecheck`/`lint`/`test`
1114
1195
  * script and no `Cargo.toml`. A manifest that cannot be read or trusted still FAILS.
1115
1196
  * "Done" for a verify phase is now the exit code the engine observed, not the seat's account of
1116
- * having run the suite. `type` alias on purpose — see {@link EvaluatorMutatedWorktreeEvent}. */
1197
+ * having run the suite.
1198
+ *
1199
+ * wicked-core#431 (api-types 0.33.0): the frame ALSO arrives for the DELIVER ord — a Tool unit —
1200
+ * whenever the worktree's tree is NOT the tree the run verified when the deliver phase is about to
1201
+ * push: after a lift onto the remote tip ({@link DeliverLiftEvaluatedEvent} `outcome: 'lifted'`), on
1202
+ * a retry after a failed re-verify, after an operator's by-hand rebase, or for a run that recorded
1203
+ * no verified tree. The engine re-runs the repository's checks on the tree that would ship before
1204
+ * allowing the push (a lockfile that moved with the base forces a frozen `--ignore-scripts` install
1205
+ * first), and the deliver unit's `gateEvaluated` then carries `hasDeterministicFloor: true` with
1206
+ * this floor's `criterion`. `passed: false` there fails the deliver unit closed — nothing is pushed.
1207
+ * `type` alias on purpose — see {@link EvaluatorMutatedWorktreeEvent}. */
1117
1208
  export type RepoChecksEvaluatedEvent = {
1118
1209
  type: 'repoChecksEvaluated';
1119
1210
  session: string;
@@ -1125,9 +1216,155 @@ export type RepoChecksEvaluatedEvent = {
1125
1216
  skipped: string[];
1126
1217
  };
1127
1218
 
1128
- /** The gate-evidence events (wicked-core F-036/F-039) as a discriminated union for consumers that
1129
- * narrow on `type`; they also flow through the permissive {@link CoreEvent}. */
1130
- export type GateEvidenceEvent = EvaluatorMutatedWorktreeEvent | RepoChecksEvaluatedEvent;
1219
+ // ── wicked-core#431 gate / deliver evidence (F-3R2-013 / -010 / -009; api-types 0.33.0) ──────────
1220
+
1221
+ /** wicked-core#431 / F-3R2-010 — the engine PUT THE CREATOR'S TREE BACK after an `executes_code:
1222
+ * false` phase changed it ({@link EvaluatorMutatedWorktreeEvent} with `restored: true`): the run
1223
+ * branch's `HEAD` is back at the baseline commit when the phase had moved it (`head`), the index and
1224
+ * working tree match `tree` (the baseline the actor snapshotted at dispatch), and every path the
1225
+ * phase ADDED is deleted. `discarded` names exactly what the evaluator's edit was — the same list the
1226
+ * mutation event carried as `changed` — so the ledger shows what was thrown away, and `suggestionRef`
1227
+ * says where the discarded edit was pinned so it can be read back. Emitted at the gate fold, AFTER
1228
+ * `evaluatorMutatedWorktree` and BEFORE `gateEvaluated`. `type` alias on purpose — see
1229
+ * {@link EvaluatorMutatedWorktreeEvent}. */
1230
+ export type WorktreeRestoredEvent = {
1231
+ type: 'worktreeRestored';
1232
+ session: string;
1233
+ ord: number;
1234
+ attempt: number;
1235
+ /** The seat that ran the unit. */
1236
+ cli: string;
1237
+ /** The workflow phase id (`verify`, `adversarial-review`, …). */
1238
+ phase: string;
1239
+ /** The tree id the worktree was restored to (the creator's baseline). */
1240
+ tree: string;
1241
+ /** The commit `HEAD` was reset to when the phase had moved it; `null` when it had not. */
1242
+ head: string | null;
1243
+ discarded: WorktreeChangedPath[];
1244
+ /** Where the DISCARDED tree was pinned so the edit is never lost (wicked-core#433 review
1245
+ * F-433-008 — the seam wicked-core#432's suggestion lane reads from):
1246
+ * `refs/wicked/suggestions/<run>/<ord>/<attempt>`, a commit whose tree is the mutation event's
1247
+ * `afterTree`. `null` when the pin failed (the discarded content is then only a gc-prunable
1248
+ * dangling tree). */
1249
+ suggestionRef: string | null;
1250
+ };
1251
+
1252
+ /**
1253
+ * `deliverLiftEvaluated.outcome` — what the engine's pre-push lift onto the remote default branch did:
1254
+ * - `unchanged` — the base was already the remote tip; the deliver rebase is a no-op and the tree the
1255
+ * checks verified is the tree that ships;
1256
+ * - `lifted` — the remote moved; the run's changes were re-applied onto its tip in the worktree
1257
+ * (`treeBefore` → `treeAfter`) and the repository's own checks were RE-RUN on the lifted tree (a
1258
+ * {@link RepoChecksEvaluatedEvent} for this ord) before the push was allowed;
1259
+ * - `conflict` — the lift would conflict in `conflicts`; the worktree was left exactly as verified and
1260
+ * the deliver unit FAILED with a `deliver: LIFT-CONFLICT — …` remedy — nothing rebased or pushed
1261
+ * (crew reads that marker as a recoverable strand, `delivery: 'stranded'`);
1262
+ * - `skipped` — the lift could not be DECIDED (no remote / fetch failed / git too old / a branch
1263
+ * carrying its own commits); the worktree was never touched and the deliver script's own rebase
1264
+ * stands, as before;
1265
+ * - `failed` — the lift was decided but its APPLICATION failed part-way; the worktree may hold a
1266
+ * partial state, the deliver unit fails closed, nothing was pushed.
1267
+ * Open-ended (`string & {}`) so a newer engine's outcome parses in an older consumer.
1268
+ */
1269
+ export type DeliverLiftOutcome =
1270
+ | 'unchanged'
1271
+ | 'lifted'
1272
+ | 'conflict'
1273
+ | 'skipped'
1274
+ | 'failed'
1275
+ | (string & {});
1276
+
1277
+ /** wicked-core#431 / F-3R2-013 — before the run's `deliver` Tool phase pushed, the engine LIFTED the
1278
+ * run's work onto the remote default branch's CURRENT tip (in memory, `git merge-tree`) and said what
1279
+ * that did (see {@link DeliverLiftOutcome}). Emitted once per deliver attempt, BEFORE the deliver
1280
+ * unit's `repoChecksEvaluated` (when a re-verify ran — the tree that would ship is not the recorded
1281
+ * verified tree) / `stepFailed` (conflict, failed, or a failed re-verify) / `unitDone`. The deliver
1282
+ * gate never pushes a tree that was not verified: on `unchanged` / `lifted` the deliver command
1283
+ * receives the verified remote-tip commit as `WICKED_DELIVER_VERIFIED_BASE` and crew's script refuses
1284
+ * to rebase past it (`deliver: BASE MOVED since verification — …`). `type` alias on purpose. */
1285
+ export type DeliverLiftEvaluatedEvent = {
1286
+ type: 'deliverLiftEvaluated';
1287
+ session: string;
1288
+ ord: number;
1289
+ attempt: number;
1290
+ outcome: DeliverLiftOutcome;
1291
+ /** The remote default ref the lift targets (`origin/main`), when one was resolved. */
1292
+ baseRef: string | null;
1293
+ /** The run branch's `HEAD` before the lift (the base the work was verified on). */
1294
+ baseBefore: string | null;
1295
+ /** The remote tip the work now sits on (`lifted`) or would have (`conflict`). */
1296
+ baseAfter: string | null;
1297
+ treeBefore: string | null;
1298
+ treeAfter: string | null;
1299
+ /** The paths the lift would conflict in (`conflict`); empty otherwise. */
1300
+ conflicts: string[];
1301
+ /** Why the lift was skipped / failed, or a disclosed degradation (a failed fetch); `null` otherwise. */
1302
+ note: string | null;
1303
+ };
1304
+
1305
+ /** wicked-core#431 / F-3R2-009 — an `executes_code: false` phase (an evaluator, a recon rung, a
1306
+ * review) asked to run a WRITE-CLASS tool (edit/write/delete/move, by ACP `kind` or by tool name) and
1307
+ * the engine REFUSED the call at the carrier's permission boundary, answering the agent's own reject
1308
+ * option. Fires on the ACP carrier (`carrier: 'acp'`) for a seat whose adapter is ADMITTED to input
1309
+ * governance (claude, opencode). A guarded unit on an UNADMITTED ACP seat never starts an ACP turn —
1310
+ * it is rerouted with `acpFallback {fallbackKind: 'read_only_requires_wrapped'}` and no per-call
1311
+ * event exists on that route. A refused call costs the seat one tool call, not the phase a retry;
1312
+ * the worktree guard ({@link EvaluatorMutatedWorktreeEvent}) remains the backstop for what a
1313
+ * permission boundary cannot see (a `bash` heredoc). `type` alias on purpose. */
1314
+ export type EvaluatorToolCallDeniedEvent = {
1315
+ type: 'evaluatorToolCallDenied';
1316
+ session: string;
1317
+ ord: number;
1318
+ attempt: number;
1319
+ /** The registry seat key (ACP-path convention, as `governanceUnenforced`). */
1320
+ cli: string;
1321
+ /** The carrier the refusal happened on — `'acp'` today. Open-ended for a future carrier. */
1322
+ carrier: 'acp' | (string & {});
1323
+ /** The tool the agent asked for, as it named it (`edit`, `write`, `str_replace_based_edit_tool`, …). */
1324
+ tool: string;
1325
+ /** The ACP `toolCall.kind` when the agent sent one (`edit`, `delete`, `move`, …); `null` otherwise. */
1326
+ kind: string | null;
1327
+ /** The path the call targeted, when its arguments carried one; `null` otherwise. */
1328
+ path: string | null;
1329
+ reason: string;
1330
+ };
1331
+
1332
+ /** wicked-core#431 / F-3R2-013 — how the run's BASE commit was chosen when its worktree was minted:
1333
+ * the engine fetches `origin` and, when the registered clone's `HEAD` is strictly behind the remote
1334
+ * default branch's tip, bases the run on that tip — so the worker starts from the current code and
1335
+ * the deliver lift has nothing to move. `lifted: true` = the base moved off the clone's `HEAD` by
1336
+ * `behind` commits; `false` = `HEAD` was already the tip, or was ahead of / diverged from it (local
1337
+ * unpushed work — kept, `note` says so), or no remote default ref resolved (`baseRef: null`).
1338
+ * Emitted once per freshly minted worktree, BEFORE `worktreeReady`; a resumed run reuses its live
1339
+ * worktree and emits nothing. Session-level (no `ord`). `type` alias on purpose. */
1340
+ export type RunBaseResolvedEvent = {
1341
+ type: 'runBaseResolved';
1342
+ session: string;
1343
+ /** The remote default ref (`origin/main`), or `null` when none could be resolved. */
1344
+ baseRef: string | null;
1345
+ /** The commit the run worktree was minted from. */
1346
+ baseCommit: string;
1347
+ /** The registered clone's `HEAD` at mint time. */
1348
+ localHead: string;
1349
+ /** How many commits `localHead` was behind `baseRef`; `0` when not behind or unknown. */
1350
+ behind: number;
1351
+ /** Whether `git fetch origin` succeeded (a failed fetch is disclosed in `note`, cached refs used). */
1352
+ fetched: boolean;
1353
+ lifted: boolean;
1354
+ note: string | null;
1355
+ };
1356
+
1357
+ /** The gate-evidence events (wicked-core F-036/F-039, extended by wicked-core#431 — api-types 0.33.0
1358
+ * added {@link WorktreeRestoredEvent}, {@link DeliverLiftEvaluatedEvent} and
1359
+ * {@link EvaluatorToolCallDeniedEvent}) as a discriminated union for consumers that narrow on `type`;
1360
+ * they also flow through the permissive {@link CoreEvent}. {@link RunBaseResolvedEvent} is
1361
+ * session-level evidence and stands on its own. */
1362
+ export type GateEvidenceEvent =
1363
+ | EvaluatorMutatedWorktreeEvent
1364
+ | RepoChecksEvaluatedEvent
1365
+ | WorktreeRestoredEvent
1366
+ | DeliverLiftEvaluatedEvent
1367
+ | EvaluatorToolCallDeniedEvent;
1131
1368
 
1132
1369
  // ── P2 decisions-full observability events (wicked-core EVT-001/012/013) ────
1133
1370
 
@@ -3070,13 +3307,105 @@ export interface ProjectPrompts {
3070
3307
  prompts: InteractionRequest[];
3071
3308
  }
3072
3309
 
3073
- /** `POST /chats` body (gains `projectId` with DES-PROJECT-001). */
3310
+ /**
3311
+ * `POST /chats` body (gains `projectId` with DES-PROJECT-001; `repoRefs` and the SCOPE semantics
3312
+ * with crew#502).
3313
+ *
3314
+ * A chat is SCOPED (crew#502, F-067): its seats run in a private scratch root — never a repo and
3315
+ * never the daemon's working directory — with the scoped repositories as read roots and, where a
3316
+ * graph can be bound, a READ-ONLY wicked-estate MCP over it (the grounding governed runs get). The
3317
+ * scope is: the explicit `repoRefs` (plus the legacy single `repoRef`, merged in) when given, else
3318
+ * ALL of `projectId`'s registered `crew.repo` members, else nothing (the seats see only their
3319
+ * scratch root). The resolved scope comes back as {@link ChatOpenResponse.scope}.
3320
+ */
3074
3321
  export interface ChatOpenBody {
3075
3322
  chatId?: string;
3076
3323
  clis?: string[];
3324
+ /** One repo in scope — the legacy spelling; merged into `repoRefs`. */
3077
3325
  repoRef?: string;
3078
- /** File the chat into a project (`crew.chat` membership, attached on open). */
3326
+ /** The repos in scope, by registry id or name (1–32). With `projectId` the PROJECT graph grounds
3327
+ * them; without it a single repo's own graph does, and several repos get no graph. */
3328
+ repoRefs?: string[];
3329
+ /** File the chat into a project (`crew.chat` membership, attached on open) — and, when no
3330
+ * `repoRefs` are given, scope it to every registered `crew.repo` member of that project. */
3331
+ projectId?: string;
3332
+ }
3333
+
3334
+ /** How a chat's scope was chosen (crew#502). */
3335
+ export type ChatScopeKind = 'project' | 'repos' | 'none';
3336
+
3337
+ /** One repository a chat's seats may read. */
3338
+ export interface ChatScopeRepo {
3339
+ id: string;
3340
+ name: string;
3341
+ /** The registered root path — the read root the seats are pointed at. */
3342
+ rootPath: string;
3343
+ }
3344
+
3345
+ /**
3346
+ * What a chat's seats can see — decided at `POST /chats`, stated to the seats in their scratch
3347
+ * root's `AGENTS.md` / `CLAUDE.md`, and returned to the caller so the UI can show it. Additive:
3348
+ * older skins ignore it.
3349
+ */
3350
+ export interface ChatScope {
3351
+ kind: ChatScopeKind;
3352
+ /** The project the chat is filed into, when any. */
3079
3353
  projectId?: string;
3354
+ /** The repositories in scope (read-only). Empty for `kind: 'none'`. */
3355
+ repos: ChatScopeRepo[];
3356
+ /** The seats' working directory: the chat's private scratch root under the OS temp dir. */
3357
+ cwd: string;
3358
+ /** Whether a READ-ONLY estate MCP over a code graph is attached, and why / why not. `repoLabel`
3359
+ * is the estate label the project graph indexes the (single) scoped repo under, when the
3360
+ * binding was repo-bound — informational; the engine binds by graph path. */
3361
+ graph: { bound: boolean; reason: string; repoLabel?: string };
3362
+ /** `crew.repo` members of the project whose registry record is gone — named, not readable. */
3363
+ dangling: string[];
3364
+ }
3365
+
3366
+ /** One seat's warm-up outcome on `POST /chats`. */
3367
+ export interface ChatSeatOutcome {
3368
+ cliKey: string;
3369
+ ok: boolean;
3370
+ error?: string;
3371
+ }
3372
+
3373
+ /** `POST /chats` → 201. */
3374
+ export interface ChatOpenResponse {
3375
+ chatId: string;
3376
+ seats: ChatSeatOutcome[];
3377
+ /** The resolved scope (crew#502). */
3378
+ scope: ChatScope;
3379
+ /** Present when the chat opened but its `crew.chat` filing into `projectId` failed. */
3380
+ projectAttachError?: string;
3381
+ }
3382
+
3383
+ /** One live chat on `GET /chats` (FINDING-027 gap 4; scope fields with crew#502). */
3384
+ export interface ChatSummary {
3385
+ chatId: string;
3386
+ /** The seats currently warm, sorted. */
3387
+ seats: string[];
3388
+ /** Seconds since the chat's last open/ensure/turn; `null` when it has no activity stamp. */
3389
+ idleSecs: number | null;
3390
+ /** The seats' working directory as the engine recorded it; absent on an engine predating scope. */
3391
+ cwd?: string | null;
3392
+ /** The estate graph the seats' read-only estate MCP is bound to; `null` ⇒ none. */
3393
+ codeGraphDb?: string | null;
3394
+ /** The repository roots in scope. */
3395
+ readRoots?: string[];
3396
+ }
3397
+
3398
+ /** `GET /chats` → 200. */
3399
+ export interface ChatListResponse {
3400
+ chats: ChatSummary[];
3401
+ }
3402
+
3403
+ /** `GET /chats/:id` → 200. */
3404
+ export interface ChatDetailResponse {
3405
+ chatId: string;
3406
+ seats: string[];
3407
+ /** The scope recorded at open; `null` for a chat this daemon did not open (or after a restart). */
3408
+ scope: ChatScope | null;
3080
3409
  }
3081
3410
 
3082
3411
  // ── Project code graph (DES-PROJECT-001; the co-located multi-repo graph) ──────
@@ -3616,7 +3945,9 @@ export interface AcpCliDiagnostics {
3616
3945
  sessionsStarted: number;
3617
3946
  /** Count of `acpFallback` events (ACP unavailable/failed; run continued single-shot). */
3618
3947
  fallbacks: number;
3619
- /** Fallback counts by `fallbackKind` (`session_died`, `auth_required`, `binary_unavailable`, …). */
3948
+ /** Fallback counts by `fallbackKind` (`session_died`, `auth_required`, `binary_unavailable`, and the
3949
+ * two deliberate reroutes `governance_requires_wrapped` / `read_only_requires_wrapped` — see
3950
+ * {@link AcpFallbackKind}). */
3620
3951
  fallbackKinds: Record<string, number>;
3621
3952
  /** Epoch ms of the newest `acpSessionStarted`, or `null` when none recorded. */
3622
3953
  lastStartedTs: number | null;
@@ -3638,13 +3969,92 @@ export interface AcpDiagnostics {
3638
3969
  export interface DiagnosticsResponse {
3639
3970
  components: DiagnosticsComponents;
3640
3971
  daemon: DiagnosticsDaemon;
3641
- /** `core.db` + sidecars + the events dir (as a total), sorted by name. */
3972
+ /** `core.db` + sidecars + the events dir (as a total), sorted by name, followed by one entry per
3973
+ * repo code graph under the state home (`repo-graphs/<key>/estate.db`, key-sorted;
3974
+ * wicked-core#406). */
3642
3975
  stores: DiagnosticsStoreFile[];
3643
3976
  /** Bounded tail of the daemon's own error-level log lines, newest first. */
3644
3977
  recentErrors: DiagnosticsRecentError[];
3645
3978
  acp: AcpDiagnostics;
3646
3979
  /** The skills seam's last outcome (api-types 0.28.0) — see `DiagnosticsSkills`. */
3647
3980
  skills: DiagnosticsSkills;
3981
+ /** Whether the engine's governance evidence is LANDING (api-types 0.31.0, crew#495) — see `DiagnosticsGovernance`. */
3982
+ governance: DiagnosticsGovernance;
3983
+ }
3984
+
3985
+ // ── Diagnostics — governance store + dead letters (api-types 0.31.0, crew#495 / F-022) ─────────
3986
+ //
3987
+ // The engine's emit seam writes every cross-product `wicked.*` event — conformance claims and
3988
+ // decisions, phase transitions, the steering-rule lifecycle — onto the shared estate store named
3989
+ // by `WICKED_ESTATE_DB`, or, when it cannot, spools the event to an NDJSON dead-letter outbox
3990
+ // (`WICKED_APPS_EMIT_DEADLETTER`). `serve` now resolves that store (`--governance-db` /
3991
+ // `WICKED_CREW_GOVERNANCE_DB` › an inherited `WICKED_ESTATE_DB` › `<core db>.governance/
3992
+ // governance.db`) and keeps the outbox under the state home (`<core db>.governance/
3993
+ // emit-outbox.ndjson`), never under HOME; this block is the read-only account of both.
3994
+
3995
+ /** Which rule chose the store: the flag, crew's env override, the engine's own inherited
3996
+ * `WICKED_ESTATE_DB`, or the default sidecar of the core db. */
3997
+ export type DiagnosticsGovernanceStoreSource = 'flag' | 'env-crew' | 'env-estate' | 'core-db-sidecar';
3998
+
3999
+ /** The store the engine's emit seam writes governance events to. */
4000
+ export interface DiagnosticsGovernanceStore {
4001
+ /** The store as exported to the engine — an absolute SQLite path, or `:memory:`. The emit seam is SQLite-only,
4002
+ * so a URL spec (`postgres://…`) is refused at boot and never appears here. */
4003
+ path: string;
4004
+ source: DiagnosticsGovernanceStoreSource;
4005
+ }
4006
+
4007
+ /** EVENT records on the governance store. Counted through the engine binding; an engine without
4008
+ * it answers `null` for both — never a fabricated 0. */
4009
+ export interface DiagnosticsGovernanceRecords {
4010
+ /** Event records on the store right now (short-TTL), or `null` when the engine cannot count. */
4011
+ total: number | null;
4012
+ /** Records landed since this daemon's API came up (`total − baseline`; the baseline is taken when the routes
4013
+ * register, after the engine has booted, so its boot-time emits are in the baseline), or `null` when either
4014
+ * side is unknown. */
4015
+ sinceBoot: number | null;
4016
+ }
4017
+
4018
+ /** The dead-letter outbox, folded (streamed, size-capped). */
4019
+ export interface DiagnosticsGovernanceDeadletters {
4020
+ /** The outbox this daemon exports to the engine; `null` when no store was resolved (library boot). */
4021
+ path: string | null;
4022
+ /** Entries in the outbox — 0 is the good answer. A floor when `truncated`. */
4023
+ count: number;
4024
+ /** Entries per event type (`wicked.crew.governance.conformance_recorded`, …); overflow folds into `other`. */
4025
+ byType: Record<string, number>;
4026
+ /** Entries per reason bucket — the engine's reason text before its first `:` (`no shared store (WICKED_ESTATE_DB unset)`,
4027
+ * `open shared store failed`, `store write failed`). */
4028
+ byReason: Record<string, number>;
4029
+ /** Entries carrying the engine's `ts` (epoch ms; written by wicked-core builds that stamp spooled records). */
4030
+ timestamped: number;
4031
+ /** Entries without a timestamp (a pre-stamp engine, or an unparseable line) — counted, never given an invented time. */
4032
+ untimestamped: number;
4033
+ /** Epoch ms of the oldest / newest timestamped entry, or `null` when none carries one. */
4034
+ oldestTs: number | null;
4035
+ newestTs: number | null;
4036
+ /** `true` when the fold stopped at its byte cap — `count` is then a floor. */
4037
+ truncated: boolean;
4038
+ /** The pre-fix outbox under HOME (`~/.something-wicked/wicked-apps/emit-outbox.ndjson`) when it exists and is
4039
+ * non-empty — events earlier daemons on this host spooled there; `null` otherwise. Reported, never written. */
4040
+ legacyOutbox: { path: string; bytes: number } | null;
4041
+ }
4042
+
4043
+ /** One governance finding. `governance.store` (error) = no store resolved, every emit dead-letters;
4044
+ * `governance.deadletter` (error) = the outbox holds entries; `governance.legacy-outbox` (warning) =
4045
+ * the pre-fix HOME outbox exists. Every message names the replay command. */
4046
+ export interface DiagnosticsGovernanceFinding {
4047
+ kind: 'governance.store' | 'governance.deadletter' | 'governance.legacy-outbox';
4048
+ severity: 'warning' | 'error';
4049
+ message: string;
4050
+ }
4051
+
4052
+ /** `GET /diagnostics` → `governance` (api-types 0.31.0). */
4053
+ export interface DiagnosticsGovernance {
4054
+ store: DiagnosticsGovernanceStore | null;
4055
+ records: DiagnosticsGovernanceRecords;
4056
+ deadletters: DiagnosticsGovernanceDeadletters;
4057
+ findings: DiagnosticsGovernanceFinding[];
3648
4058
  }
3649
4059
 
3650
4060
  /** The skills seam's state as `GET /diagnostics` reports it (skills keystone, api-types 0.28.0). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-crew-api-types",
3
- "version": "0.31.0",
3
+ "version": "0.33.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",