smashspace 0.7.0 → 0.8.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/smash.mjs CHANGED
@@ -4128,7 +4128,7 @@ ${detail.card.description}`);
4128
4128
  }
4129
4129
  }
4130
4130
  });
4131
- cardCmd.command("update <cardId>").description("Update card fields (title, description, due date, cover, checklist title)").option("--title <title>", "New title").option("-d, --description <description>", "New description (markdown)").option("--desc <description>", "alias for --description").option("--desc-file <path>", "read description from a file (or - for stdin)").option("--due <iso>", "Due date as ISO string, or empty string to clear").option("--cover <attachmentId>", "Cover attachment ID, or empty string to clear").option("--checklist-title <title>", "Custom checklist section title, or empty string to clear").action(
4131
+ cardCmd.command("update <cardId>").description("Update card fields (title, description, due date, cover, checklist title)").option("--title <title>", "New title").option("-d, --description <description>", "New description (markdown)").option("--desc <description>", "alias for --description").option("--desc-file <path>", "read description from a file (or - for stdin)").option("--due <iso>", "Due date as ISO string, or empty string to clear").option("--cover <attachmentId>", "Cover attachment ID, or empty string to clear").option("--checklist-title <title>", "Custom checklist section title, or empty string to clear").option("--comment <body>", "Add a comment in the same call").option("--comment-author <name>", "Author name for --comment").option("--to <id>", "Address the comment to an assignee id (repeatable)", collectRepeated, []).option("--list <name>", "Move the card to this list (name or id) in the same call").option("--done", "Move the card to the board's done list (wins over --list)").action(
4132
4132
  async (cardId, opts) => {
4133
4133
  const patch = {};
4134
4134
  if (opts.title !== void 0)
@@ -4144,15 +4144,35 @@ cardCmd.command("update <cardId>").description("Update card fields (title, descr
4144
4144
  patch.coverAttachmentId = opts.cover === "" ? null : opts.cover;
4145
4145
  if (opts.checklistTitle !== void 0)
4146
4146
  patch.checklistTitle = opts.checklistTitle === "" ? null : opts.checklistTitle;
4147
+ if (opts.comment !== void 0) {
4148
+ patch.comment = {
4149
+ body: opts.comment,
4150
+ ...opts.commentAuthor ? { authorName: opts.commentAuthor } : {},
4151
+ ...opts.to.length > 0 ? { recipients: opts.to } : {}
4152
+ };
4153
+ }
4154
+ if (opts.done)
4155
+ patch.complete = true;
4156
+ else if (opts.list !== void 0)
4157
+ patch.list = opts.list;
4147
4158
  if (Object.keys(patch).length === 0) {
4148
- console.error("Provide at least one of: --title, --description, --desc-file, --due, --cover, --checklist-title");
4159
+ console.error(
4160
+ "Provide at least one of: --title, --description, --desc-file, --due, --cover, --checklist-title, --comment, --list, --done"
4161
+ );
4149
4162
  process.exit(1);
4150
4163
  }
4151
4164
  const card = await api(`/api/cards/${cardId}`, {
4152
4165
  method: "PATCH",
4153
4166
  body: JSON.stringify(patch)
4154
4167
  });
4155
- show(card, [`\u2713 card ${card.id} updated`]);
4168
+ const done = [];
4169
+ if (opts.comment !== void 0)
4170
+ done.push("commented");
4171
+ if (opts.done)
4172
+ done.push("completed");
4173
+ else if (opts.list !== void 0)
4174
+ done.push(`moved to ${opts.list}`);
4175
+ show(card, [`\u2713 card ${card.id} updated${done.length ? ` (${done.join(", ")})` : ""}`]);
4156
4176
  }
4157
4177
  );
4158
4178
  cardCmd.command("move <cardId>").description("Move a card to a list (and optionally a position)").requiredOption("--list <listId>", "Destination list ID").option("--position <n>", "Target index (0-based)", "0").action(
@@ -4269,7 +4289,7 @@ program2.command("done <cardId>").description(
4269
4289
  });
4270
4290
  program2.command("cards").description(
4271
4291
  "List cards on the resolved board \u2014 light by default (no description). Filter by list/assignee, pick columns with --fields."
4272
- ).option("-b, --board <label>", "board label from config").option("--board-id <id>", "explicit board id (bypass config)").option("-l, --list <name>", "only cards in this list (name or id)").option("--assignee <idOrName>", "only cards assigned to this id or display name").option("--status <status>", "open (skip cards in lists marked done) | done | all (default)").option(
4292
+ ).option("-b, --board <label>", "board label from config").option("--board-id <id>", "explicit board id (bypass config)").option("-l, --list <name>", "only cards in this list (name or id)").option("--assignee <idOrName>", "only cards assigned to this id or display name").option("--status <status>", "open (skip cards in lists marked done) | done | all (default)").option("--stale <days>", "only cards untouched for N days, oldest first (adds lastActivityAt)").option(
4273
4293
  "--fields <list>",
4274
4294
  "comma-separated columns (default: id,title,listId,listTitle,updatedAt). Add description only when you need bodies."
4275
4295
  ).option("--limit <n>", "max cards per page (default 100, max 500)").option("--cursor <cursor>", "continue from a previous response's cursor").action(async (opts) => {
@@ -4285,6 +4305,8 @@ program2.command("cards").description(
4285
4305
  params.set("assignee", opts.assignee);
4286
4306
  if (opts.status)
4287
4307
  params.set("status", opts.status);
4308
+ if (opts.stale)
4309
+ params.set("staleDays", opts.stale);
4288
4310
  if (opts.fields)
4289
4311
  params.set("fields", opts.fields);
4290
4312
  if (opts.limit)
@@ -4303,7 +4325,9 @@ program2.command("cards").description(
4303
4325
  }
4304
4326
  for (const card of result.cards) {
4305
4327
  const listTitle = typeof card.listTitle === "string" ? `[${card.listTitle}] ` : "";
4306
- console.log(`${listTitle}${String(card.title ?? "")} (${String(card.id ?? "")})`);
4328
+ const last = typeof card.lastActivityAt === "string" ? card.lastActivityAt : null;
4329
+ const age = last ? ` ${last.slice(0, 10)} (${Math.floor((Date.now() - Date.parse(last)) / 864e5)}\u65E5\u524D)` : "";
4330
+ console.log(`${listTitle}${String(card.title ?? "")} (${String(card.id ?? "")})${age}`);
4307
4331
  }
4308
4332
  console.log(
4309
4333
  `
