Release gate. See docs/release-process.md for the consolidated release workflow: what must be green before a tag, how a three-platform smoke pass is recorded, and when a waiver is permitted.
These cases exercise behavior that integration tests can't cover: real browser rendering, real OTP email delivery, real Cloudflare challenge, and real keychain dialogs. Run on Windows 11, macOS 14+, and Ubuntu 22+ before tagging 0.3.0.
- Fresh install:
npx perplexity-user-mcp@0.3.0 --helpprints the subcommand list. -
npx perplexity-user-mcp add-account --name work --mode manualcreates~/.perplexity-mcp/profiles/work/. -
npx perplexity-user-mcp login --profile work --mode manualopens a headed browser; after login,vault.encexists and CLI printslogin finished (0). - Within 2s of login, a running MCP server (Claude Desktop or Cursor) accepts a
perplexity_modelscall and reports Pro tier (proves.reinitsentinel fires across runtimes). -
npx perplexity-user-mcp status --jsonreports{"valid":true,"tier":"Pro",...}. -
npx perplexity-user-mcp add-account --name personal --mode autothenlogin --profile personal --mode auto --email you@example.com: CLI prompts for OTP, accepts it, succeeds. -
npx perplexity-user-mcp switch-account workfollowed bystatusreports theworkprofile's tier (notpersonal). - In VS Code, open the dashboard: profile pill shows active profile name + tier + green status dot.
- Click the pill -> Switch to
personal-> status pill re-renders withpersonal's tier; the extension firesserverDefinitionsChanged, MCP host refreshes. - Click Logout (soft) -> pill shows yellow/red;
perplexity_searchfrom any MCP host returns a "session expired, run login" remediation error rather than crashing. - Force session expiry (delete the vault's
cookieskey manually) then run any auth-requiring tool: extension shows "Re-login" warning dialog. - On headless Linux (no libsecret), set
PERPLEXITY_VAULT_PASSPHRASE, runstatus-> succeeds. Unset the env var ->statusprints the "Vault locked" remediation message and exits non-zero.
Referenced by release gate in docs/superpowers/plans/2026-04-20-phase-2-auth.md Task 14.
Run these manually before tagging v0.4.0. Each item should pass on Windows 11, macOS 14+, and Ubuntu 22+.
- Clean install passes. On a fresh
pnpm install && pnpm build,npx perplexity-user-mcp doctorexits 0 with overallpassorwarn(nofail). - Broken VSIX packaging is detected. Temporarily delete
dist/node_modules/is-obj/in the built VSIX, then load the extension fromcode --install-extension <vsix>. Open the Doctor tab and click Run — thenative-deps/got-scraping-chaincheck should emit awarnwith a hint pointing atprepare-package-deps.mjs. -
--proberuns a live search. Log in via the extension first, thennpx perplexity-user-mcp doctor --probe. Theprobe/probe-searchcheck should emitpasswithlatencyMs < 10000andsourceCount ≥ 1. -
--jsonoutput is valid JSON.npx perplexity-user-mcp doctor --json | jq .overallprints one of"pass","warn","fail". - Doctor tab renders. Open the extension's
Doctortab. All 10 category cards render. Clicking a category toggles the expanded check list. Status dots reflect the category rollup. - Report-issue preview shows no PII. Artificially induce a fail (e.g., rename your Chrome binary so
browser/chrome-familyfails). Click Report issue. Verify the preview modal contains no emails, no userIds, no cookie values, no home paths, and no IPs.
Run these on Windows 11 after npm run package:vsix in packages/extension/ produces perplexity-vscode-0.4.1.vsix AND the VSIX is installed via code --install-extension perplexity-vscode-0.4.1.vsix. All four items must be green before tagging v0.4.1.
- Login succeeds end-to-end. Open the extension -> click Login in the header -> the manual-login browser opens (or OTP flow starts). You must get past the Phase-2
"require not available"error. A successful login writes cookies to~/.perplexity-mcp/profiles/default/vault.enc. - Doctor: patchright + got-scraping-chain both pass. Open the Doctor tab -> click Run. The
native-depscategory'spatchrightcheck should bepass(no "not resolvable" error) andgot-scraping-chainshould bepass(no warn). The carry-over #5 detector remains, but the false positive is gone. - Doctor report timestamp is readable. In the Doctor tab, click Report issue on any failing check -> the preview modal shows
Generated: <real ISO timestamp>-- NOTGenerated: <ip>.278Z. - Tab order. The tab strip reads: Home -> IDEs -> Rules -> Models -> Doctor -> History. Doctor is second-to-last, not second.
Run these before tagging v0.5.0.
- History writes as Markdown. Run a new
perplexity_searchorperplexity_research, then confirm a new~/.perplexity-mcp/profiles/<name>/history/*.mdfile exists with YAML frontmatter and readable Markdown body. - Rich View renders. Open the dashboard -> History -> Rich View for an entry. Confirm the overlay shows the Markdown body, metadata, sources, and attachments sidebar. Press
Escand confirm it closes. - Markdown export fallback works. From the dashboard or
Perplexity: Export History Entry, export an entry as Markdown. Confirm a.mdcopy is written under that entry's attachments directory. - Native PDF or DOCX export works for an authenticated entry. Export a logged-in entry as PDF or DOCX and confirm the saved file opens correctly from the attachments directory.
- Preview and external open flows work. Use Open with ->
VS Code previewand at least one detected external viewer orSystem default. - Pin and tag changes round-trip. Pin an entry in Rich View, add/update tags, refresh the dashboard, and confirm the card and Rich View metadata stay in sync.
- Rebuild index recovers history. Run
Perplexity: Rebuild History Indexornpx perplexity-user-mcp rebuild-history-index --jsonand confirm it reports scan counts and the History tab still loads. - Doctor reports viewer detection. Run
npx perplexity-user-mcp doctorand confirm theide.mdViewerscheck reports detected viewers without failing when none are installed.
Phase 8.3 flips every auto-configured external stdio MCP client (Claude Desktop, Cursor, Cline, Codex CLI, Amp, …) onto the shared daemon. Pre-8.3.0, each client spawned its own in-process stdio server + Chromium; post-8.3.0, they all multiplex onto one daemon + one Chromium. The integration suite covers the CLI/launcher-generator paths but cannot exercise three real clients opening Chromium simultaneously — this checklist is gating for v0.8.0.
Prereqs before running:
- Install the fresh smoke VSIX:
code --install-extension packages/extension/perplexity-vscode-0.7.4.vsix --force. The VSIX still carries the 0.7.4 version stamp deliberately — the bump to 0.8.0 happens in Task 8.3.5 after this smoke passes. The artifact at HEADd987f60contains the 8.3.1–8.3.3 code and is the correct smoke target; the filename only becomesperplexity-vscode-0.8.0.vsixduring release prep. - Reload the VS Code window.
- Profile must already be logged in (daemon needs cookies in
~/.perplexity-mcp/profiles/<active>/vault.enc). - Claude Desktop, Cursor, and Cline all installed. (If any is unavailable, substitute another stdio MCP client but note the substitution in the smoke-evidence file.)
Run these on Windows 11 (primary) + macOS 14 (secondary, if available). All eight must pass or be explicitly waived before tagging v0.8.0.
-
Migration — stale launcher is rewritten. Before installing 0.8.0, note the current contents of
~/.perplexity-mcp/start.mjs(should be the pre-8.3.3 one-linerawait import(config.serverPath)). Install the 0.8.0 VSIX and reload VS Code. Re-openstart.mjs— it must now contain the literal substringattachToDaemonANDfallbackStdio: true. Fresh installs (no pre-existing file) are also acceptable; in that case, note "fresh install" in the evidence. -
Configs generated. Run command
Perplexity: Generate MCP Configsfrom the command palette. Select at least Claude Desktop, Cursor, and Cline (add more if configured). Each target's config file (claude_desktop_config.json,.cursor/mcp.json,.cline/mcp_config.jsonor equivalent) pointsargsat~/.perplexity-mcp/start.mjs. -
One daemon + one Chromium invariant. Launch Claude Desktop, Cursor, and Cline in sequence (give each ~5s to hand-shake). Open Task Manager (Windows) or Activity Monitor (macOS). Filter by process tree. Assert: exactly one
nodeprocess holdingdaemon.lock's PID AND exactly one Chromium tree (one parent + N renderer children is fine — "one tree" means one parent PID). Attach a screenshot or copy the process table into the evidence file. If you see three Chromium parents, the consolidation failed. -
Distinct launcher client IDs in audit. Open
~/.perplexity-mcp/audit.log(or wherever the daemon writes OAuth/request audit entries — check the daemon's startup banner). Each of the three clients should have stamped a distinctx-perplexity-client-idheader with prefixperplexity-launcher-<pid>. Count the distinct PIDs: expect exactly three (one per client's launcher process). -
End-to-end tool call. From each of the three clients, trigger a
perplexity_modelsor simpleperplexity_searchtool call. All three responses must succeed and include model/account-tier data. This proves the stdio↔HTTP proxy path is fully wired across all three launchers simultaneously. -
PERPLEXITY_NO_DAEMON opt-out. Edit one client's
mcp.jsonto add"env": { "PERPLEXITY_NO_DAEMON": "1" }alongside the existing env block. Restart that client only. Assert: that client's process inventory shows a new Chromium tree (its own, not shared with the daemon). Its stderr (visible in the client's MCP log) contains the literal line[perplexity-mcp] PERPLEXITY_NO_DAEMON=1 set; running in-process stdio (daemon bypass). Aperplexity_modelscall from that client still succeeds. Revert the edit before moving on. -
Stdout discipline. Enable MCP protocol logging in one client (e.g., Claude Desktop:
MCP_LOGS=1or check the view logs menu). After a tool call, inspect the MCP session log — it must contain zeroParse error/SyntaxError/Unexpected tokenentries. If the launcher ever writes to stdout, JSON-RPC framing breaks and these errors appear. -
Fallback-stdio path — best-effort manual. Naively killing the running daemon does NOT reliably exercise the fallback path:
ensureDaemonhas a 15s retry loop that cheerfully re-spawns a fresh daemon on the next poll, so a restarted client will just re-attach to the respawned daemon and never enter the fallback branch. The authoritative evidence for the fallback path is the automated integration testpackages/mcp-server/test/daemon/attach.test.js(fallback-stdio case added in Task 8.3.1), which the headless release gate (npx vitest run) proves on every commit — re-run it here and record the count:npx vitest run packages/mcp-server/test/daemon/attach.test.jsExpect: 3 passed / 1 file. Paste the output in the evidence file.
Optional best-effort manual recipe (skip if integration test is green and time is short): in ONE client's
mcp.json, set an env block"PERPLEXITY_CONFIG_DIR": "<userprofile>/.perplexity-mcp-smoke-blocker.txt"where that path is a pre-created empty file (not a directory). The daemon can'tmkdirSynconto a file, sospawnDetachedDaemon's child crashes,ensureDaemontimes out after 15s, andattachToDaemonruns the fallback. Restart that client. Expected behavior if fallback triggers:- That client's MCP stderr contains the literal line:
[perplexity-mcp] daemon unreachable (...); falling back to in-process stdio - The in-process stdio then runs
server.main()via the DIrunStdioMainshim added in 8.3.3 (the defaultattach.tsfallback path —import("../index.js")— does NOT work in the bundled extension layout where attach.ts is inlined intodist/mcp/server.mjs; if you ever seeERR_MODULE_NOT_FOUNDhere instead of the fallback line, the DI shim did NOT land correctly in the bundle). server.main()may itself fail to find a logged-in profile under the bogus config dir — that's OK for this check. The evidence you need is the stderr line plus clean process exit (no ERR_MODULE_NOT_FOUND). If the client shows "no session" after fallback, that's a secondary confirmation thatserver.main()ran.
Revert the bogus
PERPLEXITY_CONFIG_DIRedit before moving on. Mark this check ✅ if the integration test passed OR the manual recipe showed the stderr line. - That client's MCP stderr contains the literal line:
When all eight are green (or explicitly waived), save the evidence file to docs/smoke-evidence/phase-8-3-YYYY-MM-DD.md and proceed to Task 8.3.5 (release v0.8.0).
Referenced by release gate in docs/superpowers/plans/2026-04-22-phase-8-completeness.md Task 8.3.4.
Phase 8.4 adds the cf-named tunnel provider: a persistent URL on a user-managed Cloudflare zone (as opposed to the ephemeral *.trycloudflare.com of cf-quick). Unlike Phase 8.3 — where hermetic integration tests covered the fallback path cleanly — this phase's external surface cannot be meaningfully mocked: cloudflared tunnel login, origin-cert placement, tunnel-creation stdout parsing, DNS CNAME creation, and named-tunnel readiness detection (a NEW Registered tunnel connection stderr pattern, NOT the *.trycloudflare.com URL-extraction used by cf-quick) ALL need to be validated against real Cloudflare APIs at least once before the first public release of this provider. The 6-step minimum-viable smoke below is the release gate for v0.8.1.
Run on Windows 11 (primary) plus any second host if available.
Prereqs:
- A Cloudflare account with an owned zone (free tier is fine; this smoke creates exactly one tunnel + one DNS CNAME and the cleanup in step 8 removes them).
- One pre-chosen subdomain. Use something unambiguously disposable — e.g.
mcp-smoke-<YYYYMMDD>.<zone>so accidental orphaning is obvious. - Fresh VSIX installed at v0.8.1 (filename
perplexity-vscode-0.8.1.vsixafter Task 8.4.5's bump) OR the post-8.4.4 build at HEAD381f75cstamped 0.8.0 (the CLI-only checks don't require the extension at all). - Profile logged in (only required for step 6's end-to-end daemon-start check; steps 1-5 and 7-8 are CLI-only and don't need a profile).
- A browser available for step 3 (cloudflared login opens one).
- The chosen hostname must not be subject to Cloudflare Challenge/CAPTCHA on MCP/OAuth paths. If the zone has WAF, Security Level, Browser Integrity Check, or Super Bot Fight Mode challenge rules, create a higher-priority Skip rule for this smoke hostname before step 6.
Placeholders (substitute throughout):
<sub>— the disposable subdomain you chose (e.g.mcp-smoke-20260423)<zone>— your Cloudflare-managed zone (e.g.example.com)<hostname>—<sub>.<zone>fully qualified<uuid>— the tunnel UUID returned bycf-named-createin step 5 (record it for steps 7 and 8)
Shell note: PowerShell is the primary shell below. Git-Bash fallback is given where the syntax materially differs. Do NOT use curl in PowerShell (alias for Invoke-WebRequest, wrong output shape) — use curl.exe explicitly.
Before starting — guard against orphaned prior attempts:
npx perplexity-user-mcp daemon cf-named-listIf any mcp-smoke-* tunnels show up from a prior run, jump to step 8 and clean them before proceeding. A stale tunnel + DNS route blocks re-running step 5 with the same hostname.
-
Step 1 — Install cloudflared binary.
PowerShell:
npx perplexity-user-mcp daemon install-tunnel --json
Bash:
npx perplexity-user-mcp daemon install-tunnel --json
Expect: exit 0; stdout is a single JSON line containing
"ok":trueand abinaryPathpointing at<configDir>/bin/cloudflared(.exe). The binary should be executable from that exact path in step 3. -
Step 2 — cf-named-login decline path returns 130.
PowerShell:
"n" | npx perplexity-user-mcp daemon cf-named-login; $LASTEXITCODE
Bash:
echo n | npx perplexity-user-mcp daemon cf-named-login; echo "exit=$?"
Expect: stderr shows the confirmation prompt
This opens your default browser to authorize Cloudflare. Continue? [y/N]followed byCancelled.— then the exit code printed is 130. If you see exit 0 or 1 the confirmation wiring is wrong and this is a release blocker. -
Step 3 — cf-named-login --yes completes browser auth and cert appears.
PowerShell:
npx perplexity-user-mcp daemon cf-named-login --yes
Bash:
npx perplexity-user-mcp daemon cf-named-login --yes
A browser tab opens to
https://dash.cloudflare.com/argotunnel?.... Authorize the zone. The CLI blocks until~/.cloudflared/cert.pemappears (up to 10 minutes default timeout); it should land within ~30s of clicking Authorize.Expect: exit 0; stdout prints
cloudflared login completed. Cert at <path>. Then verify manually:PowerShell:
Test-Path "$env:USERPROFILE\.cloudflared\cert.pem"
Bash:
ls -la ~/.cloudflared/cert.pemExpect
True/ a regular file. -
Step 4 — cf-named-list works (initially empty or pre-existing-only).
PowerShell:
npx perplexity-user-mcp daemon cf-named-list --json
Bash:
npx perplexity-user-mcp daemon cf-named-list --json
Expect: exit 0; stdout is a single parseable JSON line
{"tunnels":[...]}. If the array is empty that's fine — this confirms the plain-text formatter works (run without--jsonto seeNo named tunnels.on stdout). If you have pre-existing named tunnels from another workflow, they'll appear — that's expected, the list is cert-scoped not script-scoped. -
Step 5 — cf-named-create creates tunnel, DNS route, and managed YAML.
PowerShell:
npx perplexity-user-mcp daemon cf-named-create --name "mcp-smoke-$(Get-Date -Format yyyyMMdd)" --hostname "<sub>.<zone>" --yes --json
Bash:
npx perplexity-user-mcp daemon cf-named-create --name "mcp-smoke-$(date +%Y%m%d)" --hostname "<sub>.<zone>" --yes --json
Expect: exit 0; stdout is a single JSON line
{"ok":true,"hostname":"<sub>.<zone>","uuid":"<uuid>","configPath":"<configDir>/cloudflared-named.yml"}. Record<uuid>for step 7 and step 8 cleanup.Then verify manually:
PowerShell:
Get-Content "$env:USERPROFILE\.perplexity-mcp\cloudflared-named.yml" Test-Path "$env:USERPROFILE\.cloudflared\<uuid>.json"
Bash:
cat ~/.perplexity-mcp/cloudflared-named.yml ls -la ~/.cloudflared/<uuid>.json
Expect the YAML contains
tunnel: <uuid>andhostname: <sub>.<zone>andservice: http://127.0.0.1:1(port=1 placeholder — real port is rewritten by the provider at daemon start; see step 6). Expect the<uuid>.jsoncredentials file exists.DNS cross-check (optional but recommended):
PowerShell:
Resolve-DnsName "<sub>.<zone>" -Type CNAME
Bash:
dig +short CNAME <sub>.<zone>
Expect a CNAME pointing at
<uuid>.cfargotunnel.com. If DNS hasn't propagated within ~2 minutes, Cloudflare's side of the route creation failed and step 6 will not reach the hostname. -
Step 6 — set-provider cf-named + daemon start --tunnel reaches the named URL.
PowerShell:
npx perplexity-user-mcp daemon set-provider cf-named npx perplexity-user-mcp daemon start --tunnel
Bash:
npx perplexity-user-mcp daemon set-provider cf-named npx perplexity-user-mcp daemon start --tunnel
The daemon starts, writes the lockfile at the OS-assigned loopback port, rewrites
cloudflared-named.ymlwith that port (replacing the port=1 placeholder from step 5 — this is the load-bearing 8.4.2 port-drift rewrite), and spawns cloudflared withtunnel --no-autoupdate --config <managed-yml> run. Wait ~15s for the firstRegistered tunnel connectionline in the daemon log.In a second terminal, probe the public URL via the allowlisted tunnel endpoints. Do not try
/daemon/*through the tunnel — v0.7.4's H11 hardening returns 404 to all/daemon/*routes on the tunnel regardless of bearer, and the security regression check below verifies that still holds.Primary probe: protected-resource metadata (allowlisted public endpoint).
PowerShell:
curl.exe -i "https://<sub>.<zone>/.well-known/oauth-protected-resource"
Bash:
curl -i "https://<sub>.<zone>/.well-known/oauth-protected-resource"Expect: HTTP 200. Response body is JSON containing
"resource": "https://<sub>.<zone>/mcp"and"resource_name": "Perplexity MCP". The host-awareresourceURL proves (a) the named tunnel is up, (b) traffic reaches the local daemon on the LIVE port (not the port=1 placeholder), (c) the OAuth resource-binding logic correctly reflects the incoming Host header rather than 127.0.0.1.Cloudflare edge challenge check (release blocker if present).
PowerShell:
curl.exe -i -X POST "https://<sub>.<zone>/mcp" -H "Content-Type: application/json" -H "Accept: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
Bash:
curl -i -X POST "https://<sub>.<zone>/mcp" -H "Content-Type: application/json" -H "Accept: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
Expect: not
403and noCf-Mitigated: challengeresponse header. Cloudflare Challenge/CAPTCHA pages are returned astext/htmlbefore the request reaches the local daemon; MCP clients cannot solve them and will report the server as unreachable.If this probe is challenged, add or fix a Cloudflare WAF Custom Rule above the challenge rule:
http.host eq "<sub>.<zone>" and ( http.request.uri.path eq "/" or starts_with(http.request.uri.path, "/mcp") or starts_with(http.request.uri.path, "/.well-known/") or http.request.uri.path in {"/authorize" "/token" "/register" "/revoke"} )Action:
Skip. Select the products/phases that are issuing the challenge for this hostname: all remaining custom rules, managed rules, Super Bot Fight Mode, Browser Integrity Check, Security Level, and rate limiting rules as applicable. If legacy Bot Fight Mode is the source, it cannot be skipped; disable it for the zone or use a hostname/zone that does not challenge MCP traffic.Optional: unauthenticated /mcp POST returns 401 with correct WWW-Authenticate.
PowerShell:
curl.exe -i -X POST "https://<sub>.<zone>/mcp" -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
Bash:
curl -i -X POST "https://<sub>.<zone>/mcp" -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
Expect: HTTP 401 with a
WWW-Authenticateresponse header that containsresource_metadata="https://<sub>.<zone>/.well-known/oauth-protected-resource"(host-aware — MUST match the tunnel hostname, NOT 127.0.0.1).Security regression check (H11 holds through the named tunnel).
PowerShell:
$bearer = (Get-Content "$env:USERPROFILE\.perplexity-mcp\daemon.token" | ConvertFrom-Json).bearerToken curl.exe -i -H "Authorization: Bearer $bearer" "https://<sub>.<zone>/daemon/health"
Bash:
curl -i -H "Authorization: Bearer $(jq -r .bearerToken ~/.perplexity-mcp/daemon.token)" "https://<sub>.<zone>/daemon/health"
Expect: HTTP 404, not 200. Even with the correct daemon bearer, tunnel callers must be blocked from all
/daemon/*admin routes. This is the v0.7.4 H11 contract — if the response is 200 OR 401, the H11 hardening regressed under the cf-named provider and this is a release blocker.Port-drift YAML verification (load-bearing — 8.4.2 contract).
PowerShell:
Select-String "service: http" "$env:USERPROFILE\.perplexity-mcp\cloudflared-named.yml"
Expect a line like
service: http://127.0.0.1:<live-port>where<live-port>≠ 1. If it still reads port=1, the port-drift rewrite regressed — release blocker.Stop the daemon (Ctrl-C in the first terminal, or
npx perplexity-user-mcp daemon stopfrom another) before step 7. -
Step 7 — cf-named-list confirms the UUID appears.
PowerShell:
npx perplexity-user-mcp daemon cf-named-list --json
Expect: stdout JSON
tunnelsarray now includes an object withuuid == <uuid>andname == "mcp-smoke-<date>".connectionswill be 0 now that the daemon has stopped. -
Step 8 — CLEANUP. Delete the smoke tunnel + DNS route.
Always run this step, whether the smoke passed or failed midway. A stale tunnel + DNS route costs nothing but clutters your zone and blocks re-running the smoke with the same hostname.
The
cloudflaredbinary that landed in step 1 includes delete/route commands — our CLI doesn't surface delete yet (that's a future enhancement), so drive it directly.PowerShell:
$cf = "$env:USERPROFILE\.perplexity-mcp\bin\cloudflared.exe" & $cf tunnel delete <uuid> # if this fails with "has active connections", ensure daemon is stopped and retry; add --force as last resort # DNS route: cloudflared doesn't have a direct "delete route" for CNAMEs created via `tunnel route dns`. # Delete the `<sub>` CNAME manually in the Cloudflare dashboard: zone -> DNS -> Records -> find <sub>.<zone> -> Delete. Remove-Item "$env:USERPROFILE\.cloudflared\<uuid>.json" -ErrorAction SilentlyContinue Remove-Item "$env:USERPROFILE\.perplexity-mcp\cloudflared-named.yml" -ErrorAction SilentlyContinue npx perplexity-user-mcp daemon set-provider cf-quick # reset active provider so the daemon doesn't try to start a deleted tunnel on next `daemon start`
Bash:
cf=~/.perplexity-mcp/bin/cloudflared "$cf" tunnel delete <uuid> rm -f ~/.cloudflared/<uuid>.json ~/.perplexity-mcp/cloudflared-named.yml npx perplexity-user-mcp daemon set-provider cf-quick
Verify cleanup:
npx perplexity-user-mcp daemon cf-named-list --json
Expect the
<uuid>is gone from the array (if the smoke tunnel was the only one, the array is empty). Also open the Cloudflare dashboard → DNS → confirm<sub>.<zone>is gone; if it lingers, delete it manually.The origin cert at
~/.cloudflared/cert.pemis zone-scoped and is safe to keep for future smokes; delete it only if you want to fully reset the machine's Cloudflare trust.
Release gate for v0.8.1: all 8 boxes checked OR step 8 cleanup executed AND a distinct waiver recorded in docs/smoke-evidence/ + the release commit body stating that external provider smoke was not performed (stronger language than v0.8.0's waiver because the risk is external-API, not code-only).
Referenced by Task 8.4.5 in docs/superpowers/plans/2026-04-22-phase-8-completeness.md.
Phase 8.5 replaces the pre-0.8.2 debugCollector infrastructure (three commands + a dedicated output channel + DashboardState.debug slice) with a single one-click diagnostics bundle: Perplexity.captureDiagnostics. The bundle is a redacted zip with the extension output channel (last 5000 lines via an in-memory ring), daemon log, last 1000 audit lines, inline doctor report, daemon.lock.json (bearer scrubbed), tunnel-settings.json, oauth-clients.json, package-versions.json, and REDACTION_NOTES.md. Automated tests cover the pure-function path (PEM redaction, zip entry count, bearer scrub); this smoke exists because an interactive save dialog + doctor probe + extension output integration can't be exercised hermetically.
Run on Windows 11 (primary) plus macOS 14+ / Ubuntu 22+ as available.
Prereqs:
- Fresh VSIX installed at v0.8.2 or the consolidated 0.8.6 VSIX; reload VS Code window.
- Profile logged in (only needed so the doctor probe produces an auth-positive section — an unauthenticated capture should still succeed with a
warnoverall).
- Command palette entry exists. Command Palette → type
Perplexity: Capture Diagnostics. The entry is present and enabled. - Dashboard button exists. Open the Perplexity dashboard → Home tab → Daemon status card. A Capture diagnostics button sits alongside the existing kill/restart actions. Click it.
- Save dialog defaults correctly. The OS save dialog opens with the default filename
perplexity-mcp-diagnostics-<ISO>.zipunder~/Downloads. ISO timestamp in the filename is readable (no<ip>.278Zregression). - Success toast offers "Show in folder". On save, a VS Code info toast appears with a Show in folder action. Clicking it opens the enclosing directory via the OS file manager (Explorer / Finder / Nautilus).
- Zip contents are correct. Unzip the saved file. Confirm presence of all nine entries: the extension output channel text, daemon log,
audit.log.txt(≤1000 lines),doctor.json,daemon.lock.json,tunnel-settings.json,oauth-clients.json,package-versions.json,REDACTION_NOTES.md. - Bearer is redacted in
daemon.lock.json. Open the zip'sdaemon.lock.json; thebearerTokenfield (if present) is replaced with"<redacted>"— NOT the live token. Cross-check by diffing against the raw~/.perplexity-mcp/daemon.lock.jsonon disk. - PEM blocks are redacted where they appear. If you've run cf-named,
tunnel-settings.jsonmay reference cert material; open the zip's copy and confirm any-----BEGIN CERTIFICATE-----…-----END CERTIFICATE-----block is replaced with a<redacted PEM block>marker (or similar).package-versions.jsonshould be untouched — it's allowlisted. - Legacy debug commands are GONE. Command Palette searches for
Perplexity.debugStartSession,Perplexity.debugStopAndExport,Perplexity.debugExportAllreturn zero results. The Perplexity Debug Trace output channel is no longer listed in the Output dropdown. - Legacy debug setting is GONE. Settings UI search
Perplexity.debugBufferSizereturns zero results (legacy setting removed; the new ring is not user-configurable). - Cancel path releases the spinner. Click the dashboard button, then cancel the save dialog. The dashboard's pending-action spinner clears (the daemon card returns to its normal idle state). No stuck busy state on any subsequent action click.
- Bundle produces no secret leaks. Run the no-secret-leak gate against a captured bundle: unzip, concatenate all text entries, and grep for the current daemon bearer. Expected: zero matches.
Expect: no output (no matches).
$bearer = (Get-Content "$env:USERPROFILE\.perplexity-mcp\daemon.token" -Raw | ConvertFrom-Json).bearerToken # Extract and concatenate zip entries — use Expand-Archive then Get-Content -Raw * Expand-Archive -Path "<saved-zip>" -DestinationPath "$env:TEMP\pplx-smoke-unzip" -Force Get-Content "$env:TEMP\pplx-smoke-unzip\*" -Raw | Select-String -SimpleMatch $bearer
Release gate for Phase 8.5: all 10 boxes checked. This phase's surface is largely pure-function tested, so the smoke is primarily about confirming the command/button wiring and the interactive save dialog/doctor pipeline.
Phase 8.6 introduces a per-IDE MCP transport picker in the dashboard (radio group inside each auto-configurable IdeCard) with four options: stdio-in-process, stdio-daemon-proxy (default), http-loopback, http-tunnel. v0.8.3 shipped the UI + dispatcher; v0.8.4 hotfixed the wire between them (http-loopback static-bearer variant, capability-matrix httpBearerLoopback=true for every auto-configurable JSON IDE, transport:select handler, staleness detector, surfaced error modals, cf-named WAF banner). H3–H8 security prechecks (sanitized .bak, sync-folder detection, port-pin nudge, stability gates for http-tunnel, audit on every exit path) must hold across both.
Run on Windows 11 (primary) plus macOS 14+ / Ubuntu 22+ as available.
Prereqs:
- Fresh VSIX installed at v0.8.4 or the consolidated 0.8.6 VSIX; reload VS Code window.
- Profile logged in.
- At least two auto-configurable IDEs available (e.g. Cursor + Claude Desktop) so the picker's "per-IDE" nature is exercisable.
- For step 5 (sync-folder gate): a synced directory (OneDrive / Dropbox / iCloud) with a dummy IDE config you can point
Perplexity.syncFolderPatternsat OR a real IDE whose mcp.json happens to live under a sync folder.
- Picker renders for every IDE. Open the dashboard → IDEs tab. Each auto-configurable IdeCard shows a 4-radio
TransportPickerlabelled stdio-in-process / stdio-daemon-proxy / http-loopback / http-tunnel. Unsupported options render disabled with an inline reason hint. Default selection isstdio-daemon-proxy. - http-loopback radios are ENABLED (not greyed) for cursor, claudeDesktop, claudeCode, cline, windsurf, windsurfNext, amp, rooCode, continueDev, zed. This is the v0.8.4 capability-matrix flip.
- http-tunnel radios are DISABLED for every IDE (no
httpOAuthTunnelevidence yet) with an inline reason tooltip pointing at the missing capability. - Pick http-loopback for one IDE → generate → config shape is correct. Select http-loopback for, e.g., Cursor. Click Generate. Confirm
~/.cursor/mcp.jsonnow contains:The{ "Perplexity": { "url": "http://127.0.0.1:<live-port>/mcp", "headers": { "Authorization": "Bearer <daemon-static-bearer>" } } }<live-port>matches the current daemon lockfile port and<daemon-static-bearer>matches~/.perplexity-mcp/daemon.token'sbearerTokenbyte-for-byte. - Picker persists across reload. Reload the VS Code window. Re-open dashboard → IDEs tab → the previously-picked
http-loopbackfor Cursor is still selected (not reset to default). This provesPerplexity.mcpTransportByIdewas written. - H4 sync-folder gate fires. Configure
Perplexity.syncFolderPatternsto match the path of a target IDE's mcp.json (or pick an IDE whose config legitimately lives under OneDrive/Dropbox). Pick http-loopback → Generate. A VS Code warning modal appears with default-deny wording ("This will write a daemon bearer to a file under a sync folder…"). Cancel → no write occurs. Accept → write proceeds;.bakof the prior content is sanitized (no bearer substring). - H3 sanitized
.bakon rewrite. Pre-populate a target IDE's mcp.json with abearerTokenorAuthorization: Bearer pplx_...field. Run http-loopback Generate again (second time). Open the resulting<configPath>.bak— the bearer value is replaced with<redacted>(not the live token). On success, the.bakis deleted. Check tempfile POSIX / ACL: during the write window the tempfile has 0600 (Unix) or restricted ACLs (Windows icacls), never world-readable. - H8 audit on every exit. After the preceding three items, tail
~/.perplexity-mcp/audit.logand confirm at least oneapplyIdeConfigentry per attempted outcome:ok,rejected-sync(if you cancelled the sync-folder modal),rejected-cancelled(if you cancelled the confirm modal).configPathis home-redacted (~/..., not the absolute path). - Stale-config banner appears after daemon restart. With at least one IDE configured http-loopback, click Restart daemon in the dashboard. On new port landing, the IDEs tab top-of-list shows a
"N config(s) contain(s) stale auth"banner with a Regenerate all button. Per-IDEStalechip appears on the affected IdeCard header. - v0.8.4 picker hotfix:
mcpTransportByIdepersistence works. Before the hotfix this was{}no matter what you picked. After a pick + reload,vscode.workspace.getConfiguration('Perplexity').get('mcpTransportByIde')returns a populated object. Verify via aPerplexity.captureDiagnosticszip → check the output-channel text for[staleness]traces or atransport:selecthandler entry; OR open the VS Code settings.json for the workspace/user and confirmPerplexity.mcpTransportByIdehas the entry. - Regenerate all from banner works. Click Regenerate all in the stale-config banner. A single confirm modal appears (because the banner is a refresh of an already-approved
(IDE, transport)pair, not a first-time write, per 0.8.5's auto-regen policy; if v0.8.3/0.8.4-only is installed, expect a modal per IDE). Each affected IDE's mcp.json is rewritten with the new port/bearer; banner clears on success. Audit lines carry the sameokshape as a manual generate. - Surfaced error modal on failure. Induce a failure: pick http-tunnel for an IDE whose capability allows it (none ship this way — skip if no IDE has httpOAuthTunnel=true), OR set
Perplexity.daemonPortto a port you've intentionally blocked, then Generate. A VS Code error modal appears with a reason-specific message + an Open Output action that reveals the Perplexity output channel. Expected reasons observed by the modal string:unsupported,sync-folder,tunnel-unstable,port-unavailable,cancelled,error.
Release gate for Phase 8.6: all 11 boxes checked. The v0.8.4 hotfix was itself driven by a smoke that found mcpTransportByIde: {}, so the persistence check is the load-bearing one; everything else verifies the security prechecks (H3/H4/H8) hold through both the 0.8.3 UI and the 0.8.4 wire.
Phase 8.7 — Loopback-default + perf dashboard + tunnel-switch confirm + auto-regen + cf-named WAF banner (0.8.5)
Phase 8.7 covers the five UX shifts v0.8.4's smoke surfaced: (1) loopback-default mode with tunnels opt-in, (2) tunnel performance dashboard, (3) tunnel-switch confirmation modal + post-switch staleness refresh, (4) auto-regenerate stale MCP configs on port/tunnel change, (5) cf-named WAF warning banner. The first makes the extension usable out-of-the-box without touching a tunnel; the others prevent the "tunnel switched, my IDE still points at the old URL, I got silent 401s for an hour" class of footgun.
Run on Windows 11 (primary) plus macOS 14+ / Ubuntu 22+ as available.
Prereqs:
- Fresh VSIX installed at v0.8.5 or the consolidated 0.8.6 VSIX; reload VS Code window.
- For step 2 (tunnel opt-in flow): ability to enable at least one tunnel provider (cf-quick requires no auth; ngrok requires authtoken; cf-named requires cert + zone). cf-quick is recommended for this smoke because it needs no prereqs.
- For step 6 (cf-named WAF banner): a cf-named provider already set up with
activeProvider === "cf-named"ANDtunnel.status === "enabled". If not available, mark this item "waived — no cf-named tunnel in the smoke environment" and rely on the automated 7 banner-component tests for coverage. - For step 1 (fresh install default): a machine WITHOUT
<configDir>/tunnel-settings.json(i.e. no prior Perplexity MCP install), OR delete the file + theglobalState.perplexity.enableTunnels.migratedflag before the smoke.
- Loopback-default on fresh install. On a machine with no prior
tunnel-settings.json, install 0.8.5+ and reload. Open the dashboard → Home tab. The TunnelManager card is collapsed to a singleRemoteAccessOptIncard ("Enable tunnel options" button).http-tunnelis NOT a selectable radio in any IdeCard's TransportPicker (it's removed, not just disabled). Run Generate for any IDE and confirm the default transport in its mcp.json is stdio-daemon-proxy OR http-loopback with the static bearer (never http-tunnel).Perplexity.enableTunnelsreadsfalsevia settings JSON inspection. - Upgrader migration preserves tunnel UI. On a machine with a pre-existing
<configDir>/tunnel-settings.jsoncontaining a non-emptyactiveProvider, install 0.8.5+ and reload. Open the dashboard → the full TunnelManager UI appears (not the opt-in card).Perplexity.enableTunnelsreadstrueafter activation. TheglobalState.perplexity.enableTunnels.migratedflag is set so the auto-migration is one-shot (re-installing doesn't run it again). - Tunnel opt-in flow. From the loopback-default state (item 1), click Enable tunnel options on the opt-in card.
Perplexity.enableTunnelsflips totrue; the full TunnelManager card replaces the opt-in card;http-tunnelradio returns to every IdeCard's TransportPicker (gated by the per-IDE capability, still disabled for most IDEs). At the bottom of TunnelManager a Disable tunnel options link is visible. - Tunnel opt-out confirm tears down active tunnel. With a tunnel enabled and a provider selected, click the Disable tunnel options link. A VS Code modal fires. Accept → the tunnel is disabled atomically (the tunnel URL card clears) BEFORE
enableTunnelsflips tofalse. After the flip: dashboard shows the opt-in card again;http-tunnelis removed from pickers. Cancel path: modal dismissed, no changes. - Perf dashboard: enable durations per provider. With tunnels enabled, enable + disable cf-quick (or any provider) three times. Expand the TunnelManager's TunnelPerformance section. The Last enable durations row shows a wall-clock ms value for that provider (cf-quick typically ~5.5s, cf-named ~1.5s, ngrok ~2s per the CHANGELOG). Switch to a second provider and enable → its own row populates. Values reset on VS Code reload (session-local ring buffer).
- Perf dashboard: rolling health-check latency. With a daemon running for >1 minute (enough to accrue ≥10
/daemon/healthaudit entries), the Average health-check latency row shows a single ms number. Reload the audit log — the value recomputes from the audit tail (last 10 entries). - Perf dashboard: MCP status ratios by source. Trigger at least one
/mcptool call from a loopback-configured IDE AND, if a tunnel is enabled, one from a tunnel-configured IDE. Expand the MCP /mcp status ratios row. Two sub-rows appear (loopback+tunnel) withok / unauthorized / serverError / othercounts totaling over the last 200 audit entries. - High-401 warning fires when tunnel unauthorized ratio >10%. This is hard to induce manually; if you can trigger ≥20 unauthenticated POSTs to
/mcpthrough the tunnel (e.g. viacurl.exewithout a bearer), the perf dashboard emits a yellow High tunnel 401 ratio warning row below the stats. Skip if not easily inducible and rely on the automated component tests; mark this item "waived — covered by tunnel-performance component tests". - Tunnel-switch confirm modal. With provider A active and tunnel enabled, switch to provider B in the TunnelManager. A VS Code warning modal appears naming both providers and explaining: (i) current tunnel will disconnect, (ii) MCP clients connected via the current URL will drop, (iii) IDEs configured http-tunnel will need regenerating. The text explicitly states "http-loopback and stdio IDEs are unaffected." Cancel → no provider change. Accept → provider flips, old tunnel tears down, new tunnel spins up.
- Tunnel-switch is idempotent. Re-select the currently-active provider in the TunnelManager. No modal appears (idempotent no-op). Dashboard state unchanged.
- Post-switch staleness refresh. After accepting a provider switch (item 9), within a second or two the IDEs tab's stale-config banner updates to reflect the new tunnel URL. Any IDE previously configured
http-tunnelnow shows aStalechip. ProvespostStalenessfires immediately after the switch per the CHANGELOG'spostDaemonState → postStaleness → auto-regen → postTunnelPerformancechain. - Auto-regen on daemon restart (default setting). Confirm
Perplexity.autoRegenerateStaleConfigsdefaults totruein the settings UI. With at least one IDE configured http-loopback, click Restart daemon. Wait for the new lockfile. Check~/.cursor/mcp.json(or equivalent): theurlnow reflects the new port; theAuthorizationheader still carries the current daemon bearer. No modal fires (refresh of an already-approved(IDE, transport)pair). Audit log shows anapplyIdeConfigentry withauto=truetag. - Auto-regen on tunnel-URL rotation. With at least one IDE configured
http-tunnel(requires an httpOAuthTunnel-enabled IDE — skip if none available in the smoke environment), disable + re-enable the tunnel so a new URL is minted. Expected: the IDE's mcp.jsonurlis auto-updated to the new tunnel URL without a modal. Auditauto=true. - H4 sync-folder gate STILL fires under auto-regen. Configure an IDE whose mcp.json lives under a sync folder (per 8.6 item 5) with http-loopback. Restart daemon. Expected: the default-deny modal still appears (H4 is preserved even during the silent refresh). Without it, the auto-regen would silently write bearer material to OneDrive — the CHANGELOG explicitly calls this out.
- Auto-regen disabled via setting. Flip
Perplexity.autoRegenerateStaleConfigstofalsein settings. Restart daemon. Expected: no auto-regen occurs; the stale-config banner appears instead (the user must click Regenerate all manually). Audit shows noauto=trueentries. - cf-named WAF warning banner — manual swap if no cf-named available. If the smoke environment has a cf-named provider enabled, open the dashboard → the TunnelManager card shows a Cloudflare WAF warning banner with: (i) the tunnel URL inline, (ii) an inline
Path = "/mcp"WAF-skip-rule recipe, (iii) a link tohttps://developers.cloudflare.com/waf/custom-rules/skip/. The banner is not dismissable (Zone config is one-time). If cf-named is NOT available, mark this item "waived — no cf-named environment; covered by 7 banner-component tests (v0.8.4)". - Observability traces land in output channel. Open the Perplexity MCP output channel. After a daemon restart or tunnel switch, two traces appear per staleness cycle:
Grepping the output channel proves the pipeline ran and what it found.
[staleness] checking <N> ides against daemonPort=<P> tunnelUrl=<U> [staleness] posted <N> stale config(s): <tag>(<reason>), ...
Release gate for Phase 8.7: all 16 boxes checked OR explicitly waived per-item rationale. Items 8 (high-401 warning) and 15 (cf-named WAF banner) are the likeliest to be waived because both require environment setup beyond the default smoke scope; waivers for either cite the automated component tests that cover them.
Phase 8.8 is the release-hardening patch that backs v0.8.6: it addresses the consolidated-smoke findings against 0.8.2–0.8.5 and closes the gap left by four untested releases. The surface is small (atomic auto-config rules-file writes, stale-lockfile reclaim, VSIX express-4.x invariant) but each item closes a real foot-gun that only shows up on long-running or crash-recovery scenarios.
Run on Windows 11 (primary) plus macOS 14+ / Ubuntu 22+ as available.
Prereqs:
- Fresh VSIX packaged at v0.8.6 installed; reload VS Code window.
- For step 3 (stale lockfile reclaim): ability to
SIGKILL/ end-task a running daemon process so it can't run its own shutdown path (Task Manager → End Task, orkill -9 <pid>). - For step 4 (express-4.x invariant): ability to inspect the packed VSIX. On Windows, 7-Zip or VS Code's built-in VSIX-explorer extension work; on macOS/Linux,
unzipis enough.
- Atomic auto-config rules-file write — marker integrity. In
~/.claude/CLAUDE.md(or any target that uses md-section upsert), manually reverse the marker pair: renamePERPLEXITY-MCP-START→PERPLEXITY-MCP-ENDandPERPLEXITY-MCP-END→PERPLEXITY-MCP-START, so the end marker now appears before the start marker. Leave the interior content alone. Run Perplexity: Generate MCP Configs → select this target.- Pre-0.8.6 behavior (regression): the upsert could not find a valid marker pair, so it either ate the interior content OR wrote a second marker pair leaving the reversed ones orphaned. File content outside the markers was at risk.
- Post-0.8.6 expected: the extension detects the reversed markers as "no valid block present", appends a fresh block with correct markers at EOF, and preserves every byte outside the (broken) markers. The reversed markers remain in place verbatim (the extension doesn't touch them). Diffing the file pre/post-generate shows additions only — zero deletions to the pre-existing content.
- Evidence: paste the pre/post file diff into the evidence file (or a
git diffif the file is tracked).
- Stale lockfile reclaim on restart after SIGKILL. Start the daemon (via dashboard or
npx perplexity-user-mcp daemon start). Find its PID from~/.perplexity-mcp/daemon.lock.json.SIGKILLit (Windows:taskkill /F /PID <pid>; Unix:kill -9 <pid>).daemon.lock.jsonremains on disk stale (the process couldn't run its own shutdown cleanup).- Click Start daemon in the dashboard (or run
npx perplexity-user-mcp daemon start). Expected: the new daemon detects the stale lock (PID no longer alive), reclaims and overwrites it with its own PID + port + bearer, and starts cleanly. No "another daemon is already running" error. Lockfile'spidfield now matches the new process. - Evidence: paste pre-kill lockfile JSON, kill command output, post-start lockfile JSON.
- Click Start daemon in the dashboard (or run
- VSIX ships express 4.x. Unpack the packaged VSIX (
packages/extension/perplexity-vscode-0.8.6.vsix) and inspectextension/dist/node_modules/express/package.json. The"version"field must start with"4.". Express 5.x introduces behavior changes (async router, promise-based middleware signatures) that would break the daemon's OAuth routes silently.- PowerShell:
Bash:Expand-Archive -Path "packages\extension\perplexity-vscode-0.8.6.vsix" -DestinationPath "$env:TEMP\pplx-vsix-unpack" -Force (Get-Content "$env:TEMP\pplx-vsix-unpack\extension\dist\node_modules\express\package.json" -Raw | ConvertFrom-Json).version
Expect: a string starting withunzip -p packages/extension/perplexity-vscode-0.8.6.vsix \ extension/dist/node_modules/express/package.json | jq -r .version4.(e.g.4.21.2). Any5.x= release blocker — revert the offending dependency upgrade and re-pack. - Daemon shutdown under onShutdown failure — SKIPPED in manual smoke. This is an internal-only path (an
onShutdownhook throws; the daemon must still exit cleanly without hanging the process). Fully covered bypackages/mcp-server/test/daemon/unit tests. Mark this item "skipped — test-only" in the evidence file; do not attempt to manually induce anonShutdownthrow.
Release gate for Phase 8.8: items 1, 2, 3 checked; item 4 marked skipped — test-only. Item 3 (express 4.x) is automatable in CI; if CI is green on the packaged VSIX, item 3 can be recorded as verified-ci with the CI job link.
Releases 0.8.2, 0.8.3, 0.8.4, and 0.8.5 all deferred their manual smoke per the execution strategy docs/superpowers/specs/2026-04-24-phase-8-completion-execution-design.md. 0.8.6 closes that loop: do not tag v0.8.6 until a single consolidated smoke pass covering Phases 8.5 → 8.8 is recorded on Windows 11, macOS 14+, and Ubuntu 22+ (or each uncovered OS is explicitly waived in the release commit message with reason).
The three evidence skeletons for this consolidated smoke live at:
- docs/smoke-evidence/2026-04-XX-v0.8.6-win11.md (rename
XXto the day of smoke execution) - docs/smoke-evidence/2026-04-XX-v0.8.6-macos14.md
- docs/smoke-evidence/2026-04-XX-v0.8.6-ubuntu22.md
Each skeleton carries the full checklist from Phase 8.5 through Phase 8.8 (this document's last four sections), ready for the tester to tick off. Per the release process in docs/release-process.md: one fully-green platform + two waived platforms is acceptable if the waived platforms document a distinct reason (hardware unavailability, not "no time").
Release gate for closure of #3: at least one Win11 + external-IDE row PASS recorded below before the PR is marked ready-for-review and the issue is closed.
| Date | Platform | IDE / external client | Daemon spawn telemetry | perplexity_reason result |
Status |
|---|---|---|---|---|---|
| 2026-05-10 | Windows 11 Pro 26200, VS Code 1.119.0 (Node 22.22.1 internal) | VS Code dashboard (extension host) | [daemon] PERPLEXITY_VAULT_PASSPHRASE: unset (keytar happy-path) |
Doctor: vault: pass (unseal-path: OS keychain holds master key, unseal-verify: vault.enc decrypts cleanly); models refresh succeeded accountTier=Enterprise |
PASS |
| 2026-05-10 | Windows 11 Pro 26200, Windsurf (VS Code 1.110.1-next, Node 22.22.0) running Claude Code as MCP host | Claude Code (this maintainer's session) routed through the bundled stdio-daemon-proxy |
[daemon] PERPLEXITY_VAULT_PASSPHRASE: set (SecretStorage-passphrase fallback path — Windsurf's runtime triggered the env-var route) |
perplexity_reason "...current open question in cosmology..." returned a substantive Pro reply with 15 citations. Daemon pid=28768 port=10368 version=0.8.41; live MCP roundtrip confirmed. |
PASS |
The 0.8.41 fix ships and works on both unseal paths in production:
- Keychain path (
unset): keytar in the daemon's runtime loaded successfully; the daemon read thevault-master-keydirectly from Windows Credential Manager. No env-var injection needed. (Common case for Win11 + native VS Code.) - Passphrase path (
set): keytar in this runtime did not fully work; SecretStorage had a passphrase from a prior login;buildDaemonEnv(context)injected it into the daemon's spawn env; the daemon decrypted via the passphrase-derived key. (This was the path that was previously broken — the daemon never received the passphrase before 0.8.41.)
The Windsurf row is the definitive evidence for closing issue #3 because Windsurf is exactly the class of "external-IDE-with-Node-runtime-that-may-mismatch-keytar-ABI" that the issue reporter hit. The MCP client (Claude Code) sitting inside Windsurf successfully invoked an authenticated Pro tool end-to-end.
- Linux + headless-no-libsecret (Codex CLI path) — same code path covered by the
setrow above; deferred until a clean Linux box is available. - macOS — covered by the existing 0.8.x release-gate matrix; no behavior change in 0.8.41 specific to macOS.
- Cross-IDE soak — Antigravity, Cursor outside VS Code, Codex CLI — pending; will be folded into the 0.8.42 / 0.8.43 smoke checklists as those releases ship.