@mnemom/mnemom 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib/api.d.ts CHANGED
@@ -9,56 +9,187 @@ export declare const API_BASE: string;
9
9
  * cached reservation) — when omitted, we mint a UUIDv4.
10
10
  */
11
11
  export declare function newIdempotencyKey(): string;
12
+ /**
13
+ * GET /v1/agents/:id.
14
+ *
15
+ * Source-verified at canonical ref c18491e6 (handleGetAgent): the OWNER view
16
+ * returns the raw agents row plus a computed `status` (active if last_seen
17
+ * within 1h); a non-owner of a claimed+public agent gets publicAgentProjection
18
+ * ({ id, name, claimed: !!claimed_by, last_seen, ... }). The previously-typed
19
+ * `gateway` is a PHANTOM — no agents column and neither projection emits it;
20
+ * it was always undefined. `claimed` is only emitted on the public projection
21
+ * (derived from claimed_by); the owner view carries claimed_by/claimed_at.
22
+ * Fields are optional/nullable to tolerate both projections.
23
+ */
12
24
  export interface Agent {
13
25
  id: string;
14
- gateway: string;
26
+ status?: "active" | "offline";
15
27
  last_seen: string | null;
16
- claimed: boolean;
17
- email?: string;
18
- created_at: string;
28
+ email?: string | null;
29
+ created_at?: string;
30
+ claimed_by?: string | null;
31
+ claimed_at?: string | null;
32
+ name?: string | null;
33
+ claimed?: boolean;
19
34
  }
20
35
  /**
21
- * Per api.mnemom.ai/openapi.json#components/schemas/IntegrityScore:
36
+ * GET /v1/integrity/:id — components/schemas/IntegrityScore:
22
37
  *
23
38
  * { agent_id, total_traces, verified_traces, violation_count, integrity_score }
24
39
  *
25
40
  * `integrity_score` is a value in [0, 1].
26
41
  *
27
- * Pre-this-fix the CLI's interface declared `score` / `verified` /
28
- * `violations` / `last_updated` none of which exist on the wire. The
29
- * `mnemom integrity` command rendered every field as `undefined` (and the
30
- * score as `NaN%`) against any agent. Field names now match the docs
31
- * verbatim.
42
+ * The array-vs-object divergence flagged here previously is RESOLVED upstream:
43
+ * source-verified at canonical contract ref c18491e6, handleGetIntegrity now
44
+ * normalizes BOTH the RPC path (which Supabase wraps as a one-row array) and
45
+ * the manual fallback to a single object with `agent_id` always populated
46
+ * the interface comment in src/index.ts credits "CLI consumers" for the fix.
47
+ * So `agent_id` is reliably emitted (hence required here). The defensive
48
+ * array-unwrap in getIntegrity below is retained only as belt-and-suspenders
49
+ * for a CLI pointed at an older, pre-normalization API.
32
50
  *
33
- * NOTE API shape divergence (flagged for a follow-up mnemom-api PR):
34
- * the RPC path in handleGetIntegrity returns an *array* of one object
35
- * (Supabase wraps TABLE-returning RPCs as arrays) without `agent_id`;
36
- * the manual fallback returns the *object* with `agent_id`. The docs
37
- * canonical is the object shape. We accept both shapes defensively in
38
- * getIntegrity below so this CLI works against today's prod API and
39
- * keeps working when the API normalizes to a single shape.
51
+ * (The spec schema does not list a `required` array, but the emitted-set
52
+ * always includes all five fields doc-set == emitted-set.)
40
53
  */
41
54
  export interface IntegrityScore {
42
- agent_id?: string;
55
+ agent_id: string;
43
56
  total_traces: number;
44
57
  verified_traces: number;
45
58
  violation_count: number;
46
59
  integrity_score: number;
47
60
  }
61
+ /**
62
+ * GET /v1/traces row — components/schemas/APTrace.
63
+ *
64
+ * Source-verified at canonical ref c18491e6: handleGetTraces selects the raw
65
+ * `traces` table rows (no projection), whose columns are AIP-NESTED:
66
+ * `trace_id, timestamp, action(object), decision(object), verification(object|null)`
67
+ * (confirmed by the explicit selects at index.ts:2563 / :4217 and the
68
+ * `trace.decision.selection_reasoning` / `trace.verification?.verified`
69
+ * readers).
70
+ *
71
+ * Pre-this-fix the CLI typed this FLAT — { id, action:string, verified:boolean,
72
+ * reasoning, tool_name } — none of which the wire emits. `mnemom logs` rendered
73
+ * every action as "[object Object]" and flagged EVERY trace as [VIOLATION]
74
+ * (undefined `verified` is falsy). Field names + nesting now match the wire.
75
+ */
48
76
  export interface Trace {
49
- id: string;
77
+ trace_id: string;
50
78
  agent_id: string;
51
79
  timestamp: string;
52
- action: string;
53
- verified: boolean;
54
- reasoning?: string;
55
- tool_name?: string;
56
- tool_input?: Record<string, unknown>;
80
+ action: {
81
+ type?: string;
82
+ name?: string;
83
+ category?: string;
84
+ };
85
+ decision?: {
86
+ selected?: string;
87
+ selection_reasoning?: string;
88
+ values_applied?: string[];
89
+ confidence?: number | null;
90
+ };
91
+ verification: {
92
+ verified: boolean;
93
+ violations: string[];
94
+ } | null;
95
+ created_at?: string;
57
96
  }
