memax-sdk 0.1.12 → 0.1.13

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 (64) hide show
  1. package/dist/client.d.ts +4 -2
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +6 -3
  4. package/dist/client.js.map +1 -1
  5. package/dist/client.test.js +226 -1
  6. package/dist/client.test.js.map +1 -1
  7. package/dist/errors.d.ts +4 -1
  8. package/dist/errors.d.ts.map +1 -1
  9. package/dist/errors.js +7 -1
  10. package/dist/errors.js.map +1 -1
  11. package/dist/index.d.ts +2 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/resources/admin.d.ts +357 -0
  15. package/dist/resources/admin.d.ts.map +1 -0
  16. package/dist/resources/admin.js +168 -0
  17. package/dist/resources/admin.js.map +1 -0
  18. package/dist/resources/agent-sessions.d.ts +3 -1
  19. package/dist/resources/agent-sessions.d.ts.map +1 -1
  20. package/dist/resources/agent-sessions.js +6 -0
  21. package/dist/resources/agent-sessions.js.map +1 -1
  22. package/dist/resources/agents.d.ts +14 -0
  23. package/dist/resources/agents.d.ts.map +1 -1
  24. package/dist/resources/agents.js +21 -1
  25. package/dist/resources/agents.js.map +1 -1
  26. package/dist/resources/auth.d.ts +12 -2
  27. package/dist/resources/auth.d.ts.map +1 -1
  28. package/dist/resources/auth.js +15 -1
  29. package/dist/resources/auth.js.map +1 -1
  30. package/dist/resources/configs.d.ts +20 -1
  31. package/dist/resources/configs.d.ts.map +1 -1
  32. package/dist/resources/configs.js +25 -0
  33. package/dist/resources/configs.js.map +1 -1
  34. package/dist/resources/hubs.d.ts +22 -3
  35. package/dist/resources/hubs.d.ts.map +1 -1
  36. package/dist/resources/hubs.js +26 -4
  37. package/dist/resources/hubs.js.map +1 -1
  38. package/dist/resources/memories.d.ts +48 -7
  39. package/dist/resources/memories.d.ts.map +1 -1
  40. package/dist/resources/memories.js +60 -3
  41. package/dist/resources/memories.js.map +1 -1
  42. package/dist/resources/notifications.d.ts +75 -0
  43. package/dist/resources/notifications.d.ts.map +1 -0
  44. package/dist/resources/notifications.js +106 -0
  45. package/dist/resources/notifications.js.map +1 -0
  46. package/dist/resources/settings.d.ts +11 -3
  47. package/dist/resources/settings.d.ts.map +1 -1
  48. package/dist/resources/settings.js +10 -0
  49. package/dist/resources/settings.js.map +1 -1
  50. package/dist/resources/topics.d.ts +54 -2
  51. package/dist/resources/topics.d.ts.map +1 -1
  52. package/dist/resources/topics.js +58 -2
  53. package/dist/resources/topics.js.map +1 -1
  54. package/dist/transport.d.ts +8 -1
  55. package/dist/transport.d.ts.map +1 -1
  56. package/dist/transport.js +20 -2
  57. package/dist/transport.js.map +1 -1
  58. package/dist/types.d.ts +771 -18
  59. package/dist/types.d.ts.map +1 -1
  60. package/package.json +1 -1
  61. package/dist/resources/reviews.d.ts +0 -9
  62. package/dist/resources/reviews.d.ts.map +0 -1
  63. package/dist/resources/reviews.js +0 -16
  64. package/dist/resources/reviews.js.map +0 -1
package/dist/types.d.ts CHANGED
@@ -18,6 +18,8 @@ export interface MemaxConfig {
18
18
  maxRetries?: number;
19
19
  /** Delay between retry attempts in milliseconds */
20
20
  retryDelayMs?: number;
21
+ /** Optional hook for warning headers returned by the API transport. */
22
+ onWarning?: (warning: string) => void;
21
23
  }
22
24
  export type AskModel = "auto" | "haiku" | "sonnet";
23
25
  export type Locale = "en" | "zh";
