team-toon-tack 3.9.0 → 3.9.3
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/.codex-plugin/plugin.json +20 -0
- package/README.md +26 -3
- package/README.zh-TW.md +26 -3
- package/commands/ttt-work-on.md +10 -57
- package/dist/bin/cli.js +1 -1
- package/dist/scripts/cancel.js +4 -1
- package/dist/scripts/create.d.ts +1 -1
- package/dist/scripts/create.js +23 -5
- package/dist/scripts/lib/adapters/linear-adapter.js +10 -3
- package/dist/scripts/lib/adapters/trello-adapter.d.ts +1 -1
- package/dist/scripts/lib/adapters/trello-adapter.js +85 -5
- package/package.json +2 -1
- package/skills/managing-linear-tasks/SKILL.md +33 -32
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "team-toon-tack",
|
|
3
|
+
"version": "3.9.1",
|
|
4
|
+
"description": "透過 ttt CLI 同步與管理 Linear、Trello 任務。",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "wayne930242"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/wayne930242/team-toon-tack",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"skills": "./skills/",
|
|
11
|
+
"interface": {
|
|
12
|
+
"displayName": "team-toon-tack",
|
|
13
|
+
"shortDescription": "同步與管理 Linear、Trello 任務",
|
|
14
|
+
"longDescription": "透過 ttt CLI 同步任務、查詢狀態、記錄估時,並依使用者要求更新 Linear 與 Trello。",
|
|
15
|
+
"developerName": "wayne930242",
|
|
16
|
+
"category": "Productivity",
|
|
17
|
+
"capabilities": ["Interactive", "Write"],
|
|
18
|
+
"defaultPrompt": ["使用 ttt 同步並列出我的任務。"]
|
|
19
|
+
}
|
|
20
|
+
}
|
package/README.md
CHANGED
|
@@ -67,9 +67,32 @@ During init, you'll be prompted to select your task source (Linear or Trello) an
|
|
|
67
67
|
|
|
68
68
|
```
|
|
69
69
|
/plugin marketplace add wayne930242/team-toon-tack
|
|
70
|
-
/plugin install team-toon-tack@
|
|
70
|
+
/plugin install team-toon-tack@ttt-marketplace
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
### Codex plugin 安裝(選擇性)
|
|
74
|
+
|
|
75
|
+
先依上方步驟安裝 `ttt` CLI 並執行 `ttt init`。Plugin 提供任務管理技能,透過 shell 呼叫 CLI。
|
|
76
|
+
|
|
77
|
+
從 GitHub 安裝:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
codex plugin marketplace add wayne930242/team-toon-tack
|
|
81
|
+
codex plugin add team-toon-tack@ttt-marketplace
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
從本地 checkout 安裝,在此 repository 根目錄執行:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
codex plugin marketplace add "$PWD"
|
|
88
|
+
codex plugin add team-toon-tack@ttt-marketplace
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
若已註冊同名的 GitHub marketplace,先執行 `codex plugin marketplace remove ttt-marketplace`,再加入本地路徑。
|
|
92
|
+
修改已安裝的同版本內容後,先執行 `codex plugin remove team-toon-tack@ttt-marketplace`,再執行上述 `codex plugin add` 重新安裝。
|
|
93
|
+
|
|
94
|
+
安裝完成後開啟新的 Codex 對話,使用 `$managing-linear-tasks`,或直接說「使用 ttt 同步並列出我的任務」。Codex 會使用 `ttt sync`、`ttt show` 等 CLI 指令。
|
|
95
|
+
|
|
73
96
|
### 3. Daily Workflow
|
|
74
97
|
|
|
75
98
|
In Claude Code (with plugin installed):
|
|
@@ -237,7 +260,7 @@ Install the plugin for Claude Code integration:
|
|
|
237
260
|
|
|
238
261
|
```
|
|
239
262
|
/plugin marketplace add wayne930242/team-toon-tack
|
|
240
|
-
/plugin install team-toon-tack@
|
|
263
|
+
/plugin install team-toon-tack@ttt-marketplace
|
|
241
264
|
```
|
|
242
265
|
|
|
243
266
|
### Available Commands
|
|
@@ -253,7 +276,7 @@ Install the plugin for Claude Code integration:
|
|
|
253
276
|
|
|
254
277
|
### Auto-Activated Skill
|
|
255
278
|
|
|
256
|
-
The plugin includes a `linear-
|
|
279
|
+
The plugin includes a `managing-linear-tasks` skill that automatically activates when working with tasks, providing workflow guidance and best practices.
|
|
257
280
|
|
|
258
281
|
## License
|
|
259
282
|
|
package/README.zh-TW.md
CHANGED
|
@@ -67,9 +67,32 @@ ttt init
|
|
|
67
67
|
|
|
68
68
|
```
|
|
69
69
|
/plugin marketplace add wayne930242/team-toon-tack
|
|
70
|
-
/plugin install team-toon-tack@
|
|
70
|
+
/plugin install team-toon-tack@ttt-marketplace
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
### Codex plugin 安裝(選擇性)
|
|
74
|
+
|
|
75
|
+
先依上方步驟安裝 `ttt` CLI 並執行 `ttt init`。Plugin 提供任務管理技能,透過 shell 呼叫 CLI。
|
|
76
|
+
|
|
77
|
+
從 GitHub 安裝:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
codex plugin marketplace add wayne930242/team-toon-tack
|
|
81
|
+
codex plugin add team-toon-tack@ttt-marketplace
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
從本地 checkout 安裝,在此 repository 根目錄執行:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
codex plugin marketplace add "$PWD"
|
|
88
|
+
codex plugin add team-toon-tack@ttt-marketplace
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
若已註冊同名的 GitHub marketplace,先執行 `codex plugin marketplace remove ttt-marketplace`,再加入本地路徑。
|
|
92
|
+
修改已安裝的同版本內容後,先執行 `codex plugin remove team-toon-tack@ttt-marketplace`,再執行上述 `codex plugin add` 重新安裝。
|
|
93
|
+
|
|
94
|
+
安裝完成後開啟新的 Codex 對話,使用 `$managing-linear-tasks`,或直接說「使用 ttt 同步並列出我的任務」。Codex 會使用 `ttt sync`、`ttt show` 等 CLI 指令。
|
|
95
|
+
|
|
73
96
|
### 3. 每日工作流
|
|
74
97
|
|
|
75
98
|
在 Claude Code 中(安裝 plugin 後):
|
|
@@ -237,7 +260,7 @@ your-project/
|
|
|
237
260
|
|
|
238
261
|
```
|
|
239
262
|
/plugin marketplace add wayne930242/team-toon-tack
|
|
240
|
-
/plugin install team-toon-tack@
|
|
263
|
+
/plugin install team-toon-tack@ttt-marketplace
|
|
241
264
|
```
|
|
242
265
|
|
|
243
266
|
### 可用指令
|
|
@@ -253,7 +276,7 @@ your-project/
|
|
|
253
276
|
|
|
254
277
|
### 自動啟用技能
|
|
255
278
|
|
|
256
|
-
Plugin 包含 `linear-
|
|
279
|
+
Plugin 包含 `managing-linear-tasks` 技能,在處理任務時會自動啟用,提供工作流程指導和最佳實踐。
|
|
257
280
|
|
|
258
281
|
## 授權
|
|
259
282
|
|
package/commands/ttt-work-on.md
CHANGED
|
@@ -5,7 +5,6 @@ arguments:
|
|
|
5
5
|
- name: issue-id
|
|
6
6
|
description: "Issue ID (e.g., MP-624) or 'next' for auto-select. Defaults to 'next'."
|
|
7
7
|
required: false
|
|
8
|
-
default: next
|
|
9
8
|
- name: dry-run
|
|
10
9
|
description: Preview selection without changing status
|
|
11
10
|
required: false
|
|
@@ -48,67 +47,21 @@ Options:
|
|
|
48
47
|
--dry-run Pick task without changing status (preview only)
|
|
49
48
|
```
|
|
50
49
|
|
|
51
|
-
##
|
|
50
|
+
## After Selection — Delegate the Implementation
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
Skipping phases is not "pragmatic", it is debt.
|
|
52
|
+
This command picks the task. The implementation workflow belongs to the user.
|
|
55
53
|
|
|
56
|
-
|
|
54
|
+
**Use the user's own workflow whenever one exists** — routing or laws in their root `CLAUDE.md`, the project `CLAUDE.md`, or a `work-on` / `start-work` skill. Follow it as written and add nothing.
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
If unclear whether to branch or what name to use, ask the user instead of assuming.
|
|
56
|
+
**Only when none exists**, run this minimal loop:
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Scope decides depth.
|
|
68
|
-
|
|
69
|
-
- Unclear requirements or 3+ files touched → if your environment has a brainstorming/planning skill, use it; otherwise clarify scope with the user and write a short plan before coding.
|
|
70
|
-
- Clear and small (≤2 files, obvious change) → state a 2–3 bullet plan inline before coding.
|
|
71
|
-
|
|
72
|
-
Never go straight to code.
|
|
73
|
-
Planning collapses ambiguity before implementation.
|
|
74
|
-
|
|
75
|
-
### 3. Test First (TDD)
|
|
76
|
-
|
|
77
|
-
Red → Green → Refactor per behavior:
|
|
78
|
-
|
|
79
|
-
1. Write one failing test naming the behavior.
|
|
80
|
-
2. Run test — verify it fails for the expected reason.
|
|
81
|
-
3. Write minimal code to pass.
|
|
82
|
-
4. Run test — verify pass, other tests still green.
|
|
83
|
-
5. Refactor if needed, keep green.
|
|
84
|
-
|
|
85
|
-
No production code without a failing test first.
|
|
86
|
-
|
|
87
|
-
### 4. Review (before `/ttt:done`)
|
|
88
|
-
|
|
89
|
-
Verify before claiming completion — run and confirm output:
|
|
90
|
-
|
|
91
|
-
- Full test suite passes.
|
|
92
|
-
- `npm run lint` / `npm run type` clean (or project-specific commands).
|
|
93
|
-
- Only requested scope changed — no drive-by edits.
|
|
94
|
-
- No debug logs, stubs, TODOs.
|
|
95
|
-
|
|
96
|
-
Evidence before assertions.
|
|
97
|
-
Do not claim complete without running the commands.
|
|
98
|
-
|
|
99
|
-
### 5. Complete
|
|
100
|
-
|
|
101
|
-
```text
|
|
102
|
-
/ttt:done -m "summary"
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
A task is NOT complete until `/ttt:done` runs.
|
|
106
|
-
This is MANDATORY.
|
|
107
|
-
|
|
108
|
-
## Project-Specific Skill
|
|
58
|
+
- Branch using the repo's existing naming convention.
|
|
59
|
+
- State a short plan before coding; for unclear scope or 3+ files, settle the scope with the user first.
|
|
60
|
+
- Write the failing test first, then the minimal code to pass it.
|
|
61
|
+
- Run lint / type / test and report the real output before claiming completion.
|
|
62
|
+
- Offer `/ttt:write-work-on-skill` to capture this project's commands as a reusable skill.
|
|
109
63
|
|
|
110
|
-
|
|
111
|
-
If missing, suggest `/ttt:write-work-on-skill` — it scaffolds a skill following this same 4-phase structure.
|
|
64
|
+
Either path closes the task with `/ttt:done -m "summary"`.
|
|
112
65
|
|
|
113
66
|
## Error Handling
|
|
114
67
|
|
package/dist/bin/cli.js
CHANGED
|
@@ -172,7 +172,7 @@ async function main() {
|
|
|
172
172
|
break;
|
|
173
173
|
case "create":
|
|
174
174
|
process.argv = ["node", "create.js", ...commandArgs];
|
|
175
|
-
await importScript("create.js");
|
|
175
|
+
await importScript("create.js").then((module) => module.create());
|
|
176
176
|
break;
|
|
177
177
|
case "assign":
|
|
178
178
|
process.argv = ["node", "assign.js", ...commandArgs];
|
package/dist/scripts/cancel.js
CHANGED
package/dist/scripts/create.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
export
|
|
2
|
+
export declare function create(args?: string[]): Promise<void>;
|
package/dist/scripts/create.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
2
4
|
import { input, select } from "@inquirer/prompts";
|
|
3
5
|
import { createAdapter } from "./lib/adapters/index.js";
|
|
4
6
|
import { getSourceType, getTeamId, loadConfig, loadCycleData, loadLocalConfig, sourceIssueToTask, upsertTaskInCycleData, } from "./utils.js";
|
|
@@ -121,8 +123,7 @@ async function resolveParentSourceId(adapter, parentIdentifier) {
|
|
|
121
123
|
}
|
|
122
124
|
return parent.sourceId;
|
|
123
125
|
}
|
|
124
|
-
async function create() {
|
|
125
|
-
const args = process.argv.slice(2);
|
|
126
|
+
export async function create(args = process.argv.slice(2)) {
|
|
126
127
|
if (args.includes("--help") || args.includes("-h")) {
|
|
127
128
|
console.log(`Usage: ttt create [options]
|
|
128
129
|
|
|
@@ -156,6 +157,10 @@ Examples:
|
|
|
156
157
|
const labelArg = parsed.label;
|
|
157
158
|
const statusName = parsed.status;
|
|
158
159
|
const parentId = parsed.parent;
|
|
160
|
+
if (sourceType === "trello" && parentId) {
|
|
161
|
+
console.error("Parent issues are not supported for Trello cards.");
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
159
164
|
if (!title) {
|
|
160
165
|
if (!parsed.interactive) {
|
|
161
166
|
console.error("Title is required when --no-interactive is set.");
|
|
@@ -204,8 +209,13 @@ Examples:
|
|
|
204
209
|
}
|
|
205
210
|
console.log("Creating issue...");
|
|
206
211
|
const adapter = createAdapter(config);
|
|
212
|
+
let cycleData = sourceType === "trello" ? await loadCycleData() : null;
|
|
213
|
+
if (sourceType === "trello" && !cycleData) {
|
|
214
|
+
console.error("No cycle data found. Run ttt sync before creating a card.");
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
207
217
|
const assigneeId = resolveAssigneeId(config, assigneeKey);
|
|
208
|
-
const statusId = await resolveStatusId(config, adapter, teamId, statusName);
|
|
218
|
+
const statusId = await resolveStatusId(config, adapter, teamId, sourceType === "trello" && !statusName ? "todo" : statusName);
|
|
209
219
|
const labelIds = resolveLabelIds(config, labelArg);
|
|
210
220
|
const parentSourceId = await resolveParentSourceId(adapter, parentId);
|
|
211
221
|
const currentCycle = await adapter.getCurrentCycle(teamId);
|
|
@@ -229,11 +239,19 @@ Examples:
|
|
|
229
239
|
console.log(`\n✅ Created ${issue.id}: ${issue.title}`);
|
|
230
240
|
if (issue.url)
|
|
231
241
|
console.log(` ${issue.url}`);
|
|
232
|
-
|
|
242
|
+
if (sourceType !== "trello")
|
|
243
|
+
cycleData = await loadCycleData();
|
|
233
244
|
if (cycleData) {
|
|
234
245
|
const task = sourceIssueToTask(issue, sourceType);
|
|
235
246
|
await upsertTaskInCycleData(task, cycleData);
|
|
236
247
|
console.log(` Added to local cycle data.`);
|
|
237
248
|
}
|
|
238
249
|
}
|
|
239
|
-
|
|
250
|
+
const entryPath = process.argv[1];
|
|
251
|
+
if (entryPath &&
|
|
252
|
+
import.meta.url === pathToFileURL(path.resolve(entryPath)).href) {
|
|
253
|
+
create().catch((error) => {
|
|
254
|
+
console.error("Failed to create issue:", error instanceof Error ? error.message : error);
|
|
255
|
+
process.exitCode = 1;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
@@ -294,18 +294,25 @@ export class LinearAdapter {
|
|
|
294
294
|
}
|
|
295
295
|
async cancelIssue(sourceId) {
|
|
296
296
|
try {
|
|
297
|
-
//
|
|
297
|
+
// Resolve by statusType, not display name -- teams name this state
|
|
298
|
+
// "Canceled", "Cancelled", "Done - Cancelled", etc.
|
|
298
299
|
const issue = await this.client.issue(sourceId);
|
|
299
300
|
const team = await issue.team;
|
|
300
301
|
if (!team) {
|
|
301
302
|
return { success: false, error: "Could not determine issue team" };
|
|
302
303
|
}
|
|
303
304
|
const states = await this.client.workflowStates({
|
|
304
|
-
filter: {
|
|
305
|
+
filter: {
|
|
306
|
+
team: { id: { eq: team.id } },
|
|
307
|
+
type: { in: ["canceled", "cancelled"] },
|
|
308
|
+
},
|
|
305
309
|
});
|
|
306
310
|
const cancelledState = states.nodes[0];
|
|
307
311
|
if (!cancelledState) {
|
|
308
|
-
return {
|
|
312
|
+
return {
|
|
313
|
+
success: false,
|
|
314
|
+
error: `No cancelled-type workflow state found for team ${team.id}`,
|
|
315
|
+
};
|
|
309
316
|
}
|
|
310
317
|
const payload = await this.client.updateIssue(sourceId, {
|
|
311
318
|
stateId: cancelledState.id,
|
|
@@ -27,7 +27,7 @@ export declare class TrelloAdapter implements TaskSourceAdapter {
|
|
|
27
27
|
error?: string;
|
|
28
28
|
}>;
|
|
29
29
|
getInitData(teamId?: string): Promise<InitData>;
|
|
30
|
-
createIssue(
|
|
30
|
+
createIssue(options: CreateIssueOptions): Promise<{
|
|
31
31
|
success: boolean;
|
|
32
32
|
issue?: SourceIssue;
|
|
33
33
|
error?: string;
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { TrelloClient } from "../trello.js";
|
|
6
6
|
import { detectPriorityFromLabels, } from "./types.js";
|
|
7
|
+
const PRIORITY_NAMES = {
|
|
8
|
+
1: "urgent",
|
|
9
|
+
2: "high",
|
|
10
|
+
3: "medium",
|
|
11
|
+
4: "low",
|
|
12
|
+
};
|
|
7
13
|
export class TrelloAdapter {
|
|
8
14
|
type = "trello";
|
|
9
15
|
client;
|
|
@@ -278,11 +284,85 @@ export class TrelloAdapter {
|
|
|
278
284
|
currentCycle: undefined, // Trello has no cycle
|
|
279
285
|
};
|
|
280
286
|
}
|
|
281
|
-
async createIssue(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
287
|
+
async createIssue(options) {
|
|
288
|
+
try {
|
|
289
|
+
const statuses = await this.getStatuses(options.teamId);
|
|
290
|
+
const targetStatus = options.statusId
|
|
291
|
+
? statuses.find((status) => status.id === options.statusId)
|
|
292
|
+
: statuses[0];
|
|
293
|
+
if (!targetStatus) {
|
|
294
|
+
return {
|
|
295
|
+
success: false,
|
|
296
|
+
error: options.statusId
|
|
297
|
+
? `Trello list ${options.statusId} is not open on board ${options.teamId}`
|
|
298
|
+
: `Trello board ${options.teamId} has no open lists`,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
const labelIds = new Set(options.labelIds ?? []);
|
|
302
|
+
let knownLabels = [];
|
|
303
|
+
if (labelIds.size > 0 || (options.priority ?? 0) > 0) {
|
|
304
|
+
knownLabels = await this.getLabels(options.teamId);
|
|
305
|
+
}
|
|
306
|
+
if (options.priority && options.priority > 0) {
|
|
307
|
+
const priorityLabel = knownLabels.find((label) => detectPriorityFromLabels([label.name]) === options.priority);
|
|
308
|
+
if (!priorityLabel) {
|
|
309
|
+
return {
|
|
310
|
+
success: false,
|
|
311
|
+
error: `Trello board ${options.teamId} has no label matching priority "${PRIORITY_NAMES[options.priority]}"`,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
labelIds.add(priorityLabel.id);
|
|
315
|
+
}
|
|
316
|
+
const card = await this.client.createCard({
|
|
317
|
+
name: options.title,
|
|
318
|
+
idList: targetStatus.id,
|
|
319
|
+
desc: options.description,
|
|
320
|
+
idMembers: options.assigneeId ? [options.assigneeId] : undefined,
|
|
321
|
+
idLabels: labelIds.size > 0 ? [...labelIds] : undefined,
|
|
322
|
+
});
|
|
323
|
+
if (!card.id || !card.shortLink || !card.name || !card.idList) {
|
|
324
|
+
return {
|
|
325
|
+
success: false,
|
|
326
|
+
error: "Trello created a card but returned an incomplete response",
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
const labelNames = Array.isArray(card.labels)
|
|
330
|
+
? card.labels.map((label) => label.name).filter(Boolean)
|
|
331
|
+
: knownLabels
|
|
332
|
+
.filter((label) => labelIds.has(label.id))
|
|
333
|
+
.map((label) => label.name);
|
|
334
|
+
const status = statuses.find((candidate) => candidate.id === card.idList)?.name ??
|
|
335
|
+
targetStatus.name;
|
|
336
|
+
const assigneeId = Array.isArray(card.idMembers)
|
|
337
|
+
? card.idMembers[0]
|
|
338
|
+
: options.assigneeId;
|
|
339
|
+
return {
|
|
340
|
+
success: true,
|
|
341
|
+
issue: {
|
|
342
|
+
id: card.shortLink,
|
|
343
|
+
sourceId: card.id,
|
|
344
|
+
title: card.name,
|
|
345
|
+
description: card.desc || undefined,
|
|
346
|
+
status,
|
|
347
|
+
statusId: card.idList,
|
|
348
|
+
assigneeId,
|
|
349
|
+
assigneeEmail: undefined,
|
|
350
|
+
priority: detectPriorityFromLabels(labelNames),
|
|
351
|
+
labels: labelNames,
|
|
352
|
+
url: card.url,
|
|
353
|
+
parentIssueId: undefined,
|
|
354
|
+
branchName: undefined,
|
|
355
|
+
attachments: undefined,
|
|
356
|
+
comments: undefined,
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
return {
|
|
362
|
+
success: false,
|
|
363
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
364
|
+
};
|
|
365
|
+
}
|
|
286
366
|
}
|
|
287
367
|
async updateIssue(_sourceId, _fields) {
|
|
288
368
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "team-toon-tack",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.3",
|
|
4
4
|
"description": "Linear & Trello task sync & management CLI with TOON format",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"files": [
|
|
15
15
|
"dist",
|
|
16
16
|
".claude-plugin",
|
|
17
|
+
".codex-plugin",
|
|
17
18
|
"commands",
|
|
18
19
|
"skills"
|
|
19
20
|
],
|
|
@@ -3,12 +3,13 @@ name: managing-linear-tasks
|
|
|
3
3
|
description: Use when the user mentions Linear or Trello issues, references issue IDs like MP-123, or asks to sync, show, start, complete, create, assign, edit, cancel, comment on, or check status of tasks.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
## 執行方式
|
|
7
|
+
|
|
8
|
+
在 Codex 與 Claude Code 中,使用可用的 shell 工具執行 `ttt` CLI。
|
|
9
|
+
任務資料以 CLI 的查詢結果為準;透過 CLI 更新 `.ttt/` 內的設定與狀態。
|
|
10
|
+
使用者要求完成任務時,執行 `ttt done -m "摘要"`。
|
|
11
|
+
Claude Code 也提供 `/ttt:*` slash commands,對應下方相同的 CLI 操作。
|
|
12
|
+
|
|
12
13
|
|
|
13
14
|
# Task Manager (Linear/Trello)
|
|
14
15
|
|
|
@@ -16,23 +17,23 @@ Manage developer task workflows using the `ttt` CLI.
|
|
|
16
17
|
|
|
17
18
|
## Command Router
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
依使用者意圖選擇下列 `ttt` CLI 指令:
|
|
20
21
|
|
|
21
22
|
| User Intent | Command | Example |
|
|
22
23
|
|-------------|---------|---------|
|
|
23
|
-
| Sync/fetch issues |
|
|
24
|
-
| Show/search issues |
|
|
25
|
-
| Start working on a task |
|
|
26
|
-
| Create a new issue |
|
|
27
|
-
| Reassign an issue |
|
|
28
|
-
| Edit issue fields |
|
|
29
|
-
| Cancel an issue |
|
|
30
|
-
| Record an estimate |
|
|
31
|
-
| Check/change status |
|
|
32
|
-
| Add a comment |
|
|
33
|
-
| Complete a task |
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
| Sync/fetch issues | `ttt sync` | "sync my issues", "pull from Linear" |
|
|
25
|
+
| Show/search issues | `ttt show` | "show MP-624", "list my tasks", "what issues do I have" |
|
|
26
|
+
| Start working on a task | `ttt work-on` | "work on next", "start MP-624" |
|
|
27
|
+
| Create a new issue | `ttt create` | "create issue", "open a ticket", "new task" |
|
|
28
|
+
| Reassign an issue | `ttt assign` | "assign MP-624 to john", "reassign to jane" |
|
|
29
|
+
| Edit issue fields | `ttt edit` | "rename MP-624", "change priority", "update labels" |
|
|
30
|
+
| Cancel an issue | `ttt cancel` | "cancel MP-624", "abandon this task" |
|
|
31
|
+
| Record an estimate | `ttt estimate` | "estimate MP-624 as 6h", "save 2.5h estimate" |
|
|
32
|
+
| Check/change status | `ttt status` | "what's my current task", "set MP-624 to blocked" |
|
|
33
|
+
| Add a comment | `ttt comment` | "comment on MP-624", "add note to task" |
|
|
34
|
+
| Complete a task | `ttt done` | "done", "mark complete", "finish task" |
|
|
35
|
+
|
|
36
|
+
**意圖符合時,透過 shell 工具執行對應的 `ttt` CLI 指令。**
|
|
36
37
|
|
|
37
38
|
## Quick Reference
|
|
38
39
|
|
|
@@ -96,7 +97,7 @@ ttt sync → ttt work-on next → ttt estimate <id> <hours> → [implement] →
|
|
|
96
97
|
| "I'll edit `cycle.toon` directly, faster" | `cycle.toon` is auto-generated. Manual edits get overwritten on next `ttt sync`. Always go through the CLI. |
|
|
97
98
|
| "I remember this issue ID, no need to sync" | Remote status, assignee, priority may have changed. Run `ttt sync` or `ttt show <id> --remote` first. |
|
|
98
99
|
| "I'll create the issue in the Linear/Trello UI instead" | Bypassing `ttt create` leaves the new issue outside local cycle data. Use the CLI so it gets tracked. |
|
|
99
|
-
| "Task is obvious, skip
|
|
100
|
+
| "Task is obvious, skip `ttt done`" | `ttt done` syncs local + remote status, posts a completion comment, reads git commit info. Skipping leaves state inconsistent. |
|
|
100
101
|
| "I know what the task needs without reading it" | Fabricated assumptions produce wrong work. Run `ttt show <id>` before starting. |
|
|
101
102
|
| "Fetch issue details via Linear MCP / web UI" | The CLI is authoritative and token-efficient. Use `ttt show` / `ttt sync`, not alternate data paths. |
|
|
102
103
|
|
|
@@ -109,17 +110,17 @@ digraph ttt_router {
|
|
|
109
110
|
user [label="User mentions\nLinear/Trello", shape=doublecircle];
|
|
110
111
|
classify [label="Classify intent", shape=diamond];
|
|
111
112
|
|
|
112
|
-
sync [label="
|
|
113
|
-
show [label="
|
|
114
|
-
work_on [label="
|
|
115
|
-
create [label="
|
|
116
|
-
assign [label="
|
|
117
|
-
edit [label="
|
|
118
|
-
cancel [label="
|
|
119
|
-
estimate [label="
|
|
120
|
-
status [label="
|
|
121
|
-
comment [label="
|
|
122
|
-
done [label="
|
|
113
|
+
sync [label="ttt sync", shape=box];
|
|
114
|
+
show [label="ttt show", shape=box];
|
|
115
|
+
work_on [label="ttt work-on", shape=box];
|
|
116
|
+
create [label="ttt create", shape=box];
|
|
117
|
+
assign [label="ttt assign", shape=box];
|
|
118
|
+
edit [label="ttt edit", shape=box];
|
|
119
|
+
cancel [label="ttt cancel", shape=box];
|
|
120
|
+
estimate [label="ttt estimate", shape=box];
|
|
121
|
+
status [label="ttt status", shape=box];
|
|
122
|
+
comment [label="ttt comment", shape=box];
|
|
123
|
+
done [label="ttt done", shape=box];
|
|
123
124
|
|
|
124
125
|
user -> classify;
|
|
125
126
|
classify -> sync [label="fetch / pull"];
|