memax-sdk 0.1.12 → 0.1.14

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 (68) 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 +20 -2
  27. package/dist/resources/auth.d.ts.map +1 -1
  28. package/dist/resources/auth.js +27 -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/resources/uploads.d.ts +8 -1
  55. package/dist/resources/uploads.d.ts.map +1 -1
  56. package/dist/resources/uploads.js +6 -0
  57. package/dist/resources/uploads.js.map +1 -1
  58. package/dist/transport.d.ts +8 -1
  59. package/dist/transport.d.ts.map +1 -1
  60. package/dist/transport.js +20 -2
  61. package/dist/transport.js.map +1 -1
  62. package/dist/types.d.ts +796 -18
  63. package/dist/types.d.ts.map +1 -1
  64. package/package.json +1 -1
  65. package/dist/resources/reviews.d.ts +0 -9
  66. package/dist/resources/reviews.d.ts.map +0 -1
  67. package/dist/resources/reviews.js +0 -16
  68. 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;
@@ -140,6 +327,8 @@ export interface FileRef {
140
327
  size_bytes?: number;
141
328
  sha256?: string;
142
329
  }
330
+ /** Discriminates the two legitimate upload flows. */
331
+ export type UploadPurpose = "memory_attachment" | "agent_session";
143
332
  export interface UploadIntent {
144
333
  object_key: string;
145
334
  upload_url: string;
@@ -147,6 +336,10 @@ export interface UploadIntent {
147
336
  filename: string;
148
337
  content_type: string;
149
338
  size_bytes: number;
339
+ /** The purpose echoed back from the server for client bookkeeping. */
340
+ purpose: UploadPurpose;
341
+ /** The effective server-side cap for this purpose (bytes). */
342
+ max_bytes: number;
150
343
  expires_in: number;
151
344
  }
152
345
  export interface RelatedMemory {
@@ -333,7 +526,7 @@ export interface DeletedAgentSession {
333
526
  content_hash?: string;
334
527
  content_expires_at?: string;
335
528
  }
336
- export type SessionSyncAction = "unchanged" | "push" | "pull" | "conflict" | "delete_local";
529
+ export type SessionSyncAction = "unchanged" | "push" | "pull" | "diverged" | "tombstone_diverged" | "delete_local";
337
530
  export interface SessionSyncPlanAction {
338
531
  action: SessionSyncAction;
339
532
  agent: string;
@@ -343,8 +536,28 @@ export interface SessionSyncPlanAction {
343
536
  session_id?: string;
344
537
  cloud_hash?: string;
345
538
  cloud_updated_at?: string;
539
+ cloud_version?: number;
346
540
  version?: number;
347
541
  }
542
+ /** Request to atomically resolve a diverged session. */
543
+ export interface ResolveDivergenceRequest {
544
+ agent: string;
545
+ file_path: string;
546
+ scope: Scope;
547
+ device_id: string;
548
+ local_file_ref?: FileRef;
549
+ local_content_hash: string;
550
+ expected_cloud_version: number;
551
+ expected_cloud_hash: string;
552
+ resolution: "keep_local" | "keep_cloud";
553
+ }
554
+ /** Response from a successful divergence resolution. */
555
+ export interface ResolveDivergenceResponse {
556
+ winner: "local" | "cloud";
557
+ snapshot_id: string;
558
+ snapshot_device: string;
559
+ new_version: number;
560
+ }
348
561
  export interface SessionSyncManifestEntry {
349
562
  agent: string;
350
563
  file_path: string;
@@ -399,8 +612,12 @@ export interface User {
399
612
  name: string;
400
613
  email: string;
401
614
  plan: string;
615
+ personal_plan_id: string;
402
616
  display_name?: string;
403
617
  avatar_url?: string;
618
+ can_create_hub?: boolean;
619
+ created_at?: string;
620
+ updated_at?: string;
404
621
  }
405
622
  export interface Usage {
406
623
  user_id: string;
@@ -410,6 +627,56 @@ export interface Usage {
410
627
  recall_count: number;
411
628
  ask_count: number;
412
629
  }
630
+ /** Plan scope distinguishes personal plans (assigned to users) from hub plans (assigned to team hubs). */
631
+ export type PlanScope = "personal" | "hub";
632
+ export interface PlanDefinition {
633
+ id: string;
634
+ scope: PlanScope;
635
+ display_name: string;
636
+ tier_order: number;
637
+ entitlement_rank: number;
638
+ monthly_price_cents: number;
639
+ memory_limit: number;
640
+ push_limit: number;
641
+ recall_limit: number;
642
+ ask_limit: number;
643
+ ask_model: "haiku" | "sonnet";
644
+ dreams_enabled: boolean;
645
+ review_inbox: boolean;
646
+ max_team_hubs: number;
647
+ max_owned_free_team_hubs: number;
648
+ max_hub_members: number | null;
649
+ seat_minimum: number;
650
+ seat_billed: boolean;
651
+ rate_limit_rpm: number;
652
+ rate_limit_heavy_rpm: number;
653
+ rate_limit_light_rpm: number;
654
+ features: Record<string, unknown>;
655
+ active: boolean;
656
+ created_at: string;
657
+ updated_at: string;
658
+ }
659
+ export interface UserLimits {
660
+ plan_id: string;
661
+ plan_display_name: string;
662
+ memory_limit: number;
663
+ push_limit: number;
664
+ recall_limit: number;
665
+ ask_limit: number;
666
+ ask_model: string;
667
+ dreams_enabled: boolean;
668
+ review_inbox: boolean;
669
+ max_team_hubs: number;
670
+ rate_limit_rpm: number;
671
+ rate_limit_heavy_rpm: number;
672
+ rate_limit_light_rpm: number;
673
+ }
674
+ /** Enriched usage response with plan limits. Backward-compatible with Usage. */
675
+ export interface UsageWithLimits extends Usage {
676
+ limits: UserLimits;
677
+ plan: string;
678
+ plan_display_name: string;
679
+ }
413
680
  export interface MeResponse {
414
681
  user: User;
415
682
  connected_providers?: AuthProviderName[];
@@ -421,6 +688,7 @@ export interface MeResponse {
421
688
  };
422
689
  role: HubRole;
423
690
  }>;
691
+ /** Basic usage from /v1/auth/me. For enriched usage with limits, use settings.usage(). */
424
692
  usage?: Usage;
425
693
  }
426
694
  export interface AuthTokenPair {
@@ -481,11 +749,30 @@ export interface ApiKeyListItem {
481
749
  hub_scope_mode?: "all_accessible" | "hub_allowlist";
482
750
  default_permissions?: string[];
483
751
  trust_level?: "public" | "standard" | "elevated" | "admin";
752
+ /** Structured agent attribution. Empty string = unassigned. */
484
753
  agent_name?: string;
754
+ /**
755
+ * Explicit "no agent, by design" flag. Keys used by CI/scripts can be
756
+ * marked standalone so the Assign affordance stops nagging. Defaults
757
+ * to false; every new unassigned key shows the affordance until the
758
+ * user either assigns an agent or marks it standalone.
759
+ */
760
+ standalone?: boolean;
485
761
  expires_at: string | null;
486
762
  last_used: string | null;
487
763
  created_at: string;
488
764
  }
765
+ export interface UpdateApiKeyPayload {
766
+ /** Empty string clears the assignment. Omit to leave unchanged. */
767
+ agent_name?: string;
768
+ /** Toggle explicit "no agent, by design" state. Omit to leave unchanged. */
769
+ standalone?: boolean;
770
+ }
771
+ export interface UpdateApiKeyResult {
772
+ id: string;
773
+ agent_name: string;
774
+ standalone: boolean;
775
+ }
489
776
  export interface UpdateProfileResult {
490
777
  status: string;
491
778
  display_name: string;
@@ -570,8 +857,32 @@ export interface HubInvite {
570
857
  invite_url?: string;
571
858
  expires_at: string;
572
859
  accepted_by?: string | null;
860
+ /**
861
+ * When present, the invite is addressed to a specific existing
862
+ * user. The server writes this field when `createInvite` is
863
+ * called with an `invitee` that resolves to an account. Link-only
864
+ * invites (the legacy copy-link flow) leave this null / omitted.
865
+ */
866
+ invitee_user_id?: string | null;
867
+ /** The email the admin typed. Set for email invites alongside invitee_user_id (if resolved). */
868
+ invitee_email?: string | null;
869
+ /** When the email job was last submitted to the queue. Enqueue time, not confirmed delivery. */
870
+ email_enqueued_at?: string | null;
573
871
  created_at: string;
574
872
  }
873
+ /**
874
+ * HubInviteeInput is the addressed-recipient shape accepted by
875
+ * `hubs.createInvite`. Exactly one of `user_id` or `email` should be
876
+ * set; when both are present the server prefers `user_id`.
877
+ *
878
+ * Unknown emails / user ids do not fail the request — they fall
879
+ * through to a link-only invite so the admin can forward the URL
880
+ * manually.
881
+ */
882
+ export interface HubInviteeInput {
883
+ user_id?: string;
884
+ email?: string;
885
+ }
575
886
  export interface HubOwnershipTransfer {
576
887
  id: string;
577
888
  hub_id: string;
@@ -588,7 +899,6 @@ export interface HubUpdateParams {
588
899
  name?: string;
589
900
  icon?: string;
590
901
  accent?: HubAccent;
591
- slug?: string;
592
902
  allow_contributor_topics?: boolean;
593
903
  allow_contributor_dreams?: boolean;
594
904
  contributor_delete_policy?: ContributorDeletePolicy;
@@ -636,6 +946,14 @@ export interface InviteAcceptResult {
636
946
  hub: Hub;
637
947
  role: HubRole;
638
948
  }
949
+ export interface DevFlagsSettings {
950
+ mockDreams: boolean;
951
+ mockDreaming: boolean;
952
+ mockEmptyInbox: boolean;
953
+ mockProUser: boolean;
954
+ debuggerEnabled: boolean;
955
+ skipRerank: boolean;
956
+ }
639
957
  export interface Settings {
640
958
  dreams_enabled: boolean;
641
959
  dreams_merge_enabled: boolean;
@@ -645,10 +963,24 @@ export interface Settings {
645
963
  dreams_similarity_threshold: number;
646
964
  dreams_staleness_days: number;
647
965
  hub_header_aurora_mode?: "none" | "signature" | "time";
966
+ dev_flags?: DevFlagsSettings;
648
967
  notifications_enabled: boolean;
649
968
  theme: string;
650
969
  [key: string]: unknown;
651
970
  }
971
+ export interface SettingsUpdateInput {
972
+ dreams_enabled?: boolean;
973
+ dreams_merge_enabled?: boolean;
974
+ dreams_archive_enabled?: boolean;
975
+ dreams_organize_enabled?: boolean;
976
+ dreams_excluded_kinds?: MemoryKind[];
977
+ dreams_similarity_threshold?: number;
978
+ dreams_staleness_days?: number;
979
+ hub_header_aurora_mode?: "none" | "signature" | "time";
980
+ dev_flags?: Partial<DevFlagsSettings>;
981
+ notifications_enabled?: boolean;
982
+ theme?: string;
983
+ }
652
984
  export interface Topic {
653
985
  id: string;
654
986
  owner_id: string;
@@ -663,6 +995,24 @@ export interface Topic {
663
995
  created_at: string;
664
996
  updated_at: string;
665
997
  activity_summary?: TopicActivitySummary;
998
+ /** Server-resolved dream-activity aggregate scoped to viewer's last
999
+ * visit of this topic. Clears when viewer calls topics.markVisit. */
1000
+ lifecycle?: TopicLifecycle;
1001
+ }
1002
+ export interface TopicLifecycle {
1003
+ delta_since_visit: TopicDeltaSummary | null;
1004
+ }
1005
+ /**
1006
+ * TopicDeltaSummary — aggregate of dream actions touching this topic
1007
+ * since the viewer's last visit. Counts are non-overlapping:
1008
+ * - added: new inbound from unassigned (from_topic = null, to_topic = this)
1009
+ * - reorganized: inter-topic moves involving this topic
1010
+ */
1011
+ export interface TopicDeltaSummary {
1012
+ since_visit_at: string;
1013
+ run_ids: string[];
1014
+ added: number;
1015
+ reorganized: number;
666
1016
  }
667
1017
  export interface TopicActivityContributor {
668
1018
  user_id: string;
@@ -700,6 +1050,20 @@ export interface TopicUpdateParams {
700
1050
  parent_id?: string | null;
701
1051
  pinned?: boolean;
702
1052
  }
1053
+ /**
1054
+ * TopicUpdateErrorCode enumerates the domain-specific error codes the server
1055
+ * can return from PATCH /v1/topics/{id} when a `parent_id` change is
1056
+ * rejected. The SDK surfaces these as MemaxError.code on a rejected update
1057
+ * so the caller can map them to user-facing toasts.
1058
+ *
1059
+ * Note on `invalid_parent`: the server collapses two cases under this code —
1060
+ * (a) the parent id does not exist, and (b) the parent exists but lives in a
1061
+ * different hub. The client cannot tell them apart without a cross-hub read,
1062
+ * and collapsing avoids leaking hub existence across tenants. If a future
1063
+ * admin-tooling use case needs the split, introduce a separate
1064
+ * `cross_hub_parent` code at that point.
1065
+ */
1066
+ export type TopicUpdateErrorCode = "invalid_parent" | "cycle_detected" | "max_depth_subtree" | "max_depth" | "duplicate_name";
703
1067
  export interface TopicReorderOperation {
704
1068
  topic_id: string;
705
1069
  position: number;
@@ -713,8 +1077,40 @@ export interface TopicMemoriesResponse {
713
1077
  export type DreamRunMode = "maintenance" | "bootstrap";
714
1078
  export type DreamRunStatus = "running" | "completed" | "failed";
715
1079
  export type DreamActionType = "merge" | "contradiction" | "archive" | "organize" | "restructure";
716
- export type ReviewType = "contradiction" | "stale" | "proposal" | "low_confidence";
717
- export type ReviewStatus = "pending" | "resolved" | "dismissed";
1080
+ /**
1081
+ * ReviewTopicRef is the shared topic-pointer shape used by enriched
1082
+ * topic_merge and topic_restructure notification payloads. Mirrors
1083
+ * model.ReviewTopicRef on the server. The "Review" prefix is a
1084
+ * historical holdover from the legacy /v1/reviews surface retired in
1085
+ * Phase 6; the type is still reused verbatim by the notification
1086
+ * payloads for review_topic_merge and review_topic_restructure.
1087
+ */
1088
+ export interface ReviewTopicRef {
1089
+ id: string;
1090
+ name: string;
1091
+ memory_count?: number;
1092
+ }
1093
+ /**
1094
+ * Payload shape for notifications with kind = "review_topic_merge".
1095
+ * The merge resolve action collapses every entry in source_topics into
1096
+ * target_topic via the server's MergeTopics primitive. source_topics
1097
+ * never includes target_topic — the dream restructure writer filters
1098
+ * it out at write time.
1099
+ */
1100
+ export interface ReviewTopicMergePayload {
1101
+ target_topic: ReviewTopicRef;
1102
+ source_topics: ReviewTopicRef[];
1103
+ reason: string;
1104
+ }
1105
+ /**
1106
+ * Payload shape for notifications with kind = "review_topic_restructure".
1107
+ * The apply resolve action reparents child_topic under parent_topic.
1108
+ */
1109
+ export interface ReviewTopicRestructurePayload {
1110
+ parent_topic: ReviewTopicRef;
1111
+ child_topic: ReviewTopicRef;
1112
+ reason: string;
1113
+ }
718
1114
  export interface DreamRun {
719
1115
  id: string;
720
1116
  owner_id?: string;
@@ -765,32 +1161,345 @@ export interface DreamAction {
765
1161
  similarity: number;
766
1162
  created_at: string;
767
1163
  }
1164
+ export interface DreamLatestRunSummary {
1165
+ merged: number;
1166
+ contradictions_found: number;
1167
+ archived: number;
1168
+ organized: number;
1169
+ restructured: number;
1170
+ }
1171
+ export interface DreamPendingReviewSummary {
1172
+ contradictions: number;
1173
+ topic_merges: number;
1174
+ topic_restructures: number;
1175
+ total: number;
1176
+ }
1177
+ export interface DreamIntelligenceSummary {
1178
+ latest_run?: DreamLatestRunSummary;
1179
+ pending_review: DreamPendingReviewSummary;
1180
+ }
768
1181
  export interface DreamReport {
769
1182
  has_run: boolean;
770
1183
  message?: string;
771
1184
  run?: DreamRun;
772
1185
  actions?: DreamAction[];
773
- pending_reviews?: number;
1186
+ intelligence: DreamIntelligenceSummary;
774
1187
  }
775
- export interface Review {
1188
+ /**
1189
+ * NotificationAudience is the routing enum for notifications:
1190
+ *
1191
+ * - `hub` — reserved for future hub-wide announcements
1192
+ * (no producer in Phase 3b)
1193
+ * - `hub_member` — scoped to members of a specific hub; the
1194
+ * default for review notifications
1195
+ * - `user` — addressed to a specific user regardless of
1196
+ * hub membership; used for dream receipts, hub
1197
+ * invites, system notices
1198
+ */
1199
+ export type NotificationAudience = "hub" | "hub_member" | "user";
1200
+ /**
1201
+ * NotificationStatus is the lifecycle state machine. Read state
1202
+ * lives in `seen_at`, not here: a row can be `status="pending"`
1203
+ * with `seen_at` set, meaning "surfaced but not yet acted on".
1204
+ *
1205
+ * Transitions:
1206
+ * - pending → resolved : every /resolve action (including dismiss)
1207
+ * - pending → dismissed : /dismiss on a receipt row only
1208
+ * - pending → expired : nightly sweep on receipts past expires_at
1209
+ */
1210
+ export type NotificationStatus = "pending" | "resolved" | "dismissed" | "expired";
1211
+ /**
1212
+ * NotificationResolution records which /resolve action actually ran
1213
+ * on a decision row. Non-empty only when status=resolved. Mirrors
1214
+ * the server's notification_resolution Postgres enum.
1215
+ */
1216
+ export type NotificationResolution = "kept_a" | "kept_b" | "kept_both" | "merged" | "kept_separate" | "applied" | "kept" | "dismissed" | "accepted" | "declined";
1217
+ /**
1218
+ * NotificationKind is the open set of kinds the inbox framework
1219
+ * will grow over Phase 3–5. Typed as a union rather than a closed
1220
+ * enum so future scaffold kinds don't require a client bump to
1221
+ * decode a response.
1222
+ */
1223
+ 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 & {});
1224
+ /**
1225
+ * Notification is the wire shape for a single row returned by
1226
+ * /v1/notifications. Payload shape varies by `kind` — consumers
1227
+ * do a type switch on `kind` before decoding `payload`.
1228
+ */
1229
+ export interface Notification {
776
1230
  id: string;
777
- owner_id: string;
1231
+ audience: NotificationAudience;
1232
+ /** Required when audience in (hub, hub_member). */
778
1233
  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;
1234
+ /** Required when audience = user. */
1235
+ recipient_user_id?: string;
1236
+ /** Optional narrowing for hub_member audience. */
1237
+ hub_member_role?: string;
1238
+ kind: NotificationKind;
1239
+ status: NotificationStatus;
1240
+ /** Set only on resolved decision rows. */
1241
+ resolution?: NotificationResolution;
1242
+ priority: number;
1243
+ source_kind: string;
1244
+ source_id?: string;
1245
+ /**
1246
+ * Per-kind payload. Shape varies:
1247
+ * - review_contradiction → ReviewContradictionPayload
1248
+ * - review_topic_merge → ReviewTopicMergePayload
1249
+ * - review_topic_restructure → ReviewTopicRestructurePayload
1250
+ * - dream_run_completed → DreamRunCompletedPayload
1251
+ * - hub_invite → HubInvitePayload
1252
+ * - other kinds → opaque
1253
+ */
1254
+ payload?: Record<string, unknown>;
787
1255
  created_at: string;
788
- memories: Memory[];
1256
+ expires_at?: string;
1257
+ resolved_at?: string;
1258
+ seen_at?: string;
1259
+ }
1260
+ /**
1261
+ * NotificationKindCount is the per-kind slice of the summary shape.
1262
+ * Both fields are always present, even when zero, per plan §4.4.
1263
+ */
1264
+ export interface NotificationKindCount {
1265
+ pending: number;
1266
+ unseen: number;
1267
+ }
1268
+ /**
1269
+ * NotificationSummary is the response shape for
1270
+ * GET /v1/notifications/summary. Plan §4.4 canonical shape. The
1271
+ * badge dot reads `needs_action_pending`; the Updates header reads
1272
+ * `updates_pending`; the unseen emphasis reads `updates_unseen`;
1273
+ * the settings > dreams contradictions counter reads
1274
+ * `by_kind.review_contradiction.pending`. Every supported kind is
1275
+ * pre-populated with zero counts so consumers can iterate
1276
+ * `by_kind[kind]` without null-checking.
1277
+ */
1278
+ export interface NotificationSummary {
1279
+ needs_action_pending: number;
1280
+ updates_pending: number;
1281
+ updates_unseen: number;
1282
+ by_kind: Record<string, NotificationKindCount>;
1283
+ }
1284
+ /**
1285
+ * NotificationListQuery is the query surface for GET /v1/notifications.
1286
+ * All fields optional; defaults match the server behavior:
1287
+ * - status defaults to "pending"
1288
+ * - limit defaults to 50, max 500
1289
+ */
1290
+ export interface NotificationListQuery {
1291
+ hub?: string;
1292
+ status?: NotificationStatus;
1293
+ /** Repeatable. Narrows to one or more kinds. */
1294
+ kind?: NotificationKind[];
1295
+ /** Repeatable. Only meaningful with status=resolved. */
1296
+ resolution?: NotificationResolution[];
1297
+ unseenOnly?: boolean;
1298
+ /** RFC3339 lower bound on created_at. */
1299
+ since?: string;
1300
+ /** 1..500; default 50. */
1301
+ limit?: number;
1302
+ /** Opaque RFC3339 cursor from a previous list response. */
1303
+ cursor?: string;
1304
+ }
1305
+ /**
1306
+ * NotificationListResponse is the paginated list response shape.
1307
+ */
1308
+ export interface NotificationListResponse {
1309
+ notifications: Notification[];
1310
+ next_cursor?: string;
1311
+ has_more: boolean;
1312
+ }
1313
+ /**
1314
+ * NotificationBulkQuery is the body shape for the bulk seen/dismiss
1315
+ * endpoints. Decision kinds are refused with
1316
+ * `400 bulk_not_allowed_for_decision_kind`.
1317
+ */
1318
+ export interface NotificationBulkQuery {
1319
+ hub?: string;
1320
+ kinds: NotificationKind[];
1321
+ /** RFC3339 lower bound on created_at. */
1322
+ since?: string;
1323
+ }
1324
+ export interface NotificationBulkResult {
1325
+ affected: number;
789
1326
  }
790
- export type ReviewResolution = "keep_a" | "keep_b" | "keep_both" | "dismiss";
791
- export interface ReviewResolutionResult {
1327
+ /**
1328
+ * NotificationResolveAction is the closed set of actions the
1329
+ * /v1/notifications/{id}/resolve endpoint accepts. Kept in lockstep
1330
+ * with the per-kind allow-list in the server notifications handler.
1331
+ */
1332
+ export type NotificationResolveAction = "keep_a" | "keep_b" | "keep_both" | "merge" | "keep_separate" | "apply" | "keep" | "accept" | "decline" | "dismiss";
1333
+ export interface NotificationResolveResult {
792
1334
  status: string;
793
1335
  action: string;
1336
+ resolution: string;
1337
+ }
1338
+ /**
1339
+ * ReviewContradictionPayload is the notification payload shape for
1340
+ * kind = "review_contradiction". Carries lightweight memory refs so
1341
+ * the inbox row can render without a /v1/memories round-trip.
1342
+ */
1343
+ export interface ReviewContradictionPayload {
1344
+ memory_a: ReviewMemoryRef;
1345
+ memory_b: ReviewMemoryRef;
1346
+ similarity: number;
1347
+ reason: string;
1348
+ }
1349
+ /**
1350
+ * ReviewMemoryRef is the lightweight memory pointer used by
1351
+ * review notification payloads.
1352
+ */
1353
+ export interface ReviewMemoryRef {
1354
+ id: string;
1355
+ title: string;
1356
+ }
1357
+ /**
1358
+ * DreamRunCompletedPayload is the payload for kind =
1359
+ * "dream_run_completed". Produced at the end of a successful dream
1360
+ * run, including clean runs with zero counts.
1361
+ *
1362
+ * memories_scanned is embedded here (not read from the active hub's
1363
+ * dream report) because dream_run_completed is a user-audience
1364
+ * notification that can render while the user is browsing an
1365
+ * unrelated hub. Clients MUST read the scan count from the payload,
1366
+ * never from the active hub's dreamReport — see the Phase 4 bar-fix
1367
+ * commit for the original cross-hub leak bug.
1368
+ */
1369
+ export interface DreamRunCompletedPayload {
1370
+ run_id: string;
1371
+ mode: string;
1372
+ counts: DreamRunCounts;
1373
+ memories_scanned: number;
1374
+ finished_at: string;
1375
+ report?: string;
1376
+ touched_topic_ids?: string[];
1377
+ }
1378
+ /**
1379
+ * DreamRunCounts is the per-phase outcome counts embedded in a
1380
+ * dream_run_completed payload.
1381
+ */
1382
+ export interface DreamRunCounts {
1383
+ merged: number;
1384
+ archived: number;
1385
+ organized: number;
1386
+ contradictions: number;
1387
+ restructures: number;
1388
+ }
1389
+ /**
1390
+ * HubInvitePayload is the payload for kind = "hub_invite".
1391
+ */
1392
+ export interface HubInvitePayload {
1393
+ hub: HubInviteHubRef;
1394
+ inviter: HubInviteInviterRef;
1395
+ role: string;
1396
+ expires_at: string;
1397
+ }
1398
+ export interface HubInviteHubRef {
1399
+ id: string;
1400
+ name: string;
1401
+ icon?: string;
1402
+ accent?: string;
1403
+ }
1404
+ export interface HubInviteInviterRef {
1405
+ id: string;
1406
+ display?: string;
1407
+ avatar_url?: string;
1408
+ }
1409
+ /**
1410
+ * HubMemberJoinedPayload is the payload for kind = "hub_member_joined".
1411
+ * Fired to the hub owner when a user accepts an invite.
1412
+ */
1413
+ export interface HubMemberJoinedPayload {
1414
+ hub: HubInviteHubRef;
1415
+ member: HubMemberRef;
1416
+ role: string;
1417
+ }
1418
+ export interface HubMemberRef {
1419
+ id: string;
1420
+ display?: string;
1421
+ avatar_url?: string;
1422
+ }
1423
+ /**
1424
+ * HubInviteAcceptedPayload is the payload for kind =
1425
+ * "hub_invite_accepted" — the invitee's self-receipt after a
1426
+ * successful accept. Renders as "You joined {hub}". Fan-out target
1427
+ * is the invitee themself, not the hub owner (the owner's receipt
1428
+ * is `hub_member_joined`). Both receipts exist so each side of the
1429
+ * accept reads their own view of the same event.
1430
+ */
1431
+ export interface HubInviteAcceptedPayload {
1432
+ hub: HubInviteHubRef;
1433
+ role: string;
1434
+ }
1435
+ /**
1436
+ * HubInviteDeclinedPayload is the payload for kind =
1437
+ * "hub_invite_declined" — fan-out to the original inviter (the
1438
+ * admin who created the invite, via `invite.invited_by`), telling
1439
+ * them their invitee declined. Renders as "{invitee} declined
1440
+ * your invite to {hub}".
1441
+ */
1442
+ export interface HubInviteDeclinedPayload {
1443
+ hub: HubInviteHubRef;
1444
+ invitee: HubMemberRef;
1445
+ }
1446
+ /**
1447
+ * HubInviteDeclinedByYouPayload is the payload for kind =
1448
+ * "hub_invite_declined_by_you" — the invitee's self-receipt after
1449
+ * a decline. Renders as "You declined {hub}". Lives in the Updates
1450
+ * bucket so the invitee has a durable self-oriented record of the
1451
+ * decline.
1452
+ */
1453
+ export interface HubInviteDeclinedByYouPayload {
1454
+ hub: HubInviteHubRef;
1455
+ }
1456
+ /**
1457
+ * SystemNoticePayload is the payload for kind = "system_notice".
1458
+ * Used for product announcements and billing notices. Phase 5 ships
1459
+ * the renderer + types only; producers land alongside the individual
1460
+ * features that emit them.
1461
+ */
1462
+ export interface SystemNoticePayload {
1463
+ title: string;
1464
+ body: string;
1465
+ link?: string;
1466
+ link_text?: string;
1467
+ }
1468
+ /**
1469
+ * GiftInviteLinkPayload is the payload for kind = "gift_invite_link".
1470
+ * Phase 5 ships the renderer only; the gift / referral producer lands
1471
+ * alongside the gift feature.
1472
+ */
1473
+ export interface GiftInviteLinkPayload {
1474
+ sender: HubInviteInviterRef;
1475
+ hub?: HubInviteHubRef;
1476
+ token: string;
1477
+ url?: string;
1478
+ expires_at: string;
1479
+ }
1480
+ /**
1481
+ * HubOwnershipTransferPayload is the payload for kind =
1482
+ * "hub_ownership_transfer". Addressed to the transfer target so the
1483
+ * inbox shows a decision row with accept / decline actions. The
1484
+ * source_id on the notification row is the transfer id, so there is
1485
+ * exactly one pending notification per transfer.
1486
+ */
1487
+ export interface HubOwnershipTransferPayload {
1488
+ hub: HubInviteHubRef;
1489
+ initiator: HubMemberRef;
1490
+ role?: string;
1491
+ expires_at: string;
1492
+ }
1493
+ /**
1494
+ * HubOwnershipTransferredPayload is the payload for kind =
1495
+ * "hub_ownership_transferred" — a receipt fired to both sides of an
1496
+ * accepted ownership handoff. Clients should render recipient-aware
1497
+ * copy from the current user id versus `new_owner.id`.
1498
+ */
1499
+ export interface HubOwnershipTransferredPayload {
1500
+ hub: HubInviteHubRef;
1501
+ new_owner: HubMemberRef;
1502
+ old_owner: HubMemberRef;
794
1503
  }
795
1504
  export interface ConnectedAgent {
796
1505
  id: string;
@@ -806,13 +1515,82 @@ export interface ConnectedAgentWithStats extends ConnectedAgent {
806
1515
  key_count: number;
807
1516
  config_count: number;
808
1517
  memory_count: number;
1518
+ needs_reconnect?: boolean;
809
1519
  last_active_at: string | null;
1520
+ last_operation?: string | null;
1521
+ last_activity_summary?: string | null;
1522
+ last_observed_at?: string | null;
810
1523
  }
811
1524
  export interface ConnectedAgentUpdate {
812
1525
  displayName?: string;
813
1526
  icon?: string;
814
1527
  }
1528
+ /**
1529
+ * Skip reasons for `DELETE /v1/auth/api-keys/{id}`.
1530
+ *
1531
+ * - `not_found`: the key id did not match a row the caller owns.
1532
+ * Unknown id, already revoked, or belongs to another user (the
1533
+ * SQL WHERE clause makes these indistinguishable). Client treats
1534
+ * as idempotent success — the user's target state is reached.
1535
+ * - `revoke_failed`: the DELETE returned a store-level error. Server
1536
+ * still has the key; client rolls back the optimistic removal
1537
+ * and surfaces retry copy.
1538
+ */
1539
+ export type ApiKeyRevokeSkipReason = "not_found" | "revoke_failed";
1540
+ export interface ApiKeyRevokeSkippedItem {
1541
+ id: string;
1542
+ reason: ApiKeyRevokeSkipReason;
1543
+ }
1544
+ /**
1545
+ * Structured response from `DELETE /v1/auth/api-keys/{id}`.
1546
+ *
1547
+ * Always 200 — 4xx/5xx are reserved for full-request failures (bad
1548
+ * path, missing auth). Partial-success semantics mirror
1549
+ * `memories.batchDelete` and `configs.batchDelete`: `revoked: false`
1550
+ * with a non-empty `skipped` array is a normal outcome, and clients
1551
+ * branch on the reason to distinguish idempotent success
1552
+ * (`not_found`) from rollback + retry (`revoke_failed`).
1553
+ */
1554
+ export interface ApiKeyRevokeResult {
1555
+ revoked: boolean;
1556
+ skipped: ApiKeyRevokeSkippedItem[];
1557
+ }
1558
+ /**
1559
+ * Skip reasons for `DELETE /v1/agents/{slug}`.
1560
+ *
1561
+ * - `not_found`: `GetConnectedAgent` did not resolve for the caller.
1562
+ * Unknown slug or another user's agent. Client treats this as
1563
+ * idempotent success — the user's target state is reached.
1564
+ * - `cascade_failed`: the atomic delete tx (revoke keys + tombstone
1565
+ * configs + delete agent row) returned an error. Server still has
1566
+ * the agent; client must roll back the optimistic removal and
1567
+ * surface an inline retry hint.
1568
+ */
1569
+ export type AgentDisconnectSkipReason = "not_found" | "cascade_failed";
1570
+ export interface AgentDisconnectSkippedItem {
1571
+ id: string;
1572
+ reason: AgentDisconnectSkipReason;
1573
+ }
1574
+ /**
1575
+ * Structured response from `DELETE /v1/agents/{slug}`.
1576
+ *
1577
+ * Always 200 — 4xx/5xx are reserved for full-request failures (bad
1578
+ * path, auth). Partial-success semantics: `disconnected: false` with a
1579
+ * non-empty `skipped` array is a normal outcome; clients branch on the
1580
+ * reason to choose between silent success (`not_found`) and rollback
1581
+ * + retry (`cascade_failed`).
1582
+ *
1583
+ * `keys_revoked` / `configs_tombstoned` are pre-query counts — they
1584
+ * describe what the cascade is about to clean up, not the exact exec
1585
+ * RowsAffected. This matches the memory-move pattern of reporting the
1586
+ * user-visible outcome rather than raw DB stats, and gives the web
1587
+ * hook enough data to render "Disconnected claude-code — revoked 3
1588
+ * keys, forgot 12 configs" without waiting for a refetch.
1589
+ */
815
1590
  export interface DisconnectAgentResult {
816
1591
  disconnected: boolean;
1592
+ keys_revoked: number;
1593
+ configs_tombstoned: number;
1594
+ skipped: AgentDisconnectSkippedItem[];
817
1595
  }
818
1596
  //# sourceMappingURL=types.d.ts.map