@nestos/kanban 0.5.1 → 0.5.2

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 (147) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +73 -29
  3. package/dist/{activity-C6xDM-cg.d.cts → activity-BbC4sgKL.d.cts} +28 -2
  4. package/dist/{activity-Dw8DOw0L.d.ts → activity-Czlan5xW.d.ts} +28 -2
  5. package/dist/activity-module-DaO1Rry0.d.cts +22 -0
  6. package/dist/activity-module-T22wliZu.d.ts +22 -0
  7. package/dist/activity-ports-Dqxa86zT.d.cts +12 -0
  8. package/dist/activity-ports-cxfrelaL.d.ts +12 -0
  9. package/dist/activity.cjs +10 -282
  10. package/dist/activity.cjs.map +1 -1
  11. package/dist/activity.d.cts +8 -30
  12. package/dist/activity.d.ts +8 -30
  13. package/dist/activity.js +9 -281
  14. package/dist/activity.js.map +1 -1
  15. package/dist/{chunk-O4OGAAV4.js → chunk-3JYLJPE5.js} +29 -5
  16. package/dist/chunk-3JYLJPE5.js.map +1 -0
  17. package/dist/{chunk-ATUFFNLV.js → chunk-3LEIHB7Y.js} +5 -5
  18. package/dist/chunk-4XF6LQSU.cjs.map +1 -1
  19. package/dist/chunk-5Q7WB63A.cjs +282 -0
  20. package/dist/chunk-5Q7WB63A.cjs.map +1 -0
  21. package/dist/{chunk-PSKQAFDF.cjs → chunk-7KDOTBRX.cjs} +1 -1
  22. package/dist/chunk-7KDOTBRX.cjs.map +1 -0
  23. package/dist/{chunk-5DLZWW5Y.js → chunk-AHHEGTUA.js} +3 -3
  24. package/dist/chunk-AOHQCX7K.cjs +95 -0
  25. package/dist/chunk-AOHQCX7K.cjs.map +1 -0
  26. package/dist/{chunk-IUI5CI2S.cjs → chunk-DINLR6E6.cjs} +96 -92
  27. package/dist/chunk-DINLR6E6.cjs.map +1 -0
  28. package/dist/{chunk-L44TM4EE.cjs → chunk-EYTVC2H5.cjs} +568 -454
  29. package/dist/chunk-EYTVC2H5.cjs.map +1 -0
  30. package/dist/chunk-FEE2YBZ7.js +1972 -0
  31. package/dist/chunk-FEE2YBZ7.js.map +1 -0
  32. package/dist/chunk-FNO5K3A7.js +282 -0
  33. package/dist/chunk-FNO5K3A7.js.map +1 -0
  34. package/dist/chunk-IHHDXZPZ.js +382 -0
  35. package/dist/chunk-IHHDXZPZ.js.map +1 -0
  36. package/dist/chunk-J3EAIVA3.js +280 -0
  37. package/dist/chunk-J3EAIVA3.js.map +1 -0
  38. package/dist/{chunk-DFTOTBGF.js → chunk-KH3WF3K4.js} +20 -16
  39. package/dist/chunk-KH3WF3K4.js.map +1 -0
  40. package/dist/{chunk-TB2RZGDV.js → chunk-M35X5PHO.js} +14 -1
  41. package/dist/chunk-M35X5PHO.js.map +1 -0
  42. package/dist/chunk-QRGZD2JU.cjs +1972 -0
  43. package/dist/chunk-QRGZD2JU.cjs.map +1 -0
  44. package/dist/{chunk-4KF7KUAI.cjs → chunk-RBOER6EW.cjs} +6 -6
  45. package/dist/chunk-RBOER6EW.cjs.map +1 -0
  46. package/dist/{chunk-6MN3H3YF.cjs → chunk-RSH6QSEC.cjs} +16 -3
  47. package/dist/chunk-RSH6QSEC.cjs.map +1 -0
  48. package/dist/{chunk-T7P5EIC4.cjs → chunk-VMRDXOLX.cjs} +33 -33
  49. package/dist/chunk-VMRDXOLX.cjs.map +1 -0
  50. package/dist/{chunk-5XKOCKY2.js → chunk-X4UHZX6F.js} +1 -1
  51. package/dist/chunk-XBSGUVCY.cjs +382 -0
  52. package/dist/chunk-XBSGUVCY.cjs.map +1 -0
  53. package/dist/{chunk-OHQTKGQN.js → chunk-XKDZHAUE.js} +242 -128
  54. package/dist/chunk-XKDZHAUE.js.map +1 -0
  55. package/dist/chunk-ZUZGAO6G.cjs +280 -0
  56. package/dist/chunk-ZUZGAO6G.cjs.map +1 -0
  57. package/dist/{content-CAIp1njn.d.cts → content-C5aJZFlw.d.cts} +1 -1
  58. package/dist/{content-CGMJdyH_.d.ts → content-hLH5BNud.d.ts} +1 -1
  59. package/dist/contracts/index.cjs +13 -3
  60. package/dist/contracts/index.cjs.map +1 -1
  61. package/dist/contracts/index.d.cts +5 -4
  62. package/dist/contracts/index.d.ts +5 -4
  63. package/dist/contracts/index.js +14 -4
  64. package/dist/{discovery-DxpirOz3.d.cts → discovery-9E-LfwIw.d.cts} +1 -1
  65. package/dist/{discovery-gSqWpuRm.d.ts → discovery-D60yrjej.d.ts} +1 -1
  66. package/dist/discovery.cjs +63 -65
  67. package/dist/discovery.cjs.map +1 -1
  68. package/dist/discovery.d.cts +4 -4
  69. package/dist/discovery.d.ts +4 -4
  70. package/dist/discovery.js +5 -7
  71. package/dist/discovery.js.map +1 -1
  72. package/dist/execution-bridge-fpCnH6z5.d.cts +52 -0
  73. package/dist/execution-bridge-rk0uVy_n.d.ts +52 -0
  74. package/dist/execution.cjs +6 -356
  75. package/dist/execution.cjs.map +1 -1
  76. package/dist/execution.d.cts +4 -51
  77. package/dist/execution.d.ts +4 -51
  78. package/dist/execution.js +9 -359
  79. package/dist/execution.js.map +1 -1
  80. package/dist/index.cjs +10 -12
  81. package/dist/index.cjs.map +1 -1
  82. package/dist/index.d.cts +9 -16
  83. package/dist/index.d.ts +9 -16
  84. package/dist/index.js +10 -12
  85. package/dist/index.js.map +1 -1
  86. package/dist/{module-CWNK2BMj.d.ts → module-CYfE7YhM.d.ts} +2 -2
  87. package/dist/{module-BbvwdCDF.d.cts → module-Ca9L3qCn.d.cts} +2 -2
  88. package/dist/{planning-CcFZYdIL.d.cts → planning-CHrOqQ6b.d.cts} +45 -10
  89. package/dist/{planning-CcFZYdIL.d.ts → planning-CHrOqQ6b.d.ts} +45 -10
  90. package/dist/{ports-Bn6ro2FB.d.ts → ports-B0McVg7B.d.ts} +4 -3
  91. package/dist/ports-BeGO1VRI.d.cts +49 -0
  92. package/dist/{ports-CaL6geqR.d.cts → ports-GQy0x-RI.d.cts} +4 -3
  93. package/dist/ports-ykGiNUSx.d.ts +49 -0
  94. package/dist/runtime/index.cjs +205 -0
  95. package/dist/runtime/index.cjs.map +1 -0
  96. package/dist/runtime/index.d.cts +75 -0
  97. package/dist/runtime/index.d.ts +75 -0
  98. package/dist/runtime/index.js +205 -0
  99. package/dist/runtime/index.js.map +1 -0
  100. package/dist/runtime/integration.cjs +423 -0
  101. package/dist/runtime/integration.cjs.map +1 -0
  102. package/dist/runtime/integration.d.cts +658 -0
  103. package/dist/runtime/integration.d.ts +658 -0
  104. package/dist/runtime/integration.js +423 -0
  105. package/dist/runtime/integration.js.map +1 -0
  106. package/dist/storage.cjs +9 -277
  107. package/dist/storage.cjs.map +1 -1
  108. package/dist/storage.d.cts +6 -6
  109. package/dist/storage.d.ts +6 -6
  110. package/dist/storage.js +11 -279
  111. package/dist/storage.js.map +1 -1
  112. package/dist/{store-q63eSMoT.d.cts → store-DPwHzGiz.d.cts} +2 -2
  113. package/dist/{store-Ct0gOAAg.d.ts → store-DgdrPCV9.d.ts} +2 -2
  114. package/dist/task-projection-CSorlMws.d.ts +11 -0
  115. package/dist/task-projection-DKKB_ueb.d.cts +11 -0
  116. package/examples/standalone.ts +22 -0
  117. package/package.json +117 -87
  118. package/dist/chunk-2YFPV5GF.cjs +0 -16
  119. package/dist/chunk-2YFPV5GF.cjs.map +0 -1
  120. package/dist/chunk-4KF7KUAI.cjs.map +0 -1
  121. package/dist/chunk-6MN3H3YF.cjs.map +0 -1
  122. package/dist/chunk-DFTOTBGF.js.map +0 -1
  123. package/dist/chunk-G6FCDLDF.js +0 -16
  124. package/dist/chunk-G6FCDLDF.js.map +0 -1
  125. package/dist/chunk-IUI5CI2S.cjs.map +0 -1
  126. package/dist/chunk-KYNYPKKH.cjs +0 -71
  127. package/dist/chunk-KYNYPKKH.cjs.map +0 -1
  128. package/dist/chunk-L44TM4EE.cjs.map +0 -1
  129. package/dist/chunk-LSE6JG5I.cjs +0 -20
  130. package/dist/chunk-LSE6JG5I.cjs.map +0 -1
  131. package/dist/chunk-O4OGAAV4.js.map +0 -1
  132. package/dist/chunk-OHQTKGQN.js.map +0 -1
  133. package/dist/chunk-PSKQAFDF.cjs.map +0 -1
  134. package/dist/chunk-QTMTBEBA.js +0 -20
  135. package/dist/chunk-QTMTBEBA.js.map +0 -1
  136. package/dist/chunk-T7P5EIC4.cjs.map +0 -1
  137. package/dist/chunk-TB2RZGDV.js.map +0 -1
  138. package/dist/ui/index.cjs +0 -1961
  139. package/dist/ui/index.cjs.map +0 -1
  140. package/dist/ui/index.d.cts +0 -209
  141. package/dist/ui/index.d.ts +0 -209
  142. package/dist/ui/index.js +0 -1961
  143. package/dist/ui/index.js.map +0 -1
  144. package/dist/ui/kanban.css +0 -194
  145. /package/dist/{chunk-ATUFFNLV.js.map → chunk-3LEIHB7Y.js.map} +0 -0
  146. /package/dist/{chunk-5DLZWW5Y.js.map → chunk-AHHEGTUA.js.map} +0 -0
  147. /package/dist/{chunk-5XKOCKY2.js.map → chunk-X4UHZX6F.js.map} +0 -0
