mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
* feat(agent-launch): accept a create-folder-workspace target agent.launch can now create a folder workspace and start its agent there, the same operation it already runs for a new git worktree. The host creates the folder workspace (metadata only, no startup terminal), resolves it the way an existing target is resolved, then settles the mode and builds the surface as for any existing folder workspace. Hosts advertise agent.launch.create-folder-workspace.v1 so a client offers the target only to a host that accepts it. * fix(agent-launch): authorize, classify and navigate folder creates like their create method A create-folder-workspace launch could do three things its two-call equivalent never did: - A phone could create folder workspaces. The mobile allowlist admits agent.launch but not folderWorkspace.create, and is checked by method name only. A create target now needs the authorization of the create method it stands for, read from the same allowlist, and a phone is refused with agent_launch_target_forbidden before admission, so no ledger row and no create. create-worktree maps to worktree.create, which phones already may call, so nothing changes for it. - A create refused before anything was stored (group gone, folder missing, SSH host unreachable) replayed as agent_session_operation_unknown, and a retry under the same operation id was refused until the row expired. runtime.createFolderWorkspace now raises those refusals as FolderWorkspaceCreateRefusedError, with the same message text, and the launch records it as failed for any target. A failure after the create still replays unknown. - A paired caller's folder create activated the new chat on the host window and did not select the caller's own tab. Only create-worktree, whose host activation runs setup, keeps the host navigation now; a folder create navigates like an existing workspace. Tests cover the phone refusal, replay of a success, a refused create settling failed and replaying that failure, an after-create failure staying unknown, an SSH connection reaching the agent's view mode, paired navigation, and an older host refusing the target at parse. * fix(agent-launch): replay a refused folder create with its whole path A folder create refused before anything was stored is recorded as the launch's failure, and a retry under the same operation id answers from that record. The record went through the 128-character cap every launch failure code gets, and folder refusals carry the folder's absolute path, so a retry could show the user a path cut short: a different folder. The refusal is now recorded whole when it fits a path as long as Linux's PATH_MAX after its code. Past that, which no folder a stat accepts reaches, only the code before the path is kept, so the replay degrades to the bare code instead of a partial path. Also: the controller test asserts the exact refusal message, the create-folder-workspace capability comment says a phone needs its own gate, and the forbidden-target code says why it is not `forbidden`. * test(folder-workspace): type the controller test's store stub without an assertion The changed-code quality gate refuses the `as never` cast on the stub store. It is now a RuntimeStore whose unreached members throw. * test(agent-launch): run the folder-create launch tests in the Node runtime project The operationId replay tests open the real SQLite record store, so the file belongs with the other ledger-backed agent.launch tests. * test(agent-launch): pin that a paired folder create's terminal stays off the host window The folder-create test now asserts surfaceOwner: false on the terminal a paired caller's launch creates, rather than matching any options. The caller-selection header now says only an in-process worktree create keeps worktree.create's navigation. * test(agent-launch): drop the per-connection view-mode expectation main removed
67 lines
3.9 KiB
TypeScript
67 lines
3.9 KiB
TypeScript
// Split out of protocol-version.ts, which spreads the list below into RUNTIME_CAPABILITIES in this
|
|
// order. Import these names from here: the mobile recording loader cannot follow `export *`.
|
|
|
|
/**
|
|
* `agent.launch` exists: one host-side method that decides structured-vs-terminal and creates the
|
|
* surface, instead of each client routing for itself.
|
|
*
|
|
* Negotiated rather than assumed because a client that cannot see it must keep using
|
|
* `worktree.create` + `startupAgent`, which stays supported verbatim. The reverse skew is the
|
|
* dangerous one: `worktree.create` returns `agentTerminalHandle` only when a startup agent was
|
|
* requested, so a host that quietly routed that call to a structured session would hand an old
|
|
* client a response with no handle and no error.
|
|
*
|
|
* Advertising it is a statement that the client understands EITHER outcome, since the host is what
|
|
* picks: a structured session it can open, or a terminal agent. A client that renders only one of
|
|
* the two keeps using the surface-specific methods.
|
|
*/
|
|
// v2 makes prompt delivery an outcome union and top-level warnings the only supported shape.
|
|
export const AGENT_LAUNCH_RUNTIME_CAPABILITY = 'agent.launch.v2' as const
|
|
|
|
// Optional identity support on agent.launch; mobile replay across replacement hosts requires the new method.
|
|
export const AGENT_LAUNCH_REPLAY_RUNTIME_CAPABILITY = 'agent.launch.replay.v1' as const
|
|
|
|
// A host that sends a launch prompt its typed startup line cannot carry to a paste after
|
|
// readiness; an older host folds any prompt into that line, so clients gate prompted launches on it.
|
|
export const AGENT_LAUNCH_PROMPT_CARRY_RUNTIME_CAPABILITY = 'agent.launch.prompt-carry.v1' as const
|
|
|
|
// agent.launchReplay requires the ledger; older replacement hosts must reject the method.
|
|
export const AGENT_LAUNCH_REPLAY_REQUIRED_RUNTIME_CAPABILITY =
|
|
'agent.launch.replay-required.v1' as const
|
|
|
|
// A client that reads `prompt.outcome: 'unconfirmed'` on a replayed launch. Without it, a launch
|
|
// whose host stopped mid-delivery replays as `agent_session_operation_unknown`, as it always has.
|
|
export const AGENT_LAUNCH_PROMPT_UNCONFIRMED_RUNTIME_CAPABILITY =
|
|
'agent.launch.prompt-unconfirmed.v1' as const
|
|
|
|
// Host-advertised: reads `placement` and `presentation`, reports the placement in the receipt, and
|
|
// may publish the launch's tab before it admits the launch.
|
|
export const AGENT_LAUNCH_PLACEMENT_RUNTIME_CAPABILITY = 'agent.launch.placement.v1' as const
|
|
|
|
// Host-advertised: accepts `target.kind: 'create-folder-workspace'`. An older host refuses the
|
|
// unknown target kind, so a client offers the new-folder-workspace launch only on this. It is not
|
|
// enough on its own: the target also needs `folderWorkspace.create` authorization, which a
|
|
// mobile-scope device lacks, so a phone folder launch needs its own gate.
|
|
export const AGENT_LAUNCH_CREATE_FOLDER_WORKSPACE_RUNTIME_CAPABILITY =
|
|
'agent.launch.create-folder-workspace.v1' as const
|
|
|
|
// Client-advertised only: the client reads a listed launch tab with no terminal yet as "not
|
|
// started", never as proof its agent runs. The host publishes a paired caller's tab before the
|
|
// spawn only for a client that says so.
|
|
export const AGENT_LAUNCH_UNSTARTED_TAB_CLIENT_CAPABILITY = 'agent.launch.unstarted-tab.v1' as const
|
|
|
|
// Client-advertised only: the client reads `agent_launch_tab_closed` (the user closed the launch's
|
|
// tab while it started, so it was stopped) as a definite answer. Others get
|
|
// `agent_session_operation_unknown` for it, as before the host knew.
|
|
export const AGENT_LAUNCH_TAB_CLOSED_CLIENT_CAPABILITY = 'agent.launch.tab-closed.v1' as const
|
|
|
|
export const AGENT_LAUNCH_RUNTIME_CAPABILITIES = [
|
|
AGENT_LAUNCH_RUNTIME_CAPABILITY,
|
|
AGENT_LAUNCH_REPLAY_RUNTIME_CAPABILITY,
|
|
AGENT_LAUNCH_REPLAY_REQUIRED_RUNTIME_CAPABILITY,
|
|
AGENT_LAUNCH_PROMPT_CARRY_RUNTIME_CAPABILITY,
|
|
AGENT_LAUNCH_PROMPT_UNCONFIRMED_RUNTIME_CAPABILITY,
|
|
AGENT_LAUNCH_PLACEMENT_RUNTIME_CAPABILITY,
|
|
AGENT_LAUNCH_CREATE_FOLDER_WORKSPACE_RUNTIME_CAPABILITY
|
|
] as const
|