exponential-mcp 0.1.1 → 0.3.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 +22 -1
- package/dist/cli.js +0 -0
- package/dist/index.js +192 -6
- package/package.json +2 -2
- package/dist/api.d.ts +0 -84
- package/dist/api.js +0 -82
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Exponential MCP
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/exponential-mcp)
|
|
4
|
+
|
|
3
5
|
Connect Claude to your [Exponential](https://exponential.im) workspace. Manage projects, actions, and OKRs directly from Claude.
|
|
4
6
|
|
|
5
7
|
## Quick Start
|
|
@@ -104,12 +106,31 @@ exponential-mcp serve
|
|
|
104
106
|
|------|-------------|
|
|
105
107
|
| `get_workspaces` | List all workspaces |
|
|
106
108
|
| `get_projects` | List projects (optionally by workspace) |
|
|
107
|
-
| `get_actions` | List actions/tasks (filter by project or status) |
|
|
109
|
+
| `get_actions` | List actions/tasks (filter by project or status; no date filtering) |
|
|
110
|
+
| `get_todays_actions` | **What's on your plate now** — overdue / today / inbox, across all workspaces |
|
|
111
|
+
| `get_overdue_triage` | Why the overdue pile is that size: bulk-created cohorts vs real debt |
|
|
108
112
|
| `create_action` | Create a new task (supports natural language) |
|
|
113
|
+
| `update_action` | Rename, re-prioritise, move project, or set dates (incl. `scheduledStart`) |
|
|
114
|
+
| `defer_actions` | Amnesty: clear dates, back to the project backlog untimed |
|
|
115
|
+
| `reschedule_actions` | Move actions to a new do-date |
|
|
109
116
|
| `complete_action` | Mark an action as done |
|
|
110
117
|
| `get_goals` | List OKRs with progress |
|
|
111
118
|
| `search` | Search across everything |
|
|
112
119
|
|
|
120
|
+
### Asking about the day
|
|
121
|
+
|
|
122
|
+
Use **`get_todays_actions`**, not `get_actions`, for anything about today,
|
|
123
|
+
priorities, or what the user is behind on. `get_actions` has no date filtering
|
|
124
|
+
at all, so it cannot distinguish overdue work from anything else.
|
|
125
|
+
|
|
126
|
+
When there is a lot of overdue work, follow up with **`get_overdue_triage`**
|
|
127
|
+
before proposing what to do. A large overdue count is usually a few bulk writes
|
|
128
|
+
— a generated project plan stamped every row with one timestamp — not a large
|
|
129
|
+
number of missed commitments. Those are **cohorts**, and the honest disposition
|
|
130
|
+
is `defer_actions` (amnesty); `reschedule_actions` would just re-inflict the
|
|
131
|
+
same pile tomorrow. Individually-dated **loose** actions are the ones that
|
|
132
|
+
deserve a real decision.
|
|
133
|
+
|
|
113
134
|
## Development
|
|
114
135
|
|
|
115
136
|
```bash
|
package/dist/cli.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
@@ -46,6 +46,22 @@ function loadClientConfig() {
|
|
|
46
46
|
}
|
|
47
47
|
return { token, apiUrl };
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* `undefined` = leave the field alone, `null` = clear it, otherwise a Date.
|
|
51
|
+
* MCP arguments arrive as JSON, so an explicit clear can be either a real null
|
|
52
|
+
* or the string "null" depending on how the model emits it.
|
|
53
|
+
*/
|
|
54
|
+
function parseDateArg(raw) {
|
|
55
|
+
if (raw === undefined)
|
|
56
|
+
return undefined;
|
|
57
|
+
if (raw === null || raw === 'null')
|
|
58
|
+
return null;
|
|
59
|
+
const parsed = new Date(raw);
|
|
60
|
+
if (isNaN(parsed.getTime())) {
|
|
61
|
+
throw new Error(`Invalid date "${String(raw)}". Use an ISO datetime, or null to clear.`);
|
|
62
|
+
}
|
|
63
|
+
return parsed;
|
|
64
|
+
}
|
|
49
65
|
// Tool definitions
|
|
50
66
|
const TOOLS = [
|
|
51
67
|
{
|
|
@@ -63,7 +79,7 @@ const TOOLS = [
|
|
|
63
79
|
},
|
|
64
80
|
{
|
|
65
81
|
name: 'get_actions',
|
|
66
|
-
description: 'List actions/tasks
|
|
82
|
+
description: 'List actions/tasks, optionally filtered by project or status. This is a flat list with no date filtering — to answer "what should I work on today" or "what am I behind on", use get_todays_actions instead.',
|
|
67
83
|
inputSchema: {
|
|
68
84
|
type: 'object',
|
|
69
85
|
properties: {
|
|
@@ -79,6 +95,97 @@ const TOOLS = [
|
|
|
79
95
|
}
|
|
80
96
|
}
|
|
81
97
|
},
|
|
98
|
+
{
|
|
99
|
+
name: 'get_todays_actions',
|
|
100
|
+
description: "What is on the user's plate right now, split into overdue / today / inbox. This is the same set the /today page renders, across all workspaces. Use this FIRST for any question about today, this week, priorities, what to work on, or what the user is behind on — it is the only tool that surfaces overdue work. Returns action IDs, so pair it with update_action, defer_actions, or reschedule_actions to act on what it finds.",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
workspaceId: {
|
|
105
|
+
type: 'string',
|
|
106
|
+
description: 'Optional workspace ID. Omit to span all workspaces (usually what you want).'
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'get_overdue_triage',
|
|
113
|
+
description: 'Explain WHY the overdue pile is the size it is, before proposing what to do about it. Splits overdue actions into "cohorts" — groups sharing one exact timestamp, the fingerprint of a bulk write like a generated project plan, which were almost certainly never individually due — and "loose" individually-dated actions, which are real missed commitments. Use this whenever the user has a lot of overdue work: recommend defer_actions (amnesty) for cohorts and a real decision for loose items. Rescheduling a cohort just re-inflicts the pile tomorrow.',
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
workspaceId: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
description: 'Optional workspace ID. Omit to span all workspaces.'
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'update_action',
|
|
126
|
+
description: 'Update an action: rename, re-prioritise, move project, change status, or set its dates. scheduledStart is the "do date" — when the user plans to work on it — and it is what /today partitions on, taking precedence over dueDate. To move something out of the overdue bucket you must set scheduledStart; changing dueDate alone will not do it.',
|
|
127
|
+
inputSchema: {
|
|
128
|
+
type: 'object',
|
|
129
|
+
properties: {
|
|
130
|
+
id: { type: 'string', description: 'Action ID' },
|
|
131
|
+
name: { type: 'string', description: 'New name' },
|
|
132
|
+
description: { type: 'string', description: 'New description' },
|
|
133
|
+
projectId: { type: 'string', description: 'Move to this project ID' },
|
|
134
|
+
status: {
|
|
135
|
+
type: 'string',
|
|
136
|
+
enum: ['ACTIVE', 'COMPLETED', 'CANCELLED'],
|
|
137
|
+
description: 'New status'
|
|
138
|
+
},
|
|
139
|
+
dueDate: {
|
|
140
|
+
type: 'string',
|
|
141
|
+
description: 'Deadline as an ISO datetime, or null to clear'
|
|
142
|
+
},
|
|
143
|
+
scheduledStart: {
|
|
144
|
+
type: 'string',
|
|
145
|
+
description: 'Do-date as an ISO datetime (e.g. 2026-08-05T09:00:00Z), or null to clear'
|
|
146
|
+
},
|
|
147
|
+
scheduledEnd: {
|
|
148
|
+
type: 'string',
|
|
149
|
+
description: 'End of the time block as an ISO datetime, or null to clear'
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
required: ['id']
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: 'defer_actions',
|
|
157
|
+
description: 'Amnesty: clear the dates on these actions so they fall back to their project backlog untimed. Use for work that was never really due on the date it carries — most often a bulk-created cohort from get_overdue_triage. The actions stay ACTIVE and are not deleted or archived; they simply stop counting as overdue. Prefer this over reschedule_actions when the dates were never a real commitment.',
|
|
158
|
+
inputSchema: {
|
|
159
|
+
type: 'object',
|
|
160
|
+
properties: {
|
|
161
|
+
actionIds: {
|
|
162
|
+
type: 'array',
|
|
163
|
+
items: { type: 'string' },
|
|
164
|
+
description: 'Action IDs to defer'
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
required: ['actionIds']
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'reschedule_actions',
|
|
172
|
+
description: 'Move actions to a new do-date, for work that genuinely is still due, just later. Sets scheduledStart, pushing dueDate forward only where it would otherwise fall before it. If the actions were bulk-created and never individually due, use defer_actions instead — rescheduling them only re-inflicts the same pile tomorrow.',
|
|
173
|
+
inputSchema: {
|
|
174
|
+
type: 'object',
|
|
175
|
+
properties: {
|
|
176
|
+
actionIds: {
|
|
177
|
+
type: 'array',
|
|
178
|
+
items: { type: 'string' },
|
|
179
|
+
description: 'Action IDs to reschedule'
|
|
180
|
+
},
|
|
181
|
+
date: {
|
|
182
|
+
type: 'string',
|
|
183
|
+
description: 'New do-date as an ISO datetime (e.g. 2026-08-05T09:00:00Z)'
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
required: ['actionIds', 'date']
|
|
187
|
+
}
|
|
188
|
+
},
|
|
82
189
|
{
|
|
83
190
|
name: 'create_action',
|
|
84
191
|
description: 'Create a new action/task. Supports natural language with dates and project names.',
|
|
@@ -122,13 +229,21 @@ const TOOLS = [
|
|
|
122
229
|
},
|
|
123
230
|
{
|
|
124
231
|
name: 'search',
|
|
125
|
-
description:
|
|
232
|
+
description: "Global text search across everything the user can access — projects, actions/tasks, goals, workspaces (and more entity types as the API grows). Same coverage as the app's Cmd+K palette. Returns typed results with ids, workspace, and app URL.",
|
|
126
233
|
inputSchema: {
|
|
127
234
|
type: 'object',
|
|
128
235
|
properties: {
|
|
129
236
|
query: {
|
|
130
237
|
type: 'string',
|
|
131
238
|
description: 'Search query'
|
|
239
|
+
},
|
|
240
|
+
workspaceId: {
|
|
241
|
+
type: 'string',
|
|
242
|
+
description: 'Optional workspace ID to restrict results to one workspace'
|
|
243
|
+
},
|
|
244
|
+
limit: {
|
|
245
|
+
type: 'number',
|
|
246
|
+
description: 'Max results per entity type (1-25, default 10)'
|
|
132
247
|
}
|
|
133
248
|
},
|
|
134
249
|
required: ['query']
|
|
@@ -208,10 +323,34 @@ async function main() {
|
|
|
208
323
|
],
|
|
209
324
|
};
|
|
210
325
|
}
|
|
326
|
+
case 'get_todays_actions': {
|
|
327
|
+
const todays = await client.actions.getTodaysActions(args?.workspaceId);
|
|
328
|
+
return {
|
|
329
|
+
content: [
|
|
330
|
+
{
|
|
331
|
+
type: 'text',
|
|
332
|
+
text: JSON.stringify(todays, null, 2),
|
|
333
|
+
},
|
|
334
|
+
],
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
case 'get_overdue_triage': {
|
|
338
|
+
const triage = await client.actions.getOverdueTriage(args?.workspaceId);
|
|
339
|
+
return {
|
|
340
|
+
content: [
|
|
341
|
+
{
|
|
342
|
+
type: 'text',
|
|
343
|
+
text: JSON.stringify(triage, null, 2),
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
};
|
|
347
|
+
}
|
|
211
348
|
case 'create_action': {
|
|
212
|
-
//
|
|
349
|
+
// quickCreate's input field is `name`, not `text` -- it parses natural
|
|
350
|
+
// language out of the name itself (dates, project names) when
|
|
351
|
+
// parseNaturalLanguage is on, which it is by default.
|
|
213
352
|
const action = await trpcClient.action.quickCreate.mutate({
|
|
214
|
-
|
|
353
|
+
name: args?.text,
|
|
215
354
|
});
|
|
216
355
|
return {
|
|
217
356
|
content: [
|
|
@@ -222,9 +361,54 @@ async function main() {
|
|
|
222
361
|
],
|
|
223
362
|
};
|
|
224
363
|
}
|
|
364
|
+
case 'update_action': {
|
|
365
|
+
const action = await client.actions.update({
|
|
366
|
+
id: args?.id,
|
|
367
|
+
name: args?.name,
|
|
368
|
+
description: args?.description,
|
|
369
|
+
projectId: args?.projectId,
|
|
370
|
+
status: args?.status,
|
|
371
|
+
dueDate: parseDateArg(args?.dueDate),
|
|
372
|
+
scheduledStart: parseDateArg(args?.scheduledStart),
|
|
373
|
+
scheduledEnd: parseDateArg(args?.scheduledEnd),
|
|
374
|
+
});
|
|
375
|
+
return {
|
|
376
|
+
content: [
|
|
377
|
+
{
|
|
378
|
+
type: 'text',
|
|
379
|
+
text: `Updated: ${action.name} (ID: ${action.id})`,
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
case 'defer_actions': {
|
|
385
|
+
const result = await client.actions.bulkDefer(args?.actionIds);
|
|
386
|
+
return {
|
|
387
|
+
content: [
|
|
388
|
+
{
|
|
389
|
+
type: 'text',
|
|
390
|
+
text: result.message,
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
case 'reschedule_actions': {
|
|
396
|
+
const when = new Date(args?.date);
|
|
397
|
+
if (isNaN(when.getTime())) {
|
|
398
|
+
throw new Error(`Invalid date "${String(args?.date)}". Use an ISO datetime.`);
|
|
399
|
+
}
|
|
400
|
+
const result = await client.actions.bulkReschedule(args?.actionIds, when);
|
|
401
|
+
return {
|
|
402
|
+
content: [
|
|
403
|
+
{
|
|
404
|
+
type: 'text',
|
|
405
|
+
text: `Rescheduled ${result.count} action${result.count === 1 ? '' : 's'} to ${when.toISOString()}`,
|
|
406
|
+
},
|
|
407
|
+
],
|
|
408
|
+
};
|
|
409
|
+
}
|
|
225
410
|
case 'complete_action': {
|
|
226
|
-
|
|
227
|
-
const action = await trpcClient.action.update.mutate({
|
|
411
|
+
const action = await client.actions.update({
|
|
228
412
|
id: args?.id,
|
|
229
413
|
status: 'COMPLETED',
|
|
230
414
|
});
|
|
@@ -253,6 +437,8 @@ async function main() {
|
|
|
253
437
|
case 'search': {
|
|
254
438
|
const results = await trpcClient.search.global.query({
|
|
255
439
|
query: args?.query,
|
|
440
|
+
workspaceId: args?.workspaceId,
|
|
441
|
+
limit: args?.limit,
|
|
256
442
|
});
|
|
257
443
|
return {
|
|
258
444
|
content: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exponential-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MCP server for Exponential - connect Claude to your projects, actions, and goals",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
27
27
|
"commander": "^12.0.0",
|
|
28
|
-
"exponential-sdk": "^1.
|
|
28
|
+
"exponential-sdk": "^1.10.0",
|
|
29
29
|
"zod": "^3.22.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
package/dist/api.d.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Exponential API Client
|
|
3
|
-
* Handles authenticated requests to the Exponential API
|
|
4
|
-
*/
|
|
5
|
-
export interface ExponentialConfig {
|
|
6
|
-
apiKey: string;
|
|
7
|
-
baseUrl?: string;
|
|
8
|
-
}
|
|
9
|
-
export interface Project {
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
status: string;
|
|
14
|
-
priority: string;
|
|
15
|
-
progress: number;
|
|
16
|
-
}
|
|
17
|
-
export interface Action {
|
|
18
|
-
id: string;
|
|
19
|
-
name: string;
|
|
20
|
-
description?: string;
|
|
21
|
-
status: string;
|
|
22
|
-
priority: string;
|
|
23
|
-
dueDate?: string;
|
|
24
|
-
projectId?: string;
|
|
25
|
-
project?: {
|
|
26
|
-
name: string;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
export interface Goal {
|
|
30
|
-
id: number;
|
|
31
|
-
title: string;
|
|
32
|
-
description?: string;
|
|
33
|
-
period?: string;
|
|
34
|
-
keyResults: KeyResult[];
|
|
35
|
-
}
|
|
36
|
-
export interface KeyResult {
|
|
37
|
-
id: string;
|
|
38
|
-
title: string;
|
|
39
|
-
targetValue?: number;
|
|
40
|
-
currentValue?: number;
|
|
41
|
-
status: string;
|
|
42
|
-
}
|
|
43
|
-
export interface Workspace {
|
|
44
|
-
id: string;
|
|
45
|
-
name: string;
|
|
46
|
-
slug: string;
|
|
47
|
-
}
|
|
48
|
-
export declare class ExponentialAPI {
|
|
49
|
-
private apiKey;
|
|
50
|
-
private baseUrl;
|
|
51
|
-
constructor(config: ExponentialConfig);
|
|
52
|
-
private request;
|
|
53
|
-
private trpcQuery;
|
|
54
|
-
private trpcMutation;
|
|
55
|
-
getWorkspaces(): Promise<Workspace[]>;
|
|
56
|
-
getProjects(workspaceId?: string): Promise<Project[]>;
|
|
57
|
-
getProject(id: string): Promise<Project>;
|
|
58
|
-
getActions(params?: {
|
|
59
|
-
projectId?: string;
|
|
60
|
-
status?: string;
|
|
61
|
-
}): Promise<Action[]>;
|
|
62
|
-
createAction(data: {
|
|
63
|
-
name: string;
|
|
64
|
-
description?: string;
|
|
65
|
-
projectId?: string;
|
|
66
|
-
priority?: string;
|
|
67
|
-
dueDate?: string;
|
|
68
|
-
}): Promise<Action>;
|
|
69
|
-
updateAction(id: string, data: {
|
|
70
|
-
name?: string;
|
|
71
|
-
status?: string;
|
|
72
|
-
priority?: string;
|
|
73
|
-
dueDate?: string;
|
|
74
|
-
}): Promise<Action>;
|
|
75
|
-
completeAction(id: string): Promise<Action>;
|
|
76
|
-
getGoals(workspaceId?: string): Promise<Goal[]>;
|
|
77
|
-
getGoal(id: number): Promise<Goal>;
|
|
78
|
-
quickCreateAction(text: string): Promise<Action>;
|
|
79
|
-
search(query: string): Promise<{
|
|
80
|
-
projects: Project[];
|
|
81
|
-
actions: Action[];
|
|
82
|
-
goals: Goal[];
|
|
83
|
-
}>;
|
|
84
|
-
}
|
package/dist/api.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Exponential API Client
|
|
3
|
-
* Handles authenticated requests to the Exponential API
|
|
4
|
-
*/
|
|
5
|
-
const DEFAULT_BASE_URL = 'https://www.exponential.im';
|
|
6
|
-
export class ExponentialAPI {
|
|
7
|
-
apiKey;
|
|
8
|
-
baseUrl;
|
|
9
|
-
constructor(config) {
|
|
10
|
-
this.apiKey = config.apiKey;
|
|
11
|
-
this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
|
|
12
|
-
}
|
|
13
|
-
async request(endpoint, options = {}) {
|
|
14
|
-
const url = `${this.baseUrl}${endpoint}`;
|
|
15
|
-
const response = await fetch(url, {
|
|
16
|
-
...options,
|
|
17
|
-
headers: {
|
|
18
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
19
|
-
'Content-Type': 'application/json',
|
|
20
|
-
...options.headers,
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
if (!response.ok) {
|
|
24
|
-
const error = await response.text();
|
|
25
|
-
throw new Error(`Exponential API error (${response.status}): ${error}`);
|
|
26
|
-
}
|
|
27
|
-
return response.json();
|
|
28
|
-
}
|
|
29
|
-
// tRPC-style calls
|
|
30
|
-
async trpcQuery(procedure, input) {
|
|
31
|
-
const inputStr = input ? encodeURIComponent(JSON.stringify(input)) : '';
|
|
32
|
-
const url = `/api/trpc/${procedure}${inputStr ? `?input=${inputStr}` : ''}`;
|
|
33
|
-
return this.request(url).then(r => r.result.data);
|
|
34
|
-
}
|
|
35
|
-
async trpcMutation(procedure, input) {
|
|
36
|
-
const url = `/api/trpc/${procedure}`;
|
|
37
|
-
return this.request(url, {
|
|
38
|
-
method: 'POST',
|
|
39
|
-
body: JSON.stringify(input),
|
|
40
|
-
}).then(r => r.result.data);
|
|
41
|
-
}
|
|
42
|
-
// === Workspace ===
|
|
43
|
-
async getWorkspaces() {
|
|
44
|
-
return this.trpcQuery('workspace.list');
|
|
45
|
-
}
|
|
46
|
-
// === Projects ===
|
|
47
|
-
async getProjects(workspaceId) {
|
|
48
|
-
return this.trpcQuery('project.list', { workspaceId });
|
|
49
|
-
}
|
|
50
|
-
async getProject(id) {
|
|
51
|
-
return this.trpcQuery('project.get', { id });
|
|
52
|
-
}
|
|
53
|
-
// === Actions ===
|
|
54
|
-
async getActions(params) {
|
|
55
|
-
return this.trpcQuery('action.list', params);
|
|
56
|
-
}
|
|
57
|
-
async createAction(data) {
|
|
58
|
-
return this.trpcMutation('action.create', data);
|
|
59
|
-
}
|
|
60
|
-
async updateAction(id, data) {
|
|
61
|
-
return this.trpcMutation('action.update', { id, ...data });
|
|
62
|
-
}
|
|
63
|
-
async completeAction(id) {
|
|
64
|
-
return this.updateAction(id, { status: 'COMPLETED' });
|
|
65
|
-
}
|
|
66
|
-
// === Goals (OKRs) ===
|
|
67
|
-
async getGoals(workspaceId) {
|
|
68
|
-
return this.trpcQuery('goal.list', { workspaceId });
|
|
69
|
-
}
|
|
70
|
-
async getGoal(id) {
|
|
71
|
-
return this.trpcQuery('goal.get', { id });
|
|
72
|
-
}
|
|
73
|
-
// === Quick Actions ===
|
|
74
|
-
async quickCreateAction(text) {
|
|
75
|
-
// Uses natural language parsing (dates, project names, etc.)
|
|
76
|
-
return this.trpcMutation('action.quickCreate', { text });
|
|
77
|
-
}
|
|
78
|
-
// === Search ===
|
|
79
|
-
async search(query) {
|
|
80
|
-
return this.trpcQuery('search.global', { query });
|
|
81
|
-
}
|
|
82
|
-
}
|