@jacexh/claude-web-console 0.7.9 → 0.7.10
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 +1 -1
- package/server/src/session-manager.ts +35 -14
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type SDKMessage,
|
|
12
12
|
type PermissionResult,
|
|
13
13
|
} from '@anthropic-ai/claude-agent-sdk'
|
|
14
|
-
import { readFileSync, readdirSync, statSync } from 'node:fs'
|
|
14
|
+
import { readFileSync, writeFileSync, readdirSync, statSync, mkdirSync } from 'node:fs'
|
|
15
15
|
import { join } from 'node:path'
|
|
16
16
|
import { homedir } from 'node:os'
|
|
17
17
|
import type { FastifyBaseLogger } from 'fastify'
|
|
@@ -57,16 +57,16 @@ function cleanEnv(cwd?: string): Record<string, string | undefined> {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
const CLAUDE_EXECUTABLE = process.env.CLAUDE_PATH ?? 'claude'
|
|
60
|
+
const CLAUDE_DIR = process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), '.claude')
|
|
60
61
|
|
|
61
62
|
// Read ~/.claude/settings.json and resolve enabled plugins to local --plugin-dir paths
|
|
62
63
|
function getPluginDirArgs(): string[] {
|
|
63
|
-
const home = homedir()
|
|
64
64
|
try {
|
|
65
|
-
const settings = JSON.parse(readFileSync(join(
|
|
65
|
+
const settings = JSON.parse(readFileSync(join(CLAUDE_DIR, 'settings.json'), 'utf-8'))
|
|
66
66
|
const enabled = settings.enabledPlugins as Record<string, boolean> | undefined
|
|
67
67
|
if (!enabled) return []
|
|
68
68
|
const args: string[] = []
|
|
69
|
-
const pluginsBase = join(
|
|
69
|
+
const pluginsBase = join(CLAUDE_DIR, 'plugins')
|
|
70
70
|
for (const [key, value] of Object.entries(enabled)) {
|
|
71
71
|
if (!value) continue
|
|
72
72
|
// key format: "plugin-name@marketplace-id"
|
|
@@ -103,7 +103,7 @@ function getPluginDirArgs(): string[] {
|
|
|
103
103
|
|
|
104
104
|
/** Check if a session is being used by an external process (e.g. CLI) */
|
|
105
105
|
function isSessionLockedExternally(sessionId: string): boolean {
|
|
106
|
-
const sessionsDir = join(
|
|
106
|
+
const sessionsDir = join(CLAUDE_DIR, 'sessions')
|
|
107
107
|
try {
|
|
108
108
|
const files = readdirSync(sessionsDir).filter((f) => f.endsWith('.json'))
|
|
109
109
|
for (const file of files) {
|
|
@@ -119,6 +119,28 @@ function isSessionLockedExternally(sessionId: string): boolean {
|
|
|
119
119
|
return false
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
const optionsDir = join(CLAUDE_DIR, 'claude-web-console')
|
|
123
|
+
|
|
124
|
+
type SessionCreationOptions = {
|
|
125
|
+
model?: string
|
|
126
|
+
permissionMode?: string
|
|
127
|
+
executableArgs?: string[]
|
|
128
|
+
env?: Record<string, string>
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function saveSessionOptions(sessionId: string, opts: SessionCreationOptions): void {
|
|
132
|
+
try {
|
|
133
|
+
mkdirSync(optionsDir, { recursive: true })
|
|
134
|
+
writeFileSync(join(optionsDir, `${sessionId}.options.json`), JSON.stringify(opts))
|
|
135
|
+
} catch { /* best-effort */ }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function loadSessionOptions(sessionId: string): SessionCreationOptions | undefined {
|
|
139
|
+
try {
|
|
140
|
+
return JSON.parse(readFileSync(join(optionsDir, `${sessionId}.options.json`), 'utf-8'))
|
|
141
|
+
} catch { return undefined }
|
|
142
|
+
}
|
|
143
|
+
|
|
122
144
|
export class SessionManager {
|
|
123
145
|
private log: FastifyBaseLogger
|
|
124
146
|
private sessions = new Map<string, SDKSession>()
|
|
@@ -133,12 +155,7 @@ export class SessionManager {
|
|
|
133
155
|
// Track cwd for each session so we can resume in the correct project
|
|
134
156
|
private sessionCwds = new Map<string, string>()
|
|
135
157
|
/** User-supplied creation options that must survive resume cycles */
|
|
136
|
-
private sessionCreationOptions = new Map<string,
|
|
137
|
-
model?: string
|
|
138
|
-
permissionMode?: string
|
|
139
|
-
executableArgs?: string[]
|
|
140
|
-
env?: Record<string, string>
|
|
141
|
-
}>()
|
|
158
|
+
private sessionCreationOptions = new Map<string, SessionCreationOptions>()
|
|
142
159
|
// Cache commands extracted from SDK init messages
|
|
143
160
|
private sessionCommands = new Map<string, { name: string; description: string }[]>()
|
|
144
161
|
// Active stream (Query) references for control requests like setModel
|
|
@@ -491,7 +508,7 @@ export class SessionManager {
|
|
|
491
508
|
const c = this.sessionCwds.get(tempId)
|
|
492
509
|
if (c) { this.sessionCwds.delete(tempId); this.sessionCwds.set(sessionId, c) }
|
|
493
510
|
const opts = this.sessionCreationOptions.get(tempId)
|
|
494
|
-
if (opts) { this.sessionCreationOptions.delete(tempId); this.sessionCreationOptions.set(sessionId, opts) }
|
|
511
|
+
if (opts) { this.sessionCreationOptions.delete(tempId); this.sessionCreationOptions.set(sessionId, opts); saveSessionOptions(sessionId, opts) }
|
|
495
512
|
const listeners = this.sessionListeners.get(tempId)
|
|
496
513
|
if (listeners) { this.sessionListeners.delete(tempId); this.sessionListeners.set(sessionId, listeners) }
|
|
497
514
|
this.streamingSessionIds.delete(tempId)
|
|
@@ -746,9 +763,13 @@ export class SessionManager {
|
|
|
746
763
|
}
|
|
747
764
|
this.closedSessionIds.delete(sessionId)
|
|
748
765
|
|
|
749
|
-
// Use the cached cwd and creation options so claude spawns with the correct config
|
|
766
|
+
// Use the cached cwd and creation options so claude spawns with the correct config.
|
|
767
|
+
// Fall back to disk if the in-memory cache was lost (e.g. server restart).
|
|
750
768
|
const cwd = this.sessionCwds.get(sessionId)
|
|
751
|
-
const cached = this.sessionCreationOptions.get(sessionId)
|
|
769
|
+
const cached = this.sessionCreationOptions.get(sessionId) ?? loadSessionOptions(sessionId)
|
|
770
|
+
if (cached && !this.sessionCreationOptions.has(sessionId)) {
|
|
771
|
+
this.sessionCreationOptions.set(sessionId, cached)
|
|
772
|
+
}
|
|
752
773
|
const resumeSessionIdRef = { current: sessionId }
|
|
753
774
|
const pluginArgs = getPluginDirArgs()
|
|
754
775
|
const userArgs = cached?.executableArgs ?? []
|