Repository navigation
feat: vs code extension for local agents support - #2911
maxy-shpfy wants to merge 1 commit into
Conversation
🎩 PreviewA preview build has been created at: |
6959d8d to
5e8dcc4
Compare
188e38a to
9753547
Compare
camielvs
left a comment
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
Adds a standalone VS Code/Cursor extension (vscode-extension/, its own pnpm workspace) plus a Vite plugin that builds and serves it under /extension/*, and bumps the app's @tangent/* deps to a newer tangent-shell commit. The extension code is unusually clean: REST responses are zod-validated, the webview uses a nonce CSP with escaped/inert config injection, openExternal is restricted to http(s), and webview messages are schema-checked. The main risk is the vscode://…/connect deep link, which connectFromLink honours without confirmation and by reusing the saved token — contradicting the README and letting a web page silently re-point an installed editor at an attacker Shell that can drive local file-editing/terminal sub-agents (flagged high). Secondary concerns: the self-update path installs a VSIX from a possibly cross-origin, unverified URL, and the app build now hard-depends on building the extension (network/GitHub). I could not run the extension's build/typecheck/tests or the app toolchain here (static review only), could not clone tangent-shell-shopify, oasis-backend, or oasis-frontend (no access), treated the two pnpm-lock.yaml files and icon.png as non-reviewed, and reviewed the @tangent/* host packages only as dependency contracts since they belong to tangent-shell.
camielvs
left a comment
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
14 findings: 2 high (the deep link can point the editor at any Shell/API URL without asking; a failed extension build stalls the web app's dev server), 5 medium, 7 low. Details are inline.
camielvs
left a comment
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
This PR adds a standalone VS Code/Cursor extension (its own pnpm workspace) that registers the editor as a Tangent remote environment hosting local pi sub-agents, plus a Vite plugin that builds and serves the .vsix and install scripts under /extension/*. The code is generally high quality — zod-validated REST, nonce-CSP webview, origin-checked loopback proxy, meaningful node:test coverage of the pure logic — but the vscode://…/connect deep-link handler is the main risk: it applies a link-supplied Shell URL (reusing the saved token, no confirmation) and apiUrl/project without consent, which can silently repoint an installed editor at an attacker Shell (local sub-agents edit files/run the terminal → effective RCE) and leak the saved Tangle API token; the README even states the opposite. Lower-severity items: the self-updater installs a cross-origin unverified .vsix, the app build now hard-depends on building the extension (network/GitHub), one client uses an unchecked as T, and the shared @tangent/* deps are bumped app-wide (verified additive). I could not run node/tsc/eslint/vitest or the Vite/Docker build in this sandbox so all findings are from static reading, and I could not clone the Shopify-specific siblings (oasis-backend, oasis-frontend, tangent-shell-shopify) for cross-repo context, though I did diff the consumed @tangent/* packages between the old and new tangent-shell commits.
3547cd4 to
6e09cc4
Compare
camielvs
left a comment
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
This is a review pass over the whole extension. I cross-checked against @tangent/local-agent-host at b0c6ac5 and ran the extension's typecheck / lint / test / package locally; all four pass.
High: a race in controller.ts can bring back a hidden /remote-env bridge after a project switch or a Disconnect. And the chat proxy's SSO cookie never refreshes.
Medium: proxy DNS rebinding; the deep-link check compares host, not origin; background SSO refresh opens browser tabs; the Vite plugin blocks dev/E2E start; the root lockfile reverts master's bumps; no CI for the extension; vendor-specific naming; remote pipeline links.
A few lower-severity nits are inline as well.
Not raised inline: when the SSO gate is off, the Shell trusts an unsigned JWT for whatever tangent.userEmail says. The PR flags that as an MVP limit. But production vite build now serves the .vsix from /extension/, so it's worth confirming that no deployed Shell runs without the gate.
| * place of JSON) we refresh the cookie once and retry — the first attempt with | ||
| * no cached token is what opens the browser flow. | ||
| */ | ||
| export function cookieAwareMint( |
There was a problem hiding this comment.
🤖 This is an AI-generated code review comment.
Nit: this duplicates upstream code, and the copy has already drifted.
This re-implements mintRemoteEnvToken from @tangent/local-agent-host/remoteEnvToken.ts (the path constant, request body, unsigned-JWT header, isRecord, isResponseBody, the expiry parsing) only to add a Cookie header. The copy has already lost upstream's checks that token and environmentId are non-empty. Likewise, EarlyMessageBuffer works around a race inside LocalAgentBridge.onMessage, where messages are dropped while onSpawn waits before it builds the PiAgent. The same team owns both packages, so both fixes belong upstream. That's about 280 lines plus tests here.
There are also local copies: isRecord appears three times (here, controller.ts:62, chatConfig.ts:54), shellSocketConfig (controller.ts:53) matches the socket half of embedEndpoints, and the "attach cookie, retry once on 401" logic exists in TangentClient, TangleRestClient, and here.
Fix: upstream, add a headers (or fetch) option to mintRemoteEnvToken and queue messages on HostedAgent until its PiAgent exists. Locally, extract one fetchWithSsoRetry helper and one shared isRecord.
There was a problem hiding this comment.
🤖 This is an AI-facilitated answer
Deferred: the clean fix (a headers/fetch option on mintRemoteEnvToken plus upstream message queueing) belongs in @tangent/local-agent-host, not this repo.
6e09cc4 to
e2d47f8
Compare
Description
Adds a standalone VS Code / Cursor extension (
vscode-extension/) — Tangent Local Agent — that connects an editor to a Tangent Shell in both directions:/remote-envnamespace, sospawn_subagentwithenvironment: "remote"runs a localpi --mode rpcprocess in the open workspace folder and streams replies back.The web app also serves the extension:
vite.config.jsexposes/extension/*endpoints (install scripts,latest.jsonmanifest,.vsixdownload). The extension is its own pnpm workspace with its own lockfile; the root typecheck and knip skip it.Related Issue and Pull requests
Bottom of the stack:
Type of Change
Line Breakdown
Checklist
Test Instructions
cd vscode-extension && pnpm install && pnpm build.vscode-extensionin VS Code and press F5 (Run Tangent Local Agent).spawn_subagentwithenvironment: "remote"runs a local sub-agent in the open folder.curl -fsSL <app-origin>/extension/install.sh | sh -s -- <app-origin>.Additional Comments
MVP: authenticates as a dev identity (an unsigned JWT for
tangent.userEmail), or through the SSO gate when it is enabled, and is distributed as a.vsixfrom the deployment rather than a marketplace; it self-updates once installed.This PR also bumps the web app's own
@tangent/embed-react,@tangent/remote-subagent, and@tangent/sharedpins (and thepnpm.overridesfor@tangent/shared) to the same tangent-shell commit the extension uses. The surface change is additive. Before merge,pnpm-lock.yamlwill be regenerated from currentmaster(git checkout origin/master -- pnpm-lock.yaml && pnpm install --lockfile-only) so the diff touches only the@tangent/*entries, and the embedded chat / remote-subagent paths will be smoke-tested.Stack created with GitHub Stacks CLI • Give Feedback 💬