Compare commits

...

2 Commits

3 changed files with 59 additions and 12 deletions

View File

@@ -496,6 +496,17 @@ function startObserverHttpBridge() {
auto_detected: true, auto_detected: true,
source: 'dom_observer', source: 'dom_observer',
}; };
// File permission: inject multi-choice buttons
const cmdLower = (data.command || '').toLowerCase();
if (cmdLower.includes('allow') && !pending.buttons) {
pending.buttons = [
{ text: 'Allow Once', index: 0 },
{ text: 'Allow This Conversation', index: 1 },
{ text: 'Deny', index: 2 },
];
pending.step_type = 'file_permission';
pending.command = `파일 접근 권한: ${data.description || data.command}`;
}
fs.writeFileSync(path.join(pendingDir, `${rid}.json`), JSON.stringify(pending, null, 2)); fs.writeFileSync(path.join(pendingDir, `${rid}.json`), JSON.stringify(pending, null, 2));
logToFile(`[HTTP] pending created: ${rid} cmd="${data.command}" btns=${(data.buttons || []).length} ctx="${(data.description || '').substring(0, 50)}"`); logToFile(`[HTTP] pending created: ${rid} cmd="${data.command}" btns=${(data.buttons || []).length} ctx="${(data.description || '').substring(0, 50)}"`);
res.writeHead(200, { 'Content-Type': 'application/json' }); res.writeHead(200, { 'Content-Type': 'application/json' });
@@ -1987,13 +1998,24 @@ async function processResponseFile(filePath) {
|| pending.source === 'dom_observer'; || pending.source === 'dom_observer';
pendingStepType = pending.step_type || ''; pendingStepType = pending.step_type || '';
pendingStepIndex = pending.step_index ?? lastPendingStepIndex; pendingStepIndex = pending.step_index ?? lastPendingStepIndex;
// Infer step_type from cmd if not explicitly set
if (!pendingStepType && pending.command) { if (!pendingStepType && pending.command) {
const cmd = (pending.command || '').toLowerCase(); const cmd = (pending.command || '').toLowerCase();
if (cmd.includes('allow once') || cmd.includes('allow this conversation')) { if (cmd.includes('allow') || cmd.includes('파일 접근') || pending.step_type === 'file_permission') {
pendingStepType = 'file_permission'; // Map button_index → scope: 0=Once, 1=Conversation, 2=Deny
const btnIdx = resp.button_index ?? -1;
if (btnIdx === 1) {
pendingStepType = 'file_permission_conversation';
}
else {
pendingStepType = 'file_permission_once';
}
} }
} }
// Also handle when step_type was explicitly set
if (pendingStepType === 'file_permission') {
const btnIdx = resp.button_index ?? -1;
pendingStepType = btnIdx === 1 ? 'file_permission_conversation' : 'file_permission_once';
}
} }
catch { } catch { }
} }
@@ -2311,8 +2333,10 @@ async function tryApprovalStrategies(approved, sessionId, stepType = '', stepInd
interactionPayload = { runExtensionCode: { confirm: true } }; interactionPayload = { runExtensionCode: { confirm: true } };
} }
else if (typeLower.includes('file_permission')) { else if (typeLower.includes('file_permission')) {
// FilePermissionInteraction: allow=true, scope=ONCE(1) or CONVERSATION(2) // FilePermissionInteraction: allow=true, scope depends on cmd
interactionPayload = { filePermission: { allow: true, scope: 1 } }; // PERMISSION_SCOPE_ONCE // file_permission_once → 1, file_permission_conversation → 2
const scope = typeLower.includes('conversation') ? 2 : 1;
interactionPayload = { filePermission: { allow: true, scope } };
} }
else if (typeLower.includes('elicitation')) { else if (typeLower.includes('elicitation')) {
interactionPayload = { elicitation: {} }; // ElicitationInteraction (TBD) interactionPayload = { elicitation: {} }; // ElicitationInteraction (TBD)

File diff suppressed because one or more lines are too long

View File

@@ -465,7 +465,7 @@ function startObserverHttpBridge(): Promise<number> {
// Write pending file for Discord bot // Write pending file for Discord bot
const pendingDir = path.join(bridgePath, 'pending'); const pendingDir = path.join(bridgePath, 'pending');
if (!fs.existsSync(pendingDir)) fs.mkdirSync(pendingDir, { recursive: true }); if (!fs.existsSync(pendingDir)) fs.mkdirSync(pendingDir, { recursive: true });
const pending = { const pending: Record<string, any> = {
...data, ...data,
request_id: rid, request_id: rid,
conversation_id: activeSessionId || '', conversation_id: activeSessionId || '',
@@ -475,6 +475,17 @@ function startObserverHttpBridge(): Promise<number> {
auto_detected: true, auto_detected: true,
source: 'dom_observer', source: 'dom_observer',
}; };
// File permission: inject multi-choice buttons
const cmdLower = (data.command || '').toLowerCase();
if (cmdLower.includes('allow') && !pending.buttons) {
pending.buttons = [
{ text: 'Allow Once', index: 0 },
{ text: 'Allow This Conversation', index: 1 },
{ text: 'Deny', index: 2 },
];
pending.step_type = 'file_permission';
pending.command = `파일 접근 권한: ${data.description || data.command}`;
}
fs.writeFileSync(path.join(pendingDir, `${rid}.json`), JSON.stringify(pending, null, 2)); fs.writeFileSync(path.join(pendingDir, `${rid}.json`), JSON.stringify(pending, null, 2));
logToFile(`[HTTP] pending created: ${rid} cmd="${data.command}" btns=${(data.buttons || []).length} ctx="${(data.description || '').substring(0, 50)}"`); logToFile(`[HTTP] pending created: ${rid} cmd="${data.command}" btns=${(data.buttons || []).length} ctx="${(data.description || '').substring(0, 50)}"`);
res.writeHead(200, { 'Content-Type': 'application/json' }); res.writeHead(200, { 'Content-Type': 'application/json' });
@@ -1943,13 +1954,23 @@ async function processResponseFile(filePath: string) {
|| pending.source === 'dom_observer'; || pending.source === 'dom_observer';
pendingStepType = pending.step_type || ''; pendingStepType = pending.step_type || '';
pendingStepIndex = pending.step_index ?? lastPendingStepIndex; pendingStepIndex = pending.step_index ?? lastPendingStepIndex;
// Infer step_type from cmd if not explicitly set
if (!pendingStepType && pending.command) { if (!pendingStepType && pending.command) {
const cmd = (pending.command || '').toLowerCase(); const cmd = (pending.command || '').toLowerCase();
if (cmd.includes('allow once') || cmd.includes('allow this conversation')) { if (cmd.includes('allow') || cmd.includes('파일 접근') || pending.step_type === 'file_permission') {
pendingStepType = 'file_permission'; // Map button_index → scope: 0=Once, 1=Conversation, 2=Deny
const btnIdx = resp.button_index ?? -1;
if (btnIdx === 1) {
pendingStepType = 'file_permission_conversation';
} else {
pendingStepType = 'file_permission_once';
}
} }
} }
// Also handle when step_type was explicitly set
if (pendingStepType === 'file_permission') {
const btnIdx = resp.button_index ?? -1;
pendingStepType = btnIdx === 1 ? 'file_permission_conversation' : 'file_permission_once';
}
} catch { } } catch { }
} }
@@ -2252,8 +2273,10 @@ async function tryApprovalStrategies(approved: boolean, sessionId: string, stepT
} else if (typeLower.includes('invoke_subagent') || typeLower.includes('extension_code')) { } else if (typeLower.includes('invoke_subagent') || typeLower.includes('extension_code')) {
interactionPayload = { runExtensionCode: { confirm: true } }; interactionPayload = { runExtensionCode: { confirm: true } };
} else if (typeLower.includes('file_permission')) { } else if (typeLower.includes('file_permission')) {
// FilePermissionInteraction: allow=true, scope=ONCE(1) or CONVERSATION(2) // FilePermissionInteraction: allow=true, scope depends on cmd
interactionPayload = { filePermission: { allow: true, scope: 1 } }; // PERMISSION_SCOPE_ONCE // file_permission_once → 1, file_permission_conversation → 2
const scope = typeLower.includes('conversation') ? 2 : 1;
interactionPayload = { filePermission: { allow: true, scope } };
} else if (typeLower.includes('elicitation')) { } else if (typeLower.includes('elicitation')) {
interactionPayload = { elicitation: {} }; // ElicitationInteraction (TBD) interactionPayload = { elicitation: {} }; // ElicitationInteraction (TBD)
} else { } else {