team-toon-tack 1.0.12 → 1.6.0
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 +59 -8
- package/README.zh-TW.md +111 -22
- package/{bin → dist/bin}/cli.js +41 -19
- package/dist/scripts/config.js +271 -0
- package/{scripts → dist/scripts}/done-job.js +79 -62
- package/dist/scripts/init.d.ts +2 -0
- package/dist/scripts/init.js +492 -0
- package/dist/scripts/status.d.ts +2 -0
- package/dist/scripts/status.js +251 -0
- package/dist/scripts/sync.js +247 -0
- package/{scripts → dist/scripts}/utils.d.ts +11 -3
- package/{scripts → dist/scripts}/utils.js +33 -27
- package/{scripts → dist/scripts}/work-on.js +55 -41
- package/package.json +52 -50
- package/templates/claude-code-commands/done-job.md +45 -0
- package/templates/claude-code-commands/sync-linear.md +32 -0
- package/templates/claude-code-commands/work-on.md +41 -0
- package/bin/cli.ts +0 -125
- package/scripts/done-job.ts +0 -263
- package/scripts/init.js +0 -331
- package/scripts/init.ts +0 -375
- package/scripts/sync.js +0 -178
- package/scripts/sync.ts +0 -211
- package/scripts/utils.ts +0 -236
- package/scripts/work-on.ts +0 -161
- /package/{bin → dist/bin}/cli.d.ts +0 -0
- /package/{scripts/init.d.ts → dist/scripts/config.d.ts} +0 -0
- /package/{scripts → dist/scripts}/done-job.d.ts +0 -0
- /package/{scripts → dist/scripts}/sync.d.ts +0 -0
- /package/{scripts → dist/scripts}/work-on.d.ts +0 -0
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import prompts from
|
|
2
|
-
import { getLinearClient,
|
|
1
|
+
import prompts from "prompts";
|
|
2
|
+
import { getLinearClient, getPrioritySortIndex, getTeamId, loadConfig, loadCycleData, loadLocalConfig, saveCycleData, } from "./utils.js";
|
|
3
3
|
const PRIORITY_LABELS = {
|
|
4
|
-
0:
|
|
5
|
-
1:
|
|
6
|
-
2:
|
|
7
|
-
3:
|
|
8
|
-
4:
|
|
4
|
+
0: "⚪ None",
|
|
5
|
+
1: "🔴 Urgent",
|
|
6
|
+
2: "🟠 High",
|
|
7
|
+
3: "🟡 Medium",
|
|
8
|
+
4: "🟢 Low",
|
|
9
9
|
};
|
|
10
10
|
async function workOn() {
|
|
11
11
|
const args = process.argv.slice(2);
|
|
12
12
|
// Handle help flag
|
|
13
|
-
if (args.includes(
|
|
13
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
14
14
|
console.log(`Usage: ttt work-on [issue-id]
|
|
15
15
|
|
|
16
16
|
Arguments:
|
|
@@ -27,18 +27,16 @@ Examples:
|
|
|
27
27
|
const config = await loadConfig();
|
|
28
28
|
const data = await loadCycleData();
|
|
29
29
|
if (!data) {
|
|
30
|
-
console.error(
|
|
30
|
+
console.error("No cycle data found. Run /sync-linear first.");
|
|
31
31
|
process.exit(1);
|
|
32
32
|
}
|
|
33
|
-
const userEmail = await getUserEmail();
|
|
34
33
|
const localConfig = await loadLocalConfig();
|
|
35
34
|
// Build excluded emails list from user keys
|
|
36
35
|
const excludedEmails = new Set((localConfig.exclude_assignees ?? [])
|
|
37
|
-
.map(key => config.users[key]?.email)
|
|
36
|
+
.map((key) => config.users[key]?.email)
|
|
38
37
|
.filter(Boolean));
|
|
39
38
|
const pendingTasks = data.tasks
|
|
40
|
-
.filter(t => t.localStatus ===
|
|
41
|
-
!excludedEmails.has(t.assignee ?? ''))
|
|
39
|
+
.filter((t) => t.localStatus === "pending" && !excludedEmails.has(t.assignee ?? ""))
|
|
42
40
|
.sort((a, b) => {
|
|
43
41
|
const pa = getPrioritySortIndex(a.priority, config.priority_order);
|
|
44
42
|
const pb = getPrioritySortIndex(b.priority, config.priority_order);
|
|
@@ -48,52 +46,52 @@ Examples:
|
|
|
48
46
|
if (!issueId) {
|
|
49
47
|
// Interactive selection
|
|
50
48
|
if (pendingTasks.length === 0) {
|
|
51
|
-
console.log(
|
|
49
|
+
console.log("✅ 沒有待處理的任務,所有工作已完成或進行中");
|
|
52
50
|
process.exit(0);
|
|
53
51
|
}
|
|
54
|
-
const choices = pendingTasks.map(task => ({
|
|
55
|
-
title: `${PRIORITY_LABELS[task.priority] ||
|
|
52
|
+
const choices = pendingTasks.map((task) => ({
|
|
53
|
+
title: `${PRIORITY_LABELS[task.priority] || "⚪"} ${task.id}: ${task.title}`,
|
|
56
54
|
value: task.id,
|
|
57
|
-
description: task.labels.join(
|
|
55
|
+
description: task.labels.join(", "),
|
|
58
56
|
}));
|
|
59
57
|
const response = await prompts({
|
|
60
|
-
type:
|
|
61
|
-
name:
|
|
62
|
-
message:
|
|
63
|
-
choices: choices
|
|
58
|
+
type: "select",
|
|
59
|
+
name: "issueId",
|
|
60
|
+
message: "選擇要處理的任務:",
|
|
61
|
+
choices: choices,
|
|
64
62
|
});
|
|
65
63
|
if (!response.issueId) {
|
|
66
|
-
console.log(
|
|
64
|
+
console.log("已取消");
|
|
67
65
|
process.exit(0);
|
|
68
66
|
}
|
|
69
67
|
issueId = response.issueId;
|
|
70
68
|
}
|
|
71
|
-
else if ([
|
|
69
|
+
else if (["next", "下一個", "下一個工作"].includes(issueId)) {
|
|
72
70
|
// Auto-select highest priority
|
|
73
71
|
if (pendingTasks.length === 0) {
|
|
74
|
-
console.log(
|
|
72
|
+
console.log("✅ 沒有待處理的任務,所有工作已完成或進行中");
|
|
75
73
|
process.exit(0);
|
|
76
74
|
}
|
|
77
75
|
issueId = pendingTasks[0].id;
|
|
78
76
|
console.log(`Auto-selected: ${issueId}`);
|
|
79
77
|
}
|
|
80
78
|
// Phase 1: Find task
|
|
81
|
-
const task = data.tasks.find(t => t.id === issueId || t.id === `MP-${issueId}`);
|
|
79
|
+
const task = data.tasks.find((t) => t.id === issueId || t.id === `MP-${issueId}`);
|
|
82
80
|
if (!task) {
|
|
83
81
|
console.error(`Issue ${issueId} not found in current cycle.`);
|
|
84
82
|
process.exit(1);
|
|
85
83
|
}
|
|
86
84
|
// Phase 2: Availability Check
|
|
87
|
-
if (task.localStatus ===
|
|
85
|
+
if (task.localStatus === "in-progress") {
|
|
88
86
|
console.log(`⚠️ 此任務 ${task.id} 已在進行中`);
|
|
89
87
|
}
|
|
90
|
-
else if (task.localStatus ===
|
|
88
|
+
else if (task.localStatus === "completed") {
|
|
91
89
|
console.log(`⚠️ 此任務 ${task.id} 已完成`);
|
|
92
90
|
process.exit(0);
|
|
93
91
|
}
|
|
94
92
|
// Phase 3: Mark as In Progress
|
|
95
|
-
if (task.localStatus ===
|
|
96
|
-
task.localStatus =
|
|
93
|
+
if (task.localStatus === "pending") {
|
|
94
|
+
task.localStatus = "in-progress";
|
|
97
95
|
await saveCycleData(data);
|
|
98
96
|
console.log(`Local: ${task.id} → in-progress`);
|
|
99
97
|
// Update Linear using stored linearId
|
|
@@ -101,26 +99,30 @@ Examples:
|
|
|
101
99
|
try {
|
|
102
100
|
const client = getLinearClient();
|
|
103
101
|
const workflowStates = await client.workflowStates({
|
|
104
|
-
filter: { team: { id: { eq: getTeamId(config, localConfig.team) } } }
|
|
102
|
+
filter: { team: { id: { eq: getTeamId(config, localConfig.team) } } },
|
|
105
103
|
});
|
|
106
|
-
|
|
104
|
+
// Get status name from config or use default
|
|
105
|
+
const inProgressStatusName = config.status_transitions?.in_progress || "In Progress";
|
|
106
|
+
const inProgressState = workflowStates.nodes.find((s) => s.name === inProgressStatusName);
|
|
107
107
|
if (inProgressState) {
|
|
108
|
-
await client.updateIssue(task.linearId, {
|
|
109
|
-
|
|
108
|
+
await client.updateIssue(task.linearId, {
|
|
109
|
+
stateId: inProgressState.id,
|
|
110
|
+
});
|
|
111
|
+
console.log(`Linear: ${task.id} → ${inProgressStatusName}`);
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
catch (e) {
|
|
113
|
-
console.error(
|
|
115
|
+
console.error("Failed to update Linear:", e);
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
119
|
// Phase 4: Display task info
|
|
118
|
-
console.log(`\n${
|
|
120
|
+
console.log(`\n${"═".repeat(50)}`);
|
|
119
121
|
console.log(`👷 ${task.id}: ${task.title}`);
|
|
120
|
-
console.log(`${
|
|
121
|
-
console.log(`Priority: ${PRIORITY_LABELS[task.priority] ||
|
|
122
|
-
console.log(`Labels: ${task.labels.join(
|
|
123
|
-
console.log(`Branch: ${task.branch ||
|
|
122
|
+
console.log(`${"═".repeat(50)}`);
|
|
123
|
+
console.log(`Priority: ${PRIORITY_LABELS[task.priority] || "None"}`);
|
|
124
|
+
console.log(`Labels: ${task.labels.join(", ")}`);
|
|
125
|
+
console.log(`Branch: ${task.branch || "N/A"}`);
|
|
124
126
|
if (task.url)
|
|
125
127
|
console.log(`URL: ${task.url}`);
|
|
126
128
|
if (task.description) {
|
|
@@ -132,7 +134,19 @@ Examples:
|
|
|
132
134
|
console.log(` - ${att.title}: ${att.url}`);
|
|
133
135
|
}
|
|
134
136
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
if (task.comments && task.comments.length > 0) {
|
|
138
|
+
console.log(`\n💬 Comments (${task.comments.length}):`);
|
|
139
|
+
for (const comment of task.comments) {
|
|
140
|
+
const date = new Date(comment.createdAt).toLocaleDateString();
|
|
141
|
+
console.log(`\n [${comment.user || "Unknown"} - ${date}]`);
|
|
142
|
+
// Indent comment body
|
|
143
|
+
const lines = comment.body.split("\n");
|
|
144
|
+
for (const line of lines) {
|
|
145
|
+
console.log(` ${line}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
console.log(`\n${"─".repeat(50)}`);
|
|
150
|
+
console.log("Next: bun type-check && bun lint");
|
|
137
151
|
}
|
|
138
152
|
workOn().catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,52 +1,54 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
2
|
+
"name": "team-toon-tack",
|
|
3
|
+
"version": "1.6.0",
|
|
4
|
+
"description": "Linear task sync & management CLI with TOON format",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ttt": "./dist/bin/cli.js",
|
|
8
|
+
"team-toon-tack": "./dist/bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./dist/scripts/utils.js",
|
|
12
|
+
"./utils": "./dist/scripts/utils.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"templates"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"lint": "biome lint .",
|
|
21
|
+
"format": "biome format --write .",
|
|
22
|
+
"type": "tsc --noEmit",
|
|
23
|
+
"prepublishOnly": "npm run build",
|
|
24
|
+
"release": "npm config set //registry.npmjs.org/:_authToken=$NPM_PUBLISH_KEY && npm publish"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@linear/sdk": "^69.0.0",
|
|
28
|
+
"@toon-format/toon": "^2.1.0",
|
|
29
|
+
"prompts": "^2.4.2"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@biomejs/biome": "^2.3.11",
|
|
33
|
+
"@types/node": "^25.0.3",
|
|
34
|
+
"@types/prompts": "^2.4.9",
|
|
35
|
+
"typescript": "^5.9.3"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"linear",
|
|
39
|
+
"task-management",
|
|
40
|
+
"cli",
|
|
41
|
+
"toon",
|
|
42
|
+
"sync",
|
|
43
|
+
"project-management"
|
|
44
|
+
],
|
|
45
|
+
"author": "wayne930242",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/wayne930242/team-toon-tack.git"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18.0.0"
|
|
53
|
+
}
|
|
52
54
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: done-job
|
|
3
|
+
description: Mark a Linear issue as done with AI summary comment
|
|
4
|
+
arguments:
|
|
5
|
+
- name: issue-id
|
|
6
|
+
description: Linear issue ID (e.g., MP-624). Optional if only one task is in-progress
|
|
7
|
+
required: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Complete Task
|
|
11
|
+
|
|
12
|
+
Mark a task as done and update Linear with commit details.
|
|
13
|
+
|
|
14
|
+
## Process
|
|
15
|
+
|
|
16
|
+
### 1. Determine Issue ID
|
|
17
|
+
|
|
18
|
+
Check `.toon/cycle.toon` for tasks with `localStatus: in-progress`.
|
|
19
|
+
|
|
20
|
+
### 2. Write Fix Summary
|
|
21
|
+
|
|
22
|
+
Prepare a concise summary (1-3 sentences) covering:
|
|
23
|
+
- Root cause
|
|
24
|
+
- How it was resolved
|
|
25
|
+
- Key code changes
|
|
26
|
+
|
|
27
|
+
### 3. Run Command
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
ttt done -d .ttt $ARGUMENTS -m "修復說明"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## What It Does
|
|
34
|
+
|
|
35
|
+
- Linear issue status → "Done"
|
|
36
|
+
- Adds comment with commit hash, message, and diff summary
|
|
37
|
+
- Parent issue (if exists) → "Testing"
|
|
38
|
+
- Local status → `completed` in `.toon/cycle.toon`
|
|
39
|
+
|
|
40
|
+
## Example Usage
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
/done-job MP-624
|
|
44
|
+
/done-job
|
|
45
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sync-linear
|
|
3
|
+
description: Sync Linear Frontend issues to local TOON file
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sync Linear Issues
|
|
7
|
+
|
|
8
|
+
Fetch current cycle's Frontend issues from Linear to `.toon/cycle.toon`.
|
|
9
|
+
|
|
10
|
+
## Process
|
|
11
|
+
|
|
12
|
+
### 1. Run Sync
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
ttt sync -d .ttt
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 2. Review Output
|
|
19
|
+
|
|
20
|
+
Script displays a summary of tasks in the current cycle.
|
|
21
|
+
|
|
22
|
+
## When to Use
|
|
23
|
+
|
|
24
|
+
- Before starting a new work session
|
|
25
|
+
- When task list is missing or outdated
|
|
26
|
+
- After issues are updated in Linear
|
|
27
|
+
|
|
28
|
+
## Example Usage
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
/sync-linear
|
|
32
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: work-on
|
|
3
|
+
description: Select and start working on a Linear issue
|
|
4
|
+
arguments:
|
|
5
|
+
- name: issue-id
|
|
6
|
+
description: "Issue ID (e.g., MP-624) or 'next' for auto-select"
|
|
7
|
+
required: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Start Working on Issue
|
|
11
|
+
|
|
12
|
+
Select a task and update status to "In Progress" on both local and Linear.
|
|
13
|
+
|
|
14
|
+
## Process
|
|
15
|
+
|
|
16
|
+
### 1. Run Command
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
ttt work-on -d .ttt $ARGUMENTS
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Review Issue Details
|
|
23
|
+
|
|
24
|
+
Script displays title, description, priority, labels, and attachments.
|
|
25
|
+
|
|
26
|
+
### 3. Implement
|
|
27
|
+
|
|
28
|
+
1. Read the issue description carefully
|
|
29
|
+
2. Explore related code
|
|
30
|
+
3. Implement the fix/feature
|
|
31
|
+
4. Run `bun type-check && bun lint`
|
|
32
|
+
5. Commit with conventional format
|
|
33
|
+
6. Use `/done-job` to complete
|
|
34
|
+
|
|
35
|
+
## Example Usage
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
/work-on
|
|
39
|
+
/work-on MP-624
|
|
40
|
+
/work-on next
|
|
41
|
+
```
|
package/bin/cli.ts
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
6
|
-
|
|
7
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
9
|
-
const VERSION = pkg.version;
|
|
10
|
-
|
|
11
|
-
const COMMANDS = ['init', 'sync', 'work-on', 'done', 'help', 'version'] as const;
|
|
12
|
-
type Command = typeof COMMANDS[number];
|
|
13
|
-
|
|
14
|
-
function printHelp() {
|
|
15
|
-
console.log(`
|
|
16
|
-
team-toon-tack (ttt) - Linear task sync & management CLI
|
|
17
|
-
|
|
18
|
-
USAGE:
|
|
19
|
-
ttt <command> [options]
|
|
20
|
-
|
|
21
|
-
COMMANDS:
|
|
22
|
-
init Initialize config files in current directory
|
|
23
|
-
sync Sync issues from Linear to local cycle.ttt
|
|
24
|
-
work-on Start working on a task (interactive or by ID)
|
|
25
|
-
done Mark current task as completed
|
|
26
|
-
help Show this help message
|
|
27
|
-
version Show version
|
|
28
|
-
|
|
29
|
-
GLOBAL OPTIONS:
|
|
30
|
-
-d, --dir <path> Config directory (default: .ttt)
|
|
31
|
-
Can also set via TOON_DIR environment variable
|
|
32
|
-
|
|
33
|
-
EXAMPLES:
|
|
34
|
-
ttt init # Initialize .ttt directory
|
|
35
|
-
ttt init -d ./custom # Initialize in custom directory
|
|
36
|
-
ttt sync # Sync from Linear
|
|
37
|
-
ttt work-on # Interactive task selection
|
|
38
|
-
ttt work-on MP-123 # Work on specific issue
|
|
39
|
-
ttt work-on next # Auto-select highest priority
|
|
40
|
-
ttt done # Complete current task
|
|
41
|
-
ttt done -m "Fixed the bug" # With completion message
|
|
42
|
-
|
|
43
|
-
ENVIRONMENT:
|
|
44
|
-
LINEAR_API_KEY Required. Your Linear API key
|
|
45
|
-
TOON_DIR Optional. Default config directory
|
|
46
|
-
|
|
47
|
-
More info: https://github.com/wayne930242/team-toon-tack
|
|
48
|
-
`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function printVersion() {
|
|
52
|
-
console.log(`team-toon-tack v${VERSION}`);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function parseGlobalArgs(args: string[]): { dir: string; commandArgs: string[] } {
|
|
56
|
-
let dir = process.env.TOON_DIR || resolve(process.cwd(), '.ttt');
|
|
57
|
-
const commandArgs: string[] = [];
|
|
58
|
-
|
|
59
|
-
for (let i = 0; i < args.length; i++) {
|
|
60
|
-
const arg = args[i];
|
|
61
|
-
if (arg === '-d' || arg === '--dir') {
|
|
62
|
-
dir = resolve(args[++i] || '.');
|
|
63
|
-
} else {
|
|
64
|
-
commandArgs.push(arg);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return { dir, commandArgs };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async function main() {
|
|
72
|
-
const args = process.argv.slice(2);
|
|
73
|
-
|
|
74
|
-
if (args.length === 0 || args[0] === 'help' || args[0] === '-h' || args[0] === '--help') {
|
|
75
|
-
printHelp();
|
|
76
|
-
process.exit(0);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (args[0] === 'version' || args[0] === '-v' || args[0] === '--version') {
|
|
80
|
-
printVersion();
|
|
81
|
-
process.exit(0);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const command = args[0] as Command;
|
|
85
|
-
const restArgs = args.slice(1);
|
|
86
|
-
const { dir, commandArgs } = parseGlobalArgs(restArgs);
|
|
87
|
-
|
|
88
|
-
// Set TOON_DIR for scripts to use
|
|
89
|
-
process.env.TOON_DIR = dir;
|
|
90
|
-
|
|
91
|
-
if (!COMMANDS.includes(command)) {
|
|
92
|
-
console.error(`Unknown command: ${command}`);
|
|
93
|
-
console.error(`Run 'ttt help' for usage.`);
|
|
94
|
-
process.exit(1);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Import and run the appropriate script
|
|
98
|
-
const scriptDir = new URL('../scripts/', import.meta.url).pathname;
|
|
99
|
-
try {
|
|
100
|
-
switch (command) {
|
|
101
|
-
case 'init':
|
|
102
|
-
process.argv = ['node', 'init.js', ...commandArgs];
|
|
103
|
-
await import(`${scriptDir}init.js`);
|
|
104
|
-
break;
|
|
105
|
-
case 'sync':
|
|
106
|
-
await import(`${scriptDir}sync.js`);
|
|
107
|
-
break;
|
|
108
|
-
case 'work-on':
|
|
109
|
-
process.argv = ['node', 'work-on.js', ...commandArgs];
|
|
110
|
-
await import(`${scriptDir}work-on.js`);
|
|
111
|
-
break;
|
|
112
|
-
case 'done':
|
|
113
|
-
process.argv = ['node', 'done-job.js', ...commandArgs];
|
|
114
|
-
await import(`${scriptDir}done-job.js`);
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
} catch (error) {
|
|
118
|
-
if (error instanceof Error) {
|
|
119
|
-
console.error(`Error: ${error.message}`);
|
|
120
|
-
}
|
|
121
|
-
process.exit(1);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
main();
|