@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 +9 -11
- package/dist/cli.js +136 -23
- package/dist/index.d.ts +4 -1
- package/dist/index.js +95 -668
- package/dist/install.d.ts +23 -0
- package/dist/install.js +300 -40
- package/dist/lib/local-store.js +15 -4
- package/dist/lib/upgrade-nudge.js +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
186
|
+
The plugin exposes a small public tool surface:
|
|
187
187
|
|
|
188
188
|
| Tool | Purpose |
|
|
189
189
|
|---|---|
|
|
190
|
-
| `
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
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
|
-
|
|
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
|
|
24
|
-
" askthew-mcp
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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() ||
|
|
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({
|
|
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<
|
|
165
|
+
}): Promise<{
|
|
166
|
+
serverInfoVersion?: string;
|
|
167
|
+
}>;
|
|
165
168
|
export {};
|