58
- export interface ApiError {
59
- error: string;
60
- message: string;
97
+ /**
98
+ * Canonical API error envelope — backward-tolerant.
99
+ *
100
+ * Source-verified against mnemom-api (2026-05-28): the wire is NOT uniformly
101
+ * nested. Three live shapes:
102
+ * 1. NESTED {error:{code,message}, spec_deviation?} — the spec-validate
103
+ * enforce-hook only (500 internal_error / undocumented_status_code /
104
+ * enforced body deviations). src/runtime/spec-validate-hook.ts.
105
+ * 2. FLAT {error:"message"} — every per-module
106
+ * errorResponse() helper (org/sideband/network/admin/governance + the
107
+ * top-level errorResponse in index.ts). The DOMINANT shape.
108
+ * 3. FLAT+code {error:"message", code:"..."} — auth routes
109
+ * (src/auth/routes.ts).
110
+ * No route emits a top-level `message` field; `details` is reserved/forward-
111
+ * tolerant. We parse all three and prefer nested.
112
+ *
113
+ * LIVE-WIRE NOTE (shepherd 48-probe sweep, staging+prod): the spec-validate
114
+ * ENFORCE hook is active on both deployed envs and normalizes every body to the
115
+ * NESTED shape before the wire — so in practice the CLI sees nested universally.
116
+ * The flat / flat+code tolerance is insurance for non-enforce contexts
117
+ * (local dev server, enforce=observe). The hook also adds a top-level
118
+ * `spec_deviation` sibling AND can REWRITE an undocumented status to a synthetic
119
+ * 500 (e.g. an undocumented 404 → 500 with `spec_deviation.original_status:404`).
120
+ * We surface that as MnemomApiError.effectiveStatus so command-layer 404/empty-
121
+ * state branching isn't fooled by the rewrite.
122
+ *
123
+ * Pre-this-fix ApiError was flat {error,message} read at `error.message` (top
124
+ * level) — undefined for every real shape → the server message was dropped.
125
+ */
126
+ export interface SpecDeviation {
127
+ keyword?: string;
128
+ field?: string;
129
+ original_status?: number;
61
130
  }
131
+ export interface ApiError {
132
+ error?: string | {
133
+ code?: string;
134
+ message?: string;
135
+ details?: unknown;
136
+ };
137
+ message?: string;
138
+ code?: string;
139
+ details?: unknown;
140
+ conflict_agent_id?: string;
141
+ spec_deviation?: SpecDeviation;
142
+ }
143
+ /** Normalized error fields extracted from any of the three envelope shapes. */
144
+ export interface ParsedApiError {
145
+ message?: string;
146
+ code?: string;
147
+ details?: unknown;
148
+ conflict_agent_id?: string;
149
+ spec_deviation?: SpecDeviation;
150
+ }
151
+ /**
152
+ * Extract the human message + code + details from a raw error body,
153
+ * tolerating all three live envelope shapes (prefer nested).
154
+ */
155
+ export declare function normalizeApiError(raw: ApiError | null | undefined): ParsedApiError;
156
+ /** Parse a non-OK Response body into normalized error fields (never throws). */
157
+ export declare function parseApiErrorBody(response: Response): Promise<ParsedApiError>;
158
+ /**
159
+ * Structured API error. `message` is the human-readable server message (or a
160
+ * fallback); `.status`/`.code`/`.details`/`.conflictAgentId` give callers a
161
+ * structured surface to branch on without parsing the message string.
162
+ * `instanceof MnemomApiError` narrows in command-layer catch blocks.
163
+ */
164
+ export declare class MnemomApiError extends Error {
165
+ /** The wire HTTP status — may be a synthetic 500 from the enforce hook. */
166
+ readonly status: number;
167
+ /**
168
+ * The TRUE intended status: `spec_deviation.original_status ?? status`. The
169
+ * enforce hook can rewrite an undocumented status to a synthetic 500; command
170
+ * layers MUST branch on `effectiveStatus` (not `status`) for 404/empty-state
171
+ * detection or they'll be fooled by the rewrite.
172
+ */
173
+ readonly effectiveStatus: number;
174
+ readonly code?: string;
175
+ readonly details?: unknown;
176
+ readonly conflictAgentId?: string;
177
+ /** Top-level enforce-hook sibling (present only on a spec-rewritten body). */
178
+ readonly specDeviation?: SpecDeviation;
179
+ constructor(status: number, message: string, opts?: {
180
+ code?: string;
181
+ details?: unknown;
182
+ conflictAgentId?: string;
183
+ specDeviation?: SpecDeviation;
184
+ });
185
+ }
186
+ /**
187
+ * Read a non-OK Response into a MnemomApiError, preferring the server message
188
+ * and falling back to `${fallback}: ${status}` when the body carried none.
189
+ * Captures the enforce-hook `spec_deviation` sibling so `.effectiveStatus`
190
+ * reflects the true intended status behind any synthetic-500 rewrite.
191
+ */
192
+ export declare function readApiError(response: Response, fallback: string): Promise<MnemomApiError>;
62
193
  export declare function postApi<T>(endpoint: string, body: unknown, opts?: {
63
194
  idempotencyKey?: string;
64
195
  }): Promise<T>;
@@ -270,88 +401,6 @@ export declare function getIntegrity(id: string): Promise<IntegrityScore>;
270
401
  * don't need a special case for it.
271
402
  */
272
403
  export declare function getTraces(id: string, limit?: number): Promise<Trace[]>;
273
- export interface AlignmentCard {
274
- card_id?: string;
275
- version?: string;
276
- issued_at?: string;
277
- expires_at?: string;
278
- principal?: {
279
- name?: string;
280
- type?: string;
281
- organization?: string;
282
- };
283
- values?: {
284
- declared?: string[];
285
- definitions?: Record<string, string>;
286
- };
287
- autonomy_envelope?: {
288
- bounded_actions?: string[];
289
- forbidden_actions?: string[];
290
- escalation_triggers?: Array<{
291
- condition: string;
292
- action?: string;
293
- }>;
294
- };
295
- audit_commitment?: {
296
- log_level?: string;
297
- retention_days?: number;
298
- access_policy?: string;
299
- };
300
- extensions?: Record<string, unknown>;
301
- [key: string]: unknown;
302
- }
303
- export interface CardResponse {
304
- card_id: string;
305
- agent_id: string;
306
- card_json: AlignmentCard;
307
- created_at: string;
308
- updated_at: string;
309
- }
310
- export declare function getCard(agentId: string): Promise<CardResponse | null>;
311
- export declare function updateCard(agentId: string, cardJson: AlignmentCard, opts?: {
312
- idempotencyKey?: string;
313
- }): Promise<{
314
- updated: boolean;
315
- card_id: string;
316
- }>;
317
- export declare function reverifyAgent(agentId: string, opts?: {
318
- idempotencyKey?: string;
319
- }): Promise<{
320
- reverified: number;
321
- }>;
322
- export interface PolicyResponse {
323
- id: string;
324
- name: string;
325
- description: string | null;
326
- policy_json: Record<string, unknown>;
327
- version: number;
328
- created_by: string;
329
- created_at: string;
330
- }
331
- export interface PolicyListResponse {
332
- agent_id: string;
333
- policy: PolicyResponse | null;
334
- }
335
- export declare function getPolicy(agentId: string): Promise<PolicyListResponse | null>;
336
- export declare function publishPolicy(agentId: string, policyJson: Record<string, unknown>, opts?: {
337
- idempotencyKey?: string;
338
- }): Promise<{
339
- id: string;
340
- version: number;
341
- created: boolean;
342
- }>;
343
- export declare function testPolicyHistorical(agentId: string, policyJson: Record<string, unknown>, limit?: number): Promise<{
344
- agent_id: string;
345
- policy_name: string;
346
- total_traces: number;
347
- results: unknown[];
348
- summary: {
349
- pass: number;
350
- warn: number;
351
- fail: number;
352
- skipped: number;
353
- };
354
- }>;
355
404
  /**
356
405
  * Fetch the canonical alignment card as YAML (or JSON fallback).
357
406
  * Returns the raw response body as a string.
@@ -402,6 +451,30 @@ export declare const PROTECTION_CARD_MAX_BYTES: number;
402
451
  export declare function putProtectionCard(agentId: string, body: string, contentType?: "text/yaml" | "application/json", opts?: {
403
452
  idempotencyKey?: string;
404
453
  }): Promise<PublishedCardResponse>;
454
+ export interface CardPreviewResult {
455
+ /** true ⇔ the server accepted+composed the card (HTTP 200). */
456
+ valid: boolean;
457
+ status: number;
458
+ /** Canonical composed card (200 only). */
459
+ composed?: Record<string, unknown>;
460
+ /** Per-field tightenings applied by the org/platform floor (200 only). */
461
+ conflicts?: unknown[];
462
+ /** Warning-mode coherence findings (200 only). */
463
+ coherence_violations?: unknown[];
464
+ /** Parsed error envelope on a 4xx validation failure (invalid only). */
465
+ error?: {
466
+ code?: string;
467
+ message?: string;
468
+ details?: unknown;
469
+ };
470
+ }
471
+ /**
472
+ * Dry-run validate + compose a card body against the server's authoritative
473
+ * pipeline. Returns a structured result — a 422/400 validation failure is an
474
+ * expected `valid:false` outcome (NOT a thrown error). 401 throws (caller
475
+ * should fall back to offline validation); 403/5xx throw a MnemomApiError.
476
+ */
477
+ export declare function previewComposeAgentCard(agentId: string, kind: TeamTemplateKind, body: string, contentType?: "text/yaml" | "application/json"): Promise<CardPreviewResult>;
405
478
  /**
406
479
  * Resolve an agent name or ID to a server agent ID.
407
480
  *
@@ -646,7 +719,7 @@ export declare function getSafeHouseHarnessState(): Promise<{
646
719
  fast: HarnessRunSummary | null;
647
720
  }>;
648
721
  export type GovernanceSignalScope = "platform" | "org" | "team" | "agent";
649
- export type GovernanceSignalSource = "sideband.drift" | "sideband.coherence" | "sideband.fault_line" | "sideband.fleet";
722
+ export type GovernanceSignalSource = "sideband.drift" | "sideband.coherence" | "sideband.fault_line" | "sideband.fleet" | "network.threat_level.changed";
650
723
  export type GovernanceSignalSeverity = "info" | "warn" | "high" | "critical";
651
724
  export type GovernanceSignalStatus = "open" | "acknowledged" | "resolved" | "dismissed" | "expired";
652
725
  export type GovernanceResolutionStatus = "action_taken" | "wont_fix" | "duplicate" | "false_positive" | "self_resolved";
@@ -674,6 +747,7 @@ export interface GovernanceSignal {
674
747
  resolved_by: string | null;
675
748
  resolved_at: string | null;
676
749
  expires_at: string | null;
750
+ webhook_delivery_id: string | null;
677
751
  notification_state: Record<string, unknown>;
678
752
  created_at: string;
679
753
  updated_at: string;
@@ -828,6 +902,36 @@ export declare function rotateApiKey(keyId: string): Promise<ApiKeyCreated>;
828
902
  * audit; `is_active` flips to false and `revoked_at` is timestamped.
829
903
  */
