@jacexh/claude-web-console 0.12.1 → 0.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { waitForSessionId } from '../session-id-resolver'
|
|
3
|
+
|
|
4
|
+
describe('waitForSessionId', () => {
|
|
5
|
+
it('resolves when session.sessionId becomes available', async () => {
|
|
6
|
+
let ready = false
|
|
7
|
+
const session = {
|
|
8
|
+
get sessionId() {
|
|
9
|
+
if (!ready) throw new Error('not ready')
|
|
10
|
+
return 'real-session-id'
|
|
11
|
+
},
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Simulate SDK resolving sessionId after 100ms
|
|
15
|
+
setTimeout(() => { ready = true }, 100)
|
|
16
|
+
|
|
17
|
+
const result = await waitForSessionId(session as any, 5000)
|
|
18
|
+
expect(result).toBe('real-session-id')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('resolves immediately when sessionId is already available', async () => {
|
|
22
|
+
const session = { sessionId: 'already-ready' }
|
|
23
|
+
const result = await waitForSessionId(session as any, 5000)
|
|
24
|
+
expect(result).toBe('already-ready')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('rejects on timeout if sessionId never becomes available', async () => {
|
|
28
|
+
const session = {
|
|
29
|
+
get sessionId(): string { throw new Error('not ready') },
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
await expect(waitForSessionId(session as any, 200)).rejects.toThrow('Session init timed out')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('ignores pending- prefixed session IDs', async () => {
|
|
36
|
+
let callCount = 0
|
|
37
|
+
const session = {
|
|
38
|
+
get sessionId() {
|
|
39
|
+
callCount++
|
|
40
|
+
if (callCount < 3) return 'pending-123'
|
|
41
|
+
return 'real-id'
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const result = await waitForSessionId(session as any, 5000)
|
|
46
|
+
expect(result).toBe('real-id')
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -17,10 +17,10 @@ export function registerHttpRoutes(app: FastifyInstance, sessionManager: Session
|
|
|
17
17
|
await mkdir(cwd, { recursive: true })
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const
|
|
21
|
-
const status = sessionManager.getSessionStatus(
|
|
20
|
+
const sessionId = await sessionManager.createSession(body ?? undefined)
|
|
21
|
+
const status = sessionManager.getSessionStatus(sessionId)
|
|
22
22
|
|
|
23
|
-
reply.code(201).send({ sessionId
|
|
23
|
+
reply.code(201).send({ sessionId, status })
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
app.post<{ Params: { id: string } }>('/api/sessions/:id/resume', async (request, reply) => {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SDKSession } from '@anthropic-ai/claude-agent-sdk'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Polls session.sessionId until the SDK resolves the real ID.
|
|
5
|
+
* The SDK sets sessionId asynchronously after process init.
|
|
6
|
+
*/
|
|
7
|
+
export function waitForSessionId(session: SDKSession, timeoutMs: number): Promise<string> {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const timeout = setTimeout(() => {
|
|
10
|
+
clearInterval(poll)
|
|
11
|
+
reject(new Error('Session init timed out'))
|
|
12
|
+
}, timeoutMs)
|
|
13
|
+
|
|
14
|
+
const poll = setInterval(() => {
|
|
15
|
+
try {
|
|
16
|
+
const id = session.sessionId
|
|
17
|
+
if (id && !id.startsWith('pending-')) {
|
|
18
|
+
clearInterval(poll)
|
|
19
|
+
clearTimeout(timeout)
|
|
20
|
+
resolve(id)
|
|
21
|
+
}
|
|
22
|
+
} catch {
|
|
23
|
+
// sessionId not ready yet, keep polling
|
|
24
|
+
}
|
|
25
|
+
}, 50)
|
|
26
|
+
|
|
27
|
+
// Check immediately (no need to wait 50ms if already ready)
|
|
28
|
+
try {
|
|
29
|
+
const id = session.sessionId
|
|
30
|
+
if (id && !id.startsWith('pending-')) {
|
|
31
|
+
clearInterval(poll)
|
|
32
|
+
clearTimeout(timeout)
|
|
33
|
+
resolve(id)
|
|
34
|
+
}
|
|
35
|
+
} catch {
|
|
36
|
+
// not ready, poll will handle it
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
@@ -19,6 +19,7 @@ import type { FastifyBaseLogger } from 'fastify'
|
|
|
19
19
|
import type { SessionInfo, EffortLevel } from './types.js'
|
|
20
20
|
import { shouldBroadcastTurnStarted, shouldResetToIdleOnStreamEnd, isTurnMessage, type TurnState } from './turn-lifecycle.js'
|
|
21
21
|
import { SessionStatusTracker } from './session-status.js'
|
|
22
|
+
import { waitForSessionId } from './session-id-resolver.js'
|
|
22
23
|
|
|
23
24
|
type PermissionResolver = {
|
|
24
25
|
resolve: (approved: boolean, reason?: string, updatedPermissions?: import('@anthropic-ai/claude-agent-sdk').PermissionUpdate[]) => void
|
|
@@ -389,7 +390,9 @@ export class SessionManager {
|
|
|
389
390
|
// For new sessions, start stream immediately — SDK may emit init messages
|
|
390
391
|
this.startStreamConsumer(tempId, session)
|
|
391
392
|
|
|
392
|
-
|
|
393
|
+
// Poll session.sessionId directly — don't depend on consumeStream remap timing
|
|
394
|
+
const sessionId = await waitForSessionId(session, 30_000)
|
|
395
|
+
return sessionId
|
|
393
396
|
}
|
|
394
397
|
|
|
395
398
|
private fetchAndBroadcastModels(sessionId: string, session: SDKSession, currentModel?: string): void {
|