@islamihab/kds 0.2.3 → 0.3.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/index.js +203 -12
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -14597,7 +14597,7 @@ import { join } from "path";
|
|
|
14597
14597
|
// package.json
|
|
14598
14598
|
var package_default = {
|
|
14599
14599
|
name: "cli",
|
|
14600
|
-
version: "0.
|
|
14600
|
+
version: "0.3.0",
|
|
14601
14601
|
private: true,
|
|
14602
14602
|
type: "module",
|
|
14603
14603
|
bin: {
|
|
@@ -15153,7 +15153,17 @@ var KDS_DEVICE_AUTH_CLIENT_ID = "kds-cli";
|
|
|
15153
15153
|
var PAGE_MODES = ["themed", "raw"];
|
|
15154
15154
|
var PAGE_VISIBILITIES = ["public", "private"];
|
|
15155
15155
|
var MAX_PAGE_HTML_BYTES = 4000000;
|
|
15156
|
-
var ISSUE_STATUSES = [
|
|
15156
|
+
var ISSUE_STATUSES = [
|
|
15157
|
+
"backlog",
|
|
15158
|
+
"todo",
|
|
15159
|
+
"in_progress",
|
|
15160
|
+
"ready_for_review",
|
|
15161
|
+
"in_review",
|
|
15162
|
+
"changes_requested",
|
|
15163
|
+
"approved",
|
|
15164
|
+
"done",
|
|
15165
|
+
"canceled"
|
|
15166
|
+
];
|
|
15157
15167
|
var ISSUE_PRIORITIES = ["urgent", "high", "medium", "low", "none"];
|
|
15158
15168
|
var ISSUE_DISPOSITIONS = [
|
|
15159
15169
|
"needs_triage",
|
|
@@ -15169,6 +15179,15 @@ var ISSUE_CREATE_DISPOSITIONS = [
|
|
|
15169
15179
|
];
|
|
15170
15180
|
var ISSUE_ESTIMATES = [1, 2, 3, 5, 8];
|
|
15171
15181
|
var ISSUE_TERMINAL_STATUSES = ["done", "canceled"];
|
|
15182
|
+
var ISSUE_OPEN_STATUSES = [
|
|
15183
|
+
"backlog",
|
|
15184
|
+
"todo",
|
|
15185
|
+
"in_progress",
|
|
15186
|
+
"ready_for_review",
|
|
15187
|
+
"in_review",
|
|
15188
|
+
"changes_requested",
|
|
15189
|
+
"approved"
|
|
15190
|
+
];
|
|
15172
15191
|
var ISSUE_RELATION_KINDS = ["blocks", "blocked_by", "duplicate_of", "duplicated_by", "relates_to"];
|
|
15173
15192
|
var PROJECT_STATUSES = ["planned", "in_progress", "paused", "completed", "canceled"];
|
|
15174
15193
|
var PROJECT_HEALTHS = ["on_track", "at_risk", "off_track"];
|
|
@@ -15176,6 +15195,49 @@ var ISSUE_IDENTIFIER_PREFIX = "KAI";
|
|
|
15176
15195
|
var ISSUE_LIST_PAGE_SIZE = 50;
|
|
15177
15196
|
var MAX_ISSUE_ATTACHMENT_BYTES = 1e7;
|
|
15178
15197
|
var ISSUE_DUE_DATE_MODES = ["overdue", "due_today", "due_soon", "no_due_date"];
|
|
15198
|
+
var BUILT_IN_ISSUE_VIEWS = {
|
|
15199
|
+
all: {
|
|
15200
|
+
layout: "list",
|
|
15201
|
+
groupBy: "status",
|
|
15202
|
+
orderBy: "updated_at",
|
|
15203
|
+
orderDirection: "desc",
|
|
15204
|
+
filters: {}
|
|
15205
|
+
},
|
|
15206
|
+
active: {
|
|
15207
|
+
layout: "list",
|
|
15208
|
+
groupBy: "status",
|
|
15209
|
+
orderBy: "updated_at",
|
|
15210
|
+
orderDirection: "desc",
|
|
15211
|
+
filters: { statuses: [...ISSUE_OPEN_STATUSES] }
|
|
15212
|
+
},
|
|
15213
|
+
agent_queue: {
|
|
15214
|
+
layout: "list",
|
|
15215
|
+
groupBy: "status",
|
|
15216
|
+
orderBy: "updated_at",
|
|
15217
|
+
orderDirection: "desc",
|
|
15218
|
+
filters: {
|
|
15219
|
+
statuses: [...ISSUE_OPEN_STATUSES],
|
|
15220
|
+
dispositions: ["ready_for_agent"]
|
|
15221
|
+
}
|
|
15222
|
+
},
|
|
15223
|
+
triage: {
|
|
15224
|
+
layout: "list",
|
|
15225
|
+
groupBy: "disposition",
|
|
15226
|
+
orderBy: "updated_at",
|
|
15227
|
+
orderDirection: "desc",
|
|
15228
|
+
filters: {
|
|
15229
|
+
statuses: [...ISSUE_OPEN_STATUSES],
|
|
15230
|
+
dispositions: ["needs_triage", "needs_info"]
|
|
15231
|
+
}
|
|
15232
|
+
},
|
|
15233
|
+
dispatch: {
|
|
15234
|
+
layout: "board",
|
|
15235
|
+
groupBy: "none",
|
|
15236
|
+
orderBy: "updated_at",
|
|
15237
|
+
orderDirection: "desc",
|
|
15238
|
+
filters: { statuses: [...ISSUE_OPEN_STATUSES, "done"] }
|
|
15239
|
+
}
|
|
15240
|
+
};
|
|
15179
15241
|
var issueIsOpen = (status) => !ISSUE_TERMINAL_STATUSES.some((terminal) => terminal === status);
|
|
15180
15242
|
var MAX_PROJECT_REPO_LENGTH = 200;
|
|
15181
15243
|
|
|
@@ -17981,7 +18043,7 @@ var runInbox = async (options) => {
|
|
|
17981
18043
|
const inbox = await client3.query(api2.inbox.list, {});
|
|
17982
18044
|
const targetLastSeen = new Map(inbox.targetLastSeen.map((state) => [state.targetId, state.lastSeenAt]));
|
|
17983
18045
|
const events = options.all ? inbox.events : inbox.events.filter((event) => {
|
|
17984
|
-
const targetId = event.type === "
|
|
18046
|
+
const targetId = event.type === "project" ? event.project.id : event.issue.id;
|
|
17985
18047
|
return event.at > Math.max(inbox.lastSeenAt, targetLastSeen.get(targetId) ?? 0);
|
|
17986
18048
|
});
|
|
17987
18049
|
if (options.json)
|
|
@@ -18000,8 +18062,8 @@ var runInbox = async (options) => {
|
|
|
18000
18062
|
...events.map((event) => [
|
|
18001
18063
|
new Date(event.at).toISOString().slice(0, 16).replace("T", " "),
|
|
18002
18064
|
actorLabel(event.via, event.agent),
|
|
18003
|
-
event.type === "
|
|
18004
|
-
event.type === "
|
|
18065
|
+
event.type === "project" ? event.project.name : event.issue.identifier,
|
|
18066
|
+
event.type === "project" ? projectActivityLine(event.detail) : event.type === "comment" ? `commented: ${event.excerpt}` : issueActivityLine(event.detail)
|
|
18005
18067
|
])
|
|
18006
18068
|
]);
|
|
18007
18069
|
if (inbox.truncated)
|
|
@@ -18259,6 +18321,7 @@ var create = command({
|
|
|
18259
18321
|
project: exports_external.string().optional().describe("Project to create the issue in (id or URL)"),
|
|
18260
18322
|
here: exports_external.boolean().default(false).describe("Create in the checkout's connected project"),
|
|
18261
18323
|
milestone: exports_external.string().optional().describe("Milestone name (needs --project or --here)"),
|
|
18324
|
+
parent: exports_external.string().optional().describe("Create as a sub-issue of this issue (identifier, number, or URL)"),
|
|
18262
18325
|
disposition: exports_external.enum(ISSUE_CREATE_DISPOSITIONS).optional().describe("Route immediately (default needs_triage)")
|
|
18263
18326
|
},
|
|
18264
18327
|
run: async ({ positionals: { title }, options }) => {
|
|
@@ -18269,6 +18332,7 @@ var create = command({
|
|
|
18269
18332
|
if (options.milestone && !project)
|
|
18270
18333
|
throw new Error("A milestone needs --project or --here.");
|
|
18271
18334
|
const milestone = project && options.milestone ? await resolveMilestone(client3, project._id, options.milestone) : undefined;
|
|
18335
|
+
const parent = options.parent ? await resolveIssue(client3, options.parent) : undefined;
|
|
18272
18336
|
const { identifier } = await client3.mutation(api2.issues.create, {
|
|
18273
18337
|
title,
|
|
18274
18338
|
descriptionMarkdown: options.description === undefined ? undefined : await readTextOption(options.description),
|
|
@@ -18278,12 +18342,24 @@ var create = command({
|
|
|
18278
18342
|
dueDate: options.due,
|
|
18279
18343
|
projectId: project?._id,
|
|
18280
18344
|
milestoneId: milestone?._id,
|
|
18345
|
+
parentId: parent?._id,
|
|
18281
18346
|
disposition: options.disposition
|
|
18282
18347
|
});
|
|
18283
18348
|
console.log(identifier);
|
|
18284
18349
|
}
|
|
18285
18350
|
});
|
|
18286
18351
|
|
|
18352
|
+
// src/lib/tasks.ts
|
|
18353
|
+
var printTasks = (tasks) => {
|
|
18354
|
+
if (tasks.length === 0)
|
|
18355
|
+
return;
|
|
18356
|
+
const width = String(tasks.length).length;
|
|
18357
|
+
console.log(`Tasks: ${tasks.filter((task2) => task2.isDone).length}/${tasks.length}`);
|
|
18358
|
+
for (const [index, task2] of tasks.entries()) {
|
|
18359
|
+
console.log(` ${String(index + 1).padStart(width)} [${task2.isDone ? "x" : " "}] ${task2.title}`);
|
|
18360
|
+
}
|
|
18361
|
+
};
|
|
18362
|
+
|
|
18287
18363
|
// src/commands/issues/get.ts
|
|
18288
18364
|
var get = command({
|
|
18289
18365
|
name: "get",
|
|
@@ -18297,13 +18373,14 @@ var get = command({
|
|
|
18297
18373
|
run: async ({ positionals: { id }, options: { json: json2 } }) => {
|
|
18298
18374
|
const client3 = await backendClient();
|
|
18299
18375
|
const issue2 = await resolveIssue(client3, id);
|
|
18300
|
-
const [feed, relations, attachments] = await Promise.all([
|
|
18376
|
+
const [feed, relations, attachments, tasks] = await Promise.all([
|
|
18301
18377
|
client3.query(api2.issues.feed, { id: issue2._id }),
|
|
18302
18378
|
client3.query(api2.issues.relations, { id: issue2._id }),
|
|
18303
|
-
client3.query(api2.issueAttachments.list, { issueId: issue2._id })
|
|
18379
|
+
client3.query(api2.issueAttachments.list, { issueId: issue2._id }),
|
|
18380
|
+
client3.query(api2.issueTasks.list, { issueId: issue2._id })
|
|
18304
18381
|
]);
|
|
18305
18382
|
if (json2)
|
|
18306
|
-
return console.log(JSON.stringify({ ...issue2, relations, attachments, feed }, null, 2));
|
|
18383
|
+
return console.log(JSON.stringify({ ...issue2, relations, attachments, tasks, feed }, null, 2));
|
|
18307
18384
|
const project = issue2.projectId ? await client3.query(api2.projects.get, { id: issue2.projectId, today: localToday() }) : null;
|
|
18308
18385
|
const milestone = issue2.milestoneId ? await client3.query(api2.milestones.get, { id: issue2.milestoneId, today: localToday() }) : null;
|
|
18309
18386
|
console.log(`${issue2.identifier} ${issue2.title}`);
|
|
@@ -18341,6 +18418,7 @@ var get = command({
|
|
|
18341
18418
|
console.log(` ${attachment.name} \u2014 ${attachment.url ?? "unavailable"}`);
|
|
18342
18419
|
}
|
|
18343
18420
|
}
|
|
18421
|
+
printTasks(tasks);
|
|
18344
18422
|
if (issue2.descriptionMarkdown)
|
|
18345
18423
|
console.log(`
|
|
18346
18424
|
${issue2.descriptionMarkdown}`);
|
|
@@ -18549,20 +18627,115 @@ var set2 = command({
|
|
|
18549
18627
|
var shellArg = (value) => /^[\w./-]+$/.test(value) ? value : `'${value.replaceAll("'", `'\\''`)}'`;
|
|
18550
18628
|
var start = command({
|
|
18551
18629
|
name: "start",
|
|
18552
|
-
description: "Claim
|
|
18630
|
+
description: "Claim implementation work: move unstarted or changes_requested work to in_progress with its branch",
|
|
18553
18631
|
positionals: {
|
|
18554
18632
|
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18555
18633
|
},
|
|
18556
|
-
|
|
18634
|
+
options: {
|
|
18635
|
+
ready: exports_external.boolean().default(false).describe("Also route the issue to ready_for_agent")
|
|
18636
|
+
},
|
|
18637
|
+
run: async ({ positionals: { id }, options: { ready } }) => {
|
|
18557
18638
|
const client3 = await backendClient();
|
|
18558
18639
|
const issue2 = await resolveIssue(client3, id);
|
|
18559
18640
|
const { branch } = await client3.mutation(api2.issues.start, { id: issue2._id });
|
|
18641
|
+
if (ready && issue2.disposition !== "ready_for_agent") {
|
|
18642
|
+
await client3.mutation(api2.issues.route, { id: issue2._id, disposition: "ready_for_agent" });
|
|
18643
|
+
}
|
|
18560
18644
|
console.log(`Started ${issue2.identifier}: in_progress, branch ${branch}`);
|
|
18645
|
+
if (ready) {
|
|
18646
|
+
console.log("Routed to ready_for_agent.");
|
|
18647
|
+
} else if (issue2.disposition !== "ready_for_agent" && await agentClaim()) {
|
|
18648
|
+
console.log(`Note: disposition is ${issue2.disposition}. Pass --ready if this hand-off was intended.`);
|
|
18649
|
+
}
|
|
18561
18650
|
console.log(`
|
|
18562
18651
|
git switch -c ${shellArg(branch)}`);
|
|
18563
18652
|
}
|
|
18564
18653
|
});
|
|
18565
18654
|
|
|
18655
|
+
// src/commands/issues/start-review.ts
|
|
18656
|
+
var startReview = command({
|
|
18657
|
+
name: "start-review",
|
|
18658
|
+
description: "Claim review work: move a ready_for_review issue to in_review",
|
|
18659
|
+
positionals: {
|
|
18660
|
+
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18661
|
+
},
|
|
18662
|
+
run: async ({ positionals: { id } }) => {
|
|
18663
|
+
const client3 = await backendClient();
|
|
18664
|
+
const issue2 = await resolveIssue(client3, id);
|
|
18665
|
+
await client3.mutation(api2.issues.startReview, { id: issue2._id });
|
|
18666
|
+
console.log(`Reviewing ${issue2.identifier}: in_review`);
|
|
18667
|
+
}
|
|
18668
|
+
});
|
|
18669
|
+
|
|
18670
|
+
// src/commands/issues/submit.ts
|
|
18671
|
+
var submit = command({
|
|
18672
|
+
name: "submit",
|
|
18673
|
+
description: "Hand an issue off for review: move in_progress or changes_requested work to ready_for_review",
|
|
18674
|
+
positionals: {
|
|
18675
|
+
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18676
|
+
},
|
|
18677
|
+
run: async ({ positionals: { id } }) => {
|
|
18678
|
+
const client3 = await backendClient();
|
|
18679
|
+
const issue2 = await resolveIssue(client3, id);
|
|
18680
|
+
await client3.mutation(api2.issues.submit, { id: issue2._id });
|
|
18681
|
+
console.log(`Submitted ${issue2.identifier}: ready_for_review`);
|
|
18682
|
+
}
|
|
18683
|
+
});
|
|
18684
|
+
|
|
18685
|
+
// src/commands/issues/tasks.ts
|
|
18686
|
+
var position = exports_external.array(exports_external.coerce.number().int().positive());
|
|
18687
|
+
var tasks = command({
|
|
18688
|
+
name: "tasks",
|
|
18689
|
+
description: "Show an issue's checklist, or add, tick, promote, and drop its tasks",
|
|
18690
|
+
positionals: {
|
|
18691
|
+
id: exports_external.string().describe("Issue identifier, number, or URL")
|
|
18692
|
+
},
|
|
18693
|
+
options: {
|
|
18694
|
+
add: exports_external.array(exports_external.string()).optional().describe("Add a task (repeatable)").meta({ short: "a" }),
|
|
18695
|
+
check: position.optional().describe("Tick a task by its number (repeatable)"),
|
|
18696
|
+
uncheck: position.optional().describe("Untick a task by its number (repeatable)"),
|
|
18697
|
+
convert: position.optional().describe("Promote a task into its own issue (repeatable)"),
|
|
18698
|
+
remove: position.optional().describe("Drop a task by its number (repeatable)"),
|
|
18699
|
+
json: exports_external.boolean().default(false).describe("Print as JSON")
|
|
18700
|
+
},
|
|
18701
|
+
run: async ({ positionals: { id }, options: { add, check: check2, uncheck, convert, remove: remove2, json: json2 } }) => {
|
|
18702
|
+
const client3 = await backendClient();
|
|
18703
|
+
const issue2 = await resolveIssue(client3, id);
|
|
18704
|
+
const before = await client3.query(api2.issueTasks.list, { issueId: issue2._id });
|
|
18705
|
+
const at = (numbered) => (numbered ?? []).map((number4) => {
|
|
18706
|
+
const task2 = before[number4 - 1];
|
|
18707
|
+
if (!task2)
|
|
18708
|
+
throw new Error(`${issue2.identifier} has no task ${number4}.`);
|
|
18709
|
+
return task2;
|
|
18710
|
+
});
|
|
18711
|
+
const ticked = at(check2);
|
|
18712
|
+
const unticked = at(uncheck);
|
|
18713
|
+
const promoted = at(convert);
|
|
18714
|
+
const dropped = at(remove2);
|
|
18715
|
+
for (const title of add ?? [])
|
|
18716
|
+
await client3.mutation(api2.issueTasks.create, { issueId: issue2._id, title });
|
|
18717
|
+
for (const task2 of ticked)
|
|
18718
|
+
await client3.mutation(api2.issueTasks.update, { id: task2._id, isDone: true });
|
|
18719
|
+
for (const task2 of unticked)
|
|
18720
|
+
await client3.mutation(api2.issueTasks.update, { id: task2._id, isDone: false });
|
|
18721
|
+
for (const task2 of promoted) {
|
|
18722
|
+
const created = await client3.mutation(api2.issueTasks.convert, { id: task2._id });
|
|
18723
|
+
if (!json2) {
|
|
18724
|
+
console.log(`${created.identifier} ${created.nested ? "created as a sub-issue" : "created and related"}: ${task2.title}`);
|
|
18725
|
+
}
|
|
18726
|
+
}
|
|
18727
|
+
for (const task2 of dropped)
|
|
18728
|
+
await client3.mutation(api2.issueTasks.remove, { id: task2._id });
|
|
18729
|
+
const wrote = [add, check2, uncheck, convert, remove2].some((values) => values !== undefined);
|
|
18730
|
+
const after = wrote ? await client3.query(api2.issueTasks.list, { issueId: issue2._id }) : before;
|
|
18731
|
+
if (json2)
|
|
18732
|
+
return console.log(JSON.stringify(after, null, 2));
|
|
18733
|
+
if (after.length === 0)
|
|
18734
|
+
return console.log(`${issue2.identifier} has no tasks.`);
|
|
18735
|
+
printTasks(after);
|
|
18736
|
+
}
|
|
18737
|
+
});
|
|
18738
|
+
|
|
18566
18739
|
// src/commands/issues/unrelate.ts
|
|
18567
18740
|
var relationEntries = (relations, kind) => {
|
|
18568
18741
|
switch (kind) {
|
|
@@ -18633,7 +18806,22 @@ var update = command({
|
|
|
18633
18806
|
var issues = group({
|
|
18634
18807
|
name: "issues",
|
|
18635
18808
|
description: "Track and triage issues",
|
|
18636
|
-
commands: [
|
|
18809
|
+
commands: [
|
|
18810
|
+
create,
|
|
18811
|
+
list,
|
|
18812
|
+
get,
|
|
18813
|
+
update,
|
|
18814
|
+
set2,
|
|
18815
|
+
route,
|
|
18816
|
+
start,
|
|
18817
|
+
submit,
|
|
18818
|
+
startReview,
|
|
18819
|
+
tasks,
|
|
18820
|
+
relate,
|
|
18821
|
+
unrelate,
|
|
18822
|
+
comment,
|
|
18823
|
+
remove
|
|
18824
|
+
]
|
|
18637
18825
|
});
|
|
18638
18826
|
|
|
18639
18827
|
// src/lib/group.ts
|
|
@@ -19068,6 +19256,9 @@ var rootCommand = group({
|
|
|
19068
19256
|
}
|
|
19069
19257
|
});
|
|
19070
19258
|
|
|
19259
|
+
// src/lib/errors.ts
|
|
19260
|
+
var errorMessage = (error51) => error51 instanceof ConvexError && typeof error51.data === "string" ? error51.data : error51.message;
|
|
19261
|
+
|
|
19071
19262
|
// src/lib/update-check.ts
|
|
19072
19263
|
var latestVersion = async () => {
|
|
19073
19264
|
const cached2 = await Bun.file(CACHE_PATH).json().catch(() => null).then(cacheSchema.safeParse);
|
|
@@ -19105,7 +19296,7 @@ try {
|
|
|
19105
19296
|
if (args[0] !== "upgrade")
|
|
19106
19297
|
await maybeNotifyUpdate();
|
|
19107
19298
|
} catch (error51) {
|
|
19108
|
-
console.error(error51
|
|
19299
|
+
console.error(errorMessage(error51));
|
|
19109
19300
|
process.exitCode = 1;
|
|
19110
19301
|
} finally {
|
|
19111
19302
|
closePrompts();
|