You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Addresses the review findings introduced by this PR's commits (browser
handoff + top-level nav / sidebar tile). PR #1099 fixes landed
separately.
- `runHandoffWithOpener` now wraps preflight (`getCredentials`) AND the
post-listener async IIFE in one try/catch that converts every error to
a `HandoffResult`. Previously a malformed credentials file rejected the
returned Promise with no toast, and a throw inside the lazy
`import("../plugin/altimate")` left the caller waiting the full 15
minutes with no reason surfaced. The port is captured into a local
immediately after `startListener` resolves so a timeout-cleared handle
can't be dereferenced later. (M4)
- `HandoffSuccess` now carries a `credentials` fingerprint (apiUrl +
tenant) that the handoff was validated against. `runBrowserHandoff` in
both entry points re-reads `AltimateApi.getCredentials()` immediately
before `bindExisting` and refuses if either field drifted — workspace
ids are tenant-schema-local so a mid-flow account switch would
otherwise bind under the wrong tenant. (M6)
- `resolveWorkspaceWebUrl` guards the tenant with a DNS-label regex and
reconstructs the origin from the parsed URL, so a credential row
carrying `evil.example/path?x=` cannot open the handoff at
`https://evil.example`. Override still available for local dev; both
paths reject non-http(s) protocols. (m3)
- Optional `AbortSignal` on `OpenBrowserHandoffInput` — a caller-fired
abort tears down the listener immediately with `reason: "aborted"`
instead of holding the port for 15 minutes; timeout is `.unref()`'d so
it doesn't keep the CLI process alive on its own. (m2)
- `port_exhausted` is now only returned when the errno is `EADDRINUSE`
— other codes (EACCES, EBADF) map to `reason: "error"` so the user
isn't told "ports all in use" for a permissions problem. (m5)
- `project_path` + `project_remote` moved to the URL fragment, matching
the `cli_context` rationale — those two values carry usernames /
customer names / internal paths that shouldn't land in SaaS access
logs, WAF logs, or browser history. `project_name` stays in the query
because the SaaS approval modal renders it. Test updated. (m6)
- `workspace_id` uses `Number.isInteger` instead of `Number.isFinite`,
so `42.5` no longer reaches a backend expecting an integer. (m9)
- Inline `<script>` blocks now escape `</script` in JSON.stringify'd
values via a `<\/script` replacement, closing the theoretical inline-
script-break vector. (N5.b)
- Local binding cache: one-shot migration to canonical keys on the
first `readLocalBinding` that finds a non-canonical key, followed by
a plain property lookup for every subsequent read. Deletes the O(n)
`realpathSync` rescan that ran on every cache miss under the 3s
sidebar poll. (N1)
- Sidebar tile polls at 30s instead of 3s, memoizes the manage-URL
base per (apiUrl, tenant), and guards against overlapping refreshes.
Copy updated from "run /link" (the slash command doesn't exist —
N2) to "run altimate-code link" (the actual CLI subcommand).
Interval timer `.unref()`'d.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016H42Vt4pt5dcD7opRqckeM
? `Every port in ${CALLBACK_PORT_MIN}-${CALLBACK_PORT_MAX} is in use (tried ${tried.join(", ")}). Close what's using them (e.g. \`lsof -i :${CALLBACK_PORT_MIN}\`) and try again.`
259
318
: `Could not start the workspace-handoff server: ${lastErrinstanceofError ? lastErr.message : String(lastErr)}`,
260
319
),
261
-
"port_exhausted",
320
+
code==="EADDRINUSE" ? "port_exhausted" : "error",
262
321
)
263
322
}
264
323
265
324
exportinterfaceOpenBrowserHandoffInput{
266
325
identifier: ProjectIdentifier
267
326
projectName: string
327
+
/** Optional AbortSignal — if it fires the flow settles with
328
+
* ``{ok: false, reason: "aborted"}`` and tears down the listener. Lets a
329
+
* TUI supersede a stale handoff without leaking a port for the full
330
+
* 15-minute window. (m2) */
331
+
signal?: AbortSignal
268
332
}
269
333
270
334
/** Full browser-handoff flow. Returns the created/picked workspace ID on
@@ -283,12 +347,28 @@ export async function runHandoffWithOpener(
0 commit comments