@nestos/kanban 0.0.0-stage → 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.
- package/LICENSE +674 -0
- package/README.md +165 -2
- package/dist/activity-BbC4sgKL.d.cts +258 -0
- package/dist/activity-Czlan5xW.d.ts +258 -0
- package/dist/activity-module-DaO1Rry0.d.cts +22 -0
- package/dist/activity-module-T22wliZu.d.ts +22 -0
- package/dist/activity-ports-Dqxa86zT.d.cts +12 -0
- package/dist/activity-ports-cxfrelaL.d.ts +12 -0
- package/dist/activity.cjs +16 -0
- package/dist/activity.cjs.map +1 -0
- package/dist/activity.d.cts +12 -0
- package/dist/activity.d.ts +12 -0
- package/dist/activity.js +16 -0
- package/dist/activity.js.map +1 -0
- package/dist/chunk-3JYLJPE5.js +95 -0
- package/dist/chunk-3JYLJPE5.js.map +1 -0
- package/dist/chunk-3LEIHB7Y.js +221 -0
- package/dist/chunk-3LEIHB7Y.js.map +1 -0
- package/dist/chunk-4XF6LQSU.cjs +9 -0
- package/dist/chunk-4XF6LQSU.cjs.map +1 -0
- package/dist/chunk-5Q7WB63A.cjs +282 -0
- package/dist/chunk-5Q7WB63A.cjs.map +1 -0
- package/dist/chunk-7KDOTBRX.cjs +58 -0
- package/dist/chunk-7KDOTBRX.cjs.map +1 -0
- package/dist/chunk-AHHEGTUA.js +148 -0
- package/dist/chunk-AHHEGTUA.js.map +1 -0
- package/dist/chunk-AOHQCX7K.cjs +95 -0
- package/dist/chunk-AOHQCX7K.cjs.map +1 -0
- package/dist/chunk-DINLR6E6.cjs +443 -0
- package/dist/chunk-DINLR6E6.cjs.map +1 -0
- package/dist/chunk-EYTVC2H5.cjs +1612 -0
- package/dist/chunk-EYTVC2H5.cjs.map +1 -0
- package/dist/chunk-FEE2YBZ7.js +1972 -0
- package/dist/chunk-FEE2YBZ7.js.map +1 -0
- package/dist/chunk-FNO5K3A7.js +282 -0
- package/dist/chunk-FNO5K3A7.js.map +1 -0
- package/dist/chunk-IHHDXZPZ.js +382 -0
- package/dist/chunk-IHHDXZPZ.js.map +1 -0
- package/dist/chunk-J3EAIVA3.js +280 -0
- package/dist/chunk-J3EAIVA3.js.map +1 -0
- package/dist/chunk-KH3WF3K4.js +443 -0
- package/dist/chunk-KH3WF3K4.js.map +1 -0
- package/dist/chunk-M35X5PHO.js +196 -0
- package/dist/chunk-M35X5PHO.js.map +1 -0
- package/dist/chunk-QRGZD2JU.cjs +1972 -0
- package/dist/chunk-QRGZD2JU.cjs.map +1 -0
- package/dist/chunk-RBOER6EW.cjs +221 -0
- package/dist/chunk-RBOER6EW.cjs.map +1 -0
- package/dist/chunk-RQP77ZTY.js +9 -0
- package/dist/chunk-RQP77ZTY.js.map +1 -0
- package/dist/chunk-RSH6QSEC.cjs +196 -0
- package/dist/chunk-RSH6QSEC.cjs.map +1 -0
- package/dist/chunk-VMRDXOLX.cjs +148 -0
- package/dist/chunk-VMRDXOLX.cjs.map +1 -0
- package/dist/chunk-X4UHZX6F.js +58 -0
- package/dist/chunk-X4UHZX6F.js.map +1 -0
- package/dist/chunk-XBSGUVCY.cjs +382 -0
- package/dist/chunk-XBSGUVCY.cjs.map +1 -0
- package/dist/chunk-XKDZHAUE.js +1612 -0
- package/dist/chunk-XKDZHAUE.js.map +1 -0
- package/dist/chunk-ZUZGAO6G.cjs +280 -0
- package/dist/chunk-ZUZGAO6G.cjs.map +1 -0
- package/dist/content-C5aJZFlw.d.cts +35 -0
- package/dist/content-hLH5BNud.d.ts +35 -0
- package/dist/contracts/index.cjs +31 -0
- package/dist/contracts/index.cjs.map +1 -0
- package/dist/contracts/index.d.cts +5 -0
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.js +31 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/discovery-9E-LfwIw.d.cts +61 -0
- package/dist/discovery-D60yrjej.d.ts +61 -0
- package/dist/discovery.cjs +377 -0
- package/dist/discovery.cjs.map +1 -0
- package/dist/discovery.d.cts +22 -0
- package/dist/discovery.d.ts +22 -0
- package/dist/discovery.js +377 -0
- package/dist/discovery.js.map +1 -0
- package/dist/execution-bridge-fpCnH6z5.d.cts +52 -0
- package/dist/execution-bridge-rk0uVy_n.d.ts +52 -0
- package/dist/execution.cjs +18 -0
- package/dist/execution.cjs.map +1 -0
- package/dist/execution.d.cts +42 -0
- package/dist/execution.d.ts +42 -0
- package/dist/execution.js +18 -0
- package/dist/execution.js.map +1 -0
- package/dist/index.cjs +74 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +54 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/module-CYfE7YhM.d.ts +11 -0
- package/dist/module-Ca9L3qCn.d.cts +11 -0
- package/dist/planning-CHrOqQ6b.d.cts +879 -0
- package/dist/planning-CHrOqQ6b.d.ts +879 -0
- package/dist/ports-B0McVg7B.d.ts +143 -0
- package/dist/ports-BeGO1VRI.d.cts +49 -0
- package/dist/ports-GQy0x-RI.d.cts +143 -0
- package/dist/ports-ykGiNUSx.d.ts +49 -0
- package/dist/runtime/index.cjs +205 -0
- package/dist/runtime/index.cjs.map +1 -0
- package/dist/runtime/index.d.cts +75 -0
- package/dist/runtime/index.d.ts +75 -0
- package/dist/runtime/index.js +205 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/integration.cjs +423 -0
- package/dist/runtime/integration.cjs.map +1 -0
- package/dist/runtime/integration.d.cts +658 -0
- package/dist/runtime/integration.d.ts +658 -0
- package/dist/runtime/integration.js +423 -0
- package/dist/runtime/integration.js.map +1 -0
- package/dist/storage.cjs +21 -0
- package/dist/storage.cjs.map +1 -0
- package/dist/storage.d.cts +71 -0
- package/dist/storage.d.ts +71 -0
- package/dist/storage.js +21 -0
- package/dist/storage.js.map +1 -0
- package/dist/store-DPwHzGiz.d.cts +28 -0
- package/dist/store-DgdrPCV9.d.ts +28 -0
- package/dist/task-projection-CSorlMws.d.ts +11 -0
- package/dist/task-projection-DKKB_ueb.d.cts +11 -0
- package/examples/standalone.ts +22 -0
- package/package.json +143 -4
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_KANBAN_WORK_TYPES,
|
|
3
|
+
executableWorkItem
|
|
4
|
+
} from "./chunk-X4UHZX6F.js";
|
|
5
|
+
import {
|
|
6
|
+
KanbanError
|
|
7
|
+
} from "./chunk-M35X5PHO.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-3LEIHB7Y.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"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/execution-observation.ts
|
|
2
|
+
function executionObservationChanged(current, next) {
|
|
3
|
+
return current.outcome !== next.outcome || current.code !== next.code || JSON.stringify(_nullishCoalesce(current.outputs, () => ( []))) !== JSON.stringify(_nullishCoalesce(next.outputs, () => ( []))) || next.executionSessionId !== void 0 && current.executionSessionId !== next.executionSessionId || next.controlCapabilities !== void 0 && JSON.stringify(current.controlCapabilities) !== JSON.stringify(next.controlCapabilities);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
exports.executionObservationChanged = executionObservationChanged;
|
|
9
|
+
//# sourceMappingURL=chunk-4XF6LQSU.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/li/share/prj/x1/libraries/kanban/dist/chunk-4XF6LQSU.cjs","../src/execution-observation.ts"],"names":[],"mappings":"AAAA;ACIO,SAAS,2BAAA,CAA4B,OAAA,EAAsB,IAAA,EAA4B;AAC1F,EAAA,OAAO,OAAA,CAAQ,QAAA,IAAY,IAAA,CAAK,QAAA,GAAW,OAAA,CAAQ,KAAA,IAAS,IAAA,CAAK,KAAA,GAC1D,IAAA,CAAK,SAAA,kBAAU,OAAA,CAAQ,OAAA,UAAW,CAAC,GAAC,EAAA,IAAM,IAAA,CAAK,SAAA,kBAAU,IAAA,CAAK,OAAA,UAAW,CAAC,GAAC,EAAA,GAC3E,IAAA,CAAK,mBAAA,IAAuB,KAAA,EAAA,GAAa,OAAA,CAAQ,mBAAA,IAAuB,IAAA,CAAK,mBAAA,GAC7E,IAAA,CAAK,oBAAA,IAAwB,KAAA,EAAA,GAAa,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,mBAAmB,EAAA,IAAM,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,mBAAmB,CAAA;AAC5I;ADLA;AACA;AACE;AACF,kEAAC","file":"/home/li/share/prj/x1/libraries/kanban/dist/chunk-4XF6LQSU.cjs","sourcesContent":[null,"import type {KanbanDispatch} from './contracts';\n\ntype Observation = Pick<KanbanDispatch, 'outcome' | 'code' | 'outputs' | 'executionSessionId' | 'controlCapabilities'>;\n/** A lease renewal is operational state, separate from observable execution changes. */\nexport function executionObservationChanged(current: Observation, next: Observation): boolean {\n return current.outcome !== next.outcome || current.code !== next.code\n || JSON.stringify(current.outputs ?? []) !== JSON.stringify(next.outputs ?? [])\n || next.executionSessionId !== undefined && current.executionSessionId !== next.executionSessionId\n || next.controlCapabilities !== undefined && JSON.stringify(current.controlCapabilities) !== JSON.stringify(next.controlCapabilities);\n}\n"]}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } async function _asyncOptionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = await fn(value); } else if (op === 'call' || op === 'optionalCall') { value = await fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
var _chunkDINLR6E6cjs = require('./chunk-DINLR6E6.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
var _chunkRBOER6EWcjs = require('./chunk-RBOER6EW.cjs');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
var _chunkRSH6QSECcjs = require('./chunk-RSH6QSEC.cjs');
|
|
14
|
+
|
|
15
|
+
// src/session-activity-query.ts
|
|
16
|
+
async function querySessionItems(core, boardId, input, project) {
|
|
17
|
+
const { execution = "all", ...query } = input;
|
|
18
|
+
if (!["all", "running", "recent", "active"].includes(execution)) throw new (0, _chunkRSH6QSECcjs.KanbanError)("INVALID_EXECUTION_FILTER");
|
|
19
|
+
if (execution === "all") {
|
|
20
|
+
const page2 = await core.query(boardId, query);
|
|
21
|
+
return { ...page2, items: await project(page2.items) };
|
|
22
|
+
}
|
|
23
|
+
const { cursor, limit = 50, ...filters } = query;
|
|
24
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 200) throw new (0, _chunkRSH6QSECcjs.KanbanError)("INVALID_PAGE_SIZE");
|
|
25
|
+
let page = await core.query(boardId, { ...filters, limit: 200 }), rows = [...page.items];
|
|
26
|
+
const revision = page.revision;
|
|
27
|
+
while (page.nextCursor) {
|
|
28
|
+
if (rows.length >= 1e4) throw new (0, _chunkRSH6QSECcjs.KanbanError)("ACTIVITY_QUERY_LIMIT");
|
|
29
|
+
page = await core.query(boardId, { ...filters, limit: 200, cursor: page.nextCursor });
|
|
30
|
+
if (page.revision !== revision) throw new (0, _chunkRSH6QSECcjs.KanbanError)("CURSOR_STALE");
|
|
31
|
+
rows.push(...page.items);
|
|
32
|
+
}
|
|
33
|
+
const matching = (await project(rows)).filter((row) => matchesExecution(row, execution));
|
|
34
|
+
if ((await core.query(boardId, { ...filters, limit: 1 })).revision !== revision) throw new (0, _chunkRSH6QSECcjs.KanbanError)("CURSOR_STALE");
|
|
35
|
+
const scope = _chunkRSH6QSECcjs.sha256HexSync.call(void 0, JSON.stringify({ filters, execution, limit })), signature = _chunkRSH6QSECcjs.sha256HexSync.call(void 0, JSON.stringify(matching.map((row) => row.id)));
|
|
36
|
+
let start = 0;
|
|
37
|
+
if (cursor) {
|
|
38
|
+
let saved;
|
|
39
|
+
try {
|
|
40
|
+
saved = JSON.parse(cursor);
|
|
41
|
+
} catch (e) {
|
|
42
|
+
throw new (0, _chunkRSH6QSECcjs.KanbanError)("INVALID_CURSOR");
|
|
43
|
+
}
|
|
44
|
+
if (saved.scope !== scope) throw new (0, _chunkRSH6QSECcjs.KanbanError)("CURSOR_SCOPE_MISMATCH");
|
|
45
|
+
if (saved.revision !== revision || saved.signature !== signature) throw new (0, _chunkRSH6QSECcjs.KanbanError)("CURSOR_STALE");
|
|
46
|
+
start = matching.findIndex((row) => row.id === saved.after) + 1;
|
|
47
|
+
if (start < 1) throw new (0, _chunkRSH6QSECcjs.KanbanError)("INVALID_CURSOR");
|
|
48
|
+
}
|
|
49
|
+
const items = matching.slice(start, start + limit);
|
|
50
|
+
return { revision, total: matching.length, items, ...start + items.length < matching.length ? { nextCursor: JSON.stringify({ scope, revision, signature, after: items.at(-1).id }) } : {} };
|
|
51
|
+
}
|
|
52
|
+
function matchesExecution(row, filter) {
|
|
53
|
+
const session = row.execution;
|
|
54
|
+
if (!session || session.stale) return false;
|
|
55
|
+
return filter === "running" ? session.state === "running" : filter === "recent" ? session.recent : session.state === "running" || session.recent;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/session-relations.ts
|
|
59
|
+
function sessionAssociations(item, bindings, workflow) {
|
|
60
|
+
return [...bindings.map((ref) => {
|
|
61
|
+
const dispatch = workflow.dispatches[_nullishCoalesce(ref.revision, () => ( ""))];
|
|
62
|
+
const execution = _optionalChain([dispatch, 'optionalAccess', _ => _.itemId]) === item.id ? {
|
|
63
|
+
id: dispatch.id,
|
|
64
|
+
purpose: "execution",
|
|
65
|
+
dispatchId: dispatch.id,
|
|
66
|
+
attempt: dispatch.attempt,
|
|
67
|
+
outcome: dispatch.outcome,
|
|
68
|
+
createdAt: dispatch.preparedAt,
|
|
69
|
+
code: dispatch.code,
|
|
70
|
+
...dispatch.continuation ? { previousDispatchId: dispatch.continuation.previousDispatchId } : {}
|
|
71
|
+
} : void 0;
|
|
72
|
+
return { sessionId: ref.id, purpose: "execution", ...execution ? { execution } : {} };
|
|
73
|
+
}), ...item.participants.filter((row) => !bindings.some((ref) => ref.id === row.sessionId)).map((row) => ({ sessionId: row.sessionId, purpose: "discussion" }))];
|
|
74
|
+
}
|
|
75
|
+
async function projectRelatedSessions(associations, currentId, inspect) {
|
|
76
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
77
|
+
for (const row of associations) {
|
|
78
|
+
let group = grouped.get(row.sessionId);
|
|
79
|
+
if (!group) grouped.set(row.sessionId, group = { purposes: /* @__PURE__ */ new Set(), executions: /* @__PURE__ */ new Map() });
|
|
80
|
+
group.purposes.add(row.purpose);
|
|
81
|
+
if (row.execution) group.executions.set(row.execution.id, { ...group.executions.get(row.execution.id), ...row.execution });
|
|
82
|
+
}
|
|
83
|
+
const rows = [], entries = [...grouped];
|
|
84
|
+
let next = 0;
|
|
85
|
+
await Promise.all(Array.from({ length: Math.min(entries.length, 8) }, async () => {
|
|
86
|
+
while (next < entries.length) {
|
|
87
|
+
const [sessionId, group] = entries[next++], state = await inspect(sessionId);
|
|
88
|
+
rows.push({
|
|
89
|
+
...state,
|
|
90
|
+
current: sessionId === currentId,
|
|
91
|
+
purposes: [...group.purposes].sort(),
|
|
92
|
+
executions: [...group.executions.values()].sort((a, b) => (_nullishCoalesce(a.createdAt, () => ( 0))) - (_nullishCoalesce(b.createdAt, () => ( 0))) || a.id.localeCompare(b.id))
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}));
|
|
96
|
+
return rows.sort((a, b) => Number(b.current) - Number(a.current) || a.sessionId.localeCompare(b.sessionId));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/session-activity.ts
|
|
100
|
+
function executionBindings(refs, referenceSystem) {
|
|
101
|
+
return (_nullishCoalesce(refs, () => ( []))).filter((ref) => ref.system === referenceSystem);
|
|
102
|
+
}
|
|
103
|
+
function currentBinding(refs, itemId, workflow, referenceSystem) {
|
|
104
|
+
const binding = executionBindings(refs, referenceSystem).at(-1), latest = Object.values(workflow.dispatches).filter((dispatch) => dispatch.itemId === itemId).sort((a, b) => b.attempt - a.attempt)[0];
|
|
105
|
+
if (!binding || !latest || binding.revision === latest.id) return binding;
|
|
106
|
+
return ["prepared", "running", "unknown", "succeeded"].includes(latest.outcome) || workflow.dispatches[_nullishCoalesce(binding.revision, () => ( ""))] ? void 0 : binding;
|
|
107
|
+
}
|
|
108
|
+
function createKanbanSessionActivity(core, options, log, referenceSystem) {
|
|
109
|
+
const inspect = createSessionInspector(options, log);
|
|
110
|
+
const project = async (boardId, rows) => {
|
|
111
|
+
if (!rows.some((row) => executionBindings(row.externalRefs, referenceSystem).length)) return rows;
|
|
112
|
+
const [board, workflow] = await Promise.all([boardMetadata(core, boardId), core.workflow(boardId)]), bindings = new Map(rows.map((row) => [row.id, currentBinding(row.externalRefs, row.id, workflow, referenceSystem)]));
|
|
113
|
+
const ids = [...new Set([...bindings.values()].flatMap((ref) => ref ? [ref.id] : []))], states = /* @__PURE__ */ new Map();
|
|
114
|
+
let next = 0;
|
|
115
|
+
await Promise.all(Array.from({ length: Math.min(ids.length, 8) }, async () => {
|
|
116
|
+
while (next < ids.length) {
|
|
117
|
+
const id = ids[next++];
|
|
118
|
+
states.set(id, await inspect(board, id));
|
|
119
|
+
}
|
|
120
|
+
}));
|
|
121
|
+
return rows.map((row) => {
|
|
122
|
+
const binding = bindings.get(row.id);
|
|
123
|
+
return { ...row, ...binding ? { execution: states.get(binding.id) } : {} };
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
return {
|
|
127
|
+
queryActivity: (boardId, query = {}) => querySessionItems(core, boardId, query, (rows) => project(boardId, rows)),
|
|
128
|
+
async executionSession(boardId, itemId, query = {}) {
|
|
129
|
+
const started = Date.now();
|
|
130
|
+
if (!query || typeof query !== "object" || Array.isArray(query) || Object.keys(query).some((key) => key !== "includeRelated") || query.includeRelated !== void 0 && typeof query.includeRelated !== "boolean") throw new (0, _chunkRSH6QSECcjs.KanbanError)("INVALID_QUERY");
|
|
131
|
+
const { item } = await core.item(boardId, itemId), bindings = executionBindings(item.externalRefs, referenceSystem);
|
|
132
|
+
if (!bindings.length && !query.includeRelated) return { history: [] };
|
|
133
|
+
const [board, workflow] = await Promise.all([boardMetadata(core, boardId), core.workflow(boardId)]), last = currentBinding(item.externalRefs, itemId, workflow, referenceSystem);
|
|
134
|
+
let sessionsCode;
|
|
135
|
+
const related = query.includeRelated ? await _optionalChain([options, 'optionalAccess', _2 => _2.source, 'access', _3 => _3.related, 'optionalCall', _4 => _4(board, item, workflow), 'access', _5 => _5.catch, 'call', _6 => _6((error) => {
|
|
136
|
+
const candidate = _optionalChain([error, 'optionalAccess', _7 => _7.code]);
|
|
137
|
+
sessionsCode = candidate && /^[A-Z][A-Z0-9_]{0,79}$/.test(candidate) ? candidate : "SESSION_RELATIONS_FAILED";
|
|
138
|
+
try {
|
|
139
|
+
log({ operationId: _chunkRSH6QSECcjs.randomUUID.call(void 0, ), stage: "session.relations", result: "failure", code: sessionsCode, durationMs: Date.now() - started });
|
|
140
|
+
} catch (e2) {
|
|
141
|
+
}
|
|
142
|
+
return [];
|
|
143
|
+
})]) : [];
|
|
144
|
+
const sessions = query.includeRelated ? await projectRelatedSessions([
|
|
145
|
+
...sessionAssociations(item, bindings, workflow),
|
|
146
|
+
..._nullishCoalesce(related, () => ( []))
|
|
147
|
+
], _optionalChain([last, 'optionalAccess', _8 => _8.id]), (id) => inspect(board, id)) : void 0;
|
|
148
|
+
return {
|
|
149
|
+
current: last ? await _asyncNullishCoalesce(await _asyncOptionalChain([sessions, 'optionalAccess', async _9 => _9.find, 'call', async _10 => _10((row) => row.sessionId === last.id)]), async () => ( await inspect(board, last.id))) : void 0,
|
|
150
|
+
history: bindings.map((ref) => ({ sessionId: ref.id, bindingId: ref.revision, current: ref === last })).reverse(),
|
|
151
|
+
...sessions ? { sessions } : {},
|
|
152
|
+
...sessionsCode ? { sessionsCode } : {}
|
|
153
|
+
};
|
|
154
|
+
},
|
|
155
|
+
validate: (board, command, actor) => validateBinding(core, options, board, command, actor, referenceSystem)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function createSessionInspector(options, log) {
|
|
159
|
+
const now = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _11 => _11.now]), () => ( Date.now)), cache = /* @__PURE__ */ new Map();
|
|
160
|
+
return async (board, sessionId) => {
|
|
161
|
+
const started = now(), key = JSON.stringify([board.id, sessionId]);
|
|
162
|
+
try {
|
|
163
|
+
if (!options) throw new (0, _chunkRSH6QSECcjs.KanbanError)("EXECUTION_SESSION_UNAVAILABLE");
|
|
164
|
+
const row = await options.source.inspect(board, sessionId);
|
|
165
|
+
if (row.sessionId !== sessionId) throw new (0, _chunkRSH6QSECcjs.KanbanError)("SESSION_ACTIVITY_SCOPE_MISMATCH");
|
|
166
|
+
const stale = row.stale || row.observedAt === void 0 || now() - row.observedAt > 9e4;
|
|
167
|
+
const value = {
|
|
168
|
+
sessionId,
|
|
169
|
+
...typeof row.resourceId === "string" && row.resourceId.length <= 4096 && !row.resourceId.includes("\0") ? { resourceId: row.resourceId } : {},
|
|
170
|
+
title: _optionalChain([row, 'access', _12 => _12.title, 'optionalAccess', _13 => _13.slice, 'call', _14 => _14(0, 256)]),
|
|
171
|
+
state: row.state,
|
|
172
|
+
createdAt: row.createdAt,
|
|
173
|
+
lastActivityAt: row.lastActivityAt,
|
|
174
|
+
observedAt: row.observedAt,
|
|
175
|
+
stale,
|
|
176
|
+
recent: !stale && row.lastActivityAt !== void 0 && row.lastActivityAt <= now() && now() - row.lastActivityAt <= 6e5,
|
|
177
|
+
...row.code && /^[A-Z][A-Z0-9_]{0,79}$/.test(row.code) ? { code: row.code } : {}
|
|
178
|
+
};
|
|
179
|
+
if (cache.size >= 256) cache.delete(cache.keys().next().value);
|
|
180
|
+
cache.set(key, value);
|
|
181
|
+
return value;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
const candidate = _optionalChain([error, 'optionalAccess', _15 => _15.code]), code = candidate && /^[A-Z][A-Z0-9_]{0,79}$/.test(candidate) ? candidate : "SESSION_ACTIVITY_FAILED";
|
|
184
|
+
try {
|
|
185
|
+
log({ operationId: _chunkRSH6QSECcjs.randomUUID.call(void 0, ), sessionId, stage: "session.activity", result: "failure", code, durationMs: now() - started });
|
|
186
|
+
} catch (e3) {
|
|
187
|
+
}
|
|
188
|
+
const prior = ["EIO", "ETIMEDOUT", "ECONNRESET", "ECONNREFUSED", "SESSION_ACTIVITY_FAILED"].includes(code) ? cache.get(key) : void 0;
|
|
189
|
+
return { ...prior, sessionId, state: _nullishCoalesce(_optionalChain([prior, 'optionalAccess', _16 => _16.state]), () => ( "unknown")), stale: true, recent: false, code };
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
async function boardMetadata(core, boardId) {
|
|
194
|
+
const board = await _asyncNullishCoalesce((await core.catalog()).find((board2) => board2.id === boardId), async () => ( await core.read(boardId)));
|
|
195
|
+
return { ...board, items: [] };
|
|
196
|
+
}
|
|
197
|
+
async function validateBinding(core, options, board, command, actor, referenceSystem) {
|
|
198
|
+
if (_optionalChain([command, 'optionalAccess', _17 => _17.type]) !== "link-reference" || command.reference.system !== referenceSystem) return;
|
|
199
|
+
if (!options || !command.reference.revision) throw new (0, _chunkRSH6QSECcjs.KanbanError)("EXECUTION_SESSION_UNAVAILABLE");
|
|
200
|
+
const item = board.items.find((item2) => item2.id === command.itemId);
|
|
201
|
+
if (!item) throw new (0, _chunkRSH6QSECcjs.KanbanError)("ITEM_NOT_FOUND");
|
|
202
|
+
const key = _chunkRBOER6EWcjs.principalKey.call(void 0, _chunkRBOER6EWcjs.principal.call(void 0, actor)), coordinator = _optionalChain([board, 'access', _18 => _18.members, 'optionalAccess', _19 => _19.some, 'call', _20 => _20((member) => _chunkRBOER6EWcjs.principalKey.call(void 0, member) === key && _optionalChain([member, 'access', _21 => _21.roles, 'optionalAccess', _22 => _22.includes, 'call', _23 => _23("coordinator")]))]);
|
|
203
|
+
if (!coordinator && _optionalChain([item, 'access', _24 => _24.owner, 'optionalAccess', _25 => _25.principalId]) !== key && !(item.owner === void 0 && _chunkRBOER6EWcjs.candidates.call(void 0, board, item).some((candidate) => _chunkRBOER6EWcjs.principalKey.call(void 0, candidate) === key))) throw new (0, _chunkRSH6QSECcjs.KanbanError)("EXECUTION_SESSION_ASSIGNMENT_DENIED");
|
|
204
|
+
const active = Object.values((await core.workflow(board.id)).dispatches).filter((dispatch) => dispatch.itemId === item.id).sort((a, b) => b.attempt - a.attempt)[0];
|
|
205
|
+
if (active && command.reference.revision !== active.id) throw new (0, _chunkRSH6QSECcjs.KanbanError)("EXECUTION_SESSION_LOCKED");
|
|
206
|
+
if (active && executionBindings(item.externalRefs, referenceSystem).some((ref) => ref.revision === active.id && ref.id !== command.reference.id)) throw new (0, _chunkRSH6QSECcjs.KanbanError)("EXECUTION_SESSION_LOCKED");
|
|
207
|
+
if (options.source.authorizeBinding) return options.source.authorizeBinding(board, command.reference.id);
|
|
208
|
+
const state = await options.source.inspect(board, command.reference.id);
|
|
209
|
+
if (state.sessionId !== command.reference.id || state.stale) throw new (0, _chunkRSH6QSECcjs.KanbanError)("EXECUTION_SESSION_UNAVAILABLE");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/activity-module.ts
|
|
213
|
+
function createKanbanActivityModule(options) {
|
|
214
|
+
const { executionSessions, referenceSystem, ...core } = options;
|
|
215
|
+
let activity;
|
|
216
|
+
const service = _chunkDINLR6E6cjs.createKanbanModule.call(void 0, {
|
|
217
|
+
...core,
|
|
218
|
+
authorize: async (input) => {
|
|
219
|
+
await core.authorize(input);
|
|
220
|
+
await activity.validate(input.board, input.command, input.actor);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
activity = createKanbanSessionActivity(service, executionSessions, core.log, referenceSystem);
|
|
224
|
+
let stopping = false;
|
|
225
|
+
const pending = /* @__PURE__ */ new Set();
|
|
226
|
+
const track = (run) => {
|
|
227
|
+
if (stopping) return Promise.reject(new (0, _chunkRSH6QSECcjs.KanbanError)("SERVICE_STOPPING"));
|
|
228
|
+
const work = Promise.resolve().then(run).finally(() => {
|
|
229
|
+
pending.delete(work);
|
|
230
|
+
});
|
|
231
|
+
pending.add(work);
|
|
232
|
+
return work;
|
|
233
|
+
};
|
|
234
|
+
const quiesce = async () => {
|
|
235
|
+
stopping = true;
|
|
236
|
+
await Promise.allSettled([...pending]);
|
|
237
|
+
await service.quiesce();
|
|
238
|
+
};
|
|
239
|
+
return {
|
|
240
|
+
...forwardCore(service, track),
|
|
241
|
+
queryActivity: (...args) => track(() => activity.queryActivity(...args)),
|
|
242
|
+
executionSession: (...args) => track(() => activity.executionSession(...args)),
|
|
243
|
+
related: (sessionId) => track(() => relatedBoards(service, referenceSystem, sessionId)),
|
|
244
|
+
quiesce,
|
|
245
|
+
dispose: quiesce
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function forwardCore(service, track) {
|
|
249
|
+
return {
|
|
250
|
+
create: (input) => track(() => service.create(input)),
|
|
251
|
+
read: (id) => track(() => service.read(id)),
|
|
252
|
+
list: () => track(() => service.list()),
|
|
253
|
+
catalog: () => track(() => service.catalog()),
|
|
254
|
+
execute: (id, request) => track(() => service.execute(id, request)),
|
|
255
|
+
events: (id, after, limit) => track(() => service.events(id, after, limit)),
|
|
256
|
+
query: (id, query) => track(() => service.query(id, query)),
|
|
257
|
+
item: (id, item) => track(() => service.item(id, item)),
|
|
258
|
+
overview: (id) => track(() => service.overview(id)),
|
|
259
|
+
scan: () => track(() => service.scan()),
|
|
260
|
+
workflow: (id) => track(() => service.workflow(id)),
|
|
261
|
+
resolve: (reference) => track(() => service.resolve(reference)),
|
|
262
|
+
suggest: (id, query) => track(() => service.suggest(id, query)),
|
|
263
|
+
records: (id, query) => track(() => service.records(id, query)),
|
|
264
|
+
record: (id, record) => track(() => service.record(id, record)),
|
|
265
|
+
currentPrincipal: () => track(() => service.currentPrincipal())
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
async function relatedBoards(service, referenceSystem, sessionId) {
|
|
269
|
+
const boards = await service.related(sessionId);
|
|
270
|
+
for (const board of await service.catalog()) {
|
|
271
|
+
if (boards.some((old) => old.id === board.id)) continue;
|
|
272
|
+
const matches = await service.query(board.id, { view: "all", reference: { system: referenceSystem, id: sessionId }, limit: 1 });
|
|
273
|
+
if (matches.total) boards.push(await service.read(board.id));
|
|
274
|
+
}
|
|
275
|
+
return boards;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
exports.querySessionItems = querySessionItems; exports.createKanbanActivityModule = createKanbanActivityModule;
|
|
282
|
+
//# sourceMappingURL=chunk-5Q7WB63A.cjs.map
|