mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-07 05:56:41 +02:00
17b556f309
Browser-skill spawns hit `403: Tab not owned by your agent` on every first run because the gate at server.ts:639 fired for any non-root write, regardless of the token's tabPolicy. The bundled hackernews-frontpage reference skill failed identically. Every /skillify-generated skill failed identically. The user's natural tabs have no claimed owner — by design — so any skill driving them via `goto` (a write) was 403'd. The intent in skill-token.ts:79 was always correct: `tabPolicy: 'shared'` with the comment "skill scripts may switch tabs as needed." The enforcement just ignored it. Two surgical changes: browser-manager.ts:checkTabAccess — gate now keys on options.ownOnly only. Shared-policy tokens (skill spawns, default scoped clients) get permissive access — root-equivalent for the tab gate. Own-only tokens (pair-agent over the ngrok tunnel) still require ownership for every read and write. isWrite stays in the signature for callers that want to log or branch elsewhere; it no longer gates the decision. server.ts:639 — gate predicate narrowed from (WRITE_COMMANDS.has(command) || tokenInfo.tabPolicy === 'own-only') to just tokenInfo.tabPolicy === 'own-only' The 'newtab' exemption stays. Shared tokens skip the gate entirely; own-only tokens still hit it. Comment block above the gate updated to document the new predicate intent. Pair-agent isolation is intact. Tunnel tokens still default to tabPolicy: 'own-only', still must `newtab` first to get a tab they can drive, still can't dispatch any of the 23 commands outside the tunnel allowlist. The capability gate (scope checks) and rate limits already constrain what local scoped clients can do; tab ownership was never a security boundary for them — only for pair-agent. This release makes the enforcement match the original design intent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>