trelly 0.1.1 → 0.2.1
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/.claude-plugin/plugin.json +15 -0
- package/.codex-plugin/plugin.json +25 -0
- package/.cursor-plugin/mcp.json +11 -0
- package/.cursor-plugin/plugin.json +15 -0
- package/.mcp.json +8 -0
- package/PLUGIN.md +85 -0
- package/PRIVACY.md +43 -0
- package/README.md +58 -9
- package/assets/logo.svg +6 -0
- package/assets/terminal.gif +0 -0
- package/bin/install-cursor-plugin-local.sh +15 -0
- package/package.json +18 -4
- package/skills/README.md +115 -0
- package/skills/trelly/SKILL.md +190 -0
- package/skills/trelly-mcp/SKILL.md +175 -0
- package/src/api/client.ts +18 -3
- package/src/cli/commands/boards.ts +6 -6
- package/src/cli/commands/cards.ts +19 -1
- package/src/cli/ui/app.tsx +263 -70
- package/src/index.test.ts +9 -0
- package/src/util/attachment.ts +29 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: trelly
|
|
3
|
+
description: >-
|
|
4
|
+
Operate the trelly Trello CLI (npm trelly; bins trelly/trello): auth setup/login,
|
|
5
|
+
human vs --json output, boards/lists/cards, search, attachments, GitHub PR/commit
|
|
6
|
+
links on cards, trello ui, trello api. Use when the user asks to run trelly/trello
|
|
7
|
+
commands, link a GitHub PR or commit to a Trello card, or automate Trello with trelly.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# trelly
|
|
11
|
+
|
|
12
|
+
Fast Trello CLI (`npm install -g trelly`). **Human Trello-styled output by default**;
|
|
13
|
+
**`--json` for scripts**. Commands: **`trelly`** or **`trello`** (same binary).
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g trelly
|
|
19
|
+
trelly auth setup # once: API key from https://trello.com/power-ups/admin
|
|
20
|
+
trelly auth login # browser Allow → saves token
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
From source: clone [brandonkramer/trelly](https://github.com/brandonkramer/trelly),
|
|
24
|
+
`bun install`, then `./bin/trelly auth setup`.
|
|
25
|
+
|
|
26
|
+
Auth notes (common confusion):
|
|
27
|
+
|
|
28
|
+
- Power-Up admin is **developer registration**, not installing a Power-Up on a board.
|
|
29
|
+
- Pick any workspace you **admin** (personal is fine) — does not limit which boards you can use.
|
|
30
|
+
- After login the CLI is **you** on Trello (member permissions, not board admin).
|
|
31
|
+
|
|
32
|
+
Credentials: `~/.config/trelly/config.json` (migrates from `~/.config/trello-cli/`; never read/log/commit).
|
|
33
|
+
|
|
34
|
+
## Output contract
|
|
35
|
+
|
|
36
|
+
| Goal | Flags |
|
|
37
|
+
|------|--------|
|
|
38
|
+
| Human (default) | *(none)* |
|
|
39
|
+
| JSON envelope | `--json` → `{ ok, profile, data }` or `{ ok: false, error, ... }` |
|
|
40
|
+
| Pretty JSON | `--json --pretty` |
|
|
41
|
+
|
|
42
|
+
- **Scripts:** always `--json` if parsing stdout.
|
|
43
|
+
- **`--pretty` alone** does not emit JSON; it only indents `--json` output.
|
|
44
|
+
- Errors: red `✗` in human mode; exit code `1`.
|
|
45
|
+
|
|
46
|
+
## Common commands
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
trelly boards list
|
|
50
|
+
trelly --json boards list | jq '.data[].name'
|
|
51
|
+
trelly boards lists BOARD_ID
|
|
52
|
+
trelly boards cards BOARD_ID # or: api GET /boards/{id}/cards
|
|
53
|
+
trelly lists cards LIST_ID
|
|
54
|
+
trelly cards get CARD_ID --fields name,desc
|
|
55
|
+
trelly cards comments CARD_ID
|
|
56
|
+
trelly cards create --list LIST_ID --name "Task"
|
|
57
|
+
trelly cards move CARD_ID --list OTHER_LIST_ID
|
|
58
|
+
trelly cards comment CARD_ID --text "Done"
|
|
59
|
+
trelly cards attachments CARD_ID
|
|
60
|
+
trelly cards add-attachment CARD_ID --url "https://github.com/org/repo/pull/42"
|
|
61
|
+
trelly search "query"
|
|
62
|
+
trelly ui BOARD_ID # interactive kanban (TTY required)
|
|
63
|
+
trelly auth list
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Global: `-p, --profile <name>` (or `TRELLO_PROFILE`).
|
|
67
|
+
|
|
68
|
+
## Raw API escape hatch
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
trelly api -X GET --path /members/me
|
|
72
|
+
trelly api -X PUT --path /cards/CARD_ID --query idList=LIST_ID
|
|
73
|
+
trelly api -X POST --path /cards --body '{"idList":"LIST_ID","name":"Hi"}'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Request body flag is **`--body`** (not `--json` — that flag is global output).
|
|
77
|
+
|
|
78
|
+
## Card attachments
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
trelly cards attachments CARD_ID
|
|
82
|
+
trelly cards add-attachment CARD_ID --url "https://…" [--name "label"]
|
|
83
|
+
trelly cards add-attachment CARD_ID --file ./screenshot.png [--name "label"]
|
|
84
|
+
trelly cards delete-attachment CARD_ID ATTACHMENT_ID
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Pass **exactly one** of `--url` or `--file`. In `trelly ui`, open a card's detail (**⏎**), then **a** opens the attach prompt (URL or local path).
|
|
88
|
+
|
|
89
|
+
## GitHub PR / commit on a card
|
|
90
|
+
|
|
91
|
+
Boards with the **GitHub Power-Up** enabled can show rich PR metadata in the Trello UI.
|
|
92
|
+
trelly attaches the same underlying **URL attachment** — it does **not** drive the
|
|
93
|
+
Power-Up picker or OAuth flow.
|
|
94
|
+
|
|
95
|
+
### Link a PR or commit (preferred)
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Pull request — set --name so the attachment is scannable in lists/UI
|
|
99
|
+
trelly cards add-attachment CARD_ID \
|
|
100
|
+
--url "https://github.com/PangoliaDev/dogster/pull/197" \
|
|
101
|
+
--name "#197 fix(pre-existing-tests-and-types)"
|
|
102
|
+
|
|
103
|
+
# Commit
|
|
104
|
+
trelly cards add-attachment CARD_ID \
|
|
105
|
+
--url "https://github.com/PangoliaDev/dogster/commit/2d856ea" \
|
|
106
|
+
--name "2d856ea Merge PR #197"
|
|
107
|
+
|
|
108
|
+
# Issue (same mechanism)
|
|
109
|
+
trelly cards add-attachment CARD_ID \
|
|
110
|
+
--url "https://github.com/PangoliaDev/dogster/issues/42"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Accepted URL shapes: `…/pull/N`, `…/commit/SHA`, `…/issues/N`, `…/tree/branch`.
|
|
114
|
+
Use the canonical `https://github.com/…` URL (no `/files` or `/commits` tab suffix).
|
|
115
|
+
|
|
116
|
+
### Power-Up UI vs trelly URL attachment
|
|
117
|
+
|
|
118
|
+
| Feature | GitHub Power-Up (Trello UI) | `cards add-attachment --url` |
|
|
119
|
+
|--------|-----------------------------|------------------------------|
|
|
120
|
+
| Link on card | Yes | Yes |
|
|
121
|
+
| Readable `--name` / PR title | Yes (auto) | Set `--name` yourself (recommended) |
|
|
122
|
+
| CI/check badges on card front | Yes | No |
|
|
123
|
+
| Pick PR from repo browser | Yes | No — pass URL |
|
|
124
|
+
| Comment back on GitHub PR | Yes (optional setting) | No |
|
|
125
|
+
|
|
126
|
+
If the user needs badges or GitHub-side back-links, attach via **Power-Ups → GitHub**
|
|
127
|
+
in Trello. For agent/CLI workflows (ship PR → link card → move list), URL attachment
|
|
128
|
+
is enough.
|
|
129
|
+
|
|
130
|
+
### Agent workflow patterns
|
|
131
|
+
|
|
132
|
+
**After opening or merging a PR** — attach and optionally move the card:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
CARD_ID=…
|
|
136
|
+
PR_URL="https://github.com/PangoliaDev/dogster/pull/197"
|
|
137
|
+
trelly cards add-attachment "$CARD_ID" --url "$PR_URL" --name "#197 fix scope"
|
|
138
|
+
trelly cards move "$CARD_ID" --list PENDING_REVIEW_LIST_ID
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Fallback — comment only** (visible in activity, not Attachments):
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
trelly cards comment CARD_ID --text "PR: https://github.com/org/repo/pull/42"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Inspect what's linked:**
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
trelly --json cards attachments CARD_ID | jq '.data[] | {name, url}'
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Raw API (same as CLI)
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
trelly api -X POST --path "/cards/CARD_ID/attachments" \
|
|
157
|
+
--query "url=https://github.com/org/repo/pull/42" \
|
|
158
|
+
--query "name=#42 feature title"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Custom fields (list-type)
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
trelly api -X PUT \
|
|
165
|
+
--path "/cards/CARD_ID/customField/FIELD_ID/item" \
|
|
166
|
+
--body '{"idValue":"OPTION_ID"}'
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Safety
|
|
170
|
+
|
|
171
|
+
| Action | CLI | Reversible? |
|
|
172
|
+
|--------|-----|-------------|
|
|
173
|
+
| Close | `cards archive`, `boards archive` | Yes (Trello UI) |
|
|
174
|
+
| Destroy | `cards delete`, `boards delete` | **No** |
|
|
175
|
+
|
|
176
|
+
Prefer **archive** unless the user explicitly wants permanent deletion.
|
|
177
|
+
|
|
178
|
+
## Multi-profile
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
trelly auth login --profile work
|
|
182
|
+
trelly -p work boards list
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Env override: `TRELLO_APP_API_KEY`, `TRELLO_API_KEY`, `TRELLO_TOKEN`, `TRELLO_PROFILE`.
|
|
186
|
+
|
|
187
|
+
## MCP vs CLI
|
|
188
|
+
|
|
189
|
+
- **CLI:** human or `--json` on stdout.
|
|
190
|
+
- **MCP:** separate stdio server (`trelly-mcp`) — see **trelly-mcp** skill.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: trelly-mcp
|
|
3
|
+
description: >-
|
|
4
|
+
Configure and use the trelly MCP stdio server (trello_boards_list,
|
|
5
|
+
trello_card_create, trello_search, trello_api, etc.). Use when wiring Cursor/Claude
|
|
6
|
+
MCP, linking GitHub PRs/commits to Trello cards from an agent, or choosing MCP vs CLI.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# trelly-mcp
|
|
10
|
+
|
|
11
|
+
MCP server for Trello (npm package **trelly**, bin **`trelly-mcp`**). Returns JSON
|
|
12
|
+
envelope on every tool: `{ ok, profile, data }` /
|
|
13
|
+
`{ ok: false, error, status?, details? }`. Never uses CLI human/Ink output.
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
### 1. Auth (CLI, once)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
trelly auth setup
|
|
21
|
+
trelly auth login
|
|
22
|
+
trelly auth list
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Cursor — plugin or `~/.cursor/mcp.json`
|
|
26
|
+
|
|
27
|
+
**Plugin (skills + MCP):** after `npm install -g trelly`:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cp -R "$(npm root -g)/trelly" ~/.cursor/plugins/local/trelly
|
|
31
|
+
# or from clone: ./bin/install-cursor-plugin-local.sh
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**MCP only** — `~/.cursor/mcp.json`:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"trelly": {
|
|
40
|
+
"command": "trelly-mcp",
|
|
41
|
+
"env": {
|
|
42
|
+
"TRELLO_PROFILE": "default"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
See [mcp.example.json](../../mcp.example.json).
|
|
50
|
+
|
|
51
|
+
### 3. Restart the IDE
|
|
52
|
+
|
|
53
|
+
Reload MCP servers after editing config.
|
|
54
|
+
|
|
55
|
+
### 4. Smoke test (optional)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
cd trello-cli && bun run mcp
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Starts stdio MCP manually (IDE normally launches `trelly-mcp` itself).
|
|
62
|
+
|
|
63
|
+
## Using tools
|
|
64
|
+
|
|
65
|
+
- Pass **`profile`** on any tool for a non-default account (or set `TRELLO_PROFILE` in env).
|
|
66
|
+
- Read **`ok`** before using **`data`**.
|
|
67
|
+
- Prefer **`trello_card_archive`** / **`trello_board_archive`** to close items.
|
|
68
|
+
- **`trello_card_delete`** is **permanent** — no MCP board-delete tool.
|
|
69
|
+
|
|
70
|
+
## Tool catalog
|
|
71
|
+
|
|
72
|
+
| Tool | Purpose |
|
|
73
|
+
|------|---------|
|
|
74
|
+
| `trello_profiles_list` | Saved profiles + default |
|
|
75
|
+
| `trello_member_me` | Authenticated member |
|
|
76
|
+
| `trello_boards_list` | Member boards (`filter`, `fields`) |
|
|
77
|
+
| `trello_board_get` | Board by id |
|
|
78
|
+
| `trello_board_create` | Create board |
|
|
79
|
+
| `trello_board_archive` | Close board (reversible) |
|
|
80
|
+
| `trello_board_lists` | Lists on board |
|
|
81
|
+
| `trello_board_cards` | All cards on board |
|
|
82
|
+
| `trello_list_create` | Create list |
|
|
83
|
+
| `trello_list_cards` | Cards in list |
|
|
84
|
+
| `trello_card_get` | Card (`fields` optional) |
|
|
85
|
+
| `trello_card_create` | Create card on list |
|
|
86
|
+
| `trello_card_update` | Update card fields map |
|
|
87
|
+
| `trello_card_move` | Move to another list |
|
|
88
|
+
| `trello_card_comments` | List comments |
|
|
89
|
+
| `trello_card_comment` | Add comment |
|
|
90
|
+
| `trello_card_archive` | Close card (reversible) |
|
|
91
|
+
| `trello_card_delete` | **Permanent** delete |
|
|
92
|
+
| `trello_checklist_create` | Checklist on card |
|
|
93
|
+
| `trello_checklist_add_item` | Checklist item |
|
|
94
|
+
| `trello_label_create` | Board label |
|
|
95
|
+
| `trello_card_add_label` | Label on card |
|
|
96
|
+
| `trello_search` | Search Trello |
|
|
97
|
+
| `trello_webhooks_list` | Token webhooks |
|
|
98
|
+
| `trello_webhook_create` | Create webhook |
|
|
99
|
+
| `trello_webhook_delete` | Delete webhook |
|
|
100
|
+
| `trello_api` | Raw REST (`method`, `path`, `query`, `body`) |
|
|
101
|
+
|
|
102
|
+
There is **no dedicated attachment MCP tool** yet — use `trello_api` or the CLI
|
|
103
|
+
`cards add-attachment` (see **trelly** skill).
|
|
104
|
+
|
|
105
|
+
## GitHub PR / commit on a card (MCP)
|
|
106
|
+
|
|
107
|
+
Boards with the **GitHub Power-Up** show rich PR UI when attached through Trello.
|
|
108
|
+
Agents link the same way via **`trello_api`** — a URL attachment, not the Power-Up
|
|
109
|
+
OAuth picker.
|
|
110
|
+
|
|
111
|
+
### Attach PR or commit
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
trello_api
|
|
115
|
+
method: POST
|
|
116
|
+
path: /cards/{cardId}/attachments
|
|
117
|
+
query: { "url": "https://github.com/org/repo/pull/42", "name": "#42 feature title" }
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Commit:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
query: { "url": "https://github.com/org/repo/commit/abc1234", "name": "abc1234 message" }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Always set **`name`** to something scannable (`#N title` or short SHA + subject).
|
|
127
|
+
|
|
128
|
+
### List or remove attachments
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
trello_api GET /cards/{cardId}/attachments
|
|
132
|
+
trello_api DELETE /cards/{cardId}/attachments/{attachmentId}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Comment fallback
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
trello_card_comment cardId text: "PR: https://github.com/org/repo/pull/42"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Comments appear in card activity; they are **not** Attachments.
|
|
142
|
+
|
|
143
|
+
### Power-Up vs MCP/API
|
|
144
|
+
|
|
145
|
+
| Feature | GitHub Power-Up (UI) | `trello_api` URL attachment |
|
|
146
|
+
|--------|----------------------|-----------------------------|
|
|
147
|
+
| Link on card | Yes | Yes |
|
|
148
|
+
| PR title / custom name | Auto | Set `name` in query |
|
|
149
|
+
| CI badges on card front | Yes | No |
|
|
150
|
+
| GitHub PR back-link comment | Yes (optional) | No |
|
|
151
|
+
|
|
152
|
+
Use the Power-Up UI when the user needs badges or GitHub-side comments. For
|
|
153
|
+
agent workflows (link PR after push, move card to review), POST the GitHub URL.
|
|
154
|
+
|
|
155
|
+
### Typical agent sequence
|
|
156
|
+
|
|
157
|
+
1. `trello_search` or `trello_list_cards` — find the card
|
|
158
|
+
2. `trello_api` POST `/cards/{id}/attachments` with PR URL + name
|
|
159
|
+
3. `trello_card_move` — e.g. To do → Pending review
|
|
160
|
+
4. Optional: `trello_card_comment` with the same PR URL
|
|
161
|
+
|
|
162
|
+
## When to use MCP vs CLI
|
|
163
|
+
|
|
164
|
+
| Use MCP | Use CLI |
|
|
165
|
+
|---------|---------|
|
|
166
|
+
| IDE agent managing Trello in chat | Terminal, shell scripts, jq pipelines |
|
|
167
|
+
| Structured tool calls with schemas | `trello ui` interactive board |
|
|
168
|
+
| Cursor/Codex/Claude with MCP wired | CI with `--json` |
|
|
169
|
+
|
|
170
|
+
For terminal work, invoke the **trelly** skill instead.
|
|
171
|
+
|
|
172
|
+
## Extending
|
|
173
|
+
|
|
174
|
+
New tools: `src/mcp/tools/` — zod input, envelope `outputSchema`,
|
|
175
|
+
`readOnlyHint` / `destructiveHint`. See [AGENTS.md](../../AGENTS.md).
|
package/src/api/client.ts
CHANGED
|
@@ -28,7 +28,7 @@ export class TrelloClient {
|
|
|
28
28
|
method: string,
|
|
29
29
|
path: string,
|
|
30
30
|
query: Query = {},
|
|
31
|
-
body?: JsonValue,
|
|
31
|
+
body?: JsonValue | FormData,
|
|
32
32
|
): Promise<T> {
|
|
33
33
|
const url = new URL(`${this.base}${path.startsWith("/") ? path : `/${path}`}`);
|
|
34
34
|
|
|
@@ -43,7 +43,9 @@ export class TrelloClient {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
const init: RequestInit = { method, headers };
|
|
46
|
-
if (body
|
|
46
|
+
if (body instanceof FormData) {
|
|
47
|
+
init.body = body; // fetch sets the multipart boundary
|
|
48
|
+
} else if (body !== undefined) {
|
|
47
49
|
headers["Content-Type"] = "application/json";
|
|
48
50
|
init.body = JSON.stringify(body);
|
|
49
51
|
}
|
|
@@ -63,7 +65,11 @@ export class TrelloClient {
|
|
|
63
65
|
return this.request("GET", path, query);
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
post<T = JsonValue>(
|
|
68
|
+
post<T = JsonValue>(
|
|
69
|
+
path: string,
|
|
70
|
+
query?: Query,
|
|
71
|
+
body?: JsonValue | FormData,
|
|
72
|
+
): Promise<T> {
|
|
67
73
|
return this.request("POST", path, query, body);
|
|
68
74
|
}
|
|
69
75
|
|
|
@@ -218,6 +224,15 @@ export class TrelloClient {
|
|
|
218
224
|
return this.post(`/cards/${id}/attachments`, query);
|
|
219
225
|
}
|
|
220
226
|
|
|
227
|
+
/** Upload a local file as a card attachment (multipart). */
|
|
228
|
+
cardUploadAttachment(id: string, form: FormData) {
|
|
229
|
+
return this.post(`/cards/${id}/attachments`, {}, form);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
cardDeleteAttachment(id: string, attachmentId: string) {
|
|
233
|
+
return this.delete(`/cards/${id}/attachments/${attachmentId}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
221
236
|
cardCustomFieldItems(id: string) {
|
|
222
237
|
return this.get(`/cards/${id}/customFieldItems`);
|
|
223
238
|
}
|
|
@@ -71,7 +71,7 @@ export function registerBoardCommands(program: Command): void {
|
|
|
71
71
|
boards
|
|
72
72
|
.command("archive <id>")
|
|
73
73
|
.description("Close (archive) a board — reversible in Trello UI")
|
|
74
|
-
.action((id, cmd) =>
|
|
74
|
+
.action((id, _opts, cmd) =>
|
|
75
75
|
run(cmd, async () => {
|
|
76
76
|
const { client } = getClient(rootOpts(cmd).profile);
|
|
77
77
|
return client.boardArchive(id);
|
|
@@ -81,7 +81,7 @@ export function registerBoardCommands(program: Command): void {
|
|
|
81
81
|
boards
|
|
82
82
|
.command("delete <id>")
|
|
83
83
|
.description("Permanently delete a board — irreversible")
|
|
84
|
-
.action((id, cmd) =>
|
|
84
|
+
.action((id, _opts, cmd) =>
|
|
85
85
|
run(cmd, async () => {
|
|
86
86
|
const { client } = getClient(rootOpts(cmd).profile);
|
|
87
87
|
return client.boardDelete(id);
|
|
@@ -102,7 +102,7 @@ export function registerBoardCommands(program: Command): void {
|
|
|
102
102
|
boards
|
|
103
103
|
.command("cards <boardId>")
|
|
104
104
|
.description("List cards on a board")
|
|
105
|
-
.action((boardId, cmd) =>
|
|
105
|
+
.action((boardId, _opts, cmd) =>
|
|
106
106
|
run(cmd, async () => {
|
|
107
107
|
const { client } = getClient(rootOpts(cmd).profile);
|
|
108
108
|
return client.boardCards(boardId);
|
|
@@ -112,7 +112,7 @@ export function registerBoardCommands(program: Command): void {
|
|
|
112
112
|
boards
|
|
113
113
|
.command("labels <boardId>")
|
|
114
114
|
.description("List labels on a board")
|
|
115
|
-
.action((boardId, cmd) =>
|
|
115
|
+
.action((boardId, _opts, cmd) =>
|
|
116
116
|
run(cmd, async () => {
|
|
117
117
|
const { client } = getClient(rootOpts(cmd).profile);
|
|
118
118
|
return client.boardLabels(boardId);
|
|
@@ -122,7 +122,7 @@ export function registerBoardCommands(program: Command): void {
|
|
|
122
122
|
boards
|
|
123
123
|
.command("members <boardId>")
|
|
124
124
|
.description("List board members")
|
|
125
|
-
.action((boardId, cmd) =>
|
|
125
|
+
.action((boardId, _opts, cmd) =>
|
|
126
126
|
run(cmd, async () => {
|
|
127
127
|
const { client } = getClient(rootOpts(cmd).profile);
|
|
128
128
|
return client.boardMembers(boardId);
|
|
@@ -143,7 +143,7 @@ export function registerBoardCommands(program: Command): void {
|
|
|
143
143
|
boards
|
|
144
144
|
.command("custom-fields <boardId>")
|
|
145
145
|
.description("List custom field definitions")
|
|
146
|
-
.action((boardId, cmd) =>
|
|
146
|
+
.action((boardId, _opts, cmd) =>
|
|
147
147
|
run(cmd, async () => {
|
|
148
148
|
const { client } = getClient(rootOpts(cmd).profile);
|
|
149
149
|
return client.boardCustomFields(boardId);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
+
import { attachmentForm } from "../../util/attachment.ts";
|
|
2
3
|
import { getClient, parseJsonFlag, parseKvPairs } from "../context.ts";
|
|
3
4
|
import { rootOpts, run } from "./run.ts";
|
|
4
5
|
|
|
@@ -176,15 +177,32 @@ export function registerCardCommands(program: Command): void {
|
|
|
176
177
|
|
|
177
178
|
cards
|
|
178
179
|
.command("add-attachment <id>")
|
|
179
|
-
.
|
|
180
|
+
.option("--url <url>", "Attachment URL")
|
|
181
|
+
.option("--file <path>", "Local file to upload")
|
|
180
182
|
.option("--name <name>", "Attachment name")
|
|
181
183
|
.action((id, opts, cmd) =>
|
|
182
184
|
run(cmd, async () => {
|
|
183
185
|
const { client } = getClient(rootOpts(cmd).profile);
|
|
186
|
+
if (!opts.url === !opts.file) {
|
|
187
|
+
throw new Error("Pass exactly one of --url or --file");
|
|
188
|
+
}
|
|
189
|
+
if (opts.file) {
|
|
190
|
+
return client.cardUploadAttachment(id, attachmentForm(opts.file, opts.name));
|
|
191
|
+
}
|
|
184
192
|
return client.cardAddAttachment(id, { url: opts.url, name: opts.name });
|
|
185
193
|
}),
|
|
186
194
|
);
|
|
187
195
|
|
|
196
|
+
cards
|
|
197
|
+
.command("delete-attachment <id> <attachmentId>")
|
|
198
|
+
.description("Delete an attachment from a card")
|
|
199
|
+
.action((id, attachmentId, _opts, cmd) =>
|
|
200
|
+
run(cmd, async () => {
|
|
201
|
+
const { client } = getClient(rootOpts(cmd).profile);
|
|
202
|
+
return client.cardDeleteAttachment(id, attachmentId);
|
|
203
|
+
}),
|
|
204
|
+
);
|
|
205
|
+
|
|
188
206
|
cards.command("custom-fields <id>").action((id, _opts, cmd) =>
|
|
189
207
|
run(cmd, async () => {
|
|
190
208
|
const { client } = getClient(rootOpts(cmd).profile);
|