mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-15 12:53:31 +08:00
fix(server): expose desktop sessions to Claude resume #988
Stamp desktop-owned transcripts with the claude-desktop entrypoint while preserving the SDK runtime entrypoint used for provider authentication. Tests: focused regression 41/41; chat contract 240/240; server 1622/1622; coverage 5/5 with changed lines 4/4. Live-path proof: hermetic loopback transcript was visible in Claude Code 2.1.206 /resume; no real user credentials or config were used. Constraint: check:impact remains policy-blocked until a PR has the allow-cli-core-change label. Confidence: high Scope-risk: narrow
This commit is contained in:
parent
d6cd0f1fc7
commit
936d970751
@ -486,6 +486,7 @@ describe('ConversationService', () => {
|
||||
expect(env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('kimi-k2.6')
|
||||
expect(env.CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST).toBe('1')
|
||||
expect(env.CLAUDE_CODE_ATTRIBUTION_HEADER).toBe('0')
|
||||
expect(env.CC_HAHA_TRANSCRIPT_ENTRYPOINT).toBe('claude-desktop')
|
||||
expect(env.CLAUDE_CODE_ENTRYPOINT).toBeUndefined()
|
||||
expect(env.CC_HAHA_TRACE_PROVIDER_ID).toBeUndefined()
|
||||
expect(env.CC_HAHA_TRACE_PROVIDER_NAME).toBeUndefined()
|
||||
|
||||
@ -1206,6 +1206,9 @@ export class ConversationService {
|
||||
// should come from Desktop-managed config or inherited launch env, not
|
||||
// be reintroduced from the repo's .env file.
|
||||
CC_HAHA_SKIP_DOTENV: '1',
|
||||
// Keep the SDK runtime identity for auth and client behavior, but stamp
|
||||
// desktop-owned transcripts with an entrypoint visible to Claude /resume.
|
||||
CC_HAHA_TRANSCRIPT_ENTRYPOINT: 'claude-desktop',
|
||||
...(explicitProviderEnv
|
||||
? { CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST: '1' }
|
||||
: {}),
|
||||
|
||||
@ -6,11 +6,18 @@ import * as path from 'node:path'
|
||||
import {
|
||||
enqueueSessionEntryAfterPendingForTesting,
|
||||
flushSessionStorage,
|
||||
getTranscriptPathForSession,
|
||||
recordTranscript,
|
||||
resetProjectForTesting,
|
||||
} from '../sessionStorage.js'
|
||||
import { switchSession } from '../../bootstrap/state.js'
|
||||
import type { SessionId } from '../../types/ids.js'
|
||||
import type { CustomTitleMessage } from '../../types/logs.js'
|
||||
|
||||
const originalConfigDir = process.env.CLAUDE_CONFIG_DIR
|
||||
const originalTranscriptEntrypoint = process.env.CC_HAHA_TRANSCRIPT_ENTRYPOINT
|
||||
const originalEntrypoint = process.env.CLAUDE_CODE_ENTRYPOINT
|
||||
const originalTestPersistence = process.env.TEST_ENABLE_SESSION_PERSISTENCE
|
||||
|
||||
async function createTmpDir(): Promise<string> {
|
||||
const dir = path.join(
|
||||
@ -27,6 +34,7 @@ describe('sessionStorage flush', () => {
|
||||
beforeEach(async () => {
|
||||
tmpDir = await createTmpDir()
|
||||
process.env.CLAUDE_CONFIG_DIR = tmpDir
|
||||
process.env.TEST_ENABLE_SESSION_PERSISTENCE = '1'
|
||||
resetProjectForTesting()
|
||||
})
|
||||
|
||||
@ -37,9 +45,49 @@ describe('sessionStorage flush', () => {
|
||||
} else {
|
||||
process.env.CLAUDE_CONFIG_DIR = originalConfigDir
|
||||
}
|
||||
if (originalTranscriptEntrypoint === undefined) {
|
||||
delete process.env.CC_HAHA_TRANSCRIPT_ENTRYPOINT
|
||||
} else {
|
||||
process.env.CC_HAHA_TRANSCRIPT_ENTRYPOINT = originalTranscriptEntrypoint
|
||||
}
|
||||
if (originalEntrypoint === undefined) {
|
||||
delete process.env.CLAUDE_CODE_ENTRYPOINT
|
||||
} else {
|
||||
process.env.CLAUDE_CODE_ENTRYPOINT = originalEntrypoint
|
||||
}
|
||||
if (originalTestPersistence === undefined) {
|
||||
delete process.env.TEST_ENABLE_SESSION_PERSISTENCE
|
||||
} else {
|
||||
process.env.TEST_ENABLE_SESSION_PERSISTENCE = originalTestPersistence
|
||||
}
|
||||
await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {})
|
||||
})
|
||||
|
||||
it('records the desktop transcript entrypoint without changing the runtime entrypoint', async () => {
|
||||
const sessionId = '22222222-2222-4222-8222-222222222222'
|
||||
switchSession(sessionId as SessionId)
|
||||
process.env.CLAUDE_CODE_ENTRYPOINT = 'sdk-cli'
|
||||
process.env.CC_HAHA_TRANSCRIPT_ENTRYPOINT = 'claude-desktop'
|
||||
resetProjectForTesting()
|
||||
|
||||
await recordTranscript([{
|
||||
type: 'user',
|
||||
uuid: '33333333-3333-4333-8333-333333333333',
|
||||
message: { role: 'user', content: 'desktop resume visibility' },
|
||||
} as never])
|
||||
await flushSessionStorage()
|
||||
|
||||
const transcript = await fs.readFile(getTranscriptPathForSession(sessionId), 'utf-8')
|
||||
const userEntry = transcript
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line) => JSON.parse(line) as Record<string, unknown>)
|
||||
.find((entry) => entry.type === 'user')
|
||||
|
||||
expect(userEntry?.entrypoint).toBe('claude-desktop')
|
||||
expect(process.env.CLAUDE_CODE_ENTRYPOINT).toBe('sdk-cli')
|
||||
})
|
||||
|
||||
it('drains writes that are queued by pending operations during flush', async () => {
|
||||
const transcriptPath = path.join(tmpDir, 'late-enqueue.jsonl')
|
||||
const entry: CustomTitleMessage = {
|
||||
|
||||
@ -421,7 +421,10 @@ export function getUserType(): string {
|
||||
}
|
||||
|
||||
function getEntrypoint(): string | undefined {
|
||||
return process.env.CLAUDE_CODE_ENTRYPOINT
|
||||
return (
|
||||
process.env.CC_HAHA_TRANSCRIPT_ENTRYPOINT?.trim() ||
|
||||
process.env.CLAUDE_CODE_ENTRYPOINT
|
||||
)
|
||||
}
|
||||
|
||||
export function isCustomTitleEnabled(): boolean {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user