@j0hanz/todokit-mcp 1.0.1
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 +61 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/errors.d.ts +19 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +44 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/match.d.ts +47 -0
- package/dist/lib/match.d.ts.map +1 -0
- package/dist/lib/match.js +8 -0
- package/dist/lib/match.js.map +1 -0
- package/dist/lib/resolve.js +83 -0
- package/dist/lib/resolve.js.map +1 -0
- package/dist/lib/storage.d.ts +16 -0
- package/dist/lib/storage.d.ts.map +1 -0
- package/dist/lib/storage.js +363 -0
- package/dist/lib/storage.js.map +1 -0
- package/dist/lib/storage_filters.d.ts +12 -0
- package/dist/lib/storage_filters.d.ts.map +1 -0
- package/dist/lib/storage_filters.js +70 -0
- package/dist/lib/storage_filters.js.map +1 -0
- package/dist/lib/tool_response.d.ts +5 -0
- package/dist/lib/tool_response.d.ts.map +1 -0
- package/dist/lib/tool_response.js +7 -0
- package/dist/lib/tool_response.js.map +1 -0
- package/dist/lib/types.d.ts +72 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +16 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/schemas/inputs.d.ts +170 -0
- package/dist/schemas/inputs.d.ts.map +1 -0
- package/dist/schemas/inputs.js +163 -0
- package/dist/schemas/inputs.js.map +1 -0
- package/dist/schemas/iso_date.js +20 -0
- package/dist/schemas/iso_date.js.map +1 -0
- package/dist/schemas/outputs.d.ts +30 -0
- package/dist/schemas/outputs.d.ts.map +1 -0
- package/dist/schemas/outputs.js +9 -0
- package/dist/schemas/outputs.js.map +1 -0
- package/dist/tools/add_todo.d.ts +3 -0
- package/dist/tools/add_todo.d.ts.map +1 -0
- package/dist/tools/add_todo.js +34 -0
- package/dist/tools/add_todo.js.map +1 -0
- package/dist/tools/add_todos.d.ts +3 -0
- package/dist/tools/add_todos.d.ts.map +1 -0
- package/dist/tools/add_todos.js +34 -0
- package/dist/tools/add_todos.js.map +1 -0
- package/dist/tools/complete_todo.d.ts +3 -0
- package/dist/tools/complete_todo.d.ts.map +1 -0
- package/dist/tools/complete_todo.js +65 -0
- package/dist/tools/complete_todo.js.map +1 -0
- package/dist/tools/delete_todo.d.ts +3 -0
- package/dist/tools/delete_todo.d.ts.map +1 -0
- package/dist/tools/delete_todo.js +95 -0
- package/dist/tools/delete_todo.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list_todos.d.ts +3 -0
- package/dist/tools/list_todos.d.ts.map +1 -0
- package/dist/tools/list_todos.js +157 -0
- package/dist/tools/list_todos.js.map +1 -0
- package/dist/tools/update_todo.d.ts +3 -0
- package/dist/tools/update_todo.d.ts.map +1 -0
- package/dist/tools/update_todo.js +90 -0
- package/dist/tools/update_todo.js.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Todokit MCP Server
|
|
2
|
+
|
|
3
|
+
A minimal, efficient Model Context Protocol (MCP) server for managing a to-do list.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Add todos
|
|
8
|
+
- List todos
|
|
9
|
+
- Complete todos
|
|
10
|
+
- Delete todos
|
|
11
|
+
- Persists data to `todos.json`
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Build
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install
|
|
19
|
+
npm run build
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Development
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run lint
|
|
26
|
+
npm run type-check
|
|
27
|
+
npm run test
|
|
28
|
+
npm run test:coverage
|
|
29
|
+
npm run dup-check
|
|
30
|
+
npm run bench
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Storage Location
|
|
34
|
+
|
|
35
|
+
By default, todos are stored in `todos.json` at the repo root. To override the
|
|
36
|
+
path (useful for tests or sandboxing), set `TODOKIT_TODO_FILE`:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
TODOKIT_TODO_FILE=/tmp/todokit.json npm start
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Run
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm start
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Configure in Claude Desktop / Cursor
|
|
49
|
+
|
|
50
|
+
Add to your MCP config:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"mcpServers": {
|
|
55
|
+
"todokit": {
|
|
56
|
+
"command": "node",
|
|
57
|
+
"args": ["C:\\todokit\\dist\\index.js"]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
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,30 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { registerAllTools } from './tools/index.js';
|
|
4
|
+
const server = new McpServer({ name: 'todokit', version: '1.0.0' }, {
|
|
5
|
+
instructions: 'Todokit to-do list manager',
|
|
6
|
+
capabilities: { logging: {} },
|
|
7
|
+
});
|
|
8
|
+
registerAllTools(server);
|
|
9
|
+
async function shutdown(signal) {
|
|
10
|
+
try {
|
|
11
|
+
await server.close();
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
console.error(`Shutdown error (${signal}):`, error);
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
process.on('SIGINT', shutdown);
|
|
21
|
+
process.on('SIGTERM', shutdown);
|
|
22
|
+
async function main() {
|
|
23
|
+
const transport = new StdioServerTransport();
|
|
24
|
+
await server.connect(transport);
|
|
25
|
+
}
|
|
26
|
+
main().catch((error) => {
|
|
27
|
+
console.error('Server error:', error);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,EACrC;IACE,YAAY,EAAE,4BAA4B;IAC1C,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;CAC9B,CACF,CAAC;AAEF,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAEzB,KAAK,UAAU,QAAQ,CAAC,MAAsB;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,mBAAmB,MAAM,IAAI,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEhC,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ErrorResponse {
|
|
2
|
+
[key: string]: unknown;
|
|
3
|
+
content: {
|
|
4
|
+
type: 'text';
|
|
5
|
+
text: string;
|
|
6
|
+
}[];
|
|
7
|
+
structuredContent: {
|
|
8
|
+
ok: false;
|
|
9
|
+
error: {
|
|
10
|
+
code: string;
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
result?: unknown;
|
|
14
|
+
};
|
|
15
|
+
isError: true;
|
|
16
|
+
}
|
|
17
|
+
export declare function getErrorMessage(error: unknown): string;
|
|
18
|
+
export declare function createErrorResponse(code: string, message: string, result?: unknown): ErrorResponse;
|
|
19
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,iBAAiB,EAAE;QACjB,EAAE,EAAE,KAAK,CAAC;QACV,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;QACzC,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,OAAO,EAAE,IAAI,CAAC;CACf;AAgCD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAOtD;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO,GACf,aAAa,CAWf"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
function getMessageFromErrorInstance(error) {
|
|
2
|
+
if (error instanceof Error && error.message) {
|
|
3
|
+
return error.message;
|
|
4
|
+
}
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
function getMessageFromString(error) {
|
|
8
|
+
if (typeof error === 'string' && error.length > 0) {
|
|
9
|
+
return error;
|
|
10
|
+
}
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
function isNonEmptyString(value) {
|
|
14
|
+
return typeof value === 'string' && value.length > 0;
|
|
15
|
+
}
|
|
16
|
+
function isObjectWithMessage(value) {
|
|
17
|
+
return typeof value === 'object' && value !== null && 'message' in value;
|
|
18
|
+
}
|
|
19
|
+
function getMessageFromObject(error) {
|
|
20
|
+
if (!isObjectWithMessage(error)) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const message = error.message;
|
|
24
|
+
return isNonEmptyString(message) ? message : undefined;
|
|
25
|
+
}
|
|
26
|
+
export function getErrorMessage(error) {
|
|
27
|
+
return (getMessageFromErrorInstance(error) ??
|
|
28
|
+
getMessageFromString(error) ??
|
|
29
|
+
getMessageFromObject(error) ??
|
|
30
|
+
'Unknown error');
|
|
31
|
+
}
|
|
32
|
+
export function createErrorResponse(code, message, result) {
|
|
33
|
+
const structured = {
|
|
34
|
+
ok: false,
|
|
35
|
+
error: { code, message },
|
|
36
|
+
...(result === undefined ? {} : { result }),
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: 'text', text: JSON.stringify(structured) }],
|
|
40
|
+
structuredContent: structured,
|
|
41
|
+
isError: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAWA,SAAS,2BAA2B,CAAC,KAAc;IACjD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAC5C,OAAO,KAAK,CAAC,OAAO,CAAC;IACvB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc;IAC1C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,SAAS,IAAI,KAAK,CAAC;AAC3E,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc;IAC1C,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,CACL,2BAA2B,CAAC,KAAK,CAAC;QAClC,oBAAoB,CAAC,KAAK,CAAC;QAC3B,oBAAoB,CAAC,KAAK,CAAC;QAC3B,eAAe,CAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,OAAe,EACf,MAAgB;IAEhB,MAAM,UAAU,GAAuC;QACrD,EAAE,EAAE,KAAK;QACT,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QACxB,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;KAC5C,CAAC;IACF,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;QACtE,iBAAiB,EAAE,UAAU;QAC7B,OAAO,EAAE,IAAa;KACvB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ErrorResponse } from './errors.js';
|
|
2
|
+
import type { Todo } from './types.js';
|
|
3
|
+
export interface TodoMatchPreview {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
priority: Todo['priority'];
|
|
7
|
+
dueDate?: string;
|
|
8
|
+
completed: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function buildMatchPreview(todo: Todo): TodoMatchPreview;
|
|
11
|
+
export declare function buildMatchPreviews(todos: Todo[], limit?: number): TodoMatchPreview[];
|
|
12
|
+
export interface ResolveTodoInput {
|
|
13
|
+
id?: string;
|
|
14
|
+
query?: string;
|
|
15
|
+
}
|
|
16
|
+
export type ResolveTodoResult = {
|
|
17
|
+
kind: 'match';
|
|
18
|
+
todo: Todo;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'missing';
|
|
21
|
+
response: ErrorResponse;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'not_found';
|
|
24
|
+
response: ErrorResponse;
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'ambiguous';
|
|
27
|
+
response: ErrorResponse;
|
|
28
|
+
matches: Todo[];
|
|
29
|
+
previews: TodoMatchPreview[];
|
|
30
|
+
query: string;
|
|
31
|
+
};
|
|
32
|
+
export type MatchOutcome = {
|
|
33
|
+
kind: 'match';
|
|
34
|
+
todo: Todo;
|
|
35
|
+
} | {
|
|
36
|
+
kind: 'ambiguous';
|
|
37
|
+
response: ErrorResponse;
|
|
38
|
+
matches: Todo[];
|
|
39
|
+
previews: TodoMatchPreview[];
|
|
40
|
+
query: string;
|
|
41
|
+
} | {
|
|
42
|
+
kind: 'error';
|
|
43
|
+
response: ErrorResponse;
|
|
44
|
+
};
|
|
45
|
+
export declare function unwrapResolution(result: ResolveTodoResult): MatchOutcome;
|
|
46
|
+
export declare function resolveTodoTarget(input: ResolveTodoInput): Promise<ResolveTodoResult>;
|
|
47
|
+
//# sourceMappingURL=match.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../src/lib/match.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,gBAAgB,CAQ9D;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,IAAI,EAAE,EACb,KAAK,GAAE,MAAsB,GAC5B,gBAAgB,EAAE,CAEpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC9C;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,IAAI,EAAE,CAAC;IAChB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAC7B;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,IAAI,EAAE,CAAC;IAChB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,CAAC;AAE/C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAQxE;AA6DD,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,iBAAiB,CAAC,CAQ5B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { buildMatchPreview, buildMatchPreviews, resolveTodoTargetFromTodos, unwrapResolution, } from './resolve.js';
|
|
2
|
+
import { getTodos } from './storage.js';
|
|
3
|
+
export { buildMatchPreview, buildMatchPreviews, resolveTodoTargetFromTodos, unwrapResolution, };
|
|
4
|
+
export async function resolveTodoTarget(input) {
|
|
5
|
+
const todos = await getTodos();
|
|
6
|
+
return resolveTodoTargetFromTodos(todos, input);
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=match.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/lib/match.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAIlB,0BAA0B,EAE1B,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,0BAA0B,EAC1B,gBAAgB,GAKjB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAuB;IAEvB,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,OAAO,0BAA0B,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createErrorResponse } from './errors.js';
|
|
2
|
+
import { filterTodos } from './storage_filters.js';
|
|
3
|
+
const PREVIEW_LIMIT = 5;
|
|
4
|
+
function buildMatchPreview(todo) {
|
|
5
|
+
return {
|
|
6
|
+
id: todo.id,
|
|
7
|
+
title: todo.title,
|
|
8
|
+
priority: todo.priority,
|
|
9
|
+
dueDate: todo.dueDate,
|
|
10
|
+
completed: todo.completed,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function buildMatchPreviews(todos, limit = PREVIEW_LIMIT) {
|
|
14
|
+
return todos.slice(0, limit).map(buildMatchPreview);
|
|
15
|
+
}
|
|
16
|
+
export function toResolveInput(input) {
|
|
17
|
+
if (input.id) {
|
|
18
|
+
return { id: input.id };
|
|
19
|
+
}
|
|
20
|
+
if (input.query) {
|
|
21
|
+
return { query: input.query };
|
|
22
|
+
}
|
|
23
|
+
throw new Error('Provide id or query to identify the todo');
|
|
24
|
+
}
|
|
25
|
+
export function unwrapResolution(result) {
|
|
26
|
+
if (result.kind === 'match') {
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
if (result.kind === 'ambiguous') {
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
return { kind: 'error', response: result.response };
|
|
33
|
+
}
|
|
34
|
+
function createMissingIdentifierError() {
|
|
35
|
+
return createErrorResponse('E_BAD_REQUEST', 'Provide id or query to identify the todo');
|
|
36
|
+
}
|
|
37
|
+
function createNotFoundError(target) {
|
|
38
|
+
return createErrorResponse('E_NOT_FOUND', `Todo "${target}" not found`);
|
|
39
|
+
}
|
|
40
|
+
function createAmbiguousError(query, matches) {
|
|
41
|
+
const previews = buildMatchPreviews(matches);
|
|
42
|
+
const response = createErrorResponse('E_AMBIGUOUS', `Multiple todos match "${query}"`, {
|
|
43
|
+
matches: previews,
|
|
44
|
+
totalMatches: matches.length,
|
|
45
|
+
hint: `Multiple todos match "${query}". Use id for an exact match.`,
|
|
46
|
+
});
|
|
47
|
+
return { response, previews };
|
|
48
|
+
}
|
|
49
|
+
function resolveByIdFromTodos(todos, id) {
|
|
50
|
+
const match = todos.find((todo) => todo.id === id);
|
|
51
|
+
if (!match) {
|
|
52
|
+
return { kind: 'not_found', response: createNotFoundError(id) };
|
|
53
|
+
}
|
|
54
|
+
return { kind: 'match', todo: match };
|
|
55
|
+
}
|
|
56
|
+
function resolveByQueryFromTodos(todos, query) {
|
|
57
|
+
const trimmedQuery = query.trim();
|
|
58
|
+
if (!trimmedQuery) {
|
|
59
|
+
return { kind: 'missing', response: createMissingIdentifierError() };
|
|
60
|
+
}
|
|
61
|
+
const matches = filterTodos(todos, { query: trimmedQuery });
|
|
62
|
+
if (matches.length === 1 && matches[0]) {
|
|
63
|
+
return { kind: 'match', todo: matches[0] };
|
|
64
|
+
}
|
|
65
|
+
if (matches.length === 0) {
|
|
66
|
+
return { kind: 'not_found', response: createNotFoundError(trimmedQuery) };
|
|
67
|
+
}
|
|
68
|
+
const { response, previews } = createAmbiguousError(trimmedQuery, matches);
|
|
69
|
+
return {
|
|
70
|
+
kind: 'ambiguous',
|
|
71
|
+
response,
|
|
72
|
+
matches,
|
|
73
|
+
previews,
|
|
74
|
+
query: trimmedQuery,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function resolveTodoTargetFromTodos(todos, input) {
|
|
78
|
+
if (input.id !== undefined) {
|
|
79
|
+
return resolveByIdFromTodos(todos, input.id);
|
|
80
|
+
}
|
|
81
|
+
return resolveByQueryFromTodos(todos, input.query);
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/lib/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { normalizeTags, type TodoFilters } from './storage_filters.js';
|
|
2
|
+
import { type Todo } from './types.js';
|
|
3
|
+
export { normalizeTags };
|
|
4
|
+
export declare function getTodos(filters?: TodoFilters): Promise<Todo[]>;
|
|
5
|
+
interface NewTodoInput {
|
|
6
|
+
title: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
priority?: 'low' | 'normal' | 'high';
|
|
9
|
+
dueDate?: string;
|
|
10
|
+
tags?: string[];
|
|
11
|
+
}
|
|
12
|
+
export declare function addTodo(title: string, description?: string, priority?: 'low' | 'normal' | 'high', dueDate?: string, tags?: string[]): Promise<Todo>;
|
|
13
|
+
export declare function addTodos(items: NewTodoInput[]): Promise<Todo[]>;
|
|
14
|
+
export declare function updateTodo(id: string, updates: Partial<Omit<Todo, 'id' | 'createdAt'>>): Promise<Todo | null>;
|
|
15
|
+
export declare function deleteTodo(id: string): Promise<boolean>;
|
|
16
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/lib/storage.ts"],"names":[],"mappings":"AAYA,OAAO,EAEL,aAAa,EACb,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,KAAK,IAAI,EAAe,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,CAAC;AAwFzB,wBAAsB,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAIrE;AAED,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAsB,OAAO,CAC3B,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,QAAQ,GAAE,KAAK,GAAG,QAAQ,GAAG,MAAiB,EAC9C,OAAO,CAAC,EAAE,MAAM,EAChB,IAAI,GAAE,MAAM,EAAO,GAClB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAsB,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAoBrE;AAmED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,CAAC,CAAC,GAC/C,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAiBtB;AAED,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAS7D"}
|