@anchrd/intel-contract 0.22.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.
@@ -0,0 +1,41 @@
1
+ import { z } from "zod";
2
+ export declare const AuditResourceType: z.ZodEnum<{
3
+ node: "node";
4
+ }>;
5
+ export type AuditResourceType = z.infer<typeof AuditResourceType>;
6
+ export declare const AuditEvent: z.ZodObject<{
7
+ id: z.ZodString;
8
+ actorId: z.ZodString;
9
+ action: z.ZodString;
10
+ resourceType: z.ZodEnum<{
11
+ node: "node";
12
+ }>;
13
+ resourceId: z.ZodString;
14
+ metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
15
+ occurredAt: z.ZodISODateTime;
16
+ }, z.core.$strict>;
17
+ export type AuditEvent = z.infer<typeof AuditEvent>;
18
+ export declare const AuditCursor: z.ZodString;
19
+ export declare const AuditListRequest: z.ZodObject<{
20
+ resourceType: z.ZodEnum<{
21
+ node: "node";
22
+ }>;
23
+ after: z.ZodOptional<z.ZodString>;
24
+ limit: z.ZodDefault<z.ZodNumber>;
25
+ }, z.core.$strict>;
26
+ export type AuditListRequest = z.infer<typeof AuditListRequest>;
27
+ export declare const AuditListResponse: z.ZodObject<{
28
+ events: z.ZodArray<z.ZodObject<{
29
+ id: z.ZodString;
30
+ actorId: z.ZodString;
31
+ action: z.ZodString;
32
+ resourceType: z.ZodEnum<{
33
+ node: "node";
34
+ }>;
35
+ resourceId: z.ZodString;
36
+ metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
37
+ occurredAt: z.ZodISODateTime;
38
+ }, z.core.$strict>>;
39
+ nextCursor: z.ZodNullable<z.ZodString>;
40
+ }, z.core.$strict>;
41
+ export type AuditListResponse = z.infer<typeof AuditListResponse>;
@@ -0,0 +1,56 @@
1
+ import { z } from "zod";
2
+ import { IntelId, IsoDateTime } from "./contract.js";
3
+ // Which kind of resource an event is about. The column already carries three values — `node`,
4
+ // `flow` and `flow-run` — but each needs a DIFFERENT visibility check, and only the node one
5
+ // exists as a reusable walk today (`subtreeCte`).
6
+ //
7
+ // ⚠️ This enum is deliberately narrower than the column (#620). It is the boundary of what the
8
+ // reader is allowed to ask for, not a mirror of what is stored. Asking for `flow` is REFUSED
9
+ // rather than answered with an empty list: an empty list reads as "nothing happened", and a
10
+ // consumer building on that would miss every flow event without ever learning they exist. Widening
11
+ // this enum later is an extension; answering silently would have been a change of meaning.
12
+ export const AuditResourceType = z.enum(["node"]);
13
+ // One line of the change journal. `resourceId` is the node the event is about; `actorId` is who
14
+ // caused it. `metadata` is whatever the write site recorded — its shape belongs to `action` and is
15
+ // deliberately not typed here, because a schema per action would have to be kept in step with 11
16
+ // write sites and would go stale in silence.
17
+ export const AuditEvent = z.strictObject({
18
+ id: IntelId,
19
+ actorId: z.string().min(1),
20
+ action: z.string().min(1),
21
+ resourceType: AuditResourceType,
22
+ resourceId: IntelId,
23
+ metadata: z.record(z.string(), z.unknown()),
24
+ occurredAt: IsoDateTime,
25
+ });
26
+ // ⚠️ Opaque BY CONTRACT, not merely by encoding. The reader gets a string back and hands the same
27
+ // string in again; it must not take it apart, and it must not build one.
28
+ //
29
+ // The reason is that the cursor is a PAIR — `(occurredAt, id)` — and the pair is the whole point.
30
+ // A timestamp alone cannot separate two events written in the same millisecond, which for a batch
31
+ // is the normal case rather than the exception; a reader continuing on `occurredAt > X` skips the
32
+ // second one silently. If the cursor were two fields, a caller would eventually send only the
33
+ // timestamp, and the loss would look like nothing at all: no error, no log, just an event that
34
+ // never arrived.
35
+ export const AuditCursor = z.string().min(1).max(400);
36
+ export const AuditListRequest = z.strictObject({
37
+ resourceType: AuditResourceType.describe("Which kind of resource to read events about. Only `node` can be listed today; asking for anything else is refused rather than answered with an empty list."),
38
+ after: AuditCursor.optional().describe("Where to continue: the `nextCursor` of a previous answer, passed back unchanged. Omit it to start at the oldest event you may see. Do not build one — it is opaque on purpose."),
39
+ limit: z
40
+ .number()
41
+ .int()
42
+ .min(1)
43
+ .max(200)
44
+ .default(50)
45
+ .describe("How many events to return at most. The answer may be shorter."),
46
+ });
47
+ // `nextCursor` is present exactly when another page may exist, and it is the cursor of the LAST
48
+ // returned row — not a page number. A reader stores it and sends it back as `after`.
49
+ //
50
+ // ⚠️ `nextCursor` being present does not promise the next page is non-empty. The journal is a live
51
+ // table and the rows a reader may see can shrink between calls; treating "cursor present" as
52
+ // "more data" is a fair reading, treating an empty answer as "the feed ended" is not.
53
+ export const AuditListResponse = z.strictObject({
54
+ events: z.array(AuditEvent),
55
+ nextCursor: AuditCursor.nullable(),
56
+ });
@@ -0,0 +1,109 @@
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";
12
+ export declare const BoardColumn: z.ZodObject<{
13
+ id: z.ZodString;
14
+ title: z.ZodString;
15
+ terminal: z.ZodDefault<z.ZodBoolean>;
16
+ }, z.core.$strict>;
17
+ export type BoardColumn = z.infer<typeof BoardColumn>;
18
+ export declare const BoardTask: z.ZodObject<{
19
+ id: z.ZodString;
20
+ title: z.ZodString;
21
+ status: z.ZodString;
22
+ assigneeId: z.ZodNullable<z.ZodString>;
23
+ labels: z.ZodArray<z.ZodString>;
24
+ startDate: z.ZodNullable<z.ZodISODateTime>;
25
+ dueDate: z.ZodNullable<z.ZodISODateTime>;
26
+ dependsOn: z.ZodNullable<z.ZodString>;
27
+ parentTaskId: z.ZodNullable<z.ZodString>;
28
+ position: z.ZodNumber;
29
+ archivedAt: z.ZodNullable<z.ZodISODateTime>;
30
+ }, z.core.$strict>;
31
+ export type BoardTask = z.infer<typeof BoardTask>;
32
+ export declare const BoardTaskFilter: z.ZodObject<{
33
+ status: z.ZodOptional<z.ZodString>;
34
+ assigneeId: z.ZodOptional<z.ZodString>;
35
+ dueBefore: z.ZodOptional<z.ZodISODateTime>;
36
+ dependsOn: z.ZodOptional<z.ZodString>;
37
+ includeArchived: z.ZodDefault<z.ZodBoolean>;
38
+ }, z.core.$strict>;
39
+ export type BoardTaskFilter = z.infer<typeof BoardTaskFilter>;
40
+ export declare const BoardGetInput: z.ZodObject<{
41
+ status: z.ZodOptional<z.ZodString>;
42
+ assigneeId: z.ZodOptional<z.ZodString>;
43
+ dueBefore: z.ZodOptional<z.ZodISODateTime>;
44
+ dependsOn: z.ZodOptional<z.ZodString>;
45
+ includeArchived: z.ZodDefault<z.ZodBoolean>;
46
+ boardId: z.ZodString;
47
+ }, z.core.$strict>;
48
+ export type BoardGetInput = z.infer<typeof BoardGetInput>;
49
+ export declare const BoardView: z.ZodObject<{
50
+ boardId: z.ZodString;
51
+ title: z.ZodString;
52
+ columns: z.ZodArray<z.ZodObject<{
53
+ id: z.ZodString;
54
+ title: z.ZodString;
55
+ terminal: z.ZodDefault<z.ZodBoolean>;
56
+ }, z.core.$strict>>;
57
+ archiveVisible: z.ZodBoolean;
58
+ tasks: z.ZodArray<z.ZodObject<{
59
+ id: z.ZodString;
60
+ title: z.ZodString;
61
+ status: z.ZodString;
62
+ assigneeId: z.ZodNullable<z.ZodString>;
63
+ labels: z.ZodArray<z.ZodString>;
64
+ startDate: z.ZodNullable<z.ZodISODateTime>;
65
+ dueDate: z.ZodNullable<z.ZodISODateTime>;
66
+ dependsOn: z.ZodNullable<z.ZodString>;
67
+ parentTaskId: z.ZodNullable<z.ZodString>;
68
+ position: z.ZodNumber;
69
+ archivedAt: z.ZodNullable<z.ZodISODateTime>;
70
+ }, z.core.$strict>>;
71
+ }, z.core.$strict>;
72
+ export type BoardView = z.infer<typeof BoardView>;
73
+ export declare const BoardUpdateInput: z.ZodObject<{
74
+ boardId: z.ZodString;
75
+ columns: z.ZodArray<z.ZodObject<{
76
+ id: z.ZodString;
77
+ title: z.ZodString;
78
+ terminal: z.ZodDefault<z.ZodBoolean>;
79
+ }, z.core.$strict>>;
80
+ archiveVisible: z.ZodOptional<z.ZodBoolean>;
81
+ idempotencyKey: z.ZodString;
82
+ }, z.core.$strict>;
83
+ export type BoardUpdateInput = z.infer<typeof BoardUpdateInput>;
84
+ export declare const BoardTaskCreateInput: z.ZodObject<{
85
+ boardId: z.ZodString;
86
+ title: z.ZodString;
87
+ status: z.ZodOptional<z.ZodString>;
88
+ assigneeId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
89
+ labels: z.ZodDefault<z.ZodArray<z.ZodString>>;
90
+ startDate: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
91
+ dueDate: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
92
+ dependsOn: z.ZodDefault<z.ZodNullable<z.ZodString>>;
93
+ parentTaskId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
94
+ idempotencyKey: z.ZodString;
95
+ }, z.core.$strict>;
96
+ export type BoardTaskCreateInput = z.infer<typeof BoardTaskCreateInput>;
97
+ export declare const BoardTaskUpdateInput: z.ZodObject<{
98
+ taskId: z.ZodString;
99
+ title: z.ZodOptional<z.ZodString>;
100
+ status: z.ZodOptional<z.ZodString>;
101
+ position: z.ZodOptional<z.ZodNumber>;
102
+ assigneeId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
103
+ labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
104
+ startDate: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
105
+ dueDate: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
106
+ dependsOn: z.ZodOptional<z.ZodNullable<z.ZodString>>;
107
+ idempotencyKey: z.ZodString;
108
+ }, z.core.$strict>;
109
+ export type BoardTaskUpdateInput = z.infer<typeof BoardTaskUpdateInput>;
@@ -0,0 +1,190 @@
1
+ import { z } from "zod";
2
+ import { IdempotencyKey, IntelId, IsoDateTime } from "./contract.js";
3
+ // One column of a board. `terminal` is what "done" means here — a rule about the column rather than
4
+ // a magic status name, so an installation may call it "Shipped" or "Abgerechnet" without anything
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";
16
+ export const BoardColumn = z.strictObject({
17
+ id: z.string().min(1).max(60).describe("Stable key stored on every task in this column."),
18
+ title: z.string().min(1).max(80).describe("What the column is called on screen."),
19
+ terminal: z
20
+ .boolean()
21
+ .default(false)
22
+ .describe("Whether a task in this column counts as finished. More than one column may be."),
23
+ });
24
+ // One card, as the board view needs it: everything to draw and sort by, and NOTHING from R2. The
25
+ // body is fetched per task through `node_version_get` when somebody opens one.
26
+ //
27
+ // ⚠️ `position` is a float, not an index. Dropping a card between two neighbours is then the
28
+ // midpoint of the two, and no other row is written. With integers every drop would renumber
29
+ // everything below it, and two people dropping at once would fight over rows neither touched.
30
+ export const BoardTask = z.strictObject({
31
+ id: IntelId.describe("The card's node id — its address everywhere else in Intel."),
32
+ title: z.string().min(1).max(240).describe("What the card says."),
33
+ status: z.string().min(1).max(60).describe("Which column it sits in."),
34
+ assigneeId: z.string().min(1).nullable(),
35
+ labels: z.array(z.string().min(1).max(40)),
36
+ startDate: IsoDateTime.nullable(),
37
+ dueDate: IsoDateTime.nullable(),
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(),
51
+ position: z.number(),
52
+ archivedAt: IsoDateTime.nullable(),
53
+ });
54
+ // ⚠️ Every filter here is a COLUMN in `board_tasks`, and that is the whole reason the fields are not
55
+ // in the body. A filter the application applies after reading has already fetched the rows — over
56
+ // the wire, into memory, past the point where leaving them out would have helped.
57
+ export const BoardTaskFilter = z.strictObject({
58
+ status: z
59
+ .string()
60
+ .min(1)
61
+ .max(60)
62
+ .optional()
63
+ .describe("Only tasks in this column. Omit for every column."),
64
+ assigneeId: z
65
+ .string()
66
+ .min(1)
67
+ .optional()
68
+ .describe("Only tasks assigned to this Gate principal. An agent is not a special case here."),
69
+ dueBefore: IsoDateTime.optional().describe("Only tasks due strictly before this moment. Tasks without a due date never match."),
70
+ dependsOn: IntelId.optional().describe("Only tasks waiting for this node — what `board_get` answers when you ask what one thing blocks."),
71
+ includeArchived: z
72
+ .boolean()
73
+ .default(false)
74
+ .describe("Include archived tasks beside the live ones instead of hiding them."),
75
+ });
76
+ export const BoardGetInput = BoardTaskFilter.extend({
77
+ boardId: IntelId.describe("The board node to read. Must be a node of kind `board`."),
78
+ });
79
+ // One answer for the whole board, not one per card.
80
+ export const BoardView = z.strictObject({
81
+ boardId: IntelId,
82
+ title: z.string().min(1).max(240),
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(),
92
+ tasks: z.array(BoardTask),
93
+ });
94
+ export const BoardUpdateInput = z.strictObject({
95
+ boardId: IntelId.describe("The board node whose columns are being set."),
96
+ columns: z
97
+ .array(BoardColumn)
98
+ .min(1)
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."),
106
+ idempotencyKey: IdempotencyKey,
107
+ });
108
+ export const BoardTaskCreateInput = z.strictObject({
109
+ boardId: IntelId.describe("The board the task is filed under. It becomes the task's parent."),
110
+ title: z.string().min(1).max(240).describe("What the card says on the board."),
111
+ // ⚠️ Optional, and absent means the FIRST column rather than an error. A caller who does not care
112
+ // where a task starts should not have to read the board first — and a task with no status would
113
+ // be a card no view can draw.
114
+ status: z
115
+ .string()
116
+ .min(1)
117
+ .max(60)
118
+ .optional()
119
+ .describe("Which column to file it in. Omit for the board's first column."),
120
+ assigneeId: z
121
+ .string()
122
+ .min(1)
123
+ .nullable()
124
+ .default(null)
125
+ .describe("Who it is for, as a Gate principal id. An agent is not a special case."),
126
+ labels: z
127
+ .array(z.string().min(1).max(40))
128
+ .default([])
129
+ .describe("Free-form tags. They are filtered on the board, not in search."),
130
+ startDate: IsoDateTime.nullable()
131
+ .default(null)
132
+ .describe("When work on it should begin. Only the timeline view draws it."),
133
+ dueDate: IsoDateTime.nullable()
134
+ .default(null)
135
+ .describe("When it is due. A card without one never matches a due-before filter."),
136
+ dependsOn: IntelId.nullable()
137
+ .default(null)
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."),
145
+ idempotencyKey: IdempotencyKey,
146
+ });
147
+ // ⚠️ Moving a card IS this call: `status` and `position` together. There is deliberately no
148
+ // `board_task_move` — it would be a second way to write one row, and a model reading `tools/list`
149
+ // would have to guess which of the two applies.
150
+ //
151
+ // Every field is optional and absent means "leave it": a drag sends two fields, a rename sends one.
152
+ // `null` is a value where the column is nullable, so clearing a due date is `dueDate: null` and not
153
+ // its absence.
154
+ export const BoardTaskUpdateInput = z.strictObject({
155
+ taskId: IntelId.describe("The card to change, by its node id."),
156
+ title: z
157
+ .string()
158
+ .min(1)
159
+ .max(240)
160
+ .optional()
161
+ .describe("Refused on purpose: a card's title lives on the node. Rename it with node_update."),
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.`),
168
+ position: z
169
+ .number()
170
+ .optional()
171
+ .describe("Where in the column. Use the midpoint between the two neighbours it lands between."),
172
+ assigneeId: z
173
+ .string()
174
+ .min(1)
175
+ .nullable()
176
+ .optional()
177
+ .describe("Who it is for. `null` unassigns it; leaving it out keeps whoever has it."),
178
+ labels: z
179
+ .array(z.string().min(1).max(40))
180
+ .optional()
181
+ .describe("The complete new tag list. Tags are replaced, not merged."),
182
+ startDate: IsoDateTime.nullable()
183
+ .optional()
184
+ .describe("When work should begin. `null` clears it."),
185
+ dueDate: IsoDateTime.nullable().optional().describe("When it is due. `null` clears it."),
186
+ dependsOn: IntelId.nullable()
187
+ .optional()
188
+ .describe("A node this card waits for. `null` clears the dependency."),
189
+ idempotencyKey: IdempotencyKey,
190
+ });
@@ -223,8 +223,8 @@ export declare const CompleteFlowRunStepInput: z.ZodObject<{
223
223
  }, z.core.$strict>;
224
224
  export type CompleteFlowRunStepInput = z.infer<typeof CompleteFlowRunStepInput>;
225
225
  export declare const FlowRunTrigger: z.ZodEnum<{
226
- subflow: "subflow";
227
226
  manual: "manual";
227
+ subflow: "subflow";
228
228
  }>;
229
229
  export type FlowRunTrigger = z.infer<typeof FlowRunTrigger>;
230
230
  export declare const FlowRunFailure: z.ZodObject<{
@@ -246,8 +246,8 @@ export declare const FlowRunSummary: z.ZodObject<{
246
246
  cancelled: "cancelled";
247
247
  }>;
248
248
  trigger: z.ZodEnum<{
249
- subflow: "subflow";
250
249
  manual: "manual";
250
+ subflow: "subflow";
251
251
  }>;
252
252
  startedAt: z.ZodISODateTime;
253
253
  completedAt: z.ZodNullable<z.ZodISODateTime>;
@@ -282,8 +282,8 @@ export declare const FlowRunList: z.ZodObject<{
282
282
  cancelled: "cancelled";
283
283
  }>;
284
284
  trigger: z.ZodEnum<{
285
- subflow: "subflow";
286
285
  manual: "manual";
286
+ subflow: "subflow";
287
287
  }>;
288
288
  startedAt: z.ZodISODateTime;
289
289
  completedAt: z.ZodNullable<z.ZodISODateTime>;
@@ -947,7 +947,9 @@ export declare const RelationNodeKind: z.ZodEnum<{
947
947
  document: "document";
948
948
  table: "table";
949
949
  attachment: "attachment";
950
+ board: "board";
950
951
  flow: "flow";
952
+ task: "task";
951
953
  }>;
952
954
  export type RelationNodeKind = z.infer<typeof RelationNodeKind>;
953
955
  export declare const RelationNode: z.ZodObject<{
@@ -957,7 +959,9 @@ export declare const RelationNode: z.ZodObject<{
957
959
  document: "document";
958
960
  table: "table";
959
961
  attachment: "attachment";
962
+ board: "board";
960
963
  flow: "flow";
964
+ task: "task";
961
965
  }>;
962
966
  title: z.ZodString;
963
967
  inScope: z.ZodBoolean;
@@ -1007,7 +1011,9 @@ export declare const RelationGraph: z.ZodObject<{
1007
1011
  document: "document";
1008
1012
  table: "table";
1009
1013
  attachment: "attachment";
1014
+ board: "board";
1010
1015
  flow: "flow";
1016
+ task: "task";
1011
1017
  }>;
1012
1018
  title: z.ZodString;
1013
1019
  inScope: z.ZodBoolean;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { baseVersion, IdempotencyKey, IntelId, IsoDateTime, LinkConfiguration, } from "./contract.js";
3
+ import { NodeKind } from "./node.js";
3
4
  import { serverOf, ToolName, ToolServerHandle } from "./tool.js";
4
5
  export const FlowNodeId = z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,99}$/);
5
6
  export const FlowPosition = z.strictObject({ x: z.number().finite(), y: z.number().finite() });
@@ -462,7 +463,13 @@ export const FlowPublishPreview = z.strictObject({
462
463
  // What accesses what, for one level of the shared tree (#19). A folder answers it for its contents,
463
464
  // a single flow for itself. Documents and flows are two kinds of thing that share one tree
464
465
  // (ADR-0004 §1), so the graph carries both and says which of them it is.
465
- export const RelationNodeKind = z.enum(["folder", "document", "attachment", "table", "flow"]);
466
+ //
467
+ // ⚠️ **DERIVED from `NodeKind`, not written out beside it** (#376). It was a hand-kept copy until
468
+ // D66 added two kinds, and the copy did not follow — the graph would have gone on answering about
469
+ // four kinds while the tree held six, and nothing would have said so. That is the same failure
470
+ // `check:boundaries` refuses elsewhere; here the extra member `flow` had kept it out of the
471
+ // checker's reach.
472
+ export const RelationNodeKind = z.enum([...NodeKind.options, "flow"]);
466
473
  export const RelationNode = z.strictObject({
467
474
  id: IntelId,
468
475
  kind: RelationNodeKind,
@@ -4,6 +4,8 @@ export declare const NodeKind: z.ZodEnum<{
4
4
  document: "document";
5
5
  table: "table";
6
6
  attachment: "attachment";
7
+ board: "board";
8
+ task: "task";
7
9
  }>;
8
10
  export type NodeKind = z.infer<typeof NodeKind>;
9
11
  export declare const Node: z.ZodObject<{
@@ -14,6 +16,8 @@ export declare const Node: z.ZodObject<{
14
16
  document: "document";
15
17
  table: "table";
16
18
  attachment: "attachment";
19
+ board: "board";
20
+ task: "task";
17
21
  }>;
18
22
  title: z.ZodString;
19
23
  description: z.ZodNullable<z.ZodString>;
@@ -67,6 +71,8 @@ export declare const CreateNodeInput: z.ZodObject<{
67
71
  document: "document";
68
72
  table: "table";
69
73
  attachment: "attachment";
74
+ board: "board";
75
+ task: "task";
70
76
  }>;
71
77
  title: z.ZodString;
72
78
  description: z.ZodDefault<z.ZodNullable<z.ZodString>>;
@@ -133,6 +139,8 @@ export declare const NodeList: z.ZodObject<{
133
139
  document: "document";
134
140
  table: "table";
135
141
  attachment: "attachment";
142
+ board: "board";
143
+ task: "task";
136
144
  }>;
137
145
  title: z.ZodString;
138
146
  description: z.ZodNullable<z.ZodString>;
@@ -172,6 +180,8 @@ export declare const NodeDocument: z.ZodObject<{
172
180
  document: "document";
173
181
  table: "table";
174
182
  attachment: "attachment";
183
+ board: "board";
184
+ task: "task";
175
185
  }>;
176
186
  title: z.ZodString;
177
187
  description: z.ZodNullable<z.ZodString>;
@@ -208,6 +218,8 @@ export declare const NodeAttachment: z.ZodObject<{
208
218
  document: "document";
209
219
  table: "table";
210
220
  attachment: "attachment";
221
+ board: "board";
222
+ task: "task";
211
223
  }>;
212
224
  title: z.ZodString;
213
225
  description: z.ZodNullable<z.ZodString>;
@@ -244,6 +256,8 @@ export declare const NodeTable: z.ZodObject<{
244
256
  document: "document";
245
257
  table: "table";
246
258
  attachment: "attachment";
259
+ board: "board";
260
+ task: "task";
247
261
  }>;
248
262
  title: z.ZodString;
249
263
  description: z.ZodNullable<z.ZodString>;
@@ -266,8 +280,8 @@ export declare const NodeLinkRelation: z.ZodEnum<{
266
280
  }>;
267
281
  export type NodeLinkRelation = z.infer<typeof NodeLinkRelation>;
268
282
  export declare const NodeLinkOrigin: z.ZodEnum<{
269
- manual: "manual";
270
283
  text: "text";
284
+ manual: "manual";
271
285
  }>;
272
286
  export type NodeLinkOrigin = z.infer<typeof NodeLinkOrigin>;
273
287
  export declare const NodeLink: z.ZodObject<{
@@ -281,8 +295,8 @@ export declare const NodeLink: z.ZodObject<{
281
295
  implements: "implements";
282
296
  }>;
283
297
  origin: z.ZodEnum<{
284
- manual: "manual";
285
298
  text: "text";
299
+ manual: "manual";
286
300
  }>;
287
301
  label: z.ZodNullable<z.ZodString>;
288
302
  createdBy: z.ZodString;
@@ -301,8 +315,8 @@ export declare const NodeLinkList: z.ZodObject<{
301
315
  implements: "implements";
302
316
  }>;
303
317
  origin: z.ZodEnum<{
304
- manual: "manual";
305
318
  text: "text";
319
+ manual: "manual";
306
320
  }>;
307
321
  label: z.ZodNullable<z.ZodString>;
308
322
  createdBy: z.ZodString;
@@ -340,6 +354,8 @@ export declare const NodeGraph: z.ZodObject<{
340
354
  document: "document";
341
355
  table: "table";
342
356
  attachment: "attachment";
357
+ board: "board";
358
+ task: "task";
343
359
  }>;
344
360
  title: z.ZodString;
345
361
  description: z.ZodNullable<z.ZodString>;
@@ -360,8 +376,8 @@ export declare const NodeGraph: z.ZodObject<{
360
376
  implements: "implements";
361
377
  }>;
362
378
  origin: z.ZodEnum<{
363
- manual: "manual";
364
379
  text: "text";
380
+ manual: "manual";
365
381
  }>;
366
382
  label: z.ZodNullable<z.ZodString>;
367
383
  createdBy: z.ZodString;
@@ -392,8 +408,8 @@ export declare const NodeCitation: z.ZodObject<{
392
408
  freshness: z.ZodISODateTime;
393
409
  score: z.ZodNumber;
394
410
  match: z.ZodEnum<{
395
- semantic: "semantic";
396
411
  lexical: "lexical";
412
+ semantic: "semantic";
397
413
  hybrid: "hybrid";
398
414
  }>;
399
415
  }, z.core.$strict>;
@@ -408,8 +424,8 @@ export declare const SearchResult: z.ZodObject<{
408
424
  freshness: z.ZodISODateTime;
409
425
  score: z.ZodNumber;
410
426
  match: z.ZodEnum<{
411
- semantic: "semantic";
412
427
  lexical: "lexical";
428
+ semantic: "semantic";
413
429
  hybrid: "hybrid";
414
430
  }>;
415
431
  }, z.core.$strict>>;
@@ -4,17 +4,27 @@ import { baseVersion, IdempotencyKey, IntelId, IsoDateTime } from "./contract.js
4
4
  // (those stay behind each door, where `/session` deliberately does not carry them). `agentRuntime`
5
5
  // says whether an agent Worker is bound at all (#190): without it the UI offers no "New agent" and
6
6
  // an agent node explains itself instead of rendering views that could only end in a 503.
7
- // The fourth kind is `table` (#40), the fifth is `agent` (#139) and the sixth is `board` (#285).
7
+ // The fourth kind is `table` (#40); `board` and `task` are the fifth and sixth (**D66**, #376).
8
8
  // Each is a kind of node, not a kind of thing: it hangs in the same folder tree, inherits the same
9
9
  // folder grants, carries the same immutable versions and the same R2 body as a document
10
- // (ADR-0004 §1, ADR-0005 §1). Only the media type and the operations below differ.
10
+ // (ADR-0004 §1). Only the media type and the operations below differ. `agent` is NOT among them —
11
+ // D65 moved agents out of Intel entirely (ADR-0007).
11
12
  //
12
- // ⚠️ `agent` being optional is load-bearing (ADR-0005 §1): an installation without a single agent
13
- // node is complete, not unfinished, and nothing here asks anyone to classify a document as a skill
14
- // or a policy in order to file it. The same holds for `board`: it is a file somebody may make, not
15
- // a place the tree grows a special corner for — which is exactly why a board is one node carrying
16
- // its tasks and not a folder that only tasks may live in (#285).
17
- export const NodeKind = z.enum(["folder", "document", "attachment", "table"]);
13
+ // ⚠️ **The sentence that stood here said the opposite, and it was right for its day.** Until
14
+ // 2026-08-20 this comment read *"a board is one node carrying its tasks and not a folder that only
15
+ // tasks may live in (#285)"*. D66 reverses it, and the reason is not taste:
16
+ //
17
+ // * **The tree has to hide `task` on EVERY level query.** As a kind that is a condition on a
18
+ // column already in the statement; as a `document` plus a side-table row it would be a join on
19
+ // the hottest path. And with tasks hidden a board has no visible children, so the chevron falls
20
+ // away with no rule of its own.
21
+ // * **`audit_list` exists since #620.** A task that is a node makes "task assigned to Paul" an
22
+ // event `anchrd/signals` can pick up. Inside one board's content every change looks the same
23
+ // from outside — "the board changed" — and nothing can act on it.
24
+ //
25
+ // ⚠️ What did NOT change: `status`, `assignee`, the dates and the ordering live in `board_tasks`,
26
+ // not on the node. They are filter columns and would stand empty on every other kind.
27
+ export const NodeKind = z.enum(["folder", "document", "attachment", "table", "board", "task"]);
18
28
  export const Node = z.strictObject({
19
29
  id: IntelId,
20
30
  parentId: IntelId.nullable(),
@@ -28,6 +28,8 @@ export declare const AppendTableRowsResult: z.ZodObject<{
28
28
  document: "document";
29
29
  table: "table";
30
30
  attachment: "attachment";
31
+ board: "board";
32
+ task: "task";
31
33
  }>;
32
34
  title: z.ZodString;
33
35
  description: z.ZodNullable<z.ZodString>;
@@ -75,6 +77,8 @@ export declare const UpdateTableRowsResult: z.ZodObject<{
75
77
  document: "document";
76
78
  table: "table";
77
79
  attachment: "attachment";
80
+ board: "board";
81
+ task: "task";
78
82
  }>;
79
83
  title: z.ZodString;
80
84
  description: z.ZodNullable<z.ZodString>;
@@ -118,6 +122,8 @@ export declare const DeleteTableRowsResult: z.ZodObject<{
118
122
  document: "document";
119
123
  table: "table";
120
124
  attachment: "attachment";
125
+ board: "board";
126
+ task: "task";
121
127
  }>;
122
128
  title: z.ZodString;
123
129
  description: z.ZodNullable<z.ZodString>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anchrd/intel-contract",
3
- "version": "0.22.0",
3
+ "version": "0.24.0",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -16,6 +16,14 @@
16
16
  "types": "./dist/contract/contract.d.ts",
17
17
  "default": "./dist/contract/contract.js"
18
18
  },
19
+ "./audit": {
20
+ "types": "./dist/contract/audit.d.ts",
21
+ "default": "./dist/contract/audit.js"
22
+ },
23
+ "./board": {
24
+ "types": "./dist/contract/board.d.ts",
25
+ "default": "./dist/contract/board.js"
26
+ },
19
27
  "./bundle": {
20
28
  "types": "./dist/contract/bundle.d.ts",
21
29
  "default": "./dist/contract/bundle.js"