@nestos/kanban 0.0.0-stage → 0.5.1

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 (99) hide show
  1. package/README.md +121 -2
  2. package/dist/activity-C6xDM-cg.d.cts +232 -0
  3. package/dist/activity-Dw8DOw0L.d.ts +232 -0
  4. package/dist/activity.cjs +288 -0
  5. package/dist/activity.cjs.map +1 -0
  6. package/dist/activity.d.cts +34 -0
  7. package/dist/activity.d.ts +34 -0
  8. package/dist/activity.js +288 -0
  9. package/dist/activity.js.map +1 -0
  10. package/dist/chunk-2YFPV5GF.cjs +16 -0
  11. package/dist/chunk-2YFPV5GF.cjs.map +1 -0
  12. package/dist/chunk-4KF7KUAI.cjs +221 -0
  13. package/dist/chunk-4KF7KUAI.cjs.map +1 -0
  14. package/dist/chunk-4XF6LQSU.cjs +9 -0
  15. package/dist/chunk-4XF6LQSU.cjs.map +1 -0
  16. package/dist/chunk-5DLZWW5Y.js +148 -0
  17. package/dist/chunk-5DLZWW5Y.js.map +1 -0
  18. package/dist/chunk-5XKOCKY2.js +58 -0
  19. package/dist/chunk-5XKOCKY2.js.map +1 -0
  20. package/dist/chunk-6MN3H3YF.cjs +183 -0
  21. package/dist/chunk-6MN3H3YF.cjs.map +1 -0
  22. package/dist/chunk-ATUFFNLV.js +221 -0
  23. package/dist/chunk-ATUFFNLV.js.map +1 -0
  24. package/dist/chunk-DFTOTBGF.js +439 -0
  25. package/dist/chunk-DFTOTBGF.js.map +1 -0
  26. package/dist/chunk-G6FCDLDF.js +16 -0
  27. package/dist/chunk-G6FCDLDF.js.map +1 -0
  28. package/dist/chunk-IUI5CI2S.cjs +439 -0
  29. package/dist/chunk-IUI5CI2S.cjs.map +1 -0
  30. package/dist/chunk-KYNYPKKH.cjs +71 -0
  31. package/dist/chunk-KYNYPKKH.cjs.map +1 -0
  32. package/dist/chunk-L44TM4EE.cjs +1498 -0
  33. package/dist/chunk-L44TM4EE.cjs.map +1 -0
  34. package/dist/chunk-LSE6JG5I.cjs +20 -0
  35. package/dist/chunk-LSE6JG5I.cjs.map +1 -0
  36. package/dist/chunk-O4OGAAV4.js +71 -0
  37. package/dist/chunk-O4OGAAV4.js.map +1 -0
  38. package/dist/chunk-OHQTKGQN.js +1498 -0
  39. package/dist/chunk-OHQTKGQN.js.map +1 -0
  40. package/dist/chunk-PSKQAFDF.cjs +58 -0
  41. package/dist/chunk-PSKQAFDF.cjs.map +1 -0
  42. package/dist/chunk-QTMTBEBA.js +20 -0
  43. package/dist/chunk-QTMTBEBA.js.map +1 -0
  44. package/dist/chunk-RQP77ZTY.js +9 -0
  45. package/dist/chunk-RQP77ZTY.js.map +1 -0
  46. package/dist/chunk-T7P5EIC4.cjs +148 -0
  47. package/dist/chunk-T7P5EIC4.cjs.map +1 -0
  48. package/dist/chunk-TB2RZGDV.js +183 -0
  49. package/dist/chunk-TB2RZGDV.js.map +1 -0
  50. package/dist/content-CAIp1njn.d.cts +35 -0
  51. package/dist/content-CGMJdyH_.d.ts +35 -0
  52. package/dist/contracts/index.cjs +21 -0
  53. package/dist/contracts/index.cjs.map +1 -0
  54. package/dist/contracts/index.d.cts +4 -0
  55. package/dist/contracts/index.d.ts +4 -0
  56. package/dist/contracts/index.js +21 -0
  57. package/dist/contracts/index.js.map +1 -0
  58. package/dist/discovery-DxpirOz3.d.cts +61 -0
  59. package/dist/discovery-gSqWpuRm.d.ts +61 -0
  60. package/dist/discovery.cjs +379 -0
  61. package/dist/discovery.cjs.map +1 -0
  62. package/dist/discovery.d.cts +22 -0
  63. package/dist/discovery.d.ts +22 -0
  64. package/dist/discovery.js +379 -0
  65. package/dist/discovery.js.map +1 -0
  66. package/dist/execution.cjs +368 -0
  67. package/dist/execution.cjs.map +1 -0
  68. package/dist/execution.d.cts +89 -0
  69. package/dist/execution.d.ts +89 -0
  70. package/dist/execution.js +368 -0
  71. package/dist/execution.js.map +1 -0
  72. package/dist/index.cjs +76 -0
  73. package/dist/index.cjs.map +1 -0
  74. package/dist/index.d.cts +61 -0
  75. package/dist/index.d.ts +61 -0
  76. package/dist/index.js +76 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/module-BbvwdCDF.d.cts +11 -0
  79. package/dist/module-CWNK2BMj.d.ts +11 -0
  80. package/dist/planning-CcFZYdIL.d.cts +844 -0
  81. package/dist/planning-CcFZYdIL.d.ts +844 -0
  82. package/dist/ports-Bn6ro2FB.d.ts +142 -0
  83. package/dist/ports-CaL6geqR.d.cts +142 -0
  84. package/dist/storage.cjs +289 -0
  85. package/dist/storage.cjs.map +1 -0
  86. package/dist/storage.d.cts +71 -0
  87. package/dist/storage.d.ts +71 -0
  88. package/dist/storage.js +289 -0
  89. package/dist/storage.js.map +1 -0
  90. package/dist/store-Ct0gOAAg.d.ts +28 -0
  91. package/dist/store-q63eSMoT.d.cts +28 -0
  92. package/dist/ui/index.cjs +1961 -0
  93. package/dist/ui/index.cjs.map +1 -0
  94. package/dist/ui/index.d.cts +209 -0
  95. package/dist/ui/index.d.ts +209 -0
  96. package/dist/ui/index.js +1961 -0
  97. package/dist/ui/index.js.map +1 -0
  98. package/dist/ui/kanban.css +194 -0
  99. package/package.json +113 -4
@@ -0,0 +1,439 @@
1
+ import {
2
+ catalog,
3
+ createBoardState,
4
+ limits,
5
+ queryRecords,
6
+ recordSummary,
7
+ reduce,
8
+ related,
9
+ summary,
10
+ terminal,
11
+ viewFromState
12
+ } from "./chunk-OHQTKGQN.js";
13
+ import {
14
+ executable,
15
+ identity,
16
+ normalizeActor,
17
+ principal,
18
+ principalKey,
19
+ requireValue,
20
+ sameOwner,
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";
29
+ import {
30
+ kanbanReference
31
+ } from "./chunk-5XKOCKY2.js";
32
+ import {
33
+ randomUUID
34
+ } from "./chunk-TB2RZGDV.js";
35
+ import {
36
+ boardControlPhase
37
+ } from "./chunk-QTMTBEBA.js";
38
+
39
+ // src/references.ts
40
+ async function resolveReference(reference, store, read) {
41
+ requireValue(typeof reference === "string" && reference.length <= 100, "INVALID_REFERENCE");
42
+ const match = /^KB-([1-9]\d*)(?:#([1-9]\d*)|\/(L|D)-([1-9]\d*))?$/i.exec(reference.trim());
43
+ requireValue(match && [match[1], match[2], match[4]].every((value) => value === void 0 || Number.isSafeInteger(Number(value))), "INVALID_REFERENCE");
44
+ const id = await store.boardId?.(Number(match[1]));
45
+ requireValue(id, "REFERENCE_NOT_FOUND");
46
+ const view = await read(id), board = view.state.board;
47
+ requireValue(board.number === Number(match[1]), "INVALID_NUMBERING");
48
+ const target = { boardId: id, scope: board.scope, reference: kanbanReference(board) };
49
+ if (match[2]) {
50
+ const item = [...view.items, ...view.state.archiveIndex ?? []].find((item2) => item2.number === Number(match[2]));
51
+ requireValue(item, "REFERENCE_NOT_FOUND");
52
+ target.itemId = item.id;
53
+ target.reference = kanbanReference(board, item);
54
+ } else if (match[3]) {
55
+ const record = view.records.find((record2) => record2.kind === (match[3].toUpperCase() === "L" ? "log" : "decision") && record2.number === Number(match[4]));
56
+ requireValue(record, "REFERENCE_NOT_FOUND");
57
+ target.recordId = record.id;
58
+ target.reference = kanbanReference(board, record);
59
+ }
60
+ return target;
61
+ }
62
+
63
+ // src/suggestions.ts
64
+ function validateSuggestionQuery(query) {
65
+ requireValue(query && ["item", "parent", "dependency", "area", "milestone", "decision", "session"].includes(query.kind), "INVALID_SUGGESTION_KIND");
66
+ requireValue(query.search === void 0 || typeof query.search === "string" && query.search.length <= 256, "INVALID_FILTER");
67
+ const limit = query.limit ?? 20;
68
+ requireValue(Number.isSafeInteger(limit) && limit > 0 && limit <= 50, "INVALID_LIMIT");
69
+ if (query.excludeItemId !== void 0) identity(query.excludeItemId);
70
+ if (query.excludeIds !== void 0) {
71
+ requireValue(Array.isArray(query.excludeIds) && query.excludeIds.length <= 100, "INVALID_FILTER");
72
+ query.excludeIds.forEach(identity);
73
+ }
74
+ if (query.childKind !== void 0) identity(query.childKind);
75
+ return limit;
76
+ }
77
+ function suggestionPage(revision, rows, query) {
78
+ const limit = validateSuggestionQuery(query), search = query.search?.trim().toLocaleLowerCase() ?? "";
79
+ const matched = rows.filter((row) => !query.excludeIds?.includes(row.id)).filter((row) => `${row.id} ${row.label} ${row.detail ?? ""}`.toLocaleLowerCase().includes(search)).sort((a, b) => score(a.label, search) - score(b.label, search) || a.label.localeCompare(b.label) || a.id.localeCompare(b.id));
80
+ 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 !== void 0 ? { archived: row.archived } : {} })), hasMore: matched.length > limit };
81
+ }
82
+ var score = (label, query) => label.toLocaleLowerCase() === query ? 0 : label.toLocaleLowerCase().startsWith(query) ? 1 : 2;
83
+ function suggestFromState(state, query, items = catalog(state), records = (state.records ?? []).map(recordSummary)) {
84
+ validateSuggestionQuery(query);
85
+ if (query.kind === "area" || query.kind === "milestone") {
86
+ const names = [...new Set(items.map((item) => item.planning[query.kind]).filter((name) => !!name))];
87
+ return suggestionPage(state.board.revision, names.map((name) => ({ id: name, label: name })), query);
88
+ }
89
+ if (query.kind === "decision") return suggestionPage(state.board.revision, records.filter((record) => record.kind === "decision" && record.status === "confirmed").map((record) => ({ id: record.id, label: record.title, detail: kanbanReference(state.board, record) })), query);
90
+ if (query.kind === "session") {
91
+ const ids = /* @__PURE__ */ new Set([
92
+ ...state.board.participants.map((p) => p.sessionId),
93
+ ...items.flatMap((item) => item.sessionIds),
94
+ ...records.flatMap((record) => record.sessionIds)
95
+ ]);
96
+ return suggestionPage(state.board.revision, [...ids].map((id) => ({ id, label: id })), query);
97
+ }
98
+ const blocked = query.kind === "dependency" && query.excludeItemId ? dependents(items, query.excludeItemId) : /* @__PURE__ */ new Set();
99
+ const rank = query.kind === "parent" ? workType(state.board, query.childKind ?? state.board.defaultWorkType ?? "task").rank : void 0;
100
+ const rows = items.filter((item) => item.id !== query.excludeItemId && !blocked.has(item.id) && (query.kind !== "dependency" || item.status !== "cancelled") && (rank === void 0 || item.archivedAt === void 0 && !terminal(item) && workType(state.board, item.planning.kind).rank < rank)).map((item) => ({
101
+ id: item.id,
102
+ label: item.title,
103
+ status: item.status,
104
+ archived: item.archivedAt !== void 0,
105
+ detail: [kanbanReference(state.board, item), item.planning.area, item.planning.milestone].filter(Boolean).join(" \xB7 ")
106
+ }));
107
+ return suggestionPage(state.board.revision, rows, query);
108
+ }
109
+ function dependents(items, id) {
110
+ const reverse = /* @__PURE__ */ new Map();
111
+ for (const item of items) for (const dependency of item.planning.dependencies) reverse.set(dependency, [...reverse.get(dependency) ?? [], item.id]);
112
+ const result = /* @__PURE__ */ new Set([id]), pending = [id];
113
+ while (pending.length) for (const next of reverse.get(pending.pop()) ?? []) if (!result.has(next)) {
114
+ result.add(next);
115
+ pending.push(next);
116
+ }
117
+ return result;
118
+ }
119
+
120
+ // src/queries.ts
121
+ function queryItems(state, query = {}, all = catalog(state), now = Date.now()) {
122
+ const { cursor, limit = 50, ...filters } = query;
123
+ requireValue(Number.isSafeInteger(limit) && limit >= 1 && limit <= 200, "INVALID_PAGE_SIZE");
124
+ requireValue(["ready", "backlog", "in-progress", "review", "closed", "proposed", "archive", "all"].includes(query.view ?? "ready"), "INVALID_VIEW");
125
+ for (const field of ["area", "milestone", "parentId", "kind", "sessionId", "search"]) if (filters[field] !== void 0) requireValue(typeof filters[field] === "string" && filters[field].length <= 256, "INVALID_FILTER");
126
+ 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");
127
+ const fingerprint = JSON.stringify(Object.fromEntries(Object.entries({ ...filters, view: filters.view ?? "ready" }).sort(([a], [b]) => a.localeCompare(b)))), revision = state.board.revision;
128
+ all = all.map((item) => ({ ...item, task: projectKanbanTask(item, state.workflow, now, all) }));
129
+ const matches = all.filter((item) => matchesQuery(item, filters, state.board)).sort(filters.view === "archive" ? (a, b) => (b.archivedAt ?? 0) - (a.archivedAt ?? 0) || a.id.localeCompare(b.id) : order);
130
+ let start = 0;
131
+ if (cursor) {
132
+ requireValue(typeof cursor === "string" && cursor.length <= 4e3, "INVALID_CURSOR");
133
+ let decoded;
134
+ try {
135
+ decoded = JSON.parse(cursor);
136
+ } catch {
137
+ requireValue(false, "INVALID_CURSOR");
138
+ }
139
+ requireValue(decoded && decoded.filter === fingerprint, "CURSOR_SCOPE_MISMATCH");
140
+ requireValue(decoded.revision === revision, "CURSOR_STALE");
141
+ start = matches.findIndex((i) => i.id === decoded.after) + 1;
142
+ requireValue(start > 0, "INVALID_CURSOR");
143
+ }
144
+ const progress = progressByParent(state, all);
145
+ const items = matches.slice(start, start + limit).map((item) => ({ ...item, ...progress.has(item.id) ? { progress: progress.get(item.id) } : {} }));
146
+ return { revision, total: matches.length, items, ...start + items.length < matches.length ? {
147
+ nextCursor: JSON.stringify({ revision, after: items.at(-1).id, filter: fingerprint })
148
+ } : {} };
149
+ }
150
+ function order(a, b) {
151
+ return a.planning.priority - b.planning.priority || a.createdAt - b.createdAt || a.id.localeCompare(b.id);
152
+ }
153
+ function matchesQuery(item, query, board) {
154
+ if (query.phase && item.task?.phase !== query.phase) return false;
155
+ if (!matchesView(item, query.view ?? "ready")) return false;
156
+ for (const field of ["area", "milestone", "parentId", "kind"]) if (query[field] !== void 0 && item.planning[field] !== query[field]) return false;
157
+ if (query.reference && !item.externalRefs?.some((r) => r.system === query.reference.system && r.id === query.reference.id)) return false;
158
+ if (query.sessionId && !item.sessionIds.includes(query.sessionId)) return false;
159
+ if (query.search && !`${kanbanReference(board, item)} ${item.id} ${item.title} ${item.planning.area ?? ""}`.toLowerCase().includes(query.search.toLowerCase())) return false;
160
+ return true;
161
+ }
162
+ function matchesView(item, view) {
163
+ if (view === "archive") return item.archivedAt !== void 0;
164
+ if (view === "all") return true;
165
+ if (item.archivedAt !== void 0) return false;
166
+ if (view === "in-progress") return item.status === "claimed" || item.status === "review";
167
+ if (view === "closed") return terminal(item);
168
+ return item.status === { ready: "open", backlog: "backlog", review: "review", proposed: "proposed" }[view];
169
+ }
170
+ function overview(state, now, items = state.board.items.map(summary)) {
171
+ const count = (status) => items.filter((i) => i.status === status).length;
172
+ const age = state.board.policy.backlogReviewMs;
173
+ return {
174
+ revision: state.board.revision,
175
+ visible: items.length,
176
+ active: items.filter((i) => !terminal(i)).length,
177
+ archived: state.archiveIndex?.length ?? 0,
178
+ ready: count("open"),
179
+ inProgress: count("claimed") + count("review"),
180
+ backlog: count("backlog"),
181
+ proposed: count("proposed"),
182
+ closed: count("completed") + count("cancelled"),
183
+ dueForReview: age ? items.filter((i) => i.status === "backlog" && now - i.updatedAt >= age).length : 0,
184
+ limits: limits(state)
185
+ };
186
+ }
187
+ function progressByParent(state, all) {
188
+ const byId = new Map(all.map((i) => [i.id, i]));
189
+ const result = /* @__PURE__ */ new Map();
190
+ for (const item of all.filter((i) => executable(state.board, i))) {
191
+ let parent = item.planning.parentId;
192
+ const seen = /* @__PURE__ */ new Set();
193
+ while (parent && !seen.has(parent)) {
194
+ seen.add(parent);
195
+ const progress = result.get(parent) ?? { total: 0, completed: 0, cancelled: 0, inProgress: 0 };
196
+ progress.total++;
197
+ if (item.status === "completed") progress.completed++;
198
+ if (item.status === "cancelled") progress.cancelled++;
199
+ if (item.status === "claimed" || item.status === "review") progress.inProgress++;
200
+ result.set(parent, progress);
201
+ parent = byId.get(parent)?.planning.parentId;
202
+ }
203
+ }
204
+ return result;
205
+ }
206
+
207
+ // src/module.ts
208
+ function createKanbanModule(options) {
209
+ return new KanbanModule(options);
210
+ }
211
+ var KanbanModule = class {
212
+ constructor(options) {
213
+ this.options = options;
214
+ this.now = options.now ?? Date.now;
215
+ this.id = options.id ?? randomUUID;
216
+ this.actor = normalizeActor(options.actor);
217
+ }
218
+ stopping = false;
219
+ pending = /* @__PURE__ */ new Set();
220
+ async quiesce() {
221
+ this.stopping = true;
222
+ await Promise.allSettled([...this.pending]);
223
+ }
224
+ async dispose() {
225
+ await this.quiesce();
226
+ }
227
+ now;
228
+ id;
229
+ actor;
230
+ workflow = (boardId) => this.guard(this.id(), boardId, "workflow", async () => structuredClone((await this.readView(boardId)).state.workflow ?? { plans: {}, dispatches: {}, ready: [], completedPlans: [] }));
231
+ resolve = (reference) => this.guard(this.id(), void 0, "resolve", () => resolveReference(reference, this.options.store, (id) => this.readView(id)));
232
+ suggest = (boardId, query) => this.guard(this.id(), boardId, "suggest", async () => {
233
+ const snapshot = structuredClone(query), limit = validateSuggestionQuery(snapshot), view = await this.readView(boardId), state = view.state;
234
+ const suggestions = () => suggestFromState(state, snapshot, [...view.items, ...state.archiveIndex ?? []], view.records);
235
+ if (!this.options.suggestions) return suggestions();
236
+ const rows = await this.options.suggestions(structuredClone(state.board), snapshot.kind, snapshot.search?.trim() ?? "", limit + 1);
237
+ if (rows === void 0) return suggestions();
238
+ const known = suggestions().items.filter((row) => !rows.some((entry) => entry.id === row.id));
239
+ return suggestionPage(state.board.revision, [...rows, ...known], snapshot);
240
+ });
241
+ records = (boardId, query) => this.guard(this.id(), boardId, "records", async () => {
242
+ const view = await this.readView(boardId);
243
+ return structuredClone(queryRecords(view.state, query, view.records));
244
+ });
245
+ record = (boardId, recordId) => this.guard(this.id(), boardId, "record", async () => {
246
+ identity(recordId);
247
+ const record = (await this.readState(boardId)).records?.find((record2) => record2.id === recordId);
248
+ requireValue(record, "RECORD_NOT_FOUND");
249
+ return structuredClone(record);
250
+ });
251
+ currentPrincipal = async () => structuredClone(principal(this.actor));
252
+ create = (input) => {
253
+ const snapshot = structuredClone(input);
254
+ return this.guard(this.id(), snapshot.id, "create", async () => {
255
+ const initial = createBoardState(snapshot, this.actor, this.now()), board = initial.board;
256
+ await this.authorize(board, "create");
257
+ const state = await this.options.store.update(board.id, `create:${board.id}`, JSON.stringify({ snapshot, actor: this.actor }), (previous) => {
258
+ requireValue(!previous, "BOARD_EXISTS");
259
+ return initial;
260
+ });
261
+ return structuredClone(state.board);
262
+ });
263
+ };
264
+ read = (boardId) => this.guard(
265
+ this.id(),
266
+ boardId,
267
+ "read",
268
+ async () => structuredClone((await this.readState(boardId)).board)
269
+ );
270
+ catalog = () => this.guard(this.id(), void 0, "catalog", async () => {
271
+ const boards = [];
272
+ for (const id of await this.options.store.ids()) {
273
+ try {
274
+ const view = await this.readView(id);
275
+ 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 } })) });
277
+ } catch (error) {
278
+ if (!(error instanceof KanbanError) || error.code !== "FORBIDDEN") throw error;
279
+ }
280
+ }
281
+ return structuredClone(boards);
282
+ });
283
+ list = () => this.guard(this.id(), void 0, "list", async () => {
284
+ const boards = [];
285
+ for (const boardId of await this.options.store.ids()) {
286
+ try {
287
+ const board = (await this.readState(boardId)).board;
288
+ if (board.deletedAt === void 0) boards.push(structuredClone(board));
289
+ } catch (error) {
290
+ if (!(error instanceof KanbanError) || error.code !== "FORBIDDEN") throw error;
291
+ }
292
+ }
293
+ return boards;
294
+ });
295
+ execute = (boardId, input) => this.guard(input.operationId, boardId, `execute:${input.command.type}`, async () => {
296
+ const request = structuredClone(input);
297
+ identity(request.operationId);
298
+ const state = await this.readState(boardId);
299
+ await this.authorize(state.board, request.command.type, request.command);
300
+ requireValue(state.board.deletedAt === void 0, "BOARD_DELETED");
301
+ if (request.command.type === "delete-board") await this.options.verifyDeletion?.(structuredClone(state.board));
302
+ await this.verifyRelease(state.board, request.command);
303
+ const verifyStage = request.command.type === "observe-execution" && request.command.outcome === "succeeded" ? "observe" : request.command.type === "accept-execution" && request.command.accept ? "accept" : void 0;
304
+ if (verifyStage && "dispatchId" in request.command) {
305
+ const dispatch = state.workflow?.dispatches[request.command.dispatchId];
306
+ requireValue(dispatch, "DISPATCH_NOT_FOUND");
307
+ const outputs = request.command.type === "observe-execution" ? request.command.outputs : dispatch.outputs;
308
+ if (outputs?.length) requireValue(await this.options.verifyOutputs?.({
309
+ stage: verifyStage,
310
+ board: state.board,
311
+ itemId: dispatch.itemId,
312
+ dispatchId: dispatch.id,
313
+ outputs: structuredClone(outputs)
314
+ }), "OUTPUT_VERIFICATION_REQUIRED");
315
+ }
316
+ const restore = request.command.type === "restore-item" ? await this.options.store.archived(boardId, request.command.itemId) : void 0;
317
+ const result = await this.options.store.update(boardId, request.operationId, JSON.stringify({ actor: this.actor, request }), (current) => {
318
+ requireValue(current && current.board.revision === state.board.revision, "REVISION_CONFLICT");
319
+ requireValue(current.board.revision === request.expectedRevision, "REVISION_CONFLICT");
320
+ if (restore) current.restore = restore;
321
+ return reduce(current, request.command, this.actor, request.operationId, this.now(), this.id());
322
+ });
323
+ await this.publishNotifications(boardId, request.operationId);
324
+ return structuredClone(result.board);
325
+ });
326
+ events = (boardId, after = 0, limit = 100) => this.guard(this.id(), boardId, "events", async () => {
327
+ requireValue(Number.isSafeInteger(after) && after >= 0 && Number.isSafeInteger(limit) && limit > 0 && limit <= 500, "INVALID_CURSOR");
328
+ const { state } = await this.readView(boardId);
329
+ return this.options.store.events(boardId, after, limit, state.sequence);
330
+ });
331
+ query = (boardId, query) => this.guard(this.id(), boardId, "query", async () => {
332
+ const view = await this.readView(boardId);
333
+ return structuredClone(queryItems(view.state, query, [...view.items, ...view.state.archiveIndex ?? []], this.now()));
334
+ });
335
+ overview = (boardId) => this.guard(this.id(), boardId, "overview", async () => {
336
+ const view = await this.readView(boardId);
337
+ return overview(view.state, this.now(), view.items);
338
+ });
339
+ item = (boardId, itemId) => this.guard(this.id(), boardId, "item", async () => {
340
+ identity(itemId);
341
+ const state = await this.readState(boardId), item = state.board.items.find((i) => i.id === itemId);
342
+ if (item) return { item: structuredClone(item), task: projectKanbanTask(item, state.workflow, this.now(), [...state.board.items, ...state.archiveIndex ?? []]) };
343
+ requireValue(state.archiveIndex?.some((i) => i.id === itemId), "ITEM_NOT_FOUND");
344
+ const record = await this.options.store.archived(boardId, itemId);
345
+ requireValue(record, "REVISION_CONFLICT");
346
+ return { item: structuredClone(record.item), task: projectKanbanTask(record.item, state.workflow, this.now(), state.archiveIndex), archive: { archivedAt: record.archivedAt, reason: record.reason } };
347
+ });
348
+ related = (sessionId) => this.guard(this.id(), void 0, "related", async () => {
349
+ identity(sessionId);
350
+ const result = [];
351
+ for (const board of await this.list()) {
352
+ const state = await this.readState(board.id);
353
+ 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);
354
+ }
355
+ return result;
356
+ });
357
+ scan = () => this.guard(this.id(), void 0, "scan", async () => {
358
+ const errors = [];
359
+ for (const board of await this.list()) {
360
+ try {
361
+ await this.execute(board.id, { operationId: this.id(), expectedRevision: board.revision, command: { type: "scan" } });
362
+ } catch (error) {
363
+ if (!(error instanceof KanbanError) || error.code !== "REVISION_CONFLICT") errors.push(error);
364
+ }
365
+ }
366
+ if (errors.length) throw new AggregateError(errors, "KANBAN_SCAN_FAILED");
367
+ });
368
+ async verifyRelease(board, command) {
369
+ if (command.type !== "release-item") return;
370
+ const item = board.items.find((i) => i.id === command.itemId);
371
+ requireValue(item?.owner && item.owner.token === command.token, "OWNER_MISMATCH");
372
+ const own = sameOwner(item.owner, this.actor), actor = principal(this.actor);
373
+ const coordinator = board.members?.some((m) => principalKey(m) === principalKey(actor) && m.roles?.includes("coordinator"));
374
+ requireValue(own || coordinator, "OWNER_MISMATCH");
375
+ if (!(own && actor.kind === "human")) requireValue(await this.options.verifyRelease?.({ actor: this.actor, board: structuredClone(board), item: structuredClone(item) }), "EXECUTION_NOT_SETTLED");
376
+ }
377
+ async publishNotifications(boardId, operationId) {
378
+ if (!this.options.onCommitted) return;
379
+ const started = this.now();
380
+ try {
381
+ await this.options.onCommitted(boardId, this, this.now());
382
+ this.log(operationId, boardId, "notify", started, "success");
383
+ } catch (error) {
384
+ this.log(operationId, boardId, "notify", started, "failure", safeCode(error, "NOTIFICATION_PROJECTION_FAILED"));
385
+ }
386
+ }
387
+ async readView(boardId) {
388
+ identity(boardId);
389
+ if (!this.options.store.view) return viewFromState(await this.readState(boardId));
390
+ const view = await this.options.store.view(boardId);
391
+ requireValue(view, "BOARD_NOT_FOUND");
392
+ await this.authorize(view.state.board, "read");
393
+ return view;
394
+ }
395
+ async readState(boardId) {
396
+ identity(boardId);
397
+ const state = await this.options.store.read(boardId);
398
+ requireValue(state, "BOARD_NOT_FOUND");
399
+ await this.authorize(state.board, "read");
400
+ return state;
401
+ }
402
+ authorize(board, action, command) {
403
+ return this.options.authorize({ actor: structuredClone(this.actor), board: structuredClone(board), action, command: structuredClone(command) });
404
+ }
405
+ async guard(operationId, boardId, stage, run) {
406
+ const start = this.now();
407
+ if (this.stopping) {
408
+ this.log(operationId, boardId, stage, start, "failure", "SERVICE_STOPPING");
409
+ throw new KanbanError("SERVICE_STOPPING");
410
+ }
411
+ const operation = Promise.resolve().then(run);
412
+ this.pending.add(operation);
413
+ try {
414
+ const result = await operation;
415
+ this.log(operationId, boardId, stage, start, "success");
416
+ return result;
417
+ } catch (error) {
418
+ this.log(operationId, boardId, stage, start, "failure", safeCode(error, "PORT_FAILURE"));
419
+ throw error;
420
+ } finally {
421
+ this.pending.delete(operation);
422
+ }
423
+ }
424
+ log(operationId, boardId, stage, start, result, code) {
425
+ try {
426
+ this.options.log({ operationId, boardId, stage, result, code, durationMs: this.now() - start });
427
+ } catch {
428
+ }
429
+ }
430
+ };
431
+ function safeCode(error, fallback) {
432
+ const code = error?.code;
433
+ return typeof code === "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(code) ? code : fallback;
434
+ }
435
+
436
+ export {
437
+ createKanbanModule
438
+ };
439
+ //# sourceMappingURL=chunk-DFTOTBGF.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 (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 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.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.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 board of await this.list()) {\n try { await this.execute(board.id, { operationId: this.id(), expectedRevision: board.revision, command: { type: 'scan' } }); }\n catch (error) {\n if (!(error instanceof KanbanError) || error.code !== 'REVISION_CONFLICT') 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"]}
@@ -0,0 +1,16 @@
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
+
12
+ export {
13
+ KanbanError,
14
+ KanbanScanNotStartedError
15
+ };
16
+ //# sourceMappingURL=chunk-G6FCDLDF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ports.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 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"],"mappings":";AA8CO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACnC,YAAqB,MAAc;AAAE,UAAM,IAAI;AAA1B;AAA6B,SAAK,OAAO;AAAA,EAAe;AACjF;AAEO,IAAM,4BAAN,cAAwC,YAAY;AAAC;","names":[]}