team-toon-tack 2.0.0 ā 2.0.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/dist/scripts/init.js +62 -31
- package/package.json +3 -2
package/dist/scripts/init.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
4
7
|
import { decode, encode } from "@toon-format/toon";
|
|
5
8
|
import prompts from "prompts";
|
|
6
9
|
import { buildConfig, buildLocalConfig, findTeamKey, findUserKey, getDefaultStatusTransitions, } from "./lib/config-builder.js";
|
|
@@ -217,13 +220,20 @@ async function selectStatusSource(options) {
|
|
|
217
220
|
});
|
|
218
221
|
return response.statusSource || "remote";
|
|
219
222
|
}
|
|
220
|
-
async function selectStatusMappings(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
223
|
+
async function selectStatusMappings(devStates, qaStates, options) {
|
|
224
|
+
// Use dev team states for todo, in_progress, done, blocked
|
|
225
|
+
// Use qa team states for testing (fallback to dev team if not set)
|
|
226
|
+
const devDefaults = getDefaultStatusTransitions(devStates);
|
|
227
|
+
const testingStates = qaStates && qaStates.length > 0 ? qaStates : devStates;
|
|
228
|
+
const testingDefaults = getDefaultStatusTransitions(testingStates);
|
|
229
|
+
if (!options.interactive || devStates.length === 0) {
|
|
230
|
+
return {
|
|
231
|
+
...devDefaults,
|
|
232
|
+
testing: testingDefaults.testing,
|
|
233
|
+
};
|
|
224
234
|
}
|
|
225
235
|
console.log("\nš Configure status mappings:");
|
|
226
|
-
const
|
|
236
|
+
const devStateChoices = devStates.map((s) => ({
|
|
227
237
|
title: `${s.name} (${s.type})`,
|
|
228
238
|
value: s.name,
|
|
229
239
|
}));
|
|
@@ -231,53 +241,61 @@ async function selectStatusMappings(states, options) {
|
|
|
231
241
|
type: "select",
|
|
232
242
|
name: "todo",
|
|
233
243
|
message: 'Select status for "Todo" (pending tasks):',
|
|
234
|
-
choices:
|
|
235
|
-
initial:
|
|
244
|
+
choices: devStateChoices,
|
|
245
|
+
initial: devStateChoices.findIndex((c) => c.value === devDefaults.todo),
|
|
236
246
|
});
|
|
237
247
|
const inProgressResponse = await prompts({
|
|
238
248
|
type: "select",
|
|
239
249
|
name: "in_progress",
|
|
240
250
|
message: 'Select status for "In Progress" (working tasks):',
|
|
241
|
-
choices:
|
|
242
|
-
initial:
|
|
251
|
+
choices: devStateChoices,
|
|
252
|
+
initial: devStateChoices.findIndex((c) => c.value === devDefaults.in_progress),
|
|
243
253
|
});
|
|
244
254
|
const doneResponse = await prompts({
|
|
245
255
|
type: "select",
|
|
246
256
|
name: "done",
|
|
247
257
|
message: 'Select status for "Done" (completed tasks):',
|
|
248
|
-
choices:
|
|
249
|
-
initial:
|
|
258
|
+
choices: devStateChoices,
|
|
259
|
+
initial: devStateChoices.findIndex((c) => c.value === devDefaults.done),
|
|
250
260
|
});
|
|
261
|
+
// Testing uses qa team states (or dev team if qa not set)
|
|
262
|
+
const testingStateChoices = testingStates.map((s) => ({
|
|
263
|
+
title: `${s.name} (${s.type})`,
|
|
264
|
+
value: s.name,
|
|
265
|
+
}));
|
|
251
266
|
const testingChoices = [
|
|
252
267
|
{ title: "(None)", value: undefined },
|
|
253
|
-
...
|
|
268
|
+
...testingStateChoices,
|
|
254
269
|
];
|
|
270
|
+
const testingMessage = qaStates && qaStates.length > 0
|
|
271
|
+
? 'Select status for "Testing" (from QA team, for parent tasks):'
|
|
272
|
+
: 'Select status for "Testing" (optional, for parent tasks):';
|
|
255
273
|
const testingResponse = await prompts({
|
|
256
274
|
type: "select",
|
|
257
275
|
name: "testing",
|
|
258
|
-
message:
|
|
276
|
+
message: testingMessage,
|
|
259
277
|
choices: testingChoices,
|
|
260
|
-
initial:
|
|
261
|
-
? testingChoices.findIndex((c) => c.value ===
|
|
278
|
+
initial: testingDefaults.testing
|
|
279
|
+
? testingChoices.findIndex((c) => c.value === testingDefaults.testing)
|
|
262
280
|
: 0,
|
|
263
281
|
});
|
|
264
282
|
const blockedChoices = [
|
|
265
283
|
{ title: "(None)", value: undefined },
|
|
266
|
-
...
|
|
284
|
+
...devStateChoices,
|
|
267
285
|
];
|
|
268
286
|
const blockedResponse = await prompts({
|
|
269
287
|
type: "select",
|
|
270
288
|
name: "blocked",
|
|
271
289
|
message: 'Select status for "Blocked" (optional, for blocked tasks):',
|
|
272
290
|
choices: blockedChoices,
|
|
273
|
-
initial:
|
|
274
|
-
? blockedChoices.findIndex((c) => c.value ===
|
|
291
|
+
initial: devDefaults.blocked
|
|
292
|
+
? blockedChoices.findIndex((c) => c.value === devDefaults.blocked)
|
|
275
293
|
: 0,
|
|
276
294
|
});
|
|
277
295
|
return {
|
|
278
|
-
todo: todoResponse.todo ||
|
|
279
|
-
in_progress: inProgressResponse.in_progress ||
|
|
280
|
-
done: doneResponse.done ||
|
|
296
|
+
todo: todoResponse.todo || devDefaults.todo,
|
|
297
|
+
in_progress: inProgressResponse.in_progress || devDefaults.in_progress,
|
|
298
|
+
done: doneResponse.done || devDefaults.done,
|
|
281
299
|
testing: testingResponse.testing,
|
|
282
300
|
blocked: blockedResponse.blocked,
|
|
283
301
|
};
|
|
@@ -526,10 +544,12 @@ async function init() {
|
|
|
526
544
|
}
|
|
527
545
|
// Fetch data from ALL teams (not just primary) to support cross-team operations
|
|
528
546
|
console.log(` Fetching data from ${teams.length} teams...`);
|
|
529
|
-
// Collect users, labels
|
|
547
|
+
// Collect users from all teams, but labels only from primary team
|
|
548
|
+
// States are stored per-team for status mapping selection
|
|
530
549
|
const allUsers = [];
|
|
531
550
|
const allLabels = [];
|
|
532
551
|
const allStates = [];
|
|
552
|
+
const teamStatesMap = new Map(); // team.id -> states
|
|
533
553
|
const seenUserIds = new Set();
|
|
534
554
|
const seenLabelIds = new Set();
|
|
535
555
|
const seenStateIds = new Set();
|
|
@@ -543,24 +563,31 @@ async function init() {
|
|
|
543
563
|
allUsers.push(user);
|
|
544
564
|
}
|
|
545
565
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
566
|
+
// Labels: only from primary team (dev team)
|
|
567
|
+
if (team.id === primaryTeam.id) {
|
|
568
|
+
const labelsData = await client.issueLabels({
|
|
569
|
+
filter: { team: { id: { eq: team.id } } },
|
|
570
|
+
});
|
|
571
|
+
for (const label of labelsData.nodes) {
|
|
572
|
+
if (!seenLabelIds.has(label.id)) {
|
|
573
|
+
seenLabelIds.add(label.id);
|
|
574
|
+
allLabels.push(label);
|
|
575
|
+
}
|
|
553
576
|
}
|
|
554
577
|
}
|
|
578
|
+
// States: store per-team and also collect all
|
|
555
579
|
const statesData = await client.workflowStates({
|
|
556
580
|
filter: { team: { id: { eq: team.id } } },
|
|
557
581
|
});
|
|
582
|
+
const teamStates = [];
|
|
558
583
|
for (const state of statesData.nodes) {
|
|
584
|
+
teamStates.push(state);
|
|
559
585
|
if (!seenStateIds.has(state.id)) {
|
|
560
586
|
seenStateIds.add(state.id);
|
|
561
587
|
allStates.push(state);
|
|
562
588
|
}
|
|
563
589
|
}
|
|
590
|
+
teamStatesMap.set(team.id, teamStates);
|
|
564
591
|
}
|
|
565
592
|
catch (error) {
|
|
566
593
|
console.warn(` ā Could not fetch data for team ${team.name}, skipping...`);
|
|
@@ -569,8 +596,10 @@ async function init() {
|
|
|
569
596
|
const users = allUsers;
|
|
570
597
|
const labels = allLabels;
|
|
571
598
|
const states = allStates;
|
|
599
|
+
// Get team-specific states for status mapping
|
|
600
|
+
const primaryTeamStates = teamStatesMap.get(primaryTeam.id) || [];
|
|
572
601
|
console.log(` Users: ${users.length}`);
|
|
573
|
-
console.log(` Labels: ${labels.length}`);
|
|
602
|
+
console.log(` Labels: ${labels.length} (from ${primaryTeam.name})`);
|
|
574
603
|
console.log(` Workflow states: ${states.length}`);
|
|
575
604
|
// Get cycle from primary team (for current work tracking)
|
|
576
605
|
const selectedTeam = await client.team(primaryTeam.id);
|
|
@@ -580,7 +609,9 @@ async function init() {
|
|
|
580
609
|
const defaultLabel = await selectLabelFilter(labels, options);
|
|
581
610
|
const statusSource = await selectStatusSource(options);
|
|
582
611
|
const qaPmTeam = await selectQaPmTeam(teams, primaryTeam, options);
|
|
583
|
-
|
|
612
|
+
// Get qa team states for testing status mapping (fallback to primary team if not set)
|
|
613
|
+
const qaTeamStates = qaPmTeam ? teamStatesMap.get(qaPmTeam.id) : undefined;
|
|
614
|
+
const statusTransitions = await selectStatusMappings(primaryTeamStates, qaTeamStates, options);
|
|
584
615
|
// Build config
|
|
585
616
|
const config = buildConfig(teams, users, labels, states, statusTransitions, currentCycle ?? undefined);
|
|
586
617
|
// Find keys
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "team-toon-tack",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Linear task sync & management CLI with TOON format",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@linear/sdk": "^69.0.0",
|
|
28
28
|
"@toon-format/toon": "^2.1.0",
|
|
29
|
-
"prompts": "^2.4.2"
|
|
29
|
+
"prompts": "^2.4.2",
|
|
30
|
+
"team-toon-tack": "^2.0.1"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@biomejs/biome": "^2.3.11",
|