@anchrd/intel-contract 0.23.0 → 0.24.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.
@@ -1,4 +1,14 @@
1
1
  import { z } from "zod";
2
+ /**
3
+ * The id of the archive column, on every board (D68, #674).
4
+ *
5
+ * ⚠️ **It is derived, never stored.** A card sits in it because `nodes.archived_at` is set, and
6
+ * `board_tasks.status` keeps naming the working column it came from — that is what lets a card
7
+ * pulled back out land where it was. A configured column may not claim this id; `board_update`
8
+ * refuses it, because two columns with one id means every card in them lands in whichever the view
9
+ * draws first.
10
+ */
11
+ export declare const ARCHIVE_COLUMN_ID = "archived";
2
12
  export declare const BoardColumn: z.ZodObject<{
3
13
  id: z.ZodString;
4
14
  title: z.ZodString;
@@ -14,6 +24,7 @@ export declare const BoardTask: z.ZodObject<{
14
24
  startDate: z.ZodNullable<z.ZodISODateTime>;
15
25
  dueDate: z.ZodNullable<z.ZodISODateTime>;
16
26
  dependsOn: z.ZodNullable<z.ZodString>;
27
+ parentTaskId: z.ZodNullable<z.ZodString>;
17
28
  position: z.ZodNumber;
18
29
  archivedAt: z.ZodNullable<z.ZodISODateTime>;
19
30
  }, z.core.$strict>;
@@ -43,6 +54,7 @@ export declare const BoardView: z.ZodObject<{
43
54
  title: z.ZodString;
44
55
  terminal: z.ZodDefault<z.ZodBoolean>;
45
56
  }, z.core.$strict>>;
57
+ archiveVisible: z.ZodBoolean;
46
58
  tasks: z.ZodArray<z.ZodObject<{
47
59
  id: z.ZodString;
48
60
  title: z.ZodString;
@@ -52,6 +64,7 @@ export declare const BoardView: z.ZodObject<{
52
64
  startDate: z.ZodNullable<z.ZodISODateTime>;
53
65
  dueDate: z.ZodNullable<z.ZodISODateTime>;
54
66
  dependsOn: z.ZodNullable<z.ZodString>;
67
+ parentTaskId: z.ZodNullable<z.ZodString>;
55
68
  position: z.ZodNumber;
56
69
  archivedAt: z.ZodNullable<z.ZodISODateTime>;
57
70
  }, z.core.$strict>>;
@@ -64,6 +77,7 @@ export declare const BoardUpdateInput: z.ZodObject<{
64
77
  title: z.ZodString;
65
78
  terminal: z.ZodDefault<z.ZodBoolean>;
66
79
  }, z.core.$strict>>;
80
+ archiveVisible: z.ZodOptional<z.ZodBoolean>;
67
81
  idempotencyKey: z.ZodString;
68
82
  }, z.core.$strict>;
69
83
  export type BoardUpdateInput = z.infer<typeof BoardUpdateInput>;
@@ -76,6 +90,7 @@ export declare const BoardTaskCreateInput: z.ZodObject<{
76
90
  startDate: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
77
91
  dueDate: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
78
92
  dependsOn: z.ZodDefault<z.ZodNullable<z.ZodString>>;
93
+ parentTaskId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
79
94
  idempotencyKey: z.ZodString;
80
95
  }, z.core.$strict>;
81
96
  export type BoardTaskCreateInput = z.infer<typeof BoardTaskCreateInput>;
@@ -3,6 +3,16 @@ import { IdempotencyKey, IntelId, IsoDateTime } from "./contract.js";
3
3
  // One column of a board. `terminal` is what "done" means here — a rule about the column rather than
4
4
  // a magic status name, so an installation may call it "Shipped" or "Abgerechnet" without anything
5
5
  // downstream having to know the word.
6
+ /**
7
+ * The id of the archive column, on every board (D68, #674).
8
+ *
9
+ * ⚠️ **It is derived, never stored.** A card sits in it because `nodes.archived_at` is set, and
10
+ * `board_tasks.status` keeps naming the working column it came from — that is what lets a card
11
+ * pulled back out land where it was. A configured column may not claim this id; `board_update`
12
+ * refuses it, because two columns with one id means every card in them lands in whichever the view
13
+ * draws first.
14
+ */
15
+ export const ARCHIVE_COLUMN_ID = "archived";
6
16
  export const BoardColumn = z.strictObject({
7
17
  id: z.string().min(1).max(60).describe("Stable key stored on every task in this column."),
8
18
  title: z.string().min(1).max(80).describe("What the column is called on screen."),
@@ -26,6 +36,18 @@ export const BoardTask = z.strictObject({
26
36
  startDate: IsoDateTime.nullable(),
27
37
  dueDate: IsoDateTime.nullable(),
28
38
  dependsOn: IntelId.nullable(),
39
+ /**
40
+ * The task this one sits under, or `null` when it sits directly on the board.
41
+ *
42
+ * ⚠️ **The hierarchy is the node tree** (`nodes.parent_id`), not a second column here — a task
43
+ * under a task IS the tree Intel already has, which is why the cycle guard that refuses moving a
44
+ * node into its own descendant covers this for free.
45
+ *
46
+ * ⚠️ **Under a filter this may name a task that is not in the same answer.** `board_get` returns
47
+ * what matches; a subtask can match while its parent does not. A reader that assumes the parent
48
+ * is present will lose the row — treat an unknown parent as top level.
49
+ */
50
+ parentTaskId: IntelId.nullable(),
29
51
  position: z.number(),
30
52
  archivedAt: IsoDateTime.nullable(),
31
53
  });
@@ -59,6 +81,14 @@ export const BoardView = z.strictObject({
59
81
  boardId: IntelId,
60
82
  title: z.string().min(1).max(240),
61
83
  columns: z.array(BoardColumn),
84
+ /**
85
+ * Whether the archive column is drawn (D68, #674).
86
+ *
87
+ * ⚠️ It travels even when it is `false`, because the settings dialog needs to draw the switch in
88
+ * both positions — and because "the column is not in `columns`" has two possible reasons, hidden
89
+ * and not-yet-supported, which a reader cannot tell apart from the list alone.
90
+ */
91
+ archiveVisible: z.boolean(),
62
92
  tasks: z.array(BoardTask),
63
93
  });
64
94
  export const BoardUpdateInput = z.strictObject({
@@ -66,7 +96,13 @@ export const BoardUpdateInput = z.strictObject({
66
96
  columns: z
67
97
  .array(BoardColumn)
68
98
  .min(1)
69
- .describe("The complete new column list, in order. Columns are replaced, not merged."),
99
+ .describe(`The complete new column list, in order. Columns are replaced, not merged. The archive column (\`${ARCHIVE_COLUMN_ID}\`) is not part of this list and cannot be named in it — it is on every board and is only shown or hidden.`),
100
+ // ⚠️ Shown or hidden, never removed. The archive is the same place on every board; a shelf that
101
+ // could be dragged between the working columns would be a shelf pretending to be a stage.
102
+ archiveVisible: z
103
+ .boolean()
104
+ .optional()
105
+ .describe("Whether the archive column is drawn. Omit to leave it as it is."),
70
106
  idempotencyKey: IdempotencyKey,
71
107
  });
72
108
  export const BoardTaskCreateInput = z.strictObject({
@@ -100,6 +136,12 @@ export const BoardTaskCreateInput = z.strictObject({
100
136
  dependsOn: IntelId.nullable()
101
137
  .default(null)
102
138
  .describe("A node this task waits for. Any node, not only another task."),
139
+ // ⚠️ Creating a subtask is ONE call; moving an existing task under another is `node_update`
140
+ // with a new `parentId`. Two paths for "where a task sits" would mean two cycle guards, and the
141
+ // one on the node path is the one that already exists.
142
+ parentTaskId: IntelId.nullable()
143
+ .default(null)
144
+ .describe("The task this one belongs under. It must be on the same board. Omit for a card that sits directly on the board."),
103
145
  idempotencyKey: IdempotencyKey,
104
146
  });
105
147
  // ⚠️ Moving a card IS this call: `status` and `position` together. There is deliberately no
@@ -117,7 +159,12 @@ export const BoardTaskUpdateInput = z.strictObject({
117
159
  .max(240)
118
160
  .optional()
119
161
  .describe("Refused on purpose: a card's title lives on the node. Rename it with node_update."),
120
- status: z.string().min(1).max(60).optional().describe("The column to move it to."),
162
+ status: z
163
+ .string()
164
+ .min(1)
165
+ .max(60)
166
+ .optional()
167
+ .describe(`The column to move it to. \`${ARCHIVE_COLUMN_ID}\` is not an ordinary column: it archives the card through the same path as \`node_archive\`, with the same refusals — a card that still has live subtasks is refused. Moving it to any other column while it is archived brings it back.`),
121
168
  position: z
122
169
  .number()
123
170
  .optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anchrd/intel-contract",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {