@askthew/mcp-plugin 0.2.8 → 0.4.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.
Files changed (60) hide show
  1. package/README.md +65 -16
  2. package/dist/auth-pending.test.d.ts +1 -0
  3. package/dist/auth-pending.test.js +56 -0
  4. package/dist/cli-actions.test.d.ts +1 -0
  5. package/dist/cli-actions.test.js +71 -0
  6. package/dist/cli.d.ts +9 -0
  7. package/dist/cli.js +412 -18
  8. package/dist/cli.test.d.ts +1 -0
  9. package/dist/cli.test.js +274 -0
  10. package/dist/free-tier-policy.test.d.ts +1 -0
  11. package/dist/free-tier-policy.test.js +57 -0
  12. package/dist/index.d.ts +59 -13
  13. package/dist/index.js +1736 -103
  14. package/dist/index.test.d.ts +1 -0
  15. package/dist/index.test.js +952 -0
  16. package/dist/install.d.ts +56 -1
  17. package/dist/install.js +171 -26
  18. package/dist/install.test.d.ts +1 -0
  19. package/dist/install.test.js +297 -0
  20. package/dist/lib/auth-magic-link.d.ts +22 -0
  21. package/dist/lib/auth-magic-link.js +43 -0
  22. package/dist/lib/auth-pending.d.ts +23 -0
  23. package/dist/lib/auth-pending.js +36 -0
  24. package/dist/lib/cli-actions.d.ts +28 -0
  25. package/dist/lib/cli-actions.js +104 -0
  26. package/dist/lib/free-install-registration.d.ts +27 -0
  27. package/dist/lib/free-install-registration.js +52 -0
  28. package/dist/lib/free-tier-policy.d.ts +23 -0
  29. package/dist/lib/free-tier-policy.js +68 -0
  30. package/dist/lib/local-identity.d.ts +44 -0
  31. package/dist/lib/local-identity.js +81 -0
  32. package/dist/lib/local-store.d.ts +130 -0
  33. package/dist/lib/local-store.js +595 -0
  34. package/dist/lib/loopback-auth.d.ts +8 -0
  35. package/dist/lib/loopback-auth.js +30 -0
  36. package/dist/lib/paths.d.ts +9 -0
  37. package/dist/lib/paths.js +50 -0
  38. package/dist/lib/telemetry.d.ts +25 -0
  39. package/dist/lib/telemetry.js +159 -0
  40. package/dist/lib/timeline-insights.d.ts +23 -0
  41. package/dist/lib/timeline-insights.js +115 -0
  42. package/dist/lib/tip-engine.d.ts +18 -0
  43. package/dist/lib/tip-engine.js +237 -0
  44. package/dist/lib/upgrade-nudge.d.ts +19 -0
  45. package/dist/lib/upgrade-nudge.js +37 -0
  46. package/dist/lib/upgrade-sync.d.ts +38 -0
  47. package/dist/lib/upgrade-sync.js +60 -0
  48. package/dist/local-identity.test.d.ts +1 -0
  49. package/dist/local-identity.test.js +29 -0
  50. package/dist/local-store.test.d.ts +1 -0
  51. package/dist/local-store.test.js +71 -0
  52. package/dist/scope.d.ts +1 -2
  53. package/dist/scope.js +56 -8
  54. package/dist/scope.test.d.ts +1 -0
  55. package/dist/scope.test.js +49 -0
  56. package/dist/timeline-insights.test.d.ts +1 -0
  57. package/dist/timeline-insights.test.js +85 -0
  58. package/dist/tip-engine.test.d.ts +1 -0
  59. package/dist/tip-engine.test.js +51 -0
  60. package/package.json +7 -10
