claude-trello-cli 0.1.6 → 0.1.7
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 +27 -4
- package/dist/index.js +295 -74
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,12 +5,13 @@ Point [Claude Code](https://docs.anthropic.com/en/docs/claude-code) at a Trello
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx claude-trello-cli login
|
|
8
|
+
npx claude-trello-cli register # create an account (or `login` if you have one)
|
|
9
|
+
npx claude-trello-cli setup # connect Trello + save your Anthropic API key
|
|
9
10
|
cd ~/my-project
|
|
10
|
-
npx claude-trello-cli run
|
|
11
|
+
npx claude-trello-cli run # pick a board and start working
|
|
11
12
|
```
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
Everything happens in your terminal — no web app required.
|
|
14
15
|
|
|
15
16
|
## What It Does
|
|
16
17
|
|
|
@@ -78,11 +79,25 @@ claude-trello run
|
|
|
78
79
|
|
|
79
80
|
## Prerequisites
|
|
80
81
|
|
|
81
|
-
- **A
|
|
82
|
+
- **A Trello account** — you'll connect it during `setup`
|
|
83
|
+
- **An Anthropic API key** — get one from [console.anthropic.com](https://console.anthropic.com/settings/keys)
|
|
82
84
|
- **Node.js 20+**
|
|
83
85
|
|
|
84
86
|
## Commands
|
|
85
87
|
|
|
88
|
+
### `claude-trello-cli register`
|
|
89
|
+
|
|
90
|
+
Create a new account. You'll be prompted for your name, email, and password.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npx claude-trello-cli register
|
|
94
|
+
npx claude-trello-cli register --server https://your-self-hosted-instance.com
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
| Flag | Description |
|
|
98
|
+
|------|-------------|
|
|
99
|
+
| `-s, --server <url>` | Server URL (default: `https://ct.joshualevine.me`) |
|
|
100
|
+
|
|
86
101
|
### `claude-trello-cli login`
|
|
87
102
|
|
|
88
103
|
Sign in with your email and password. Your session is stored at `~/.config/claude-trello/config.json` with restricted file permissions.
|
|
@@ -96,6 +111,14 @@ npx claude-trello-cli login --server https://your-app.vercel.app
|
|
|
96
111
|
|------|-------------|
|
|
97
112
|
| `-s, --server <url>` | Server URL (default: `https://ct.joshualevine.me`) |
|
|
98
113
|
|
|
114
|
+
### `claude-trello-cli setup`
|
|
115
|
+
|
|
116
|
+
Interactive wizard that walks you through connecting Trello and saving your Anthropic API key. Opens your browser for Trello authorization and polls until complete.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
npx claude-trello-cli setup
|
|
120
|
+
```
|
|
121
|
+
|
|
99
122
|
### `claude-trello-cli run`
|
|
100
123
|
|
|
101
124
|
The main command. Select a board interactively, review the cards, and launch a Claude Code session.
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command8 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/login.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -101,14 +101,14 @@ async function apiFetch(path, options) {
|
|
|
101
101
|
}
|
|
102
102
|
return res.json();
|
|
103
103
|
}
|
|
104
|
-
async function signIn(serverUrl, email,
|
|
104
|
+
async function signIn(serverUrl, email, password4) {
|
|
105
105
|
const res = await fetch(`${serverUrl}/api/auth/sign-in/email`, {
|
|
106
106
|
method: "POST",
|
|
107
107
|
headers: {
|
|
108
108
|
"Content-Type": "application/json",
|
|
109
109
|
Origin: serverUrl
|
|
110
110
|
},
|
|
111
|
-
body: JSON.stringify({ email, password:
|
|
111
|
+
body: JSON.stringify({ email, password: password4 }),
|
|
112
112
|
redirect: "manual"
|
|
113
113
|
});
|
|
114
114
|
if (!res.ok) {
|
|
@@ -128,6 +128,43 @@ async function signIn(serverUrl, email, password2) {
|
|
|
128
128
|
const data = await res.json();
|
|
129
129
|
return { cookies, user: data.user };
|
|
130
130
|
}
|
|
131
|
+
async function signUp(serverUrl, name, email, password4) {
|
|
132
|
+
const res = await fetch(`${serverUrl}/api/auth/sign-up/email`, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers: {
|
|
135
|
+
"Content-Type": "application/json",
|
|
136
|
+
Origin: serverUrl
|
|
137
|
+
},
|
|
138
|
+
body: JSON.stringify({ name, email, password: password4 }),
|
|
139
|
+
redirect: "manual"
|
|
140
|
+
});
|
|
141
|
+
if (!res.ok) {
|
|
142
|
+
let errorMsg = "Registration failed";
|
|
143
|
+
try {
|
|
144
|
+
const body = await res.json();
|
|
145
|
+
errorMsg = body.message || body.error || errorMsg;
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
throw new ApiError(res.status, errorMsg);
|
|
149
|
+
}
|
|
150
|
+
const setCookieHeaders = res.headers.getSetCookie?.() ?? [];
|
|
151
|
+
const cookies = setCookieHeaders.map((c) => c.split(";")[0]).join("; ");
|
|
152
|
+
if (!cookies) {
|
|
153
|
+
throw new ApiError(500, "No session cookie received from server");
|
|
154
|
+
}
|
|
155
|
+
const data = await res.json();
|
|
156
|
+
return { cookies, user: data.user };
|
|
157
|
+
}
|
|
158
|
+
async function getTrelloAuthUrl() {
|
|
159
|
+
const data = await apiFetch("/api/trello/authorize");
|
|
160
|
+
return data.url;
|
|
161
|
+
}
|
|
162
|
+
async function saveApiKey(apiKey) {
|
|
163
|
+
await apiFetch("/api/settings/apikey", {
|
|
164
|
+
method: "POST",
|
|
165
|
+
body: JSON.stringify({ apiKey })
|
|
166
|
+
});
|
|
167
|
+
}
|
|
131
168
|
async function getIntegrationStatus() {
|
|
132
169
|
return apiFetch("/api/settings/status");
|
|
133
170
|
}
|
|
@@ -169,18 +206,200 @@ var loginCommand = new Command("login").description("Sign in to Claude Trello Br
|
|
|
169
206
|
}
|
|
170
207
|
});
|
|
171
208
|
|
|
172
|
-
// src/commands/
|
|
209
|
+
// src/commands/register.ts
|
|
173
210
|
import { Command as Command2 } from "commander";
|
|
211
|
+
import { input as input2, password as password2 } from "@inquirer/prompts";
|
|
174
212
|
import chalk2 from "chalk";
|
|
175
|
-
|
|
213
|
+
import ora2 from "ora";
|
|
214
|
+
var registerCommand = new Command2("register").description("Create a new Claude Trello Bridge account").option("-s, --server <url>", "Server URL (default: https://ct.joshualevine.me)").action(async (opts) => {
|
|
215
|
+
const serverUrl = opts.server || getServerUrl();
|
|
216
|
+
console.log(chalk2.bold("Create a Claude Trello Bridge account"));
|
|
217
|
+
console.log(chalk2.dim(`Server: ${serverUrl}
|
|
218
|
+
`));
|
|
219
|
+
const name = await input2({ message: "Name:" });
|
|
220
|
+
const email = await input2({ message: "Email:" });
|
|
221
|
+
const pass = await password2({ message: "Password (min 8 characters):" });
|
|
222
|
+
if (pass.length < 8) {
|
|
223
|
+
console.log(chalk2.red("Password must be at least 8 characters."));
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
const spinner = ora2("Creating account...").start();
|
|
227
|
+
try {
|
|
228
|
+
const { cookies, user } = await signUp(serverUrl, name, email, pass);
|
|
229
|
+
saveConfig({
|
|
230
|
+
serverUrl,
|
|
231
|
+
sessionCookie: cookies,
|
|
232
|
+
userEmail: user.email,
|
|
233
|
+
userName: user.name
|
|
234
|
+
});
|
|
235
|
+
spinner.succeed(
|
|
236
|
+
`Account created! Signed in as ${chalk2.bold(user.name)} (${user.email})`
|
|
237
|
+
);
|
|
238
|
+
console.log(
|
|
239
|
+
chalk2.dim(
|
|
240
|
+
"\n Run `claude-trello setup` to connect Trello and add your API key.\n"
|
|
241
|
+
)
|
|
242
|
+
);
|
|
243
|
+
} catch (err) {
|
|
244
|
+
spinner.fail(err instanceof Error ? err.message : "Registration failed");
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// src/commands/setup.ts
|
|
250
|
+
import { exec } from "child_process";
|
|
251
|
+
import { Command as Command3 } from "commander";
|
|
252
|
+
import { password as password3, confirm } from "@inquirer/prompts";
|
|
253
|
+
import chalk3 from "chalk";
|
|
254
|
+
import ora3 from "ora";
|
|
255
|
+
function openBrowser(url) {
|
|
256
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
257
|
+
exec(`${cmd} ${JSON.stringify(url)}`);
|
|
258
|
+
}
|
|
259
|
+
async function pollForTrello(timeoutMs = 12e4, intervalMs = 2e3) {
|
|
260
|
+
const deadline = Date.now() + timeoutMs;
|
|
261
|
+
while (Date.now() < deadline) {
|
|
262
|
+
try {
|
|
263
|
+
const status = await getIntegrationStatus();
|
|
264
|
+
if (status.trelloLinked) return true;
|
|
265
|
+
} catch {
|
|
266
|
+
}
|
|
267
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
268
|
+
}
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
var setupCommand = new Command3("setup").description("Connect Trello and save your Anthropic API key").action(async () => {
|
|
272
|
+
if (!isLoggedIn()) {
|
|
273
|
+
console.log(
|
|
274
|
+
chalk3.red(
|
|
275
|
+
"Not logged in. Run `claude-trello register` or `claude-trello login` first."
|
|
276
|
+
)
|
|
277
|
+
);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
console.log(chalk3.bold("\nClaude Trello Bridge \u2014 Setup\n"));
|
|
281
|
+
const statusSpinner = ora3("Checking current status...").start();
|
|
282
|
+
let status;
|
|
283
|
+
try {
|
|
284
|
+
status = await getIntegrationStatus();
|
|
285
|
+
statusSpinner.stop();
|
|
286
|
+
} catch (err) {
|
|
287
|
+
statusSpinner.fail(
|
|
288
|
+
err instanceof Error ? err.message : "Failed to check status"
|
|
289
|
+
);
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
if (status.trelloLinked) {
|
|
293
|
+
console.log(
|
|
294
|
+
` ${chalk3.green("1.")} Trello ${chalk3.green("Connected")}`
|
|
295
|
+
);
|
|
296
|
+
} else {
|
|
297
|
+
console.log(
|
|
298
|
+
` ${chalk3.yellow("1.")} Trello ${chalk3.yellow("Not connected")}
|
|
299
|
+
`
|
|
300
|
+
);
|
|
301
|
+
const proceed = await confirm({
|
|
302
|
+
message: "Open your browser to connect Trello? (you'll authorize and be redirected back)",
|
|
303
|
+
default: true
|
|
304
|
+
});
|
|
305
|
+
if (!proceed) {
|
|
306
|
+
console.log(chalk3.dim("Setup cancelled."));
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const urlSpinner = ora3("Getting Trello authorization URL...").start();
|
|
310
|
+
let authUrl;
|
|
311
|
+
try {
|
|
312
|
+
authUrl = await getTrelloAuthUrl();
|
|
313
|
+
urlSpinner.stop();
|
|
314
|
+
} catch (err) {
|
|
315
|
+
urlSpinner.fail(
|
|
316
|
+
err instanceof Error ? err.message : "Failed to get auth URL"
|
|
317
|
+
);
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
console.log(chalk3.dim(`
|
|
321
|
+
Opening: ${authUrl}
|
|
322
|
+
`));
|
|
323
|
+
openBrowser(authUrl);
|
|
324
|
+
console.log(
|
|
325
|
+
chalk3.dim(
|
|
326
|
+
" Authorize the app on Trello, then come back here.\n If the browser didn't open, copy the URL above manually.\n"
|
|
327
|
+
)
|
|
328
|
+
);
|
|
329
|
+
const pollSpinner = ora3(
|
|
330
|
+
"Waiting for Trello connection (up to 2 minutes)..."
|
|
331
|
+
).start();
|
|
332
|
+
const connected = await pollForTrello();
|
|
333
|
+
if (connected) {
|
|
334
|
+
pollSpinner.succeed("Trello connected!");
|
|
335
|
+
} else {
|
|
336
|
+
pollSpinner.fail(
|
|
337
|
+
"Timed out waiting for Trello connection. Run `claude-trello setup` to try again."
|
|
338
|
+
);
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (status.hasApiKey) {
|
|
343
|
+
console.log(
|
|
344
|
+
` ${chalk3.green("2.")} Anthropic API Key ${chalk3.green("Configured")}`
|
|
345
|
+
);
|
|
346
|
+
} else {
|
|
347
|
+
console.log(
|
|
348
|
+
`
|
|
349
|
+
${chalk3.yellow("2.")} Anthropic API Key ${chalk3.yellow("Not set")}
|
|
350
|
+
`
|
|
351
|
+
);
|
|
352
|
+
console.log(
|
|
353
|
+
chalk3.dim(
|
|
354
|
+
" Get your key from https://console.anthropic.com/settings/keys\n"
|
|
355
|
+
)
|
|
356
|
+
);
|
|
357
|
+
const apiKey = await password3({
|
|
358
|
+
message: "Paste your Anthropic API key (sk-ant-api03-...):"
|
|
359
|
+
});
|
|
360
|
+
if (!apiKey.startsWith("sk-ant-api03-")) {
|
|
361
|
+
console.log(
|
|
362
|
+
chalk3.red('Invalid key format. Must start with "sk-ant-api03-".')
|
|
363
|
+
);
|
|
364
|
+
process.exit(1);
|
|
365
|
+
}
|
|
366
|
+
const keySpinner = ora3("Saving API key...").start();
|
|
367
|
+
try {
|
|
368
|
+
await saveApiKey(apiKey);
|
|
369
|
+
keySpinner.succeed("API key saved (encrypted on server)");
|
|
370
|
+
} catch (err) {
|
|
371
|
+
keySpinner.fail(
|
|
372
|
+
err instanceof Error ? err.message : "Failed to save API key"
|
|
373
|
+
);
|
|
374
|
+
process.exit(1);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const serverUrl = getServerUrl();
|
|
378
|
+
console.log(
|
|
379
|
+
chalk3.green.bold(
|
|
380
|
+
"\n All set! Run `claude-trello run` to start a session.\n"
|
|
381
|
+
)
|
|
382
|
+
);
|
|
383
|
+
console.log(
|
|
384
|
+
chalk3.dim(
|
|
385
|
+
` You can manage your settings anytime at ${serverUrl}/settings
|
|
386
|
+
`
|
|
387
|
+
)
|
|
388
|
+
);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// src/commands/logout.ts
|
|
392
|
+
import { Command as Command4 } from "commander";
|
|
393
|
+
import chalk4 from "chalk";
|
|
394
|
+
var logoutCommand = new Command4("logout").description("Sign out and clear stored session").action(() => {
|
|
176
395
|
if (!isLoggedIn()) {
|
|
177
|
-
console.log(
|
|
396
|
+
console.log(chalk4.dim("Not currently logged in."));
|
|
178
397
|
return;
|
|
179
398
|
}
|
|
180
399
|
const config = getConfig();
|
|
181
400
|
clearConfig();
|
|
182
401
|
console.log(
|
|
183
|
-
|
|
402
|
+
chalk4.green(
|
|
184
403
|
`Signed out${config.userEmail ? ` (${config.userEmail})` : ""}.`
|
|
185
404
|
)
|
|
186
405
|
);
|
|
@@ -188,10 +407,10 @@ var logoutCommand = new Command2("logout").description("Sign out and clear store
|
|
|
188
407
|
|
|
189
408
|
// src/commands/run.ts
|
|
190
409
|
import { resolve } from "path";
|
|
191
|
-
import { Command as
|
|
192
|
-
import { select, confirm, input as
|
|
193
|
-
import
|
|
194
|
-
import
|
|
410
|
+
import { Command as Command5 } from "commander";
|
|
411
|
+
import { select, confirm as confirm2, input as input3 } from "@inquirer/prompts";
|
|
412
|
+
import chalk5 from "chalk";
|
|
413
|
+
import ora4 from "ora";
|
|
195
414
|
|
|
196
415
|
// src/lib/runner.ts
|
|
197
416
|
import {
|
|
@@ -347,10 +566,10 @@ function launchSession(options) {
|
|
|
347
566
|
}
|
|
348
567
|
|
|
349
568
|
// src/commands/run.ts
|
|
350
|
-
var runCommand = new
|
|
569
|
+
var runCommand = new Command5("run").description("Select a Trello board and start a Claude Code session").option("-b, --board <id>", "Board ID (skip interactive selection)").option("-d, --dir <path>", "Working directory (default: current)").option("-m, --message <text>", "Initial instructions for Claude").action(async (opts) => {
|
|
351
570
|
if (!isLoggedIn()) {
|
|
352
571
|
console.log(
|
|
353
|
-
|
|
572
|
+
chalk5.red("Not logged in. Run `claude-trello login` first.")
|
|
354
573
|
);
|
|
355
574
|
process.exit(1);
|
|
356
575
|
}
|
|
@@ -358,7 +577,7 @@ var runCommand = new Command3("run").description("Select a Trello board and star
|
|
|
358
577
|
let boardId = opts.board;
|
|
359
578
|
let boardName = "";
|
|
360
579
|
if (!boardId) {
|
|
361
|
-
const spinner =
|
|
580
|
+
const spinner = ora4("Fetching boards...").start();
|
|
362
581
|
let boards;
|
|
363
582
|
try {
|
|
364
583
|
boards = await getBoards();
|
|
@@ -371,7 +590,7 @@ var runCommand = new Command3("run").description("Select a Trello board and star
|
|
|
371
590
|
}
|
|
372
591
|
if (boards.length === 0) {
|
|
373
592
|
console.log(
|
|
374
|
-
|
|
593
|
+
chalk5.red("No boards found. Create a board on Trello first.")
|
|
375
594
|
);
|
|
376
595
|
process.exit(1);
|
|
377
596
|
}
|
|
@@ -385,7 +604,7 @@ var runCommand = new Command3("run").description("Select a Trello board and star
|
|
|
385
604
|
});
|
|
386
605
|
boardName = boards.find((b) => b.id === boardId)?.name ?? boardId;
|
|
387
606
|
}
|
|
388
|
-
const dataSpinner =
|
|
607
|
+
const dataSpinner = ora4("Fetching cards and checklists...").start();
|
|
389
608
|
let cardsResponse;
|
|
390
609
|
try {
|
|
391
610
|
cardsResponse = await getBoardData(boardId);
|
|
@@ -399,8 +618,8 @@ var runCommand = new Command3("run").description("Select a Trello board and star
|
|
|
399
618
|
const { cards, lists, doneListId } = cardsResponse;
|
|
400
619
|
if (!boardName) boardName = boardId;
|
|
401
620
|
console.log(`
|
|
402
|
-
${
|
|
403
|
-
console.log(
|
|
621
|
+
${chalk5.bold(boardName)}`);
|
|
622
|
+
console.log(chalk5.dim("\u2500".repeat(boardName.length)));
|
|
404
623
|
const doneCards = doneListId ? cards.filter((c) => c.idList === doneListId) : [];
|
|
405
624
|
const activeCards = doneListId ? cards.filter((c) => c.idList !== doneListId) : cards;
|
|
406
625
|
const listMap = /* @__PURE__ */ new Map();
|
|
@@ -415,7 +634,7 @@ ${chalk3.bold(boardName)}`);
|
|
|
415
634
|
const listName = listMap.get(listId)?.name ?? "Unknown";
|
|
416
635
|
console.log(
|
|
417
636
|
`
|
|
418
|
-
${
|
|
637
|
+
${chalk5.cyan.bold(listName)} (${listCards.length} card${listCards.length === 1 ? "" : "s"}):`
|
|
419
638
|
);
|
|
420
639
|
for (const card of listCards) {
|
|
421
640
|
const total = card.checklists.reduce(
|
|
@@ -428,37 +647,37 @@ ${chalk3.bold(boardName)}`);
|
|
|
428
647
|
);
|
|
429
648
|
const progress = total > 0 ? ` [${done}/${total}]` : "";
|
|
430
649
|
console.log(
|
|
431
|
-
` ${
|
|
650
|
+
` ${chalk5.white("\u2022")} ${card.name}${chalk5.dim(progress)}`
|
|
432
651
|
);
|
|
433
652
|
}
|
|
434
653
|
}
|
|
435
654
|
if (doneCards.length > 0) {
|
|
436
655
|
console.log(
|
|
437
656
|
`
|
|
438
|
-
${
|
|
657
|
+
${chalk5.dim(`Done (${doneCards.length} card${doneCards.length === 1 ? "" : "s"}) [skipped]`)}`
|
|
439
658
|
);
|
|
440
659
|
}
|
|
441
660
|
if (activeCards.length === 0) {
|
|
442
|
-
console.log(
|
|
661
|
+
console.log(chalk5.dim("\n No active cards to work on."));
|
|
443
662
|
return;
|
|
444
663
|
}
|
|
445
664
|
console.log(`
|
|
446
|
-
${
|
|
447
|
-
const proceed = await
|
|
665
|
+
${chalk5.dim(`Working directory: ${cwd}`)}`);
|
|
666
|
+
const proceed = await confirm2({
|
|
448
667
|
message: `Start Claude Code session? (${activeCards.length} active card${activeCards.length === 1 ? "" : "s"})`,
|
|
449
668
|
default: true
|
|
450
669
|
});
|
|
451
670
|
if (!proceed) {
|
|
452
|
-
console.log(
|
|
671
|
+
console.log(chalk5.dim("Cancelled."));
|
|
453
672
|
return;
|
|
454
673
|
}
|
|
455
674
|
let userMessage = opts.message;
|
|
456
675
|
if (!userMessage) {
|
|
457
|
-
userMessage = await
|
|
676
|
+
userMessage = await input3({
|
|
458
677
|
message: "Instructions for Claude (optional \u2014 press Enter to skip):"
|
|
459
678
|
});
|
|
460
679
|
}
|
|
461
|
-
const credSpinner =
|
|
680
|
+
const credSpinner = ora4("Loading credentials...").start();
|
|
462
681
|
let credentials;
|
|
463
682
|
try {
|
|
464
683
|
credentials = await getCredentials();
|
|
@@ -475,11 +694,11 @@ ${chalk3.bold(boardName)}`);
|
|
|
475
694
|
doneListId: doneListId ?? void 0
|
|
476
695
|
};
|
|
477
696
|
console.log(`
|
|
478
|
-
${
|
|
697
|
+
${chalk5.bold.blue("Starting Claude Code session...")}
|
|
479
698
|
`);
|
|
480
699
|
const abortController = new AbortController();
|
|
481
700
|
const sigintHandler = () => {
|
|
482
|
-
console.log(
|
|
701
|
+
console.log(chalk5.dim("\n\nAborting session..."));
|
|
483
702
|
abortController.abort();
|
|
484
703
|
};
|
|
485
704
|
process.on("SIGINT", sigintHandler);
|
|
@@ -495,14 +714,14 @@ ${chalk3.bold.blue("Starting Claude Code session...")}
|
|
|
495
714
|
await handleMessage(message, session);
|
|
496
715
|
}
|
|
497
716
|
console.log(`
|
|
498
|
-
${
|
|
717
|
+
${chalk5.green.bold("Session complete.")}
|
|
499
718
|
`);
|
|
500
719
|
} catch (err) {
|
|
501
720
|
if (abortController.signal.aborted) {
|
|
502
|
-
console.log(
|
|
721
|
+
console.log(chalk5.dim("\nSession aborted."));
|
|
503
722
|
} else {
|
|
504
723
|
console.error(
|
|
505
|
-
|
|
724
|
+
chalk5.red(
|
|
506
725
|
`
|
|
507
726
|
Session error: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
508
727
|
)
|
|
@@ -518,7 +737,7 @@ async function handleMessage(message, session) {
|
|
|
518
737
|
case "system": {
|
|
519
738
|
if (message.subtype === "init") {
|
|
520
739
|
console.log(
|
|
521
|
-
|
|
740
|
+
chalk5.dim(
|
|
522
741
|
` Session initialized (model: ${message.model})
|
|
523
742
|
`
|
|
524
743
|
)
|
|
@@ -537,17 +756,17 @@ async function handleMessage(message, session) {
|
|
|
537
756
|
const name = block.name;
|
|
538
757
|
const toolInput = block.input ?? {};
|
|
539
758
|
if (name === "mcp__trello-tools__check_trello_item") {
|
|
540
|
-
console.log(
|
|
759
|
+
console.log(chalk5.green(` \u2713 Checked item on Trello`));
|
|
541
760
|
} else if (name === "mcp__trello-tools__move_card_to_done") {
|
|
542
|
-
console.log(
|
|
761
|
+
console.log(chalk5.green.bold(` \u2713 Moved card to Done`));
|
|
543
762
|
} else if (name === "AskUserQuestion") {
|
|
544
763
|
const questions = toolInput.questions;
|
|
545
764
|
if (questions && questions.length > 0) {
|
|
546
765
|
const questionText = questions.map((q) => q.question).join("\n");
|
|
547
|
-
console.log(
|
|
766
|
+
console.log(chalk5.yellow(`
|
|
548
767
|
? ${questionText}
|
|
549
768
|
`));
|
|
550
|
-
const answer = await
|
|
769
|
+
const answer = await input3({ message: ">" });
|
|
551
770
|
async function* userInput() {
|
|
552
771
|
yield {
|
|
553
772
|
type: "user",
|
|
@@ -570,7 +789,7 @@ async function handleMessage(message, session) {
|
|
|
570
789
|
}
|
|
571
790
|
case "result": {
|
|
572
791
|
const result = message.result ?? message.subtype;
|
|
573
|
-
console.log(
|
|
792
|
+
console.log(chalk5.dim(`
|
|
574
793
|
Result: ${result}`));
|
|
575
794
|
break;
|
|
576
795
|
}
|
|
@@ -578,62 +797,62 @@ async function handleMessage(message, session) {
|
|
|
578
797
|
}
|
|
579
798
|
function formatToolUse(name, toolInput) {
|
|
580
799
|
const path = toolInput.file_path ?? toolInput.path ?? toolInput.pattern ?? "";
|
|
581
|
-
const shortPath = path ? ` ${
|
|
800
|
+
const shortPath = path ? ` ${chalk5.cyan(path)}` : "";
|
|
582
801
|
switch (name) {
|
|
583
802
|
case "Read":
|
|
584
|
-
return
|
|
803
|
+
return chalk5.dim(` Reading${shortPath}`);
|
|
585
804
|
case "Edit":
|
|
586
|
-
return
|
|
805
|
+
return chalk5.dim(` Editing${shortPath}`);
|
|
587
806
|
case "Write":
|
|
588
|
-
return
|
|
807
|
+
return chalk5.dim(` Writing${shortPath}`);
|
|
589
808
|
case "Glob":
|
|
590
|
-
return
|
|
809
|
+
return chalk5.dim(` Searching files${shortPath}`);
|
|
591
810
|
case "Grep":
|
|
592
|
-
return
|
|
593
|
-
` Searching for ${
|
|
811
|
+
return chalk5.dim(
|
|
812
|
+
` Searching for ${chalk5.cyan(toolInput.pattern || "...")}${toolInput.path ? ` in ${chalk5.cyan(toolInput.path)}` : ""}`
|
|
594
813
|
);
|
|
595
814
|
case "Bash": {
|
|
596
815
|
const cmd = toolInput.command || "";
|
|
597
816
|
const preview = cmd.length > 80 ? cmd.slice(0, 77) + "..." : cmd;
|
|
598
|
-
return
|
|
817
|
+
return chalk5.dim(` Running ${chalk5.cyan(preview)}`);
|
|
599
818
|
}
|
|
600
819
|
case "TodoWrite":
|
|
601
|
-
return
|
|
820
|
+
return chalk5.dim(" Updating task list");
|
|
602
821
|
case "Agent":
|
|
603
|
-
return
|
|
822
|
+
return chalk5.dim(
|
|
604
823
|
` Spawning agent${toolInput.description ? `: ${toolInput.description}` : ""}`
|
|
605
824
|
);
|
|
606
825
|
default:
|
|
607
|
-
return
|
|
826
|
+
return chalk5.dim(` [${name}]${shortPath}`);
|
|
608
827
|
}
|
|
609
828
|
}
|
|
610
829
|
|
|
611
830
|
// src/commands/boards.ts
|
|
612
|
-
import { Command as
|
|
613
|
-
import
|
|
614
|
-
import
|
|
615
|
-
var boardsCommand = new
|
|
831
|
+
import { Command as Command6 } from "commander";
|
|
832
|
+
import chalk6 from "chalk";
|
|
833
|
+
import ora5 from "ora";
|
|
834
|
+
var boardsCommand = new Command6("boards").description("List your Trello boards").action(async () => {
|
|
616
835
|
if (!isLoggedIn()) {
|
|
617
836
|
console.log(
|
|
618
|
-
|
|
837
|
+
chalk6.red("Not logged in. Run `claude-trello login` first.")
|
|
619
838
|
);
|
|
620
839
|
process.exit(1);
|
|
621
840
|
}
|
|
622
|
-
const spinner =
|
|
841
|
+
const spinner = ora5("Fetching boards...").start();
|
|
623
842
|
try {
|
|
624
843
|
const boards = await getBoards();
|
|
625
844
|
spinner.stop();
|
|
626
845
|
if (boards.length === 0) {
|
|
627
|
-
console.log(
|
|
846
|
+
console.log(chalk6.dim("No boards found."));
|
|
628
847
|
return;
|
|
629
848
|
}
|
|
630
|
-
console.log(
|
|
849
|
+
console.log(chalk6.bold(`
|
|
631
850
|
Your Trello Boards (${boards.length}):
|
|
632
851
|
`));
|
|
633
852
|
for (const board of boards) {
|
|
634
|
-
console.log(` ${
|
|
853
|
+
console.log(` ${chalk6.cyan(board.name)} ${chalk6.dim(board.id)}`);
|
|
635
854
|
if (board.desc) {
|
|
636
|
-
console.log(` ${
|
|
855
|
+
console.log(` ${chalk6.dim(board.desc.slice(0, 80))}`);
|
|
637
856
|
}
|
|
638
857
|
console.log();
|
|
639
858
|
}
|
|
@@ -646,40 +865,40 @@ Your Trello Boards (${boards.length}):
|
|
|
646
865
|
});
|
|
647
866
|
|
|
648
867
|
// src/commands/status.ts
|
|
649
|
-
import { Command as
|
|
650
|
-
import
|
|
651
|
-
import
|
|
652
|
-
var statusCommand = new
|
|
868
|
+
import { Command as Command7 } from "commander";
|
|
869
|
+
import chalk7 from "chalk";
|
|
870
|
+
import ora6 from "ora";
|
|
871
|
+
var statusCommand = new Command7("status").description("Check connection and integration status").action(async () => {
|
|
653
872
|
const config = getConfig();
|
|
654
|
-
console.log(
|
|
655
|
-
console.log(` Server: ${
|
|
873
|
+
console.log(chalk7.bold("\nClaude Trello Bridge \u2014 Status\n"));
|
|
874
|
+
console.log(` Server: ${chalk7.dim(getServerUrl())}`);
|
|
656
875
|
if (!isLoggedIn()) {
|
|
657
|
-
console.log(` Auth: ${
|
|
658
|
-
console.log(
|
|
876
|
+
console.log(` Auth: ${chalk7.red("Not logged in")}`);
|
|
877
|
+
console.log(chalk7.dim("\n Run `claude-trello login` to sign in.\n"));
|
|
659
878
|
return;
|
|
660
879
|
}
|
|
661
880
|
console.log(
|
|
662
|
-
` Auth: ${
|
|
881
|
+
` Auth: ${chalk7.green("Signed in")} as ${config.userName ?? config.userEmail ?? "unknown"}`
|
|
663
882
|
);
|
|
664
|
-
const spinner =
|
|
883
|
+
const spinner = ora6("Checking integrations...").start();
|
|
665
884
|
try {
|
|
666
885
|
const status = await getIntegrationStatus();
|
|
667
886
|
spinner.stop();
|
|
668
887
|
console.log(
|
|
669
|
-
` Trello: ${status.trelloLinked ?
|
|
888
|
+
` Trello: ${status.trelloLinked ? chalk7.green("Connected") : chalk7.red("Not connected")}`
|
|
670
889
|
);
|
|
671
890
|
console.log(
|
|
672
|
-
` API Key: ${status.hasApiKey ?
|
|
891
|
+
` API Key: ${status.hasApiKey ? chalk7.green("Configured") : chalk7.red("Not set")}`
|
|
673
892
|
);
|
|
674
893
|
if (!status.trelloLinked || !status.hasApiKey) {
|
|
675
894
|
console.log(
|
|
676
|
-
|
|
895
|
+
chalk7.dim(
|
|
677
896
|
"\n Complete setup at your web dashboard to use the CLI.\n"
|
|
678
897
|
)
|
|
679
898
|
);
|
|
680
899
|
} else {
|
|
681
900
|
console.log(
|
|
682
|
-
|
|
901
|
+
chalk7.green("\n Ready to go! Run `claude-trello run` to start.\n")
|
|
683
902
|
);
|
|
684
903
|
}
|
|
685
904
|
} catch (err) {
|
|
@@ -691,11 +910,13 @@ var statusCommand = new Command5("status").description("Check connection and int
|
|
|
691
910
|
});
|
|
692
911
|
|
|
693
912
|
// src/index.ts
|
|
694
|
-
var program = new
|
|
913
|
+
var program = new Command8();
|
|
695
914
|
program.name("claude-trello").description(
|
|
696
915
|
"Bridge Trello boards and Claude Code \u2014 work through tasks from your terminal"
|
|
697
916
|
).version("0.1.0");
|
|
917
|
+
program.addCommand(registerCommand);
|
|
698
918
|
program.addCommand(loginCommand);
|
|
919
|
+
program.addCommand(setupCommand);
|
|
699
920
|
program.addCommand(logoutCommand);
|
|
700
921
|
program.addCommand(runCommand);
|
|
701
922
|
program.addCommand(boardsCommand);
|