@anchrd/intel-contract 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,10 +9,23 @@ import { z } from "zod";
9
9
  * draws first.
10
10
  */
11
11
  export declare const ARCHIVE_COLUMN_ID = "archived";
12
+ /**
13
+ * What a colour picker starts on for a column that has none (#725).
14
+ *
15
+ * ⚠️ **Here rather than in the browser package, and that is not tidiness.** The token linter refuses
16
+ * a hard-coded hex in `packages/ui`, and it is right to: a colour written into a component bypasses
17
+ * the theme. This one is not a theme colour, it is DATA — the value a person is about to choose
18
+ * from and the api writes as a default — so it belongs where both sides may read it, which is here.
19
+ *
20
+ * ⚠️ **It is the widget's starting point, never a written value.** `color` stays absent until
21
+ * somebody picks one, so opening the dialog does not repaint a board that predates colours.
22
+ */
23
+ export declare const DEFAULT_COLUMN_COLOR = "#9ca3af";
12
24
  export declare const BoardColumn: z.ZodObject<{
13
25
  id: z.ZodString;
14
26
  title: z.ZodString;
15
27
  terminal: z.ZodDefault<z.ZodBoolean>;
28
+ color: z.ZodOptional<z.ZodString>;
16
29
  }, z.core.$strict>;
17
30
  export type BoardColumn = z.infer<typeof BoardColumn>;
