@jacexh/claude-web-console 0.10.6 → 0.11.0
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/client/dist/assets/{_baseUniq-68MegVue.js → _baseUniq-C8KadaZm.js} +1 -1
- package/client/dist/assets/{arc-DGs2oxvI.js → arc-B2W9x-cV.js} +1 -1
- package/client/dist/assets/{architectureDiagram-Q4EWVU46-9f3V68WI.js → architectureDiagram-Q4EWVU46-BRjvIRM_.js} +1 -1
- package/client/dist/assets/{blockDiagram-DXYQGD6D-nw_XrJPn.js → blockDiagram-DXYQGD6D-BcTkMEef.js} +1 -1
- package/client/dist/assets/{c4Diagram-AHTNJAMY-DtmpkbCH.js → c4Diagram-AHTNJAMY-egjSISEz.js} +1 -1
- package/client/dist/assets/channel-De3V3xku.js +1 -0
- package/client/dist/assets/{chunk-4BX2VUAB-CXkBrbXl.js → chunk-4BX2VUAB-5ky7wtNG.js} +1 -1
- package/client/dist/assets/{chunk-4TB4RGXK-Cpwuap5g.js → chunk-4TB4RGXK-CT-lH0qn.js} +1 -1
- package/client/dist/assets/{chunk-55IACEB6-MDkMv1Vj.js → chunk-55IACEB6-D9CKt7OU.js} +1 -1
- package/client/dist/assets/{chunk-EDXVE4YY-fWFZkL3K.js → chunk-EDXVE4YY-NwC01K04.js} +1 -1
- package/client/dist/assets/{chunk-FMBD7UC4-aLTS4ppS.js → chunk-FMBD7UC4-BCG3_zqC.js} +1 -1
- package/client/dist/assets/{chunk-OYMX7WX6-CdiOjMj9.js → chunk-OYMX7WX6-DJSGZ6jV.js} +1 -1
- package/client/dist/assets/{chunk-QZHKN3VN-B9w_-JI6.js → chunk-QZHKN3VN-BBIVA3HS.js} +1 -1
- package/client/dist/assets/{chunk-YZCP3GAM-BCHcb4hM.js → chunk-YZCP3GAM-C09sqCat.js} +1 -1
- package/client/dist/assets/classDiagram-6PBFFD2Q-CqsWJaxt.js +1 -0
- package/client/dist/assets/classDiagram-v2-HSJHXN6E-CqsWJaxt.js +1 -0
- package/client/dist/assets/clone-5Qb140gW.js +1 -0
- package/client/dist/assets/{cose-bilkent-S5V4N54A-D-D1pyZ4.js → cose-bilkent-S5V4N54A-35P9iw0b.js} +1 -1
- package/client/dist/assets/{dagre-KV5264BT-6Cz3n9So.js → dagre-KV5264BT-CXV-WCZD.js} +1 -1
- package/client/dist/assets/{diagram-5BDNPKRD-DFjJzsE0.js → diagram-5BDNPKRD-Dp3u_O_t.js} +1 -1
- package/client/dist/assets/{diagram-G4DWMVQ6-BS9PCHKv.js → diagram-G4DWMVQ6-BtWAfxpb.js} +1 -1
- package/client/dist/assets/{diagram-MMDJMWI5-CsF9E5G3.js → diagram-MMDJMWI5-hf_41SmM.js} +1 -1
- package/client/dist/assets/{diagram-TYMM5635-CZ413KNX.js → diagram-TYMM5635-BjK1YnVW.js} +1 -1
- package/client/dist/assets/{erDiagram-SMLLAGMA-WO8fXuNp.js → erDiagram-SMLLAGMA-CmcBJzib.js} +1 -1
- package/client/dist/assets/{flowDiagram-DWJPFMVM-CzBUR3uU.js → flowDiagram-DWJPFMVM-D90oEHbY.js} +1 -1
- package/client/dist/assets/{ganttDiagram-T4ZO3ILL-B60qcaB5.js → ganttDiagram-T4ZO3ILL-BkpoWXoe.js} +1 -1
- package/client/dist/assets/{gitGraphDiagram-UUTBAWPF-CnB_Lftl.js → gitGraphDiagram-UUTBAWPF-C8zLE_7k.js} +1 -1
- package/client/dist/assets/{graph-CwsRpftd.js → graph-Bh3K-muc.js} +1 -1
- package/client/dist/assets/{index-BlOeGePC.js → index-DBmP29uk.js} +77 -77
- package/client/dist/assets/{infoDiagram-42DDH7IO-CPfOWmw3.js → infoDiagram-42DDH7IO-BM0WXxrt.js} +1 -1
- package/client/dist/assets/{ishikawaDiagram-UXIWVN3A-DbLJUVid.js → ishikawaDiagram-UXIWVN3A-UAHaEHNp.js} +1 -1
- package/client/dist/assets/{journeyDiagram-VCZTEJTY-Dbl8zh4b.js → journeyDiagram-VCZTEJTY-Cafrpd2t.js} +1 -1
- package/client/dist/assets/{kanban-definition-6JOO6SKY-Csb1o0yW.js → kanban-definition-6JOO6SKY-D0ZRwwaM.js} +1 -1
- package/client/dist/assets/{layout-BK4Q6R8I.js → layout-D9SZ1QBf.js} +1 -1
- package/client/dist/assets/{linear-CvJiszRa.js → linear-CpQg9EBQ.js} +1 -1
- package/client/dist/assets/{mermaid.core-B3-wKFnz.js → mermaid.core-Cff27cfj.js} +4 -4
- package/client/dist/assets/{min-D5RjKPqt.js → min-CCDTUlLD.js} +1 -1
- package/client/dist/assets/{mindmap-definition-QFDTVHPH-HPPx8VRM.js → mindmap-definition-QFDTVHPH-1_xvkSC-.js} +1 -1
- package/client/dist/assets/{pieDiagram-DEJITSTG-BBd6S7qX.js → pieDiagram-DEJITSTG-CXJh-BmH.js} +1 -1
- package/client/dist/assets/{quadrantDiagram-34T5L4WZ-5mFLAEO_.js → quadrantDiagram-34T5L4WZ-IIET-zJK.js} +1 -1
- package/client/dist/assets/{requirementDiagram-MS252O5E-D_j8Btvg.js → requirementDiagram-MS252O5E-CydtzCWy.js} +1 -1
- package/client/dist/assets/{sankeyDiagram-XADWPNL6-D-mJMVBg.js → sankeyDiagram-XADWPNL6-ByQ8OATo.js} +1 -1
- package/client/dist/assets/{sequenceDiagram-FGHM5R23-Du_HXzIS.js → sequenceDiagram-FGHM5R23-D1qYShIQ.js} +1 -1
- package/client/dist/assets/{stateDiagram-FHFEXIEX-DK1zMyaT.js → stateDiagram-FHFEXIEX-CLldWrCV.js} +1 -1
- package/client/dist/assets/stateDiagram-v2-QKLJ7IA2-B5cjRsZb.js +1 -0
- package/client/dist/assets/{timeline-definition-GMOUNBTQ-C4sXzll7.js → timeline-definition-GMOUNBTQ-DnPj25Y5.js} +1 -1
- package/client/dist/assets/{vennDiagram-DHZGUBPP-CxaV9frx.js → vennDiagram-DHZGUBPP-CnaH-R-v.js} +1 -1
- package/client/dist/assets/{wardley-RL74JXVD-Ci_gt1QK.js → wardley-RL74JXVD-D-Yc5POx.js} +1 -1
- package/client/dist/assets/{wardleyDiagram-NUSXRM2D-BVBkkfaG.js → wardleyDiagram-NUSXRM2D-BqXhvnsn.js} +1 -1
- package/client/dist/assets/{xychartDiagram-5P7HB3ND-Dgg3kv43.js → xychartDiagram-5P7HB3ND--56nlnda.js} +1 -1
- package/client/dist/index.html +1 -1
- package/package.json +1 -1
- package/server/src/__tests__/session-status-forward.test.ts +39 -0
- package/server/src/__tests__/session-status.test.ts +71 -0
- package/server/src/__tests__/turn-started-broadcast.test.ts +53 -0
- package/server/src/session-manager.ts +25 -9
- package/server/src/session-status.ts +30 -0
- package/server/src/types.ts +9 -1
- package/server/src/ws-handler.ts +6 -0
- package/client/dist/assets/channel-C81EZqNp.js +0 -1
- package/client/dist/assets/classDiagram-6PBFFD2Q-Bwl-Yyn3.js +0 -1
- package/client/dist/assets/classDiagram-v2-HSJHXN6E-Bwl-Yyn3.js +0 -1
- package/client/dist/assets/clone-DwEzo7pK.js +0 -1
- package/client/dist/assets/stateDiagram-v2-QKLJ7IA2-BHkgOSON.js +0 -1
|
@@ -17,6 +17,8 @@ import { join } from 'node:path'
|
|
|
17
17
|
import { homedir } from 'node:os'
|
|
18
18
|
import type { FastifyBaseLogger } from 'fastify'
|
|
19
19
|
import type { SessionInfo, EffortLevel } from './types.js'
|
|
20
|
+
import { shouldBroadcastTurnStarted, type TurnState } from './turn-lifecycle.js'
|
|
21
|
+
import { SessionStatusTracker } from './session-status.js'
|
|
20
22
|
|
|
21
23
|
type PermissionResolver = {
|
|
22
24
|
resolve: (approved: boolean, reason?: string, updatedPermissions?: import('@anthropic-ai/claude-agent-sdk').PermissionUpdate[]) => void
|
|
@@ -147,7 +149,11 @@ export class SessionManager {
|
|
|
147
149
|
private sessions = new Map<string, SDKSession>()
|
|
148
150
|
private pendingPermissions = new Map<string, PermissionResolver>()
|
|
149
151
|
private pendingElicitations = new Map<string, { resolve: (result: ElicitationResult) => void; sessionId: string }>()
|
|
150
|
-
private
|
|
152
|
+
private sessionStatus = new SessionStatusTracker((sessionId, status) => {
|
|
153
|
+
this.broadcast(sessionId, (l) => l.onMessage(sessionId, {
|
|
154
|
+
type: 'session_status', sessionId, status,
|
|
155
|
+
} as unknown as SDKMessage))
|
|
156
|
+
})
|
|
151
157
|
private closedSessionIds = new Set<string>()
|
|
152
158
|
private streamingSessionIds = new Set<string>()
|
|
153
159
|
private sessionListeners = new Map<string, Set<SessionListener>>()
|
|
@@ -368,6 +374,7 @@ export class SessionManager {
|
|
|
368
374
|
// Use a temporary ID, then remap when real sessionId arrives.
|
|
369
375
|
const tempId = `pending-${Date.now()}`
|
|
370
376
|
this.sessions.set(tempId, session)
|
|
377
|
+
this.sessionStatus.set(tempId, 'idle')
|
|
371
378
|
this.sessionCwds.set(tempId, cwd)
|
|
372
379
|
this.sessionCreationOptions.set(tempId, {
|
|
373
380
|
model: options?.model,
|
|
@@ -425,6 +432,7 @@ export class SessionManager {
|
|
|
425
432
|
while (true) {
|
|
426
433
|
this.log.info({ sessionId: currentSessionId }, 'consumeStream: entering stream()')
|
|
427
434
|
const query = session.stream()
|
|
435
|
+
const turnState: TurnState = { turnStarted: false }
|
|
428
436
|
// Store query reference so control requests (setModel etc.) can use it
|
|
429
437
|
try {
|
|
430
438
|
const sid = session.sessionId
|
|
@@ -489,6 +497,7 @@ export class SessionManager {
|
|
|
489
497
|
} else {
|
|
490
498
|
this.log.info({ cost: (msgAny as Record<string, unknown>).total_cost_usd }, 'Turn complete')
|
|
491
499
|
}
|
|
500
|
+
this.sessionStatus.set(currentSessionId, 'idle')
|
|
492
501
|
}
|
|
493
502
|
|
|
494
503
|
let sessionId: string
|
|
@@ -514,6 +523,9 @@ export class SessionManager {
|
|
|
514
523
|
if (listeners) { this.sessionListeners.delete(tempId); this.sessionListeners.set(sessionId, listeners) }
|
|
515
524
|
this.streamingSessionIds.delete(tempId)
|
|
516
525
|
this.streamingSessionIds.add(sessionId)
|
|
526
|
+
const prevStatus = this.sessionStatus.get(tempId)
|
|
527
|
+
this.sessionStatus.delete(tempId)
|
|
528
|
+
if (prevStatus) this.sessionStatus.set(sessionId, prevStatus)
|
|
517
529
|
const q = this.activeQueries.get(tempId)
|
|
518
530
|
if (q) { this.activeQueries.delete(tempId); this.activeQueries.set(sessionId, q) }
|
|
519
531
|
this.pendingRemaps.delete(tempId)
|
|
@@ -525,7 +537,10 @@ export class SessionManager {
|
|
|
525
537
|
} as unknown as SDKMessage))
|
|
526
538
|
}
|
|
527
539
|
|
|
528
|
-
|
|
540
|
+
// Set session status to running on first message of each turn
|
|
541
|
+
if (shouldBroadcastTurnStarted(turnState)) {
|
|
542
|
+
this.sessionStatus.set(sessionId, 'running')
|
|
543
|
+
}
|
|
529
544
|
this.broadcast(sessionId, (l) => l.onMessage(sessionId, msg))
|
|
530
545
|
}
|
|
531
546
|
this.log.info({ sessionId: currentSessionId }, 'consumeStream: stream() ended (turn complete)')
|
|
@@ -544,12 +559,12 @@ export class SessionManager {
|
|
|
544
559
|
} finally {
|
|
545
560
|
try {
|
|
546
561
|
const sessionId = session.sessionId
|
|
547
|
-
this.
|
|
562
|
+
this.sessionStatus.set(sessionId, 'stopped')
|
|
548
563
|
this.streamingSessionIds.delete(sessionId)
|
|
549
564
|
this.activeQueries.delete(sessionId)
|
|
550
565
|
// Clean up stale session object if stream ended unexpectedly (not via explicit closeSession).
|
|
551
566
|
// Without this, the session stays in this.sessions (appears "already running")
|
|
552
|
-
// while
|
|
567
|
+
// while sessionStatus shows it as idle — making resume impossible.
|
|
553
568
|
if (this.sessions.has(sessionId) && !this.closedSessionIds.has(sessionId)) {
|
|
554
569
|
const s = this.sessions.get(sessionId)
|
|
555
570
|
this.sessions.delete(sessionId)
|
|
@@ -558,7 +573,7 @@ export class SessionManager {
|
|
|
558
573
|
this.broadcast(sessionId, (l) => l.onEnd(sessionId))
|
|
559
574
|
} catch {
|
|
560
575
|
// Session never initialized — try with our tracked id
|
|
561
|
-
this.
|
|
576
|
+
this.sessionStatus.set(currentSessionId, 'stopped')
|
|
562
577
|
this.streamingSessionIds.delete(currentSessionId)
|
|
563
578
|
this.activeQueries.delete(currentSessionId)
|
|
564
579
|
if (this.sessions.has(currentSessionId) && !this.closedSessionIds.has(currentSessionId)) {
|
|
@@ -642,10 +657,11 @@ export class SessionManager {
|
|
|
642
657
|
} as unknown as SDKMessage))
|
|
643
658
|
}
|
|
644
659
|
|
|
645
|
-
getSessionState(sessionId: string): { model?: string; effortLevel?: EffortLevel } {
|
|
660
|
+
getSessionState(sessionId: string): { model?: string; effortLevel?: EffortLevel; status: 'idle' | 'running' | 'stopped' } {
|
|
646
661
|
return {
|
|
647
662
|
model: this.sessionModels.get(sessionId),
|
|
648
663
|
effortLevel: this.sessionEffortLevels.get(sessionId),
|
|
664
|
+
status: this.sessionStatus.get(sessionId),
|
|
649
665
|
}
|
|
650
666
|
}
|
|
651
667
|
|
|
@@ -743,7 +759,7 @@ export class SessionManager {
|
|
|
743
759
|
sessionId: s.sessionId,
|
|
744
760
|
summary: s.summary || 'Untitled',
|
|
745
761
|
lastModified: s.lastModified,
|
|
746
|
-
status: this.
|
|
762
|
+
status: this.sessionStatus.get(s.sessionId),
|
|
747
763
|
cwd: (s as Record<string, unknown>).cwd as string | undefined,
|
|
748
764
|
}))
|
|
749
765
|
}
|
|
@@ -814,7 +830,7 @@ export class SessionManager {
|
|
|
814
830
|
const session = unstable_v2_resumeSession(sessionId, sessionOptions)
|
|
815
831
|
try { process.chdir(originalCwd) } catch { /* ignore */ }
|
|
816
832
|
this.sessions.set(sessionId, session)
|
|
817
|
-
this.
|
|
833
|
+
this.sessionStatus.set(sessionId, 'idle')
|
|
818
834
|
|
|
819
835
|
// Broadcast session_resumed to all listeners so other connections update their UI
|
|
820
836
|
this.broadcast(sessionId, (l) => l.onMessage(sessionId, {
|
|
@@ -832,7 +848,7 @@ export class SessionManager {
|
|
|
832
848
|
this.closedSessionIds.add(sessionId)
|
|
833
849
|
session.close()
|
|
834
850
|
this.sessions.delete(sessionId)
|
|
835
|
-
this.
|
|
851
|
+
this.sessionStatus.set(sessionId, 'stopped')
|
|
836
852
|
this.streamingSessionIds.delete(sessionId)
|
|
837
853
|
|
|
838
854
|
// Clean up idle timer
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type SessionStatus = 'idle' | 'running' | 'stopped'
|
|
2
|
+
|
|
3
|
+
export class SessionStatusTracker {
|
|
4
|
+
private map = new Map<string, SessionStatus>()
|
|
5
|
+
private onChange?: (sessionId: string, status: SessionStatus) => void
|
|
6
|
+
|
|
7
|
+
constructor(onChange?: (sessionId: string, status: SessionStatus) => void) {
|
|
8
|
+
this.onChange = onChange
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
get(sessionId: string): SessionStatus {
|
|
12
|
+
return this.map.get(sessionId) ?? 'stopped'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
set(sessionId: string, status: SessionStatus): void {
|
|
16
|
+
const prev = this.map.get(sessionId)
|
|
17
|
+
this.map.set(sessionId, status)
|
|
18
|
+
if (prev !== status && this.onChange) {
|
|
19
|
+
this.onChange(sessionId, status)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
delete(sessionId: string): void {
|
|
24
|
+
this.map.delete(sessionId)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getAll(): Map<string, SessionStatus> {
|
|
28
|
+
return new Map(this.map)
|
|
29
|
+
}
|
|
30
|
+
}
|
package/server/src/types.ts
CHANGED
|
@@ -158,7 +158,7 @@ export interface SessionInfo {
|
|
|
158
158
|
sessionId: string
|
|
159
159
|
summary: string
|
|
160
160
|
lastModified: number
|
|
161
|
-
status: 'idle' | 'running'
|
|
161
|
+
status: 'idle' | 'running' | 'stopped'
|
|
162
162
|
cwd?: string
|
|
163
163
|
}
|
|
164
164
|
|
|
@@ -277,6 +277,7 @@ export interface SessionStateMessage {
|
|
|
277
277
|
sessionId: string
|
|
278
278
|
model?: string
|
|
279
279
|
effortLevel?: EffortLevel
|
|
280
|
+
status?: 'idle' | 'running' | 'stopped'
|
|
280
281
|
}
|
|
281
282
|
|
|
282
283
|
export interface SubagentMessagesMessage {
|
|
@@ -302,6 +303,12 @@ export interface SessionSettingsMessage {
|
|
|
302
303
|
settings: Record<string, unknown>
|
|
303
304
|
}
|
|
304
305
|
|
|
306
|
+
export interface SessionStatusMessage {
|
|
307
|
+
type: 'session_status'
|
|
308
|
+
sessionId: string
|
|
309
|
+
status: string
|
|
310
|
+
}
|
|
311
|
+
|
|
305
312
|
export type ServerMessage =
|
|
306
313
|
| SessionCreatedMessage
|
|
307
314
|
| SessionListMessage
|
|
@@ -325,3 +332,4 @@ export type ServerMessage =
|
|
|
325
332
|
| SubagentMessagesMessage
|
|
326
333
|
| ElicitationRequestMessage
|
|
327
334
|
| SessionSettingsMessage
|
|
335
|
+
| SessionStatusMessage
|
package/server/src/ws-handler.ts
CHANGED
|
@@ -135,6 +135,12 @@ export function createWsHandler(sessionManager: SessionManager, log: FastifyBase
|
|
|
135
135
|
return // don't forward synthetic message
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
// Forward session_status as top-level message (not wrapped in sdk_message)
|
|
139
|
+
if (msg.type === 'session_status') {
|
|
140
|
+
send({ type: 'session_status', sessionId: msg.sessionId as string, status: msg.status as string })
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
138
144
|
send({ type: 'sdk_message', sessionId: sid, message })
|
|
139
145
|
},
|
|
140
146
|
onPermissionRequest(sid, toolUseId, toolName, input, meta) {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{aq as o,ar as n}from"./mermaid.core-B3-wKFnz.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-Cpwuap5g.js";import{_ as i}from"./mermaid.core-B3-wKFnz.js";import"./chunk-FMBD7UC4-aLTS4ppS.js";import"./chunk-YZCP3GAM-BCHcb4hM.js";import"./chunk-55IACEB6-MDkMv1Vj.js";import"./chunk-EDXVE4YY-fWFZkL3K.js";import"./index-BlOeGePC.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-4TB4RGXK-Cpwuap5g.js";import{_ as i}from"./mermaid.core-B3-wKFnz.js";import"./chunk-FMBD7UC4-aLTS4ppS.js";import"./chunk-YZCP3GAM-BCHcb4hM.js";import"./chunk-55IACEB6-MDkMv1Vj.js";import"./chunk-EDXVE4YY-fWFZkL3K.js";import"./index-BlOeGePC.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as r}from"./graph-CwsRpftd.js";var e=4;function a(o){return r(o,e)}export{a as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as e,b as r,a,S as s}from"./chunk-OYMX7WX6-CdiOjMj9.js";import{_ as i}from"./mermaid.core-B3-wKFnz.js";import"./chunk-55IACEB6-MDkMv1Vj.js";import"./chunk-EDXVE4YY-fWFZkL3K.js";import"./index-BlOeGePC.js";var p={parser:a,get db(){return new s(2)},renderer:r,styles:e,init:i(t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute},"init")};export{p as diagram};
|