@@ -0,0 +1,280 @@
1
+ import {
2
+ allocateBoardNumber,
3
+ archiveKey,
4
+ boardCounterKey,
5
+ boardKey,
6
+ boardNumberKey,
7
+ counter,
8
+ createBoardState,
9
+ decodeRow,
10
+ encodeBoard,
11
+ encodeRow,
12
+ hydrate,
13
+ indexedView,
14
+ numberEntities,
15
+ proposeAmendment,
16
+ receiptDigest,
17
+ reduce,
18
+ rowChanges,
19
+ rowKeys,
20
+ storedBoardNumber,
21
+ verifyReceipt,
22
+ viewFromState
23
+ } from "./chunk-XKDZHAUE.js";
24
+ import {
25
+ identity,
26
+ normalizeActor,
27
+ requireValue
28
+ } from "./chunk-3LEIHB7Y.js";
29
+ import {
30
+ KanbanError,
31
+ randomUUID
32
+ } from "./chunk-M35X5PHO.js";
33
+
34
+ // src/conditional-store.ts
35
+ var ConditionalKanbanStore = class {
36
+ constructor(client, prepareDirectory, path = "kanban/boards.seq", bodies) {
37
+ this.client = client;
38
+ this.prepareDirectory = prepareDirectory;
39
+ this.path = path;
40
+ this.bodies = bodies;
41
+ if (!bodies && client.readBody && client.writeBody) this.bodies = { read: async (hash) => {
42
+ try {
43
+ return await client.readBody(path, hash);
44
+ } catch (error) {
45
+ if (error?.remoteCode === "SEQ_BODY_INTEGRITY") throw new KanbanError("BODY_INTEGRITY");
46
+ throw error;
47
+ }
48
+ }, write: (hash, bytes) => client.writeBody(path, hash, bytes) };
49
+ }
50
+ async select(keys) {
51
+ return this.client.query(this.path, { keys });
52
+ }
53
+ async boardId(number) {
54
+ return entry(await this.select([boardNumberKey(number)]), boardNumberKey(number));
55
+ }
56
+ async ids() {
57
+ return JSON.parse(entry(await this.select(["index"]), "index") ?? "[]");
58
+ }
59
+ async view(id) {
60
+ const raw = entry(await this.select([boardKey(id)]), boardKey(id));
61
+ const indexed = indexedView(raw);
62
+ if (indexed) return indexed;
63
+ const state = await this.read(id);
64
+ return state ? viewFromState(state) : null;
65
+ }
66
+ async read(id) {
67
+ const snapshot = await this.select([boardKey(id)]);
68
+ return hydrate(await this.loadRows(entry(snapshot, boardKey(id)), snapshot.revision), this.bodies);
69
+ }
70
+ async loadRows(raw, revision) {
71
+ const keys = rowKeys(raw), rows = {};
72
+ for (let start = 0; start < keys.length; start += 256) {
73
+ requireValue(revision !== null, "INVALID_STORAGE");
74
+ const page = await this.queryRevision(keys.slice(start, start + 256), revision);
75
+ for (const row of page.entries) {
76
+ requireValue(typeof row.value === "string", "INVALID_STORAGE");
77
+ rows[row.key] = row.value;
78
+ }
79
+ }
80
+ return { raw, rows };
81
+ }
82
+ async queryRevision(keys, expectedRevision) {
83
+ try {
84
+ return await this.client.query(this.path, { keys, expectedRevision });
85
+ } catch (error) {
86
+ if (error?.code === "ECONFLICT") throw new KanbanError("REVISION_CONFLICT");
87
+ throw error;
88
+ }
89
+ }
90
+ async events(id, after, limit, through) {
91
+ const end = Math.min(through, after + limit);
92
+ const keys = Array.from({ length: Math.max(0, end - after) }, (_, index) => `event/${encodeURIComponent(id)}/${String(after + index + 1).padStart(16, "0")}`);
93
+ if (!keys.length) return [];
94
+ const events = [];
95
+ for (let start = 0; start < keys.length; start += 256) {
96
+ const rows = await this.select(keys.slice(start, start + 256));
97
+ events.push(...rows.entries.map((e) => JSON.parse(String(e.value))));
98
+ }
99
+ return events.sort((a, b) => a.sequence - b.sequence);
100
+ }
101
+ async archived(board, item) {
102
+ const raw = entry(await this.select([archiveKey(board, item)]), archiveKey(board, item));
103
+ if (!raw) return null;
104
+ const record = await decodeRow(raw, this.bodies);
105
+ record.item.number ??= (await this.view(board))?.state.archiveIndex?.find((value) => value.id === item)?.number;
106
+ return record;
107
+ }
108
+ async numberBoard(snapshot, raw, id, state) {
109
+ const high = counter(entry(snapshot, boardCounterKey)), number = allocateBoardNumber(raw, high);
110
+ state.board.number = number;
111
+ if (storedBoardNumber(raw) !== void 0) return [];
112
+ if (snapshot.revision !== null) {
113
+ const lookup = await this.queryRevision([boardNumberKey(number)], snapshot.revision), owner = entry(lookup, boardNumberKey(number));
114
+ requireValue(owner === null || owner === id, "INVALID_NUMBERING");
115
+ }
116
+ return [{ action: "set", key: boardCounterKey, value: String(Math.max(high, number)) }, { action: "set", key: boardNumberKey(number), value: id }];
117
+ }
118
+ async update(id, operationId, fingerprint, change) {
119
+ await this.prepareDirectory();
120
+ const receiptKey = `receipt/${encodeURIComponent(id)}/${encodeURIComponent(operationId)}`;
121
+ const snapshot = await this.select([boardKey(id), receiptKey, "index", boardCounterKey]);
122
+ const raw = entry(snapshot, boardKey(id)), receipt = entry(snapshot, receiptKey);
123
+ const before = await this.loadRows(raw, snapshot.revision), current = await hydrate(before, this.bodies);
124
+ if (receipt) {
125
+ verifyReceipt(receipt, fingerprint);
126
+ requireValue(current, "CORRUPT_RECEIPT");
127
+ return current;
128
+ }
129
+ const original = JSON.stringify(current), state = change(current);
130
+ numberEntities(state);
131
+ if (JSON.stringify(state) === original) return state;
132
+ const numbering = await this.numberBoard(snapshot, raw, id, state);
133
+ const { changes, encoded } = await prepareChanges(id, before, state, this.bodies);
134
+ changes.push(...numbering);
135
+ changes.push({ action: "set", key: boardKey(id), value: encoded.raw }, { action: "set", key: receiptKey, value: receiptDigest(fingerprint) });
136
+ const ids = JSON.parse(entry(snapshot, "index") ?? "[]");
137
+ if (!ids.includes(id)) changes.push({ action: "set", key: "index", value: JSON.stringify([...ids, id]) });
138
+ requireValue(changes.length <= 256, "REMOTE_TRANSACTION_LIMIT");
139
+ try {
140
+ await this.client.transaction(this.path, snapshot.revision, changes);
141
+ } catch (error) {
142
+ if (error?.outcome === "not-committed" && error?.code === "ECONFLICT") throw new KanbanError("REVISION_CONFLICT");
143
+ throw error;
144
+ }
145
+ return state;
146
+ }
147
+ };
148
+ function entry(snapshot, key) {
149
+ const value = snapshot.entries.find((e) => e.key === key)?.value;
150
+ if (value === void 0) return null;
151
+ if (typeof value !== "string") throw new KanbanError("INVALID_STORAGE");
152
+ return value;
153
+ }
154
+ async function prepareChanges(id, before, state, bodies) {
155
+ const changes = state.events.map((event) => ({
156
+ action: "set",
157
+ key: `event/${encodeURIComponent(id)}/${String(event.sequence).padStart(16, "0")}`,
158
+ value: JSON.stringify(event)
159
+ }));
160
+ for (const write of state.archiveWrites ?? []) changes.push(write.value ? { action: "set", key: archiveKey(id, write.id), value: await encodeRow(write.value, bodies) } : { action: "delete", key: archiveKey(id, write.id) });
161
+ delete state.archiveWrites;
162
+ state.events = [];
163
+ const encoded = await encodeBoard(state, bodies);
164
+ for (const row of rowChanges(before, encoded)) changes.push(row.value === null ? { action: "delete", key: row.key } : { action: "set", key: row.key, value: row.value });
165
+ return { changes, encoded };
166
+ }
167
+
168
+ // src/content.ts
169
+ async function inspectKanbanContent(store, content) {
170
+ const state = await store.read(content.board.id);
171
+ const ids = new Set([...state?.board.items ?? [], ...state?.archiveIndex ?? []].map((item) => item.id));
172
+ return {
173
+ version: state?.presetVersions?.[content.id] ?? 0,
174
+ complete: !!state && content.items.every((item) => ids.has(item.command.item.id)) && (content.records ?? []).every((entry2) => state.records?.some((record) => record.id === entry2.record.id))
175
+ };
176
+ }
177
+ async function installKanbanContent(options) {
178
+ const started = (options.now ?? Date.now)(), content = structuredClone(options.content);
179
+ try {
180
+ identity(content.id);
181
+ identity(options.operationId);
182
+ validateContent(content);
183
+ const actor = normalizeActor(options.actor), before = await options.store.read(content.board.id);
184
+ const initial = before ?? createBoardState(content.board, actor, started);
185
+ await options.authorize({ actor, board: structuredClone(initial.board), action: "install-content" });
186
+ const result = { changed: false, created: 0 };
187
+ if (before && !options.fillMissing && (before.presetVersions?.[content.id] ?? 1) >= content.version) {
188
+ report(options, started, "success");
189
+ return result;
190
+ }
191
+ await options.store.update(content.board.id, options.operationId, JSON.stringify({ content, actor, fillMissing: !!options.fillMissing, missingReferences: options.missingReferences }), (current) => {
192
+ requireValue(JSON.stringify(current) === JSON.stringify(before), "REVISION_CONFLICT");
193
+ if (current?.board.deletedAt !== void 0) {
194
+ requireValue(!options.fillMissing, "BOARD_DELETED");
195
+ return current;
196
+ }
197
+ const installed = current?.presetVersions?.[content.id] ?? (current ? 1 : 0);
198
+ if (current && !options.fillMissing && installed >= content.version) return current;
199
+ const state = current ?? initial;
200
+ result.changed = !current;
201
+ applyContent(state, { ...options, content }, actor, installed, started, result);
202
+ (state.presetVersions ??= {})[content.id] = content.version;
203
+ return state;
204
+ });
205
+ report(options, started, "success");
206
+ return result;
207
+ } catch (error) {
208
+ const raw = error?.code;
209
+ report(options, started, "failure", typeof raw === "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(raw) ? raw : "CONTENT_INSTALL_FAILED");
210
+ throw error;
211
+ }
212
+ }
213
+ function validateContent(content) {
214
+ requireValue(Number.isSafeInteger(content.version) && content.version > 0, "INVALID_CONTENT_VERSION");
215
+ requireValue(Array.isArray(content.items) && content.items.length <= 1e3, "CONTENT_ITEM_LIMIT");
216
+ for (const rows of [content.records, content.amendments]) requireValue(rows === void 0 || Array.isArray(rows) && rows.length <= 1e3, "CONTENT_RECORD_LIMIT");
217
+ for (const entry2 of [...content.items, ...content.records ?? [], ...content.amendments ?? []]) {
218
+ const version = entry2.introduced ?? 1;
219
+ requireValue(Number.isSafeInteger(version) && version > 0 && version <= content.version, "INVALID_CONTENT_VERSION");
220
+ }
221
+ }
222
+ function applyContent(state, options, actor, installed, now, result) {
223
+ const content = options.content, version = options.fillMissing ? 0 : installed;
224
+ const known = new Set([...state.board.items, ...state.archiveIndex ?? []].map((item) => item.id));
225
+ const apply = (command) => reduce(state, command, actor, options.operationId, now, (options.id ?? randomUUID)());
226
+ for (const entry2 of content.items) {
227
+ if (known.has(entry2.command.item.id) || (entry2.introduced ?? 1) <= version) continue;
228
+ insertItem(state, entry2, options.missingReferences === "detach", apply);
229
+ known.add(entry2.command.item.id);
230
+ result.changed = true;
231
+ result.created++;
232
+ }
233
+ for (const entry2 of content.records ?? []) {
234
+ if ((entry2.introduced ?? 1) <= version || state.records?.some((record2) => record2.id === entry2.record.id)) continue;
235
+ const record = structuredClone(entry2.record);
236
+ if (options.missingReferences === "detach") record.itemIds = record.itemIds.filter((id) => known.has(id));
237
+ apply({ type: "append-record", record });
238
+ if (entry2.confirmed) apply({ type: "review-record", recordId: record.id, accept: true });
239
+ result.changed = true;
240
+ }
241
+ for (const entry2 of content.amendments ?? []) {
242
+ if ((entry2.introduced ?? 1) <= version) continue;
243
+ const item = state.board.items.find((item2) => item2.id === entry2.itemId);
244
+ if (!item) continue;
245
+ const count = item.amendments?.length ?? 0;
246
+ proposeAmendment(item, { action: "update", ...entry2, sources: [] }, entry2.proposedBy, now, entry2.runId);
247
+ if ((item.amendments?.length ?? 0) > count) {
248
+ item.revision++;
249
+ state.board.revision++;
250
+ result.changed = true;
251
+ }
252
+ }
253
+ }
254
+ function insertItem(state, entry2, detach, apply) {
255
+ const command = structuredClone(entry2.command), parentId = command.planning?.parentId;
256
+ if (detach && parentId) {
257
+ const parent = state.board.items.find((item) => item.id === parentId);
258
+ if (!parent || ["completed", "cancelled"].includes(parent.status)) delete command.planning.parentId;
259
+ }
260
+ const itemId = command.item.id;
261
+ apply(command);
262
+ if (entry2.blocked) apply({ type: "block-item", itemId, reason: entry2.blocked });
263
+ if (entry2.completion) {
264
+ apply({ type: "close-plan", itemId, resultRef: entry2.completion.resultRef });
265
+ if (entry2.completion.archiveReason) apply({ type: "archive-items", itemIds: [itemId], reason: entry2.completion.archiveReason });
266
+ }
267
+ }
268
+ function report(options, start, result, code) {
269
+ try {
270
+ options.log({ operationId: options.operationId, boardId: options.content.board.id, stage: "content.install", result, code, durationMs: (options.now ?? Date.now)() - start });
271
+ } catch {
272
+ }
273
+ }
274
+
275
+ export {
276
+ ConditionalKanbanStore,
277
+ inspectKanbanContent,
278
+ installKanbanContent
279
+ };
280
+ //# sourceMappingURL=chunk-J3EAIVA3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/conditional-store.ts","../src/content.ts"],"sourcesContent":["import {numberEntities, boardCounterKey, boardNumberKey, counter, allocateBoardNumber, storedBoardNumber} from './numbering';\nimport type {KanbanSeqClient, KanbanSeqChange, KanbanSeqSnapshot} from './storage-ports';\nimport type {KanbanEvent, KanbanArchivedItem} from './contracts';\nimport {KanbanError, type KanbanState, type KanbanStore} from './ports';\nimport {requireValue} from './rules';\nimport {indexedView, viewFromState, archiveKey, boardKey as key, rowKeys, hydrate, encodeBoard, rowChanges, encodeRow, decodeRow, receiptDigest, verifyReceipt, type StoredBoard, type KanbanBodyStore} from './storage-codec';\n\n/** The project export and its authorization are frozen in the injected HTTP client. */\nexport class ConditionalKanbanStore implements KanbanStore {\n constructor(private readonly client: Pick<KanbanSeqClient, 'query' | 'transaction'> & Partial<Pick<KanbanSeqClient, 'readBody' | 'writeBody'>>,\n private readonly prepareDirectory: () => Promise<void>, private readonly path = 'kanban/boards.seq', private readonly bodies?: KanbanBodyStore) {\n if (!bodies && client.readBody && client.writeBody) this.bodies = {read: async hash => {\n try {return await client.readBody!(path, hash);}\n catch (error) {if ((error as {remoteCode?: string})?.remoteCode === 'SEQ_BODY_INTEGRITY') throw new KanbanError('BODY_INTEGRITY'); throw error;}\n }, write: (hash, bytes) => client.writeBody!(path, hash, bytes)};\n }\n private async select(keys: string[]): Promise<KanbanSeqSnapshot> {return this.client.query(this.path, {keys});}\n async boardId(number: number): Promise<string | null> {return entry(await this.select([boardNumberKey(number)]), boardNumberKey(number));}\n async ids(): Promise<string[]> {return JSON.parse(entry(await this.select(['index']), 'index') ?? '[]');}\n async view(id: string) {\n const raw = entry(await this.select([key(id)]), key(id));\n const indexed = indexedView(raw); if (indexed) return indexed;\n const state = await this.read(id); return state ? viewFromState(state) : null;\n }\n async read(id: string): Promise<KanbanState | null> {\n const snapshot = await this.select([key(id)]);\n return hydrate(await this.loadRows(entry(snapshot, key(id)), snapshot.revision), this.bodies);\n }\n private async loadRows(raw: string | null, revision: string | null): Promise<StoredBoard> {\n const keys = rowKeys(raw), rows: Record<string, string> = {};\n for (let start = 0; start < keys.length; start += 256) {\n requireValue(revision !== null, 'INVALID_STORAGE');\n const page = await this.queryRevision(keys.slice(start, start + 256), revision);\n for (const row of page.entries) {requireValue(typeof row.value === 'string', 'INVALID_STORAGE'); rows[row.key] = row.value;}\n }\n return {raw, rows};\n }\n private async queryRevision(keys: string[], expectedRevision: string) {\n try {return await this.client.query(this.path, {keys, expectedRevision});}\n catch (error) {\n if ((error as {code?: string})?.code === 'ECONFLICT') throw new KanbanError('REVISION_CONFLICT');\n throw error;\n }\n }\n async events(id: string, after: number, limit: number, through: number): Promise<KanbanEvent[]> {\n const end = Math.min(through, after + limit);\n const keys = Array.from({length: Math.max(0, end - after)}, (_, index) =>\n `event/${encodeURIComponent(id)}/${String(after + index + 1).padStart(16, '0')}`);\n if (!keys.length) return [];\n const events: KanbanEvent[] = [];\n // Event keys below through are immutable; concurrent appends cannot change this prefix.\n for (let start = 0; start < keys.length; start += 256) {\n const rows = await this.select(keys.slice(start, start + 256));\n events.push(...rows.entries.map(e => JSON.parse(String(e.value)) as KanbanEvent));\n }\n return events.sort((a, b) => a.sequence - b.sequence);\n }\n async archived(board: string, item: string): Promise<KanbanArchivedItem | null> {\n const raw = entry(await this.select([archiveKey(board, item)]), archiveKey(board, item));\n if (!raw) return null; const record = await decodeRow<KanbanArchivedItem>(raw, this.bodies);\n record.item.number ??= (await this.view(board))?.state.archiveIndex?.find(value => value.id === item)?.number; return record;\n }\n private async numberBoard(snapshot: KanbanSeqSnapshot, raw: string | null, id: string, state: KanbanState): Promise<KanbanSeqChange[]> {\n const high = counter(entry(snapshot, boardCounterKey)), number = allocateBoardNumber(raw, high);\n state.board.number = number;\n if (storedBoardNumber(raw) !== undefined) return [];\n if (snapshot.revision !== null) {\n const lookup = await this.queryRevision([boardNumberKey(number)], snapshot.revision), owner = entry(lookup, boardNumberKey(number));\n requireValue(owner === null || owner === id, 'INVALID_NUMBERING');\n }\n return [{action:'set',key:boardCounterKey,value:String(Math.max(high,number))}, {action:'set',key:boardNumberKey(number),value:id}];\n }\n async update(id: string, operationId: string, fingerprint: string,\n change: (state: KanbanState | null) => KanbanState): Promise<KanbanState> {\n await this.prepareDirectory();\n const receiptKey = `receipt/${encodeURIComponent(id)}/${encodeURIComponent(operationId)}`;\n const snapshot = await this.select([key(id), receiptKey, 'index', boardCounterKey]);\n const raw = entry(snapshot, key(id)), receipt = entry(snapshot, receiptKey);\n const before = await this.loadRows(raw, snapshot.revision), current = await hydrate(before, this.bodies);\n if (receipt) {verifyReceipt(receipt, fingerprint); requireValue(current, 'CORRUPT_RECEIPT'); return current;}\n const original = JSON.stringify(current), state = change(current); numberEntities(state); if (JSON.stringify(state) === original) return state;\n const numbering = await this.numberBoard(snapshot, raw, id, state);\n const {changes, encoded} = await prepareChanges(id, before, state, this.bodies);\n changes.push(...numbering);\n changes.push({action: 'set', key: key(id), value: encoded.raw!}, {action: 'set', key: receiptKey, value: receiptDigest(fingerprint)});\n const ids: string[] = JSON.parse(entry(snapshot, 'index') ?? '[]');\n if (!ids.includes(id)) changes.push({action: 'set', key: 'index', value: JSON.stringify([...ids, id])});\n requireValue(changes.length <= 256, 'REMOTE_TRANSACTION_LIMIT');\n // The transport owns unknown-write reconciliation. Never retry a mutation here.\n try {await this.client.transaction(this.path, snapshot.revision, changes);}\n catch (error) {\n if ((error as {outcome?: string})?.outcome === 'not-committed' && (error as {code?: string})?.code === 'ECONFLICT') throw new KanbanError('REVISION_CONFLICT');\n throw error;\n }\n return state;\n }\n}\nfunction entry(snapshot: KanbanSeqSnapshot, key: string): string | null {\n const value = snapshot.entries.find(e => e.key === key)?.value;\n if (value === undefined) return null;\n if (typeof value !== 'string') throw new KanbanError('INVALID_STORAGE'); return value;\n}\n\nasync function prepareChanges(id: string, before: StoredBoard, state: KanbanState, bodies?: KanbanBodyStore) {\n const changes: KanbanSeqChange[] = state.events.map(event => ({action: 'set',\n key: `event/${encodeURIComponent(id)}/${String(event.sequence).padStart(16, '0')}`, value: JSON.stringify(event)}));\n for (const write of state.archiveWrites ?? []) changes.push(write.value\n ? {action: 'set', key: archiveKey(id, write.id), value: await encodeRow(write.value, bodies)}\n : {action: 'delete', key: archiveKey(id, write.id)});\n delete state.archiveWrites; state.events = [];\n const encoded = await encodeBoard(state, bodies);\n for (const row of rowChanges(before, encoded)) changes.push(row.value === null ? {action: 'delete', key: row.key} : {action: 'set', key: row.key, value: row.value});\n return {changes, encoded};\n}\n","import type {KanbanActor, KanbanCommand, KanbanContent, KanbanContentItem} from './contracts';\nimport type {KanbanModuleOptions, KanbanState, KanbanStore} from './ports';\nimport {createBoardState} from './board';\nimport {normalizeActor} from './identity';\nimport {identity, requireValue} from './rules';\nimport {reduce} from './reducer';\nimport {proposeAmendment} from './amendments';\nimport {randomUUID} from './utils';\n\nexport interface KanbanContentOptions extends KanbanModuleOptions {\n content: KanbanContent;\n operationId: string;\n fillMissing?: boolean;\n missingReferences?: 'reject' | 'detach';\n}\nexport async function inspectKanbanContent(store: KanbanStore, content: KanbanContent) {\n const state = await store.read(content.board.id);\n const ids = new Set([...state?.board.items ?? [], ...state?.archiveIndex ?? []].map(item => item.id));\n return {version: state?.presetVersions?.[content.id] ?? 0,\n complete: !!state && content.items.every(item => ids.has(item.command.item.id)) && (content.records ?? []).every(entry => state.records?.some(record => record.id === entry.record.id))};\n}\n\n/** Authorized bootstrap/import: domain changes and the installed version commit together. */\nexport async function installKanbanContent(options: KanbanContentOptions): Promise<{changed: boolean; created: number}> {\n const started = (options.now ?? Date.now)(), content = structuredClone(options.content);\n try {\n identity(content.id); identity(options.operationId);\n validateContent(content);\n const actor = normalizeActor(options.actor), before = await options.store.read(content.board.id);\n const initial = before ?? createBoardState(content.board, actor, started);\n await options.authorize({actor, board: structuredClone(initial.board), action: 'install-content'});\n const result = {changed: false, created: 0};\n if (before && !options.fillMissing && (before.presetVersions?.[content.id] ?? 1) >= content.version) {report(options, started, 'success'); return result;}\n await options.store.update(content.board.id, options.operationId, JSON.stringify({content, actor, fillMissing: !!options.fillMissing, missingReferences: options.missingReferences}), current => {\n requireValue(JSON.stringify(current) === JSON.stringify(before), 'REVISION_CONFLICT');\n if (current?.board.deletedAt !== undefined) {requireValue(!options.fillMissing, 'BOARD_DELETED'); return current;}\n const installed = current?.presetVersions?.[content.id] ?? (current ? 1 : 0);\n if (current && !options.fillMissing && installed >= content.version) return current;\n const state = current ?? initial; result.changed = !current;\n applyContent(state, {...options, content}, actor, installed, started, result);\n (state.presetVersions ??= {})[content.id] = content.version;\n return state;\n });\n report(options, started, 'success'); return result;\n } catch (error) {\n const raw = (error as {code?: unknown})?.code;\n report(options, started, 'failure', typeof raw === 'string' && /^[A-Z][A-Z0-9_]{0,79}$/.test(raw) ? raw : 'CONTENT_INSTALL_FAILED');\n throw error;\n }\n}\nfunction validateContent(content: KanbanContent): void {\n requireValue(Number.isSafeInteger(content.version) && content.version > 0, 'INVALID_CONTENT_VERSION');\n requireValue(Array.isArray(content.items) && content.items.length <= 1000, 'CONTENT_ITEM_LIMIT');\n for (const rows of [content.records, content.amendments]) requireValue(rows === undefined || Array.isArray(rows) && rows.length <= 1000, 'CONTENT_RECORD_LIMIT');\n for (const entry of [...content.items, ...content.records ?? [], ...content.amendments ?? []]) {\n const version = entry.introduced ?? 1;\n requireValue(Number.isSafeInteger(version) && version > 0 && version <= content.version, 'INVALID_CONTENT_VERSION');\n }\n}\nfunction applyContent(state: KanbanState, options: KanbanContentOptions, actor: KanbanActor, installed: number, now: number, result: {changed: boolean; created: number}): void {\n const content = options.content, version = options.fillMissing ? 0 : installed;\n const known = new Set([...state.board.items, ...state.archiveIndex ?? []].map(item => item.id));\n const apply = (command: KanbanCommand) => reduce(state, command, actor, options.operationId, now, (options.id ?? randomUUID)());\n for (const entry of content.items) {\n if (known.has(entry.command.item.id) || (entry.introduced ?? 1) <= version) continue;\n insertItem(state, entry, options.missingReferences === 'detach', apply);\n known.add(entry.command.item.id); result.changed = true; result.created++;\n }\n for (const entry of content.records ?? []) {\n if ((entry.introduced ?? 1) <= version || state.records?.some(record => record.id === entry.record.id)) continue;\n const record = structuredClone(entry.record);\n if (options.missingReferences === 'detach') record.itemIds = record.itemIds.filter(id => known.has(id));\n apply({type: 'append-record', record});\n if (entry.confirmed) apply({type: 'review-record', recordId: record.id, accept: true});\n result.changed = true;\n }\n for (const entry of content.amendments ?? []) {\n if ((entry.introduced ?? 1) <= version) continue;\n const item = state.board.items.find(item => item.id === entry.itemId); if (!item) continue;\n const count = item.amendments?.length ?? 0;\n // Imported attribution grants no authority to execute or review work.\n proposeAmendment(item, {action: 'update', ...entry, sources: []}, entry.proposedBy, now, entry.runId);\n if ((item.amendments?.length ?? 0) > count) {item.revision++; state.board.revision++; result.changed = true;}\n }\n}\nfunction insertItem(state: KanbanState, entry: KanbanContentItem, detach: boolean, apply: (command: KanbanCommand) => void): void {\n const command = structuredClone(entry.command), parentId = command.planning?.parentId;\n if (detach && parentId) {\n const parent = state.board.items.find(item => item.id === parentId);\n if (!parent || ['completed', 'cancelled'].includes(parent.status)) delete command.planning!.parentId;\n }\n const itemId = command.item.id;\n apply(command);\n if (entry.blocked) apply({type: 'block-item', itemId, reason: entry.blocked});\n if (entry.completion) {\n apply({type: 'close-plan', itemId, resultRef: entry.completion.resultRef});\n if (entry.completion.archiveReason) apply({type: 'archive-items', itemIds: [itemId], reason: entry.completion.archiveReason});\n }\n}\nfunction report(options: KanbanContentOptions, start: number, result: 'success' | 'failure', code?: string): void {\n try {options.log({operationId: options.operationId, boardId: options.content.board.id, stage: 'content.install', result, code, durationMs: (options.now ?? Date.now)() - start});}\n catch { /* Diagnostics cannot undo content installation. */ }\n}\n"],"mappings":"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","names":["entry","record","item"]}
@@ -9,7 +9,7 @@ import {
9
9
  summary,
10
10
  terminal,
11
11
  viewFromState
12
- } from "./chunk-OHQTKGQN.js";
12
+ } from "./chunk-XKDZHAUE.js";
13
13
  import {
14
14
  executable,
15
15
  identity,
@@ -19,22 +19,18 @@ import {
19
19
  requireValue,
20
20
  sameOwner,
21
21
  workType
22
- } from "./chunk-ATUFFNLV.js";
23
- import {
24
- KanbanError
25
- } from "./chunk-G6FCDLDF.js";
26
- import {
27
- projectKanbanTask
28
- } from "./chunk-O4OGAAV4.js";
22
+ } from "./chunk-3LEIHB7Y.js";
29
23
  import {
30
24
  kanbanReference
31
- } from "./chunk-5XKOCKY2.js";
25
+ } from "./chunk-X4UHZX6F.js";
32
26
  import {
27
+ KanbanError,
33
28
  randomUUID
34
- } from "./chunk-TB2RZGDV.js";
29
+ } from "./chunk-M35X5PHO.js";
35
30
  import {
36
- boardControlPhase
37
- } from "./chunk-QTMTBEBA.js";
31
+ boardControlPhase,
32
+ projectKanbanTask
33
+ } from "./chunk-3JYLJPE5.js";
38
34
 
