@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,221 @@
1
+ import {
2
+ KanbanError
3
+ } from "./chunk-G6FCDLDF.js";
4
+ import {
5
+ DEFAULT_KANBAN_WORK_TYPES,
6
+ executableWorkItem
7
+ } from "./chunk-5XKOCKY2.js";
8
+
9
+ // src/discovery-state.ts
10
+ function discoveryState(state) {
11
+ return state?.discovery;
12
+ }
13
+
14
+ // src/configuration.ts
15
+ function policy(input = {}) {
16
+ return {
17
+ claimTimeoutMs: 864e5,
18
+ leaseMs: 6e5,
19
+ progressTimeoutMs: 36e5,
20
+ transferTimeoutMs: 18e5,
21
+ maxComplexity: 10,
22
+ maxWorkUnits: 100,
23
+ maxDurationMs: 288e5,
24
+ escalationSessionIds: [],
25
+ ...input
26
+ };
27
+ }
28
+ function workTypes(board) {
29
+ return board.workTypes ?? DEFAULT_KANBAN_WORK_TYPES;
30
+ }
31
+ function workType(board, id) {
32
+ const found = workTypes(board).find((type) => type.id === id);
33
+ requireValue(found, "UNKNOWN_WORK_TYPE");
34
+ return found;
35
+ }
36
+ function executable(board, item) {
37
+ workType(board, item.planning?.kind ?? board.defaultWorkType ?? "task");
38
+ return executableWorkItem(board, item);
39
+ }
40
+ function validateConfiguration(board) {
41
+ const types = workTypes(board);
42
+ requireValue(types.length > 0 && types.length <= 20, "WORK_TYPE_LIMIT");
43
+ requireValue(new Set(types.map((t) => t.id)).size === types.length, "DUPLICATE_WORK_TYPE");
44
+ for (const type of types) {
45
+ identity(type.id);
46
+ text(type.label);
47
+ requireValue(Number.isInteger(type.rank) && type.rank >= 0 && type.rank <= 9 && typeof type.executable === "boolean", "INVALID_WORK_TYPE");
48
+ }
49
+ workType(board, board.defaultWorkType ?? "task");
50
+ const members = roster(board);
51
+ requireValue(members.length > 0, "MEMBER_ROSTER_REQUIRED");
52
+ requireValue(new Set(members.map(principalKey)).size === members.length, "DUPLICATE_MEMBER");
53
+ for (const member of members) {
54
+ identity(member.id);
55
+ requireValue(["agent", "human", "service"].includes(member.kind), "INVALID_PRINCIPAL");
56
+ }
57
+ for (const member of board.members ?? []) {
58
+ text(member.responsibility);
59
+ requireValue(!member.roles || member.roles.every((r) => ["worker", "reviewer", "coordinator"].includes(r)), "INVALID_MEMBER_ROLE");
60
+ }
61
+ validateColumns(board);
62
+ for (const [kind, value] of Object.entries(board.notifications?.rules ?? {}))
63
+ requireValue(/^[a-z][a-z0-9.-]{0,79}$/.test(kind) && ["info", "error", "none"].includes(value), "INVALID_NOTIFICATION_RULE");
64
+ }
65
+ function validateColumns(board) {
66
+ if (!board.columns) return;
67
+ const states = board.columns.flatMap((c) => c.states);
68
+ requireValue(states.length === 7 && new Set(states).size === 7 && ["proposed", "backlog", "open", "claimed", "review", "completed", "cancelled"].every((s) => states.includes(s)), "INVALID_COLUMNS");
69
+ requireValue(new Set(board.columns.map((c) => c.id)).size === board.columns.length, "DUPLICATE_COLUMN");
70
+ for (const column of board.columns) {
71
+ identity(column.id);
72
+ text(column.label);
73
+ requireValue(column.states.length > 0, "EMPTY_COLUMN");
74
+ }
75
+ }
76
+
77
+ // src/rules.ts
78
+ function requireValue(condition, code) {
79
+ if (!condition) throw new KanbanError(code);
80
+ }
81
+ function text(value) {
82
+ requireValue(typeof value === "string" && value.trim().length > 0 && value.length <= 8e3, "INVALID_TEXT");
83
+ }
84
+ function identity(value) {
85
+ requireValue(typeof value === "string" && value.length > 0 && value.length <= 256 && !["__proto__", "prototype", "constructor"].includes(value), "INVALID_ID");
86
+ }
87
+ function positive(value) {
88
+ requireValue(Number.isFinite(value) && value > 0, "INVALID_THRESHOLD");
89
+ }
90
+ function validateEstimate(estimate) {
91
+ positive(estimate.complexity);
92
+ positive(estimate.workUnits);
93
+ positive(estimate.durationMs);
94
+ requireValue(["low", "medium", "high"].includes(estimate.confidence), "INVALID_CONFIDENCE");
95
+ }
96
+ function validateBoard(board) {
97
+ identity(board.id);
98
+ text(board.title);
99
+ requireValue(["system", "project", "collection"].includes(board.scope.kind), "INVALID_SCOPE");
100
+ if (board.scope.kind === "project") identity(board.scope.projectId);
101
+ if (board.scope.kind === "collection") {
102
+ identity(board.scope.namespace);
103
+ identity(board.scope.id);
104
+ }
105
+ validateConfiguration(board);
106
+ for (const agent of board.agents ?? []) {
107
+ identity(agent.agentId);
108
+ text(agent.responsibility);
109
+ }
110
+ requireValue(new Set((board.agents ?? []).map((a) => a.agentId)).size === (board.agents ?? []).length, "DUPLICATE_AGENT");
111
+ const p = board.policy;
112
+ for (const value of [p.maxReady, p.maxInProgress, p.maxInProgressPerAgent, p.maxInProgressPerAssignee]) if (value !== void 0) requireValue(Number.isSafeInteger(value) && value > 0, "INVALID_LIMIT");
113
+ requireValue(p.maxInProgressPerAgent === void 0 || p.maxInProgressPerAssignee === void 0 || p.maxInProgressPerAgent === p.maxInProgressPerAssignee, "POLICY_LIMIT_CONFLICT");
114
+ for (const value of [p.archiveAfterMs, p.backlogReviewMs]) if (value !== void 0) positive(value);
115
+ for (const value of [
116
+ p.claimTimeoutMs,
117
+ p.leaseMs,
118
+ p.progressTimeoutMs,
119
+ p.transferTimeoutMs,
120
+ p.maxComplexity,
121
+ p.maxWorkUnits,
122
+ p.maxDurationMs
123
+ ]) positive(value);
124
+ requireValue(Array.isArray(p.escalationSessionIds), "INVALID_ESCALATION_TARGETS");
125
+ requireValue(p.review === void 0 || ["independent", "assignee"].includes(p.review), "INVALID_REVIEW_POLICY");
126
+ requireValue(p.requireEstimate === void 0 || typeof p.requireEstimate === "boolean", "INVALID_ESTIMATE_POLICY");
127
+ p.escalationSessionIds.forEach(identity);
128
+ }
129
+ function participant(list, sessionId, agentId, role, subscribed, now) {
130
+ identity(sessionId);
131
+ requireValue(["creator", "owner", "consultant", "reviewer", "observer", "escalation"].includes(role), "INVALID_ROLE");
132
+ let entry = list.find((value) => value.sessionId === sessionId);
133
+ if (!entry) {
134
+ entry = { sessionId, agentId, roles: [], subscribed, joinedAt: now };
135
+ list.push(entry);
136
+ }
137
+ if (entry.agentId && agentId) requireValue(entry.agentId === agentId, "SESSION_AGENT_CONFLICT");
138
+ entry.agentId ??= agentId;
139
+ if (!entry.roles.includes(role)) entry.roles.push(role);
140
+ entry.subscribed = subscribed;
141
+ }
142
+ function owned(item, actor, token, now) {
143
+ requireValue(item.status === "claimed", "ITEM_NOT_RUNNING");
144
+ requireValue(item.owner && sameOwner(item.owner, actor) && item.owner.token === token, "OWNER_MISMATCH");
145
+ requireValue(item.owner.leaseUntil > now, "LEASE_EXPIRED");
146
+ }
147
+
148
+ // src/identity.ts
149
+ function principal(actor) {
150
+ const kind = actor.kind ?? "agent", id = kind === "agent" ? actor.agentId ?? actor.id : actor.id;
151
+ requireValue(["agent", "human", "service"].includes(kind) && id, "INVALID_ACTOR");
152
+ identity(id);
153
+ if (kind === "agent") {
154
+ requireValue(!actor.agentId || !actor.id || actor.agentId === actor.id, "ACTOR_ID_MISMATCH");
155
+ if (actor.sessionId !== void 0) identity(actor.sessionId);
156
+ if (actor.taskId !== void 0) identity(actor.taskId);
157
+ }
158
+ return { kind, id };
159
+ }
160
+ function principalKey(value) {
161
+ return JSON.stringify([value.kind, value.id]);
162
+ }
163
+ function assigneeKey(value) {
164
+ return value.principalId ?? principalKey({ kind: "agent", id: value.agentId });
165
+ }
166
+ function sameOwner(owner, actor) {
167
+ const value = principal(actor);
168
+ return assigneeKey(owner) === principalKey(value) && (value.kind !== "agent" || owner.sessionId === actor.sessionId && owner.taskId === actor.taskId);
169
+ }
170
+ function roster(board) {
171
+ return [...(board.agents ?? []).map((a) => ({ kind: "agent", id: a.agentId })), ...board.members ?? []];
172
+ }
173
+ function candidates(board, item) {
174
+ if (item.eligibleAgentIds === void 0 && item.eligiblePrincipals === void 0)
175
+ return [
176
+ ...(board.agents ?? []).map((a) => ({ kind: "agent", id: a.agentId })),
177
+ ...(board.members ?? []).filter((m) => !m.roles || m.roles.includes("worker"))
178
+ ];
179
+ return [...(item.eligibleAgentIds ?? []).map((id) => ({ kind: "agent", id })), ...item.eligiblePrincipals ?? []];
180
+ }
181
+ function eligible(board, item, actor) {
182
+ const key = principalKey(principal(actor));
183
+ requireValue(candidates(board, item).some((p) => principalKey(p) === key), actor.kind && actor.kind !== "agent" ? "ASSIGNEE_NOT_ELIGIBLE" : "AGENT_NOT_ELIGIBLE");
184
+ }
185
+ function validateCandidates(board, item, executable2) {
186
+ const allowed = new Set(roster(board).map(principalKey)), values = candidates(board, item);
187
+ requireValue(!executable2 || values.length > 0, "ELIGIBLE_ASSIGNEES_REQUIRED");
188
+ for (const value of values) {
189
+ identity(value.id);
190
+ requireValue(["agent", "human", "service"].includes(value.kind), "INVALID_PRINCIPAL");
191
+ requireValue(allowed.has(principalKey(value)), value.kind === "agent" ? "AGENT_NOT_REGISTERED" : "ASSIGNEE_NOT_REGISTERED");
192
+ }
193
+ }
194
+ function normalizeActor(actor) {
195
+ const value = principal(actor);
196
+ return value.kind === "agent" ? { agentId: value.id, sessionId: actor.sessionId, taskId: actor.taskId } : { kind: value.kind, id: value.id };
197
+ }
198
+
199
+ export {
200
+ principal,
201
+ principalKey,
202
+ assigneeKey,
203
+ sameOwner,
204
+ candidates,
205
+ eligible,
206
+ validateCandidates,
207
+ normalizeActor,
208
+ policy,
209
+ workType,
210
+ executable,
211
+ requireValue,
212
+ text,
213
+ identity,
214
+ positive,
215
+ validateEstimate,
216
+ validateBoard,
217
+ participant,
218
+ owned,
219
+ discoveryState
220
+ };
221
+ //# sourceMappingURL=chunk-ATUFFNLV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/discovery-state.ts","../src/configuration.ts","../src/rules.ts","../src/identity.ts"],"sourcesContent":["import type {KanbanDiscoveryState} from './scan-ports';\n\nexport function discoveryState(state: {discovery?: unknown} | null | undefined): KanbanDiscoveryState | undefined {\n return state?.discovery as KanbanDiscoveryState | undefined;\n}\n","import {DEFAULT_KANBAN_WORK_TYPES, executableWorkItem} from './contracts';\nimport type {KanbanBoard, KanbanPolicy, KanbanWorkType} from './contracts';\nimport {identity, requireValue, text} from './rules';\nimport {principalKey, roster} from './identity';\n\nexport function policy(input: Partial<KanbanPolicy> = {}): KanbanPolicy {\n return {claimTimeoutMs: 86400000, leaseMs: 600000, progressTimeoutMs: 3600000, transferTimeoutMs: 1800000,\n maxComplexity: 10, maxWorkUnits: 100, maxDurationMs: 28800000, escalationSessionIds: [], ...input};\n}\nexport function workTypes(board: KanbanBoard): readonly KanbanWorkType[] {return board.workTypes ?? DEFAULT_KANBAN_WORK_TYPES;}\nexport function workType(board: KanbanBoard, id: string): KanbanWorkType {\n const found = workTypes(board).find(type => type.id === id); requireValue(found, 'UNKNOWN_WORK_TYPE'); return found;\n}\nexport function executable(board: KanbanBoard, item: {planning?: {kind: string; execution?: 'direct'|'children'}}): boolean {\n workType(board, item.planning?.kind ?? board.defaultWorkType ?? 'task');\n return executableWorkItem(board,item);\n}\nexport function validateConfiguration(board: KanbanBoard): void {\n const types = workTypes(board); requireValue(types.length > 0 && types.length <= 20, 'WORK_TYPE_LIMIT');\n requireValue(new Set(types.map(t => t.id)).size === types.length, 'DUPLICATE_WORK_TYPE');\n for (const type of types) {\n identity(type.id); text(type.label); requireValue(Number.isInteger(type.rank) && type.rank >= 0 && type.rank <= 9 && typeof type.executable === 'boolean', 'INVALID_WORK_TYPE');\n }\n workType(board, board.defaultWorkType ?? 'task');\n const members = roster(board); requireValue(members.length > 0, 'MEMBER_ROSTER_REQUIRED');\n requireValue(new Set(members.map(principalKey)).size === members.length, 'DUPLICATE_MEMBER');\n for (const member of members) {identity(member.id); requireValue(['agent', 'human', 'service'].includes(member.kind), 'INVALID_PRINCIPAL');}\n for (const member of board.members ?? []) {\n text(member.responsibility); requireValue(!member.roles || member.roles.every(r => ['worker', 'reviewer', 'coordinator'].includes(r)), 'INVALID_MEMBER_ROLE');\n }\n validateColumns(board);\n for (const [kind, value] of Object.entries(board.notifications?.rules ?? {}))\n requireValue(/^[a-z][a-z0-9.-]{0,79}$/.test(kind) && ['info', 'error', 'none'].includes(value), 'INVALID_NOTIFICATION_RULE');\n}\nfunction validateColumns(board: KanbanBoard): void {\n if (!board.columns) return;\n const states = board.columns.flatMap(c => c.states);\n requireValue(states.length === 7 && new Set(states).size === 7 && ['proposed', 'backlog', 'open', 'claimed', 'review', 'completed', 'cancelled'].every(s => states.includes(s as never)), 'INVALID_COLUMNS');\n requireValue(new Set(board.columns.map(c => c.id)).size === board.columns.length, 'DUPLICATE_COLUMN');\n for (const column of board.columns) {identity(column.id); text(column.label); requireValue(column.states.length > 0, 'EMPTY_COLUMN');}\n}\n","import type { KanbanActor, KanbanBoard, KanbanEstimate, KanbanItem, KanbanParticipant } from './contracts';\nimport {validateConfiguration} from './configuration';\nimport {sameOwner} from './identity';\nimport { KanbanError } from './ports';\n\nexport function requireValue(condition: unknown, code: string): asserts condition {\n if (!condition) throw new KanbanError(code);\n}\nexport function text(value: string): void { requireValue(typeof value === 'string' && value.trim().length > 0 && value.length <= 8000, 'INVALID_TEXT'); }\nexport function identity(value: string): void { requireValue(typeof value === 'string' && value.length > 0 && value.length <= 256 && !['__proto__', 'prototype', 'constructor'].includes(value), 'INVALID_ID'); }\nexport function positive(value: number): void { requireValue(Number.isFinite(value) && value > 0, 'INVALID_THRESHOLD'); }\nexport function validateEstimate(estimate: KanbanEstimate): void {\n positive(estimate.complexity); positive(estimate.workUnits); positive(estimate.durationMs);\n requireValue(['low', 'medium', 'high'].includes(estimate.confidence), 'INVALID_CONFIDENCE');\n}\nexport function validateBoard(board: KanbanBoard): void {\n identity(board.id); text(board.title);\n requireValue(['system', 'project', 'collection'].includes(board.scope.kind), 'INVALID_SCOPE');\n if (board.scope.kind === 'project') identity(board.scope.projectId);\n if (board.scope.kind === 'collection') {identity(board.scope.namespace); identity(board.scope.id);}\n validateConfiguration(board);\n for (const agent of board.agents ?? []) { identity(agent.agentId); text(agent.responsibility); }\n requireValue(new Set((board.agents ?? []).map(a => a.agentId)).size === (board.agents ?? []).length, 'DUPLICATE_AGENT');\n const p = board.policy;\n for (const value of [p.maxReady, p.maxInProgress, p.maxInProgressPerAgent, p.maxInProgressPerAssignee]) if (value !== undefined) requireValue(Number.isSafeInteger(value) && value > 0, 'INVALID_LIMIT');\n requireValue(p.maxInProgressPerAgent === undefined || p.maxInProgressPerAssignee === undefined || p.maxInProgressPerAgent === p.maxInProgressPerAssignee, 'POLICY_LIMIT_CONFLICT');\n for (const value of [p.archiveAfterMs, p.backlogReviewMs]) if (value !== undefined) positive(value);\n for (const value of [p.claimTimeoutMs, p.leaseMs, p.progressTimeoutMs, p.transferTimeoutMs,\n p.maxComplexity, p.maxWorkUnits, p.maxDurationMs]) positive(value);\n requireValue(Array.isArray(p.escalationSessionIds), 'INVALID_ESCALATION_TARGETS');\n requireValue(p.review === undefined || ['independent', 'assignee'].includes(p.review), 'INVALID_REVIEW_POLICY');\n requireValue(p.requireEstimate === undefined || typeof p.requireEstimate === 'boolean', 'INVALID_ESTIMATE_POLICY');\n p.escalationSessionIds.forEach(identity);\n}\nexport function participant(list: KanbanParticipant[], sessionId: string, agentId: string | undefined,\n role: KanbanParticipant['roles'][number], subscribed: boolean, now: number): void {\n identity(sessionId);\n requireValue(['creator', 'owner', 'consultant', 'reviewer', 'observer', 'escalation'].includes(role), 'INVALID_ROLE');\n let entry = list.find(value => value.sessionId === sessionId);\n if (!entry) { entry = { sessionId, agentId, roles: [], subscribed, joinedAt: now }; list.push(entry); }\n if (entry.agentId && agentId) requireValue(entry.agentId === agentId, 'SESSION_AGENT_CONFLICT');\n entry.agentId ??= agentId;\n if (!entry.roles.includes(role)) entry.roles.push(role);\n entry.subscribed = subscribed;\n}\nexport function owned(item: KanbanItem, actor: KanbanActor, token: string, now: number): void {\n requireValue(item.status === 'claimed', 'ITEM_NOT_RUNNING');\n requireValue(item.owner && sameOwner(item.owner, actor) && item.owner.token === token, 'OWNER_MISMATCH');\n requireValue(item.owner.leaseUntil > now, 'LEASE_EXPIRED');\n}\n","import type {KanbanActor, KanbanAssignment, KanbanBoard, KanbanItem, KanbanPrincipal} from './contracts';\nimport {identity, requireValue} from './rules';\n\nexport function principal(actor: KanbanActor): KanbanPrincipal {\n const kind = actor.kind ?? 'agent', id = kind === 'agent' ? actor.agentId ?? actor.id : actor.id;\n requireValue(['agent', 'human', 'service'].includes(kind) && id, 'INVALID_ACTOR'); identity(id);\n if (kind === 'agent') {requireValue(!actor.agentId || !actor.id || actor.agentId === actor.id, 'ACTOR_ID_MISMATCH'); if (actor.sessionId !== undefined) identity(actor.sessionId); if (actor.taskId !== undefined) identity(actor.taskId);}\n return {kind, id};\n}\nexport function principalKey(value: KanbanPrincipal): string {return JSON.stringify([value.kind, value.id]);}\nexport function assigneeKey(value: KanbanAssignment): string {\n return value.principalId ?? principalKey({kind: 'agent', id: value.agentId!});\n}\nexport function sameOwner(owner: KanbanAssignment, actor: KanbanActor): boolean {\n const value = principal(actor);\n return assigneeKey(owner) === principalKey(value) && (value.kind !== 'agent' || owner.sessionId === actor.sessionId && owner.taskId === actor.taskId);\n}\nexport function roster(board: KanbanBoard): KanbanPrincipal[] {\n return [...(board.agents ?? []).map(a => ({kind: 'agent' as const, id: a.agentId})), ...(board.members ?? [])];\n}\nexport function candidates(board: KanbanBoard, item: KanbanItem): KanbanPrincipal[] {\n if (item.eligibleAgentIds === undefined && item.eligiblePrincipals === undefined)\n return [...(board.agents ?? []).map(a => ({kind: 'agent' as const, id: a.agentId})),\n ...(board.members ?? []).filter(m => !m.roles || m.roles.includes('worker'))];\n return [...(item.eligibleAgentIds ?? []).map(id => ({kind: 'agent' as const, id})), ...(item.eligiblePrincipals ?? [])];\n}\nexport function eligible(board: KanbanBoard, item: KanbanItem, actor: KanbanActor): void {\n const key = principalKey(principal(actor));\n requireValue(candidates(board, item).some(p => principalKey(p) === key), actor.kind && actor.kind !== 'agent' ? 'ASSIGNEE_NOT_ELIGIBLE' : 'AGENT_NOT_ELIGIBLE');\n}\nexport function validateCandidates(board: KanbanBoard, item: KanbanItem, executable: boolean): void {\n const allowed = new Set(roster(board).map(principalKey)), values = candidates(board, item);\n requireValue(!executable || values.length > 0, 'ELIGIBLE_ASSIGNEES_REQUIRED');\n for (const value of values) {\n identity(value.id); requireValue(['agent', 'human', 'service'].includes(value.kind), 'INVALID_PRINCIPAL');\n requireValue(allowed.has(principalKey(value)), value.kind === 'agent' ? 'AGENT_NOT_REGISTERED' : 'ASSIGNEE_NOT_REGISTERED');\n }\n}\n\nexport function normalizeActor(actor: KanbanActor): KanbanActor {\n const value = principal(actor);\n return value.kind === 'agent' ? {agentId: value.id, sessionId: actor.sessionId, taskId: actor.taskId}\n : {kind: value.kind, id: value.id};\n}\n"],"mappings":"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","names":["executable"]}