18
31
  export declare const BoardTask: z.ZodObject<{
@@ -53,6 +66,7 @@ export declare const BoardView: z.ZodObject<{
53
66
  id: z.ZodString;
54
67
  title: z.ZodString;
55
68
  terminal: z.ZodDefault<z.ZodBoolean>;
69
+ color: z.ZodOptional<z.ZodString>;
56
70
  }, z.core.$strict>>;
57
71
  archiveVisible: z.ZodBoolean;
58
72
  tasks: z.ZodArray<z.ZodObject<{
@@ -76,6 +90,7 @@ export declare const BoardUpdateInput: z.ZodObject<{
76
90
  id: z.ZodString;
77
91
  title: z.ZodString;
78
92
  terminal: z.ZodDefault<z.ZodBoolean>;
93
+ color: z.ZodOptional<z.ZodString>;
79
94
  }, z.core.$strict>>;
80
95
  archiveVisible: z.ZodOptional<z.ZodBoolean>;
81
96
  idempotencyKey: z.ZodString;
@@ -130,5 +145,6 @@ export declare const BoardAssigneeList: z.ZodObject<{
130
145
  email: z.ZodEmail;
131
146
  isMachine: z.ZodBoolean;
132
147
  }, z.core.$strict>>;
148
+ more: z.ZodDefault<z.ZodNumber>;
133
149
  }, z.core.$strict>;
134
150
  export type BoardAssigneeList = z.infer<typeof BoardAssigneeList>;
@@ -13,6 +13,18 @@ import { IdempotencyKey, IntelId, IsoDateTime } from "./contract.js";
13
13
  * draws first.
14
14
  */
15
15
  export const ARCHIVE_COLUMN_ID = "archived";
16
+ /**
17
+ * What a colour picker starts on for a column that has none (#725).
18
+ *
19
+ * ⚠️ **Here rather than in the browser package, and that is not tidiness.** The token linter refuses
20
+ * a hard-coded hex in `packages/ui`, and it is right to: a colour written into a component bypasses
21
+ * the theme. This one is not a theme colour, it is DATA — the value a person is about to choose
22
+ * from and the api writes as a default — so it belongs where both sides may read it, which is here.
23
+ *
24
+ * ⚠️ **It is the widget's starting point, never a written value.** `color` stays absent until
25
+ * somebody picks one, so opening the dialog does not repaint a board that predates colours.
26
+ */
27
+ export const DEFAULT_COLUMN_COLOR = "#9ca3af";
16
28
  export const BoardColumn = z.strictObject({
17
29
  id: z.string().min(1).max(60).describe("Stable key stored on every task in this column."),
18
30
  title: z.string().min(1).max(80).describe("What the column is called on screen."),
@@ -20,6 +32,20 @@ export const BoardColumn = z.strictObject({
20
32
  .boolean()
21
33
  .default(false)
22
34
  .describe("Whether a task in this column counts as finished. More than one column may be."),
35
+ /**
36
+ * ⚠️ **The colour belongs to the COLUMN, never to the card** (#725, and #365 took the status dot
37
+ * off the card on purpose). A card is in a column; drawing the column's colour on it would be the
38
+ * same fact twice, and the second copy is the one that goes stale.
39
+ *
40
+ * A free value rather than a fixed palette (Jack's decision 2026-08-22). It only ever fills a
41
+ * DOT, so a badly chosen one is hard to see but makes nothing unreadable — which is what makes a
42
+ * free choice affordable here and would not make it affordable behind text.
43
+ */
44
+ color: z
45
+ .string()
46
+ .regex(/^#[0-9a-fA-F]{6}$/, "A colour is six hex digits behind a hash, like #6b7280.")
47
+ .optional()
48
+ .describe("The dot in front of this column's title, and in front of a linked task that sits in it. Six hex digits behind a hash. Absent means the reader's own default, so an older board is not repainted by this field appearing."),
23
49
  });
24
50
  // One card, as the board view needs it: everything to draw and sort by, and NOTHING from R2. The
25
51
  // body is fetched per task through `node_version_get` when somebody opens one.
@@ -210,7 +236,7 @@ export const BoardAssigneeSearchInput = z.strictObject({
210
236
  boardId: IntelId.describe("The board whose people to offer. Only those who can open this board appear, so the same query against two boards can give two different answers."),
211
237
  query: z
212
238
  .string()
213
- .describe("What was typed. Under two characters the answer is empty rather than everybody: a single letter is a listing under a different name."),
239
+ .describe("What was typed. EMPTY names up to three people who reach this board, so a picker can open with suggestions instead of nothing. One character answers empty rather than everybody: a single letter is a listing under a different name, while an empty query asks for a bounded set this board already knows."),
214
240
  });
215
241
  // ⚠️ A DIFFERENT question from the one above, and deliberately not board-scoped. This one names
216
242
  // people who are ALREADY recorded on a card, so that a circle can carry initials instead of a raw
@@ -223,4 +249,14 @@ export const BoardAssigneeResolveInput = z.strictObject({
223
249
  .max(100)
224
250
  .describe("The ids to name. Ids that cannot be named are absent from the answer rather than reported, and more than a hundred is refused rather than silently shortened."),
225
251
  });
226
- export const BoardAssigneeList = z.strictObject({ items: z.array(BoardAssignee) });
252
+ export const BoardAssigneeList = z.strictObject({
253
+ items: z.array(BoardAssignee),
254
+ /**
255
+ * ⚠️ **How many are left over, so the cap is visible rather than silent** (#757). Three suggestions
256
+ * that look like the whole list are worse than three that say "and 4 more": the first teaches the
257
+ * reader that nobody else exists.
258
+ *
259
+ * `0` on a search answer, where the cap is gate's own and this door does not own it.
260
+ */
261
+ more: z.number().int().min(0).default(0),
262
+ });
@@ -120,9 +120,31 @@ export declare const PurgeNodePreviewInput: z.ZodObject<{
120
120
  nodeId: z.ZodString;
121
121
  }, z.core.$strict>;
122
122
  export type PurgeNodePreviewInput = z.infer<typeof PurgeNodePreviewInput>;
123
+ /**
124
+ * ⚠️ **A count is not an answer before a deletion that cannot be undone** (D71, #733). `totalItems`
125
+ * alone reads as "82 items" for a folder holding somebody's whole memory, and `destructive.md` asks
126
+ * for the number to be named BEFORE the confirmation — one step more precise is the difference
127
+ * between a number and something a person can decide on.
128
+ *
129
+ * `items` is capped, and the cap is visible rather than silent: `totalItems` keeps counting past it,
130
+ * so a caller can always say "and 40 more". A list of ten thousand rows would be an answer nobody
131
+ * reads and a response nobody can render.
132
+ */
123
133
  export declare const PurgeNodePreview: z.ZodObject<{
124
134
  inboundLinks: z.ZodNumber;
125
135
  totalItems: z.ZodNumber;
136
+ items: z.ZodArray<z.ZodObject<{
137
+ id: z.ZodString;
138
+ kind: z.ZodUnion<readonly [z.ZodEnum<{
139
+ folder: "folder";
140
+ document: "document";
141
+ table: "table";
142
+ attachment: "attachment";
143
+ board: "board";
144
+ task: "task";
145
+ }>, z.ZodLiteral<"flow">]>;
146
+ title: z.ZodString;
147
+ }, z.core.$strict>>;
126
148
  }, z.core.$strict>;
127
149
  export type PurgeNodePreview = z.infer<typeof PurgeNodePreview>;
128
150
  export declare const PurgeNodeResult: z.ZodObject<{
@@ -187,9 +187,27 @@ export const PurgeNodeInput = z.strictObject({
187
187
  export const PurgeNodePreviewInput = z.strictObject({
188
188
  nodeId: IntelId.describe("Archived node a purge would delete. Answers how many items would go with it and how many documents link to it from outside, and changes nothing. A node that is not archived is refused here for the same reason node_purge refuses it."),
189
189
  });
190
+ /**
191
+ * ⚠️ **A count is not an answer before a deletion that cannot be undone** (D71, #733). `totalItems`
192
+ * alone reads as "82 items" for a folder holding somebody's whole memory, and `destructive.md` asks
193
+ * for the number to be named BEFORE the confirmation — one step more precise is the difference
194
+ * between a number and something a person can decide on.
195
+ *
196
+ * `items` is capped, and the cap is visible rather than silent: `totalItems` keeps counting past it,
197
+ * so a caller can always say "and 40 more". A list of ten thousand rows would be an answer nobody
198
+ * reads and a response nobody can render.
199
+ */
190
200
  export const PurgeNodePreview = z.strictObject({
191
201
  inboundLinks: z.number().int().nonnegative(),
192
202
  totalItems: z.number().int().positive(),
203
+ // ⚠️ `flow` beside the node kinds, because a flow filed in the folder goes with it and is counted
204
+ // in `totalItems`. Naming everything except flows would leave out the one thing the cascade had to
205
+ // be widened for (#733).
206
+ items: z.array(z.strictObject({
207
+ id: IntelId,
208
+ kind: z.union([NodeKind, z.literal("flow")]),
209
+ title: z.string(),
210
+ })),
193
211
  });
194
212
  // The title travels back because after this call nothing can look it up any more — not the row, not
195
213
  // a version, not the index. A caller that wants to say what it just deleted has this one chance.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anchrd/intel-contract",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {