mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-08 07:17:39 +00:00
fix(hub,cli): forward permissionMode on session resume (#460)
* feat(hub,cli): forward permissionMode on session resume When a session is resumed, the cached permissionMode is now forwarded through the Hub → Runner → CLI pipeline via a new --permission-mode flag. Previously the mode was lost on resume, resetting to 'default'. Each CLI flavor validates the flag value against its own allowed permission modes (e.g. CLAUDE_PERMISSION_MODES) and rejects unknown values. The existing --yolo flag is preserved as a shorthand. * refactor(cli): extract buildCliArgs from startRunner Extract the CLI argument construction logic into a standalone exported function so it can be unit-tested independently. No behavior change. * test(cli): add buildCliArgs unit tests for --permission-mode Verify that the runner correctly forwards valid permission modes via --permission-mode, rejects invalid values, and falls back to --yolo when no permission mode is set. * fix(cli): let --permission-mode take precedence over --yolo When both flags are present, --permission-mode was silently overwritten by a later --yolo. Guard legacy flag branches with a hasExplicitPermissionMode check so the explicit flag wins.
This commit is contained in:
+44
-33
@@ -13,6 +13,7 @@ import { getEnvironmentInfo } from '@/ui/doctor';
|
||||
import { spawnHappyCLI } from '@/utils/spawnHappyCLI';
|
||||
import { writeRunnerState, RunnerLocallyPersistedState, readRunnerState, acquireRunnerLock, releaseRunnerLock } from '@/persistence';
|
||||
import { isProcessAlive, isWindows, killProcess, killProcessByChildProcess } from '@/utils/process';
|
||||
import { PERMISSION_MODES } from '@hapi/protocol/modes';
|
||||
import { withRetry } from '@/utils/time';
|
||||
import { isRetryableConnectionError } from '@/utils/errorUtils';
|
||||
|
||||
@@ -339,39 +340,7 @@ export async function startRunner(): Promise<void> {
|
||||
};
|
||||
}
|
||||
|
||||
// Construct arguments for the CLI
|
||||
const agentCommand = agent === 'codex'
|
||||
? 'codex'
|
||||
: agent === 'cursor'
|
||||
? 'cursor'
|
||||
: agent === 'gemini'
|
||||
? 'gemini'
|
||||
: agent === 'opencode'
|
||||
? 'opencode'
|
||||
: 'claude';
|
||||
const args = [agentCommand];
|
||||
if (options.resumeSessionId) {
|
||||
if (agent === 'codex') {
|
||||
args.push('resume', options.resumeSessionId);
|
||||
} else if (agent === 'cursor') {
|
||||
args.push('--resume', options.resumeSessionId);
|
||||
} else {
|
||||
args.push('--resume', options.resumeSessionId);
|
||||
}
|
||||
}
|
||||
args.push('--hapi-starting-mode', 'remote', '--started-by', 'runner');
|
||||
if (options.model && agent !== 'opencode') {
|
||||
args.push('--model', options.model);
|
||||
}
|
||||
if (options.effort && agent === 'claude') {
|
||||
args.push('--effort', options.effort);
|
||||
}
|
||||
if (options.modelReasoningEffort && agent === 'codex') {
|
||||
args.push('--model-reasoning-effort', options.modelReasoningEffort);
|
||||
}
|
||||
if (yolo) {
|
||||
args.push('--yolo');
|
||||
}
|
||||
const args = buildCliArgs(agent, options, yolo);
|
||||
|
||||
// sessionId reserved for future use
|
||||
const MAX_TAIL_CHARS = 4000;
|
||||
@@ -853,3 +822,45 @@ export async function startRunner(): Promise<void> {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
export function buildCliArgs(
|
||||
agent: string,
|
||||
options: SpawnSessionOptions,
|
||||
yolo?: boolean
|
||||
): string[] {
|
||||
const agentCommand = agent === 'codex'
|
||||
? 'codex'
|
||||
: agent === 'cursor'
|
||||
? 'cursor'
|
||||
: agent === 'gemini'
|
||||
? 'gemini'
|
||||
: agent === 'opencode'
|
||||
? 'opencode'
|
||||
: 'claude';
|
||||
const args = [agentCommand];
|
||||
if (options.resumeSessionId) {
|
||||
if (agent === 'codex') {
|
||||
args.push('resume', options.resumeSessionId);
|
||||
} else if (agent === 'cursor') {
|
||||
args.push('--resume', options.resumeSessionId);
|
||||
} else {
|
||||
args.push('--resume', options.resumeSessionId);
|
||||
}
|
||||
}
|
||||
args.push('--hapi-starting-mode', 'remote', '--started-by', 'runner');
|
||||
if (options.model && agent !== 'opencode') {
|
||||
args.push('--model', options.model);
|
||||
}
|
||||
if (options.effort && agent === 'claude') {
|
||||
args.push('--effort', options.effort);
|
||||
}
|
||||
if (options.modelReasoningEffort && agent === 'codex') {
|
||||
args.push('--model-reasoning-effort', options.modelReasoningEffort);
|
||||
}
|
||||
if (options.permissionMode && (PERMISSION_MODES as readonly string[]).includes(options.permissionMode)) {
|
||||
args.push('--permission-mode', options.permissionMode);
|
||||
} else if (yolo) {
|
||||
args.push('--yolo');
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user