team-toon-tack 2.3.0 → 2.3.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +18 -13
- package/README.zh-TW.md +18 -13
- package/commands/{ttt-done.md → ttt:done.md} +5 -3
- package/commands/ttt:show.md +126 -0
- package/commands/{ttt-status.md → ttt:status.md} +1 -1
- package/commands/{ttt-sync.md → ttt:sync.md} +1 -1
- package/commands/{ttt-work-on.md → ttt:work-on.md} +33 -2
- package/commands/ttt:write-validate.md +122 -0
- package/dist/bin/cli.js +8 -6
- package/dist/scripts/init.js +8 -24
- package/dist/scripts/show.d.ts +1 -0
- package/dist/scripts/show.js +319 -0
- package/dist/scripts/sync.js +6 -7
- package/package.json +1 -1
- package/skills/linear-task-manager/SKILL.md +28 -10
- package/commands/ttt-get-issue.md +0 -71
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Optimized Linear workflow for Claude Code — saves significant tokens compared
|
|
|
14
14
|
- **QA Team Support** — Auto-update parent issues in QA team to "Testing" when completing dev tasks
|
|
15
15
|
- **Attachment Download** — Auto-download Linear images and files to local `.ttt/output/` for AI vision analysis
|
|
16
16
|
- **Blocked Status** — Set tasks as blocked when waiting on external dependencies
|
|
17
|
-
- **Claude Code Plugin** — Install plugin for `/ttt
|
|
17
|
+
- **Claude Code Plugin** — Install plugin for `/ttt:*` commands and auto-activated skills
|
|
18
18
|
- **Cycle History** — Local `.toon` files preserve cycle data for AI context
|
|
19
19
|
- **User Filtering** — Only see issues assigned to you or unassigned
|
|
20
20
|
|
|
@@ -58,9 +58,9 @@ During init, you'll configure:
|
|
|
58
58
|
In Claude Code (with plugin installed):
|
|
59
59
|
|
|
60
60
|
```
|
|
61
|
-
/ttt
|
|
62
|
-
/ttt
|
|
63
|
-
/ttt
|
|
61
|
+
/ttt:sync # Fetch all Linear issues for current cycle
|
|
62
|
+
/ttt:work-on next # Pick highest priority task & start working
|
|
63
|
+
/ttt:done # Complete task with AI-generated summary
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
Or using CLI directly:
|
|
@@ -128,13 +128,18 @@ ttt status MP-123 --set done # Mark as done
|
|
|
128
128
|
ttt status MP-123 --set blocked # Set as blocked (waiting on dependency)
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
### `ttt
|
|
131
|
+
### `ttt show`
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
Show issue details or search issues from local cycle data.
|
|
134
134
|
|
|
135
135
|
```bash
|
|
136
|
-
ttt
|
|
137
|
-
ttt
|
|
136
|
+
ttt show # Show all issues in local cycle data
|
|
137
|
+
ttt show MP-123 # Show specific issue from local data
|
|
138
|
+
ttt show MP-123 --remote # Fetch specific issue from Linear
|
|
139
|
+
ttt show --label frontend # Filter by label
|
|
140
|
+
ttt show --status "In Progress" --user me # My in-progress issues
|
|
141
|
+
ttt show --priority 1 # Show urgent issues
|
|
142
|
+
ttt show --export # Export as markdown
|
|
138
143
|
```
|
|
139
144
|
|
|
140
145
|
### `ttt config`
|
|
@@ -181,11 +186,11 @@ Install the plugin for Claude Code integration:
|
|
|
181
186
|
|
|
182
187
|
| Command | Description |
|
|
183
188
|
|---------|-------------|
|
|
184
|
-
| `/ttt
|
|
185
|
-
| `/ttt
|
|
186
|
-
| `/ttt
|
|
187
|
-
| `/ttt
|
|
188
|
-
| `/ttt
|
|
189
|
+
| `/ttt:sync` | Sync Linear issues to local cycle data |
|
|
190
|
+
| `/ttt:work-on` | Start working on a task |
|
|
191
|
+
| `/ttt:done` | Mark current task as completed |
|
|
192
|
+
| `/ttt:status` | Show or modify task status |
|
|
193
|
+
| `/ttt:show` | Show issue details or search issues |
|
|
189
194
|
|
|
190
195
|
### Auto-Activated Skill
|
|
191
196
|
|
package/README.zh-TW.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
- **QA 團隊支援** — 完成開發任務時自動將 QA 團隊的 parent issue 更新為「Testing」
|
|
15
15
|
- **附件下載** — 自動下載 Linear 圖片和檔案到本地 `.ttt/output/`,供 AI 視覺分析
|
|
16
16
|
- **阻塞狀態** — 等待外部依賴時可設定任務為 blocked
|
|
17
|
-
- **Claude Code Plugin** — 安裝 plugin 即可使用 `/ttt
|
|
17
|
+
- **Claude Code Plugin** — 安裝 plugin 即可使用 `/ttt:*` 指令和自動啟用的技能
|
|
18
18
|
- **Cycle 歷史保存** — 本地 `.toon` 檔案保留 cycle 資料,方便 AI 檢閱
|
|
19
19
|
- **使用者過濾** — 只顯示指派給你或未指派的工作
|
|
20
20
|
|
|
@@ -58,9 +58,9 @@ ttt init
|
|
|
58
58
|
在 Claude Code 中(安裝 plugin 後):
|
|
59
59
|
|
|
60
60
|
```
|
|
61
|
-
/ttt
|
|
62
|
-
/ttt
|
|
63
|
-
/ttt
|
|
61
|
+
/ttt:sync # 從 Linear 取得當前 cycle 所有 issue
|
|
62
|
+
/ttt:work-on next # 挑選最高優先級任務並開始工作
|
|
63
|
+
/ttt:done # 完成任務,附上 AI 生成的摘要
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
或直接使用 CLI:
|
|
@@ -128,13 +128,18 @@ ttt status MP-123 --set done # 標記為完成
|
|
|
128
128
|
ttt status MP-123 --set blocked # 設為阻塞(等待外部依賴)
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
### `ttt
|
|
131
|
+
### `ttt show`
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
顯示 issue 詳情或搜尋 issue。
|
|
134
134
|
|
|
135
135
|
```bash
|
|
136
|
-
ttt
|
|
137
|
-
ttt
|
|
136
|
+
ttt show # 顯示本地 cycle 資料中的所有 issue
|
|
137
|
+
ttt show MP-123 # 顯示特定 issue(從本地資料)
|
|
138
|
+
ttt show MP-123 --remote # 從 Linear 取得特定 issue
|
|
139
|
+
ttt show --label frontend # 依標籤過濾
|
|
140
|
+
ttt show --status "In Progress" --user me # 我進行中的 issue
|
|
141
|
+
ttt show --priority 1 # 顯示緊急 issue
|
|
142
|
+
ttt show --export # 輸出為 markdown 格式
|
|
138
143
|
```
|
|
139
144
|
|
|
140
145
|
### `ttt config`
|
|
@@ -181,11 +186,11 @@ your-project/
|
|
|
181
186
|
|
|
182
187
|
| 指令 | 說明 |
|
|
183
188
|
|------|------|
|
|
184
|
-
| `/ttt
|
|
185
|
-
| `/ttt
|
|
186
|
-
| `/ttt
|
|
187
|
-
| `/ttt
|
|
188
|
-
| `/ttt
|
|
189
|
+
| `/ttt:sync` | 同步 Linear issue 到本地 |
|
|
190
|
+
| `/ttt:work-on` | 開始處理任務 |
|
|
191
|
+
| `/ttt:done` | 標記當前任務完成 |
|
|
192
|
+
| `/ttt:status` | 顯示或修改任務狀態 |
|
|
193
|
+
| `/ttt:show` | 顯示 issue 詳情或搜尋 issue |
|
|
189
194
|
|
|
190
195
|
### 自動啟用技能
|
|
191
196
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: ttt
|
|
2
|
+
name: ttt:done
|
|
3
3
|
description: Mark current task as completed
|
|
4
4
|
arguments:
|
|
5
5
|
- name: issue-id
|
|
@@ -57,6 +57,8 @@ Also:
|
|
|
57
57
|
## Before Running
|
|
58
58
|
|
|
59
59
|
Ensure you have:
|
|
60
|
-
1.
|
|
61
|
-
2.
|
|
60
|
+
1. **Run project validation** - Use `/validate` command or validation skill if available
|
|
61
|
+
2. Committed your changes with a meaningful message
|
|
62
62
|
3. Pushed to remote branch (if applicable)
|
|
63
|
+
|
|
64
|
+
**Important**: If validation fails, fix issues before marking as done.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ttt:show
|
|
3
|
+
description: Show issue details or search issues from local cycle data
|
|
4
|
+
arguments:
|
|
5
|
+
- name: issue-id
|
|
6
|
+
description: Issue ID to show (e.g., MP-624)
|
|
7
|
+
required: false
|
|
8
|
+
- name: label
|
|
9
|
+
description: Filter by label (--label <label>)
|
|
10
|
+
required: false
|
|
11
|
+
- name: status
|
|
12
|
+
description: Filter by status (--status <status>)
|
|
13
|
+
required: false
|
|
14
|
+
- name: user
|
|
15
|
+
description: Filter by assignee (--user <email|me|unassigned>)
|
|
16
|
+
required: false
|
|
17
|
+
- name: priority
|
|
18
|
+
description: Filter by priority (--priority <0-4>)
|
|
19
|
+
required: false
|
|
20
|
+
- name: remote
|
|
21
|
+
description: Fetch from Linear instead of local data (--remote)
|
|
22
|
+
required: false
|
|
23
|
+
- name: export
|
|
24
|
+
description: Output as markdown format (--export)
|
|
25
|
+
required: false
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# TTT Show Command
|
|
29
|
+
|
|
30
|
+
Show issue details or search issues from local cycle data.
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
### Show All Issues
|
|
35
|
+
```bash
|
|
36
|
+
ttt show
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Show Specific Issue
|
|
40
|
+
```bash
|
|
41
|
+
ttt show {{ issue-id }}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Search by Filters
|
|
45
|
+
```bash
|
|
46
|
+
ttt show --label {{ label }}
|
|
47
|
+
ttt show --status "{{ status }}"
|
|
48
|
+
ttt show --user {{ user }}
|
|
49
|
+
ttt show --priority {{ priority }}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Fetch from Linear (Remote)
|
|
53
|
+
```bash
|
|
54
|
+
ttt show {{ issue-id }} --remote
|
|
55
|
+
ttt show --remote --status todo
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## What This Does
|
|
59
|
+
|
|
60
|
+
1. By default, reads from local cycle.toon data (no API calls)
|
|
61
|
+
2. Supports filtering by label, status, user, priority
|
|
62
|
+
3. Use --remote to fetch fresh data from Linear API
|
|
63
|
+
4. Displays comprehensive information:
|
|
64
|
+
- Title and description
|
|
65
|
+
- Status (both Linear and local)
|
|
66
|
+
- Priority level
|
|
67
|
+
- Labels
|
|
68
|
+
- Assignee
|
|
69
|
+
- Branch name
|
|
70
|
+
- Parent issue (if subtask)
|
|
71
|
+
- Attachments with local paths
|
|
72
|
+
- Comments with timestamps
|
|
73
|
+
|
|
74
|
+
## Filter Options
|
|
75
|
+
|
|
76
|
+
| Option | Description | Example |
|
|
77
|
+
|--------|-------------|---------|
|
|
78
|
+
| `--label` | Filter by label name | `--label frontend` |
|
|
79
|
+
| `--status` | Filter by Linear status | `--status "In Progress"` |
|
|
80
|
+
| `--user` | Filter by assignee | `--user me`, `--user unassigned` |
|
|
81
|
+
| `--priority` | Filter by priority (0-4) | `--priority 1` (Urgent) |
|
|
82
|
+
| `--remote` | Fetch from Linear API | `--remote` |
|
|
83
|
+
| `--export` | Output as markdown | `--export` |
|
|
84
|
+
|
|
85
|
+
## Priority Values
|
|
86
|
+
|
|
87
|
+
- 0: None
|
|
88
|
+
- 1: Urgent
|
|
89
|
+
- 2: High
|
|
90
|
+
- 3: Medium
|
|
91
|
+
- 4: Low
|
|
92
|
+
|
|
93
|
+
## Use Cases
|
|
94
|
+
|
|
95
|
+
- List all issues in current cycle
|
|
96
|
+
- Search issues by label or status
|
|
97
|
+
- Review issue details before starting work
|
|
98
|
+
- Check requirements and acceptance criteria
|
|
99
|
+
- View attachments and mockups
|
|
100
|
+
- Read comment history and discussions
|
|
101
|
+
|
|
102
|
+
## Examples
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Show all local issues
|
|
106
|
+
ttt show
|
|
107
|
+
|
|
108
|
+
# Show specific issue
|
|
109
|
+
ttt show MP-624
|
|
110
|
+
|
|
111
|
+
# My in-progress issues
|
|
112
|
+
ttt show --status "In Progress" --user me
|
|
113
|
+
|
|
114
|
+
# All urgent issues
|
|
115
|
+
ttt show --priority 1
|
|
116
|
+
|
|
117
|
+
# Frontend issues
|
|
118
|
+
ttt show --label frontend
|
|
119
|
+
|
|
120
|
+
# Fetch fresh data from Linear
|
|
121
|
+
ttt show MP-624 --remote
|
|
122
|
+
|
|
123
|
+
# Export as markdown
|
|
124
|
+
ttt show --export
|
|
125
|
+
ttt show MP-624 --export
|
|
126
|
+
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: ttt
|
|
2
|
+
name: ttt:work-on
|
|
3
3
|
description: Start working on a Linear task
|
|
4
4
|
arguments:
|
|
5
5
|
- name: issue-id
|
|
@@ -44,5 +44,36 @@ ttt work-on next
|
|
|
44
44
|
|
|
45
45
|
1. Read the task description and requirements
|
|
46
46
|
2. Check out the suggested branch: `git checkout -b <branch-name>`
|
|
47
|
-
3. Run
|
|
47
|
+
3. **Run project validation** (see below)
|
|
48
48
|
4. Begin implementation
|
|
49
|
+
|
|
50
|
+
## Project Validation
|
|
51
|
+
|
|
52
|
+
Before starting work, check for validation tools:
|
|
53
|
+
|
|
54
|
+
### 1. Check for Existing Validation
|
|
55
|
+
|
|
56
|
+
Look for:
|
|
57
|
+
- **Commands**: `/validate`, `/check`, `/lint` in available commands
|
|
58
|
+
- **Skills**: `validate`, `check`, `verify` in available skills
|
|
59
|
+
- **Scripts**: `lint`, `type-check`, `test` in `package.json` or `Makefile`
|
|
60
|
+
|
|
61
|
+
### 2. If No Validation Found
|
|
62
|
+
|
|
63
|
+
Ask user:
|
|
64
|
+
```
|
|
65
|
+
No validation command or skill found for this project.
|
|
66
|
+
Would you like to create one? (y/n)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
If yes, run:
|
|
70
|
+
```
|
|
71
|
+
/ttt:write-validate
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Run Validation
|
|
75
|
+
|
|
76
|
+
Once validation is available:
|
|
77
|
+
- Use `/validate` command if exists
|
|
78
|
+
- Or use validation skill if available
|
|
79
|
+
- Or run detected scripts directly
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ttt:write-validate
|
|
3
|
+
description: Create a project validation command by detecting project type and existing lint/test configurations
|
|
4
|
+
arguments:
|
|
5
|
+
- name: command-name
|
|
6
|
+
description: Name for the command (default: validate)
|
|
7
|
+
required: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# TTT Write-Validate Command
|
|
11
|
+
|
|
12
|
+
Create a project-specific validation command by analyzing the codebase.
|
|
13
|
+
|
|
14
|
+
## Process
|
|
15
|
+
|
|
16
|
+
### 1. Detect Project Type
|
|
17
|
+
|
|
18
|
+
Check for project indicators:
|
|
19
|
+
|
|
20
|
+
| File | Project Type |
|
|
21
|
+
|------|--------------|
|
|
22
|
+
| `package.json` | Node.js / Bun |
|
|
23
|
+
| `Cargo.toml` | Rust |
|
|
24
|
+
| `go.mod` | Go |
|
|
25
|
+
| `pyproject.toml`, `requirements.txt` | Python |
|
|
26
|
+
|
|
27
|
+
### 2. Find Existing Configurations
|
|
28
|
+
|
|
29
|
+
Look for static analysis configs:
|
|
30
|
+
|
|
31
|
+
**Linting**: `biome.json`, `.eslintrc.*`, `ruff.toml`
|
|
32
|
+
**Type Check**: `tsconfig.json`, `mypy.ini`
|
|
33
|
+
**Testing**: `jest.config.*`, `vitest.config.*`, `pytest.ini`
|
|
34
|
+
|
|
35
|
+
### 3. Check package.json Scripts
|
|
36
|
+
|
|
37
|
+
If Node.js project:
|
|
38
|
+
```bash
|
|
39
|
+
cat package.json | jq '.scripts | keys[]' 2>/dev/null
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Look for: `lint`, `type-check`, `test`, `check`, `validate`
|
|
43
|
+
|
|
44
|
+
### 4. Create Command File
|
|
45
|
+
|
|
46
|
+
Create `.claude/commands/{{ $1 | default: "validate" }}.md`:
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
---
|
|
50
|
+
name: {{ $1 | default: "validate" }}
|
|
51
|
+
description: Run project validation (lint, type-check, test)
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
# Project Validation
|
|
55
|
+
|
|
56
|
+
Run validation checks for this project.
|
|
57
|
+
|
|
58
|
+
## Process
|
|
59
|
+
|
|
60
|
+
### 1. Lint
|
|
61
|
+
\`\`\`bash
|
|
62
|
+
{{ lint-command }}
|
|
63
|
+
\`\`\`
|
|
64
|
+
|
|
65
|
+
### 2. Type Check
|
|
66
|
+
\`\`\`bash
|
|
67
|
+
{{ type-check-command }}
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
### 3. Test (optional)
|
|
71
|
+
\`\`\`bash
|
|
72
|
+
{{ test-command }}
|
|
73
|
+
\`\`\`
|
|
74
|
+
|
|
75
|
+
## Quick Validate All
|
|
76
|
+
|
|
77
|
+
\`\`\`bash
|
|
78
|
+
{{ combined-command }}
|
|
79
|
+
\`\`\`
|
|
80
|
+
|
|
81
|
+
## On Failure
|
|
82
|
+
|
|
83
|
+
1. Show error output
|
|
84
|
+
2. Identify failing file(s) and line(s)
|
|
85
|
+
3. Suggest fixes
|
|
86
|
+
4. Re-run validation after fixes
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 5. Output
|
|
90
|
+
|
|
91
|
+
After creating:
|
|
92
|
+
1. Show created file path
|
|
93
|
+
2. Display detected validation commands
|
|
94
|
+
3. Suggest running `/{{ $1 | default: "validate" }}` to test
|
|
95
|
+
|
|
96
|
+
## Examples
|
|
97
|
+
|
|
98
|
+
### Node.js with Biome
|
|
99
|
+
```
|
|
100
|
+
Detected: Node.js project with Biome + TypeScript
|
|
101
|
+
Created: .claude/commands/validate.md
|
|
102
|
+
|
|
103
|
+
Commands:
|
|
104
|
+
Lint: bun run lint
|
|
105
|
+
Type: bun run type-check
|
|
106
|
+
Test: bun run test
|
|
107
|
+
|
|
108
|
+
Try: /validate
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Python with Ruff
|
|
112
|
+
```
|
|
113
|
+
Detected: Python project with Ruff + mypy
|
|
114
|
+
Created: .claude/commands/validate.md
|
|
115
|
+
|
|
116
|
+
Commands:
|
|
117
|
+
Lint: ruff check .
|
|
118
|
+
Type: mypy .
|
|
119
|
+
Test: pytest
|
|
120
|
+
|
|
121
|
+
Try: /validate
|
|
122
|
+
```
|
package/dist/bin/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ const COMMANDS = [
|
|
|
12
12
|
"work-on",
|
|
13
13
|
"done",
|
|
14
14
|
"status",
|
|
15
|
-
"
|
|
15
|
+
"show",
|
|
16
16
|
"config",
|
|
17
17
|
"help",
|
|
18
18
|
"version",
|
|
@@ -30,7 +30,7 @@ COMMANDS:
|
|
|
30
30
|
work-on Start working on a task (interactive or by ID)
|
|
31
31
|
done Mark current task as completed
|
|
32
32
|
status Show or modify task status
|
|
33
|
-
|
|
33
|
+
show Show issue details or search issues by filters
|
|
34
34
|
config Configure settings (status mappings, filters)
|
|
35
35
|
help Show this help message
|
|
36
36
|
version Show version
|
|
@@ -48,7 +48,9 @@ EXAMPLES:
|
|
|
48
48
|
ttt work-on next # Auto-select highest priority
|
|
49
49
|
ttt done # Complete current task
|
|
50
50
|
ttt done -m "Fixed the bug" # With completion message
|
|
51
|
-
ttt
|
|
51
|
+
ttt show MP-123 # Show issue from local data
|
|
52
|
+
ttt show --label frontend # Search local issues by label
|
|
53
|
+
ttt show --status "In Progress" # Filter by status
|
|
52
54
|
|
|
53
55
|
ENVIRONMENT:
|
|
54
56
|
LINEAR_API_KEY Required. Your Linear API key
|
|
@@ -120,9 +122,9 @@ async function main() {
|
|
|
120
122
|
process.argv = ["node", "status.js", ...commandArgs];
|
|
121
123
|
await import(`${scriptDir}status.js`);
|
|
122
124
|
break;
|
|
123
|
-
case "
|
|
124
|
-
process.argv = ["node", "
|
|
125
|
-
await import(`${scriptDir}
|
|
125
|
+
case "show":
|
|
126
|
+
process.argv = ["node", "show.js", ...commandArgs];
|
|
127
|
+
await import(`${scriptDir}show.js`);
|
|
126
128
|
break;
|
|
127
129
|
case "config":
|
|
128
130
|
process.argv = ["node", "config.js", ...commandArgs];
|
package/dist/scripts/init.js
CHANGED
|
@@ -400,21 +400,9 @@ async function updateGitignore(tttDir, interactive) {
|
|
|
400
400
|
// Silently ignore gitignore errors
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
|
-
|
|
404
|
-
if (!interactive) {
|
|
405
|
-
return false;
|
|
406
|
-
}
|
|
403
|
+
function showPluginInstallInstructions() {
|
|
407
404
|
console.log("\n🤖 Claude Code Plugin:");
|
|
408
|
-
|
|
409
|
-
type: "confirm",
|
|
410
|
-
name: "showInstructions",
|
|
411
|
-
message: "Show Claude Code plugin installation instructions? (provides /ttt-* commands)",
|
|
412
|
-
initial: true,
|
|
413
|
-
});
|
|
414
|
-
if (!showInstructions) {
|
|
415
|
-
return false;
|
|
416
|
-
}
|
|
417
|
-
console.log("\n┌─────────────────────────────────────────────────────────────┐");
|
|
405
|
+
console.log("┌─────────────────────────────────────────────────────────────┐");
|
|
418
406
|
console.log("│ Install team-toon-tack plugin in Claude Code: │");
|
|
419
407
|
console.log("├─────────────────────────────────────────────────────────────┤");
|
|
420
408
|
console.log("│ │");
|
|
@@ -425,14 +413,13 @@ async function showPluginInstallInstructions(interactive) {
|
|
|
425
413
|
console.log("│ /plugin install team-toon-tack@wayne930242 │");
|
|
426
414
|
console.log("│ │");
|
|
427
415
|
console.log("│ Available commands after install: │");
|
|
428
|
-
console.log("│ /ttt
|
|
429
|
-
console.log("│ /ttt
|
|
430
|
-
console.log("│ /ttt
|
|
431
|
-
console.log("│ /ttt
|
|
432
|
-
console.log("│ /ttt-
|
|
416
|
+
console.log("│ /ttt:sync - Sync Linear issues │");
|
|
417
|
+
console.log("│ /ttt:work-on - Start working on a task │");
|
|
418
|
+
console.log("│ /ttt:done - Complete current task │");
|
|
419
|
+
console.log("│ /ttt:status - Show/modify task status │");
|
|
420
|
+
console.log("│ /ttt:show - Show/search issues │");
|
|
433
421
|
console.log("│ │");
|
|
434
422
|
console.log("└─────────────────────────────────────────────────────────────┘");
|
|
435
|
-
return true;
|
|
436
423
|
}
|
|
437
424
|
async function init() {
|
|
438
425
|
const args = process.argv.slice(2);
|
|
@@ -625,7 +612,7 @@ async function init() {
|
|
|
625
612
|
// Update .gitignore (always use relative path .ttt)
|
|
626
613
|
await updateGitignore(".ttt", options.interactive ?? true);
|
|
627
614
|
// Show Claude Code plugin installation instructions
|
|
628
|
-
|
|
615
|
+
showPluginInstallInstructions();
|
|
629
616
|
// Summary
|
|
630
617
|
console.log("\n✅ Initialization complete!\n");
|
|
631
618
|
console.log("Configuration summary:");
|
|
@@ -659,8 +646,5 @@ async function init() {
|
|
|
659
646
|
console.log(` export LINEAR_API_KEY="${apiKey}"`);
|
|
660
647
|
console.log(" 2. Run sync: ttt sync");
|
|
661
648
|
console.log(" 3. Start working: ttt work-on");
|
|
662
|
-
if (pluginInstructionsShown) {
|
|
663
|
-
console.log("\n💡 Tip: Install the Claude Code plugin for /ttt-* commands.");
|
|
664
|
-
}
|
|
665
649
|
}
|
|
666
650
|
init().catch(console.error);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { displayTaskFull, PRIORITY_LABELS, getStatusIcon } from "./lib/display.js";
|
|
2
|
+
import { fetchIssueDetail } from "./lib/sync.js";
|
|
3
|
+
import { getLinearClient, getTeamId, loadConfig, loadCycleData, loadLocalConfig, } from "./utils.js";
|
|
4
|
+
function taskToMarkdown(task) {
|
|
5
|
+
const lines = [];
|
|
6
|
+
const priority = PRIORITY_LABELS[task.priority] || "None";
|
|
7
|
+
lines.push(`## ${task.id}: ${task.title}`);
|
|
8
|
+
lines.push("");
|
|
9
|
+
lines.push(`- **Status**: ${task.status} (Local: ${task.localStatus})`);
|
|
10
|
+
lines.push(`- **Priority**: ${priority}`);
|
|
11
|
+
lines.push(`- **Labels**: ${task.labels.length > 0 ? task.labels.join(", ") : "-"}`);
|
|
12
|
+
lines.push(`- **Assignee**: ${task.assignee || "Unassigned"}`);
|
|
13
|
+
if (task.branch)
|
|
14
|
+
lines.push(`- **Branch**: \`${task.branch}\``);
|
|
15
|
+
if (task.url)
|
|
16
|
+
lines.push(`- **URL**: ${task.url}`);
|
|
17
|
+
if (task.parentIssueId)
|
|
18
|
+
lines.push(`- **Parent**: ${task.parentIssueId}`);
|
|
19
|
+
if (task.description) {
|
|
20
|
+
lines.push("");
|
|
21
|
+
lines.push("### Description");
|
|
22
|
+
lines.push("");
|
|
23
|
+
lines.push(task.description);
|
|
24
|
+
}
|
|
25
|
+
if (task.attachments && task.attachments.length > 0) {
|
|
26
|
+
lines.push("");
|
|
27
|
+
lines.push("### Attachments");
|
|
28
|
+
lines.push("");
|
|
29
|
+
for (const att of task.attachments) {
|
|
30
|
+
const path = att.localPath || att.url;
|
|
31
|
+
lines.push(`- ${att.title}: ${path}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (task.comments && task.comments.length > 0) {
|
|
35
|
+
lines.push("");
|
|
36
|
+
lines.push("### Comments");
|
|
37
|
+
for (const comment of task.comments) {
|
|
38
|
+
const date = new Date(comment.createdAt).toLocaleDateString();
|
|
39
|
+
lines.push("");
|
|
40
|
+
lines.push(`**${comment.user || "Unknown"}** - ${date}`);
|
|
41
|
+
lines.push("");
|
|
42
|
+
lines.push(comment.body);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return lines.join("\n");
|
|
46
|
+
}
|
|
47
|
+
function tasksToMarkdownList(tasks) {
|
|
48
|
+
if (tasks.length === 0) {
|
|
49
|
+
return "No issues found.";
|
|
50
|
+
}
|
|
51
|
+
const lines = [];
|
|
52
|
+
lines.push(`# Issues (${tasks.length})`);
|
|
53
|
+
lines.push("");
|
|
54
|
+
for (const task of tasks) {
|
|
55
|
+
const icon = getStatusIcon(task.localStatus);
|
|
56
|
+
const priority = PRIORITY_LABELS[task.priority] || "None";
|
|
57
|
+
const assignee = task.assignee ? task.assignee.split("@")[0] : "unassigned";
|
|
58
|
+
lines.push(`## ${icon} ${task.id}: ${task.title}`);
|
|
59
|
+
lines.push("");
|
|
60
|
+
lines.push(`| Field | Value |`);
|
|
61
|
+
lines.push(`|-------|-------|`);
|
|
62
|
+
lines.push(`| Status | ${task.status} |`);
|
|
63
|
+
lines.push(`| Priority | ${priority} |`);
|
|
64
|
+
lines.push(`| Assignee | ${assignee} |`);
|
|
65
|
+
lines.push(`| Labels | ${task.labels.length > 0 ? task.labels.join(", ") : "-"} |`);
|
|
66
|
+
if (task.url)
|
|
67
|
+
lines.push(`| URL | ${task.url} |`);
|
|
68
|
+
lines.push("");
|
|
69
|
+
}
|
|
70
|
+
return lines.join("\n");
|
|
71
|
+
}
|
|
72
|
+
function displayTaskList(tasks) {
|
|
73
|
+
if (tasks.length === 0) {
|
|
74
|
+
console.log("No issues found.");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.log(`\nFound ${tasks.length} issue(s):\n`);
|
|
78
|
+
console.log("─".repeat(80));
|
|
79
|
+
for (const task of tasks) {
|
|
80
|
+
const icon = getStatusIcon(task.localStatus);
|
|
81
|
+
const priority = PRIORITY_LABELS[task.priority] || "⚪ None";
|
|
82
|
+
const assignee = task.assignee ? task.assignee.split("@")[0] : "unassigned";
|
|
83
|
+
const labels = task.labels.length > 0 ? task.labels.join(", ") : "-";
|
|
84
|
+
console.log(`${icon} ${task.id}: ${task.title}`);
|
|
85
|
+
console.log(` Status: ${task.status} | Priority: ${priority} | Assignee: ${assignee}`);
|
|
86
|
+
console.log(` Labels: ${labels}`);
|
|
87
|
+
console.log("─".repeat(80));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function searchIssuesFromLinear(filters) {
|
|
91
|
+
const config = await loadConfig();
|
|
92
|
+
const localConfig = await loadLocalConfig();
|
|
93
|
+
const client = getLinearClient();
|
|
94
|
+
const teamId = getTeamId(config, localConfig.team);
|
|
95
|
+
// Build filter
|
|
96
|
+
const issueFilter = {
|
|
97
|
+
team: { id: { eq: teamId } },
|
|
98
|
+
};
|
|
99
|
+
if (filters.label) {
|
|
100
|
+
issueFilter.labels = { name: { containsIgnoreCase: filters.label } };
|
|
101
|
+
}
|
|
102
|
+
if (filters.status) {
|
|
103
|
+
issueFilter.state = { name: { containsIgnoreCase: filters.status } };
|
|
104
|
+
}
|
|
105
|
+
if (filters.assignee) {
|
|
106
|
+
if (filters.assignee.toLowerCase() === "me") {
|
|
107
|
+
issueFilter.assignee = { email: { eq: localConfig.current_user } };
|
|
108
|
+
}
|
|
109
|
+
else if (filters.assignee.toLowerCase() === "unassigned") {
|
|
110
|
+
issueFilter.assignee = { null: true };
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
issueFilter.assignee = { email: { containsIgnoreCase: filters.assignee } };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (filters.priority !== undefined) {
|
|
117
|
+
issueFilter.priority = { eq: filters.priority };
|
|
118
|
+
}
|
|
119
|
+
const issues = await client.issues({
|
|
120
|
+
filter: issueFilter,
|
|
121
|
+
first: 50,
|
|
122
|
+
});
|
|
123
|
+
const tasks = [];
|
|
124
|
+
for (const issueNode of issues.nodes) {
|
|
125
|
+
const issue = await client.issue(issueNode.id);
|
|
126
|
+
const assignee = await issue.assignee;
|
|
127
|
+
const labels = await issue.labels();
|
|
128
|
+
const state = await issue.state;
|
|
129
|
+
const parent = await issue.parent;
|
|
130
|
+
const task = {
|
|
131
|
+
id: issue.identifier,
|
|
132
|
+
linearId: issue.id,
|
|
133
|
+
title: issue.title,
|
|
134
|
+
status: state ? state.name : "Unknown",
|
|
135
|
+
localStatus: "pending",
|
|
136
|
+
assignee: assignee?.email,
|
|
137
|
+
priority: issue.priority,
|
|
138
|
+
labels: labels.nodes.map((l) => l.name),
|
|
139
|
+
branch: issue.branchName,
|
|
140
|
+
description: issue.description ?? undefined,
|
|
141
|
+
parentIssueId: parent ? parent.identifier : undefined,
|
|
142
|
+
url: issue.url,
|
|
143
|
+
};
|
|
144
|
+
tasks.push(task);
|
|
145
|
+
}
|
|
146
|
+
return tasks;
|
|
147
|
+
}
|
|
148
|
+
async function searchIssuesFromLocal(data, filters) {
|
|
149
|
+
let tasks = data.tasks;
|
|
150
|
+
if (filters.label) {
|
|
151
|
+
const labelLower = filters.label.toLowerCase();
|
|
152
|
+
tasks = tasks.filter((t) => t.labels.some((l) => l.toLowerCase().includes(labelLower)));
|
|
153
|
+
}
|
|
154
|
+
if (filters.status) {
|
|
155
|
+
const statusLower = filters.status.toLowerCase();
|
|
156
|
+
tasks = tasks.filter((t) => t.status.toLowerCase().includes(statusLower));
|
|
157
|
+
}
|
|
158
|
+
if (filters.assignee) {
|
|
159
|
+
const assigneeLower = filters.assignee.toLowerCase();
|
|
160
|
+
if (assigneeLower === "unassigned") {
|
|
161
|
+
tasks = tasks.filter((t) => !t.assignee);
|
|
162
|
+
}
|
|
163
|
+
else if (assigneeLower === "me") {
|
|
164
|
+
const localConfig = await loadLocalConfig();
|
|
165
|
+
const config = await loadConfig();
|
|
166
|
+
const userEmail = config.users[localConfig.current_user]?.email?.toLowerCase();
|
|
167
|
+
if (userEmail) {
|
|
168
|
+
tasks = tasks.filter((t) => t.assignee?.toLowerCase() === userEmail);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
tasks = tasks.filter((t) => t.assignee?.toLowerCase().includes(assigneeLower));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (filters.priority !== undefined) {
|
|
176
|
+
tasks = tasks.filter((t) => t.priority === filters.priority);
|
|
177
|
+
}
|
|
178
|
+
return tasks;
|
|
179
|
+
}
|
|
180
|
+
async function show() {
|
|
181
|
+
const args = process.argv.slice(2);
|
|
182
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
183
|
+
console.log(`Usage: ttt show [issue-id] [options]
|
|
184
|
+
|
|
185
|
+
Show issue details or search for issues from local cycle data.
|
|
186
|
+
|
|
187
|
+
Arguments:
|
|
188
|
+
issue-id Optional. Show specific issue (e.g., MP-624)
|
|
189
|
+
|
|
190
|
+
Options:
|
|
191
|
+
--remote Fetch from Linear instead of local data
|
|
192
|
+
--export Output as markdown format
|
|
193
|
+
--label <label> Filter by label
|
|
194
|
+
--status <status> Filter by status
|
|
195
|
+
--user <email> Filter by assignee (use "me" for yourself, "unassigned" for no assignee)
|
|
196
|
+
--priority <n> Filter by priority (0=None, 1=Urgent, 2=High, 3=Medium, 4=Low)
|
|
197
|
+
|
|
198
|
+
Examples:
|
|
199
|
+
ttt show # Show all issues in local cycle data
|
|
200
|
+
ttt show MP-624 # Show specific issue from local data
|
|
201
|
+
ttt show MP-624 --remote # Fetch specific issue from Linear
|
|
202
|
+
ttt show MP-624 --export # Export issue as markdown
|
|
203
|
+
ttt show --label frontend # Filter local issues by label
|
|
204
|
+
ttt show --status "In Progress" --user me # My in-progress issues
|
|
205
|
+
ttt show --priority 1 # Show all urgent issues
|
|
206
|
+
ttt show --export # Export all issues as markdown`);
|
|
207
|
+
process.exit(0);
|
|
208
|
+
}
|
|
209
|
+
const useRemote = args.includes("--remote");
|
|
210
|
+
const exportMarkdown = args.includes("--export");
|
|
211
|
+
// Parse filters
|
|
212
|
+
const filters = {};
|
|
213
|
+
for (let i = 0; i < args.length; i++) {
|
|
214
|
+
const arg = args[i];
|
|
215
|
+
if (arg === "--label" && args[i + 1]) {
|
|
216
|
+
filters.label = args[++i];
|
|
217
|
+
}
|
|
218
|
+
else if (arg === "--status" && args[i + 1]) {
|
|
219
|
+
filters.status = args[++i];
|
|
220
|
+
}
|
|
221
|
+
else if (arg === "--user" && args[i + 1]) {
|
|
222
|
+
filters.assignee = args[++i];
|
|
223
|
+
}
|
|
224
|
+
else if (arg === "--priority" && args[i + 1]) {
|
|
225
|
+
filters.priority = parseInt(args[++i], 10);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Check if this is a search (has filters) or single issue lookup
|
|
229
|
+
const hasFilters = Object.keys(filters).length > 0;
|
|
230
|
+
// Find issue ID (argument that doesn't start with -)
|
|
231
|
+
const issueId = args.find((arg) => !arg.startsWith("-") && arg.match(/^[A-Z]+-\d+$/i));
|
|
232
|
+
// If no issue ID and no filters, show all local issues
|
|
233
|
+
if (!issueId && !hasFilters) {
|
|
234
|
+
const data = await loadCycleData();
|
|
235
|
+
if (!data) {
|
|
236
|
+
console.error("No cycle data found. Run ttt sync first.");
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
if (exportMarkdown) {
|
|
240
|
+
console.log(tasksToMarkdownList(data.tasks));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
displayTaskList(data.tasks);
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
// Search mode: has filters but no specific issue ID
|
|
248
|
+
if (hasFilters && !issueId) {
|
|
249
|
+
let tasks;
|
|
250
|
+
if (useRemote) {
|
|
251
|
+
console.error("Searching issues from Linear...");
|
|
252
|
+
tasks = await searchIssuesFromLinear(filters);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
const data = await loadCycleData();
|
|
256
|
+
if (!data) {
|
|
257
|
+
console.error("No cycle data found. Run ttt sync first.");
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
tasks = await searchIssuesFromLocal(data, filters);
|
|
261
|
+
}
|
|
262
|
+
if (exportMarkdown) {
|
|
263
|
+
console.log(tasksToMarkdownList(tasks));
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
displayTaskList(tasks);
|
|
267
|
+
}
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// Single issue mode
|
|
271
|
+
if (!issueId) {
|
|
272
|
+
console.error("Issue ID is required for single issue lookup.");
|
|
273
|
+
console.error("Usage: ttt show <issue-id> or ttt show --label <label>");
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
276
|
+
// Fetch from remote Linear
|
|
277
|
+
if (useRemote) {
|
|
278
|
+
console.error(`Fetching ${issueId} from Linear...`);
|
|
279
|
+
const task = await fetchIssueDetail(issueId);
|
|
280
|
+
if (!task) {
|
|
281
|
+
console.error(`Issue ${issueId} not found in Linear.`);
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
// Check local data for local status
|
|
285
|
+
const data = await loadCycleData();
|
|
286
|
+
if (data) {
|
|
287
|
+
const localTask = data.tasks.find((t) => t.id === issueId);
|
|
288
|
+
if (localTask) {
|
|
289
|
+
task.localStatus = localTask.localStatus;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (exportMarkdown) {
|
|
293
|
+
console.log(taskToMarkdown(task));
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
displayTaskFull(task, "📋");
|
|
297
|
+
}
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
// Default: get from local cycle data
|
|
301
|
+
const data = await loadCycleData();
|
|
302
|
+
if (!data) {
|
|
303
|
+
console.error("No cycle data found. Run ttt sync first.");
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
const task = data.tasks.find((t) => t.id === issueId || t.id === issueId.toUpperCase());
|
|
307
|
+
if (!task) {
|
|
308
|
+
console.error(`Issue ${issueId} not found in local data.`);
|
|
309
|
+
console.error("Use --remote to fetch from Linear.");
|
|
310
|
+
process.exit(1);
|
|
311
|
+
}
|
|
312
|
+
if (exportMarkdown) {
|
|
313
|
+
console.log(taskToMarkdown(task));
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
displayTaskFull(task, "📋");
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
show().catch(console.error);
|
package/dist/scripts/sync.js
CHANGED
|
@@ -17,12 +17,13 @@ Options:
|
|
|
17
17
|
|
|
18
18
|
What it does:
|
|
19
19
|
- Fetches active cycle from Linear
|
|
20
|
-
- Downloads all issues
|
|
20
|
+
- Downloads all issues in the cycle (regardless of status)
|
|
21
|
+
- Filters by label if configured
|
|
21
22
|
- Preserves local status for existing tasks
|
|
22
23
|
- Updates config with new cycle info
|
|
23
24
|
|
|
24
25
|
Examples:
|
|
25
|
-
ttt sync # Sync all
|
|
26
|
+
ttt sync # Sync all issues in current cycle
|
|
26
27
|
ttt sync MP-624 # Sync only this specific issue
|
|
27
28
|
ttt sync --update # Push local changes to Linear, then sync
|
|
28
29
|
ttt sync -d .ttt # Sync using .ttt directory`);
|
|
@@ -150,7 +151,6 @@ Examples:
|
|
|
150
151
|
const existingTasksMap = new Map(existingData?.tasks.map((t) => [t.id, t]));
|
|
151
152
|
// Phase 4: Fetch current issues with full content
|
|
152
153
|
const filterLabel = localConfig.label;
|
|
153
|
-
const syncStatuses = [statusTransitions.todo, statusTransitions.in_progress];
|
|
154
154
|
let issues;
|
|
155
155
|
if (singleIssueId) {
|
|
156
156
|
// Sync single issue by ID
|
|
@@ -165,12 +165,11 @@ Examples:
|
|
|
165
165
|
}
|
|
166
166
|
else {
|
|
167
167
|
// Sync all matching issues
|
|
168
|
-
console.log(`Fetching issues
|
|
169
|
-
// Build filter - label is optional
|
|
168
|
+
console.log(`Fetching all issues in current cycle${filterLabel ? ` with label: ${filterLabel}` : ""}...`);
|
|
169
|
+
// Build filter - label is optional, no status filter
|
|
170
170
|
const issueFilter = {
|
|
171
171
|
team: { id: { eq: teamId } },
|
|
172
172
|
cycle: { id: { eq: cycleId } },
|
|
173
|
-
state: { name: { in: syncStatuses } },
|
|
174
173
|
};
|
|
175
174
|
if (filterLabel) {
|
|
176
175
|
issueFilter.labels = { name: { eq: filterLabel } };
|
|
@@ -181,7 +180,7 @@ Examples:
|
|
|
181
180
|
});
|
|
182
181
|
}
|
|
183
182
|
if (issues.nodes.length === 0) {
|
|
184
|
-
console.log(`No issues found in current cycle
|
|
183
|
+
console.log(`No issues found in current cycle${filterLabel ? ` with label: ${filterLabel}` : ""}.`);
|
|
185
184
|
}
|
|
186
185
|
const tasks = [];
|
|
187
186
|
let updatedCount = 0;
|
package/package.json
CHANGED
|
@@ -43,8 +43,14 @@ ttt work-on MP-624
|
|
|
43
43
|
# Check current task status
|
|
44
44
|
ttt status
|
|
45
45
|
|
|
46
|
-
#
|
|
47
|
-
ttt
|
|
46
|
+
# Show issue details from local data
|
|
47
|
+
ttt show MP-624
|
|
48
|
+
|
|
49
|
+
# Search issues by filters
|
|
50
|
+
ttt show --status "In Progress" --user me
|
|
51
|
+
|
|
52
|
+
# Export issues as markdown
|
|
53
|
+
ttt show --export
|
|
48
54
|
|
|
49
55
|
# Mark task as blocked if waiting on dependency
|
|
50
56
|
ttt status MP-624 --set blocked
|
|
@@ -108,10 +114,20 @@ The `ttt done` command behaves differently based on configured mode:
|
|
|
108
114
|
└── output/ # Downloaded attachments
|
|
109
115
|
```
|
|
110
116
|
|
|
117
|
+
## Project Validation
|
|
118
|
+
|
|
119
|
+
Before starting or completing tasks, run project validation:
|
|
120
|
+
|
|
121
|
+
1. **Check for validation command/skill**: Look for `/validate`, `/check` commands or validation skills
|
|
122
|
+
2. **Check package.json/Makefile**: Look for `lint`, `type-check`, `test` scripts
|
|
123
|
+
|
|
124
|
+
If no validation exists, suggest running `/ttt:write-validate` to create a project-specific validation command.
|
|
125
|
+
|
|
111
126
|
## Best Practices
|
|
112
127
|
|
|
113
128
|
### DO
|
|
114
129
|
- Always `ttt sync` before starting work
|
|
130
|
+
- **Run project validation** before starting and before completing tasks
|
|
115
131
|
- Use `ttt work-on next` for auto-prioritization
|
|
116
132
|
- Include meaningful messages with `ttt done -m "..."`
|
|
117
133
|
- Check `ttt status` to verify state before commits
|
|
@@ -120,17 +136,18 @@ The `ttt done` command behaves differently based on configured mode:
|
|
|
120
136
|
- Don't manually edit `cycle.toon` - use CLI commands
|
|
121
137
|
- Don't skip sync - local data may be stale
|
|
122
138
|
- Don't forget to commit before `ttt done`
|
|
139
|
+
- Don't mark tasks done without running validation
|
|
123
140
|
|
|
124
141
|
## Troubleshooting
|
|
125
142
|
|
|
126
143
|
### "No cycle data found"
|
|
127
144
|
Run `ttt sync` to fetch issues from Linear.
|
|
128
145
|
|
|
129
|
-
### "Issue not found in
|
|
130
|
-
The issue may not
|
|
131
|
-
-
|
|
132
|
-
-
|
|
133
|
-
-
|
|
146
|
+
### "Issue not found in local data"
|
|
147
|
+
The issue may not be synced. Try:
|
|
148
|
+
- Run `ttt sync` to fetch latest issues
|
|
149
|
+
- Use `ttt show MP-624 --remote` to fetch directly from Linear
|
|
150
|
+
- Check if issue is in active cycle
|
|
134
151
|
|
|
135
152
|
### "LINEAR_API_KEY not set"
|
|
136
153
|
```bash
|
|
@@ -157,8 +174,9 @@ ttt work-on next # Move to next task
|
|
|
157
174
|
|
|
158
175
|
### Example: Check Specific Issue
|
|
159
176
|
```bash
|
|
160
|
-
ttt
|
|
161
|
-
ttt
|
|
177
|
+
ttt show MP-624 # Show from local data
|
|
178
|
+
ttt show MP-624 --remote # Fetch from Linear
|
|
179
|
+
ttt show MP-624 --export # Export as markdown
|
|
162
180
|
```
|
|
163
181
|
|
|
164
182
|
## Important Rules
|
|
@@ -166,5 +184,5 @@ ttt get-issue MP-624 --local # Show cached data
|
|
|
166
184
|
- Always verify `LINEAR_API_KEY` is set before operations
|
|
167
185
|
- Run `ttt sync` at the start of each work session
|
|
168
186
|
- Commit code before running `ttt done`
|
|
169
|
-
- Use
|
|
187
|
+
- Use `ttt show` (default) to read from local data; use `--remote` only when needed
|
|
170
188
|
- Check `.ttt/output/` for downloaded attachments and images
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ttt-get-issue
|
|
3
|
-
description: Fetch and display issue details from Linear
|
|
4
|
-
arguments:
|
|
5
|
-
- name: issue-id
|
|
6
|
-
description: Issue ID to fetch (e.g., MP-624)
|
|
7
|
-
required: true
|
|
8
|
-
- name: local
|
|
9
|
-
description: Only show from local data (add --local flag)
|
|
10
|
-
required: false
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
# TTT Get-Issue Command
|
|
14
|
-
|
|
15
|
-
Fetch and display full issue details from Linear.
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
### Fetch from Linear
|
|
20
|
-
```bash
|
|
21
|
-
ttt get-issue {{ issue-id }}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Show from Local Data Only
|
|
25
|
-
If `local` is "true" or "--local":
|
|
26
|
-
```bash
|
|
27
|
-
ttt get-issue {{ issue-id }} --local
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## What This Does
|
|
31
|
-
|
|
32
|
-
1. Fetches full issue details from Linear API (or local cache if --local)
|
|
33
|
-
2. Displays comprehensive information:
|
|
34
|
-
- Title and description
|
|
35
|
-
- Status (both Linear and local)
|
|
36
|
-
- Priority level
|
|
37
|
-
- Labels
|
|
38
|
-
- Assignee
|
|
39
|
-
- Branch name
|
|
40
|
-
- Parent issue (if subtask)
|
|
41
|
-
- Attachments with local paths
|
|
42
|
-
- Comments with timestamps
|
|
43
|
-
|
|
44
|
-
## Use Cases
|
|
45
|
-
|
|
46
|
-
- Review issue details before starting work
|
|
47
|
-
- Check requirements and acceptance criteria
|
|
48
|
-
- View attachments and mockups
|
|
49
|
-
- Read comment history and discussions
|
|
50
|
-
- Verify issue status without full sync
|
|
51
|
-
|
|
52
|
-
## Output Format
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
📋 MP-624: Issue Title
|
|
56
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
57
|
-
Status: In Progress | Local: in-progress
|
|
58
|
-
Priority: 🔴 Urgent
|
|
59
|
-
Labels: frontend, bug
|
|
60
|
-
Assignee: developer@example.com
|
|
61
|
-
Branch: feature/mp-624-fix-bug
|
|
62
|
-
|
|
63
|
-
Description:
|
|
64
|
-
[Full description content]
|
|
65
|
-
|
|
66
|
-
Attachments:
|
|
67
|
-
- screenshot.png (local: .ttt/output/MP-624/...)
|
|
68
|
-
|
|
69
|
-
Comments:
|
|
70
|
-
[Comment history]
|
|
71
|
-
```
|