feat: report permission mode persist receipt status

This commit is contained in:
Tam Nhu Tran
2026-05-22 11:14:17 -04:00
parent e7fed040ee
commit 3dc1810540
2 changed files with 116 additions and 2 deletions
+34 -2
View File
@@ -42,6 +42,8 @@ interface PersistReceipt {
clearedCodexTranslatorUrlKeys: string[];
writtenKeys: string[];
unchangedWrittenKeys: string[];
writtenSettings: string[];
unchangedSettings: string[];
codexTranslatorUrlPaths: string[];
}
@@ -553,8 +555,10 @@ function findCodexTranslatorUrlPaths(value: unknown, path = ''): string[] {
function buildPersistReceipt(
existingEnv: Record<string, string>,
existingSettings: Record<string, unknown>,
mergedSettings: Record<string, unknown>,
resolved: ResolvedEnv
resolved: ResolvedEnv,
resolvedPermissionMode?: PermissionMode
): PersistReceipt {
const mergedEnv =
typeof mergedSettings.env === 'object' &&
@@ -577,12 +581,28 @@ function buildPersistReceipt(
.filter(([key, value]) => existingEnv[key] === value)
.map(([key]) => key)
.sort((left, right) => left.localeCompare(right));
const existingPermissions =
typeof existingSettings.permissions === 'object' &&
existingSettings.permissions !== null &&
!Array.isArray(existingSettings.permissions)
? (existingSettings.permissions as Record<string, unknown>)
: {};
const writtenSettings =
resolvedPermissionMode && existingPermissions.defaultMode !== resolvedPermissionMode
? ['permissions.defaultMode']
: [];
const unchangedSettings =
resolvedPermissionMode && existingPermissions.defaultMode === resolvedPermissionMode
? ['permissions.defaultMode']
: [];
return {
clearedKeys,
clearedCodexTranslatorUrlKeys,
writtenKeys,
unchangedWrittenKeys,
writtenSettings,
unchangedSettings,
codexTranslatorUrlPaths: findCodexTranslatorUrlPaths(mergedSettings),
};
}
@@ -607,6 +627,12 @@ function printPersistReceipt(receipt: PersistReceipt): void {
if (receipt.unchangedWrittenKeys.length > 0) {
console.log(` Already current keys: ${formatKeyList(receipt.unchangedWrittenKeys)}`);
}
if (receipt.writtenSettings.length > 0 || receipt.unchangedSettings.length > 0) {
console.log(` Written/rewritten managed settings: ${formatKeyList(receipt.writtenSettings)}`);
if (receipt.unchangedSettings.length > 0) {
console.log(` Already current settings: ${formatKeyList(receipt.unchangedSettings)}`);
}
}
const hadCodexTranslatorCleanup = receipt.clearedCodexTranslatorUrlKeys.length > 0;
if (receipt.codexTranslatorUrlPaths.length > 0) {
@@ -1044,7 +1070,13 @@ export async function handlePersistCommand(args: string[]): Promise<void> {
await writeClaudeSettings(mergedSettings);
const persistedSettings = await readClaudeSettings();
const receipt = buildPersistReceipt(existingEnv, persistedSettings, resolved);
const receipt = buildPersistReceipt(
existingEnv,
existingSettings,
persistedSettings,
resolved,
resolvedPermissionMode
);
console.log('');
console.log(
@@ -498,6 +498,88 @@ describe('persist command Claude extension parity', () => {
expect(renderedLogs).not.toContain('Native Codex target:');
});
it('reports written permission defaultMode without exposing the mode value', async () => {
await writeUnifiedConfig();
const settingsPath = path.join(tempRoot, '.claude', 'settings.json');
await fs.promises.mkdir(path.dirname(settingsPath), { recursive: true });
await fs.promises.writeFile(
settingsPath,
JSON.stringify(
{
env: {
KEEP_ME: 'still-here',
},
},
null,
2
) + '\n',
'utf8'
);
const originalConsoleLog = console.log;
const capturedLogs: string[] = [];
console.log = (...args: unknown[]) => {
capturedLogs.push(args.map((arg) => String(arg)).join(' '));
};
try {
await withScopedHome(() =>
handlePersistCommand(['glm', '--yes', '--permission-mode', 'acceptEdits'])
);
} finally {
console.log = originalConsoleLog;
}
const renderedLogs = capturedLogs.join('\n');
expect(renderedLogs).toContain('Written/rewritten managed settings: permissions.defaultMode');
expect(renderedLogs).not.toContain('Already current settings: permissions.defaultMode');
expect(renderedLogs).not.toContain('permissions.defaultMode: acceptEdits');
});
it('reports already-current permission defaultMode without exposing the mode value', async () => {
await writeUnifiedConfig();
const settingsPath = path.join(tempRoot, '.claude', 'settings.json');
await fs.promises.mkdir(path.dirname(settingsPath), { recursive: true });
await fs.promises.writeFile(
settingsPath,
JSON.stringify(
{
env: {
KEEP_ME: 'still-here',
},
permissions: {
defaultMode: 'acceptEdits',
allow: ['Bash(ls:*)'],
},
},
null,
2
) + '\n',
'utf8'
);
const originalConsoleLog = console.log;
const capturedLogs: string[] = [];
console.log = (...args: unknown[]) => {
capturedLogs.push(args.map((arg) => String(arg)).join(' '));
};
try {
await withScopedHome(() =>
handlePersistCommand(['glm', '--yes', '--permission-mode', 'acceptEdits'])
);
} finally {
console.log = originalConsoleLog;
}
const renderedLogs = capturedLogs.join('\n');
expect(renderedLogs).toContain('Written/rewritten managed settings: none');
expect(renderedLogs).toContain('Already current settings: permissions.defaultMode');
expect(renderedLogs).not.toContain('permissions.defaultMode: acceptEdits');
});
it('does not print native Codex target guidance for non-Codex profile persistence', async () => {
await writeUnifiedConfig();