@koda-sl/baker-cli 0.368.0 → 0.369.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/README.md CHANGED
@@ -3459,7 +3459,8 @@ baker actions list # default: bucketed (claimable, myCla
3459
3459
  # then most recent. The `blocked` bucket is ordered closest-to-ready first.
3460
3460
  baker actions list --bucketed=false --status pending
3461
3461
  baker actions list --bucketed=false --sort priority # flat list, do-first order (default); use --sort recent for newest-first
3462
- baker actions list --output md # id-first Markdown; works for both the bucketed and flat shapes
3462
+ baker actions list --output md # id-first Markdown; each bucket's guidance on its heading, blockers/holder under a row; flat rows add a one-line summary
3463
+ baker actions list --full # whole descriptions and full records (large on a real backlog)
3463
3464
  baker actions list --search "conversion goal" --output md # find Tasks by words in name/description/tags (flat, best match first)
3464
3465
  # With BAKER_CHAT_ID, the bucketed list folds in THIS chat's draft: staged creates appear in
3465
3466
  # `draftCreates`; published actions being completed/discarded/updated carry a `draftStatus` marker.
package/dist/cli.js CHANGED
@@ -9258,9 +9258,10 @@ var linkCommand = defineCommand7({
9258
9258
 
9259
9259
  // src/commands/actions/list.ts
9260
9260
  import { defineCommand as defineCommand8 } from "citty";
9261
+ import { Lexer } from "marked";
9261
9262
  registerSchema({
9262
9263
  command: "actions.list",
9263
- description: 'List actions for the current company. Default: pre-bucketed (claimable/myClaims/blocked/claimedByOthers/completed/discarded), each bucket ordered do-first (blockers before blocked, then highest-leverage). The bucketed view reads the whole open backlog, so nothing pending is ever hidden from it. Set --bucketed=false for a flat list filterable by --status, orderable by --sort, and windowed by --limit. Looking for one Task by name? --search "conversion goal" --output md returns only the matching Tasks instead of the whole backlog.',
9264
+ description: 'List actions for the current company. Compact by default: a bucketed Task is its id and name (plus its blockers, holder or staged change); a flat row (--search, --bucketed=false) adds status, priority, tags and a one-line `summary` of its description. Checking whether a Task already exists? --search "<words>" returns the matches with their summaries. --full prints whole descriptions (or `baker actions get <id>` for one Task). Default: pre-bucketed (claimable/myClaims/blocked/claimedByOthers/completed/discarded), each bucket ordered do-first (blockers before blocked, then highest-leverage). The bucketed view reads the whole open backlog, so nothing pending is ever hidden from it. Set --bucketed=false for a flat list filterable by --status, orderable by --sort, and windowed by --limit. Looking for one Task by name? --search "conversion goal" --output md returns only the matching Tasks instead of the whole backlog.',
9264
9265
  args: {
9265
9266
  search: {
9266
9267
  type: "string",
@@ -9288,13 +9289,19 @@ registerSchema({
9288
9289
  description: `How many Tasks a flat list reads, newest first (only with --bucketed=false). Default: ${ACTIONS_LIST_DEFAULT_LIMIT}. When the read comes back full, hints[] says so \u2014 raise --limit to reach older Tasks.`,
9289
9290
  required: false
9290
9291
  },
9292
+ full: {
9293
+ type: "boolean",
9294
+ description: "Print every Task's whole description and full record instead of the compact row. Large on a real backlog \u2014 prefer --search, or `baker actions get <id>` for one Task.",
9295
+ required: false,
9296
+ default: false
9297
+ },
9291
9298
  output: { type: "string", description: "Output format: json|md. Default: json", required: false }
9292
9299
  }
9293
9300
  });
9294
9301
  var listCommand2 = defineCommand8({
9295
9302
  meta: {
9296
9303
  name: "list",
9297
- description: "List actions. Default: bucketed view (claimable, myClaims, blocked, claimedByOthers). Use --bucketed=false for raw filter by --status, or --search <text> to find Tasks by name."
9304
+ description: "List actions, one short row per Task (id and name; --search rows add a one-line summary). Default: bucketed view (claimable, myClaims, blocked, claimedByOthers). Use --bucketed=false for raw filter by --status, --search <text> to find Tasks by name, --full for whole descriptions."
9298
9305
  },
9299
9306
  args: {
9300
9307
  search: { type: "string", description: "Find Tasks by words in name/description/tags", required: false },
@@ -9302,6 +9309,12 @@ var listCommand2 = defineCommand8({
9302
9309
  status: { type: "string", description: "Status filter (raw mode)", required: false },
9303
9310
  sort: { type: "string", description: "Order (raw mode): priority|recent", required: false },
9304
9311
  limit: { type: "string", description: "How many Tasks to read (raw mode)", required: false },
9312
+ full: {
9313
+ type: "boolean",
9314
+ description: "Whole descriptions and full records",
9315
+ required: false,
9316
+ default: false
9317
+ },
9305
9318
  output: { type: "string", description: "Output format: json|md", required: false }
9306
9319
  },
9307
9320
  run: async ({ args: args5 }) => {
@@ -9309,9 +9322,16 @@ var listCommand2 = defineCommand8({
9309
9322
  const body = buildListRequest(args5, getEnv().BAKER_CHAT_ID);
9310
9323
  const response = await apiPost("/api/actions/list", body);
9311
9324
  const hints2 = body.bucketed === false && body.limit !== void 0 && response.ok && Array.isArray(response.data) ? buildListHints({ returned: response.data.length, limit: body.limit }) : [];
9312
- const envelope = hints2.length > 0 ? { ...response, hints: hints2 } : response;
9313
- if (args5.output === "md" && envelope.ok) {
9314
- process.stdout.write(renderMarkdown(envelope.data, hints2));
9325
+ if (args5.output === "md" && response.ok) {
9326
+ process.stdout.write(renderMarkdown(response.data, hints2, { full: args5.full === true }));
9327
+ return;
9328
+ }
9329
+ const compact3 = !args5.full && response.ok;
9330
+ const shaped = compact3 ? { ...response, data: compactListData(response.data) } : response;
9331
+ const envelope = hints2.length > 0 ? { ...shaped, hints: hints2 } : shaped;
9332
+ if (compact3) {
9333
+ process.stdout.write(`${JSON.stringify(envelope)}
9334
+ `);
9315
9335
  return;
9316
9336
  }
9317
9337
  writeJson(envelope);
@@ -9341,6 +9361,81 @@ function buildListRequest(args5, chatId) {
9341
9361
  }
9342
9362
  return body;
9343
9363
  }
9364
+ var SUMMARY_MAX_CHARS = 100;
9365
+ function plainText(tokens) {
9366
+ return tokens.map((token) => {
9367
+ if (token.type === "image" || token.type === "html") {
9368
+ return "";
9369
+ }
9370
+ if (token.type === "br") {
9371
+ return " ";
9372
+ }
9373
+ if ("tokens" in token && Array.isArray(token.tokens)) {
9374
+ return plainText(token.tokens);
9375
+ }
9376
+ return "text" in token && typeof token.text === "string" ? token.text : "";
9377
+ }).join("");
9378
+ }
9379
+ function firstProse(tokens) {
9380
+ for (const token of tokens) {
9381
+ let text2 = "";
9382
+ if (token.type === "paragraph" || token.type === "text") {
9383
+ text2 = plainText(Array.isArray(token.tokens) ? token.tokens : [token]);
9384
+ } else if (token.type === "list") {
9385
+ text2 = firstProse(token.items.flatMap((item) => item.tokens));
9386
+ } else if (token.type === "blockquote") {
9387
+ text2 = firstProse(token.tokens ?? []);
9388
+ }
9389
+ const line = text2.replace(/\s+/g, " ").trim();
9390
+ if (line) {
9391
+ return line;
9392
+ }
9393
+ }
9394
+ return "";
9395
+ }
9396
+ function summarizeDescription(description) {
9397
+ const line = firstProse(Lexer.lex(description));
9398
+ if (line.length <= SUMMARY_MAX_CHARS) {
9399
+ return line;
9400
+ }
9401
+ const cut = line.slice(0, SUMMARY_MAX_CHARS - 1);
9402
+ const lastSpace = cut.lastIndexOf(" ");
9403
+ return `${(lastSpace > SUMMARY_MAX_CHARS / 2 ? cut.slice(0, lastSpace) : cut).trimEnd()}\u2026`;
9404
+ }
9405
+ function compactBucketEntry(entry) {
9406
+ const { description: _description, status: _status, hint: _hint, ...rest } = entry;
9407
+ return rest;
9408
+ }
9409
+ function compactFlatRow(entry) {
9410
+ const nested = entry.action;
9411
+ const doc = nested && typeof nested === "object" ? nested : entry;
9412
+ const { id, name, status, hint } = toRow(entry);
9413
+ const assignee = entry.assignee && typeof entry.assignee === "object" ? entry.assignee : null;
9414
+ return {
9415
+ id,
9416
+ name,
9417
+ status,
9418
+ ...typeof doc.priority === "string" ? { priority: doc.priority } : {},
9419
+ ...Array.isArray(doc.tags) && doc.tags.length > 0 ? { tags: doc.tags } : {},
9420
+ summary: summarizeDescription(typeof doc.description === "string" ? doc.description : ""),
9421
+ ...hint ? { hint } : {},
9422
+ ...typeof assignee?.name === "string" ? { assignee: assignee.name } : {}
9423
+ };
9424
+ }
9425
+ function compactListData(data) {
9426
+ if (Array.isArray(data)) {
9427
+ return data.map((entry) => compactFlatRow(entry));
9428
+ }
9429
+ if (!data || typeof data !== "object") {
9430
+ return data;
9431
+ }
9432
+ return Object.fromEntries(
9433
+ Object.entries(data).map(([bucket, entries]) => [
9434
+ bucket,
9435
+ Array.isArray(entries) ? entries.map((entry) => compactBucketEntry(entry)) : entries
9436
+ ])
9437
+ );
9438
+ }
9344
9439
  function toRow(entry) {
9345
9440
  const nested = entry.action;
9346
9441
  const doc = nested && typeof nested === "object" ? nested : entry;
@@ -9358,35 +9453,69 @@ function toRow(entry) {
9358
9453
  hint
9359
9454
  };
9360
9455
  }
9361
- function renderEntry(entry) {
9456
+ function renderEntry(entry, full) {
9362
9457
  const row = toRow(entry);
9363
9458
  const suffix = row.status ? ` [${row.status}]` : "";
9364
9459
  const lines = [`- \`${row.id}\` ${row.name}${suffix}`];
9460
+ const nested = entry.action;
9461
+ const doc = nested && typeof nested === "object" ? nested : entry;
9462
+ const description = typeof doc.description === "string" ? doc.description : "";
9463
+ const text2 = typeof entry.summary === "string" ? entry.summary : full ? description : summarizeDescription(description);
9464
+ if (typeof text2 === "string" && text2.trim()) {
9465
+ lines.push(
9466
+ ...text2.trim().split("\n").map((line) => line ? ` ${line}` : "")
9467
+ );
9468
+ }
9365
9469
  if (row.hint) {
9366
9470
  lines.push(` ${row.hint}`);
9367
9471
  }
9368
9472
  return lines;
9369
9473
  }
9370
- function renderBuckets(data) {
9474
+ function sharedHint(entries) {
9475
+ const first = entries[0]?.hint;
9476
+ return typeof first === "string" && entries.every((entry) => entry.hint === first) ? first : "";
9477
+ }
9478
+ function renderBucketRow(entry, shared) {
9479
+ const { id, name } = toRow(entry);
9480
+ const suffix = typeof entry.draftStatus === "string" ? ` [${entry.draftStatus}]` : "";
9481
+ const lines = [`- \`${id}\` ${name}${suffix}`];
9482
+ if (typeof entry.hint === "string" && entry.hint && entry.hint !== shared) {
9483
+ lines.push(` ${entry.hint}`);
9484
+ }
9485
+ if (Array.isArray(entry.blockedBy) && entry.blockedBy.length > 0) {
9486
+ const blockers = entry.blockedBy.map((b) => `\`${b.id}\` ${b.name}`);
9487
+ lines.push(` blocked by: ${blockers.join(", ")}`);
9488
+ }
9489
+ const holder = entry.claimedByChat;
9490
+ if (typeof holder?.title === "string") {
9491
+ lines.push(` held by chat: ${holder.title}`);
9492
+ }
9493
+ return lines;
9494
+ }
9495
+ function renderBuckets(data, full) {
9371
9496
  const lines = [];
9372
9497
  for (const [bucket, entries] of Object.entries(data)) {
9373
9498
  if (!Array.isArray(entries) || entries.length === 0) {
9374
9499
  continue;
9375
9500
  }
9376
- lines.push(`## ${bucket} (${entries.length})`);
9377
- for (const entry of entries) {
9378
- lines.push(...renderEntry(entry));
9501
+ const rows = entries;
9502
+ if (full) {
9503
+ lines.push(`## ${bucket} (${rows.length})`, ...rows.flatMap((entry) => renderEntry(entry, true)));
9504
+ } else {
9505
+ const shared = sharedHint(rows);
9506
+ lines.push(`## ${bucket} (${rows.length})${shared ? `: ${shared}` : ""}`);
9507
+ lines.push(...rows.flatMap((entry) => renderBucketRow(entry, shared)));
9379
9508
  }
9380
9509
  lines.push("");
9381
9510
  }
9382
9511
  return lines;
9383
9512
  }
9384
- function renderMarkdown(data, hints2) {
9513
+ function renderMarkdown(data, hints2, { full = false } = {}) {
9385
9514
  let lines;
9386
9515
  if (Array.isArray(data)) {
9387
- lines = data.flatMap((entry) => renderEntry(entry));
9516
+ lines = data.flatMap((entry) => renderEntry(entry, full));
9388
9517
  } else if (data && typeof data === "object") {
9389
- lines = renderBuckets(data);
9518
+ lines = renderBuckets(data, full);
9390
9519
  } else {
9391
9520
  lines = [];
9392
9521
  }