830
904
  export declare function revokeApiKey(keyId: string): Promise<void>;
905
+ export interface LicenseValidationResult {
906
+ valid: boolean;
907
+ license_id?: string;
908
+ plan_id?: string;
909
+ feature_flags?: Record<string, boolean>;
910
+ limits?: Record<string, unknown>;
911
+ expires_at?: string;
912
+ next_check_seconds?: number;
913
+ warning?: string | null;
914
+ [key: string]: unknown;
915
+ }
916
+ /**
917
+ * POST /v1/license/validate — validate a license JWT for an instance.
918
+ *
919
+ * UNAUTHENTICATED by design (the license JWT IS the credential; this is a
920
+ * pre-login path) — sends NO auth header. Source-verified at canonical ref
921
+ * c18491e6 (handleLicenseValidate): the request body keys are
922
+ * `{ license, instance_id, instance_metadata }` (NOT `jwt`) — sending `jwt`
923
+ * would 400 "license is required".
924
+ *
925
+ * Returns the parsed validation result on 2xx (including the grace-period
926
+ * `valid:false` 200 body); throws MnemomApiError on non-2xx so the command
927
+ * renders `.message`/`.status`. This fixes the live H1 "[object Object]" bug:
928
+ * the old command-layer `err.error || "unknown"` string-coerced the nested
929
+ * `{code,message}` object that the enforce hook puts on the wire.
930
+ *
931
+ * `license deactivate` may reuse this (best-effort, fire-and-forget) by
932
+ * catching the throw at the command layer.
933
+ */
934
+ export declare function validateLicense(jwt: string, instanceId: string, instanceMetadata?: Record<string, unknown>): Promise<LicenseValidationResult>;
831
935
  export interface RecipeReportInput {
832
936
  type: "fn" | "fp";
833
937
  summary: string;