smashspace 0.2.0 → 0.2.2

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
@@ -89,12 +89,19 @@ smash scan --list "やること" # cards as JSON (id/title/list only)
89
89
  smash scan --list "やること" --full # + description/agentMeta/labels — pick up work in ONE request
90
90
  smash create "Fix signup bug" # add a card (to the first list, or --list; --desc for a body)
91
91
  smash move <cardId> "レビュー" # move a card to a list by name
92
+ smash attachment add <cardId> ./out.png # upload a local file (agent-generated images, etc.)
92
93
  smash archive <cardId> # archive (soft-delete) a card
93
94
  smash --help # full command list (board/list/card/…)
94
95
  ```
95
96
 
96
97
  Output is a concise line by default; add `--json` for machine-readable output on
97
- any command. For agents:
98
+ any command.
99
+
100
+ **Field naming** (three concepts, three names — not a typo): a card's is
101
+ `title`, an artifact's is `name` (`--name`), a file/attachment's is `filename`
102
+ (with `sizeBytes`).
103
+
104
+ For agents:
98
105
 
99
106
  ```bash
100
107
  smash scan --full # or --fields description,agentMeta
package/dist/smash.mjs CHANGED
@@ -3395,7 +3395,7 @@ import { randomBytes } from "node:crypto";
3395
3395
  import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
3396
3396
  import { platform as platform2 } from "node:os";
3397
3397
  import { createInterface } from "node:readline/promises";
3398
- import { relative, join as join3, dirname as dirname3 } from "node:path";
3398
+ import { relative, join as join3, dirname as dirname3, basename } from "node:path";
3399
3399
  import { stdin, stdout } from "node:process";
3400
3400
 
3401
3401
  // ../../shared/board-registry.ts
@@ -3654,6 +3654,10 @@ Use \`smash <group> --help\` for the full surface (\`board\`/\`list\`/\`card\`/
3654
3654
  \`comment\`/\`checklist\`/\`label\`/\`artifact\`/\`attachment\`/\`agent-meta\`/
3655
3655
  \`external-refs\`/\`assignees\`).
3656
3656
 
3657
+ **Field naming** (three concepts, three names \u2014 not a typo): a card's is
3658
+ \`title\`, an artifact's is \`name\` (\`--name\`), a file/attachment's is
3659
+ \`filename\` (with \`sizeBytes\`).
3660
+
3657
3661
  ## List matching
3658
3662
 
3659
3663
  Use exact canonical names when present. For Todo-like selection, match
@@ -4343,7 +4347,47 @@ artifactCmd.command("delete <cardId> <artifactId>").description("Delete an artif
4343
4347
  await api(`/api/cards/${cardId}/artifacts/${artifactId}`, { method: "DELETE" });
4344
4348
  console.log(`\u2713 artifact ${artifactId} deleted`);
4345
4349
  });
4350
+ var ATTACH_EXT_MIME = {
4351
+ png: "image/png",
4352
+ jpg: "image/jpeg",
4353
+ jpeg: "image/jpeg",
4354
+ gif: "image/gif",
4355
+ webp: "image/webp",
4356
+ svg: "image/svg+xml",
4357
+ bmp: "image/bmp",
4358
+ ico: "image/x-icon",
4359
+ pdf: "application/pdf",
4360
+ txt: "text/plain",
4361
+ md: "text/markdown",
4362
+ csv: "text/csv",
4363
+ json: "application/json",
4364
+ zip: "application/zip"
4365
+ };
4366
+ function guessMime(name) {
4367
+ const ext = name.split(".").pop()?.toLowerCase() ?? "";
4368
+ return ATTACH_EXT_MIME[ext] ?? "application/octet-stream";
4369
+ }
4346
4370
  var attachmentCmd = program2.command("attachment").description("Card attachments");
4371
+ attachmentCmd.command("add <cardId> <file>").alias("upload").description("Upload a local file as a card attachment (\u2264100 MB)").action(async (cardId, filePath) => {
4372
+ const buf = await readFile2(filePath);
4373
+ const name = basename(filePath);
4374
+ const type = guessMime(name);
4375
+ const fd = new FormData();
4376
+ fd.append("file", new Blob([buf], { type }), name);
4377
+ const baseUrl = resolveBaseUrl();
4378
+ const token = await resolveToken(baseUrl);
4379
+ const res = await fetch(new URL(`/api/cards/${cardId}/attachments`, baseUrl), {
4380
+ method: "POST",
4381
+ headers: token ? { Authorization: `Bearer ${token}` } : {},
4382
+ body: fd
4383
+ });
4384
+ if (!res.ok) {
4385
+ const text = await res.text().catch(() => "");
4386
+ throw new Error(`API ${res.status} /api/cards/${cardId}/attachments: ${text || res.statusText}`);
4387
+ }
4388
+ const att = await res.json();
4389
+ show(att, [`\u2713 attached "${att.filename ?? name}" to ${cardId} (${att.id ?? "?"})`]);
4390
+ });
4347
4391
  attachmentCmd.command("list <cardId>").description("List attachments on a card").action(async (cardId) => {
4348
4392
  const items = await api(`/api/cards/${cardId}/attachments`);
4349
4393
  show(items, [`\u2713 ${items.length} attachment(s)`]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smashspace",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "SmashSpace CLI + MCP — operate SmashSpace boards from your terminal, Claude Code, Cursor, and Codex.",
5
5
  "type": "module",
6
6
  "bin": {