taskin 4.1.4 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +282 -155
  3. package/package.json +7 -7
package/README.md CHANGED
@@ -87,6 +87,7 @@ Taskin is built as a modular ecosystem. Besides the CLI, you can use individual
87
87
  2. **List all tasks:**
88
88
  \`\`\`bash
89
89
  taskin list
90
+ taskin list --json # JSON array, for another tool to consume
90
91
  \`\`\`
91
92
 
92
93
  3. **Start working on a task:**
package/dist/index.js CHANGED
@@ -3456,6 +3456,51 @@ init_esm_shims();
3456
3456
  // ../task-manager/src/index.ts
3457
3457
  init_esm_shims();
3458
3458
 
3459
+ // ../task-manager/src/filter-tasks/index.ts
3460
+ init_esm_shims();
3461
+
3462
+ // ../task-manager/src/filter-tasks/filter-tasks.ts
3463
+ init_esm_shims();
3464
+ var EM_ABERTO = ["pending", "in-progress", "paused", "in-review", "blocked"];
3465
+ var ENCERRADOS = ["done", "canceled"];
3466
+ var contem = (valor, procurado) => valor !== void 0 && valor.toLowerCase().includes(procurado);
3467
+ function casaResponsavel(task, procurado) {
3468
+ const alvo = procurado.toLowerCase();
3469
+ return contem(task.assignee?.id, alvo) || contem(task.assignee?.name, alvo);
3470
+ }
3471
+ function filterTasks(tasks, criteria) {
3472
+ return tasks.filter((task) => {
3473
+ if (criteria.status !== void 0) {
3474
+ if (task.status !== criteria.status) return false;
3475
+ } else if (criteria.open && !EM_ABERTO.includes(task.status)) {
3476
+ return false;
3477
+ } else if (criteria.closed && !ENCERRADOS.includes(task.status)) {
3478
+ return false;
3479
+ }
3480
+ if (criteria.type !== void 0 && task.type !== criteria.type) return false;
3481
+ if (criteria.assignee !== void 0 && !casaResponsavel(task, criteria.assignee)) return false;
3482
+ if (criteria.text !== void 0) {
3483
+ const procurado = criteria.text.toLowerCase();
3484
+ const casa = task.id.toLowerCase().includes(procurado) || contem(task.title, procurado) || contem(task.status, procurado) || casaResponsavel(task, procurado);
3485
+ if (!casa) return false;
3486
+ }
3487
+ return true;
3488
+ });
3489
+ }
3490
+ function summarizeTask(task) {
3491
+ return {
3492
+ id: task.id,
3493
+ title: task.title,
3494
+ status: task.status,
3495
+ type: task.type,
3496
+ ...task.assignee && { assignee: { id: task.assignee.id, name: task.assignee.name } },
3497
+ ...task.order !== void 0 && { priority: task.order },
3498
+ ...task.groupId && { groupId: task.groupId },
3499
+ ...task.groupName && { groupName: task.groupName },
3500
+ ...task.difficulty !== void 0 && { difficulty: task.difficulty }
3501
+ };
3502
+ }
3503
+
3459
3504
  // ../task-manager/src/metrics.types.ts
3460
3505
  init_esm_shims();
3461
3506
 
@@ -3502,6 +3547,16 @@ var TaskManager = class {
3502
3547
  await this.taskProvider.updateTask(updatedTask);
3503
3548
  return updatedTask;
3504
3549
  }
3550
+ /**
3551
+ * Every task the configured provider knows about.
3552
+ *
3553
+ * Pass-through on purpose: the manager owns the state transitions, not the
3554
+ * storage. Having it here is what lets a consumer holding only the manager —
3555
+ * the MCP server — answer "what work exists?".
3556
+ */
3557
+ async getAllTasks() {
3558
+ return await this.taskProvider.getAllTasks();
3559
+ }
3505
3560
  async finishTask(taskId) {
3506
3561
  const task = await this.taskProvider.findTask(taskId);
3507
3562
  if (!task) {
@@ -4313,7 +4368,7 @@ async function startDashboard(options) {
4313
4368
  }
4314
4369
  });
4315
4370
  await wsServer.start();
4316
- success(`\u2713 WebSocket server running on ws://${host}:${wsPort}`);
4371
+ success(`WebSocket server running on ws://${host}:${wsPort}`);
4317
4372
  info(`Starting dashboard server on http://${host}:${port}...`);
4318
4373
  const isDev = __dirname2.includes("/src/");
4319
4374
  const dashboardDist = isDev ? path8.join(__dirname2, "..", "..", "dashboard-dist") : path8.join(__dirname2, "..", "dashboard-dist");
