mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-07 04:08:45 +02:00
feat: category-based approval for runtime tools
Replace 20+ individual runtime tool toggles with 5 permission categories (read, write, shell, web_fetch, store_memory) matching how Copilot CLI, Cline, and other coding agents handle approvals. - Add resolveApprovalToolKey() to map permission kinds to category IDs - Simplify fallbackRuntimeApprovalTools to 5 categories - Thread alwaysApprove through PendingApprovalHandle → sidecar resolve - Update ApprovalBanner to use category labels for Always Approve button - Update ResolveApprovalCommand contract with alwaysApprove field - Update tests for category-based model Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
||||
normalizeSessionApprovalSettings,
|
||||
pruneApprovalPolicyTools,
|
||||
pruneSessionApprovalSettings,
|
||||
resolveApprovalToolKey,
|
||||
resolvePendingApproval,
|
||||
type ApprovalDecision,
|
||||
type PendingApprovalMessageRecord,
|
||||
@@ -124,7 +125,7 @@ type AppServiceEvents = {
|
||||
type PendingApprovalHandle = {
|
||||
sessionId: string;
|
||||
requestId: string;
|
||||
resolve: (decision: ApprovalDecision) => void | Promise<void>;
|
||||
resolve: (decision: ApprovalDecision, alwaysApprove?: boolean) => void | Promise<void>;
|
||||
};
|
||||
|
||||
type PendingUserInputHandle = {
|
||||
@@ -635,8 +636,8 @@ export class AryxAppService extends EventEmitter<AppServiceEvents> {
|
||||
await this.applyAgentActivity(workspace, session.id, requestId, event);
|
||||
},
|
||||
async (event) => {
|
||||
await this.handleApprovalRequested(workspace, session.id, requestId, event, (decision) =>
|
||||
this.sidecar.resolveApproval(event.approvalId, decision));
|
||||
await this.handleApprovalRequested(workspace, session.id, requestId, event, (decision, alwaysApprove) =>
|
||||
this.sidecar.resolveApproval(event.approvalId, decision, alwaysApprove));
|
||||
},
|
||||
async (event) => {
|
||||
await this.handleUserInputRequested(workspace, session.id, requestId, event, (answer, wasFreeform) =>
|
||||
@@ -729,7 +730,7 @@ export class AryxAppService extends EventEmitter<AppServiceEvents> {
|
||||
this.setSessionPendingApprovalState(session, dequeuePendingApprovalState(session, approvalId));
|
||||
session.updatedAt = resolvedAt;
|
||||
|
||||
const approvalKey = approval.toolName ?? approval.permissionKind;
|
||||
const approvalKey = resolveApprovalToolKey(approval.toolName, approval.permissionKind);
|
||||
if (decision === 'approved' && alwaysApprove && approvalKey) {
|
||||
const existing = session.approvalSettings?.autoApprovedToolNames ?? [];
|
||||
if (!existing.includes(approvalKey)) {
|
||||
@@ -748,7 +749,7 @@ export class AryxAppService extends EventEmitter<AppServiceEvents> {
|
||||
this.pendingApprovalHandles.delete(approvalId);
|
||||
|
||||
try {
|
||||
await Promise.resolve(handle.resolve(decision));
|
||||
await Promise.resolve(handle.resolve(decision, alwaysApprove));
|
||||
} catch (error) {
|
||||
const failedAt = nowIso();
|
||||
this.rejectPendingApprovals(
|
||||
@@ -1396,7 +1397,7 @@ export class AryxAppService extends EventEmitter<AppServiceEvents> {
|
||||
sessionId: string,
|
||||
requestId: string,
|
||||
approval: ApprovalRequestedEvent | PendingApprovalRecord,
|
||||
resolve: (decision: ApprovalDecision) => void | Promise<void>,
|
||||
resolve: (decision: ApprovalDecision, alwaysApprove?: boolean) => void | Promise<void>,
|
||||
): Promise<void> {
|
||||
const session = this.requireSession(workspace, sessionId);
|
||||
const pendingApproval =
|
||||
|
||||
@@ -120,12 +120,13 @@ export class SidecarClient {
|
||||
});
|
||||
}
|
||||
|
||||
async resolveApproval(approvalId: string, decision: ApprovalDecision): Promise<void> {
|
||||
async resolveApproval(approvalId: string, decision: ApprovalDecision, alwaysApprove?: boolean): Promise<void> {
|
||||
return this.dispatch<void>({
|
||||
type: 'resolve-approval',
|
||||
requestId: `approval-${Date.now()}`,
|
||||
approvalId,
|
||||
decision,
|
||||
alwaysApprove: alwaysApprove ?? false,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user