@crossworks/client-types 0.232.356 → 0.232.365

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crossworks/client-types",
3
- "version": "0.232.356",
3
+ "version": "0.232.365",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
package/src/app-nav.ts CHANGED
@@ -29,6 +29,7 @@ export const APP_TINTS = [
29
29
  'lime',
30
30
  'green',
31
31
  'teal',
32
+ 'cyan',
32
33
  'sky',
33
34
  'blue',
34
35
  'indigo',
package/src/dto/access.ts CHANGED
@@ -26,7 +26,8 @@ export type AccessLinkView = {
26
26
  token: string;
27
27
  path: string;
28
28
  mode: ShareMode;
29
- /** Page links only: sub-pages are shared with it. */
29
+ /** DEPRECATED (folder phase 7): a page link no longer shares sub-pages
30
+ * (pages do not nest); always false. Kept for older clients. */
30
31
  cascade: boolean;
31
32
  };
32
33
 
@@ -52,7 +53,8 @@ export type AccessNodeView = {
52
53
  * contents, which keep their own levels. */
53
54
  closure: AccessItemView[];
54
55
  share: AccessLinkView | null;
55
- /** Descendant pages (pages only; 0 otherwise). */
56
+ /** DEPRECATED (folder phase 7): pages do not nest, so always 0. Kept for
57
+ * older clients, which showed "Include sub-pages" above 0. */
56
58
  childCount: number;
57
59
  /** Only workspace kinds go below admin (tasks, events, … are admin only). */
58
60
  canLower: boolean;
@@ -77,6 +79,30 @@ export type AccessNodeView = {
77
79
  /** The shared folder it takes its share from (folder sharing); null when
78
80
  * none. Absent from brains before folder sharing. */
79
81
  sharedVia?: AccessSharedVia | null;
82
+ /** What it is read through by embeds (migration 0208); null when nothing
83
+ * reaches it. Absent from brains before 0208. */
84
+ readThrough?: AccessReadThrough | null;
85
+ };
86
+
87
+ /** An item is read through the items that embed it (migration 0208): a
88
+ * shared note makes its image readable wherever the image lives. The item
89
+ * is read at least at `level`, whatever its own level says, so the control
90
+ * offers nothing above it: take the embed out, or move the embedder out of
91
+ * its shared folder, to hide it. */
92
+ export type AccessReadThrough = {
93
+ level: 'team' | 'client';
94
+ /** The nearest items that embed it and carry a share, most open first
95
+ * (at most five). */
96
+ via: Array<{
97
+ id: string;
98
+ title: string;
99
+ /** The node type ('note', 'page', 'draw', ...). */
100
+ type: string;
101
+ level: 'team' | 'client';
102
+ /** 'folder': shared by its own folder; 'embed': itself read through
103
+ * another embed. */
104
+ through: 'folder' | 'embed';
105
+ }>;
80
106
  };
81
107
 
82
108
  /** The nearest shared folder holding an item (folder sharing, phase 4). The
package/src/dto/client.ts CHANGED
@@ -61,7 +61,7 @@ export type ClientSharedPage = {
61
61
  * a mention chip or a link names "Private item" and points nowhere, an
62
62
  * embed of such an item is left out. */
63
63
  export type ClientSharedItem =
64
- | (ClientSharedRow & { type: 'page'; doc: unknown })
64
+ | (ClientSharedRow & { type: 'page'; doc: unknown; folderId?: string | null })
65
65
  | (ClientSharedRow & { type: 'note'; content: string })
66
66
  | (ClientSharedRow & { type: 'table'; table: ClientSharedTable })
67
67
  | (ClientSharedRow & { type: 'draw' })
@@ -342,7 +342,7 @@ export type ClientSpaceRefusedReason =
342
342
  * current version). A file's bytes: /api/client/files/:id while the brain
343
343
  * file still holds the bytes accepted (`changedByAdmin` otherwise). */
344
344
  export type ClientAcceptedItem =
345
- | (ClientAcceptedBase & { type: 'page'; doc: unknown })
345
+ | (ClientAcceptedBase & { type: 'page'; doc: unknown; folderId?: string | null })
346
346
  | (ClientAcceptedBase & { type: 'note'; content: string })
347
347
  | (ClientAcceptedBase & {
348
348
  type: 'file';
package/src/dto/member.ts CHANGED
@@ -64,7 +64,7 @@ export type MemberLibraryPage = {
64
64
 
65
65
  /** GET /api/member/library/:id -> { item } */
66
66
  export type MemberLibraryItem =
67
- | (MemberLibraryRow & { type: 'page'; doc: unknown })
67
+ | (MemberLibraryRow & { type: 'page'; doc: unknown; folderId?: string | null })
68
68
  | (MemberLibraryRow & { type: 'note'; content: string })
69
69
  | (MemberLibraryRow & { type: 'table'; table: unknown })
70
70
  | (MemberLibraryRow & { type: 'draw' })
@@ -248,7 +248,7 @@ export type MemberAcceptedPage = {
248
248
  * saved picture) since, so its bytes are not served any more; the metadata
249
249
  * is what was accepted. */
250
250
  export type MemberAcceptedItem =
251
- | (MemberAcceptedRow & { type: 'page'; doc: unknown })
251
+ | (MemberAcceptedRow & { type: 'page'; doc: unknown; folderId?: string | null })
252
252
  | (MemberAcceptedRow & { type: 'note'; content: string })
253
253
  | (MemberAcceptedRow & { type: 'table'; table: unknown })
254
254
  | (MemberAcceptedRow & { type: 'draw'; changedByAdmin?: boolean })
package/src/dto/recall.ts CHANGED
@@ -14,8 +14,6 @@ export type {
14
14
  RecallActorKind,
15
15
  RecallCardDetailDTO,
16
16
  RecallCardWriteDTO,
17
- RecallLintIssueDTO,
18
- RecallLintSeverity,
19
17
  RecallMapCreateDTO,
20
18
  RecallMapCreateResultDTO,
21
19
  RecallMapDetailDTO,
@@ -23,7 +21,6 @@ export type {
23
21
  RecallMapSummaryDTO,
24
22
  RecallNodeDTO,
25
23
  RecallOptionDTO,
26
- RecallPageStateDTO,
27
24
  RecallRevisionDTO,
28
25
  RecallWarningDTO,
29
26
  RecallWriteErrorDTO,
package/src/dto/review.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * the wire, so an older brain or an older client keeps working.
6
6
  */
7
7
  import type { AccessItemView, AccessLevel } from './access';
8
- import type { TreeCrumb, TreeKind } from '../tree';
8
+ import type { TreeCrumb, TreeKind, TreeShareLevel, TreeVisibilityChange } from '../tree';
9
9
 
10
10
  /** Who wrote a reviewable item: a member or a client login. */
11
11
  export type ReviewAuthorRole = 'member' | 'client';
@@ -32,8 +32,8 @@ export type AcceptPreview = {
32
32
  closure?: AccessItemView[];
33
33
  /** Where it lands by default (folder plan phase 5): the brain folder the
34
34
  * author filed it in (`folderId` null = the kind's top level), and the
35
- * author's own folders that become brain folders below it. Absent for a
36
- * page (no tree yet) and from brains before the tree. */
35
+ * author's own folders that become brain folders below it. Absent from
36
+ * brains before the tree (pages joined it in folder phase 7). */
37
37
  place?: AcceptPlace;
38
38
  };
39
39
 
@@ -43,12 +43,18 @@ export type AcceptPlace = {
43
43
  /** The folder's crumbs, top-down, itself included. */
44
44
  crumbs: TreeCrumb[];
45
45
  creates: string[];
46
+ /** The share it is read at there through a shared folder (null: none):
47
+ * the item is read at the more open of this and the chosen level. Absent
48
+ * from brains before the Accept visibility check. */
49
+ share?: TreeShareLevel | null;
46
50
  };
47
51
 
48
52
  /** POST /api/team-admin/submissions/:id/accept and
49
53
  * POST /api/admin/space/:id/accept. */
50
54
  export type AcceptRequest = {
51
55
  audience?: AccessLevel;
56
+ /** DEPRECATED (folder phase 7): pages do not nest; ignored. A page lands
57
+ * like every tree kind (`folderId`). */
52
58
  parentPageId?: string | null;
53
59
  folderPath?: string | null;
54
60
  /** Where the item lands (folder plan phase 5): left out, in place; null,
@@ -61,6 +67,25 @@ export type AcceptRequest = {
61
67
  * For a client's item at client or public every closure item that goes
62
68
  * down must be here. */
63
69
  confirmedIds?: string[];
70
+ /** The admin saw the `visibility` refusal's list and accepts that those
71
+ * items are read above the chosen level where they land. */
72
+ visibilityConfirmed?: boolean;
73
+ };
74
+
75
+ /** 409 from either Accept (brains with the Accept visibility check): the item, or something of its
76
+ * bundle, lands in a shared folder and would be read above the chosen
77
+ * level there. Nothing moved; repeat with `visibilityConfirmed: true`. */
78
+ export type AcceptVisibilityRefusal = {
79
+ error: string;
80
+ reason: 'visibility';
81
+ /** The first changes (at most TREE_VISIBILITY_LIST_MAX): `from` the
82
+ * chosen level, `to` the level it would be read at. */
83
+ changes: TreeVisibilityChange[];
84
+ total: number;
85
+ /** Brain items the bundle embeds that would be read through it at the
86
+ * folder's share (migration 0208), `from` now, `to` then. Absent when
87
+ * there are none, and from brains before it was listed. */
88
+ alsoEmbeds?: TreeVisibilityChange[];
64
89
  };
65
90
 
66
91
  /** 409 from either Accept: a client's item at client or public without the
package/src/dto/rows.ts CHANGED
@@ -120,8 +120,10 @@ export type PageWidth = 'narrow' | 'wide';
120
120
 
121
121
  export type PageRow = {
122
122
  id: string;
123
- /** Parent page id, or null for a top-level page. Drives the /pages tree
124
- * and the `childPage` card (Phase 4a sub-pages). */
123
+ /** DEPRECATED (folder phase 7): pages do not nest, so this is always
124
+ * null. A page's place is its folder in the pages tree
125
+ * (`GET /api/tree/pages`; `PageDetail.folderId`). Kept so a client from
126
+ * before the tree, which built a hierarchy from it, still parses the row. */
125
127
  parentId: string | null;
126
128
  title: string;
127
129
  icon: string | null;
@@ -136,17 +138,14 @@ export type PageRow = {
136
138
  };
137
139
 
138
140
  /**
139
- * A row of the /pages LIST response (`GET /api/pages`): a `PageRow` plus where
140
- * it sits in the hierarchy. The list needs this per row because a search or tag
141
- * filter returns only the HITS, so the client cannot derive it from the rows it
142
- * holds: a hit's children and its parent are usually not among them.
141
+ * DEPRECATED (folder phase 7): `GET /api/pages` answers plain `PageRow`s.
142
+ * Pages do not nest, so nothing has sub-pages or a parent page any more; a
143
+ * client from before the tree reads `childCount` as 0 and `parentTitle` as
144
+ * null (both absent from the wire). Where a page sits is the pages tree's
145
+ * (`GET /api/tree/pages`).
143
146
  */
144
147
  export type PageListRow = PageRow & {
145
- /** Direct sub-pages, counted across the whole hierarchy (not just this
146
- * response), so a search hit can offer the way into its sub-pages. */
147
148
  childCount: number;
148
- /** The parent page's title, or null for a top-level page, so a hit can say
149
- * where it lives. */
150
149
  parentTitle: string | null;
151
150
  };
152
151
 
@@ -175,6 +174,13 @@ export type AppRow = {
175
174
  isHub: boolean;
176
175
  /** Access level (admin > team > client > public); the owner UI's badge. */
177
176
  audience: AccessLevel;
177
+ /** The share it inherits from a folder above it (team or client), or
178
+ * null; it is read at the more open of this and `audience`. Optional:
179
+ * absent from brains before the folder audit fixes. */
180
+ inherited?: 'team' | 'client' | null;
181
+ /** The share it is read at through something that embeds it (migration
182
+ * 0208), or null. Optional: absent from brains before it. */
183
+ embedded?: 'team' | 'client' | null;
178
184
  /** Informational (client logins C6): members and clients only read the
179
185
  * app's data. Off, an app at team or client level is a shared workspace
180
186
  * everyone who runs it writes. Set with PATCH /api/apps/:id
package/src/index.ts CHANGED
@@ -41,6 +41,7 @@ export type {
41
41
  AccessNodeUpdate,
42
42
  AccessNodeView,
43
43
  AccessSharedVia,
44
+ AccessReadThrough,
44
45
  ClientOldLinkAbove,
45
46
  ClientReport,
46
47
  ClientReportAck,
@@ -56,6 +57,7 @@ export type {
56
57
  AcceptPlace,
57
58
  AcceptPreview,
58
59
  AcceptRequest,
60
+ AcceptVisibilityRefusal,
59
61
  ReviewAuthorRole,
60
62
  ReviewAuthorView,
61
63
  } from './dto/review';
package/src/tree.ts CHANGED
@@ -28,7 +28,7 @@ export const TREE_KINDS = [
28
28
  'contacts',
29
29
  'secrets',
30
30
  // Recall v2's maps (its own content type, not pages). Appended last so no
31
- // earlier kind's index moves. Not served until the Recall screen ships.
31
+ // earlier kind's index moves. Served since the Recall screen (R3).
32
32
  'recall',
33
33
  ] as const;
34
34
  export type TreeKind = (typeof TREE_KINDS)[number];
@@ -160,11 +160,14 @@ export const TREE_KIND_SPECS: Readonly<Record<TreeKind, TreeKindSpec>> = {
160
160
  },
161
161
  // The tree lists maps only; a map's cards are recall_nodes rows, never
162
162
  // nodes, so they never appear as items.
163
+ // Not shareable YET: team sharing is Recall R6, which adds the recall root
164
+ // to nodes_share_level_ck and the type to mantle_workspace_kind(). Until
165
+ // then the database refuses the share, so the tree must not offer it.
163
166
  recall: {
164
167
  kind: 'recall',
165
168
  root: 'recall',
166
169
  nodeType: 'recall',
167
- shareable: true,
170
+ shareable: false,
168
171
  shareLevels: ['team'],
169
172
  sorts: ['name', 'updated'],
170
173
  },
@@ -222,12 +225,16 @@ export type TreeItem = {
222
225
  /** A short kind-specific token for the status slot: a file's extension, a
223
226
  * secret's kind, an event's start. Null when the kind has none. */
224
227
  subtype: string | null;
225
- /** Who can read it: its own level, or its folder's share when that is more
226
- * open. */
228
+ /** Who can read it: the most open of its own level, its folder's share and
229
+ * the share of something that embeds it. */
227
230
  level: AccessLevel;
228
231
  /** The share it takes from the nearest shared folder holding it (what
229
232
  * "Shared via" names); null = none. `level` already counts it. */
230
233
  inherited?: TreeShareLevel | null;
234
+ /** The share it is read at through something that embeds it (a shared
235
+ * note's image), kept by the brain; absent = none. `level` already
236
+ * counts it. */
237
+ embedded?: TreeShareLevel | null;
231
238
  state: TreeItemState | null;
232
239
  updatedAt: string;
233
240
  meta?: TreeItemMeta;
@@ -299,6 +306,10 @@ export type TreeVisibilityChange = {
299
306
  title: string;
300
307
  from: AccessLevel;
301
308
  to: AccessLevel;
309
+ /** The item's node type ('file', 'table', 'note', 'branch', ...), sent in
310
+ * `alsoEmbeds`: an embed may open any workspace item, and a table
311
+ * opening is more than an image. Absent elsewhere. */
312
+ type?: string;
302
313
  };
303
314
  export type TreeVisibilityRefusal = {
304
315
  error: 'visibility';
@@ -306,6 +317,18 @@ export type TreeVisibilityRefusal = {
306
317
  changes: TreeVisibilityChange[];
307
318
  /** How many items change in all. */
308
319
  total: number;
320
+ /** Items elsewhere that pages, drawings and notes in `changes` embed,
321
+ * whose access changes with them: `to` more open when they become
322
+ * readable through them, less open when an unshare or a move out takes
323
+ * that away (nothing's own level changes; migration 0208). Absent when
324
+ * there are none, and from brains before it was listed. */
325
+ alsoEmbeds?: TreeVisibilityChange[];
326
+ /** How many embedded items change in all (`alsoEmbeds` holds the first
327
+ * TREE_VISIBILITY_LIST_MAX). A confirm's `seen` is `total` plus this. */
328
+ embedsTotal?: number;
329
+ /** @deprecated Never sent: an unreleased first form of `alsoEmbeds`, when
330
+ * a share still lowered embeds for good. */
331
+ alsoLowered?: TreeVisibilityChange[];
309
332
  };
310
333
  export const TREE_VISIBILITY_LIST_MAX = 100;
311
334
 
@@ -321,7 +344,10 @@ export const TREE_VISIBILITY_LIST_MAX = 100;
321
344
  /** A folder as a client login's tree shows it. */
322
345
  export type ClientTreeFolder = Omit<TreeFolder, 'share' | 'inherited' | 'system' | 'own'>;
323
346
  /** An item as a client login's tree shows it. */
324
- export type ClientTreeItem = Omit<TreeItem, 'level' | 'inherited' | 'state' | 'source' | 'author'>;
347
+ export type ClientTreeItem = Omit<
348
+ TreeItem,
349
+ 'level' | 'inherited' | 'embedded' | 'state' | 'source' | 'author'
350
+ >;
325
351
 
326
352
  export type ClientTreeFolderPage = Omit<TreeFolderPage, 'folder' | 'folders' | 'items'> & {
327
353
  folder: ClientTreeFolder | null;
@@ -2,65 +2,37 @@
2
2
  * Wire shapes for the owner Recall API (roadmap tasks 073b322d / 91c93428;
3
3
  * docs/recall.md in the mantle repo). Dates are ISO strings.
4
4
  *
5
- * ── Two kinds of map ───────────────────────────────────────────────────────
6
- * v1 maps are COMPILED from a page tree: the rows are a build artifact, and a
7
- * card's `id` is its source page's node id, so every row is a click-through to
8
- * the page editor. v2 maps are NATIVE: the map is one `recall` item in the
9
- * tree, its cards are rows written directly, and a card's `id` is its own —
10
- * NOT a page. A client must not link a card to the page editor unless the map
11
- * is page-built, which `nodeId === null` tells it.
5
+ * A map is one `recall` item in the tree; its cards are rows written
6
+ * directly, and a card's `id` is its own, NOT a page. (Page-built v1 maps,
7
+ * compiled from a page tree, were retired in R5: the compile report, the
8
+ * page state route and `lastCompileOk` went with them.)
12
9
  *
13
10
  * Plan: "PLAN: Recall v2, its own content type" (dev brain, task 5d6ce06a).
14
- * Everything v2 adds here is additive, so a client written against the v1
15
- * shapes keeps compiling and keeps working against a v1 map.
16
11
  *
17
- * Whether a brain can serve the native path at all is `features.recallV2` from
18
- * `GET /api/shell`, absent on an older brain. Branch the SCREEN on that, not
19
- * on the shapes below.
12
+ * Whether a brain can serve Recall at all is `features.recallV2` from
13
+ * `GET /api/shell`, absent on a brain older than v2. Branch the SCREEN on
14
+ * that, not on the shapes below.
20
15
  */
21
16
 
22
- export type RecallLintSeverity = 'error' | 'warning';
23
-
24
- /** One issue from a map's last compile report (v1), or one warning from a
25
- * native write (v2). */
26
- export interface RecallLintIssueDTO {
27
- severity: RecallLintSeverity;
28
- code: string;
29
- message: string;
30
- /** v1 only: the page the issue is about — the page-editor click-through. */
31
- pageId?: string;
32
- /** v2: the card the warning is about, by slug. A native map has no pages,
33
- * and a write that fails a CHECK is refused rather than reported here —
34
- * so on a native map these are only ever warnings (an orphan card, an
35
- * entry card with no options yet). */
36
- cardSlug?: string;
37
- }
38
-
39
17
  /** One map in the catalog (`GET /api/recall/maps`). Unlike the agent-facing
40
- * `recall_index`, the owner catalog includes never-compiled maps
41
- * (`nodeCount` 0) — a failed compile is exactly what the owner must see. */
18
+ * `recall_index`, the owner catalog includes unpublished maps and maps with
19
+ * no cards yet. */
42
20
  export interface RecallMapSummaryDTO {
43
- /** v1: the map root page's node id — a map IS its root page. v2: the map's
44
- * own id, which equals `nodeId`. Either way this is what the other Recall
21
+ /** The map's id, which equals `nodeId`. This is what the other Recall
45
22
  * routes take as `:id`. */
46
23
  id: string;
47
24
  slug: string;
48
25
  title: string;
49
26
  /** The catalog line: when an agent should enter this map. */
50
27
  enterWhen: string;
51
- /** Card count; 0 = a v1 map that never compiled clean. */
28
+ /** Card count. */
52
29
  nodeCount: number;
53
- /** v1 only: false = the served rows are one rev behind the pages, and
54
- * `report` says why. Always true for a native map, which cannot be stale:
55
- * its rows are the source, and a write that fails its checks is refused. */
56
- lastCompileOk: boolean;
57
- /** v2: the map's `recall` item in the tree. NULL means this map is still
58
- * page-built, which is also the flag for "link its cards to the page
59
- * editor". */
60
- nodeId: string | null;
30
+ /** The map's `recall` item in the tree. (It was null for a page-built map
31
+ * before R5; a brain on R5 or later never serves one.) */
32
+ nodeId: string;
61
33
  /** v2: where the owner filed it, as display crumbs ("Mantle / Fleet");
62
- * null when unsorted or page-built. Derived from the item's folder, so it
63
- * is a label to show, never something to write back. */
34
+ * null when unsorted. Derived from the item's folder, so it is a label to
35
+ * show, never something to write back. */
64
36
  folder: string | null;
65
37
  /** v2: false while a map an AGENT created waits for the owner to publish
66
38
  * it. An unpublished map is invisible to every agent-facing tool, so the
@@ -79,7 +51,7 @@ export interface RecallOptionDTO {
79
51
  /** Slug of the target card, within this map unless `targetMap` is set. */
80
52
  targetSlug: string;
81
53
  /** v2: the target card's id. Draw the graph from this, not from the slug —
82
- * it survives a rename. Absent on a v1-compiled row. */
54
+ * it survives a rename. */
83
55
  targetId?: string;
84
56
  /** v2: a CROSS-MAP option. The slug of another published map, whose entry
85
57
  * card this option leads to. Absent for an ordinary same-map edge. */
@@ -87,8 +59,7 @@ export interface RecallOptionDTO {
87
59
  }
88
60
 
89
61
  export interface RecallNodeDTO {
90
- /** v1: the source page's node id, the page-editor click-through target.
91
- * v2: the card's own id. It is NOT a page — see the file header. */
62
+ /** The card's own id. It is NOT a page — see the file header. */
92
63
  id: string;
93
64
  slug: string;
94
65
  kind: 'index' | 'knowledge' | 'prompt';
@@ -100,8 +71,7 @@ export interface RecallNodeDTO {
100
71
  * megabyte on the wire to render a sidebar. Fetch one card to edit it. */
101
72
  bodyChars: number;
102
73
  options: RecallOptionDTO[];
103
- /** v1: the `pages.version` this row was compiled from. v2: the map version
104
- * the card was written at. */
74
+ /** The map version the card was written at. */
105
75
  sourceVersion: number;
106
76
  /** v2: the card's order in the editor. The list arrives sorted by it. */
107
77
  rank: number;
@@ -112,9 +82,9 @@ export interface RecallNodeDTO {
112
82
  updatedAt: string;
113
83
  }
114
84
 
115
- /** One card with its body — `GET /api/recall/maps/:id/cards/:cardId`, what
116
- * the editor opens. Separate from the list shape on purpose (see
117
- * `bodyChars`). */
85
+ /** One card with its body, `GET /api/recall/maps/:id/cards/:slug`: what
86
+ * the editor opens. A slug the card had before an explicit slug change still
87
+ * finds it. Separate from the list shape on purpose (see `bodyChars`). */
118
88
  export interface RecallCardDetailDTO extends RecallNodeDTO {
119
89
  /** The markdown the owner edits, at most RECALL_BODY_CHAR_BUDGET characters
120
90
  * (`@mantle/content-core/recall-compile`). */
@@ -128,29 +98,16 @@ export interface RecallCardDetailDTO extends RecallNodeDTO {
128
98
  * write check must read the same constant, or the counter promises room the
129
99
  * write refuses. */
130
100
 
131
- /** `GET /api/recall/maps/:id` — the whole compiled map, index node first,
132
- * plus the last lint report (null when the last compile was clean). */
101
+ /** `GET /api/recall/maps/:id` — the whole map, its cards in rank order
102
+ * (the entry card is rank 0). */
133
103
  export interface RecallMapDetailDTO extends RecallMapSummaryDTO {
134
- report: RecallLintIssueDTO[] | null;
135
104
  nodes: RecallNodeDTO[];
136
105
  }
137
106
 
138
- /** `GET /api/recall/pages/:id` — this page's place in Recall, if any. Backs
139
- * the editor lint badge: the compiler never blocks a commit, so this badge
140
- * is the ONLY place an author learns the map is serving a stale rev.
141
- * `node` is null when the page is named in a failing report but has no
142
- * compiled row yet (a brand-new page that broke the map). */
143
- export interface RecallPageStateDTO {
144
- map: RecallMapSummaryDTO;
145
- node: { slug: string; kind: RecallNodeDTO['kind'] } | null;
146
- report: RecallLintIssueDTO[] | null;
147
- }
148
-
149
107
  // ── v2: the write side ───────────────────────────────────────────────────────
150
108
  // The owner routes the Recall editor calls. Every write carries the map
151
109
  // `version` it was made against; a stale one is refused rather than silently
152
- // overwriting another editor's (or an agent's) change. Nothing here exists on
153
- // a v1 map: the page editor is its authoring surface.
110
+ // overwriting another editor's (or an agent's) change.
154
111
 
155
112
  /** Who made a change. An `agent` row is why the revision log exists: v2 serves
156
113
  * an agent's card edit immediately, with no compile step to hold it back. */
@@ -179,8 +136,10 @@ export interface RecallMapCreateResultDTO {
179
136
  /** The body of every refused Recall write. `error` is a sentence written to be
180
137
  * shown as is: what failed and what to do. `code` is stable and absent only on
181
138
  * a malformed request (a body that failed validation). A stale `version` is
182
- * 409 with code `version_stale`; any code ending `_not_found` is 404; every
183
- * other refusal is 400. */
139
+ * 409 with code `version_stale`; `map_not_found`, `card_not_found` and
140
+ * `revision_not_found` are 404; every other refusal is 400, including a bad
141
+ * reference inside the body (`cross_map_not_found`, `folder_not_found`) and a
142
+ * revision that has nothing to put back (`revision_not_restorable`). */
184
143
  export interface RecallWriteErrorDTO {
185
144
  error: string;
186
145
  code?: string;
@@ -199,28 +158,44 @@ export interface RecallMapPatchDTO {
199
158
  version: number;
200
159
  }
201
160
 
202
- /** `PUT /api/recall/maps/:id/cards/:cardId` — create or replace one card.
203
- * `options` replaces the card's whole list, so read-modify-write it. */
161
+ /** A card write. `POST /api/recall/maps/:id/cards` adds one;
162
+ * `PUT /api/recall/maps/:id/cards/:slug` replaces an existing one (an unknown
163
+ * slug is 404, not a create).
164
+ *
165
+ * `title` and `bodyMd` always replace. `useWhen`, `options` and `prompt` are
166
+ * STICKY on a replace: leave one out and the card keeps its value. So send
167
+ * `prompt` only when the owner changed the Prompt switch: a save that sends
168
+ * `prompt: false` for a card with a pending request drops the request. When
169
+ * `options` is sent it replaces the card's whole list: read-modify-write it. */
204
170
  export interface RecallCardWriteDTO {
205
171
  title: string;
206
172
  /** Markdown, at most RECALL_BODY_CHAR_BUDGET characters. */
207
173
  bodyMd: string;
208
- /** The matcher line. Required when `prompt` is true: a prompt without one
209
- * cannot be matched by meaning, which is the only thing prompts are for. */
174
+ /** The matcher line. Required when the card is or asks to be a prompt: a
175
+ * prompt without one cannot be matched by meaning, which is the only thing
176
+ * prompts are for. */
210
177
  useWhen?: string;
211
- /** Ask for this card to be a prompt. From the OWNER this makes it one; from
212
- * an agent it only records the request (`promptPending`). */
178
+ /** From the OWNER: true makes the card a prompt (confirming any pending
179
+ * request), false makes it knowledge (demoting a prompt, or dropping a
180
+ * request). From an agent, true only records a request (`promptPending`). */
213
181
  prompt?: boolean;
214
182
  options?: RecallOptionDTO[];
215
- /** Slug of the card to place this one after, for a new card. */
183
+ /** POST only: the slug of the card to place the new one after. A slug that
184
+ * names no card is refused (`after_not_found`). */
216
185
  after?: string;
186
+ /** PUT only, owner only: an explicit slug change. The old slug keeps
187
+ * resolving (recall_go, the card GET), and options in this map that led to
188
+ * it follow the card. */
189
+ slug?: string;
217
190
  version: number;
218
191
  }
219
192
 
220
193
  /** One advisory warning from a native write. Never blocks: an orphan card is
221
194
  * a normal intermediate state while a map is being built. No `severity`,
222
195
  * because a native write has only one kind of issue it reports rather than
223
- * refuses. Codes today: `orphan_card`, `entry_without_options`. */
196
+ * refuses. Codes today: `orphan_card`, `entry_without_options`,
197
+ * `cross_map_target_gone` (an option to a map no longer published, hidden
198
+ * from agents), `prompt_kept` (an agent tried to demote a prompt). */
224
199
  export interface RecallWarningDTO {
225
200
  code: string;
226
201
  message: string;
@@ -242,7 +217,13 @@ export interface RecallWriteResultDTO {
242
217
  }
243
218
 
244
219
  /** One entry in a map's revision log (`GET /api/recall/maps/:id/revisions`),
245
- * newest first. Restore one with `POST /api/recall/revisions/:id/restore`. */
220
+ * newest first. Restore one with `POST /api/recall/revisions/:id/restore`,
221
+ * which puts back what that write replaced: a card's content (and its slug,
222
+ * if that write moved it); a deleted card under its old slug, at its old
223
+ * place, with the options other cards had to it; the old order for a
224
+ * reorder; the map fields that write changed. Undoing "card added" deletes
225
+ * the card. "map created" cannot be restored (`revision_not_restorable`), nor
226
+ * can a reorder logged before its old order was kept. */
246
227
  export interface RecallRevisionDTO {
247
228
  id: string;
248
229
  /** The card this touched; null for a map-level change. */
@@ -250,9 +231,12 @@ export interface RecallRevisionDTO {
250
231
  /** The card's slug at the time, for display when the card is gone. */
251
232
  cardSlug: string | null;
252
233
  actorKind: RecallActorKind;
253
- /** The agent's slug or the admin's display name, when known. */
234
+ /** The agent's slug, 'mcp' for an external MCP client, or the admin's
235
+ * display name, stored with the revision. Null on rows written before
236
+ * brain v0.232.357. */
254
237
  actorName: string | null;
255
- /** One line on what changed ("body edited", "card added", "published"). */
238
+ /** One line on what changed: "card added", "card edited", "card deleted",
239
+ * "cards reordered", "prompt confirmed", "renamed, published", and so on. */
256
240
  summary: string;
257
241
  createdAt: string;
258
242
  }