From c6e0b8a3bbe8b28015f3caf7e1d9a695424debe6 Mon Sep 17 00:00:00 2001 From: Megan Mott Date: Wed, 1 Jul 2026 10:57:18 -0700 Subject: [PATCH 1/2] intial --- .../copilotOnRails/extension/autopilot.ts | 21 +++++++++++++++++++ .../copilotOnRails/views/LocalPlanView.tsx | 6 ++++-- .../copilotOnRails/views/ScaffoldPlanView.tsx | 6 ++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/webviews/copilotOnRails/extension/autopilot.ts b/src/webviews/copilotOnRails/extension/autopilot.ts index 24754b64..40084a7f 100644 --- a/src/webviews/copilotOnRails/extension/autopilot.ts +++ b/src/webviews/copilotOnRails/extension/autopilot.ts @@ -21,6 +21,8 @@ const MAX_REQUESTS_KEY = 'maxRequests'; /** Workspace request budget used for scaffolding runs. */ export const WORKSPACE_MAX_REQUESTS = 9999; +const PERMISSIONS_SECTION = 'chat.permissions'; +const PERMISSIONS_KEY = 'default'; /** * Maximum wall-clock duration an autopilot run may keep global auto-approve on. @@ -38,6 +40,7 @@ export const DEBUG_PLAN_GLOB = '.azure/vscode-debug-plan.md'; /** globalState keys used to survive window reloads mid-run. */ const STATE_ACTIVE = 'azureResourceGroups.autopilot.active'; const STATE_PRIOR_VALUE = 'azureResourceGroups.autopilot.priorAutoApprove'; +const STATE_PRIOR_PERMISSION_LEVEL = 'azureResourceGroups.autopilot.priorPermissionLevel'; /** Epoch ms after which an active run is considered stale and auto-restored. */ const STATE_DEADLINE = 'azureResourceGroups.autopilot.deadline'; @@ -84,6 +87,17 @@ export async function raiseWorkspaceMaxRequests(): Promise { } } +function getPermissionLevelValue(): unknown { + const config = vscode.workspace.getConfiguration(PERMISSIONS_SECTION); + const inspected = config.inspect(PERMISSIONS_KEY); + return inspected?.globalValue; +} + +async function setPermissionLevelValue(value: unknown): Promise { + const config = vscode.workspace.getConfiguration(PERMISSIONS_SECTION); + await config.update(PERMISSIONS_KEY, value, vscode.ConfigurationTarget.Global); +} + function showStatusBarItem(): void { if (!statusBarItem) { statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); @@ -162,6 +176,7 @@ export async function enableAutopilot(context: vscode.ExtensionContext): Promise // Don't clobber a previously-saved prior value if autopilot is already on. if (context.globalState.get(STATE_ACTIVE) !== true) { await context.globalState.update(STATE_PRIOR_VALUE, getAutoApproveValue() ?? null); + await context.globalState.update(STATE_PRIOR_PERMISSION_LEVEL, getPermissionLevelValue() ?? null); } const deadline = Date.now() + MAX_RUN_DURATION_MS; await context.globalState.update(STATE_ACTIVE, true); @@ -169,6 +184,7 @@ export async function enableAutopilot(context: vscode.ExtensionContext): Promise await setAutoApproveValue(true); await raiseWorkspaceMaxRequests(); + await setPermissionLevelValue('autopilot'); armAutopilot(deadline); } @@ -188,8 +204,13 @@ export async function disableAutopilot(): Promise { const prior = context.globalState.get(STATE_PRIOR_VALUE); // `null` means there was no explicit global value, so clear it. await setAutoApproveValue(prior === null ? undefined : prior); + + const priorPermission = context.globalState.get(STATE_PRIOR_PERMISSION_LEVEL); + await setPermissionLevelValue(priorPermission === null ? undefined : priorPermission); + await context.globalState.update(STATE_ACTIVE, false); await context.globalState.update(STATE_PRIOR_VALUE, undefined); + await context.globalState.update(STATE_PRIOR_PERMISSION_LEVEL, undefined); await context.globalState.update(STATE_DEADLINE, undefined); } diff --git a/src/webviews/copilotOnRails/views/LocalPlanView.tsx b/src/webviews/copilotOnRails/views/LocalPlanView.tsx index 23dfcaa4..37e2971e 100644 --- a/src/webviews/copilotOnRails/views/LocalPlanView.tsx +++ b/src/webviews/copilotOnRails/views/LocalPlanView.tsx @@ -190,8 +190,10 @@ export const LocalPlanView = (): JSX.Element => { ); const isAlreadyApproved = useMemo(() => { - const s = plan?.status?.trim().toLowerCase(); - return s === "approved"; + const s = plan?.status?.trim().toLowerCase().replace(/[*_~`]/g, ''); + if (!s) { return false; } + const unapprovedStatuses = new Set(['planning', 'unknown', 'draft', 'awaiting approval', 'new']); + return !unapprovedStatuses.has(s); }, [plan?.status]); useEffect(() => { diff --git a/src/webviews/copilotOnRails/views/ScaffoldPlanView.tsx b/src/webviews/copilotOnRails/views/ScaffoldPlanView.tsx index a52ec67c..8b8d8f5c 100644 --- a/src/webviews/copilotOnRails/views/ScaffoldPlanView.tsx +++ b/src/webviews/copilotOnRails/views/ScaffoldPlanView.tsx @@ -205,8 +205,10 @@ export const ScaffoldPlanView = (): JSX.Element => { ); const isAlreadyApproved = useMemo(() => { - const s = plan?.status?.trim().toLowerCase(); - return s === 'approved'; + const s = plan?.status?.trim().toLowerCase().replace(/[*_~`]/g, ''); + if (!s) { return false; } + const unapprovedStatuses = new Set(['planning', 'unknown', 'draft', 'awaiting approval', 'new']); + return !unapprovedStatuses.has(s); }, [plan?.status]); const editedCells = useMemo(() => { From e82f59e418121f7aa20724392dc17acf924919d7 Mon Sep 17 00:00:00 2001 From: Megan Mott Date: Wed, 15 Jul 2026 10:50:07 -0700 Subject: [PATCH 2/2] disable --- .../copilotOnRails/extension/openLocalDevNextStepsView.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/webviews/copilotOnRails/extension/openLocalDevNextStepsView.ts b/src/webviews/copilotOnRails/extension/openLocalDevNextStepsView.ts index 5b5be4de..92eabcdc 100644 --- a/src/webviews/copilotOnRails/extension/openLocalDevNextStepsView.ts +++ b/src/webviews/copilotOnRails/extension/openLocalDevNextStepsView.ts @@ -5,6 +5,7 @@ import * as vscode from "vscode"; import { type LocalDevNextStepsViewConfiguration } from "../views/utils/viewConfigTypes"; +import { disableAutopilot } from "./autopilot"; import { LocalDevNextStepsViewController } from "./controllers/LocalDevNextStepsViewController"; import { closeLoadingView } from "./openLoadingView"; @@ -18,6 +19,8 @@ let controller: LocalDevNextStepsViewController | undefined; * whether `api-test-collections/` contains any files in the workspace. */ export async function openLocalDevNextStepsView(hasApiTests?: boolean): Promise { + await disableAutopilot(); + let apiTestsDetected = !!hasApiTests; if (!apiTestsDetected) { const results = await vscode.workspace.findFiles('api-test-collections/**/*', undefined, 1);