smashspace 0.5.0 → 0.7.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
@@ -4259,18 +4259,32 @@ cardCmd.command("comment <cardId> <body>").description("Add a comment to a card"
4259
4259
  function collectRepeated(value, previous) {
4260
4260
  return [...previous, value];
4261
4261
  }
4262
+ program2.command("done <cardId>").description(
4263
+ "Mark a card done \u2014 moves it to the board's done list (it stays on the board). Not the same as `smash archive`, which takes it off."
4264
+ ).action(async (cardId) => {
4265
+ const result = await api(`/api/cards/${cardId}/complete`, {
4266
+ method: "POST"
4267
+ });
4268
+ show(result.card, [`\u2713 card ${result.card.id} \u2192 ${result.listTitle}`]);
4269
+ });
4262
4270
  program2.command("cards").description(
4263
4271
  "List cards on the resolved board \u2014 light by default (no description). Filter by list/assignee, pick columns with --fields."
4264
- ).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(
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(
4265
4273
  "--fields <list>",
4266
4274
  "comma-separated columns (default: id,title,listId,listTitle,updatedAt). Add description only when you need bodies."
4267
4275
  ).option("--limit <n>", "max cards per page (default 100, max 500)").option("--cursor <cursor>", "continue from a previous response's cursor").action(async (opts) => {
4276
+ if (opts.status && !["open", "done", "all"].includes(opts.status)) {
4277
+ console.error("--status must be one of: open, done, all");
4278
+ process.exit(1);
4279
+ }
4268
4280
  const ctx = resolveContext(opts);
4269
4281
  const params = new URLSearchParams();
4270
4282
  if (opts.list)
4271
4283
  params.set("list", opts.list);
4272
4284
  if (opts.assignee)
4273
4285
  params.set("assignee", opts.assignee);
4286
+ if (opts.status)
4287
+ params.set("status", opts.status);
4274
4288
  if (opts.fields)
4275
4289
  params.set("fields", opts.fields);
4276
4290
  if (opts.limit)
@@ -4564,6 +4578,13 @@ tokenCmd.command("revoke <boardId> <tokenId>").description("Revoke a write token
4564
4578
  );
4565
4579
  show(revoked, [`\u2713 token ${revoked.id} revoked at ${revoked.revokedAt}`]);
4566
4580
  });
4581
+ listCmd.command("done <listId>").description("Mark a list as done (cards in it are excluded by `smash cards --status open`)").option("--no-done", "unmark it instead").action(async (listId, opts) => {
4582
+ const list = await api(`/api/lists/${listId}`, {
4583
+ method: "PATCH",
4584
+ body: JSON.stringify({ isDone: opts.done })
4585
+ });
4586
+ show(list, [`\u2713 list ${list.id} (${list.title}) isDone=${list.isDone}`]);
4587
+ });
4567
4588
  var labelCmd = program2.command("label").description("Labels");
4568
4589
  labelCmd.command("create <boardId> <name>").description("Create a board label").option(
4569
4590
  "--color <color>",
@@ -15553,18 +15553,25 @@ var tools = [
15553
15553
  },
15554
15554
  {
15555
15555
  name: "smash_rename_list",
15556
- description: "Rename a list.",
15556
+ description: "Rename a list, and/or mark it as a done list. Cards in a list with isDone=true are excluded by smash_list_cards({status: 'open'}), so an agent can ask for open work without knowing the board's list names.",
15557
15557
  inputSchema: {
15558
15558
  type: "object",
15559
15559
  properties: {
15560
15560
  listId: { type: "string" },
15561
- title: { type: "string" }
15561
+ title: { type: "string" },
15562
+ isDone: {
15563
+ type: "boolean",
15564
+ description: "Treat cards in this list as done"
15565
+ }
15562
15566
  },
15563
- required: ["listId", "title"]
15567
+ required: ["listId"]
15564
15568
  },
15565
15569
  handler: async (args) => api(`/api/lists/${args.listId}`, {
15566
15570
  method: "PATCH",
15567
- body: JSON.stringify({ title: args.title })
15571
+ body: JSON.stringify({
15572
+ ...typeof args.title === "string" ? { title: args.title } : {},
15573
+ ...typeof args.isDone === "boolean" ? { isDone: args.isDone } : {}
15574
+ })
15568
15575
  })
15569
15576
  },
15570
15577
  {
@@ -15710,6 +15717,11 @@ var tools = [
15710
15717
  boardId: { type: "string" },
15711
15718
  list: { type: "string", description: "List name (case-insensitive) or list id" },
15712
15719
  assignee: { type: "string", description: "Assignee id or display name" },
15720
+ status: {
15721
+ type: "string",
15722
+ enum: ["open", "done", "all"],
15723
+ 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
+ },
15713
15725
  fields: {
15714
15726
  type: "array",
15715
15727
  items: { type: "string" },
@@ -15726,6 +15738,8 @@ var tools = [
15726
15738
  params.set("list", args.list);
15727
15739
  if (typeof args.assignee === "string" && args.assignee)
15728
15740
  params.set("assignee", args.assignee);
15741
+ if (typeof args.status === "string" && args.status)
15742
+ params.set("status", args.status);
15729
15743
  if (Array.isArray(args.fields) && args.fields.length > 0)
15730
15744
  params.set("fields", args.fields.join(","));
15731
15745
  if (typeof args.limit === "number")
@@ -15786,9 +15800,19 @@ var tools = [
15786
15800
  })
15787
15801
  })
15788
15802
  },
15803
+ {
15804
+ name: "smash_complete_card",
15805
+ description: "Mark a card done: it moves to the list flagged as done on its board and STAYS on the board, where people can see it. Use this when work finished. smash_delete_card is different \u2014 that archives the card off the board. Fails with a message when no list is marked done yet (mark one with smash_rename_list({listId, isDone: true})).",
15806
+ inputSchema: {
15807
+ type: "object",
15808
+ properties: { cardId: { type: "string" } },
15809
+ required: ["cardId"]
15810
+ },
15811
+ handler: async (args) => api(`/api/cards/${args.cardId}/complete`, { method: "POST" })
15812
+ },
15789
15813
  {
15790
15814
  name: "smash_delete_card",
15791
- description: "Archive a card (soft delete). It leaves the board but is kept: it shows up in the space's archived column and smash_restore_card puts it back. Nothing is destroyed here \u2014 smash_permanently_delete_card is the irreversible one.",
15815
+ description: "Archive a card (soft delete) \u2014 NOT the same as marking it done. It leaves the board but is kept: it shows up in the space's archived column and smash_restore_card puts it back. Nothing is destroyed here \u2014 smash_permanently_delete_card is the irreversible one.",
15792
15816
  inputSchema: {
15793
15817
  type: "object",
15794
15818
  properties: { cardId: { type: "string" } },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smashspace",
3
- "version": "0.5.0",
3
+ "version": "0.7.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": {