feat(v2): add permission mode passthrough and fix agent stop-on-close
- Add permission_mode field to AgentQueryOptions (Rust, sidecar, bridge) flowing from controller through sidecar to SDK; defaults to bypassPermissions, supports default mode - Fix AgentPane onDestroy bug: remove stopAgent() from onDestroy (fires on layout remounts), move stop-on-close to TilingGrid onClose handler - Bundle SDK into sidecar via esbuild (remove --external flag)
This commit is contained in:
parent
af0eb362e6
commit
d5eb08ed42
7 changed files with 26 additions and 14 deletions
|
|
@ -18,6 +18,7 @@ pub struct AgentQueryOptions {
|
||||||
pub max_turns: Option<u32>,
|
pub max_turns: Option<u32>,
|
||||||
pub max_budget_usd: Option<f64>,
|
pub max_budget_usd: Option<f64>,
|
||||||
pub resume_session_id: Option<String>,
|
pub resume_session_id: Option<String>,
|
||||||
|
pub permission_mode: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Directories to search for sidecar scripts.
|
/// Directories to search for sidecar scripts.
|
||||||
|
|
@ -168,6 +169,7 @@ impl SidecarManager {
|
||||||
"maxTurns": options.max_turns,
|
"maxTurns": options.max_turns,
|
||||||
"maxBudgetUsd": options.max_budget_usd,
|
"maxBudgetUsd": options.max_budget_usd,
|
||||||
"resumeSessionId": options.resume_session_id,
|
"resumeSessionId": options.resume_session_id,
|
||||||
|
"permissionMode": options.permission_mode,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.send_message(&msg)
|
self.send_message(&msg)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
"tauri:dev": "cargo tauri dev",
|
"tauri:dev": "cargo tauri dev",
|
||||||
"tauri:build": "cargo tauri build",
|
"tauri:build": "cargo tauri build",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"build:sidecar": "esbuild sidecar/agent-runner.ts --bundle --platform=node --format=esm --outfile=sidecar/dist/agent-runner.mjs --external:@anthropic-ai/claude-agent-sdk"
|
"build:sidecar": "esbuild sidecar/agent-runner.ts --bundle --platform=node --format=esm --outfile=sidecar/dist/agent-runner.mjs"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ interface QueryMessage {
|
||||||
maxTurns?: number;
|
maxTurns?: number;
|
||||||
maxBudgetUsd?: number;
|
maxBudgetUsd?: number;
|
||||||
resumeSessionId?: string;
|
resumeSessionId?: string;
|
||||||
|
permissionMode?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StopMessage {
|
interface StopMessage {
|
||||||
|
|
@ -51,7 +52,7 @@ function handleMessage(msg: Record<string, unknown>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleQuery(msg: QueryMessage) {
|
async function handleQuery(msg: QueryMessage) {
|
||||||
const { sessionId, prompt, cwd, maxTurns, maxBudgetUsd, resumeSessionId } = msg;
|
const { sessionId, prompt, cwd, maxTurns, maxBudgetUsd, resumeSessionId, permissionMode } = msg;
|
||||||
|
|
||||||
if (sessions.has(sessionId)) {
|
if (sessions.has(sessionId)) {
|
||||||
send({ type: "error", sessionId, message: "Session already running" });
|
send({ type: "error", sessionId, message: "Session already running" });
|
||||||
|
|
@ -84,8 +85,8 @@ async function handleQuery(msg: QueryMessage) {
|
||||||
"Bash", "Read", "Write", "Edit", "Glob", "Grep",
|
"Bash", "Read", "Write", "Edit", "Glob", "Grep",
|
||||||
"WebSearch", "WebFetch", "TodoWrite", "NotebookEdit",
|
"WebSearch", "WebFetch", "TodoWrite", "NotebookEdit",
|
||||||
],
|
],
|
||||||
permissionMode: "bypassPermissions",
|
permissionMode: (permissionMode ?? "bypassPermissions") as "bypassPermissions" | "default",
|
||||||
allowDangerouslySkipPermissions: true,
|
allowDangerouslySkipPermissions: (permissionMode ?? "bypassPermissions") === "bypassPermissions",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ interface QueryMessage {
|
||||||
maxTurns?: number;
|
maxTurns?: number;
|
||||||
maxBudgetUsd?: number;
|
maxBudgetUsd?: number;
|
||||||
resumeSessionId?: string;
|
resumeSessionId?: string;
|
||||||
|
permissionMode?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StopMessage {
|
interface StopMessage {
|
||||||
|
|
@ -60,7 +61,7 @@ function handleMessage(msg: Record<string, unknown>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleQuery(msg: QueryMessage) {
|
async function handleQuery(msg: QueryMessage) {
|
||||||
const { sessionId, prompt, cwd, maxTurns, maxBudgetUsd, resumeSessionId } = msg;
|
const { sessionId, prompt, cwd, maxTurns, maxBudgetUsd, resumeSessionId, permissionMode } = msg;
|
||||||
|
|
||||||
if (sessions.has(sessionId)) {
|
if (sessions.has(sessionId)) {
|
||||||
send({ type: 'error', sessionId, message: 'Session already running' });
|
send({ type: 'error', sessionId, message: 'Session already running' });
|
||||||
|
|
@ -93,8 +94,8 @@ async function handleQuery(msg: QueryMessage) {
|
||||||
'Bash', 'Read', 'Write', 'Edit', 'Glob', 'Grep',
|
'Bash', 'Read', 'Write', 'Edit', 'Glob', 'Grep',
|
||||||
'WebSearch', 'WebFetch', 'TodoWrite', 'NotebookEdit',
|
'WebSearch', 'WebFetch', 'TodoWrite', 'NotebookEdit',
|
||||||
],
|
],
|
||||||
permissionMode: 'bypassPermissions',
|
permissionMode: (permissionMode ?? 'bypassPermissions') as 'bypassPermissions' | 'default',
|
||||||
allowDangerouslySkipPermissions: true,
|
allowDangerouslySkipPermissions: (permissionMode ?? 'bypassPermissions') === 'bypassPermissions',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ export interface AgentQueryOptions {
|
||||||
max_turns?: number;
|
max_turns?: number;
|
||||||
max_budget_usd?: number;
|
max_budget_usd?: number;
|
||||||
resume_session_id?: string;
|
resume_session_id?: string;
|
||||||
|
permission_mode?: string;
|
||||||
remote_machine_id?: string;
|
remote_machine_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { marked, Renderer } from 'marked';
|
import { marked, Renderer } from 'marked';
|
||||||
import { queryAgent, stopAgent, isAgentReady, restartAgent } from '../../adapters/agent-bridge';
|
import { queryAgent, stopAgent, isAgentReady, restartAgent } from '../../adapters/agent-bridge';
|
||||||
import {
|
import {
|
||||||
|
|
@ -68,11 +68,8 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
// NOTE: Do NOT stop agents in onDestroy — it fires on layout changes/remounts,
|
||||||
if (session?.status === 'running' || session?.status === 'starting') {
|
// not just explicit close. Stop-on-close is handled by TilingGrid.
|
||||||
stopAgent(sessionId).catch(() => {});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let followUpPrompt = $state('');
|
let followUpPrompt = $state('');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
} from '../../stores/layout.svelte';
|
} from '../../stores/layout.svelte';
|
||||||
import { detachPane } from '../../utils/detach';
|
import { detachPane } from '../../utils/detach';
|
||||||
import { isDetachedMode } from '../../utils/detach';
|
import { isDetachedMode } from '../../utils/detach';
|
||||||
|
import { stopAgent } from '../../adapters/agent-bridge';
|
||||||
|
import { getAgentSession } from '../../stores/agents.svelte';
|
||||||
|
|
||||||
let gridTemplate = $derived(getGridTemplate());
|
let gridTemplate = $derived(getGridTemplate());
|
||||||
let panes = $derived(getPanes());
|
let panes = $derived(getPanes());
|
||||||
|
|
@ -162,7 +164,15 @@
|
||||||
<PaneContainer
|
<PaneContainer
|
||||||
title={pane.title}
|
title={pane.title}
|
||||||
status={pane.focused ? 'running' : 'idle'}
|
status={pane.focused ? 'running' : 'idle'}
|
||||||
onClose={() => removePane(pane.id)}
|
onClose={() => {
|
||||||
|
if (pane.type === 'agent') {
|
||||||
|
const s = getAgentSession(pane.id);
|
||||||
|
if (s?.status === 'running' || s?.status === 'starting') {
|
||||||
|
stopAgent(pane.id).catch(() => {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removePane(pane.id);
|
||||||
|
}}
|
||||||
onDetach={detached ? undefined : () => handleDetach(pane)}
|
onDetach={detached ? undefined : () => handleDetach(pane)}
|
||||||
>
|
>
|
||||||
{#if pane.type === 'terminal'}
|
{#if pane.type === 'terminal'}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue