@askthew/mcp-plugin 0.4.8 → 0.4.10

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 CHANGED
@@ -6,7 +6,7 @@ Connect a local coding agent to Ask The W. The fastest path is free and local-fi
6
6
  npx -y --prefer-online --package @askthew/mcp-plugin@latest askthew-mcp install --host claude_code --free --email you@founder.com
7
7
  ```
8
8
 
9
- This captures decisions and session signals to `~/.askthew/store.sqlite` and lets your agent run `review_decisions`, `review_session`, `recap`, `coach`, and `promote_signal_to_decision` without onboarding into the web app.
9
+ This captures decisions and session signals to `~/.askthew/store.sqlite` and lets your agent list the trail, keep decisions, and get limited local recap and coaching without onboarding into the web app.
10
10
 
11
11
  Founder-friendly promise: install from npm, then ask your coding agent to review the last session. You should see value in under 60 seconds.
12
12
 
@@ -19,7 +19,7 @@ This package runs a small MCP server that lets Codex, Claude Code, Cursor, and o
19
19
  - Adds marked project instructions so future coding-agent sessions know when to send Ask The W updates.
20
20
  - Free mode stores full-fidelity signals and decisions locally in SQLite.
21
21
  - Paid workspace mode sends a startup heartbeat so Ask The W can show the plugin as installed.
22
- - Exposes `capture_session_signal` plus v1 API tools for decisions, outcomes, signals, outcome detail graphs, and north star reads or updates.
22
+ - Exposes a small MCP surface for capture, signals, decisions, recap, and coaching.
23
23
  - Redacts obvious secrets from summaries, evidence excerpts, commands, and metadata before sending.
24
24
  - Adds lightweight workspace metadata such as host type, repo name, app path, and server name.
25
25
 
@@ -27,10 +27,10 @@ This package runs a small MCP server that lets Codex, Claude Code, Cursor, and o
27
27
 
28
28
  - It does not send full transcripts by default.
29
29
  - It does not send local free-tier content to Ask The W unless you upgrade and run sync upload.
30
- - It does not link outcomes, score confidence, dedupe signals, or update the graph locally.
30
+ - It does not expose internal workspace APIs through the plugin.
31
31
  - It does not include the Ask The W app, private server code, Supabase code, or internal analytics code.
32
32
 
33
- Ask The W performs inference, linking, approval state, dedupe, and outcome updates in the app.
33
+ Ask The W keeps the local plugin focused on the trail your agent can use while it works.
34
34
 
35
35
  ## Free Local Install
36
36
 
@@ -183,15 +183,13 @@ The session-signal tool remains the main automatic capture path.
183
183
 
184
184
  Use compact summaries and short evidence excerpts. Do not send full transcripts. By default, write tools return compact responses; use `echo: "full"` only when you need the larger payload for debugging.
185
185
 
186
- The plugin also exposes v1 API tools that map to the app's authenticated routes:
186
+ The plugin exposes a small public tool surface:
187
187
 
188
188
  | Tool | Purpose |
189
189
  |---|---|
190
- | `list_decisions`, `get_decision`, `create_decision`, `update_decision`, `delete_decision` | Work with decision feed entries. |
191
- | `review_session`, `recap`, `coach`, `promote_signal_to_decision`, `find_signal_by_summary` | Review local sessions, get session coaching, find recent evidence, and turn signals into decisions in free mode. |
192
- | `list_outcomes`, `get_outcome`, `list_outcome_signals`, `create_outcome`, `update_outcome`, `delete_outcome` | Work with outcomes and their linked signals. |
193
- | `get_north_star`, `update_north_star` | Read or update the workspace north star. API updates are allowed only for private workspaces. |
194
- | `list_signals`, `get_signal` | Read workspace signals. |
190
+ | `capture_session_signal`, `list_signals` | Capture and list the local signal trail. |
191
+ | `list_decisions`, `get_decision`, `create_decision`, `promote_signal_to_decision` | Keep the decisions worth remembering. |
192
+ | `recap`, `coach` | Get up to three local recaps and three coaching nudges. After that, the plugin returns `Limit reached. Upgrade to the paid plan.` |
195
193
 
196
194
  Free PLG helpers:
197
195
 
@@ -202,7 +200,7 @@ npx -y --prefer-online --package @askthew/mcp-plugin@latest askthew-mcp digest -
202
200
 
203
201
  The hook prompts when staged files recently had implementation signals but no linked decision. The weekly digest writes `~/Documents/askthew-digest-YYYY-WW.md`.
204
202
 
205
- API mutations are text-only and are recorded back into the workspace signal feed. Decision and outcome deletes require a `confirmText` value that exactly matches the stored decision headline or outcome name after whitespace normalization. North star delete is not available through the API.
203
+ Decision writes are text-only and are recorded with the local trail.
206
204
 
207
205
  ## Troubleshooting
208
206
 
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { execFileSync } from "node:child_process";
6
6
  import { fileURLToPath } from "node:url";
7
- import { createAskTheWMcpServer } from "./index.js";
7
+ import { createAskTheWMcpServer, runInitializeHandshake } from "./index.js";
8
8
  import { askTheWDataDir, ensureAskTheWDataDir, identityPath } from "./lib/paths.js";
9
9
  import { loadCliCredentials } from "./lib/free-tier-policy.js";
10
10
  import { describeFreeIdentity, tryRegisterFreeInstall } from "./lib/free-install-registration.js";
@@ -13,17 +13,21 @@ import { LocalStore } from "./lib/local-store.js";
13
13
  import { buildTelemetryPayload } from "./lib/telemetry.js";
14
14
  import { syncDryRun, uploadLocalStore } from "./lib/upgrade-sync.js";
15
15
  import { installPreCommitHook, localScopeKey, preCommitDecisionGap, stagedFiles, writeWeeklyDigest, } from "./lib/cli-actions.js";
16
- import { createHostConfigSnippet, findInstallReceipts, formatInstallCommand, installBehaviorInstructions, installHostConfig, removeInstallReceipts, sendInstallHeartbeat, uninstallBehaviorInstructions, uninstallHostConfig, writeInstallReceipt, } from "./install.js";
16
+ import { createHostConfigSnippet, defaultServerNameForTier, findInstallReceipts, formatInstallCommand, installBehaviorInstructions, installHostConfig, packageVersion, removeInstallReceipts, sendInstallHeartbeat, uninstallBehaviorInstructions, uninstallHostConfig, upgradePinnedHostConfig, writeInstallReceipt, } from "./install.js";
17
17
  function usage() {
18
18
  return [
19
19
  "Ask The W Coding Agent Connector",
20
20
  "",
21
21
  "Usage:",
22
- " askthew-mcp",
23
- " askthew-mcp install --host <claude_code|codex|cursor> --token <install-token> --api-url <url> --server-name <name> [--client-id <id>] [--client-label <label>] [--server-entrypoint <path>] [--dry-run] [--no-agent-instructions]",
24
- " askthew-mcp install --host <claude_code|codex|cursor> --free [--email <email>] [--api-url <url>] [--server-name <name>] [--server-entrypoint <path>]",
22
+ " askthew-mcp [stdio MCP server when stdin is piped]",
23
+ " askthew-mcp --version",
24
+ " askthew-mcp doctor [--server-entrypoint <path>]",
25
+ " askthew-mcp install --host <claude_code|codex|cursor> --token <install-token> --api-url <url> [--server-name <name>] [--client-id <id>] [--client-label <label>] [--server-entrypoint <path>] [--dry-run] [--no-agent-instructions]",
26
+ " askthew-mcp install --host <claude_code|codex|cursor> --free [--email <email>] [--api-url <url>] [--server-name <name>] [--server-entrypoint <path>] [--dry-run]",
25
27
  " askthew-mcp refresh --host <claude_code|codex|cursor> [--free] [--token <install-token>] [--api-url <url>] [--server-name <name>] [--server-entrypoint <path>] [--dry-run]",
26
28
  " askthew-mcp uninstall --host <claude_code|codex|cursor> [--server-name <name>] [--dry-run] [--keep-local-data] [--keep-auth] [--keep-agent-instructions]",
29
+ " askthew-mcp upgrade --host <claude_code|codex|cursor> [--server-name <name>] [--version <version>] [--dry-run]",
30
+ " askthew-mcp upgrade --browser",
27
31
  " askthew-mcp identify --email <email> [--no-telemetry]",
28
32
  " askthew-mcp identity status",
29
33
  " askthew-mcp auth login --email <email> [--no-telemetry]",
@@ -43,6 +47,7 @@ function parseInstallArgs(argv) {
43
47
  let token = normalizeInstallToken(process.env.ASKTHEW_INSTALL_TOKEN) || "";
44
48
  let apiUrl = process.env.ASKTHEW_API_URL?.trim() || "";
45
49
  let serverName = process.env.ASKTHEW_SERVER_NAME?.trim() || "";
50
+ let serverNameExplicit = Boolean(serverName);
46
51
  let dryRun = false;
47
52
  let installAgentInstructions = true;
48
53
  let free = false;
@@ -96,6 +101,7 @@ function parseInstallArgs(argv) {
96
101
  }
97
102
  if (argument === "--server-name") {
98
103
  serverName = next;
104
+ serverNameExplicit = true;
99
105
  index += 1;
100
106
  continue;
101
107
  }
@@ -121,7 +127,7 @@ function parseInstallArgs(argv) {
121
127
  apiUrl = "https://app.askthew.com";
122
128
  }
123
129
  if (!serverName) {
124
- serverName = "askthew";
130
+ serverName = defaultServerNameForTier(free);
125
131
  }
126
132
  return {
127
133
  hostType,
@@ -130,6 +136,7 @@ function parseInstallArgs(argv) {
130
136
  token,
131
137
  apiUrl,
132
138
  serverName,
139
+ serverNameExplicit,
133
140
  dryRun,
134
141
  installAgentInstructions,
135
142
  free,
@@ -140,16 +147,6 @@ function parseInstallArgs(argv) {
140
147
  function normalizeInstallToken(token) {
141
148
  return String(token ?? "").trim().replace(/^['"]/, "").replace(/['"]$/, "");
142
149
  }
143
- function packageVersion() {
144
- try {
145
- const packagePath = fileURLToPath(new URL("../package.json", import.meta.url));
146
- const parsed = JSON.parse(fs.readFileSync(packagePath, "utf8"));
147
- return typeof parsed.version === "string" ? parsed.version : "unknown";
148
- }
149
- catch {
150
- return "unknown";
151
- }
152
- }
153
150
  function detectLoginEmail() {
154
151
  for (const value of [
155
152
  process.env.ASKTHEW_EMAIL,
@@ -189,6 +186,14 @@ async function main() {
189
186
  console.log(usage());
190
187
  return;
191
188
  }
189
+ if (command === "--version" || command === "-v" || command === "version") {
190
+ console.log(packageVersion());
191
+ return;
192
+ }
193
+ if (command === "doctor") {
194
+ await runDoctorCommand(argv);
195
+ return;
196
+ }
192
197
  if (command === "print-config") {
193
198
  const options = parseInstallArgs(argv);
194
199
  const snippet = createHostConfigSnippet(options);
@@ -196,6 +201,7 @@ async function main() {
196
201
  return;
197
202
  }
198
203
  if (command === "install") {
204
+ console.error(`Downloading @askthew/mcp-plugin@${packageVersion()}...`);
199
205
  const options = parseInstallArgs(argv);
200
206
  let freeIdentity = null;
201
207
  if (options.free && !options.dryRun) {
@@ -228,11 +234,14 @@ async function main() {
228
234
  console.log(result.wroteFile ? "Ask The W plugin install complete." : "Ask The W plugin dry run complete.");
229
235
  console.log(`Settings path: ${result.settingsPath}`);
230
236
  if (instructions) {
231
- console.log(`Agent instructions: ${instructions.paths?.join(", ") ?? instructions.path}`);
237
+ console.log(`${options.dryRun ? "Would update agent instructions" : "Agent instructions"}: ${instructions.paths?.join(", ") ?? instructions.path}`);
232
238
  }
233
239
  if (receipt) {
234
240
  console.log(`Install receipt: ${receipt.hostType}/${receipt.serverName} at ${receipt.cwd}`);
235
241
  }
242
+ else if (options.dryRun) {
243
+ console.log(`Would write install receipt: ${options.hostType}/${options.serverName} at ${process.cwd()}`);
244
+ }
236
245
  console.log(`Install command: ${formatInstallCommand(options)}`);
237
246
  if (result.wroteFile) {
238
247
  if (freeIdentity) {
@@ -257,6 +266,7 @@ async function main() {
257
266
  console.log(`Next step: ${result.nextStep}`);
258
267
  if (!result.wroteFile) {
259
268
  console.log("");
269
+ console.log("Planned host config:");
260
270
  console.log(result.json);
261
271
  }
262
272
  return;
@@ -306,22 +316,24 @@ async function main() {
306
316
  return;
307
317
  }
308
318
  if (command === "upgrade") {
309
- console.log("Open https://askthew.com/plugin to upgrade, then run `askthew-mcp upgrade --finalize`.");
310
- if (argv.includes("--finalize")) {
311
- console.log("Finalize will rewrite host config after a paid workspace token is available in the web app.");
312
- }
319
+ await runUpgradeCommand(argv);
313
320
  return;
314
321
  }
315
322
  if (command) {
316
323
  throw new Error(`Unknown command "${command}".\n\n${usage()}`);
317
324
  }
325
+ if (process.stdin.isTTY) {
326
+ console.log(usage());
327
+ return;
328
+ }
318
329
  const server = createAskTheWMcpServer();
319
330
  const transport = new StdioServerTransport();
320
331
  await server.connect(transport);
321
332
  }
322
333
  async function runUninstallCommand(argv) {
323
334
  let hostType;
324
- let serverName = process.env.ASKTHEW_SERVER_NAME?.trim() || "askthew";
335
+ let serverName = process.env.ASKTHEW_SERVER_NAME?.trim() || undefined;
336
+ let serverNameExplicit = Boolean(serverName);
325
337
  let dryRun = false;
326
338
  let keepLocalData = false;
327
339
  let keepAuth = false;
@@ -357,6 +369,7 @@ async function runUninstallCommand(argv) {
357
369
  }
358
370
  if (argument === "--server-name") {
359
371
  serverName = next;
372
+ serverNameExplicit = true;
360
373
  index += 1;
361
374
  continue;
362
375
  }
@@ -366,7 +379,12 @@ async function runUninstallCommand(argv) {
366
379
  throw new Error("Usage: askthew-mcp uninstall --host <claude_code|codex|cursor> [--server-name <name>]");
367
380
  }
368
381
  const receipts = findInstallReceipts({ hostType, serverName });
369
- const config = uninstallHostConfig({ hostType, serverName, dryRun });
382
+ const config = uninstallHostConfig({
383
+ hostType,
384
+ serverName: serverNameExplicit ? serverName : undefined,
385
+ dryRun,
386
+ cwds: Array.from(new Set([process.cwd(), ...receipts.map((receipt) => receipt.cwd)])),
387
+ });
370
388
  const instructionCwds = Array.from(new Set([process.cwd(), ...receipts.map((receipt) => receipt.cwd)]));
371
389
  const instructionPaths = keepAgentInstructions
372
390
  ? []
@@ -419,6 +437,9 @@ async function runRefreshCommand(argv) {
419
437
  const options = {
420
438
  ...parsed,
421
439
  free: !isPaidRefresh,
440
+ serverName: parsed.serverNameExplicit
441
+ ? parsed.serverName
442
+ : defaultServerNameForTier(!isPaidRefresh),
422
443
  };
423
444
  const existingIdentity = loadLocalIdentity();
424
445
  let freeIdentity = existingIdentity;
@@ -497,6 +518,98 @@ async function runRefreshCommand(argv) {
497
518
  console.log(install.json);
498
519
  }
499
520
  }
521
+ async function runDoctorCommand(argv) {
522
+ const serverEntrypoint = argValue(argv, "--server-entrypoint")?.trim();
523
+ const result = await runInitializeHandshake({
524
+ entrypoint: serverEntrypoint ? path.resolve(serverEntrypoint) : undefined,
525
+ });
526
+ const expectedVersion = packageVersion();
527
+ if (result.serverInfoVersion !== expectedVersion) {
528
+ throw new Error(`MCP initialize version mismatch: package.json=${expectedVersion} serverInfo.version=${result.serverInfoVersion ?? "missing"}`);
529
+ }
530
+ console.log("Ask The W MCP doctor passed.");
531
+ console.log(`Package version: ${expectedVersion}`);
532
+ console.log(`serverInfo.version: ${result.serverInfoVersion}`);
533
+ }
534
+ async function runUpgradeCommand(argv) {
535
+ if (argv.includes("--browser")) {
536
+ console.log("Open https://askthew.com/plugin to manage workspace upgrades.");
537
+ return;
538
+ }
539
+ let hostType = process.env.ASKTHEW_HOST_TYPE?.trim();
540
+ if (hostType !== "claude_code" && hostType !== "codex" && hostType !== "cursor") {
541
+ hostType = undefined;
542
+ }
543
+ let serverName = process.env.ASKTHEW_SERVER_NAME?.trim() || undefined;
544
+ let serverNameExplicit = Boolean(serverName);
545
+ let version = process.env.ASKTHEW_PIN?.trim() || packageVersion();
546
+ let dryRun = false;
547
+ for (let index = 0; index < argv.length; index += 1) {
548
+ const argument = argv[index];
549
+ if (argument === "--dry-run") {
550
+ dryRun = true;
551
+ continue;
552
+ }
553
+ const next = argv[index + 1];
554
+ if (!next)
555
+ throw new Error(`Missing value for ${argument}.`);
556
+ if (argument === "--host") {
557
+ if (next !== "claude_code" && next !== "codex" && next !== "cursor") {
558
+ throw new Error(`Unsupported host "${next}". Expected claude_code, codex, or cursor.`);
559
+ }
560
+ hostType = next;
561
+ index += 1;
562
+ continue;
563
+ }
564
+ if (argument === "--server-name") {
565
+ serverName = next;
566
+ serverNameExplicit = true;
567
+ index += 1;
568
+ continue;
569
+ }
570
+ if (argument === "--version" || argument === "--pin") {
571
+ version = next;
572
+ index += 1;
573
+ continue;
574
+ }
575
+ throw new Error(`Unknown argument: ${argument}`);
576
+ }
577
+ if (!hostType) {
578
+ throw new Error("Usage: askthew-mcp upgrade --host <claude_code|codex|cursor> [--server-name <name>] [--version <version>] [--dry-run]");
579
+ }
580
+ const packageSpec = version.startsWith("@askthew/mcp-plugin@")
581
+ ? version
582
+ : `@askthew/mcp-plugin@${version}`;
583
+ if (!dryRun) {
584
+ const handshake = await runInitializeHandshake();
585
+ if (handshake.serverInfoVersion !== packageVersion()) {
586
+ throw new Error(`Refusing to upgrade pinned host config: MCP initialize returned ${handshake.serverInfoVersion ?? "missing"} but package.json is ${packageVersion()}.`);
587
+ }
588
+ }
589
+ const receipts = findInstallReceipts({
590
+ hostType,
591
+ serverName: serverNameExplicit ? serverName : undefined,
592
+ });
593
+ const result = upgradePinnedHostConfig({
594
+ hostType,
595
+ serverName: serverNameExplicit ? serverName : undefined,
596
+ packageSpec,
597
+ dryRun,
598
+ cwds: Array.from(new Set([process.cwd(), ...receipts.map((receipt) => receipt.cwd)])),
599
+ });
600
+ console.log(dryRun ? "Ask The W plugin upgrade dry run complete." : "Ask The W plugin upgrade complete.");
601
+ console.log(`Settings path: ${result.settingsPath}`);
602
+ console.log(`Pinned package: ${result.packageSpec}`);
603
+ console.log(result.upgradedServer
604
+ ? `${dryRun ? "Would update" : "Updated"} MCP server pin${result.upgradedServerNames.length ? `: ${result.upgradedServerNames.join(", ")}` : "."}`
605
+ : result.foundConfigFile
606
+ ? "No Ask The W MCP server pins needed an update."
607
+ : "No host config file found.");
608
+ if (dryRun && result.json) {
609
+ console.log("");
610
+ console.log(result.json);
611
+ }
612
+ }
500
613
  function argValue(argv, name) {
501
614
  const index = argv.indexOf(name);
502
615
  return index >= 0 ? argv[index + 1] : undefined;
package/dist/index.d.ts CHANGED
@@ -160,6 +160,9 @@ export declare function normalizeInstallTokenInput(token: string | undefined): s
160
160
  export declare function createAskTheWMcpServer(options?: AskTheWMcpServerOptions): McpServer;
161
161
  export declare function runInitializeHandshake(input?: {
162
162
  entrypoint?: string;
163
+ env?: NodeJS.ProcessEnv;
163
164
  timeoutMs?: number;
164
- }): Promise<void>;
165
+ }): Promise<{
166
+ serverInfoVersion?: string;
167
+ }>;
165
168
  export {};