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.
- package/README.md +56 -3
- package/dist/index.js +61 -21
- 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
|
-
|
|
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:**
|
|
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.
|
|
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.
|
|
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(
|
|
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(
|
|
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(
|
|
198
|
-
|
|
199
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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-
|
|
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-
|
|
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",
|