@@ -31,6 +33,9 @@ export interface PushOptions {
31
33
  source?: string;
32
34
  /** Agent identity: "claude-code", "cursor", "copilot", etc. Auto-set by hooks/MCP. */
33
35
  sourceAgent?: string;
36
+ /** Human collaboration credit, not actor identity. */
37
+ assistedByAgent?: string;
38
+ initiationType?: "human_direct" | "human_requested_agent" | "agent_proactive" | "agent_automatic" | "import" | "unknown";
34
39
  sourcePath?: string;
35
40
  contentType?: string;
36
41
  projectContext?: Record<string, string>;
@@ -98,6 +103,8 @@ export interface Memory {
98
103
  pinned: boolean;
99
104
  source: string;
100
105
  source_agent?: string;
106
+ assisted_by_agent?: string;
107
+ provenance?: MemoryProvenance;
101
108
  source_path?: string;
102
109
  hub_reason?: string;
103
110
  original_file_ref?: string;
@@ -114,6 +121,59 @@ export interface Memory {
114
121
  hub_name?: string;
115
122
  agent_display_name?: string;
116
123
  agent_icon?: string;
124
+ /** Server-resolved dream-delta signals. See MemoryLifecycle docs. */
125
+ lifecycle?: MemoryLifecycle;
126
+ }
127
+ export interface MemoryProvenance {
128
+ created_by_type: "human" | "agent";
129
+ created_by_slug?: string;
130
+ created_by_display_name?: string;
131
+ created_via?: string;
132
+ assisted_by_agent?: string;
133
+ initiation_type: "human_direct" | "human_requested_agent" | "agent_proactive" | "agent_automatic" | "import" | "unknown";
134
+ attribution_source?: string;
135
+ }
136
+ /**
137
+ * MemoryLifecycle — durable dream-delta signals for memory rows + detail.
138
+ *
139
+ * Two fields with distinct scopes:
140
+ * - pending_dream_action drives scan surfaces (row breadcrumb tint).
141
+ * Scoped to the viewer's last visit of the memory's current topic;
142
+ * server returns null after the viewer visits.
143
+ * - dream_history drives the memory detail provenance strip. Up to 10
144
+ * most recent dream actions, unscoped, durable. Empty array on list
145
+ * reads; populated only on detail reads.
146
+ */
147
+ export interface MemoryLifecycle {
148
+ pending_dream_action: DreamActionRef | null;
149
+ dream_history: DreamActionRef[];
150
+ }
151
+ /**
152
+ * DreamActionRef — client-facing shape of a dream action.
153
+ *
154
+ * from_topic / to_topic are nullable — historical rows (pre-migration 069)
155
+ * stay null and UI renders verb + reason without lineage.
156
+ */
157
+ export interface DreamActionRef {
158
+ run_id: string;
159
+ action_type: "organize" | "merge" | "archive" | "restructure";
160
+ at: string;
161
+ from_topic: DreamTopicRef | null;
162
+ to_topic: DreamTopicRef | null;
163
+ reason?: string;
164
+ }
165
+ export interface DreamTopicRef {
166
+ id: string;
167
+ name: string;
168
+ /**
169
+ * Lucide icon name at the time the reference was resolved (e.g.
170
+ * "folder", "code"). Empty/undefined when the topic has no icon.
171
+ * Server uses the scoped topic join, so this field is never present
172
+ * when the topic is out of the viewer's scope (whole ref is null in
173
+ * that case). UI chips render `icon + name` to keep topic identity
174
+ * consistent across row breadcrumb, dream history, and hover card.
175
+ */
176
+ icon?: string;
117
177
  }
118
178
  export interface MemoryUpdateInput {
119
179
  title?: string;
@@ -122,6 +182,113 @@ export interface MemoryUpdateInput {
122
182
  tags?: string[];
123
183
  }
124
184
  export type ShareMemoryResult = Memory;
185
+ /**
186
+ * Reason a batch-move request skipped a given memory id.
187
+ * - `not_owned`: the caller does not own this memory (team-hub shared content).
188
+ * - `not_found`: the id does not exist or has been deleted.
189
+ * - `already_at_target`: the memory's current hub + topic already matches.
190
+ * - `source_delete_forbidden`: the caller owns the memory but lacks
191
+ * authority to remove it from its current hub. Move is semantically
192
+ * delete-from-source + create-in-destination, so the source hub's
193
+ * `contributor_delete_policy` must be honored. Emitted only for
194
+ * cross-hub moves; same-hub topic reassignments skip the check.
195
+ */
196
+ export type BatchMoveSkipReason = "not_owned" | "not_found" | "already_at_target" | "source_delete_forbidden";
197
+ export interface BatchMoveSkippedMemory {
198
+ id: string;
199
+ reason: BatchMoveSkipReason;
200
+ }
201
+ /**
202
+ * Structured response from `POST /v1/memories/batch-move`.
203
+ *
204
+ * `moved` is the count of memories actually reassigned in this request.
205
+ * `skipped` lists every input id that was not moved, with a reason code.
206
+ * Consumers should treat any `moved > 0` as partial success and surface
207
+ * skipped counts to the user so they know why fewer moved than requested.
208
+ */
209
+ export interface BatchMoveResult {
210
+ moved: number;
211
+ skipped: BatchMoveSkippedMemory[];
212
+ }
213
+ /**
214
+ * Reason a batch-delete request skipped a given memory id.
215
+ * - `not_owned`: the caller does not own the memory and does not hold a
216
+ * hub role + contributor_delete_policy that covers it. Single code for
217
+ * both "wrong owner, no hub context" and "hub member but policy forbids."
218
+ * - `not_found`: the id does not exist at request time. Covers unknown
219
+ * ids AND the race where a row is removed concurrently between
220
+ * accessibility load and the actual DELETE.
221
+ * - `delete_failed`: a store-level error occurred while attempting to
222
+ * delete this id (postgres transient error, object-store failure).
223
+ * Distinguished from `not_found` so clients can retry infra issues
224
+ * without blaming the user. Server logs the underlying error.
225
+ */
226
+ export type BatchDeleteSkipReason = "not_owned" | "not_found" | "delete_failed";
227
+ export interface BatchDeleteSkippedMemory {
228
+ id: string;
229
+ reason: BatchDeleteSkipReason;
230
+ }
231
+ /**
232
+ * Structured response from `POST /v1/memories/batch-delete`.
233
+ *
234
+ * `deleted` is the count of memories actually removed in this request.
235
+ * `skipped` lists every input id that was not deleted, with a reason.
236
+ *
237
+ * Partial-success semantics: `deleted > 0` with non-empty `skipped` is a
238
+ * normal, intentional outcome — the server commits what it can and
239
+ * reports the rest. Clients should surface the partial count to the user.
240
+ *
241
+ * Full-skip semantics: `deleted === 0` can happen for three different
242
+ * reasons (all-not_owned, all-not_found, all-delete_failed). Clients
243
+ * should inspect `skipped[].reason` to pick appropriate copy rather than
244
+ * showing one generic error for all three. `not_found` in particular is
245
+ * usually the user's desired end state (the memory is gone) and should
246
+ * be treated as effective success.
247
+ */
248
+ export interface BatchDeleteResult {
249
+ deleted: number;
250
+ skipped: BatchDeleteSkippedMemory[];
251
+ }
252
+ /**
253
+ * Skip reasons for `POST /v1/configs/batch-delete`. The agent config reason
254
+ * set is deliberately narrower than `BatchDeleteSkipReason`:
255
+ *
256
+ * - `not_found`: the config id does not resolve for the caller. The server
257
+ * collapses "unknown id", "already deleted", and "owned by another user"
258
+ * into this single reason because the SQL WHERE clause makes them
259
+ * indistinguishable without an extra round-trip, and all three map to
260
+ * idempotent success on the client (the user's target state is reached).
261
+ * - `delete_failed`: the tombstone insert or the DELETE itself returned an
262
+ * error mid-batch. Distinguished from `not_found` so the client can
263
+ * retry infra failures and roll back the optimistic list removal.
264
+ *
265
+ * There is deliberately no `not_owned` — the agent config store enforces
266
+ * ownership via the WHERE clause, so the web hook's catch branch does not
267
+ * need to handle a permission-style reason. Keeping the union narrow means
268
+ * dead code (e.g. a `forgetDenied` toast branch) would be caught at
269
+ * compile time.
270
+ */
271
+ export type AgentConfigDeleteSkipReason = "not_found" | "delete_failed";
272
+ export interface AgentConfigDeleteSkippedItem {
273
+ id: string;
274
+ reason: AgentConfigDeleteSkipReason;
275
+ }
276
+ /**
277
+ * Structured response from `POST /v1/configs/batch-delete`.
278
+ *
279
+ * Shares the same shape as `BatchDeleteResult` (deleted count + skipped
280
+ * array) but narrows the reason union to the agent-config taxonomy. The
281
+ * server always returns 200 with this body in the ApiResponse envelope —
282
+ * 4xx/5xx are reserved for full-request failures.
283
+ *
284
+ * Partial-success is the default: `deleted > 0` with non-empty `skipped`
285
+ * means the server committed what it could and reports the rest so the
286
+ * client can surface a partial-success toast.
287
+ */
288
+ export interface AgentConfigBatchDeleteResult {
289
+ deleted: number;
290
+ skipped: AgentConfigDeleteSkippedItem[];
291
+ }
125
292
  export interface MemoryAttachment {
126
293
  id: string;
127
294
  memory_id: string;
@@ -131,8 +298,28 @@ export interface MemoryAttachment {
131
298
  content_type: string;
132
299
  size_bytes: number;
133
300
  sha256: string;
301
+ /** Width in pixels. Present only for images that decoded successfully
302
+ * at upload time. Use with `height` to reserve layout space and
303
+ * avoid CLS when rendering inline previews. */
304
+ width?: number | null;
305
+ /** Height in pixels. See `width`. */
306
+ height?: number | null;
307
+ /** True when the signed view endpoint may serve this attachment
308
+ * with Content-Disposition: inline. Clients should require BOTH
309
+ * this flag AND a raster content_type before rendering via
310
+ * <img src> — defense in depth against partially-migrated rows. */
311
+ inline_eligible?: boolean;
134
312
  created_at: string;
135
313
  }
314
+ /** Short-lived signed URL for rendering an attachment inline. Caller
315
+ * passes this straight to <img src>. Reuse within the TTL window is
316
+ * expected — the same image renders across inbox modal, memory
317
+ * detail, and lightbox without re-signing. */
318
+ export interface AttachmentViewURL {
319
+ url: string;
320
+ /** Unix seconds UTC. Clients should refresh shortly before expiry. */
321
+ expires_at: number;
322
+ }
136
323
  export interface FileRef {
137
324
  object_key: string;
138
325
  filename: string;
@@ -333,7 +520,7 @@ export interface DeletedAgentSession {
333
520
  content_hash?: string;
334
521
  content_expires_at?: string;
335
522
  }
336
- export type SessionSyncAction = "unchanged" | "push" | "pull" | "conflict" | "delete_local";
523
+ export type SessionSyncAction = "unchanged" | "push" | "pull" | "diverged" | "tombstone_diverged" | "delete_local";
337
524
  export interface SessionSyncPlanAction {
338
525
  action: SessionSyncAction;
339
526
  agent: string;
@@ -343,8 +530,28 @@ export interface SessionSyncPlanAction {
343
530
  session_id?: string;
344
531
  cloud_hash?: string;
345
532
  cloud_updated_at?: string;
533
+ cloud_version?: number;
346
534
  version?: number;
347
535
  }
536
+ /** Request to atomically resolve a diverged session. */
537
+ export interface ResolveDivergenceRequest {
538
+ agent: string;
539
+ file_path: string;
540
+ scope: Scope;
541
+ device_id: string;
542
+ local_file_ref?: FileRef;
543
+ local_content_hash: string;
544
+ expected_cloud_version: number;
545
+ expected_cloud_hash: string;
546
+ resolution: "keep_local" | "keep_cloud";
547
+ }
548
+ /** Response from a successful divergence resolution. */
549
+ export interface ResolveDivergenceResponse {
550
+ winner: "local" | "cloud";
551
+ snapshot_id: string;
552
+ snapshot_device: string;
553
+ new_version: number;
554
+ }
348
555
  export interface SessionSyncManifestEntry {
349
556
  agent: string;
350
557
  file_path: string;
@@ -399,8 +606,12 @@ export interface User {
399
606
  name: string;
400
607
  email: string;
401
608
  plan: string;
609
+ personal_plan_id: string;
402
610
  display_name?: string;
403
611
  avatar_url?: string;
612
+ can_create_hub?: boolean;
613
+ created_at?: string;
614
+ updated_at?: string;
404
615
  }
405
616
  export interface Usage {
406
617
  user_id: string;
@@ -410,6 +621,56 @@ export interface Usage {
410
621
  recall_count: number;
411
622
  ask_count: number;
412
623
  }
624
+ /** Plan scope distinguishes personal plans (assigned to users) from hub plans (assigned to team hubs). */
625
+ export type PlanScope = "personal" | "hub";
626
+ export interface PlanDefinition {
627
+ id: string;
628
+ scope: PlanScope;
629
+ display_name: string;
630
+ tier_order: number;
631
+ entitlement_rank: number;
632
+ monthly_price_cents: number;
633
+ memory_limit: number;
634
+ push_limit: number;
635
+ recall_limit: number;
636
+ ask_limit: number;
637
+ ask_model: "haiku" | "sonnet";
638
+ dreams_enabled: boolean;
639
+ review_inbox: boolean;
640
+ max_team_hubs: number;
641
+ max_owned_free_team_hubs: number;
642
+ max_hub_members: number | null;
643
+ seat_minimum: number;
644
+ seat_billed: boolean;
645
+ rate_limit_rpm: number;
646
+ rate_limit_heavy_rpm: number;
647
+ rate_limit_light_rpm: number;
648
+ features: Record<string, unknown>;
649
+ active: boolean;
650
+ created_at: string;
651
+ updated_at: string;
652
+ }
653
+ export interface UserLimits {
654
+ plan_id: string;
655
+ plan_display_name: string;
656
+ memory_limit: number;
657
+ push_limit: number;
658
+ recall_limit: number;
659
+ ask_limit: number;
660
+ ask_model: string;
661
+ dreams_enabled: boolean;
662
+ review_inbox: boolean;
663
+ max_team_hubs: number;
664
+ rate_limit_rpm: number;
665
+ rate_limit_heavy_rpm: number;
666
+ rate_limit_light_rpm: number;
667
+ }
668
+ /** Enriched usage response with plan limits. Backward-compatible with Usage. */
669
+ export interface UsageWithLimits extends Usage {
670
+ limits: UserLimits;
671
+ plan: string;
672
+ plan_display_name: string;
673
+ }
413
674
  export interface MeResponse {
414
675
  user: User;
415
676
  connected_providers?: AuthProviderName[];
@@ -421,6 +682,7 @@ export interface MeResponse {
421
682
  };
422
683
  role: HubRole;
423
684
  }>;
685
+ /** Basic usage from /v1/auth/me. For enriched usage with limits, use settings.usage(). */
424
686
  usage?: Usage;
425
687
  }
426
688
  export interface AuthTokenPair {
@@ -570,8 +832,32 @@ export interface HubInvite {
570
832
  invite_url?: string;
571
833
  expires_at: string;
572
834
  accepted_by?: string | null;
835
+ /**
836
+ * When present, the invite is addressed to a specific existing
837
+ * user. The server writes this field when `createInvite` is
838
+ * called with an `invitee` that resolves to an account. Link-only
839
+ * invites (the legacy copy-link flow) leave this null / omitted.
840
+ */
841
+ invitee_user_id?: string | null;
842
+ /** The email the admin typed. Set for email invites alongside invitee_user_id (if resolved). */
843
+ invitee_email?: string | null;
844
+ /** When the email job was last submitted to the queue. Enqueue time, not confirmed delivery. */
845
+ email_enqueued_at?: string | null;
573
846
  created_at: string;
574
847
  }
848
+ /**
849
+ * HubInviteeInput is the addressed-recipient shape accepted by
850
+ * `hubs.createInvite`. Exactly one of `user_id` or `email` should be
851
+ * set; when both are present the server prefers `user_id`.
852
+ *
853
+ * Unknown emails / user ids do not fail the request — they fall
854
+ * through to a link-only invite so the admin can forward the URL
855
+ * manually.
856
+ */
857
+ export interface HubInviteeInput {
858
+ user_id?: string;
859
+ email?: string;
860
+ }
575
861
  export interface HubOwnershipTransfer {
576
862
  id: string;
577
863
  hub_id: string;
@@ -588,7 +874,6 @@ export interface HubUpdateParams {
588
874
  name?: string;
589
875
  icon?: string;
590
876
  accent?: HubAccent;
591
- slug?: string;
592
877
  allow_contributor_topics?: boolean;
593
878
  allow_contributor_dreams?: boolean;
594
879
  contributor_delete_policy?: ContributorDeletePolicy;
@@ -636,6 +921,14 @@ export interface InviteAcceptResult {
636
921
  hub: Hub;
637
922
  role: HubRole;
638
923
  }
924
+ export interface DevFlagsSettings {
925
+ mockDreams: boolean;
926
+ mockDreaming: boolean;
927
+ mockEmptyInbox: boolean;
928
+ mockProUser: boolean;
929
+ debuggerEnabled: boolean;
930
+ skipRerank: boolean;
931
+ }
639
932
  export interface Settings {
640
933
  dreams_enabled: boolean;
641
934
  dreams_merge_enabled: boolean;
@@ -645,10 +938,24 @@ export interface Settings {
645
938
  dreams_similarity_threshold: number;
646
939
  dreams_staleness_days: number;
647
940
  hub_header_aurora_mode?: "none" | "signature" | "time";
941
+ dev_flags?: DevFlagsSettings;
648
942
  notifications_enabled: boolean;
649
943
  theme: string;
650
944
  [key: string]: unknown;
651
945
  }
946
+ export interface SettingsUpdateInput {
947
+ dreams_enabled?: boolean;
948
+ dreams_merge_enabled?: boolean;
949
+ dreams_archive_enabled?: boolean;
950
+ dreams_organize_enabled?: boolean;
951
+ dreams_excluded_kinds?: MemoryKind[];
952
+ dreams_similarity_threshold?: number;
953
+ dreams_staleness_days?: number;
954
+ hub_header_aurora_mode?: "none" | "signature" | "time";
955
+ dev_flags?: Partial<DevFlagsSettings>;
956
+ notifications_enabled?: boolean;
957
+ theme?: string;
958
+ }
652
959
  export interface Topic {
653
960
  id: string;
654
961
  owner_id: string;
@@ -663,6 +970,24 @@ export interface Topic {
663
970
  created_at: string;
664
971
  updated_at: string;
665
972
  activity_summary?: TopicActivitySummary;
973
+ /** Server-resolved dream-activity aggregate scoped to viewer's last
974
+ * visit of this topic. Clears when viewer calls topics.markVisit. */
975
+ lifecycle?: TopicLifecycle;
976
+ }
977
+ export interface TopicLifecycle {
978
+ delta_since_visit: TopicDeltaSummary | null;
979
+ }
980
+ /**
981
+ * TopicDeltaSummary — aggregate of dream actions touching this topic
982
+ * since the viewer's last visit. Counts are non-overlapping:
983
+ * - added: new inbound from unassigned (from_topic = null, to_topic = this)
984
+ * - reorganized: inter-topic moves involving this topic
985
+ */
986
+ export interface TopicDeltaSummary {
987
+ since_visit_at: string;
988
+ run_ids: string[];
989
+ added: number;
990
+ reorganized: number;
666
991
  }
667
992
  export interface TopicActivityContributor {
668
993
  user_id: string;
@@ -700,6 +1025,20 @@ export interface TopicUpdateParams {
700
1025
  parent_id?: string | null;
701
1026
  pinned?: boolean;
702
1027
  }
1028
+ /**
1029
+ * TopicUpdateErrorCode enumerates the domain-specific error codes the server
1030
+ * can return from PATCH /v1/topics/{id} when a `parent_id` change is
1031
+ * rejected. The SDK surfaces these as MemaxError.code on a rejected update
1032
+ * so the caller can map them to user-facing toasts.
1033
+ *
1034
+ * Note on `invalid_parent`: the server collapses two cases under this code —
1035
+ * (a) the parent id does not exist, and (b) the parent exists but lives in a
1036
+ * different hub. The client cannot tell them apart without a cross-hub read,
1037
+ * and collapsing avoids leaking hub existence across tenants. If a future
1038
+ * admin-tooling use case needs the split, introduce a separate
1039
+ * `cross_hub_parent` code at that point.
1040
+ */
1041
+ export type TopicUpdateErrorCode = "invalid_parent" | "cycle_detected" | "max_depth_subtree" | "max_depth" | "duplicate_name";
703
1042
  export interface TopicReorderOperation {
704
1043
  topic_id: string;
705
1044
  position: number;
@@ -713,8 +1052,40 @@ export interface TopicMemoriesResponse {
713
1052
  export type DreamRunMode = "maintenance" | "bootstrap";
714
1053
  export type DreamRunStatus = "running" | "completed" | "failed";
715
1054
  export type DreamActionType = "merge" | "contradiction" | "archive" | "organize" | "restructure";
716
- export type ReviewType = "contradiction" | "stale" | "proposal" | "low_confidence";
717
- export type ReviewStatus = "pending" | "resolved" | "dismissed";
1055
+ /**
1056
+ * ReviewTopicRef is the shared topic-pointer shape used by enriched
1057
+ * topic_merge and topic_restructure notification payloads. Mirrors
1058
+ * model.ReviewTopicRef on the server. The "Review" prefix is a
1059
+ * historical holdover from the legacy /v1/reviews surface retired in
1060
+ * Phase 6; the type is still reused verbatim by the notification
1061
+ * payloads for review_topic_merge and review_topic_restructure.
1062
+ */
1063
+ export interface ReviewTopicRef {
1064
+ id: string;
1065
+ name: string;
1066
+ memory_count?: number;
1067
+ }
1068
+ /**
1069
+ * Payload shape for notifications with kind = "review_topic_merge".
1070
+ * The merge resolve action collapses every entry in source_topics into
1071
+ * target_topic via the server's MergeTopics primitive. source_topics
1072
+ * never includes target_topic — the dream restructure writer filters
1073
+ * it out at write time.
1074
+ */
1075
+ export interface ReviewTopicMergePayload {
1076
+ target_topic: ReviewTopicRef;
1077
+ source_topics: ReviewTopicRef[];
1078
+ reason: string;
1079
+ }
1080
+ /**
1081
+ * Payload shape for notifications with kind = "review_topic_restructure".
1082
+ * The apply resolve action reparents child_topic under parent_topic.
1083
+ */
1084
+ export interface ReviewTopicRestructurePayload {
1085
+ parent_topic: ReviewTopicRef;
1086
+ child_topic: ReviewTopicRef;
1087
+ reason: string;
1088
+ }
718
1089
  export interface DreamRun {
719
1090
  id: string;
720
1091
  owner_id?: string;
@@ -765,32 +1136,345 @@ export interface DreamAction {
765
1136
  similarity: number;
766
1137
  created_at: string;
767
1138
  }
1139
+ export interface DreamLatestRunSummary {
1140
+ merged: number;
1141
+ contradictions_found: number;
1142
+ archived: number;
1143
+ organized: number;
1144
+ restructured: number;
1145
+ }
1146
+ export interface DreamPendingReviewSummary {
1147
+ contradictions: number;
1148
+ topic_merges: number;
1149
+ topic_restructures: number;
1150
+ total: number;
1151
+ }
1152
+ export interface DreamIntelligenceSummary {
1153
+ latest_run?: DreamLatestRunSummary;
1154
+ pending_review: DreamPendingReviewSummary;
1155
+ }
768
1156
  export interface DreamReport {
769
1157
  has_run: boolean;
770
1158
  message?: string;
771
1159
  run?: DreamRun;
772
1160
  actions?: DreamAction[];
773
- pending_reviews?: number;
1161
+ intelligence: DreamIntelligenceSummary;
774
1162
  }
775
- export interface Review {
1163
+ /**
1164
+ * NotificationAudience is the routing enum for notifications:
1165
+ *
1166
+ * - `hub` — reserved for future hub-wide announcements
1167
+ * (no producer in Phase 3b)
1168
+ * - `hub_member` — scoped to members of a specific hub; the
1169
+ * default for review notifications
1170
+ * - `user` — addressed to a specific user regardless of
1171
+ * hub membership; used for dream receipts, hub
1172
+ * invites, system notices
1173
+ */
1174
+ export type NotificationAudience = "hub" | "hub_member" | "user";
1175
+ /**
1176
+ * NotificationStatus is the lifecycle state machine. Read state
1177
+ * lives in `seen_at`, not here: a row can be `status="pending"`
1178
+ * with `seen_at` set, meaning "surfaced but not yet acted on".
1179
+ *
1180
+ * Transitions:
1181
+ * - pending → resolved : every /resolve action (including dismiss)
1182
+ * - pending → dismissed : /dismiss on a receipt row only
1183
+ * - pending → expired : nightly sweep on receipts past expires_at
1184
+ */
1185
+ export type NotificationStatus = "pending" | "resolved" | "dismissed" | "expired";
1186
+ /**
1187
+ * NotificationResolution records which /resolve action actually ran
1188
+ * on a decision row. Non-empty only when status=resolved. Mirrors
1189
+ * the server's notification_resolution Postgres enum.
1190
+ */
1191
+ export type NotificationResolution = "kept_a" | "kept_b" | "kept_both" | "merged" | "kept_separate" | "applied" | "kept" | "dismissed" | "accepted" | "declined";
1192
+ /**
1193
+ * NotificationKind is the open set of kinds the inbox framework
1194
+ * will grow over Phase 3–5. Typed as a union rather than a closed
1195
+ * enum so future scaffold kinds don't require a client bump to
1196
+ * decode a response.
1197
+ */
1198
+ export type NotificationKind = "review_contradiction" | "review_topic_merge" | "review_topic_restructure" | "review_stale" | "review_low_confidence" | "dream_run_completed" | "hub_invite" | "hub_invite_accepted" | "hub_invite_declined" | "hub_invite_declined_by_you" | "hub_member_joined" | "hub_ownership_transfer" | "hub_ownership_transferred" | "system_notice" | "gift_invite_link" | (string & {});
1199
+ /**
1200
+ * Notification is the wire shape for a single row returned by
1201
+ * /v1/notifications. Payload shape varies by `kind` — consumers
1202
+ * do a type switch on `kind` before decoding `payload`.
1203
+ */
1204
+ export interface Notification {
776
1205
  id: string;
777
- owner_id: string;
1206
+ audience: NotificationAudience;
1207
+ /** Required when audience in (hub, hub_member). */
778
1208
  hub_id?: string;
779
- review_type: ReviewType;
780
- status: ReviewStatus;
781
- memory_ids: string[];
782
- dream_run_id?: string;
783
- title: string;
784
- description: string;
785
- similarity: number;
786
- resolution?: ReviewResolution;
1209
+ /** Required when audience = user. */
1210
+ recipient_user_id?: string;
1211
+ /** Optional narrowing for hub_member audience. */
1212
+ hub_member_role?: string;
1213
+ kind: NotificationKind;
1214
+ status: NotificationStatus;
1215
+ /** Set only on resolved decision rows. */
1216
+ resolution?: NotificationResolution;
1217
+ priority: number;
1218
+ source_kind: string;
1219
+ source_id?: string;
1220
+ /**
1221
+ * Per-kind payload. Shape varies:
1222
+ * - review_contradiction → ReviewContradictionPayload
1223
+ * - review_topic_merge → ReviewTopicMergePayload
1224
+ * - review_topic_restructure → ReviewTopicRestructurePayload
1225
+ * - dream_run_completed → DreamRunCompletedPayload
1226
+ * - hub_invite → HubInvitePayload
1227
+ * - other kinds → opaque
1228
+ */
1229
+ payload?: Record<string, unknown>;
787
1230
  created_at: string;
788
- memories: Memory[];
1231
+ expires_at?: string;
1232
+ resolved_at?: string;
1233
+ seen_at?: string;
789
1234
  }
790
- export type ReviewResolution = "keep_a" | "keep_b" | "keep_both" | "dismiss";
791
- export interface ReviewResolutionResult {
1235
+ /**
1236
+ * NotificationKindCount is the per-kind slice of the summary shape.
1237
+ * Both fields are always present, even when zero, per plan §4.4.
1238
+ */
1239
+ export interface NotificationKindCount {
1240
+ pending: number;
1241
+ unseen: number;
1242
+ }
1243
+ /**
1244
+ * NotificationSummary is the response shape for
1245
+ * GET /v1/notifications/summary. Plan §4.4 canonical shape. The
1246
+ * badge dot reads `needs_action_pending`; the Updates header reads
1247
+ * `updates_pending`; the unseen emphasis reads `updates_unseen`;
1248
+ * the settings > dreams contradictions counter reads
1249
+ * `by_kind.review_contradiction.pending`. Every supported kind is
1250
+ * pre-populated with zero counts so consumers can iterate
1251
+ * `by_kind[kind]` without null-checking.
1252
+ */
1253
+ export interface NotificationSummary {
1254
+ needs_action_pending: number;
1255
+ updates_pending: number;
1256
+ updates_unseen: number;
1257
+ by_kind: Record<string, NotificationKindCount>;
1258
+ }
1259
+ /**
1260
+ * NotificationListQuery is the query surface for GET /v1/notifications.
1261
+ * All fields optional; defaults match the server behavior:
1262
+ * - status defaults to "pending"
1263
+ * - limit defaults to 50, max 500
1264
+ */
1265
+ export interface NotificationListQuery {
1266
+ hub?: string;
1267
+ status?: NotificationStatus;
1268
+ /** Repeatable. Narrows to one or more kinds. */
1269
+ kind?: NotificationKind[];
1270
+ /** Repeatable. Only meaningful with status=resolved. */
1271
+ resolution?: NotificationResolution[];
1272
+ unseenOnly?: boolean;
1273
+ /** RFC3339 lower bound on created_at. */
1274
+ since?: string;
1275
+ /** 1..500; default 50. */
1276
+ limit?: number;
1277
+ /** Opaque RFC3339 cursor from a previous list response. */
1278
+ cursor?: string;
1279
+ }
1280
+ /**
1281
+ * NotificationListResponse is the paginated list response shape.
1282
+ */
1283
+ export interface NotificationListResponse {
1284
+ notifications: Notification[];
1285
+ next_cursor?: string;
1286
+ has_more: boolean;
1287
+ }
1288
+ /**
1289
+ * NotificationBulkQuery is the body shape for the bulk seen/dismiss
1290
+ * endpoints. Decision kinds are refused with
1291
+ * `400 bulk_not_allowed_for_decision_kind`.
1292
+ */
1293
+ export interface NotificationBulkQuery {
1294
+ hub?: string;
1295
+ kinds: NotificationKind[];
1296
+ /** RFC3339 lower bound on created_at. */
1297
+ since?: string;
1298
+ }
1299
+ export interface NotificationBulkResult {
1300
+ affected: number;
1301
+ }
1302
+ /**
1303
+ * NotificationResolveAction is the closed set of actions the
1304
+ * /v1/notifications/{id}/resolve endpoint accepts. Kept in lockstep
1305
+ * with the per-kind allow-list in the server notifications handler.
1306
+ */
1307
+ export type NotificationResolveAction = "keep_a" | "keep_b" | "keep_both" | "merge" | "keep_separate" | "apply" | "keep" | "accept" | "decline" | "dismiss";
1308
+ export interface NotificationResolveResult {
792
1309
  status: string;
793
1310
  action: string;
1311
+ resolution: string;
1312
+ }
1313
+ /**
1314
+ * ReviewContradictionPayload is the notification payload shape for
1315
+ * kind = "review_contradiction". Carries lightweight memory refs so
1316
+ * the inbox row can render without a /v1/memories round-trip.
1317
+ */
1318
+ export interface ReviewContradictionPayload {
1319
+ memory_a: ReviewMemoryRef;
1320
+ memory_b: ReviewMemoryRef;
1321
+ similarity: number;
1322
+ reason: string;
1323
+ }
1324
+ /**
1325
+ * ReviewMemoryRef is the lightweight memory pointer used by
1326
+ * review notification payloads.
1327
+ */
1328
+ export interface ReviewMemoryRef {
1329
+ id: string;
1330
+ title: string;
1331
+ }
1332
+ /**
1333
+ * DreamRunCompletedPayload is the payload for kind =
1334
+ * "dream_run_completed". Produced at the end of a successful dream
1335
+ * run, including clean runs with zero counts.
1336
+ *
1337
+ * memories_scanned is embedded here (not read from the active hub's
1338
+ * dream report) because dream_run_completed is a user-audience
1339
+ * notification that can render while the user is browsing an
1340
+ * unrelated hub. Clients MUST read the scan count from the payload,
1341
+ * never from the active hub's dreamReport — see the Phase 4 bar-fix
1342
+ * commit for the original cross-hub leak bug.
1343
+ */
1344
+ export interface DreamRunCompletedPayload {
1345
+ run_id: string;
1346
+ mode: string;
1347
+ counts: DreamRunCounts;
1348
+ memories_scanned: number;
1349
+ finished_at: string;
1350
+ report?: string;
1351
+ touched_topic_ids?: string[];
1352
+ }
1353
+ /**
1354
+ * DreamRunCounts is the per-phase outcome counts embedded in a
1355
+ * dream_run_completed payload.
1356
+ */
1357
+ export interface DreamRunCounts {
1358
+ merged: number;
1359
+ archived: number;
1360
+ organized: number;
1361
+ contradictions: number;
1362
+ restructures: number;
1363
+ }
1364
+ /**
1365
+ * HubInvitePayload is the payload for kind = "hub_invite".
1366
+ */
1367
+ export interface HubInvitePayload {
1368
+ hub: HubInviteHubRef;
1369
+ inviter: HubInviteInviterRef;
1370
+ role: string;
1371
+ expires_at: string;
1372
+ }
1373
+ export interface HubInviteHubRef {
1374
+ id: string;
1375
+ name: string;
1376
+ icon?: string;
1377
+ accent?: string;
1378
+ }
1379
+ export interface HubInviteInviterRef {
1380
+ id: string;
1381
+ display?: string;
1382
+ avatar_url?: string;
1383
+ }
1384
+ /**
1385
+ * HubMemberJoinedPayload is the payload for kind = "hub_member_joined".
1386
+ * Fired to the hub owner when a user accepts an invite.
1387
+ */
1388
+ export interface HubMemberJoinedPayload {
1389
+ hub: HubInviteHubRef;
1390
+ member: HubMemberRef;
1391
+ role: string;
1392
+ }
1393
+ export interface HubMemberRef {
1394
+ id: string;
1395
+ display?: string;
1396
+ avatar_url?: string;
1397
+ }
1398
+ /**
1399
+ * HubInviteAcceptedPayload is the payload for kind =
1400
+ * "hub_invite_accepted" — the invitee's self-receipt after a
1401
+ * successful accept. Renders as "You joined {hub}". Fan-out target
1402
+ * is the invitee themself, not the hub owner (the owner's receipt
1403
+ * is `hub_member_joined`). Both receipts exist so each side of the
1404
+ * accept reads their own view of the same event.
1405
+ */
1406
+ export interface HubInviteAcceptedPayload {
1407
+ hub: HubInviteHubRef;
1408
+ role: string;
1409
+ }
1410
+ /**
1411
+ * HubInviteDeclinedPayload is the payload for kind =
1412
+ * "hub_invite_declined" — fan-out to the original inviter (the
1413
+ * admin who created the invite, via `invite.invited_by`), telling
1414
+ * them their invitee declined. Renders as "{invitee} declined
1415
+ * your invite to {hub}".
1416
+ */
1417
+ export interface HubInviteDeclinedPayload {
1418
+ hub: HubInviteHubRef;
1419
+ invitee: HubMemberRef;
1420
+ }
1421
+ /**
1422
+ * HubInviteDeclinedByYouPayload is the payload for kind =
1423
+ * "hub_invite_declined_by_you" — the invitee's self-receipt after
1424
+ * a decline. Renders as "You declined {hub}". Lives in the Updates
1425
+ * bucket so the invitee has a durable self-oriented record of the
1426
+ * decline.
1427
+ */
1428
+ export interface HubInviteDeclinedByYouPayload {
1429
+ hub: HubInviteHubRef;
1430
+ }
1431
+ /**
1432
+ * SystemNoticePayload is the payload for kind = "system_notice".
1433
+ * Used for product announcements and billing notices. Phase 5 ships
1434
+ * the renderer + types only; producers land alongside the individual
1435
+ * features that emit them.
1436
+ */
1437
+ export interface SystemNoticePayload {
1438
+ title: string;
1439
+ body: string;
1440
+ link?: string;
1441
+ link_text?: string;
1442
+ }
1443
+ /**
1444
+ * GiftInviteLinkPayload is the payload for kind = "gift_invite_link".
1445
+ * Phase 5 ships the renderer only; the gift / referral producer lands
1446
+ * alongside the gift feature.
1447
+ */
1448
+ export interface GiftInviteLinkPayload {
1449
+ sender: HubInviteInviterRef;
1450
+ hub?: HubInviteHubRef;
1451
+ token: string;
1452
+ url?: string;
1453
+ expires_at: string;
1454
+ }
1455
+ /**
1456
+ * HubOwnershipTransferPayload is the payload for kind =
1457
+ * "hub_ownership_transfer". Addressed to the transfer target so the
1458
+ * inbox shows a decision row with accept / decline actions. The
1459
+ * source_id on the notification row is the transfer id, so there is
1460
+ * exactly one pending notification per transfer.
1461
+ */
1462
+ export interface HubOwnershipTransferPayload {
1463
+ hub: HubInviteHubRef;
1464
+ initiator: HubMemberRef;
1465
+ role?: string;
1466
+ expires_at: string;
1467
+ }
1468
+ /**
1469
+ * HubOwnershipTransferredPayload is the payload for kind =
1470
+ * "hub_ownership_transferred" — a receipt fired to both sides of an
1471
+ * accepted ownership handoff. Clients should render recipient-aware
1472
+ * copy from the current user id versus `new_owner.id`.
1473
+ */
1474
+ export interface HubOwnershipTransferredPayload {
1475
+ hub: HubInviteHubRef;
1476
+ new_owner: HubMemberRef;
1477
+ old_owner: HubMemberRef;
794
1478
  }
795
1479
  export interface ConnectedAgent {
796
1480
  id: string;
@@ -806,13 +1490,82 @@ export interface ConnectedAgentWithStats extends ConnectedAgent {
806
1490
  key_count: number;
807
1491
  config_count: number;
808
1492
  memory_count: number;
1493
+ needs_reconnect?: boolean;
809
1494
  last_active_at: string | null;
1495
+ last_operation?: string | null;
1496
+ last_activity_summary?: string | null;
1497
+ last_observed_at?: string | null;
810
1498
  }
811
1499
  export interface ConnectedAgentUpdate {
812
1500
  displayName?: string;
813
1501
  icon?: string;
814
1502
  }
1503
+ /**
1504
+ * Skip reasons for `DELETE /v1/auth/api-keys/{id}`.
1505
+ *
1506
+ * - `not_found`: the key id did not match a row the caller owns.
1507
+ * Unknown id, already revoked, or belongs to another user (the
1508
+ * SQL WHERE clause makes these indistinguishable). Client treats
1509
+ * as idempotent success — the user's target state is reached.
1510
+ * - `revoke_failed`: the DELETE returned a store-level error. Server
1511
+ * still has the key; client rolls back the optimistic removal
1512
+ * and surfaces retry copy.
1513
+ */
1514
+ export type ApiKeyRevokeSkipReason = "not_found" | "revoke_failed";
1515
+ export interface ApiKeyRevokeSkippedItem {
1516
+ id: string;
1517
+ reason: ApiKeyRevokeSkipReason;
1518
+ }
1519
+ /**
1520
+ * Structured response from `DELETE /v1/auth/api-keys/{id}`.
1521
+ *
1522
+ * Always 200 — 4xx/5xx are reserved for full-request failures (bad
1523
+ * path, missing auth). Partial-success semantics mirror
1524
+ * `memories.batchDelete` and `configs.batchDelete`: `revoked: false`
1525
+ * with a non-empty `skipped` array is a normal outcome, and clients
1526
+ * branch on the reason to distinguish idempotent success
1527
+ * (`not_found`) from rollback + retry (`revoke_failed`).
1528
+ */
1529
+ export interface ApiKeyRevokeResult {
1530
+ revoked: boolean;
1531
+ skipped: ApiKeyRevokeSkippedItem[];
1532
+ }
1533
+ /**
1534
+ * Skip reasons for `DELETE /v1/agents/{slug}`.
1535
+ *
1536
+ * - `not_found`: `GetConnectedAgent` did not resolve for the caller.
1537
+ * Unknown slug or another user's agent. Client treats this as
1538
+ * idempotent success — the user's target state is reached.
1539
+ * - `cascade_failed`: the atomic delete tx (revoke keys + tombstone
1540
+ * configs + delete agent row) returned an error. Server still has
1541
+ * the agent; client must roll back the optimistic removal and
1542
+ * surface an inline retry hint.
1543
+ */
1544
+ export type AgentDisconnectSkipReason = "not_found" | "cascade_failed";
1545
+ export interface AgentDisconnectSkippedItem {
1546
+ id: string;
1547
+ reason: AgentDisconnectSkipReason;
1548
+ }
1549
+ /**
1550
+ * Structured response from `DELETE /v1/agents/{slug}`.
1551
+ *
1552
+ * Always 200 — 4xx/5xx are reserved for full-request failures (bad
1553
+ * path, auth). Partial-success semantics: `disconnected: false` with a
1554
+ * non-empty `skipped` array is a normal outcome; clients branch on the
1555
+ * reason to choose between silent success (`not_found`) and rollback
1556
+ * + retry (`cascade_failed`).
1557
+ *
1558
+ * `keys_revoked` / `configs_tombstoned` are pre-query counts — they
1559
+ * describe what the cascade is about to clean up, not the exact exec
1560
+ * RowsAffected. This matches the memory-move pattern of reporting the
1561
+ * user-visible outcome rather than raw DB stats, and gives the web
1562
+ * hook enough data to render "Disconnected claude-code — revoked 3
1563
+ * keys, forgot 12 configs" without waiting for a refetch.
1564
+ */
815
1565
  export interface DisconnectAgentResult {
816
1566
  disconnected: boolean;
1567
+ keys_revoked: number;
1568
+ configs_tombstoned: number;
1569
+ skipped: AgentDisconnectSkippedItem[];
817
1570
  }
818
1571
  //# sourceMappingURL=types.d.ts.map