/** * Permission-gate helpers for native BooCode write tools. The gate comes from * the per-run inference context (`ToolContext.permissionMode`): * plan — deny the write (read-only); nothing is staged. * bypass — apply the staged change immediately (no queue, no approval). * ask / undefined — leave it in the pending-changes queue for review. */ import type { ToolContext } from './types.js'; import { applyOne } from '../pending_changes.js'; /** Result returned when a write is denied under Plan (read-only) mode. */ export function denyReadOnly(operation: string): unknown { return { status: 'denied', operation, message: `Read-only (Plan) permission mode — ${operation} is not permitted. Switch to Ask or Bypass to make changes.`, }; } /** Finalize a just-staged change per the permission gate: apply now under Bypass, * otherwise return it as queued for the human to approve. */ export async function finalizeWrite( context: ToolContext, projectRoot: string, change: { id: string; file_path: string; operation: string }, queuedHint: string, ): Promise { if (context.permissionMode === 'bypass') { const res = await applyOne(context.sql, change.id, projectRoot); console.log( `[write-gate] bypass apply ${change.operation} ${change.file_path} -> ${res.success ? 'applied' : 'FAILED: ' + (res.error ?? '?')}`, ); return { status: res.success ? 'applied' : 'failed', change_id: change.id, file_path: change.file_path, operation: change.operation, message: res.success ? `${change.operation} applied to ${change.file_path}.` : `Apply failed for ${change.file_path}: ${res.error ?? 'unknown error'}. Left in the pending queue.`, }; } console.log( `[write-gate] ${context.permissionMode ?? 'legacy'} queued ${change.operation} ${change.file_path}`, ); return { status: 'queued', change_id: change.id, file_path: change.file_path, operation: change.operation, message: queuedHint, }; }