@islamihab/kds 0.2.4 → 0.4.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.
Files changed (2) hide show
  1. package/index.js +398 -26
  2. 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.2.4",
14600
+ version: "0.4.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 = ["backlog", "todo", "in_progress", "done", "canceled"];
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,13 +15179,136 @@ 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
+ ];
15191
+ var ISSUE_LABEL_COLORS = [
15192
+ "gray",
15193
+ "red",
15194
+ "orange",
15195
+ "amber",
15196
+ "green",
15197
+ "teal",
15198
+ "blue",
15199
+ "indigo",
15200
+ "purple",
15201
+ "pink"
15202
+ ];
15172
15203
  var ISSUE_RELATION_KINDS = ["blocks", "blocked_by", "duplicate_of", "duplicated_by", "relates_to"];
15204
+ var AGENT_HARNESS_LABELS = {
15205
+ codex: "Codex",
15206
+ claude_code: "Claude Code"
15207
+ };
15208
+ var AGENT_CONFIGURATION_IDS = [
15209
+ "codex-gpt-5-6-sol",
15210
+ "codex-gpt-5-6-terra",
15211
+ "codex-gpt-5-6-luna",
15212
+ "claude-code-claude-fable-5",
15213
+ "claude-code-claude-opus-5",
15214
+ "claude-code-claude-sonnet-5"
15215
+ ];
15216
+ var AGENT_CONFIGURATIONS = {
15217
+ "codex-gpt-5-6-sol": {
15218
+ label: "Codex \xB7 GPT-5.6 Sol",
15219
+ harness: "codex",
15220
+ model: "gpt-5.6-sol",
15221
+ lifecycle: "current"
15222
+ },
15223
+ "codex-gpt-5-6-terra": {
15224
+ label: "Codex \xB7 GPT-5.6 Terra",
15225
+ harness: "codex",
15226
+ model: "gpt-5.6-terra",
15227
+ lifecycle: "current"
15228
+ },
15229
+ "codex-gpt-5-6-luna": {
15230
+ label: "Codex \xB7 GPT-5.6 Luna",
15231
+ harness: "codex",
15232
+ model: "gpt-5.6-luna",
15233
+ lifecycle: "current"
15234
+ },
15235
+ "claude-code-claude-fable-5": {
15236
+ label: "Claude Code \xB7 Claude Fable 5",
15237
+ harness: "claude_code",
15238
+ model: "claude-fable-5",
15239
+ lifecycle: "current"
15240
+ },
15241
+ "claude-code-claude-opus-5": {
15242
+ label: "Claude Code \xB7 Claude Opus 5",
15243
+ harness: "claude_code",
15244
+ model: "claude-opus-5",
15245
+ lifecycle: "current"
15246
+ },
15247
+ "claude-code-claude-sonnet-5": {
15248
+ label: "Claude Code \xB7 Claude Sonnet 5",
15249
+ harness: "claude_code",
15250
+ model: "claude-sonnet-5",
15251
+ lifecycle: "current"
15252
+ }
15253
+ };
15254
+ var orderAgentConfigurations = (entries) => [
15255
+ ...entries.filter((entry) => entry.lifecycle === "current"),
15256
+ ...entries.filter((entry) => entry.lifecycle === "legacy")
15257
+ ];
15258
+ var agentConfiguration = (id) => ({
15259
+ id,
15260
+ ...AGENT_CONFIGURATIONS[id]
15261
+ });
15262
+ var AGENT_CONFIGURATION_OPTIONS = orderAgentConfigurations(AGENT_CONFIGURATION_IDS.map(agentConfiguration));
15173
15263
  var PROJECT_STATUSES = ["planned", "in_progress", "paused", "completed", "canceled"];
15174
15264
  var PROJECT_HEALTHS = ["on_track", "at_risk", "off_track"];
15175
15265
  var ISSUE_IDENTIFIER_PREFIX = "KAI";
15176
15266
  var ISSUE_LIST_PAGE_SIZE = 50;
15177
15267
  var MAX_ISSUE_ATTACHMENT_BYTES = 1e7;
