team-toon-tack 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/config/filters.d.ts +2 -0
- package/dist/scripts/config/filters.js +71 -0
- package/dist/scripts/config/show.d.ts +2 -0
- package/dist/scripts/config/show.js +33 -0
- package/dist/scripts/config/status.d.ts +2 -0
- package/dist/scripts/config/status.js +73 -0
- package/dist/scripts/config/teams.d.ts +2 -0
- package/dist/scripts/config/teams.js +59 -0
- package/dist/scripts/config.js +20 -244
- package/dist/scripts/done-job.js +41 -119
- package/dist/scripts/init.js +138 -261
- package/dist/scripts/lib/config-builder.d.ts +41 -0
- package/dist/scripts/lib/config-builder.js +116 -0
- package/dist/scripts/lib/display.d.ts +12 -0
- package/dist/scripts/lib/display.js +91 -0
- package/dist/scripts/lib/git.d.ts +10 -0
- package/dist/scripts/lib/git.js +78 -0
- package/dist/scripts/lib/linear.d.ts +11 -0
- package/dist/scripts/lib/linear.js +61 -0
- package/dist/scripts/status.js +16 -105
- package/dist/scripts/work-on.js +14 -64
- package/package.json +1 -1
package/dist/scripts/done-job.js
CHANGED
|
@@ -1,51 +1,7 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
2
1
|
import prompts from "prompts";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const shortHash = execSync("git rev-parse --short HEAD", {
|
|
7
|
-
encoding: "utf-8",
|
|
8
|
-
}).trim();
|
|
9
|
-
const fullHash = execSync("git rev-parse HEAD", {
|
|
10
|
-
encoding: "utf-8",
|
|
11
|
-
}).trim();
|
|
12
|
-
const message = execSync("git log -1 --format=%s", {
|
|
13
|
-
encoding: "utf-8",
|
|
14
|
-
}).trim();
|
|
15
|
-
const diffStat = execSync("git diff HEAD~1 --stat --stat-width=60", {
|
|
16
|
-
encoding: "utf-8",
|
|
17
|
-
}).trim();
|
|
18
|
-
// Get remote URL and construct commit link
|
|
19
|
-
let commitUrl = null;
|
|
20
|
-
try {
|
|
21
|
-
const remoteUrl = execSync("git remote get-url origin", {
|
|
22
|
-
encoding: "utf-8",
|
|
23
|
-
}).trim();
|
|
24
|
-
// Handle SSH or HTTPS URLs
|
|
25
|
-
// git@gitlab.com:org/repo.git -> https://gitlab.com/org/repo/-/commit/hash
|
|
26
|
-
// https://gitlab.com/org/repo.git -> https://gitlab.com/org/repo/-/commit/hash
|
|
27
|
-
if (remoteUrl.includes("gitlab")) {
|
|
28
|
-
const match = remoteUrl.match(/(?:git@|https:\/\/)([^:/]+)[:\\/](.+?)(?:\.git)?$/);
|
|
29
|
-
if (match) {
|
|
30
|
-
commitUrl = `https://${match[1]}/${match[2]}/-/commit/${fullHash}`;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
else if (remoteUrl.includes("github")) {
|
|
34
|
-
const match = remoteUrl.match(/(?:git@|https:\/\/)([^:/]+)[:\\/](.+?)(?:\.git)?$/);
|
|
35
|
-
if (match) {
|
|
36
|
-
commitUrl = `https://${match[1]}/${match[2]}/commit/${fullHash}`;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
// Ignore if can't get remote URL
|
|
42
|
-
}
|
|
43
|
-
return { shortHash, fullHash, message, diffStat, commitUrl };
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
2
|
+
import { buildCompletionComment, getLatestCommit } from "./lib/git.js";
|
|
3
|
+
import { addComment, getStatusTransitions, getWorkflowStates, updateIssueStatus, } from "./lib/linear.js";
|
|
4
|
+
import { getLinearClient, loadConfig, loadCycleData, loadLocalConfig, saveCycleData, } from "./utils.js";
|
|
49
5
|
function parseArgs(args) {
|
|
50
6
|
let issueId;
|
|
51
7
|
let message;
|
|
@@ -62,7 +18,6 @@ function parseArgs(args) {
|
|
|
62
18
|
}
|
|
63
19
|
async function doneJob() {
|
|
64
20
|
const args = process.argv.slice(2);
|
|
65
|
-
// Handle help flag
|
|
66
21
|
if (args.includes("--help") || args.includes("-h")) {
|
|
67
22
|
console.log(`Usage: ttt done [issue-id] [-m message]
|
|
68
23
|
|
|
@@ -94,7 +49,7 @@ Examples:
|
|
|
94
49
|
console.log("沒有進行中的任務");
|
|
95
50
|
process.exit(0);
|
|
96
51
|
}
|
|
97
|
-
//
|
|
52
|
+
// Issue Resolution
|
|
98
53
|
if (!issueId) {
|
|
99
54
|
if (inProgressTasks.length === 1) {
|
|
100
55
|
issueId = inProgressTasks[0].id;
|
|
@@ -126,7 +81,7 @@ Examples:
|
|
|
126
81
|
process.exit(1);
|
|
127
82
|
}
|
|
128
83
|
}
|
|
129
|
-
//
|
|
84
|
+
// Find task
|
|
130
85
|
const task = data.tasks.find((t) => t.id === issueId || t.id === `MP-${issueId}`);
|
|
131
86
|
if (!task) {
|
|
132
87
|
console.error(`Issue ${issueId} not found in current cycle.`);
|
|
@@ -136,9 +91,9 @@ Examples:
|
|
|
136
91
|
console.log(`⚠️ 任務 ${task.id} 不在進行中狀態 (目前: ${task.localStatus})`);
|
|
137
92
|
process.exit(1);
|
|
138
93
|
}
|
|
139
|
-
// Get latest commit
|
|
140
|
-
const commit =
|
|
141
|
-
//
|
|
94
|
+
// Get latest commit
|
|
95
|
+
const commit = getLatestCommit();
|
|
96
|
+
// Get AI summary message
|
|
142
97
|
let aiMessage = argMessage || "";
|
|
143
98
|
if (!aiMessage && process.stdin.isTTY) {
|
|
144
99
|
const aiMsgResponse = await prompts({
|
|
@@ -148,85 +103,52 @@ Examples:
|
|
|
148
103
|
});
|
|
149
104
|
aiMessage = aiMsgResponse.aiMessage || "";
|
|
150
105
|
}
|
|
151
|
-
//
|
|
106
|
+
// Update Linear
|
|
152
107
|
if (task.linearId && process.env.LINEAR_API_KEY) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
-
await client.updateIssue(task.linearId, { stateId: doneState.id });
|
|
165
|
-
console.log(`Linear: ${task.id} → ${doneStatusName}`);
|
|
166
|
-
}
|
|
167
|
-
// Add comment with commit info and AI summary
|
|
168
|
-
if (commit) {
|
|
169
|
-
const commitLink = commit.commitUrl
|
|
170
|
-
? `[${commit.shortHash}](${commit.commitUrl})`
|
|
171
|
-
: `\`${commit.shortHash}\``;
|
|
172
|
-
const commentParts = [
|
|
173
|
-
"## ✅ 開發完成",
|
|
174
|
-
"",
|
|
175
|
-
"### 🤖 AI 修復說明",
|
|
176
|
-
aiMessage || "_No description provided_",
|
|
177
|
-
"",
|
|
178
|
-
"### 📝 Commit Info",
|
|
179
|
-
`**Commit:** ${commitLink}`,
|
|
180
|
-
`**Message:** ${commit.message}`,
|
|
181
|
-
"",
|
|
182
|
-
"### 📊 Changes",
|
|
183
|
-
"```",
|
|
184
|
-
commit.diffStat,
|
|
185
|
-
"```",
|
|
186
|
-
];
|
|
187
|
-
await client.createComment({
|
|
188
|
-
issueId: task.linearId,
|
|
189
|
-
body: commentParts.join("\n"),
|
|
190
|
-
});
|
|
108
|
+
const transitions = getStatusTransitions(config);
|
|
109
|
+
// Update issue to Done
|
|
110
|
+
const success = await updateIssueStatus(task.linearId, transitions.done, config, localConfig.team);
|
|
111
|
+
if (success) {
|
|
112
|
+
console.log(`Linear: ${task.id} → ${transitions.done}`);
|
|
113
|
+
}
|
|
114
|
+
// Add comment with commit info
|
|
115
|
+
if (commit) {
|
|
116
|
+
const commentBody = buildCompletionComment(commit, aiMessage);
|
|
117
|
+
const commentSuccess = await addComment(task.linearId, commentBody);
|
|
118
|
+
if (commentSuccess) {
|
|
191
119
|
console.log(`Linear: 已新增 commit 留言`);
|
|
192
120
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
121
|
+
}
|
|
122
|
+
// Update parent to Testing if exists
|
|
123
|
+
if (task.parentIssueId && transitions.testing) {
|
|
124
|
+
try {
|
|
125
|
+
const client = getLinearClient();
|
|
126
|
+
const searchResult = await client.searchIssues(task.parentIssueId);
|
|
127
|
+
const parentIssue = searchResult.nodes.find((issue) => issue.identifier === task.parentIssueId);
|
|
128
|
+
if (parentIssue) {
|
|
129
|
+
const parentTeam = await parentIssue.team;
|
|
130
|
+
if (parentTeam) {
|
|
131
|
+
const parentStates = await getWorkflowStates(config, localConfig.team);
|
|
132
|
+
const testingState = parentStates.find((s) => s.name === transitions.testing);
|
|
133
|
+
if (testingState) {
|
|
134
|
+
await client.updateIssue(parentIssue.id, {
|
|
135
|
+
stateId: testingState.id,
|
|
205
136
|
});
|
|
206
|
-
|
|
207
|
-
if (testingState) {
|
|
208
|
-
await client.updateIssue(parentIssue.id, {
|
|
209
|
-
stateId: testingState.id,
|
|
210
|
-
});
|
|
211
|
-
console.log(`Linear: Parent ${task.parentIssueId} → ${testingStatusName}`);
|
|
212
|
-
}
|
|
137
|
+
console.log(`Linear: Parent ${task.parentIssueId} → ${transitions.testing}`);
|
|
213
138
|
}
|
|
214
139
|
}
|
|
215
140
|
}
|
|
216
|
-
catch (parentError) {
|
|
217
|
-
console.error("Failed to update parent issue:", parentError);
|
|
218
|
-
}
|
|
219
141
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
142
|
+
catch (parentError) {
|
|
143
|
+
console.error("Failed to update parent issue:", parentError);
|
|
144
|
+
}
|
|
223
145
|
}
|
|
224
146
|
}
|
|
225
|
-
//
|
|
147
|
+
// Update local status
|
|
226
148
|
task.localStatus = "completed";
|
|
227
149
|
await saveCycleData(data);
|
|
228
150
|
console.log(`Local: ${task.id} → completed`);
|
|
229
|
-
//
|
|
151
|
+
// Summary
|
|
230
152
|
console.log(`\n${"═".repeat(50)}`);
|
|
231
153
|
console.log(`✅ ${task.id}: ${task.title}`);
|
|
232
154
|
console.log(`${"═".repeat(50)}`);
|