cc-mirror 1.3.0 → 1.4.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.
@@ -39,9 +39,17 @@ var parseArgs = (argv) => {
39
39
  if (value2) opts.env.push(value2);
40
40
  continue;
41
41
  }
42
- const [key, inlineValue] = arg.startsWith("--") ? arg.slice(2).split("=") : [null, null];
42
+ const [key, inlineValue] = arg.startsWith("--") ? arg.slice(2).split("=") : [void 0, void 0];
43
43
  if (!key) continue;
44
- const value = inlineValue ?? args.shift();
44
+ let value;
45
+ if (inlineValue !== void 0) {
46
+ value = inlineValue;
47
+ } else {
48
+ const next = args[0];
49
+ if (next && !next.startsWith("-")) {
50
+ value = args.shift();
51
+ }
52
+ }
45
53
  if (value !== void 0) {
46
54
  opts[key] = value;
47
55
  } else {
@@ -104,6 +112,7 @@ COMMANDS
104
112
  remove <name> Remove a variant
105
113
  doctor Health check all variants
106
114
  tweak <name> Launch tweakcc customization
115
+ tasks [operation] Manage team tasks (list, show, create, update, delete, clean)
107
116
 
108
117
  OPTIONS (create/quick)
109
118
  --name <name> Variant name (becomes CLI command)
@@ -2456,6 +2465,63 @@ var removeOrchestratorSkill = (configDir) => {
2456
2465
  return { status: "failed", message };
2457
2466
  }
2458
2467
  };
