minutes-mcp 0.25.0 → 0.25.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/dist/index.d.ts +11 -0
- package/dist/index.js +90 -14
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -411,6 +411,17 @@ export declare function selectCopilotNudges(observation: CopilotNudgeObservation
|
|
|
411
411
|
since?: string;
|
|
412
412
|
limit?: number;
|
|
413
413
|
}, nowMs?: number): CopilotNudgeReadPage;
|
|
414
|
+
/**
|
|
415
|
+
* What a person should actually do when the CLI is absent, phrased for the
|
|
416
|
+
* surface they installed.
|
|
417
|
+
*
|
|
418
|
+
* The server downloads a prebuilt CLI on first run, so this text is only ever
|
|
419
|
+
* reached when that could not complete: no network, a proxy, or a platform
|
|
420
|
+
* with no published binary. Naming the likely cause matters more than naming
|
|
421
|
+
* the component, because the reader is usually a Claude Desktop user who never
|
|
422
|
+
* chose to have a CLI at all (#774).
|
|
423
|
+
*/
|
|
424
|
+
export declare function cliMissingGuidance(platform?: NodeJS.Platform): string;
|
|
414
425
|
declare function runMinutes(args: string[], timeoutMs?: number, signal?: AbortSignal, extraEnv?: Record<string, string>): Promise<{
|
|
415
426
|
stdout: string;
|
|
416
427
|
stderr: string;
|
package/dist/index.js
CHANGED
|
@@ -1499,7 +1499,8 @@ else {
|
|
|
1499
1499
|
}
|
|
1500
1500
|
// ── Find the minutes binary ─────────────────────────────────
|
|
1501
1501
|
function findMinutesBinary() {
|
|
1502
|
-
const
|
|
1502
|
+
const platform = process.platform;
|
|
1503
|
+
const isWindows = platform === "win32";
|
|
1503
1504
|
const ext = isWindows ? ".exe" : "";
|
|
1504
1505
|
const candidates = [
|
|
1505
1506
|
join(__dirname, "..", "..", "..", "target", "release", `minutes${ext}`),
|
|
@@ -1517,6 +1518,19 @@ function findMinutesBinary() {
|
|
|
1517
1518
|
"/opt/homebrew/bin/minutes",
|
|
1518
1519
|
"/usr/local/bin/minutes",
|
|
1519
1520
|
]),
|
|
1521
|
+
// Inside the desktop app, which ships the CLI as a sidecar and updates it
|
|
1522
|
+
// with the app. Without this, someone who installed the app and never
|
|
1523
|
+
// opened it has the engine on disk while the extension reports it missing,
|
|
1524
|
+
// and the remedy we print is something they have already done. The app's
|
|
1525
|
+
// own "Set up CLI" symlinks ~/.local/bin above, so this is the path for
|
|
1526
|
+
// people who never clicked it.
|
|
1527
|
+
...(platform === "darwin"
|
|
1528
|
+
? [
|
|
1529
|
+
"/Applications/Minutes.app/Contents/MacOS/minutes",
|
|
1530
|
+
join(homedir(), "Applications", "Minutes.app", "Contents", "MacOS", "minutes"),
|
|
1531
|
+
join(homedir(), "Applications", "Minutes Dev.app", "Contents", "MacOS", "minutes"),
|
|
1532
|
+
]
|
|
1533
|
+
: []),
|
|
1520
1534
|
];
|
|
1521
1535
|
for (const candidate of candidates) {
|
|
1522
1536
|
if (existsSync(candidate)) {
|
|
@@ -1555,7 +1569,7 @@ const COPILOT_SUPPORTED = hasFeature(CLI_CAPABILITIES, "copilot_realtime");
|
|
|
1555
1569
|
// `./version.ts` (see issue #183). Hosted `.mcpb` bundles will run
|
|
1556
1570
|
// against CLIs with different minor/patch numbers within the same
|
|
1557
1571
|
// major; that is explicitly supported.
|
|
1558
|
-
const MCP_SERVER_VERSION = "0.25.
|
|
1572
|
+
const MCP_SERVER_VERSION = "0.25.2";
|
|
1559
1573
|
export function parseKnowledgeConfig(configContent) {
|
|
1560
1574
|
const knowledgeMatch = configContent.match(/\[knowledge\][\s\S]*?(?=\n\[|$)/);
|
|
1561
1575
|
if (!knowledgeMatch) {
|
|
@@ -2378,6 +2392,28 @@ export function selectCopilotNudges(observation, options, nowMs = Date.now()) {
|
|
|
2378
2392
|
* than several.
|
|
2379
2393
|
*/
|
|
2380
2394
|
const MCP_CLI_MAX_STDOUT_BYTES = 64 * 1024 * 1024;
|
|
2395
|
+
/**
|
|
2396
|
+
* What a person should actually do when the CLI is absent, phrased for the
|
|
2397
|
+
* surface they installed.
|
|
2398
|
+
*
|
|
2399
|
+
* The server downloads a prebuilt CLI on first run, so this text is only ever
|
|
2400
|
+
* reached when that could not complete: no network, a proxy, or a platform
|
|
2401
|
+
* with no published binary. Naming the likely cause matters more than naming
|
|
2402
|
+
* the component, because the reader is usually a Claude Desktop user who never
|
|
2403
|
+
* chose to have a CLI at all (#774).
|
|
2404
|
+
*/
|
|
2405
|
+
export function cliMissingGuidance(platform = process.platform) {
|
|
2406
|
+
// Only macOS and Windows have a desktop app. Linux ships the CLI alone, so
|
|
2407
|
+
// pointing a Linux user at "the app" sends them to a download that does not
|
|
2408
|
+
// exist.
|
|
2409
|
+
const manual = platform === "darwin" || platform === "win32"
|
|
2410
|
+
? "Install the free Minutes desktop app from https://useminutes.app, which includes the engine and keeps it updated."
|
|
2411
|
+
: "Install the Minutes CLI from https://useminutes.app, or run `cargo install minutes-cli`.";
|
|
2412
|
+
return ("The Minutes engine is not installed yet. Minutes normally installs it " +
|
|
2413
|
+
"automatically on first run, so this usually means it could not be " +
|
|
2414
|
+
"downloaded: no internet access, a proxy, or an unsupported platform. " +
|
|
2415
|
+
`${manual} Then restart this app.`);
|
|
2416
|
+
}
|
|
2381
2417
|
async function runMinutes(args, timeoutMs = 30000, signal, extraEnv = {}) {
|
|
2382
2418
|
try {
|
|
2383
2419
|
const { stdout, stderr } = await execFileAsync(MINUTES_BIN, args, {
|
|
@@ -2392,6 +2428,16 @@ async function runMinutes(args, timeoutMs = 30000, signal, extraEnv = {}) {
|
|
|
2392
2428
|
if (error.killed) {
|
|
2393
2429
|
throw new Error(`Command timed out after ${timeoutMs}ms`);
|
|
2394
2430
|
}
|
|
2431
|
+
// Every tool reaches the CLI through here, including the readiness probe
|
|
2432
|
+
// behind the content-bearing tools, so this one branch is what turns a
|
|
2433
|
+
// missing engine into advice instead of ENOENT.
|
|
2434
|
+
if (error?.code === "ENOENT") {
|
|
2435
|
+
const missing = new Error(cliMissingGuidance());
|
|
2436
|
+
// Tagged rather than string-matched, so callers that deliberately keep
|
|
2437
|
+
// their own failures opaque can still let this one through.
|
|
2438
|
+
missing.cliMissing = true;
|
|
2439
|
+
throw missing;
|
|
2440
|
+
}
|
|
2395
2441
|
const stderr = error.stderr?.trim() || "";
|
|
2396
2442
|
const stdout = error.stdout?.trim() || "";
|
|
2397
2443
|
// Preserve both streams on the thrown error: some commands (e.g.
|
|
@@ -2442,7 +2488,14 @@ export async function readAgentTrustReadiness(runner = runMinutes) {
|
|
|
2442
2488
|
try {
|
|
2443
2489
|
({ stdout } = await runner(["agent-readiness", "--json"]));
|
|
2444
2490
|
}
|
|
2445
|
-
catch {
|
|
2491
|
+
catch (error) {
|
|
2492
|
+
// A malformed or unverifiable readiness answer stays opaque on purpose:
|
|
2493
|
+
// the caller must not learn why the boundary refused. A missing engine is
|
|
2494
|
+
// not that. It is the reader's own machine state, it is already printed by
|
|
2495
|
+
// the capture tools, and withholding it leaves a Claude Desktop user with
|
|
2496
|
+
// "could not be verified safely" and nothing to do about it (#774).
|
|
2497
|
+
if (error?.cliMissing)
|
|
2498
|
+
throw error;
|
|
2446
2499
|
throw new Error("Minutes agent readiness could not be verified safely.");
|
|
2447
2500
|
}
|
|
2448
2501
|
let result;
|
|
@@ -2470,7 +2523,7 @@ export async function requireAgentTrustReadiness(runner = runMinutes) {
|
|
|
2470
2523
|
const readiness = await readAgentTrustReadiness(runner);
|
|
2471
2524
|
if (!readiness.ready) {
|
|
2472
2525
|
throw new Error(readiness.remediation ||
|
|
2473
|
-
"
|
|
2526
|
+
"This machine shows a Minutes-owned QMD registration that qmd could not confirm was removed. Make sure `qmd` runs (`qmd collection list`), then run `minutes qmd cleanup` and restart Minutes.");
|
|
2474
2527
|
}
|
|
2475
2528
|
return readiness;
|
|
2476
2529
|
}
|
|
@@ -7099,6 +7152,24 @@ function printUsage() {
|
|
|
7099
7152
|
].join("\n"));
|
|
7100
7153
|
}
|
|
7101
7154
|
// ── Start server ────────────────────────────────────────────
|
|
7155
|
+
/**
|
|
7156
|
+
* Probe for the engine at startup, install it if possible, and say what
|
|
7157
|
+
* happened. Never throws: startup does not depend on the outcome.
|
|
7158
|
+
*/
|
|
7159
|
+
async function announceCliAvailability() {
|
|
7160
|
+
let available = false;
|
|
7161
|
+
try {
|
|
7162
|
+
available = await isCliAvailable();
|
|
7163
|
+
}
|
|
7164
|
+
catch {
|
|
7165
|
+
// A probe that fails is the same as one that says no.
|
|
7166
|
+
}
|
|
7167
|
+
crashTrace(available ? "required-cli-ready" : "required-cli-absent");
|
|
7168
|
+
if (!available) {
|
|
7169
|
+
console.error(`[Minutes] ${cliMissingGuidance()}`);
|
|
7170
|
+
console.error("[Minutes] Starting anyway so tools can report this. Tools that need the engine will explain it.");
|
|
7171
|
+
}
|
|
7172
|
+
}
|
|
7102
7173
|
async function main() {
|
|
7103
7174
|
crashTrace("main-start");
|
|
7104
7175
|
const config = parseTransportConfig(process.argv.slice(2));
|
|
@@ -7108,8 +7179,8 @@ async function main() {
|
|
|
7108
7179
|
}
|
|
7109
7180
|
if (config.transport === "http") {
|
|
7110
7181
|
crashTrace("main-transport-http", { port: config.port });
|
|
7111
|
-
await
|
|
7112
|
-
|
|
7182
|
+
await announceCliAvailability();
|
|
7183
|
+
{
|
|
7113
7184
|
const httpServer = await startMinutesHttpServer({
|
|
7114
7185
|
port: config.port,
|
|
7115
7186
|
maxSessions: config.maxSessions,
|
|
@@ -7123,16 +7194,21 @@ async function main() {
|
|
|
7123
7194
|
};
|
|
7124
7195
|
process.once("SIGINT", shutdown);
|
|
7125
7196
|
process.once("SIGTERM", shutdown);
|
|
7126
|
-
}
|
|
7197
|
+
}
|
|
7127
7198
|
return;
|
|
7128
7199
|
}
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7200
|
+
// The handshake is never gated on the engine. Refusing to start buys no
|
|
7201
|
+
// safety over refusing each operation, because completing a handshake and
|
|
7202
|
+
// listing tools exposes nothing, and every tool that touches content still
|
|
7203
|
+
// checks readiness on each call. What it did cost was the entire diagnosis:
|
|
7204
|
+
// a user whose auto-install could not reach the network got a server that
|
|
7205
|
+
// exited before saying anything, which reads as a broken extension rather
|
|
7206
|
+
// than a missing dependency (#774, reported against v0.25.0).
|
|
7207
|
+
await announceCliAvailability();
|
|
7208
|
+
const transport = new StdioServerTransport();
|
|
7209
|
+
crashTrace("transport-created");
|
|
7210
|
+
await server.connect(transport);
|
|
7211
|
+
crashTrace("transport-connected");
|
|
7136
7212
|
console.error("Minutes MCP server running on stdio");
|
|
7137
7213
|
}
|
|
7138
7214
|
crashTrace("pre-main-guard", {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minutes-mcp",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.2",
|
|
4
4
|
"description": "MCP server for minutes \u2014 conversation memory for AI assistants. Works with Claude Desktop, Mistral Vibe, Cursor, Windsurf, and any MCP client.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@modelcontextprotocol/ext-apps": "^1.6.0",
|
|
47
47
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
48
|
-
"minutes-sdk": "0.25.
|
|
48
|
+
"minutes-sdk": "0.25.2",
|
|
49
49
|
"yaml": "^2.8.3",
|
|
50
50
|
"zod": "^3.25 || ^4.0"
|
|
51
51
|
},
|