mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 02:14:32 +00:00
fix(auth): keep resume lane warning non-blocking
- extract account resume lane guidance into a dedicated auth helper - swallow diagnostic failures so account launches still reach execClaude - add focused tests for the warning success and failure paths
This commit is contained in:
1 parent
2830c2ae9e
commit
1b3528f61a
3 files changed
+118
-42
No files matched your search
@@ -0,0 +1,64 @@
|
|||||||
|
import * as path from 'path';
|
||||||
|
import { info, warn } from '../utils/ui';
|
||||||
|
import {
|
||||||
|
parseResumeFlagIntent,
|
||||||
|
resolveRuntimePlainCcsResumeLane,
|
||||||
|
type ResumeLaneSummary,
|
||||||
|
} from './resume-lane-diagnostics';
|
||||||
|
|
||||||
|
interface ResumeLaneWarningDependencies {
|
||||||
|
resolvePlainLane?: () => Promise<ResumeLaneSummary>;
|
||||||
|
log?: (message: string) => void;
|
||||||
|
debug?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function maybeWarnAboutResumeLaneMismatch(
|
||||||
|
profileName: string,
|
||||||
|
accountConfigDir: string,
|
||||||
|
args: string[],
|
||||||
|
deps: ResumeLaneWarningDependencies = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const resumeIntent = parseResumeFlagIntent(args);
|
||||||
|
if (!resumeIntent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const log = deps.log ?? console.error;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const plainLane = await (deps.resolvePlainLane ?? resolveRuntimePlainCcsResumeLane)();
|
||||||
|
if (path.resolve(plainLane.configDir) === path.resolve(accountConfigDir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(
|
||||||
|
warn(
|
||||||
|
`Resume for account "${profileName}" will search that account lane, not the current plain ccs lane.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
log(info(` Account lane: ${accountConfigDir}`));
|
||||||
|
log(info(` Plain ccs lane: ${plainLane.label} (${plainLane.configDir})`));
|
||||||
|
if (resumeIntent.explicitSessionId) {
|
||||||
|
log(
|
||||||
|
info(
|
||||||
|
' This explicit session ID may have been created in a different lane, so Claude may not find it here.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
log(info(' Recover the original lane first: ccs -r'));
|
||||||
|
log(info(' Back it up before changing setup: ccs auth backup default'));
|
||||||
|
log(
|
||||||
|
info(` For future work, align plain ccs with this account: ccs auth default ${profileName}`)
|
||||||
|
);
|
||||||
|
log('');
|
||||||
|
} catch (error) {
|
||||||
|
log(
|
||||||
|
warn(
|
||||||
|
'Resume lane guidance skipped because diagnostics failed; continuing with the account lane.'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (deps.debug ?? Boolean(process.env.CCS_DEBUG)) {
|
||||||
|
log(info(` Diagnostic error: ${(error as Error).message}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-42
@@ -1,7 +1,6 @@
|
|||||||
import './utils/fetch-proxy-setup';
|
import './utils/fetch-proxy-setup';
|
||||||
|
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
|
||||||
import { detectClaudeCli } from './utils/claude-detector';
|
import { detectClaudeCli } from './utils/claude-detector';
|
||||||
import {
|
import {
|
||||||
getSettingsPath,
|
getSettingsPath,
|
||||||
@@ -65,10 +64,7 @@ import { tryHandleRootCommand } from './commands/root-command-router';
|
|||||||
// Import extracted utility functions
|
// Import extracted utility functions
|
||||||
import { execClaude } from './utils/shell-executor';
|
import { execClaude } from './utils/shell-executor';
|
||||||
import { isDeprecatedGlmtProfileName, normalizeDeprecatedGlmtEnv } from './utils/glmt-deprecation';
|
import { isDeprecatedGlmtProfileName, normalizeDeprecatedGlmtEnv } from './utils/glmt-deprecation';
|
||||||
import {
|
import { maybeWarnAboutResumeLaneMismatch } from './auth/resume-lane-warning';
|
||||||
parseResumeFlagIntent,
|
|
||||||
resolveRuntimePlainCcsResumeLane,
|
|
||||||
} from './auth/resume-lane-diagnostics';
|
|
||||||
|
|
||||||
// Import target adapter system
|
// Import target adapter system
|
||||||
import {
|
import {
|
||||||
@@ -264,43 +260,6 @@ function shouldPassthroughNativeCodexFlagCommand(args: string[]): boolean {
|
|||||||
return getNativeCodexPassthroughArgs(args) !== null;
|
return getNativeCodexPassthroughArgs(args) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function maybeWarnAboutResumeLaneMismatch(
|
|
||||||
profileName: string,
|
|
||||||
accountConfigDir: string,
|
|
||||||
args: string[]
|
|
||||||
): Promise<void> {
|
|
||||||
const resumeIntent = parseResumeFlagIntent(args);
|
|
||||||
if (!resumeIntent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const plainLane = await resolveRuntimePlainCcsResumeLane();
|
|
||||||
if (path.resolve(plainLane.configDir) === path.resolve(accountConfigDir)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error(
|
|
||||||
warn(
|
|
||||||
`Resume for account "${profileName}" will search that account lane, not the current plain ccs lane.`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
console.error(info(` Account lane: ${accountConfigDir}`));
|
|
||||||
console.error(info(` Plain ccs lane: ${plainLane.label} (${plainLane.configDir})`));
|
|
||||||
if (resumeIntent.explicitSessionId) {
|
|
||||||
console.error(
|
|
||||||
info(
|
|
||||||
` This explicit session ID may have been created in a different lane, so Claude may not find it here.`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
console.error(info(` Recover the original lane first: ccs -r`));
|
|
||||||
console.error(info(` Back it up before changing setup: ccs auth backup default`));
|
|
||||||
console.error(
|
|
||||||
info(` For future work, align plain ccs with this account: ccs auth default ${profileName}`)
|
|
||||||
);
|
|
||||||
console.error('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNativeCodexPassthroughArgs(args: string[]): string[] | null {
|
function getNativeCodexPassthroughArgs(args: string[]): string[] | null {
|
||||||
const targetArgs = stripTargetFlag(args);
|
const targetArgs = stripTargetFlag(args);
|
||||||
if (resolveTargetType(args) !== 'codex' || targetArgs.length === 0) {
|
if (resolveTargetType(args) !== 'codex' || targetArgs.length === 0) {
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { describe, expect, it } from 'bun:test';
|
||||||
|
import { maybeWarnAboutResumeLaneMismatch } from '../../../src/auth/resume-lane-warning';
|
||||||
|
|
||||||
|
describe('resume lane warning', () => {
|
||||||
|
it('prints guidance when the plain ccs lane differs from the account lane', async () => {
|
||||||
|
const logs: string[] = [];
|
||||||
|
|
||||||
|
await maybeWarnAboutResumeLaneMismatch('work', '/tmp/account-lane', ['--resume'], {
|
||||||
|
log: (message) => logs.push(message),
|
||||||
|
resolvePlainLane: async () => ({
|
||||||
|
kind: 'native',
|
||||||
|
label: 'native Claude lane',
|
||||||
|
configDir: '/tmp/native-lane',
|
||||||
|
projectCount: 12,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(logs[0]).toContain('Resume for account "work" will search that account lane');
|
||||||
|
expect(logs).toContain('[i] Account lane: /tmp/account-lane');
|
||||||
|
expect(logs).toContain('[i] Plain ccs lane: native Claude lane (/tmp/native-lane)');
|
||||||
|
expect(logs).toContain('[i] Recover the original lane first: ccs -r');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not log anything when resume is not requested', async () => {
|
||||||
|
const logs: string[] = [];
|
||||||
|
|
||||||
|
await maybeWarnAboutResumeLaneMismatch('work', '/tmp/account-lane', ['hello'], {
|
||||||
|
log: (message) => logs.push(message),
|
||||||
|
resolvePlainLane: async () => {
|
||||||
|
throw new Error('should not be called');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(logs).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('swallows diagnostic failures and keeps the warning path non-fatal', async () => {
|
||||||
|
const logs: string[] = [];
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
maybeWarnAboutResumeLaneMismatch('work', '/tmp/account-lane', ['-r'], {
|
||||||
|
debug: true,
|
||||||
|
log: (message) => logs.push(message),
|
||||||
|
resolvePlainLane: async () => {
|
||||||
|
throw new Error('broken config');
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).resolves.toBeUndefined();
|
||||||
|
|
||||||
|
expect(logs[0]).toContain('Resume lane guidance skipped because diagnostics failed');
|
||||||
|
expect(logs[1]).toContain('Diagnostic error: broken config');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user