taskin 4.1.3 → 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 +292 -156
  3. package/package.json +8 -8
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
@@ -5473,8 +5528,17 @@ async function executeLint(options) {
5473
5528
  console.log();
5474
5529
  }
5475
5530
  if (result.valid) {
5476
- console.log(chalk5.green(`\u2705 All task files are valid!
5531
+ if (notices.length === 0) {
5532
+ console.log(chalk5.green(`\u2705 All task files are valid!
5477
5533
  `));
5534
+ } else {
5535
+ const partes = [
5536
+ result.warningCount > 0 ? `${result.warningCount} warning(s)` : "",
5537
+ result.infoCount > 0 ? `${result.infoCount} info` : ""
5538
+ ].filter(Boolean);
5539
+ console.log(chalk5.green(`\u2705 No errors \u2014 ${partes.join(" and ")} above, listed for a human to decide.
5540
+ `));
5541
+ }
5478
5542
  }
5479
5543
  if (!result.valid && !options.fix) {
5480
5544
  console.log(chalk5.blue(`\u{1F4A1} Run with --fix to automatically fix format issues
@@ -5509,6 +5573,10 @@ var listCommand = defineCommand({
5509
5573
  {
5510
5574
  flags: "--closed",
5511
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"
5512
5580
  }
5513
5581
  ],
5514
5582
  handler: async (filter, options) => {
@@ -5517,36 +5585,28 @@ var listCommand = defineCommand({
5517
5585
  });
5518
5586
  async function listTasks(filter, options) {
5519
5587
  requireTaskinProject();
5520
- printHeader("Task List", "\u{1F4CA}");
5588
+ const comoJson = options.json === true;
5589
+ if (!comoJson) {
5590
+ printHeader("Task List", "\u{1F4CA}");
5591
+ }
5521
5592
  const { provider: taskProvider } = await resolveTaskProvider();
5522
5593
  const tasks = await taskProvider.getAllTasks();
5523
- if (tasks.length === 0) {
5594
+ if (tasks.length === 0 && !comoJson) {
5524
5595
  console.log(colors.warning("No tasks found in TASKS/ directory"));
5525
5596
  return;
5526
5597
  }
5527
- const openStatuses = ["pending", "in-progress", "paused", "in-review", "blocked"];
5528
- const closedStatuses = ["done", "canceled"];
5529
- let filteredTasks = tasks;
5530
- if (options.status) {
5531
- filteredTasks = filteredTasks.filter((t) => t.status === options.status);
5532
- } else if (options.open) {
5533
- filteredTasks = filteredTasks.filter((t) => t.status && openStatuses.includes(t.status));
5534
- } else if (options.closed) {
5535
- filteredTasks = filteredTasks.filter((t) => t.status && closedStatuses.includes(t.status));
5536
- }
5537
- if (options.type) {
5538
- filteredTasks = filteredTasks.filter((t) => t.type === options.type);
5539
- }
5540
- if (options.assignee) {
5541
- filteredTasks = filteredTasks.filter(
5542
- (t) => t.assignee?.name.toLowerCase().includes(options.assignee.toLowerCase()) || t.assignee?.id.toLowerCase().includes(options.assignee.toLowerCase())
5543
- );
5544
- }
5545
- if (filter) {
5546
- const lowerFilter = filter.toLowerCase();
5547
- filteredTasks = filteredTasks.filter(
5548
- (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)
5549
- );
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;
5550
5610
  }
5551
5611
  if (filteredTasks.length === 0) {
5552
5612
  console.log(colors.warning("No tasks match the filters"));
@@ -5625,6 +5685,72 @@ init_esm_shims();
5625
5685
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
5626
5686
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5627
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
5628
5754
  import { TaskIdSchema as TaskIdSchema4 } from "@opentask/taskin-types";
5629
5755
  function readTaskId(raw) {
5630
5756
  if (typeof raw !== "string")
@@ -5643,7 +5769,7 @@ function invalidTaskId(raw) {
5643
5769
  isError: true
5644
5770
  };
5645
5771
  }
5646
- var TaskMCPServer = class {
5772
+ var TaskMCPServer = class _TaskMCPServer {
5647
5773
  server;
5648
5774
  taskManager;
5649
5775
  config;
@@ -5682,12 +5808,7 @@ var TaskMCPServer = class {
5682
5808
  arguments: request.params.arguments
5683
5809
  });
5684
5810
  return {
5685
- content: [
5686
- {
5687
- type: "text",
5688
- text: result.content
5689
- }
5690
- ],
5811
+ content: result.content,
5691
5812
  isError: result.isError
5692
5813
  };
5693
5814
  });
@@ -5753,6 +5874,22 @@ var TaskMCPServer = class {
5753
5874
  */
5754
5875
  listTools() {
5755
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
+ },
5756
5893
  {
5757
5894
  name: "start_task",
5758
5895
  description: "Start working on a task by changing its status to in-progress",
@@ -5791,6 +5928,8 @@ var TaskMCPServer = class {
5791
5928
  try {
5792
5929
  this.log(`Calling tool: ${params.name}`, params.arguments);
5793
5930
  switch (params.name) {
5931
+ case "list_tasks":
5932
+ return await this.handleListTasks(params.arguments ?? {});
5794
5933
  case "start_task": {
5795
5934
  const taskId = readTaskId(params.arguments?.taskId);
5796
5935
  return taskId ? await this.handleStartTask(taskId) : invalidTaskId(params.arguments?.taskId);
@@ -5994,6 +6133,35 @@ Let me start by marking the task as done using the finish_task tool.`
5994
6133
  throw new Error(`Unknown prompt: ${params.name}`);
5995
6134
  }
5996
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
+ }
5997
6165
  /**
5998
6166
  * List available resources
5999
6167
  */
@@ -6016,15 +6184,13 @@ Let me start by marking the task as done using the finish_task tool.`
6016
6184
  this.log(`Reading resource: ${params.uri}`);
6017
6185
  const uri = params.uri;
6018
6186
  if (uri === "taskin://tasks") {
6187
+ const tarefas = await this.selecionarTarefas({});
6019
6188
  return {
6020
6189
  contents: [
6021
6190
  {
6022
6191
  uri,
6023
6192
  mimeType: "application/json",
6024
- text: JSON.stringify({
6025
- message: "Task list would be here",
6026
- note: "Requires ITaskProvider integration"
6027
- })
6193
+ text: JSON.stringify(tarefas, null, 2)
6028
6194
  }
6029
6195
  ]
6030
6196
  };
@@ -6083,7 +6249,7 @@ async function startMCPServer(options) {
6083
6249
  });
6084
6250
  info("Starting MCP server...");
6085
6251
  await mcpServer.connect({ transport });
6086
- success("\u2713 MCP server started successfully");
6252
+ success("MCP server started successfully");
6087
6253
  info("");
6088
6254
  info(chalk6.bold("Server Information:"));
6089
6255
  info(` \u2022 Transport: ${chalk6.cyan(transport)}`);
@@ -6105,7 +6271,7 @@ async function startMCPServer(options) {
6105
6271
  info("");
6106
6272
  const cleanup = async () => {
6107
6273
  info("\nShutting down MCP server...");
6108
- success("\u2713 Server stopped");
6274
+ success("Server stopped");
6109
6275
  process.exit(0);
6110
6276
  };
6111
6277
  process.on("SIGINT", cleanup);
@@ -6278,7 +6444,7 @@ async function createTask(options, gitService) {
6278
6444
  console.log(colors.secondary(`\u{1F4C1} Path: ${createdPath}`));
6279
6445
  }
6280
6446
  if (autoSyncActive) {
6281
- success("\u2713 Task committed and pushed to remote");
6447
+ success("Task committed and pushed to remote");
6282
6448
  }
6283
6449
  console.log();
6284
6450
  console.log(colors.info("Next steps:"));
@@ -6433,7 +6599,7 @@ async function pauseTask(taskId, options) {
6433
6599
  console.log(colors.secondary(` - Add all changes: git add -A`));
6434
6600
  console.log(colors.secondary(` - Commit: git commit -m "${commitMessage2}"`));
6435
6601
  console.log();
6436
- info("\u2713 Dry run complete");
6602
+ info("Dry run complete");
6437
6603
  return;
6438
6604
  }
6439
6605
  if (task.status !== "in-progress") {
@@ -6467,7 +6633,7 @@ async function pauseTask(taskId, options) {
6467
6633
  }
6468
6634
  await taskManager.pauseTask(normalizedId);
6469
6635
  success("Task paused successfully!");
6470
- success("\u2713 Auto-committed work in progress");
6636
+ success("Auto-committed work in progress");
6471
6637
  info("Status updated to paused");
6472
6638
  console.log();
6473
6639
  info("Next steps:");
@@ -6654,7 +6820,7 @@ async function reviewTask(taskId, options) {
6654
6820
  });
6655
6821
  console.log();
6656
6822
  }
6657
- info("\u2713 Dry run complete");
6823
+ info("Dry run complete");
6658
6824
  return;
6659
6825
  }
6660
6826
  if (reviewHooks.pre && reviewHooks.pre.length > 0 && !options.skipMerge) {
@@ -6673,7 +6839,7 @@ async function reviewTask(taskId, options) {
6673
6839
  const failedPre = preResults.find((r) => !r.success);
6674
6840
  if (failedPre && !hookSettings.continueOnError) {
6675
6841
  console.log();
6676
- error("\u2717 Pre-review hooks failed!");
6842
+ error("Pre-review hooks failed!");
6677
6843
  error("Fix the errors above and try again.");
6678
6844
  process.exit(1);
6679
6845
  }
@@ -6695,7 +6861,7 @@ async function reviewTask(taskId, options) {
6695
6861
  const failedCheck = duringResults.find((r) => !r.success);
6696
6862
  if (failedCheck && !hookSettings.continueOnError) {
6697
6863
  console.log();
6698
- error("\u2717 Review checks failed!");
6864
+ error("Review checks failed!");
6699
6865
  error("Fix the errors above and try again.");
6700
6866
  console.log();
6701
6867
  info("Tip: Run individual checks to see full error details");
@@ -6705,7 +6871,7 @@ async function reviewTask(taskId, options) {
6705
6871
  }
6706
6872
  info("Marking task as ready for review...");
6707
6873
  const updatedTask = await taskManager.reviewTask(task.id);
6708
- success(`\u2713 Task ${updatedTask.id} status changed to: ${updatedTask.status}`);
6874
+ success(`Task ${updatedTask.id} status changed to: ${updatedTask.status}`);
6709
6875
  if (behavior.autoCommitStatusChange) {
6710
6876
  try {
6711
6877
  const message = appendCiSkipTag(
@@ -6716,7 +6882,7 @@ async function reviewTask(taskId, options) {
6716
6882
  cwd: monorepoRoot,
6717
6883
  stdio: "ignore"
6718
6884
  });
6719
- success("\u2713 Auto-committed status change");
6885
+ success("Auto-committed status change");
6720
6886
  } catch {
6721
6887
  }
6722
6888
  }
@@ -6737,7 +6903,7 @@ async function reviewTask(taskId, options) {
6737
6903
  console.log();
6738
6904
  }
6739
6905
  const totalDuration = [...reviewHooks.pre ?? [], ...reviewHooks.during ?? [], ...reviewHooks.post ?? []].length > 0 ? "with hooks" : "";
6740
- success(`\u2713 Task ready for review! ${totalDuration}`);
6906
+ success(`Task ready for review! ${totalDuration}`);
6741
6907
  await sendTaskNotification(configManager, "task:review", normalizedId, task.title);
6742
6908
  if (options.sound !== false) {
6743
6909
  await playSound("review");
@@ -6830,7 +6996,7 @@ async function startTask(taskId, _options, gitService) {
6830
6996
  )
6831
6997
  );
6832
6998
  console.log();
6833
- info("\u2713 Dry run complete");
6999
+ info("Dry run complete");
6834
7000
  return;
6835
7001
  }
6836
7002
  if (task.status === "in-progress") {
@@ -6849,7 +7015,7 @@ async function startTask(taskId, _options, gitService) {
6849
7015
  if (behavior.autoCommitStatusChange) {
6850
7016
  const committed = await git.commitTaskStatusChangeOnBranch(normalizedId, "in-progress", behavior.defaultBranch);
6851
7017
  if (committed) {
6852
- success("\u2713 Auto-committed status change");
7018
+ success("Auto-committed status change");
6853
7019
  }
6854
7020
  }
6855
7021
  console.log();
@@ -7068,102 +7234,72 @@ function getStatusEmoji(status) {
7068
7234
 
7069
7235
  // src/lib/help.ts
7070
7236
  init_esm_shims();
7071
- 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) {
7072
7281
  printHeader("Taskin - Task Management System", icons.rocket);
7073
7282
  console.log(colors.info("\u{1F4CB} AVAILABLE COMMANDS"));
7074
7283
  console.log(colors.highlight("\u2550".repeat(60)));
7075
7284
  console.log();
7076
- const commands = [
7077
- {
7078
- name: colors.highlight("taskin init"),
7079
- alias: colors.secondary("Alias: setup"),
7080
- description: "Initialize Taskin in your project",
7081
- examples: ["taskin init", "taskin setup"],
7082
- icon: "\u{1F3AF}"
7083
- },
7084
- {
7085
- name: colors.highlight("taskin list") + colors.normal(" [filter]"),
7086
- alias: colors.secondary("Alias: ls"),
7087
- description: "List all tasks in the project",
7088
- examples: ["taskin list", "taskin list pending", "taskin list --status in-progress", "taskin list --type feat"],
7089
- icon: "\u{1F4CA}"
7090
- },
7091
- {
7092
- name: colors.highlight("taskin new"),
7093
- alias: colors.secondary("Alias: create"),
7094
- description: "Create a new task",
7095
- examples: [
7096
- 'taskin new -t feat -T "Add login" -d "Implement user authentication"',
7097
- 'taskin new --type fix --title "Fix bug" --user "John"',
7098
- 'taskin create -t docs -T "Update README"'
7099
- ],
7100
- icon: "\u{1F4DD}"
7101
- },
7102
- {
7103
- name: colors.highlight("taskin start") + colors.normal(" <task-id>"),
7104
- alias: colors.secondary("Alias: begin"),
7105
- description: "Start working on a task (suggests commits)",
7106
- examples: ["taskin start 001", "taskin start task-001", "taskin start 001 --force"],
7107
- icon: "\u{1F680}"
7108
- },
7109
- {
7110
- name: colors.highlight("taskin pause") + colors.normal(" <task-id>"),
7111
- alias: colors.secondary("Alias: stop"),
7112
- description: "Pause a task (auto-commits work in progress)",
7113
- examples: ["taskin pause 001", 'taskin pause 001 -m "saving progress"'],
7114
- icon: "\u23F8\uFE0F"
7115
- },
7116
- {
7117
- name: colors.highlight("taskin finish") + colors.normal(" <task-id>"),
7118
- alias: colors.secondary("Alias: done"),
7119
- description: "Finish a task (suggests commits)",
7120
- examples: ["taskin finish 001", "taskin done task-001"],
7121
- icon: "\u2705"
7122
- },
7123
- {
7124
- name: colors.highlight("taskin config") + colors.normal(" [options]"),
7125
- alias: colors.secondary("Options: --level <manual|assisted|autopilot>"),
7126
- description: "Configure automation level",
7127
- examples: ["taskin config", "taskin config --level assisted", "taskin config --level autopilot"],
7128
- icon: "\u2699\uFE0F"
7129
- },
7130
- {
7131
- name: colors.highlight("taskin lint") + colors.normal(" [options]"),
7132
- alias: colors.secondary("Options: -p, --path <directory>"),
7133
- description: "Validate task markdown files",
7134
- examples: ["taskin lint", "taskin lint --path ./TASKS", "taskin lint -p /path/to/tasks"],
7135
- icon: "\u{1F50D}"
7136
- },
7137
- {
7138
- name: colors.highlight("taskin dashboard") + colors.normal(" [options]"),
7139
- alias: colors.secondary("Options: --host, --port, --filter-open, --filter-closed"),
7140
- description: "Start the web dashboard",
7141
- examples: [
7142
- "taskin dashboard",
7143
- "taskin dashboard --port 3000",
7144
- "taskin dashboard --filter-open",
7145
- "taskin dashboard --filter-closed -o"
7146
- ],
7147
- icon: "\u{1F4CA}"
7148
- },
7149
- {
7150
- name: colors.highlight("taskin mcp-server"),
7151
- alias: colors.secondary("Alias: mcp"),
7152
- description: "Start MCP server for Claude Desktop integration",
7153
- examples: ["taskin mcp-server", "taskin mcp"],
7154
- 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
+ }
7155
7301
  }
7156
- ];
7157
- commands.forEach((cmd, index) => {
7158
- console.log(colors.warning(`${cmd.icon} ${cmd.name}`));
7159
- console.log(colors.normal(` ${cmd.alias}`));
7160
- console.log(colors.info(` ${cmd.description}`));
7161
- console.log();
7162
- console.log(colors.normal(` ${colors.info("\u{1F4DD} Examples:")}`));
7163
- cmd.examples.forEach((example) => {
7164
- console.log(colors.secondary(` ${example}`));
7165
- });
7166
- if (index < commands.length - 1) {
7302
+ if (index < comandos.length - 1) {
7167
7303
  console.log();
7168
7304
  console.log(colors.normal(` ${colors.secondary("\u2500".repeat(50))}`));
7169
7305
  console.log();
@@ -7565,7 +7701,7 @@ var program = new Command();
7565
7701
  program.name("taskin").description("\u{1F680} Task Management System").version(getVersion());
7566
7702
  program.helpOption("-h, --help", "Display help information");
7567
7703
  program.command("help").description("Show help information").action(() => {
7568
- showCustomHelp();
7704
+ showCustomHelp(program);
7569
7705
  });
7570
7706
  initCommand(program);
7571
7707
  listCommand(program);
@@ -7582,15 +7718,15 @@ dashboardCommand(program);
7582
7718
  mcpServerCommand(program);
7583
7719
  notifyCommand(program);
7584
7720
  program.on("option:help", () => {
7585
- showCustomHelp();
7721
+ showCustomHelp(program);
7586
7722
  process.exit(0);
7587
7723
  });
7588
7724
  if (process.argv.length <= 2) {
7589
- showCustomHelp();
7725
+ showCustomHelp(program);
7590
7726
  process.exit(0);
7591
7727
  }
7592
7728
  if (process.argv.length === 3 && (process.argv[2] === "--help" || process.argv[2] === "-h")) {
7593
- showCustomHelp();
7729
+ showCustomHelp(program);
7594
7730
  process.exit(0);
7595
7731
  }
7596
7732
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskin",
3
- "version": "4.1.3",
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,13 +79,13 @@
79
79
  "play-sound": "^1.1.6",
80
80
  "ws": "^8.18.3",
81
81
  "zod": "^3.25.76",
82
- "@opentask/taskin-file-system-provider": "3.2.3",
83
- "@opentask/taskin-task-manager": "3.0.2",
84
- "@opentask/taskin-task-server-ws": "0.3.2",
85
- "@opentask/taskin-task-server-mcp": "0.2.4",
86
- "@opentask/taskin-git-utils": "3.0.2",
87
- "@opentask/taskin-utils": "1.1.1",
88
- "@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
+ "@opentask/taskin-utils": "1.1.1"
89
89
  },
90
90
  "devDependencies": {
91
91
  "@types/node": "^20.19.24",