15178
15268
  var ISSUE_DUE_DATE_MODES = ["overdue", "due_today", "due_soon", "no_due_date"];
15269
+ var BUILT_IN_ISSUE_VIEWS = {
15270
+ all: {
15271
+ layout: "list",
15272
+ groupBy: "status",
15273
+ orderBy: "updated_at",
15274
+ orderDirection: "desc",
15275
+ filters: {}
15276
+ },
15277
+ active: {
15278
+ layout: "list",
15279
+ groupBy: "status",
15280
+ orderBy: "updated_at",
15281
+ orderDirection: "desc",
15282
+ filters: { statuses: [...ISSUE_OPEN_STATUSES] }
15283
+ },
15284
+ agent_queue: {
15285
+ layout: "list",
15286
+ groupBy: "status",
15287
+ orderBy: "updated_at",
15288
+ orderDirection: "desc",
15289
+ filters: {
15290
+ statuses: [...ISSUE_OPEN_STATUSES],
15291
+ dispositions: ["ready_for_agent"]
15292
+ }
15293
+ },
15294
+ triage: {
15295
+ layout: "list",
15296
+ groupBy: "disposition",
15297
+ orderBy: "updated_at",
15298
+ orderDirection: "desc",
15299
+ filters: {
15300
+ statuses: [...ISSUE_OPEN_STATUSES],
15301
+ dispositions: ["needs_triage", "needs_info"]
15302
+ }
15303
+ },
15304
+ dispatch: {
15305
+ layout: "board",
15306
+ groupBy: "none",
15307
+ orderBy: "updated_at",
15308
+ orderDirection: "desc",
15309
+ filters: { statuses: [...ISSUE_OPEN_STATUSES, "done"] }
15310
+ }
15311
+ };
15179
15312
  var issueIsOpen = (status) => !ISSUE_TERMINAL_STATUSES.some((terminal) => terminal === status);
15180
15313
  var MAX_PROJECT_REPO_LENGTH = 200;
15181
15314
 
@@ -17892,6 +18025,7 @@ var issueActivityLine = (detail) => {
17892
18025
  case "disposition_changed":
17893
18026
  case "estimate_changed":
17894
18027
  case "due_date_changed":
18028
+ case "agent_configuration_changed":
17895
18029
  case "branch_changed":
17896
18030
  case "pr_changed":
17897
18031
  case "project_changed":
@@ -18135,6 +18269,16 @@ var resolveIssueLabels = async (client3, names) => {
18135
18269
  return label;
18136
18270
  });
18137
18271
  };
18272
+ var resolveIssueLabel = async (client3, ref) => {
18273
+ const labels = await client3.query(api2.issueLabels.list, {});
18274
+ const wanted = ref.trim().toLowerCase();
18275
+ const label = labels.find((candidate) => candidate._id === ref || candidate.name.toLowerCase() === wanted);
18276
+ if (!label) {
18277
+ const available = labels.map((candidate) => candidate.name).join(", ");
18278
+ throw new Error(available ? `No label matches "${ref}". The labels are: ${available}.` : "There are no labels yet.");
18279
+ }
18280
+ return label;
18281
+ };
18138
18282
  var resolveMilestone = async (client3, projectId, name) => {
18139
18283
  const milestones = await client3.query(api2.milestones.listByProject, { projectId, today: localToday() });
18140
18284
  const wanted = name.trim().toLowerCase();
@@ -18243,6 +18387,17 @@ var comment = command({
18243
18387
  }
18244
18388
  });
18245
18389
 
18390
+ // src/lib/agents.ts
18391
+ var agentConfigurationLegacyNote = () => {
18392
+ const legacy = AGENT_CONFIGURATION_OPTIONS.filter((entry) => entry.lifecycle === "legacy");
18393
+ return legacy.length === 0 ? "" : ` (legacy: ${legacy.map((entry) => entry.id).join(", ")})`;
18394
+ };
18395
+ var agentConfigurationLine = (id) => {
18396
+ const entry = agentConfiguration(id);
18397
+ const legacy = entry.lifecycle === "legacy" ? " (legacy)" : "";
18398
+ return `${entry.label}${legacy} \u2014 ${entry.id} \xB7 ${AGENT_HARNESS_LABELS[entry.harness]} \xB7 ${entry.model}`;
18399
+ };
18400
+
18246
18401
  // src/commands/issues/create.ts
