49f87c4da3
Whole tree from parallel sessions, plus the version bump: - Clone: a queue with live progress (Add workspace and extra folders), clones run under nice/ionice so the machine stays responsive. - Settings → AI tools → Session defaults: a new session's default permission mode / bypass per account. - Chat lists the background subagents that have not reported back yet. - A file pasted or dropped into a claude pane goes in as an @ mention. - Changes panel: say why amend/undo is refused on a pushed commit. - openapi.yaml regenerated (Artifacts, Host, resumeById).
88 lines
3.6 KiB
TypeScript
88 lines
3.6 KiB
TypeScript
/**
|
|
* @file sessionDefaults.ts
|
|
* @description The account's own starting choices for new work, picked in the
|
|
* first-run setup (docs/plans/onboarding) or Settings → AI tools → Session
|
|
* defaults, and synced per account like every other preference
|
|
* (`lib/userPrefs.ts`): the AI a new workspace starts on, the permission mode
|
|
* a new Claude session starts in, and a new Codex session's sandbox, approval
|
|
* and bypass. Bypass (Claude's `bypassPermissions`, Codex's bypass switch) may
|
|
* be a default only because the user turned it on in Settings behind a
|
|
* confirm — the first-run setup never offers it, and the pet chat never
|
|
* starts in it (`readDefaultMode({ safe: true })`).
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
import type { CodexApproval, CodexSandbox, PermissionMode } from "./api";
|
|
|
|
const TOOL_KEY = "agenthub.defaultTool";
|
|
const MODE_KEY = "agenthub.permissionMode";
|
|
const CODEX_SANDBOX_KEY = "agenthub.codex.sandbox";
|
|
const CODEX_APPROVAL_KEY = "agenthub.codex.approval";
|
|
const CODEX_BYPASS_KEY = "agenthub.codex.bypass";
|
|
|
|
/** The permission modes a default may be. */
|
|
export const DEFAULT_MODES = ["auto", "acceptEdits", "default", "plan", "bypassPermissions"] as const;
|
|
export type DefaultMode = (typeof DEFAULT_MODES)[number];
|
|
/** The ones the first-run setup offers: never bypass. */
|
|
export const SAFE_MODES = DEFAULT_MODES.filter((m) => m !== "bypassPermissions");
|
|
|
|
export const CODEX_SANDBOXES: readonly CodexSandbox[] = [
|
|
"read-only",
|
|
"workspace-write",
|
|
"danger-full-access",
|
|
];
|
|
export const CODEX_APPROVALS: readonly CodexApproval[] = ["on-request", "never"];
|
|
|
|
function read(key: string): string | null {
|
|
try {
|
|
return localStorage.getItem(key);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
function write(key: string, value: string): void {
|
|
try {
|
|
localStorage.setItem(key, value);
|
|
} catch {
|
|
/* storage blocked */
|
|
}
|
|
}
|
|
|
|
/** The account's own default AI tool id, or null (the install's default applies). */
|
|
export const readDefaultTool = (): string | null => read(TOOL_KEY);
|
|
export const writeDefaultTool = (id: string): void => write(TOOL_KEY, id);
|
|
|
|
/** The permission mode a new Claude session starts in ("auto" when none was
|
|
* picked); `safe` turns a bypass default into "auto". */
|
|
export function readDefaultMode({ safe = false }: { safe?: boolean } = {}): PermissionMode {
|
|
const v = read(MODE_KEY);
|
|
if (safe && v === "bypassPermissions") return "auto";
|
|
return (DEFAULT_MODES as readonly string[]).includes(v ?? "") ? (v as DefaultMode) : "auto";
|
|
}
|
|
export function writeDefaultMode(mode: DefaultMode): void {
|
|
if ((DEFAULT_MODES as readonly string[]).includes(mode)) write(MODE_KEY, mode);
|
|
}
|
|
|
|
export interface CodexDefaults {
|
|
sandbox: CodexSandbox;
|
|
approval: CodexApproval;
|
|
bypass: boolean;
|
|
}
|
|
|
|
/** A new Codex session's sandbox, approval and bypass (Codex's own defaults when none was picked). */
|
|
export function readCodexDefaults(): CodexDefaults {
|
|
const sandbox = read(CODEX_SANDBOX_KEY) as CodexSandbox | null;
|
|
const approval = read(CODEX_APPROVAL_KEY) as CodexApproval | null;
|
|
return {
|
|
sandbox: sandbox && CODEX_SANDBOXES.includes(sandbox) ? sandbox : "workspace-write",
|
|
approval: approval && CODEX_APPROVALS.includes(approval) ? approval : "on-request",
|
|
bypass: read(CODEX_BYPASS_KEY) === "true",
|
|
};
|
|
}
|
|
export function writeCodexDefaults(patch: Partial<CodexDefaults>): void {
|
|
if (patch.sandbox && CODEX_SANDBOXES.includes(patch.sandbox)) write(CODEX_SANDBOX_KEY, patch.sandbox);
|
|
if (patch.approval && CODEX_APPROVALS.includes(patch.approval))
|
|
write(CODEX_APPROVAL_KEY, patch.approval);
|
|
if (patch.bypass !== undefined) write(CODEX_BYPASS_KEY, String(patch.bypass === true));
|
|
}
|