minutes-mcp 0.25.0 → 0.25.1

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 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 isWindows = process.platform === "win32";
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.0";
1572
+ const MCP_SERVER_VERSION = "0.25.1";
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;
@@ -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 afterRequiredCli(async () => {
7112
- crashTrace("required-cli-ready");
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
- await afterRequiredCli(async () => {
7130
- crashTrace("required-cli-ready");
7131
- const transport = new StdioServerTransport();
7132
- crashTrace("transport-created");
7133
- await server.connect(transport);
7134
- crashTrace("transport-connected");
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.0",
3
+ "version": "0.25.1",
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.0",
48
+ "minutes-sdk": "0.25.1",
49
49
  "yaml": "^2.8.3",
50
50
  "zod": "^3.25 || ^4.0"
51
51
  },