propagate native session identity through CLI orchestration

This commit is contained in:
Merge Sim
2026-09-08 16:04:11 -07:00
parent eafcb48e0b
commit cc3a18cd91
3 changed files with 40 additions and 13 deletions
@@ -2,7 +2,7 @@ import type { CommandHandler } from '../../dispatch'
import { printResult } from '../../format'
import { getOptionalJsonFlag, getOptionalStringFlag, getRequiredStringFlag } from '../../flags'
import { callOrchestrationMutation } from './mutation-request'
import { resolveCoordinatorTerminalHandle } from './terminal-identity'
import { orchestrationSessionPayload, resolveCoordinatorTerminalHandle } from './terminal-identity'
export const ORCHESTRATION_GATE_HANDLERS: Record<string, CommandHandler> = {
'orchestration gate-create': async ({ flags, client, cwd, json }) => {
@@ -13,7 +13,9 @@ export const ORCHESTRATION_GATE_HANDLERS: Record<string, CommandHandler> = {
question: getRequiredStringFlag(flags, 'question'),
options: getOptionalJsonFlag(flags, 'options'),
// Why: gates are Run-scoped, so the coordinator handle is the authorized caller identity.
from: await resolveCoordinatorTerminalHandle(flags, cwd, client)
...(orchestrationSessionPayload().agentSessionId
? orchestrationSessionPayload()
: { from: await resolveCoordinatorTerminalHandle(flags, cwd, client) })
})
printResult(
result,
@@ -29,7 +31,9 @@ export const ORCHESTRATION_GATE_HANDLERS: Record<string, CommandHandler> = {
}>(client, flags, 'orchestration.gateResolve', {
id: getRequiredStringFlag(flags, 'id'),
resolution: getRequiredStringFlag(flags, 'resolution'),
from: await resolveCoordinatorTerminalHandle(flags, cwd, client)
...(orchestrationSessionPayload().agentSessionId
? orchestrationSessionPayload()
: { from: await resolveCoordinatorTerminalHandle(flags, cwd, client) })
})
printResult(result, json, (value) => `Gate ${value.gate.id} resolved: ${value.gate.resolution}`)
},
@@ -37,7 +41,11 @@ export const ORCHESTRATION_GATE_HANDLERS: Record<string, CommandHandler> = {
'orchestration gate-list': async ({ flags, client, cwd, json }) => {
const run = getOptionalStringFlag(flags, 'run')
// Why: named runs remain inspectable without a pane; only implicit runs resolve identity.
const from = run ? undefined : await resolveCoordinatorTerminalHandle(flags, cwd, client)
const session = orchestrationSessionPayload()
const from =
run || session.agentSessionId
? undefined
: await resolveCoordinatorTerminalHandle(flags, cwd, client)
const result = await client.call<{
gates: { id: string; task_id: string; question: string; status: string }[]
count: number
@@ -46,7 +54,8 @@ export const ORCHESTRATION_GATE_HANDLERS: Record<string, CommandHandler> = {
task: getOptionalStringFlag(flags, 'task'),
status: getOptionalStringFlag(flags, 'status'),
run,
from
from,
...session
})
printResult(result, json, (value) => {
if (value.gates.length === 0) {
@@ -4,7 +4,7 @@ import { getOptionalStringFlag, getRequiredStringFlag } from '../../flags'
import { RuntimeClientError } from '../../runtime-client'
import { abbreviateOrchestrationTasks } from '../../../shared/orchestration-task-summary'
import { callOrchestrationMutation } from './mutation-request'
import { resolveCoordinatorTerminalHandle } from './terminal-identity'
import { orchestrationSessionPayload, resolveCoordinatorTerminalHandle } from './terminal-identity'
const TASK_STATUS_VALUES = [
'pending',
@@ -17,7 +17,10 @@ const TASK_STATUS_VALUES = [
export const ORCHESTRATION_TASK_HANDLERS: Record<string, CommandHandler> = {
'orchestration task-create': async ({ flags, client, cwd, json }) => {
const callerTerminalHandle = await resolveCoordinatorTerminalHandle(flags, cwd, client)
const session = orchestrationSessionPayload()
const callerTerminalHandle = session.agentSessionId
? undefined
: await resolveCoordinatorTerminalHandle(flags, cwd, client)
const result = await callOrchestrationMutation<{ task: { id: string; status: string } }>(
client,
flags,
@@ -29,7 +32,8 @@ export const ORCHESTRATION_TASK_HANDLERS: Record<string, CommandHandler> = {
deps: getOptionalStringFlag(flags, 'deps'),
parent: getOptionalStringFlag(flags, 'parent'),
run: getOptionalStringFlag(flags, 'run'),
callerTerminalHandle
callerTerminalHandle,
...session
}
)
printResult(result, json, (r) => `Created ${r.task.id} [${r.task.status}]`)
@@ -38,9 +42,11 @@ export const ORCHESTRATION_TASK_HANDLERS: Record<string, CommandHandler> = {
'orchestration task-list': async ({ flags, client, cwd, json }) => {
const brief = flags.has('brief')
const run = getOptionalStringFlag(flags, 'run')
const callerTerminalHandle = run
? undefined
: await resolveCoordinatorTerminalHandle(flags, cwd, client)
const session = orchestrationSessionPayload()
const callerTerminalHandle =
run || session.agentSessionId
? undefined
: await resolveCoordinatorTerminalHandle(flags, cwd, client)
const result = await client.call<{
tasks: {
id: string
@@ -60,7 +66,8 @@ export const ORCHESTRATION_TASK_HANDLERS: Record<string, CommandHandler> = {
ready: flags.has('ready') ? true : undefined,
brief: brief ? true : undefined,
run,
callerTerminalHandle
callerTerminalHandle,
...session
})
// Why: only older runtimes (no spec_truncated) skip server-side abbreviation and need this client-side fallback.
const needsClientAbbreviation =
@@ -106,7 +113,9 @@ export const ORCHESTRATION_TASK_HANDLERS: Record<string, CommandHandler> = {
status,
result: getOptionalStringFlag(flags, 'result'),
run: getOptionalStringFlag(flags, 'run'),
callerTerminalHandle: await resolveCoordinatorTerminalHandle(flags, cwd, client)
...(orchestrationSessionPayload().agentSessionId
? orchestrationSessionPayload()
: { callerTerminalHandle: await resolveCoordinatorTerminalHandle(flags, cwd, client) })
}
)
printResult(result, json, (r) => `Updated ${r.task.id} -> ${r.task.status}`)
@@ -59,6 +59,15 @@ export function resolveOrchestrationRuntimeFence(): string | undefined {
return value && value.length > 0 ? value : undefined
}
export function orchestrationSessionPayload(): {
agentSessionId?: string
runtimeFence?: number
} {
const agentSessionId = resolveOrchestrationAgentSessionId()
const fence = resolveOrchestrationRuntimeFence()
return agentSessionId && fence ? { agentSessionId, runtimeFence: Number(fence) } : {}
}
/**
* Whether the handle this process was born with still names a live identity.
*