mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 08:17:11 +00:00
feat: report permission mode persist receipt status
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user