@@ -4364,7 +4419,7 @@ async function startDashboard(options) {
4364
4419
  if (actualPort !== port) {
4365
4420
  warning(`Port ${port} was in use. Dashboard started on port ${actualPort}.`);
4366
4421
  }
4367
- success(`\u2713 Dashboard available at http://${host}:${actualPort}`);
4422
+ success(`Dashboard available at http://${host}:${actualPort}`);
4368
4423
  const filterParams = new URLSearchParams();
4369
4424
  if (options.open) {
4370
4425
  filterParams.set("filter", "open");
@@ -4396,7 +4451,7 @@ async function startDashboard(options) {
4396
4451
  httpServer.close(() => resolve());
4397
4452
  });
4398
4453
  await wsServer.stop();
4399
- success("\u2713 Servers stopped");
4454
+ success("Servers stopped");
4400
4455
  process.exit(0);
4401
4456
  };
4402
4457
  process.on("SIGINT", cleanup);
@@ -4943,7 +4998,7 @@ async function finishTask(taskId, options, gitService) {
4943
4998
  );
4944
4999
  console.log(colors.secondary(` - Push: git push`));
4945
5000
  console.log();
4946
- info("\u2713 Dry run complete");
5001
+ info("Dry run complete");
4947
5002
  return;
4948
5003
  }
4949
5004
  if (task.status === "done") {
@@ -4962,7 +5017,7 @@ async function finishTask(taskId, options, gitService) {
4962
5017
  if (behavior.autoCommitStatusChange) {
4963
5018
  const committed = await git.commitTaskStatusChangeOnBranch(normalizedId, "done", behavior.defaultBranch);
4964
5019
  if (committed) {
4965
- success("\u2713 Auto-committed status change");
5020
+ success("Auto-committed status change");
4966
5021
  }
4967
5022
  }
4968
5023
  if (behavior.autoSync && behavior.originBranch && behavior.defaultBranch) {
@@ -4974,7 +5029,7 @@ async function finishTask(taskId, options, gitService) {
4974
5029
  ciSkipTag: behavior.ciSkipTag
4975
5030
  });
4976
5031
  if (squashed) {
4977
- success(`\u2713 Squash commit pushed to ${behavior.originBranch}`);
5032
+ success(`Squash commit pushed to ${behavior.originBranch}`);
4978
5033
  }
4979
5034
  } catch (squashError) {
4980
5035
  error(
@@ -4990,7 +5045,7 @@ async function finishTask(taskId, options, gitService) {
4990
5045
  cwd: process.cwd(),
4991
5046
  stdio: "ignore"
4992
5047
  });
4993
- success("\u2713 Auto-committed completed work");
5048
+ success("Auto-committed completed work");
4994
5049
  } catch {
4995
5050
  }
4996
5051
  }
@@ -5227,7 +5282,7 @@ async function initializeTaskin(options) {
5227
5282
  };
5228
5283
  info("Creating configuration file...");
5229
5284
  writeFileSync2(configFile, JSON.stringify(config, null, 2), "utf-8");
5230
- success(`\u2713 Created ${colors.highlight(".taskin.json")}`);
5285
+ success(`Created ${colors.highlight(".taskin.json")}`);
5231
5286
  if (process.env.CI !== "true" && selectedProvider.id === "fs") {
5232
5287
  await promptCreateFirstUser(cwd);
5233
5288
  }
@@ -5310,7 +5365,7 @@ async function setupProviderConfig(provider, cwd) {
5310
5365
  }));
5311
5366
  const answers = await inquirer2.prompt(questions);
5312
5367
  console.log();
5313
- success(`\u2713 ${provider.name} configuration saved`);
5368
+ success(`${provider.name} configuration saved`);
5314
5369
  return answers;
5315
5370
  }
5316
5371
  async function setupFileSystemProvider(cwd) {
@@ -5352,7 +5407,7 @@ This is a sample task created during Taskin initialization.
5352
5407
  You can edit or delete this file. Use \`taskin list\` to see all tasks.
5353
5408
  `;
5354
5409
  writeFileSync2(sampleTaskFile, sampleTask, "utf-8");
5355
- success(`\u2713 Created sample task ${colors.highlight("task-001-setup-project.md")}`);
5410
+ success(`Created sample task ${colors.highlight("task-001-setup-project.md")}`);
5356
5411
  }
5357
5412
  return {
5358
5413
  tasksDir: "TASKS",
@@ -5397,7 +5452,7 @@ async function promptCreateFirstUser(cwd) {
5397
5452
  email: answers.email
5398
5453
  };
5399
5454
  await userRegistry.saveUser(user);
5400
- success(`\u2713 User "${user.name}" (${user.email}) created successfully!`);
5455
+ success(`User "${user.name}" (${user.email}) created successfully!`);
5401
5456
  }
5402
5457
 
5403
5458
  // src/commands/lint.ts
