|
| 1 | +import { readFile } from "node:fs/promises"; |
| 2 | +import { join } from "node:path"; |
| 3 | + |
| 4 | +import type { JsonObject, PermissionMode } from "@pymodel/pythinker-code-sdk"; |
| 5 | + |
| 6 | +export const LEGACY_APPROVAL_METADATA_KEY = "vscode_legacy_approval"; |
| 7 | + |
| 8 | +export interface LegacyApprovalFlags { |
| 9 | + readonly yolo: boolean; |
| 10 | + readonly afk: boolean; |
| 11 | +} |
| 12 | + |
| 13 | +export function readLegacyApprovalFlags( |
| 14 | + metadata: Readonly<Record<string, unknown>> | undefined, |
| 15 | +): LegacyApprovalFlags | undefined { |
| 16 | + const value = metadata?.[LEGACY_APPROVAL_METADATA_KEY]; |
| 17 | + return parseLegacyApprovalFlags(value); |
| 18 | +} |
| 19 | + |
| 20 | +export async function readMigratedLegacyApprovalFlags( |
| 21 | + metadata: Readonly<Record<string, unknown>> | undefined, |
| 22 | +): Promise<LegacyApprovalFlags | undefined> { |
| 23 | + const sourcePath = metadata?.["pythinker_cli_source_path"]; |
| 24 | + if (typeof sourcePath !== "string" || sourcePath.length === 0) return undefined; |
| 25 | + let text: string; |
| 26 | + try { |
| 27 | + text = await readFile(join(sourcePath, "state.json"), "utf8"); |
| 28 | + } catch (error) { |
| 29 | + if ((error as NodeJS.ErrnoException).code === "ENOENT") return undefined; |
| 30 | + throw error; |
| 31 | + } |
| 32 | + const state = JSON.parse(text) as { readonly approval?: unknown }; |
| 33 | + return parseLegacyApprovalFlags(state.approval); |
| 34 | +} |
| 35 | + |
| 36 | +function parseLegacyApprovalFlags(value: unknown): LegacyApprovalFlags | undefined { |
| 37 | + if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined; |
| 38 | + const yolo = Reflect.get(value, "yolo"); |
| 39 | + const afk = Reflect.get(value, "afk"); |
| 40 | + if (typeof yolo !== "boolean" && typeof afk !== "boolean") return undefined; |
| 41 | + return { |
| 42 | + yolo: typeof yolo === "boolean" ? yolo : false, |
| 43 | + afk: typeof afk === "boolean" ? afk : false, |
| 44 | + }; |
| 45 | +} |
| 46 | + |
| 47 | +export function legacyApprovalMetadata(flags: LegacyApprovalFlags): JsonObject { |
| 48 | + return { |
| 49 | + [LEGACY_APPROVAL_METADATA_KEY]: { |
| 50 | + yolo: flags.yolo, |
| 51 | + afk: flags.afk, |
| 52 | + }, |
| 53 | + }; |
| 54 | +} |
| 55 | + |
| 56 | +export function corePermissionForLegacyApproval(flags: LegacyApprovalFlags): PermissionMode { |
| 57 | + if (flags.afk) return "auto"; |
| 58 | + return flags.yolo ? "yolo" : "manual"; |
| 59 | +} |
| 60 | + |
| 61 | +/** |
| 62 | + * The global `pythinker.yoloMode` setting is authoritative whenever a session |
| 63 | + * attaches to the runtime; afk stays per-session because it has no global |
| 64 | + * setting counterpart. |
| 65 | + */ |
| 66 | +export function withGlobalYoloMode( |
| 67 | + flags: LegacyApprovalFlags, |
| 68 | + yoloMode: boolean, |
| 69 | +): LegacyApprovalFlags { |
| 70 | + return flags.yolo === yoloMode ? flags : { yolo: yoloMode, afk: flags.afk }; |
| 71 | +} |
0 commit comments