Files
openchamber/plans/opencode-v1.17.12-sdk/implementation/phase-5-impl.md
T
Leonidandbashrusakh 01a52eccab SDK v1.17.12: session.permission — programmatic create/fetch, more reliable auto-accept (#1982)
* docs: add SDK v1.17.12 migration plan — phase 4 (session.permission)

* feat(permissions): verify pending permission before auto-accept via SDK v1.17.12

Adds createPermission() and fetchPermission() wrappers on OpencodeService
for the new v2.session.permission endpoints (OpenCode SDK 1.17.12).

fetchPermission() is used by the auto-accept sweep in
resyncBlockingRequestsForDirectory to verify a permission is still
pending before replying. The auto-accept flow now skips permissions
that are already resolved, returning a null from fetchPermission()
rather than blindly calling respondToPermission on a stale entry.

createPermission() is exposed for future programmatic permission
creation; the V1 list/reply path used by the UI is unchanged.

The plan doc at plans/opencode-v1.17.12-sdk/ was rebased onto
origin/main in the prior commit to keep the PR diff focused on
this change.

Closes #1972

* fix(permissions): drop confirmed-resolved permissions from auto-accept resync

fetchPermission() now returns a tagged FetchPermissionResult so the
auto-accept loop can distinguish a server-confirmed 404 (the
permission is no longer pending) from a fetch failure (network error
or pre-v1.17.12 server). Previously both cases collapsed to null, so
a permission the server had already answered would still appear in
the resync output and trigger a spurious 'Permission needed' toast.

The auto-accept loop in resyncBlockingRequestsForDirectory now tracks
both accepted and resolved permissions, then drops both from the
'grouped' map before it falls through to the toast path. On a
pre-v1.17.12 server (no V2 endpoint) the call still returns
'unknown' and the permission stays in the resync output so the user
can answer manually — fail-closed, no false-resolved signals.

Adds a focused unit test for fetchPermission (4 cases: 200 ok, 404
resolved, 500 unknown, network throw) mocking the V2 SDK client
shape.

---------

Co-authored-by: bashrusakh <bashrusakh@users.noreply.github.com>
2026-07-11 16:11:13 +03:00

2.4 KiB

Phase 4 Implementation: session.permission — Programmatic Endpoints

Prerequisite

Verify session.permission.create and session.permission.fetch exist in SDK v1.17.12 types. Check node_modules/@opencode-ai/sdk/dist/v2/gen/sdk.gen.d.ts for Permission2 class (referenced by Session3 at line 1672).

If absent, skip this phase.

Step 1: Add wrappers to client.ts

File: packages/ui/src/lib/opencode/client.ts

Add after replyToPermission() (line 1108):

async createPermission(
  sessionID: string,
  permission: string,
  options?: { message?: string; directory?: string | null }
): Promise<PermissionRequest | null> {
  const requestDirectory = this.normalizeCandidatePath(options?.directory ?? null) ?? this.currentDirectory;
  const response = await this.client.session.permission.create({
    sessionID,
    permission,
    ...(requestDirectory ? { directory: requestDirectory } : {}),
    ...(options?.message ? { message: options.message } : {}),
  });
  return (response.data as PermissionRequest) ?? null;
}

async fetchPermission(
  sessionID: string,
  requestID: string,
  directory?: string | null
): Promise<PermissionRequest | null> {
  const requestDirectory = this.normalizeCandidatePath(directory) ?? this.currentDirectory;
  const response = await this.client.session.permission.fetch({
    sessionID,
    requestID,
    ...(requestDirectory ? { directory: requestDirectory } : {}),
  });
  return (response.data as PermissionRequest) ?? null;
}

Step 2: Use in auto-accept flow (optional)

File: packages/ui/src/sync/sync-context.tsx, line 1118-1143

The auto-accept flow currently iterates grouped permissions and calls respondToPermission(). The new fetchPermission() could be used to verify a permission still exists before auto-accepting:

await Promise.all(autoAcceptingSessionIds.flatMap((sessionId) =>
  (grouped[sessionId] ?? []).map(async (permission) => {
    try {
      const fresh = await opencodeClient.fetchPermission(
        permission.sessionID,
        permission.id
      );
      if (!fresh) return; // Permission already resolved
      await sessionActions.respondToPermission(permission.sessionID, permission.id, "once")
    } catch {
      // Keep failed auto-accept permissions in UI state
    }
  }),
))

Step 3: Validation

cd packages/ui && bun run type-check

Manual: trigger a permission request, verify auto-accept flow works.