taskin 1.0.9 → 1.0.11

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 +56 -3
  2. package/dist/index.js +61 -21
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -19,7 +19,7 @@ Taskin is a command-line tool that helps you manage tasks directly from your ter
19
19
 
20
20
  ## 🚀 Installation
21
21
 
22
- \`\`\`bash
22
+ ```bash
23
23
 
24
24
  # Using npx (recommended - no installation needed!)
25
25
 
@@ -36,9 +36,9 @@ pnpm add -g taskin
36
36
  # Or with yarn
37
37
 
38
38
  yarn global add taskin
39
- \`\`\`
39
+ ```
40
40
 
41
- > **Note:** This is a beta version. Please report any issues on [GitHub](https://github.com/sidartaveloso/taskin/issues).
41
+ > **Note:** Please report any issues on [GitHub](https://github.com/sidartaveloso/taskin/issues).
42
42
 
43
43
  ## 📦 Available Packages
44
44
 
@@ -103,6 +103,59 @@ Taskin is built as a modular ecosystem. Besides the CLI, you can use individual
103
103
  - `taskin pause <id>` - Pause work on a task
104
104
  - `taskin finish <id>` - Complete a task
105
105
  - `taskin lint` - Validate task files
106
+ - `taskin dashboard` - Start the web dashboard
107
+ - `taskin mcp-server` - Start MCP server for Claude Desktop integration (alias: `mcp`)
108
+
109
+ ## 🤖 MCP Server (Model Context Protocol)
110
+
111
+ Taskin includes an MCP server that allows AI assistants like Claude Desktop to interact with your tasks:
112
+
113
+ ```bash
114
+ taskin mcp-server
115
+ ```
116
+
117
+ ### Integration with Claude Desktop
118
+
119
+ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
120
+
121
+ ```json
122
+ {
123
+ "mcpServers": {
124
+ "taskin": {
125
+ "args": ["taskin@beta", "mcp-server"],
126
+ "command": "npx"
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ Or if installed globally:
133
+
134
+ ```json
135
+ {
136
+ "mcpServers": {
137
+ "taskin": {
138
+ "args": ["mcp-server"],
139
+ "command": "taskin"
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ **Available MCP Tools:**
146
+
147
+ - `start_task` - Start working on a task
148
+ - `finish_task` - Mark a task as finished
149
+
150
+ **Available MCP Prompts:**
151
+
152
+ - `start-task-workflow` - Guide for starting tasks
153
+ - `finish-task-workflow` - Guide for finishing tasks
154
+ - `task-summary` - Get task summary and insights
155
+
156
+ **Available MCP Resources:**
157
+
158
+ - `taskin://tasks` - Access all tasks
106
159
 
107
160
  ## 📦 Programmatic Usage
108
161
 
package/dist/index.js CHANGED
@@ -38,12 +38,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
38
38
  mod
39
39
  ));
40
40
 
41
- // ../../node_modules/.pnpm/tsup@8.5.0_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
41
+ // ../../node_modules/.pnpm/tsup@8.5.0_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
42
42
  import path from "path";
43
43
  import { fileURLToPath } from "url";
44
44
  var getFilename, getDirname, __dirname;
45
45
  var init_esm_shims = __esm({
46
- "../../node_modules/.pnpm/tsup@8.5.0_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js"() {
46
+ "../../node_modules/.pnpm/tsup@8.5.0_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js"() {
47
47
  "use strict";
48
48
  getFilename = () => fileURLToPath(import.meta.url);
49
49
  getDirname = () => path.dirname(getFilename());
@@ -127,7 +127,9 @@ async function validateTaskFile(filePath) {
127
127
  });
128
128
  }
129
129
  if (hasInlineStatus) {
130
- const statusLineIdx = lines.findIndex((line) => /^Status:/i.test(line.trim()));
130
+ const statusLineIdx = lines.findIndex(
131
+ (line) => /^Status:/i.test(line.trim())
132
+ );
131
133
  issues.push({
132
134
  file: filePath,
133
135
  line: statusLineIdx >= 0 ? statusLineIdx + 1 : void 0,
@@ -147,7 +149,9 @@ async function validateTaskFile(filePath) {
147
149
  const statusMatch = content.match(/## Status\s*\n\s*([^\n\r]+)/i);
148
150
  const statusValue = statusMatch ? statusMatch[1].trim().toLowerCase() : "";
149
151
  if (!["todo", "in-progress", "done", "pending"].includes(statusValue)) {
150
- const statusLineIdx = lines.findIndex((line) => line.trim() === "## Status");
152
+ const statusLineIdx = lines.findIndex(
153
+ (line) => line.trim() === "## Status"
154
+ );
151
155
  issues.push({
152
156
  file: filePath,
153
157
  line: statusLineIdx >= 0 ? statusLineIdx + 2 : void 0,
@@ -194,9 +198,15 @@ async function validateTaskFile(filePath) {
194
198
  return issues;
195
199
  }
196
200
  function createLintResult(allIssues) {
197
- const errorCount = allIssues.filter((issue) => issue.severity === "error").length;
198
- const warningCount = allIssues.filter((issue) => issue.severity === "warning").length;
199
- const infoCount = allIssues.filter((issue) => issue.severity === "info").length;
201
+ const errorCount = allIssues.filter(
202
+ (issue) => issue.severity === "error"
203
+ ).length;
204
+ const warningCount = allIssues.filter(
205
+ (issue) => issue.severity === "warning"
206
+ ).length;
207
+ const infoCount = allIssues.filter(
208
+ (issue) => issue.severity === "info"
209
+ ).length;
200
210
  return {
201
211
  valid: errorCount === 0,
202
212
  issues: allIssues,
@@ -7105,7 +7115,9 @@ var FileSystemTaskProvider = class {
7105
7115
  }
7106
7116
  async findTask(taskId) {
7107
7117
  const files = await fs.readdir(this.tasksDirectory);
7108
- const taskFile = files.find((file) => file.startsWith(`task-${taskId}-`) && file.endsWith(".md"));
7118
+ const taskFile = files.find(
7119
+ (file) => file.startsWith(`task-${taskId}-`) && file.endsWith(".md")
7120
+ );
7109
7121
  if (!taskFile) {
7110
7122
  return void 0;
7111
7123
  }
@@ -7120,8 +7132,7 @@ var FileSystemTaskProvider = class {
7120
7132
  for (const n of names) {
7121
7133
  const rx = new RegExp(`##\\s*${n}\\s*\\n\\s*([^\\n\\r]+)`, "i");
7122
7134
  const m = content.match(rx);
7123
- if (m)
7124
- return m[1].trim();
7135
+ if (m) return m[1].trim();
7125
7136
  }
7126
7137
  return null;
7127
7138
  };
@@ -7133,7 +7144,9 @@ var FileSystemTaskProvider = class {
7133
7144
  const assigneeValue = assigneeMatch.trim();
7134
7145
  assignee = this.userRegistry.resolveUser(assigneeValue);
7135
7146
  if (!assignee) {
7136
- console.warn(`[FS Provider] User "${assigneeValue}" not found in registry, creating temporary user`);
7147
+ console.warn(
7148
+ `[FS Provider] User "${assigneeValue}" not found in registry, creating temporary user`
7149
+ );
7137
7150
  assignee = this.userRegistry.createTemporaryUser(assigneeValue);
7138
7151
  }
7139
7152
  }
@@ -7151,7 +7164,9 @@ var FileSystemTaskProvider = class {
7151
7164
  }
7152
7165
  async updateTask(task) {
7153
7166
  const currentContent = await fs.readFile(task.filePath, "utf-8");
7154
- const hasInlineMetadata = /^(Status|Type|Assignee):\s*.+$/im.test(currentContent);
7167
+ const hasInlineMetadata = /^(Status|Type|Assignee):\s*.+$/im.test(
7168
+ currentContent
7169
+ );
7155
7170
  if (hasInlineMetadata) {
7156
7171
  const { fixTaskFile: fixTaskFile2 } = await Promise.resolve().then(() => (init_task_validator(), task_validator_exports));
7157
7172
  await fixTaskFile2(task.filePath);
@@ -7159,18 +7174,26 @@ var FileSystemTaskProvider = class {
7159
7174
  const content = await fs.readFile(task.filePath, "utf-8");
7160
7175
  let updatedContent;
7161
7176
  if (/##\s*Status/i.test(content)) {
7162
- updatedContent = content.replace(/(##\s*Status\s*\n\s*)([^\n\r]*)/i, `$1${task.status}`);
7177
+ updatedContent = content.replace(
7178
+ /(##\s*Status\s*\n\s*)([^\n\r]*)/i,
7179
+ `$1${task.status}`
7180
+ );
7163
7181
  } else {
7164
- updatedContent = content.replace(/(^#.*\n)/, `$1
7182
+ updatedContent = content.replace(
7183
+ /(^#.*\n)/,
7184
+ `$1
7165
7185
  ## Status
7166
7186
  ${task.status}
7167
- `);
7187
+ `
7188
+ );
7168
7189
  }
7169
7190
  await fs.writeFile(task.filePath, updatedContent, "utf-8");
7170
7191
  }
7171
7192
  async getAllTasks() {
7172
7193
  const files = await fs.readdir(this.tasksDirectory);
7173
- const taskFiles = files.filter((file) => file.startsWith("task-") && file.endsWith(".md"));
7194
+ const taskFiles = files.filter(
7195
+ (file) => file.startsWith("task-") && file.endsWith(".md")
7196
+ );
7174
7197
  const tasks = [];
7175
7198
  for (const file of taskFiles) {
7176
7199
  const filePath = path2.join(this.tasksDirectory, file);
@@ -7186,8 +7209,7 @@ ${task.status}
7186
7209
  for (const n of names) {
7187
7210
  const rx = new RegExp(`##\\s*${n}\\s*\\n\\s*([^\\n\\r]+)`, "i");
7188
7211
  const m = content.match(rx);
7189
- if (m)
7190
- return m[1].trim();
7212
+ if (m) return m[1].trim();
7191
7213
  }
7192
7214
  return null;
7193
7215
  };
@@ -9027,13 +9049,13 @@ async function listTasks(filter, options) {
9027
9049
  }
9028
9050
  if (options.assignee) {
9029
9051
  filteredTasks = filteredTasks.filter(
9030
- (t) => t.userId?.toLowerCase().includes(options.assignee.toLowerCase())
9052
+ (t) => t.assignee?.name.toLowerCase().includes(options.assignee.toLowerCase()) || t.assignee?.id.toLowerCase().includes(options.assignee.toLowerCase())
9031
9053
  );
9032
9054
  }
9033
9055
  if (filter) {
9034
9056
  const lowerFilter = filter.toLowerCase();
9035
9057
  filteredTasks = filteredTasks.filter(
9036
- (t) => t.id.includes(lowerFilter) || t.title.toLowerCase().includes(lowerFilter) || t.status.toLowerCase().includes(lowerFilter) || t.userId?.toLowerCase().includes(lowerFilter)
9058
+ (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)
9037
9059
  );
9038
9060
  }
9039
9061
  if (filteredTasks.length === 0) {
@@ -9050,7 +9072,7 @@ async function listTasks(filter, options) {
9050
9072
  const statusColor = getStatusColor(task.status);
9051
9073
  const typeColor = getTypeColor(task.type);
9052
9074
  console.log(
9053
- `${colors2.info(task.id.padEnd(15))} ${statusColor(task.status.padEnd(15))} ${typeColor(task.type.padEnd(12))} ${colors2.secondary((task.userId || "unknown").padEnd(15))} ${colors2.normal(task.title)}`
9075
+ `${colors2.info(task.id.padEnd(15))} ${statusColor(task.status.padEnd(15))} ${typeColor(task.type.padEnd(12))} ${colors2.secondary((task.assignee?.name || "unassigned").padEnd(15))} ${colors2.normal(task.title)}`
9054
9076
  );
9055
9077
  });
9056
9078
  console.log();
@@ -11712,6 +11734,24 @@ function showCustomHelp() {
11712
11734
  "taskin lint -p /path/to/tasks"
11713
11735
  ],
11714
11736
  icon: "\u{1F50D}"
11737
+ },
11738
+ {
11739
+ name: colors2.highlight("taskin dashboard") + colors2.normal(" [options]"),
11740
+ alias: colors2.secondary("Options: --host, --port"),
11741
+ description: "Start the web dashboard",
11742
+ examples: [
11743
+ "taskin dashboard",
11744
+ "taskin dashboard --port 3000",
11745
+ "taskin dashboard --host 0.0.0.0"
11746
+ ],
11747
+ icon: "\u{1F4CA}"
11748
+ },
11749
+ {
11750
+ name: colors2.highlight("taskin mcp-server"),
11751
+ alias: colors2.secondary("Alias: mcp"),
11752
+ description: "Start MCP server for Claude Desktop integration",
11753
+ examples: ["taskin mcp-server", "taskin mcp"],
11754
+ icon: "\u{1F916}"
11715
11755
  }
11716
11756
  ];
11717
11757
  commands.forEach((cmd, index) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskin",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
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",
@@ -87,10 +87,10 @@
87
87
  "vitest": "^1.6.1",
88
88
  "@opentask/taskin-fs-provider": "1.0.5",
89
89
  "@opentask/taskin-task-manager": "1.0.5",
90
- "@opentask/taskin-task-server-mcp": "0.1.0",
91
- "@opentask/taskin-types": "1.0.5",
90
+ "@opentask/taskin-task-server-ws": "0.1.0",
92
91
  "@opentask/taskin-utils": "1.0.5",
93
- "@opentask/taskin-task-server-ws": "0.1.0"
92
+ "@opentask/taskin-task-server-mcp": "0.1.0",
93
+ "@opentask/taskin-types": "1.0.5"
94
94
  },
95
95
  "scripts": {
96
96
  "build": "pnpm run build:dashboard && tsup",