wicked-crew-api-types 0.19.0 → 0.25.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 +370 -18
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -197,9 +197,14 @@ export interface AgentSession {
197
197
  *
198
198
  * - `'delivered'` — a PR was opened for this run (by the deliver phase, or post-hoc via
199
199
  * `POST /runs/:id/deliver`); `deliverUrl` carries the PR URL.
200
- * - `'stranded'` — a COMPLETED repo-scoped run with no recorded PR whose worktree still
201
- * exists on disk AND carries work: reviewable work nobody lifted. Derived honestly for
202
- * OLD runs too — records written before this field existed strand exactly the same way.
200
+ * - `'stranded'` — reviewable work nobody lifted, reached two ways: a COMPLETED repo-scoped
201
+ * run with no recorded PR whose worktree still exists on disk AND carries work (derived
202
+ * honestly for OLD runs too — records written before this field existed strand the same
203
+ * way); OR (crew#418) a run whose deliver phase hit a LIFT collision — a rebase conflict or
204
+ * non-fast-forward push — which the daemon reinterprets from the engine's `failed` to
205
+ * `completed`+`stranded`: its work is committed on the `wicked/<id>` branch (the engine
206
+ * reaps the now-clean worktree, but never the branch), recoverable via `POST /runs/:id/
207
+ * deliver`, which stands a throwaway worktree back up from that branch to lift it.
203
208
  * - `'vacuous'` — a COMPLETED repo-scoped run whose surviving worktree carries NO
204
209
  * contribution at all (crew#311: nothing uncommitted, no run-branch commit — units all
205
210
  * reached "done" while producing nothing). There is nothing to deliver; the recovery is a
@@ -250,6 +255,33 @@ export interface AgentSession {
250
255
  * `GET /campaigns`.
251
256
  */
252
257
  group_label?: string;
258
+ /**
259
+ * When this run was LAUNCHED — unix SECONDS (home command-center run metrics; api-types 0.24.0).
260
+ * Daemon-derived at DTO assembly on BOTH `GET /runs` and `GET /runs/:id` from the `run.launched`
261
+ * audit entry's timestamp (the daemon's durable system-of-record for run provenance — task #88),
262
+ * joined exactly like {@link retry_of} / {@link guidance} and hydrated from the SAME trail scan
263
+ * at boot, so it survives a daemon restart.
264
+ *
265
+ * This is the ONE launch instant the daemon records: "created" and "started" are the SAME event
266
+ * here — the engine's `AgentSession` (wicked-core `domain.rs`) carries no launch time, so there
267
+ * is no separate queued-vs-started split to expose. Unlocks time-bucketed KPI deltas and a real
268
+ * 7/30/90-day range on the home dashboard.
269
+ *
270
+ * ABSENT — never `null`, never fabricated — when the daemon has no `run.launched` entry for the
271
+ * run: a run launched OFF the `POST /runs` path (a repo's onboarding run, a campaign's own
272
+ * DAG-node runs), a run predating this field, or a `--db`-isolated daemon reading a trail that
273
+ * never saw the launch. Read with `typeof === 'number'`; a bucketed KPI or a 7/30/90-day range
274
+ * must EXCLUDE an undated run, never date it with a fabricated now.
275
+ *
276
+ * COST (deferred, not faked): a per-run cost/spend figure is deliberately NOT joined onto this
277
+ * DTO. Cost exists only on the per-unit {@link CliUsageEvent} (`costUsd`), streamed over `/ws`
278
+ * and never accumulated per run daemon-side — a reliable per-run total would require replaying
279
+ * the durable event log per run on this hot path (the unbounded cost the GET /runs delivery-cache
280
+ * architecture forbids) or a new live cliUsage accumulator plus a durable per-run store. A burn
281
+ * chart should sum `cliUsage.costUsd` from the live `/ws` stream (or `GET /runs/:id/events`) for
282
+ * now; a joined `AgentSession.cost` is a follow-up once that store exists.
283
+ */
284
+ created_at?: number;
253
285
  }
254
286
 
255
287
  /** An ordered unit of work within a run (`WorkUnit`). */
@@ -425,6 +457,13 @@ export interface GateInfo {
425
457
  prompt: string;
426
458
  lifecycle: string;
427
459
  receivedAt: string;
460
+ /**
461
+ * Refusal-detection warning (issue #419, api-types 0.20.0). Present ONLY when the gate prompt
462
+ * reads as a pure sandbox/tool refusal — the worker reported it could not act, with no sign of
463
+ * productive work — so an operator does not approve a refusal as if it were work. Additive and
464
+ * advisory: it never gates a decision, and is omitted entirely on a normal gate.
465
+ */
466
+ refusal?: { matched: boolean; reason: string };
428
467
  }
429
468
 
430
469
  /** Approve / reject payload for the steering gate (`POST /runs/:id/gate`). On a
@@ -436,6 +475,16 @@ export interface GateDecision {
436
475
  amend?: string;
437
476
  }
438
477
 
478
+ /**
479
+ * Body of `POST /runs/:id/reassign` — the manual operator lever that reassigns a wedged run's
480
+ * cursor unit through the same engine path the stall-watchdog's automatic escalation uses
481
+ * (crew#442). `cli` omitted lets the engine's council re-pick the seat; when present it must be
482
+ * a seat in the run's own pool (`SessionView.clis`) or the route answers 400.
483
+ */
484
+ export interface ReassignRequest {
485
+ cli?: string;
486
+ }
487
+
439
488
  /**
440
489
  * A CoreEvent frame as delivered verbatim over `/ws` — a tagged-JSON object
441
490
  * discriminated on `type` (wicked-core-ts `event_to_json`). The named optional
@@ -531,7 +580,15 @@ export interface CoreEvent {
531
580
  updatedDescription?: string;
532
581
  // unitOutputCaptured (EVT-013)
533
582
  outputBytes?: number;
534
- stepStatus?: 'ok' | 'failed' | 'cancelled';
583
+ /**
584
+ * How the worker step finished. `'elicitation_failed'` (DES-002) and `'timed_out'` (perf#4 —
585
+ * the ENGINE's own turn ceiling, `WICKED_UNIT_TIMEOUT_SECS`) widen the original trio.
586
+ * `'timed_out'` vs `'cancelled'` is THE wire distinction between the platform's deadline and
587
+ * an operator cancel: automation may key recovery on `'timed_out'`, and must treat
588
+ * `'cancelled'` as final. Older engines never send the newer values — consumers keying on
589
+ * them degrade to doing nothing, which is the safe direction.
590
+ */
591
+ stepStatus?: 'ok' | 'failed' | 'cancelled' | 'elicitation_failed' | 'timed_out';
535
592
  /** `unitOutputDelta` (api-types 0.5.1): one streamed chunk of a worker's live output text. */
536
593
  text?: string;
537
594
  // unitPlanned enrichment fields — the wire spelling is camelCase (event_to_json);
@@ -649,13 +706,15 @@ export type WorkerStalledFrame = {
649
706
 
650
707
  /**
651
708
  * The stall watchdog's ESCALATION frame (crew#341; api-types 0.18.0). DAEMON-SYNTHETIC, emitted
652
- * only when escalation is armed (`SystemSettings.workerStallEscalateMinutes` > 0 — OFF by
653
- * default) and a detected stall stays silent past that threshold. Reports what the watchdog DID
654
- * and how it ended, one escalation per quiet period:
709
+ * only when escalation is armed (`SystemSettings.workerStallEscalateMinutes` > 0 — ON by default
710
+ * as of perf#4, default 30 minutes; an explicit `0` disarms) and a detected stall stays silent
711
+ * past that threshold. Reports what the watchdog DID and how it ended, one escalation per quiet
712
+ * period:
655
713
  *
656
- * - `action: 'reassign'` — the wedged cursor unit was recycled in place (engine `reassignUnit`:
657
- * the stale turn is superseded, the session closed, the unit re-dispatched; queued operator
658
- * injects survive into the fresh turn). `outcome: 'ok' | 'failed' | 'exhausted'`.
714
+ * - `action: 'reassign'` — the wedged cursor unit was recycled (engine `reassignUnit`: the stale
715
+ * turn is superseded, the session closed, the unit re-dispatched; queued operator injects
716
+ * survive into the fresh turn), routed to a DIFFERENT seat from the run's pool when one is
717
+ * available (perf#4) and in place otherwise. `outcome: 'ok' | 'failed' | 'exhausted'`.
659
718
  * - `action: 'notify'` — surface loudly without touching the run (the fail-loud rung).
660
719
  *
661
720
  * `needsYou: true` marks the frames a human should act on (failed / exhausted / notify).
@@ -675,8 +734,14 @@ export type WorkerStallEscalatedFrame = {
675
734
  outcome: 'ok' | 'failed' | 'exhausted';
676
735
  /** True when a human should look; false = the platform recovered on its own. */
677
736
  needsYou: boolean;
678
- /** action `reassign`: the seat the unit was re-dispatched to, when known. */
737
+ /** action `reassign`: the seat the unit was re-dispatched to, when known. As of perf#4 this
738
+ * is the failover TARGET — a different seat from the run's pool when one exists, else the
739
+ * stalled seat recycled in place. */
679
740
  cli?: string;
741
+ /** action `reassign` (perf#4, additive): the seat that was stalled and reassigned AWAY from,
742
+ * when the watchdog knew it. Equal to `cli` on a single-seat in-place recycle. Absent on
743
+ * frames from daemons predating the field. */
744
+ previousCli?: string;
680
745
  /** action `reassign`: automatic reassigns consumed for this run, this one included. */
681
746
  escalations?: number;
682
747
  /** outcome `failed`: bounded excerpt of what the recovery call threw. */
@@ -939,8 +1004,10 @@ export interface UnitReworkAmendedEvent {
939
1004
  }
940
1005
 
941
1006
  /** P2 — a worker's ApplyStepResult arrived and output is ready to be gated. Fires before GateDecided.
942
- * `outputBytes` is the byte length of the worker's output; `stepStatus` is "ok"/"failed"/"cancelled";
943
- * `governed` reflects whether the runner armed input governance for this unit. */
1007
+ * `outputBytes` is the byte length of the worker's output; `stepStatus` is "ok" / "failed" /
1008
+ * "cancelled" / "elicitation_failed" (DES-002) / "timed_out" (perf#4 — the engine's own turn
1009
+ * ceiling, kept apart from "cancelled" so an operator cancel is never mistaken for a platform
1010
+ * timeout); `governed` reflects whether the runner armed input governance for this unit. */
944
1011
  export interface UnitOutputCapturedEvent {
945
1012
  type: 'unitOutputCaptured';
946
1013
  session: string;
@@ -948,7 +1015,7 @@ export interface UnitOutputCapturedEvent {
948
1015
  attempt: number;
949
1016
  /** Byte length of the worker's raw output — distinguishes 0-byte from 8 MB truncated. */
950
1017
  outputBytes: number;
951
- stepStatus: 'ok' | 'failed' | 'cancelled';
1018
+ stepStatus: 'ok' | 'failed' | 'cancelled' | 'elicitation_failed' | 'timed_out';
952
1019
  governed: boolean;
953
1020
  }
954
1021
 
@@ -1095,6 +1162,21 @@ export interface ConformanceRule {
1095
1162
  obligations?: string[];
1096
1163
  /** The frozen acceptance-criteria text (becomes a claim's `criteria` when the rule decides a gate). */
1097
1164
  criteria?: string;
1165
+ /**
1166
+ * Unix-SECONDS timestamp of when this rule FIRST entered the store — the "added" time the Steering
1167
+ * surface sorts + date-filters on (NOT the latest-edit time), stamped once by the engine on first
1168
+ * create and preserved across updates (api-types 0.23.0).
1169
+ *
1170
+ * WIRED-BUT-PENDING A CORE-TS BUMP: the field exists on the engine's `ConformanceRule`
1171
+ * (wicked-core `conformance.rs`, serialized with `skip_serializing_if = Option::is_none`), but it
1172
+ * landed AFTER the published `core-ts-v0.7.16` this daemon builds against — so a rule served by
1173
+ * the current binding carries NO `created_at`. The daemon passes the field through verbatim
1174
+ * (`listConformanceRules` returns the parsed rows unchanged), so it begins flowing the moment
1175
+ * crew re-pins to a core-ts that includes it — no daemon change needed. ABSENT — never
1176
+ * fabricated — on any rule the engine did not stamp (pre-field rows, and every row from a
1177
+ * pre-bump binding), so a `since`/`until` filter cannot assert an undated rule in range.
1178
+ */
1179
+ created_at?: number;
1098
1180
  }
1099
1181
 
1100
1182
  /** Facet query for `GET /governance/rules/preview`. All fields are optional. */
@@ -1130,6 +1212,21 @@ export interface RuleBrowseQuery {
1130
1212
  * contradict, and picking a winner silently would answer a question the caller didn't ask).
1131
1213
  */
1132
1214
  include_retired?: 'true' | 'false';
1215
+ /**
1216
+ * Inclusive LOWER date bound (api-types 0.23.0): keep only rules with `created_at >= since`.
1217
+ * Unix SECONDS, a non-negative integer (a present-but-non-integer value is a 400). Applied
1218
+ * server-side over the listed rows, alongside the facet filters. A rule with NO `created_at`
1219
+ * is EXCLUDED whenever `since` (or `until`) is set — see {@link ConformanceRule.created_at}: on
1220
+ * a pre-bump core-ts binding NO rule carries the field, so this filter narrows to empty until the
1221
+ * engine surfaces it. Omitted ⇒ no lower bound.
1222
+ */
1223
+ since?: string;
1224
+ /**
1225
+ * Inclusive UPPER date bound (api-types 0.23.0): keep only rules with `created_at <= until`.
1226
+ * Same units/validation/undated-exclusion as {@link RuleBrowseQuery.since}. Omitted ⇒ no upper
1227
+ * bound.
1228
+ */
1229
+ until?: string;
1133
1230
  }
1134
1231
 
1135
1232
  // ── Steering management (STEERING program) ──────────────────────────────────────
@@ -1412,6 +1509,66 @@ export interface ImportEvalCorpusResponse {
1412
1509
  embedded: boolean;
1413
1510
  }
1414
1511
 
1512
+ // ── Eval run history (crew-side EvalRunStore) — the Evals section's real list ───
1513
+
1514
+ /**
1515
+ * One steering type's slice of an eval run's rollup — the same four counts as
1516
+ * {@link GovernanceEvalSummary}, derived from the run's results grouped by `sample.steering_type`.
1517
+ * This is what makes "which steering type carries the gaps" a stored field, not a per-request
1518
+ * recompute over the full results.
1519
+ */
1520
+ export interface EvalRunPerTypeCount {
1521
+ total: number;
1522
+ caught: number;
1523
+ gaps: number;
1524
+ false_positives: number;
1525
+ }
1526
+
1527
+ /**
1528
+ * One PERSISTED eval run — the listable rollup row (`GET /testing/evals`). A run is one
1529
+ * `POST /testing/evals/run` and its report, stamped with WHO ran it, WHAT it ran against, and
1530
+ * WHEN, so the Evals section is a real history instead of a single session-local report that a
1531
+ * reload loses. The per-sample `results` are NOT here — they live on {@link EvalRunDetail} (the
1532
+ * drilldown), so listing the history stays cheap no matter how large a custom corpus is.
1533
+ *
1534
+ * Evals take no repo/project (they judge a STORE, not a workspace), so this is a single GLOBAL
1535
+ * feed per daemon — unlike recon campaign runs, which file into projects.
1536
+ */
1537
+ export interface EvalRunSummary {
1538
+ /** Server-minted run id. */
1539
+ id: string;
1540
+ /** Unix SECONDS the run was recorded (the crew `created_at` convention — see AgentSession). */
1541
+ created_at: number;
1542
+ /** The authenticated actor who ran it. */
1543
+ actor: string;
1544
+ /** The corpus scope (`evals:<name>`), or null for the engine's built-in dev-behaviors corpus. */
1545
+ corpus: string | null;
1546
+ /** The single steering type the run was narrowed to, or null when it ran all seven. */
1547
+ type_filter: SteeringType | null;
1548
+ /** The steering rule store the run was judged against (the daemon's `--db` steering store). */
1549
+ rule_store: string;
1550
+ /** The report's rollup, verbatim ({@link GovernanceEvalSummary}). */
1551
+ summary: GovernanceEvalSummary;
1552
+ /** Per-steering-type rollup, derived from the results — present only for the types the run covered. */
1553
+ per_type: Partial<Record<SteeringType, EvalRunPerTypeCount>>;
1554
+ /** `'facet-only'` when the run degraded to facet matching; null when it ran full-fidelity. */
1555
+ degraded: 'facet-only' | null;
1556
+ }
1557
+
1558
+ /**
1559
+ * One eval run WITH its full per-sample results (`GET /testing/evals/:id`) — the drilldown behind a
1560
+ * history row. `results` is the same verbatim {@link GovernanceEvalResult} array the run's original
1561
+ * `POST /testing/evals/run` returned, so the existing report view renders it unchanged.
1562
+ */
1563
+ export interface EvalRunDetail extends EvalRunSummary {
1564
+ results: GovernanceEvalResult[];
1565
+ }
1566
+
1567
+ /** The `GET /testing/evals` 200 body — the eval run history, newest first. */
1568
+ export interface ListEvalRunsResponse {
1569
+ runs: EvalRunSummary[];
1570
+ }
1571
+
1415
1572
  /**
1416
1573
  * The `POST /testing/recon` request body (api-types 0.15.0) — the Testing page's campaign-recon
1417
1574
  * trigger. `problem` is the recon brief, passed to every launched run VERBATIM (the client owns
@@ -1826,16 +1983,23 @@ export interface SystemSettings {
1826
1983
  /**
1827
1984
  * The stall watchdog's ESCALATION threshold (crew#341; api-types 0.18.0): quiet minutes before
1828
1985
  * the watchdog ACTS on a detected stall (see {@link WorkerStallEscalatedFrame}). Integer
1829
- * 0..1440; **absent or 0 = escalation OFF — the shipped default** (the issue's design: automatic
1830
- * recovery on a run that is merely slow would be worse than the wedge). Values below
1986
+ * 0..1440; `0` = escalation OFF. **Absent = the daemon default (30 — armed)**: as of perf#4 the
1987
+ * ladder is ON by default (run 616c8661 burned a full 2h turn ceiling with the watchdog
1988
+ * detection-only; the engine's `reassignUnit` supersedes the wedged turn safely, so acting is
1989
+ * strictly better than watching). 30 leaves ~55% headroom over the slowest legitimate
1990
+ * time-to-first-output observed in the field (~19.4 min) while still recovering ~4x faster
1991
+ * than the 2h ceiling. Opt out with an explicit `0`. Values below
1831
1992
  * `workerStallMinutes` escalate at the detection threshold — the ladder never acts before it
1832
1993
  * has notified.
1833
1994
  */
1834
1995
  workerStallEscalateMinutes?: number;
1835
1996
  /**
1836
1997
  * What an armed escalation DOES (crew#341): `'reassign'` (default) recycles the wedged cursor
1837
- * unit in place — the engine supersedes the stale turn, closes the worker session, bumps the
1838
- * attempt, and re-dispatches (queued operator injects survive into the fresh turn);
1998
+ * unit — the engine supersedes the stale turn, closes the worker session, bumps the
1999
+ * attempt, and re-dispatches (queued operator injects survive into the fresh turn). As of
2000
+ * perf#4 the watchdog routes the re-dispatch to a DIFFERENT seat from the run's own pool when
2001
+ * one is available (a seat that just sat silent past the escalation threshold is the last
2002
+ * seat to hand the retry to), falling back to an in-place recycle on a single-seat pool.
1839
2003
  * `'notify'` is the fail-loud rung — a `needsYou` `workerStallEscalated` frame + an audit
1840
2004
  * entry, the run untouched.
1841
2005
  */
@@ -2718,3 +2882,191 @@ export interface DiagnosticsResponse {
2718
2882
  recentErrors: DiagnosticsRecentError[];
2719
2883
  acp: AcpDiagnostics;
2720
2884
  }
2885
+
2886
+ // ── Memory proposal queue (DES-MEM-FACETED-001 §5.0, api-types 0.21.0) ─────────
2887
+
2888
+ /**
2889
+ * A proposal's lifecycle state. A proposal is INERT while `pending` (never recalled/applied);
2890
+ * `approve` promotes its payload to the active store and marks it `approved`, `reject` marks it
2891
+ * `rejected`.
2892
+ */
2893
+ export type ProposalState = 'pending' | 'approved' | 'rejected';
2894
+
2895
+ /**
2896
+ * One entry in the estate proposal queue — a type-generic, inert write agents submit and operators
2897
+ * decide (estate #162). The shape is the estate MCP `proposal.list` wire form verbatim.
2898
+ */
2899
+ export interface Proposal {
2900
+ /** Stable proposal-node id. */
2901
+ id: string;
2902
+ /** `"memory"` | `"policy:<steering_type>"` | future — the router key `approve` promotes by. */
2903
+ kind_type: string;
2904
+ /** The proposed content (a memory body, a policy rule, …). Opaque here; narrowed by `kind_type`. */
2905
+ payload: unknown;
2906
+ /** Agent-declared orthogonal facets (axis → value). */
2907
+ facets: Record<string, string>;
2908
+ /** Run/unit/agent attribution — AUTHORITY-STAMPED by the estate MCP from its launch env, never
2909
+ * taken from the submitter. Empty when the server had no `WICKED_RUN_*` env. */
2910
+ provenance: Record<string, string>;
2911
+ state: ProposalState;
2912
+ /** Unix seconds. */
2913
+ created_at: number;
2914
+ }
2915
+
2916
+ /** `GET /proposals` query filters — both optional; omitting a filter lists across that dimension. */
2917
+ export interface ListProposalsQuery {
2918
+ kind_type?: string;
2919
+ state?: ProposalState;
2920
+ }
2921
+
2922
+ /** `GET /proposals` → 200. */
2923
+ export interface ListProposalsResponse {
2924
+ proposals: Proposal[];
2925
+ }
2926
+
2927
+ /**
2928
+ * The result of landing an approved POLICY proposal as a steering rule (DES-MEM-FACETED-001 §5.2).
2929
+ * estate performs no rules-write for a policy proposal (the AW-11 invariant) — it hands the payload
2930
+ * to crew, the one governed rules-write path, which shapes a `ConformanceRule` and upserts it. Like
2931
+ * the steering-author landing (crew#388) the estate decision (approve) stands regardless, so a
2932
+ * landing that could not complete reports `outcome:"failed"` with a loud, operator-readable `error`
2933
+ * (recoverable by hand via `POST /governance/rules`) rather than turning the approve into a 500.
2934
+ */
2935
+ export interface PolicyLandingResult {
2936
+ /** `landed` = the steering rule is in the store; `failed` = the proposal is approved but no rule
2937
+ * was written — `error` says why. */
2938
+ outcome: 'landed' | 'failed';
2939
+ /** The upserted rule's id (deterministic `proposal:<proposalId>`, idempotent on replay). Present on `landed`. */
2940
+ ruleId?: string;
2941
+ /** The steering type derived from the proposal's `kind_type` (`policy:<type>`). Present on `landed`. */
2942
+ steering_type?: SteeringType;
2943
+ /** Present iff `outcome:"failed"` — the loud reason the rule did not land. */
2944
+ error?: string;
2945
+ }
2946
+
2947
+ /**
2948
+ * `POST /proposals/:id/approve` → 200. A MEMORY proposal is `promoted` (its payload is now an
2949
+ * active memory, `active_id`) and is complete. A POLICY proposal is `handed_off` — its `payload`
2950
+ * (`{ rule, severity }`) is still returned verbatim, and `landing` now reports the steering rule
2951
+ * crew created from it (`landing.outcome:"landed"` with the `ruleId`), or the loud reason it could
2952
+ * not (`landing.outcome:"failed"`). `landing` is absent only from responses served by a daemon
2953
+ * predating the policy→steering landing (forward-additive, DES-MEM-FACETED-001 §5.2).
2954
+ */
2955
+ export type ApproveProposalResponse =
2956
+ | { outcome: 'promoted'; active_id: string }
2957
+ | { outcome: 'handed_off'; payload: unknown; landing?: PolicyLandingResult };
2958
+
2959
+ /** `POST /proposals/:id/reject` → 200. */
2960
+ export interface RejectProposalResponse {
2961
+ ok: true;
2962
+ }
2963
+
2964
+ // ── Memory management (governed-knowledge surface, DES-MEM-FACETED-001, api-types 0.22.0) ──────
2965
+ //
2966
+ // The studio's surface for managing the memories that ALREADY exist in the operator store — the
2967
+ // counterpart to the proposal queue (which decides learnings not yet stored). Backed by the estate
2968
+ // MCP memory tools (memory.recall / memory.coverage / memory.erase) exposed over crew's /api/v1.
2969
+ // The granularity is estate's, surfaced honestly: browse is query-based (no "list all"), and
2970
+ // retire is SUBTREE-scoped (no per-id delete).
2971
+
2972
+ /**
2973
+ * One memory as browsed from the store (`GET /memory`, from estate `memory.recall`).
2974
+ *
2975
+ * estate `memory.recall` is query-based and token-budgeted — there is NO "list all" — and returns
2976
+ * `{ memory_id, scope, content, tier, score }` per item. It does NOT surface per-item `facets`, so
2977
+ * `facets` is presently always `{}` (kept in the shape for forward-compatibility and to mirror
2978
+ * `Proposal.facets`); `score` is the recall relevance score, absent when estate omits it.
2979
+ */
2980
+ export interface MemoryItem {
2981
+ /** Stable memory-node id (estate `memory_id`). */
2982
+ id: string;
2983
+ /** The memory body. */
2984
+ content: string;
2985
+ /** Tier: `working` | `episodic` | `semantic` | `procedural` | `archival`. */
2986
+ tier: string;
2987
+ /** The memory's own hierarchical scope path (slash-separated `kind:id` segments; `""` = root). */
2988
+ scope: string;
2989
+ /** Orthogonal facets (axis → value) the memory is tagged with. Populated by estate `memory.list`
2990
+ * (the management browse) — this is what powers the surface's facet filter. `{}` for an
2991
+ * unfaceted memory (and for a `memory.recall`-sourced item, which carries no facets). */
2992
+ facets: Record<string, string>;
2993
+ /** Relevance score — only present on a `memory.recall` item; `memory.list` (the browse) is not
2994
+ * relevance-ranked, so it is absent there. */
2995
+ score?: number;
2996
+ /**
2997
+ * Unix-SECONDS timestamp of when this memory FIRST entered the store — the "added" time the
2998
+ * governance surface sorts + date-filters on (api-types 0.23.0). Populated from estate
2999
+ * `memory.list`, which returns `created_at` per item; ABSENT — never fabricated — on a memory
3000
+ * whose creation time the store did not report (and on a `memory.recall`-sourced item, which
3001
+ * carries none). Additive: absence is the one spelling of "unknown", so a `since`/`until` filter
3002
+ * cannot assert an undated memory in range.
3003
+ */
3004
+ created_at?: number;
3005
+ }
3006
+
3007
+ /**
3008
+ * `GET /memory` query filters. All optional. The browse itself lists the COMPLETE in-scope set via
3009
+ * estate `memory.list`; `query`, `facets`, and `limit` are applied server-side as post-filters over
3010
+ * that set (they are NOT a relevance query). `scope_prefix` is the only estate-side argument — a
3011
+ * subtree filter where `""`/omitted matches EVERY memory (the same predicate as retire). `query` is
3012
+ * a case-insensitive CONTENT substring match. `facets` is a JSON-encoded object of axis→value
3013
+ * strings; an item is kept only if it carries every pair. `limit` caps the returned ROW count.
3014
+ */
3015
+ export interface ListMemoriesQuery {
3016
+ /** Case-insensitive content substring filter over the complete set. */
3017
+ query?: string;
3018
+ scope_prefix?: string;
3019
+ /** JSON-encoded `Record<string, string>` (axis→value); a malformed value is a 400. */
3020
+ facets?: string;
3021
+ /** Positive integer; caps the returned row count. */
3022
+ limit?: string;
3023
+ /**
3024
+ * Inclusive LOWER date bound (api-types 0.23.0): keep only memories with `created_at >= since`.
3025
+ * Unix SECONDS, a non-negative integer (a present-but-non-integer value is a 400). Applied
3026
+ * server-side over the loaded set, alongside `query`/`facets`. A memory with NO `created_at`
3027
+ * is EXCLUDED whenever `since` (or `until`) is set — an unknown creation time is not asserted
3028
+ * in range. Omitted ⇒ no lower bound.
3029
+ */
3030
+ since?: string;
3031
+ /**
3032
+ * Inclusive UPPER date bound (api-types 0.23.0): keep only memories with `created_at <= until`.
3033
+ * Same units/validation/undated-exclusion as {@link ListMemoriesQuery.since}. Omitted ⇒ no
3034
+ * upper bound.
3035
+ */
3036
+ until?: string;
3037
+ }
3038
+
3039
+ /** `GET /memory` → 200. */
3040
+ export interface ListMemoriesResponse {
3041
+ memories: MemoryItem[];
3042
+ }
3043
+
3044
+ /** `GET /memory/coverage` query — an optional subtree filter (`""`/omitted = global totals). */
3045
+ export interface MemoryCoverageQuery {
3046
+ scope_prefix?: string;
3047
+ }
3048
+
3049
+ /**
3050
+ * `GET /memory/coverage` → 200 (estate `memory.coverage`). Memory-node counts, optionally scoped to
3051
+ * a subtree: `total`, plus per-tier and per-kind breakdowns.
3052
+ */
3053
+ export interface MemoryCoverageResponse {
3054
+ total: number;
3055
+ by_tier: Record<string, number>;
3056
+ by_kind: Record<string, number>;
3057
+ }
3058
+
3059
+ /**
3060
+ * `POST /memory/retire` body. Retire is SUBTREE-scoped, never per-id: estate `memory.erase`
3061
+ * hard-deletes EVERY memory whose scope equals or descends from `scope_prefix`. `scope_prefix` is
3062
+ * required and must be non-empty (estate refuses a total wipe) — the surface must show the operator
3063
+ * the whole subtree it will remove, not a single row.
3064
+ */
3065
+ export interface RetireMemoryBody {
3066
+ scope_prefix: string;
3067
+ }
3068
+
3069
+ /** `POST /memory/retire` → 200. The number of memories the subtree wipe deleted. */
3070
+ export interface RetireMemoryResponse {
3071
+ erased: number;
3072
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-crew-api-types",
3
- "version": "0.19.0",
3
+ "version": "0.25.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",