team-toon-tack 1.0.0 → 1.0.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
@@ -1,5 +1,7 @@
1
1
  # team-toon-tack (ttt)
2
2
 
3
+ [繁體中文](./README.zh-TW.md) | English
4
+
3
5
  CLI tool for syncing and managing Linear issues with local TOON format.
4
6
 
5
7
  ## Installation
@@ -0,0 +1,436 @@
1
+ # team-toon-tack (ttt)
2
+
3
+ 繁體中文 | [English](./README.md)
4
+
5
+ 使用 TOON 格式同步與管理 Linear 任務的 CLI 工具。
6
+
7
+ ## 為什麼需要這個工具?
8
+
9
+ 在使用 Linear 管理專案任務時,常見的痛點:
10
+
11
+ - **AI 助手整合困難**:Claude Code 等 AI 工具無法直接讀取 Linear 的任務上下文
12
+ - **狀態同步繁瑣**:手動在 Linear 和本地之間切換更新狀態
13
+ - **團隊協作不透明**:難以追蹤誰在做什麼、進度如何
14
+
15
+ **team-toon-tack** 解決這些問題:將 Linear 任務同步到本地 TOON 檔案,讓 AI 助手能讀取任務內容,並自動同步狀態變更。
16
+
17
+ ## 運作原理
18
+
19
+ ```
20
+ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐
21
+ │ Linear │────▶│ ttt sync │────▶│ cycle.toon │
22
+ │ (雲端) │ │ │ │ (本地) │
23
+ └─────────────┘ └──────────────┘ └─────────────┘
24
+
25
+
26
+ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐
27
+ │ Linear │◀────│ ttt done │◀────│ Claude Code │
28
+ │ 狀態更新 │ │ ttt work-on │ │ 讀取任務 │
29
+ └─────────────┘ └──────────────┘ └─────────────┘
30
+ ```
31
+
32
+ ### 核心流程
33
+
34
+ 1. **同步 (sync)**
35
+ - 從 Linear API 抓取當前 Cycle 的任務
36
+ - 根據 `local.toon` 設定過濾(標籤、排除指派人)
37
+ - 寫入 `cycle.toon`,包含完整任務資訊
38
+
39
+ 2. **開始任務 (work-on)**
40
+ - 讀取 `cycle.toon` 中的待處理任務
41
+ - 更新本地狀態為 `in-progress`
42
+ - 同步更新 Linear 狀態為 "In Progress"
43
+
44
+ 3. **完成任務 (done)**
45
+ - 更新本地狀態為 `completed`
46
+ - 同步更新 Linear 狀態為 "Done"
47
+ - 自動在 Linear 新增完成留言(含 commit 資訊)
48
+ - 若有父任務,自動更新為 "Testing"
49
+
50
+ ### 檔案結構與用途
51
+
52
+ ```
53
+ .toon/ # 配置目錄(建議 gitignore)
54
+ ├── config.toon # 團隊配置
55
+ │ ├── teams # Linear 團隊 ID 映射
56
+ │ ├── users # 成員 ID/email 映射
57
+ │ ├── labels # 標籤 ID 映射
58
+ │ ├── statuses # 狀態定義
59
+ │ └── current_cycle # 當前 Cycle 資訊
60
+
61
+ ├── local.toon # 個人設定(必須 gitignore)
62
+ │ ├── current_user # 你的 user key
63
+ │ ├── label # 過濾標籤
64
+ │ └── exclude_assignees # 排除的指派人
65
+
66
+ └── cycle.toon # 任務資料(自動產生)
67
+ ├── cycleId # Cycle UUID
68
+ ├── cycleName # Cycle 名稱
69
+ ├── updatedAt # 最後同步時間
70
+ └── tasks[] # 任務列表
71
+ ├── id # 任務編號 (MP-123)
72
+ ├── linearId # Linear UUID
73
+ ├── title # 標題
74
+ ├── description # 描述(Markdown)
75
+ ├── status # Linear 狀態
76
+ ├── localStatus # 本地狀態
77
+ ├── priority # 優先級 (1=Urgent, 4=Low)
78
+ ├── labels # 標籤列表
79
+ ├── branch # Git 分支名
80
+ ├── attachments # 附件列表
81
+ └── comments # 留言列表
82
+ ```
83
+
84
+ ## 安裝
85
+
86
+ ```bash
87
+ # npm(推薦)
88
+ npm install -g team-toon-tack
89
+
90
+ # 或用 bun
91
+ bun add -g team-toon-tack
92
+ ```
93
+
94
+ ## 快速開始
95
+
96
+ ```bash
97
+ # 1. 設定 Linear API 金鑰
98
+ export LINEAR_API_KEY="lin_api_xxxxx"
99
+
100
+ # 2. 初始化(會從 Linear 抓取團隊資料)
101
+ mkdir .toon && cd .toon
102
+ ttt init
103
+
104
+ # 3. 同步任務
105
+ ttt sync
106
+
107
+ # 4. 開始工作
108
+ ttt work-on
109
+ ```
110
+
111
+ ## 使用情境
112
+
113
+ ### 情境 1:每日開工流程
114
+
115
+ ```bash
116
+ # 早上開始工作前,同步最新任務
117
+ ttt sync -d .toon
118
+
119
+ # 查看待處理任務並選擇一個開始
120
+ ttt work-on -d .toon
121
+
122
+ # Claude Code 現在可以讀取任務內容
123
+ # 在 .toon/cycle.toon 中找到任務描述、附件等
124
+ ```
125
+
126
+ ### 情境 2:搭配 Claude Code 自動化
127
+
128
+ 建立以下三個 slash command 檔案:
129
+
130
+ #### `.claude/commands/sync-linear.md`
131
+
132
+ ```markdown
133
+ ---
134
+ name: sync-linear
135
+ description: Sync Linear issues to local TOON file
136
+ ---
137
+
138
+ # Sync Linear Issues
139
+
140
+ Fetch current cycle's issues from Linear to `.toon/cycle.toon`.
141
+
142
+ ## Process
143
+
144
+ ### 1. Run Sync
145
+
146
+ \`\`\`bash
147
+ ttt sync -d .toon
148
+ \`\`\`
149
+
150
+ ### 2. Review Output
151
+
152
+ Script displays a summary of tasks in the current cycle.
153
+
154
+ ## When to Use
155
+
156
+ - Before starting a new work session
157
+ - When task list is missing or outdated
158
+ - After issues are updated in Linear
159
+ ```
160
+
161
+ #### `.claude/commands/work-on.md`
162
+
163
+ ```markdown
164
+ ---
165
+ name: work-on
166
+ description: Select and start working on a Linear issue
167
+ arguments:
168
+ - name: issue-id
169
+ description: "Issue ID (e.g., MP-624) or 'next' for auto-select"
170
+ required: false
171
+ ---
172
+
173
+ # Start Working on Issue
174
+
175
+ Select a task and update status to "In Progress" on both local and Linear.
176
+
177
+ ## Process
178
+
179
+ ### 1. Run Command
180
+
181
+ \`\`\`bash
182
+ ttt work-on -d .toon $ARGUMENTS
183
+ \`\`\`
184
+
185
+ ### 2. Review Issue Details
186
+
187
+ Script displays title, description, priority, labels, and attachments.
188
+
189
+ ### 3. Implement
190
+
191
+ 1. Read the issue description carefully
192
+ 2. Explore related code
193
+ 3. Implement the fix/feature
194
+ 4. Run validation commands
195
+ 5. Commit with conventional format
196
+ 6. Use `/done-job` to complete
197
+ ```
198
+
199
+ #### `.claude/commands/done-job.md`
200
+
201
+ ```markdown
202
+ ---
203
+ name: done-job
204
+ description: Mark a Linear issue as done with AI summary comment
205
+ arguments:
206
+ - name: issue-id
207
+ description: Linear issue ID (e.g., MP-624). Optional if only one task is in-progress
208
+ required: false
209
+ ---
210
+
211
+ # Complete Task
212
+
213
+ Mark a task as done and update Linear with commit details.
214
+
215
+ ## Process
216
+
217
+ ### 1. Determine Issue ID
218
+
219
+ Check `.toon/cycle.toon` for tasks with `localStatus: in-progress`.
220
+
221
+ ### 2. Write Fix Summary
222
+
223
+ Prepare a concise summary (1-3 sentences) covering:
224
+ - Root cause
225
+ - How it was resolved
226
+ - Key code changes
227
+
228
+ ### 3. Run Command
229
+
230
+ \`\`\`bash
231
+ ttt done -d .toon $ARGUMENTS -m "修復說明"
232
+ \`\`\`
233
+
234
+ ## What It Does
235
+
236
+ - Linear issue status → "Done"
237
+ - Adds comment with commit hash, message, and diff summary
238
+ - Parent issue (if exists) → "Testing"
239
+ - Local status → `completed` in `.toon/cycle.toon`
240
+ ```
241
+
242
+ #### 使用方式
243
+
244
+ ```
245
+ /sync-linear # 同步任務
246
+ /work-on # 互動選擇任務
247
+ /work-on MP-624 # 指定任務
248
+ /work-on next # 自動選最高優先級
249
+ /done-job # 完成當前任務
250
+ /done-job MP-624 # 完成指定任務
251
+ ```
252
+
253
+ Claude Code 會自動:
254
+ - 執行 `ttt work-on` 開始任務
255
+ - 讀取任務描述和附件
256
+ - 根據需求實作功能
257
+ - 執行 `ttt done` 更新狀態並留言
258
+
259
+ ### 情境 3:完成任務並自動留言
260
+
261
+ ```bash
262
+ # 完成開發後
263
+ git add . && git commit -m "feat: implement feature X"
264
+
265
+ # 標記任務完成,會自動在 Linear 新增留言
266
+ ttt done -d .toon -m "實作了 X 功能,修改了 Y 元件"
267
+ ```
268
+
269
+ Linear 上會自動新增留言:
270
+ ```markdown
271
+ ## ✅ 開發完成
272
+
273
+ ### 🤖 AI 修復說明
274
+ 實作了 X 功能,修改了 Y 元件
275
+
276
+ ### 📝 Commit Info
277
+ **Commit:** [abc1234](https://github.com/...)
278
+ **Message:** feat: implement feature X
279
+
280
+ ### 📊 Changes
281
+ src/components/X.vue | 50 +++
282
+ src/utils/Y.ts | 20 +-
283
+ 2 files changed, 60 insertions(+), 10 deletions(-)
284
+ ```
285
+
286
+ ### 情境 4:團隊協作過濾
287
+
288
+ 前端工程師只想看前端任務:
289
+ ```toon
290
+ # local.toon
291
+ current_user: alice
292
+ label: Frontend
293
+ exclude_assignees[1]: bob # 排除後端同事的任務
294
+ exclude_assignees[2]: charlie
295
+ ```
296
+
297
+ 後端工程師的設定:
298
+ ```toon
299
+ # local.toon
300
+ current_user: bob
301
+ label: Backend
302
+ ```
303
+
304
+ ### 情境 5:多專案管理
305
+
306
+ ```bash
307
+ # 專案 A
308
+ cd project-a
309
+ ttt sync -d .toon
310
+
311
+ # 專案 B(不同 Linear 團隊)
312
+ cd ../project-b
313
+ ttt init -d .toon # 初始化不同的配置
314
+ ttt sync -d .toon
315
+ ```
316
+
317
+ ### 情境 6:CI/CD 整合
318
+
319
+ ```yaml
320
+ # .github/workflows/sync.yml
321
+ name: Sync Linear Tasks
322
+ on:
323
+ schedule:
324
+ - cron: '0 9 * * 1-5' # 週一到週五早上 9 點
325
+ jobs:
326
+ sync:
327
+ runs-on: ubuntu-latest
328
+ steps:
329
+ - uses: actions/checkout@v4
330
+ - run: npm install -g team-toon-tack
331
+ - run: ttt sync -d .toon
332
+ env:
333
+ LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
334
+ - run: |
335
+ git add .toon/cycle.toon
336
+ git commit -m "chore: sync linear tasks" || true
337
+ git push
338
+ ```
339
+
340
+ ## 指令參考
341
+
342
+ ### `ttt init`
343
+
344
+ 初始化配置檔,從 Linear 抓取團隊資料。
345
+
346
+ ```bash
347
+ ttt init [options]
348
+
349
+ 選項:
350
+ -d, --dir <path> 配置目錄(預設:當前目錄)
351
+ -k, --api-key <key> Linear API 金鑰
352
+ -u, --user <email> 預選使用者
353
+ -l, --label <name> 預設標籤過濾
354
+ -f, --force 覆蓋現有配置
355
+ -y, --yes 非互動模式
356
+ ```
357
+
358
+ ### `ttt sync`
359
+
360
+ 從 Linear 同步任務到本地。
361
+
362
+ ```bash
363
+ ttt sync [options]
364
+
365
+ 選項:
366
+ -d, --dir <path> 配置目錄
367
+ ```
368
+
369
+ ### `ttt work-on`
370
+
371
+ 開始處理任務。
372
+
373
+ ```bash
374
+ ttt work-on [issue-id] [options]
375
+
376
+ 參數:
377
+ issue-id 任務編號(如 MP-624)或 "next"
378
+
379
+ 選項:
380
+ -d, --dir <path> 配置目錄
381
+ ```
382
+
383
+ ### `ttt done`
384
+
385
+ 標記任務完成。
386
+
387
+ ```bash
388
+ ttt done [issue-id] [options]
389
+
390
+ 參數:
391
+ issue-id 任務編號(可選)
392
+
393
+ 選項:
394
+ -d, --dir <path> 配置目錄
395
+ -m, --message <msg> 完成說明
396
+ ```
397
+
398
+ ## 環境變數
399
+
400
+ | 變數 | 說明 |
401
+ |------|------|
402
+ | `LINEAR_API_KEY` | **必填**。Linear API 金鑰([取得方式](https://linear.app/settings/api)) |
403
+ | `TOON_DIR` | 配置目錄路徑(可取代 `-d` 參數) |
404
+
405
+ ## 常見問題
406
+
407
+ ### Q: 為什麼用 TOON 格式?
408
+
409
+ TOON 是一種人類可讀的資料格式,類似 YAML 但更簡潔。相比 JSON:
410
+ - 更容易手動編輯
411
+ - 支援註解
412
+ - AI 助手更容易理解
413
+
414
+ ### Q: config.toon 可以提交到 Git 嗎?
415
+
416
+ 可以,但建議 gitignore。因為包含:
417
+ - 團隊成員的 email
418
+ - Linear 內部 UUID
419
+
420
+ 如果是私有倉庫且團隊成員都有 Linear 存取權,提交是安全的。
421
+
422
+ ### Q: 如何處理衝突?
423
+
424
+ `cycle.toon` 是自動產生的,直接用 `ttt sync` 重新同步即可。
425
+
426
+ ### Q: 支援哪些 Linear 功能?
427
+
428
+ - ✅ Cycle 任務同步
429
+ - ✅ 狀態雙向同步
430
+ - ✅ 附件和留言讀取
431
+ - ✅ 父子任務關聯
432
+ - ✅ 優先級排序
433
+
434
+ ## 授權
435
+
436
+ MIT
package/bin/cli.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  #!/usr/bin/env bun
2
2
  import { resolve } from 'node:path';
3
+ import { readFileSync } from 'node:fs';
4
+
5
+ // Read version from package.json
6
+ const pkgPath = new URL('../package.json', import.meta.url).pathname;
7
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
8
+ const VERSION = pkg.version;
3
9
 
4
10
  const COMMANDS = ['init', 'sync', 'work-on', 'done', 'help', 'version'] as const;
5
11
  type Command = typeof COMMANDS[number];
@@ -42,7 +48,7 @@ More info: https://github.com/wayne930242/team-toon-tack
42
48
  }
43
49
 
44
50
  function printVersion() {
45
- console.log('team-toon-tack v1.0.0');
51
+ console.log(`team-toon-tack v${VERSION}`);
46
52
  }
47
53
 
48
54
  function parseGlobalArgs(args: string[]): { dir: string; commandArgs: string[] } {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "team-toon-tack",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Linear task sync & management CLI with TOON format",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,8 @@
14
14
  "files": [
15
15
  "bin",
16
16
  "scripts",
17
- "templates"
17
+ "templates",
18
+ "package.json"
18
19
  ],
19
20
  "scripts": {
20
21
  "start": "bun bin/cli.ts",
@@ -62,7 +62,27 @@ function parseArgs(args: string[]): { issueId?: string; message?: string } {
62
62
  }
63
63
 
64
64
  async function doneJob() {
65
- const { issueId: argIssueId, message: argMessage } = parseArgs(process.argv.slice(2));
65
+ const args = process.argv.slice(2);
66
+
67
+ // Handle help flag
68
+ if (args.includes('--help') || args.includes('-h')) {
69
+ console.log(`Usage: ttt done [issue-id] [-m message]
70
+
71
+ Arguments:
72
+ issue-id Issue ID (e.g., MP-624). Optional if only one task is in-progress
73
+
74
+ Options:
75
+ -m, --message AI summary message describing the fix
76
+
77
+ Examples:
78
+ ttt done # Complete current in-progress task
79
+ ttt done MP-624 # Complete specific task
80
+ ttt done -m "Fixed null check" # With completion message
81
+ ttt done MP-624 -m "Refactored" # Specific task with message`);
82
+ process.exit(0);
83
+ }
84
+
85
+ const { issueId: argIssueId, message: argMessage } = parseArgs(args);
66
86
  let issueId = argIssueId;
67
87
 
68
88
  const config = await loadConfig();
package/scripts/sync.ts CHANGED
@@ -1,6 +1,26 @@
1
1
  import { getLinearClient, loadConfig, loadLocalConfig, saveConfig, loadCycleData, saveCycleData, getTeamId, CycleData, Task, Attachment, Comment } from './utils';
2
2
 
3
3
  async function sync() {
4
+ const args = process.argv.slice(2);
5
+
6
+ // Handle help flag
7
+ if (args.includes('--help') || args.includes('-h')) {
8
+ console.log(`Usage: ttt sync
9
+
10
+ Sync issues from Linear to local cycle.toon file.
11
+
12
+ What it does:
13
+ - Fetches active cycle from Linear
14
+ - Downloads all issues matching configured label
15
+ - Preserves local status for existing tasks
16
+ - Updates config with new cycle info
17
+
18
+ Examples:
19
+ ttt sync # Sync in current directory
20
+ ttt sync -d .toon # Sync using .toon directory`);
21
+ process.exit(0);
22
+ }
23
+
4
24
  const config = await loadConfig();
5
25
  const localConfig = await loadLocalConfig();
6
26
  const client = getLinearClient();
@@ -11,6 +11,22 @@ const PRIORITY_LABELS: Record<number, string> = {
11
11
 
12
12
  async function workOn() {
13
13
  const args = process.argv.slice(2);
14
+
15
+ // Handle help flag
16
+ if (args.includes('--help') || args.includes('-h')) {
17
+ console.log(`Usage: ttt work-on [issue-id]
18
+
19
+ Arguments:
20
+ issue-id Issue ID (e.g., MP-624) or 'next' for auto-select
21
+ If omitted, shows interactive selection
22
+
23
+ Examples:
24
+ ttt work-on # Interactive selection
25
+ ttt work-on MP-624 # Work on specific issue
26
+ ttt work-on next # Auto-select highest priority`);
27
+ process.exit(0);
28
+ }
29
+
14
30
  let issueId = args[0];
15
31
 
16
32
  const config = await loadConfig();