team-toon-tack 2.1.0 → 2.3.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.
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: ttt:write-validate
3
+ description: Create a project validation command by detecting project type and existing lint/test configurations
4
+ arguments:
5
+ - name: command-name
6
+ description: Name for the command (default: validate)
7
+ required: false
8
+ ---
9
+
10
+ # TTT Write-Validate Command
11
+
12
+ Create a project-specific validation command by analyzing the codebase.
13
+
14
+ ## Process
15
+
16
+ ### 1. Detect Project Type
17
+
18
+ Check for project indicators:
19
+
20
+ | File | Project Type |
21
+ |------|--------------|
22
+ | `package.json` | Node.js / Bun |
23
+ | `Cargo.toml` | Rust |
24
+ | `go.mod` | Go |
25
+ | `pyproject.toml`, `requirements.txt` | Python |
26
+
27
+ ### 2. Find Existing Configurations
28
+
29
+ Look for static analysis configs:
30
+
31
+ **Linting**: `biome.json`, `.eslintrc.*`, `ruff.toml`
32
+ **Type Check**: `tsconfig.json`, `mypy.ini`
33
+ **Testing**: `jest.config.*`, `vitest.config.*`, `pytest.ini`
34
+
35
+ ### 3. Check package.json Scripts
36
+
37
+ If Node.js project:
38
+ ```bash
39
+ cat package.json | jq '.scripts | keys[]' 2>/dev/null
40
+ ```
41
+
42
+ Look for: `lint`, `type-check`, `test`, `check`, `validate`
43
+
44
+ ### 4. Create Command File
45
+
46
+ Create `.claude/commands/{{ $1 | default: "validate" }}.md`:
47
+
48
+ ```markdown
49
+ ---
50
+ name: {{ $1 | default: "validate" }}
51
+ description: Run project validation (lint, type-check, test)
52
+ ---
53
+
54
+ # Project Validation
55
+
56
+ Run validation checks for this project.
57
+
58
+ ## Process
59
+
60
+ ### 1. Lint
61
+ \`\`\`bash
62
+ {{ lint-command }}
63
+ \`\`\`
64
+
65
+ ### 2. Type Check
66
+ \`\`\`bash
67
+ {{ type-check-command }}
68
+ \`\`\`
69
+
70
+ ### 3. Test (optional)
71
+ \`\`\`bash
72
+ {{ test-command }}
73
+ \`\`\`
74
+
75
+ ## Quick Validate All
76
+
77
+ \`\`\`bash
78
+ {{ combined-command }}
79
+ \`\`\`
80
+
81
+ ## On Failure
82
+
83
+ 1. Show error output
84
+ 2. Identify failing file(s) and line(s)
85
+ 3. Suggest fixes
86
+ 4. Re-run validation after fixes
87
+ ```
88
+
89
+ ### 5. Output
90
+
91
+ After creating:
92
+ 1. Show created file path
93
+ 2. Display detected validation commands
94
+ 3. Suggest running `/{{ $1 | default: "validate" }}` to test
95
+
96
+ ## Examples
97
+
98
+ ### Node.js with Biome
99
+ ```
100
+ Detected: Node.js project with Biome + TypeScript
101
+ Created: .claude/commands/validate.md
102
+
103
+ Commands:
104
+ Lint: bun run lint
105
+ Type: bun run type-check
106
+ Test: bun run test
107
+
108
+ Try: /validate
109
+ ```
110
+
111
+ ### Python with Ruff
112
+ ```
113
+ Detected: Python project with Ruff + mypy
114
+ Created: .claude/commands/validate.md
115
+
116
+ Commands:
117
+ Lint: ruff check .
118
+ Type: mypy .
119
+ Test: pytest
120
+
121
+ Try: /validate
122
+ ```
package/dist/bin/cli.js CHANGED
@@ -12,6 +12,7 @@ const COMMANDS = [
12
12
  "work-on",
13
13
  "done",
14
14
  "status",
15
+ "show",
15
16
  "config",
16
17
  "help",
17
18
  "version",
@@ -24,14 +25,15 @@ USAGE:
24
25
  ttt <command> [options]
25
26
 
26
27
  COMMANDS:
27
- init Initialize config files in current directory
28
- sync Sync issues from Linear to local cycle.ttt
29
- work-on Start working on a task (interactive or by ID)
30
- done Mark current task as completed
31
- status Show or modify task status
32
- config Configure settings (status mappings, filters)
33
- help Show this help message
34
- version Show version
28
+ init Initialize config files in current directory
29
+ sync Sync issues from Linear to local cycle.ttt
30
+ work-on Start working on a task (interactive or by ID)
31
+ done Mark current task as completed
32
+ status Show or modify task status
33
+ show Show issue details or search issues by filters
34
+ config Configure settings (status mappings, filters)
35
+ help Show this help message
36
+ version Show version
35
37
 
36
38
  GLOBAL OPTIONS:
37
39
  -d, --dir <path> Config directory (default: .ttt)
@@ -46,6 +48,9 @@ EXAMPLES:
46
48
  ttt work-on next # Auto-select highest priority
47
49
  ttt done # Complete current task
48
50
  ttt done -m "Fixed the bug" # With completion message
51
+ ttt show MP-123 # Show issue from local data
52
+ ttt show --label frontend # Search local issues by label
53
+ ttt show --status "In Progress" # Filter by status
49
54
 
50
55
  ENVIRONMENT:
51
56
  LINEAR_API_KEY Required. Your Linear API key
@@ -117,6 +122,10 @@ async function main() {
117
122
  process.argv = ["node", "status.js", ...commandArgs];
118
123
  await import(`${scriptDir}status.js`);
119
124
  break;
125
+ case "show":
126
+ process.argv = ["node", "show.js", ...commandArgs];
127
+ await import(`${scriptDir}show.js`);
128
+ break;
120
129
  case "config":
121
130
  process.argv = ["node", "config.js", ...commandArgs];
122
131
  await import(`${scriptDir}config.js`);
@@ -1,6 +1,6 @@
1
1
  import prompts from "prompts";
2
- import { getLinearClient, saveLocalConfig, } from "../utils.js";
3
2
  import { getDefaultStatusTransitions } from "../lib/config-builder.js";
3
+ import { getLinearClient, saveLocalConfig, } from "../utils.js";
4
4
  export async function configureTeams(_config, localConfig) {
5
5
  console.log("šŸ‘„ Configure Teams\n");
6
6
  const client = getLinearClient();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ import { displayTaskFull } from "./lib/display.js";
2
+ import { fetchIssueDetail } from "./lib/sync.js";
3
+ import { loadCycleData } from "./utils.js";
4
+ async function getIssue() {
5
+ const args = process.argv.slice(2);
6
+ if (args.includes("--help") || args.includes("-h")) {
7
+ console.log(`Usage: ttt get-issue <issue-id> [--local]
8
+
9
+ Fetch and display issue details from Linear.
10
+
11
+ Arguments:
12
+ issue-id Issue ID (e.g., MP-624). Required.
13
+
14
+ Options:
15
+ --local Only show from local cycle data, don't fetch from Linear
16
+
17
+ Examples:
18
+ ttt get-issue MP-624 # Fetch from Linear and display
19
+ ttt get-issue MP-624 --local # Show from local data only`);
20
+ process.exit(0);
21
+ }
22
+ const localOnly = args.includes("--local");
23
+ const issueId = args.find((arg) => !arg.startsWith("-"));
24
+ if (!issueId) {
25
+ console.error("Issue ID is required.");
26
+ console.error("Usage: ttt get-issue <issue-id>");
27
+ process.exit(1);
28
+ }
29
+ // If local only, get from cycle data
30
+ if (localOnly) {
31
+ const data = await loadCycleData();
32
+ if (!data) {
33
+ console.error("No cycle data found. Run ttt sync first.");
34
+ process.exit(1);
35
+ }
36
+ const task = data.tasks.find((t) => t.id === issueId || t.id === `MP-${issueId}`);
37
+ if (!task) {
38
+ console.error(`Issue ${issueId} not found in local data.`);
39
+ process.exit(1);
40
+ }
41
+ displayTaskFull(task, "šŸ“‹");
42
+ return;
43
+ }
44
+ // Fetch from Linear
45
+ console.log(`Fetching ${issueId} from Linear...`);
46
+ const task = await fetchIssueDetail(issueId);
47
+ if (!task) {
48
+ console.error(`Issue ${issueId} not found in Linear.`);
49
+ process.exit(1);
50
+ }
51
+ // Check local data for local status
52
+ const data = await loadCycleData();
53
+ if (data) {
54
+ const localTask = data.tasks.find((t) => t.id === issueId);
55
+ if (localTask) {
56
+ task.localStatus = localTask.localStatus;
57
+ }
58
+ }
59
+ displayTaskFull(task, "šŸ“‹");
60
+ }
61
+ getIssue().catch(console.error);
@@ -400,147 +400,26 @@ async function updateGitignore(tttDir, interactive) {
400
400
  // Silently ignore gitignore errors
401
401
  }
402
402
  }
403
- async function installClaudeCommands(interactive, statusSource) {
404
- if (!interactive) {
405
- return { installed: false, prefix: "" };
406
- }
407
- console.log("\nšŸ¤– Claude Code Commands:");
408
- // Ask if user wants to install commands
409
- const { install } = await prompts({
410
- type: "confirm",
411
- name: "install",
412
- message: "Install Claude Code commands? (work-on, done-job, sync-linear)",
413
- initial: true,
414
- });
415
- if (!install) {
416
- return { installed: false, prefix: "" };
417
- }
418
- // Ask for prefix
419
- const { prefixChoice } = await prompts({
420
- type: "select",
421
- name: "prefixChoice",
422
- message: "Command prefix style:",
423
- choices: [
424
- {
425
- title: "No prefix (recommended)",
426
- value: "",
427
- description: "/work-on, /done-job, /sync-linear",
428
- },
429
- {
430
- title: "ttt:",
431
- value: "ttt:",
432
- description: "/ttt:work-on, /ttt:done-job, /ttt:sync-linear",
433
- },
434
- {
435
- title: "linear:",
436
- value: "linear:",
437
- description: "/linear:work-on, /linear:done-job, /linear:sync-linear",
438
- },
439
- {
440
- title: "Custom...",
441
- value: "custom",
442
- description: "Enter your own prefix",
443
- },
444
- ],
445
- initial: 0,
446
- });
447
- let prefix = prefixChoice || "";
448
- if (prefixChoice === "custom") {
449
- const { customPrefix } = await prompts({
450
- type: "text",
451
- name: "customPrefix",
452
- message: "Enter custom prefix (e.g., 'my:'):",
453
- initial: "",
454
- });
455
- prefix = customPrefix || "";
456
- }
457
- // Find templates directory
458
- // Try multiple locations: installed package, local dev
459
- const possibleTemplatePaths = [
460
- path.join(__dirname, "..", "templates", "claude-code-commands"),
461
- path.join(__dirname, "..", "..", "templates", "claude-code-commands"),
462
- path.join(process.cwd(), "templates", "claude-code-commands"),
463
- ];
464
- let templateDir = null;
465
- for (const p of possibleTemplatePaths) {
466
- try {
467
- await fs.access(p);
468
- templateDir = p;
469
- break;
470
- }
471
- catch {
472
- // Try next path
473
- }
474
- }
475
- if (!templateDir) {
476
- // Try to get repo URL from package.json
477
- let repoUrl = "https://github.com/wayne930242/team-toon-tack";
478
- try {
479
- const pkgPaths = [
480
- path.join(__dirname, "..", "package.json"),
481
- path.join(__dirname, "..", "..", "package.json"),
482
- ];
483
- for (const pkgPath of pkgPaths) {
484
- try {
485
- const pkgContent = await fs.readFile(pkgPath, "utf-8");
486
- const pkg = JSON.parse(pkgContent);
487
- if (pkg.repository?.url) {
488
- // Parse git+https://github.com/user/repo.git format
489
- repoUrl = pkg.repository.url
490
- .replace(/^git\+/, "")
491
- .replace(/\.git$/, "");
492
- }
493
- break;
494
- }
495
- catch {
496
- // Try next path
497
- }
498
- }
499
- }
500
- catch {
501
- // Use default URL
502
- }
503
- console.log(" ⚠ Could not find command templates. Please copy manually from:");
504
- console.log(` ${repoUrl}/tree/main/templates/claude-code-commands`);
505
- return { installed: false, prefix };
506
- }
507
- // Create .claude/commands directory
508
- const commandsDir = path.join(process.cwd(), ".claude", "commands");
509
- await fs.mkdir(commandsDir, { recursive: true });
510
- // Copy and rename template files
511
- const templateFiles = await fs.readdir(templateDir);
512
- const commandFiles = templateFiles.filter((f) => f.endsWith(".md"));
513
- for (const file of commandFiles) {
514
- const baseName = file.replace(".md", "");
515
- const newFileName = prefix ? `${prefix}${baseName}.md` : file;
516
- const srcPath = path.join(templateDir, file);
517
- const destPath = path.join(commandsDir, newFileName);
518
- // Read template content
519
- let content = await fs.readFile(srcPath, "utf-8");
520
- // Update the name in frontmatter if prefix is used
521
- if (prefix) {
522
- content = content.replace(/^(---\s*\n[\s\S]*?name:\s*)(\S+)/m, `$1${prefix}${baseName}`);
523
- }
524
- // Modify content based on statusSource for work-on and done-job
525
- if (statusSource === "local") {
526
- if (baseName === "work-on" || baseName.endsWith("work-on")) {
527
- // Update description for local mode
528
- content = content.replace(/Select a task and update status to "In Progress" on both local and Linear\./, 'Select a task and update local status to "In Progress". (Linear will be updated when you run `sync --update`)');
529
- // Add reminder after Complete section
530
- content = content.replace(/Use `?\/done-job`? to mark task as completed/, "Use `/done-job` to mark task as completed\n\n### 7. Sync to Linear\n\nWhen ready to update Linear with all your changes:\n\n```bash\nttt sync --update\n```");
531
- }
532
- if (baseName === "done-job" || baseName.endsWith("done-job")) {
533
- // Update description for local mode
534
- content = content.replace(/Mark a task as done and update Linear with commit details\./, "Mark a task as done locally. (Run `ttt sync --update` to push changes to Linear)");
535
- // Add reminder at the end
536
- content = content.replace(/## What It Does\n\n- Linear issue status → "Done"/, "## What It Does\n\n- Local status → `completed`");
537
- content += `\n## Sync to Linear\n\nAfter completing tasks, push all changes to Linear:\n\n\`\`\`bash\nttt sync --update\n\`\`\`\n`;
538
- }
539
- }
540
- await fs.writeFile(destPath, content, "utf-8");
541
- console.log(` āœ“ .claude/commands/${newFileName}`);
542
- }
543
- return { installed: true, prefix };
403
+ function showPluginInstallInstructions() {
404
+ console.log("\nšŸ¤– Claude Code Plugin:");
405
+ console.log("ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”");
406
+ console.log("│ Install team-toon-tack plugin in Claude Code: │");
407
+ console.log("ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤");
408
+ console.log("│ │");
409
+ console.log("│ 1. Add marketplace: │");
410
+ console.log("│ /plugin marketplace add wayne930242/team-toon-tack │");
411
+ console.log("│ │");
412
+ console.log("│ 2. Install plugin: │");
413
+ console.log("│ /plugin install team-toon-tack@wayne930242 │");
414
+ console.log("│ │");
415
+ console.log("│ Available commands after install: │");
416
+ console.log("│ /ttt:sync - Sync Linear issues │");
417
+ console.log("│ /ttt:work-on - Start working on a task │");
418
+ console.log("│ /ttt:done - Complete current task │");
419
+ console.log("│ /ttt:status - Show/modify task status │");
420
+ console.log("│ /ttt:show - Show/search issues │");
421
+ console.log("│ │");
422
+ console.log("ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜");
544
423
  }
545
424
  async function init() {
546
425
  const args = process.argv.slice(2);
@@ -732,8 +611,8 @@ async function init() {
732
611
  console.log(` āœ“ ${paths.localPath}`);
733
612
  // Update .gitignore (always use relative path .ttt)
734
613
  await updateGitignore(".ttt", options.interactive ?? true);
735
- // Install Claude Code commands
736
- const { installed: commandsInstalled, prefix: commandPrefix } = await installClaudeCommands(options.interactive ?? true, statusSource);
614
+ // Show Claude Code plugin installation instructions
615
+ showPluginInstallInstructions();
737
616
  // Summary
738
617
  console.log("\nāœ… Initialization complete!\n");
739
618
  console.log("Configuration summary:");
@@ -762,21 +641,10 @@ async function init() {
762
641
  if (statusTransitions.blocked) {
763
642
  console.log(` Blocked: ${statusTransitions.blocked}`);
764
643
  }
765
- if (commandsInstalled) {
766
- const cmdPrefix = commandPrefix ? `${commandPrefix}` : "";
767
- console.log(` Claude commands: /${cmdPrefix}work-on, /${cmdPrefix}done-job, /${cmdPrefix}sync-linear`);
768
- }
769
644
  console.log("\nNext steps:");
770
645
  console.log(" 1. Set LINEAR_API_KEY in your shell profile:");
771
646
  console.log(` export LINEAR_API_KEY="${apiKey}"`);
772
647
  console.log(" 2. Run sync: ttt sync");
773
- if (commandsInstalled) {
774
- const cmdPrefix = commandPrefix ? `${commandPrefix}` : "";
775
- console.log(` 3. In Claude Code: /${cmdPrefix}work-on next`);
776
- console.log(`\nšŸ’” Tip: Edit .claude/commands/${cmdPrefix}work-on.md to customize the "Verify" section for your project.`);
777
- }
778
- else {
779
- console.log(" 3. Start working: ttt work-on");
780
- }
648
+ console.log(" 3. Start working: ttt work-on");
781
649
  }
782
650
  init().catch(console.error);
@@ -1,4 +1,4 @@
1
- import type { CompletionMode, Config, LocalConfig, QaPmTeamConfig, StatusTransitions, TeamConfig, UserConfig, LabelConfig } from "../utils.js";
1
+ import type { CompletionMode, Config, LabelConfig, LocalConfig, QaPmTeamConfig, StatusTransitions, TeamConfig, UserConfig } from "../utils.js";
2
2
  export interface LinearTeam {
3
3
  id: string;
4
4
  name: string;
@@ -1,11 +1,19 @@
1
1
  import type { LinearClient } from "@linear/sdk";
2
2
  import { type Config, type LocalConfig, type Task } from "../utils.js";
3
+ export interface FetchIssueOptions {
4
+ client?: LinearClient;
5
+ }
3
6
  export interface SyncIssueOptions {
4
7
  config: Config;
5
8
  localConfig: LocalConfig;
6
9
  client?: LinearClient;
7
10
  preserveLocalStatus?: boolean;
8
11
  }
12
+ /**
13
+ * Fetch issue details from Linear without saving to local data
14
+ * Returns Task object or null if issue not found
15
+ */
16
+ export declare function fetchIssueDetail(issueId: string, options?: FetchIssueOptions): Promise<Task | null>;
9
17
  /**
10
18
  * Sync a single issue from Linear and update local cycle data
11
19
  * Returns the updated task or null if issue not found
@@ -1,17 +1,15 @@
1
- import { getLinearClient, loadCycleData, saveCycleData, getPrioritySortIndex, } from "../utils.js";
1
+ import { getLinearClient, getPrioritySortIndex, loadCycleData, saveCycleData, } from "../utils.js";
2
2
  import { getStatusTransitions } from "./linear.js";
3
3
  /**
4
- * Sync a single issue from Linear and update local cycle data
5
- * Returns the updated task or null if issue not found
4
+ * Fetch issue details from Linear without saving to local data
5
+ * Returns Task object or null if issue not found
6
6
  */
7
- export async function syncSingleIssue(issueId, options) {
8
- const { config, localConfig: _localConfig, preserveLocalStatus = true, } = options;
7
+ export async function fetchIssueDetail(issueId, options = {}) {
9
8
  const client = options.client ?? getLinearClient();
10
9
  // Search for the issue
11
10
  const searchResult = await client.searchIssues(issueId);
12
11
  const matchingIssue = searchResult.nodes.find((i) => i.identifier === issueId);
13
12
  if (!matchingIssue) {
14
- console.error(`Issue ${issueId} not found in Linear.`);
15
13
  return null;
16
14
  }
17
15
  // Fetch full issue data
@@ -41,34 +39,12 @@ export async function syncSingleIssue(issueId, options) {
41
39
  user: user?.displayName ?? user?.email,
42
40
  };
43
41
  }));
44
- // Determine local status
45
- let localStatus = "pending";
46
- const existingData = await loadCycleData();
47
- if (preserveLocalStatus && existingData) {
48
- const existingTask = existingData.tasks.find((t) => t.id === issueId);
49
- if (existingTask) {
50
- localStatus = existingTask.localStatus;
51
- }
52
- }
53
- // Map remote status to local status if not preserving
54
- if (!preserveLocalStatus && state) {
55
- const transitions = getStatusTransitions(config);
56
- if (state.name === transitions.done) {
57
- localStatus = "completed";
58
- }
59
- else if (state.name === transitions.in_progress) {
60
- localStatus = "in-progress";
61
- }
62
- else {
63
- localStatus = "pending";
64
- }
65
- }
66
42
  const task = {
67
43
  id: issue.identifier,
68
44
  linearId: issue.id,
69
45
  title: issue.title,
70
46
  status: state ? state.name : "Unknown",
71
- localStatus: localStatus,
47
+ localStatus: "pending", // Default, will be overridden by sync if needed
72
48
  assignee: assigneeEmail,
73
49
  priority: issue.priority,
74
50
  labels: labelNames,
@@ -79,6 +55,42 @@ export async function syncSingleIssue(issueId, options) {
79
55
  attachments: attachments.length > 0 ? attachments : undefined,
80
56
  comments: comments.length > 0 ? comments : undefined,
81
57
  };
58
+ return task;
59
+ }
60
+ /**
61
+ * Sync a single issue from Linear and update local cycle data
62
+ * Returns the updated task or null if issue not found
63
+ */
64
+ export async function syncSingleIssue(issueId, options) {
65
+ const { config, localConfig: _localConfig, preserveLocalStatus = true, } = options;
66
+ const client = options.client ?? getLinearClient();
67
+ // Fetch issue details using shared function
68
+ const task = await fetchIssueDetail(issueId, { client });
69
+ if (!task) {
70
+ console.error(`Issue ${issueId} not found in Linear.`);
71
+ return null;
72
+ }
73
+ // Determine local status
74
+ const existingData = await loadCycleData();
75
+ if (preserveLocalStatus && existingData) {
76
+ const existingTask = existingData.tasks.find((t) => t.id === issueId);
77
+ if (existingTask) {
78
+ task.localStatus = existingTask.localStatus;
79
+ }
80
+ }
81
+ // Map remote status to local status if not preserving
82
+ if (!preserveLocalStatus) {
83
+ const transitions = getStatusTransitions(config);
84
+ if (task.status === transitions.done) {
85
+ task.localStatus = "completed";
86
+ }
87
+ else if (task.status === transitions.in_progress) {
88
+ task.localStatus = "in-progress";
89
+ }
90
+ else {
91
+ task.localStatus = "pending";
92
+ }
93
+ }
82
94
  // Update cycle data
83
95
  if (existingData) {
84
96
  const existingTasks = existingData.tasks.filter((t) => t.id !== issueId);
@@ -0,0 +1 @@
1
+ export {};