@@ -0,0 +1,274 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { spawnSync } from "node:child_process";
4
+ import fs from "node:fs";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { runAuthCommand } from "./cli.js";
9
+ import { configPath, credentialsPath, identityPath, writePrivateJson } from "./lib/paths.js";
10
+ const cliPath = fileURLToPath(new URL("./cli.js", import.meta.url));
11
+ function makeFixture() {
12
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "askthew-cli-install-"));
13
+ const home = path.join(root, "home");
14
+ const dataDir = path.join(root, "data");
15
+ const project = path.join(root, "project");
16
+ fs.mkdirSync(home, { recursive: true });
17
+ fs.mkdirSync(dataDir, { recursive: true });
18
+ fs.mkdirSync(project, { recursive: true });
19
+ fs.writeFileSync(path.join(project, "package.json"), "{}", "utf8");
20
+ return { root, home, dataDir, project };
21
+ }
22
+ function runCli(input) {
23
+ return spawnSync(process.execPath, [cliPath, ...input.args], {
24
+ cwd: input.cwd,
25
+ encoding: "utf8",
26
+ env: {
27
+ ...process.env,
28
+ HOME: input.home,
29
+ USERPROFILE: input.home,
30
+ ASKTHEW_DATA_DIR: input.dataDir,
31
+ ASKTHEW_EMAIL: "founder@example.com",
32
+ ASKTHEW_CLI_TOKEN: "",
33
+ ASKTHEW_CLI_TOKEN_ID: "",
34
+ ASKTHEW_USER_ID: "",
35
+ ASKTHEW_INSTALL_TOKEN: "",
36
+ ASKTHEW_FREE_MODE: "",
37
+ ...(input.extraEnv ?? {}),
38
+ },
39
+ });
40
+ }
41
+ function writeCredentials(dataDir) {
42
+ fs.writeFileSync(path.join(dataDir, "credentials.json"), `${JSON.stringify({
43
+ email: "founder@example.com",
44
+ userId: "user_1",
45
+ cliToken: "cli_token",
46
+ cliTokenId: "cli_token_1",
47
+ }, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
48
+ }
49
+ async function withCliEnv(dataDir, fn) {
50
+ const previous = {
51
+ ASKTHEW_DATA_DIR: process.env.ASKTHEW_DATA_DIR,
52
+ ASKTHEW_EMAIL: process.env.ASKTHEW_EMAIL,
53
+ ASKTHEW_CLI_TOKEN: process.env.ASKTHEW_CLI_TOKEN,
54
+ ASKTHEW_CLI_TOKEN_ID: process.env.ASKTHEW_CLI_TOKEN_ID,
55
+ ASKTHEW_USER_ID: process.env.ASKTHEW_USER_ID,
56
+ ASKTHEW_INSTALL_TOKEN: process.env.ASKTHEW_INSTALL_TOKEN,
57
+ ASKTHEW_FREE_MODE: process.env.ASKTHEW_FREE_MODE,
58
+ };
59
+ process.env.ASKTHEW_DATA_DIR = dataDir;
60
+ process.env.ASKTHEW_EMAIL = "founder@example.com";
61
+ delete process.env.ASKTHEW_CLI_TOKEN;
62
+ delete process.env.ASKTHEW_CLI_TOKEN_ID;
63
+ delete process.env.ASKTHEW_USER_ID;
64
+ delete process.env.ASKTHEW_INSTALL_TOKEN;
65
+ delete process.env.ASKTHEW_FREE_MODE;
66
+ try {
67
+ return await fn();
68
+ }
69
+ finally {
70
+ for (const [key, value] of Object.entries(previous)) {
71
+ if (value === undefined) {
72
+ delete process.env[key];
73
+ }
74
+ else {
75
+ process.env[key] = value;
76
+ }
77
+ }
78
+ }
79
+ }
80
+ test("free install without prior auth writes config, instructions, and local identity", () => {
81
+ const fixture = makeFixture();
82
+ try {
83
+ const result = runCli({
84
+ args: ["install", "--host", "claude_code", "--free", "--email", "founder@example.com", "--api-url", "http://127.0.0.1:9"],
85
+ cwd: fixture.project,
86
+ home: fixture.home,
87
+ dataDir: fixture.dataDir,
88
+ });
89
+ assert.equal(result.status, 0, result.stderr);
90
+ assert.match(result.stdout, /Free local mode installed/);
91
+ assert.match(result.stdout, /Free install identity saved locally|Free install identity registered/);
92
+ assert.equal(fs.existsSync(path.join(fixture.home, ".claude.json")), true);
93
+ assert.match(fs.readFileSync(path.join(fixture.project, "CLAUDE.md"), "utf8"), /capture_session_signal/);
94
+ const identity = JSON.parse(fs.readFileSync(path.join(fixture.dataDir, "identity.json"), "utf8"));
95
+ assert.match(identity.installId, /^[0-9a-f-]{36}$/);
96
+ assert.equal(identity.emailClaim, "founder@example.com");
97
+ assert.equal(typeof identity.privateKey, "string");
98
+ assert.equal(typeof identity.publicKey, "string");
99
+ }
100
+ finally {
101
+ fs.rmSync(fixture.root, { recursive: true, force: true });
102
+ }
103
+ });
104
+ test("free install dry-run stays non-mutating and does not create identity", () => {
105
+ const fixture = makeFixture();
106
+ try {
107
+ const result = runCli({
108
+ args: ["install", "--host", "codex", "--free", "--email", "founder@example.com", "--dry-run"],
109
+ cwd: fixture.project,
110
+ home: fixture.home,
111
+ dataDir: fixture.dataDir,
112
+ });
113
+ assert.equal(result.status, 0, result.stderr);
114
+ assert.equal(fs.existsSync(path.join(fixture.home, ".codex", "config.toml")), false);
115
+ assert.equal(fs.existsSync(path.join(fixture.project, "CLAUDE.md")), false);
116
+ assert.equal(fs.existsSync(path.join(fixture.project, "AGENTS.md")), false);
117
+ assert.equal(fs.existsSync(path.join(fixture.dataDir, "identity.json")), false);
118
+ }
119
+ finally {
120
+ fs.rmSync(fixture.root, { recursive: true, force: true });
121
+ }
122
+ });
123
+ test("free install with auth writes host config and agent instructions", () => {
124
+ const fixture = makeFixture();
125
+ try {
126
+ writeCredentials(fixture.dataDir);
127
+ const result = runCli({
128
+ args: ["install", "--host", "claude_code", "--free", "--api-url", "http://127.0.0.1:9"],
129
+ cwd: fixture.project,
130
+ home: fixture.home,
131
+ dataDir: fixture.dataDir,
132
+ });
133
+ assert.equal(result.status, 0, result.stderr);
134
+ assert.match(result.stdout, /Free local mode installed/);
135
+ const settings = JSON.parse(fs.readFileSync(path.join(fixture.home, ".claude.json"), "utf8"));
136
+ const projectEntries = Object.values(settings.projects);
137
+ assert.equal(projectEntries.length, 1);
138
+ const server = projectEntries[0].mcpServers.askthew;
139
+ assert.equal(server.env.ASKTHEW_FREE_MODE, "1");
140
+ assert.equal("ASKTHEW_CLI_TOKEN" in server.env, false);
141
+ assert.equal("ASKTHEW_INSTALL_TOKEN" in server.env, false);
142
+ assert.match(fs.readFileSync(path.join(fixture.project, "CLAUDE.md"), "utf8"), /capture_session_signal/);
143
+ }
144
+ finally {
145
+ fs.rmSync(fixture.root, { recursive: true, force: true });
146
+ }
147
+ });
148
+ test("auth status reports a pending verification code", () => {
149
+ const fixture = makeFixture();
150
+ try {
151
+ fs.writeFileSync(path.join(fixture.dataDir, "config.json"), `${JSON.stringify({
152
+ pendingAuth: {
153
+ email: "founder@example.com",
154
+ requestId: "request_1",
155
+ expiresAt: new Date(Date.now() + 60_000).toISOString(),
156
+ },
157
+ }, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
158
+ const result = runCli({
159
+ args: ["auth", "status"],
160
+ cwd: fixture.project,
161
+ home: fixture.home,
162
+ dataDir: fixture.dataDir,
163
+ });
164
+ assert.equal(result.status, 0, result.stderr);
165
+ assert.match(result.stdout, /Pending code for founder@example\.com/);
166
+ assert.match(result.stdout, /askthew-mcp auth verify --code/);
167
+ }
168
+ finally {
169
+ fs.rmSync(fixture.root, { recursive: true, force: true });
170
+ }
171
+ });
172
+ test("auth code commands require pending state and do not issue a new code", () => {
173
+ const fixture = makeFixture();
174
+ try {
175
+ for (const args of [
176
+ ["auth", "verify", "--code", "123456"],
177
+ ["auth", "login", "--email", "founder@example.com", "--code", "123456"],
178
+ ]) {
179
+ const result = runCli({
180
+ args,
181
+ cwd: fixture.project,
182
+ home: fixture.home,
183
+ dataDir: fixture.dataDir,
184
+ extraEnv: { ASKTHEW_API_URL: "http://127.0.0.1:9" },
185
+ });
186
+ assert.equal(result.status, 1);
187
+ assert.match(result.stderr, /No pending Ask The W login request/);
188
+ assert.doesNotMatch(result.stdout, /Code sent/);
189
+ }
190
+ }
191
+ finally {
192
+ fs.rmSync(fixture.root, { recursive: true, force: true });
193
+ }
194
+ });
195
+ test("auth login now identifies the local free install without requesting an email code", async () => {
196
+ const fixture = makeFixture();
197
+ const calls = [];
198
+ const logs = [];
199
+ try {
200
+ await withCliEnv(fixture.dataDir, async () => {
201
+ await runAuthCommand(["login", "--email", "ymtest89+test5@gmail.com"], {
202
+ log: (message) => logs.push(message),
203
+ requestMagicLinkCode: async () => {
204
+ calls.push({ type: "unexpected_request" });
205
+ throw new Error("auth login must not request a new code.");
206
+ },
207
+ verifyMagicLinkCode: async () => {
208
+ calls.push({ type: "unexpected_verify" });
209
+ throw new Error("auth login must not verify a code.");
210
+ },
211
+ registerFreeInstall: async ({ identity }) => {
212
+ calls.push({ type: "register", installId: identity.installId, emailClaim: identity.emailClaim });
213
+ return { ok: true, registeredAt: new Date().toISOString() };
214
+ },
215
+ });
216
+ });
217
+ assert.equal(calls.length, 1);
218
+ assert.equal(calls[0].type, "register");
219
+ assert.equal(calls[0].emailClaim, "ymtest89+test5@gmail.com");
220
+ assert.equal(fs.existsSync(identityPath({ ASKTHEW_DATA_DIR: fixture.dataDir })), true);
221
+ assert.equal(fs.existsSync(credentialsPath({ ASKTHEW_DATA_DIR: fixture.dataDir })), false);
222
+ assert.match(logs.join("\n"), /No email code is required/);
223
+ }
224
+ finally {
225
+ fs.rmSync(fixture.root, { recursive: true, force: true });
226
+ }
227
+ });
228
+ test("backwards-compatible auth login --code verifies pending state without requesting a new code", async () => {
229
+ const fixture = makeFixture();
230
+ const calls = [];
231
+ const logs = [];
232
+ try {
233
+ await withCliEnv(fixture.dataDir, async () => {
234
+ writePrivateJson(configPath(), {
235
+ pendingAuth: {
236
+ email: "ymtest89+test5@gmail.com",
237
+ requestId: "22222222-2222-4222-8222-222222222222",
238
+ expiresAt: new Date(Date.now() + 10 * 60_000).toISOString(),
239
+ },
240
+ });
241
+ await runAuthCommand(["login", "--email", "ymtest89+test5@gmail.com", "--code", "150259"], {
242
+ log: (message) => logs.push(message),
243
+ requestMagicLinkCode: async () => {
244
+ calls.push({ type: "unexpected_request" });
245
+ throw new Error("login --code must not request a new code.");
246
+ },
247
+ verifyMagicLinkCode: async (input) => {
248
+ calls.push({ type: "verify", requestId: input.requestId, code: input.code });
249
+ const credentials = {
250
+ email: "ymtest89+test5@gmail.com",
251
+ userId: "user_2",
252
+ cliToken: "cli_token_2",
253
+ cliTokenId: "cli_token_2",
254
+ accountStatus: "new_dormant",
255
+ };
256
+ writePrivateJson(credentialsPath(), credentials);
257
+ return credentials;
258
+ },
259
+ });
260
+ });
261
+ assert.deepEqual(calls, [
262
+ {
263
+ type: "verify",
264
+ requestId: "22222222-2222-4222-8222-222222222222",
265
+ code: "150259",
266
+ },
267
+ ]);
268
+ assert.match(logs.join("\n"), /Using the pending Ask The W login request/);
269
+ assert.match(logs.join("\n"), /Logged in/);
270
+ }
271
+ finally {
272
+ fs.rmSync(fixture.root, { recursive: true, force: true });
273
+ }
274
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,57 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { resolveMcpMode } from "./lib/free-tier-policy.js";
7
+ function withTempDataDir(fn) {
8
+ const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "askthew-mode-"));
9
+ try {
10
+ return fn({ ASKTHEW_DATA_DIR: dataDir }, dataDir);
11
+ }
12
+ finally {
13
+ fs.rmSync(dataDir, { recursive: true, force: true });
14
+ }
15
+ }
16
+ test("mode resolution prefers paid install tokens", () => {
17
+ const mode = resolveMcpMode({
18
+ ASKTHEW_INSTALL_TOKEN: "atw_token",
19
+ ASKTHEW_FREE_MODE: "1",
20
+ });
21
+ assert.equal(mode.mode, "paid");
22
+ assert.equal(mode.reason, "workspace_install_token");
23
+ });
24
+ test("mode resolution detects authenticated free credentials", () => {
25
+ const mode = resolveMcpMode({
26
+ ASKTHEW_CLI_TOKEN: "cli_token",
27
+ ASKTHEW_USER_ID: "user_1",
28
+ ASKTHEW_CLI_TOKEN_ID: "cli_token_1",
29
+ });
30
+ assert.equal(mode.mode, "free");
31
+ assert.equal(mode.reason, "cli_free_tier_credentials");
32
+ assert.equal(mode.cliCredentials?.userId, "user_1");
33
+ });
34
+ test("mode resolution distinguishes pending free auth from no identity", () => {
35
+ withTempDataDir((env) => {
36
+ const pending = resolveMcpMode({
37
+ ...env,
38
+ ASKTHEW_FREE_MODE: "1",
39
+ });
40
+ const none = resolveMcpMode(env);
41
+ assert.equal(pending.mode, "free_pending_auth");
42
+ assert.equal(pending.reason, "free_mode_no_credentials");
43
+ assert.equal(none.mode, "unauthenticated");
44
+ assert.equal(none.reason, "no_identity");
45
+ });
46
+ });
47
+ test("mode resolution marks malformed free credentials as pending auth", () => {
48
+ withTempDataDir((env, dataDir) => {
49
+ fs.writeFileSync(path.join(dataDir, "credentials.json"), "{\"not\":\"credentials\"}\n", "utf8");
50
+ const mode = resolveMcpMode({
51
+ ...env,
52
+ ASKTHEW_FREE_MODE: "1",
53
+ });
54
+ assert.equal(mode.mode, "free_pending_auth");
55
+ assert.equal(mode.reason, "invalid_cli_credentials");
56
+ });
57
+ });
package/dist/index.d.ts CHANGED
@@ -8,36 +8,56 @@ export declare const codingSessionSignalSchema: z.ZodObject<{
8
8
  evidence: z.ZodDefault<z.ZodArray<z.ZodObject<{
9
9
  role: z.ZodEnum<["user", "assistant", "system"]>;
10
10
  excerpt: z.ZodString;
11
+ kind: z.ZodOptional<z.ZodEnum<["excerpt", "diff", "prompt_diff"]>>;
12
+ diff: z.ZodOptional<z.ZodString>;
13
+ before: z.ZodOptional<z.ZodString>;
14
+ after: z.ZodOptional<z.ZodString>;
11
15
  }, "strip", z.ZodTypeAny, {
12
16
  role: "user" | "assistant" | "system";
13
17
  excerpt: string;
18
+ diff?: string | undefined;
19
+ kind?: "diff" | "excerpt" | "prompt_diff" | undefined;
20
+ before?: string | undefined;
21
+ after?: string | undefined;
14
22
  }, {
15
23
  role: "user" | "assistant" | "system";
16
24
  excerpt: string;
25
+ diff?: string | undefined;
26
+ kind?: "diff" | "excerpt" | "prompt_diff" | undefined;
27
+ before?: string | undefined;
28
+ after?: string | undefined;
17
29
  }>, "many">>;
18
30
  filesTouched: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
19
31
  commandsRun: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
20
32
  metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
21
33
  }, "strip", z.ZodTypeAny, {
22
34
  sessionId: string;
23
- sequence: number;
24
35
  kind: "setup_complete" | "session_checkpoint" | "direction_change" | "implementation_update" | "verification_result" | "final_summary";
36
+ sequence: number;
25
37
  summary: string;
26
38
  evidence: {
27
39
  role: "user" | "assistant" | "system";
28
40
  excerpt: string;
41
+ diff?: string | undefined;
42
+ kind?: "diff" | "excerpt" | "prompt_diff" | undefined;
43
+ before?: string | undefined;
44
+ after?: string | undefined;
29
45
  }[];
30
46
  filesTouched: string[];
31
47
  commandsRun: string[];
32
48
  metadata: Record<string, unknown>;
33
49
  }, {
34
50
  sessionId: string;
35
- sequence: number;
36
51
  kind: "setup_complete" | "session_checkpoint" | "direction_change" | "implementation_update" | "verification_result" | "final_summary";
52
+ sequence: number;
37
53
  summary: string;
38
54
  evidence?: {
39
55
  role: "user" | "assistant" | "system";
40
56
  excerpt: string;
57
+ diff?: string | undefined;
58
+ kind?: "diff" | "excerpt" | "prompt_diff" | undefined;
59
+ before?: string | undefined;
60
+ after?: string | undefined;
41
61
  }[] | undefined;
42
62
  filesTouched?: string[] | undefined;
43
63
  commandsRun?: string[] | undefined;
@@ -82,13 +102,18 @@ export declare const provenanceSignalSchema: z.ZodObject<{
82
102
  installToken?: string | undefined;
83
103
  }>;
84
104
  export type ProvenanceSignal = z.infer<typeof provenanceSignalSchema>;
85
- export declare function inferFunctionalArea(signal: Pick<ProvenanceSignal, "filesAffected">): string;
86
- export declare function redactProvenanceSignal(input: ProvenanceSignal): {
87
- originatingPrompt: string | undefined;
88
- metadata: {
89
- functional_area: string;
105
+ type AskTheWConfig = {
106
+ redaction?: {
107
+ enabled?: boolean;
108
+ };
109
+ digest?: {
110
+ footer?: boolean;
90
111
  };
112
+ };
113
+ export declare function loadAskTheWConfig(env?: NodeJS.ProcessEnv): AskTheWConfig;
114
+ export declare function redactProvenanceSignal(input: ProvenanceSignal): {
91
115
  sessionId: string;
116
+ metadata: Record<string, unknown>;
92
117
  source: string;
93
118
  decision: string;
94
119
  rationale: string;
@@ -96,20 +121,41 @@ export declare function redactProvenanceSignal(input: ProvenanceSignal): {
96
121
  filesAffected: string[];
97
122
  framework?: string | undefined;
98
123
  pendingApproval?: boolean | undefined;
124
+ originatingPrompt?: string | undefined;
99
125
  installToken?: string | undefined;
100
126
  };
101
127
  export declare function redactCodingSessionSignal(input: CodingSessionSignal): {
128
+ sessionId: string;
129
+ kind: "setup_complete" | "session_checkpoint" | "direction_change" | "implementation_update" | "verification_result" | "final_summary";
130
+ sequence: number;
102
131
  summary: string;
103
132
  evidence: {
104
- excerpt: string;
105
133
  role: "user" | "assistant" | "system";
134
+ excerpt: string;
135
+ diff?: string | undefined;
136
+ kind?: "diff" | "excerpt" | "prompt_diff" | undefined;
137
+ before?: string | undefined;
138
+ after?: string | undefined;
106
139
  }[];
140
+ filesTouched: string[];
107
141
  commandsRun: string[];
108
142
  metadata: Record<string, unknown>;
109
- sessionId: string;
110
- sequence: number;
111
- kind: "setup_complete" | "session_checkpoint" | "direction_change" | "implementation_update" | "verification_result" | "final_summary";
112
- filesTouched: string[];
113
143
  };
144
+ export interface AskTheWMcpServerOptions {
145
+ credentials?: {
146
+ installToken?: string;
147
+ userId?: string;
148
+ apiKey?: string;
149
+ serverName?: string;
150
+ clientId?: string;
151
+ clientLabel?: string;
152
+ hostType?: "claude_code" | "codex" | "cursor";
153
+ };
154
+ apiBaseUrl?: string;
155
+ fetchImpl?: typeof fetch;
156
+ runtimeMetadata?: Record<string, unknown> | (() => Record<string, unknown>);
157
+ sendStartupHeartbeat?: boolean;
158
+ }
114
159
  export declare function normalizeInstallTokenInput(token: string | undefined): string;
115
- export declare function createAskTheWMcpServer(): McpServer;
160
+ export declare function createAskTheWMcpServer(options?: AskTheWMcpServerOptions): McpServer;
161
+ export {};