18247
18402
  var create = command({
18248
18403
  name: "create",
@@ -18259,7 +18414,9 @@ var create = command({
18259
18414
  project: exports_external.string().optional().describe("Project to create the issue in (id or URL)"),
18260
18415
  here: exports_external.boolean().default(false).describe("Create in the checkout's connected project"),
18261
18416
  milestone: exports_external.string().optional().describe("Milestone name (needs --project or --here)"),
18262
- disposition: exports_external.enum(ISSUE_CREATE_DISPOSITIONS).optional().describe("Route immediately (default needs_triage)")
18417
+ parent: exports_external.string().optional().describe("Create as a sub-issue of this issue (identifier, number, or URL)"),
18418
+ disposition: exports_external.enum(ISSUE_CREATE_DISPOSITIONS).optional().describe("Route immediately (default needs_triage)"),
18419
+ "agent-config": exports_external.enum(AGENT_CONFIGURATION_IDS).optional().describe(`Agent configuration${agentConfigurationLegacyNote()}`)
18263
18420
  },
18264
18421
  run: async ({ positionals: { title }, options }) => {
18265
18422
  if (options.project && options.here)
@@ -18269,6 +18426,7 @@ var create = command({
18269
18426
  if (options.milestone && !project)
18270
18427
  throw new Error("A milestone needs --project or --here.");
18271
18428
  const milestone = project && options.milestone ? await resolveMilestone(client3, project._id, options.milestone) : undefined;
18429
+ const parent = options.parent ? await resolveIssue(client3, options.parent) : undefined;
18272
18430
  const { identifier } = await client3.mutation(api2.issues.create, {
18273
18431
  title,
18274
18432
  descriptionMarkdown: options.description === undefined ? undefined : await readTextOption(options.description),
@@ -18278,12 +18436,25 @@ var create = command({
18278
18436
  dueDate: options.due,
18279
18437
  projectId: project?._id,
18280
18438
  milestoneId: milestone?._id,
18281
- disposition: options.disposition
18439
+ parentId: parent?._id,
18440
+ disposition: options.disposition,
18441
+ agentConfigurationId: options["agent-config"]
18282
18442
  });
18283
18443
  console.log(identifier);
18284
18444
  }
18285
18445
  });
18286
18446
 
18447
+ // src/lib/tasks.ts
18448
+ var printTasks = (tasks) => {
18449
+ if (tasks.length === 0)
18450
+ return;
18451
+ const width = String(tasks.length).length;
18452
+ console.log(`Tasks: ${tasks.filter((task2) => task2.isDone).length}/${tasks.length}`);
18453
+ for (const [index, task2] of tasks.entries()) {
18454
+ console.log(` ${String(index + 1).padStart(width)} [${task2.isDone ? "x" : " "}] ${task2.title}`);
18455
+ }
18456
+ };
18457
+
18287
18458
  // src/commands/issues/get.ts
18288
18459
  var get = command({
18289
18460
  name: "get",
@@ -18297,13 +18468,14 @@ var get = command({
18297
18468
  run: async ({ positionals: { id }, options: { json: json2 } }) => {
18298
18469
  const client3 = await backendClient();
18299
18470
  const issue2 = await resolveIssue(client3, id);
18300
- const [feed, relations, attachments] = await Promise.all([
18471
+ const [feed, relations, attachments, tasks] = await Promise.all([
18301
18472
  client3.query(api2.issues.feed, { id: issue2._id }),
18302
18473
  client3.query(api2.issues.relations, { id: issue2._id }),
18303
- client3.query(api2.issueAttachments.list, { issueId: issue2._id })
18474
+ client3.query(api2.issueAttachments.list, { issueId: issue2._id }),
18475
+ client3.query(api2.issueTasks.list, { issueId: issue2._id })
18304
18476
  ]);
18305
18477
  if (json2)
18306
- return console.log(JSON.stringify({ ...issue2, relations, attachments, feed }, null, 2));
18478
+ return console.log(JSON.stringify({ ...issue2, relations, attachments, tasks, feed }, null, 2));
18307
18479
  const project = issue2.projectId ? await client3.query(api2.projects.get, { id: issue2.projectId, today: localToday() }) : null;
18308
18480
  const milestone = issue2.milestoneId ? await client3.query(api2.milestones.get, { id: issue2.milestoneId, today: localToday() }) : null;
18309
18481
  console.log(`${issue2.identifier} ${issue2.title}`);
@@ -18312,6 +18484,8 @@ var get = command({
18312
18484
  console.log(`Estimate: ${issue2.estimate}`);
18313
18485
  if (issue2.dueDate)
18314
18486
  console.log(`Due: ${issue2.dueDate}`);
18487
+ if (issue2.agentConfigurationId)
18488
+ console.log(`Agent: ${agentConfigurationLine(issue2.agentConfigurationId)}`);
18315
18489
  if (issue2.branch)
18316
18490
  console.log(`Branch: ${issue2.branch}`);
18317
18491
  if (issue2.prUrl)
@@ -18341,6 +18515,7 @@ var get = command({
18341
18515
  console.log(` ${attachment.name} \u2014 ${attachment.url ?? "unavailable"}`);
18342
18516
  }
18343
18517
  }
18518
+ printTasks(tasks);
18344
18519
  if (issue2.descriptionMarkdown)
18345
18520
  console.log(`
18346
18521
  ${issue2.descriptionMarkdown}`);
@@ -18364,8 +18539,85 @@ Feed:`);
18364
18539
  }
18365
18540
  });
18366
18541
 
18367
- // src/commands/issues/list.ts
18542
+ // src/commands/issues/labels/create.ts
18543
+ var create2 = command({
18544
+ name: "create",
18545
+ description: "Create an issue label and print its id",
18546
+ positionals: {
18547
+ name: exports_external.string().describe("Label name")
18548
+ },
18549
+ options: {
18550
+ color: exports_external.enum(ISSUE_LABEL_COLORS).default("gray").describe("Label color (default gray)")
18551
+ },
18552
+ run: async ({ positionals: { name }, options: { color } }) => {
18553
+ const client3 = await backendClient();
18554
+ const id = await client3.mutation(api2.issueLabels.create, { name, color });
18555
+ console.log(id);
18556
+ }
18557
+ });
18558
+
18559
+ // src/commands/issues/labels/list.ts
18368
18560
  var list = command({
18561
+ name: "list",
18562
+ description: "List issue labels alphabetically",
18563
+ options: {
18564
+ json: exports_external.boolean().default(false).describe("Print as JSON")
18565
+ },
18566
+ run: async ({ options: { json: json2 } }) => {
18567
+ const labels = await (await backendClient()).query(api2.issueLabels.list, {});
18568
+ if (json2)
18569
+ return console.log(JSON.stringify(labels, null, 2));
18570
+ if (labels.length === 0)
18571
+ return console.log("No labels yet.");
18572
+ printTable([["NAME", "COLOR", "ID"], ...labels.map((label) => [label.name, label.color, label._id])]);
18573
+ }
18574
+ });
18575
+
18576
+ // src/commands/issues/labels/remove.ts
18577
+ var remove = command({
18578
+ name: "delete",
18579
+ description: "Delete an issue label and remove it from every issue",
18580
+ positionals: {
18581
+ label: exports_external.string().describe("Label name or id")
18582
+ },
18583
+ run: async ({ positionals: { label: ref } }) => {
18584
+ const client3 = await backendClient();
18585
+ const label = await resolveIssueLabel(client3, ref);
18586
+ await client3.mutation(api2.issueLabels.remove, { id: label._id });
18587
+ console.log(`Deleted ${label.name}.`);
18588
+ }
18589
+ });
18590
+
18591
+ // src/commands/issues/labels/update.ts
18592
+ var update = command({
18593
+ name: "update",
18594
+ description: "Rename or recolor an issue label",
18595
+ positionals: {
18596
+ label: exports_external.string().describe("Label name or id")
18597
+ },
18598
+ options: {
18599
+ name: exports_external.string().optional().describe("New name").meta({ short: "n" }),
18600
+ color: exports_external.enum(ISSUE_LABEL_COLORS).optional().describe("New color")
18601
+ },
18602
+ run: async ({ positionals: { label: ref }, options: { name, color } }) => {
18603
+ if (name === undefined && color === undefined)
18604
+ throw new Error("Nothing to update. Pass --name or --color.");
18605
+ const client3 = await backendClient();
18606
+ const label = await resolveIssueLabel(client3, ref);
18607
+ await client3.mutation(api2.issueLabels.update, { id: label._id, name, color });
18608
+ console.log(`Updated ${name ?? label.name}.`);
18609
+ }
18610
+ });
18611
+
18612
+ // src/commands/issues/labels/index.ts
18613
+ var labels = group({
18614
+ name: "labels",
18615
+ description: "Manage issue labels",
18616
+ commands: [create2, list, update, remove]
18617
+ });
18618
+
18619
+ // src/commands/issues/list.ts
18620
+ var list2 = command({
18369
18621
  name: "list",
18370
18622
  description: "List open issues, most recently updated first",
18371
18623
  options: {
@@ -18452,7 +18704,7 @@ var relate = command({
18452
18704
  });
18453
18705
 
18454
18706
  // src/commands/issues/remove.ts
18455
- var remove = command({
18707
+ var remove2 = command({
18456
18708
  name: "delete",
18457
18709
  description: "Delete an issue permanently (sub-issues survive as top-level issues)",
18458
18710
  positionals: {
@@ -18492,7 +18744,7 @@ var route = command({
18492
18744
  // src/commands/issues/set.ts
18493
18745
  var set2 = command({
18494
18746
  name: "set",
18495
- description: "Set an issue's status, priority, estimate, due date, project, milestone, parent, or labels",
18747
+ description: "Set an issue's status, priority, estimate, due date, project, milestone, parent, agent configuration, or labels",
18496
18748
  positionals: {
18497
18749
  id: exports_external.string().describe("Issue identifier, number, or URL")
18498
18750
  },
@@ -18504,13 +18756,25 @@ var set2 = command({
18504
18756
  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 }),
18505
18757
  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 }),
18506
18758
  parent: exports_external.string().nullable().optional().describe("Make this a sub-issue of another issue, or --no-parent to promote it").meta({ negatable: true }),
18759
+ "agent-config": exports_external.enum(AGENT_CONFIGURATION_IDS).nullable().optional().describe(`Agent configuration${agentConfigurationLegacyNote()}, or --no-agent-config to clear`).meta({ negatable: true }),
18507
18760
  label: exports_external.array(exports_external.string()).optional().describe("Add a label by name (repeatable)"),
18508
18761
  "no-label": exports_external.array(exports_external.string()).optional().describe("Remove a label by name (repeatable)")
18509
18762
  },
18510
18763
  run: async ({ positionals: { id }, options }) => {
18511
- const { status: status2, priority, estimate, due, project, milestone, parent, label, "no-label": noLabel } = options;
18764
+ const {
18765
+ status: status2,
18766
+ priority,
18767
+ estimate,
18768
+ due,
18769
+ project,
18770
+ milestone,
18771
+ parent,
18772
+ label,
18773
+ "agent-config": agentConfig,
18774
+ "no-label": noLabel
18775
+ } = options;
18512
18776
  if (Object.values(options).every((value) => value === undefined))
18513
- throw new Error("Nothing to set. Pass --status, --priority, --estimate, --due, --project, --milestone, --parent, or --label.");
18777
+ throw new Error("Nothing to set. Pass --status, --priority, --estimate, --due, --project, --milestone, --parent, --agent-config, or --label.");
18514
18778
  const client3 = await backendClient();
18515
18779
  const issue2 = await resolveIssue(client3, id);
18516
18780
  const projectId = project === undefined ? issue2.projectId : project === null ? undefined : (await resolveProject(client3, project))._id;
@@ -18531,6 +18795,11 @@ var set2 = command({
18531
18795
  await client3.mutation(api2.issues.addLabel, { issueId: issue2._id, labelId: _id });
18532
18796
  for (const { _id } of removeLabels)
18533
18797
  await client3.mutation(api2.issues.removeLabel, { issueId: issue2._id, labelId: _id });
18798
+ if (agentConfig !== undefined)
18799
+ await client3.mutation(api2.issues.setAgentConfiguration, {
18800
+ id: issue2._id,
18801
+ agentConfigurationId: agentConfig ?? undefined
18802
+ });
18534
18803
  if (status2 !== undefined)
18535
18804
  await client3.mutation(api2.issues.setStatus, { id: issue2._id, status: status2 });
18536
18805
  if (priority !== undefined)
@@ -18549,7 +18818,7 @@ var set2 = command({
18549
18818
  var shellArg = (value) => /^[\w./-]+$/.test(value) ? value : `'${value.replaceAll("'", `'\\''`)}'`;
18550
18819
  var start = command({
18551
18820
  name: "start",
18552
- description: "Claim an issue: move it to in_progress and record the branch to work under",
18821
+ description: "Claim implementation work: move unstarted or changes_requested work to in_progress with its branch",
18553
18822
  positionals: {
18554
18823
  id: exports_external.string().describe("Issue identifier, number, or URL")
18555
18824
  },
@@ -18574,6 +18843,90 @@ var start = command({
18574
18843
  }
18575
18844
  });
18576
18845
 
18846
+ // src/commands/issues/start-review.ts
18847
+ var startReview = command({
18848
+ name: "start-review",
18849
+ description: "Claim review work: move a ready_for_review issue to in_review",
18850
+ positionals: {
18851
+ id: exports_external.string().describe("Issue identifier, number, or URL")
18852
+ },
18853
+ run: async ({ positionals: { id } }) => {
18854
+ const client3 = await backendClient();
18855
+ const issue2 = await resolveIssue(client3, id);
18856
+ await client3.mutation(api2.issues.startReview, { id: issue2._id });
18857
+ console.log(`Reviewing ${issue2.identifier}: in_review`);
18858
+ }
18859
+ });
18860
+
18861
+ // src/commands/issues/submit.ts
18862
+ var submit = command({
18863
+ name: "submit",
18864
+ description: "Hand an issue off for review: move in_progress or changes_requested work to ready_for_review",
18865
+ positionals: {
18866
+ id: exports_external.string().describe("Issue identifier, number, or URL")
18867
+ },
18868
+ run: async ({ positionals: { id } }) => {
18869
+ const client3 = await backendClient();
18870
+ const issue2 = await resolveIssue(client3, id);
18871
+ await client3.mutation(api2.issues.submit, { id: issue2._id });
18872
+ console.log(`Submitted ${issue2.identifier}: ready_for_review`);
18873
+ }
18874
+ });
18875
+
18876
+ // src/commands/issues/tasks.ts
18877
+ var position = exports_external.array(exports_external.coerce.number().int().positive());
18878
+ var tasks = command({
18879
+ name: "tasks",
18880
+ description: "Show an issue's checklist, or add, tick, promote, and drop its tasks",
18881
+ positionals: {
18882
+ id: exports_external.string().describe("Issue identifier, number, or URL")
18883
+ },
18884
+ options: {
18885
+ add: exports_external.array(exports_external.string()).optional().describe("Add a task (repeatable)").meta({ short: "a" }),
18886
+ check: position.optional().describe("Tick a task by its number (repeatable)"),
18887
+ uncheck: position.optional().describe("Untick a task by its number (repeatable)"),
18888
+ convert: position.optional().describe("Promote a task into its own issue (repeatable)"),
18889
+ remove: position.optional().describe("Drop a task by its number (repeatable)"),
18890
+ json: exports_external.boolean().default(false).describe("Print as JSON")
18891
+ },
18892
+ run: async ({ positionals: { id }, options: { add, check: check2, uncheck, convert, remove: remove3, json: json2 } }) => {
18893
+ const client3 = await backendClient();
18894
+ const issue2 = await resolveIssue(client3, id);
18895
+ const before = await client3.query(api2.issueTasks.list, { issueId: issue2._id });
18896
+ const at = (numbered) => (numbered ?? []).map((number4) => {
18897
+ const task2 = before[number4 - 1];
18898
+ if (!task2)
18899
+ throw new Error(`${issue2.identifier} has no task ${number4}.`);
18900
+ return task2;
18901
+ });
18902
+ const ticked = at(check2);
18903
+ const unticked = at(uncheck);
18904
+ const promoted = at(convert);
18905
+ const dropped = at(remove3);
18906
+ for (const title of add ?? [])
18907
+ await client3.mutation(api2.issueTasks.create, { issueId: issue2._id, title });
18908
+ for (const task2 of ticked)
18909
+ await client3.mutation(api2.issueTasks.update, { id: task2._id, isDone: true });
18910
+ for (const task2 of unticked)
18911
+ await client3.mutation(api2.issueTasks.update, { id: task2._id, isDone: false });
18912
+ for (const task2 of promoted) {
18913
+ const created = await client3.mutation(api2.issueTasks.convert, { id: task2._id });
18914
+ if (!json2) {
18915
+ console.log(`${created.identifier} ${created.nested ? "created as a sub-issue" : "created and related"}: ${task2.title}`);
18916
+ }
18917
+ }
18918
+ for (const task2 of dropped)
18919
+ await client3.mutation(api2.issueTasks.remove, { id: task2._id });
18920
+ const wrote = [add, check2, uncheck, convert, remove3].some((values) => values !== undefined);
18921
+ const after = wrote ? await client3.query(api2.issueTasks.list, { issueId: issue2._id }) : before;
18922
+ if (json2)
18923
+ return console.log(JSON.stringify(after, null, 2));
18924
+ if (after.length === 0)
18925
+ return console.log(`${issue2.identifier} has no tasks.`);
18926
+ printTasks(after);
18927
+ }
18928
+ });
18929
+
18577
18930
  // src/commands/issues/unrelate.ts
18578
18931
  var relationEntries = (relations, kind) => {
18579
18932
  switch (kind) {
@@ -18612,7 +18965,7 @@ var unrelate = command({
18612
18965
  });
18613
18966
 
18614
18967
  // src/commands/issues/update.ts
18615
- var update = command({
18968
+ var update2 = command({
18616
18969
  name: "update",
18617
18970
  description: "Rewrite an issue's title or description, or attach files",
18618
18971
  positionals: {
@@ -18644,7 +18997,23 @@ var update = command({
18644
18997
  var issues = group({
18645
18998
  name: "issues",
18646
18999
  description: "Track and triage issues",
18647
- commands: [create, list, get, update, set2, route, start, relate, unrelate, comment, remove]
19000
+ commands: [
19001
+ create,
19002
+ list2,
19003
+ get,
19004
+ update2,
19005
+ set2,
19006
+ labels,
19007
+ route,
19008
+ start,
19009
+ submit,
19010
+ startReview,
19011
+ tasks,
19012
+ relate,
19013
+ unrelate,
19014
+ comment,
19015
+ remove2
19016
+ ]
18648
19017
  });
18649
19018
 
18650
19019
  // src/lib/group.ts
@@ -18665,7 +19034,7 @@ var detectRepoGroup = async () => {
18665
19034
  var groupForCreate = async (group2) => group2 === null ? undefined : group2 ?? await detectRepoGroup();
18666
19035
 
18667
19036
  // src/commands/pages/create.ts
18668
- var create2 = command({
19037
+ var create3 = command({
18669
19038
  name: "create",
18670
19039
  description: "Publish a page and print its URL",
18671
19040
  positionals: {
@@ -18717,7 +19086,7 @@ var get2 = command({
18717
19086
  var formatBytes = (bytes) => bytes < 1024 ? `${bytes} B` : `${Math.round(bytes / 1024)} KB`;
18718
19087
 
18719
19088
  // src/commands/pages/list.ts
18720
- var list2 = command({
19089
+ var list3 = command({
18721
19090
  name: "list",
18722
19091
  description: "List your published pages",
18723
19092
  options: {
@@ -18747,7 +19116,7 @@ var list2 = command({
18747
19116
  });
18748
19117
 
18749
19118
  // src/commands/pages/remove.ts
18750
- var remove2 = command({
19119
+ var remove3 = command({
18751
19120
  name: "delete",
18752
19121
  description: "Delete a page",
18753
19122
  positionals: {
@@ -18774,7 +19143,7 @@ var revert = command({
18774
19143
  });
18775
19144
 
18776
19145
  // src/commands/pages/update.ts
18777
- var update2 = command({
19146
+ var update3 = command({
18778
19147
  name: "update",
18779
19148
  description: "Replace a page's HTML, title, group, mode, or visibility",
18780
19149
  positionals: {
@@ -18835,7 +19204,7 @@ var versions2 = command({
18835
19204
  var pages = group({
18836
19205
  name: "pages",
18837
19206
  description: "Publish HTML documents to the web",
18838
- commands: [create2, list2, get2, update2, versions2, revert, remove2]
19207
+ commands: [create3, list3, get2, update3, versions2, revert, remove3]
18839
19208
  });
18840
19209
 
18841
19210
  // src/commands/project.ts
@@ -18868,7 +19237,7 @@ var project = command({
18868
19237
  });
18869
19238
 
18870
19239
  // src/commands/projects/create.ts
18871
- var create3 = command({
19240
+ var create4 = command({
18872
19241
  name: "create",
18873
19242
  description: "Create a project and print its id",
18874
19243
  positionals: {
@@ -18939,7 +19308,7 @@ Milestones:`);
18939
19308
  });
18940
19309
 
18941
19310
  // src/commands/projects/list.ts
18942
- var list3 = command({
19311
+ var list4 = command({
18943
19312
  name: "list",
18944
19313
  description: "List your projects, most recently updated first",
18945
19314
  options: {
@@ -18974,7 +19343,7 @@ More projects exist; raise --limit past ${limit}.`);
18974
19343
  });
18975
19344
 
18976
19345
  // src/commands/projects/remove.ts
18977
- var remove3 = command({
19346
+ var remove4 = command({
18978
19347
  name: "delete",
18979
19348
  description: "Delete a project and its milestones (its issues survive, projectless)",
18980
19349
  positionals: {
@@ -19020,7 +19389,7 @@ var set3 = command({
19020
19389
  });
19021
19390
 
19022
19391
  // src/commands/projects/update.ts
19023
- var update3 = command({
19392
+ var update4 = command({
19024
19393
  name: "update",
19025
19394
  description: "Rewrite a project's name, summary, or description",
19026
19395
  positionals: {
@@ -19050,7 +19419,7 @@ var update3 = command({
19050
19419
  var projects = group({
19051
19420
  name: "projects",
19052
19421
  description: "Manage projects",
19053
- commands: [create3, list3, get3, update3, set3, remove3]
19422
+ commands: [create4, list4, get3, update4, set3, remove4]
19054
19423
  });
19055
19424
 
19056
19425
  // src/commands/upgrade.ts
@@ -19079,6 +19448,9 @@ var rootCommand = group({
19079
19448
  }
19080
19449
  });
19081
19450
 
19451
+ // src/lib/errors.ts
19452
+ var errorMessage = (error51) => error51 instanceof ConvexError && typeof error51.data === "string" ? error51.data : error51.message;
19453
+
19082
19454
  // src/lib/update-check.ts
19083
19455
  var latestVersion = async () => {
19084
19456
  const cached2 = await Bun.file(CACHE_PATH).json().catch(() => null).then(cacheSchema.safeParse);
@@ -19116,7 +19488,7 @@ try {
19116
19488
  if (args[0] !== "upgrade")
19117
19489
  await maybeNotifyUpdate();
19118
19490
  } catch (error51) {
19119
- console.error(error51.message);
19491
+ console.error(errorMessage(error51));
19120
19492
  process.exitCode = 1;
19121
19493
  } finally {
19122
19494
  closePrompts();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@islamihab/kds",
3
- "version": "0.2.4",
3
+ "version": "0.4.0",
4
4
  "description": "Command-line client for Kai Dev Studio",
5
5
  "license": "MIT",
6
6
  "publishConfig": {