mirror of
https://github.com/stablyai/orca.git
synced 2026-10-28 08:02:54 +00:00
feat(agent-launch): let a caller reserve the pane its terminal launch creates (#22291)
* feat(agent-launch): let a caller reserve the pane its terminal launch creates * fix(agent-launch): refuse a launch whose reserved pane is already live * fix(agent-launch): refuse a live reserved pane before it is revealed The live-pane refusal used to fire in the executor, after createTerminal had already issued a handle, published the mobile snapshot and revealed the tab. The reveal re-registered a fresh launch config over the running agent's. agent.launch now passes requireFreshPane with a reserved pane, and createTerminal throws AgentLaunchPaneAlreadyLiveError as soon as spawn reports it attached to a live pane. That is before any handle, snapshot or reveal. The spawn reattach itself is the one terminal.create already uses, so the live PTY is never killed, and the stable-pane create claim is still released in finally. The isReattach plumbing added to the launch factory for the old check is gone. A replay-safe launch refused this way on an existing workspace now records a failed ledger row, the same way a name collision does. Before, the row stayed claimed, so every retry got agent_session_operation_unknown. agent.launchReplay passes the code through. On create-worktree the workspace already exists when the terminal is refused, so the row stays unknown. The code is added to the runtime passthrough list so callers can branch on it. The pane key is now in the replay fingerprint, deliberately. It is not placement: group, anchor and focus still stay out of the request and out of the ledger. It is identity. It is written into the pane's PTY environment and names the tab the caller has placed. A retry that reserved a different pane is therefore a different request. Replaying the first answer would return a key the new reservation can never find. This matches terminal.createAgentSession, which also fingerprints its tab and leaf ids. The key is only folded in when present, so every existing digest is unchanged, and a test pins that. The wire schema now refuses a tab id the runtime would not adopt as sent: one with surrounding whitespace, which the runtime trims, and one longer than 512 characters, which the spawn reservation does not key on. It reuses the tab-id schema that Placement uses. * test(agent-launch): pin that a refused live pane issues no handle The refusal test named handle issuance but only asserted the reveal, so a throw moved to just before the reveal would still pass. Assert no terminal is registered, with the attach test as the positive control.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { paneIdentity } from './runtime-terminal-pane-identity'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { getProjectHostSetupWorktreeMeta } from '../../shared/project-host-setup-lookup'
|
||||
import { resolveWorktreeCreateDisplayNameRequest } from '../ipc/worktree-logic'
|
||||
@@ -137,6 +138,7 @@ export async function createRuntimeFolderWorktree(args: {
|
||||
const terminal = await deps.createTerminal(`id:${worktree.id}`, {
|
||||
command: args.startup.command,
|
||||
...(request.startupCwd ? { cwd: request.startupCwd } : {}),
|
||||
...paneIdentity(request.startupPaneKey),
|
||||
env: args.startup.env,
|
||||
...(args.startup.launchConfig ? { launchConfig: args.startup.launchConfig } : {}),
|
||||
...(args.createdWithAgent ? { launchAgent: args.createdWithAgent } : {}),
|
||||
|
||||
Reference in New Issue
Block a user