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
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import prompts from "prompts";
|
|
2
|
+
import { getLinearClient, getTeamId, saveLocalConfig, } from "../utils.js";
|
|
3
|
+
export async function configureFilters(config, localConfig) {
|
|
4
|
+
console.log("š Configure Filters\n");
|
|
5
|
+
const client = getLinearClient();
|
|
6
|
+
const teamId = getTeamId(config, localConfig.team);
|
|
7
|
+
// Fetch labels
|
|
8
|
+
const labelsData = await client.issueLabels({
|
|
9
|
+
filter: { team: { id: { eq: teamId } } },
|
|
10
|
+
});
|
|
11
|
+
const labels = labelsData.nodes;
|
|
12
|
+
// Fetch users
|
|
13
|
+
const team = await client.team(teamId);
|
|
14
|
+
const members = await team.members();
|
|
15
|
+
const users = members.nodes;
|
|
16
|
+
// Label filter (optional)
|
|
17
|
+
const labelChoices = [
|
|
18
|
+
{ title: "(No filter - sync all labels)", value: "" },
|
|
19
|
+
...labels.map((l) => ({ title: l.name, value: l.name })),
|
|
20
|
+
];
|
|
21
|
+
const labelResponse = await prompts({
|
|
22
|
+
type: "select",
|
|
23
|
+
name: "label",
|
|
24
|
+
message: "Select label filter (optional):",
|
|
25
|
+
choices: labelChoices,
|
|
26
|
+
initial: localConfig.label
|
|
27
|
+
? labelChoices.findIndex((c) => c.value === localConfig.label)
|
|
28
|
+
: 0,
|
|
29
|
+
});
|
|
30
|
+
// Exclude labels
|
|
31
|
+
const excludeLabelsResponse = await prompts({
|
|
32
|
+
type: "multiselect",
|
|
33
|
+
name: "excludeLabels",
|
|
34
|
+
message: "Select labels to exclude (space to select):",
|
|
35
|
+
choices: labels.map((l) => ({
|
|
36
|
+
title: l.name,
|
|
37
|
+
value: l.name,
|
|
38
|
+
selected: localConfig.exclude_labels?.includes(l.name),
|
|
39
|
+
})),
|
|
40
|
+
});
|
|
41
|
+
// Exclude users
|
|
42
|
+
const excludeUsersResponse = await prompts({
|
|
43
|
+
type: "multiselect",
|
|
44
|
+
name: "excludeUsers",
|
|
45
|
+
message: "Select users to exclude (space to select):",
|
|
46
|
+
choices: users.map((u) => {
|
|
47
|
+
const key = (u.displayName || u.name || u.email?.split("@")[0] || "user")
|
|
48
|
+
.toLowerCase()
|
|
49
|
+
.replace(/[^a-z0-9]/g, "_");
|
|
50
|
+
return {
|
|
51
|
+
title: `${u.displayName || u.name} (${u.email})`,
|
|
52
|
+
value: key,
|
|
53
|
+
selected: localConfig.exclude_assignees?.includes(key),
|
|
54
|
+
};
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
localConfig.label = labelResponse.label || undefined;
|
|
58
|
+
localConfig.exclude_labels =
|
|
59
|
+
excludeLabelsResponse.excludeLabels?.length > 0
|
|
60
|
+
? excludeLabelsResponse.excludeLabels
|
|
61
|
+
: undefined;
|
|
62
|
+
localConfig.exclude_assignees =
|
|
63
|
+
excludeUsersResponse.excludeUsers?.length > 0
|
|
64
|
+
? excludeUsersResponse.excludeUsers
|
|
65
|
+
: undefined;
|
|
66
|
+
await saveLocalConfig(localConfig);
|
|
67
|
+
console.log("\nā
Filters updated:");
|
|
68
|
+
console.log(` Label: ${localConfig.label || "(all)"}`);
|
|
69
|
+
console.log(` Exclude labels: ${localConfig.exclude_labels?.join(", ") || "(none)"}`);
|
|
70
|
+
console.log(` Exclude users: ${localConfig.exclude_assignees?.join(", ") || "(none)"}`);
|
|
71
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function showConfig(config, localConfig) {
|
|
2
|
+
console.log("š Current Configuration:\n");
|
|
3
|
+
// Teams
|
|
4
|
+
console.log("Teams:");
|
|
5
|
+
if (localConfig.teams && localConfig.teams.length > 0) {
|
|
6
|
+
console.log(` Selected: ${localConfig.teams.join(", ")}`);
|
|
7
|
+
console.log(` Primary: ${localConfig.team}`);
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
console.log(` ${localConfig.team}`);
|
|
11
|
+
}
|
|
12
|
+
// User
|
|
13
|
+
console.log(`\nUser: ${localConfig.current_user}`);
|
|
14
|
+
// Filters
|
|
15
|
+
console.log("\nFilters:");
|
|
16
|
+
console.log(` Label: ${localConfig.label || "(all)"}`);
|
|
17
|
+
console.log(` Exclude labels: ${localConfig.exclude_labels?.join(", ") || "(none)"}`);
|
|
18
|
+
console.log(` Exclude users: ${localConfig.exclude_assignees?.join(", ") || "(none)"}`);
|
|
19
|
+
// Status Mappings
|
|
20
|
+
console.log("\nStatus Mappings:");
|
|
21
|
+
if (config.status_transitions) {
|
|
22
|
+
const st = config.status_transitions;
|
|
23
|
+
console.log(` Todo: ${st.todo}`);
|
|
24
|
+
console.log(` In Progress: ${st.in_progress}`);
|
|
25
|
+
console.log(` Done: ${st.done}`);
|
|
26
|
+
if (st.testing) {
|
|
27
|
+
console.log(` Testing: ${st.testing}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.log(" (not configured)");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import prompts from "prompts";
|
|
2
|
+
import { getWorkflowStates } from "../lib/linear.js";
|
|
3
|
+
import { saveConfig, } from "../utils.js";
|
|
4
|
+
export async function configureStatus(config, localConfig) {
|
|
5
|
+
console.log("š Configure Status Mappings\n");
|
|
6
|
+
const states = await getWorkflowStates(config, localConfig.team);
|
|
7
|
+
if (states.length === 0) {
|
|
8
|
+
console.error("No workflow states found for this team.");
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const stateChoices = states.map((s) => ({
|
|
12
|
+
title: `${s.name} (${s.type})`,
|
|
13
|
+
value: s.name,
|
|
14
|
+
}));
|
|
15
|
+
// Get current values or defaults
|
|
16
|
+
const current = config.status_transitions || {};
|
|
17
|
+
const defaultTodo = current.todo || states.find((s) => s.type === "unstarted")?.name || "Todo";
|
|
18
|
+
const defaultInProgress = current.in_progress ||
|
|
19
|
+
states.find((s) => s.type === "started")?.name ||
|
|
20
|
+
"In Progress";
|
|
21
|
+
const defaultDone = current.done || states.find((s) => s.type === "completed")?.name || "Done";
|
|
22
|
+
const defaultTesting = current.testing || states.find((s) => s.name === "Testing")?.name;
|
|
23
|
+
const todoResponse = await prompts({
|
|
24
|
+
type: "select",
|
|
25
|
+
name: "todo",
|
|
26
|
+
message: 'Select status for "Todo" (pending tasks):',
|
|
27
|
+
choices: stateChoices,
|
|
28
|
+
initial: stateChoices.findIndex((c) => c.value === defaultTodo),
|
|
29
|
+
});
|
|
30
|
+
const inProgressResponse = await prompts({
|
|
31
|
+
type: "select",
|
|
32
|
+
name: "in_progress",
|
|
33
|
+
message: 'Select status for "In Progress" (working tasks):',
|
|
34
|
+
choices: stateChoices,
|
|
35
|
+
initial: stateChoices.findIndex((c) => c.value === defaultInProgress),
|
|
36
|
+
});
|
|
37
|
+
const doneResponse = await prompts({
|
|
38
|
+
type: "select",
|
|
39
|
+
name: "done",
|
|
40
|
+
message: 'Select status for "Done" (completed tasks):',
|
|
41
|
+
choices: stateChoices,
|
|
42
|
+
initial: stateChoices.findIndex((c) => c.value === defaultDone),
|
|
43
|
+
});
|
|
44
|
+
// Testing is optional
|
|
45
|
+
const testingChoices = [
|
|
46
|
+
{ title: "(None)", value: undefined },
|
|
47
|
+
...stateChoices,
|
|
48
|
+
];
|
|
49
|
+
const testingResponse = await prompts({
|
|
50
|
+
type: "select",
|
|
51
|
+
name: "testing",
|
|
52
|
+
message: 'Select status for "Testing" (optional, for parent tasks):',
|
|
53
|
+
choices: testingChoices,
|
|
54
|
+
initial: defaultTesting
|
|
55
|
+
? testingChoices.findIndex((c) => c.value === defaultTesting)
|
|
56
|
+
: 0,
|
|
57
|
+
});
|
|
58
|
+
const statusTransitions = {
|
|
59
|
+
todo: todoResponse.todo || defaultTodo,
|
|
60
|
+
in_progress: inProgressResponse.in_progress || defaultInProgress,
|
|
61
|
+
done: doneResponse.done || defaultDone,
|
|
62
|
+
testing: testingResponse.testing,
|
|
63
|
+
};
|
|
64
|
+
config.status_transitions = statusTransitions;
|
|
65
|
+
await saveConfig(config);
|
|
66
|
+
console.log("\nā
Status mappings updated:");
|
|
67
|
+
console.log(` Todo: ${statusTransitions.todo}`);
|
|
68
|
+
console.log(` In Progress: ${statusTransitions.in_progress}`);
|
|
69
|
+
console.log(` Done: ${statusTransitions.done}`);
|
|
70
|
+
if (statusTransitions.testing) {
|
|
71
|
+
console.log(` Testing: ${statusTransitions.testing}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import prompts from "prompts";
|
|
2
|
+
import { getLinearClient, saveLocalConfig, } from "../utils.js";
|
|
3
|
+
export async function configureTeams(_config, localConfig) {
|
|
4
|
+
console.log("š„ Configure Teams\n");
|
|
5
|
+
const client = getLinearClient();
|
|
6
|
+
const teamsData = await client.teams();
|
|
7
|
+
const teams = teamsData.nodes;
|
|
8
|
+
if (teams.length === 0) {
|
|
9
|
+
console.error("No teams found.");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
// Multi-select teams
|
|
13
|
+
const teamsResponse = await prompts({
|
|
14
|
+
type: "multiselect",
|
|
15
|
+
name: "teamKeys",
|
|
16
|
+
message: "Select teams to sync (space to select):",
|
|
17
|
+
choices: teams.map((t) => {
|
|
18
|
+
const key = t.name.toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
19
|
+
const currentTeams = localConfig.teams || [localConfig.team];
|
|
20
|
+
return {
|
|
21
|
+
title: t.name,
|
|
22
|
+
value: key,
|
|
23
|
+
selected: currentTeams.includes(key),
|
|
24
|
+
};
|
|
25
|
+
}),
|
|
26
|
+
min: 1,
|
|
27
|
+
});
|
|
28
|
+
const selectedTeamKeys = teamsResponse.teamKeys || [localConfig.team];
|
|
29
|
+
// If multiple teams, ask for primary
|
|
30
|
+
let primaryTeam = localConfig.team;
|
|
31
|
+
if (selectedTeamKeys.length > 1) {
|
|
32
|
+
const primaryResponse = await prompts({
|
|
33
|
+
type: "select",
|
|
34
|
+
name: "primary",
|
|
35
|
+
message: "Select primary team:",
|
|
36
|
+
choices: selectedTeamKeys.map((key) => ({
|
|
37
|
+
title: key,
|
|
38
|
+
value: key,
|
|
39
|
+
})),
|
|
40
|
+
initial: selectedTeamKeys.indexOf(localConfig.team),
|
|
41
|
+
});
|
|
42
|
+
primaryTeam = primaryResponse.primary || selectedTeamKeys[0];
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
primaryTeam = selectedTeamKeys[0];
|
|
46
|
+
}
|
|
47
|
+
localConfig.team = primaryTeam;
|
|
48
|
+
localConfig.teams =
|
|
49
|
+
selectedTeamKeys.length > 1 ? selectedTeamKeys : undefined;
|
|
50
|
+
await saveLocalConfig(localConfig);
|
|
51
|
+
console.log("\nā
Teams updated:");
|
|
52
|
+
if (localConfig.teams) {
|
|
53
|
+
console.log(` Selected: ${localConfig.teams.join(", ")}`);
|
|
54
|
+
console.log(` Primary: ${localConfig.team}`);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.log(` Team: ${localConfig.team}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
package/dist/scripts/config.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import { configureFilters } from "./config/filters.js";
|
|
3
|
+
import { showConfig } from "./config/show.js";
|
|
4
|
+
import { configureStatus } from "./config/status.js";
|
|
5
|
+
import { configureTeams } from "./config/teams.js";
|
|
6
|
+
import { loadConfig, loadLocalConfig } from "./utils.js";
|
|
4
7
|
async function config() {
|
|
5
8
|
const args = process.argv.slice(2);
|
|
6
|
-
// Handle help flag
|
|
7
9
|
if (args.includes("--help") || args.includes("-h")) {
|
|
8
10
|
console.log(`Usage: ttt config [subcommand]
|
|
9
11
|
|
|
@@ -24,248 +26,22 @@ Examples:
|
|
|
24
26
|
const subcommand = args[0] || "show";
|
|
25
27
|
const configData = await loadConfig();
|
|
26
28
|
const localConfig = await loadLocalConfig();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
console.log(` Label: ${localConfig.label || "(all)"}`);
|
|
43
|
-
console.log(` Exclude labels: ${localConfig.exclude_labels?.join(", ") || "(none)"}`);
|
|
44
|
-
console.log(` Exclude users: ${localConfig.exclude_assignees?.join(", ") || "(none)"}`);
|
|
45
|
-
// Status Mappings
|
|
46
|
-
console.log("\nStatus Mappings:");
|
|
47
|
-
if (configData.status_transitions) {
|
|
48
|
-
const st = configData.status_transitions;
|
|
49
|
-
console.log(` Todo: ${st.todo}`);
|
|
50
|
-
console.log(` In Progress: ${st.in_progress}`);
|
|
51
|
-
console.log(` Done: ${st.done}`);
|
|
52
|
-
if (st.testing) {
|
|
53
|
-
console.log(` Testing: ${st.testing}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
console.log(" (not configured)");
|
|
58
|
-
}
|
|
59
|
-
process.exit(0);
|
|
60
|
-
}
|
|
61
|
-
if (subcommand === "status") {
|
|
62
|
-
console.log("š Configure Status Mappings\n");
|
|
63
|
-
const client = getLinearClient();
|
|
64
|
-
const teamId = getTeamId(configData, localConfig.team);
|
|
65
|
-
// Fetch workflow states
|
|
66
|
-
const statesData = await client.workflowStates({
|
|
67
|
-
filter: { team: { id: { eq: teamId } } },
|
|
68
|
-
});
|
|
69
|
-
const states = statesData.nodes;
|
|
70
|
-
if (states.length === 0) {
|
|
71
|
-
console.error("No workflow states found for this team.");
|
|
72
|
-
process.exit(1);
|
|
73
|
-
}
|
|
74
|
-
const stateChoices = states.map((s) => ({
|
|
75
|
-
title: `${s.name} (${s.type})`,
|
|
76
|
-
value: s.name,
|
|
77
|
-
}));
|
|
78
|
-
// Get current values or defaults
|
|
79
|
-
const current = configData.status_transitions || {};
|
|
80
|
-
const defaultTodo = current.todo ||
|
|
81
|
-
states.find((s) => s.type === "unstarted")?.name ||
|
|
82
|
-
"Todo";
|
|
83
|
-
const defaultInProgress = current.in_progress ||
|
|
84
|
-
states.find((s) => s.type === "started")?.name ||
|
|
85
|
-
"In Progress";
|
|
86
|
-
const defaultDone = current.done ||
|
|
87
|
-
states.find((s) => s.type === "completed")?.name ||
|
|
88
|
-
"Done";
|
|
89
|
-
const defaultTesting = current.testing || states.find((s) => s.name === "Testing")?.name;
|
|
90
|
-
const todoResponse = await prompts({
|
|
91
|
-
type: "select",
|
|
92
|
-
name: "todo",
|
|
93
|
-
message: 'Select status for "Todo" (pending tasks):',
|
|
94
|
-
choices: stateChoices,
|
|
95
|
-
initial: stateChoices.findIndex((c) => c.value === defaultTodo),
|
|
96
|
-
});
|
|
97
|
-
const inProgressResponse = await prompts({
|
|
98
|
-
type: "select",
|
|
99
|
-
name: "in_progress",
|
|
100
|
-
message: 'Select status for "In Progress" (working tasks):',
|
|
101
|
-
choices: stateChoices,
|
|
102
|
-
initial: stateChoices.findIndex((c) => c.value === defaultInProgress),
|
|
103
|
-
});
|
|
104
|
-
const doneResponse = await prompts({
|
|
105
|
-
type: "select",
|
|
106
|
-
name: "done",
|
|
107
|
-
message: 'Select status for "Done" (completed tasks):',
|
|
108
|
-
choices: stateChoices,
|
|
109
|
-
initial: stateChoices.findIndex((c) => c.value === defaultDone),
|
|
110
|
-
});
|
|
111
|
-
// Testing is optional
|
|
112
|
-
const testingChoices = [
|
|
113
|
-
{ title: "(None)", value: undefined },
|
|
114
|
-
...stateChoices,
|
|
115
|
-
];
|
|
116
|
-
const testingResponse = await prompts({
|
|
117
|
-
type: "select",
|
|
118
|
-
name: "testing",
|
|
119
|
-
message: 'Select status for "Testing" (optional, for parent tasks):',
|
|
120
|
-
choices: testingChoices,
|
|
121
|
-
initial: defaultTesting
|
|
122
|
-
? testingChoices.findIndex((c) => c.value === defaultTesting)
|
|
123
|
-
: 0,
|
|
124
|
-
});
|
|
125
|
-
const statusTransitions = {
|
|
126
|
-
todo: todoResponse.todo || defaultTodo,
|
|
127
|
-
in_progress: inProgressResponse.in_progress || defaultInProgress,
|
|
128
|
-
done: doneResponse.done || defaultDone,
|
|
129
|
-
testing: testingResponse.testing,
|
|
130
|
-
};
|
|
131
|
-
configData.status_transitions = statusTransitions;
|
|
132
|
-
await saveConfig(configData);
|
|
133
|
-
console.log("\nā
Status mappings updated:");
|
|
134
|
-
console.log(` Todo: ${statusTransitions.todo}`);
|
|
135
|
-
console.log(` In Progress: ${statusTransitions.in_progress}`);
|
|
136
|
-
console.log(` Done: ${statusTransitions.done}`);
|
|
137
|
-
if (statusTransitions.testing) {
|
|
138
|
-
console.log(` Testing: ${statusTransitions.testing}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
if (subcommand === "filters") {
|
|
142
|
-
console.log("š Configure Filters\n");
|
|
143
|
-
const client = getLinearClient();
|
|
144
|
-
const teamId = getTeamId(configData, localConfig.team);
|
|
145
|
-
// Fetch labels
|
|
146
|
-
const labelsData = await client.issueLabels({
|
|
147
|
-
filter: { team: { id: { eq: teamId } } },
|
|
148
|
-
});
|
|
149
|
-
const labels = labelsData.nodes;
|
|
150
|
-
// Fetch users
|
|
151
|
-
const team = await client.team(teamId);
|
|
152
|
-
const members = await team.members();
|
|
153
|
-
const users = members.nodes;
|
|
154
|
-
// Label filter (optional)
|
|
155
|
-
const labelChoices = [
|
|
156
|
-
{ title: "(No filter - sync all labels)", value: "" },
|
|
157
|
-
...labels.map((l) => ({ title: l.name, value: l.name })),
|
|
158
|
-
];
|
|
159
|
-
const labelResponse = await prompts({
|
|
160
|
-
type: "select",
|
|
161
|
-
name: "label",
|
|
162
|
-
message: "Select label filter (optional):",
|
|
163
|
-
choices: labelChoices,
|
|
164
|
-
initial: localConfig.label
|
|
165
|
-
? labelChoices.findIndex((c) => c.value === localConfig.label)
|
|
166
|
-
: 0,
|
|
167
|
-
});
|
|
168
|
-
// Exclude labels
|
|
169
|
-
const excludeLabelsResponse = await prompts({
|
|
170
|
-
type: "multiselect",
|
|
171
|
-
name: "excludeLabels",
|
|
172
|
-
message: "Select labels to exclude (space to select):",
|
|
173
|
-
choices: labels.map((l) => ({
|
|
174
|
-
title: l.name,
|
|
175
|
-
value: l.name,
|
|
176
|
-
selected: localConfig.exclude_labels?.includes(l.name),
|
|
177
|
-
})),
|
|
178
|
-
});
|
|
179
|
-
// Exclude users
|
|
180
|
-
const excludeUsersResponse = await prompts({
|
|
181
|
-
type: "multiselect",
|
|
182
|
-
name: "excludeUsers",
|
|
183
|
-
message: "Select users to exclude (space to select):",
|
|
184
|
-
choices: users.map((u) => {
|
|
185
|
-
const key = (u.displayName ||
|
|
186
|
-
u.name ||
|
|
187
|
-
u.email?.split("@")[0] ||
|
|
188
|
-
"user")
|
|
189
|
-
.toLowerCase()
|
|
190
|
-
.replace(/[^a-z0-9]/g, "_");
|
|
191
|
-
return {
|
|
192
|
-
title: `${u.displayName || u.name} (${u.email})`,
|
|
193
|
-
value: key,
|
|
194
|
-
selected: localConfig.exclude_assignees?.includes(key),
|
|
195
|
-
};
|
|
196
|
-
}),
|
|
197
|
-
});
|
|
198
|
-
localConfig.label = labelResponse.label || undefined;
|
|
199
|
-
localConfig.exclude_labels =
|
|
200
|
-
excludeLabelsResponse.excludeLabels?.length > 0
|
|
201
|
-
? excludeLabelsResponse.excludeLabels
|
|
202
|
-
: undefined;
|
|
203
|
-
localConfig.exclude_assignees =
|
|
204
|
-
excludeUsersResponse.excludeUsers?.length > 0
|
|
205
|
-
? excludeUsersResponse.excludeUsers
|
|
206
|
-
: undefined;
|
|
207
|
-
await saveLocalConfig(localConfig);
|
|
208
|
-
console.log("\nā
Filters updated:");
|
|
209
|
-
console.log(` Label: ${localConfig.label || "(all)"}`);
|
|
210
|
-
console.log(` Exclude labels: ${localConfig.exclude_labels?.join(", ") || "(none)"}`);
|
|
211
|
-
console.log(` Exclude users: ${localConfig.exclude_assignees?.join(", ") || "(none)"}`);
|
|
212
|
-
}
|
|
213
|
-
if (subcommand === "teams") {
|
|
214
|
-
console.log("š„ Configure Teams\n");
|
|
215
|
-
const client = getLinearClient();
|
|
216
|
-
const teamsData = await client.teams();
|
|
217
|
-
const teams = teamsData.nodes;
|
|
218
|
-
if (teams.length === 0) {
|
|
219
|
-
console.error("No teams found.");
|
|
29
|
+
switch (subcommand) {
|
|
30
|
+
case "show":
|
|
31
|
+
showConfig(configData, localConfig);
|
|
32
|
+
break;
|
|
33
|
+
case "status":
|
|
34
|
+
await configureStatus(configData, localConfig);
|
|
35
|
+
break;
|
|
36
|
+
case "filters":
|
|
37
|
+
await configureFilters(configData, localConfig);
|
|
38
|
+
break;
|
|
39
|
+
case "teams":
|
|
40
|
+
await configureTeams(configData, localConfig);
|
|
41
|
+
break;
|
|
42
|
+
default:
|
|
43
|
+
console.error(`Unknown subcommand: ${subcommand}`);
|
|
220
44
|
process.exit(1);
|
|
221
|
-
}
|
|
222
|
-
// Multi-select teams
|
|
223
|
-
const teamsResponse = await prompts({
|
|
224
|
-
type: "multiselect",
|
|
225
|
-
name: "teamKeys",
|
|
226
|
-
message: "Select teams to sync (space to select):",
|
|
227
|
-
choices: teams.map((t) => {
|
|
228
|
-
const key = t.name.toLowerCase().replace(/[^a-z0-9]/g, "_");
|
|
229
|
-
const currentTeams = localConfig.teams || [localConfig.team];
|
|
230
|
-
return {
|
|
231
|
-
title: t.name,
|
|
232
|
-
value: key,
|
|
233
|
-
selected: currentTeams.includes(key),
|
|
234
|
-
};
|
|
235
|
-
}),
|
|
236
|
-
min: 1,
|
|
237
|
-
});
|
|
238
|
-
const selectedTeamKeys = teamsResponse.teamKeys || [localConfig.team];
|
|
239
|
-
// If multiple teams, ask for primary
|
|
240
|
-
let primaryTeam = localConfig.team;
|
|
241
|
-
if (selectedTeamKeys.length > 1) {
|
|
242
|
-
const primaryResponse = await prompts({
|
|
243
|
-
type: "select",
|
|
244
|
-
name: "primary",
|
|
245
|
-
message: "Select primary team:",
|
|
246
|
-
choices: selectedTeamKeys.map((key) => ({
|
|
247
|
-
title: key,
|
|
248
|
-
value: key,
|
|
249
|
-
})),
|
|
250
|
-
initial: selectedTeamKeys.indexOf(localConfig.team),
|
|
251
|
-
});
|
|
252
|
-
primaryTeam = primaryResponse.primary || selectedTeamKeys[0];
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
primaryTeam = selectedTeamKeys[0];
|
|
256
|
-
}
|
|
257
|
-
localConfig.team = primaryTeam;
|
|
258
|
-
localConfig.teams =
|
|
259
|
-
selectedTeamKeys.length > 1 ? selectedTeamKeys : undefined;
|
|
260
|
-
await saveLocalConfig(localConfig);
|
|
261
|
-
console.log("\nā
Teams updated:");
|
|
262
|
-
if (localConfig.teams) {
|
|
263
|
-
console.log(` Selected: ${localConfig.teams.join(", ")}`);
|
|
264
|
-
console.log(` Primary: ${localConfig.team}`);
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
console.log(` Team: ${localConfig.team}`);
|
|
268
|
-
}
|
|
269
45
|
}
|
|
270
46
|
}
|
|
271
47
|
config().catch(console.error);
|