39
35
  // src/references.ts
40
36
  async function resolveReference(reference, store, read) {
@@ -151,6 +147,7 @@ function order(a, b) {
151
147
  return a.planning.priority - b.planning.priority || a.createdAt - b.createdAt || a.id.localeCompare(b.id);
152
148
  }
153
149
  function matchesQuery(item, query, board) {
150
+ if (item.deletedAt !== void 0 && !query.includeDeleted) return false;
154
151
  if (query.phase && item.task?.phase !== query.phase) return false;
155
152
  if (!matchesView(item, query.view ?? "ready")) return false;
156
153
  for (const field of ["area", "milestone", "parentId", "kind"]) if (query[field] !== void 0 && item.planning[field] !== query[field]) return false;
@@ -168,6 +165,7 @@ function matchesView(item, view) {
168
165
  return item.status === { ready: "open", backlog: "backlog", review: "review", proposed: "proposed" }[view];
169
166
  }
170
167
  function overview(state, now, items = state.board.items.map(summary)) {
168
+ items = items.filter((item) => item.deletedAt === void 0);
171
169
  const count = (status) => items.filter((i) => i.status === status).length;
172
170
  const age = state.board.policy.backlogReviewMs;
173
171
  return {
@@ -273,7 +271,7 @@ var KanbanModule = class {
273
271
  try {
274
272
  const view = await this.readView(id);
275
273
  if (view.state.board.deletedAt !== void 0) continue;
276
- boards.push({ ...view.state.board, executionPhase: boardControlPhase({ ...view.state.board, items: view.items }), items: view.items.map(({ id: id2, title, number }) => ({ id: id2, title, ...number === void 0 ? {} : { number } })) });
274
+ boards.push({ ...view.state.board, executionPhase: boardControlPhase({ ...view.state.board, items: view.items }), items: view.items.filter((item) => item.deletedAt === void 0).map(({ id: id2, title, number }) => ({ id: id2, title, ...number === void 0 ? {} : { number } })) });
277
275
  } catch (error) {
278
276
  if (!(error instanceof KanbanError) || error.code !== "FORBIDDEN") throw error;
279
277
  }
@@ -299,6 +297,7 @@ var KanbanModule = class {
299
297
  await this.authorize(state.board, request.command.type, request.command);
300
298
  requireValue(state.board.deletedAt === void 0, "BOARD_DELETED");
301
299
  if (request.command.type === "delete-board") await this.options.verifyDeletion?.(structuredClone(state.board));
300
+ await this.options.verifyLifecycle?.(structuredClone(state.board), request.command);
302
301
  await this.verifyRelease(state.board, request.command);
303
302
  const verifyStage = request.command.type === "observe-execution" && request.command.outcome === "succeeded" ? "observe" : request.command.type === "accept-execution" && request.command.accept ? "accept" : void 0;
304
303
  if (verifyStage && "dispatchId" in request.command) {
@@ -356,11 +355,16 @@ var KanbanModule = class {
356
355
  });
357
356
  scan = () => this.guard(this.id(), void 0, "scan", async () => {
358
357
  const errors = [];
359
- for (const board of await this.list()) {
358
+ for (const id of await this.options.store.ids()) {
360
359
  try {
360
+ const board = (await this.readState(id)).board;
361
+ if (board.deletedAt !== void 0) {
362
+ await this.publishNotifications(id, this.id());
363
+ continue;
364
+ }
361
365
  await this.execute(board.id, { operationId: this.id(), expectedRevision: board.revision, command: { type: "scan" } });
362
366
  } catch (error) {
363
- if (!(error instanceof KanbanError) || error.code !== "REVISION_CONFLICT") errors.push(error);
367
+ if (!(error instanceof KanbanError) || !["REVISION_CONFLICT", "FORBIDDEN"].includes(error.code)) errors.push(error);
364
368
  }
365
369
  }
366
370
  if (errors.length) throw new AggregateError(errors, "KANBAN_SCAN_FAILED");
@@ -436,4 +440,4 @@ function safeCode(error, fallback) {
436
440
  export {
437
441
  createKanbanModule
438
442
  };
439
- //# sourceMappingURL=chunk-DFTOTBGF.js.map
443
+ //# sourceMappingURL=chunk-KH3WF3K4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/references.ts","../src/suggestions.ts","../src/queries.ts","../src/module.ts"],"sourcesContent":["import {kanbanReference, type KanbanReferenceTarget} from './contracts';\nimport type {KanbanReadView, KanbanStore} from './ports';\nimport {requireValue} from './rules';\n\nexport async function resolveReference(reference: string, store: KanbanStore, read: (id: string) => Promise<KanbanReadView>): Promise<KanbanReferenceTarget> {\n requireValue(typeof reference === 'string' && reference.length <= 100, 'INVALID_REFERENCE');\n const match = /^KB-([1-9]\\d*)(?:#([1-9]\\d*)|\\/(L|D)-([1-9]\\d*))?$/i.exec(reference.trim());\n requireValue(match && [match[1], match[2], match[4]].every(value => value === undefined || Number.isSafeInteger(Number(value))), 'INVALID_REFERENCE');\n const id = await store.boardId?.(Number(match[1])); requireValue(id, 'REFERENCE_NOT_FOUND');\n const view = await read(id), board = view.state.board;\n requireValue(board.number === Number(match[1]), 'INVALID_NUMBERING');\n const target: KanbanReferenceTarget = {boardId: id, scope: board.scope, reference: kanbanReference(board)};\n if (match[2]) {\n const item = [...view.items, ...(view.state.archiveIndex ?? [])].find(item => item.number === Number(match[2]));\n requireValue(item, 'REFERENCE_NOT_FOUND'); target.itemId = item.id; target.reference = kanbanReference(board, item);\n } else if (match[3]) {\n const record = view.records.find(record => record.kind === (match[3].toUpperCase() === 'L' ? 'log' : 'decision') && record.number === Number(match[4]));\n requireValue(record, 'REFERENCE_NOT_FOUND'); target.recordId = record.id; target.reference = kanbanReference(board, record);\n }\n return target;\n}\n","import {kanbanReference} from './contracts';\nimport type {KanbanSuggestion, KanbanSuggestionPage, KanbanSuggestionQuery} from './contracts';\nimport type {KanbanState} from './ports';\nimport {recordSummary} from './project-records';\nimport {catalog, terminal} from './planning';\nimport {workType} from './configuration';\nimport {identity, requireValue} from './rules';\n\nexport function validateSuggestionQuery(query: KanbanSuggestionQuery): number {\n requireValue(query && ['item', 'parent', 'dependency', 'area', 'milestone', 'decision', 'session'].includes(query.kind), 'INVALID_SUGGESTION_KIND');\n requireValue(query.search === undefined || typeof query.search === 'string' && query.search.length <= 256, 'INVALID_FILTER');\n const limit = query.limit ?? 20; requireValue(Number.isSafeInteger(limit) && limit > 0 && limit <= 50, 'INVALID_LIMIT');\n if (query.excludeItemId !== undefined) identity(query.excludeItemId);\n if (query.excludeIds !== undefined) {requireValue(Array.isArray(query.excludeIds) && query.excludeIds.length <= 100, 'INVALID_FILTER'); query.excludeIds.forEach(identity);}\n if (query.childKind !== undefined) identity(query.childKind);\n return limit;\n}\nexport function suggestionPage(revision: number, rows: KanbanSuggestion[], query: KanbanSuggestionQuery): KanbanSuggestionPage {\n const limit = validateSuggestionQuery(query), search = query.search?.trim().toLocaleLowerCase() ?? '';\n const matched = rows.filter(row => !query.excludeIds?.includes(row.id)).filter(row => `${row.id} ${row.label} ${row.detail ?? ''}`.toLocaleLowerCase().includes(search))\n .sort((a, b) => score(a.label, search) - score(b.label, search) || a.label.localeCompare(b.label) || a.id.localeCompare(b.id));\n return {revision, items: matched.slice(0, limit).map(row => ({id: row.id, label: row.label.slice(0, 256), ...(row.detail ? {detail: row.detail.slice(0, 512)} : {}), ...(row.status ? {status: row.status} : {}), ...(row.archived !== undefined ? {archived: row.archived} : {})})), hasMore: matched.length > limit};\n}\nconst score = (label: string, query: string) => label.toLocaleLowerCase() === query ? 0 : label.toLocaleLowerCase().startsWith(query) ? 1 : 2;\nexport function suggestFromState(state: KanbanState, query: KanbanSuggestionQuery, items = catalog(state), records = (state.records ?? []).map(recordSummary)): KanbanSuggestionPage {\n validateSuggestionQuery(query);\n if (query.kind === 'area' || query.kind === 'milestone') {\n const names = [...new Set(items.map(item => item.planning[query.kind as 'area' | 'milestone']).filter((name): name is string => !!name))];\n return suggestionPage(state.board.revision, names.map(name => ({id: name, label: name})), query);\n }\n if (query.kind === 'decision') return suggestionPage(state.board.revision, records\n .filter(record => record.kind === 'decision' && record.status === 'confirmed').map(record => ({id: record.id, label: record.title, detail: kanbanReference(state.board, record)})), query);\n if (query.kind === 'session') {\n const ids = new Set([...state.board.participants.map(p => p.sessionId), ...items.flatMap(item => item.sessionIds),\n ...records.flatMap(record => record.sessionIds)]);\n return suggestionPage(state.board.revision, [...ids].map(id => ({id, label: id})), query);\n }\n const blocked = query.kind === 'dependency' && query.excludeItemId ? dependents(items, query.excludeItemId) : new Set<string>();\n const rank = query.kind === 'parent' ? workType(state.board, query.childKind ?? state.board.defaultWorkType ?? 'task').rank : undefined;\n const rows = items.filter(item => item.id !== query.excludeItemId && !blocked.has(item.id)\n && (query.kind !== 'dependency' || item.status !== 'cancelled')\n && (rank === undefined || item.archivedAt === undefined && !terminal(item) && workType(state.board, item.planning.kind).rank < rank))\n .map(item => ({id: item.id, label: item.title, status: item.status, archived: item.archivedAt !== undefined,\n detail: [kanbanReference(state.board, item), item.planning.area, item.planning.milestone].filter(Boolean).join(' · ')}));\n return suggestionPage(state.board.revision, rows, query);\n}\nfunction dependents(items: import('./contracts').KanbanItemSummary[], id: string): Set<string> {\n const reverse = new Map<string, string[]>();\n for (const item of items) for (const dependency of item.planning.dependencies) reverse.set(dependency, [...(reverse.get(dependency) ?? []), item.id]);\n const result = new Set([id]), pending = [id];\n while (pending.length) for (const next of reverse.get(pending.pop()!) ?? []) if (!result.has(next)) {result.add(next); pending.push(next);}\n return result;\n}\n","import {projectKanbanTask} from './contracts/task-projection';\nimport {kanbanReference} from './contracts';\nimport type {KanbanItemPage, KanbanItemQuery, KanbanItemSummary, KanbanOverview} from './contracts';\nimport type {KanbanState} from './ports';\nimport {requireValue} from './rules';\nimport {executable} from './configuration';\nimport {catalog, limits, summary, terminal} from './planning';\n\nexport function queryItems(state: KanbanState, query: KanbanItemQuery = {}, all = catalog(state), now = Date.now()): KanbanItemPage {\n const {cursor, limit = 50, ...filters} = query;\n requireValue(Number.isSafeInteger(limit) && limit >= 1 && limit <= 200, 'INVALID_PAGE_SIZE');\n requireValue(['ready', 'backlog', 'in-progress', 'review', 'closed', 'proposed', 'archive', 'all'].includes(query.view ?? 'ready'), 'INVALID_VIEW');\n for (const field of ['area', 'milestone', 'parentId', 'kind', 'sessionId', 'search'] as const) if (filters[field] !== undefined) requireValue(typeof filters[field] === 'string' && filters[field]!.length <= 256, 'INVALID_FILTER');\n if (filters.reference) requireValue(typeof filters.reference.system === 'string' && typeof filters.reference.id === 'string' && filters.reference.system.length <= 256 && filters.reference.id.length <= 256, 'INVALID_REFERENCE_FILTER');\n const fingerprint = JSON.stringify(Object.fromEntries(Object.entries({...filters, view: filters.view ?? 'ready'}).sort(([a], [b]) => a.localeCompare(b)))), revision = state.board.revision;\n all = all.map(item => ({...item, task: projectKanbanTask(item, state.workflow, now, all)}));\n const matches = all.filter(item => matchesQuery(item, filters, state.board)).sort(filters.view === 'archive'\n ? (a, b) => (b.archivedAt ?? 0) - (a.archivedAt ?? 0) || a.id.localeCompare(b.id) : order);\n let start = 0;\n if (cursor) {\n requireValue(typeof cursor === 'string' && cursor.length <= 4000, 'INVALID_CURSOR');\n let decoded: {revision: number; after: string; filter: string};\n try {decoded = JSON.parse(cursor);} catch {requireValue(false, 'INVALID_CURSOR');}\n requireValue(decoded && decoded.filter === fingerprint, 'CURSOR_SCOPE_MISMATCH');\n requireValue(decoded.revision === revision, 'CURSOR_STALE');\n start = matches.findIndex(i => i.id === decoded.after) + 1; requireValue(start > 0, 'INVALID_CURSOR');\n }\n const progress = progressByParent(state, all);\n const items = matches.slice(start, start + limit).map(item => ({...item, ...(progress.has(item.id) ? {progress: progress.get(item.id)} : {})}));\n return {revision, total: matches.length, items, ...(start + items.length < matches.length ? {\n nextCursor: JSON.stringify({revision, after: items.at(-1)!.id, filter: fingerprint}),\n } : {})};\n}\nfunction order(a: KanbanItemSummary, b: KanbanItemSummary): number {\n return a.planning.priority - b.planning.priority || a.createdAt - b.createdAt || a.id.localeCompare(b.id);\n}\nfunction matchesQuery(item: KanbanItemSummary, query: Omit<KanbanItemQuery, 'cursor' | 'limit'>, board: KanbanState['board']): boolean {\n if (item.deletedAt !== undefined && !query.includeDeleted) return false;\n if (query.phase && item.task?.phase !== query.phase) return false;\n if (!matchesView(item, query.view ?? 'ready')) return false;\n for (const field of ['area', 'milestone', 'parentId', 'kind'] as const) if (query[field] !== undefined && item.planning[field] !== query[field]) return false;\n if (query.reference && !item.externalRefs?.some(r => r.system === query.reference!.system && r.id === query.reference!.id)) return false;\n if (query.sessionId && !item.sessionIds.includes(query.sessionId)) return false;\n if (query.search && !`${kanbanReference(board, item)} ${item.id} ${item.title} ${item.planning.area ?? ''}`.toLowerCase().includes(query.search.toLowerCase())) return false;\n return true;\n}\nfunction matchesView(item: KanbanItemSummary, view: KanbanItemQuery['view']): boolean {\n if (view === 'archive') return item.archivedAt !== undefined;\n if (view === 'all') return true;\n if (item.archivedAt !== undefined) return false;\n if (view === 'in-progress') return item.status === 'claimed' || item.status === 'review';\n if (view === 'closed') return terminal(item);\n return item.status === ({ready: 'open', backlog: 'backlog', review: 'review', proposed: 'proposed'} as Record<string, string>)[view!];\n}\nexport function overview(state: KanbanState, now: number, items = state.board.items.map(summary)): KanbanOverview {\n items = items.filter(item => item.deletedAt === undefined);\n const count = (status: string) => items.filter(i => i.status === status).length;\n const age = state.board.policy.backlogReviewMs;\n return {revision: state.board.revision, visible: items.length, active: items.filter(i => !terminal(i)).length, archived: state.archiveIndex?.length ?? 0, ready: count('open'),\n inProgress: count('claimed') + count('review'), backlog: count('backlog'), proposed: count('proposed'),\n closed: count('completed') + count('cancelled'), dueForReview: age ? items.filter(i => i.status === 'backlog' && now - i.updatedAt >= age).length : 0,\n limits: limits(state)};\n}\n\nfunction progressByParent(state: KanbanState, all: KanbanItemSummary[]): Map<string, NonNullable<KanbanItemSummary['progress']>> {\n const byId = new Map(all.map(i => [i.id, i]));\n const result = new Map<string, NonNullable<KanbanItemSummary['progress']>>();\n for (const item of all.filter(i => executable(state.board, i))) {\n let parent = item.planning.parentId; const seen = new Set<string>();\n while (parent && !seen.has(parent)) {\n seen.add(parent); const progress = result.get(parent) ?? {total: 0, completed: 0, cancelled: 0, inProgress: 0};\n progress.total++; if (item.status === 'completed') progress.completed++; if (item.status === 'cancelled') progress.cancelled++;\n if (item.status === 'claimed' || item.status === 'review') progress.inProgress++;\n result.set(parent, progress); parent = byId.get(parent)?.planning.parentId;\n }\n }\n return result;\n}\n","import {boardControlPhase} from './contracts/board-control';\nimport {projectKanbanTask} from './contracts/task-projection';\nimport {resolveReference} from './references';\nimport {suggestFromState, suggestionPage, validateSuggestionQuery} from './suggestions';\nimport {queryRecords} from './project-records';\nimport { randomUUID } from './utils';\nimport type { KanbanBoard, KanbanRequest, KanbanService, KanbanItemQuery, KanbanBoardInput } from './contracts';\nimport { KanbanError, type KanbanModuleOptions, type KanbanState } from './ports';\nimport { identity, requireValue } from './rules';\nimport {createBoardState} from './board';\nimport {normalizeActor, principal, principalKey, sameOwner} from './identity';\nimport {queryItems, overview} from './queries';\nimport {viewFromState} from './storage-codec';\nimport { reduce, related } from './reducer';\n\n/** Optional host-owned service; no timer or model calls are started implicitly. */\nexport function createKanbanModule(options: KanbanModuleOptions): KanbanModuleHandle { return new KanbanModule(options); }\nexport interface KanbanModuleHandle extends KanbanService {quiesce(): Promise<void>; dispose(): Promise<void>}\nclass KanbanModule implements KanbanService {\n private stopping = false;\n private readonly pending = new Set<Promise<unknown>>();\n async quiesce(): Promise<void> {this.stopping = true; await Promise.allSettled([...this.pending]);}\n async dispose(): Promise<void> {await this.quiesce();}\n private readonly now;\n private readonly id;\n private readonly actor;\n constructor(private readonly options: KanbanModuleOptions) {\n this.now = options.now ?? Date.now; this.id = options.id ?? randomUUID;\n this.actor = normalizeActor(options.actor);\n }\n workflow = (boardId: string) => this.guard(this.id(), boardId, 'workflow', async () => structuredClone((await this.readView(boardId)).state.workflow ?? {plans:{},dispatches:{},ready:[],completedPlans:[]}));\n resolve = (reference: string) => this.guard(this.id(), undefined, 'resolve', () => resolveReference(reference, this.options.store, id => this.readView(id)));\n suggest = (boardId: string, query: import('./contracts').KanbanSuggestionQuery) => this.guard(this.id(), boardId, 'suggest', async () => {\n const snapshot = structuredClone(query), limit = validateSuggestionQuery(snapshot), view = await this.readView(boardId), state = view.state;\n const suggestions = () => suggestFromState(state, snapshot, [...view.items, ...(state.archiveIndex ?? [])], view.records);\n if (!this.options.suggestions) return suggestions();\n const rows = await this.options.suggestions(structuredClone(state.board), snapshot.kind, snapshot.search?.trim() ?? '', limit + 1);\n if (rows === undefined) return suggestions();\n const known = suggestions().items.filter(row => !rows.some(entry => entry.id === row.id));\n return suggestionPage(state.board.revision, [...rows, ...known], snapshot);\n });\n records = (boardId: string, query?: import('./contracts').KanbanRecordQuery) => this.guard(this.id(), boardId, 'records', async () => {const view = await this.readView(boardId); return structuredClone(queryRecords(view.state, query, view.records));});\n record = (boardId: string, recordId: string) => this.guard(this.id(), boardId, 'record', async () => {\n identity(recordId); const record = (await this.readState(boardId)).records?.find(record => record.id === recordId);\n requireValue(record, 'RECORD_NOT_FOUND'); return structuredClone(record);\n });\n currentPrincipal = async () => structuredClone(principal(this.actor));\n create = (input: KanbanBoardInput): Promise<KanbanBoard> => {\n const snapshot = structuredClone(input);\n return this.guard(this.id(), snapshot.id, 'create', async () => {\n const initial = createBoardState(snapshot, this.actor, this.now()), board = initial.board;\n await this.authorize(board, 'create');\n const state = await this.options.store.update(board.id, `create:${board.id}`, JSON.stringify({ snapshot, actor: this.actor }), previous => {\n requireValue(!previous, 'BOARD_EXISTS'); return initial;\n });\n return structuredClone(state.board);\n });\n };\n read = (boardId: string): Promise<KanbanBoard> => this.guard(this.id(), boardId, 'read',\n async () => structuredClone((await this.readState(boardId)).board));\n catalog = () => this.guard(this.id(), undefined, 'catalog', async () => {\n const boards: import('./contracts').KanbanBoardSummary[] = [];\n for (const id of await this.options.store.ids()) {\n try {const view = await this.readView(id); if (view.state.board.deletedAt !== undefined) continue; boards.push({...view.state.board, executionPhase: boardControlPhase({...view.state.board, items: view.items}), items: view.items.filter(item => item.deletedAt === undefined).map(({id, title, number}) => ({id, title, ...(number === undefined ? {} : {number})}))});}\n catch (error) {if (!(error instanceof KanbanError) || error.code !== 'FORBIDDEN') throw error;}\n }\n return structuredClone(boards);\n });\n list = (): Promise<KanbanBoard[]> => this.guard(this.id(), undefined, 'list', async () => {\n const boards: KanbanBoard[] = [];\n for (const boardId of await this.options.store.ids()) {\n try { const board = (await this.readState(boardId)).board; if (board.deletedAt === undefined) boards.push(structuredClone(board)); }\n catch (error) { if (!(error instanceof KanbanError) || error.code !== 'FORBIDDEN') throw error; }\n }\n return boards;\n });\n execute = (boardId: string, input: KanbanRequest): Promise<KanbanBoard> => this.guard(input.operationId, boardId, `execute:${input.command.type}`, async () => {\n const request = structuredClone(input); identity(request.operationId);\n const state = await this.readState(boardId);\n await this.authorize(state.board, request.command.type, request.command);\n requireValue(state.board.deletedAt === undefined, 'BOARD_DELETED');\n if (request.command.type === 'delete-board') await this.options.verifyDeletion?.(structuredClone(state.board));\n await this.options.verifyLifecycle?.(structuredClone(state.board), request.command);\n await this.verifyRelease(state.board, request.command);\n const verifyStage = request.command.type === 'observe-execution' && request.command.outcome === 'succeeded' ? 'observe'\n : request.command.type === 'accept-execution' && request.command.accept ? 'accept' : undefined;\n if (verifyStage && 'dispatchId' in request.command) {\n const dispatch = state.workflow?.dispatches[request.command.dispatchId]; requireValue(dispatch, 'DISPATCH_NOT_FOUND');\n const outputs = request.command.type === 'observe-execution' ? request.command.outputs : dispatch.outputs;\n if (outputs?.length) requireValue(await this.options.verifyOutputs?.({stage: verifyStage, board: state.board, itemId: dispatch.itemId,\n dispatchId: dispatch.id, outputs: structuredClone(outputs)}), 'OUTPUT_VERIFICATION_REQUIRED');\n }\n const restore = request.command.type === 'restore-item' ? await this.options.store.archived(boardId, request.command.itemId) : undefined;\n const result = await this.options.store.update(boardId, request.operationId, JSON.stringify({ actor: this.actor, request }), current => {\n requireValue(current && current.board.revision === state.board.revision, 'REVISION_CONFLICT');\n requireValue(current.board.revision === request.expectedRevision, 'REVISION_CONFLICT');\n if (restore) current.restore = restore;\n return reduce(current, request.command, this.actor, request.operationId, this.now(), this.id());\n });\n await this.publishNotifications(boardId, request.operationId);\n return structuredClone(result.board);\n });\n events = (boardId: string, after = 0, limit = 100) => this.guard(this.id(), boardId, 'events', async () => {\n requireValue(Number.isSafeInteger(after) && after >= 0 && Number.isSafeInteger(limit) && limit > 0 && limit <= 500, 'INVALID_CURSOR');\n const {state} = await this.readView(boardId);\n return this.options.store.events(boardId, after, limit, state.sequence);\n });\n query = (boardId: string, query?: KanbanItemQuery) => this.guard(this.id(), boardId, 'query', async () => {const view = await this.readView(boardId); return structuredClone(queryItems(view.state, query, [...view.items, ...(view.state.archiveIndex ?? [])], this.now()));});\n overview = (boardId: string) => this.guard(this.id(), boardId, 'overview', async () => {const view = await this.readView(boardId); return overview(view.state, this.now(), view.items);});\n item = (boardId: string, itemId: string) => this.guard(this.id(), boardId, 'item', async () => {\n identity(itemId); const state = await this.readState(boardId), item = state.board.items.find(i => i.id === itemId);\n if (item) return {item: structuredClone(item),task:projectKanbanTask(item,state.workflow,this.now(),[...state.board.items,...state.archiveIndex??[]])};\n requireValue(state.archiveIndex?.some(i => i.id === itemId), 'ITEM_NOT_FOUND');\n const record = await this.options.store.archived(boardId, itemId); requireValue(record, 'REVISION_CONFLICT');\n return {item: structuredClone(record.item), task:projectKanbanTask(record.item,state.workflow,this.now(),state.archiveIndex), archive: {archivedAt: record.archivedAt, reason: record.reason}};\n });\n related = (sessionId: string): Promise<KanbanBoard[]> => this.guard(this.id(), undefined, 'related', async () => {\n identity(sessionId); const result: KanbanBoard[] = [];\n for (const board of await this.list()) {\n const state = await this.readState(board.id);\n if (related(board).includes(sessionId) || state.records?.some(record => record.sources.some(source => source.sessionId === sessionId)) || state.archiveIndex?.some(i => i.sessionIds.includes(sessionId))) result.push(board);\n }\n return result;\n });\n scan = (): Promise<void> => this.guard(this.id(), undefined, 'scan', async () => {\n const errors: unknown[] = [];\n for (const id of await this.options.store.ids()) {\n try {\n const board = (await this.readState(id)).board;\n if (board.deletedAt !== undefined) {await this.publishNotifications(id,this.id()); continue;}\n await this.execute(board.id, { operationId: this.id(), expectedRevision: board.revision, command: { type: 'scan' } });\n }\n catch (error) {\n if (!(error instanceof KanbanError) || !['REVISION_CONFLICT','FORBIDDEN'].includes(error.code)) errors.push(error);\n }\n }\n if (errors.length) throw new AggregateError(errors, 'KANBAN_SCAN_FAILED');\n });\n private async verifyRelease(board: KanbanBoard, command: KanbanRequest['command']): Promise<void> {\n if (command.type !== 'release-item') return;\n const item = board.items.find(i => i.id === command.itemId); requireValue(item?.owner && item.owner.token === command.token, 'OWNER_MISMATCH');\n const own = sameOwner(item.owner, this.actor), actor = principal(this.actor);\n const coordinator = board.members?.some(m => principalKey(m) === principalKey(actor) && m.roles?.includes('coordinator'));\n requireValue(own || coordinator, 'OWNER_MISMATCH');\n if (!(own && actor.kind === 'human')) requireValue(await this.options.verifyRelease?.({actor: this.actor, board: structuredClone(board), item: structuredClone(item)}), 'EXECUTION_NOT_SETTLED');\n }\n private async publishNotifications(boardId: string, operationId: string): Promise<void> {\n if (!this.options.onCommitted) return;\n const started = this.now();\n try {await this.options.onCommitted(boardId, this, this.now()); this.log(operationId, boardId, 'notify', started, 'success');}\n catch (error) {this.log(operationId, boardId, 'notify', started, 'failure', safeCode(error, 'NOTIFICATION_PROJECTION_FAILED'));}\n }\n private async readView(boardId: string) {\n identity(boardId);\n if (!this.options.store.view) return viewFromState(await this.readState(boardId));\n const view = await this.options.store.view(boardId); requireValue(view, 'BOARD_NOT_FOUND');\n await this.authorize(view.state.board, 'read'); return view;\n }\n private async readState(boardId: string): Promise<KanbanState> {\n identity(boardId); const state = await this.options.store.read(boardId); requireValue(state, 'BOARD_NOT_FOUND');\n await this.authorize(state.board, 'read'); return state;\n }\n private authorize(board: KanbanBoard, action: Parameters<KanbanModuleOptions['authorize']>[0]['action'], command?: KanbanRequest['command']) {\n return this.options.authorize({ actor: structuredClone(this.actor), board: structuredClone(board), action, command: structuredClone(command) });\n }\n private async guard<T>(operationId: string, boardId: string | undefined, stage: string, run: () => Promise<T>): Promise<T> {\n const start = this.now();\n if (this.stopping) {this.log(operationId,boardId,stage,start,'failure','SERVICE_STOPPING'); throw new KanbanError('SERVICE_STOPPING');}\n const operation = Promise.resolve().then(run); this.pending.add(operation);\n try { const result = await operation; this.log(operationId, boardId, stage, start, 'success'); return result; }\n catch (error) {\n this.log(operationId, boardId, stage, start, 'failure', safeCode(error, 'PORT_FAILURE')); throw error;\n } finally {this.pending.delete(operation);}\n }\n private log(operationId: string, boardId: string | undefined, stage: string, start: number, result: 'success' | 'failure', code?: string): void {\n try { this.options.log({ operationId, boardId, stage, result, code, durationMs: this.now() - start }); }\n catch { /* Diagnostics cannot undo a commit. */ }\n }\n}\n\nfunction safeCode(error: unknown, fallback: string): string {\n const code = (error as {code?: unknown})?.code;\n return typeof code === 'string' && /^[A-Z][A-Z0-9_]{0,79}$/.test(code) ? code : fallback;\n}\n"],"mappings":"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","names":["item","record","record","id"]}
@@ -1,3 +1,14 @@
1
+ // src/ports.ts
2
+ var KanbanError = class extends Error {
3
+ constructor(code) {
4
+ super(code);
5
+ this.code = code;
6
+ this.name = "KanbanError";
7
+ }
8
+ };
9
+ var KanbanScanNotStartedError = class extends KanbanError {
10
+ };
11
+
1
12
  // src/utils/random.ts
2
13
  function randomUUID() {
3
14
  const webCrypto = globalThis.crypto;
@@ -177,7 +188,9 @@ function sha256HexSync(input) {
177
188
  }
178
189
 
179
190
  export {
191
+ KanbanError,
192
+ KanbanScanNotStartedError,
180
193
  randomUUID,
181
194
  sha256HexSync
182
195
  };
183
- //# sourceMappingURL=chunk-TB2RZGDV.js.map
196
+ //# sourceMappingURL=chunk-M35X5PHO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ports.ts","../src/utils/random.ts","../src/utils/digest.ts"],"sourcesContent":["import type { KanbanActor, KanbanBoard, KanbanCommand, KanbanEvent, KanbanArchivedItem, KanbanItemSummary } from './contracts';\n\nexport interface KanbanState {\n workflow?: import('./contracts').KanbanWorkflowState;\n numbering?: {item: number; log: number; decision: number};\n presetVersions?: Record<string, number>;\n records?: import('./contracts').KanbanProjectRecord[];\n discovery?: import('./scan-ports').KanbanDiscoveryState;\n archiveIndex?: KanbanItemSummary[];\n archiveWrites?: Array<{id: string; value: KanbanArchivedItem | null}>;\n restore?: KanbanArchivedItem;\n schema: 1; board: KanbanBoard; sequence: number; events: KanbanEvent[]; escalations: string[];\n}\nexport interface KanbanReadView {\n /** Board metadata and summary indexes; no item/record bodies. */\n state: KanbanState;\n items: import('./contracts').KanbanItemSummary[];\n records: import('./contracts').KanbanRecordSummary[];\n}\nexport interface KanbanStore {\n boardId?(number: number): Promise<string | null>;\n view?(id: string): Promise<KanbanReadView | null>;\n ids(): Promise<string[]>;\n archived(boardId: string, itemId: string): Promise<KanbanArchivedItem | null>;\n events(id: string, after: number, limit: number, through: number): Promise<KanbanEvent[]>;\n read(id: string): Promise<KanbanState | null>;\n update(id: string, operationId: string, fingerprint: string,\n change: (state: KanbanState | null) => KanbanState): Promise<KanbanState>;\n}\nexport interface KanbanModuleOptions {\n /** Host supplies metadata within the authorized user's/project's session scope. */\n suggestions?(board: KanbanBoard, kind: import('./contracts').KanbanSuggestionKind, search: string, limit: number): Promise<import('./contracts').KanbanSuggestion[] | undefined>;\n verifyOutputs?(input: {stage?: 'observe' | 'accept'; board: KanbanBoard; itemId: string; dispatchId?: string; outputs: import('./contracts').KanbanArtifactRef[]}): Promise<boolean>;\n onCommitted?(boardId: string, service: import('./contracts').KanbanService, now: number): Promise<void>;\n store: KanbanStore;\n /** Trusted identity resolved by the host, never from command payloads. */\n actor: KanbanActor;\n /** Must validate project access, delegated authority and session registration. */\n authorize(input: { actor: KanbanActor; board: KanbanBoard; action: 'create' | 'read' | 'install-content' | KanbanCommand['type']; command?: KanbanCommand }): Promise<void>;\n /** Confirm an automated owner has settled before releasing responsibility. */\n verifyDeletion?(board: KanbanBoard): Promise<void>;\n verifyLifecycle?(board: KanbanBoard, command: KanbanCommand): Promise<void>;\n verifyRelease?(input: {actor: KanbanActor; board: KanbanBoard; item: import('./contracts').KanbanItem}): Promise<boolean>;\n now?: () => number;\n id?: () => string;\n log(event: { operationId: string; boardId?: string; sessionId?: string; stage: string; result: 'success' | 'failure'; code?: string; durationMs: number }): void;\n}\nexport class KanbanError extends Error {\n constructor(readonly code: string) { super(code); this.name = 'KanbanError'; }\n}\n\nexport class KanbanScanNotStartedError extends KanbanError {}\n","/**\n * @file common/utils/random.ts\n * @description UUID v4 that also works outside a secure context.\n *\n * `crypto.randomUUID()` is secure-context-only: it is undefined over plain-HTTP\n * LAN origins (e.g. http://192.168.x.x:3000) and in WebKitGTK, so calling it\n * directly throws \"crypto.randomUUID is not a function\". `crypto.getRandomValues()`\n * stays available everywhere, so it backs the fallback below.\n */\n\n/** UUID v4 — native WebCrypto when available, `getRandomValues` otherwise. */\nexport function randomUUID(): string {\n const webCrypto = globalThis.crypto;\n if (typeof webCrypto?.randomUUID === 'function') {\n try {\n return webCrypto.randomUUID();\n } catch {\n // Present but unusable (insecure context) — fall through.\n }\n }\n return formatV4(randomBytes(16));\n}\n\nfunction randomBytes(length: number): Uint8Array {\n const bytes = new Uint8Array(length);\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes);\n return bytes;\n }\n for (let i = 0; i < length; i++) bytes[i] = Math.floor(Math.random() * 256);\n return bytes;\n}\n\nfunction formatV4(bytes: Uint8Array): string {\n bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4\n bytes[8] = (bytes[8] & 0x3f) | 0x80; // RFC 4122 variant\n const hex = [...bytes].map(byte => byte.toString(16).padStart(2, '0'));\n return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex.slice(6, 8).join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10).join('')}`;\n}\n","/**\n * @file common/utils/digest.ts\n * @description SHA-256 that does not require WebCrypto.\n *\n * `crypto.subtle` only exists in a secure context (HTTPS or localhost) and is\n * absent in WebKitGTK, so `crypto.subtle.digest(...)` throws \"Cannot read\n * properties of undefined (reading 'digest')\" when the app is opened over a LAN\n * HTTP origin (e.g. http://192.168.x.x:3000) or in the packaged Linux app. The\n * pure-JS fallback below computes the very same SHA-256, so digests stay stable\n * across environments.\n */\n\n/** Any input a caller may want hashed. */\nexport type DigestInput = string | ArrayBuffer | ArrayBufferView;\n\nconst SHA256_K = new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n]);\n\nconst SHA256_H = new Uint32Array([\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n]);\n\nconst rotateRight = (value: number, bits: number): number =>\n ((value >>> bits) | (value << (32 - bits))) >>> 0;\n\nfunction toBytes(input: DigestInput): Uint8Array<ArrayBuffer> {\n if (typeof input === 'string') return new TextEncoder().encode(input);\n if (input instanceof Uint8Array && input.buffer instanceof ArrayBuffer) {\n return input as Uint8Array<ArrayBuffer>;\n }\n if (ArrayBuffer.isView(input)) {\n // Copy so WebCrypto gets a plain ArrayBuffer (never a SharedArrayBuffer view).\n const source = new Uint8Array(input.buffer as ArrayBufferLike, input.byteOffset, input.byteLength);\n const copy = new Uint8Array(input.byteLength);\n copy.set(source);\n return copy;\n }\n return new Uint8Array(input);\n}\n\nfunction toHex(bytes: Uint8Array): string {\n return [...bytes].map(byte => byte.toString(16).padStart(2, '0')).join('');\n}\n\nfunction paddedMessage(message: Uint8Array): Uint8Array {\n const padded = new Uint8Array((Math.floor((message.length + 8) / 64) + 1) * 64);\n padded.set(message);\n padded[message.length] = 0x80;\n const view = new DataView(padded.buffer);\n const bitLength = message.length * 8;\n view.setUint32(padded.length - 8, Math.floor(bitLength / 0x1_0000_0000));\n view.setUint32(padded.length - 4, bitLength >>> 0);\n return padded;\n}\n\nfunction blockSchedule(view: DataView, offset: number): Uint32Array {\n const words = new Uint32Array(64);\n for (let i = 0; i < 16; i++) words[i] = view.getUint32(offset + i * 4);\n for (let i = 16; i < 64; i++) {\n const s0 = rotateRight(words[i - 15], 7) ^ rotateRight(words[i - 15], 18) ^ (words[i - 15] >>> 3);\n const s1 = rotateRight(words[i - 2], 17) ^ rotateRight(words[i - 2], 19) ^ (words[i - 2] >>> 10);\n words[i] = (words[i - 16] + s0 + words[i - 7] + s1) >>> 0;\n }\n return words;\n}\n\nfunction compressBlock(state: Uint32Array, words: Uint32Array): void {\n let [a, b, c, d, e, f, g, h] = state;\n for (let i = 0; i < 64; i++) {\n const sigma1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);\n const choose = (e & f) ^ (~e & g);\n const temp1 = (h + sigma1 + choose + SHA256_K[i] + words[i]) >>> 0;\n const sigma0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);\n const majority = (a & b) ^ (a & c) ^ (b & c);\n const temp2 = (sigma0 + majority) >>> 0;\n h = g; g = f; f = e; e = (d + temp1) >>> 0;\n d = c; c = b; b = a; a = (temp1 + temp2) >>> 0;\n }\n const next = [a, b, c, d, e, f, g, h];\n for (let i = 0; i < 8; i++) state[i] = (state[i] + next[i]) >>> 0;\n}\n\n/** Pure-JS SHA-256 usable where WebCrypto is unavailable. */\nexport function sha256Bytes(input: DigestInput): Uint8Array {\n const padded = paddedMessage(toBytes(input));\n const view = new DataView(padded.buffer);\n const state = SHA256_H.slice();\n for (let offset = 0; offset < padded.length; offset += 64) {\n compressBlock(state, blockSchedule(view, offset));\n }\n const out = new Uint8Array(32);\n const outView = new DataView(out.buffer);\n for (let i = 0; i < 8; i++) outView.setUint32(i * 4, state[i]);\n return out;\n}\n\n/** SHA-256 hex digest — WebCrypto when available, pure JS otherwise. */\nexport async function sha256Hex(input: DigestInput): Promise<string> {\n const bytes = toBytes(input);\n const subtle = globalThis.crypto?.subtle;\n if (subtle?.digest) {\n try {\n return toHex(new Uint8Array(await subtle.digest('SHA-256', bytes)));\n } catch {\n // WebCrypto present but unusable (e.g. blocked by an insecure context).\n }\n }\n return toHex(sha256Bytes(bytes));\n}\n\n/** Synchronous SHA-256 hex digest (pure JS, no WebCrypto). */\nexport function sha256HexSync(input: DigestInput): string {\n return toHex(sha256Bytes(input));\n}\n"],"mappings":"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","names":[]}