2468
+ var TASK_MANAGER_SKILL_NAME = "task-manager";
2469
+ var findBundledTaskManagerSkillDir = () => {
2470
+ const thisFile = fileURLToPath2(import.meta.url);
2471
+ const thisDir = path7.dirname(thisFile);
2472
+ const devPath = path7.join(thisDir, "..", "skills", TASK_MANAGER_SKILL_NAME);
2473
+ if (fs6.existsSync(devPath)) return devPath;
2474
+ const distPath = path7.join(thisDir, "skills", TASK_MANAGER_SKILL_NAME);
2475
+ if (fs6.existsSync(distPath)) return distPath;
2476
+ const distPath2 = path7.join(thisDir, "..", "skills", TASK_MANAGER_SKILL_NAME);
2477
+ if (fs6.existsSync(distPath2)) return distPath2;
2478
+ return null;
2479
+ };
2480
+ var installTaskManagerSkill = (configDir) => {
2481
+ const sourceDir = findBundledTaskManagerSkillDir();
2482
+ if (!sourceDir) {
2483
+ return { status: "failed", message: "bundled task-manager skill not found" };
2484
+ }
2485
+ const skillsDir = path7.join(configDir, "skills");
2486
+ const targetDir = path7.join(skillsDir, TASK_MANAGER_SKILL_NAME);
2487
+ const markerPath = path7.join(targetDir, MANAGED_MARKER);
2488
+ try {
2489
+ ensureDir2(skillsDir);
2490
+ if (fs6.existsSync(targetDir) && !fs6.existsSync(markerPath)) {
2491
+ return { status: "skipped", message: "existing skill is user-managed", path: targetDir };
2492
+ }
2493
+ if (fs6.existsSync(targetDir)) {
2494
+ fs6.rmSync(targetDir, { recursive: true, force: true });
2495
+ }
2496
+ copyDir(sourceDir, targetDir);
2497
+ fs6.writeFileSync(
2498
+ markerPath,
2499
+ JSON.stringify({ managedBy: "cc-mirror", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
2500
+ );
2501
+ return { status: "installed", path: targetDir };
2502
+ } catch (error) {
2503
+ const message = error instanceof Error ? error.message : String(error);
2504
+ return { status: "failed", message };
2505
+ }
2506
+ };
2507
+ var removeTaskManagerSkill = (configDir) => {
2508
+ const skillsDir = path7.join(configDir, "skills");
2509
+ const targetDir = path7.join(skillsDir, TASK_MANAGER_SKILL_NAME);
2510
+ const markerPath = path7.join(targetDir, MANAGED_MARKER);
2511
+ if (!fs6.existsSync(targetDir)) {
2512
+ return { status: "skipped", message: "skill not installed" };
2513
+ }
2514
+ if (!fs6.existsSync(markerPath)) {
2515
+ return { status: "skipped", message: "skill is user-managed, not removing" };
2516
+ }
2517
+ try {
2518
+ fs6.rmSync(targetDir, { recursive: true, force: true });
2519
+ return { status: "removed", path: targetDir };
2520
+ } catch (error) {
2521
+ const message = error instanceof Error ? error.message : String(error);
2522
+ return { status: "failed", message };
2523
+ }
2524
+ };
2459
2525
  var spawnAsync = (cmd, args) => {
2460
2526
  return new Promise((resolve) => {
2461
2527
  const child = spawn3(cmd, args, { stdio: "pipe" });
@@ -2666,6 +2732,12 @@ var TeamModeStep = class {
2666
2732
  } else if (skillResult.status === "failed") {
2667
2733
  state.notes.push(`Warning: orchestrator skill install failed: ${skillResult.message}`);
2668
2734
  }
2735
+ const taskSkillResult = installTaskManagerSkill(paths.configDir);
2736
+ if (taskSkillResult.status === "installed") {
2737
+ state.notes.push("Task manager skill installed");
2738
+ } else if (taskSkillResult.status === "failed") {
2739
+ state.notes.push(`Warning: task-manager skill install failed: ${taskSkillResult.message}`);
2740
+ }
2669
2741
  const systemPromptsDir = path9.join(paths.tweakDir, "system-prompts");
2670
2742
  const copiedFiles = copyTeamPackPrompts(systemPromptsDir);
2671
2743
  if (copiedFiles.length > 0) {
@@ -4111,6 +4183,12 @@ var TeamModeUpdateStep = class {
4111
4183
  } else if (skillResult.status === "failed") {
4112
4184
  state.notes.push(`Warning: orchestrator skill removal failed: ${skillResult.message}`);
4113
4185
  }
4186
+ const taskSkillResult = removeTaskManagerSkill(meta.configDir);
4187
+ if (taskSkillResult.status === "removed") {
4188
+ state.notes.push("Task manager skill removed");
4189
+ } else if (taskSkillResult.status === "failed") {
4190
+ state.notes.push(`Warning: task-manager skill removal failed: ${taskSkillResult.message}`);
4191
+ }
4114
4192
  }
4115
4193
  patchCli(ctx) {
4116
4194
  const { state, meta, paths } = ctx;
@@ -4169,6 +4247,12 @@ var TeamModeUpdateStep = class {
4169
4247
  } else if (skillResult.status === "failed") {
4170
4248
  state.notes.push(`Warning: orchestrator skill install failed: ${skillResult.message}`);
4171
4249
  }
4250
+ const taskSkillResult = installTaskManagerSkill(meta.configDir);
4251
+ if (taskSkillResult.status === "installed") {
4252
+ state.notes.push("Task manager skill installed");
4253
+ } else if (taskSkillResult.status === "failed") {
4254
+ state.notes.push(`Warning: task-manager skill install failed: ${taskSkillResult.message}`);
4255
+ }
4172
4256
  const systemPromptsDir = path18.join(meta.tweakDir, "system-prompts");
4173
4257
  const copiedFiles = copyTeamPackPrompts(systemPromptsDir);
4174
4258
  if (copiedFiles.length > 0) {
@@ -5028,6 +5112,1034 @@ async function runCreateCommand({ opts, quickMode }) {
5028
5112
  }
5029
5113
  }
5030
5114
 
5115
+ // src/core/tasks/store.ts
5116
+ import fs15 from "node:fs";
5117
+ import path25 from "node:path";
5118
+ function getTasksDir(rootDir, variant, team) {
5119
+ return path25.join(rootDir, variant, "config", "tasks", team);
5120
+ }
5121
+ function listTaskIds(tasksDir) {
5122
+ if (!fs15.existsSync(tasksDir)) return [];
5123
+ return fs15.readdirSync(tasksDir).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", "")).sort((a, b) => parseInt(a, 10) - parseInt(b, 10));
5124
+ }
5125
+ function loadTask(tasksDir, id) {
5126
+ const taskPath = path25.join(tasksDir, `${id}.json`);
5127
+ if (!fs15.existsSync(taskPath)) return null;
5128
+ return readJson(taskPath);
5129
+ }
5130
+ function loadAllTasks(tasksDir) {
5131
+ const ids = listTaskIds(tasksDir);
5132
+ return ids.map((id) => loadTask(tasksDir, id)).filter((task) => task !== null);
5133
+ }
5134
+ function saveTask(tasksDir, task) {
5135
+ fs15.mkdirSync(tasksDir, { recursive: true });
5136
+ const taskPath = path25.join(tasksDir, `${task.id}.json`);
5137
+ writeJson(taskPath, task);
5138
+ }
5139
+ function deleteTask(tasksDir, id) {
5140
+ const taskPath = path25.join(tasksDir, `${id}.json`);
5141
+ if (!fs15.existsSync(taskPath)) return false;
5142
+ fs15.unlinkSync(taskPath);
5143
+ return true;
5144
+ }
5145
+ function getNextTaskId(tasksDir) {
5146
+ const ids = listTaskIds(tasksDir);
5147
+ if (ids.length === 0) return "1";
5148
+ const maxId = Math.max(...ids.map((id) => parseInt(id, 10)));
5149
+ return String(maxId + 1);
5150
+ }
5151
+ function createTask(tasksDir, subject, description, opts) {
5152
+ const id = getNextTaskId(tasksDir);
5153
+ const task = {
5154
+ id,
5155
+ subject,
5156
+ description,
5157
+ status: "open",
5158
+ owner: opts?.owner,
5159
+ references: [],
5160
+ blocks: opts?.blocks || [],
5161
+ blockedBy: opts?.blockedBy || [],
5162
+ comments: []
5163
+ };
5164
+ saveTask(tasksDir, task);
5165
+ return task;
5166
+ }
5167
+ function listTeams(rootDir, variant) {
5168
+ const tasksRoot = path25.join(rootDir, variant, "config", "tasks");
5169
+ if (!fs15.existsSync(tasksRoot)) return [];
5170
+ return fs15.readdirSync(tasksRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
5171
+ }
5172
+
5173
+ // src/core/tasks/resolve.ts
5174
+ import fs16 from "node:fs";
5175
+ import path26 from "node:path";
5176
+ import { execSync } from "node:child_process";
5177
+ function detectVariantFromEnv() {
5178
+ const configDir = process.env.CLAUDE_CONFIG_DIR;
5179
+ if (!configDir) return null;
5180
+ const match = configDir.match(/\.cc-mirror\/([^/]+)\/config/);
5181
+ return match ? match[1] : null;
5182
+ }
5183
+ function detectCurrentTeam(cwd) {
5184
+ const teamFromEnv = process.env.CLAUDE_CODE_TEAM_NAME;
5185
+ if (teamFromEnv) {
5186
+ return teamFromEnv;
5187
+ }
5188
+ const workDir = cwd || process.cwd();
5189
+ let gitRoot;
5190
+ try {
5191
+ gitRoot = execSync("git rev-parse --show-toplevel 2>/dev/null", {
5192
+ cwd: workDir,
5193
+ encoding: "utf8"
5194
+ }).trim();
5195
+ } catch {
5196
+ gitRoot = workDir;
5197
+ }
5198
+ const folderName = path26.basename(gitRoot);
5199
+ const teamModifier = process.env.TEAM;
5200
+ if (teamModifier) {
5201
+ return `${folderName}-${teamModifier}`;
5202
+ }
5203
+ return folderName;
5204
+ }
5205
+ function listVariantsWithTasks(rootDir) {
5206
+ const variants = listVariants(rootDir);
5207
+ return variants.map((v) => v.name).filter((name) => {
5208
+ const tasksRoot = path26.join(rootDir, name, "config", "tasks");
5209
+ return fs16.existsSync(tasksRoot);
5210
+ });
5211
+ }
5212
+ function resolveContext(opts) {
5213
+ const { rootDir, variant, team, allVariants, allTeams, cwd } = opts;
5214
+ const locations = [];
5215
+ let variants;
5216
+ if (allVariants) {
5217
+ variants = listVariantsWithTasks(rootDir);
5218
+ } else if (variant) {
5219
+ variants = [variant];
5220
+ } else {
5221
+ const envVariant = detectVariantFromEnv();
5222
+ if (envVariant) {
5223
+ variants = [envVariant];
5224
+ } else {
5225
+ const variantsWithTasks = listVariantsWithTasks(rootDir);
5226
+ variants = variantsWithTasks.length > 0 ? [variantsWithTasks[0]] : [];
5227
+ }
5228
+ }
5229
+ for (const v of variants) {
5230
+ let teams;
5231
+ if (allTeams) {
5232
+ teams = listTeams(rootDir, v);
5233
+ } else if (team) {
5234
+ teams = [team];
5235
+ } else {
5236
+ const detectedTeam = detectCurrentTeam(cwd);
5237
+ const availableTeams = listTeams(rootDir, v);
5238
+ if (availableTeams.includes(detectedTeam)) {
5239
+ teams = [detectedTeam];
5240
+ } else if (availableTeams.length > 0) {
5241
+ teams = availableTeams;
5242
+ } else {
5243
+ teams = [];
5244
+ }
5245
+ }
5246
+ for (const t of teams) {
5247
+ const tasksDir = path26.join(rootDir, v, "config", "tasks", t);
5248
+ if (fs16.existsSync(tasksDir)) {
5249
+ locations.push({ variant: v, team: t, tasksDir });
5250
+ }
5251
+ }
5252
+ }
5253
+ return { locations };
5254
+ }
5255
+
5256
+ // src/core/tasks/queries.ts
5257
+ function isBlocked(task, allTasks) {
5258
+ if (task.blockedBy.length === 0) return false;
5259
+ const taskMap = new Map(allTasks.map((t) => [t.id, t]));
5260
+ return task.blockedBy.some((id) => {
5261
+ const blockingTask = taskMap.get(id);
5262
+ return blockingTask && blockingTask.status === "open";
5263
+ });
5264
+ }
5265
+ function isBlocking(task) {
5266
+ return task.blocks.length > 0;
5267
+ }
5268
+ function filterTasks(tasks, filter, allTasks) {
5269
+ let filtered = [...tasks];
5270
+ const taskContext = allTasks || tasks;
5271
+ if (filter.status && filter.status !== "all") {
5272
+ filtered = filtered.filter((t) => t.status === filter.status);
5273
+ }
5274
+ if (filter.blocked !== void 0) {
5275
+ if (filter.blocked) {
5276
+ filtered = filtered.filter((t) => isBlocked(t, taskContext));
5277
+ } else {
5278
+ filtered = filtered.filter((t) => !isBlocked(t, taskContext));
5279
+ }
5280
+ }
5281
+ if (filter.blocking !== void 0) {
5282
+ if (filter.blocking) {
5283
+ filtered = filtered.filter((t) => isBlocking(t));
5284
+ } else {
5285
+ filtered = filtered.filter((t) => !isBlocking(t));
5286
+ }
5287
+ }
5288
+ if (filter.owner) {
5289
+ filtered = filtered.filter((t) => t.owner === filter.owner);
5290
+ }
5291
+ if (filter.limit && filter.limit > 0) {
5292
+ filtered = filtered.slice(0, filter.limit);
5293
+ }
5294
+ return filtered;
5295
+ }
5296
+ function getTaskSummary(tasks) {
5297
+ const open = tasks.filter((t) => t.status === "open");
5298
+ const resolved = tasks.filter((t) => t.status === "resolved");
5299
+ const blocked = open.filter((t) => isBlocked(t, tasks));
5300
+ return {
5301
+ total: tasks.length,
5302
+ open: open.length,
5303
+ resolved: resolved.length,
5304
+ blocked: blocked.length
5305
+ };
5306
+ }
5307
+ function sortTasksById(tasks) {
5308
+ return [...tasks].sort((a, b) => parseInt(a.id, 10) - parseInt(b.id, 10));
5309
+ }
5310
+
5311
+ // src/cli/commands/tasks/output.ts
5312
+ function truncate(text, maxLen) {
5313
+ if (text.length <= maxLen) return text;
5314
+ return text.slice(0, maxLen - 3) + "...";
5315
+ }
5316
+ function pad(text, width) {
5317
+ return text.padEnd(width);
5318
+ }
5319
+ function formatTaskTable(tasks, location, summary) {
5320
+ const lines = [];
5321
+ const { variant, team } = location;
5322
+ lines.push(`TASKS (${variant} / ${team}) - ${summary.open} open, ${summary.resolved} resolved`);
5323
+ lines.push("\u2500".repeat(70));
5324
+ lines.push(`${pad("ID", 5)} ${pad("STATUS", 10)} ${pad("SUBJECT", 45)} BLOCKED`);
5325
+ lines.push("\u2500".repeat(70));
5326
+ for (const task of tasks) {
5327
+ const blocked = isBlocked(task, tasks) ? "\u25CF" : "";
5328
+ const status = task.status;
5329
+ const subject = truncate(task.subject, 45);
5330
+ lines.push(`${pad(task.id, 5)} ${pad(status, 10)} ${pad(subject, 45)} ${blocked}`);
5331
+ }
5332
+ lines.push("\u2500".repeat(70));
5333
+ if (summary.blocked > 0) {
5334
+ lines.push("\u25CF = blocked by unresolved tasks");
5335
+ }
5336
+ return lines.join("\n");
5337
+ }
5338
+ function formatMultiLocationTaskTable(tasksByLocation) {
5339
+ const sections = [];
5340
+ for (const { location, tasks, summary } of tasksByLocation) {
5341
+ sections.push(formatTaskTable(tasks, location, summary));
5342
+ sections.push("");
5343
+ }
5344
+ return sections.join("\n");
5345
+ }
5346
+ function formatTaskDetail(task, location, allTasks) {
5347
+ const lines = [];
5348
+ const { variant, team } = location;
5349
+ lines.push(`TASK #${task.id} (${variant} / ${team})`);
5350
+ lines.push("\u2550".repeat(60));
5351
+ lines.push("");
5352
+ lines.push(`Subject: ${task.subject}`);
5353
+ lines.push(`Status: ${task.status}`);
5354
+ lines.push(`Owner: ${task.owner || "(unassigned)"}`);
5355
+ lines.push("");
5356
+ if (task.description) {
5357
+ lines.push("Description:");
5358
+ const descLines = task.description.split("\n");
5359
+ for (const line of descLines.slice(0, 10)) {
5360
+ lines.push(` ${line}`);
5361
+ }
5362
+ if (descLines.length > 10) {
5363
+ lines.push(` ... (${descLines.length - 10} more lines)`);
5364
+ }
5365
+ lines.push("");
5366
+ }
5367
+ if (task.blockedBy.length > 0 || task.blocks.length > 0) {
5368
+ lines.push("Dependencies:");
5369
+ if (task.blockedBy.length > 0) {
5370
+ const blockedByStatus = task.blockedBy.map((id) => {
5371
+ const t = allTasks.find((t2) => t2.id === id);
5372
+ return t ? `#${id} (${t.status})` : `#${id} (?)`;
5373
+ });
5374
+ lines.push(` Blocked by: ${blockedByStatus.join(", ")}`);
5375
+ }
5376
+ if (task.blocks.length > 0) {
5377
+ lines.push(` Blocks: ${task.blocks.map((id) => `#${id}`).join(", ")}`);
5378
+ }
5379
+ lines.push("");
5380
+ }
5381
+ if (task.references.length > 0) {
5382
+ lines.push(`References: ${task.references.map((id) => `#${id}`).join(", ")}`);
5383
+ lines.push("");
5384
+ }
5385
+ if (task.comments.length > 0) {
5386
+ lines.push(`Comments (${task.comments.length}):`);
5387
+ for (const comment of task.comments) {
5388
+ lines.push(` \u250C\u2500 ${comment.author} ${"\u2500".repeat(Math.max(0, 50 - comment.author.length))}`);
5389
+ const commentLines = comment.content.split("\n");
5390
+ for (const line of commentLines) {
5391
+ lines.push(` \u2502 ${line}`);
5392
+ }
5393
+ lines.push(" \u2514" + "\u2500".repeat(55));
5394
+ }
5395
+ }
5396
+ return lines.join("\n");
5397
+ }
5398
+ function formatTasksJson(tasks, location, summary) {
5399
+ return JSON.stringify(
5400
+ {
5401
+ variant: location.variant,
5402
+ team: location.team,
5403
+ tasks,
5404
+ summary
5405
+ },
5406
+ null,
5407
+ 2
5408
+ );
5409
+ }
5410
+ function formatTaskJson(task, location) {
5411
+ return JSON.stringify(
5412
+ {
5413
+ variant: location.variant,
5414
+ team: location.team,
5415
+ task
5416
+ },
5417
+ null,
5418
+ 2
5419
+ );
5420
+ }
5421
+ function formatMultiLocationJson(tasksByLocation) {
5422
+ return JSON.stringify(
5423
+ {
5424
+ locations: tasksByLocation.map(({ location, tasks, summary }) => ({
5425
+ variant: location.variant,
5426
+ team: location.team,
5427
+ tasks,
5428
+ summary
5429
+ }))
5430
+ },
5431
+ null,
5432
+ 2
5433
+ );
5434
+ }
5435
+ function formatCleanResults(results) {
5436
+ const lines = [];
5437
+ for (const { location, deleted, dryRun } of results) {
5438
+ const action = dryRun ? "Would delete" : "Deleted";
5439
+ lines.push(`${location.variant} / ${location.team}: ${action} ${deleted.length} tasks`);
5440
+ if (deleted.length > 0 && deleted.length <= 10) {
5441
+ lines.push(` IDs: ${deleted.join(", ")}`);
5442
+ }
5443
+ }
5444
+ return lines.join("\n");
5445
+ }
5446
+
5447
+ // src/cli/commands/tasks/list.ts
5448
+ function runTasksList(opts) {
5449
+ const context = resolveContext({
5450
+ rootDir: opts.rootDir,
5451
+ variant: opts.variant,
5452
+ team: opts.team,
5453
+ allVariants: opts.allVariants,
5454
+ allTeams: opts.allTeams
5455
+ });
5456
+ if (context.locations.length === 0) {
5457
+ console.log("No task locations found. Check variant and team settings.");
5458
+ return;
5459
+ }
5460
+ const tasksByLocation = context.locations.map((location) => {
5461
+ const allTasks = loadAllTasks(location.tasksDir);
5462
+ const filteredTasks = filterTasks(
5463
+ allTasks,
5464
+ {
5465
+ status: opts.status || "open",
5466
+ blocked: opts.blocked,
5467
+ blocking: opts.blocking,
5468
+ owner: opts.owner,
5469
+ limit: opts.limit
5470
+ },
5471
+ allTasks
5472
+ );
5473
+ const sortedTasks = sortTasksById(filteredTasks);
5474
+ const summary = getTaskSummary(allTasks);
5475
+ return { location, tasks: sortedTasks, summary };
5476
+ });
5477
+ if (opts.json) {
5478
+ if (tasksByLocation.length === 1) {
5479
+ const { location, tasks, summary } = tasksByLocation[0];
5480
+ console.log(formatTasksJson(tasks, location, summary));
5481
+ } else {
5482
+ console.log(formatMultiLocationJson(tasksByLocation));
5483
+ }
5484
+ } else {
5485
+ if (tasksByLocation.length === 1) {
5486
+ const { location, tasks, summary } = tasksByLocation[0];
5487
+ console.log(formatTaskTable(tasks, location, summary));
5488
+ } else {
5489
+ console.log(formatMultiLocationTaskTable(tasksByLocation));
5490
+ }
5491
+ }
5492
+ }
5493
+
5494
+ // src/cli/commands/tasks/show.ts
5495
+ function runTasksShow(opts) {
5496
+ const context = resolveContext({
5497
+ rootDir: opts.rootDir,
5498
+ variant: opts.variant,
5499
+ team: opts.team
5500
+ });
5501
+ if (context.locations.length === 0) {
5502
+ console.error("No task locations found. Check variant and team settings.");
5503
+ process.exitCode = 1;
5504
+ return;
5505
+ }
5506
+ for (const location of context.locations) {
5507
+ const task = loadTask(location.tasksDir, opts.taskId);
5508
+ if (task) {
5509
+ const allTasks = loadAllTasks(location.tasksDir);
5510
+ if (opts.json) {
5511
+ console.log(formatTaskJson(task, location));
5512
+ } else {
5513
+ console.log(formatTaskDetail(task, location, allTasks));
5514
+ }
5515
+ return;
5516
+ }
5517
+ }
5518
+ console.error(`Task #${opts.taskId} not found.`);
5519
+ process.exitCode = 1;
5520
+ }
5521
+
5522
+ // src/cli/commands/tasks/create.ts
5523
+ function runTasksCreate(opts) {
5524
+ const context = resolveContext({
5525
+ rootDir: opts.rootDir,
5526
+ variant: opts.variant,
5527
+ team: opts.team
5528
+ });
5529
+ let location = context.locations[0];
5530
+ if (!location) {
5531
+ const team = opts.team || detectCurrentTeam();
5532
+ const variant = opts.variant;
5533
+ if (!variant) {
5534
+ console.error("No variant specified. Use --variant to specify a variant.");
5535
+ process.exitCode = 1;
5536
+ return;
5537
+ }
5538
+ const tasksDir = getTasksDir(opts.rootDir, variant, team);
5539
+ location = { variant, team, tasksDir };
5540
+ }
5541
+ const task = createTask(location.tasksDir, opts.subject, opts.description || "", {
5542
+ owner: opts.owner,
5543
+ blocks: opts.blocks,
5544
+ blockedBy: opts.blockedBy
5545
+ });
5546
+ if (opts.json) {
5547
+ console.log(formatTaskJson(task, location));
5548
+ } else {
5549
+ console.log(`Created task #${task.id}: ${task.subject}`);
5550
+ console.log(`Location: ${location.variant} / ${location.team}`);
5551
+ }
5552
+ }
5553
+
5554
+ // src/cli/commands/tasks/update.ts
5555
+ function runTasksUpdate(opts) {
5556
+ const context = resolveContext({
5557
+ rootDir: opts.rootDir,
5558
+ variant: opts.variant,
5559
+ team: opts.team
5560
+ });
5561
+ if (context.locations.length === 0) {
5562
+ console.error("No task locations found. Check variant and team settings.");
5563
+ process.exitCode = 1;
5564
+ return;
5565
+ }
5566
+ for (const location of context.locations) {
5567
+ const task = loadTask(location.tasksDir, opts.taskId);
5568
+ if (!task) continue;
5569
+ if (opts.subject) task.subject = opts.subject;
5570
+ if (opts.description) task.description = opts.description;
5571
+ if (opts.status) task.status = opts.status;
5572
+ if (opts.owner !== void 0) task.owner = opts.owner || void 0;
5573
+ if (opts.addBlocks) {
5574
+ for (const id of opts.addBlocks) {
5575
+ if (!task.blocks.includes(id)) task.blocks.push(id);
5576
+ }
5577
+ }
5578
+ if (opts.removeBlocks) {
5579
+ task.blocks = task.blocks.filter((id) => !opts.removeBlocks.includes(id));
5580
+ }
5581
+ if (opts.addBlockedBy) {
5582
+ for (const id of opts.addBlockedBy) {
5583
+ if (!task.blockedBy.includes(id)) task.blockedBy.push(id);
5584
+ }
5585
+ }
5586
+ if (opts.removeBlockedBy) {
5587
+ task.blockedBy = task.blockedBy.filter((id) => !opts.removeBlockedBy.includes(id));
5588
+ }
5589
+ if (opts.addComment) {
5590
+ task.comments.push({
5591
+ author: opts.commentAuthor || "cli",
5592
+ content: opts.addComment
5593
+ });
5594
+ }
5595
+ saveTask(location.tasksDir, task);
5596
+ if (opts.json) {
5597
+ console.log(formatTaskJson(task, location));
5598
+ } else {
5599
+ console.log(`Updated task #${task.id}: ${task.subject}`);
5600
+ }
5601
+ return;
5602
+ }
5603
+ console.error(`Task #${opts.taskId} not found.`);
5604
+ process.exitCode = 1;
5605
+ }
5606
+
5607
+ // src/cli/commands/tasks/delete.ts
5608
+ import * as readline2 from "node:readline";
5609
+ async function confirm(prompt2) {
5610
+ const rl = readline2.createInterface({
5611
+ input: process.stdin,
5612
+ output: process.stdout
5613
+ });
5614
+ return new Promise((resolve) => {
5615
+ rl.question(prompt2, (answer) => {
5616
+ rl.close();
5617
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
5618
+ });
5619
+ });
5620
+ }
5621
+ async function runTasksDelete(opts) {
5622
+ const context = resolveContext({
5623
+ rootDir: opts.rootDir,
5624
+ variant: opts.variant,
5625
+ team: opts.team
5626
+ });
5627
+ if (context.locations.length === 0) {
5628
+ console.error("No task locations found. Check variant and team settings.");
5629
+ process.exitCode = 1;
5630
+ return;
5631
+ }
5632
+ for (const location of context.locations) {
5633
+ const task = loadTask(location.tasksDir, opts.taskId);
5634
+ if (!task) continue;
5635
+ if (!opts.force) {
5636
+ const confirmed = await confirm(`Delete task #${task.id} "${task.subject}"? [y/N] `);
5637
+ if (!confirmed) {
5638
+ console.log("Cancelled.");
5639
+ return;
5640
+ }
5641
+ }
5642
+ const deleted = deleteTask(location.tasksDir, opts.taskId);
5643
+ if (deleted) {
5644
+ if (opts.json) {
5645
+ console.log(JSON.stringify({ deleted: true, taskId: opts.taskId }));
5646
+ } else {
5647
+ console.log(`Deleted task #${opts.taskId}`);
5648
+ }
5649
+ } else {
5650
+ console.error(`Failed to delete task #${opts.taskId}`);
5651
+ process.exitCode = 1;
5652
+ }
5653
+ return;
5654
+ }
5655
+ console.error(`Task #${opts.taskId} not found.`);
5656
+ process.exitCode = 1;
5657
+ }
5658
+
5659
+ // src/cli/commands/tasks/clean.ts
5660
+ import fs17 from "node:fs";
5661
+ import path27 from "node:path";
5662
+ import * as readline3 from "node:readline";
5663
+ async function confirm2(prompt2) {
5664
+ const rl = readline3.createInterface({
5665
+ input: process.stdin,
5666
+ output: process.stdout
5667
+ });
5668
+ return new Promise((resolve) => {
5669
+ rl.question(prompt2, (answer) => {
5670
+ rl.close();
5671
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
5672
+ });
5673
+ });
5674
+ }
5675
+ function getTaskAge(tasksDir, taskId) {
5676
+ const taskPath = path27.join(tasksDir, `${taskId}.json`);
5677
+ try {
5678
+ const stats = fs17.statSync(taskPath);
5679
+ const now = Date.now();
5680
+ const mtime = stats.mtime.getTime();
5681
+ return Math.floor((now - mtime) / (1e3 * 60 * 60 * 24));
5682
+ } catch {
5683
+ return null;
5684
+ }
5685
+ }
5686
+ function filterTasksForClean(tasks, tasksDir, opts) {
5687
+ let candidates = [...tasks];
5688
+ if (opts.resolved) {
5689
+ candidates = candidates.filter((t) => t.status === "resolved");
5690
+ }
5691
+ if (opts.olderThan !== void 0) {
5692
+ candidates = candidates.filter((t) => {
5693
+ const age = getTaskAge(tasksDir, t.id);
5694
+ return age !== null && age >= opts.olderThan;
5695
+ });
5696
+ }
5697
+ return candidates;
5698
+ }
5699
+ async function runTasksClean(opts) {
5700
+ const context = resolveContext({
5701
+ rootDir: opts.rootDir,
5702
+ variant: opts.variant,
5703
+ team: opts.team,
5704
+ allVariants: opts.allVariants,
5705
+ allTeams: opts.allTeams
5706
+ });
5707
+ if (context.locations.length === 0) {
5708
+ console.log("No task locations found. Check variant and team settings.");
5709
+ return;
5710
+ }
5711
+ if (!opts.resolved && opts.olderThan === void 0) {
5712
+ console.error("Error: Specify at least one filter (--resolved or --older-than).");
5713
+ process.exitCode = 1;
5714
+ return;
5715
+ }
5716
+ const results = [];
5717
+ let totalToDelete = 0;
5718
+ for (const location of context.locations) {
5719
+ const tasks = loadAllTasks(location.tasksDir);
5720
+ const toDelete = filterTasksForClean(tasks, location.tasksDir, opts);
5721
+ totalToDelete += toDelete.length;
5722
+ results.push({
5723
+ location,
5724
+ deleted: toDelete.map((t) => t.id),
5725
+ dryRun: opts.dryRun || false
5726
+ });
5727
+ }
5728
+ if (totalToDelete === 0) {
5729
+ console.log("No tasks match the cleanup criteria.");
5730
+ return;
5731
+ }
5732
+ console.log(formatCleanResults(results));
5733
+ if (opts.dryRun) {
5734
+ console.log(`
5735
+ Dry run: ${totalToDelete} tasks would be deleted.`);
5736
+ return;
5737
+ }
5738
+ if (!opts.force) {
5739
+ const confirmed = await confirm2(`
5740
+ Delete ${totalToDelete} tasks? [y/N] `);
5741
+ if (!confirmed) {
5742
+ console.log("Cancelled.");
5743
+ return;
5744
+ }
5745
+ }
5746
+ let deletedCount = 0;
5747
+ for (const result of results) {
5748
+ for (const taskId of result.deleted) {
5749
+ if (deleteTask(result.location.tasksDir, taskId)) {
5750
+ deletedCount++;
5751
+ }
5752
+ }
5753
+ }
5754
+ if (opts.json) {
5755
+ console.log(
5756
+ JSON.stringify({
5757
+ deleted: deletedCount,
5758
+ locations: results.map((r) => ({
5759
+ variant: r.location.variant,
5760
+ team: r.location.team,
5761
+ taskIds: r.deleted
5762
+ }))
5763
+ })
5764
+ );
5765
+ } else {
5766
+ console.log(`
5767
+ Deleted ${deletedCount} tasks.`);
5768
+ }
5769
+ }
5770
+
5771
+ // src/cli/commands/tasks/graph.ts
5772
+ function buildDependencyLine(task, allTasks, depth, visited) {
5773
+ const lines = [];
5774
+ const indent = " ".repeat(depth);
5775
+ const prefix = depth === 0 ? "" : "\u2514\u2500 ";
5776
+ if (visited.has(task.id)) {
5777
+ lines.push(`${indent}${prefix}#${task.id} (circular ref)`);
5778
+ return lines;
5779
+ }
5780
+ visited.add(task.id);
5781
+ const statusIcon = task.status === "resolved" ? "\u2713" : isBlocked(task, allTasks) ? "\u25CF" : "\u25CB";
5782
+ lines.push(`${indent}${prefix}[${statusIcon}] #${task.id}: ${task.subject.slice(0, 50)}`);
5783
+ const blockedTasks = allTasks.filter((t) => t.blockedBy.includes(task.id));
5784
+ for (const blocked of blockedTasks) {
5785
+ lines.push(...buildDependencyLine(blocked, allTasks, depth + 1, new Set(visited)));
5786
+ }
5787
+ return lines;
5788
+ }
5789
+ function formatTaskGraph(tasks, variant, team) {
5790
+ const lines = [];
5791
+ lines.push(`TASK DEPENDENCY GRAPH (${variant} / ${team})`);
5792
+ lines.push("\u2550".repeat(60));
5793
+ lines.push("");
5794
+ lines.push("Legend: [\u2713] resolved [\u25CB] open [\u25CF] blocked");
5795
+ lines.push("");
5796
+ const roots = tasks.filter((t) => t.blockedBy.length === 0);
5797
+ const visited = /* @__PURE__ */ new Set();
5798
+ for (const root of roots) {
5799
+ if (!visited.has(root.id)) {
5800
+ const treeLines = buildDependencyLine(root, tasks, 0, /* @__PURE__ */ new Set());
5801
+ lines.push(...treeLines);
5802
+ lines.push("");
5803
+ for (const line of treeLines) {
5804
+ const match = line.match(/#(\d+)/);
5805
+ if (match) visited.add(match[1]);
5806
+ }
5807
+ }
5808
+ }
5809
+ const orphans = tasks.filter((t) => !visited.has(t.id) && t.blockedBy.length > 0);
5810
+ if (orphans.length > 0) {
5811
+ lines.push("\u2500".repeat(40));
5812
+ lines.push("Orphan tasks (blockedBy non-existent tasks):");
5813
+ for (const task of orphans) {
5814
+ const statusIcon = task.status === "resolved" ? "\u2713" : "\u25CB";
5815
+ lines.push(` [${statusIcon}] #${task.id}: ${task.subject.slice(0, 50)}`);
5816
+ lines.push(` blockedBy: ${task.blockedBy.join(", ")}`);
5817
+ }
5818
+ }
5819
+ lines.push("");
5820
+ lines.push("\u2500".repeat(60));
5821
+ const open = tasks.filter((t) => t.status === "open");
5822
+ const blocked = open.filter((t) => isBlocked(t, tasks));
5823
+ const ready = open.filter((t) => !isBlocked(t, tasks));
5824
+ lines.push(`Total: ${tasks.length} | Open: ${open.length} | Ready: ${ready.length} | Blocked: ${blocked.length}`);
5825
+ return lines.join("\n");
5826
+ }
5827
+ function runTasksGraph(opts) {
5828
+ const context = resolveContext({
5829
+ rootDir: opts.rootDir,
5830
+ variant: opts.variant,
5831
+ team: opts.team
5832
+ });
5833
+ if (context.locations.length === 0) {
5834
+ console.log("No task locations found. Check variant and team settings.");
5835
+ return;
5836
+ }
5837
+ const location = context.locations[0];
5838
+ const tasks = loadAllTasks(location.tasksDir);
5839
+ if (tasks.length === 0) {
5840
+ console.log(`No tasks found in ${location.variant} / ${location.team}`);
5841
+ return;
5842
+ }
5843
+ console.log(formatTaskGraph(tasks, location.variant, location.team));
5844
+ }
5845
+
5846
+ // src/cli/commands/tasks/archive.ts
5847
+ import fs18 from "node:fs";
5848
+ import path28 from "node:path";
5849
+ function getArchiveDir(tasksDir) {
5850
+ return path28.join(path28.dirname(tasksDir), "archive", path28.basename(tasksDir));
5851
+ }
5852
+ function archiveTask(tasksDir, task) {
5853
+ const archiveDir = getArchiveDir(tasksDir);
5854
+ fs18.mkdirSync(archiveDir, { recursive: true });
5855
+ const archivedTask = {
5856
+ ...task,
5857
+ archivedAt: (/* @__PURE__ */ new Date()).toISOString()
5858
+ };
5859
+ const archivePath = path28.join(archiveDir, `${task.id}.json`);
5860
+ writeJson(archivePath, archivedTask);
5861
+ return deleteTask(tasksDir, task.id);
5862
+ }
5863
+ async function runTasksArchive(opts) {
5864
+ const context = resolveContext({
5865
+ rootDir: opts.rootDir,
5866
+ variant: opts.variant,
5867
+ team: opts.team
5868
+ });
5869
+ if (context.locations.length === 0) {
5870
+ console.error("No task locations found. Check variant and team settings.");
5871
+ process.exitCode = 1;
5872
+ return;
5873
+ }
5874
+ const location = context.locations[0];
5875
+ if (opts.taskId) {
5876
+ const task = loadTask(location.tasksDir, opts.taskId);
5877
+ if (!task) {
5878
+ console.error(`Task #${opts.taskId} not found.`);
5879
+ process.exitCode = 1;
5880
+ return;
5881
+ }
5882
+ if (opts.dryRun) {
5883
+ console.log(`Would archive task #${task.id}: ${task.subject}`);
5884
+ return;
5885
+ }
5886
+ if (archiveTask(location.tasksDir, task)) {
5887
+ if (opts.json) {
5888
+ console.log(JSON.stringify({ archived: [task.id] }));
5889
+ } else {
5890
+ console.log(`Archived task #${task.id}: ${task.subject}`);
5891
+ }
5892
+ }
5893
+ return;
5894
+ }
5895
+ if (opts.resolved) {
5896
+ const tasks = loadAllTasks(location.tasksDir);
5897
+ const resolvedTasks = tasks.filter((t) => t.status === "resolved");
5898
+ if (resolvedTasks.length === 0) {
5899
+ console.log("No resolved tasks to archive.");
5900
+ return;
5901
+ }
5902
+ if (opts.dryRun) {
5903
+ console.log(`Would archive ${resolvedTasks.length} resolved tasks:`);
5904
+ for (const task of resolvedTasks.slice(0, 10)) {
5905
+ console.log(` #${task.id}: ${task.subject.slice(0, 50)}`);
5906
+ }
5907
+ if (resolvedTasks.length > 10) {
5908
+ console.log(` ... and ${resolvedTasks.length - 10} more`);
5909
+ }
5910
+ return;
5911
+ }
5912
+ const archived = [];
5913
+ for (const task of resolvedTasks) {
5914
+ if (archiveTask(location.tasksDir, task)) {
5915
+ archived.push(task.id);
5916
+ }
5917
+ }
5918
+ if (opts.json) {
5919
+ console.log(JSON.stringify({ archived }));
5920
+ } else {
5921
+ console.log(`Archived ${archived.length} tasks to:`);
5922
+ console.log(` ${getArchiveDir(location.tasksDir)}`);
5923
+ }
5924
+ return;
5925
+ }
5926
+ console.error("Specify --resolved to archive all resolved tasks, or provide a task ID.");
5927
+ process.exitCode = 1;
5928
+ }
5929
+
5930
+ // src/cli/commands/tasks.ts
5931
+ function parseIds(value) {
5932
+ if (!value) return void 0;
5933
+ return value.split(",").map((s) => s.trim());
5934
+ }
5935
+ function showTasksHelp() {
5936
+ console.log(`
5937
+ cc-mirror tasks - Manage team tasks
5938
+
5939
+ USAGE:
5940
+ cc-mirror tasks [operation] [id] [options]
5941
+
5942
+ OPERATIONS:
5943
+ list List tasks (default if no operation specified)
5944
+ show <id> Show detailed task info
5945
+ create Create a new task
5946
+ update <id> Update an existing task
5947
+ delete <id> Delete a task (permanent)
5948
+ archive [id] Move task(s) to archive (preserves history)
5949
+ clean Bulk delete tasks (permanent)
5950
+ graph Show task dependency graph
5951
+
5952
+ GLOBAL OPTIONS:
5953
+ --variant <name> Target variant (auto-detects if omitted)
5954
+ --all-variants Show tasks across all variants
5955
+ --team <name> Target team name
5956
+ --all Show all teams in variant(s)
5957
+ --json Output as JSON
5958
+ --help Show this help
5959
+
5960
+ LIST OPTIONS:
5961
+ --status <s> Filter: open, resolved, all (default: open)
5962
+ --blocked Show only blocked tasks
5963
+ --blocking Show only tasks blocking others
5964
+ --owner <id> Filter by owner
5965
+ --limit <n> Limit results (default: 50)
5966
+
5967
+ CREATE OPTIONS:
5968
+ --subject <text> Task subject (required)
5969
+ --description <t> Task description
5970
+ --owner <id> Assign owner
5971
+ --blocks <ids> Comma-separated task IDs this task blocks
5972
+ --blocked-by <ids> Comma-separated task IDs that block this task
5973
+
5974
+ UPDATE OPTIONS:
5975
+ --subject <text> Update subject
5976
+ --description <t> Update description
5977
+ --status <s> Set status: open or resolved
5978
+ --owner <id> Set owner (empty string to unassign)
5979
+ --add-blocks <ids> Add blocking relationships
5980
+ --remove-blocks <ids> Remove blocking relationships
5981
+ --add-blocked-by <ids> Add blocked-by relationships
5982
+ --remove-blocked-by <ids> Remove blocked-by relationships
5983
+ --add-comment <text> Add a comment
5984
+ --comment-author <id> Comment author (default: cli)
5985
+
5986
+ CLEAN OPTIONS:
5987
+ --resolved Delete all resolved tasks
5988
+ --older-than <n> Delete tasks older than N days
5989
+ --dry-run Preview without deleting
5990
+ --force Skip confirmation
5991
+
5992
+ EXAMPLES:
5993
+ cc-mirror tasks # List open tasks
5994
+ cc-mirror tasks --status all # List all tasks
5995
+ cc-mirror tasks show 5 # Show task #5
5996
+ cc-mirror tasks create --subject "Fix bug" --description "..."
5997
+ cc-mirror tasks update 5 --status resolved
5998
+ cc-mirror tasks delete 5 --force
5999
+ cc-mirror tasks clean --resolved --dry-run
6000
+ `);
6001
+ }
6002
+ async function runTasksCommand({ opts }) {
6003
+ const rootDir = opts.root || DEFAULT_ROOT;
6004
+ const positional = opts._ || [];
6005
+ if (opts.help || opts.h) {
6006
+ showTasksHelp();
6007
+ return;
6008
+ }
6009
+ const operation = positional[0];
6010
+ const taskId = positional[1];
6011
+ const variant = opts.variant;
6012
+ const team = opts.team;
6013
+ const allVariants = Boolean(opts["all-variants"]);
6014
+ const allTeams = Boolean(opts.all);
6015
+ const json = Boolean(opts.json);
6016
+ switch (operation) {
6017
+ case "show": {
6018
+ if (!taskId) {
6019
+ console.error("Error: Task ID required. Usage: cc-mirror tasks show <id>");
6020
+ process.exitCode = 1;
6021
+ return;
6022
+ }
6023
+ runTasksShow({ rootDir, taskId, variant, team, json });
6024
+ break;
6025
+ }
6026
+ case "create": {
6027
+ const subject = opts.subject;
6028
+ if (!subject) {
6029
+ console.error("Error: --subject required for create.");
6030
+ process.exitCode = 1;
6031
+ return;
6032
+ }
6033
+ runTasksCreate({
6034
+ rootDir,
6035
+ subject,
6036
+ description: opts.description,
6037
+ variant,
6038
+ team,
6039
+ owner: opts.owner,
6040
+ blocks: parseIds(opts.blocks),
6041
+ blockedBy: parseIds(opts["blocked-by"]),
6042
+ json
6043
+ });
6044
+ break;
6045
+ }
6046
+ case "update": {
6047
+ if (!taskId) {
6048
+ console.error("Error: Task ID required. Usage: cc-mirror tasks update <id>");
6049
+ process.exitCode = 1;
6050
+ return;
6051
+ }
6052
+ runTasksUpdate({
6053
+ rootDir,
6054
+ taskId,
6055
+ variant,
6056
+ team,
6057
+ subject: opts.subject,
6058
+ description: opts.description,
6059
+ status: opts.status,
6060
+ owner: opts.owner,
6061
+ addBlocks: parseIds(opts["add-blocks"]),
6062
+ removeBlocks: parseIds(opts["remove-blocks"]),
6063
+ addBlockedBy: parseIds(opts["add-blocked-by"]),
6064
+ removeBlockedBy: parseIds(opts["remove-blocked-by"]),
6065
+ addComment: opts["add-comment"],
6066
+ commentAuthor: opts["comment-author"],
6067
+ json
6068
+ });
6069
+ break;
6070
+ }
6071
+ case "delete": {
6072
+ if (!taskId) {
6073
+ console.error("Error: Task ID required. Usage: cc-mirror tasks delete <id>");
6074
+ process.exitCode = 1;
6075
+ return;
6076
+ }
6077
+ await runTasksDelete({
6078
+ rootDir,
6079
+ taskId,
6080
+ variant,
6081
+ team,
6082
+ force: Boolean(opts.force),
6083
+ json
6084
+ });
6085
+ break;
6086
+ }
6087
+ case "clean": {
6088
+ await runTasksClean({
6089
+ rootDir,
6090
+ variant,
6091
+ team,
6092
+ allVariants,
6093
+ allTeams,
6094
+ resolved: Boolean(opts.resolved),
6095
+ olderThan: opts["older-than"] !== void 0 ? Number(opts["older-than"]) : void 0,
6096
+ dryRun: Boolean(opts["dry-run"]),
6097
+ force: Boolean(opts.force),
6098
+ json
6099
+ });
6100
+ break;
6101
+ }
6102
+ case "graph": {
6103
+ runTasksGraph({ rootDir, variant, team });
6104
+ break;
6105
+ }
6106
+ case "archive": {
6107
+ await runTasksArchive({
6108
+ rootDir,
6109
+ variant,
6110
+ team,
6111
+ taskId,
6112
+ resolved: Boolean(opts.resolved),
6113
+ dryRun: Boolean(opts["dry-run"]),
6114
+ force: Boolean(opts.force),
6115
+ json
6116
+ });
6117
+ break;
6118
+ }
6119
+ case "list":
6120
+ case void 0: {
6121
+ runTasksList({
6122
+ rootDir,
6123
+ variant,
6124
+ team,
6125
+ allVariants,
6126
+ allTeams,
6127
+ status: opts.status || "open",
6128
+ blocked: opts.blocked !== void 0 ? Boolean(opts.blocked) : void 0,
6129
+ blocking: opts.blocking !== void 0 ? Boolean(opts.blocking) : void 0,
6130
+ owner: opts.owner,
6131
+ limit: opts.limit !== void 0 ? Number(opts.limit) : 50,
6132
+ json
6133
+ });
6134
+ break;
6135
+ }
6136
+ default:
6137
+ console.error(`Unknown operation: ${operation}`);
6138
+ console.error('Run "cc-mirror tasks --help" for usage.');
6139
+ process.exitCode = 1;
6140
+ }
6141
+ }
6142
+
5031
6143
  // src/cli/index.ts
5032
6144
  var main = async () => {
5033
6145
  const argv = process.argv.slice(2);
@@ -5039,7 +6151,8 @@ var main = async () => {
5039
6151
  const opts = parseArgs(argv);
5040
6152
  const quickMode = cmd === "quick" || Boolean(opts.quick || opts.simple);
5041
6153
  if (cmd === "quick") cmd = "create";
5042
- if (cmd === "help" || cmd === "--help" || opts.help) {
6154
+ const commandsWithOwnHelp = ["tasks"];
6155
+ if (cmd === "help" || cmd === "--help" || opts.help && !commandsWithOwnHelp.includes(cmd)) {
5043
6156
  printHelp();
5044
6157
  return;
5045
6158
  }
@@ -5070,6 +6183,9 @@ var main = async () => {
5070
6183
  case "create":
5071
6184
  await runCreateCommand({ opts, quickMode });
5072
6185
  break;
6186
+ case "tasks":
6187
+ await runTasksCommand({ opts });
6188
+ break;
5073
6189
  default:
5074
6190
  printHelp();
5075
6191
  }