@@ -15615,7 +15615,7 @@ var tools = [
15615
15615
  },
15616
15616
  {
15617
15617
  name: "smash_update_card",
15618
- description: "Update a card's fields. All fields except cardId are optional. Pass null to clear dueAt / coverAttachmentId / checklistTitle / description.",
15618
+ description: "Update a card, and optionally comment on it and move it IN THE SAME CALL. Advancing a card is usually 'write what happened, then move it' \u2014 pass `comment` plus `list` (or `complete: true`) instead of making three calls. All fields except cardId are optional. Pass null to clear dueAt / coverAttachmentId / checklistTitle / description.",
15619
15619
  inputSchema: {
15620
15620
  type: "object",
15621
15621
  properties: {
@@ -15636,6 +15636,33 @@ var tools = [
15636
15636
  checklistTitle: {
15637
15637
  type: ["string", "null"],
15638
15638
  description: "Custom title for the checklist section, or null to reset to default"
15639
+ },
15640
+ comment: {
15641
+ type: "object",
15642
+ description: "Add one comment in the same call",
15643
+ properties: {
15644
+ body: { type: "string" },
15645
+ authorName: { type: "string" },
15646
+ recipients: {
15647
+ type: "array",
15648
+ items: { type: "string" },
15649
+ description: "Assignee ids this comment is addressed to"
15650
+ }
15651
+ },
15652
+ required: ["body"]
15653
+ },
15654
+ list: {
15655
+ type: "string",
15656
+ description: "Move the card to this list (name, case-insensitive, or id)"
15657
+ },
15658
+ position: { type: "number", description: "Position within the destination list" },
15659
+ complete: {
15660
+ type: "boolean",
15661
+ description: "Move the card to the board's done list (wins over `list`). Fails with 409 when no list is marked done."
15662
+ },
15663
+ assignees: {
15664
+ type: ["array", "null"],
15665
+ description: "Replace the card's assignees (same shape as smash_set_assignees)"
15639
15666
  }
15640
15667
  },
15641
15668
  required: ["cardId"]
@@ -15652,6 +15679,16 @@ var tools = [
15652
15679
  patch.coverAttachmentId = args.coverAttachmentId;
15653
15680
  if (args.checklistTitle !== void 0)
15654
15681
  patch.checklistTitle = args.checklistTitle;
15682
+ if (args.comment !== void 0)
15683
+ patch.comment = args.comment;
15684
+ if (typeof args.list === "string")
15685
+ patch.list = args.list;
15686
+ if (typeof args.position === "number")
15687
+ patch.position = args.position;
15688
+ if (args.complete === true)
15689
+ patch.complete = true;
15690
+ if (args.assignees !== void 0)
15691
+ patch.assignees = args.assignees;
15655
15692
  return api(`/api/cards/${args.cardId}`, {
15656
15693
  method: "PATCH",
15657
15694
  body: JSON.stringify(patch)
@@ -15722,10 +15759,14 @@ var tools = [
15722
15759
  enum: ["open", "done", "all"],
15723
15760
  description: "open skips cards sitting in a list marked done (a flag on the list, not a name match); done keeps only those. Default all."
15724
15761
  },
15762
+ staleDays: {
15763
+ type: "number",
15764
+ description: "Only cards untouched for this many days, oldest first. Each row gets lastActivityAt, so you can tell a two-week stall from a three-month one. Use it to find work that stopped without anyone noticing."
15765
+ },
15725
15766
  fields: {
15726
15767
  type: "array",
15727
15768
  items: { type: "string" },
15728
- description: "Columns to return: id, boardId, title, description, listId, listTitle, position, dueAt, labelIds, checklistTitle, agentMeta, externalRefs, assignees, customData, createdAt, updatedAt"
15769
+ description: "Columns to return: id, boardId, title, description, listId, listTitle, position, dueAt, labelIds, checklistTitle, agentMeta, externalRefs, assignees, customData, source, createdAt, updatedAt, lastActivityAt"
15729
15770
  },
15730
15771
  limit: { type: "number", description: "Max cards per page (default 100, max 500)" },
15731
15772
  cursor: { type: "string", description: "Cursor from a previous response" }
@@ -15740,6 +15781,8 @@ var tools = [
15740
15781
  params.set("assignee", args.assignee);
15741
15782
  if (typeof args.status === "string" && args.status)
15742
15783
  params.set("status", args.status);
15784
+ if (typeof args.staleDays === "number")
15785
+ params.set("staleDays", String(args.staleDays));
15743
15786
  if (Array.isArray(args.fields) && args.fields.length > 0)
15744
15787
  params.set("fields", args.fields.join(","));
15745
15788
  if (typeof args.limit === "number")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smashspace",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "SmashSpace CLI + MCP — operate SmashSpace boards from your terminal, Claude Code, Cursor, and Codex.",
5
5
  "type": "module",
6
6
  "bin": {