@perrylink/dsh-ticktick 0.1.2
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/CHANGELOG.md +24 -0
- package/LICENSE +201 -0
- package/README.es.md +41 -0
- package/README.hi.md +33 -0
- package/README.md +111 -0
- package/README.pt.md +41 -0
- package/README.zh.md +111 -0
- package/cordis.patch.yml +35 -0
- package/lib/client.js +6233 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +1349 -0
- package/lib/typert.host.js +26 -0
- package/lib/types/client/TicktickAction.d.ts +29 -0
- package/lib/types/client/TicktickAction.d.ts.map +1 -0
- package/lib/types/client/TicktickSettingsCard.d.ts +27 -0
- package/lib/types/client/TicktickSettingsCard.d.ts.map +1 -0
- package/lib/types/client/api.d.ts +34 -0
- package/lib/types/client/api.d.ts.map +1 -0
- package/lib/types/client/dates.d.ts +26 -0
- package/lib/types/client/dates.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +34 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/locales.d.ts +61 -0
- package/lib/types/client/locales.d.ts.map +1 -0
- package/lib/types/client/order.d.ts +25 -0
- package/lib/types/client/order.d.ts.map +1 -0
- package/lib/types/client/remote.d.ts +260 -0
- package/lib/types/client/remote.d.ts.map +1 -0
- package/lib/types/client/styles.d.ts +13 -0
- package/lib/types/client/styles.d.ts.map +1 -0
- package/lib/types/config.d.ts +64 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/domain.d.ts +70 -0
- package/lib/types/domain.d.ts.map +1 -0
- package/lib/types/index.d.ts +56 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/mcp.d.ts +94 -0
- package/lib/types/mcp.d.ts.map +1 -0
- package/lib/types/service.d.ts +160 -0
- package/lib/types/service.d.ts.map +1 -0
- package/lib/types/tools.d.ts +18 -0
- package/lib/types/tools.d.ts.map +1 -0
- package/lib/types/typert.host.d.ts +216 -0
- package/lib/types/typert.host.d.ts.map +1 -0
- package/lib/types/wire.d.ts +561 -0
- package/lib/types/wire.d.ts.map +1 -0
- package/lib/wire-C-vDxxnC.js +5288 -0
- package/package.json +187 -0
- package/probes/lib.mjs +65 -0
- package/probes/probe-bootstrap.mjs +10 -0
- package/probes/probe-crud.mjs +15 -0
- package/probes/probe-due.mjs +28 -0
- package/probes/probe-queries.mjs +18 -0
- package/probes/probe-reorder.mjs +24 -0
- package/src/client/TicktickAction.tsx +356 -0
- package/src/client/TicktickSettingsCard.tsx +182 -0
- package/src/client/api.ts +56 -0
- package/src/client/dates.ts +61 -0
- package/src/client/index.ts +119 -0
- package/src/client/locales.ts +113 -0
- package/src/client/order.ts +37 -0
- package/src/client/remote.ts +76 -0
- package/src/client/styles.ts +48 -0
- package/src/config.ts +136 -0
- package/src/domain.ts +224 -0
- package/src/index.ts +139 -0
- package/src/mcp.ts +213 -0
- package/src/service.ts +403 -0
- package/src/tools.ts +336 -0
- package/src/typert.host.ts +25 -0
- package/src/wire.ts +401 -0
package/src/tools.ts
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The curated model-facing tools of the TickTick bridge. All eight reuse the
|
|
3
|
+
* host service's business methods, so the model and the widget share one
|
|
4
|
+
* policy (protected ids, workarounds, error codes). Each `output.schema`
|
|
5
|
+
* returns a structured JSON value — the Code Mode `await tools.ticktick_*`
|
|
6
|
+
* surface derives from it — while `output.render` carries the human text.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-ticktick/tools
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
12
|
+
import type { TicktickService } from './service.ts'
|
|
13
|
+
import type { TicktickTaskWire } from './wire.ts'
|
|
14
|
+
|
|
15
|
+
/** Task wire projection shared by the add/tasks tools. */
|
|
16
|
+
function taskWire(task: TicktickTaskWire): string {
|
|
17
|
+
const due = task.dueDate === null ? 'no due date' : task.dueDate
|
|
18
|
+
return `${task.title} [${task.projectId ?? '?'}] due ${due}`
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Value schema of one task wire row. */
|
|
22
|
+
const TASK_ROW_SCHEMA = {
|
|
23
|
+
type: 'object' as const,
|
|
24
|
+
properties: {
|
|
25
|
+
id: { type: 'string' as const, required: true as const },
|
|
26
|
+
title: { type: 'string' as const, required: true as const },
|
|
27
|
+
done: { type: 'boolean' as const, required: true as const },
|
|
28
|
+
projectId: { oneOf: [{ type: 'string' as const }, { type: 'null' as const }] as const, required: true as const },
|
|
29
|
+
dueDate: { oneOf: [{ type: 'string' as const }, { type: 'null' as const }] as const, required: true as const },
|
|
30
|
+
sortOrder: { oneOf: [{ type: 'number' as const }, { type: 'null' as const }] as const, required: true as const },
|
|
31
|
+
},
|
|
32
|
+
additionalProperties: false as const,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Value schema of an `{ ok: boolean }` mutation result. */
|
|
36
|
+
const OK_RESULT_SCHEMA = {
|
|
37
|
+
type: 'object' as const,
|
|
38
|
+
properties: {
|
|
39
|
+
ok: { type: 'boolean' as const, required: true as const },
|
|
40
|
+
},
|
|
41
|
+
additionalProperties: false as const,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Build the eight tools bound to one service instance.
|
|
46
|
+
* @param service - the mounted TickTick service.
|
|
47
|
+
* @returns the registered tool definitions.
|
|
48
|
+
*/
|
|
49
|
+
export function buildTicktickTools(service: TicktickService): ReturnType<typeof defineTool>[] {
|
|
50
|
+
return [
|
|
51
|
+
defineTool({
|
|
52
|
+
name: 'ticktick_status',
|
|
53
|
+
description: 'Read the TickTick (Dida365) bridge connection state: token configured, client connected, endpoint, and last error.',
|
|
54
|
+
parameters: {},
|
|
55
|
+
output: {
|
|
56
|
+
schema: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
configured: { type: 'boolean', required: true },
|
|
60
|
+
connected: { type: 'boolean', required: true },
|
|
61
|
+
mcpUrl: { type: 'string', required: true },
|
|
62
|
+
lastError: { oneOf: [{ type: 'string' as const }, { type: 'null' as const }] as const, required: true },
|
|
63
|
+
},
|
|
64
|
+
additionalProperties: false,
|
|
65
|
+
},
|
|
66
|
+
render: (_args, value) => {
|
|
67
|
+
const status = value as { configured: boolean, connected: boolean, mcpUrl: string, lastError: string | null }
|
|
68
|
+
const line = status.configured
|
|
69
|
+
? (status.connected ? `connected to ${status.mcpUrl}` : 'configured but not connected')
|
|
70
|
+
: 'not configured (no token)'
|
|
71
|
+
return [{ type: 'text', text: status.lastError === null ? `TickTick bridge: ${line}` : `TickTick bridge: ${line}; last error: ${status.lastError}` }]
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
async execute() {
|
|
75
|
+
const status = service.status()
|
|
76
|
+
return {
|
|
77
|
+
configured: status.configured,
|
|
78
|
+
connected: status.connected,
|
|
79
|
+
mcpUrl: status.mcpUrl,
|
|
80
|
+
lastError: status.lastError,
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
}),
|
|
84
|
+
defineTool({
|
|
85
|
+
name: 'ticktick_lists',
|
|
86
|
+
description: 'List every TickTick list (project), including the virtual Inbox.',
|
|
87
|
+
parameters: {},
|
|
88
|
+
output: {
|
|
89
|
+
schema: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
properties: {
|
|
92
|
+
projects: {
|
|
93
|
+
type: 'array',
|
|
94
|
+
required: true,
|
|
95
|
+
items: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
properties: {
|
|
98
|
+
id: { type: 'string', required: true },
|
|
99
|
+
name: { type: 'string', required: true },
|
|
100
|
+
},
|
|
101
|
+
additionalProperties: false,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
additionalProperties: false,
|
|
106
|
+
},
|
|
107
|
+
render: (_args, value) => {
|
|
108
|
+
const { projects } = value as { projects: readonly { id: string, name: string }[] }
|
|
109
|
+
return [{ type: 'text', text: projects.length === 0 ? 'no lists' : projects.map(p => `${p.name} (${p.id})`).join('\n') }]
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
async execute() {
|
|
113
|
+
const result = await service.projects()
|
|
114
|
+
return { projects: [...result.projects] }
|
|
115
|
+
},
|
|
116
|
+
}),
|
|
117
|
+
defineTool({
|
|
118
|
+
name: 'ticktick_tasks',
|
|
119
|
+
description: 'List undone TickTick tasks: one named list, or every list aggregated with per-list warnings for lists the server could not read.',
|
|
120
|
+
parameters: {
|
|
121
|
+
projectId: { type: 'string', description: 'Optional list id (omit for every list)' },
|
|
122
|
+
},
|
|
123
|
+
output: {
|
|
124
|
+
schema: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
tasks: { type: 'array', required: true, items: TASK_ROW_SCHEMA },
|
|
128
|
+
warnings: { type: 'array', required: true, items: { type: 'string' } },
|
|
129
|
+
},
|
|
130
|
+
additionalProperties: false,
|
|
131
|
+
},
|
|
132
|
+
render: (_args, value) => {
|
|
133
|
+
const { tasks, warnings } = value as { tasks: readonly TicktickTaskWire[], warnings: readonly string[] }
|
|
134
|
+
const lines = tasks.length === 0 ? ['no undone tasks'] : tasks.map(taskWire)
|
|
135
|
+
if (warnings.length > 0) lines.push(...warnings.map(w => `warning: ${w}`))
|
|
136
|
+
return [{ type: 'text', text: lines.join('\n') }]
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
async execute(args) {
|
|
140
|
+
const result = await service.tasks(args.projectId)
|
|
141
|
+
return { tasks: [...result.tasks], warnings: [...result.warnings] }
|
|
142
|
+
},
|
|
143
|
+
}),
|
|
144
|
+
defineTool({
|
|
145
|
+
name: 'ticktick_add',
|
|
146
|
+
description: 'Create one TickTick task: a named list places it there, otherwise the Inbox.',
|
|
147
|
+
parameters: {
|
|
148
|
+
title: { type: 'string', required: true, description: 'Task title' },
|
|
149
|
+
projectId: { type: 'string', description: 'Optional list id (default Inbox)' },
|
|
150
|
+
dueDate: { type: 'string', description: 'Optional ISO due date (e.g. 2026-09-05 or a full ISO date-time)' },
|
|
151
|
+
},
|
|
152
|
+
output: {
|
|
153
|
+
schema: {
|
|
154
|
+
type: 'object',
|
|
155
|
+
properties: {
|
|
156
|
+
task: { oneOf: [TASK_ROW_SCHEMA, { type: 'null' as const }] as const, required: true },
|
|
157
|
+
verifyWarning: { oneOf: [{ type: 'string' as const }, { type: 'null' as const }] as const, required: true },
|
|
158
|
+
},
|
|
159
|
+
additionalProperties: false,
|
|
160
|
+
},
|
|
161
|
+
render: (_args, value) => {
|
|
162
|
+
const { task, verifyWarning } = value as { task: TicktickTaskWire | null, verifyWarning: string | null }
|
|
163
|
+
const line = task === null ? 'task created (server returned no echo)' : `created: ${taskWire(task)}`
|
|
164
|
+
return [{ type: 'text', text: verifyWarning === null ? line : `${line}; verification warning: ${verifyWarning}` }]
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
async execute(args) {
|
|
168
|
+
return service.add(args.title, args.projectId, args.dueDate)
|
|
169
|
+
},
|
|
170
|
+
}),
|
|
171
|
+
defineTool({
|
|
172
|
+
name: 'ticktick_complete',
|
|
173
|
+
description: 'Mark one TickTick task complete (both the task id and its list id are required).',
|
|
174
|
+
parameters: {
|
|
175
|
+
id: { type: 'string', required: true, description: 'Task id' },
|
|
176
|
+
projectId: { type: 'string', required: true, description: 'Owning list id' },
|
|
177
|
+
},
|
|
178
|
+
output: {
|
|
179
|
+
schema: OK_RESULT_SCHEMA,
|
|
180
|
+
render: (_args, value) => {
|
|
181
|
+
const { ok } = value as { ok: boolean }
|
|
182
|
+
return [{ type: 'text', text: ok ? 'task completed' : 'completion rejected' }]
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
async execute(args) {
|
|
186
|
+
return service.complete(args.id, args.projectId)
|
|
187
|
+
},
|
|
188
|
+
}),
|
|
189
|
+
defineTool({
|
|
190
|
+
name: 'ticktick_delete',
|
|
191
|
+
description: 'Delete one TickTick task (both the task id and its list id are required).',
|
|
192
|
+
parameters: {
|
|
193
|
+
id: { type: 'string', required: true, description: 'Task id' },
|
|
194
|
+
projectId: { type: 'string', required: true, description: 'Owning list id' },
|
|
195
|
+
},
|
|
196
|
+
output: {
|
|
197
|
+
schema: OK_RESULT_SCHEMA,
|
|
198
|
+
render: (_args, value) => {
|
|
199
|
+
const { ok } = value as { ok: boolean }
|
|
200
|
+
return [{ type: 'text', text: ok ? 'task deleted' : 'delete rejected' }]
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
async execute(args) {
|
|
204
|
+
return service.remove(args.id, args.projectId)
|
|
205
|
+
},
|
|
206
|
+
}),
|
|
207
|
+
defineTool({
|
|
208
|
+
name: 'ticktick_due',
|
|
209
|
+
description: 'Set or clear one TickTick task due date. Omit dueDate to clear. Project tasks fall back to a move-to-inbox detour when the server rejects the direct update.',
|
|
210
|
+
parameters: {
|
|
211
|
+
id: { type: 'string', required: true, description: 'Task id' },
|
|
212
|
+
projectId: { type: 'string', description: 'Owning list id (required for project tasks)' },
|
|
213
|
+
dueDate: { type: 'string', description: 'ISO due date; omit to clear' },
|
|
214
|
+
},
|
|
215
|
+
output: {
|
|
216
|
+
schema: OK_RESULT_SCHEMA,
|
|
217
|
+
render: (_args, value) => {
|
|
218
|
+
const { ok } = value as { ok: boolean }
|
|
219
|
+
return [{ type: 'text', text: ok ? 'due date applied' : 'due date rejected' }]
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
async execute(args) {
|
|
223
|
+
return service.setDue(args.id, args.projectId, args.dueDate)
|
|
224
|
+
},
|
|
225
|
+
}),
|
|
226
|
+
defineTool({
|
|
227
|
+
name: 'ticktick_reorder',
|
|
228
|
+
description: 'Move one TickTick task to a new sortOrder (lists order by descending sortOrder; compute the target from the neighboring task).',
|
|
229
|
+
parameters: {
|
|
230
|
+
id: { type: 'string', required: true, description: 'Task id' },
|
|
231
|
+
projectId: { type: 'string', description: 'Owning list id (inbox tasks omit it)' },
|
|
232
|
+
sortOrder: { type: 'integer', required: true, description: 'Integer sortOrder to assign' },
|
|
233
|
+
},
|
|
234
|
+
output: {
|
|
235
|
+
schema: OK_RESULT_SCHEMA,
|
|
236
|
+
render: (_args, value) => {
|
|
237
|
+
const { ok } = value as { ok: boolean }
|
|
238
|
+
return [{ type: 'text', text: ok ? 'task reordered' : 'reorder rejected' }]
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
async execute(args) {
|
|
242
|
+
return service.reorder(args.id, args.projectId, args.sortOrder)
|
|
243
|
+
},
|
|
244
|
+
}),
|
|
245
|
+
defineTool({
|
|
246
|
+
name: 'ticktick_completed',
|
|
247
|
+
description: 'List TickTick tasks completed within a window (default the last 30 days), optionally narrowed to one list.',
|
|
248
|
+
parameters: {
|
|
249
|
+
projectId: { type: 'string', description: 'Optional list id (omit for every list)' },
|
|
250
|
+
days: { type: 'integer', description: 'Window length in days (default 30)' },
|
|
251
|
+
},
|
|
252
|
+
output: {
|
|
253
|
+
schema: {
|
|
254
|
+
type: 'object',
|
|
255
|
+
properties: {
|
|
256
|
+
tasks: { type: 'array', required: true, items: TASK_ROW_SCHEMA },
|
|
257
|
+
warnings: { type: 'array', required: true, items: { type: 'string' } },
|
|
258
|
+
},
|
|
259
|
+
additionalProperties: false,
|
|
260
|
+
},
|
|
261
|
+
render: (_args, value) => {
|
|
262
|
+
const { tasks, warnings } = value as { tasks: readonly TicktickTaskWire[], warnings: readonly string[] }
|
|
263
|
+
const lines = tasks.length === 0 ? ['no completed tasks in the window'] : tasks.map(taskWire)
|
|
264
|
+
if (warnings.length > 0) lines.push(...warnings.map(w => `warning: ${w}`))
|
|
265
|
+
return [{ type: 'text', text: lines.join('\n') }]
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
async execute(args) {
|
|
269
|
+
const result = await service.completed(args.projectId, args.days)
|
|
270
|
+
return { tasks: [...result.tasks], warnings: [...result.warnings] }
|
|
271
|
+
},
|
|
272
|
+
}),
|
|
273
|
+
defineTool({
|
|
274
|
+
name: 'ticktick_search',
|
|
275
|
+
description: 'Full-text search over TickTick tasks (the official search / search_task tool).',
|
|
276
|
+
parameters: {
|
|
277
|
+
query: { type: 'string', required: true, description: 'Search keyword' },
|
|
278
|
+
},
|
|
279
|
+
output: {
|
|
280
|
+
schema: {
|
|
281
|
+
type: 'object',
|
|
282
|
+
properties: {
|
|
283
|
+
tasks: { type: 'array', required: true, items: TASK_ROW_SCHEMA },
|
|
284
|
+
warnings: { type: 'array', required: true, items: { type: 'string' } },
|
|
285
|
+
},
|
|
286
|
+
additionalProperties: false,
|
|
287
|
+
},
|
|
288
|
+
render: (_args, value) => {
|
|
289
|
+
const { tasks } = value as { tasks: readonly TicktickTaskWire[], warnings: readonly string[] }
|
|
290
|
+
const lines = tasks.length === 0 ? ['no matches'] : tasks.map(taskWire)
|
|
291
|
+
return [{ type: 'text', text: lines.join('\n') }]
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
async execute(args) {
|
|
295
|
+
const result = await service.search(args.query)
|
|
296
|
+
return { tasks: [...result.tasks], warnings: [...result.warnings] }
|
|
297
|
+
},
|
|
298
|
+
}),
|
|
299
|
+
defineTool({
|
|
300
|
+
name: 'ticktick_batch_add',
|
|
301
|
+
description: 'Create several TickTick tasks in one call (batch_add_tasks); rows carry title plus optional list id and ISO due date.',
|
|
302
|
+
parameters: {
|
|
303
|
+
tasks: {
|
|
304
|
+
type: 'array',
|
|
305
|
+
required: true,
|
|
306
|
+
description: 'Task rows to create',
|
|
307
|
+
items: {
|
|
308
|
+
type: 'object',
|
|
309
|
+
properties: {
|
|
310
|
+
title: { type: 'string', required: true },
|
|
311
|
+
projectId: { type: 'string' },
|
|
312
|
+
dueDate: { type: 'string' },
|
|
313
|
+
},
|
|
314
|
+
additionalProperties: false,
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
output: {
|
|
319
|
+
schema: {
|
|
320
|
+
type: 'object',
|
|
321
|
+
properties: {
|
|
322
|
+
created: { type: 'integer', required: true },
|
|
323
|
+
},
|
|
324
|
+
additionalProperties: false,
|
|
325
|
+
},
|
|
326
|
+
render: (_args, value) => {
|
|
327
|
+
const { created } = value as { created: number }
|
|
328
|
+
return [{ type: 'text', text: `created ${created} task${created === 1 ? '' : 's'}` }]
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
async execute(args) {
|
|
332
|
+
return service.batchAdd(args.tasks)
|
|
333
|
+
},
|
|
334
|
+
}),
|
|
335
|
+
]
|
|
336
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hand-written Typert HOST manifest for `dsh-ticktick`, exported as
|
|
3
|
+
* `./typert` so the harness's typert-loader registers the `ticktick`
|
|
4
|
+
* invocations automatically when this plugin mounts. Same shape as a
|
|
5
|
+
* generator output (validated by the loader): package face, empty model and
|
|
6
|
+
* schemas, and the canonical invocation list shared with the client Remote
|
|
7
|
+
* contribution (`src/wire.ts`).
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-ticktick/typert
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { TICKTICK_INVOCATIONS } from './wire.ts'
|
|
13
|
+
|
|
14
|
+
/** Host Typert manifest (validated by `@deepseek-ai/dsh-typert-loader`). */
|
|
15
|
+
export const TYPERT = Object.freeze({
|
|
16
|
+
package: 'dsh-ticktick',
|
|
17
|
+
face: 'host',
|
|
18
|
+
schemas: Object.freeze([]),
|
|
19
|
+
invocations: TICKTICK_INVOCATIONS,
|
|
20
|
+
model: Object.freeze({
|
|
21
|
+
services: Object.freeze([]),
|
|
22
|
+
events: Object.freeze([]),
|
|
23
|
+
objects: Object.freeze([]),
|
|
24
|
+
}),
|
|
25
|
+
})
|