@astramindapp/mcp-server 0.21.0 → 0.23.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 +35 -6
- package/dist/mind-client.d.ts +90 -0
- package/dist/mind-client.d.ts.map +1 -1
- package/dist/mind-client.js +34 -0
- package/dist/mind-client.js.map +1 -1
- package/dist/oauth-connect.d.ts +36 -0
- package/dist/oauth-connect.d.ts.map +1 -0
- package/dist/oauth-connect.js +291 -0
- package/dist/oauth-connect.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +150 -1
- package/dist/server.js.map +1 -1
- package/dist/setup.d.ts +5 -2
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +54 -15
- package/dist/setup.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MIND MCP Setup — browser OAuth connect.
|
|
4
|
+
*
|
|
5
|
+
* Implements the loopback OAuth 2.1 Authorization Code + PKCE flow against
|
|
6
|
+
* the MIND backend (backend/routes/mcp_oauth_routes.py):
|
|
7
|
+
*
|
|
8
|
+
* 1. Start a local HTTP server on 127.0.0.1 (OS-assigned port), path /callback.
|
|
9
|
+
* 2. Dynamically register a public client (RFC 7591) at {base}/oauth/mcp/register.
|
|
10
|
+
* 3. Open {base}/oauth/mcp/authorize in the default browser — the user clicks
|
|
11
|
+
* "Connect" on the m-i-n-d.ai consent page.
|
|
12
|
+
* 4. The browser is redirected back to the loopback server with ?code=...&state=...
|
|
13
|
+
* 5. Exchange the code at {base}/oauth/mcp/token (PKCE verified) and receive a
|
|
14
|
+
* standard `mind_` API key as the access token.
|
|
15
|
+
*
|
|
16
|
+
* No dependencies beyond Node built-ins (http, crypto, child_process) and the
|
|
17
|
+
* global fetch available in Node 18+.
|
|
18
|
+
*/
|
|
19
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
22
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
23
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
24
|
+
}
|
|
25
|
+
Object.defineProperty(o, k2, desc);
|
|
26
|
+
}) : (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
o[k2] = m[k];
|
|
29
|
+
}));
|
|
30
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
31
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32
|
+
}) : function(o, v) {
|
|
33
|
+
o["default"] = v;
|
|
34
|
+
});
|
|
35
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
36
|
+
var ownKeys = function(o) {
|
|
37
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
38
|
+
var ar = [];
|
|
39
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
40
|
+
return ar;
|
|
41
|
+
};
|
|
42
|
+
return ownKeys(o);
|
|
43
|
+
};
|
|
44
|
+
return function (mod) {
|
|
45
|
+
if (mod && mod.__esModule) return mod;
|
|
46
|
+
var result = {};
|
|
47
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
48
|
+
__setModuleDefault(result, mod);
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
})();
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
exports.connectViaBrowser = connectViaBrowser;
|
|
54
|
+
const http = __importStar(require("http"));
|
|
55
|
+
const crypto = __importStar(require("crypto"));
|
|
56
|
+
const child_process_1 = require("child_process");
|
|
57
|
+
const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
58
|
+
const CALLBACK_PATH = "/callback";
|
|
59
|
+
const DEFAULT_CLIENT_NAME = "MIND Setup CLI";
|
|
60
|
+
function base64url(buf) {
|
|
61
|
+
return buf.toString("base64url");
|
|
62
|
+
}
|
|
63
|
+
/** RFC 7636 §4.1 — 43–128 char base64url verifier. 64 random bytes → 86 chars. */
|
|
64
|
+
function generatePkcePair() {
|
|
65
|
+
const verifier = base64url(crypto.randomBytes(64));
|
|
66
|
+
const challenge = base64url(crypto.createHash("sha256").update(verifier, "ascii").digest());
|
|
67
|
+
return { verifier, challenge };
|
|
68
|
+
}
|
|
69
|
+
function openInBrowser(url) {
|
|
70
|
+
try {
|
|
71
|
+
let child;
|
|
72
|
+
if (process.platform === "darwin") {
|
|
73
|
+
child = (0, child_process_1.spawn)("open", [url], { detached: true, stdio: "ignore" });
|
|
74
|
+
}
|
|
75
|
+
else if (process.platform === "win32") {
|
|
76
|
+
// `start` is a cmd built-in; empty "" is the window title slot.
|
|
77
|
+
child = (0, child_process_1.spawn)("cmd", ["/c", "start", "", url.replace(/&/g, "^&")], {
|
|
78
|
+
detached: true,
|
|
79
|
+
stdio: "ignore",
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
child = (0, child_process_1.spawn)("xdg-open", [url], { detached: true, stdio: "ignore" });
|
|
84
|
+
}
|
|
85
|
+
child.on("error", () => {
|
|
86
|
+
/* swallow — the URL is printed as a fallback either way */
|
|
87
|
+
});
|
|
88
|
+
child.unref();
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function htmlPage(title, heading, body, ok) {
|
|
96
|
+
const accent = ok ? "#10b981" : "#ef4444";
|
|
97
|
+
return `<!DOCTYPE html>
|
|
98
|
+
<html lang="en">
|
|
99
|
+
<head>
|
|
100
|
+
<meta charset="utf-8">
|
|
101
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
102
|
+
<title>${title}</title>
|
|
103
|
+
<style>
|
|
104
|
+
body { margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center;
|
|
105
|
+
background: #0b0f19; color: #e5e7eb; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
|
|
106
|
+
.card { text-align: center; padding: 48px 56px; border-radius: 16px; background: #111827;
|
|
107
|
+
border: 1px solid #1f2937; box-shadow: 0 20px 60px rgba(0,0,0,.5); max-width: 440px; }
|
|
108
|
+
.badge { font-size: 44px; line-height: 1; margin-bottom: 18px; color: ${accent}; }
|
|
109
|
+
h1 { font-size: 20px; margin: 0 0 10px; font-weight: 600; }
|
|
110
|
+
p { margin: 0; color: #9ca3af; font-size: 14px; line-height: 1.6; }
|
|
111
|
+
</style>
|
|
112
|
+
</head>
|
|
113
|
+
<body>
|
|
114
|
+
<div class="card">
|
|
115
|
+
<div class="badge">${ok ? "✓" : "✕"}</div>
|
|
116
|
+
<h1>${heading}</h1>
|
|
117
|
+
<p>${body}</p>
|
|
118
|
+
</div>
|
|
119
|
+
</body>
|
|
120
|
+
</html>`;
|
|
121
|
+
}
|
|
122
|
+
const SUCCESS_PAGE = htmlPage("Connected to MIND", "✓ Connected to MIND", "You can close this tab and return to your terminal.", true);
|
|
123
|
+
function errorPage(detail) {
|
|
124
|
+
return htmlPage("MIND connection failed", "Connection failed", `${detail} — close this tab and retry from your terminal.`, false);
|
|
125
|
+
}
|
|
126
|
+
async function registerClient(base, redirectUri, clientName) {
|
|
127
|
+
const res = await fetch(`${base}/oauth/mcp/register`, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
headers: { "Content-Type": "application/json" },
|
|
130
|
+
body: JSON.stringify({
|
|
131
|
+
redirect_uris: [redirectUri],
|
|
132
|
+
client_name: clientName,
|
|
133
|
+
}),
|
|
134
|
+
});
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
const text = await res.text().catch(() => "");
|
|
137
|
+
throw new Error(`Client registration failed (${res.status}): ${text.slice(0, 300)}`);
|
|
138
|
+
}
|
|
139
|
+
const data = (await res.json());
|
|
140
|
+
if (!data.client_id) {
|
|
141
|
+
throw new Error("Client registration response did not include a client_id.");
|
|
142
|
+
}
|
|
143
|
+
return data.client_id;
|
|
144
|
+
}
|
|
145
|
+
async function exchangeCode(base, code, redirectUri, clientId, verifier) {
|
|
146
|
+
const res = await fetch(`${base}/oauth/mcp/token`, {
|
|
147
|
+
method: "POST",
|
|
148
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
149
|
+
body: new URLSearchParams({
|
|
150
|
+
grant_type: "authorization_code",
|
|
151
|
+
code,
|
|
152
|
+
redirect_uri: redirectUri,
|
|
153
|
+
client_id: clientId,
|
|
154
|
+
code_verifier: verifier,
|
|
155
|
+
}).toString(),
|
|
156
|
+
});
|
|
157
|
+
const data = (await res.json().catch(() => ({})));
|
|
158
|
+
if (!res.ok || !data.access_token) {
|
|
159
|
+
const detail = data.error_description || data.error || `HTTP ${res.status}`;
|
|
160
|
+
throw new Error(`Token exchange failed: ${detail}`);
|
|
161
|
+
}
|
|
162
|
+
return data.access_token;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Run the full browser OAuth flow against a MIND backend and return the
|
|
166
|
+
* minted `mind_` API key.
|
|
167
|
+
*/
|
|
168
|
+
async function connectViaBrowser(baseUrl, options = {}) {
|
|
169
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
170
|
+
const clientName = options.clientName ?? DEFAULT_CLIENT_NAME;
|
|
171
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
172
|
+
const shouldOpenBrowser = options.openBrowser ?? process.env.MIND_CONNECT_NO_BROWSER !== "1";
|
|
173
|
+
const { verifier, challenge } = generatePkcePair();
|
|
174
|
+
const state = base64url(crypto.randomBytes(24));
|
|
175
|
+
return new Promise((resolve, reject) => {
|
|
176
|
+
let settled = false;
|
|
177
|
+
let timer;
|
|
178
|
+
const server = http.createServer();
|
|
179
|
+
const finish = (err, key) => {
|
|
180
|
+
if (settled)
|
|
181
|
+
return;
|
|
182
|
+
settled = true;
|
|
183
|
+
if (timer)
|
|
184
|
+
clearTimeout(timer);
|
|
185
|
+
// Stop accepting connections; in-flight responses use "Connection: close"
|
|
186
|
+
// so they flush fully and the server drains on its own.
|
|
187
|
+
server.close();
|
|
188
|
+
// Drop any lingering idle keep-alive sockets so the CLI exits promptly
|
|
189
|
+
// (Node 18.2+). Responses are flushed before this runs because every
|
|
190
|
+
// handler ends the response before calling finish().
|
|
191
|
+
setImmediate(() => {
|
|
192
|
+
server.closeIdleConnections?.();
|
|
193
|
+
});
|
|
194
|
+
if (err)
|
|
195
|
+
reject(err);
|
|
196
|
+
else
|
|
197
|
+
resolve(key);
|
|
198
|
+
};
|
|
199
|
+
server.on("error", (err) => finish(new Error(`Local callback server error: ${err.message}`)));
|
|
200
|
+
server.on("request", (req, res) => {
|
|
201
|
+
void (async () => {
|
|
202
|
+
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
203
|
+
if (url.pathname !== CALLBACK_PATH) {
|
|
204
|
+
res.writeHead(404, { "Content-Type": "text/plain", Connection: "close" });
|
|
205
|
+
res.end("Not found");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const respond = (status, html) => {
|
|
209
|
+
res.writeHead(status, {
|
|
210
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
211
|
+
"Cache-Control": "no-store",
|
|
212
|
+
Connection: "close",
|
|
213
|
+
});
|
|
214
|
+
res.end(html);
|
|
215
|
+
};
|
|
216
|
+
const errParam = url.searchParams.get("error");
|
|
217
|
+
if (errParam) {
|
|
218
|
+
const desc = url.searchParams.get("error_description") || errParam;
|
|
219
|
+
respond(400, errorPage(desc));
|
|
220
|
+
finish(new Error(`Authorization failed: ${desc}`));
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const code = url.searchParams.get("code");
|
|
224
|
+
const returnedState = url.searchParams.get("state");
|
|
225
|
+
if (!code) {
|
|
226
|
+
respond(400, errorPage("No authorization code was returned"));
|
|
227
|
+
finish(new Error("Callback did not include an authorization code."));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (returnedState !== state) {
|
|
231
|
+
respond(400, errorPage("State mismatch — possible cross-site request forgery"));
|
|
232
|
+
finish(new Error("State mismatch on OAuth callback — aborting (possible CSRF). Retry the connection."));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const accessToken = await exchangeCode(base, code, redirectUri, clientId, verifier);
|
|
237
|
+
respond(200, SUCCESS_PAGE);
|
|
238
|
+
finish(null, accessToken);
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
242
|
+
respond(502, errorPage(message));
|
|
243
|
+
finish(new Error(message));
|
|
244
|
+
}
|
|
245
|
+
})();
|
|
246
|
+
});
|
|
247
|
+
let redirectUri = "";
|
|
248
|
+
let clientId = "";
|
|
249
|
+
server.listen(0, "127.0.0.1", () => {
|
|
250
|
+
void (async () => {
|
|
251
|
+
try {
|
|
252
|
+
const { port } = server.address();
|
|
253
|
+
redirectUri = `http://127.0.0.1:${port}${CALLBACK_PATH}`;
|
|
254
|
+
clientId = await registerClient(base, redirectUri, clientName);
|
|
255
|
+
const authorizeUrl = `${base}/oauth/mcp/authorize?` +
|
|
256
|
+
new URLSearchParams({
|
|
257
|
+
response_type: "code",
|
|
258
|
+
client_id: clientId,
|
|
259
|
+
redirect_uri: redirectUri,
|
|
260
|
+
state,
|
|
261
|
+
code_challenge: challenge,
|
|
262
|
+
code_challenge_method: "S256",
|
|
263
|
+
scope: "mind:full",
|
|
264
|
+
}).toString();
|
|
265
|
+
options.onAuthorizeUrl?.(authorizeUrl);
|
|
266
|
+
if (shouldOpenBrowser) {
|
|
267
|
+
console.log("Opening your browser to connect to MIND...");
|
|
268
|
+
openInBrowser(authorizeUrl);
|
|
269
|
+
console.log("If the browser didn't open, use this link to connect:");
|
|
270
|
+
console.log(` ${authorizeUrl}`);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
console.log("Open this link to connect:");
|
|
274
|
+
console.log(` ${authorizeUrl}`);
|
|
275
|
+
}
|
|
276
|
+
console.log("");
|
|
277
|
+
console.log("Waiting for you to click \"Connect\" in the browser...");
|
|
278
|
+
timer = setTimeout(() => {
|
|
279
|
+
finish(new Error(`Timed out after ${Math.round(timeoutMs / 60000)} minutes waiting for the browser connection. Run the setup again to retry.`));
|
|
280
|
+
}, timeoutMs);
|
|
281
|
+
// Don't let the timer keep the process alive on its own.
|
|
282
|
+
timer.unref?.();
|
|
283
|
+
}
|
|
284
|
+
catch (err) {
|
|
285
|
+
finish(err instanceof Error ? err : new Error(String(err)));
|
|
286
|
+
}
|
|
287
|
+
})();
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=oauth-connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-connect.js","sourceRoot":"","sources":["../src/oauth-connect.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAo7JjE"}
|
package/dist/server.js
CHANGED
|
@@ -48,7 +48,7 @@ const integration_guide_js_1 = require("./integration-guide.js");
|
|
|
48
48
|
function createMindMcpServer(client) {
|
|
49
49
|
const server = new mcp_js_1.McpServer({
|
|
50
50
|
name: "mind",
|
|
51
|
-
version: "0.
|
|
51
|
+
version: "0.23.0",
|
|
52
52
|
}, {
|
|
53
53
|
// Returned to every client in the MCP `initialize` response — the first
|
|
54
54
|
// thing any connecting agent sees about how to integrate with MIND.
|
|
@@ -1392,6 +1392,155 @@ function createMindMcpServer(client) {
|
|
|
1392
1392
|
};
|
|
1393
1393
|
}
|
|
1394
1394
|
});
|
|
1395
|
+
// ─── mind_checklists ────────────────────────────────────
|
|
1396
|
+
// The granular level beneath a Task. Shape: Template → Sections[phase] →
|
|
1397
|
+
// Items. Templates (yours + flagship) instantiate into runs attached to a
|
|
1398
|
+
// task or life item; items are toggled and runs completed (which mirrors the
|
|
1399
|
+
// finished checklist into the knowledge graph).
|
|
1400
|
+
server.tool("mind_checklists", "Manage checklists in MIND — the granular level beneath a Task in the Focus→Project→Outcome→Task→Checklist hierarchy. A checklist attaches to a task (parent_type=task) or a Life item (parent_type=life_item) and groups checkable steps into phase-bucketed sections (pre/run/post). Use list_templates/get_template/create_template for reusable blueprints (including global flagship templates), then create a run from a template_id or inline sections_json, toggle_item to check steps, and complete to finish + mirror it into the knowledge graph.", {
|
|
1401
|
+
action: zod_1.z
|
|
1402
|
+
.enum([
|
|
1403
|
+
"list_templates", "get_template", "create_template",
|
|
1404
|
+
"list", "create", "get", "toggle_item", "complete", "delete",
|
|
1405
|
+
])
|
|
1406
|
+
.describe("What to do: list_templates/get_template/create_template (blueprints); list/create/get/toggle_item/complete/delete (runs)"),
|
|
1407
|
+
template_id: zod_1.z.string().optional().describe("Template ID — required for get_template; optional on create (instantiate from a template)"),
|
|
1408
|
+
checklist_id: zod_1.z.string().optional().describe("Checklist run ID — required for get/toggle_item/complete/delete"),
|
|
1409
|
+
item_id: zod_1.z.string().optional().describe("Checklist item ID — required for toggle_item"),
|
|
1410
|
+
title: zod_1.z.string().optional().describe("Title (required for create_template; optional for create run)"),
|
|
1411
|
+
description: zod_1.z.string().optional().describe("Template description (create_template)"),
|
|
1412
|
+
parent_type: zod_1.z.string().optional().describe("Attach a run to: task or life_item (required for create + list filter)"),
|
|
1413
|
+
parent_id: zod_1.z.string().optional().describe("ID of the parent task / life item (required for create)"),
|
|
1414
|
+
parent_label: zod_1.z.string().optional().describe("Optional human label for the parent"),
|
|
1415
|
+
sections_json: zod_1.z.string().optional().describe('Inline sections as JSON, e.g. [{"title":"Setup","phase":"pre","items":[{"label":"do x"}]}] — for create_template or an inline create run'),
|
|
1416
|
+
}, async ({ action, template_id, checklist_id, item_id, title, description, parent_type, parent_id, parent_label, sections_json }) => {
|
|
1417
|
+
try {
|
|
1418
|
+
const parseSections = () => {
|
|
1419
|
+
if (!sections_json)
|
|
1420
|
+
return undefined;
|
|
1421
|
+
const parsed = JSON.parse(sections_json);
|
|
1422
|
+
if (!Array.isArray(parsed))
|
|
1423
|
+
throw new Error("sections_json must be a JSON array of sections");
|
|
1424
|
+
return parsed;
|
|
1425
|
+
};
|
|
1426
|
+
const fmtTemplate = (t) => {
|
|
1427
|
+
const secCount = (t.sections ?? []).length;
|
|
1428
|
+
const itemCount = (t.sections ?? []).reduce((n, s) => n + (s.items?.length ?? 0), 0);
|
|
1429
|
+
return `• ${t.title}${t.origin === "flagship" ? " ⭐ flagship" : ""} — ${secCount} section(s), ${itemCount} item(s) — id: ${t.template_id}`;
|
|
1430
|
+
};
|
|
1431
|
+
const fmtSections = (sections) => (sections ?? [])
|
|
1432
|
+
.map((s) => {
|
|
1433
|
+
const head = ` [${s.phase}] ${s.title}`;
|
|
1434
|
+
const items = (s.items ?? [])
|
|
1435
|
+
.map((it) => ` ${it.checked ? "[x]" : "[ ]"} ${it.label} — id: ${it.item_id}`)
|
|
1436
|
+
.join("\n");
|
|
1437
|
+
return items ? `${head}\n${items}` : head;
|
|
1438
|
+
})
|
|
1439
|
+
.join("\n");
|
|
1440
|
+
const fmtChecklist = (c, withItems = false) => {
|
|
1441
|
+
const p = c.progress ?? { done: 0, total: 0, pct: 0 };
|
|
1442
|
+
const head = `• ${c.title} (${p.done}/${p.total}, ${p.pct}%)` +
|
|
1443
|
+
`${c.completed_at ? " ✅ complete" : ""}` +
|
|
1444
|
+
`${c.parent_label ? `, on ${c.parent_label}` : ""} — id: ${c.checklist_id}`;
|
|
1445
|
+
return withItems ? `${head}\n${fmtSections(c.sections ?? [])}` : head;
|
|
1446
|
+
};
|
|
1447
|
+
switch (action) {
|
|
1448
|
+
case "list_templates": {
|
|
1449
|
+
const result = await client.listChecklistTemplates();
|
|
1450
|
+
const templates = result.templates ?? [];
|
|
1451
|
+
if (templates.length === 0) {
|
|
1452
|
+
return { content: [{ type: "text", text: "No checklist templates found." }] };
|
|
1453
|
+
}
|
|
1454
|
+
return {
|
|
1455
|
+
content: [{
|
|
1456
|
+
type: "text",
|
|
1457
|
+
text: `${result.total} template(s):\n` + templates.map(fmtTemplate).join("\n"),
|
|
1458
|
+
}],
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
case "get_template": {
|
|
1462
|
+
if (!template_id) {
|
|
1463
|
+
return { content: [{ type: "text", text: "Error: template_id is required for get_template" }], isError: true };
|
|
1464
|
+
}
|
|
1465
|
+
const t = await client.getChecklistTemplate(template_id);
|
|
1466
|
+
return {
|
|
1467
|
+
content: [{
|
|
1468
|
+
type: "text",
|
|
1469
|
+
text: `${fmtTemplate(t)}${t.description ? `\n${t.description}` : ""}\n${fmtSections(t.sections ?? [])}`,
|
|
1470
|
+
}],
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
case "create_template": {
|
|
1474
|
+
if (!title) {
|
|
1475
|
+
return { content: [{ type: "text", text: "Error: title is required to create a template" }], isError: true };
|
|
1476
|
+
}
|
|
1477
|
+
const t = await client.createChecklistTemplate({
|
|
1478
|
+
title, description, sections: parseSections(),
|
|
1479
|
+
});
|
|
1480
|
+
return { content: [{ type: "text", text: `✅ Created template: ${fmtTemplate(t)}` }] };
|
|
1481
|
+
}
|
|
1482
|
+
case "list": {
|
|
1483
|
+
const result = await client.listChecklists(parent_type, parent_id);
|
|
1484
|
+
const checklists = result.checklists ?? [];
|
|
1485
|
+
if (checklists.length === 0) {
|
|
1486
|
+
return { content: [{ type: "text", text: "No checklists found." }] };
|
|
1487
|
+
}
|
|
1488
|
+
return {
|
|
1489
|
+
content: [{
|
|
1490
|
+
type: "text",
|
|
1491
|
+
text: `${result.total} checklist(s):\n` + checklists.map((c) => fmtChecklist(c)).join("\n"),
|
|
1492
|
+
}],
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
case "create": {
|
|
1496
|
+
if (!parent_type || !parent_id) {
|
|
1497
|
+
return { content: [{ type: "text", text: "Error: parent_type and parent_id are required to create a checklist run" }], isError: true };
|
|
1498
|
+
}
|
|
1499
|
+
const c = await client.createChecklist({
|
|
1500
|
+
parent_type, parent_id, parent_label, title,
|
|
1501
|
+
template_id, sections: parseSections(),
|
|
1502
|
+
});
|
|
1503
|
+
return { content: [{ type: "text", text: `✅ Created checklist:\n${fmtChecklist(c, true)}` }] };
|
|
1504
|
+
}
|
|
1505
|
+
case "get": {
|
|
1506
|
+
if (!checklist_id) {
|
|
1507
|
+
return { content: [{ type: "text", text: "Error: checklist_id is required for get" }], isError: true };
|
|
1508
|
+
}
|
|
1509
|
+
const c = await client.getChecklist(checklist_id);
|
|
1510
|
+
return { content: [{ type: "text", text: fmtChecklist(c, true) }] };
|
|
1511
|
+
}
|
|
1512
|
+
case "toggle_item": {
|
|
1513
|
+
if (!checklist_id || !item_id) {
|
|
1514
|
+
return { content: [{ type: "text", text: "Error: checklist_id and item_id are required for toggle_item" }], isError: true };
|
|
1515
|
+
}
|
|
1516
|
+
const c = await client.toggleChecklistItem(checklist_id, item_id);
|
|
1517
|
+
return { content: [{ type: "text", text: `✅ Toggled item:\n${fmtChecklist(c, true)}` }] };
|
|
1518
|
+
}
|
|
1519
|
+
case "complete": {
|
|
1520
|
+
if (!checklist_id) {
|
|
1521
|
+
return { content: [{ type: "text", text: "Error: checklist_id is required for complete" }], isError: true };
|
|
1522
|
+
}
|
|
1523
|
+
const c = await client.completeChecklist(checklist_id);
|
|
1524
|
+
return { content: [{ type: "text", text: `✅ Completed checklist "${c.title}" — mirrored to the knowledge graph.` }] };
|
|
1525
|
+
}
|
|
1526
|
+
case "delete": {
|
|
1527
|
+
if (!checklist_id) {
|
|
1528
|
+
return { content: [{ type: "text", text: "Error: checklist_id is required for delete" }], isError: true };
|
|
1529
|
+
}
|
|
1530
|
+
await client.deleteChecklist(checklist_id);
|
|
1531
|
+
return { content: [{ type: "text", text: `🗑️ Deleted checklist ${checklist_id}` }] };
|
|
1532
|
+
}
|
|
1533
|
+
default:
|
|
1534
|
+
return { content: [{ type: "text", text: `Unknown action: ${action}` }], isError: true };
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
catch (err) {
|
|
1538
|
+
return {
|
|
1539
|
+
content: [{ type: "text", text: `mind_checklists error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
1540
|
+
isError: true,
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1395
1544
|
// ─── mind_crm ───────────────────────────────────────────
|
|
1396
1545
|
// Read/write contacts, interactions, and activities.
|
|
1397
1546
|
// Enhanced: delete, get, log_activity, list_activities.
|