mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-20 00:14:58 +00:00
fix: support Claude subcommands and background sessions
Squash merge PR #1240.\n\nValidated locally from the PR head because trusted-author GitHub CI was skipped for this fork PR:\n- bun run validate\n- bun run build:all\n- bun run test:all\n- CCS_E2E_SKIP_BUILD=1 bun run test:e2e
This commit is contained in:
1 parent
e87b627764
commit
35b6210cd2
7 files changed
+340
-113
No files matched your search
@@ -0,0 +1,57 @@
|
||||
import { describe, it, expect } from 'bun:test';
|
||||
import {
|
||||
hasClaudeBackgroundWorkerUsingBaseUrlInProcessList,
|
||||
shouldKeepSessionProxiesAlive,
|
||||
} from '../../../src/cliproxy/executor/session-bridge';
|
||||
|
||||
describe('session bridge background proxy keepalive', () => {
|
||||
it('keeps per-session proxies alive after a clean Claude exit when a bg worker inherited the base URL', () => {
|
||||
expect(
|
||||
shouldKeepSessionProxiesAlive({
|
||||
code: 0,
|
||||
signal: null,
|
||||
backgroundKeepAliveBaseUrl: 'http://127.0.0.1:64314/api/provider/codex',
|
||||
hasBackgroundWorkerUsingBaseUrl: () => true,
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('cleans up per-session proxies when no bg worker inherited the base URL', () => {
|
||||
expect(
|
||||
shouldKeepSessionProxiesAlive({
|
||||
code: 0,
|
||||
signal: null,
|
||||
backgroundKeepAliveBaseUrl: 'http://127.0.0.1:64314/api/provider/codex',
|
||||
hasBackgroundWorkerUsingBaseUrl: () => false,
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('cleans up per-session proxies for signaled Claude exits', () => {
|
||||
expect(
|
||||
shouldKeepSessionProxiesAlive({
|
||||
code: null,
|
||||
signal: 'SIGTERM',
|
||||
backgroundKeepAliveBaseUrl: 'http://127.0.0.1:64314/api/provider/codex',
|
||||
hasBackgroundWorkerUsingBaseUrl: () => true,
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('detects Claude bg workers that inherited the exact base URL', () => {
|
||||
const baseUrl = 'http://127.0.0.1:64314/api/provider/codex';
|
||||
const processList = `
|
||||
123 /opt/claude/claude.exe --bg-spare /tmp/claim.sock ANTHROPIC_BASE_URL=${baseUrl} ANTHROPIC_AUTH_TOKEN=ccs-internal-managed
|
||||
456 /opt/claude/claude.exe --bg-spare /tmp/claim.sock ANTHROPIC_BASE_URL=http://127.0.0.1:62075/api/provider/codex
|
||||
789 /opt/claude/claude.exe --print ANTHROPIC_BASE_URL=${baseUrl}
|
||||
`;
|
||||
|
||||
expect(hasClaudeBackgroundWorkerUsingBaseUrlInProcessList(processList, baseUrl)).toBe(true);
|
||||
expect(
|
||||
hasClaudeBackgroundWorkerUsingBaseUrlInProcessList(
|
||||
processList,
|
||||
'http://127.0.0.1:65535/api/provider/codex'
|
||||
)
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
import { isClaudeSubcommandInvocation } from '../../../src/utils/claude-subcommand-detector';
|
||||
import {
|
||||
isClaudeSubcommandInvocation,
|
||||
stripClaudeCodeFeatureBlockingEnv,
|
||||
stripClaudeSubcommandSessionArgs,
|
||||
} from '../../../src/utils/claude-subcommand-detector';
|
||||
import { appendThirdPartyWebSearchToolArgs } from '../../../src/utils/websearch/claude-tool-args';
|
||||
import { appendThirdPartyImageAnalysisToolArgs } from '../../../src/utils/image-analysis/claude-tool-args';
|
||||
import { appendBrowserToolArgs } from '../../../src/utils/browser/claude-tool-args';
|
||||
@@ -36,6 +40,14 @@ describe('isClaudeSubcommandInvocation', () => {
|
||||
it('skips past value-taking flags before the positional', () => {
|
||||
expect(isClaudeSubcommandInvocation(['--model', 'sonnet', 'agents'])).toBe(true);
|
||||
expect(isClaudeSubcommandInvocation(['--settings', '/tmp/s.json', 'doctor'])).toBe(true);
|
||||
expect(
|
||||
isClaudeSubcommandInvocation([
|
||||
'--dangerously-skip-permissions',
|
||||
'--teammate-mode',
|
||||
'in-process',
|
||||
'agents',
|
||||
])
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('does not treat a flag value matching a subcommand name as a subcommand', () => {
|
||||
@@ -57,6 +69,59 @@ describe('isClaudeSubcommandInvocation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('stripClaudeCodeFeatureBlockingEnv', () => {
|
||||
it('removes telemetry disable env that blocks Claude Code background features', () => {
|
||||
const env = stripClaudeCodeFeatureBlockingEnv({
|
||||
DISABLE_TELEMETRY: '1',
|
||||
DISABLE_BUG_COMMAND: '1',
|
||||
DISABLE_ERROR_REPORTING: '1',
|
||||
ANTHROPIC_MODEL: 'gpt-5.5',
|
||||
});
|
||||
|
||||
expect(env.DISABLE_TELEMETRY).toBeUndefined();
|
||||
expect(env.DISABLE_BUG_COMMAND).toBe('1');
|
||||
expect(env.DISABLE_ERROR_REPORTING).toBe('1');
|
||||
expect(env.ANTHROPIC_MODEL).toBe('gpt-5.5');
|
||||
});
|
||||
});
|
||||
|
||||
describe('stripClaudeSubcommandSessionArgs', () => {
|
||||
it('removes session-only flags before a Claude subcommand', () => {
|
||||
expect(
|
||||
stripClaudeSubcommandSessionArgs([
|
||||
'--dangerously-skip-permissions',
|
||||
'--teammate-mode',
|
||||
'in-process',
|
||||
'agents',
|
||||
])
|
||||
).toEqual(['agents']);
|
||||
});
|
||||
|
||||
it('removes session-only flags after a Claude subcommand while preserving subcommand flags', () => {
|
||||
expect(
|
||||
stripClaudeSubcommandSessionArgs([
|
||||
'agents',
|
||||
'--dangerously-skip-permissions',
|
||||
'--teammate-mode',
|
||||
'in-process',
|
||||
'--setting-sources',
|
||||
'user',
|
||||
])
|
||||
).toEqual(['agents', '--setting-sources', 'user']);
|
||||
});
|
||||
|
||||
it('leaves non-subcommand interactive launches unchanged', () => {
|
||||
expect(
|
||||
stripClaudeSubcommandSessionArgs([
|
||||
'--dangerously-skip-permissions',
|
||||
'--teammate-mode',
|
||||
'in-process',
|
||||
'fix the bug',
|
||||
])
|
||||
).toEqual(['--dangerously-skip-permissions', '--teammate-mode', 'in-process', 'fix the bug']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('subcommand passthrough — injectors short-circuit', () => {
|
||||
it('appendThirdPartyWebSearchToolArgs returns args unchanged for subcommand invocations', () => {
|
||||
expect(appendThirdPartyWebSearchToolArgs(['agents'])).toEqual(['agents']);
|
||||
|
||||
Reference in new issue
Block a user