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.cjs
CHANGED
|
@@ -1,258 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_manifest = require("./manifest-
|
|
2
|
+
const require_manifest = require("./manifest-RDyoGrVR.cjs");
|
|
3
3
|
const require_migrations_path = require("./migrations-path-CZxVOgeD.cjs");
|
|
4
|
-
//#region src/ops/board-copy.ts
|
|
5
|
-
/** Nothing copied — what a move that had nothing to move reports. */
|
|
6
|
-
function emptyCopyCounts() {
|
|
7
|
-
return {
|
|
8
|
-
statuses: 0,
|
|
9
|
-
milestones: 0,
|
|
10
|
-
issues: 0,
|
|
11
|
-
comments: 0,
|
|
12
|
-
runs: 0,
|
|
13
|
-
relations: 0,
|
|
14
|
-
fieldChanges: 0,
|
|
15
|
-
contextRefs: 0,
|
|
16
|
-
pullRequests: 0
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Everything the workspace has on this board, read in one pass before a single
|
|
21
|
-
* row is written anywhere.
|
|
22
|
-
*
|
|
23
|
-
* Links are collected by id because an edge is listed by both of the cards it
|
|
24
|
-
* touches, and one reaching a card outside this workspace is left behind rather
|
|
25
|
-
* than copied: the target holds this workspace's board and nothing else, so the
|
|
26
|
-
* far end of that edge is not there to point at.
|
|
27
|
-
*/
|
|
28
|
-
async function readBoardSlice(from, workspaceId) {
|
|
29
|
-
const warnings = [];
|
|
30
|
-
const statuses = await from.statuses.listByWorkspace(workspaceId);
|
|
31
|
-
const milestones = await from.milestones.listByWorkspace(workspaceId);
|
|
32
|
-
const issues = orderParentsFirst(await from.issues.listByWorkspace(workspaceId));
|
|
33
|
-
const issueIds = new Set(issues.map((issue) => issue.id));
|
|
34
|
-
const comments = [];
|
|
35
|
-
const runs = [];
|
|
36
|
-
const relations = /* @__PURE__ */ new Map();
|
|
37
|
-
const fieldChanges = [];
|
|
38
|
-
const pullRequests = [];
|
|
39
|
-
const skippedRelations = /* @__PURE__ */ new Set();
|
|
40
|
-
for (const issue of issues) {
|
|
41
|
-
comments.push(...await from.comments.listByIssue(issue.id));
|
|
42
|
-
runs.push(...await from.runs.listByIssue(issue.id));
|
|
43
|
-
for (const relation of await from.relations.listByIssue(issue.id)) {
|
|
44
|
-
if (issueIds.has(relation.sourceIssueId) && issueIds.has(relation.targetIssueId)) {
|
|
45
|
-
relations.set(relation.id, relation);
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
skippedRelations.add(relation.id);
|
|
49
|
-
}
|
|
50
|
-
fieldChanges.push(...await from.fieldChanges.listByIssue(issue.id));
|
|
51
|
-
pullRequests.push(...await from.pullRequests.listByIssue(issue.id));
|
|
52
|
-
}
|
|
53
|
-
if (skippedRelations.size > 0) warnings.push(`${skippedRelations.size} links to cards in other workspaces were not moved`);
|
|
54
|
-
return {
|
|
55
|
-
statuses,
|
|
56
|
-
milestones,
|
|
57
|
-
issues,
|
|
58
|
-
comments,
|
|
59
|
-
runs,
|
|
60
|
-
relations: [...relations.values()],
|
|
61
|
-
fieldChanges,
|
|
62
|
-
pullRequests,
|
|
63
|
-
warnings
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Write a slice into the target board, in one transaction, and say what was
|
|
68
|
-
* written and what a person should know about it — the slice's own warnings
|
|
69
|
-
* first.
|
|
70
|
-
*
|
|
71
|
-
* It is idempotent by id. A row the target already has is left exactly as it
|
|
72
|
-
* is and counted as already present, so a copy interrupted half-way is finished
|
|
73
|
-
* by running it again, and a second run of a finished one copies nothing. A
|
|
74
|
-
* clash that is not the same row — a column name or a card number the target
|
|
75
|
-
* holds under another id — refuses the whole copy before its first insert
|
|
76
|
-
* (`board_copy_conflict`, ruling 3-55).
|
|
77
|
-
*/
|
|
78
|
-
async function writeBoardSlice(to, slice, workspaceId) {
|
|
79
|
-
const warnings = [...slice.warnings];
|
|
80
|
-
const copied = emptyCopyCounts();
|
|
81
|
-
let alreadyPresent = 0;
|
|
82
|
-
await to.transaction(async (tx) => {
|
|
83
|
-
await assertTheCopyFits(tx, slice, workspaceId);
|
|
84
|
-
for (const status of slice.statuses) {
|
|
85
|
-
if (await tx.statuses.findById(status.id)) {
|
|
86
|
-
alreadyPresent += 1;
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
await tx.statuses.create(status);
|
|
90
|
-
copied.statuses += 1;
|
|
91
|
-
}
|
|
92
|
-
for (const milestone of slice.milestones) {
|
|
93
|
-
if (await tx.milestones.findById(milestone.id)) {
|
|
94
|
-
alreadyPresent += 1;
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
await tx.milestones.create(milestone);
|
|
98
|
-
copied.milestones += 1;
|
|
99
|
-
}
|
|
100
|
-
const movingIssueIds = new Set(slice.issues.map((issue) => issue.id));
|
|
101
|
-
for (const issue of slice.issues) {
|
|
102
|
-
if (await tx.issues.findById(issue.id)) {
|
|
103
|
-
alreadyPresent += 1;
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
const parentIsReachable = issue.parentIssueId === null || movingIssueIds.has(issue.parentIssueId) || await tx.issues.findById(issue.parentIssueId) !== null;
|
|
107
|
-
if (!parentIsReachable) warnings.push(`${issue.id} lost its parent card, which is not on this board`);
|
|
108
|
-
const { contextRefs, ...row } = issue;
|
|
109
|
-
await tx.issues.create({
|
|
110
|
-
...row,
|
|
111
|
-
parentIssueId: parentIsReachable ? issue.parentIssueId : null
|
|
112
|
-
});
|
|
113
|
-
copied.issues += 1;
|
|
114
|
-
if (contextRefs !== "[]") {
|
|
115
|
-
await tx.contextRefs.replace(issue.id, contextRefs, issue.updatedAt);
|
|
116
|
-
copied.contextRefs += 1;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
for (const comment of slice.comments) {
|
|
120
|
-
if (await tx.comments.findById(comment.id)) {
|
|
121
|
-
alreadyPresent += 1;
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
await tx.comments.create(comment);
|
|
125
|
-
copied.comments += 1;
|
|
126
|
-
}
|
|
127
|
-
for (const run of slice.runs) {
|
|
128
|
-
if (await tx.runs.findById(run.id)) {
|
|
129
|
-
alreadyPresent += 1;
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
await tx.runs.create(run);
|
|
133
|
-
copied.runs += 1;
|
|
134
|
-
}
|
|
135
|
-
for (const relation of slice.relations) {
|
|
136
|
-
if (await tx.relations.findById(relation.id)) {
|
|
137
|
-
alreadyPresent += 1;
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
await tx.relations.create(relation);
|
|
141
|
-
copied.relations += 1;
|
|
142
|
-
}
|
|
143
|
-
const changesByIssue = /* @__PURE__ */ new Map();
|
|
144
|
-
for (const change of slice.fieldChanges) changesByIssue.set(change.issueId, [...changesByIssue.get(change.issueId) ?? [], change]);
|
|
145
|
-
for (const [issueId, changes] of changesByIssue) {
|
|
146
|
-
const present = new Set((await tx.fieldChanges.listByIssue(issueId)).map((change) => change.id));
|
|
147
|
-
for (const change of changes) {
|
|
148
|
-
if (present.has(change.id)) {
|
|
149
|
-
alreadyPresent += 1;
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
await tx.fieldChanges.create(change);
|
|
153
|
-
copied.fieldChanges += 1;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
const linksByIssue = /* @__PURE__ */ new Map();
|
|
157
|
-
for (const link of slice.pullRequests) linksByIssue.set(link.issueId, [...linksByIssue.get(link.issueId) ?? [], link]);
|
|
158
|
-
for (const [issueId, links] of linksByIssue) {
|
|
159
|
-
const present = new Set((await tx.pullRequests.listByIssue(issueId)).map((link) => link.id));
|
|
160
|
-
for (const link of links) {
|
|
161
|
-
if (present.has(link.id) || (await tx.pullRequests.link(link)).id !== link.id) {
|
|
162
|
-
alreadyPresent += 1;
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
copied.pullRequests += 1;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
await tx.meta.bumpRevision("board", require_manifest.currentUnixSeconds());
|
|
169
|
-
});
|
|
170
|
-
if (alreadyPresent > 0) warnings.push(`${alreadyPresent} rows were already present on the target board and were left as they are`);
|
|
171
|
-
return {
|
|
172
|
-
copied,
|
|
173
|
-
warnings
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Empty the slice off the board it was read from, in a transaction of its own.
|
|
178
|
-
*
|
|
179
|
-
* Only the cards, the columns and the milestones are named: comments, runs,
|
|
180
|
-
* links, pull request links and the field-change history hang off a card by a
|
|
181
|
-
* foreign key that cascades on both engines, so deleting the card takes them
|
|
182
|
-
* with it.
|
|
183
|
-
*/
|
|
184
|
-
async function deleteBoardSlice(from, slice) {
|
|
185
|
-
await from.transaction(async (tx) => {
|
|
186
|
-
for (const issue of slice.issues) await tx.issues.delete(issue.id);
|
|
187
|
-
for (const milestone of slice.milestones) await tx.milestones.delete(milestone.id);
|
|
188
|
-
for (const status of slice.statuses) await tx.statuses.delete(status.id);
|
|
189
|
-
await tx.meta.bumpRevision("board", require_manifest.currentUnixSeconds());
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* What a copy would collide with on the target, said before a row is written.
|
|
194
|
-
*
|
|
195
|
-
* The board carries two uniqueness rules that a *second* board of the same
|
|
196
|
-
* workspace can break: a column's name within its workspace, and a card's
|
|
197
|
-
* number within it. In practice it is the columns that collide: a standard set
|
|
198
|
-
* created a second time carries the same names under new ids, while a card's id
|
|
199
|
-
* is its key (`BST-001`), so two generations of card *number* 1 are two rows
|
|
200
|
-
* with one id — which the copy treats as already present rather than as a
|
|
201
|
-
* clash. The number check covers the case where they are not: a workspace whose
|
|
202
|
-
* identifier changed between the two generations numbers from 1 again under
|
|
203
|
-
* different ids.
|
|
204
|
-
*
|
|
205
|
-
* A row the target already has *by id* is not a collision — it is the
|
|
206
|
-
* idempotent half of the copy, which is why the holder's id is compared rather
|
|
207
|
-
* than merely counted. Milestones need no check: neither engine makes their
|
|
208
|
-
* titles unique.
|
|
209
|
-
*/
|
|
210
|
-
async function assertTheCopyFits(tx, slice, workspaceId) {
|
|
211
|
-
const conflicts = [];
|
|
212
|
-
const numbers = new Map((await tx.issues.listByWorkspace(workspaceId)).map((issue) => [issue.number, issue.id]));
|
|
213
|
-
for (const issue of slice.issues) {
|
|
214
|
-
const holder = numbers.get(issue.number);
|
|
215
|
-
if (holder !== void 0 && holder !== issue.id) conflicts.push({
|
|
216
|
-
kind: "card",
|
|
217
|
-
value: issue.number,
|
|
218
|
-
heldBy: holder
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
const names = new Map((await tx.statuses.listByWorkspace(workspaceId)).map((status) => [status.name, status.id]));
|
|
222
|
-
for (const status of slice.statuses) {
|
|
223
|
-
const holder = names.get(status.name);
|
|
224
|
-
if (holder !== void 0 && holder !== status.id) conflicts.push({
|
|
225
|
-
kind: "column",
|
|
226
|
-
value: status.name,
|
|
227
|
-
heldBy: holder
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
if (conflicts.length > 0) throw new require_migrations_path.BoardError("board_copy_conflict", {
|
|
231
|
-
workspaceId,
|
|
232
|
-
conflicts
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* The same cards, ordered so that a parent is always written before its
|
|
237
|
-
* children. The column is a foreign key onto the same table, so any other order
|
|
238
|
-
* writes a card pointing at one that is not there yet.
|
|
239
|
-
*/
|
|
240
|
-
function orderParentsFirst(issues) {
|
|
241
|
-
const byId = new Map(issues.map((issue) => [issue.id, issue]));
|
|
242
|
-
const ordered = [];
|
|
243
|
-
const placed = /* @__PURE__ */ new Set();
|
|
244
|
-
function place(issue, ancestors) {
|
|
245
|
-
if (placed.has(issue.id) || ancestors.has(issue.id)) return;
|
|
246
|
-
ancestors.add(issue.id);
|
|
247
|
-
const parent = issue.parentIssueId === null ? void 0 : byId.get(issue.parentIssueId);
|
|
248
|
-
if (parent) place(parent, ancestors);
|
|
249
|
-
placed.add(issue.id);
|
|
250
|
-
ordered.push(issue);
|
|
251
|
-
}
|
|
252
|
-
for (const issue of issues) place(issue, /* @__PURE__ */ new Set());
|
|
253
|
-
return ordered;
|
|
254
|
-
}
|
|
255
|
-
//#endregion
|
|
256
4
|
exports.BINDING_FILE_PATH = require_manifest.BINDING_FILE_PATH;
|
|
257
5
|
exports.BOARD_ACTOR = require_manifest.BOARD_ACTOR;
|
|
258
6
|
exports.BOARD_ERROR_RESPONSES = require_manifest.BOARD_ERROR_RESPONSES;
|
|
@@ -274,9 +22,7 @@ exports.cardDisplayTitle = require_manifest.cardDisplayTitle;
|
|
|
274
22
|
exports.commentAuthorReference = require_manifest.commentAuthorReference;
|
|
275
23
|
exports.createBoardOps = require_manifest.createBoardOps;
|
|
276
24
|
exports.currentUnixSeconds = require_manifest.currentUnixSeconds;
|
|
277
|
-
exports.deleteBoardSlice = deleteBoardSlice;
|
|
278
25
|
exports.diffFieldChanges = require_manifest.diffFieldChanges;
|
|
279
|
-
exports.emptyCopyCounts = emptyCopyCounts;
|
|
280
26
|
exports.evaluateEntryRules = require_manifest.evaluateEntryRules;
|
|
281
27
|
exports.formatActivityIssueReference = require_manifest.formatActivityIssueReference;
|
|
282
28
|
exports.formatExternalSessionRef = require_manifest.formatExternalSessionRef;
|
|
@@ -296,7 +42,6 @@ exports.parseActivityStringArray = require_manifest.parseActivityStringArray;
|
|
|
296
42
|
exports.parseExternalSessionRef = require_manifest.parseExternalSessionRef;
|
|
297
43
|
exports.pullRequestFactKeys = require_manifest.pullRequestFactKeys;
|
|
298
44
|
exports.readBinding = require_manifest.readBinding;
|
|
299
|
-
exports.readBoardSlice = readBoardSlice;
|
|
300
45
|
exports.readChangeSeq = require_manifest.readChangeSeq;
|
|
301
46
|
exports.readChecklist = require_manifest.readChecklist;
|
|
302
47
|
exports.readEntryRules = require_manifest.readEntryRules;
|
|
@@ -308,6 +53,3 @@ exports.runBoardWrite = require_manifest.runBoardWrite;
|
|
|
308
53
|
exports.serializeEntryRules = require_manifest.serializeEntryRules;
|
|
309
54
|
exports.toIssueView = require_manifest.toIssueView;
|
|
310
55
|
exports.writeBinding = require_manifest.writeBinding;
|
|
311
|
-
exports.writeBoardSlice = writeBoardSlice;
|
|
312
|
-
|
|
313
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/lib/index.d.cts
CHANGED
|
@@ -383,20 +383,8 @@ export declare function maskDatabaseUrls(text: string): string;
|
|
|
383
383
|
* this list: what each code is over HTTP is `BOARD_ERROR_RESPONSES`
|
|
384
384
|
* (`../serve/board-error-responses.ts`), the one table `kanbo serve` and any app
|
|
385
385
|
* serving the board over HTTP answer with.
|
|
386
|
-
*
|
|
387
|
-
* Five of them are about where a board lives rather than about what is on it,
|
|
388
|
-
* and they are named here for the same reason as the rest: a host that keeps
|
|
389
|
-
* one board in a file and another in a database still answers its callers in
|
|
390
|
-
* one vocabulary. `board_storage_not_prepared` is a connection string pointing
|
|
391
|
-
* at a database that holds no board this build can speak for,
|
|
392
|
-
* `board_storage_unavailable` is one the host could not reach at all,
|
|
393
|
-
* `board_storage_not_configured` is a workspace that names no board to look at,
|
|
394
|
-
* `board_storage_not_empty` is a board still holding cards when something asked
|
|
395
|
-
* to point the workspace somewhere else, and `board_mixed_workspaces` is a
|
|
396
|
-
* single operation naming cards that turned out to live in two different
|
|
397
|
-
* boards — which no transaction can commit as one.
|
|
398
386
|
*/
|
|
399
|
-
type BoardErrorCode = 'board_approval_requires_user' | 'board_column_rules_requires_user' | 'board_column_rules_unmet' | '
|
|
387
|
+
type BoardErrorCode = 'board_approval_requires_user' | 'board_column_rules_requires_user' | 'board_column_rules_unmet' | 'board_entry_rule_invalid' | 'board_execution_mode_locked' | 'board_pull_request_invalid' | 'board_pull_request_not_found' | 'board_pull_request_not_yours' | 'board_return_no_previous_column' | 'board_return_requires_user' | 'board_run_already_finished' | 'board_run_not_found' | 'board_run_session_ref_conflict' | 'board_run_session_ref_invalid' | 'board_run_session_ref_requires_user' | 'board_schema_outdated' | 'board_sprint_carry_invalid' | 'board_sprint_close_requires_user' | 'board_sprint_dates_invalid' | 'issue_comment_delete_requires_user' | 'issue_comment_not_found' | 'issue_context_ref_invalid_index' | 'issue_milestone_not_found' | 'issue_not_found' | 'issue_parent_not_found' | 'issue_parent_self_reference' | 'issue_relation_not_found' | 'issue_relation_self_reference' | 'issue_status_name_empty' | 'issue_status_not_found' | 'issue_status_reference_conflict' | 'issue_workspace_not_found';
|
|
400
388
|
/** A board rule the caller broke, carrying the offending values in `details`. */
|
|
401
389
|
export declare class BoardError extends Error {
|
|
402
390
|
readonly code: BoardErrorCode;
|
|
@@ -1174,6 +1162,19 @@ export declare function createBoardOps<TStore extends BoardStore>(store: TStore)
|
|
|
1174
1162
|
card: Issue;
|
|
1175
1163
|
stoppedRunIds: string[];
|
|
1176
1164
|
}>;
|
|
1165
|
+
assertReturnable: (issueId: string, input: {
|
|
1166
|
+
toStatusName?: string | null;
|
|
1167
|
+
}, actor: BoardActor) => Promise<{
|
|
1168
|
+
category: "backlog" | "canceled" | "completed" | "started" | "triage" | "unstarted";
|
|
1169
|
+
color: string | null;
|
|
1170
|
+
createdAt: number;
|
|
1171
|
+
description: string | null;
|
|
1172
|
+
entryRules: string | null;
|
|
1173
|
+
id: string;
|
|
1174
|
+
name: string;
|
|
1175
|
+
order: number;
|
|
1176
|
+
workspaceId: string;
|
|
1177
|
+
}>;
|
|
1177
1178
|
readApproval: (issueId: string) => Promise<BoardApproval>;
|
|
1178
1179
|
linkPullRequest: (issueId: string, urlOrRef: string, actor: BoardActor, scope?: BoardWriteScope<TStore>) => Promise<{
|
|
1179
1180
|
createdAt: number;
|
|
@@ -1490,72 +1491,6 @@ export declare function createBoardOps<TStore extends BoardStore>(store: TStore)
|
|
|
1490
1491
|
/** The board's operations, as a type callers can name. */
|
|
1491
1492
|
type BoardOps = ReturnType<typeof createBoardOps<BoardStore>>;
|
|
1492
1493
|
//#endregion
|
|
1493
|
-
//#region src/ops/board-copy.d.ts
|
|
1494
|
-
/** How many rows of each kind a copy wrote into the target board. */
|
|
1495
|
-
interface BoardCopyCounts {
|
|
1496
|
-
statuses: number;
|
|
1497
|
-
milestones: number;
|
|
1498
|
-
issues: number;
|
|
1499
|
-
comments: number;
|
|
1500
|
-
runs: number;
|
|
1501
|
-
relations: number;
|
|
1502
|
-
fieldChanges: number;
|
|
1503
|
-
/** Cards that carried refs, not rows: context refs are a column on the card. */
|
|
1504
|
-
contextRefs: number;
|
|
1505
|
-
pullRequests: number;
|
|
1506
|
-
}
|
|
1507
|
-
/** Everything one workspace has on a board, read before anything is written. */
|
|
1508
|
-
interface BoardSlice {
|
|
1509
|
-
statuses: IssueStatus[];
|
|
1510
|
-
milestones: IssueMilestone[];
|
|
1511
|
-
/** In an order where a card's parent always comes before it. */
|
|
1512
|
-
issues: Issue[];
|
|
1513
|
-
comments: IssueComment[];
|
|
1514
|
-
runs: IssueRun[];
|
|
1515
|
-
relations: IssueRelation[];
|
|
1516
|
-
fieldChanges: IssueFieldChange[];
|
|
1517
|
-
pullRequests: IssuePullRequest[];
|
|
1518
|
-
/** What reading it had to leave behind, said to a person. */
|
|
1519
|
-
warnings: string[];
|
|
1520
|
-
}
|
|
1521
|
-
/** Nothing copied — what a move that had nothing to move reports. */
|
|
1522
|
-
export declare function emptyCopyCounts(): BoardCopyCounts;
|
|
1523
|
-
/**
|
|
1524
|
-
* Everything the workspace has on this board, read in one pass before a single
|
|
1525
|
-
* row is written anywhere.
|
|
1526
|
-
*
|
|
1527
|
-
* Links are collected by id because an edge is listed by both of the cards it
|
|
1528
|
-
* touches, and one reaching a card outside this workspace is left behind rather
|
|
1529
|
-
* than copied: the target holds this workspace's board and nothing else, so the
|
|
1530
|
-
* far end of that edge is not there to point at.
|
|
1531
|
-
*/
|
|
1532
|
-
export declare function readBoardSlice(from: BoardStore, workspaceId: string): Promise<BoardSlice>;
|
|
1533
|
-
/**
|
|
1534
|
-
* Write a slice into the target board, in one transaction, and say what was
|
|
1535
|
-
* written and what a person should know about it — the slice's own warnings
|
|
1536
|
-
* first.
|
|
1537
|
-
*
|
|
1538
|
-
* It is idempotent by id. A row the target already has is left exactly as it
|
|
1539
|
-
* is and counted as already present, so a copy interrupted half-way is finished
|
|
1540
|
-
* by running it again, and a second run of a finished one copies nothing. A
|
|
1541
|
-
* clash that is not the same row — a column name or a card number the target
|
|
1542
|
-
* holds under another id — refuses the whole copy before its first insert
|
|
1543
|
-
* (`board_copy_conflict`, ruling 3-55).
|
|
1544
|
-
*/
|
|
1545
|
-
export declare function writeBoardSlice(to: BoardStore, slice: BoardSlice, workspaceId: string): Promise<{
|
|
1546
|
-
copied: BoardCopyCounts;
|
|
1547
|
-
warnings: string[];
|
|
1548
|
-
}>;
|
|
1549
|
-
/**
|
|
1550
|
-
* Empty the slice off the board it was read from, in a transaction of its own.
|
|
1551
|
-
*
|
|
1552
|
-
* Only the cards, the columns and the milestones are named: comments, runs,
|
|
1553
|
-
* links, pull request links and the field-change history hang off a card by a
|
|
1554
|
-
* foreign key that cascades on both engines, so deleting the card takes them
|
|
1555
|
-
* with it.
|
|
1556
|
-
*/
|
|
1557
|
-
export declare function deleteBoardSlice(from: BoardStore, slice: BoardSlice): Promise<void>;
|
|
1558
|
-
//#endregion
|
|
1559
1494
|
//#region src/serve/board-error-responses.d.ts
|
|
1560
1495
|
/** What one board failure is over HTTP: the status, the sentence, and the code a client matches on when it is renamed. */
|
|
1561
1496
|
interface BoardErrorResponse {
|
|
@@ -1582,21 +1517,6 @@ interface BoardErrorResponse {
|
|
|
1582
1517
|
* reason turned around: the answer will be yes once the card meets them, and
|
|
1583
1518
|
* `details.unmet` says what is missing.
|
|
1584
1519
|
*
|
|
1585
|
-
* The five failures about where a board is kept read the same rule. A database
|
|
1586
|
-
* that holds no board this build can speak for is 409 — the setting is there,
|
|
1587
|
-
* the board behind it is not yet, and `board-storage prepare` is what settles
|
|
1588
|
-
* that — and one nobody could reach at all is 503, because nothing about the
|
|
1589
|
-
* request was wrong. A workspace naming no board at all is 404: the caller
|
|
1590
|
-
* asked about a setting that is not there. A board still holding cards when
|
|
1591
|
-
* somebody asks to point the workspace elsewhere is 409, because the answer
|
|
1592
|
-
* would have been yes on an empty board and `board-storage migrate` is what
|
|
1593
|
-
* makes it one. An operation naming cards from two different boards is 400: no
|
|
1594
|
-
* transaction reaches both, so the caller asked for something that cannot be
|
|
1595
|
-
* done. A copy that would land on a card number or a column name the target
|
|
1596
|
-
* already holds under a different id is 409 for the same reason the others
|
|
1597
|
-
* are: the answer would have been yes on a target that did not hold that
|
|
1598
|
-
* board, and `details.conflicts` names every value that clashed.
|
|
1599
|
-
*
|
|
1600
1520
|
* A failure may also be renamed here: the package names its codes after the
|
|
1601
1521
|
* board, while every error the `/issues` routes answer with is named after the
|
|
1602
1522
|
* issue, and a client matching on `issue_*` should not have to learn a second
|
|
@@ -1604,5 +1524,5 @@ interface BoardErrorResponse {
|
|
|
1604
1524
|
*/
|
|
1605
1525
|
export declare const BOARD_ERROR_RESPONSES: Record<BoardErrorCode, BoardErrorResponse>;
|
|
1606
1526
|
//#endregion
|
|
1607
|
-
export { type AddCommentInput, type AttachRunExecutionInput, type BoardActiveRun, type BoardActor, type BoardApproval, type BoardCardWrite, type BoardColumnInput, type BoardColumnPatch, type
|
|
1527
|
+
export { type AddCommentInput, type AttachRunExecutionInput, type BoardActiveRun, type BoardActor, type BoardApproval, type BoardCardWrite, type BoardColumnInput, type BoardColumnPatch, type BoardErrorCode, type BoardErrorResponse, type BoardLinkedPullRequest, type BoardOps, type BoardPullRequestStanding, type BoardRunProjection, type BoardRunProjectionScope, type BoardRunView, type BoardSprint, type BoardStore, type BoardTransactionMode, type BoardWorkspaceIdentity, type BoardWriteScope, type BulkUpdateCardsInput, type BulkUpdateCardsResult, type CloseSprintResult, type CreateCardInput, type CreateCommentOnceInput, type CreateMilestoneInput, type CreateRelationInput, ENTRY_RULES, ENTRY_RULE_DESCRIPTIONS, type EntryRule, type EntryRuleFacts, type ExternalSessionRef, type FinishRunInput, type Issue, type IssueActivityAction, type IssueActivityCommentView, type IssueActivityField, type IssueActivityFieldChangeView, type IssueActivityItemView, type IssueActivityLookup, type IssueActivityResolver, type IssueActivityValueToken, type IssueActivityValueView, type IssueActorKind, type IssueActorReference, type IssueComment, type IssueCommentAuthorView, type IssueCommentStore, type IssueContextRefStore, type IssueFieldChange, type IssueFieldChangeStore, type IssueMilestone, type IssueMilestoneStore, type IssueMutationActor, type IssuePullRequest, type IssuePullRequestStore, type IssueRelation, type IssueRelationCounterpart, type IssueRelationStore, type IssueRelationView, type IssueRowStore, type IssueRun, type IssueRunStore, type IssueStatus, type IssueStatusStore, type IssueView, KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, type KanbanMeta, type KanbanMetaStore, type KanboBinding, type KanboCapabilities, type KanboCapabilitiesPackage, type KanboCapabilitiesRoles, type KanboCapabilityCommand, type KanboCapabilityCommandArgument, type KanboCapabilityCommandOption, type KanboCapabilityEntryRule, type KanboCapabilityStorage, type KanboCapabilityTool, type KanboToolCliEquivalent, type KanboToolName, type MigrateCardsInput, type MigrateCardsResult, type PullRequestFactKeys, type StartRunInput, UNMET_ENTRY_RULE_REASONS, type UnmetEntryRule, type UpdateCardInput, type UpdateMilestoneInput, evaluateEntryRules, readChecklist, readEntryRules, serializeEntryRules };
|
|
1608
1528
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/lib/index.d.mts
CHANGED
|
@@ -383,20 +383,8 @@ export declare function maskDatabaseUrls(text: string): string;
|
|
|
383
383
|
* this list: what each code is over HTTP is `BOARD_ERROR_RESPONSES`
|
|
384
384
|
* (`../serve/board-error-responses.ts`), the one table `kanbo serve` and any app
|
|
385
385
|
* serving the board over HTTP answer with.
|
|
386
|
-
*
|
|
387
|
-
* Five of them are about where a board lives rather than about what is on it,
|
|
388
|
-
* and they are named here for the same reason as the rest: a host that keeps
|
|
389
|
-
* one board in a file and another in a database still answers its callers in
|
|
390
|
-
* one vocabulary. `board_storage_not_prepared` is a connection string pointing
|
|
391
|
-
* at a database that holds no board this build can speak for,
|
|
392
|
-
* `board_storage_unavailable` is one the host could not reach at all,
|
|
393
|
-
* `board_storage_not_configured` is a workspace that names no board to look at,
|
|
394
|
-
* `board_storage_not_empty` is a board still holding cards when something asked
|
|
395
|
-
* to point the workspace somewhere else, and `board_mixed_workspaces` is a
|
|
396
|
-
* single operation naming cards that turned out to live in two different
|
|
397
|
-
* boards — which no transaction can commit as one.
|
|
398
386
|
*/
|
|
399
|
-
type BoardErrorCode = 'board_approval_requires_user' | 'board_column_rules_requires_user' | 'board_column_rules_unmet' | '
|
|
387
|
+
type BoardErrorCode = 'board_approval_requires_user' | 'board_column_rules_requires_user' | 'board_column_rules_unmet' | 'board_entry_rule_invalid' | 'board_execution_mode_locked' | 'board_pull_request_invalid' | 'board_pull_request_not_found' | 'board_pull_request_not_yours' | 'board_return_no_previous_column' | 'board_return_requires_user' | 'board_run_already_finished' | 'board_run_not_found' | 'board_run_session_ref_conflict' | 'board_run_session_ref_invalid' | 'board_run_session_ref_requires_user' | 'board_schema_outdated' | 'board_sprint_carry_invalid' | 'board_sprint_close_requires_user' | 'board_sprint_dates_invalid' | 'issue_comment_delete_requires_user' | 'issue_comment_not_found' | 'issue_context_ref_invalid_index' | 'issue_milestone_not_found' | 'issue_not_found' | 'issue_parent_not_found' | 'issue_parent_self_reference' | 'issue_relation_not_found' | 'issue_relation_self_reference' | 'issue_status_name_empty' | 'issue_status_not_found' | 'issue_status_reference_conflict' | 'issue_workspace_not_found';
|
|
400
388
|
/** A board rule the caller broke, carrying the offending values in `details`. */
|
|
401
389
|
export declare class BoardError extends Error {
|
|
402
390
|
readonly code: BoardErrorCode;
|
|
@@ -1174,6 +1162,19 @@ export declare function createBoardOps<TStore extends BoardStore>(store: TStore)
|
|
|
1174
1162
|
card: Issue;
|
|
1175
1163
|
stoppedRunIds: string[];
|
|
1176
1164
|
}>;
|
|
1165
|
+
assertReturnable: (issueId: string, input: {
|
|
1166
|
+
toStatusName?: string | null;
|
|
1167
|
+
}, actor: BoardActor) => Promise<{
|
|
1168
|
+
category: "backlog" | "canceled" | "completed" | "started" | "triage" | "unstarted";
|
|
1169
|
+
color: string | null;
|
|
1170
|
+
createdAt: number;
|
|
1171
|
+
description: string | null;
|
|
1172
|
+
entryRules: string | null;
|
|
1173
|
+
id: string;
|
|
1174
|
+
name: string;
|
|
1175
|
+
order: number;
|
|
1176
|
+
workspaceId: string;
|
|
1177
|
+
}>;
|
|
1177
1178
|
readApproval: (issueId: string) => Promise<BoardApproval>;
|
|
1178
1179
|
linkPullRequest: (issueId: string, urlOrRef: string, actor: BoardActor, scope?: BoardWriteScope<TStore>) => Promise<{
|
|
1179
1180
|
createdAt: number;
|
|
@@ -1490,72 +1491,6 @@ export declare function createBoardOps<TStore extends BoardStore>(store: TStore)
|
|
|
1490
1491
|
/** The board's operations, as a type callers can name. */
|
|
1491
1492
|
type BoardOps = ReturnType<typeof createBoardOps<BoardStore>>;
|
|
1492
1493
|
//#endregion
|
|
1493
|
-
//#region src/ops/board-copy.d.ts
|
|
1494
|
-
/** How many rows of each kind a copy wrote into the target board. */
|
|
1495
|
-
interface BoardCopyCounts {
|
|
1496
|
-
statuses: number;
|
|
1497
|
-
milestones: number;
|
|
1498
|
-
issues: number;
|
|
1499
|
-
comments: number;
|
|
1500
|
-
runs: number;
|
|
1501
|
-
relations: number;
|
|
1502
|
-
fieldChanges: number;
|
|
1503
|
-
/** Cards that carried refs, not rows: context refs are a column on the card. */
|
|
1504
|
-
contextRefs: number;
|
|
1505
|
-
pullRequests: number;
|
|
1506
|
-
}
|
|
1507
|
-
/** Everything one workspace has on a board, read before anything is written. */
|
|
1508
|
-
interface BoardSlice {
|
|
1509
|
-
statuses: IssueStatus[];
|
|
1510
|
-
milestones: IssueMilestone[];
|
|
1511
|
-
/** In an order where a card's parent always comes before it. */
|
|
1512
|
-
issues: Issue[];
|
|
1513
|
-
comments: IssueComment[];
|
|
1514
|
-
runs: IssueRun[];
|
|
1515
|
-
relations: IssueRelation[];
|
|
1516
|
-
fieldChanges: IssueFieldChange[];
|
|
1517
|
-
pullRequests: IssuePullRequest[];
|
|
1518
|
-
/** What reading it had to leave behind, said to a person. */
|
|
1519
|
-
warnings: string[];
|
|
1520
|
-
}
|
|
1521
|
-
/** Nothing copied — what a move that had nothing to move reports. */
|
|
1522
|
-
export declare function emptyCopyCounts(): BoardCopyCounts;
|
|
1523
|
-
/**
|
|
1524
|
-
* Everything the workspace has on this board, read in one pass before a single
|
|
1525
|
-
* row is written anywhere.
|
|
1526
|
-
*
|
|
1527
|
-
* Links are collected by id because an edge is listed by both of the cards it
|
|
1528
|
-
* touches, and one reaching a card outside this workspace is left behind rather
|
|
1529
|
-
* than copied: the target holds this workspace's board and nothing else, so the
|
|
1530
|
-
* far end of that edge is not there to point at.
|
|
1531
|
-
*/
|
|
1532
|
-
export declare function readBoardSlice(from: BoardStore, workspaceId: string): Promise<BoardSlice>;
|
|
1533
|
-
/**
|
|
1534
|
-
* Write a slice into the target board, in one transaction, and say what was
|
|
1535
|
-
* written and what a person should know about it — the slice's own warnings
|
|
1536
|
-
* first.
|
|
1537
|
-
*
|
|
1538
|
-
* It is idempotent by id. A row the target already has is left exactly as it
|
|
1539
|
-
* is and counted as already present, so a copy interrupted half-way is finished
|
|
1540
|
-
* by running it again, and a second run of a finished one copies nothing. A
|
|
1541
|
-
* clash that is not the same row — a column name or a card number the target
|
|
1542
|
-
* holds under another id — refuses the whole copy before its first insert
|
|
1543
|
-
* (`board_copy_conflict`, ruling 3-55).
|
|
1544
|
-
*/
|
|
1545
|
-
export declare function writeBoardSlice(to: BoardStore, slice: BoardSlice, workspaceId: string): Promise<{
|
|
1546
|
-
copied: BoardCopyCounts;
|
|
1547
|
-
warnings: string[];
|
|
1548
|
-
}>;
|
|
1549
|
-
/**
|
|
1550
|
-
* Empty the slice off the board it was read from, in a transaction of its own.
|
|
1551
|
-
*
|
|
1552
|
-
* Only the cards, the columns and the milestones are named: comments, runs,
|
|
1553
|
-
* links, pull request links and the field-change history hang off a card by a
|
|
1554
|
-
* foreign key that cascades on both engines, so deleting the card takes them
|
|
1555
|
-
* with it.
|
|
1556
|
-
*/
|
|
1557
|
-
export declare function deleteBoardSlice(from: BoardStore, slice: BoardSlice): Promise<void>;
|
|
1558
|
-
//#endregion
|
|
1559
1494
|
//#region src/serve/board-error-responses.d.ts
|
|
1560
1495
|
/** What one board failure is over HTTP: the status, the sentence, and the code a client matches on when it is renamed. */
|
|
1561
1496
|
interface BoardErrorResponse {
|
|
@@ -1582,21 +1517,6 @@ interface BoardErrorResponse {
|
|
|
1582
1517
|
* reason turned around: the answer will be yes once the card meets them, and
|
|
1583
1518
|
* `details.unmet` says what is missing.
|
|
1584
1519
|
*
|
|
1585
|
-
* The five failures about where a board is kept read the same rule. A database
|
|
1586
|
-
* that holds no board this build can speak for is 409 — the setting is there,
|
|
1587
|
-
* the board behind it is not yet, and `board-storage prepare` is what settles
|
|
1588
|
-
* that — and one nobody could reach at all is 503, because nothing about the
|
|
1589
|
-
* request was wrong. A workspace naming no board at all is 404: the caller
|
|
1590
|
-
* asked about a setting that is not there. A board still holding cards when
|
|
1591
|
-
* somebody asks to point the workspace elsewhere is 409, because the answer
|
|
1592
|
-
* would have been yes on an empty board and `board-storage migrate` is what
|
|
1593
|
-
* makes it one. An operation naming cards from two different boards is 400: no
|
|
1594
|
-
* transaction reaches both, so the caller asked for something that cannot be
|
|
1595
|
-
* done. A copy that would land on a card number or a column name the target
|
|
1596
|
-
* already holds under a different id is 409 for the same reason the others
|
|
1597
|
-
* are: the answer would have been yes on a target that did not hold that
|
|
1598
|
-
* board, and `details.conflicts` names every value that clashed.
|
|
1599
|
-
*
|
|
1600
1520
|
* A failure may also be renamed here: the package names its codes after the
|
|
1601
1521
|
* board, while every error the `/issues` routes answer with is named after the
|
|
1602
1522
|
* issue, and a client matching on `issue_*` should not have to learn a second
|
|
@@ -1604,5 +1524,5 @@ interface BoardErrorResponse {
|
|
|
1604
1524
|
*/
|
|
1605
1525
|
export declare const BOARD_ERROR_RESPONSES: Record<BoardErrorCode, BoardErrorResponse>;
|
|
1606
1526
|
//#endregion
|
|
1607
|
-
export { type AddCommentInput, type AttachRunExecutionInput, type BoardActiveRun, type BoardActor, type BoardApproval, type BoardCardWrite, type BoardColumnInput, type BoardColumnPatch, type
|
|
1527
|
+
export { type AddCommentInput, type AttachRunExecutionInput, type BoardActiveRun, type BoardActor, type BoardApproval, type BoardCardWrite, type BoardColumnInput, type BoardColumnPatch, type BoardErrorCode, type BoardErrorResponse, type BoardLinkedPullRequest, type BoardOps, type BoardPullRequestStanding, type BoardRunProjection, type BoardRunProjectionScope, type BoardRunView, type BoardSprint, type BoardStore, type BoardTransactionMode, type BoardWorkspaceIdentity, type BoardWriteScope, type BulkUpdateCardsInput, type BulkUpdateCardsResult, type CloseSprintResult, type CreateCardInput, type CreateCommentOnceInput, type CreateMilestoneInput, type CreateRelationInput, ENTRY_RULES, ENTRY_RULE_DESCRIPTIONS, type EntryRule, type EntryRuleFacts, type ExternalSessionRef, type FinishRunInput, type Issue, type IssueActivityAction, type IssueActivityCommentView, type IssueActivityField, type IssueActivityFieldChangeView, type IssueActivityItemView, type IssueActivityLookup, type IssueActivityResolver, type IssueActivityValueToken, type IssueActivityValueView, type IssueActorKind, type IssueActorReference, type IssueComment, type IssueCommentAuthorView, type IssueCommentStore, type IssueContextRefStore, type IssueFieldChange, type IssueFieldChangeStore, type IssueMilestone, type IssueMilestoneStore, type IssueMutationActor, type IssuePullRequest, type IssuePullRequestStore, type IssueRelation, type IssueRelationCounterpart, type IssueRelationStore, type IssueRelationView, type IssueRowStore, type IssueRun, type IssueRunStore, type IssueStatus, type IssueStatusStore, type IssueView, KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, type KanbanMeta, type KanbanMetaStore, type KanboBinding, type KanboCapabilities, type KanboCapabilitiesPackage, type KanboCapabilitiesRoles, type KanboCapabilityCommand, type KanboCapabilityCommandArgument, type KanboCapabilityCommandOption, type KanboCapabilityEntryRule, type KanboCapabilityStorage, type KanboCapabilityTool, type KanboToolCliEquivalent, type KanboToolName, type MigrateCardsInput, type MigrateCardsResult, type PullRequestFactKeys, type StartRunInput, UNMET_ENTRY_RULE_REASONS, type UnmetEntryRule, type UpdateCardInput, type UpdateMilestoneInput, evaluateEntryRules, readChecklist, readEntryRules, serializeEntryRules };
|
|
1608
1528
|
//# sourceMappingURL=index.d.mts.map
|