@mzwing/pi-permission-auto-review 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -630,7 +630,8 @@ function buildStreamOptions(runtime, signal, timeoutMs, reasoning) {
630
630
  maxRetries: 0,
631
631
  maxTokens: MAX_OUTPUT_TOKENS,
632
632
  signal,
633
- timeoutMs
633
+ timeoutMs,
634
+ sessionId: runtime.sessionManager.getSessionId()
634
635
  };
635
636
  if (reasoning && runtime.config.reasoning !== "off") options.reasoning = runtime.config.reasoning;
636
637
  return options;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["getPermissionsService","getKeyedPermissionsService","ready"],"sources":["../src/circuit-breaker.ts","../src/command.ts","../src/config-store.ts","../src/model.ts","../src/reviewer.ts","../src/extension.ts","../src/index.ts"],"sourcesContent":["const MAX_CONSECUTIVE_DENIALS = 3\nconst RECENT_WINDOW_SIZE = 50\nconst MAX_RECENT_DENIALS = 10\n\nexport class DenialCircuitBreaker {\n private consecutiveDenials = 0\n private recentDenials: boolean[] = []\n\n isOpen(): boolean {\n return (\n this.consecutiveDenials >= MAX_CONSECUTIVE_DENIALS ||\n this.recentDenials.filter(Boolean).length >= MAX_RECENT_DENIALS\n )\n }\n\n recordDenied(): void {\n this.consecutiveDenials += 1\n this.recordRecent(true)\n }\n\n recordNonDenial(): void {\n this.consecutiveDenials = 0\n this.recordRecent(false)\n }\n\n resetTurn(): void {\n this.consecutiveDenials = 0\n this.recentDenials = []\n }\n\n private recordRecent(denied: boolean): void {\n this.recentDenials.push(denied)\n if (this.recentDenials.length > RECENT_WINDOW_SIZE) {\n this.recentDenials.shift()\n }\n }\n}\n","import type { AutoReviewConfigStore, AutoReviewConfigScope } from './config-store.js'\nimport type { AutoReviewConfig, AutoReviewConfigFile, LoadConfigResult } from './config.js'\nimport type { ExtensionAPI, ExtensionCommandContext } from '@earendil-works/pi-coding-agent'\nimport { DEFAULT_CONFIG, DEFAULT_MODEL, DEFAULT_PROVIDER, REASONING_LEVELS } from './config.js'\n\nconst COMMAND_NAME = 'permission-auto-review'\nconst USAGE = 'Usage: /permission-auto-review [show|path|reset [global|project]|help]'\nconst INHERIT = 'Use inherited value'\nconst CUSTOM = 'Enter custom value...'\nconst SAVE = 'Save changes'\nconst CANCEL = 'Cancel'\nconst WHITESPACE = /\\s+/\n\n/** Every editable config key, so a new one cannot be added without a menu entry. */\ntype ConfigField = Exclude<keyof AutoReviewConfig, '$schema'>\n\ninterface FieldSpec {\n label: string\n format?: (value: unknown) => string\n edit: (\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n effective: AutoReviewConfig,\n ) => Promise<AutoReviewConfigFile>\n}\n\nexport type AutoReviewActivationResult = { kind: 'active' } | { kind: 'pending' } | { kind: 'failed'; message: string }\n\nexport interface AutoReviewCommandController {\n configStore: AutoReviewConfigStore\n getActiveConfig: () => AutoReviewConfig | undefined\n applyConfig: (result: LoadConfigResult) => AutoReviewActivationResult\n}\n\ninterface ConfigLayers {\n global: AutoReviewConfigFile\n project: AutoReviewConfigFile\n}\n\nfunction resolveOrigin(layers: ConfigLayers, field: ConfigField): AutoReviewConfigScope | 'default' {\n if (Object.hasOwn(layers.project, field)) {\n return 'project'\n }\n if (Object.hasOwn(layers.global, field)) {\n return 'global'\n }\n return 'default'\n}\n\nfunction removeField(config: AutoReviewConfigFile, field: ConfigField): AutoReviewConfigFile {\n const next = { ...config }\n delete next[field]\n return next\n}\n\nfunction uniqueSorted(values: string[]): string[] {\n return [...new Set(values)].toSorted((left, right) => left.localeCompare(right))\n}\n\nasync function chooseStringValue(\n ctx: ExtensionCommandContext,\n title: string,\n knownValues: string[],\n currentValue: string,\n): Promise<{ kind: 'inherit' } | { kind: 'value'; value: string } | undefined> {\n const values = uniqueSorted([...knownValues, currentValue])\n const valueOptions = values.map(value => `Value: ${value}`)\n const selected = await ctx.ui.select(title, [INHERIT, ...valueOptions, CUSTOM])\n if (selected === undefined) {\n return undefined\n }\n if (selected === INHERIT) {\n return { kind: 'inherit' }\n }\n if (selected === CUSTOM) {\n const custom = await ctx.ui.input(title, currentValue)\n const normalized = custom?.trim()\n if (normalized === undefined || normalized.length === 0) {\n return undefined\n }\n return { kind: 'value', value: normalized }\n }\n const index = valueOptions.indexOf(selected)\n return index < 0 ? undefined : { kind: 'value', value: values[index] ?? currentValue }\n}\n\nasync function editStringField(\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n field: 'provider' | 'model',\n effective: AutoReviewConfig,\n): Promise<AutoReviewConfigFile> {\n const registry = ctx.modelRegistry\n const knownValues =\n field === 'provider'\n ? registry.getAll().map(model => model.provider)\n : registry\n .getAll()\n .filter(model => model.provider === effective.provider)\n .map(model => model.id)\n if (field === 'provider') {\n knownValues.push(DEFAULT_PROVIDER)\n } else if (effective.provider === DEFAULT_PROVIDER) {\n knownValues.push(DEFAULT_MODEL)\n }\n\n const title = field === 'provider' ? 'Configure Provider' : 'Configure Model'\n const selected = await chooseStringValue(ctx, title, knownValues, effective[field])\n if (selected === undefined) {\n return draft\n }\n if (selected.kind === 'inherit') {\n return removeField(draft, field)\n }\n return field === 'provider' ? { ...draft, provider: selected.value } : { ...draft, model: selected.value }\n}\n\nasync function editReasoning(ctx: ExtensionCommandContext, draft: AutoReviewConfigFile): Promise<AutoReviewConfigFile> {\n const selected = await ctx.ui.select('Configure Reasoning', [INHERIT, ...REASONING_LEVELS])\n if (selected === INHERIT) {\n return removeField(draft, 'reasoning')\n }\n const reasoning = REASONING_LEVELS.find(level => level === selected)\n return reasoning === undefined ? draft : { ...draft, reasoning }\n}\n\nasync function editTimeout(\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n currentValue: number,\n): Promise<AutoReviewConfigFile> {\n const action = await ctx.ui.select('Configure Timeout', [INHERIT, 'Enter timeout...'])\n if (action === INHERIT) {\n return removeField(draft, 'timeoutMs')\n }\n if (action !== 'Enter timeout...') {\n return draft\n }\n\n const source = await ctx.ui.input('Timeout in milliseconds', String(currentValue))\n if (source === undefined) {\n return draft\n }\n const timeoutMs = Number(source.trim())\n if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 300_000) {\n ctx.ui.notify('timeoutMs must be an integer between 1 and 300000.', 'warning')\n return draft\n }\n return { ...draft, timeoutMs }\n}\n\nasync function editBaselinePolicy(\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n): Promise<AutoReviewConfigFile> {\n const selected = await ctx.ui.select('Configure Baseline Policy', [INHERIT, 'Enabled', 'Disabled'])\n if (selected === INHERIT) {\n return removeField(draft, 'includeBaselinePolicy')\n }\n if (selected === 'Enabled' || selected === 'Disabled') {\n return { ...draft, includeBaselinePolicy: selected === 'Enabled' }\n }\n return draft\n}\n\nasync function editAdditionalPolicy(\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n currentValue: string | undefined,\n): Promise<AutoReviewConfigFile> {\n const selected = await ctx.ui.select('Configure Additional Policy', ['Edit policy...', INHERIT])\n if (selected === INHERIT) {\n return removeField(draft, 'additionalPolicy')\n }\n if (selected !== 'Edit policy...') {\n return draft\n }\n const value = await ctx.ui.editor('Additional review policy', currentValue ?? '')\n if (value === undefined) {\n return draft\n }\n const additionalPolicy = value.trim()\n return additionalPolicy.length === 0 ? removeField(draft, 'additionalPolicy') : { ...draft, additionalPolicy }\n}\n\nconst fields: Record<ConfigField, FieldSpec> = {\n provider: {\n label: 'Provider',\n edit: async (ctx, draft, effective) => editStringField(ctx, draft, 'provider', effective),\n },\n model: {\n label: 'Model',\n edit: async (ctx, draft, effective) => editStringField(ctx, draft, 'model', effective),\n },\n reasoning: {\n label: 'Reasoning',\n edit: async (ctx, draft) => editReasoning(ctx, draft),\n },\n timeoutMs: {\n label: 'Timeout',\n format: value => (typeof value === 'number' ? `${value} ms` : String(value ?? 'not set')),\n edit: async (ctx, draft, effective) => editTimeout(ctx, draft, effective.timeoutMs),\n },\n includeBaselinePolicy: {\n label: 'Baseline policy',\n edit: async (ctx, draft) => editBaselinePolicy(ctx, draft),\n },\n additionalPolicy: {\n label: 'Additional policy',\n format: value => (typeof value === 'string' && value.length > 0 ? 'configured' : 'not set'),\n edit: async (ctx, draft, effective) => editAdditionalPolicy(ctx, draft, effective.additionalPolicy),\n },\n}\n\nconst configFields = Object.keys(fields) as ConfigField[]\n\n/**\n * Effective values for display. The draft being edited may still violate the cross-field policy\n * invariant, so this resolves layer precedence directly rather than through the schema, which\n * rejects the whole object.\n */\nfunction mergeLayers(layers: ConfigLayers): AutoReviewConfig {\n const merged = { ...DEFAULT_CONFIG }\n for (const field of configFields) {\n const value = layers.project[field] ?? layers.global[field]\n if (value !== undefined) {\n Object.assign(merged, { [field]: value })\n }\n }\n\n return merged\n}\n\nfunction formatFieldValue(field: ConfigField, value: unknown): string {\n return fields[field].format?.(value) ?? String(value ?? 'not set')\n}\n\nfunction formatMenuOptions(effective: AutoReviewConfig, layers: ConfigLayers, scope: AutoReviewConfigScope): string[] {\n return configFields.map(field => {\n const origin = resolveOrigin(layers, field)\n const scopeState = Object.hasOwn(layers[scope], field) ? 'override' : 'inherit'\n return `${fields[field].label}: ${formatFieldValue(field, effective[field])} (source: ${origin}; ${scope}: ${scopeState})`\n })\n}\n\nasync function chooseScope(ctx: ExtensionCommandContext, title: string): Promise<AutoReviewConfigScope | undefined> {\n const selected = await ctx.ui.select(title, ['Global configuration', 'Project configuration'])\n if (selected === 'Global configuration') {\n return 'global'\n }\n if (selected === 'Project configuration') {\n return 'project'\n }\n return undefined\n}\n\nasync function openSettingsMenu(ctx: ExtensionCommandContext, controller: AutoReviewCommandController): Promise<void> {\n if (ctx.mode !== 'tui') {\n ctx.ui.notify(`/${COMMAND_NAME} requires interactive TUI mode.`, 'warning')\n return\n }\n\n await ctx.waitForIdle()\n const scope = await chooseScope(ctx, 'Select configuration scope')\n if (scope === undefined) {\n return\n }\n\n const selected = controller.configStore.readScope(ctx.cwd, scope)\n const other = controller.configStore.readScope(ctx.cwd, scope === 'global' ? 'project' : 'global')\n if (!selected.valid) {\n ctx.ui.notify(\n `Cannot edit config at '${selected.path}': ${selected.issue.message}. Use reset to remove it or fix it manually.`,\n 'error',\n )\n return\n }\n if (!other.valid) {\n ctx.ui.notify(\n `Cannot edit config at '${other.path}': ${other.issue.message}. Use reset to remove it or fix it manually.`,\n 'error',\n )\n return\n }\n\n let draft: AutoReviewConfigFile = { ...selected.config }\n while (true) {\n const layers: ConfigLayers =\n scope === 'global' ? { global: draft, project: other.config } : { global: other.config, project: draft }\n const effective = mergeLayers(layers)\n const fieldOptions = formatMenuOptions(effective, layers, scope)\n const selectedOption = await ctx.ui.select(`Permission auto-review settings (${scope})`, [\n ...fieldOptions,\n SAVE,\n CANCEL,\n ])\n if (selectedOption === undefined || selectedOption === CANCEL) {\n return\n }\n if (selectedOption === SAVE) {\n const saved = controller.configStore.save(selected, draft)\n if (!saved.ok) {\n ctx.ui.notify(saved.message, 'error')\n continue\n }\n const activation = controller.applyConfig(saved.loadResult)\n if (activation.kind === 'failed') {\n ctx.ui.notify(`Config saved, but the current reviewer could not be replaced: ${activation.message}`, 'error')\n } else if (activation.kind === 'pending') {\n ctx.ui.notify('Config saved. It will become active when pi-permission-system is ready.', 'warning')\n } else {\n ctx.ui.notify('Config saved and applied without reloading the Pi session.', 'info')\n }\n return\n }\n\n const field = configFields[fieldOptions.indexOf(selectedOption)]\n if (field !== undefined) {\n draft = await fields[field].edit(ctx, draft, effective)\n }\n }\n}\n\nfunction getScopeLayers(store: AutoReviewConfigStore, cwd: string): ConfigLayers | undefined {\n const global = store.readScope(cwd, 'global')\n const project = store.readScope(cwd, 'project')\n return global.valid && project.valid ? { global: global.config, project: project.config } : undefined\n}\n\nfunction showConfig(ctx: ExtensionCommandContext, controller: AutoReviewCommandController): void {\n const paths = controller.configStore.getPaths(ctx.cwd)\n const active = controller.getActiveConfig()\n const layers = getScopeLayers(controller.configStore, ctx.cwd)\n if (active === undefined || layers === undefined) {\n const result = controller.configStore.load(ctx.cwd)\n const issues = result.issues.map(issue => `${issue.sourcePath}: ${issue.message}`).join('\\n')\n ctx.ui.notify(\n `Automatic review is disabled because the active config is invalid.${issues ? `\\n${issues}` : ''}`,\n 'warning',\n )\n return\n }\n\n const fields = configFields.map(field => {\n const origin = resolveOrigin(layers, field)\n return `${field}=${formatFieldValue(field, active[field])} (${origin})`\n })\n ctx.ui.notify(\n `permission-auto-review:\\n${fields.join('\\n')}\\nglobal=${paths.globalPath}\\nproject=${paths.projectPath}`,\n 'info',\n )\n}\n\nfunction showPaths(ctx: ExtensionCommandContext, controller: AutoReviewCommandController): void {\n const paths = controller.configStore.getPaths(ctx.cwd)\n ctx.ui.notify(\n `permission-auto-review config paths:\\nglobal=${paths.globalPath}\\nproject=${paths.projectPath}`,\n 'info',\n )\n}\n\nasync function resetConfig(\n ctx: ExtensionCommandContext,\n controller: AutoReviewCommandController,\n requestedScope: string | undefined,\n): Promise<void> {\n if (ctx.mode !== 'tui') {\n ctx.ui.notify(`/${COMMAND_NAME} reset requires interactive TUI mode.`, 'warning')\n return\n }\n await ctx.waitForIdle()\n\n let scope: AutoReviewConfigScope | undefined\n if (requestedScope === 'global' || requestedScope === 'project') {\n scope = requestedScope\n } else if (requestedScope === undefined) {\n scope = await chooseScope(ctx, 'Select configuration scope to reset')\n } else {\n ctx.ui.notify(USAGE, 'warning')\n return\n }\n if (scope === undefined) {\n return\n }\n\n const snapshot = controller.configStore.readScope(ctx.cwd, scope)\n const confirmed = await ctx.ui.confirm(\n `Reset ${scope} auto-review config?`,\n `Delete '${snapshot.path}' and immediately apply inherited values?`,\n )\n if (!confirmed) {\n return\n }\n\n const reset = controller.configStore.reset(snapshot)\n if (!reset.ok) {\n ctx.ui.notify(reset.message, 'error')\n return\n }\n const activation = controller.applyConfig(reset.loadResult)\n if (activation.kind === 'failed') {\n ctx.ui.notify(`Config reset, but the current reviewer could not be replaced: ${activation.message}`, 'error')\n } else if (activation.kind === 'pending') {\n ctx.ui.notify(\n `${scope} config reset. The inherited config will activate when pi-permission-system is ready.`,\n 'warning',\n )\n } else if (reset.loadResult.config === undefined) {\n ctx.ui.notify(\n `${scope} config reset, but automatic review remains disabled because another config layer is invalid.`,\n 'warning',\n )\n } else {\n ctx.ui.notify(`${scope} config reset and inherited values applied without reloading the Pi session.`, 'info')\n }\n}\n\nfunction getArgumentCompletions(\n argumentPrefix: string,\n): Array<{ value: string; label: string; description: string }> | null {\n const normalized = argumentPrefix.trimStart().toLowerCase()\n const items = normalized.startsWith('reset ')\n ? [\n {\n value: 'reset global',\n label: 'Reset global config',\n description: 'Delete the global auto-review config',\n },\n {\n value: 'reset project',\n label: 'Reset project config',\n description: 'Delete the project auto-review config',\n },\n ]\n : [\n {\n value: 'show',\n label: 'Show active config',\n description: 'Display effective values and their origins',\n },\n {\n value: 'path',\n label: 'Show config paths',\n description: 'Display global and project config paths',\n },\n {\n value: 'reset',\n label: 'Reset config',\n description: 'Delete one config layer and apply inherited values',\n },\n {\n value: 'help',\n label: 'Show help',\n description: 'Display command usage',\n },\n ]\n const filtered = items.filter(item => item.value.startsWith(normalized))\n return filtered.length > 0 ? filtered : null\n}\n\nexport function registerAutoReviewCommand(pi: ExtensionAPI, controller: AutoReviewCommandController): void {\n pi.registerCommand(COMMAND_NAME, {\n description: 'Configure pi-permission-auto-review without reloading the Pi session',\n getArgumentCompletions,\n handler: async (args, ctx) => {\n const normalized = args.trim().toLowerCase()\n if (!normalized) {\n await openSettingsMenu(ctx, controller)\n return\n }\n if (normalized === 'show') {\n showConfig(ctx, controller)\n return\n }\n if (normalized === 'path') {\n showPaths(ctx, controller)\n return\n }\n if (normalized === 'help') {\n ctx.ui.notify(USAGE, 'info')\n return\n }\n if (normalized === 'reset' || normalized.startsWith('reset ')) {\n const scope = normalized.split(WHITESPACE)[1]\n await resetConfig(ctx, controller, scope)\n return\n }\n ctx.ui.notify(USAGE, 'warning')\n },\n })\n}\n","import type { AutoReviewConfigFile, AutoReviewConfigPaths, ConfigIssue, LoadConfigResult } from './config.js'\nimport { mkdirSync, renameSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport {\n CONFIG_SCHEMA_URL,\n defaultAutoReviewAgentDir,\n getAutoReviewConfigPaths,\n loadAutoReviewConfig,\n parseAutoReviewConfigFile,\n readConfigFile,\n validateAutoReviewConfigFile,\n} from './config.js'\n\nexport type AutoReviewConfigScope = 'global' | 'project'\n\ninterface ScopeSnapshotBase {\n scope: AutoReviewConfigScope\n cwd: string\n path: string\n source: string | undefined\n}\n\nexport type AutoReviewScopeSnapshot =\n | (ScopeSnapshotBase & {\n valid: true\n config: AutoReviewConfigFile\n })\n | (ScopeSnapshotBase & {\n valid: false\n issue: ConfigIssue\n })\n\nexport type ConfigMutationResult = { ok: true; loadResult: LoadConfigResult } | { ok: false; message: string }\n\nexport interface AutoReviewConfigFileSystem {\n readFile: (path: string) => string | undefined\n writeFile: (path: string, source: string) => void\n rename: (sourcePath: string, destinationPath: string) => void\n mkdir: (path: string) => void\n unlink: (path: string) => void\n}\n\nexport interface AutoReviewConfigStoreOptions {\n agentDir?: string\n fileSystem?: AutoReviewConfigFileSystem\n}\n\nconst defaultFileSystem: AutoReviewConfigFileSystem = {\n readFile: readConfigFile,\n writeFile(path, source) {\n writeFileSync(path, source, 'utf8')\n },\n rename(sourcePath, destinationPath) {\n renameSync(sourcePath, destinationPath)\n },\n mkdir(path) {\n mkdirSync(path, { recursive: true })\n },\n unlink(path) {\n unlinkSync(path)\n },\n}\n\nfunction formatIssues(issues: ConfigIssue[]): string {\n return issues.map(issue => `${issue.sourcePath}: ${issue.message}`).join('\\n')\n}\n\nexport class AutoReviewConfigStore {\n private readonly agentDir: string\n private readonly fileSystem: AutoReviewConfigFileSystem\n\n constructor(options: AutoReviewConfigStoreOptions = {}) {\n this.agentDir = options.agentDir ?? defaultAutoReviewAgentDir()\n this.fileSystem = options.fileSystem ?? defaultFileSystem\n }\n\n getPaths(cwd: string): AutoReviewConfigPaths {\n return getAutoReviewConfigPaths(cwd, this.agentDir)\n }\n\n load(cwd: string): LoadConfigResult {\n return loadAutoReviewConfig({\n cwd,\n agentDir: this.agentDir,\n readFile: path => this.fileSystem.readFile(path),\n })\n }\n\n readScope(cwd: string, scope: AutoReviewConfigScope): AutoReviewScopeSnapshot {\n const paths = this.getPaths(cwd)\n const path = scope === 'global' ? paths.globalPath : paths.projectPath\n let source: string | undefined\n try {\n source = this.fileSystem.readFile(path)\n } catch (error) {\n return {\n scope,\n cwd,\n path,\n source: undefined,\n valid: false,\n issue: {\n sourcePath: path,\n message: error instanceof Error ? error.message : String(error),\n },\n }\n }\n\n if (source === undefined) {\n return { scope, cwd, path, source, valid: true, config: {} }\n }\n\n const parsed = parseAutoReviewConfigFile(source, path)\n if (!parsed.ok) {\n return { scope, cwd, path, source, valid: false, issue: parsed.issue }\n }\n return { scope, cwd, path, source, valid: true, config: parsed.config }\n }\n\n save(snapshot: AutoReviewScopeSnapshot, draft: AutoReviewConfigFile): ConfigMutationResult {\n if (!snapshot.valid) {\n return {\n ok: false,\n message: `Cannot save invalid config at '${snapshot.path}': ${snapshot.issue.message}`,\n }\n }\n\n const parsed = validateAutoReviewConfigFile(draft, snapshot.path)\n if (!parsed.ok) {\n return { ok: false, message: `${parsed.issue.sourcePath}: ${parsed.issue.message}` }\n }\n\n const source = this.serialize(parsed.config)\n const loadResult = this.loadWithOverride(snapshot, source)\n if (loadResult.config === undefined) {\n return { ok: false, message: formatIssues(loadResult.issues) }\n }\n\n const conflict = this.checkForConflict(snapshot)\n if (conflict !== undefined) {\n return { ok: false, message: conflict }\n }\n\n const tempPath = `${snapshot.path}.tmp`\n try {\n this.fileSystem.mkdir(dirname(snapshot.path))\n this.fileSystem.writeFile(tempPath, source)\n this.fileSystem.rename(tempPath, snapshot.path)\n } catch (error) {\n this.cleanupTempFile(tempPath)\n return {\n ok: false,\n message: `Failed to save config at '${snapshot.path}': ${error instanceof Error ? error.message : String(error)}`,\n }\n }\n\n return { ok: true, loadResult }\n }\n\n reset(snapshot: AutoReviewScopeSnapshot): ConfigMutationResult {\n if (!snapshot.valid && snapshot.source === undefined) {\n return {\n ok: false,\n message: `Cannot reset unreadable config at '${snapshot.path}': ${snapshot.issue.message}`,\n }\n }\n\n const conflict = this.checkForConflict(snapshot)\n if (conflict !== undefined) {\n return { ok: false, message: conflict }\n }\n\n if (snapshot.source !== undefined) {\n try {\n this.fileSystem.unlink(snapshot.path)\n } catch (error) {\n return {\n ok: false,\n message: `Failed to reset config at '${snapshot.path}': ${error instanceof Error ? error.message : String(error)}`,\n }\n }\n }\n\n return { ok: true, loadResult: this.loadWithOverride(snapshot, undefined) }\n }\n\n private loadWithOverride(snapshot: AutoReviewScopeSnapshot, source: string | undefined): LoadConfigResult {\n return loadAutoReviewConfig({\n cwd: snapshot.cwd,\n agentDir: this.agentDir,\n readFile: path => (path === snapshot.path ? source : this.fileSystem.readFile(path)),\n })\n }\n\n private serialize(config: AutoReviewConfigFile): string {\n const { $schema = CONFIG_SCHEMA_URL, ...fields } = config\n return `${JSON.stringify({ $schema, ...fields }, null, 2)}\\n`\n }\n\n private checkForConflict(snapshot: AutoReviewScopeSnapshot): string | undefined {\n let currentSource: string | undefined\n try {\n currentSource = this.fileSystem.readFile(snapshot.path)\n } catch (error) {\n return `Failed to re-read config at '${snapshot.path}': ${error instanceof Error ? error.message : String(error)}`\n }\n return currentSource === snapshot.source\n ? undefined\n : `Config at '${snapshot.path}' changed while it was being edited; reopen the command and try again.`\n }\n\n private cleanupTempFile(tempPath: string): void {\n try {\n this.fileSystem.unlink(tempPath)\n } catch {\n // The original write error is more actionable than a best-effort cleanup failure.\n }\n }\n}\n","import type { AutoReviewConfig } from './config.js'\nimport type { Api, Model, Provider } from '@earendil-works/pi-ai'\nimport type { ModelRegistry } from '@earendil-works/pi-coding-agent'\nimport { DEFAULT_MODEL, DEFAULT_PROVIDER } from './config.js'\n\nexport type ReviewModelRegistry = Pick<ModelRegistry, 'find' | 'getAll' | 'getProvider' | 'streamSimple'>\n\nexport type ResolveReviewModelResult =\n | { ok: true; value: Model<Api> }\n | {\n ok: false\n category: 'provider-unresolved' | 'model-unresolved'\n }\n\nfunction findCodexTemplate(registry: ReviewModelRegistry, provider: Provider<Api>): Model<Api> | undefined {\n return (\n registry.getAll().find(model => model.provider === DEFAULT_PROVIDER && model.api === 'openai-codex-responses') ??\n provider.getModels().find(model => model.api === 'openai-codex-responses')\n )\n}\n\nexport function resolveReviewModel(registry: ReviewModelRegistry, config: AutoReviewConfig): ResolveReviewModelResult {\n const provider = registry.getProvider(config.provider)\n if (provider === undefined) {\n return { ok: false, category: 'provider-unresolved' }\n }\n\n const registeredModel = registry.find(config.provider, config.model)\n if (registeredModel !== undefined) {\n return { ok: true, value: registeredModel }\n }\n\n if (config.provider !== DEFAULT_PROVIDER || config.model !== DEFAULT_MODEL) {\n return { ok: false, category: 'model-unresolved' }\n }\n\n const template = findCodexTemplate(registry, provider)\n if (template === undefined) {\n return { ok: false, category: 'model-unresolved' }\n }\n\n return {\n ok: true,\n value: {\n ...template,\n id: DEFAULT_MODEL,\n name: 'Codex Auto Review',\n reasoning: true,\n input: ['text'],\n },\n }\n}\n","import type { DenialCircuitBreaker } from './circuit-breaker.js'\nimport type { AutoReviewConfig } from './config.js'\nimport type { ReviewModelRegistry } from './model.js'\nimport type { TranscriptStats } from './transcript.js'\nimport type { ReviewAssessment } from './verdict.js'\nimport type { AssistantMessage, SimpleStreamOptions } from '@earendil-works/pi-ai'\nimport type { SessionManager } from '@earendil-works/pi-coding-agent'\nimport type { Authorizer, AuthorizerLog, PromptPermissionDetails } from '@gotgenes/pi-permission-system'\nimport { resolveReviewModel } from './model.js'\nimport { POLICY_REVISION } from './policy.js'\nimport { buildReviewPrompt } from './prompt.js'\nimport { renderTranscript } from './transcript.js'\nimport { parseReviewAssessment } from './verdict.js'\n\nconst RETRY_DELAYS_MS = [250, 1_000]\nconst MAX_ATTEMPTS = RETRY_DELAYS_MS.length + 1\nconst MAX_OUTPUT_TOKENS = 1_000\nconst DECISION_EVENT = 'auto_review.decision'\nconst FAILURE_EVENT = 'auto_review.failure'\nconst CIRCUIT_OPEN_EVENT = 'auto_review.circuit_open'\n\ntype FailureCategory =\n | 'provider-unresolved'\n | 'model-unresolved'\n | 'provider-error'\n | 'invalid-response'\n | 'timeout'\n | 'cancelled'\n | 'internal-error'\n\nexport interface ReviewerRuntime {\n config: AutoReviewConfig\n registry: ReviewModelRegistry\n sessionManager: Pick<SessionManager, 'getBranch'>\n circuitBreaker: DenialCircuitBreaker\n sessionSignal?: AbortSignal\n}\n\n/** The clock and timer, injectable so a test does not wait out a real retry delay. */\nexport interface ReviewerDependencies {\n now?: () => number\n sleep?: (milliseconds: number, signal: AbortSignal) => Promise<void>\n}\n\ninterface ContextDiagnostics extends TranscriptStats {\n policyRevision: string\n contextSource: 'active-branch'\n}\n\ninterface Failure {\n category: FailureCategory\n contextDiagnostics?: ContextDiagnostics\n}\n\ninterface ReviewCallResult {\n assessment: ReviewAssessment\n contextDiagnostics: ContextDiagnostics\n}\n\nfunction abortError(): Error {\n const error = new Error('operation aborted')\n error.name = 'AbortError'\n return error\n}\n\nasync function defaultSleep(milliseconds: number, signal: AbortSignal): Promise<void> {\n if (milliseconds <= 0) {\n return Promise.resolve()\n }\n return new Promise((resolve, reject) => {\n if (signal.aborted) {\n reject(abortError())\n return\n }\n const timer = setTimeout(resolve, milliseconds)\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(abortError())\n },\n { once: true },\n )\n })\n}\n\nasync function raceWithSignal<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) {\n return Promise.reject(abortError())\n }\n return new Promise((resolve, reject) => {\n const onAbort = (): void => reject(abortError())\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(\n value => {\n signal.removeEventListener('abort', onAbort)\n resolve(value)\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort)\n reject(error)\n },\n )\n })\n}\n\nfunction responseText(message: AssistantMessage): string {\n return message.content\n .filter((block): block is Extract<(typeof message.content)[number], { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n .join('')\n .trim()\n}\n\nfunction buildStreamOptions(\n runtime: ReviewerRuntime,\n signal: AbortSignal,\n timeoutMs: number,\n reasoning: boolean,\n): SimpleStreamOptions {\n const options: SimpleStreamOptions = {\n maxRetries: 0,\n maxTokens: MAX_OUTPUT_TOKENS,\n signal,\n timeoutMs,\n }\n if (reasoning && runtime.config.reasoning !== 'off') {\n options.reasoning = runtime.config.reasoning\n }\n return options\n}\n\n// The registry resolves the configured provider and its authentication at\n// request time, so an unusable Codex login surfaces as a provider error here\n// rather than as a separate pre-flight category.\nasync function callModel(\n registry: ReviewModelRegistry,\n model: Parameters<ReviewModelRegistry['streamSimple']>[0],\n systemPrompt: string,\n userPrompt: string,\n options: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n const stream = registry.streamSimple(\n model,\n {\n systemPrompt,\n messages: [\n {\n role: 'user',\n content: userPrompt,\n timestamp: Date.now(),\n },\n ],\n },\n options,\n )\n return stream.result()\n}\n\nfunction writeFailure(\n log: AuthorizerLog,\n runtime: ReviewerRuntime,\n details: PromptPermissionDetails,\n failure: Failure,\n durationMs: number,\n): void {\n const common = {\n requestId: details.requestId,\n provider: runtime.config.provider,\n model: runtime.config.model,\n outcome: 'defer',\n errorCategory: failure.category,\n durationMs,\n ...failure.contextDiagnostics,\n }\n log.review(DECISION_EVENT, common)\n log.debug(FAILURE_EVENT, common)\n}\n\nasync function runReview(\n runtime: ReviewerRuntime,\n details: PromptPermissionDetails,\n dependencies: Required<ReviewerDependencies>,\n): Promise<ReviewCallResult | Failure> {\n const startedAt = dependencies.now()\n const timeoutController = new AbortController()\n const timeout = setTimeout(() => timeoutController.abort(), runtime.config.timeoutMs)\n const signal =\n runtime.sessionSignal === undefined\n ? timeoutController.signal\n : AbortSignal.any([timeoutController.signal, runtime.sessionSignal])\n\n try {\n const transcript = renderTranscript(runtime.sessionManager.getBranch())\n const contextDiagnostics: ContextDiagnostics = {\n policyRevision: POLICY_REVISION,\n contextSource: 'active-branch',\n ...transcript.stats,\n }\n const failure = (category: FailureCategory): Failure => ({ category, contextDiagnostics })\n const resolved = resolveReviewModel(runtime.registry, runtime.config)\n if (!resolved.ok) {\n return failure(resolved.category)\n }\n\n const prompt = buildReviewPrompt(runtime.config, transcript, details)\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) {\n try {\n const remainingMs = Math.max(1, runtime.config.timeoutMs - (dependencies.now() - startedAt))\n const message = await raceWithSignal(\n callModel(\n runtime.registry,\n resolved.value,\n prompt.systemPrompt,\n prompt.userPrompt,\n buildStreamOptions(runtime, signal, remainingMs, resolved.value.reasoning),\n ),\n signal,\n )\n\n if (message.stopReason === 'error' || message.stopReason === 'aborted') {\n throw new Error(message.errorMessage ?? message.stopReason)\n }\n\n try {\n return {\n assessment: parseReviewAssessment(responseText(message)),\n contextDiagnostics,\n }\n } catch {\n return failure('invalid-response')\n }\n } catch {\n if (signal.aborted) {\n return failure(timeoutController.signal.aborted ? 'timeout' : 'cancelled')\n }\n if (attempt >= MAX_ATTEMPTS) {\n return failure('provider-error')\n }\n try {\n await dependencies.sleep(RETRY_DELAYS_MS[attempt - 1] ?? 0, signal)\n } catch {\n return failure(timeoutController.signal.aborted ? 'timeout' : 'cancelled')\n }\n }\n }\n return failure('provider-error')\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport function createPermissionReviewer(\n runtime: ReviewerRuntime,\n reviewerDependencies: ReviewerDependencies = {},\n): Authorizer['authorize'] {\n const dependencies: Required<ReviewerDependencies> = {\n now: reviewerDependencies.now ?? Date.now,\n sleep: reviewerDependencies.sleep ?? defaultSleep,\n }\n\n return async (details, _query, log) => {\n const startedAt = dependencies.now()\n try {\n if (runtime.circuitBreaker.isOpen()) {\n const reason =\n 'Too many denials this turn; further requests are refused unreviewed until the next turn. Ask the user for explicit approval before retrying'\n log.review(CIRCUIT_OPEN_EVENT, {\n requestId: details.requestId,\n provider: runtime.config.provider,\n model: runtime.config.model,\n outcome: 'deny',\n durationMs: 0,\n errorCategory: 'circuit-open',\n })\n return { kind: 'deny', reason }\n }\n\n const result = await runReview(runtime, details, dependencies)\n const durationMs = Math.max(0, dependencies.now() - startedAt)\n if ('category' in result) {\n runtime.circuitBreaker.recordNonDenial()\n writeFailure(log, runtime, details, result, durationMs)\n return { kind: 'defer' }\n }\n\n const { assessment, contextDiagnostics } = result\n log.review(DECISION_EVENT, {\n requestId: details.requestId,\n provider: runtime.config.provider,\n model: runtime.config.model,\n riskLevel: assessment.riskLevel,\n userAuthorization: assessment.userAuthorization,\n outcome: assessment.outcome,\n durationMs,\n ...contextDiagnostics,\n })\n\n if (assessment.outcome === 'allow') {\n runtime.circuitBreaker.recordNonDenial()\n return { kind: 'allow' }\n }\n\n runtime.circuitBreaker.recordDenied()\n // The reason is rendered after the host's own attribution sentence\n // (\"The 'auto-review' authorizer denied this ...\"), so it carries only\n // what that sentence does not: why, and the two grades behind the call.\n return {\n kind: 'deny',\n reason: `${assessment.rationale} (risk: ${assessment.riskLevel}, user authorization: ${assessment.userAuthorization})`,\n }\n } catch {\n // The chain does not isolate a link that throws, so every internal failure\n // has to leave here as a verdict.\n runtime.circuitBreaker.recordNonDenial()\n writeFailure(log, runtime, details, { category: 'internal-error' }, Math.max(0, dependencies.now() - startedAt))\n return { kind: 'defer' }\n }\n }\n}\n","import type { AutoReviewActivationResult } from './command.js'\nimport type { AutoReviewConfig, LoadConfigResult } from './config.js'\nimport type { ExtensionAPI, ModelRegistry, SessionManager } from '@earendil-works/pi-coding-agent'\nimport type { Authorizer, PermissionsReadyEvent, PermissionsService } from '@gotgenes/pi-permission-system'\nimport {\n getPermissionsService as getKeyedPermissionsService,\n PERMISSIONS_READY_CHANNEL,\n} from '@gotgenes/pi-permission-system'\nimport { DenialCircuitBreaker } from './circuit-breaker.js'\nimport { registerAutoReviewCommand } from './command.js'\nimport { AutoReviewConfigStore } from './config-store.js'\nimport { AUTHORIZER_NAME, EXTENSION_ID } from './config.js'\nimport { createPermissionReviewer } from './reviewer.js'\n\ninterface SessionRuntime {\n registry: ModelRegistry\n sessionManager: Pick<SessionManager, 'getBranch'>\n}\n\ninterface ReviewerFactoryOptions extends SessionRuntime {\n config: AutoReviewConfig\n circuitBreaker: DenialCircuitBreaker\n sessionSignal: AbortSignal\n}\n\nexport interface AutoReviewExtensionDependencies {\n configStore?: AutoReviewConfigStore\n getPermissionsService?: (sessionId: string) => PermissionsService | undefined\n createReviewer?: (options: ReviewerFactoryOptions) => Authorizer['authorize']\n}\n\ninterface ReviewerGeneration {\n config: AutoReviewConfig | undefined\n controller: AbortController\n authorize: Authorizer['authorize']\n dispose: (() => void) | undefined\n}\n\nconst deferInvalidConfig: Authorizer['authorize'] = async (details, _query, log) => {\n log.review('auto_review.decision', {\n requestId: details.requestId,\n outcome: 'defer',\n errorCategory: 'config-invalid',\n })\n return { kind: 'defer' }\n}\n\nfunction warn(message: string): void {\n console.warn(`[${EXTENSION_ID}] ${message}`)\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nexport function createAutoReviewExtension(pi: ExtensionAPI, dependencies: AutoReviewExtensionDependencies = {}): void {\n const configStore = dependencies.configStore ?? new AutoReviewConfigStore()\n const getPermissionsService = dependencies.getPermissionsService ?? getKeyedPermissionsService\n const createReviewer = dependencies.createReviewer ?? createPermissionReviewer\n\n const circuitBreaker = new DenialCircuitBreaker()\n let sessionRuntime: SessionRuntime | undefined\n let generation: ReviewerGeneration | undefined\n // The key for the keyed locator, learned from `permissions:ready`. One Pi\n // process hosts several nodes — a root session and each in-process subagent\n // child — and a chain link is only read by the node it was registered in.\n let sessionId: string | undefined\n let warnedMissingSessionId = false\n\n function createGeneration(runtime: SessionRuntime, config: AutoReviewConfig | undefined): ReviewerGeneration {\n const controller = new AbortController()\n return {\n config,\n controller,\n authorize:\n config === undefined\n ? deferInvalidConfig\n : createReviewer({ ...runtime, config, circuitBreaker, sessionSignal: controller.signal }),\n dispose: undefined,\n }\n }\n\n // Resolved per use rather than cached, so registration survives `/reload` and\n // load-order edge cases (ADR 0012).\n function resolveService(): PermissionsService | undefined {\n return sessionId === undefined ? undefined : getPermissionsService(sessionId)\n }\n\n function tryRegister(): void {\n // `permissions:ready` fires at least once per session and may repeat, so the\n // stored dispose handle is what keeps a second emission a no-op instead of\n // hitting `registerAuthorizer`'s duplicate-name throw.\n if (generation === undefined || generation.dispose !== undefined) {\n return\n }\n const service = resolveService()\n if (service === undefined) {\n return\n }\n\n try {\n generation.dispose = service.registerAuthorizer(AUTHORIZER_NAME, generation.authorize)\n } catch (error) {\n warn(`failed to register ${AUTHORIZER_NAME}: ${describeError(error)}`)\n }\n }\n\n function reportIssues(result: LoadConfigResult): void {\n for (const issue of result.issues) {\n warn(`config issue at ${issue.sourcePath}: ${issue.message}`)\n }\n }\n\n function applyConfig(result: LoadConfigResult): AutoReviewActivationResult {\n reportIssues(result)\n const current = generation\n const runtime = sessionRuntime\n if (current === undefined || runtime === undefined) {\n return { kind: 'failed', message: 'the Pi session has not started' }\n }\n if (result.config === undefined) {\n return {\n kind: 'failed',\n message: 'the merged config is invalid; the previous reviewer remains active',\n }\n }\n\n const service = resolveService()\n if (service === undefined && current.dispose !== undefined) {\n // Swapping would strand the registered reviewer: without the service the\n // old link cannot be released, and dropping its handle would leave it\n // deciding under the superseded config for the rest of the session.\n return {\n kind: 'failed',\n message: 'pi-permission-system became unavailable while the old reviewer was still registered',\n }\n }\n\n const candidate = createGeneration(runtime, result.config)\n current.dispose?.()\n generation = candidate\n current.controller.abort()\n circuitBreaker.resetTurn()\n\n if (service === undefined) {\n return { kind: 'pending' }\n }\n\n try {\n candidate.dispose = service.registerAuthorizer(AUTHORIZER_NAME, candidate.authorize)\n } catch (error) {\n // Nothing is registered now, so asks fall through to the human authorizer\n // and the next `permissions:ready` retries this generation.\n return {\n kind: 'failed',\n message: `the new reviewer could not be registered: ${describeError(error)}`,\n }\n }\n\n return { kind: 'active' }\n }\n\n pi.on('session_start', (_event, context) => {\n generation?.dispose?.()\n generation?.controller.abort()\n circuitBreaker.resetTurn()\n\n const result = configStore.load(context.cwd)\n sessionRuntime = {\n registry: context.modelRegistry,\n sessionManager: context.sessionManager,\n }\n generation = createGeneration(sessionRuntime, result.config)\n reportIssues(result)\n })\n\n // The whole registration. `permissions:ready` is re-emitted at the node's\n // first `before_agent_start`, which runs after every extension's\n // `session_start` and before any ask, so this handler is sufficient on its own\n // regardless of load order — a second attempt from `session_start` is not.\n pi.events.on(PERMISSIONS_READY_CHANNEL, (data: unknown) => {\n const ready = data as PermissionsReadyEvent | undefined\n const readySessionId = ready?.sessionId\n if (readySessionId == null) {\n if (!warnedMissingSessionId) {\n warnedMissingSessionId = true\n warn(`pi-permission-system published no keyed service for this node; ${AUTHORIZER_NAME} stays unregistered`)\n }\n return\n }\n // Our own node's id, which does not change for the life of the session —\n // `session_shutdown` is what clears it. Ready repeats, so this is a\n // learn-once rather than a last-writer-wins assignment.\n sessionId ??= readySessionId\n tryRegister()\n })\n\n pi.on('turn_start', () => {\n circuitBreaker.resetTurn()\n })\n\n pi.on('session_shutdown', () => {\n generation?.dispose?.()\n generation?.controller.abort()\n generation = undefined\n sessionRuntime = undefined\n sessionId = undefined\n warnedMissingSessionId = false\n circuitBreaker.resetTurn()\n })\n\n registerAutoReviewCommand(pi, {\n configStore,\n getActiveConfig: () => generation?.config,\n applyConfig,\n })\n}\n","import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'\nimport { createAutoReviewExtension } from './extension.js'\n\nexport default function permissionAutoReviewExtension(pi: ExtensionAPI): void {\n createAutoReviewExtension(pi)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["getPermissionsService","getKeyedPermissionsService","ready"],"sources":["../src/circuit-breaker.ts","../src/command.ts","../src/config-store.ts","../src/model.ts","../src/reviewer.ts","../src/extension.ts","../src/index.ts"],"sourcesContent":["const MAX_CONSECUTIVE_DENIALS = 3\nconst RECENT_WINDOW_SIZE = 50\nconst MAX_RECENT_DENIALS = 10\n\nexport class DenialCircuitBreaker {\n private consecutiveDenials = 0\n private recentDenials: boolean[] = []\n\n isOpen(): boolean {\n return (\n this.consecutiveDenials >= MAX_CONSECUTIVE_DENIALS ||\n this.recentDenials.filter(Boolean).length >= MAX_RECENT_DENIALS\n )\n }\n\n recordDenied(): void {\n this.consecutiveDenials += 1\n this.recordRecent(true)\n }\n\n recordNonDenial(): void {\n this.consecutiveDenials = 0\n this.recordRecent(false)\n }\n\n resetTurn(): void {\n this.consecutiveDenials = 0\n this.recentDenials = []\n }\n\n private recordRecent(denied: boolean): void {\n this.recentDenials.push(denied)\n if (this.recentDenials.length > RECENT_WINDOW_SIZE) {\n this.recentDenials.shift()\n }\n }\n}\n","import type { AutoReviewConfigStore, AutoReviewConfigScope } from './config-store.js'\nimport type { AutoReviewConfig, AutoReviewConfigFile, LoadConfigResult } from './config.js'\nimport type { ExtensionAPI, ExtensionCommandContext } from '@earendil-works/pi-coding-agent'\nimport { DEFAULT_CONFIG, DEFAULT_MODEL, DEFAULT_PROVIDER, REASONING_LEVELS } from './config.js'\n\nconst COMMAND_NAME = 'permission-auto-review'\nconst USAGE = 'Usage: /permission-auto-review [show|path|reset [global|project]|help]'\nconst INHERIT = 'Use inherited value'\nconst CUSTOM = 'Enter custom value...'\nconst SAVE = 'Save changes'\nconst CANCEL = 'Cancel'\nconst WHITESPACE = /\\s+/\n\n/** Every editable config key, so a new one cannot be added without a menu entry. */\ntype ConfigField = Exclude<keyof AutoReviewConfig, '$schema'>\n\ninterface FieldSpec {\n label: string\n format?: (value: unknown) => string\n edit: (\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n effective: AutoReviewConfig,\n ) => Promise<AutoReviewConfigFile>\n}\n\nexport type AutoReviewActivationResult = { kind: 'active' } | { kind: 'pending' } | { kind: 'failed'; message: string }\n\nexport interface AutoReviewCommandController {\n configStore: AutoReviewConfigStore\n getActiveConfig: () => AutoReviewConfig | undefined\n applyConfig: (result: LoadConfigResult) => AutoReviewActivationResult\n}\n\ninterface ConfigLayers {\n global: AutoReviewConfigFile\n project: AutoReviewConfigFile\n}\n\nfunction resolveOrigin(layers: ConfigLayers, field: ConfigField): AutoReviewConfigScope | 'default' {\n if (Object.hasOwn(layers.project, field)) {\n return 'project'\n }\n if (Object.hasOwn(layers.global, field)) {\n return 'global'\n }\n return 'default'\n}\n\nfunction removeField(config: AutoReviewConfigFile, field: ConfigField): AutoReviewConfigFile {\n const next = { ...config }\n delete next[field]\n return next\n}\n\nfunction uniqueSorted(values: string[]): string[] {\n return [...new Set(values)].toSorted((left, right) => left.localeCompare(right))\n}\n\nasync function chooseStringValue(\n ctx: ExtensionCommandContext,\n title: string,\n knownValues: string[],\n currentValue: string,\n): Promise<{ kind: 'inherit' } | { kind: 'value'; value: string } | undefined> {\n const values = uniqueSorted([...knownValues, currentValue])\n const valueOptions = values.map(value => `Value: ${value}`)\n const selected = await ctx.ui.select(title, [INHERIT, ...valueOptions, CUSTOM])\n if (selected === undefined) {\n return undefined\n }\n if (selected === INHERIT) {\n return { kind: 'inherit' }\n }\n if (selected === CUSTOM) {\n const custom = await ctx.ui.input(title, currentValue)\n const normalized = custom?.trim()\n if (normalized === undefined || normalized.length === 0) {\n return undefined\n }\n return { kind: 'value', value: normalized }\n }\n const index = valueOptions.indexOf(selected)\n return index < 0 ? undefined : { kind: 'value', value: values[index] ?? currentValue }\n}\n\nasync function editStringField(\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n field: 'provider' | 'model',\n effective: AutoReviewConfig,\n): Promise<AutoReviewConfigFile> {\n const registry = ctx.modelRegistry\n const knownValues =\n field === 'provider'\n ? registry.getAll().map(model => model.provider)\n : registry\n .getAll()\n .filter(model => model.provider === effective.provider)\n .map(model => model.id)\n if (field === 'provider') {\n knownValues.push(DEFAULT_PROVIDER)\n } else if (effective.provider === DEFAULT_PROVIDER) {\n knownValues.push(DEFAULT_MODEL)\n }\n\n const title = field === 'provider' ? 'Configure Provider' : 'Configure Model'\n const selected = await chooseStringValue(ctx, title, knownValues, effective[field])\n if (selected === undefined) {\n return draft\n }\n if (selected.kind === 'inherit') {\n return removeField(draft, field)\n }\n return field === 'provider' ? { ...draft, provider: selected.value } : { ...draft, model: selected.value }\n}\n\nasync function editReasoning(ctx: ExtensionCommandContext, draft: AutoReviewConfigFile): Promise<AutoReviewConfigFile> {\n const selected = await ctx.ui.select('Configure Reasoning', [INHERIT, ...REASONING_LEVELS])\n if (selected === INHERIT) {\n return removeField(draft, 'reasoning')\n }\n const reasoning = REASONING_LEVELS.find(level => level === selected)\n return reasoning === undefined ? draft : { ...draft, reasoning }\n}\n\nasync function editTimeout(\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n currentValue: number,\n): Promise<AutoReviewConfigFile> {\n const action = await ctx.ui.select('Configure Timeout', [INHERIT, 'Enter timeout...'])\n if (action === INHERIT) {\n return removeField(draft, 'timeoutMs')\n }\n if (action !== 'Enter timeout...') {\n return draft\n }\n\n const source = await ctx.ui.input('Timeout in milliseconds', String(currentValue))\n if (source === undefined) {\n return draft\n }\n const timeoutMs = Number(source.trim())\n if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 300_000) {\n ctx.ui.notify('timeoutMs must be an integer between 1 and 300000.', 'warning')\n return draft\n }\n return { ...draft, timeoutMs }\n}\n\nasync function editBaselinePolicy(\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n): Promise<AutoReviewConfigFile> {\n const selected = await ctx.ui.select('Configure Baseline Policy', [INHERIT, 'Enabled', 'Disabled'])\n if (selected === INHERIT) {\n return removeField(draft, 'includeBaselinePolicy')\n }\n if (selected === 'Enabled' || selected === 'Disabled') {\n return { ...draft, includeBaselinePolicy: selected === 'Enabled' }\n }\n return draft\n}\n\nasync function editAdditionalPolicy(\n ctx: ExtensionCommandContext,\n draft: AutoReviewConfigFile,\n currentValue: string | undefined,\n): Promise<AutoReviewConfigFile> {\n const selected = await ctx.ui.select('Configure Additional Policy', ['Edit policy...', INHERIT])\n if (selected === INHERIT) {\n return removeField(draft, 'additionalPolicy')\n }\n if (selected !== 'Edit policy...') {\n return draft\n }\n const value = await ctx.ui.editor('Additional review policy', currentValue ?? '')\n if (value === undefined) {\n return draft\n }\n const additionalPolicy = value.trim()\n return additionalPolicy.length === 0 ? removeField(draft, 'additionalPolicy') : { ...draft, additionalPolicy }\n}\n\nconst fields: Record<ConfigField, FieldSpec> = {\n provider: {\n label: 'Provider',\n edit: async (ctx, draft, effective) => editStringField(ctx, draft, 'provider', effective),\n },\n model: {\n label: 'Model',\n edit: async (ctx, draft, effective) => editStringField(ctx, draft, 'model', effective),\n },\n reasoning: {\n label: 'Reasoning',\n edit: async (ctx, draft) => editReasoning(ctx, draft),\n },\n timeoutMs: {\n label: 'Timeout',\n format: value => (typeof value === 'number' ? `${value} ms` : String(value ?? 'not set')),\n edit: async (ctx, draft, effective) => editTimeout(ctx, draft, effective.timeoutMs),\n },\n includeBaselinePolicy: {\n label: 'Baseline policy',\n edit: async (ctx, draft) => editBaselinePolicy(ctx, draft),\n },\n additionalPolicy: {\n label: 'Additional policy',\n format: value => (typeof value === 'string' && value.length > 0 ? 'configured' : 'not set'),\n edit: async (ctx, draft, effective) => editAdditionalPolicy(ctx, draft, effective.additionalPolicy),\n },\n}\n\nconst configFields = Object.keys(fields) as ConfigField[]\n\n/**\n * Effective values for display. The draft being edited may still violate the cross-field policy\n * invariant, so this resolves layer precedence directly rather than through the schema, which\n * rejects the whole object.\n */\nfunction mergeLayers(layers: ConfigLayers): AutoReviewConfig {\n const merged = { ...DEFAULT_CONFIG }\n for (const field of configFields) {\n const value = layers.project[field] ?? layers.global[field]\n if (value !== undefined) {\n Object.assign(merged, { [field]: value })\n }\n }\n\n return merged\n}\n\nfunction formatFieldValue(field: ConfigField, value: unknown): string {\n return fields[field].format?.(value) ?? String(value ?? 'not set')\n}\n\nfunction formatMenuOptions(effective: AutoReviewConfig, layers: ConfigLayers, scope: AutoReviewConfigScope): string[] {\n return configFields.map(field => {\n const origin = resolveOrigin(layers, field)\n const scopeState = Object.hasOwn(layers[scope], field) ? 'override' : 'inherit'\n return `${fields[field].label}: ${formatFieldValue(field, effective[field])} (source: ${origin}; ${scope}: ${scopeState})`\n })\n}\n\nasync function chooseScope(ctx: ExtensionCommandContext, title: string): Promise<AutoReviewConfigScope | undefined> {\n const selected = await ctx.ui.select(title, ['Global configuration', 'Project configuration'])\n if (selected === 'Global configuration') {\n return 'global'\n }\n if (selected === 'Project configuration') {\n return 'project'\n }\n return undefined\n}\n\nasync function openSettingsMenu(ctx: ExtensionCommandContext, controller: AutoReviewCommandController): Promise<void> {\n if (ctx.mode !== 'tui') {\n ctx.ui.notify(`/${COMMAND_NAME} requires interactive TUI mode.`, 'warning')\n return\n }\n\n await ctx.waitForIdle()\n const scope = await chooseScope(ctx, 'Select configuration scope')\n if (scope === undefined) {\n return\n }\n\n const selected = controller.configStore.readScope(ctx.cwd, scope)\n const other = controller.configStore.readScope(ctx.cwd, scope === 'global' ? 'project' : 'global')\n if (!selected.valid) {\n ctx.ui.notify(\n `Cannot edit config at '${selected.path}': ${selected.issue.message}. Use reset to remove it or fix it manually.`,\n 'error',\n )\n return\n }\n if (!other.valid) {\n ctx.ui.notify(\n `Cannot edit config at '${other.path}': ${other.issue.message}. Use reset to remove it or fix it manually.`,\n 'error',\n )\n return\n }\n\n let draft: AutoReviewConfigFile = { ...selected.config }\n while (true) {\n const layers: ConfigLayers =\n scope === 'global' ? { global: draft, project: other.config } : { global: other.config, project: draft }\n const effective = mergeLayers(layers)\n const fieldOptions = formatMenuOptions(effective, layers, scope)\n const selectedOption = await ctx.ui.select(`Permission auto-review settings (${scope})`, [\n ...fieldOptions,\n SAVE,\n CANCEL,\n ])\n if (selectedOption === undefined || selectedOption === CANCEL) {\n return\n }\n if (selectedOption === SAVE) {\n const saved = controller.configStore.save(selected, draft)\n if (!saved.ok) {\n ctx.ui.notify(saved.message, 'error')\n continue\n }\n const activation = controller.applyConfig(saved.loadResult)\n if (activation.kind === 'failed') {\n ctx.ui.notify(`Config saved, but the current reviewer could not be replaced: ${activation.message}`, 'error')\n } else if (activation.kind === 'pending') {\n ctx.ui.notify('Config saved. It will become active when pi-permission-system is ready.', 'warning')\n } else {\n ctx.ui.notify('Config saved and applied without reloading the Pi session.', 'info')\n }\n return\n }\n\n const field = configFields[fieldOptions.indexOf(selectedOption)]\n if (field !== undefined) {\n draft = await fields[field].edit(ctx, draft, effective)\n }\n }\n}\n\nfunction getScopeLayers(store: AutoReviewConfigStore, cwd: string): ConfigLayers | undefined {\n const global = store.readScope(cwd, 'global')\n const project = store.readScope(cwd, 'project')\n return global.valid && project.valid ? { global: global.config, project: project.config } : undefined\n}\n\nfunction showConfig(ctx: ExtensionCommandContext, controller: AutoReviewCommandController): void {\n const paths = controller.configStore.getPaths(ctx.cwd)\n const active = controller.getActiveConfig()\n const layers = getScopeLayers(controller.configStore, ctx.cwd)\n if (active === undefined || layers === undefined) {\n const result = controller.configStore.load(ctx.cwd)\n const issues = result.issues.map(issue => `${issue.sourcePath}: ${issue.message}`).join('\\n')\n ctx.ui.notify(\n `Automatic review is disabled because the active config is invalid.${issues ? `\\n${issues}` : ''}`,\n 'warning',\n )\n return\n }\n\n const fields = configFields.map(field => {\n const origin = resolveOrigin(layers, field)\n return `${field}=${formatFieldValue(field, active[field])} (${origin})`\n })\n ctx.ui.notify(\n `permission-auto-review:\\n${fields.join('\\n')}\\nglobal=${paths.globalPath}\\nproject=${paths.projectPath}`,\n 'info',\n )\n}\n\nfunction showPaths(ctx: ExtensionCommandContext, controller: AutoReviewCommandController): void {\n const paths = controller.configStore.getPaths(ctx.cwd)\n ctx.ui.notify(\n `permission-auto-review config paths:\\nglobal=${paths.globalPath}\\nproject=${paths.projectPath}`,\n 'info',\n )\n}\n\nasync function resetConfig(\n ctx: ExtensionCommandContext,\n controller: AutoReviewCommandController,\n requestedScope: string | undefined,\n): Promise<void> {\n if (ctx.mode !== 'tui') {\n ctx.ui.notify(`/${COMMAND_NAME} reset requires interactive TUI mode.`, 'warning')\n return\n }\n await ctx.waitForIdle()\n\n let scope: AutoReviewConfigScope | undefined\n if (requestedScope === 'global' || requestedScope === 'project') {\n scope = requestedScope\n } else if (requestedScope === undefined) {\n scope = await chooseScope(ctx, 'Select configuration scope to reset')\n } else {\n ctx.ui.notify(USAGE, 'warning')\n return\n }\n if (scope === undefined) {\n return\n }\n\n const snapshot = controller.configStore.readScope(ctx.cwd, scope)\n const confirmed = await ctx.ui.confirm(\n `Reset ${scope} auto-review config?`,\n `Delete '${snapshot.path}' and immediately apply inherited values?`,\n )\n if (!confirmed) {\n return\n }\n\n const reset = controller.configStore.reset(snapshot)\n if (!reset.ok) {\n ctx.ui.notify(reset.message, 'error')\n return\n }\n const activation = controller.applyConfig(reset.loadResult)\n if (activation.kind === 'failed') {\n ctx.ui.notify(`Config reset, but the current reviewer could not be replaced: ${activation.message}`, 'error')\n } else if (activation.kind === 'pending') {\n ctx.ui.notify(\n `${scope} config reset. The inherited config will activate when pi-permission-system is ready.`,\n 'warning',\n )\n } else if (reset.loadResult.config === undefined) {\n ctx.ui.notify(\n `${scope} config reset, but automatic review remains disabled because another config layer is invalid.`,\n 'warning',\n )\n } else {\n ctx.ui.notify(`${scope} config reset and inherited values applied without reloading the Pi session.`, 'info')\n }\n}\n\nfunction getArgumentCompletions(\n argumentPrefix: string,\n): Array<{ value: string; label: string; description: string }> | null {\n const normalized = argumentPrefix.trimStart().toLowerCase()\n const items = normalized.startsWith('reset ')\n ? [\n {\n value: 'reset global',\n label: 'Reset global config',\n description: 'Delete the global auto-review config',\n },\n {\n value: 'reset project',\n label: 'Reset project config',\n description: 'Delete the project auto-review config',\n },\n ]\n : [\n {\n value: 'show',\n label: 'Show active config',\n description: 'Display effective values and their origins',\n },\n {\n value: 'path',\n label: 'Show config paths',\n description: 'Display global and project config paths',\n },\n {\n value: 'reset',\n label: 'Reset config',\n description: 'Delete one config layer and apply inherited values',\n },\n {\n value: 'help',\n label: 'Show help',\n description: 'Display command usage',\n },\n ]\n const filtered = items.filter(item => item.value.startsWith(normalized))\n return filtered.length > 0 ? filtered : null\n}\n\nexport function registerAutoReviewCommand(pi: ExtensionAPI, controller: AutoReviewCommandController): void {\n pi.registerCommand(COMMAND_NAME, {\n description: 'Configure pi-permission-auto-review without reloading the Pi session',\n getArgumentCompletions,\n handler: async (args, ctx) => {\n const normalized = args.trim().toLowerCase()\n if (!normalized) {\n await openSettingsMenu(ctx, controller)\n return\n }\n if (normalized === 'show') {\n showConfig(ctx, controller)\n return\n }\n if (normalized === 'path') {\n showPaths(ctx, controller)\n return\n }\n if (normalized === 'help') {\n ctx.ui.notify(USAGE, 'info')\n return\n }\n if (normalized === 'reset' || normalized.startsWith('reset ')) {\n const scope = normalized.split(WHITESPACE)[1]\n await resetConfig(ctx, controller, scope)\n return\n }\n ctx.ui.notify(USAGE, 'warning')\n },\n })\n}\n","import type { AutoReviewConfigFile, AutoReviewConfigPaths, ConfigIssue, LoadConfigResult } from './config.js'\nimport { mkdirSync, renameSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport {\n CONFIG_SCHEMA_URL,\n defaultAutoReviewAgentDir,\n getAutoReviewConfigPaths,\n loadAutoReviewConfig,\n parseAutoReviewConfigFile,\n readConfigFile,\n validateAutoReviewConfigFile,\n} from './config.js'\n\nexport type AutoReviewConfigScope = 'global' | 'project'\n\ninterface ScopeSnapshotBase {\n scope: AutoReviewConfigScope\n cwd: string\n path: string\n source: string | undefined\n}\n\nexport type AutoReviewScopeSnapshot =\n | (ScopeSnapshotBase & {\n valid: true\n config: AutoReviewConfigFile\n })\n | (ScopeSnapshotBase & {\n valid: false\n issue: ConfigIssue\n })\n\nexport type ConfigMutationResult = { ok: true; loadResult: LoadConfigResult } | { ok: false; message: string }\n\nexport interface AutoReviewConfigFileSystem {\n readFile: (path: string) => string | undefined\n writeFile: (path: string, source: string) => void\n rename: (sourcePath: string, destinationPath: string) => void\n mkdir: (path: string) => void\n unlink: (path: string) => void\n}\n\nexport interface AutoReviewConfigStoreOptions {\n agentDir?: string\n fileSystem?: AutoReviewConfigFileSystem\n}\n\nconst defaultFileSystem: AutoReviewConfigFileSystem = {\n readFile: readConfigFile,\n writeFile(path, source) {\n writeFileSync(path, source, 'utf8')\n },\n rename(sourcePath, destinationPath) {\n renameSync(sourcePath, destinationPath)\n },\n mkdir(path) {\n mkdirSync(path, { recursive: true })\n },\n unlink(path) {\n unlinkSync(path)\n },\n}\n\nfunction formatIssues(issues: ConfigIssue[]): string {\n return issues.map(issue => `${issue.sourcePath}: ${issue.message}`).join('\\n')\n}\n\nexport class AutoReviewConfigStore {\n private readonly agentDir: string\n private readonly fileSystem: AutoReviewConfigFileSystem\n\n constructor(options: AutoReviewConfigStoreOptions = {}) {\n this.agentDir = options.agentDir ?? defaultAutoReviewAgentDir()\n this.fileSystem = options.fileSystem ?? defaultFileSystem\n }\n\n getPaths(cwd: string): AutoReviewConfigPaths {\n return getAutoReviewConfigPaths(cwd, this.agentDir)\n }\n\n load(cwd: string): LoadConfigResult {\n return loadAutoReviewConfig({\n cwd,\n agentDir: this.agentDir,\n readFile: path => this.fileSystem.readFile(path),\n })\n }\n\n readScope(cwd: string, scope: AutoReviewConfigScope): AutoReviewScopeSnapshot {\n const paths = this.getPaths(cwd)\n const path = scope === 'global' ? paths.globalPath : paths.projectPath\n let source: string | undefined\n try {\n source = this.fileSystem.readFile(path)\n } catch (error) {\n return {\n scope,\n cwd,\n path,\n source: undefined,\n valid: false,\n issue: {\n sourcePath: path,\n message: error instanceof Error ? error.message : String(error),\n },\n }\n }\n\n if (source === undefined) {\n return { scope, cwd, path, source, valid: true, config: {} }\n }\n\n const parsed = parseAutoReviewConfigFile(source, path)\n if (!parsed.ok) {\n return { scope, cwd, path, source, valid: false, issue: parsed.issue }\n }\n return { scope, cwd, path, source, valid: true, config: parsed.config }\n }\n\n save(snapshot: AutoReviewScopeSnapshot, draft: AutoReviewConfigFile): ConfigMutationResult {\n if (!snapshot.valid) {\n return {\n ok: false,\n message: `Cannot save invalid config at '${snapshot.path}': ${snapshot.issue.message}`,\n }\n }\n\n const parsed = validateAutoReviewConfigFile(draft, snapshot.path)\n if (!parsed.ok) {\n return { ok: false, message: `${parsed.issue.sourcePath}: ${parsed.issue.message}` }\n }\n\n const source = this.serialize(parsed.config)\n const loadResult = this.loadWithOverride(snapshot, source)\n if (loadResult.config === undefined) {\n return { ok: false, message: formatIssues(loadResult.issues) }\n }\n\n const conflict = this.checkForConflict(snapshot)\n if (conflict !== undefined) {\n return { ok: false, message: conflict }\n }\n\n const tempPath = `${snapshot.path}.tmp`\n try {\n this.fileSystem.mkdir(dirname(snapshot.path))\n this.fileSystem.writeFile(tempPath, source)\n this.fileSystem.rename(tempPath, snapshot.path)\n } catch (error) {\n this.cleanupTempFile(tempPath)\n return {\n ok: false,\n message: `Failed to save config at '${snapshot.path}': ${error instanceof Error ? error.message : String(error)}`,\n }\n }\n\n return { ok: true, loadResult }\n }\n\n reset(snapshot: AutoReviewScopeSnapshot): ConfigMutationResult {\n if (!snapshot.valid && snapshot.source === undefined) {\n return {\n ok: false,\n message: `Cannot reset unreadable config at '${snapshot.path}': ${snapshot.issue.message}`,\n }\n }\n\n const conflict = this.checkForConflict(snapshot)\n if (conflict !== undefined) {\n return { ok: false, message: conflict }\n }\n\n if (snapshot.source !== undefined) {\n try {\n this.fileSystem.unlink(snapshot.path)\n } catch (error) {\n return {\n ok: false,\n message: `Failed to reset config at '${snapshot.path}': ${error instanceof Error ? error.message : String(error)}`,\n }\n }\n }\n\n return { ok: true, loadResult: this.loadWithOverride(snapshot, undefined) }\n }\n\n private loadWithOverride(snapshot: AutoReviewScopeSnapshot, source: string | undefined): LoadConfigResult {\n return loadAutoReviewConfig({\n cwd: snapshot.cwd,\n agentDir: this.agentDir,\n readFile: path => (path === snapshot.path ? source : this.fileSystem.readFile(path)),\n })\n }\n\n private serialize(config: AutoReviewConfigFile): string {\n const { $schema = CONFIG_SCHEMA_URL, ...fields } = config\n return `${JSON.stringify({ $schema, ...fields }, null, 2)}\\n`\n }\n\n private checkForConflict(snapshot: AutoReviewScopeSnapshot): string | undefined {\n let currentSource: string | undefined\n try {\n currentSource = this.fileSystem.readFile(snapshot.path)\n } catch (error) {\n return `Failed to re-read config at '${snapshot.path}': ${error instanceof Error ? error.message : String(error)}`\n }\n return currentSource === snapshot.source\n ? undefined\n : `Config at '${snapshot.path}' changed while it was being edited; reopen the command and try again.`\n }\n\n private cleanupTempFile(tempPath: string): void {\n try {\n this.fileSystem.unlink(tempPath)\n } catch {\n // The original write error is more actionable than a best-effort cleanup failure.\n }\n }\n}\n","import type { AutoReviewConfig } from './config.js'\nimport type { Api, Model, Provider } from '@earendil-works/pi-ai'\nimport type { ModelRegistry } from '@earendil-works/pi-coding-agent'\nimport { DEFAULT_MODEL, DEFAULT_PROVIDER } from './config.js'\n\nexport type ReviewModelRegistry = Pick<ModelRegistry, 'find' | 'getAll' | 'getProvider' | 'streamSimple'>\n\nexport type ResolveReviewModelResult =\n | { ok: true; value: Model<Api> }\n | {\n ok: false\n category: 'provider-unresolved' | 'model-unresolved'\n }\n\nfunction findCodexTemplate(registry: ReviewModelRegistry, provider: Provider<Api>): Model<Api> | undefined {\n return (\n registry.getAll().find(model => model.provider === DEFAULT_PROVIDER && model.api === 'openai-codex-responses') ??\n provider.getModels().find(model => model.api === 'openai-codex-responses')\n )\n}\n\nexport function resolveReviewModel(registry: ReviewModelRegistry, config: AutoReviewConfig): ResolveReviewModelResult {\n const provider = registry.getProvider(config.provider)\n if (provider === undefined) {\n return { ok: false, category: 'provider-unresolved' }\n }\n\n const registeredModel = registry.find(config.provider, config.model)\n if (registeredModel !== undefined) {\n return { ok: true, value: registeredModel }\n }\n\n if (config.provider !== DEFAULT_PROVIDER || config.model !== DEFAULT_MODEL) {\n return { ok: false, category: 'model-unresolved' }\n }\n\n const template = findCodexTemplate(registry, provider)\n if (template === undefined) {\n return { ok: false, category: 'model-unresolved' }\n }\n\n return {\n ok: true,\n value: {\n ...template,\n id: DEFAULT_MODEL,\n name: 'Codex Auto Review',\n reasoning: true,\n input: ['text'],\n },\n }\n}\n","import type { DenialCircuitBreaker } from './circuit-breaker.js'\nimport type { AutoReviewConfig } from './config.js'\nimport type { ReviewModelRegistry } from './model.js'\nimport type { TranscriptStats } from './transcript.js'\nimport type { ReviewAssessment } from './verdict.js'\nimport type { AssistantMessage, SimpleStreamOptions } from '@earendil-works/pi-ai'\nimport type { SessionManager } from '@earendil-works/pi-coding-agent'\nimport type { Authorizer, AuthorizerLog, PromptPermissionDetails } from '@gotgenes/pi-permission-system'\nimport { resolveReviewModel } from './model.js'\nimport { POLICY_REVISION } from './policy.js'\nimport { buildReviewPrompt } from './prompt.js'\nimport { renderTranscript } from './transcript.js'\nimport { parseReviewAssessment } from './verdict.js'\n\nconst RETRY_DELAYS_MS = [250, 1_000]\nconst MAX_ATTEMPTS = RETRY_DELAYS_MS.length + 1\nconst MAX_OUTPUT_TOKENS = 1_000\nconst DECISION_EVENT = 'auto_review.decision'\nconst FAILURE_EVENT = 'auto_review.failure'\nconst CIRCUIT_OPEN_EVENT = 'auto_review.circuit_open'\n\ntype FailureCategory =\n | 'provider-unresolved'\n | 'model-unresolved'\n | 'provider-error'\n | 'invalid-response'\n | 'timeout'\n | 'cancelled'\n | 'internal-error'\n\nexport interface ReviewerRuntime {\n config: AutoReviewConfig\n registry: ReviewModelRegistry\n sessionManager: Pick<SessionManager, 'getBranch' | 'getSessionId'>\n circuitBreaker: DenialCircuitBreaker\n sessionSignal?: AbortSignal\n}\n\n/** The clock and timer, injectable so a test does not wait out a real retry delay. */\nexport interface ReviewerDependencies {\n now?: () => number\n sleep?: (milliseconds: number, signal: AbortSignal) => Promise<void>\n}\n\ninterface ContextDiagnostics extends TranscriptStats {\n policyRevision: string\n contextSource: 'active-branch'\n}\n\ninterface Failure {\n category: FailureCategory\n contextDiagnostics?: ContextDiagnostics\n}\n\ninterface ReviewCallResult {\n assessment: ReviewAssessment\n contextDiagnostics: ContextDiagnostics\n}\n\nfunction abortError(): Error {\n const error = new Error('operation aborted')\n error.name = 'AbortError'\n return error\n}\n\nasync function defaultSleep(milliseconds: number, signal: AbortSignal): Promise<void> {\n if (milliseconds <= 0) {\n return Promise.resolve()\n }\n return new Promise((resolve, reject) => {\n if (signal.aborted) {\n reject(abortError())\n return\n }\n const timer = setTimeout(resolve, milliseconds)\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(abortError())\n },\n { once: true },\n )\n })\n}\n\nasync function raceWithSignal<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) {\n return Promise.reject(abortError())\n }\n return new Promise((resolve, reject) => {\n const onAbort = (): void => reject(abortError())\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(\n value => {\n signal.removeEventListener('abort', onAbort)\n resolve(value)\n },\n (error: unknown) => {\n signal.removeEventListener('abort', onAbort)\n reject(error)\n },\n )\n })\n}\n\nfunction responseText(message: AssistantMessage): string {\n return message.content\n .filter((block): block is Extract<(typeof message.content)[number], { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n .join('')\n .trim()\n}\n\nfunction buildStreamOptions(\n runtime: ReviewerRuntime,\n signal: AbortSignal,\n timeoutMs: number,\n reasoning: boolean,\n): SimpleStreamOptions {\n const options: SimpleStreamOptions = {\n maxRetries: 0,\n maxTokens: MAX_OUTPUT_TOKENS,\n signal,\n timeoutMs,\n // Gateways such as opencode-go reject requests without a session ID,\n // which pi-ai sends as `x-opencode-session` when this is set.\n sessionId: runtime.sessionManager.getSessionId(),\n }\n if (reasoning && runtime.config.reasoning !== 'off') {\n options.reasoning = runtime.config.reasoning\n }\n return options\n}\n\n// The registry resolves the configured provider and its authentication at\n// request time, so an unusable Codex login surfaces as a provider error here\n// rather than as a separate pre-flight category.\nasync function callModel(\n registry: ReviewModelRegistry,\n model: Parameters<ReviewModelRegistry['streamSimple']>[0],\n systemPrompt: string,\n userPrompt: string,\n options: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n const stream = registry.streamSimple(\n model,\n {\n systemPrompt,\n messages: [\n {\n role: 'user',\n content: userPrompt,\n timestamp: Date.now(),\n },\n ],\n },\n options,\n )\n return stream.result()\n}\n\nfunction writeFailure(\n log: AuthorizerLog,\n runtime: ReviewerRuntime,\n details: PromptPermissionDetails,\n failure: Failure,\n durationMs: number,\n): void {\n const common = {\n requestId: details.requestId,\n provider: runtime.config.provider,\n model: runtime.config.model,\n outcome: 'defer',\n errorCategory: failure.category,\n durationMs,\n ...failure.contextDiagnostics,\n }\n log.review(DECISION_EVENT, common)\n log.debug(FAILURE_EVENT, common)\n}\n\nasync function runReview(\n runtime: ReviewerRuntime,\n details: PromptPermissionDetails,\n dependencies: Required<ReviewerDependencies>,\n): Promise<ReviewCallResult | Failure> {\n const startedAt = dependencies.now()\n const timeoutController = new AbortController()\n const timeout = setTimeout(() => timeoutController.abort(), runtime.config.timeoutMs)\n const signal =\n runtime.sessionSignal === undefined\n ? timeoutController.signal\n : AbortSignal.any([timeoutController.signal, runtime.sessionSignal])\n\n try {\n const transcript = renderTranscript(runtime.sessionManager.getBranch())\n const contextDiagnostics: ContextDiagnostics = {\n policyRevision: POLICY_REVISION,\n contextSource: 'active-branch',\n ...transcript.stats,\n }\n const failure = (category: FailureCategory): Failure => ({ category, contextDiagnostics })\n const resolved = resolveReviewModel(runtime.registry, runtime.config)\n if (!resolved.ok) {\n return failure(resolved.category)\n }\n\n const prompt = buildReviewPrompt(runtime.config, transcript, details)\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) {\n try {\n const remainingMs = Math.max(1, runtime.config.timeoutMs - (dependencies.now() - startedAt))\n const message = await raceWithSignal(\n callModel(\n runtime.registry,\n resolved.value,\n prompt.systemPrompt,\n prompt.userPrompt,\n buildStreamOptions(runtime, signal, remainingMs, resolved.value.reasoning),\n ),\n signal,\n )\n\n if (message.stopReason === 'error' || message.stopReason === 'aborted') {\n throw new Error(message.errorMessage ?? message.stopReason)\n }\n\n try {\n return {\n assessment: parseReviewAssessment(responseText(message)),\n contextDiagnostics,\n }\n } catch {\n return failure('invalid-response')\n }\n } catch {\n if (signal.aborted) {\n return failure(timeoutController.signal.aborted ? 'timeout' : 'cancelled')\n }\n if (attempt >= MAX_ATTEMPTS) {\n return failure('provider-error')\n }\n try {\n await dependencies.sleep(RETRY_DELAYS_MS[attempt - 1] ?? 0, signal)\n } catch {\n return failure(timeoutController.signal.aborted ? 'timeout' : 'cancelled')\n }\n }\n }\n return failure('provider-error')\n } finally {\n clearTimeout(timeout)\n }\n}\n\nexport function createPermissionReviewer(\n runtime: ReviewerRuntime,\n reviewerDependencies: ReviewerDependencies = {},\n): Authorizer['authorize'] {\n const dependencies: Required<ReviewerDependencies> = {\n now: reviewerDependencies.now ?? Date.now,\n sleep: reviewerDependencies.sleep ?? defaultSleep,\n }\n\n return async (details, _query, log) => {\n const startedAt = dependencies.now()\n try {\n if (runtime.circuitBreaker.isOpen()) {\n const reason =\n 'Too many denials this turn; further requests are refused unreviewed until the next turn. Ask the user for explicit approval before retrying'\n log.review(CIRCUIT_OPEN_EVENT, {\n requestId: details.requestId,\n provider: runtime.config.provider,\n model: runtime.config.model,\n outcome: 'deny',\n durationMs: 0,\n errorCategory: 'circuit-open',\n })\n return { kind: 'deny', reason }\n }\n\n const result = await runReview(runtime, details, dependencies)\n const durationMs = Math.max(0, dependencies.now() - startedAt)\n if ('category' in result) {\n runtime.circuitBreaker.recordNonDenial()\n writeFailure(log, runtime, details, result, durationMs)\n return { kind: 'defer' }\n }\n\n const { assessment, contextDiagnostics } = result\n log.review(DECISION_EVENT, {\n requestId: details.requestId,\n provider: runtime.config.provider,\n model: runtime.config.model,\n riskLevel: assessment.riskLevel,\n userAuthorization: assessment.userAuthorization,\n outcome: assessment.outcome,\n durationMs,\n ...contextDiagnostics,\n })\n\n if (assessment.outcome === 'allow') {\n runtime.circuitBreaker.recordNonDenial()\n return { kind: 'allow' }\n }\n\n runtime.circuitBreaker.recordDenied()\n // The reason is rendered after the host's own attribution sentence\n // (\"The 'auto-review' authorizer denied this ...\"), so it carries only\n // what that sentence does not: why, and the two grades behind the call.\n return {\n kind: 'deny',\n reason: `${assessment.rationale} (risk: ${assessment.riskLevel}, user authorization: ${assessment.userAuthorization})`,\n }\n } catch {\n // The chain does not isolate a link that throws, so every internal failure\n // has to leave here as a verdict.\n runtime.circuitBreaker.recordNonDenial()\n writeFailure(log, runtime, details, { category: 'internal-error' }, Math.max(0, dependencies.now() - startedAt))\n return { kind: 'defer' }\n }\n }\n}\n","import type { AutoReviewActivationResult } from './command.js'\nimport type { AutoReviewConfig, LoadConfigResult } from './config.js'\nimport type { ExtensionAPI, ModelRegistry, SessionManager } from '@earendil-works/pi-coding-agent'\nimport type { Authorizer, PermissionsReadyEvent, PermissionsService } from '@gotgenes/pi-permission-system'\nimport {\n getPermissionsService as getKeyedPermissionsService,\n PERMISSIONS_READY_CHANNEL,\n} from '@gotgenes/pi-permission-system'\nimport { DenialCircuitBreaker } from './circuit-breaker.js'\nimport { registerAutoReviewCommand } from './command.js'\nimport { AutoReviewConfigStore } from './config-store.js'\nimport { AUTHORIZER_NAME, EXTENSION_ID } from './config.js'\nimport { createPermissionReviewer } from './reviewer.js'\n\ninterface SessionRuntime {\n registry: ModelRegistry\n sessionManager: Pick<SessionManager, 'getBranch' | 'getSessionId'>\n}\n\ninterface ReviewerFactoryOptions extends SessionRuntime {\n config: AutoReviewConfig\n circuitBreaker: DenialCircuitBreaker\n sessionSignal: AbortSignal\n}\n\nexport interface AutoReviewExtensionDependencies {\n configStore?: AutoReviewConfigStore\n getPermissionsService?: (sessionId: string) => PermissionsService | undefined\n createReviewer?: (options: ReviewerFactoryOptions) => Authorizer['authorize']\n}\n\ninterface ReviewerGeneration {\n config: AutoReviewConfig | undefined\n controller: AbortController\n authorize: Authorizer['authorize']\n dispose: (() => void) | undefined\n}\n\nconst deferInvalidConfig: Authorizer['authorize'] = async (details, _query, log) => {\n log.review('auto_review.decision', {\n requestId: details.requestId,\n outcome: 'defer',\n errorCategory: 'config-invalid',\n })\n return { kind: 'defer' }\n}\n\nfunction warn(message: string): void {\n console.warn(`[${EXTENSION_ID}] ${message}`)\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nexport function createAutoReviewExtension(pi: ExtensionAPI, dependencies: AutoReviewExtensionDependencies = {}): void {\n const configStore = dependencies.configStore ?? new AutoReviewConfigStore()\n const getPermissionsService = dependencies.getPermissionsService ?? getKeyedPermissionsService\n const createReviewer = dependencies.createReviewer ?? createPermissionReviewer\n\n const circuitBreaker = new DenialCircuitBreaker()\n let sessionRuntime: SessionRuntime | undefined\n let generation: ReviewerGeneration | undefined\n // The key for the keyed locator, learned from `permissions:ready`. One Pi\n // process hosts several nodes — a root session and each in-process subagent\n // child — and a chain link is only read by the node it was registered in.\n let sessionId: string | undefined\n let warnedMissingSessionId = false\n\n function createGeneration(runtime: SessionRuntime, config: AutoReviewConfig | undefined): ReviewerGeneration {\n const controller = new AbortController()\n return {\n config,\n controller,\n authorize:\n config === undefined\n ? deferInvalidConfig\n : createReviewer({ ...runtime, config, circuitBreaker, sessionSignal: controller.signal }),\n dispose: undefined,\n }\n }\n\n // Resolved per use rather than cached, so registration survives `/reload` and\n // load-order edge cases (ADR 0012).\n function resolveService(): PermissionsService | undefined {\n return sessionId === undefined ? undefined : getPermissionsService(sessionId)\n }\n\n function tryRegister(): void {\n // `permissions:ready` fires at least once per session and may repeat, so the\n // stored dispose handle is what keeps a second emission a no-op instead of\n // hitting `registerAuthorizer`'s duplicate-name throw.\n if (generation === undefined || generation.dispose !== undefined) {\n return\n }\n const service = resolveService()\n if (service === undefined) {\n return\n }\n\n try {\n generation.dispose = service.registerAuthorizer(AUTHORIZER_NAME, generation.authorize)\n } catch (error) {\n warn(`failed to register ${AUTHORIZER_NAME}: ${describeError(error)}`)\n }\n }\n\n function reportIssues(result: LoadConfigResult): void {\n for (const issue of result.issues) {\n warn(`config issue at ${issue.sourcePath}: ${issue.message}`)\n }\n }\n\n function applyConfig(result: LoadConfigResult): AutoReviewActivationResult {\n reportIssues(result)\n const current = generation\n const runtime = sessionRuntime\n if (current === undefined || runtime === undefined) {\n return { kind: 'failed', message: 'the Pi session has not started' }\n }\n if (result.config === undefined) {\n return {\n kind: 'failed',\n message: 'the merged config is invalid; the previous reviewer remains active',\n }\n }\n\n const service = resolveService()\n if (service === undefined && current.dispose !== undefined) {\n // Swapping would strand the registered reviewer: without the service the\n // old link cannot be released, and dropping its handle would leave it\n // deciding under the superseded config for the rest of the session.\n return {\n kind: 'failed',\n message: 'pi-permission-system became unavailable while the old reviewer was still registered',\n }\n }\n\n const candidate = createGeneration(runtime, result.config)\n current.dispose?.()\n generation = candidate\n current.controller.abort()\n circuitBreaker.resetTurn()\n\n if (service === undefined) {\n return { kind: 'pending' }\n }\n\n try {\n candidate.dispose = service.registerAuthorizer(AUTHORIZER_NAME, candidate.authorize)\n } catch (error) {\n // Nothing is registered now, so asks fall through to the human authorizer\n // and the next `permissions:ready` retries this generation.\n return {\n kind: 'failed',\n message: `the new reviewer could not be registered: ${describeError(error)}`,\n }\n }\n\n return { kind: 'active' }\n }\n\n pi.on('session_start', (_event, context) => {\n generation?.dispose?.()\n generation?.controller.abort()\n circuitBreaker.resetTurn()\n\n const result = configStore.load(context.cwd)\n sessionRuntime = {\n registry: context.modelRegistry,\n sessionManager: context.sessionManager,\n }\n generation = createGeneration(sessionRuntime, result.config)\n reportIssues(result)\n })\n\n // The whole registration. `permissions:ready` is re-emitted at the node's\n // first `before_agent_start`, which runs after every extension's\n // `session_start` and before any ask, so this handler is sufficient on its own\n // regardless of load order — a second attempt from `session_start` is not.\n pi.events.on(PERMISSIONS_READY_CHANNEL, (data: unknown) => {\n const ready = data as PermissionsReadyEvent | undefined\n const readySessionId = ready?.sessionId\n if (readySessionId == null) {\n if (!warnedMissingSessionId) {\n warnedMissingSessionId = true\n warn(`pi-permission-system published no keyed service for this node; ${AUTHORIZER_NAME} stays unregistered`)\n }\n return\n }\n // Our own node's id, which does not change for the life of the session —\n // `session_shutdown` is what clears it. Ready repeats, so this is a\n // learn-once rather than a last-writer-wins assignment.\n sessionId ??= readySessionId\n tryRegister()\n })\n\n pi.on('turn_start', () => {\n circuitBreaker.resetTurn()\n })\n\n pi.on('session_shutdown', () => {\n generation?.dispose?.()\n generation?.controller.abort()\n generation = undefined\n sessionRuntime = undefined\n sessionId = undefined\n warnedMissingSessionId = false\n circuitBreaker.resetTurn()\n })\n\n registerAutoReviewCommand(pi, {\n configStore,\n getActiveConfig: () => generation?.config,\n applyConfig,\n })\n}\n","import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'\nimport { createAutoReviewExtension } from './extension.js'\n\nexport default function permissionAutoReviewExtension(pi: ExtensionAPI): void {\n createAutoReviewExtension(pi)\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mzwing/pi-permission-auto-review",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Codex-style automatic approval reviews for @gotgenes/pi-permission-system",
5
5
  "keywords": [
6
6
  "authorizer",