pi-soly 1.9.3 → 1.11.0

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 (104) hide show
  1. package/ask/index.ts +12 -11
  2. package/ask/picker.ts +356 -76
  3. package/ask/prompt.ts +6 -2
  4. package/ask/tests/picker.test.ts +273 -82
  5. package/codemap.ts +276 -0
  6. package/hotreload.ts +239 -0
  7. package/init.ts +302 -0
  8. package/mcp/CHANGELOG.md +384 -0
  9. package/mcp/LICENSE +21 -0
  10. package/mcp/OAUTH.md +355 -0
  11. package/mcp/README.md +410 -0
  12. package/mcp/__tests__/agent-dir-paths.upstream-test.ts +80 -0
  13. package/mcp/__tests__/cli.upstream-test.ts +97 -0
  14. package/mcp/__tests__/commands-onboarding.upstream-test.ts +157 -0
  15. package/mcp/__tests__/config.upstream-test.ts +303 -0
  16. package/mcp/__tests__/consent-manager.upstream-test.ts +151 -0
  17. package/mcp/__tests__/direct-tools-auto-auth.upstream-test.ts +218 -0
  18. package/mcp/__tests__/direct-tools.upstream-test.ts +299 -0
  19. package/mcp/__tests__/elicitation-handler.upstream-test.ts +346 -0
  20. package/mcp/__tests__/elicitation-sdk-integration.upstream-test.ts +140 -0
  21. package/mcp/__tests__/errors.upstream-test.ts +218 -0
  22. package/mcp/__tests__/fixtures/elicitation-server.mjs +98 -0
  23. package/mcp/__tests__/host-html-template.upstream-test.ts +278 -0
  24. package/mcp/__tests__/index-lifecycle.upstream-test.ts +484 -0
  25. package/mcp/__tests__/init-elicitation.upstream-test.ts +86 -0
  26. package/mcp/__tests__/interactive-visualizer-server.upstream-test.ts +28 -0
  27. package/mcp/__tests__/logger.upstream-test.ts +175 -0
  28. package/mcp/__tests__/mcp-auth-flow-client-credentials.upstream-test.ts +612 -0
  29. package/mcp/__tests__/mcp-auth-storage.upstream-test.ts +47 -0
  30. package/mcp/__tests__/mcp-callback-server-unref.upstream-test.ts +264 -0
  31. package/mcp/__tests__/mcp-oauth-provider.upstream-test.ts +216 -0
  32. package/mcp/__tests__/mcp-panel-auth.upstream-test.ts +206 -0
  33. package/mcp/__tests__/mcp-panel-exclude-tools.upstream-test.ts +69 -0
  34. package/mcp/__tests__/mcp-panel-keybindings.upstream-test.ts +186 -0
  35. package/mcp/__tests__/npx-resolver.upstream-test.ts +54 -0
  36. package/mcp/__tests__/oauth-handler.upstream-test.ts +77 -0
  37. package/mcp/__tests__/onboarding-state.upstream-test.ts +52 -0
  38. package/mcp/__tests__/package-manifest.upstream-test.ts +22 -0
  39. package/mcp/__tests__/proxy-modes-auto-auth.upstream-test.ts +253 -0
  40. package/mcp/__tests__/proxy-modes-discovery.upstream-test.ts +84 -0
  41. package/mcp/__tests__/proxy-modes-manual-auth.upstream-test.ts +91 -0
  42. package/mcp/__tests__/proxy-modes-ui-messages.upstream-test.ts +72 -0
  43. package/mcp/__tests__/sampling-handler.upstream-test.ts +285 -0
  44. package/mcp/__tests__/server-manager-http-auth.upstream-test.ts +144 -0
  45. package/mcp/__tests__/server-manager-sampling.upstream-test.ts +236 -0
  46. package/mcp/__tests__/tool-metadata.upstream-test.ts +111 -0
  47. package/mcp/__tests__/tool-result-renderer.upstream-test.ts +147 -0
  48. package/mcp/__tests__/ui-integration.upstream-test.ts +551 -0
  49. package/mcp/__tests__/ui-resource-handler.upstream-test.ts +303 -0
  50. package/mcp/__tests__/ui-server.upstream-test.ts +967 -0
  51. package/mcp/__tests__/ui-session-messages.upstream-test.ts +72 -0
  52. package/mcp/__tests__/ui-streaming.upstream-test.ts +543 -0
  53. package/mcp/agent-dir.ts +20 -0
  54. package/mcp/app-bridge.bundle.js +67 -0
  55. package/mcp/cli.js +184 -0
  56. package/mcp/commands.ts +422 -0
  57. package/mcp/config.ts +666 -0
  58. package/mcp/consent-manager.ts +64 -0
  59. package/mcp/direct-tools.ts +439 -0
  60. package/mcp/elicitation-handler.ts +347 -0
  61. package/mcp/errors.ts +219 -0
  62. package/mcp/glimpse-ui.ts +80 -0
  63. package/mcp/host-html-template.ts +427 -0
  64. package/mcp/index.ts +362 -0
  65. package/mcp/init.ts +362 -0
  66. package/mcp/lifecycle.ts +93 -0
  67. package/mcp/logger.ts +169 -0
  68. package/mcp/mcp-auth-flow.ts +559 -0
  69. package/mcp/mcp-auth-flow.upstream-test.ts +259 -0
  70. package/mcp/mcp-auth.ts +302 -0
  71. package/mcp/mcp-auth.upstream-test.ts +373 -0
  72. package/mcp/mcp-callback-server.ts +372 -0
  73. package/mcp/mcp-callback-server.upstream-test.ts +416 -0
  74. package/mcp/mcp-oauth-provider.ts +369 -0
  75. package/mcp/mcp-oauth-provider.upstream-test.ts +518 -0
  76. package/mcp/mcp-panel.ts +829 -0
  77. package/mcp/mcp-setup-panel.ts +580 -0
  78. package/mcp/metadata-cache.ts +201 -0
  79. package/mcp/notify.ts +111 -0
  80. package/mcp/npx-resolver.ts +424 -0
  81. package/mcp/oauth-handler.ts +57 -0
  82. package/mcp/onboarding-state.ts +68 -0
  83. package/mcp/package.json +106 -0
  84. package/mcp/panel-keys.ts +37 -0
  85. package/mcp/proxy-modes.ts +949 -0
  86. package/mcp/resource-tools.ts +17 -0
  87. package/mcp/sampling-handler.ts +268 -0
  88. package/mcp/server-manager.ts +545 -0
  89. package/mcp/state.ts +41 -0
  90. package/mcp/tool-metadata.ts +216 -0
  91. package/mcp/tool-registrar.ts +46 -0
  92. package/mcp/tool-result-renderer.ts +161 -0
  93. package/mcp/types.ts +448 -0
  94. package/mcp/ui-resource-handler.ts +146 -0
  95. package/mcp/ui-server.ts +623 -0
  96. package/mcp/ui-session.ts +386 -0
  97. package/mcp/ui-stream-types.ts +89 -0
  98. package/mcp/utils.ts +129 -0
  99. package/mcp/vitest.config.ts +14 -0
  100. package/migrate.ts +258 -0
  101. package/notification.ts +218 -0
  102. package/notifications-log.ts +83 -0
  103. package/package.json +20 -3
  104. package/status.ts +140 -0
