@aioproductoscom/mcp 0.15.10 → 0.16.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.
@@ -0,0 +1,16 @@
1
+ import type { RestCall } from "./registry.js";
2
+ export interface RestResult {
3
+ ok: boolean;
4
+ status: number;
5
+ /** Raw response body. Passed through verbatim — same contract as the hosted
6
+ * dispatcher, and it sidesteps the old failure mode where a non-JSON error
7
+ * page (a 502 from the edge) crashed JSON.parse with "Unexpected token '<'"
8
+ * instead of reporting what actually happened. */
9
+ text: string;
10
+ }
11
+ export declare class PlatformClient {
12
+ private readonly baseUrl;
13
+ private readonly token;
14
+ constructor(baseUrl: string, token: string);
15
+ request(call: RestCall): Promise<RestResult>;
16
+ }
package/dist/client.js CHANGED
@@ -1,5 +1,14 @@
1
- // Thin typed HTTP client over the platform's token-authed PM endpoints.
2
- // Uses global fetch (Node 18+). The PAT is the only credential; nothing is stored.
1
+ // One hardened HTTP executor over the platform's token-authed REST endpoints.
2
+ // The registry's RestCall describes WHAT to call; this describes HOW the PAT
3
+ // header, a timeout, and honest failure text. The PAT is the only credential;
4
+ // nothing is stored.
5
+ //
6
+ // This file used to be 70 near-identical methods (one per tool). The shared
7
+ // registry made them redundant: every tool already declares its own
8
+ // method/path/body, so the client collapses to a single request function.
9
+ /** A hung platform request must fail the TOOL CALL, not hang the agent's turn
10
+ * forever — 30s is far beyond any healthy endpoint here. */
11
+ const TIMEOUT_MS = 30_000;
3
12
  export class PlatformClient {
4
13
  baseUrl;
5
14
  token;
@@ -7,351 +16,25 @@ export class PlatformClient {
7
16
  this.baseUrl = baseUrl;
8
17
  this.token = token;
9
18
  }
10
- async req(path, init) {
11
- const res = await fetch(`${this.baseUrl}${path}`, {
12
- ...init,
13
- headers: {
14
- "Content-Type": "application/json",
15
- Authorization: `Bearer ${this.token}`,
16
- ...(init?.headers ?? {}),
17
- },
18
- });
19
- const body = await res.text();
20
- const json = body ? JSON.parse(body) : {};
21
- if (!res.ok) {
22
- const o = (json ?? {});
23
- const msg = o.error ? `${o.error}${o.detail ? `: ${o.detail}` : ""}` : `HTTP ${res.status}`;
24
- const e = new Error(msg);
25
- e.status = res.status;
26
- throw e;
19
+ async request(call) {
20
+ try {
21
+ const res = await fetch(`${this.baseUrl}${call.path}`, {
22
+ method: call.method,
23
+ headers: {
24
+ "Content-Type": "application/json",
25
+ Authorization: `Bearer ${this.token}`,
26
+ },
27
+ body: call.body !== undefined ? JSON.stringify(call.body) : undefined,
28
+ signal: AbortSignal.timeout(TIMEOUT_MS),
29
+ });
30
+ return { ok: res.ok, status: res.status, text: await res.text() };
31
+ }
32
+ catch (e) {
33
+ // Transport-level failure (offline, DNS, timeout) — return it as an
34
+ // honest error result rather than throwing, so the tool result tells the
35
+ // model what happened instead of surfacing a stack trace.
36
+ const why = e instanceof Error && e.name === "TimeoutError" ? `platform did not respond within ${TIMEOUT_MS / 1000}s` : String(e);
37
+ return { ok: false, status: 0, text: `Platform unreachable: ${why}` };
27
38
  }
28
- return json;
29
- }
30
- whoami() {
31
- return this.req("/api/me");
32
- }
33
- meta() {
34
- return this.req("/api/pm/meta");
35
- }
36
- listTasks(q) {
37
- const params = new URLSearchParams();
38
- if (q.status_id)
39
- params.set("status_id", q.status_id);
40
- if (q.list_id)
41
- params.set("list_id", q.list_id);
42
- const qs = params.toString();
43
- return this.req(`/api/pm/tasks${qs ? `?${qs}` : ""}`);
44
- }
45
- getTask(id) {
46
- return this.req(`/api/pm/tasks/${encodeURIComponent(id)}`);
47
- }
48
- createTask(body) {
49
- return this.req("/api/pm/tasks", { method: "POST", body: JSON.stringify(body) });
50
- }
51
- createFeature(body) {
52
- return this.req("/api/me/features", { method: "POST", body: JSON.stringify(body) });
53
- }
54
- createObjective(body) {
55
- return this.req("/api/me/objectives", { method: "POST", body: JSON.stringify(body) });
56
- }
57
- createSprint(body) {
58
- return this.req("/api/me/sprints", { method: "POST", body: JSON.stringify(body) });
59
- }
60
- createPage(body) {
61
- return this.req("/api/me/pages", { method: "POST", body: JSON.stringify(body) });
62
- }
63
- updateFeature(body) {
64
- return this.req("/api/me/features", { method: "PATCH", body: JSON.stringify(body) });
65
- }
66
- updateObjective(body) {
67
- return this.req("/api/me/objectives", { method: "PATCH", body: JSON.stringify(body) });
68
- }
69
- updateKeyResult(body) {
70
- return this.req("/api/me/key-results", { method: "PATCH", body: JSON.stringify(body) });
71
- }
72
- updateSprint(body) {
73
- return this.req("/api/me/sprints", { method: "PATCH", body: JSON.stringify(body) });
74
- }
75
- updatePage(body) {
76
- return this.req("/api/me/pages", { method: "PATCH", body: JSON.stringify(body) });
77
- }
78
- createRelease(body) {
79
- return this.req("/api/me/releases", { method: "POST", body: JSON.stringify(body) });
80
- }
81
- updateRelease(body) {
82
- return this.req("/api/me/releases", { method: "PATCH", body: JSON.stringify(body) });
83
- }
84
- createExperiment(body) {
85
- return this.req("/api/me/experiments", { method: "POST", body: JSON.stringify(body) });
86
- }
87
- updateExperiment(body) {
88
- return this.req("/api/me/experiments", { method: "PATCH", body: JSON.stringify(body) });
89
- }
90
- listDecisions(status) {
91
- return this.req(`/api/me/decisions${status ? `?status=${encodeURIComponent(status)}` : ""}`);
92
- }
93
- createDecision(body) {
94
- return this.req("/api/me/decisions", { method: "POST", body: JSON.stringify(body) });
95
- }
96
- updateDecision(body) {
97
- return this.req("/api/me/decisions", { method: "PATCH", body: JSON.stringify(body) });
98
- }
99
- updateTask(id, body) {
100
- return this.req(`/api/pm/tasks/${encodeURIComponent(id)}`, { method: "PATCH", body: JSON.stringify(body) });
101
- }
102
- deleteTask(id) {
103
- return this.req(`/api/pm/tasks/${encodeURIComponent(id)}`, { method: "DELETE" });
104
- }
105
- comment(id, body) {
106
- return this.req(`/api/pm/tasks/${encodeURIComponent(id)}/comments`, {
107
- method: "POST",
108
- body: JSON.stringify({ body }),
109
- });
110
- }
111
- brain(productId) {
112
- const qs = productId ? `?product_id=${encodeURIComponent(productId)}` : "";
113
- return this.req(`/api/me/brain${qs}`);
114
- }
115
- captureInsight(body) {
116
- return this.req("/api/me/insight", { method: "POST", body: JSON.stringify(body) });
117
- }
118
- customer360(query) {
119
- return this.req(`/api/me/customer?q=${encodeURIComponent(query)}`);
120
- }
121
- nps(opts) {
122
- const p = new URLSearchParams();
123
- if (opts.productId)
124
- p.set("product_id", opts.productId);
125
- if (opts.windowDays)
126
- p.set("window_days", String(opts.windowDays));
127
- const qs = p.toString();
128
- return this.req(`/api/me/nps${qs ? `?${qs}` : ""}`);
129
- }
130
- nrr(windowDays) {
131
- const qs = windowDays ? `?window_days=${windowDays}` : "";
132
- return this.req(`/api/me/nrr${qs}`);
133
- }
134
- funnel(opts) {
135
- const p = new URLSearchParams();
136
- if (opts.productId)
137
- p.set("product_id", opts.productId);
138
- if (opts.window)
139
- p.set("window", String(opts.window));
140
- for (const s of opts.steps ?? [])
141
- p.append("step", s);
142
- const qs = p.toString();
143
- return this.req(`/api/me/funnel${qs ? `?${qs}` : ""}`);
144
- }
145
- retention(opts) {
146
- const p = new URLSearchParams();
147
- if (opts.productId)
148
- p.set("product_id", opts.productId);
149
- if (opts.window)
150
- p.set("window", String(opts.window));
151
- const qs = p.toString();
152
- return this.req(`/api/me/retention${qs ? `?${qs}` : ""}`);
153
- }
154
- paths(opts) {
155
- const p = new URLSearchParams();
156
- if (opts.productId)
157
- p.set("product_id", opts.productId);
158
- if (opts.window)
159
- p.set("window", String(opts.window));
160
- if (opts.start)
161
- p.set("start", opts.start);
162
- const qs = p.toString();
163
- return this.req(`/api/me/paths${qs ? `?${qs}` : ""}`);
164
- }
165
- listConversations(opts) {
166
- const p = new URLSearchParams();
167
- if (opts.productId)
168
- p.set("product_id", opts.productId);
169
- if (opts.status)
170
- p.set("status", opts.status);
171
- const qs = p.toString();
172
- return this.req(`/api/me/inbox${qs ? `?${qs}` : ""}`);
173
- }
174
- getConversation(id) {
175
- return this.req(`/api/me/inbox?conversation_id=${encodeURIComponent(id)}`);
176
- }
177
- inboxAction(body) {
178
- return this.req("/api/me/inbox", { method: "POST", body: JSON.stringify(body) });
179
- }
180
- listBookings(opts) {
181
- const qs = opts.include === "all" ? "?include=all" : "";
182
- return this.req(`/api/me/scheduling${qs}`);
183
- }
184
- schedulingAction(body) {
185
- return this.req("/api/me/scheduling", { method: "POST", body: JSON.stringify(body) });
186
- }
187
- listChannels() {
188
- return this.req("/api/me/comms");
189
- }
190
- readChannel(channelId, limit) {
191
- const p = new URLSearchParams({ channel_id: channelId });
192
- if (limit)
193
- p.set("limit", String(limit));
194
- return this.req(`/api/me/comms?${p.toString()}`);
195
- }
196
- postToChannel(channelId, body) {
197
- return this.req("/api/me/comms", {
198
- method: "POST",
199
- body: JSON.stringify({ action: "post", channel_id: channelId, body }),
200
- });
201
- }
202
- replyInChannel(channelId, parentId, body) {
203
- return this.req("/api/me/comms", {
204
- method: "POST",
205
- body: JSON.stringify({ action: "reply", channel_id: channelId, parent_id: parentId, body }),
206
- });
207
- }
208
- // ---- Strategy ladder: initiatives + ideas (goal → initiative → feature) ----
209
- listInitiatives(productId) {
210
- const qs = productId ? `?product_id=${encodeURIComponent(productId)}` : "";
211
- return this.req(`/api/me/initiatives${qs}`);
212
- }
213
- createInitiative(body) {
214
- return this.req("/api/me/initiatives", { method: "POST", body: JSON.stringify(body) });
215
- }
216
- updateInitiative(id, body) {
217
- return this.req(`/api/me/initiatives/${encodeURIComponent(id)}`, { method: "PATCH", body: JSON.stringify(body) });
218
- }
219
- listIdeas(opts) {
220
- const p = new URLSearchParams();
221
- if (opts.status)
222
- p.set("status", opts.status);
223
- if (opts.productId)
224
- p.set("product_id", opts.productId);
225
- const qs = p.toString();
226
- return this.req(`/api/me/ideas${qs ? `?${qs}` : ""}`);
227
- }
228
- createIdea(body) {
229
- return this.req("/api/me/ideas", { method: "POST", body: JSON.stringify(body) });
230
- }
231
- updateIdea(id, body) {
232
- return this.req(`/api/me/ideas/${encodeURIComponent(id)}`, { method: "PATCH", body: JSON.stringify(body) });
233
- }
234
- voteIdea(id, remove) {
235
- return this.req(`/api/me/ideas/${encodeURIComponent(id)}/vote`, { method: remove ? "DELETE" : "POST" });
236
- }
237
- promoteIdea(id, body) {
238
- return this.req(`/api/me/ideas/${encodeURIComponent(id)}/promote`, { method: "POST", body: JSON.stringify(body) });
239
- }
240
- // ---- Read parity with the hosted connector: catalogue + strategy + docs ----
241
- listFeatures(opts) {
242
- const p = new URLSearchParams();
243
- if (opts.q)
244
- p.set("q", opts.q);
245
- if (opts.productId)
246
- p.set("product_id", opts.productId);
247
- const qs = p.toString();
248
- return this.req(`/api/me/features${qs ? `?${qs}` : ""}`);
249
- }
250
- listObjectives(productId) {
251
- const qs = productId ? `?product_id=${encodeURIComponent(productId)}` : "";
252
- return this.req(`/api/me/objectives${qs}`);
253
- }
254
- listExperiments(opts) {
255
- const p = new URLSearchParams();
256
- if (opts.productId)
257
- p.set("product_id", opts.productId);
258
- if (opts.state)
259
- p.set("state", opts.state);
260
- const qs = p.toString();
261
- return this.req(`/api/me/experiments${qs ? `?${qs}` : ""}`);
262
- }
263
- listReleases(productId) {
264
- const qs = productId ? `?product_id=${encodeURIComponent(productId)}` : "";
265
- return this.req(`/api/me/releases${qs}`);
266
- }
267
- listSprints(state) {
268
- const qs = state ? `?state=${encodeURIComponent(state)}` : "";
269
- return this.req(`/api/me/sprints${qs}`);
270
- }
271
- listPages(productId) {
272
- const qs = productId ? `?product_id=${encodeURIComponent(productId)}` : "";
273
- return this.req(`/api/me/pages${qs}`);
274
- }
275
- getPage(id) {
276
- return this.req(`/api/me/pages?id=${encodeURIComponent(id)}`);
277
- }
278
- listInsights(opts) {
279
- const p = new URLSearchParams();
280
- if (opts.q)
281
- p.set("q", opts.q);
282
- if (opts.status)
283
- p.set("status", opts.status);
284
- if (opts.kind)
285
- p.set("kind", opts.kind);
286
- if (opts.featureId)
287
- p.set("feature_id", opts.featureId);
288
- if (opts.accountId)
289
- p.set("account_id", opts.accountId);
290
- if (opts.productId)
291
- p.set("product_id", opts.productId);
292
- if (opts.limit)
293
- p.set("limit", String(opts.limit));
294
- const qs = p.toString();
295
- return this.req(`/api/me/insights${qs ? `?${qs}` : ""}`);
296
- }
297
- roadmapDrift(opts) {
298
- const p = new URLSearchParams();
299
- if (opts.window)
300
- p.set("window", opts.window);
301
- if (opts.productId)
302
- p.set("product_id", opts.productId);
303
- const qs = p.toString();
304
- return this.req(`/api/me/roadmap-drift${qs ? `?${qs}` : ""}`);
305
- }
306
- weeklySignalMemo(opts) {
307
- const p = new URLSearchParams();
308
- if (opts.week)
309
- p.set("week", opts.week);
310
- if (opts.generate)
311
- p.set("generate", "1");
312
- const qs = p.toString();
313
- return this.req(`/api/me/weekly-signal${qs ? `?${qs}` : ""}`);
314
- }
315
- codebaseMap(productId) {
316
- const qs = productId ? `?product_id=${encodeURIComponent(productId)}` : "";
317
- return this.req(`/api/me/codebase${qs}`);
318
- }
319
- listArtifactVersions(opts) {
320
- const p = new URLSearchParams();
321
- if (opts.targetId)
322
- p.set("target_id", opts.targetId);
323
- if (opts.targetType)
324
- p.set("target_type", opts.targetType);
325
- const qs = p.toString();
326
- return this.req(`/api/me/artifact-versions${qs ? `?${qs}` : ""}`);
327
- }
328
- // ---- Identity graph: candidates, merge history, merge / unmerge ----
329
- deviceCandidates() {
330
- return this.req("/api/me/identity");
331
- }
332
- listIdentityMerges(limit) {
333
- const p = new URLSearchParams({ view: "merges" });
334
- if (limit)
335
- p.set("limit", String(limit));
336
- return this.req(`/api/me/identity?${p.toString()}`);
337
- }
338
- mergeEndUsers(body) {
339
- return this.req("/api/me/identity", {
340
- method: "POST",
341
- body: JSON.stringify({ action: "merge_end_users", ...body }),
342
- });
343
- }
344
- unmergeEndUsers(eventId) {
345
- return this.req("/api/me/identity", {
346
- method: "POST",
347
- body: JSON.stringify({ action: "unmerge_end_users", event_id: eventId }),
348
- });
349
- }
350
- // ---- AI artifacts: critic review + version revert ----
351
- reviewArtifact(body) {
352
- return this.req("/api/me/review-artifact", { method: "POST", body: JSON.stringify(body) });
353
- }
354
- revertToVersion(body) {
355
- return this.req("/api/me/revert-version", { method: "POST", body: JSON.stringify(body) });
356
39
  }
357
40
  }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};