telos-mcp 0.1.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.
- package/README.md +134 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +154 -0
- package/dist/index.js.map +1 -0
- package/dist/store.d.ts +41 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +260 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +12 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +102 -0
- package/dist/utils.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# telos-mcp
|
|
2
|
+
|
|
3
|
+
Task planning and tracking for AI agents. An MCP server with markdown file storage.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Gives any MCP-compatible AI agent persistent task management:
|
|
8
|
+
- **Create, update, list, delete** tasks with full status tracking
|
|
9
|
+
- **Dependencies** — blockedBy/blocks relationships between tasks
|
|
10
|
+
- **Markdown files** — each task is a human-readable `.md` file with frontmatter
|
|
11
|
+
- **Zero native addons** — pure JavaScript, works on any Node version without rebuild
|
|
12
|
+
- **Multi-agent** — owner tracking so you know who's doing what
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx telos-mcp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Stable install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install -g telos-mcp
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or from source:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git clone https://github.com/skye-flyhigh/telos-mcp.git
|
|
30
|
+
cd telos-mcp && npm install && npm run build
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then point your client to `"command": "node", "args": ["/path/to/telos-mcp/dist/index.js"]`.
|
|
34
|
+
|
|
35
|
+
## Configuration
|
|
36
|
+
|
|
37
|
+
| Variable | Default | Description |
|
|
38
|
+
|----------|---------|-------------|
|
|
39
|
+
| `TELOS_DIR` | `~/.telos` | Directory where task files are stored |
|
|
40
|
+
|
|
41
|
+
## Client Setup
|
|
42
|
+
|
|
43
|
+
### Claude Code
|
|
44
|
+
|
|
45
|
+
Add to `.claude.json`:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"telos": {
|
|
51
|
+
"type": "stdio",
|
|
52
|
+
"command": "npx",
|
|
53
|
+
"args": ["telos-mcp"],
|
|
54
|
+
"env": {}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Claude Desktop
|
|
61
|
+
|
|
62
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"telos": {
|
|
68
|
+
"command": "npx",
|
|
69
|
+
"args": ["telos-mcp"]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Tools
|
|
76
|
+
|
|
77
|
+
| Tool | Description |
|
|
78
|
+
|------|-------------|
|
|
79
|
+
| `task_create` | Create a new task with subject, description, tags, dependencies |
|
|
80
|
+
| `task_update` | Update status, dependencies, or details of an existing task |
|
|
81
|
+
| `task_get` | Get full details of a task by ID |
|
|
82
|
+
| `task_list` | List all tasks (summary view), with optional filters |
|
|
83
|
+
| `task_delete` | Delete a task by ID |
|
|
84
|
+
|
|
85
|
+
## Status Workflow
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
pending → in_progress → completed
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Use `status: "deleted"` in `task_update` to remove a task (same as `task_delete`).
|
|
92
|
+
|
|
93
|
+
## Dependencies
|
|
94
|
+
|
|
95
|
+
Tasks can block each other:
|
|
96
|
+
|
|
97
|
+
- `blockedBy: [1, 3]` — this task can't start until tasks 1 and 3 complete
|
|
98
|
+
- When a task is completed, it's automatically removed from dependents' `blockedBy`
|
|
99
|
+
- When a task is deleted, all dependency references are cleaned up
|
|
100
|
+
|
|
101
|
+
## Storage Format
|
|
102
|
+
|
|
103
|
+
Each task is a markdown file at `~/.telos/{id}-{slug}.md`:
|
|
104
|
+
|
|
105
|
+
```markdown
|
|
106
|
+
---
|
|
107
|
+
id: 1
|
|
108
|
+
subject: Fix authentication bug
|
|
109
|
+
status: pending
|
|
110
|
+
created: 2026-03-06T10:00:00Z
|
|
111
|
+
updated: 2026-03-06T10:00:00Z
|
|
112
|
+
owner: echo
|
|
113
|
+
activeForm: Fixing authentication bug
|
|
114
|
+
blockedBy: []
|
|
115
|
+
blocks: [2]
|
|
116
|
+
tags: [backend, auth]
|
|
117
|
+
metadata_sources: https://docs.example.com
|
|
118
|
+
metadata_pr: #42
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
Detailed description with full markdown support.
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Filenames use slugified subjects for readability: `1-fix-authentication-bug.md`.
|
|
125
|
+
|
|
126
|
+
Metadata is stored as `metadata_` prefixed keys in frontmatter, reconstructed into a `{ key: value }` object on read.
|
|
127
|
+
|
|
128
|
+
A `.next_id` counter file tracks the next available task ID (prevents ID reuse after deletion). It's a dotfile — hidden by default.
|
|
129
|
+
|
|
130
|
+
Human-readable, git-friendly, works with Obsidian/any markdown viewer.
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { TaskStore } from "./store.js";
|
|
7
|
+
import { loadConfig } from "./types.js";
|
|
8
|
+
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
9
|
+
const config = loadConfig();
|
|
10
|
+
const store = new TaskStore(config.dir);
|
|
11
|
+
const server = new McpServer({
|
|
12
|
+
name: "telos-mcp",
|
|
13
|
+
version: pkg.version,
|
|
14
|
+
});
|
|
15
|
+
const descriptionStructure = `
|
|
16
|
+
Structured description, details points when applicable:
|
|
17
|
+
- Context: explain the why, and overall view how to solve the problem
|
|
18
|
+
- Task details
|
|
19
|
+
- Task location: where the task takes place
|
|
20
|
+
- Architecture: final structure of the expected output
|
|
21
|
+
- Dependencies: explain what are required for delivery
|
|
22
|
+
- Examples of the deliverable and expectations
|
|
23
|
+
- Reasoning for the offered solution
|
|
24
|
+
- Foreseen barriers and solution (from task context)
|
|
25
|
+
- Implementation steps: real, commitable implementation steps, questions to ask the user for clarification and decision
|
|
26
|
+
- Testing plan
|
|
27
|
+
- Deployment plan
|
|
28
|
+
`;
|
|
29
|
+
// ── task_create ─────────────────────────────────────────────────
|
|
30
|
+
server.registerTool("task_create", {
|
|
31
|
+
description: "Create a new task for tracking work",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
subject: z.string().describe("Brief imperative title (e.g. 'Fix auth bug')"),
|
|
34
|
+
description: z.string().optional().describe(`Detailed markdown description. \n ${descriptionStructure}`),
|
|
35
|
+
activeForm: z
|
|
36
|
+
.string()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Present-continuous form shown in spinner when task is in_progress. Subject is imperative ('Fix auth bug'), activeForm is what's happening now ('Fixing auth bug'). Displayed as: ⠋ Fixing auth bug..."),
|
|
39
|
+
owner: z.string().optional().describe("Who owns this task"),
|
|
40
|
+
blockedBy: z.array(z.number()).optional().describe("Task IDs that must complete first"),
|
|
41
|
+
tags: z.array(z.string()).optional().describe("Categorization tags"),
|
|
42
|
+
metadata: z.record(z.string()).optional().describe("Arbitrary key-value pairs (e.g. { sources: 'https://...', pr: '#42' })"),
|
|
43
|
+
}
|
|
44
|
+
}, async (params) => {
|
|
45
|
+
const task = store.create(params);
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: JSON.stringify(task, null, 2) }],
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
// ── task_update ─────────────────────────────────────────────────
|
|
51
|
+
server.registerTool("task_update", {
|
|
52
|
+
description: "Update an existing task's status, dependencies, or details",
|
|
53
|
+
inputSchema: {
|
|
54
|
+
taskId: z.number().describe("The task ID to update"),
|
|
55
|
+
status: z
|
|
56
|
+
.enum(["pending", "in_progress", "completed", "deleted"])
|
|
57
|
+
.optional()
|
|
58
|
+
.describe("New status (deleted removes the task)"),
|
|
59
|
+
subject: z.string().optional().describe("New subject"),
|
|
60
|
+
description: z.string().optional().describe(`New description with structure: \n ${descriptionStructure}`),
|
|
61
|
+
activeForm: z.string().optional().describe("New spinner text"),
|
|
62
|
+
owner: z.string().optional().describe("New owner"),
|
|
63
|
+
addBlockedBy: z.array(z.number()).optional().describe("Task IDs to add as blockers"),
|
|
64
|
+
addBlocks: z.array(z.number()).optional().describe("Task IDs that this task blocks"),
|
|
65
|
+
tags: z.array(z.string()).optional().describe("Replace tags"),
|
|
66
|
+
metadata: z.record(z.string().nullable()).optional().describe("Merge metadata keys into the task. Set a key to null to delete it."),
|
|
67
|
+
}
|
|
68
|
+
}, async (params) => {
|
|
69
|
+
const { taskId, ...fields } = params;
|
|
70
|
+
const task = store.update(taskId, fields);
|
|
71
|
+
if (!task && fields.status === "deleted") {
|
|
72
|
+
return {
|
|
73
|
+
content: [{ type: "text", text: `Task ${taskId} deleted.` }],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (!task) {
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: `Task ${taskId} not found.` }],
|
|
79
|
+
isError: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: "text", text: JSON.stringify(task, null, 2) }],
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
// ── task_get ────────────────────────────────────────────────────
|
|
87
|
+
server.registerTool("task_get", { description: "Get full details of a task by ID",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
taskId: z.number().describe("The task ID to retrieve"),
|
|
90
|
+
} }, async ({ taskId }) => {
|
|
91
|
+
const task = store.get(taskId);
|
|
92
|
+
if (!task) {
|
|
93
|
+
return {
|
|
94
|
+
content: [{ type: "text", text: `Task ${taskId} not found.` }],
|
|
95
|
+
isError: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
content: [{ type: "text", text: JSON.stringify(task, null, 2) }],
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
// ── task_list ───────────────────────────────────────────────────
|
|
103
|
+
server.registerTool("task_list", { description: "List all tasks (summary view: id, subject, status, owner, blockedBy)",
|
|
104
|
+
inputSchema: {
|
|
105
|
+
status: z
|
|
106
|
+
.enum(["pending", "in_progress", "completed"])
|
|
107
|
+
.optional()
|
|
108
|
+
.describe("Filter by status"),
|
|
109
|
+
owner: z.string().optional().describe("Filter by owner"),
|
|
110
|
+
tag: z.string().optional().describe("Filter by tag"),
|
|
111
|
+
} }, async (params) => {
|
|
112
|
+
const tasks = store.list(params);
|
|
113
|
+
if (tasks.length === 0) {
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: "text", text: "No tasks found." }],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const lines = tasks.map((t) => {
|
|
119
|
+
const owner = t.owner ? ` @${t.owner}` : "";
|
|
120
|
+
const tags = t.tags.length > 0 ? ` ${t.tags.map((tag) => `#${tag}`).join(" ")}` : "";
|
|
121
|
+
const blocked = t.blockedBy.length > 0 ? ` (blocked by: ${t.blockedBy.join(", ")})` : "";
|
|
122
|
+
return `[${t.id}] ${t.status} — ${t.subject}${owner}${tags}${blocked}`;
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
// ── task_delete ─────────────────────────────────────────────────
|
|
129
|
+
server.registerTool("task_delete", { description: "Delete a task by ID (removes the file)",
|
|
130
|
+
inputSchema: {
|
|
131
|
+
taskId: z.number().describe("The task ID to delete"),
|
|
132
|
+
} }, async ({ taskId }) => {
|
|
133
|
+
const deleted = store.delete(taskId);
|
|
134
|
+
if (!deleted) {
|
|
135
|
+
return {
|
|
136
|
+
content: [{ type: "text", text: `Task ${taskId} not found.` }],
|
|
137
|
+
isError: true,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
content: [{ type: "text", text: `Task ${taskId} deleted.` }],
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
// ── Start ───────────────────────────────────────────────────────
|
|
145
|
+
async function main() {
|
|
146
|
+
const transport = new StdioServerTransport();
|
|
147
|
+
await server.connect(transport);
|
|
148
|
+
console.error(`[telos] Task server running on stdio (${store.count()} tasks in ${config.dir})`);
|
|
149
|
+
}
|
|
150
|
+
main().catch((err) => {
|
|
151
|
+
console.error("[telos] Fatal error:", err);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
});
|
|
154
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Task, TaskSummary, TaskStatus, ListFilters } from "./types.js";
|
|
2
|
+
export declare class TaskStore {
|
|
3
|
+
private dir;
|
|
4
|
+
constructor(dir: string);
|
|
5
|
+
create(fields: {
|
|
6
|
+
subject: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
activeForm?: string;
|
|
9
|
+
owner?: string;
|
|
10
|
+
blockedBy?: number[];
|
|
11
|
+
tags?: string[];
|
|
12
|
+
metadata?: Record<string, string>;
|
|
13
|
+
}): Task;
|
|
14
|
+
get(id: number): Task | null;
|
|
15
|
+
list(filters?: ListFilters): TaskSummary[];
|
|
16
|
+
update(id: number, fields: {
|
|
17
|
+
status?: TaskStatus | "deleted";
|
|
18
|
+
subject?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
activeForm?: string;
|
|
21
|
+
owner?: string;
|
|
22
|
+
addBlockedBy?: number[];
|
|
23
|
+
addBlocks?: number[];
|
|
24
|
+
tags?: string[];
|
|
25
|
+
metadata?: Record<string, string | null>;
|
|
26
|
+
}): Task | null;
|
|
27
|
+
delete(id: number): boolean;
|
|
28
|
+
count(): number;
|
|
29
|
+
private nextId;
|
|
30
|
+
private taskPath;
|
|
31
|
+
/** Find a task file by ID prefix (handles slug changes) */
|
|
32
|
+
private findTaskFile;
|
|
33
|
+
private taskFiles;
|
|
34
|
+
private readTask;
|
|
35
|
+
private writeTask;
|
|
36
|
+
/** Remove this task's ID from all dependents' blockedBy arrays */
|
|
37
|
+
private unblockDependents;
|
|
38
|
+
/** Remove this task's ID from all blockers' blocks arrays */
|
|
39
|
+
private removeFromBlockers;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI7E,qBAAa,SAAS;IACpB,OAAO,CAAC,GAAG,CAAS;gBAER,GAAG,EAAE,MAAM;IAKvB,MAAM,CAAC,MAAM,EAAE;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACnC,GAAG,IAAI;IAiCR,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAM5B,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE;IAwB1C,MAAM,CACJ,EAAE,EAAE,MAAM,EACV,MAAM,EAAE;QACN,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;QAChC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;KAC1C,GACA,IAAI,GAAG,IAAI;IAkFd,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAY3B,KAAK,IAAI,MAAM;IAMf,OAAO,CAAC,MAAM;IAsBd,OAAO,CAAC,QAAQ;IAKhB,2DAA2D;IAC3D,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,SAAS;IAmBjB,kEAAkE;IAClE,OAAO,CAAC,iBAAiB;IAczB,6DAA6D;IAC7D,OAAO,CAAC,kBAAkB;CAa3B"}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync, readdirSync, unlinkSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { VALID_STATUSES } from "./types.js";
|
|
4
|
+
import { parseFrontmatter, serializeFrontmatter, isoNow, slugify } from "./utils.js";
|
|
5
|
+
export class TaskStore {
|
|
6
|
+
dir;
|
|
7
|
+
constructor(dir) {
|
|
8
|
+
this.dir = dir;
|
|
9
|
+
mkdirSync(dir, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
create(fields) {
|
|
12
|
+
const now = isoNow();
|
|
13
|
+
const id = this.nextId();
|
|
14
|
+
const task = {
|
|
15
|
+
id,
|
|
16
|
+
subject: fields.subject,
|
|
17
|
+
description: fields.description ?? "",
|
|
18
|
+
status: "pending",
|
|
19
|
+
created: now,
|
|
20
|
+
updated: now,
|
|
21
|
+
owner: fields.owner ?? "",
|
|
22
|
+
activeForm: fields.activeForm ?? "",
|
|
23
|
+
blockedBy: fields.blockedBy ?? [],
|
|
24
|
+
blocks: [],
|
|
25
|
+
tags: fields.tags ?? [],
|
|
26
|
+
metadata: fields.metadata ?? {},
|
|
27
|
+
};
|
|
28
|
+
// Update reverse dependencies: add this task to each blocker's `blocks`
|
|
29
|
+
for (const blockerId of task.blockedBy) {
|
|
30
|
+
const blocker = this.get(blockerId);
|
|
31
|
+
if (blocker && !blocker.blocks.includes(id)) {
|
|
32
|
+
blocker.blocks.push(id);
|
|
33
|
+
blocker.updated = now;
|
|
34
|
+
this.writeTask(blocker);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
this.writeTask(task);
|
|
38
|
+
return task;
|
|
39
|
+
}
|
|
40
|
+
get(id) {
|
|
41
|
+
const path = this.findTaskFile(id);
|
|
42
|
+
if (!path)
|
|
43
|
+
return null;
|
|
44
|
+
return this.readTask(path);
|
|
45
|
+
}
|
|
46
|
+
list(filters) {
|
|
47
|
+
const files = this.taskFiles();
|
|
48
|
+
const results = [];
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
const task = this.readTask(join(this.dir, file));
|
|
51
|
+
if (filters?.status && task.status !== filters.status)
|
|
52
|
+
continue;
|
|
53
|
+
if (filters?.owner && task.owner !== filters.owner)
|
|
54
|
+
continue;
|
|
55
|
+
if (filters?.tag && !task.tags.includes(filters.tag))
|
|
56
|
+
continue;
|
|
57
|
+
results.push({
|
|
58
|
+
id: task.id,
|
|
59
|
+
subject: task.subject,
|
|
60
|
+
status: task.status,
|
|
61
|
+
owner: task.owner,
|
|
62
|
+
blockedBy: task.blockedBy,
|
|
63
|
+
tags: task.tags,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return results.sort((a, b) => a.id - b.id);
|
|
67
|
+
}
|
|
68
|
+
update(id, fields) {
|
|
69
|
+
// Handle delete via status
|
|
70
|
+
if (fields.status === "deleted") {
|
|
71
|
+
this.delete(id);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const oldPath = this.findTaskFile(id);
|
|
75
|
+
if (!oldPath)
|
|
76
|
+
return null;
|
|
77
|
+
const task = this.readTask(oldPath);
|
|
78
|
+
const now = isoNow();
|
|
79
|
+
if (fields.status && VALID_STATUSES.includes(fields.status)) {
|
|
80
|
+
task.status = fields.status;
|
|
81
|
+
}
|
|
82
|
+
if (fields.subject !== undefined)
|
|
83
|
+
task.subject = fields.subject;
|
|
84
|
+
if (fields.description !== undefined)
|
|
85
|
+
task.description = fields.description;
|
|
86
|
+
if (fields.activeForm !== undefined)
|
|
87
|
+
task.activeForm = fields.activeForm;
|
|
88
|
+
if (fields.owner !== undefined)
|
|
89
|
+
task.owner = fields.owner;
|
|
90
|
+
if (fields.tags !== undefined)
|
|
91
|
+
task.tags = fields.tags;
|
|
92
|
+
// Merge metadata (null values delete keys)
|
|
93
|
+
if (fields.metadata) {
|
|
94
|
+
for (const [key, val] of Object.entries(fields.metadata)) {
|
|
95
|
+
if (val === null) {
|
|
96
|
+
delete task.metadata[key];
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
task.metadata[key] = val;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Add blocking dependencies
|
|
104
|
+
if (fields.addBlockedBy) {
|
|
105
|
+
for (const blockerId of fields.addBlockedBy) {
|
|
106
|
+
if (!task.blockedBy.includes(blockerId)) {
|
|
107
|
+
task.blockedBy.push(blockerId);
|
|
108
|
+
// Update reverse: add this task to blocker's `blocks`
|
|
109
|
+
const blocker = this.get(blockerId);
|
|
110
|
+
if (blocker && !blocker.blocks.includes(id)) {
|
|
111
|
+
blocker.blocks.push(id);
|
|
112
|
+
blocker.updated = now;
|
|
113
|
+
this.writeTask(blocker);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Add tasks that this one blocks
|
|
119
|
+
if (fields.addBlocks) {
|
|
120
|
+
for (const blockedId of fields.addBlocks) {
|
|
121
|
+
if (!task.blocks.includes(blockedId)) {
|
|
122
|
+
task.blocks.push(blockedId);
|
|
123
|
+
// Update reverse: add this task to blocked's `blockedBy`
|
|
124
|
+
const blocked = this.get(blockedId);
|
|
125
|
+
if (blocked && !blocked.blockedBy.includes(id)) {
|
|
126
|
+
blocked.blockedBy.push(id);
|
|
127
|
+
blocked.updated = now;
|
|
128
|
+
this.writeTask(blocked);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// When completing, unblock dependents
|
|
134
|
+
if (fields.status === "completed") {
|
|
135
|
+
this.unblockDependents(id, now);
|
|
136
|
+
}
|
|
137
|
+
task.updated = now;
|
|
138
|
+
// Delete old file if path changed (subject change or pre-slug migration)
|
|
139
|
+
const newPath = this.taskPath(task.id, task.subject);
|
|
140
|
+
if (oldPath !== newPath) {
|
|
141
|
+
unlinkSync(oldPath);
|
|
142
|
+
}
|
|
143
|
+
this.writeTask(task);
|
|
144
|
+
return task;
|
|
145
|
+
}
|
|
146
|
+
delete(id) {
|
|
147
|
+
const path = this.findTaskFile(id);
|
|
148
|
+
if (!path)
|
|
149
|
+
return false;
|
|
150
|
+
// Clean up dependencies before removing
|
|
151
|
+
this.unblockDependents(id, isoNow());
|
|
152
|
+
this.removeFromBlockers(id, isoNow());
|
|
153
|
+
unlinkSync(path);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
count() {
|
|
157
|
+
return this.taskFiles().length;
|
|
158
|
+
}
|
|
159
|
+
// ── Private ────────────────────────────────────────────────────
|
|
160
|
+
nextId() {
|
|
161
|
+
const counterPath = join(this.dir, ".next_id");
|
|
162
|
+
let nextId = 1;
|
|
163
|
+
if (existsSync(counterPath)) {
|
|
164
|
+
const stored = parseInt(readFileSync(counterPath, "utf-8").trim(), 10);
|
|
165
|
+
if (!Number.isNaN(stored))
|
|
166
|
+
nextId = stored;
|
|
167
|
+
}
|
|
168
|
+
// Also check existing files in case counter is stale
|
|
169
|
+
const files = this.taskFiles();
|
|
170
|
+
if (files.length > 0) {
|
|
171
|
+
const maxExisting = Math.max(...files.map((f) => parseInt(f.split("-")[0], 10)).filter((n) => !Number.isNaN(n)));
|
|
172
|
+
if (maxExisting >= nextId)
|
|
173
|
+
nextId = maxExisting + 1;
|
|
174
|
+
}
|
|
175
|
+
writeFileSync(counterPath, String(nextId + 1), "utf-8");
|
|
176
|
+
return nextId;
|
|
177
|
+
}
|
|
178
|
+
taskPath(id, subject) {
|
|
179
|
+
const slug = slugify(subject);
|
|
180
|
+
return join(this.dir, slug ? `${id}-${slug}.md` : `${id}.md`);
|
|
181
|
+
}
|
|
182
|
+
/** Find a task file by ID prefix (handles slug changes) */
|
|
183
|
+
findTaskFile(id) {
|
|
184
|
+
const files = this.taskFiles();
|
|
185
|
+
const match = files.find((f) => {
|
|
186
|
+
const fileId = parseInt(f.split("-")[0], 10);
|
|
187
|
+
return fileId === id;
|
|
188
|
+
});
|
|
189
|
+
return match ? join(this.dir, match) : null;
|
|
190
|
+
}
|
|
191
|
+
taskFiles() {
|
|
192
|
+
if (!existsSync(this.dir))
|
|
193
|
+
return [];
|
|
194
|
+
return readdirSync(this.dir).filter((f) => /^\d+(-[a-z0-9-]+)?\.md$/.test(f));
|
|
195
|
+
}
|
|
196
|
+
readTask(path) {
|
|
197
|
+
const raw = readFileSync(path, "utf-8");
|
|
198
|
+
const { data, body } = parseFrontmatter(raw);
|
|
199
|
+
return {
|
|
200
|
+
id: data.id,
|
|
201
|
+
subject: data.subject ?? "",
|
|
202
|
+
description: body,
|
|
203
|
+
status: data.status ?? "pending",
|
|
204
|
+
created: data.created ?? "",
|
|
205
|
+
updated: data.updated ?? "",
|
|
206
|
+
owner: data.owner ?? "",
|
|
207
|
+
activeForm: data.activeForm ?? "",
|
|
208
|
+
blockedBy: data.blockedBy ?? [],
|
|
209
|
+
blocks: data.blocks ?? [],
|
|
210
|
+
tags: data.tags ?? [],
|
|
211
|
+
metadata: data.metadata ?? {},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
writeTask(task) {
|
|
215
|
+
const data = {
|
|
216
|
+
id: task.id,
|
|
217
|
+
subject: task.subject,
|
|
218
|
+
status: task.status,
|
|
219
|
+
created: task.created,
|
|
220
|
+
updated: task.updated,
|
|
221
|
+
owner: task.owner,
|
|
222
|
+
activeForm: task.activeForm,
|
|
223
|
+
blockedBy: task.blockedBy,
|
|
224
|
+
blocks: task.blocks,
|
|
225
|
+
tags: task.tags,
|
|
226
|
+
metadata: task.metadata,
|
|
227
|
+
};
|
|
228
|
+
const content = serializeFrontmatter(data, task.description);
|
|
229
|
+
writeFileSync(this.taskPath(task.id, task.subject), content, "utf-8");
|
|
230
|
+
}
|
|
231
|
+
/** Remove this task's ID from all dependents' blockedBy arrays */
|
|
232
|
+
unblockDependents(id, now) {
|
|
233
|
+
const task = this.get(id);
|
|
234
|
+
if (!task)
|
|
235
|
+
return;
|
|
236
|
+
for (const blockedId of task.blocks) {
|
|
237
|
+
const blocked = this.get(blockedId);
|
|
238
|
+
if (blocked) {
|
|
239
|
+
blocked.blockedBy = blocked.blockedBy.filter((bid) => bid !== id);
|
|
240
|
+
blocked.updated = now;
|
|
241
|
+
this.writeTask(blocked);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/** Remove this task's ID from all blockers' blocks arrays */
|
|
246
|
+
removeFromBlockers(id, now) {
|
|
247
|
+
const task = this.get(id);
|
|
248
|
+
if (!task)
|
|
249
|
+
return;
|
|
250
|
+
for (const blockerId of task.blockedBy) {
|
|
251
|
+
const blocker = this.get(blockerId);
|
|
252
|
+
if (blocker) {
|
|
253
|
+
blocker.blocks = blocker.blocks.filter((bid) => bid !== id);
|
|
254
|
+
blocker.updated = now;
|
|
255
|
+
this.writeTask(blocker);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type TaskStatus = "pending" | "in_progress" | "completed";
|
|
2
|
+
export declare const VALID_STATUSES: TaskStatus[];
|
|
3
|
+
export interface Task {
|
|
4
|
+
id: number;
|
|
5
|
+
subject: string;
|
|
6
|
+
description: string;
|
|
7
|
+
status: TaskStatus;
|
|
8
|
+
created: string;
|
|
9
|
+
updated: string;
|
|
10
|
+
owner: string;
|
|
11
|
+
activeForm: string;
|
|
12
|
+
blockedBy: number[];
|
|
13
|
+
blocks: number[];
|
|
14
|
+
tags: string[];
|
|
15
|
+
metadata: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
export interface TaskSummary {
|
|
18
|
+
id: number;
|
|
19
|
+
subject: string;
|
|
20
|
+
status: TaskStatus;
|
|
21
|
+
owner: string;
|
|
22
|
+
blockedBy: number[];
|
|
23
|
+
tags: string[];
|
|
24
|
+
}
|
|
25
|
+
export interface ListFilters {
|
|
26
|
+
status?: TaskStatus;
|
|
27
|
+
owner?: string;
|
|
28
|
+
tag?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface TelosConfig {
|
|
31
|
+
dir: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function loadConfig(): TelosConfig;
|
|
34
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;AAEjE,eAAO,MAAM,cAAc,EAAE,UAAU,EAA4C,CAAC;AAEpF,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,UAAU,IAAI,WAAW,CAIxC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export const VALID_STATUSES = ["pending", "in_progress", "completed"];
|
|
4
|
+
export function loadConfig() {
|
|
5
|
+
return {
|
|
6
|
+
dir: process.env.TELOS_DIR ?? join(homedir(), ".telos"),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,MAAM,CAAC,MAAM,cAAc,GAAiB,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;AAoCpF,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC;KACxD,CAAC;AACJ,CAAC"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal frontmatter parser/serializer.
|
|
3
|
+
* Handles strings, numbers, booleans, and flat arrays — no nested objects.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseFrontmatter(raw: string): {
|
|
6
|
+
data: Record<string, unknown>;
|
|
7
|
+
body: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function serializeFrontmatter(data: Record<string, unknown>, body: string): string;
|
|
10
|
+
export declare function slugify(text: string, maxLength?: number): string;
|
|
11
|
+
export declare function isoNow(): string;
|
|
12
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAsC7F;AA8BD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CA6BxF;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAK,GAAG,MAAM,CAO5D;AAED,wBAAgB,MAAM,IAAI,MAAM,CAE/B"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal frontmatter parser/serializer.
|
|
3
|
+
* Handles strings, numbers, booleans, and flat arrays — no nested objects.
|
|
4
|
+
*/
|
|
5
|
+
export function parseFrontmatter(raw) {
|
|
6
|
+
const data = {};
|
|
7
|
+
if (!raw.startsWith("---")) {
|
|
8
|
+
return { data, body: raw };
|
|
9
|
+
}
|
|
10
|
+
const end = raw.indexOf("\n---", 3);
|
|
11
|
+
if (end === -1) {
|
|
12
|
+
return { data, body: raw };
|
|
13
|
+
}
|
|
14
|
+
const frontmatter = raw.slice(4, end).trim();
|
|
15
|
+
const body = raw.slice(end + 4).trim();
|
|
16
|
+
for (const line of frontmatter.split("\n")) {
|
|
17
|
+
const colonIdx = line.indexOf(":");
|
|
18
|
+
if (colonIdx === -1)
|
|
19
|
+
continue;
|
|
20
|
+
const key = line.slice(0, colonIdx).trim();
|
|
21
|
+
const val = line.slice(colonIdx + 1).trim();
|
|
22
|
+
data[key] = parseValue(val);
|
|
23
|
+
}
|
|
24
|
+
// Reconstruct metadata_ prefixed keys into a metadata object
|
|
25
|
+
const metadata = {};
|
|
26
|
+
for (const key of Object.keys(data)) {
|
|
27
|
+
if (key.startsWith("metadata_")) {
|
|
28
|
+
metadata[key.slice(9)] = String(data[key]);
|
|
29
|
+
delete data[key];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (Object.keys(metadata).length > 0) {
|
|
33
|
+
data.metadata = metadata;
|
|
34
|
+
}
|
|
35
|
+
return { data, body };
|
|
36
|
+
}
|
|
37
|
+
function parseValue(val) {
|
|
38
|
+
// Array: [a, b, c] or [1, 2, 3]
|
|
39
|
+
if (val.startsWith("[") && val.endsWith("]")) {
|
|
40
|
+
const inner = val.slice(1, -1).trim();
|
|
41
|
+
if (inner === "")
|
|
42
|
+
return [];
|
|
43
|
+
return inner.split(",").map((item) => {
|
|
44
|
+
const trimmed = item.trim();
|
|
45
|
+
const num = Number(trimmed);
|
|
46
|
+
return Number.isNaN(num) ? trimmed : num;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Number
|
|
50
|
+
const num = Number(val);
|
|
51
|
+
if (val !== "" && !Number.isNaN(num))
|
|
52
|
+
return num;
|
|
53
|
+
// Boolean
|
|
54
|
+
if (val === "true")
|
|
55
|
+
return true;
|
|
56
|
+
if (val === "false")
|
|
57
|
+
return false;
|
|
58
|
+
// String (strip surrounding quotes if present)
|
|
59
|
+
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
|
|
60
|
+
return val.slice(1, -1);
|
|
61
|
+
}
|
|
62
|
+
return val;
|
|
63
|
+
}
|
|
64
|
+
export function serializeFrontmatter(data, body) {
|
|
65
|
+
const lines = ["---"];
|
|
66
|
+
for (const [key, val] of Object.entries(data)) {
|
|
67
|
+
if (val === undefined || val === null)
|
|
68
|
+
continue;
|
|
69
|
+
// Expand metadata object into metadata_ prefixed keys
|
|
70
|
+
if (key === "metadata" && typeof val === "object" && !Array.isArray(val)) {
|
|
71
|
+
for (const [mk, mv] of Object.entries(val)) {
|
|
72
|
+
if (mv === undefined || mv === null)
|
|
73
|
+
continue;
|
|
74
|
+
lines.push(`metadata_${mk}: ${mv}`);
|
|
75
|
+
}
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (Array.isArray(val)) {
|
|
79
|
+
lines.push(`${key}: [${val.join(", ")}]`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
lines.push(`${key}: ${val}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
lines.push("---");
|
|
86
|
+
if (body) {
|
|
87
|
+
lines.push("", body);
|
|
88
|
+
}
|
|
89
|
+
return lines.join("\n") + "\n";
|
|
90
|
+
}
|
|
91
|
+
export function slugify(text, maxLength = 50) {
|
|
92
|
+
return text
|
|
93
|
+
.toLowerCase()
|
|
94
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
95
|
+
.replace(/^-|-$/g, "")
|
|
96
|
+
.slice(0, maxLength)
|
|
97
|
+
.replace(/-$/, "");
|
|
98
|
+
}
|
|
99
|
+
export function isoNow() {
|
|
100
|
+
return new Date().toISOString();
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "telos-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Task planning MCP server with markdown file storage",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"telos-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"dev": "tsc --watch",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"mcp",
|
|
23
|
+
"tasks",
|
|
24
|
+
"planning",
|
|
25
|
+
"todo",
|
|
26
|
+
"agent",
|
|
27
|
+
"model-context-protocol"
|
|
28
|
+
],
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/skye-flyhigh/telos-mcp.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/skye-flyhigh/telos-mcp#readme",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/skye-flyhigh/telos-mcp/issues"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
39
|
+
"zod": "^3.25.67"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^22.15.21",
|
|
43
|
+
"typescript": "^5.8.3",
|
|
44
|
+
"vitest": "^4.0.18"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=20"
|
|
48
|
+
},
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"author": "Skye"
|
|
51
|
+
}
|