@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.
Files changed (71) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +201 -0
  3. package/README.es.md +41 -0
  4. package/README.hi.md +33 -0
  5. package/README.md +111 -0
  6. package/README.pt.md +41 -0
  7. package/README.zh.md +111 -0
  8. package/cordis.patch.yml +35 -0
  9. package/lib/client.js +6233 -0
  10. package/lib/client.js.map +1 -0
  11. package/lib/index.js +1349 -0
  12. package/lib/typert.host.js +26 -0
  13. package/lib/types/client/TicktickAction.d.ts +29 -0
  14. package/lib/types/client/TicktickAction.d.ts.map +1 -0
  15. package/lib/types/client/TicktickSettingsCard.d.ts +27 -0
  16. package/lib/types/client/TicktickSettingsCard.d.ts.map +1 -0
  17. package/lib/types/client/api.d.ts +34 -0
  18. package/lib/types/client/api.d.ts.map +1 -0
  19. package/lib/types/client/dates.d.ts +26 -0
  20. package/lib/types/client/dates.d.ts.map +1 -0
  21. package/lib/types/client/index.d.ts +34 -0
  22. package/lib/types/client/index.d.ts.map +1 -0
  23. package/lib/types/client/locales.d.ts +61 -0
  24. package/lib/types/client/locales.d.ts.map +1 -0
  25. package/lib/types/client/order.d.ts +25 -0
  26. package/lib/types/client/order.d.ts.map +1 -0
  27. package/lib/types/client/remote.d.ts +260 -0
  28. package/lib/types/client/remote.d.ts.map +1 -0
  29. package/lib/types/client/styles.d.ts +13 -0
  30. package/lib/types/client/styles.d.ts.map +1 -0
  31. package/lib/types/config.d.ts +64 -0
  32. package/lib/types/config.d.ts.map +1 -0
  33. package/lib/types/domain.d.ts +70 -0
  34. package/lib/types/domain.d.ts.map +1 -0
  35. package/lib/types/index.d.ts +56 -0
  36. package/lib/types/index.d.ts.map +1 -0
  37. package/lib/types/mcp.d.ts +94 -0
  38. package/lib/types/mcp.d.ts.map +1 -0
  39. package/lib/types/service.d.ts +160 -0
  40. package/lib/types/service.d.ts.map +1 -0
  41. package/lib/types/tools.d.ts +18 -0
  42. package/lib/types/tools.d.ts.map +1 -0
  43. package/lib/types/typert.host.d.ts +216 -0
  44. package/lib/types/typert.host.d.ts.map +1 -0
  45. package/lib/types/wire.d.ts +561 -0
  46. package/lib/types/wire.d.ts.map +1 -0
  47. package/lib/wire-C-vDxxnC.js +5288 -0
  48. package/package.json +187 -0
  49. package/probes/lib.mjs +65 -0
  50. package/probes/probe-bootstrap.mjs +10 -0
  51. package/probes/probe-crud.mjs +15 -0
  52. package/probes/probe-due.mjs +28 -0
  53. package/probes/probe-queries.mjs +18 -0
  54. package/probes/probe-reorder.mjs +24 -0
  55. package/src/client/TicktickAction.tsx +356 -0
  56. package/src/client/TicktickSettingsCard.tsx +182 -0
  57. package/src/client/api.ts +56 -0
  58. package/src/client/dates.ts +61 -0
  59. package/src/client/index.ts +119 -0
  60. package/src/client/locales.ts +113 -0
  61. package/src/client/order.ts +37 -0
  62. package/src/client/remote.ts +76 -0
  63. package/src/client/styles.ts +48 -0
  64. package/src/config.ts +136 -0
  65. package/src/domain.ts +224 -0
  66. package/src/index.ts +139 -0
  67. package/src/mcp.ts +213 -0
  68. package/src/service.ts +403 -0
  69. package/src/tools.ts +336 -0
  70. package/src/typert.host.ts +25 -0
  71. package/src/wire.ts +401 -0
