@islamihab/kds 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +219 -25
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -14450,7 +14450,12 @@ var isHidden = (field) => field.meta()?.hidden === true;
|
|
|
14450
14450
|
var isNegatable = (field) => field.meta()?.negatable === true;
|
|
14451
14451
|
var isHelpFlag = (arg) => arg === "-h" || arg === "--help";
|
|
14452
14452
|
var valuePlaceholder = (field) => {
|
|
14453
|
-
|
|
14453
|
+
let base = baseType(field);
|
|
14454
|
+
if (base instanceof exports_external.ZodArray) {
|
|
14455
|
+
const element = base.element;
|
|
14456
|
+
if (element instanceof exports_external.ZodType)
|
|
14457
|
+
base = element;
|
|
14458
|
+
}
|
|
14454
14459
|
if (base instanceof exports_external.ZodBoolean)
|
|
14455
14460
|
return "";
|
|
14456
14461
|
if (base instanceof exports_external.ZodEnum)
|
|
@@ -14496,8 +14501,10 @@ var parseArgs = ({
|
|
|
14496
14501
|
}) => {
|
|
14497
14502
|
const options = {};
|
|
14498
14503
|
for (const { key, field, short, negatedKey } of optionsEntries) {
|
|
14499
|
-
const
|
|
14500
|
-
|
|
14504
|
+
const base = baseType(field);
|
|
14505
|
+
const type = base instanceof exports_external.ZodBoolean ? "boolean" : "string";
|
|
14506
|
+
const multiple = base instanceof exports_external.ZodArray ? true : undefined;
|
|
14507
|
+
options[key] = short ? { short, type, multiple } : { type, multiple };
|
|
14501
14508
|
if (negatedKey)
|
|
14502
14509
|
options[negatedKey] = { type: "boolean" };
|
|
14503
14510
|
}
|
|
@@ -14587,7 +14594,7 @@ import { join } from "path";
|
|
|
14587
14594
|
// package.json
|
|
14588
14595
|
var package_default = {
|
|
14589
14596
|
name: "cli",
|
|
14590
|
-
version: "0.2.
|
|
14597
|
+
version: "0.2.1",
|
|
14591
14598
|
private: true,
|
|
14592
14599
|
type: "module",
|
|
14593
14600
|
bin: {
|
|
@@ -15159,10 +15166,12 @@ var ISSUE_CREATE_DISPOSITIONS = [
|
|
|
15159
15166
|
];
|
|
15160
15167
|
var ISSUE_ESTIMATES = [1, 2, 3, 5, 8];
|
|
15161
15168
|
var ISSUE_TERMINAL_STATUSES = ["done", "canceled"];
|
|
15169
|
+
var ISSUE_RELATION_KINDS = ["blocks", "blocked_by", "duplicate_of", "duplicated_by", "relates_to"];
|
|
15162
15170
|
var PROJECT_STATUSES = ["planned", "in_progress", "paused", "completed", "canceled"];
|
|
15163
15171
|
var PROJECT_HEALTHS = ["on_track", "at_risk", "off_track"];
|
|
15164
15172
|
var ISSUE_IDENTIFIER_PREFIX = "KAI";
|
|
15165
15173
|
var ISSUE_LIST_PAGE_SIZE = 50;
|
|
15174
|
+
var MAX_ISSUE_ATTACHMENT_BYTES = 1e7;
|
|
15166
15175
|
var ISSUE_DUE_DATE_MODES = ["overdue", "due_today", "due_soon", "no_due_date"];
|
|
15167
15176
|
var issueIsOpen = (status) => !ISSUE_TERMINAL_STATUSES.some((terminal) => terminal === status);
|
|
15168
15177
|
var MAX_PROJECT_REPO_LENGTH = 200;
|
|
@@ -17814,6 +17823,59 @@ var auth = group({
|
|
|
17814
17823
|
commands: [login, logout, status]
|
|
17815
17824
|
});
|
|
17816
17825
|
|
|
17826
|
+
// src/lib/attachments.ts
|
|
17827
|
+
import { basename } from "path";
|
|
17828
|
+
var attachFiles = async (client3, issueId, paths) => {
|
|
17829
|
+
if (paths.length === 0)
|
|
17830
|
+
return [];
|
|
17831
|
+
const files = paths.map((path) => ({ path, file: Bun.file(path) }));
|
|
17832
|
+
for (const { path, file: file2 } of files) {
|
|
17833
|
+
if (!await file2.exists())
|
|
17834
|
+
throw new Error(`No file at ${path}.`);
|
|
17835
|
+
if (file2.size <= 0)
|
|
17836
|
+
throw new Error(`${path} is empty; an attachment cannot be.`);
|
|
17837
|
+
if (file2.size > MAX_ISSUE_ATTACHMENT_BYTES) {
|
|
17838
|
+
throw new Error(`${path} is too large (${file2.size} bytes; max ${MAX_ISSUE_ATTACHMENT_BYTES}).`);
|
|
17839
|
+
}
|
|
17840
|
+
}
|
|
17841
|
+
const created = new Set;
|
|
17842
|
+
try {
|
|
17843
|
+
for (const { path, file: file2 } of files) {
|
|
17844
|
+
const uploadUrl = await client3.mutation(api2.issueAttachments.generateUploadUrl, { issueId });
|
|
17845
|
+
const response = await fetch(uploadUrl, {
|
|
17846
|
+
method: "POST",
|
|
17847
|
+
headers: { "Content-Type": file2.type },
|
|
17848
|
+
body: file2
|
|
17849
|
+
});
|
|
17850
|
+
if (!response.ok)
|
|
17851
|
+
throw new Error(`Uploading ${path} failed (${response.status}).`);
|
|
17852
|
+
const storageId = exports_external.custom((value) => typeof value === "string");
|
|
17853
|
+
const body = exports_external.object({ storageId }).safeParse(await response.json());
|
|
17854
|
+
if (!body.success)
|
|
17855
|
+
throw new Error("The upload returned no file reference.");
|
|
17856
|
+
created.add(await client3.action(api2.issueAttachments.create, {
|
|
17857
|
+
issueId,
|
|
17858
|
+
storageId: body.data.storageId,
|
|
17859
|
+
name: basename(path)
|
|
17860
|
+
}));
|
|
17861
|
+
}
|
|
17862
|
+
} catch (error51) {
|
|
17863
|
+
for (const id of created) {
|
|
17864
|
+
await client3.mutation(api2.issueAttachments.remove, { id }).catch(() => {
|
|
17865
|
+
console.error("An attachment from this failed batch could not be removed; check the dashboard.");
|
|
17866
|
+
});
|
|
17867
|
+
}
|
|
17868
|
+
throw error51;
|
|
17869
|
+
}
|
|
17870
|
+
const attachments = await client3.query(api2.issueAttachments.list, { issueId });
|
|
17871
|
+
return attachments.filter((attachment) => created.has(attachment._id));
|
|
17872
|
+
};
|
|
17873
|
+
var printAttachments = (attachments) => {
|
|
17874
|
+
for (const attachment of attachments) {
|
|
17875
|
+
console.log(`Attached ${attachment.name}${attachment.url ? ` \u2014 ${attachment.url}` : ""}`);
|
|
17876
|
+
}
|
|
17877
|
+
};
|
|
17878
|
+
|
|
17817
17879
|
// src/lib/input.ts
|
|
17818
17880
|
var assertSize = (size) => {
|
|
17819
17881
|
if (size > MAX_PAGE_HTML_BYTES)
|
|
@@ -17924,6 +17986,20 @@ var repoProject = async (client3) => {
|
|
|
17924
17986
|
throw new Error(`No project is connected to ${repo}. Connect one on the project in the dashboard.`);
|
|
17925
17987
|
return project;
|
|
17926
17988
|
};
|
|
17989
|
+
var resolveIssueLabels = async (client3, names) => {
|
|
17990
|
+
if (names.length === 0)
|
|
17991
|
+
return [];
|
|
17992
|
+
const labels = await client3.query(api2.issueLabels.list, {});
|
|
17993
|
+
return names.map((name) => {
|
|
17994
|
+
const wanted = name.trim().toLowerCase();
|
|
17995
|
+
const label = labels.find((candidate) => candidate.name.toLowerCase() === wanted);
|
|
17996
|
+
if (!label) {
|
|
17997
|
+
const available = labels.map((candidate) => candidate.name).join(", ");
|
|
17998
|
+
throw new Error(available ? `No label named "${name}". The labels are: ${available}.` : "There are no labels yet.");
|
|
17999
|
+
}
|
|
18000
|
+
return label;
|
|
18001
|
+
});
|
|
18002
|
+
};
|
|
17927
18003
|
var resolveMilestone = async (client3, projectId, name) => {
|
|
17928
18004
|
const milestones = await client3.query(api2.milestones.listByProject, { projectId, today: localToday() });
|
|
17929
18005
|
const wanted = name.trim().toLowerCase();
|
|
@@ -17943,9 +18019,13 @@ var comment = command({
|
|
|
17943
18019
|
id: exports_external.string().describe("Issue identifier, number, or URL"),
|
|
17944
18020
|
body: exports_external.string().describe("Comment markdown, or - for stdin")
|
|
17945
18021
|
},
|
|
17946
|
-
|
|
18022
|
+
options: {
|
|
18023
|
+
attach: exports_external.array(exports_external.string()).optional().describe("Attach a file to the issue (repeatable)").meta({ short: "a" })
|
|
18024
|
+
},
|
|
18025
|
+
run: async ({ positionals: { id, body }, options: { attach } }) => {
|
|
17947
18026
|
const client3 = await backendClient();
|
|
17948
18027
|
const issue2 = await resolveIssue(client3, id);
|
|
18028
|
+
printAttachments(await attachFiles(client3, issue2._id, attach ?? []));
|
|
17949
18029
|
await client3.mutation(api2.issueComments.create, { issueId: issue2._id, bodyMarkdown: await readTextOption(body) });
|
|
17950
18030
|
console.log(`Commented on ${issue2.identifier}.`);
|
|
17951
18031
|
}
|
|
@@ -17993,6 +18073,7 @@ var create = command({
|
|
|
17993
18073
|
});
|
|
17994
18074
|
|
|
17995
18075
|
// src/commands/issues/get.ts
|
|
18076
|
+
var SOURCE_LABELS = { github: "GitHub" };
|
|
17996
18077
|
var activityLine = (detail) => {
|
|
17997
18078
|
const label = detail.kind.replaceAll("_", " ");
|
|
17998
18079
|
switch (detail.kind) {
|
|
@@ -18005,6 +18086,8 @@ var activityLine = (detail) => {
|
|
|
18005
18086
|
case "disposition_changed":
|
|
18006
18087
|
case "estimate_changed":
|
|
18007
18088
|
case "due_date_changed":
|
|
18089
|
+
case "branch_changed":
|
|
18090
|
+
case "pr_changed":
|
|
18008
18091
|
case "project_changed":
|
|
18009
18092
|
case "milestone_changed":
|
|
18010
18093
|
case "parent_changed":
|
|
@@ -18034,9 +18117,13 @@ var get = command({
|
|
|
18034
18117
|
run: async ({ positionals: { id }, options: { json: json2 } }) => {
|
|
18035
18118
|
const client3 = await backendClient();
|
|
18036
18119
|
const issue2 = await resolveIssue(client3, id);
|
|
18037
|
-
const feed = await
|
|
18120
|
+
const [feed, relations, attachments] = await Promise.all([
|
|
18121
|
+
client3.query(api2.issues.feed, { id: issue2._id }),
|
|
18122
|
+
client3.query(api2.issues.relations, { id: issue2._id }),
|
|
18123
|
+
client3.query(api2.issueAttachments.list, { issueId: issue2._id })
|
|
18124
|
+
]);
|
|
18038
18125
|
if (json2)
|
|
18039
|
-
return console.log(JSON.stringify({ ...issue2, feed }, null, 2));
|
|
18126
|
+
return console.log(JSON.stringify({ ...issue2, relations, attachments, feed }, null, 2));
|
|
18040
18127
|
const project = issue2.projectId ? await client3.query(api2.projects.get, { id: issue2.projectId, today: localToday() }) : null;
|
|
18041
18128
|
const milestone = issue2.milestoneId ? await client3.query(api2.milestones.get, { id: issue2.milestoneId, today: localToday() }) : null;
|
|
18042
18129
|
console.log(`${issue2.identifier} ${issue2.title}`);
|
|
@@ -18045,6 +18132,10 @@ var get = command({
|
|
|
18045
18132
|
console.log(`Estimate: ${issue2.estimate}`);
|
|
18046
18133
|
if (issue2.dueDate)
|
|
18047
18134
|
console.log(`Due: ${issue2.dueDate}`);
|
|
18135
|
+
if (issue2.branch)
|
|
18136
|
+
console.log(`Branch: ${issue2.branch}`);
|
|
18137
|
+
if (issue2.prUrl)
|
|
18138
|
+
console.log(`PR: ${issue2.prUrl}`);
|
|
18048
18139
|
if (project)
|
|
18049
18140
|
console.log(`Project: ${project.name}${milestone ? ` \xB7 Milestone: ${milestone.name}` : ""}`);
|
|
18050
18141
|
if (issue2.parent)
|
|
@@ -18053,6 +18144,23 @@ var get = command({
|
|
|
18053
18144
|
console.log(`Labels: ${issue2.labels.map((label) => label.name).join(", ")}`);
|
|
18054
18145
|
if (issue2.children.total > 0)
|
|
18055
18146
|
console.log(`Sub-issues: ${issue2.children.done}/${issue2.children.total} done`);
|
|
18147
|
+
const related = (entries) => entries.map((entry) => `${entry.issue.identifier} (${entry.issue.status})`).join(", ");
|
|
18148
|
+
if (relations.blockedBy.length > 0)
|
|
18149
|
+
console.log(`Blocked by: ${related(relations.blockedBy)}`);
|
|
18150
|
+
if (relations.blocks.length > 0)
|
|
18151
|
+
console.log(`Blocks: ${related(relations.blocks)}`);
|
|
18152
|
+
if (relations.duplicateOf)
|
|
18153
|
+
console.log(`Duplicate of: ${related([relations.duplicateOf])}`);
|
|
18154
|
+
if (relations.duplicates.length > 0)
|
|
18155
|
+
console.log(`Duplicated by: ${related(relations.duplicates)}`);
|
|
18156
|
+
if (relations.relatesTo.length > 0)
|
|
18157
|
+
console.log(`Related: ${related(relations.relatesTo)}`);
|
|
18158
|
+
if (attachments.length > 0) {
|
|
18159
|
+
console.log("Attachments:");
|
|
18160
|
+
for (const attachment of attachments) {
|
|
18161
|
+
console.log(` ${attachment.name} \u2014 ${attachment.url ?? "unavailable"}`);
|
|
18162
|
+
}
|
|
18163
|
+
}
|
|
18056
18164
|
if (issue2.descriptionMarkdown)
|
|
18057
18165
|
console.log(`
|
|
18058
18166
|
${issue2.descriptionMarkdown}`);
|
|
@@ -18064,7 +18172,8 @@ Feed:`);
|
|
|
18064
18172
|
for (const event of feed.events) {
|
|
18065
18173
|
const at = new Date(event.at).toISOString().slice(0, 16).replace("T", " ");
|
|
18066
18174
|
if (event.type === "activity") {
|
|
18067
|
-
|
|
18175
|
+
const via = event.via === undefined ? "" : ` (via ${SOURCE_LABELS[event.via]})`;
|
|
18176
|
+
console.log(`${at} ${activityLine(event.detail)}${via}`);
|
|
18068
18177
|
} else {
|
|
18069
18178
|
console.log(`${at} comment${event.editedAt ? " (edited)" : ""}:`);
|
|
18070
18179
|
for (const line of event.bodyMarkdown.split(`
|
|
@@ -18155,6 +18264,24 @@ More issues match; raise --limit past ${options.limit}.`);
|
|
|
18155
18264
|
}
|
|
18156
18265
|
});
|
|
18157
18266
|
|
|
18267
|
+
// src/commands/issues/relate.ts
|
|
18268
|
+
var relate = command({
|
|
18269
|
+
name: "relate",
|
|
18270
|
+
description: "Relate two issues, stated from the first one's side (duplicate_of also cancels it)",
|
|
18271
|
+
positionals: {
|
|
18272
|
+
id: exports_external.string().describe("Issue identifier, number, or URL"),
|
|
18273
|
+
kind: exports_external.enum(ISSUE_RELATION_KINDS).describe(`How the first issue relates to the second (${ISSUE_RELATION_KINDS.join("|")})`),
|
|
18274
|
+
other: exports_external.string().describe("The other issue's identifier, number, or URL")
|
|
18275
|
+
},
|
|
18276
|
+
run: async ({ positionals: { id, kind, other } }) => {
|
|
18277
|
+
const client3 = await backendClient();
|
|
18278
|
+
const issue2 = await resolveIssue(client3, id);
|
|
18279
|
+
const otherIssue = await resolveIssue(client3, other);
|
|
18280
|
+
await client3.mutation(api2.issues.addRelation, { id: issue2._id, kind, otherIssueId: otherIssue._id });
|
|
18281
|
+
console.log(`${issue2.identifier} ${kind.replaceAll("_", " ")} ${otherIssue.identifier}.`);
|
|
18282
|
+
}
|
|
18283
|
+
});
|
|
18284
|
+
|
|
18158
18285
|
// src/commands/issues/remove.ts
|
|
18159
18286
|
var remove = command({
|
|
18160
18287
|
name: "delete",
|
|
@@ -18196,7 +18323,7 @@ var route = command({
|
|
|
18196
18323
|
// src/commands/issues/set.ts
|
|
18197
18324
|
var set2 = command({
|
|
18198
18325
|
name: "set",
|
|
18199
|
-
description: "Set an issue's status, priority, estimate, due date, project, milestone, or
|
|
18326
|
+
description: "Set an issue's status, priority, estimate, due date, project, milestone, parent, or labels",
|
|
18200
18327
|
positionals: {
|
|
18201
18328
|
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18202
18329
|
},
|
|
@@ -18207,12 +18334,14 @@ var set2 = command({
|
|
|
18207
18334
|
due: exports_external.iso.date().nullable().optional().describe("Due date (YYYY-MM-DD), or --no-due to clear").meta({ negatable: true }),
|
|
18208
18335
|
project: exports_external.string().nullable().optional().describe("Move to this project (id or URL), or --no-project to make the issue projectless").meta({ negatable: true }),
|
|
18209
18336
|
milestone: exports_external.string().nullable().optional().describe("Move to this milestone of the issue's project (name), or --no-milestone to clear").meta({ negatable: true }),
|
|
18210
|
-
parent: exports_external.string().nullable().optional().describe("Make this a sub-issue of another issue, or --no-parent to promote it").meta({ negatable: true })
|
|
18337
|
+
parent: exports_external.string().nullable().optional().describe("Make this a sub-issue of another issue, or --no-parent to promote it").meta({ negatable: true }),
|
|
18338
|
+
label: exports_external.array(exports_external.string()).optional().describe("Add a label by name (repeatable)"),
|
|
18339
|
+
"no-label": exports_external.array(exports_external.string()).optional().describe("Remove a label by name (repeatable)")
|
|
18211
18340
|
},
|
|
18212
18341
|
run: async ({ positionals: { id }, options }) => {
|
|
18213
|
-
const { status: status2, priority, estimate, due, project, milestone, parent } = options;
|
|
18342
|
+
const { status: status2, priority, estimate, due, project, milestone, parent, label, "no-label": noLabel } = options;
|
|
18214
18343
|
if (Object.values(options).every((value) => value === undefined))
|
|
18215
|
-
throw new Error("Nothing to set. Pass --status, --priority, --estimate, --due, --project, --milestone, or --
|
|
18344
|
+
throw new Error("Nothing to set. Pass --status, --priority, --estimate, --due, --project, --milestone, --parent, or --label.");
|
|
18216
18345
|
const client3 = await backendClient();
|
|
18217
18346
|
const issue2 = await resolveIssue(client3, id);
|
|
18218
18347
|
const projectId = project === undefined ? issue2.projectId : project === null ? undefined : (await resolveProject(client3, project))._id;
|
|
@@ -18225,8 +18354,14 @@ var set2 = command({
|
|
|
18225
18354
|
milestoneId = (await resolveMilestone(client3, projectId, milestone))._id;
|
|
18226
18355
|
}
|
|
18227
18356
|
const parentId = parent == null ? undefined : (await resolveIssue(client3, parent))._id;
|
|
18357
|
+
const addLabels = await resolveIssueLabels(client3, label ?? []);
|
|
18358
|
+
const removeLabels = await resolveIssueLabels(client3, noLabel ?? []);
|
|
18228
18359
|
if (parent !== undefined)
|
|
18229
18360
|
await client3.mutation(api2.issues.setParent, { id: issue2._id, parentId });
|
|
18361
|
+
for (const { _id } of addLabels)
|
|
18362
|
+
await client3.mutation(api2.issues.addLabel, { issueId: issue2._id, labelId: _id });
|
|
18363
|
+
for (const { _id } of removeLabels)
|
|
18364
|
+
await client3.mutation(api2.issues.removeLabel, { issueId: issue2._id, labelId: _id });
|
|
18230
18365
|
if (status2 !== undefined)
|
|
18231
18366
|
await client3.mutation(api2.issues.setStatus, { id: issue2._id, status: status2 });
|
|
18232
18367
|
if (priority !== undefined)
|
|
@@ -18241,27 +18376,86 @@ var set2 = command({
|
|
|
18241
18376
|
}
|
|
18242
18377
|
});
|
|
18243
18378
|
|
|
18379
|
+
// src/commands/issues/start.ts
|
|
18380
|
+
var shellArg = (value) => /^[\w./-]+$/.test(value) ? value : `'${value.replaceAll("'", `'\\''`)}'`;
|
|
18381
|
+
var start = command({
|
|
18382
|
+
name: "start",
|
|
18383
|
+
description: "Claim an issue: move it to in_progress and record the branch to work under",
|
|
18384
|
+
positionals: {
|
|
18385
|
+
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18386
|
+
},
|
|
18387
|
+
run: async ({ positionals: { id } }) => {
|
|
18388
|
+
const client3 = await backendClient();
|
|
18389
|
+
const issue2 = await resolveIssue(client3, id);
|
|
18390
|
+
const { branch } = await client3.mutation(api2.issues.start, { id: issue2._id });
|
|
18391
|
+
console.log(`Started ${issue2.identifier}: in_progress, branch ${branch}`);
|
|
18392
|
+
console.log(`
|
|
18393
|
+
git switch -c ${shellArg(branch)}`);
|
|
18394
|
+
}
|
|
18395
|
+
});
|
|
18396
|
+
|
|
18397
|
+
// src/commands/issues/unrelate.ts
|
|
18398
|
+
var relationEntries = (relations, kind) => {
|
|
18399
|
+
switch (kind) {
|
|
18400
|
+
case "blocks":
|
|
18401
|
+
return relations.blocks;
|
|
18402
|
+
case "blocked_by":
|
|
18403
|
+
return relations.blockedBy;
|
|
18404
|
+
case "duplicate_of":
|
|
18405
|
+
return relations.duplicateOf ? [relations.duplicateOf] : [];
|
|
18406
|
+
case "duplicated_by":
|
|
18407
|
+
return relations.duplicates;
|
|
18408
|
+
case "relates_to":
|
|
18409
|
+
return relations.relatesTo;
|
|
18410
|
+
}
|
|
18411
|
+
};
|
|
18412
|
+
var unrelate = command({
|
|
18413
|
+
name: "unrelate",
|
|
18414
|
+
description: "Remove a relation between two issues (a canceled duplicate stays canceled)",
|
|
18415
|
+
positionals: {
|
|
18416
|
+
id: exports_external.string().describe("Issue identifier, number, or URL"),
|
|
18417
|
+
kind: exports_external.enum(ISSUE_RELATION_KINDS).describe(`How the first issue relates to the second (${ISSUE_RELATION_KINDS.join("|")})`),
|
|
18418
|
+
other: exports_external.string().describe("The other issue's identifier, number, or URL")
|
|
18419
|
+
},
|
|
18420
|
+
run: async ({ positionals: { id, kind, other } }) => {
|
|
18421
|
+
const client3 = await backendClient();
|
|
18422
|
+
const issue2 = await resolveIssue(client3, id);
|
|
18423
|
+
const otherIssue = await resolveIssue(client3, other);
|
|
18424
|
+
const relations = await client3.query(api2.issues.relations, { id: issue2._id });
|
|
18425
|
+
const relation = relationEntries(relations, kind).find((entry) => entry.issue._id === otherIssue._id);
|
|
18426
|
+
const label = kind.replaceAll("_", " ");
|
|
18427
|
+
if (!relation)
|
|
18428
|
+
throw new Error(`${issue2.identifier} has no "${label}" relation to ${otherIssue.identifier}.`);
|
|
18429
|
+
await client3.mutation(api2.issues.removeRelation, { id: relation._id });
|
|
18430
|
+
console.log(`Removed: ${issue2.identifier} ${label} ${otherIssue.identifier}.`);
|
|
18431
|
+
}
|
|
18432
|
+
});
|
|
18433
|
+
|
|
18244
18434
|
// src/commands/issues/update.ts
|
|
18245
18435
|
var update = command({
|
|
18246
18436
|
name: "update",
|
|
18247
|
-
description: "Rewrite an issue's title or description",
|
|
18437
|
+
description: "Rewrite an issue's title or description, or attach files",
|
|
18248
18438
|
positionals: {
|
|
18249
18439
|
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18250
18440
|
},
|
|
18251
18441
|
options: {
|
|
18252
18442
|
title: exports_external.string().optional().describe("New title").meta({ short: "t" }),
|
|
18253
|
-
description: exports_external.string().optional().describe("New markdown description, or - for stdin").meta({ short: "d" })
|
|
18443
|
+
description: exports_external.string().optional().describe("New markdown description, or - for stdin").meta({ short: "d" }),
|
|
18444
|
+
attach: exports_external.array(exports_external.string()).optional().describe("Attach a file to the issue (repeatable)").meta({ short: "a" })
|
|
18254
18445
|
},
|
|
18255
|
-
run: async ({ positionals: { id }, options: { title, description } }) => {
|
|
18256
|
-
if (title === undefined && description === undefined)
|
|
18257
|
-
throw new Error("Nothing to update. Pass --title or --
|
|
18446
|
+
run: async ({ positionals: { id }, options: { title, description, attach } }) => {
|
|
18447
|
+
if (title === undefined && description === undefined && attach === undefined)
|
|
18448
|
+
throw new Error("Nothing to update. Pass --title, --description, or --attach.");
|
|
18258
18449
|
const client3 = await backendClient();
|
|
18259
18450
|
const issue2 = await resolveIssue(client3, id);
|
|
18260
|
-
await client3.
|
|
18261
|
-
|
|
18262
|
-
|
|
18263
|
-
|
|
18264
|
-
|
|
18451
|
+
printAttachments(await attachFiles(client3, issue2._id, attach ?? []));
|
|
18452
|
+
if (title !== undefined || description !== undefined) {
|
|
18453
|
+
await client3.mutation(api2.issues.update, {
|
|
18454
|
+
id: issue2._id,
|
|
18455
|
+
title,
|
|
18456
|
+
descriptionMarkdown: description === undefined ? undefined : await readTextOption(description)
|
|
18457
|
+
});
|
|
18458
|
+
}
|
|
18265
18459
|
console.log(`Updated ${issue2.identifier}.`);
|
|
18266
18460
|
}
|
|
18267
18461
|
});
|
|
@@ -18270,11 +18464,11 @@ var update = command({
|
|
|
18270
18464
|
var issues = group({
|
|
18271
18465
|
name: "issues",
|
|
18272
18466
|
description: "Track and triage issues",
|
|
18273
|
-
commands: [create, list, get, update, set2, route, comment, remove]
|
|
18467
|
+
commands: [create, list, get, update, set2, route, start, relate, unrelate, comment, remove]
|
|
18274
18468
|
});
|
|
18275
18469
|
|
|
18276
18470
|
// src/lib/group.ts
|
|
18277
|
-
import { basename } from "path";
|
|
18471
|
+
import { basename as basename2 } from "path";
|
|
18278
18472
|
var git = async (...args) => {
|
|
18279
18473
|
const proc = Bun.spawn(["git", ...args], { stdout: "pipe", stderr: "ignore" });
|
|
18280
18474
|
const [output, exitCode] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
|
|
@@ -18286,7 +18480,7 @@ var detectRepoGroup = async () => {
|
|
|
18286
18480
|
if (remote)
|
|
18287
18481
|
return repoNameFromRemote(remote);
|
|
18288
18482
|
const root = await git("rev-parse", "--show-toplevel");
|
|
18289
|
-
return root ?
|
|
18483
|
+
return root ? basename2(root) : undefined;
|
|
18290
18484
|
};
|
|
18291
18485
|
var groupForCreate = async (group2) => group2 === null ? undefined : group2 ?? await detectRepoGroup();
|
|
18292
18486
|
|