package/init.ts ADDED
@@ -0,0 +1,302 @@
1
+ // =============================================================================
2
+ // init.ts — Scaffold a new soly project
3
+ // =============================================================================
4
+ //
5
+ // Creates the initial `.agents/` directory structure for a new project, with
6
+ // optional project-type templates. Idempotent — existing files are kept.
7
+ //
8
+ // Layout created:
9
+ // .agents/
10
+ // ├── ROADMAP.md (single phase "01-bootstrap" + checklist)
11
+ // ├── STATE.md (empty template with frontmatter)
12
+ // ├── docs/
13
+ // │ └── vision.md (placeholder for intent doc)
14
+ // ├── rules/
15
+ // │ └── code-style.md (TypeScript-friendly defaults)
16
+ // ├── phases/
17
+ // │ └── .gitkeep
18
+ // ├── iterations/
19
+ // │ └── .gitkeep
20
+ // └── HANDOFF.json ({ "version": 1, "snapshot": null })
21
+ // agents.md (AGENTS.md standard, top-level)
22
+ //
23
+ // Templates:
24
+ // "minimal" — just the structure, no rules/docs
25
+ // "web-app" — adds routing/, auth/, api/ example rules
26
+ // "library" — adds publishing/, testing/, breaking-changes/ example rules
27
+ // "cli" — adds command/, flags/, shell-compat/ example rules
28
+ //
29
+ // Usage:
30
+ // /soly-init # interactive: pick template
31
+ // /soly-init minimal # no prompts
32
+ // /soly-init web-app --yes
33
+ // =============================================================================
34
+
35
+ import * as fs from "node:fs";
36
+ import * as path from "node:path";
37
+ import { SOLY_DIRNAME } from "./core.js";
38
+
39
+ export type InitTemplate = "minimal" | "web-app" | "library" | "cli";
40
+
41
+ /** UI primitives. */
42
+ export interface InitUI {
43
+ notify: (text: string, level?: "info" | "warning" | "error") => void;
44
+ select: (label: string, options: string[]) => Promise<string | undefined>;
45
+ confirm: (title: string, message: string) => Promise<boolean>;
46
+ input: (label: string, placeholder?: string) => Promise<string | undefined>;
47
+ }
48
+
49
+ export interface InitOptions {
50
+ /** Skip template picker + confirm dialog. */
51
+ autoYes?: boolean;
52
+ /** Force template (otherwise: picker or default 'minimal'). */
53
+ template?: InitTemplate;
54
+ /** Project name (for STATE.md). Defaults to cwd basename. */
55
+ projectName?: string;
56
+ }
57
+
58
+ const ROADMAP_MINIMAL = `# Roadmap
59
+
60
+ | # | Phase | Status | Notes |
61
+ |---|-------|--------|-------|
62
+ | 01 | bootstrap | pending | Initial setup |
63
+
64
+ Open \`/plan 1\` to start the first phase.
65
+ `;
66
+
67
+ const STATE_MINIMAL = `---
68
+ milestone: 0.1.0
69
+ current_position: ready
70
+ last_updated: ${new Date().toISOString().slice(0, 10)}
71
+ ---
72
+
73
+ # Project state
74
+
75
+ Use \`/soly\` to see current state. Use \`/plan N\` to plan phase N.
76
+
77
+ ## Decisions
78
+
79
+ | Date | Decision | Why |
80
+ |------|----------|-----|
81
+ | ${new Date().toISOString().slice(0, 10)} | Initial scaffold | Created by \`soly init\` |
82
+ `;
83
+
84
+ const VISION_DOC = `# Vision
85
+
86
+ What does this project do? Who is it for? Why does it exist?
87
+
88
+ Replace this paragraph with 1-2 sentences describing the project's purpose.
89
+
90
+ ## Goals
91
+
92
+ - Goal 1
93
+ - Goal 2
94
+
95
+ ## Non-goals
96
+
97
+ - Non-goal 1
98
+ - Non-goal 2
99
+ `;
100
+
101
+ const CODE_STYLE_RULE = `# Code style
102
+
103
+ - Prefer \`type\` over \`interface\` for object shapes
104
+ - Use \`strict\` mode
105
+ - Never use \`any\` — use \`unknown\` and narrow
106
+ - Functions under 50 lines; extract helpers beyond
107
+ `;
108
+
109
+ const HANDOFF_INITIAL = JSON.stringify({ version: 1, snapshot: null }, null, 2) + "\n";
110
+
111
+ /** Template-specific extra rules. Each is a (filename, content) pair. */
112
+ const TEMPLATE_EXTRAS: Record<InitTemplate, Array<{ file: string; content: string }>> = {
113
+ minimal: [],
114
+ "web-app": [
115
+ {
116
+ file: "rules/routing.md",
117
+ content: `# Routing
118
+
119
+ - Each route is a file under \`src/routes/<path>.ts\`
120
+ - Loader and action in same file
121
+ - Typed params via \`Route.LoaderArgs\`
122
+ `,
123
+ },
124
+ {
125
+ file: "rules/auth.md",
126
+ content: `# Auth
127
+
128
+ - Sessions in HTTP-only cookies
129
+ - CSRF tokens on all mutations
130
+ - Never trust client-supplied user IDs
131
+ `,
132
+ },
133
+ ],
134
+ library: [
135
+ {
136
+ file: "rules/publishing.md",
137
+ content: `# Publishing
138
+
139
+ - Semver strictly: breaking changes bump major
140
+ - CHANGELOG.md updated with every release
141
+ - Public API = what's in the README + index.ts
142
+ `,
143
+ },
144
+ {
145
+ file: "rules/testing.md",
146
+ content: `# Testing
147
+
148
+ - One assertion per test (ideally)
149
+ - Tests live next to source as \`*.test.ts\`
150
+ - Run \`bun test\` before every commit
151
+ `,
152
+ },
153
+ ],
154
+ cli: [
155
+ {
156
+ file: "rules/commands.md",
157
+ content: `# Commands
158
+
159
+ - Each command is a file under \`src/commands/<name>.ts\`
160
+ - Export \`name\`, \`description\`, \`run(args: string[]): Promise<void>\`
161
+ - All errors exit non-zero with a message on stderr
162
+ `,
163
+ },
164
+ {
165
+ file: "rules/flags.md",
166
+ content: `# Flags
167
+
168
+ - \`--flag value\` style, not GNU \`-f value\`
169
+ - Short aliases only for the 3-4 most common flags
170
+ - \`--help\` always supported, auto-generated from command metadata
171
+ `,
172
+ },
173
+ ],
174
+ };
175
+
176
+ const AGENTS_MD_TOP = `# Agent conventions
177
+
178
+ This project uses [soly](https://github.com/lowern1ght/pi-soly) for project management.
179
+
180
+ ## Quick reference
181
+
182
+ - \`/plan N\` — plan phase N
183
+ - \`/execute N.MM\` — execute plan MM in phase N
184
+ - \`/inspect\` — see current state
185
+ - \`/pause\` — save handoff for later
186
+ - \`/resume\` — restore from handoff
187
+
188
+ ## State
189
+
190
+ - \`.agents/ROADMAP.md\` — phase table
191
+ - \`.agents/STATE.md\` — current position + decisions
192
+ - \`.agents/docs/\` — intent docs (vision, architecture, ...)
193
+ - \`.agents/rules/\` — project rules (style, testing, ...)
194
+ - \`.agents/phases/<NN>-<slug>/\` — one dir per phase
195
+ - \`.agents/HANDOFF.json\` — pause snapshot
196
+ `;
197
+
198
+ /** Run the init flow. Returns true if project was created. */
199
+ export async function initSolyProject(
200
+ cwd: string,
201
+ ui: InitUI,
202
+ options: InitOptions = {},
203
+ ): Promise<{ created: boolean; template: InitTemplate | null; projectName: string }> {
204
+ const projectName = options.projectName ?? path.basename(cwd);
205
+ const safeProjectName = projectName || "project";
206
+ const agentsDir = path.join(cwd, SOLY_DIRNAME);
207
+
208
+ // Preconditions
209
+ if (fs.existsSync(agentsDir) || fs.existsSync(path.join(cwd, ".soly"))) {
210
+ ui.notify(
211
+ `soly-init: project already initialized (found ${SOLY_DIRNAME}/ or .soly/). ` +
212
+ `Aborting to avoid overwriting.`,
213
+ "error",
214
+ );
215
+ return { created: false, template: null, projectName };
216
+ }
217
+
218
+ // Pick template
219
+ let template: InitTemplate | null = options.template ?? null;
220
+ if (!template && !options.autoYes) {
221
+ const pick = await ui.select(
222
+ "template:",
223
+ ["minimal", "web-app", "library", "cli"],
224
+ );
225
+ if (!pick) {
226
+ ui.notify("soly-init: cancelled", "info");
227
+ return { created: false, template: null, projectName };
228
+ }
229
+ template = pick as InitTemplate;
230
+ }
231
+ if (!template) template = "minimal";
232
+
233
+ // Confirm (unless --yes)
234
+ if (!options.autoYes) {
235
+ const ok = await ui.confirm(
236
+ `soly init (${template})`,
237
+ `Create .agents/ structure in:\n ${cwd}\n\nProject name: ${projectName}`,
238
+ );
239
+ if (!ok) {
240
+ ui.notify("soly-init: cancelled", "info");
241
+ return { created: false, template: null, projectName };
242
+ }
243
+ }
244
+
245
+ // Build
246
+ fs.mkdirSync(path.join(agentsDir, "docs"), { recursive: true });
247
+ fs.mkdirSync(path.join(agentsDir, "rules"), { recursive: true });
248
+ fs.mkdirSync(path.join(agentsDir, "phases"), { recursive: true });
249
+ fs.mkdirSync(path.join(agentsDir, "iterations"), { recursive: true });
250
+
251
+ writeIfMissing(path.join(agentsDir, "ROADMAP.md"), ROADMAP_MINIMAL);
252
+ writeIfMissing(path.join(agentsDir, "STATE.md"), STATE_MINIMAL);
253
+ writeIfMissing(path.join(agentsDir, "docs", "vision.md"), VISION_DOC);
254
+ writeIfMissing(path.join(agentsDir, "rules", "code-style.md"), CODE_STYLE_RULE);
255
+ writeIfMissing(path.join(agentsDir, "HANDOFF.json"), HANDOFF_INITIAL);
256
+ fs.writeFileSync(path.join(agentsDir, "phases", ".gitkeep"), "");
257
+ fs.writeFileSync(path.join(agentsDir, "iterations", ".gitkeep"), "");
258
+
259
+ // Top-level AGENTS.md
260
+ writeIfMissing(path.join(cwd, "AGENTS.md"), AGENTS_MD_TOP);
261
+
262
+ // Template extras
263
+ for (const extra of TEMPLATE_EXTRAS[template]) {
264
+ writeIfMissing(path.join(agentsDir, extra.file), extra.content);
265
+ }
266
+
267
+ // Optional project name in STATE.md
268
+ if (safeProjectName !== "project") {
269
+ try {
270
+ const statePath = path.join(agentsDir, "STATE.md");
271
+ const cur = fs.readFileSync(statePath, "utf-8");
272
+ const updated = cur.replace(/^# Project state$/m, `# Project state — ${projectName}`);
273
+ fs.writeFileSync(statePath, updated, "utf-8");
274
+ } catch { /* best-effort */ }
275
+ }
276
+
277
+ // Report
278
+ const created: string[] = [
279
+ ".agents/ROADMAP.md",
280
+ ".agents/STATE.md",
281
+ ".agents/HANDOFF.json",
282
+ ".agents/docs/vision.md",
283
+ ".agents/rules/code-style.md",
284
+ ".agents/phases/.gitkeep",
285
+ ".agents/iterations/.gitkeep",
286
+ "AGENTS.md",
287
+ ];
288
+ for (const extra of TEMPLATE_EXTRAS[template]) {
289
+ created.push(`.agents/${extra.file}`);
290
+ }
291
+ ui.notify(
292
+ `soly-init: done (${template}). Created:\n - ${created.join("\n - ")}\n\n` +
293
+ `Next:\n 1. Edit \`.agents/docs/vision.md\`\n 2. \`/plan 1\` to start the first phase`,
294
+ "info",
295
+ );
296
+ return { created: true, template, projectName: safeProjectName };
297
+ }
298
+
299
+ function writeIfMissing(file: string, content: string): void {
300
+ if (fs.existsSync(file)) return;
301
+ fs.writeFileSync(file, content, "utf-8");
302
+ }
@@ -0,0 +1,384 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [2.10.0] - 2026-06-13
11
+
12
+ ### Added
13
+ - Added manual remote/headless OAuth proxy actions for copying authorization URLs and completing pasted redirect URLs or codes. Thanks @Gabrielgvl for PR #120.
14
+
15
+ ### Fixed
16
+ - Honored user `tui.select.*` keybindings in MCP management, setup, and auth panels. Thanks @owenniles for PR #138.
17
+ - Included configured OAuth scopes in authorization-code flows while preserving token endpoint authentication method selection. Thanks @carlosdagos for PR #140.
18
+ - Fixed MCP elicitation on stock Pi, including form dialogs with validation and review, consent-based URL handling, URL-required errors, completion notifications, and TUI-only browser navigation. Thanks @dmmulroy for PR #139.
19
+ - Expanded MCP schema formatting for nested `anyOf`/`oneOf` variants, `const` discriminators, nested object properties, and array items.
20
+
21
+ ## [2.9.0] - 2026-06-04
22
+
23
+ ### Added
24
+ - Added MCP elicitation support with Pi form prompts and browser-opening URL requests.
25
+
26
+ ### Fixed
27
+ - Rejected non-http/https MCP URL elicitations before prompting or opening a browser.
28
+ - Preserved empty string form values for MCP string elicitations unless schema constraints reject them.
29
+
30
+ ## [2.8.0] - 2026-05-25
31
+
32
+ ### Added
33
+ - Added per-server OAuth `redirectUri`, `clientName`, and `clientUri` overrides for pre-registered callbacks and dynamic client metadata.
34
+
35
+ ### Fixed
36
+ - Avoided OAuth callback port exhaustion by starting the callback server lazily and using OS-assigned ports for dynamic OAuth flows.
37
+ - Re-register dynamic OAuth clients before browser auth when cached redirect URI metadata is missing or no longer matches the active callback URI.
38
+
39
+ ## [2.7.0] - 2026-05-22
40
+
41
+ ### Added
42
+ - Added TUI call rendering for MCP proxy and direct tool inputs. Thanks @dmmulroy for PR #102.
43
+
44
+ ### Fixed
45
+ - Hardened OAuth credential storage paths against server-name path traversal without rejecting valid configured server names.
46
+ - Rejected unsafe regex-mode MCP search patterns before executing them.
47
+
48
+ ## [2.6.1] - 2026-05-13
49
+
50
+ ### Added
51
+ - Added `/mcp logout <server>` to clear stored OAuth credentials and disconnect the server. Thanks @mattzcarey for PR #96.
52
+
53
+ ### Fixed
54
+ - Cancel pending OAuth callbacks when logging out of an MCP server.
55
+
56
+ ## [2.6.0] - 2026-05-10
57
+
58
+ ### Added
59
+ - Added a no-argument `/mcp-auth` OAuth picker and in-panel auth shortcut for OAuth-capable MCP servers.
60
+ - Added compact collapsed rendering for MCP proxy and direct-tool result rows while keeping full tool results available when expanded.
61
+
62
+ ### Changed
63
+ - Migrated Pi runtime dependencies and imports from deprecated `@mariozechner/*` packages to `@earendil-works/*` packages.
64
+
65
+ ### Fixed
66
+ - Re-register dynamic OAuth clients during fresh auth when cached DCR client info exists without tokens, avoiding dead authorization URLs after server-side client invalidation.
67
+ - Kept OAuth tokens, dynamic client info, PKCE verifiers, and OAuth state bound to the server URL so stale credentials cannot be reused after a server URL changes.
68
+ - Kept the `/mcp-auth` OAuth picker search focused on OAuth server rows and prevented hidden panel shortcuts from unexpectedly launching auth.
69
+ - Kept long MCP error results expanded in compact tool result rendering.
70
+
71
+ ## [2.5.4] - 2026-05-04
72
+
73
+ ### Changed
74
+ - Ignored npm lockfiles and removed checked-in `package-lock.json` files.
75
+
76
+ ### Fixed
77
+ - Resolved `${VAR}` and `$env:VAR` placeholders in HTTP bearer tokens.
78
+ - Honored MCP sampling `modelPreferences.hints` before falling back to the current/default model.
79
+
80
+ ## [2.5.3] - 2026-05-01
81
+
82
+ ### Added
83
+ - Added environment variable and `~` expansion for stdio server `cwd` values.
84
+
85
+ ## [2.5.2] - 2026-04-29
86
+
87
+ ### Fixed
88
+ - Respected `PI_CODING_AGENT_DIR` for Pi-owned MCP config and state files, including metadata cache, npx cache, onboarding state, OAuth credentials, and `pi-mcp-adapter init` writes.
89
+
90
+ ## [2.5.1] - 2026-04-24
91
+
92
+ ### Fixed
93
+ - Changed OAuth browser callbacks to `http://localhost:<port>/callback` for pre-registered clients such as Slack MCP. Thanks @shenal for PR #53.
94
+
95
+ ## [2.5.0] - 2026-04-24
96
+
97
+ ### Added
98
+ - Added MCP `sampling/createMessage` support with conservative human approval by default and opt-in `settings.samplingAutoApprove` for non-interactive flows.
99
+ - Added configured Vitest coverage for OAuth provider authorization fallback behavior.
100
+ - Added `test:oauth-provider` for running the root OAuth provider node test with the required TypeScript loader.
101
+
102
+ ### Fixed
103
+ - Applied `settings.authRequiredMessage` to proxy and direct-tool auth-required paths, including non-UI `autoAuth` failures.
104
+ - Fixed `/mcp-auth <server>` reporting success for expired stored OAuth tokens without forcing the SDK refresh/re-auth flow.
105
+ - Kept `mcp` search focused on MCP tools and added a direct-call hint when native Pi tools are accidentally routed through the proxy.
106
+
107
+ ## [2.4.2] - 2026-04-22
108
+
109
+ ### Fixed
110
+ - Migrated extension tool schemas from `@sinclair/typebox` to `typebox` 1.x so packaged installs follow Pi's current extension runtime contract.
111
+
112
+ ### Changed
113
+ - Replaced the legacy `@sinclair/typebox` runtime dependency with `typebox`.
114
+
115
+ ## [2.4.1] - 2026-04-22
116
+
117
+ ### Added
118
+ - Added standard-MCP-first config discovery: `~/.config/mcp/mcp.json` and project `.mcp.json` now load automatically, with Pi-owned files preserved as override layers.
119
+ - Added `pi-mcp-adapter init` as a native post-install helper that detects host-specific MCP configs and scaffolds Pi compatibility imports without using the old raw GitHub downloader flow.
120
+ - Added first-run onboarding inside the extension: `/mcp` now shows shared-config hints or actionable empty states, and `/mcp setup` opens a guided setup flow for compatibility imports, minimal `.mcp.json` scaffolding, detected config paths, RepoPrompt quick-add, and exact before/after write previews.
121
+ - Added automatic Pi-core reload after setup or direct-tool config changes, using the same flow as `/reload` so freshly configured direct tools can appear without a manual restart.
122
+ - Added a dedicated Pi-owned onboarding state file so shared-config hints behave as one-time guidance instead of repeating every session.
123
+
124
+ ### Changed
125
+ - Updated config precedence to prefer shared MCP files first, then Pi overrides, with `.pi/mcp.json` acting as the final Pi-specific project override.
126
+ - Updated Claude Code compatibility probing to prefer modern Claude MCP config locations before legacy paths.
127
+ - Updated project scaffolding so generated `.mcp.json` files are safe minimal shells instead of fake placeholder servers that fail on first reload.
128
+ - Updated the setup panel and README for clearer first-run guidance, improved spacing, and a more digestible shared-MCP-first setup story.
129
+
130
+ ## [2.4.0] - 2026-04-13
131
+
132
+ ### Added
133
+ - `settings.disableProxyTool` to hide the `mcp` proxy tool once configured direct tools are fully available from cache. Thanks @tanavamsikrishna for PR #41.
134
+ - Per-server `excludeTools` to hide specific MCP tools/resources by original or prefixed name across direct tools, proxy discovery, and the `/mcp` panel. Thanks @ahmadaccino for issue #36.
135
+ - `settings.autoAuth` to optionally trigger OAuth automatically from proxy/direct tool usage, then rerun the original blocked connect/tool operation once after authentication succeeds. Thanks @unimonkiez for issue #34.
136
+
137
+ ### Fixed
138
+ - Regenerated `package-lock.json` so the root lockfile metadata matches `package.json` again, including the declared `open`, `@types/bun`, `@types/open`, and `tsx` entries.
139
+ - Kept the `mcp` proxy tool available as a first-session fallback when configured direct tools are still missing cache metadata, avoiding no-tool startup gaps.
140
+
141
+ ## [2.3.5] - 2026-04-13
142
+
143
+ ### Fixed
144
+ - Session lifecycle now always tears down OAuth callback state on restart and shutdown, preventing callback-server leaks across session transitions.
145
+ - OAuth callback server now calls `unref()` after successful bind so it no longer keeps sub-agent processes alive by itself.
146
+ - Strict OAuth port mode now rebinds to the configured callback port when safe, while refusing to switch ports when authorizations are still pending.
147
+ - Added focused lifecycle/callback-server regression coverage for teardown, `unref()`, strict rebinding, and pending-auth guardrails.
148
+ - Thanks @blai for the investigation and PR #43 that surfaced the sub-agent hang/root lifecycle issues.
149
+
150
+ ## [2.3.4] - 2026-04-12
151
+
152
+ ### Fixed
153
+ - OAuth callback handling now allows dynamic-registration flows to fall back to a free local port when the preferred callback port is busy, while keeping pre-registered clients on their exact configured redirect port.
154
+ - Documented the new callback-port behavior and added focused auth-flow regression coverage.
155
+
156
+ ## [2.3.3] - 2026-04-12
157
+
158
+ ### Fixed
159
+ - Remove the blank footer status line when no MCP servers are configured by clearing the MCP status entry instead of setting it to an empty string. Thanks @HazAT for PR #27.
160
+
161
+ ## [2.3.2] - 2026-04-11
162
+
163
+ ### Added
164
+ - Optional `oauth.grantType: "client_credentials"` for non-interactive machine-to-machine OAuth on HTTP MCP servers.
165
+
166
+ ### Fixed
167
+ - `/mcp-auth <server>` now handles `client_credentials` without browser/callback flow.
168
+ - MCP panel status no longer marks `client_credentials` servers as auth-blocked solely because no stored user tokens exist yet.
169
+ - OAuth auth flow now closes temporary transports consistently on success, refresh, and auth removal paths.
170
+ - Init paths now preserve debug-level context for previously silent direct-tool bootstrap and lazy-connect failures.
171
+
172
+ ## [2.3.1] - 2026-04-11
173
+
174
+ ### Fixed
175
+ - Removed `/mcp-auth-callback`. OAuth auth now hard-cuts to `/mcp-auth <server>` only.
176
+
177
+ ## [2.3.0] - 2026-04-11
178
+
179
+ ### Added
180
+ - OAuth callback server initialization on session start and a deprecated `/mcp-auth-callback` command that now points users to `/mcp-auth <server>`.
181
+
182
+ ### Fixed
183
+ - OAuth `needs-auth` handling across `/mcp` status/panel, `mcp({ connect })`, `mcp({ tool })`, reconnect flow, lazy/direct tool execution, and startup bootstrap.
184
+ - OAuth callback cleanup now cancels by stored OAuth state and closes pending transports on failure/cancel paths.
185
+ - Callback server now fails fast when the OAuth callback port is occupied by another process.
186
+ - Package manifest test now ignores root `*.test.ts` files.
187
+
188
+ ## [2.2.2] - 2026-04-03
189
+
190
+ ### Fixed
191
+ - Session lifecycle teardown now handles repeated `session_start` transitions safely and prevents stale async init results from replacing newer state.
192
+ - Shutdown now still runs `gracefulShutdown()` even if metadata cache flushing throws, avoiding leaked MCP processes.
193
+ - Proxy/direct tool init error paths now preserve and surface underlying error messages instead of returning generic failures.
194
+ - Invalid `mcp` tool `args` now fail by throwing with parse/type context instead of returning non-failing tool payloads.
195
+ - Added focused lifecycle regressions tests for stale init cleanup and init-error visibility.
196
+
197
+ ## [2.2.1] - 2026-03-23
198
+
199
+ ### Fixed
200
+ - Added `promptSnippet` to MCP proxy tool and direct MCP tools so they appear in the system prompt's Available tools section (required since pi 0.59.0)
201
+
202
+ ## [2.2.0] - 2026-03-16
203
+
204
+ ### Added
205
+ - **MCP UI Integration** - Support for the [MCP UI](https://github.com/MCP-UI-Org/mcp-ui) standard. Tools with `_meta.ui.resourceUri` open interactive UIs:
206
+ - Bidirectional AppBridge communication (tool calls, messages, context updates)
207
+ - Works with both stdio and HTTP MCP servers
208
+ - User consent management for tool calls from UI (configurable: never/once-per-server/always)
209
+ - Keyboard shortcuts: Cmd/Ctrl+Enter to complete, Escape to cancel
210
+ - UI prompts/intents trigger agent turns via `pi.sendMessage({ triggerTurn: true })`
211
+ - `mcp({ action: "ui-messages" })` retrieves accumulated messages from UI sessions
212
+
213
+ - **Session reuse** - When the agent calls the same tool while its UI is already open, results push to the existing window instead of replacing it. Per-call stream IDs with independent sequences. Error results scoped to the individual call.
214
+
215
+ - **Glimpse integration** - MCP UI opens in a native macOS WKWebView window instead of a browser tab when [Glimpse](https://github.com/hazat/glimpse) is installed (`pi install npm:glimpseui`). Falls back to browser on non-macOS or when unavailable. Override with `MCP_UI_VIEWER=browser` or `MCP_UI_VIEWER=glimpse`.
216
+
217
+ - **Logger module** (`logger.ts`) - Centralized logging with levels (debug/info/warn/error), contextual child loggers, and `MCP_UI_DEBUG=1` env var.
218
+
219
+ - **Error types** (`errors.ts`) - Structured errors with recovery hints: `ResourceFetchError`, `ResourceParseError`, `BridgeConnectionError`, `ConsentError`, `SessionError`, `ServerError`, and `wrapError()` helper.
220
+
221
+ - **Test suite** - 178 tests covering consent manager, UI resource handler, host HTML template, logger, and error types.
222
+
223
+ - **Interactive visualizer example** (`examples/interactive-visualizer`) - Minimal MCP server demonstrating charts (bar/line/pie/doughnut via Chart.js), bidirectional messaging, and streaming.
224
+
225
+ ### Fixed
226
+ - Host-iframe timing: bridge now connects before loading iframe, fixing `ui/initialize` timeout on first load
227
+ - All internal `log.info` calls demoted to `log.debug` to eliminate stdout noise during normal use
228
+
229
+ ### Technical Notes
230
+ - Uses local minified AppBridge bundle (408KB) to avoid CDN Zod bundling issues
231
+ - Serves app HTML from `/ui-app` endpoint instead of blob URLs to avoid iframe issues
232
+ - SSE for real-time tool result streaming to browser
233
+
234
+ ## [2.1.2] - 2026-02-03
235
+
236
+ ### Changed
237
+ - Added demo video and `pi.video` field to package.json for pi package browser.
238
+
239
+ ## [2.1.0] - 2026-02-02
240
+
241
+ ### Added
242
+ - **Direct tool registration** - Promote specific MCP tools to first-class Pi tools via `directTools` config (per-server or global). Direct tools appear in the agent's tool list alongside builtins, so the LLM uses them without needing to search through the proxy first. Registers from cached metadata at startup — no server connections needed.
243
+ - **`/mcp` interactive panel** - New TUI overlay replacing the text-based status dump. Shows server connection status, tool lists with direct/proxy toggles, token cost estimates, inline reconnect, and auth notices. Changes written to config on save.
244
+ - **Auto-enriched proxy description** - The `mcp` proxy tool description now includes server names and tool counts from the metadata cache, so the LLM knows what's available without a search call (~30 extra tokens).
245
+ - **`MCP_DIRECT_TOOLS` env var** - Subagent processes receive their direct tool configuration via environment variable, keeping subagents lean by default.
246
+ - **First-run bootstrap** - Servers with `directTools` configured but no cache entry are connected during `session_start` to populate the cache. Direct tools become available after restart.
247
+ - Config provenance tracking for correct write-back to user/project/import sources
248
+ - Builtin name collision guard (skips direct tools that would shadow `read`, `write`, etc.)
249
+ - Cross-server name deduplication for `prefix: "none"` and `prefix: "short"` modes
250
+
251
+ ## [2.0.1] - 2026-02-01
252
+
253
+ ### Fixed
254
+ - Adapt execute signature to pi v0.51.0: add signal, onUpdate, ctx parameters
255
+
256
+ ## [2.0.0] - 2026-01-29
257
+
258
+ ### Changed
259
+ - **BREAKING: Lazy startup by default** - All servers now default to `lifecycle: "lazy"` and only connect when a tool call needs them. Previously all servers connected eagerly on session start. Set `lifecycle: "keep-alive"` or `lifecycle: "eager"` to restore the old behavior per-server.
260
+ - **Idle timeout** - Connected servers are automatically disconnected after 10 minutes of inactivity (configurable via `settings.idleTimeout` or per-server `idleTimeout`). Cached metadata keeps search/list working after disconnect. Set `idleTimeout: 0` to disable.
261
+ - `/mcp reconnect` accepts an optional server name to connect or reconnect a single server
262
+
263
+ ### Added
264
+ - **Metadata cache** - Tool and resource metadata persisted to `~/.pi/agent/mcp-cache.json`. Enables search/list/describe without live connections. Per-server config hashing with 7-day staleness. Multi-session safe via read-merge-write with per-process tmp files.
265
+ - **npx binary resolution** - Resolves npx package binaries to direct paths, eliminating the ~143 MB npm parent process per server. Persistent cache at `~/.pi/agent/mcp-npx-cache.json` with 24h TTL.
266
+ - **`mcp({ connect: "server-name" })` mode** - Explicitly trigger connection and metadata refresh for a named server
267
+ - **Failure backoff** - Servers that fail to connect are skipped for 60 seconds to avoid repeated connection storms
268
+ - **In-flight tracking** - Active tool calls prevent idle timeout from shutting down a server mid-request
269
+ - **Prefix-match fallback** - Tool calls with unrecognized names try to match a server prefix and lazy-connect the matching server
270
+ - Lifecycle options: `lazy` (default), `eager` (connect at startup, no auto-reconnect), `keep-alive` (unchanged)
271
+ - Per-server `idleTimeout` override and global `settings.idleTimeout`
272
+ - First-run bootstrap: connects all servers on first session to populate the cache
273
+
274
+ ### Fixed
275
+ - Connection close race condition: concurrent close + connect no longer orphans server processes
276
+ - **Fuzzy tool name matching** - Hyphens and underscores are treated as equivalent during tool lookup. MCP tools like `resolve-library-id` are now found when called as `resolve_library_id`, which LLMs naturally guess since the prefix separator is `_`.
277
+ - **Better "tool not found" errors** - When a server is identified (via prefix match or override) but the tool isn't found, the error now lists that server's available tools so the LLM can self-correct immediately instead of needing a separate list call
278
+
279
+ ## [1.6.0] - 2026-01-29
280
+
281
+ ### Added
282
+ - **Unified pi tool search** - `mcp({ search: "..." })` now searches both MCP tools and Pi tools (from installed extensions)
283
+ - Pi tools appear first in results with `[pi tool]` prefix
284
+ - Details object includes `server: "pi"` for pi tools
285
+ - Banner image for README
286
+
287
+ ## [1.5.1] - 2026-01-26
288
+
289
+ ### Changed
290
+ - Added `pi-package` keyword for npm discoverability (pi v0.50.0 package system)
291
+
292
+ ## [1.5.0] - 2026-01-22
293
+
294
+ ### Changed
295
+ - **BREAKING: `args` parameter is now a JSON string** - The `args` parameter which previously accepted an object now accepts a JSON string. This change was required for compatibility with Claude's Vertex AI API (`google-antigravity` provider) which rejects `patternProperties` in JSON schemas (generated by `Type.Record()`).
296
+
297
+ ### Added
298
+ - **Type validation for args** - Parsed args are now validated to ensure they're a JSON object (not null, array, or primitive). Clear error messages for invalid input.
299
+ - **`isError: true` on error responses** - JSON parse errors and type validation errors now properly set `isError: true` to indicate failure to the LLM.
300
+
301
+ ### Migration
302
+ ```typescript
303
+ // Before (1.4.x)
304
+ mcp({ tool: "my_tool", args: { key: "value" } })
305
+
306
+ // After (1.5.0)
307
+ mcp({ tool: "my_tool", args: '{"key": "value"}' })
308
+ ```
309
+
310
+ ## [1.4.1] - 2026-01-19
311
+
312
+ ### Changed
313
+
314
+ - Status bar shows server count instead of tool count ("MCP: 5 servers")
315
+
316
+ ## [1.4.0] - 2026-01-19
317
+
318
+ ### Changed
319
+
320
+ - **Non-blocking startup** - Pi starts immediately, MCP servers connect in background. First MCP call waits only if init isn't done yet.
321
+
322
+ ### Fixed
323
+
324
+ - Tool metadata now includes `inputSchema` after `/mcp reconnect` (was missing, breaking describe and error hints)
325
+
326
+ ## [1.3.0] - 2026-01-19
327
+
328
+ ### Changed
329
+
330
+ - **Parallel server connections** - All MCP servers now connect in parallel on startup instead of sequentially, significantly faster with many servers
331
+
332
+ ## [1.2.2] - 2026-01-19
333
+
334
+ ### Fixed
335
+
336
+ - Installer now downloads from `main` branch (renamed from `master`)
337
+
338
+ ## [1.2.1] - 2026-01-19
339
+
340
+ ### Added
341
+
342
+ - **npx installer** - Run `npx pi-mcp-adapter` to install (downloads files, installs deps, configures settings.json)
343
+
344
+ ## [1.1.0] - 2026-01-19
345
+
346
+ ### Changed
347
+
348
+ - **Search includes schemas by default** - Search results now include parameter schemas, reducing tool calls needed (search + call instead of search + describe + call)
349
+ - **Space-separated search terms match as OR** - `"navigate screenshot"` finds tools matching either word (like most search engines)
350
+ - **Suppress server stderr by default** - MCP server logs no longer clutter terminal on startup
351
+ - Use `includeSchemas: false` for compact output without schemas
352
+ - Use `debug: true` per-server to show stderr when troubleshooting
353
+
354
+ ## [1.0.0] - 2026-01-19
355
+
356
+ ### Added
357
+
358
+ - **Single unified `mcp` tool** with token-efficient architecture (~200 tokens vs ~15,000 for individual tools)
359
+ - **Five operation modes:**
360
+ - `mcp({})` - Show server status
361
+ - `mcp({ server: "name" })` - List tools from a server
362
+ - `mcp({ search: "query" })` - Search tools by name/description
363
+ - `mcp({ describe: "tool_name" })` - Show tool details and parameter schema
364
+ - `mcp({ tool: "name", args: {...} })` - Call a tool
365
+ - **Stdio transport** for local MCP servers (command + args)
366
+ - **HTTP transport** with automatic fallback (StreamableHTTP → SSE)
367
+ - **Config imports** from Cursor, Claude Code, Claude Desktop, VS Code, Windsurf, Codex
368
+ - **Resource tools** - MCP resources exposed as callable tools
369
+ - **OAuth support** - Token file-based authentication
370
+ - **Bearer token auth** - Static or environment variable tokens
371
+ - **Keep-alive connections** with automatic health checks and reconnection
372
+ - **Schema on-demand** - Parameter schemas shown in `describe` mode and error responses
373
+ - **Commands:**
374
+ - `/mcp` or `/mcp status` - Show server status
375
+ - `/mcp tools` - List all tools
376
+ - `/mcp reconnect` - Force reconnect all servers
377
+ - `/mcp-auth <server>` - Show OAuth setup instructions
378
+
379
+ ### Architecture
380
+
381
+ - Tools stored in metadata map, not registered individually with Pi
382
+ - MCP server validates arguments (no client-side schema conversion)
383
+ - Reconnect callback updates metadata after auto-reconnect
384
+ - Human-readable schema formatting for LLM consumption