package/package.json ADDED
@@ -0,0 +1,187 @@
1
+ {
2
+ "name": "@perrylink/dsh-ticktick",
3
+ "version": "0.1.2",
4
+ "description": "TickTick (Dida365) task bridge for DeepSeek Harness: a Session-header task panel (list filter, quick add, complete, delete, due dates, drag reorder) over the official TickTick MCP endpoint, a Ticktick Remote service, curated agent tools, and a plugin settings card.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/PerryLink/dsh-ticktick.git"
8
+ },
9
+ "homepage": "https://github.com/PerryLink/dsh-ticktick#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/PerryLink/dsh-ticktick/issues"
12
+ },
13
+ "author": "PerryLink",
14
+ "private": false,
15
+ "type": "module",
16
+ "main": "./lib/index.js",
17
+ "types": "./lib/types/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./lib/types/index.d.ts",
21
+ "default": "./lib/index.js"
22
+ },
23
+ "./typert": {
24
+ "types": "./lib/types/typert.host.d.ts",
25
+ "default": "./lib/typert.host.js"
26
+ },
27
+ "./client": {
28
+ "types": "./lib/types/client/index.d.ts",
29
+ "default": "./lib/client.js"
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "files": [
34
+ "lib",
35
+ "src",
36
+ "probes",
37
+ "cordis.patch.yml",
38
+ "CHANGELOG.md",
39
+ "README.md",
40
+ "README.zh.md",
41
+ "README.es.md",
42
+ "README.pt.md",
43
+ "README.hi.md",
44
+ "LICENSE"
45
+ ],
46
+ "dsh": {
47
+ "bundle": {
48
+ "patch": "./cordis.patch.yml"
49
+ },
50
+ "client": {
51
+ "platform": "web",
52
+ "inject": [
53
+ "@deepseek-ai/dsh-client-locale",
54
+ "@deepseek-ai/dsh-api-remotes",
55
+ "@deepseek-ai/dsh-client-ui-conversation",
56
+ "@deepseek-ai/dsh-client-ui-primitives"
57
+ ]
58
+ },
59
+ "dshWorkshop": {
60
+ "schema": "omdsh-workshop-package/v1",
61
+ "type": "plugin",
62
+ "integration": {
63
+ "protocol": "harness-profile",
64
+ "artifact": "cordis.patch.yml"
65
+ },
66
+ "install": {
67
+ "mode": "transactional",
68
+ "adapter": "profile-bundle",
69
+ "failurePolicy": "generation-rollback",
70
+ "touchesCurrentBeforeActivation": false
71
+ },
72
+ "lifecycle": {
73
+ "activation": "restart-plugin",
74
+ "dispose": "supported"
75
+ },
76
+ "permissions": [
77
+ "browser:local-storage",
78
+ "settings:read",
79
+ "settings:write",
80
+ "network:https://mcp.dida365.com"
81
+ ],
82
+ "compatibility": {
83
+ "dshVersions": [
84
+ "0.1.2-rc.1"
85
+ ]
86
+ },
87
+ "capability": {
88
+ "id": "ticktick-task-panel",
89
+ "kind": "ui",
90
+ "invocation": "open the ticktick panel from a session header",
91
+ "expected": "the task list renders and quick add/complete/delete operations reach the configured TickTick endpoint"
92
+ },
93
+ "evidence": {
94
+ "install": null,
95
+ "failureIsolation": null,
96
+ "hotReload": null,
97
+ "remove": null
98
+ }
99
+ }
100
+ },
101
+ "keywords": [
102
+ "dsh",
103
+ "dsh-plugin",
104
+ "deepseek-harness",
105
+ "deepseek",
106
+ "cordis",
107
+ "ticktick",
108
+ "dida365",
109
+ "todo",
110
+ "task",
111
+ "mcp",
112
+ "widget"
113
+ ],
114
+ "engines": {
115
+ "node": "^22.19.0 || >=24.0.0"
116
+ },
117
+ "peerDependencies": {
118
+ "@deepseek-ai/cordis": "^4.0.2",
119
+ "@deepseek-ai/dsh-tools": ">=0.1.0-rc.8 <0.2.0",
120
+ "@deepseek-ai/dsh-typert-protocol": ">=0.1.0-rc.8 <0.2.0",
121
+ "@deepseek-ai/dsh-settings": ">=0.1.0-rc.8 <0.2.0",
122
+ "@deepseek-ai/dsh-system-prompt": ">=0.1.0-rc.8 <0.2.0",
123
+ "@deepseek-ai/schemastery": "^3.18.0",
124
+ "@deepseek-ai/dsh-api-remotes": ">=0.1.1-rc.2 <0.2.0",
125
+ "@deepseek-ai/dsh-client-locale": ">=0.1.1-rc.2 <0.2.0",
126
+ "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.1-rc.2 <0.2.0",
127
+ "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.1-rc.2 <0.2.0"
128
+ },
129
+ "peerDependenciesMeta": {
130
+ "@deepseek-ai/dsh-api-remotes": {
131
+ "optional": true
132
+ },
133
+ "@deepseek-ai/dsh-client-locale": {
134
+ "optional": true
135
+ },
136
+ "@deepseek-ai/dsh-client-ui-conversation": {
137
+ "optional": true
138
+ },
139
+ "@deepseek-ai/dsh-client-ui-primitives": {
140
+ "optional": true
141
+ }
142
+ },
143
+ "dependencies": {
144
+ "tsdown": "^0.22.14",
145
+ "typescript": "^5.9.3",
146
+ "zod": "^4.4.3"
147
+ },
148
+ "devDependencies": {
149
+ "@deepseek-ai/cordis": "^4.0.2",
150
+ "@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1",
151
+ "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1",
152
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1",
153
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1",
154
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1",
155
+ "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.2-rc.1",
156
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1",
157
+ "@deepseek-ai/dsh-settings": "0.1.2-rc.1",
158
+ "@deepseek-ai/dsh-system-prompt": "0.1.2-rc.1",
159
+ "@deepseek-ai/dsh-tools": "0.1.2-rc.1",
160
+ "@deepseek-ai/dsh-typert-protocol": "0.1.2-rc.1",
161
+ "@deepseek-ai/schemastery": "^3.18.0",
162
+ "@testing-library/react": "^16.3.0",
163
+ "@types/node": "^22.19.0",
164
+ "@types/react": "18.3.31",
165
+ "@types/react-dom": "18.3.7",
166
+ "jsdom": "^30.0.1",
167
+ "oxlint": "0.18.1",
168
+ "react": "18.3.1",
169
+ "react-dom": "18.3.1",
170
+ "vitest": "^4.1.10"
171
+ },
172
+ "license": "Apache-2.0",
173
+ "funding": {
174
+ "type": "individual",
175
+ "url": "https://github.com/sponsors/PerryLink"
176
+ },
177
+ "scripts": {
178
+ "build": "node scripts/prepare.mjs",
179
+ "typecheck": "tsc --noEmit",
180
+ "typecheck:ci": "tsc -p tsconfig.ci.json --noEmit",
181
+ "test": "vitest run",
182
+ "test:watch": "vitest",
183
+ "lint": "oxlint",
184
+ "verify:self-contained": "node scripts/verify-self-contained.mjs",
185
+ "verify:artifacts": "node scripts/verify-artifacts.mjs"
186
+ }
187
+ }
package/probes/lib.mjs ADDED
@@ -0,0 +1,65 @@
1
+ // Shared mini MCP client for the probe scripts: no dependencies, reads the
2
+ // token from DIDA365_TOKEN (dp_ prefix, exported by the user), never logs
3
+ // the token. Usage: $env:DIDA365_TOKEN='dp_...'; node probes/probe-xxx.mjs
4
+ const TOKEN = process.env.DIDA365_TOKEN ?? ''
5
+ const URL = process.env.DIDA365_MCP_URL ?? 'https://mcp.dida365.com'
6
+
7
+ if (TOKEN === '') {
8
+ console.error('set DIDA365_TOKEN first (export $env:DIDA365_TOKEN="dp_...")')
9
+ process.exit(2)
10
+ }
11
+
12
+ let sessionId
13
+ let protocolVersion
14
+ let nextId = 1
15
+
16
+ export async function call(method, params) {
17
+ const headers = {
18
+ 'content-type': 'application/json',
19
+ accept: 'application/json, text/event-stream',
20
+ authorization: `Bearer ${TOKEN}`,
21
+ }
22
+ if (sessionId !== undefined) headers['mcp-session-id'] = sessionId
23
+ if (protocolVersion !== undefined) headers['mcp-protocol-version'] = protocolVersion
24
+ const response = await fetch(URL, {
25
+ method: 'POST',
26
+ headers,
27
+ body: JSON.stringify({ jsonrpc: '2.0', id: nextId++, method, params: params ?? {} }),
28
+ })
29
+ const text = await response.text()
30
+ if (response.status !== 200 && response.status !== 202) {
31
+ throw new Error(`HTTP ${response.status}: ${text.slice(0, 300)}`)
32
+ }
33
+ return { message: parse(text), text }
34
+ }
35
+
36
+ function parse(text) {
37
+ if (text.trim() === '') return undefined
38
+ const dataLines = text.split(/\r?\n/).filter(line => line.startsWith('data:'))
39
+ if (dataLines.length > 0) return JSON.parse(dataLines[dataLines.length - 1].slice(5).trim())
40
+ return JSON.parse(text)
41
+ }
42
+
43
+ export async function initialize() {
44
+ const { message } = await call('initialize', {
45
+ protocolVersion: '2025-03-26',
46
+ capabilities: {},
47
+ clientInfo: { name: 'dsh-ticktick-probe', version: '0.1.0' },
48
+ })
49
+ protocolVersion = message?.result?.protocolVersion
50
+ await call('notifications/initialized')
51
+ return protocolVersion
52
+ }
53
+
54
+ export async function tool(name, args) {
55
+ const { message } = await call('tools/call', { name, arguments: args ?? {} })
56
+ if (message?.result?.isError === true) {
57
+ throw new Error(`tool ${name} isError: ${message.result.content.map(b => b.text).join('\n').slice(0, 300)}`)
58
+ }
59
+ return message?.result ?? {}
60
+ }
61
+
62
+ export async function listTools() {
63
+ const { message } = await call('tools/list', {})
64
+ return message?.result?.tools ?? []
65
+ }
@@ -0,0 +1,10 @@
1
+ // Probe 1: handshake + tool catalogue. Verifies the endpoint, the token,
2
+ // the negotiated protocol version, and prints every advertised tool name
3
+ // (the catalogue the reorder/update pins resolve from).
4
+ import { initialize, listTools } from './lib.mjs'
5
+
6
+ const version = await initialize()
7
+ console.log(`protocolVersion: ${version}`)
8
+ const tools = await listTools()
9
+ console.log(`tools: ${tools.length}`)
10
+ for (const tool of tools) console.log(`- ${tool.name}`)
@@ -0,0 +1,15 @@
1
+ // Probe 2: CRUD round trip in the Inbox — create, read back, complete,
2
+ // delete. Verifies the wire argument shapes the service drives.
3
+ import { initialize, tool } from './lib.mjs'
4
+
5
+ await initialize()
6
+ const created = await tool('create_task', { task: { title: `dsh-probe-${Date.now()}` } })
7
+ const record = JSON.parse(created.content[0].text)
8
+ console.log(`created ${record.id} in ${record.projectId}`)
9
+ try {
10
+ const completed = await tool('complete_task', { project_id: record.projectId ?? 'inbox', task_id: record.id })
11
+ console.log('complete_task ok:', !completed.isError)
12
+ } finally {
13
+ await tool('delete_task', { project_id: record.projectId ?? 'inbox', task_id: record.id })
14
+ console.log('deleted')
15
+ }
@@ -0,0 +1,28 @@
1
+ // Probe 3: due-date update paths. Verifies (a) inbox update, (b) the
2
+ // update_task crash signature for project tasks and the move-to-inbox
3
+ // detour, (c) the epoch sentinel clear. Usage: node probes/probe-due.mjs
4
+ // [PROJECT_ID] — a project id enables the detour half.
5
+ import { initialize, tool } from './lib.mjs'
6
+
7
+ await initialize()
8
+ const projectId = process.argv[2] ?? ''
9
+ const created = await tool('create_task', { task: { title: `dsh-due-probe-${Date.now()}`, ...(projectId === '' ? {} : { projectId }) } })
10
+ const record = JSON.parse(created.content[0].text)
11
+ console.log(`created ${record.id} in ${record.projectId ?? 'inbox'}`)
12
+ try {
13
+ const direct = await tool('update_task', { task_id: record.id, task: { dueDate: '2026-09-20T23:59:59+08:00' } })
14
+ console.log(`direct update ok: ${!direct.isError}`)
15
+ } catch (error) {
16
+ const message = error instanceof Error ? error.message : String(error)
17
+ console.log(`direct update FAILED: ${message.slice(0, 200)}`)
18
+ if (/Expecting value|char 0/i.test(message) && projectId !== '') {
19
+ console.log('crash signature matched — probing the detour:')
20
+ await tool('move_task', { moves: [{ fromProjectId: projectId, toProjectId: 'inbox', taskId: record.id }] })
21
+ const inboxUpdate = await tool('update_task', { task_id: record.id, task: { dueDate: '2026-09-20T23:59:59+08:00' } })
22
+ console.log(`inbox update ok: ${!inboxUpdate.isError}`)
23
+ await tool('move_task', { moves: [{ fromProjectId: 'inbox', toProjectId: projectId, taskId: record.id }] })
24
+ console.log('moved back ok')
25
+ }
26
+ }
27
+ await tool('delete_task', { project_id: projectId === '' ? 'inbox' : projectId, task_id: record.id })
28
+ console.log('deleted')
@@ -0,0 +1,18 @@
1
+ // Probe 5: query-tool contract discovery for the P2 backlog — completed
2
+ // tasks by date and undone tasks by time query. Prints each tool's raw
3
+ // result shape (no mutation). Feeds the future completed-view and search
4
+ // features once their wire contracts are confirmed.
5
+ import { initialize, tool } from './lib.mjs'
6
+
7
+ await initialize()
8
+ for (const [name, args] of [
9
+ ['list_undone_tasks_by_time_query', { query_command: 'today' }],
10
+ ['list_completed_tasks_by_date', { date: new Date().toISOString().slice(0, 10) }],
11
+ ]) {
12
+ try {
13
+ const result = await tool(name, args)
14
+ console.log(`${name}: ${JSON.stringify(result).slice(0, 500)}`)
15
+ } catch (error) {
16
+ console.log(`${name} FAILED: ${error instanceof Error ? error.message : String(error)}`)
17
+ }
18
+ }
@@ -0,0 +1,24 @@
1
+ // Probe 4: reorder semantics. Verifies the descending sortOrder list order,
2
+ // the inbox update path, and (with PROJECT_ID) the same-project move path.
3
+ // Usage: node probes/probe-reorder.mjs [PROJECT_ID]
4
+ import { initialize, tool } from './lib.mjs'
5
+
6
+ await initialize()
7
+ const projectId = process.argv[2] ?? ''
8
+ const created = await tool('create_task', { task: { title: `dsh-reorder-probe-${Date.now()}`, ...(projectId === '' ? {} : { projectId }) } })
9
+ const record = JSON.parse(created.content[0].text)
10
+ console.log(`created ${record.id} (sortOrder ${record.sortOrder})`)
11
+ try {
12
+ if (projectId === '') {
13
+ await tool('update_task', { task_id: record.id, task: { sortOrder: -1 } })
14
+ console.log('inbox update sortOrder ok')
15
+ } else {
16
+ await tool('move_task', { moves: [{ fromProjectId: projectId, toProjectId: projectId, taskId: record.id, sortOrder: -1 }] })
17
+ console.log('same-project move sortOrder ok')
18
+ }
19
+ } catch (error) {
20
+ console.log(`reorder FAILED: ${error instanceof Error ? error.message : String(error)}`)
21
+ } finally {
22
+ await tool('delete_task', { project_id: projectId === '' ? 'inbox' : projectId, task_id: record.id })
23
+ console.log('deleted')
24
+ }