@@ -5518,6 +5573,10 @@ var listCommand = defineCommand({
5518
5573
  {
5519
5574
  flags: "--closed",
5520
5575
  description: "Show only closed tasks (done, canceled)"
5576
+ },
5577
+ {
5578
+ flags: "--json",
5579
+ description: "Print the tasks as JSON, for other tools to consume"
5521
5580
  }
5522
5581
  ],
5523
5582
  handler: async (filter, options) => {
@@ -5526,36 +5585,28 @@ var listCommand = defineCommand({
5526
5585
  });
5527
5586
  async function listTasks(filter, options) {
5528
5587
  requireTaskinProject();
5529
- printHeader("Task List", "\u{1F4CA}");
5588
+ const comoJson = options.json === true;
5589
+ if (!comoJson) {
5590
+ printHeader("Task List", "\u{1F4CA}");
5591
+ }
5530
5592
  const { provider: taskProvider } = await resolveTaskProvider();
5531
5593
  const tasks = await taskProvider.getAllTasks();
5532
- if (tasks.length === 0) {
5594
+ if (tasks.length === 0 && !comoJson) {
5533
5595
  console.log(colors.warning("No tasks found in TASKS/ directory"));
5534
5596
  return;
5535
5597
  }
5536
- const openStatuses = ["pending", "in-progress", "paused", "in-review", "blocked"];
5537
- const closedStatuses = ["done", "canceled"];
5538
- let filteredTasks = tasks;
5539
- if (options.status) {
5540
- filteredTasks = filteredTasks.filter((t) => t.status === options.status);
5541
- } else if (options.open) {
5542
- filteredTasks = filteredTasks.filter((t) => t.status && openStatuses.includes(t.status));
5543
- } else if (options.closed) {
5544
- filteredTasks = filteredTasks.filter((t) => t.status && closedStatuses.includes(t.status));
5545
- }
5546
- if (options.type) {
5547
- filteredTasks = filteredTasks.filter((t) => t.type === options.type);
5548
- }
5549
- if (options.assignee) {
5550
- filteredTasks = filteredTasks.filter(
5551
- (t) => t.assignee?.name.toLowerCase().includes(options.assignee.toLowerCase()) || t.assignee?.id.toLowerCase().includes(options.assignee.toLowerCase())
5552
- );
5553
- }
5554
- if (filter) {
5555
- const lowerFilter = filter.toLowerCase();
5556
- filteredTasks = filteredTasks.filter(
5557
- (t) => t.id.includes(lowerFilter) || t.title.toLowerCase().includes(lowerFilter) || t.status.toLowerCase().includes(lowerFilter) || t.assignee?.name.toLowerCase().includes(lowerFilter) || t.assignee?.id.toLowerCase().includes(lowerFilter)
5558
- );
5598
+ const criteria = {
5599
+ ...options.status && { status: options.status },
5600
+ ...options.type && { type: options.type },
5601
+ ...options.assignee && { assignee: options.assignee },
5602
+ ...options.open && { open: true },
5603
+ ...options.closed && { closed: true },
5604
+ ...filter && { text: filter }
5605
+ };
5606
+ const filteredTasks = filterTasks(tasks, criteria);
5607
+ if (comoJson) {
5608
+ console.log(JSON.stringify(filteredTasks.map(summarizeTask), null, 2));
5609
+ return;
5559
5610
  }
5560
5611
  if (filteredTasks.length === 0) {
5561
5612
  console.log(colors.warning("No tasks match the filters"));
@@ -5634,6 +5685,72 @@ init_esm_shims();
5634
5685
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
5635
5686
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5636
5687
  import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
5688
+
5689
+ // node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/index.js
5690
+ init_esm_shims();
5691
+
5692
+ // node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/filter-tasks/index.js
5693
+ init_esm_shims();
5694
+
5695
+ // node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/filter-tasks/filter-tasks.js
5696
+ init_esm_shims();
5697
+ var EM_ABERTO2 = ["pending", "in-progress", "paused", "in-review", "blocked"];
5698
+ var ENCERRADOS2 = ["done", "canceled"];
5699
+ var contem2 = (valor, procurado) => valor !== void 0 && valor.toLowerCase().includes(procurado);
5700
+ function casaResponsavel2(task, procurado) {
5701
+ const alvo = procurado.toLowerCase();
5702
+ return contem2(task.assignee?.id, alvo) || contem2(task.assignee?.name, alvo);
5703
+ }
5704
+ function filterTasks2(tasks, criteria) {
5705
+ return tasks.filter((task) => {
5706
+ if (criteria.status !== void 0) {
5707
+ if (task.status !== criteria.status)
5708
+ return false;
5709
+ } else if (criteria.open && !EM_ABERTO2.includes(task.status)) {
5710
+ return false;
5711
+ } else if (criteria.closed && !ENCERRADOS2.includes(task.status)) {
5712
+ return false;
5713
+ }
5714
+ if (criteria.type !== void 0 && task.type !== criteria.type)
5715
+ return false;
5716
+ if (criteria.assignee !== void 0 && !casaResponsavel2(task, criteria.assignee))
5717
+ return false;
5718
+ if (criteria.text !== void 0) {
5719
+ const procurado = criteria.text.toLowerCase();
5720
+ const casa = task.id.toLowerCase().includes(procurado) || contem2(task.title, procurado) || contem2(task.status, procurado) || casaResponsavel2(task, procurado);
5721
+ if (!casa)
5722
+ return false;
5723
+ }
5724
+ return true;
5725
+ });
5726
+ }
5727
+ function summarizeTask2(task) {
5728
+ return {
5729
+ id: task.id,
5730
+ title: task.title,
5731
+ status: task.status,
5732
+ type: task.type,
5733
+ ...task.assignee && { assignee: { id: task.assignee.id, name: task.assignee.name } },
5734
+ ...task.order !== void 0 && { priority: task.order },
5735
+ ...task.groupId && { groupId: task.groupId },
5736
+ ...task.groupName && { groupName: task.groupName },
5737
+ ...task.difficulty !== void 0 && { difficulty: task.difficulty }
5738
+ };
5739
+ }
5740
+
5741
+ // node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/metrics.types.js
5742
+ init_esm_shims();
5743
+
5744
+ // node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/task-manager.js
5745
+ init_esm_shims();
5746
+
5747
+ // node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/task-manager.types.js
5748
+ init_esm_shims();
5749
+
5750
+ // node_modules/@opentask/taskin-task-server-mcp/node_modules/@opentask/taskin-task-manager/dist/user-registry.types.js
5751
+ init_esm_shims();
5752
+
5753
+ // node_modules/@opentask/taskin-task-server-mcp/dist/task-server-mcp.js
5637
5754
  import { TaskIdSchema as TaskIdSchema4 } from "@opentask/taskin-types";
5638
5755
  function readTaskId(raw) {
5639
5756
  if (typeof raw !== "string")
@@ -5652,7 +5769,7 @@ function invalidTaskId(raw) {
5652
5769
  isError: true
5653
5770
  };
5654
5771
  }
5655
- var TaskMCPServer = class {
5772
+ var TaskMCPServer = class _TaskMCPServer {
5656
5773
  server;
5657
5774
  taskManager;
5658
5775
  config;
@@ -5691,12 +5808,7 @@ var TaskMCPServer = class {
5691
5808
  arguments: request.params.arguments
5692
5809
  });
5693
5810
  return {
5694
- content: [
5695
- {
5696
- type: "text",
5697
- text: result.content
5698
- }
5699
- ],
5811
+ content: result.content,
5700
5812
  isError: result.isError
5701
5813
  };
5702
5814
  });
@@ -5762,6 +5874,22 @@ var TaskMCPServer = class {
5762
5874
  */
5763
5875
  listTools() {
5764
5876
  const tools = [
5877
+ {
5878
+ name: "list_tasks",
5879
+ description: "List the tasks in the project. Returns a JSON array with what identifies each task \u2014 id, title, status, type, assignee \u2014 without the markdown body. Fetch a task body by id after choosing one.",
5880
+ inputSchema: {
5881
+ type: "object",
5882
+ properties: {
5883
+ status: { type: "string", description: "Exact status (pending, in-progress, done, ...)" },
5884
+ type: { type: "string", description: "Exact type (feat, fix, chore, ...)" },
5885
+ assignee: { type: "string", description: "Assignee id or name, whole or in part" },
5886
+ open: { type: "boolean", description: "Only tasks still open" },
5887
+ closed: { type: "boolean", description: "Only tasks already closed" },
5888
+ text: { type: "string", description: "Free text over id, title, status and assignee" }
5889
+ },
5890
+ required: []
5891
+ }
5892
+ },
5765
5893
  {
5766
5894
  name: "start_task",
5767
5895
  description: "Start working on a task by changing its status to in-progress",
@@ -5800,6 +5928,8 @@ var TaskMCPServer = class {
5800
5928
  try {
5801
5929
  this.log(`Calling tool: ${params.name}`, params.arguments);
5802
5930
  switch (params.name) {
5931
+ case "list_tasks":
5932
+ return await this.handleListTasks(params.arguments ?? {});
5803
5933
  case "start_task": {
5804
5934
  const taskId = readTaskId(params.arguments?.taskId);
5805
5935
  return taskId ? await this.handleStartTask(taskId) : invalidTaskId(params.arguments?.taskId);
@@ -6003,6 +6133,35 @@ Let me start by marking the task as done using the finish_task tool.`
6003
6133
  throw new Error(`Unknown prompt: ${params.name}`);
6004
6134
  }
6005
6135
  }
6136
+ /**
6137
+ * Le e seleciona as tarefas, pela mesma seam que o CLI usa.
6138
+ *
6139
+ * `filterTasks` e `summarizeTask` vivem no pacote agnostico justamente para
6140
+ * que a resposta aqui e a de `taskin list --json` nao possam divergir — ja
6141
+ * houve duas filtragens discordando no repositorio.
6142
+ */
6143
+ async selecionarTarefas(criteria) {
6144
+ const tasks = await this.taskManager.getAllTasks();
6145
+ return filterTasks2(tasks, criteria).map(summarizeTask2);
6146
+ }
6147
+ /** Converte os argumentos crus da chamada MCP no criterio tipado. */
6148
+ static criterioDe(args) {
6149
+ return {
6150
+ ...typeof args.status === "string" && { status: args.status },
6151
+ ...typeof args.type === "string" && { type: args.type },
6152
+ ...typeof args.assignee === "string" && { assignee: args.assignee },
6153
+ ...args.open === true && { open: true },
6154
+ ...args.closed === true && { closed: true },
6155
+ ...typeof args.text === "string" && { text: args.text }
6156
+ };
6157
+ }
6158
+ async handleListTasks(args) {
6159
+ const tarefas = await this.selecionarTarefas(_TaskMCPServer.criterioDe(args));
6160
+ return {
6161
+ content: [{ type: "text", text: JSON.stringify(tarefas, null, 2) }],
6162
+ isError: false
6163
+ };
6164
+ }
6006
6165
  /**
6007
6166
  * List available resources
6008
6167
  */
@@ -6025,15 +6184,13 @@ Let me start by marking the task as done using the finish_task tool.`
6025
6184
  this.log(`Reading resource: ${params.uri}`);
6026
6185
  const uri = params.uri;
6027
6186
  if (uri === "taskin://tasks") {
6187
+ const tarefas = await this.selecionarTarefas({});
6028
6188
  return {
6029
6189
  contents: [
6030
6190
  {
6031
6191
  uri,
6032
6192
  mimeType: "application/json",
6033
- text: JSON.stringify({
6034
- message: "Task list would be here",
6035
- note: "Requires ITaskProvider integration"
6036
- })
6193
+ text: JSON.stringify(tarefas, null, 2)
6037
6194
  }
6038
6195
  ]
6039
6196
  };
@@ -6092,7 +6249,7 @@ async function startMCPServer(options) {
6092
6249
  });
6093
6250
  info("Starting MCP server...");
6094
6251
  await mcpServer.connect({ transport });
6095
- success("\u2713 MCP server started successfully");
6252
+ success("MCP server started successfully");
6096
6253
  info("");
6097
6254
  info(chalk6.bold("Server Information:"));
6098
6255
  info(` \u2022 Transport: ${chalk6.cyan(transport)}`);
@@ -6114,7 +6271,7 @@ async function startMCPServer(options) {
6114
6271
  info("");
6115
6272
  const cleanup = async () => {
6116
6273
  info("\nShutting down MCP server...");
6117
- success("\u2713 Server stopped");
6274
+ success("Server stopped");
6118
6275
  process.exit(0);
6119
6276
  };
6120
6277
  process.on("SIGINT", cleanup);
@@ -6287,7 +6444,7 @@ async function createTask(options, gitService) {
6287
6444
  console.log(colors.secondary(`\u{1F4C1} Path: ${createdPath}`));
6288
6445
  }
6289
6446
  if (autoSyncActive) {
6290
- success("\u2713 Task committed and pushed to remote");
6447
+ success("Task committed and pushed to remote");
6291
6448
  }
6292
6449
  console.log();
6293
6450
  console.log(colors.info("Next steps:"));
@@ -6442,7 +6599,7 @@ async function pauseTask(taskId, options) {
6442
6599
  console.log(colors.secondary(` - Add all changes: git add -A`));
6443
6600
  console.log(colors.secondary(` - Commit: git commit -m "${commitMessage2}"`));
6444
6601
  console.log();
6445
- info("\u2713 Dry run complete");
6602
+ info("Dry run complete");
6446
6603
  return;
6447
6604
  }
6448
6605
  if (task.status !== "in-progress") {
@@ -6476,7 +6633,7 @@ async function pauseTask(taskId, options) {
6476
6633
  }
6477
6634
  await taskManager.pauseTask(normalizedId);
6478
6635
  success("Task paused successfully!");
6479
- success("\u2713 Auto-committed work in progress");
6636
+ success("Auto-committed work in progress");
6480
6637
  info("Status updated to paused");
6481
6638
  console.log();
6482
6639
  info("Next steps:");
@@ -6663,7 +6820,7 @@ async function reviewTask(taskId, options) {
6663
6820
  });
6664
6821
  console.log();
6665
6822
  }
6666
- info("\u2713 Dry run complete");
6823
+ info("Dry run complete");
6667
6824
  return;
6668
6825
  }
6669
6826
  if (reviewHooks.pre && reviewHooks.pre.length > 0 && !options.skipMerge) {
@@ -6682,7 +6839,7 @@ async function reviewTask(taskId, options) {
6682
6839
  const failedPre = preResults.find((r) => !r.success);
6683
6840
  if (failedPre && !hookSettings.continueOnError) {
6684
6841
  console.log();
6685
- error("\u2717 Pre-review hooks failed!");
6842
+ error("Pre-review hooks failed!");
6686
6843
  error("Fix the errors above and try again.");
6687
6844
  process.exit(1);
6688
6845
  }
@@ -6704,7 +6861,7 @@ async function reviewTask(taskId, options) {
6704
6861
  const failedCheck = duringResults.find((r) => !r.success);
6705
6862
  if (failedCheck && !hookSettings.continueOnError) {
6706
6863
  console.log();
6707
- error("\u2717 Review checks failed!");
6864
+ error("Review checks failed!");
6708
6865
  error("Fix the errors above and try again.");
6709
6866
  console.log();
6710
6867
  info("Tip: Run individual checks to see full error details");
@@ -6714,7 +6871,7 @@ async function reviewTask(taskId, options) {
6714
6871
  }
6715
6872
  info("Marking task as ready for review...");
6716
6873
  const updatedTask = await taskManager.reviewTask(task.id);
6717
- success(`\u2713 Task ${updatedTask.id} status changed to: ${updatedTask.status}`);
6874
+ success(`Task ${updatedTask.id} status changed to: ${updatedTask.status}`);
6718
6875
  if (behavior.autoCommitStatusChange) {
6719
6876
  try {
6720
6877
  const message = appendCiSkipTag(
@@ -6725,7 +6882,7 @@ async function reviewTask(taskId, options) {
6725
6882
  cwd: monorepoRoot,
6726
6883
  stdio: "ignore"
6727
6884
  });
6728
- success("\u2713 Auto-committed status change");
6885
+ success("Auto-committed status change");
6729
6886
  } catch {
6730
6887
  }
6731
6888
  }
@@ -6746,7 +6903,7 @@ async function reviewTask(taskId, options) {
6746
6903
  console.log();
6747
6904
  }
6748
6905
  const totalDuration = [...reviewHooks.pre ?? [], ...reviewHooks.during ?? [], ...reviewHooks.post ?? []].length > 0 ? "with hooks" : "";
6749
- success(`\u2713 Task ready for review! ${totalDuration}`);
6906
+ success(`Task ready for review! ${totalDuration}`);
6750
6907
  await sendTaskNotification(configManager, "task:review", normalizedId, task.title);
6751
6908
  if (options.sound !== false) {
6752
6909
  await playSound("review");
@@ -6839,7 +6996,7 @@ async function startTask(taskId, _options, gitService) {
6839
6996
  )
6840
6997
  );
6841
6998
  console.log();
6842
- info("\u2713 Dry run complete");
6999
+ info("Dry run complete");
6843
7000
  return;
6844
7001
  }
6845
7002
  if (task.status === "in-progress") {
@@ -6858,7 +7015,7 @@ async function startTask(taskId, _options, gitService) {
6858
7015
  if (behavior.autoCommitStatusChange) {
6859
7016
  const committed = await git.commitTaskStatusChangeOnBranch(normalizedId, "in-progress", behavior.defaultBranch);
6860
7017
  if (committed) {
6861
- success("\u2713 Auto-committed status change");
7018
+ success("Auto-committed status change");
6862
7019
  }
6863
7020
  }
6864
7021
  console.log();
@@ -7077,102 +7234,72 @@ function getStatusEmoji(status) {
7077
7234
 
7078
7235
  // src/lib/help.ts
7079
7236
  init_esm_shims();
7080
- function showCustomHelp() {
7237
+ var EXEMPLOS = {
7238
+ init: ["taskin init", "taskin setup"],
7239
+ list: ["taskin list", "taskin list pending", "taskin list --status in-progress", "taskin list --type feat"],
7240
+ new: [
7241
+ 'taskin new -t feat -T "Add login" -d "Implement user authentication"',
7242
+ 'taskin new --type fix --title "Fix bug" --user "John"',
7243
+ 'taskin create -t docs -T "Update README"'
7244
+ ],
7245
+ start: ["taskin start 001", "taskin start task-001", "taskin start 001 --force"],
7246
+ pause: ["taskin pause 001", 'taskin pause 001 -m "saving progress"'],
7247
+ review: ["taskin review 001", "taskin review 001 --dry-run"],
7248
+ finish: ["taskin finish 001", "taskin done task-001"],
7249
+ stats: ["taskin stats", "taskin stats --team", "taskin stats --period month"],
7250
+ config: ["taskin config", "taskin config --level assisted", "taskin config --show"],
7251
+ export: ["taskin export", "taskin export --format json"],
7252
+ lint: ["taskin lint", "taskin lint --fix", "taskin lint --fix --metadata-style=list"],
7253
+ dashboard: ["taskin dashboard", "taskin dashboard --port 3000", "taskin dashboard --filter-open"],
7254
+ "mcp-server": ["taskin mcp-server", "taskin mcp"],
7255
+ notify: ["taskin notify --event task:done --task 001"]
7256
+ };
7257
+ var ICONE_PADRAO = "\u2022";
7258
+ function separarIcone(descricao) {
7259
+ const match = descricao.match(new RegExp("^(\\p{Extended_Pictographic}\\uFE0F?)\\s+(.*)$", "su"));
7260
+ return match?.[1] && match[2] !== void 0 ? { icone: match[1], texto: match[2] } : { icone: ICONE_PADRAO, texto: descricao };
7261
+ }
7262
+ var OCULTOS = ["help"];
7263
+ function assinatura(cmd) {
7264
+ const argumentos = cmd.usage().replace("[options]", "").trim();
7265
+ const nome = colors.highlight(`taskin ${cmd.name()}`);
7266
+ return argumentos ? nome + colors.normal(` ${argumentos}`) : nome;
7267
+ }
7268
+ function detalhes(cmd) {
7269
+ const partes = [];
7270
+ const aliases = cmd.aliases();
7271
+ if (aliases.length > 0) {
7272
+ partes.push(`Alias: ${aliases.join(", ")}`);
7273
+ }
7274
+ const flags = cmd.options.map((opcao) => opcao.flags.split(",")[0]?.trim()).filter(Boolean);
7275
+ if (flags.length > 0) {
7276
+ partes.push(`Options: ${flags.join(", ")}`);
7277
+ }
7278
+ return partes.length > 0 ? partes.join(" \xB7 ") : void 0;
7279
+ }
7280
+ function showCustomHelp(program2) {
7081
7281
  printHeader("Taskin - Task Management System", icons.rocket);
7082
7282
  console.log(colors.info("\u{1F4CB} AVAILABLE COMMANDS"));
7083
7283
  console.log(colors.highlight("\u2550".repeat(60)));
7084
7284
  console.log();
7085
- const commands = [
7086
- {
7087
- name: colors.highlight("taskin init"),
7088
- alias: colors.secondary("Alias: setup"),
7089
- description: "Initialize Taskin in your project",
7090
- examples: ["taskin init", "taskin setup"],
7091
- icon: "\u{1F3AF}"
7092
- },
7093
- {
7094
- name: colors.highlight("taskin list") + colors.normal(" [filter]"),
7095
- alias: colors.secondary("Alias: ls"),
7096
- description: "List all tasks in the project",
7097
- examples: ["taskin list", "taskin list pending", "taskin list --status in-progress", "taskin list --type feat"],
7098
- icon: "\u{1F4CA}"
7099
- },
7100
- {
7101
- name: colors.highlight("taskin new"),
7102
- alias: colors.secondary("Alias: create"),
7103
- description: "Create a new task",
7104
- examples: [
7105
- 'taskin new -t feat -T "Add login" -d "Implement user authentication"',
7106
- 'taskin new --type fix --title "Fix bug" --user "John"',
7107
- 'taskin create -t docs -T "Update README"'
7108
- ],
7109
- icon: "\u{1F4DD}"
7110
- },
7111
- {
7112
- name: colors.highlight("taskin start") + colors.normal(" <task-id>"),
7113
- alias: colors.secondary("Alias: begin"),
7114
- description: "Start working on a task (suggests commits)",
7115
- examples: ["taskin start 001", "taskin start task-001", "taskin start 001 --force"],
7116
- icon: "\u{1F680}"
7117
- },
7118
- {
7119
- name: colors.highlight("taskin pause") + colors.normal(" <task-id>"),
7120
- alias: colors.secondary("Alias: stop"),
7121
- description: "Pause a task (auto-commits work in progress)",
7122
- examples: ["taskin pause 001", 'taskin pause 001 -m "saving progress"'],
7123
- icon: "\u23F8\uFE0F"
7124
- },
7125
- {
7126
- name: colors.highlight("taskin finish") + colors.normal(" <task-id>"),
7127
- alias: colors.secondary("Alias: done"),
7128
- description: "Finish a task (suggests commits)",
7129
- examples: ["taskin finish 001", "taskin done task-001"],
7130
- icon: "\u2705"
7131
- },
7132
- {
7133
- name: colors.highlight("taskin config") + colors.normal(" [options]"),
7134
- alias: colors.secondary("Options: --level <manual|assisted|autopilot>"),
7135
- description: "Configure automation level",
7136
- examples: ["taskin config", "taskin config --level assisted", "taskin config --level autopilot"],
7137
- icon: "\u2699\uFE0F"
7138
- },
7139
- {
7140
- name: colors.highlight("taskin lint") + colors.normal(" [options]"),
7141
- alias: colors.secondary("Options: -p, --path <directory>"),
7142
- description: "Validate task markdown files",
7143
- examples: ["taskin lint", "taskin lint --path ./TASKS", "taskin lint -p /path/to/tasks"],
7144
- icon: "\u{1F50D}"
7145
- },
7146
- {
7147
- name: colors.highlight("taskin dashboard") + colors.normal(" [options]"),
7148
- alias: colors.secondary("Options: --host, --port, --filter-open, --filter-closed"),
7149
- description: "Start the web dashboard",
7150
- examples: [
7151
- "taskin dashboard",
7152
- "taskin dashboard --port 3000",
7153
- "taskin dashboard --filter-open",
7154
- "taskin dashboard --filter-closed -o"
7155
- ],
7156
- icon: "\u{1F4CA}"
7157
- },
7158
- {
7159
- name: colors.highlight("taskin mcp-server"),
7160
- alias: colors.secondary("Alias: mcp"),
7161
- description: "Start MCP server for Claude Desktop integration",
7162
- examples: ["taskin mcp-server", "taskin mcp"],
7163
- icon: "\u{1F916}"
7285
+ const comandos = program2.commands.filter((cmd) => !OCULTOS.includes(cmd.name()));
7286
+ comandos.forEach((cmd, index) => {
7287
+ const exemplos = EXEMPLOS[cmd.name()] ?? [];
7288
+ const { icone, texto } = separarIcone(cmd.description());
7289
+ console.log(colors.warning(`${icone} ${assinatura(cmd)}`));
7290
+ const linhaDeDetalhes = detalhes(cmd);
7291
+ if (linhaDeDetalhes) {
7292
+ console.log(colors.normal(` ${colors.secondary(linhaDeDetalhes)}`));
7293
+ }
7294
+ console.log(colors.info(` ${texto}`));
7295
+ if (exemplos.length > 0) {
7296
+ console.log();
7297
+ console.log(colors.normal(` ${colors.info("\u{1F4DD} Examples:")}`));
7298
+ for (const exemplo of exemplos) {
7299
+ console.log(colors.secondary(` ${exemplo}`));
7300
+ }
7164
7301
  }
7165
- ];
7166
- commands.forEach((cmd, index) => {
7167
- console.log(colors.warning(`${cmd.icon} ${cmd.name}`));
7168
- console.log(colors.normal(` ${cmd.alias}`));
7169
- console.log(colors.info(` ${cmd.description}`));
7170
- console.log();
7171
- console.log(colors.normal(` ${colors.info("\u{1F4DD} Examples:")}`));
7172
- cmd.examples.forEach((example) => {
7173
- console.log(colors.secondary(` ${example}`));
7174
- });
7175
- if (index < commands.length - 1) {
7302
+ if (index < comandos.length - 1) {
7176
7303
  console.log();
7177
7304
  console.log(colors.normal(` ${colors.secondary("\u2500".repeat(50))}`));
7178
7305
  console.log();
@@ -7574,7 +7701,7 @@ var program = new Command();
7574
7701
  program.name("taskin").description("\u{1F680} Task Management System").version(getVersion());
7575
7702
  program.helpOption("-h, --help", "Display help information");
7576
7703
  program.command("help").description("Show help information").action(() => {
7577
- showCustomHelp();
7704
+ showCustomHelp(program);
7578
7705
  });
7579
7706
  initCommand(program);
7580
7707
  listCommand(program);
@@ -7591,15 +7718,15 @@ dashboardCommand(program);
7591
7718
  mcpServerCommand(program);
7592
7719
  notifyCommand(program);
7593
7720
  program.on("option:help", () => {
7594
- showCustomHelp();
7721
+ showCustomHelp(program);
7595
7722
  process.exit(0);
7596
7723
  });
7597
7724
  if (process.argv.length <= 2) {
7598
- showCustomHelp();
7725
+ showCustomHelp(program);
7599
7726
  process.exit(0);
7600
7727
  }
7601
7728
  if (process.argv.length === 3 && (process.argv[2] === "--help" || process.argv[2] === "-h")) {
7602
- showCustomHelp();
7729
+ showCustomHelp(program);
7603
7730
  process.exit(0);
7604
7731
  }
7605
7732
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskin",
3
- "version": "4.1.4",
3
+ "version": "4.2.0",
4
4
  "description": "Task management system integrated with Git workflows",
5
5
  "motivation": "Provide a CLI tool for task management integrated with Git workflows",
6
6
  "solve": "Simplifies task tracking and management directly from the command line",
@@ -79,12 +79,12 @@
79
79
  "play-sound": "^1.1.6",
80
80
  "ws": "^8.18.3",
81
81
  "zod": "^3.25.76",
82
- "@opentask/taskin-git-utils": "3.0.2",
83
- "@opentask/taskin-task-manager": "3.0.2",
84
- "@opentask/taskin-file-system-provider": "3.2.3",
85
- "@opentask/taskin-task-server-mcp": "0.2.4",
86
- "@opentask/taskin-task-server-ws": "0.3.2",
87
- "@opentask/taskin-types": "2.1.1",
82
+ "@opentask/taskin-file-system-provider": "3.2.4",
83
+ "@opentask/taskin-git-utils": "3.0.3",
84
+ "@opentask/taskin-task-server-mcp": "0.3.0",
85
+ "@opentask/taskin-task-manager": "3.1.0",
86
+ "@opentask/taskin-task-server-ws": "0.3.3",
87
+ "@opentask/taskin-types": "2.2.0",
88
88
  "@opentask/taskin-utils": "1.1.1"
89
89
  },
90
90
  "devDependencies": {