kanbo-cli 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +26 -46
- package/dist/cli.cjs.map +1 -1
- package/dist/lib/index.cjs +1 -259
- package/dist/lib/index.d.cts +15 -95
- package/dist/lib/index.d.mts +15 -95
- package/dist/lib/index.mjs +2 -256
- package/dist/lib/{manifest-mkDJmxt2.mjs → manifest-BwpC-4BO.mjs} +27 -47
- package/dist/lib/manifest-BwpC-4BO.mjs.map +1 -0
- package/dist/lib/{manifest-BBJIrMw7.cjs → manifest-RDyoGrVR.cjs} +27 -47
- package/dist/lib/manifest-RDyoGrVR.cjs.map +1 -0
- package/dist/lib/mcp/index.cjs +1 -1
- package/dist/lib/mcp/index.mjs +1 -1
- package/dist/lib/migrations-path-CZxVOgeD.cjs.map +1 -1
- package/dist/lib/migrations-path-Ciwan537.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/lib/index.cjs.map +0 -1
- package/dist/lib/index.mjs.map +0 -1
- package/dist/lib/manifest-BBJIrMw7.cjs.map +0 -1
- package/dist/lib/manifest-mkDJmxt2.mjs.map +0 -1
package/dist/lib/index.mjs
CHANGED
|
@@ -1,257 +1,3 @@
|
|
|
1
|
-
import { $ as commentAuthorReference, A as maskDatabaseUrls, B as readEntryRules, C as cardDisplayTitle, D as readProjectBinding, E as readBinding, F as ENTRY_RULES, G as normalizeStatusName, H as readChangeSeq, I as ENTRY_RULE_DESCRIPTIONS, J as BOARD_ACTOR, K as TRACKED_FIELDS, L as UNMET_ENTRY_RULE_REASONS, M as formatExternalSessionRef, N as parseExternalSessionRef, O as writeBinding, P as pullRequestFactKeys, Q as activityToken, R as evaluateEntryRules, S as renderCapabilitiesMarkdown, T as ignoreBoardFile, U as runBoardWrite, V as serializeEntryRules, W as DEFAULT_STATUSES, X as activityKindOrder, Y as currentUnixSeconds, Z as activityText, a as BOARD_ERROR_RESPONSES, at as isOutsideWriter, ct as formatIssueId, dt as nextIssueOrder, et as formatActivityIssueReference, ft as readIssuePrefix, i as KANBO_TOOL_NAMES, it as readSystemCommentKind, j as createBoardOps, k as maskDatabaseUrl, lt as nextIssueIdentity, n as buildCapabilitiesManifest, nt as isEmptyActivityValue, ot as normalizeCommentAuthorKind, q as diffFieldChanges, r as KANBO_TOOL_CLI_EQUIVALENTS, rt as parseActivityStringArray, st as toIssueView, t as CAPABILITIES_MANIFEST_VERSION, tt as formatPlainActivityValue, ut as nextIssueNumber, w as BINDING_FILE_PATH, x as DEFAULT_BOARD_FILE_PATH, z as readChecklist } from "./manifest-
|
|
1
|
+
import { $ as commentAuthorReference, A as maskDatabaseUrls, B as readEntryRules, C as cardDisplayTitle, D as readProjectBinding, E as readBinding, F as ENTRY_RULES, G as normalizeStatusName, H as readChangeSeq, I as ENTRY_RULE_DESCRIPTIONS, J as BOARD_ACTOR, K as TRACKED_FIELDS, L as UNMET_ENTRY_RULE_REASONS, M as formatExternalSessionRef, N as parseExternalSessionRef, O as writeBinding, P as pullRequestFactKeys, Q as activityToken, R as evaluateEntryRules, S as renderCapabilitiesMarkdown, T as ignoreBoardFile, U as runBoardWrite, V as serializeEntryRules, W as DEFAULT_STATUSES, X as activityKindOrder, Y as currentUnixSeconds, Z as activityText, a as BOARD_ERROR_RESPONSES, at as isOutsideWriter, ct as formatIssueId, dt as nextIssueOrder, et as formatActivityIssueReference, ft as readIssuePrefix, i as KANBO_TOOL_NAMES, it as readSystemCommentKind, j as createBoardOps, k as maskDatabaseUrl, lt as nextIssueIdentity, n as buildCapabilitiesManifest, nt as isEmptyActivityValue, ot as normalizeCommentAuthorKind, q as diffFieldChanges, r as KANBO_TOOL_CLI_EQUIVALENTS, rt as parseActivityStringArray, st as toIssueView, t as CAPABILITIES_MANIFEST_VERSION, tt as formatPlainActivityValue, ut as nextIssueNumber, w as BINDING_FILE_PATH, x as DEFAULT_BOARD_FILE_PATH, z as readChecklist } from "./manifest-BwpC-4BO.mjs";
|
|
2
2
|
import { a as BoardError } from "./migrations-path-Ciwan537.mjs";
|
|
3
|
-
|
|
4
|
-
/** Nothing copied — what a move that had nothing to move reports. */
|
|
5
|
-
function emptyCopyCounts() {
|
|
6
|
-
return {
|
|
7
|
-
statuses: 0,
|
|
8
|
-
milestones: 0,
|
|
9
|
-
issues: 0,
|
|
10
|
-
comments: 0,
|
|
11
|
-
runs: 0,
|
|
12
|
-
relations: 0,
|
|
13
|
-
fieldChanges: 0,
|
|
14
|
-
contextRefs: 0,
|
|
15
|
-
pullRequests: 0
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Everything the workspace has on this board, read in one pass before a single
|
|
20
|
-
* row is written anywhere.
|
|
21
|
-
*
|
|
22
|
-
* Links are collected by id because an edge is listed by both of the cards it
|
|
23
|
-
* touches, and one reaching a card outside this workspace is left behind rather
|
|
24
|
-
* than copied: the target holds this workspace's board and nothing else, so the
|
|
25
|
-
* far end of that edge is not there to point at.
|
|
26
|
-
*/
|
|
27
|
-
async function readBoardSlice(from, workspaceId) {
|
|
28
|
-
const warnings = [];
|
|
29
|
-
const statuses = await from.statuses.listByWorkspace(workspaceId);
|
|
30
|
-
const milestones = await from.milestones.listByWorkspace(workspaceId);
|
|
31
|
-
const issues = orderParentsFirst(await from.issues.listByWorkspace(workspaceId));
|
|
32
|
-
const issueIds = new Set(issues.map((issue) => issue.id));
|
|
33
|
-
const comments = [];
|
|
34
|
-
const runs = [];
|
|
35
|
-
const relations = /* @__PURE__ */ new Map();
|
|
36
|
-
const fieldChanges = [];
|
|
37
|
-
const pullRequests = [];
|
|
38
|
-
const skippedRelations = /* @__PURE__ */ new Set();
|
|
39
|
-
for (const issue of issues) {
|
|
40
|
-
comments.push(...await from.comments.listByIssue(issue.id));
|
|
41
|
-
runs.push(...await from.runs.listByIssue(issue.id));
|
|
42
|
-
for (const relation of await from.relations.listByIssue(issue.id)) {
|
|
43
|
-
if (issueIds.has(relation.sourceIssueId) && issueIds.has(relation.targetIssueId)) {
|
|
44
|
-
relations.set(relation.id, relation);
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
skippedRelations.add(relation.id);
|
|
48
|
-
}
|
|
49
|
-
fieldChanges.push(...await from.fieldChanges.listByIssue(issue.id));
|
|
50
|
-
pullRequests.push(...await from.pullRequests.listByIssue(issue.id));
|
|
51
|
-
}
|
|
52
|
-
if (skippedRelations.size > 0) warnings.push(`${skippedRelations.size} links to cards in other workspaces were not moved`);
|
|
53
|
-
return {
|
|
54
|
-
statuses,
|
|
55
|
-
milestones,
|
|
56
|
-
issues,
|
|
57
|
-
comments,
|
|
58
|
-
runs,
|
|
59
|
-
relations: [...relations.values()],
|
|
60
|
-
fieldChanges,
|
|
61
|
-
pullRequests,
|
|
62
|
-
warnings
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Write a slice into the target board, in one transaction, and say what was
|
|
67
|
-
* written and what a person should know about it — the slice's own warnings
|
|
68
|
-
* first.
|
|
69
|
-
*
|
|
70
|
-
* It is idempotent by id. A row the target already has is left exactly as it
|
|
71
|
-
* is and counted as already present, so a copy interrupted half-way is finished
|
|
72
|
-
* by running it again, and a second run of a finished one copies nothing. A
|
|
73
|
-
* clash that is not the same row — a column name or a card number the target
|
|
74
|
-
* holds under another id — refuses the whole copy before its first insert
|
|
75
|
-
* (`board_copy_conflict`, ruling 3-55).
|
|
76
|
-
*/
|
|
77
|
-
async function writeBoardSlice(to, slice, workspaceId) {
|
|
78
|
-
const warnings = [...slice.warnings];
|
|
79
|
-
const copied = emptyCopyCounts();
|
|
80
|
-
let alreadyPresent = 0;
|
|
81
|
-
await to.transaction(async (tx) => {
|
|
82
|
-
await assertTheCopyFits(tx, slice, workspaceId);
|
|
83
|
-
for (const status of slice.statuses) {
|
|
84
|
-
if (await tx.statuses.findById(status.id)) {
|
|
85
|
-
alreadyPresent += 1;
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
await tx.statuses.create(status);
|
|
89
|
-
copied.statuses += 1;
|
|
90
|
-
}
|
|
91
|
-
for (const milestone of slice.milestones) {
|
|
92
|
-
if (await tx.milestones.findById(milestone.id)) {
|
|
93
|
-
alreadyPresent += 1;
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
await tx.milestones.create(milestone);
|
|
97
|
-
copied.milestones += 1;
|
|
98
|
-
}
|
|
99
|
-
const movingIssueIds = new Set(slice.issues.map((issue) => issue.id));
|
|
100
|
-
for (const issue of slice.issues) {
|
|
101
|
-
if (await tx.issues.findById(issue.id)) {
|
|
102
|
-
alreadyPresent += 1;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
const parentIsReachable = issue.parentIssueId === null || movingIssueIds.has(issue.parentIssueId) || await tx.issues.findById(issue.parentIssueId) !== null;
|
|
106
|
-
if (!parentIsReachable) warnings.push(`${issue.id} lost its parent card, which is not on this board`);
|
|
107
|
-
const { contextRefs, ...row } = issue;
|
|
108
|
-
await tx.issues.create({
|
|
109
|
-
...row,
|
|
110
|
-
parentIssueId: parentIsReachable ? issue.parentIssueId : null
|
|
111
|
-
});
|
|
112
|
-
copied.issues += 1;
|
|
113
|
-
if (contextRefs !== "[]") {
|
|
114
|
-
await tx.contextRefs.replace(issue.id, contextRefs, issue.updatedAt);
|
|
115
|
-
copied.contextRefs += 1;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
for (const comment of slice.comments) {
|
|
119
|
-
if (await tx.comments.findById(comment.id)) {
|
|
120
|
-
alreadyPresent += 1;
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
await tx.comments.create(comment);
|
|
124
|
-
copied.comments += 1;
|
|
125
|
-
}
|
|
126
|
-
for (const run of slice.runs) {
|
|
127
|
-
if (await tx.runs.findById(run.id)) {
|
|
128
|
-
alreadyPresent += 1;
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
await tx.runs.create(run);
|
|
132
|
-
copied.runs += 1;
|
|
133
|
-
}
|
|
134
|
-
for (const relation of slice.relations) {
|
|
135
|
-
if (await tx.relations.findById(relation.id)) {
|
|
136
|
-
alreadyPresent += 1;
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
await tx.relations.create(relation);
|
|
140
|
-
copied.relations += 1;
|
|
141
|
-
}
|
|
142
|
-
const changesByIssue = /* @__PURE__ */ new Map();
|
|
143
|
-
for (const change of slice.fieldChanges) changesByIssue.set(change.issueId, [...changesByIssue.get(change.issueId) ?? [], change]);
|
|
144
|
-
for (const [issueId, changes] of changesByIssue) {
|
|
145
|
-
const present = new Set((await tx.fieldChanges.listByIssue(issueId)).map((change) => change.id));
|
|
146
|
-
for (const change of changes) {
|
|
147
|
-
if (present.has(change.id)) {
|
|
148
|
-
alreadyPresent += 1;
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
await tx.fieldChanges.create(change);
|
|
152
|
-
copied.fieldChanges += 1;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
const linksByIssue = /* @__PURE__ */ new Map();
|
|
156
|
-
for (const link of slice.pullRequests) linksByIssue.set(link.issueId, [...linksByIssue.get(link.issueId) ?? [], link]);
|
|
157
|
-
for (const [issueId, links] of linksByIssue) {
|
|
158
|
-
const present = new Set((await tx.pullRequests.listByIssue(issueId)).map((link) => link.id));
|
|
159
|
-
for (const link of links) {
|
|
160
|
-
if (present.has(link.id) || (await tx.pullRequests.link(link)).id !== link.id) {
|
|
161
|
-
alreadyPresent += 1;
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
copied.pullRequests += 1;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
await tx.meta.bumpRevision("board", currentUnixSeconds());
|
|
168
|
-
});
|
|
169
|
-
if (alreadyPresent > 0) warnings.push(`${alreadyPresent} rows were already present on the target board and were left as they are`);
|
|
170
|
-
return {
|
|
171
|
-
copied,
|
|
172
|
-
warnings
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Empty the slice off the board it was read from, in a transaction of its own.
|
|
177
|
-
*
|
|
178
|
-
* Only the cards, the columns and the milestones are named: comments, runs,
|
|
179
|
-
* links, pull request links and the field-change history hang off a card by a
|
|
180
|
-
* foreign key that cascades on both engines, so deleting the card takes them
|
|
181
|
-
* with it.
|
|
182
|
-
*/
|
|
183
|
-
async function deleteBoardSlice(from, slice) {
|
|
184
|
-
await from.transaction(async (tx) => {
|
|
185
|
-
for (const issue of slice.issues) await tx.issues.delete(issue.id);
|
|
186
|
-
for (const milestone of slice.milestones) await tx.milestones.delete(milestone.id);
|
|
187
|
-
for (const status of slice.statuses) await tx.statuses.delete(status.id);
|
|
188
|
-
await tx.meta.bumpRevision("board", currentUnixSeconds());
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* What a copy would collide with on the target, said before a row is written.
|
|
193
|
-
*
|
|
194
|
-
* The board carries two uniqueness rules that a *second* board of the same
|
|
195
|
-
* workspace can break: a column's name within its workspace, and a card's
|
|
196
|
-
* number within it. In practice it is the columns that collide: a standard set
|
|
197
|
-
* created a second time carries the same names under new ids, while a card's id
|
|
198
|
-
* is its key (`BST-001`), so two generations of card *number* 1 are two rows
|
|
199
|
-
* with one id — which the copy treats as already present rather than as a
|
|
200
|
-
* clash. The number check covers the case where they are not: a workspace whose
|
|
201
|
-
* identifier changed between the two generations numbers from 1 again under
|
|
202
|
-
* different ids.
|
|
203
|
-
*
|
|
204
|
-
* A row the target already has *by id* is not a collision — it is the
|
|
205
|
-
* idempotent half of the copy, which is why the holder's id is compared rather
|
|
206
|
-
* than merely counted. Milestones need no check: neither engine makes their
|
|
207
|
-
* titles unique.
|
|
208
|
-
*/
|
|
209
|
-
async function assertTheCopyFits(tx, slice, workspaceId) {
|
|
210
|
-
const conflicts = [];
|
|
211
|
-
const numbers = new Map((await tx.issues.listByWorkspace(workspaceId)).map((issue) => [issue.number, issue.id]));
|
|
212
|
-
for (const issue of slice.issues) {
|
|
213
|
-
const holder = numbers.get(issue.number);
|
|
214
|
-
if (holder !== void 0 && holder !== issue.id) conflicts.push({
|
|
215
|
-
kind: "card",
|
|
216
|
-
value: issue.number,
|
|
217
|
-
heldBy: holder
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
const names = new Map((await tx.statuses.listByWorkspace(workspaceId)).map((status) => [status.name, status.id]));
|
|
221
|
-
for (const status of slice.statuses) {
|
|
222
|
-
const holder = names.get(status.name);
|
|
223
|
-
if (holder !== void 0 && holder !== status.id) conflicts.push({
|
|
224
|
-
kind: "column",
|
|
225
|
-
value: status.name,
|
|
226
|
-
heldBy: holder
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
if (conflicts.length > 0) throw new BoardError("board_copy_conflict", {
|
|
230
|
-
workspaceId,
|
|
231
|
-
conflicts
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* The same cards, ordered so that a parent is always written before its
|
|
236
|
-
* children. The column is a foreign key onto the same table, so any other order
|
|
237
|
-
* writes a card pointing at one that is not there yet.
|
|
238
|
-
*/
|
|
239
|
-
function orderParentsFirst(issues) {
|
|
240
|
-
const byId = new Map(issues.map((issue) => [issue.id, issue]));
|
|
241
|
-
const ordered = [];
|
|
242
|
-
const placed = /* @__PURE__ */ new Set();
|
|
243
|
-
function place(issue, ancestors) {
|
|
244
|
-
if (placed.has(issue.id) || ancestors.has(issue.id)) return;
|
|
245
|
-
ancestors.add(issue.id);
|
|
246
|
-
const parent = issue.parentIssueId === null ? void 0 : byId.get(issue.parentIssueId);
|
|
247
|
-
if (parent) place(parent, ancestors);
|
|
248
|
-
placed.add(issue.id);
|
|
249
|
-
ordered.push(issue);
|
|
250
|
-
}
|
|
251
|
-
for (const issue of issues) place(issue, /* @__PURE__ */ new Set());
|
|
252
|
-
return ordered;
|
|
253
|
-
}
|
|
254
|
-
//#endregion
|
|
255
|
-
export { BINDING_FILE_PATH, BOARD_ACTOR, BOARD_ERROR_RESPONSES, BoardError, CAPABILITIES_MANIFEST_VERSION, DEFAULT_BOARD_FILE_PATH, DEFAULT_STATUSES, ENTRY_RULES, ENTRY_RULE_DESCRIPTIONS, KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, TRACKED_FIELDS, UNMET_ENTRY_RULE_REASONS, activityKindOrder, activityText, activityToken, buildCapabilitiesManifest, cardDisplayTitle, commentAuthorReference, createBoardOps, currentUnixSeconds, deleteBoardSlice, diffFieldChanges, emptyCopyCounts, evaluateEntryRules, formatActivityIssueReference, formatExternalSessionRef, formatIssueId, formatPlainActivityValue, ignoreBoardFile, isEmptyActivityValue, isOutsideWriter, maskDatabaseUrl, maskDatabaseUrls, nextIssueIdentity, nextIssueNumber, nextIssueOrder, normalizeCommentAuthorKind, normalizeStatusName, parseActivityStringArray, parseExternalSessionRef, pullRequestFactKeys, readBinding, readBoardSlice, readChangeSeq, readChecklist, readEntryRules, readIssuePrefix, readProjectBinding, readSystemCommentKind, renderCapabilitiesMarkdown, runBoardWrite, serializeEntryRules, toIssueView, writeBinding, writeBoardSlice };
|
|
256
|
-
|
|
257
|
-
//# sourceMappingURL=index.mjs.map
|
|
3
|
+
export { BINDING_FILE_PATH, BOARD_ACTOR, BOARD_ERROR_RESPONSES, BoardError, CAPABILITIES_MANIFEST_VERSION, DEFAULT_BOARD_FILE_PATH, DEFAULT_STATUSES, ENTRY_RULES, ENTRY_RULE_DESCRIPTIONS, KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, TRACKED_FIELDS, UNMET_ENTRY_RULE_REASONS, activityKindOrder, activityText, activityToken, buildCapabilitiesManifest, cardDisplayTitle, commentAuthorReference, createBoardOps, currentUnixSeconds, diffFieldChanges, evaluateEntryRules, formatActivityIssueReference, formatExternalSessionRef, formatIssueId, formatPlainActivityValue, ignoreBoardFile, isEmptyActivityValue, isOutsideWriter, maskDatabaseUrl, maskDatabaseUrls, nextIssueIdentity, nextIssueNumber, nextIssueOrder, normalizeCommentAuthorKind, normalizeStatusName, parseActivityStringArray, parseExternalSessionRef, pullRequestFactKeys, readBinding, readChangeSeq, readChecklist, readEntryRules, readIssuePrefix, readProjectBinding, readSystemCommentKind, renderCapabilitiesMarkdown, runBoardWrite, serializeEntryRules, toIssueView, writeBinding };
|
|
@@ -1903,15 +1903,12 @@ async function approve(store, issueId, input, actor, scope) {
|
|
|
1903
1903
|
* leaves even says "returned by you".
|
|
1904
1904
|
*/
|
|
1905
1905
|
async function returnCard(store, issueId, input, actor, scope) {
|
|
1906
|
-
if (actor.kind !== "user") throw new BoardError("board_return_requires_user", {
|
|
1907
|
-
issueId,
|
|
1908
|
-
actorKind: actor.kind
|
|
1909
|
-
});
|
|
1910
1906
|
return await runBoardWrite(store, async ({ tx }) => {
|
|
1907
|
+
await ensureDefaultColumns(tx, (await requireCard$1(tx, issueId)).workspaceId, { tx });
|
|
1908
|
+
const target = await assertReturnable(tx, issueId, input, actor);
|
|
1911
1909
|
const card = await requireCard$1(tx, issueId);
|
|
1912
|
-
const columns = await ensureDefaultColumns(tx, card.workspaceId, { tx });
|
|
1913
1910
|
const updates = {
|
|
1914
|
-
statusId:
|
|
1911
|
+
statusId: target.id,
|
|
1915
1912
|
waitingFor: null,
|
|
1916
1913
|
updatedAt: currentUnixSeconds()
|
|
1917
1914
|
};
|
|
@@ -1932,6 +1929,27 @@ async function returnCard(store, issueId, input, actor, scope) {
|
|
|
1932
1929
|
};
|
|
1933
1930
|
}, scope);
|
|
1934
1931
|
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Every reason `returnCard` would refuse, asked on reads alone, and the column
|
|
1934
|
+
* the card would go back to when none applies.
|
|
1935
|
+
*
|
|
1936
|
+
* `returnCard` asks exactly this inside its write. A caller that has to undo
|
|
1937
|
+
* something of its own before the return — stop listening for the approval the
|
|
1938
|
+
* card is waiting on, say — asks it first, so a return the board refuses leaves
|
|
1939
|
+
* that untouched. The refusals are the same `BoardError` codes: an actor who is
|
|
1940
|
+
* not a person (`board_return_requires_user`), a card that is not there
|
|
1941
|
+
* (`issue_not_found`), a named column the workspace does not hold
|
|
1942
|
+
* (`issue_status_not_found`), and a card already in the first column with no
|
|
1943
|
+
* column named (`board_return_no_previous_column`).
|
|
1944
|
+
*/
|
|
1945
|
+
async function assertReturnable(store, issueId, input, actor) {
|
|
1946
|
+
if (actor.kind !== "user") throw new BoardError("board_return_requires_user", {
|
|
1947
|
+
issueId,
|
|
1948
|
+
actorKind: actor.kind
|
|
1949
|
+
});
|
|
1950
|
+
const card = await requireCard$1(store, issueId);
|
|
1951
|
+
return input.toStatusName ? await requireColumn(store, card.workspaceId, input.toStatusName) : previousColumn(await listColumns(store, card.workspaceId), card);
|
|
1952
|
+
}
|
|
1935
1953
|
/** Write a comment on the card, as the actor unless the caller names another author. */
|
|
1936
1954
|
async function addComment(store, input, actor, scope) {
|
|
1937
1955
|
return await runBoardWrite(store, async ({ tx }) => {
|
|
@@ -2809,6 +2827,7 @@ function createBoardOps(store) {
|
|
|
2809
2827
|
waitApproval: async (issueId, input, actor, scope) => await waitApproval(store, issueId, input, actor, scope),
|
|
2810
2828
|
approve: async (issueId, input, actor, scope) => await approve(store, issueId, input, actor, scope),
|
|
2811
2829
|
returnCard: async (issueId, input, actor, scope) => await returnCard(store, issueId, input, actor, scope),
|
|
2830
|
+
assertReturnable: async (issueId, input, actor) => await assertReturnable(store, issueId, input, actor),
|
|
2812
2831
|
readApproval: async (issueId) => await readApproval(store, issueId),
|
|
2813
2832
|
linkPullRequest: async (issueId, urlOrRef, actor, scope) => await linkPullRequest(store, issueId, urlOrRef, actor, scope),
|
|
2814
2833
|
unlinkPullRequest: async (issueId, linkId, actor, scope) => await unlinkPullRequest(store, issueId, linkId, actor, scope),
|
|
@@ -4311,7 +4330,7 @@ dirname(fileURLToPath(import.meta.url));
|
|
|
4311
4330
|
* `package.version`. A build carries it as a literal; running from source
|
|
4312
4331
|
* (tests, `tsx`) reads the package's own `package.json` instead.
|
|
4313
4332
|
*/
|
|
4314
|
-
const KANBO_PACKAGE_VERSION = "0.
|
|
4333
|
+
const KANBO_PACKAGE_VERSION = "0.2.0";
|
|
4315
4334
|
//#endregion
|
|
4316
4335
|
//#region src/cli/failure.ts
|
|
4317
4336
|
/**
|
|
@@ -6997,21 +7016,6 @@ function sendBoardPage(response, pathname, assets) {
|
|
|
6997
7016
|
* reason turned around: the answer will be yes once the card meets them, and
|
|
6998
7017
|
* `details.unmet` says what is missing.
|
|
6999
7018
|
*
|
|
7000
|
-
* The five failures about where a board is kept read the same rule. A database
|
|
7001
|
-
* that holds no board this build can speak for is 409 — the setting is there,
|
|
7002
|
-
* the board behind it is not yet, and `board-storage prepare` is what settles
|
|
7003
|
-
* that — and one nobody could reach at all is 503, because nothing about the
|
|
7004
|
-
* request was wrong. A workspace naming no board at all is 404: the caller
|
|
7005
|
-
* asked about a setting that is not there. A board still holding cards when
|
|
7006
|
-
* somebody asks to point the workspace elsewhere is 409, because the answer
|
|
7007
|
-
* would have been yes on an empty board and `board-storage migrate` is what
|
|
7008
|
-
* makes it one. An operation naming cards from two different boards is 400: no
|
|
7009
|
-
* transaction reaches both, so the caller asked for something that cannot be
|
|
7010
|
-
* done. A copy that would land on a card number or a column name the target
|
|
7011
|
-
* already holds under a different id is 409 for the same reason the others
|
|
7012
|
-
* are: the answer would have been yes on a target that did not hold that
|
|
7013
|
-
* board, and `details.conflicts` names every value that clashed.
|
|
7014
|
-
*
|
|
7015
7019
|
* A failure may also be renamed here: the package names its codes after the
|
|
7016
7020
|
* board, while every error the `/issues` routes answer with is named after the
|
|
7017
7021
|
* issue, and a client matching on `issue_*` should not have to learn a second
|
|
@@ -7033,10 +7037,6 @@ const BOARD_ERROR_RESPONSES = {
|
|
|
7033
7037
|
message: "The card does not meet what that column asks for yet",
|
|
7034
7038
|
code: "issue_column_rules_unmet"
|
|
7035
7039
|
},
|
|
7036
|
-
board_copy_conflict: {
|
|
7037
|
-
status: 409,
|
|
7038
|
-
message: "That board already holds cards or columns of this workspace under the same numbers or names; nothing was copied"
|
|
7039
|
-
},
|
|
7040
7040
|
board_entry_rule_invalid: {
|
|
7041
7041
|
status: 400,
|
|
7042
7042
|
message: "Unknown column entry rule"
|
|
@@ -7045,10 +7045,6 @@ const BOARD_ERROR_RESPONSES = {
|
|
|
7045
7045
|
status: 400,
|
|
7046
7046
|
message: "Execution mode cannot change once the card has been launched"
|
|
7047
7047
|
},
|
|
7048
|
-
board_mixed_workspaces: {
|
|
7049
|
-
status: 400,
|
|
7050
|
-
message: "Those cards are not all on the same board"
|
|
7051
|
-
},
|
|
7052
7048
|
board_pull_request_invalid: {
|
|
7053
7049
|
status: 400,
|
|
7054
7050
|
message: "Not a GitHub pull request: give its URL or owner/repo#number"
|
|
@@ -7108,22 +7104,6 @@ const BOARD_ERROR_RESPONSES = {
|
|
|
7108
7104
|
status: 400,
|
|
7109
7105
|
message: "A sprint cannot start after it is due"
|
|
7110
7106
|
},
|
|
7111
|
-
board_storage_not_configured: {
|
|
7112
|
-
status: 404,
|
|
7113
|
-
message: "This workspace names no board storage"
|
|
7114
|
-
},
|
|
7115
|
-
board_storage_not_empty: {
|
|
7116
|
-
status: 409,
|
|
7117
|
-
message: "That board still holds cards of this workspace; move them with migrate before changing where the board is kept"
|
|
7118
|
-
},
|
|
7119
|
-
board_storage_not_prepared: {
|
|
7120
|
-
status: 409,
|
|
7121
|
-
message: "That board has not been prepared yet"
|
|
7122
|
-
},
|
|
7123
|
-
board_storage_unavailable: {
|
|
7124
|
-
status: 503,
|
|
7125
|
-
message: "That board could not be reached"
|
|
7126
|
-
},
|
|
7127
7107
|
issue_comment_delete_requires_user: {
|
|
7128
7108
|
status: 403,
|
|
7129
7109
|
message: "Only a person can delete a comment the board wrote"
|
|
@@ -8950,4 +8930,4 @@ function buildCapabilitiesManifest() {
|
|
|
8950
8930
|
//#endregion
|
|
8951
8931
|
export { commentAuthorReference as $, maskDatabaseUrls as A, readEntryRules as B, cardDisplayTitle as C, readProjectBinding as D, readBinding as E, ENTRY_RULES as F, normalizeStatusName as G, readChangeSeq as H, ENTRY_RULE_DESCRIPTIONS as I, BOARD_ACTOR as J, TRACKED_FIELDS as K, UNMET_ENTRY_RULE_REASONS as L, formatExternalSessionRef as M, parseExternalSessionRef as N, writeBinding as O, pullRequestFactKeys as P, activityToken as Q, evaluateEntryRules as R, renderCapabilitiesMarkdown as S, ignoreBoardFile as T, runBoardWrite as U, serializeEntryRules as V, DEFAULT_STATUSES as W, activityKindOrder as X, currentUnixSeconds as Y, activityText as Z, projectKanboPullRequest as _, BOARD_ERROR_RESPONSES as a, isOutsideWriter as at, projectKanboSubCard as b, registerKanboTools as c, formatIssueId as ct, KANBO_MCP_INSTRUCTIONS as d, nextIssueOrder as dt, formatActivityIssueReference as et, KANBO_CAPABILITIES_MARKDOWN_RESOURCE_URI as f, readIssuePrefix as ft, projectKanboColumn as g, projectKanboCard as h, KANBO_TOOL_NAMES as i, readSystemCommentKind as it, createBoardOps as j, maskDatabaseUrl as k, KANBO_TOOLS as l, nextIssueIdentity as lt, registerKanboCapabilitiesResources as m, buildCapabilitiesManifest as n, isEmptyActivityValue as nt, KANBO_MCP_SERVER_NAME as o, normalizeCommentAuthorKind as ot, KANBO_CAPABILITIES_RESOURCE_URI as p, diffFieldChanges as q, KANBO_TOOL_CLI_EQUIVALENTS as r, parseActivityStringArray as rt, createKanboMcpServer as s, toIssueView as st, CAPABILITIES_MANIFEST_VERSION as t, formatPlainActivityValue as tt, buildKanboTools as u, nextIssueNumber as ut, projectKanboRun as v, BINDING_FILE_PATH as w, DEFAULT_BOARD_FILE_PATH as x, projectKanboSprint as y, readChecklist as z };
|
|
8952
8932
|
|
|
8953
|
-
//# sourceMappingURL=manifest-
|
|
8933
|
+
//# sourceMappingURL=manifest-BwpC-4BO.mjs.map
|