dsclaw 0.1.5 → 0.1.7
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/dist/cli/index.js +66 -33
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +66 -33
- package/dist/index.js.map +1 -1
- package/dist/pkg/index.cjs +101029 -0
- package/dist/pkg/package.json +11 -0
- package/dist/pkg/release/dsclaw-macos-arm64 +0 -0
- package/dist/pkg/release/dsclaw-win-x64.exe +0 -0
- package/dist/pkg/web/assets/index--NY6w2i6.js +40 -0
- package/dist/pkg/web/assets/index-DXkqRQn1.css +2 -0
- package/dist/pkg/web/favicon.svg +1 -0
- package/dist/pkg/web/icon-192.png +0 -0
- package/dist/pkg/web/icon-512.png +0 -0
- package/dist/pkg/web/icons.svg +24 -0
- package/dist/pkg/web/index.html +20 -0
- package/dist/pkg/web/manifest.json +28 -0
- package/dist/pkg/web/sw.js +37 -0
- package/package.json +4 -2
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shared/tracer.ts","../../src/shared/logger.ts","../../src/cli/index.ts","../../src/cli/init.ts","../../src/gateway/config.ts","../../src/gateway/user-session.ts","../../src/dsers/auth.ts","../../src/shared/errors.ts","../../src/dsers/client.ts","../../src/shared/utils.ts","../../src/resilience/rate-limiter.ts","../../src/dsers/config.ts","../../src/dsers/browser-auth.ts","../../src/dsers/browser-finder.ts","../../src/agents/core-agent.ts","../../src/shared/audit.ts","../../src/dsers/product.ts","../../src/gateway/gateway.ts","../../src/web/server.ts","../../src/channels/telegram.ts","../../src/memory/file-provider.ts","../../src/resilience/degradation.ts","../../src/context/token-counter.ts","../../src/context/context-budget.ts","../../src/context/compaction.ts","../../src/context/history-store.ts","../../src/gateway/i18n.ts","../../src/cli/pid.ts","../../src/shared/open-browser.ts","../../src/cli/start.ts","../../src/cli/stop.ts","../../src/cli/status.ts","../../src/cli/reset.ts","../../src/cli/doctor.ts"],"sourcesContent":["/**\n * Request-scoped tracing via AsyncLocalStorage.\n * Every inbound message gets a traceId that propagates\n * through agents, tools, API calls, and logs.\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { nanoid } from \"nanoid\";\n\nexport interface TraceContext {\n traceId: string;\n userId?: string;\n channelId?: string;\n sessionId?: string;\n agentId?: string;\n}\n\nconst storage = new AsyncLocalStorage<TraceContext>();\n\nexport function runWithTrace<T>(\n ctx: Partial<TraceContext>,\n fn: () => T,\n): T {\n const traceId = ctx.traceId ?? nanoid(12);\n return storage.run({ traceId, ...ctx }, fn);\n}\n\nexport function getTraceContext(): TraceContext {\n return storage.getStore() ?? { traceId: nanoid(12) };\n}\n\nexport function getTraceId(): string {\n return getTraceContext().traceId;\n}\n","/**\n * Structured logger powered by pino.\n * Automatically injects traceId from AsyncLocalStorage.\n */\n\nimport pino from \"pino\";\nimport { getTraceContext } from \"./tracer.js\";\n\nconst rootLogger = pino({\n level: process.env[\"LOG_LEVEL\"] ?? \"info\",\n transport:\n process.env[\"NODE_ENV\"] !== \"production\"\n ? { target: \"pino-pretty\", options: { colorize: true } }\n : undefined,\n mixin() {\n const ctx = getTraceContext();\n return {\n traceId: ctx.traceId,\n ...(ctx.userId ? { userId: ctx.userId } : {}),\n ...(ctx.channelId ? { channelId: ctx.channelId } : {}),\n ...(ctx.agentId ? { agentId: ctx.agentId } : {}),\n };\n },\n});\n\nexport function createLogger(module: string): pino.Logger {\n return rootLogger.child({ module });\n}\n\nexport { rootLogger as logger };\n","/**\n * DSClaw CLI entry point.\n * No subcommand → defaults to `start` (auto-opens browser).\n */\n\nimport { Command } from \"commander\";\nimport { initCommand } from \"./init.js\";\nimport { startCommand } from \"./start.js\";\nimport { stopCommand } from \"./stop.js\";\nimport { statusCommand } from \"./status.js\";\nimport { resetCommand } from \"./reset.js\";\nimport { doctorCommand } from \"./doctor.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"dsclaw\")\n .description(\"AI-powered dropshipping agent — chat with your DSers store.\")\n .version(\"0.1.4\");\n\nprogram.action(() => startCommand({}));\n\nprogram\n .command(\"init\")\n .description(\"Setup wizard — configure Telegram (optional)\")\n .action(initCommand);\n\nprogram\n .command(\"start\")\n .description(\"Start the DSClaw bot\")\n .option(\"-c, --config <path>\", \"Path to config file\")\n .option(\"--no-open\", \"Don't auto-open browser\")\n .action(startCommand);\n\nprogram\n .command(\"stop\")\n .description(\"Stop the running DSClaw instance\")\n .action(stopCommand);\n\nprogram\n .command(\"status\")\n .description(\"Show whether DSClaw is running\")\n .action(statusCommand);\n\nprogram\n .command(\"reset\")\n .description(\"Clear all session data (re-do onboarding)\")\n .option(\"--hard\", \"Also delete config file\")\n .action(resetCommand);\n\nprogram\n .command(\"doctor\")\n .description(\"Verify configuration\")\n .action(doctorCommand);\n\nprogram.parse();\n","/**\n * Optional setup wizard — for advanced configuration.\n * Web chat works with zero config; this is for adding Telegram or changing the port.\n */\n\nimport inquirer from \"inquirer\";\nimport {\n saveConfig,\n configExists,\n CONFIG_PATH,\n type DSClawConfig,\n} from \"../gateway/config.js\";\n\nexport async function initCommand(): Promise<void> {\n console.log(\"\\n DSClaw Setup (optional)\\n\");\n console.log(\" Web chat works out of the box — this is for extra settings.\\n\");\n\n if (configExists()) {\n const { overwrite } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"overwrite\",\n message: `Config already exists at ${CONFIG_PATH}. Overwrite?`,\n default: false,\n },\n ]);\n if (!overwrite) {\n console.log(\" Cancelled.\");\n return;\n }\n }\n\n const { port } = await inquirer.prompt({\n type: \"number\",\n name: \"port\",\n message: \"Web chat port (default 3000):\",\n default: 3000,\n });\n\n const { addTelegram } = await inquirer.prompt({\n type: \"confirm\",\n name: \"addTelegram\",\n message: \"Add Telegram bot?\",\n default: false,\n });\n\n const config: DSClawConfig = { port: port as number };\n\n if (addTelegram) {\n const { botToken } = await inquirer.prompt({\n type: \"password\",\n name: \"botToken\",\n message: \"Telegram Bot Token (from @BotFather):\",\n mask: \"*\",\n validate: (v: string) =>\n v.includes(\":\") ? true : \"Token format: 123456:ABC-DEF...\",\n });\n config.telegramBotToken = botToken as string;\n }\n\n saveConfig(config);\n console.log(`\\n Config saved to ${CONFIG_PATH}`);\n console.log(\" Run 'dsclaw start' to launch.\\n\");\n}\n","/**\n * Minimal configuration — defaults work out of the box.\n * Web chat starts automatically; Telegram is optional.\n */\n\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { z } from \"zod\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"config\");\n\nexport const CONFIG_DIR = join(homedir(), \".dsclaw\");\nexport const CONFIG_PATH = join(CONFIG_DIR, \"config.json\");\n\nexport const ConfigSchema = z.object({\n port: z.number().default(3000),\n telegramBotToken: z.string().optional(),\n});\n\nexport type DSClawConfig = z.infer<typeof ConfigSchema>;\n\nconst DEFAULT_CONFIG: DSClawConfig = { port: 3000 };\n\nexport function ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n }\n}\n\nexport function loadConfig(path?: string): DSClawConfig {\n const configPath = path ?? CONFIG_PATH;\n\n if (!existsSync(configPath)) {\n log.info(\"No config file found — using defaults (web chat on port 3000)\");\n return DEFAULT_CONFIG;\n }\n\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw) as unknown;\n\n const result = ConfigSchema.safeParse(parsed);\n if (!result.success) {\n log.warn(\"Config validation failed — using defaults\");\n return DEFAULT_CONFIG;\n }\n\n log.info(\"Configuration loaded\");\n return result.data;\n}\n\nexport function saveConfig(config: DSClawConfig): void {\n ensureConfigDir();\n writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });\n log.info({ path: CONFIG_PATH }, \"Configuration saved\");\n}\n\nexport function configExists(): boolean {\n return existsSync(CONFIG_PATH);\n}\n","/**\n * User session state machine + encrypted credential storage.\n * Each Telegram user has their own session with DSers + LLM credentials.\n * Credentials are AES-256-GCM encrypted, bound to machine identity.\n */\n\nimport {\n randomBytes,\n createCipheriv,\n createDecipheriv,\n createHash,\n} from \"node:crypto\";\nimport {\n readFileSync,\n writeFileSync,\n mkdirSync,\n existsSync,\n unlinkSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { hostname, userInfo } from \"node:os\";\nimport { CONFIG_DIR } from \"./config.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"user-session\");\n\nconst ALG = \"aes-256-gcm\";\nconst IV_LEN = 12;\nconst TAG_LEN = 16;\nconst KEY_SEED = \"dsclaw-v1\";\nconst SESSIONS_DIR = join(CONFIG_DIR, \"sessions\");\nconst SALT_FILE = join(CONFIG_DIR, \".salt\");\n\nfunction getOrCreateSalt(): string {\n try {\n if (existsSync(SALT_FILE)) {\n return readFileSync(SALT_FILE, \"utf-8\").trim();\n }\n } catch { /* fall through */ }\n const salt = randomBytes(32).toString(\"hex\");\n try {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(SALT_FILE, salt, { mode: 0o600 });\n } catch (err) {\n log.warn({ err }, \"Failed to persist salt file\");\n }\n return salt;\n}\n\nlet cachedSalt: string | null = null;\nfunction getSalt(): string {\n if (!cachedSalt) cachedSalt = getOrCreateSalt();\n return cachedSalt;\n}\n\nexport type SessionState =\n | \"new\"\n | \"onboard_demo\"\n | \"onboard_dsers_email\"\n | \"onboard_dsers_password\"\n | \"onboard_llm\"\n | \"ready\";\n\nexport interface UserSessionData {\n state: SessionState;\n dspiEmail?: string;\n dspiPassword?: string;\n dspiSessionId?: string;\n dspiSessionState?: string;\n llmProvider?: string;\n llmApiKey?: string;\n llmModel?: string;\n llmBaseUrl?: string;\n language?: string;\n}\n\nfunction deriveKeyBase(extra: string): Buffer {\n let user = \"\";\n try {\n user = userInfo().username;\n } catch {\n user = process.env[\"USER\"] ?? process.env[\"USERNAME\"] ?? \"default\";\n }\n return createHash(\"sha256\")\n .update(`${KEY_SEED}:${hostname()}:${user}${extra}`)\n .digest();\n}\n\nfunction deriveKey(): Buffer {\n return deriveKeyBase(`:${getSalt()}`);\n}\n\nfunction deriveKeyLegacy(): Buffer {\n return deriveKeyBase(\"\");\n}\n\nfunction encrypt(data: string): string {\n const key = deriveKey();\n const iv = randomBytes(IV_LEN);\n const cipher = createCipheriv(ALG, key, iv, { authTagLength: TAG_LEN });\n const ct = Buffer.concat([cipher.update(data, \"utf8\"), cipher.final()]);\n const tag = cipher.getAuthTag();\n return Buffer.concat([iv, tag, ct]).toString(\"base64\");\n}\n\nfunction decryptWithKey(encoded: string, key: Buffer): string | null {\n try {\n const buf = Buffer.from(encoded, \"base64\");\n if (buf.length < IV_LEN + TAG_LEN + 1) return null;\n const iv = buf.subarray(0, IV_LEN);\n const tag = buf.subarray(IV_LEN, IV_LEN + TAG_LEN);\n const ct = buf.subarray(IV_LEN + TAG_LEN);\n const decipher = createDecipheriv(ALG, key, iv, { authTagLength: TAG_LEN });\n decipher.setAuthTag(tag);\n return Buffer.concat([decipher.update(ct), decipher.final()]).toString(\"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction decrypt(encoded: string): string | null {\n const result = decryptWithKey(encoded, deriveKey());\n if (result) return result;\n return decryptWithKey(encoded, deriveKeyLegacy());\n}\n\nfunction ensureSessionsDir(): void {\n if (!existsSync(SESSIONS_DIR)) {\n mkdirSync(SESSIONS_DIR, { recursive: true, mode: 0o700 });\n }\n}\n\nfunction sessionPath(userId: string): string {\n const safe = userId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return join(SESSIONS_DIR, `${safe}.enc`);\n}\n\nexport function loadSession(userId: string): UserSessionData {\n const p = sessionPath(userId);\n if (!existsSync(p)) {\n return { state: \"new\" };\n }\n try {\n const encrypted = readFileSync(p, \"utf-8\").trim();\n\n let json = decryptWithKey(encrypted, deriveKey());\n let needsMigration = false;\n if (!json) {\n json = decryptWithKey(encrypted, deriveKeyLegacy());\n needsMigration = !!json;\n }\n if (!json) {\n log.warn({ userId }, \"Failed to decrypt session — starting fresh\");\n return { state: \"new\" };\n }\n const session = JSON.parse(json) as UserSessionData;\n if (needsMigration) {\n log.info({ userId }, \"Migrating session to salted key\");\n saveSession(userId, session);\n }\n return session;\n } catch {\n return { state: \"new\" };\n }\n}\n\nexport function saveSession(userId: string, session: UserSessionData): void {\n ensureSessionsDir();\n const json = JSON.stringify(session);\n const encrypted = encrypt(json);\n writeFileSync(sessionPath(userId), encrypted, { mode: 0o600 });\n log.debug({ userId, state: session.state }, \"Session saved\");\n}\n\nexport function deleteSession(userId: string): void {\n const p = sessionPath(userId);\n if (existsSync(p)) {\n try {\n unlinkSync(p);\n } catch {\n /* ignore */\n }\n }\n}\n\nexport function isOnboarding(state: SessionState): boolean {\n return state !== \"ready\";\n}\n","/**\n * DSers authentication with session caching.\n * Uses email + password login matching the actual DSers API.\n * Ported from dsers-mcp-product with enhanced error classification.\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport type { DSersClientConfig } from \"./config.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { DSClawError, ErrorCategory } from \"../shared/errors.js\";\n\nconst log = createLogger(\"dsers:auth\");\nconst SESSION_TTL = 3600 * 6 * 1000;\n\ninterface SessionCache {\n session_id: string;\n state: string;\n ts: number;\n}\n\nexport class DSersAuth {\n private config: DSersClientConfig;\n private sessionId: string | null = null;\n private state: string | null = null;\n private fetchedAt = 0;\n\n constructor(config: DSersClientConfig) {\n this.config = config;\n if (config.sessionId) {\n this.sessionId = config.sessionId;\n this.state = config.sessionState ?? \"\";\n this.fetchedAt = Date.now();\n }\n }\n\n async getSession(): Promise<[string, string]> {\n if (this.sessionId && Date.now() - this.fetchedAt < SESSION_TTL) {\n return [this.sessionId, this.state ?? \"\"];\n }\n\n const cached = this.readCache();\n if (cached) {\n [this.sessionId, this.state, this.fetchedAt] = cached;\n return [this.sessionId, this.state];\n }\n\n return this.login();\n }\n\n async login(): Promise<[string, string]> {\n if (!this.config.email || !this.config.password) {\n throw new DSClawError({\n category: ErrorCategory.NEEDS_HUMAN,\n code: \"DSERS_NO_CREDENTIALS\",\n message: \"DSers email and password not configured.\",\n retryable: false,\n });\n }\n\n log.info(\"Authenticating with DSers...\");\n\n const resp = await fetch(\n `${this.config.baseUrl}/account-user-bff/v1/users/login`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n email: this.config.email,\n password: this.config.password,\n }),\n },\n );\n\n if (!resp.ok) {\n const body = await resp.text();\n throw new DSClawError({\n category:\n resp.status === 401 || resp.status === 403\n ? ErrorCategory.NEEDS_HUMAN\n : ErrorCategory.RETRYABLE,\n code: `DSERS_LOGIN_${resp.status}`,\n message: `DSers login failed (HTTP ${resp.status}): ${body.slice(0, 200)}`,\n retryable: resp.status >= 500,\n });\n }\n\n const data = (await resp.json()) as Record<string, unknown>;\n const inner = data[\"data\"] as Record<string, unknown> | undefined;\n if (!inner?.[\"sessionId\"]) {\n throw new DSClawError({\n category: ErrorCategory.NEEDS_HUMAN,\n code: \"DSERS_LOGIN_NO_SESSION\",\n message: \"DSers login succeeded but no session returned.\",\n retryable: false,\n details: { response: data },\n });\n }\n\n this.sessionId = inner[\"sessionId\"] as string;\n this.state = (inner[\"state\"] as string) ?? \"\";\n this.fetchedAt = Date.now();\n this.writeCache();\n\n log.info(\"DSers authentication successful\");\n return [this.sessionId, this.state];\n }\n\n invalidate(): void {\n this.sessionId = null;\n this.state = null;\n this.fetchedAt = 0;\n log.debug(\"Session invalidated\");\n }\n\n /** Fast session validity check — calls DSers account info endpoint. */\n async checkHealth(): Promise<{ valid: boolean; reason?: string }> {\n if (!this.sessionId) {\n return { valid: false, reason: \"未授权(无 session)\" };\n }\n\n if (Date.now() - this.fetchedAt > SESSION_TTL) {\n return { valid: false, reason: \"session 已过期(超过 6 小时)\" };\n }\n\n try {\n const resp = await fetch(\n `${this.config.baseUrl}/account-user-bff/v1/users/current`,\n {\n headers: {\n Cookie: `sessionid=${this.sessionId}; djdt=hide; state=${this.state}`,\n },\n },\n );\n\n if (resp.status === 401 || resp.status === 403) {\n this.invalidate();\n return { valid: false, reason: `DSers 返回 ${resp.status}(token 失效),请重新授权` };\n }\n\n if (!resp.ok) {\n return { valid: false, reason: `DSers 服务异常(HTTP ${resp.status})` };\n }\n\n return { valid: true };\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n return { valid: false, reason: `网络错误(${reason}),请检查网络连接` };\n }\n }\n\n /**\n * Attempt session renewal for session-only users (no email/password).\n * Returns success if the session is still valid; fails with guidance otherwise.\n */\n async tryRenew(): Promise<{ renewed: boolean; reason?: string }> {\n const health = await this.checkHealth();\n if (health.valid) {\n this.fetchedAt = Date.now();\n return { renewed: true };\n }\n\n if (this.config.email && this.config.password) {\n try {\n await this.login();\n return { renewed: true };\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"登录失败\";\n return { renewed: false, reason };\n }\n }\n\n return {\n renewed: false,\n reason: `${health.reason}。当前为 session 模式,需要通过浏览器重新授权。`,\n };\n }\n\n private readCache(): [string, string, number] | null {\n try {\n const p = this.config.sessionFile;\n if (!existsSync(p)) return null;\n const obj: SessionCache = JSON.parse(readFileSync(p, \"utf-8\"));\n if (Date.now() - obj.ts > SESSION_TTL) return null;\n return [obj.session_id, obj.state ?? \"\", obj.ts];\n } catch {\n return null;\n }\n }\n\n private writeCache(): void {\n if (this.config.sessionId) return;\n try {\n const p = this.config.sessionFile;\n mkdirSync(dirname(p), { recursive: true });\n const payload: SessionCache = {\n session_id: this.sessionId!,\n state: this.state ?? \"\",\n ts: this.fetchedAt,\n };\n writeFileSync(p, JSON.stringify(payload), { encoding: \"utf-8\", mode: 0o600 });\n try {\n chmodSync(p, 0o600);\n } catch {\n /* Windows */\n }\n } catch {\n log.warn(\"Failed to write session cache\");\n }\n }\n}\n","/**\n * Structured error classification for DSClaw.\n * Every error flowing through the system must have a category\n * so upstream layers (agents, channels) know how to react.\n */\n\nexport const ErrorCategory = {\n RETRYABLE: \"RETRYABLE\",\n NEEDS_HUMAN: \"NEEDS_HUMAN\",\n NEEDS_DATA: \"NEEDS_DATA\",\n FATAL: \"FATAL\",\n DEGRADED: \"DEGRADED\",\n} as const;\n\nexport type ErrorCategory =\n (typeof ErrorCategory)[keyof typeof ErrorCategory];\n\nexport interface StructuredError {\n category: ErrorCategory;\n code: string;\n message: string;\n retryable: boolean;\n details?: Record<string, unknown>;\n cause?: Error;\n}\n\nexport class DSClawError extends Error {\n readonly category: ErrorCategory;\n readonly code: string;\n readonly retryable: boolean;\n readonly details?: Record<string, unknown>;\n\n constructor(opts: StructuredError) {\n super(opts.message);\n this.name = \"DSClawError\";\n this.category = opts.category;\n this.code = opts.code;\n this.retryable = opts.retryable;\n this.details = opts.details;\n if (opts.cause) this.cause = opts.cause;\n }\n\n toJSON(): StructuredError {\n return {\n category: this.category,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n details: this.details,\n };\n }\n}\n\nexport function classifyHttpError(\n status: number,\n body?: string,\n): ErrorCategory {\n if (status === 429) return ErrorCategory.RETRYABLE;\n if (status >= 500) return ErrorCategory.RETRYABLE;\n if (status === 401 || status === 403) return ErrorCategory.NEEDS_HUMAN;\n if (status === 404 || status === 422) return ErrorCategory.NEEDS_DATA;\n if (status === 400) return ErrorCategory.NEEDS_DATA;\n return ErrorCategory.FATAL;\n}\n","/**\n * Enhanced DSers HTTP client with:\n * - 429 Retry-After handling\n * - 5xx exponential backoff (max 2 retries)\n * - Structured error classification\n * - traceId injection\n * - Session auto-refresh on 400 auth errors\n */\n\nimport { DSersAuth } from \"./auth.js\";\nimport type { DSersClientConfig } from \"./config.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { getTraceId } from \"../shared/tracer.js\";\nimport {\n DSClawError,\n ErrorCategory,\n classifyHttpError,\n} from \"../shared/errors.js\";\nimport { parseRetryAfter, sleep } from \"../shared/utils.js\";\nimport { getOutboundLimiter } from \"../resilience/rate-limiter.js\";\n\nconst log = createLogger(\"dsers:client\");\n\nconst RETRYABLE_REASONS = new Set([\n \"TOKEN_NOT_FOUND\",\n \"TOKEN_EXPIRED\",\n \"UNAUTHORIZED\",\n \"INVALID_TOKEN\",\n]);\n\nconst MAX_RETRIES = 2;\n\nexport class DSersClient {\n private config: DSersClientConfig;\n private auth: DSersAuth;\n private limiter: ReturnType<typeof getOutboundLimiter>;\n\n constructor(config: DSersClientConfig) {\n this.config = config;\n this.auth = new DSersAuth(config);\n this.limiter = getOutboundLimiter(\"dsers\");\n }\n\n async request(\n method: string,\n path: string,\n opts?: {\n params?: Record<string, unknown>;\n json?: Record<string, unknown>;\n },\n attempt = 0,\n ): Promise<Record<string, unknown>> {\n return this.limiter(async () => {\n const [sessionId, state] = await this.auth.getSession();\n const traceId = getTraceId();\n\n const url = new URL(`${this.config.baseUrl}${path}`);\n if (opts?.params) {\n for (const [k, v] of Object.entries(opts.params)) {\n if (v != null) url.searchParams.set(k, String(v));\n }\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${sessionId}`,\n Cookie: `session_id=${sessionId}; state=${state}`,\n \"X-Trace-Id\": traceId,\n };\n\n log.debug({ method, path, traceId, attempt }, \"DSers API request\");\n\n const resp = await fetch(url.toString(), {\n method,\n headers,\n body: opts?.json ? JSON.stringify(opts.json) : undefined,\n });\n\n const bodyText = await resp.text();\n\n if (resp.status === 400 && attempt === 0) {\n try {\n const body = JSON.parse(bodyText) as Record<string, unknown>;\n if (RETRYABLE_REASONS.has(body[\"reason\"] as string)) {\n log.info({ reason: body[\"reason\"] }, \"Session expired, re-authenticating\");\n this.auth.invalidate();\n return this.request(method, path, opts, 1);\n }\n } catch {\n // not JSON\n }\n }\n\n if (resp.status === 429) {\n const retryAfterMs =\n parseRetryAfter(resp.headers.get(\"Retry-After\")) ?? 5000;\n if (attempt < MAX_RETRIES) {\n log.warn({ retryAfterMs, attempt }, \"Rate limited by DSers\");\n await sleep(retryAfterMs);\n return this.request(method, path, opts, attempt + 1);\n }\n }\n\n if (resp.status >= 500 && attempt < MAX_RETRIES) {\n const delay = Math.min(1000 * Math.pow(2, attempt) + Math.random() * 500, 15000);\n log.warn({ status: resp.status, attempt }, \"DSers server error, retrying\");\n await sleep(delay);\n return this.request(method, path, opts, attempt + 1);\n }\n\n if (resp.status >= 400) {\n const category = classifyHttpError(resp.status, bodyText);\n throw new DSClawError({\n category,\n code: `DSERS_API_${resp.status}`,\n message: `DSers API ${method} ${path} returned ${resp.status}: ${bodyText.slice(0, 300)}`,\n retryable: category === ErrorCategory.RETRYABLE,\n details: { status: resp.status, path, method },\n });\n }\n\n return JSON.parse(bodyText) as Record<string, unknown>;\n });\n }\n\n async get(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n return this.request(\"GET\", path, { params });\n }\n\n async post(\n path: string,\n json?: Record<string, unknown>,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n return this.request(\"POST\", path, { json, params });\n }\n\n async put(\n path: string,\n json?: Record<string, unknown>,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n return this.request(\"PUT\", path, { json, params });\n }\n\n async del(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n return this.request(\"DELETE\", path, { params });\n }\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Generate an idempotency key from operation parameters.\n * Uses a 5-minute time bucket so the same operation within\n * 5 minutes is considered duplicate.\n */\nexport function idempotencyKey(\n userId: string,\n action: string,\n params: Record<string, unknown>,\n): string {\n const timeBucket = Math.floor(Date.now() / (5 * 60 * 1000));\n const payload = JSON.stringify({ userId, action, params, timeBucket });\n return createHash(\"sha256\").update(payload).digest(\"hex\").slice(0, 16);\n}\n\n/**\n * Sleep for a given number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Parse Retry-After header value to milliseconds.\n * Supports both seconds (integer) and HTTP-date formats.\n */\nexport function parseRetryAfter(value: string | null): number | null {\n if (!value) return null;\n const seconds = Number(value);\n if (!Number.isNaN(seconds)) return seconds * 1000;\n const date = Date.parse(value);\n if (!Number.isNaN(date)) return Math.max(0, date - Date.now());\n return null;\n}\n","/**\n * Three-layer rate limiting:\n * L1 Inbound: per-IP / per-channel flood protection\n * L2 Tenant: per-userId session serialization + debounce\n * L3 Outbound: per-service concurrency cap (DSers, LLM, mem0)\n */\n\nimport pLimit from \"p-limit\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"rate-limiter\");\n\n// --- L3: Outbound per-service concurrency limits ---\n\nexport interface OutboundLimits {\n dsers: number;\n llm: number;\n mem0: number;\n}\n\nconst DEFAULT_OUTBOUND_LIMITS: OutboundLimits = {\n dsers: 20,\n llm: 5,\n mem0: 10,\n};\n\nconst outboundLimiters = new Map<string, ReturnType<typeof pLimit>>();\n\nexport function getOutboundLimiter(\n service: keyof OutboundLimits,\n customLimits?: Partial<OutboundLimits>,\n): ReturnType<typeof pLimit> {\n if (!outboundLimiters.has(service)) {\n const limits = { ...DEFAULT_OUTBOUND_LIMITS, ...customLimits };\n const limiter = pLimit(limits[service]);\n outboundLimiters.set(service, limiter);\n log.info({ service, concurrency: limits[service] }, \"Outbound limiter created\");\n }\n return outboundLimiters.get(service)!;\n}\n\n// --- L2: Per-user message queue (serialization + debounce) ---\n\ninterface PendingMessage {\n resolve: (value: void) => void;\n timer?: ReturnType<typeof setTimeout>;\n}\n\ninterface LockEntry {\n promise: Promise<void>;\n resolve: () => void;\n version: number;\n}\n\nconst userLocks = new Map<string, LockEntry>();\nlet lockVersion = 0;\nconst debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();\n\n/**\n * Ensure messages from the same user are processed serially.\n * Returns a release function to call when processing is done.\n * Times out after `timeoutMs` — on timeout the waiter proceeds but\n * the stale holder's release() becomes a no-op (version check).\n */\nexport async function acquireUserLock(userId: string, timeoutMs = 180_000): Promise<() => void> {\n const deadline = Date.now() + timeoutMs;\n\n while (userLocks.has(userId)) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) {\n log.warn({ userId }, \"User lock wait timed out — forcing entry\");\n const stale = userLocks.get(userId);\n if (stale) {\n stale.resolve();\n }\n userLocks.delete(userId);\n break;\n }\n await Promise.race([\n userLocks.get(userId)!.promise,\n new Promise<void>((r) => setTimeout(r, remaining)),\n ]);\n }\n\n const myVersion = ++lockVersion;\n let resolve!: () => void;\n const promise = new Promise<void>((r) => { resolve = r; });\n userLocks.set(userId, { promise, resolve, version: myVersion });\n\n const release = () => {\n const current = userLocks.get(userId);\n if (current && current.version === myVersion) {\n userLocks.delete(userId);\n resolve();\n }\n };\n\n return release;\n}\n\n/**\n * Debounce rapid-fire messages from the same user.\n * Resolves after `delayMs` of silence.\n */\nexport function debounceUser(\n userId: string,\n delayMs = 500,\n): Promise<void> {\n return new Promise((resolve) => {\n const existing = debounceTimers.get(userId);\n if (existing) clearTimeout(existing);\n\n debounceTimers.set(\n userId,\n setTimeout(() => {\n debounceTimers.delete(userId);\n resolve();\n }, delayMs),\n );\n });\n}\n\n// --- L1: Inbound sliding window ---\n\ninterface WindowEntry {\n timestamps: number[];\n}\n\nconst inboundWindows = new Map<string, WindowEntry>();\n\n/**\n * Check if an inbound source has exceeded the rate limit.\n * @returns true if the request should be allowed, false if throttled.\n */\nexport function checkInboundLimit(\n sourceId: string,\n maxRequests = 30,\n windowMs = 60_000,\n): boolean {\n const now = Date.now();\n const entry = inboundWindows.get(sourceId) ?? { timestamps: [] };\n\n entry.timestamps = entry.timestamps.filter((t) => now - t < windowMs);\n\n if (entry.timestamps.length >= maxRequests) {\n log.warn({ sourceId, count: entry.timestamps.length }, \"Inbound rate limit hit\");\n return false;\n }\n\n entry.timestamps.push(now);\n inboundWindows.set(sourceId, entry);\n return true;\n}\n","/**\n * DSers API configuration.\n * Uses email + password auth (matching actual DSers login flow).\n */\n\nimport { join } from \"node:path\";\nimport { CONFIG_DIR } from \"../gateway/config.js\";\n\nconst PROD_URL = \"https://bff-api-gw.dsers.com\";\n\nexport interface DSersClientConfig {\n baseUrl: string;\n email: string;\n password?: string;\n sessionFile: string;\n sessionId?: string;\n sessionState?: string;\n}\n\nexport function createDSersConfig(\n email: string,\n password?: string,\n baseUrl?: string,\n): DSersClientConfig {\n const safeEmail = email.replace(/[^a-zA-Z0-9_@.-]/g, \"_\");\n return {\n baseUrl: baseUrl ?? PROD_URL,\n email,\n password,\n sessionFile: join(CONFIG_DIR, `session-${safeEmail}.json`),\n };\n}\n","/**\n * DSers browser-based authentication via CDP.\n *\n * 1. spawn() a fresh Chromium process in app mode pointing to DSers login\n * 2. Parse stderr for \"DevTools listening on ws://...\" to get the debug WS URL\n * 3. Connect via WebSocket (using the `ws` package already in deps)\n * 4. Intercept the login API response to extract sessionId + state from JSON body\n * 5. On success: resolve with tokens, kill browser, cleanup temp dir\n * 6. On timeout / user close: reject, cleanup\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { mkdtempSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { WebSocket } from \"ws\";\nimport { findChromium } from \"./browser-finder.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"dsers:browser-auth\");\n\nconst DSERS_LOGIN_URL = \"https://accounts.dsers.com/accounts/login\";\nconst LOGIN_API_PATTERN = \"/account-user-bff/v1/users/login\";\nconst TIMEOUT = 180_000; // 3 minutes\n\nexport interface DSersAuthResult {\n sessionId: string;\n state: string;\n}\n\nlet activeProcess: ChildProcess | null = null;\nlet activeTmpDir: string | null = null;\n\nexport function isAuthInProgress(): boolean {\n return activeProcess !== null && !activeProcess.killed;\n}\n\nexport function cancelAuth(): void {\n cleanup();\n}\n\nfunction cleanup(): void {\n if (activeProcess && !activeProcess.killed) {\n try { activeProcess.kill(); } catch { /* ignore */ }\n }\n activeProcess = null;\n\n if (activeTmpDir) {\n try { rmSync(activeTmpDir, { recursive: true, force: true }); } catch { /* ignore */ }\n activeTmpDir = null;\n }\n}\n\nfunction parseWsUrl(stderrChunk: string): string | null {\n const match = stderrChunk.match(/DevTools listening on (ws:\\/\\/[^\\s]+)/);\n return match?.[1] ?? null;\n}\n\nfunction launchBrowser(): { proc: ChildProcess; wsUrlPromise: Promise<string> } {\n const browser = findChromium();\n if (!browser) {\n throw new Error(\"No Chromium-based browser found. Please install Chrome, Edge, or Brave.\");\n }\n\n const tmpDir = mkdtempSync(join(tmpdir(), \"dsclaw-auth-\"));\n activeTmpDir = tmpDir;\n\n log.info({ browser: browser.name }, \"Launching browser for DSers auth\");\n\n const proc = spawn(browser.executablePath, [\n `--app=${DSERS_LOGIN_URL}`,\n \"--remote-debugging-port=0\",\n `--user-data-dir=${tmpDir}`,\n \"--no-first-run\",\n \"--no-default-browser-check\",\n \"--disable-extensions\",\n \"--mute-audio\",\n \"--window-size=480,700\",\n ], {\n stdio: [\"ignore\", \"ignore\", \"pipe\"],\n detached: false,\n });\n\n activeProcess = proc;\n\n const wsUrlPromise = new Promise<string>((resolve, reject) => {\n let stderr = \"\";\n const timer = setTimeout(() => {\n reject(new Error(\"Timed out waiting for Chrome DevTools\"));\n }, 15000);\n\n proc.stderr!.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString();\n const url = parseWsUrl(stderr);\n if (url) {\n clearTimeout(timer);\n resolve(url);\n }\n });\n\n proc.on(\"error\", (err) => {\n clearTimeout(timer);\n reject(err);\n });\n\n proc.on(\"exit\", () => {\n clearTimeout(timer);\n reject(new Error(\"Browser exited before DevTools was ready\"));\n });\n });\n\n return { proc, wsUrlPromise };\n}\n\n/**\n * Connect to CDP and intercept the DSers login API response.\n * When the login POST returns, we read the response body to get sessionId + state.\n */\nfunction watchLoginResponse(wsUrl: string): Promise<DSersAuthResult> {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(wsUrl);\n let msgId = 1;\n let timeoutTimer: ReturnType<typeof setTimeout> | null = null;\n let settled = false;\n\n const pending = new Map<number, (data: unknown) => void>();\n const requestMap = new Map<string, string>(); // requestId → url\n\n function cdpSend(method: string, params: Record<string, unknown> = {}): Promise<unknown> {\n return new Promise((res) => {\n const id = msgId++;\n pending.set(id, res);\n ws.send(JSON.stringify({ id, method, params }));\n });\n }\n\n function finish(result?: DSersAuthResult, err?: Error) {\n if (settled) return;\n settled = true;\n if (timeoutTimer) clearTimeout(timeoutTimer);\n try { ws.close(); } catch { /* ignore */ }\n if (result) resolve(result);\n else reject(err ?? new Error(\"Unknown error\"));\n }\n\n ws.on(\"open\", async () => {\n log.info(\"CDP connected, intercepting login API responses\");\n await cdpSend(\"Network.enable\");\n\n timeoutTimer = setTimeout(() => {\n finish(undefined, new Error(\"Login timed out (3 minutes). Please try again.\"));\n cleanup();\n }, TIMEOUT);\n });\n\n ws.on(\"message\", async (raw: Buffer) => {\n try {\n const msg = JSON.parse(raw.toString()) as {\n id?: number;\n result?: unknown;\n method?: string;\n params?: Record<string, unknown>;\n };\n\n // Handle RPC responses\n if (msg.id && pending.has(msg.id)) {\n pending.get(msg.id)!(msg.result);\n pending.delete(msg.id);\n return;\n }\n\n // Handle CDP events\n if (msg.method === \"Network.requestWillBeSent\") {\n const p = msg.params as { requestId: string; request: { url: string; method: string } };\n if (p.request.url.includes(LOGIN_API_PATTERN) && p.request.method === \"POST\") {\n requestMap.set(p.requestId, p.request.url);\n log.info(\"Detected DSers login request\");\n }\n return;\n }\n\n if (msg.method === \"Network.responseReceived\") {\n const p = msg.params as { requestId: string; response: { status: number } };\n if (!requestMap.has(p.requestId)) return;\n\n log.info({ status: p.response.status }, \"DSers login response received\");\n if (p.response.status !== 200) {\n log.warn(\"Login response was not 200, waiting for retry...\");\n requestMap.delete(p.requestId);\n return;\n }\n\n // Wait a bit for the body to be available\n await new Promise((r) => setTimeout(r, 500));\n\n try {\n const bodyResp = await cdpSend(\"Network.getResponseBody\", {\n requestId: p.requestId,\n }) as { body: string; base64Encoded: boolean };\n\n const body = bodyResp.base64Encoded\n ? Buffer.from(bodyResp.body, \"base64\").toString()\n : bodyResp.body;\n\n const data = JSON.parse(body) as {\n data?: { sessionId?: string; state?: string };\n };\n\n const sessionId = data?.data?.sessionId;\n const state = data?.data?.state ?? \"\";\n\n if (sessionId) {\n log.info(\"DSers session captured from login API response\");\n finish({ sessionId, state });\n } else {\n log.warn({ responseData: body.slice(0, 300) }, \"Login response missing sessionId\");\n }\n } catch (e) {\n log.warn({ error: e instanceof Error ? e.message : String(e) }, \"Failed to read login response body\");\n }\n requestMap.delete(p.requestId);\n }\n } catch { /* ignore malformed messages */ }\n });\n\n ws.on(\"error\", () => {\n finish(undefined, new Error(\"CDP connection lost\"));\n });\n\n ws.on(\"close\", () => {\n finish(undefined, new Error(\"Browser was closed before login completed\"));\n });\n });\n}\n\n/**\n * Main entry point: launch browser, wait for DSers login, return session tokens.\n * Resolves when user successfully logs in, rejects on timeout or cancel.\n */\nexport async function loginViaCDP(): Promise<DSersAuthResult> {\n if (isAuthInProgress()) {\n throw new Error(\"Auth already in progress\");\n }\n\n try {\n const { proc, wsUrlPromise } = launchBrowser();\n\n proc.on(\"exit\", () => {\n activeProcess = null;\n });\n\n const wsUrl = await wsUrlPromise;\n log.info({ wsUrl }, \"DevTools endpoint acquired\");\n\n // Get the page-level WS URL\n const httpUrl = wsUrl.replace(\"ws://\", \"http://\").replace(/\\/devtools\\/browser\\/.*/, \"/json\");\n const resp = await fetch(httpUrl);\n const tabs = (await resp.json()) as { webSocketDebuggerUrl: string; url: string }[];\n const dsersTab = tabs.find((t) => t.url.includes(\"dsers.com\")) ?? tabs[0];\n\n if (!dsersTab?.webSocketDebuggerUrl) {\n throw new Error(\"Could not find browser tab\");\n }\n\n log.info({ tabUrl: dsersTab.url }, \"Watching tab for login API response\");\n const result = await watchLoginResponse(dsersTab.webSocketDebuggerUrl);\n cleanup();\n return result;\n } catch (error) {\n cleanup();\n throw error;\n }\n}\n","/**\n * Find an installed Chromium-based browser on the local machine.\n * Search order: Chrome → Edge → Brave → Arc → Chromium → Opera → Vivaldi\n */\n\nimport { existsSync } from \"node:fs\";\n\ninterface BrowserCandidate {\n name: string;\n paths: Partial<Record<NodeJS.Platform, string[]>>;\n}\n\nconst CANDIDATES: BrowserCandidate[] = [\n {\n name: \"Google Chrome\",\n paths: {\n darwin: [\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\"],\n win32: [\n `${process.env[\"PROGRAMFILES\"]}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n `${process.env[\"PROGRAMFILES(X86)\"]}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n `${process.env[\"LOCALAPPDATA\"]}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n ],\n linux: [\"/usr/bin/google-chrome\", \"/usr/bin/google-chrome-stable\"],\n },\n },\n {\n name: \"Microsoft Edge\",\n paths: {\n darwin: [\"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge\"],\n win32: [\n `${process.env[\"PROGRAMFILES(X86)\"]}\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe`,\n `${process.env[\"PROGRAMFILES\"]}\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe`,\n ],\n linux: [\"/usr/bin/microsoft-edge\", \"/usr/bin/microsoft-edge-stable\"],\n },\n },\n {\n name: \"Brave\",\n paths: {\n darwin: [\"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser\"],\n win32: [\n `${process.env[\"PROGRAMFILES\"]}\\\\BraveSoftware\\\\Brave-Browser\\\\Application\\\\brave.exe`,\n `${process.env[\"LOCALAPPDATA\"]}\\\\BraveSoftware\\\\Brave-Browser\\\\Application\\\\brave.exe`,\n ],\n linux: [\"/usr/bin/brave-browser\"],\n },\n },\n {\n name: \"Arc\",\n paths: {\n darwin: [\"/Applications/Arc.app/Contents/MacOS/Arc\"],\n },\n },\n {\n name: \"Chromium\",\n paths: {\n darwin: [\"/Applications/Chromium.app/Contents/MacOS/Chromium\"],\n linux: [\"/usr/bin/chromium\", \"/usr/bin/chromium-browser\"],\n },\n },\n {\n name: \"Opera\",\n paths: {\n darwin: [\"/Applications/Opera.app/Contents/MacOS/Opera\"],\n win32: [\n `${process.env[\"LOCALAPPDATA\"]}\\\\Programs\\\\Opera\\\\opera.exe`,\n ],\n linux: [\"/usr/bin/opera\"],\n },\n },\n {\n name: \"Vivaldi\",\n paths: {\n darwin: [\"/Applications/Vivaldi.app/Contents/MacOS/Vivaldi\"],\n win32: [\n `${process.env[\"LOCALAPPDATA\"]}\\\\Vivaldi\\\\Application\\\\vivaldi.exe`,\n ],\n linux: [\"/usr/bin/vivaldi\"],\n },\n },\n];\n\nexport interface FoundBrowser {\n name: string;\n executablePath: string;\n}\n\nexport function findChromium(): FoundBrowser | null {\n const platform = process.platform;\n\n for (const candidate of CANDIDATES) {\n const platformPaths = candidate.paths[platform];\n if (!platformPaths) continue;\n\n for (const p of platformPaths) {\n if (existsSync(p)) {\n return { name: candidate.name, executablePath: p };\n }\n }\n }\n\n return null;\n}\n","/**\n * DSClaw Core Agent — unified prototype agent using Vercel AI SDK.\n * Created per-user with their own DSers client and LLM config.\n * System prompt targets zero-technical-ability dropshipping users.\n */\n\nimport { generateText, streamText, type ModelMessage, tool as aiTool, stepCountIs } from \"ai\";\nimport { createOpenAI } from \"@ai-sdk/openai\";\nimport { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\nimport { z } from \"zod\";\nimport type { AgentBase, AgentContext, AgentResponse, AgentTool } from \"./base.js\";\nimport type { DSersClient } from \"../dsers/client.js\";\nimport type { MemoryProvider } from \"../memory/provider.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { writeAuditLog } from \"../shared/audit.js\";\nimport * as productApi from \"../dsers/product.js\";\nimport { configFromToken } from \"@lofder/dsers-mcp-product/dist/dsers/config.js\";\nimport { buildProvider } from \"@lofder/dsers-mcp-product/dist/provider.js\";\nimport { ImportFlowService } from \"@lofder/dsers-mcp-product/dist/service.js\";\nimport { MemoryJobStore } from \"@lofder/dsers-mcp-product/dist/job-store-memory.js\";\nimport type { JobStore } from \"@lofder/dsers-mcp-product/dist/job-store.js\";\nimport { readFileSync, writeFileSync, mkdirSync, renameSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst log = createLogger(\"agent:core\");\n\nconst JOB_ID_MAP_DIR = join(homedir(), \".dsclaw\");\nconst JOB_ID_MAP_FILE = join(JOB_ID_MAP_DIR, \"job-id-map.json\");\nconst JOB_ID_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\nfunction loadJobIdMap(): Map<string, string> {\n const map = new Map<string, string>();\n try {\n if (!existsSync(JOB_ID_MAP_FILE)) return map;\n const raw = JSON.parse(readFileSync(JOB_ID_MAP_FILE, \"utf-8\")) as Record<string, { full: string; ts: number }>;\n const now = Date.now();\n for (const [short, entry] of Object.entries(raw)) {\n if (now - entry.ts < JOB_ID_TTL_MS) {\n map.set(short, entry.full);\n }\n }\n } catch (err) {\n log.warn({ err }, \"Failed to load job ID map from disk\");\n }\n return map;\n}\n\nfunction persistJobIdMap(map: Map<string, string>): void {\n try {\n mkdirSync(JOB_ID_MAP_DIR, { recursive: true });\n const obj: Record<string, { full: string; ts: number }> = {};\n const now = Date.now();\n for (const [short, full] of map) {\n obj[short] = { full, ts: now };\n }\n const tmp = JOB_ID_MAP_FILE + \".tmp\";\n writeFileSync(tmp, JSON.stringify(obj));\n renameSync(tmp, JOB_ID_MAP_FILE);\n } catch (err) {\n log.warn({ err }, \"Failed to persist job ID map\");\n }\n}\n\nexport interface LLMConfig {\n provider: string;\n apiKey: string;\n model: string;\n baseUrl?: string;\n}\n\nfunction normalizeBaseUrl(url: string | undefined): string | undefined {\n if (!url) return undefined;\n let u = url.trim();\n if (!/^https?:\\/\\//i.test(u)) u = `https://${u}`;\n u = u.replace(/\\/+$/, \"\");\n if (!/\\/v\\d/.test(u)) u += \"/v1\";\n return u;\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n const id = setTimeout(() => reject(new Error(`${label} timed out after ${Math.round(ms / 1000)}s`)), ms);\n if (typeof id === \"object\" && \"unref\" in id) (id as NodeJS.Timeout).unref();\n }),\n ]);\n}\n\nfunction withToolAwareTimeout<T>(\n promise: Promise<T>,\n baseMs: number,\n isToolActive: () => boolean,\n label: string,\n): Promise<T> {\n let timerId: ReturnType<typeof setTimeout> | null = null;\n const cleanup = () => { if (timerId !== null) { clearTimeout(timerId); timerId = null; } };\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n let deadline = Date.now() + baseMs;\n const tick = () => {\n if (isToolActive()) {\n deadline = Date.now() + baseMs;\n timerId = setTimeout(tick, 10_000);\n } else if (Date.now() >= deadline) {\n reject(new Error(`${label} timed out after ${Math.round(baseMs / 1000)}s`));\n } else {\n timerId = setTimeout(tick, Math.min(deadline - Date.now(), 10_000));\n }\n };\n timerId = setTimeout(tick, baseMs);\n });\n\n return Promise.race([promise.finally(cleanup), timeoutPromise]);\n}\n\nconst MCP_PREVIEW_KEYS = new Set([\n \"job_id\", \"batch_id\", \"status\", \"source_url\", \"target_store\",\n \"visibility_mode\", \"title\", \"title_before\", \"title_after\", \"variant_count\",\n \"variants_count\", \"sell_price\", \"cost\", \"compare_at_price\", \"no_markup\",\n \"skus\", \"skus_more\", \"skus_offset\", \"stock\", \"stock_low\", \"supplier_stock\",\n \"desc_changed\", \"images\", \"options\", \"store\", \"visibility\",\n \"ship_to\", \"ship_from\",\n \"rule_summary\", \"total\", \"succeeded\", \"failed\",\n \"error\", \"blocked\", \"warnings\", \"visibility_applied\", \"push_options_applied\",\n \"job_summary\", \"has_push_result\", \"push_result\",\n \"deleted\", \"confirmed\", \"message\",\n]);\n\nconst MCP_DROP_KEYS = new Set([\n \"image_urls\", \"description_html_snippet\",\n \"effective_rules_snapshot\", \"requested_rules\", \"original_draft\",\n \"resolved_source_url\", \"resolver_mode\", \"tags_before\", \"tags_after\",\n]);\n\nfunction compactToolResult(result: Record<string, any>, jobIdMap?: Map<string, string>): Record<string, any> {\n if (!result || typeof result !== \"object\") return result;\n\n const isMcpPreview = \"job_id\" in result && (\"title_after\" in result || \"status\" in result);\n if (isMcpPreview) {\n const out: Record<string, any> = {};\n for (const [k, v] of Object.entries(result)) {\n if (MCP_DROP_KEYS.has(k)) continue;\n out[k] = v;\n }\n if (out.job_id && typeof out.job_id === \"string\") {\n const dotIdx = out.job_id.indexOf(\".\");\n if (dotIdx > 0) {\n const short = out.job_id.slice(0, dotIdx);\n if (jobIdMap) jobIdMap.set(short, out.job_id);\n out.job_id = short;\n }\n }\n if (out.skus && Array.isArray(out.skus) && out.skus.length > 1) {\n const [header, ...rows] = out.skus as [string[], ...any[][]];\n out.variant_summary = rows.slice(0, 5).map((row: any[]) => {\n const obj: Record<string, any> = {};\n header.forEach((key: string, i: number) => { obj[key] = row[i]; });\n return obj;\n });\n if (rows.length > 5) {\n out.variant_summary_note = `Showing 5 of ${rows.length} variants`;\n }\n delete out.skus;\n }\n if (out.title_after) {\n out._title_modified = true;\n out._display_title = out.title_after;\n }\n if (out.desc_changed) {\n out._description_modified = true;\n }\n if (out.warnings?.length > 5) out.warnings = out.warnings.slice(0, 5);\n if (out.stores) {\n out.stores = out.stores.map((s: any) => ({\n store_ref: s.store_ref, display_name: s.display_name, platform: s.platform,\n }));\n }\n if (out.account_info) {\n const ai = out.account_info;\n out.account_info = { plan: ai.plan, limits: ai.limits, aliexpress_auth: ai.aliexpress_auth };\n }\n return out;\n }\n\n const json = JSON.stringify(result);\n if (json.length <= 4000) return result;\n\n const out: Record<string, any> = {};\n for (const [k, v] of Object.entries(result)) {\n if (MCP_DROP_KEYS.has(k)) continue;\n if (Array.isArray(v) && v.length > 20) {\n out[k] = v.slice(0, 20);\n out[`_${k}_truncated`] = `${v.length} total, showing first 20`;\n } else {\n out[k] = v;\n }\n }\n const outJson = JSON.stringify(out);\n if (outJson.length > 8000) {\n return { _truncated: true, _original_size: json.length, summary: outJson.slice(0, 6000) + \"...\" };\n }\n return out;\n}\n\nfunction buildModel(llm: LLMConfig) {\n const baseURL = normalizeBaseUrl(llm.baseUrl);\n\n // Custom URL = proxy, always use OpenAI Chat Completions format\n if (baseURL || llm.provider === \"other\") {\n return createOpenAI({\n apiKey: llm.apiKey,\n baseURL: baseURL ?? \"http://localhost:11434/v1\",\n }).chat(llm.model);\n }\n\n // Direct to official API — use native SDK\n switch (llm.provider) {\n case \"openai\":\n return createOpenAI({ apiKey: llm.apiKey }).chat(llm.model);\n case \"anthropic\":\n return createAnthropic({ apiKey: llm.apiKey })(llm.model);\n case \"google\":\n return createGoogleGenerativeAI({ apiKey: llm.apiKey })(llm.model);\n default:\n return createOpenAI({ apiKey: llm.apiKey }).chat(llm.model);\n }\n}\n\nexport function getDefaultModel(provider: string): string {\n switch (provider) {\n case \"openai\": return \"gpt-4o\";\n case \"anthropic\": return \"claude-sonnet-4-20250514\";\n case \"google\": return \"gemini-2.0-flash\";\n case \"other\": return \"gpt-3.5-turbo\";\n default: return \"gpt-4o\";\n }\n}\n\nconst TOOL_LABELS: Record<string, string> = {\n dsers_store_discover: \"Discovering stores & capabilities...\",\n dsers_product_import: \"Importing product...\",\n dsers_product_preview: \"Loading preview...\",\n dsers_product_delete: \"Deleting product...\",\n dsers_product_visibility: \"Setting visibility...\",\n dsers_store_push: \"Pushing to store...\",\n dsers_rules_validate: \"Validating rules...\",\n dsers_job_status: \"Checking job status...\",\n dsers_import_list_search: \"Searching import list...\",\n dsers_my_products: \"Loading your products...\",\n};\n\nconst SYSTEM_PROMPT = `You are DSClaw, a friendly dropshipping AI for DSers. User has zero technical background.\n{{LANGUAGE_RULE}}\nBe warm, clear. Confirm before push/delete/bulk ops.\n\nPRICES — always show separately:\n- cost (采购价): supplier price. Field: \"cost\"\n- sell_price (售价): store price. Field: \"sell_price\"\n- compare_at_price: strikethrough price\n- no_markup=true → warn user to set pricing rules\n- From dsers_import_list_search: use \"cost_range\" and \"sell_price_range\"\nWhen in Chinese: Format: 采购价:$2.51–$4.00 | 售价:$5.02–$8.00\nWhen in English: Format: Cost: $2.51–$4.00 | Sell price: $5.02–$8.00\n\nWORKFLOWS:\nImport: dsers_store_discover → dsers_product_import(url) → (rules) → dsers_store_push(confirm first)\nBatch: source_urls_json / job_ids_json / target_stores_json\nDelete: dsers_product_delete without confirm → show details → dsers_product_delete with confirm=true\n\nTOOL SELECTION — ALL modifications go through dsers_product_import:\n- dsers_import_list_search returns each item's \"source_url\". Use it for re-import.\n- Title/description/price changes on existing items:\n 1. dsers_product_import(source_url from dsers_import_list_search, rules_json with changes)\n 2. This re-imports and applies rules in one call, persisting changes via MCP.\n- PRICING (pick mode by user intent):\n | \"set price $9.99\" / \"all $9.99\" → fixed_price: {\"pricing\":{\"mode\":\"fixed_price\",\"fixed_price\":9.99}}\n | \"double the price\" / \"3x\" → multiplier: {\"pricing\":{\"mode\":\"multiplier\",\"multiplier\":2.0}}\n | \"add $5 markup\" → fixed_markup: {\"pricing\":{\"mode\":\"fixed_markup\",\"fixed_markup\":5.00}}\n | \"Red $9.99, Blue $12.99\" → variant_overrides: {\"variant_overrides\":[{\"match\":\"Red\",\"sell_price\":9.99},{\"match\":\"Blue\",\"sell_price\":12.99}]}\n All modes accept optional round_digits (0-10).\n- CONTENT: title_override, title_prefix, title_suffix, description_override_html, description_append_html, tags_add (array)\n- IMAGES: drop_indexes, reorder, add_urls, keep_first_n. Only URLs, no base64.\n- VARIANT_OVERRIDES: array of {match, sell_price, compare_at_price, stock, title, image_url}. Applied AFTER global pricing.\n- OPTION_EDITS: array of {action, option_name, value_name?, new_name?}. Actions: rename_option, rename_value, remove_value (DESTRUCTIVE), remove_option.\n- Check response: title_after (changed title), _title_modified, sell_price, cost, desc_changed\n- Existing job_id: dsers_product_import(job_id + rules_json) to re-apply rules.\n\nPUSH CONFIRMATION: Before calling dsers_store_push, ALWAYS show a confirmation checklist and wait for user approval:\n- Product: title, variant count\n- Price: sell vs cost range\n- Store: name\n- Visibility: Draft or Published (warn if Published)\n- Shipping profile: selected profile name, or \"NOT SELECTED\" with available options listed\n- Pricing Rule: MCP pricing or store rule (warn if conflict)\nIf required info is missing (e.g. no shipping profile selected), show warning with available options and ask user to choose.\nONLY call dsers_store_push after explicit user confirmation (e.g. \"push\", \"go\", \"confirmed\", \"推送\", \"确认\").\nException: if user's ORIGINAL message already contains explicit push instruction (\"push it\", \"直接推送\", \"推送到店铺\"), treat as pre-confirmed — show checklist as summary, not blocker.\n\nSHIPPING PROFILES: Shopify stores may have multiple shipping profiles.\n- Single profile → auto-selected, no action needed.\n- Multiple profiles + none specified → push BLOCKED with available_profiles list.\n- Use shipping_profile_name in push_options_json to select one.\n- Do NOT rely on \"default\" profiles — always show user available options when blocked.\n\nERROR RECOVERY:\n- Expired job_id → re-import with source_url\n- blocked array → hard stop, fix before retry\n- warnings array → soft alert, push proceeds\n- push_blocked_by_missing_shipping_profile → show available profiles, ask user to pick, retry with shipping_profile_name\n- Auth/401/session errors → call dsers_authorize to open browser login\n- After dsers_authorize succeeds: tell user authorization succeeded and ask them to resend their request. Do NOT retry in the same turn (session will refresh on next message).\n- If DSers session expired: tell user to go to Settings → Disconnect DSers → Reconnect. NEVER mention terminal commands (npx, npm, node) or environment variables (DSERS_TOKEN).\n- NEVER ask user to run terminal commands or npx`;\n\nexport class DSClawCoreAgent implements AgentBase {\n readonly id = \"dsclaw-core\";\n readonly name = \"DSClaw Core Agent\";\n\n private dsers: DSersClient;\n private memory: MemoryProvider;\n private llm: LLMConfig;\n private customTools: Map<string, AgentTool> = new Map();\n private importService: ImportFlowService | null = null;\n private jobIdMap: Map<string, string> = loadJobIdMap();\n public mcpAvailable = false;\n private authCallback?: () => Promise<{ success: boolean; email?: string; reason?: string }>;\n\n constructor(\n dsers: DSersClient,\n memory: MemoryProvider,\n llm: LLMConfig,\n dsersSession?: { sessionId: string; state: string },\n authCallback?: () => Promise<{ success: boolean; email?: string; reason?: string }>,\n jobStore?: JobStore,\n ) {\n this.dsers = dsers;\n this.memory = memory;\n this.llm = llm;\n this.authCallback = authCallback;\n if (dsersSession?.sessionId) {\n try {\n const mcpConfig = configFromToken(dsersSession.sessionId, dsersSession.state);\n const provider = buildProvider(mcpConfig);\n this.importService = new ImportFlowService(provider, jobStore ?? new MemoryJobStore());\n this.mcpAvailable = true;\n log.info(\"MCP ImportFlowService initialized\");\n } catch (err) {\n log.warn({ err }, \"Failed to init MCP ImportFlowService — product tools unavailable\");\n }\n }\n }\n\n private getSystemPrompt(): string {\n const rule = \"ALWAYS respond in the same language as the user's most recent message. \"\n + \"If they write Chinese, respond in Chinese. If English, respond in English. \"\n + \"Never switch languages unless the user does.\";\n return SYSTEM_PROMPT.replace(\"{{LANGUAGE_RULE}}\", `Language rule: ${rule}`);\n }\n\n private shortenJobId(fullId: string): string {\n const dotIdx = fullId.indexOf(\".\");\n if (dotIdx <= 0) return fullId;\n const short = fullId.slice(0, dotIdx);\n this.jobIdMap.set(short, fullId);\n persistJobIdMap(this.jobIdMap);\n return short;\n }\n\n private resolveJobId(maybeShort: string): string {\n return this.jobIdMap.get(maybeShort) ?? maybeShort;\n }\n\n registerTool(t: AgentTool): void {\n this.customTools.set(t.name, t);\n }\n\n removeTool(name: string): void {\n this.customTools.delete(name);\n }\n\n getTools(): AgentTool[] {\n return Array.from(this.customTools.values());\n }\n\n async process(\n message: string,\n context: AgentContext,\n ): Promise<AgentResponse> {\n const model = buildModel(this.llm);\n\n const memories = await this.memory\n .search(message, { userId: context.userId, limit: 5 })\n .catch(() => []);\n\n const memoryContext =\n memories.length > 0\n ? `\\n\\nRelevant memories:\\n${memories.map((m) => `- ${m.content}`).join(\"\\n\")}`\n : \"\";\n\n const messages: ModelMessage[] = [\n { role: \"system\", content: this.getSystemPrompt() + memoryContext },\n ...context.history.map(\n (h) =>\n ({\n role: h.role as \"user\" | \"assistant\",\n content: h.content,\n }) as ModelMessage,\n ),\n { role: \"user\", content: message },\n ];\n\n const tools = this.buildAITools(context);\n\n log.info(\n { userId: context.userId, messageLen: message.length, toolCount: Object.keys(tools).length },\n \"Processing message\",\n );\n\n try {\n const abort = new AbortController();\n const timer = setTimeout(() => abort.abort(), 120_000);\n const result = await generateText({\n model,\n messages,\n tools,\n stopWhen: stepCountIs(10),\n abortSignal: abort.signal,\n });\n clearTimeout(timer);\n\n const toolCalls =\n result.steps\n ?.flatMap((step) =>\n step.toolCalls?.map((tc) => ({\n tool: tc.toolName,\n params: (\"input\" in tc ? tc.input : {}) as Record<string, unknown>,\n result: {\n success: true,\n data: step.toolResults?.find(\n (tr) => tr.toolCallId === tc.toolCallId,\n )?.output,\n },\n })),\n )\n .filter(Boolean) ?? [];\n\n return {\n text: result.text,\n toolCalls: toolCalls as AgentResponse[\"toolCalls\"],\n };\n } catch (error) {\n log.error({ error, userId: context.userId }, \"Agent processing failed\");\n writeAuditLog({\n userId: context.userId,\n agentId: this.id,\n action: \"process_message\",\n target: \"llm\",\n result: \"failed\",\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Streaming version of process() — yields text chunks for real-time display.\n * Calls onStatus when tool calls happen so the UI can show activity.\n */\n processStream(\n message: string,\n context: AgentContext,\n onStatus?: (status: string) => void,\n callbacks?: {\n onToolCall?: (id: string, name: string, args: Record<string, unknown>) => void;\n onToolResult?: (id: string, name: string, result: unknown, error: string | undefined, durationMs: number) => void;\n },\n attachments?: Array<{ url: string; data?: Buffer; mimeType: string }>,\n ): { textStream: AsyncIterable<string>; response: Promise<AgentResponse> } {\n const model = buildModel(this.llm);\n\n const memories = this.memory\n .search(message, { userId: context.userId, limit: 5 })\n .catch(() => []);\n\n const tools = this.buildAITools(context);\n\n const self = this;\n\n const streamPromise = memories.then((mems) => {\n const memoryContext =\n mems.length > 0\n ? `\\n\\nRelevant memories:\\n${mems.map((m) => `- ${m.content}`).join(\"\\n\")}`\n : \"\";\n\n const userContent: ModelMessage[\"content\"] =\n attachments?.length\n ? [\n ...attachments.map((a) => ({\n type: \"image\" as const,\n image: a.data ?? a.url,\n mimeType: a.mimeType,\n })),\n { type: \"text\" as const, text: message },\n ]\n : message;\n\n const messages: ModelMessage[] = [\n { role: \"system\", content: this.getSystemPrompt() + memoryContext },\n ...context.history.map(\n (h) =>\n ({\n role: h.role as \"user\" | \"assistant\",\n content: h.content,\n }) as ModelMessage,\n ),\n { role: \"user\", content: userContent } as ModelMessage,\n ];\n\n const totalMsgChars = messages.reduce((sum, m) => sum + (typeof m.content === \"string\" ? m.content.length : JSON.stringify(m.content).length), 0);\n const toolNames = Object.keys(tools);\n const toolSchemaChars = JSON.stringify(Object.fromEntries(\n Object.entries(tools).map(([k, v]) => [k, (v as Record<string, unknown>).description ?? \"\"]),\n )).length;\n\n log.info(\n { userId: context.userId, messageLen: message.length, streaming: true,\n llmProvider: self.llm.provider, llmModel: self.llm.model, llmBaseUrl: self.llm.baseUrl,\n historyTurns: context.history.length, totalMsgChars, toolCount: toolNames.length, toolSchemaChars,\n approxTokens: Math.ceil(totalMsgChars / 3.5) },\n \"Processing message (stream)\",\n );\n\n return streamText({\n model,\n messages,\n tools,\n stopWhen: stepCountIs(10),\n onChunk({ chunk }: { chunk: { type: string; toolName?: string; toolCallId?: string; args?: unknown; result?: unknown } }) {\n if (chunk.type === \"tool-call\") {\n toolActive = true;\n const name = chunk.toolName ?? \"\";\n const args = ((chunk as any).args ?? (chunk as any).input ?? {}) as Record<string, unknown>;\n log.info({ tool: name, args: JSON.stringify(args).slice(0, 500) }, \"Tool call\");\n if (onStatus) {\n let label = TOOL_LABELS[name] ?? name;\n if (name === \"dsers_product_import\") {\n if (args.job_id && !args.source_url && !args.source_urls_json) {\n label = args.rules_json ? \"Applying rules...\" : \"Refreshing preview...\";\n }\n }\n onStatus(label ?? \"Working...\");\n }\n if (callbacks?.onToolCall && chunk.toolCallId) {\n toolStartTimes.set(chunk.toolCallId, Date.now());\n callbacks.onToolCall(chunk.toolCallId, name, args);\n }\n }\n if (chunk.type === \"tool-result\") {\n toolActive = false;\n const name = chunk.toolName ?? \"\";\n const output = (chunk as any).output ?? (chunk as any).result;\n const resultStr = JSON.stringify(output ?? \"\").slice(0, 500);\n log.info({ tool: name, resultSnippet: resultStr }, \"Tool result\");\n if (callbacks?.onToolResult && chunk.toolCallId) {\n const startTime = toolStartTimes.get(chunk.toolCallId) ?? Date.now();\n const durationMs = Date.now() - startTime;\n toolStartTimes.delete(chunk.toolCallId);\n callbacks.onToolResult(chunk.toolCallId, name, chunk.result, undefined, durationMs);\n }\n if (onStatus) onStatus(\"Thinking...\");\n }\n },\n });\n });\n\n let toolActive = false;\n const toolStartTimes = new Map<string, number>();\n\n const textStream: AsyncIterable<string> = {\n [Symbol.asyncIterator]() {\n let innerIterator: AsyncIterator<string> | null = null;\n let gotFirstToken = false;\n return {\n async next(): Promise<IteratorResult<string>> {\n try {\n if (!innerIterator) {\n const result = await withTimeout(streamPromise, 60_000, \"LLM init\");\n innerIterator = result.textStream[Symbol.asyncIterator]();\n }\n const timeout = gotFirstToken ? 60_000 : 120_000;\n const res = await withToolAwareTimeout(innerIterator.next(), timeout, () => toolActive, \"LLM response\");\n if (!res.done && res.value) {\n gotFirstToken = true;\n toolActive = false;\n }\n return res;\n } catch (err) {\n log.error({ err, toolActive, gotFirstToken }, \"Stream iterator error\");\n throw err;\n }\n },\n };\n },\n };\n\n const response: Promise<AgentResponse> = streamPromise.then(async (result) => {\n const text = await result.text;\n const steps = await result.steps;\n\n const toolCalls =\n steps\n ?.flatMap((step) =>\n step.toolCalls?.map((tc) => ({\n tool: tc.toolName,\n params: (\"input\" in tc ? tc.input : {}) as Record<string, unknown>,\n result: {\n success: true,\n data: step.toolResults?.find(\n (tr) => tr.toolCallId === tc.toolCallId,\n )?.output,\n },\n })),\n )\n .filter(Boolean) ?? [];\n\n return {\n text,\n toolCalls: toolCalls as AgentResponse[\"toolCalls\"],\n };\n });\n\n return { textStream, response };\n }\n\n private buildAITools(context: AgentContext) {\n const dsers = this.dsers;\n const svc = this.importService;\n const jmap = this.jobIdMap;\n const resolveJid = (id: string) => this.resolveJobId(id);\n const audit = (action: string, target: string, params?: Record<string, unknown>, result: \"pending\" | \"success\" = \"pending\") =>\n writeAuditLog({ userId: context.userId, agentId: this.id, action, target, params, result });\n\n const tools: Record<string, any> = {};\n\n if (svc) {\n tools.dsers_store_discover = aiTool({\n description: \"Get connected stores, account info (plan/limits), and rule capabilities. Call first before import/push.\",\n inputSchema: z.object({\n target_store: z.string().optional().describe(\"Filter by store ID or name\"),\n }),\n execute: async (input) => {\n audit(\"dsers_store_discover\", \"mcp\");\n const result = await withTimeout(svc.getRuleCapabilities(input as Record<string, unknown>), 60_000, \"Store discovery\");\n audit(\"dsers_store_discover\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_product_import = aiTool({\n description:\n \"Import product by URL or re-apply rules to existing job. \" +\n \"Modes: (1) source_url for new import, (2) job_id+rules_json to update rules, (3) job_id alone to refresh. \" +\n \"Expired job_id → re-import with source_url. \" +\n \"Returns: job_id, title (or title_before+title_after), sell_price, cost, variants, blocked, warnings.\",\n inputSchema: z.object({\n source_url: z.string().optional().describe(\"Supplier product URL\"),\n source_urls_json: z.string().optional().describe(\"Batch: JSON array of URLs\"),\n job_id: z.string().optional().describe(\"Existing job ID for rule updates\"),\n source_hint: z.string().optional().describe(\"auto|aliexpress|alibaba|accio\"),\n country: z.string().default(\"US\").describe(\"Country code\"),\n target_store: z.string().optional().describe(\"Store ID or name\"),\n visibility_mode: z.string().optional().describe(\"backend_only|sell_immediately\"),\n rules_json: z.string().optional().describe(\n \"JSON rules. Pricing: fixed_price({fixed_price:9.99}), multiplier({multiplier:2}), fixed_markup({fixed_markup:5}). \" +\n \"Content: title_override, description_override_html. Images: keep_first_n, drop_indexes, add_urls. \" +\n \"variant_overrides: [{match,sell_price,compare_at_price,stock}]. option_edits: [{action,option_name,value_name?,new_name?}].\"\n ),\n }),\n execute: async (input) => {\n audit(\"dsers_product_import\", \"mcp\", input as Record<string, unknown>);\n const payload: Record<string, unknown> = {};\n if (input.job_id && !input.source_url && !input.source_urls_json) {\n payload.job_id = resolveJid(input.job_id);\n if (input.rules_json) {\n try { payload.rules = JSON.parse(input.rules_json); } catch {\n throw new Error(\n \"Invalid JSON in rules_json. Expected: \" +\n '{\"pricing\":{\"mode\":\"fixed_price\",\"fixed_price\":9.99}} or ' +\n '{\"content\":{\"title_override\":\"New Title\"}}',\n );\n }\n } else {\n payload._keep_existing_rules = true;\n }\n if (input.target_store) payload.target_store = input.target_store;\n if (input.visibility_mode) payload.visibility_mode = input.visibility_mode;\n const result = await withTimeout(svc.reapplyRules(payload), 120_000, \"Rule reapply\");\n audit(\"dsers_product_import\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n }\n if (input.source_url) payload.source_url = input.source_url;\n if (input.source_urls_json) {\n try { payload.source_urls = JSON.parse(input.source_urls_json); } catch {\n throw new Error(\"Invalid JSON in source_urls_json.\");\n }\n }\n if (input.source_hint) payload.source_hint = input.source_hint;\n if (input.country) payload.country = input.country;\n if (input.target_store) payload.target_store = input.target_store;\n payload.visibility_mode = input.visibility_mode || \"backend_only\";\n if (input.rules_json) {\n try { payload.rules = JSON.parse(input.rules_json); } catch {\n throw new Error(\"Invalid JSON in rules_json.\");\n }\n }\n const result = await withTimeout(svc.prepareImportCandidate(payload), 120_000, \"Product import\");\n audit(\"dsers_product_import\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_product_preview = aiTool({\n description: \"Reload preview for an imported job. Returns prices, variants, images.\",\n inputSchema: z.object({\n job_id: z.string().describe(\"Job ID from dsers_product_import\"),\n variant_offset: z.number().optional().describe(\"Start index for variant pagination\"),\n variant_limit: z.number().optional().describe(\"Max variants to return\"),\n }),\n execute: async (input) => {\n audit(\"dsers_product_preview\", \"mcp\", input as Record<string, unknown>);\n const result = await withTimeout(svc.getImportPreview({ ...input, job_id: resolveJid(input.job_id) }), 30_000, \"Preview\");\n audit(\"dsers_product_preview\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_store_push = aiTool({\n description:\n \"Push product(s) to store(s). Show confirmation checklist and get user approval first. \" +\n \"May return blocked (shipping_profile, pricing_rule) or warnings. \" +\n \"Use push_options_json with shipping_profile_name when store has multiple shipping profiles.\",\n inputSchema: z.object({\n job_id: z.string().optional().describe(\"Job ID\"),\n job_ids_json: z.string().optional().describe(\"Batch: JSON array of job IDs\"),\n target_store: z.string().optional().describe(\"Store ID or name from dsers_store_discover\"),\n target_stores_json: z.string().optional().describe(\"Multi-store: JSON array of store names\"),\n visibility_mode: z.string().optional().describe(\"backend_only|sell_immediately\"),\n force_push: z.boolean().optional().describe(\"Override safety checks\"),\n push_options_json: z.string().optional().describe(\n 'Push config JSON. Include shipping_profile_name when multiple profiles exist. ' +\n 'E.g. {\"shipping_profile_name\":\"General Profile\",\"pricing_rule_behavior\":\"apply_store_pricing_rule\"}'\n ),\n }),\n execute: async (input) => {\n audit(\"dsers_store_push\", \"mcp\", input as Record<string, unknown>);\n const payload: Record<string, unknown> = {};\n if (input.job_ids_json) {\n try {\n const ids = JSON.parse(input.job_ids_json) as string[];\n payload.job_ids = ids.map(resolveJid);\n } catch { throw new Error(\"Invalid JSON in job_ids_json\"); }\n } else if (input.job_id) {\n payload.job_id = resolveJid(input.job_id);\n }\n if (input.target_store) payload.target_store = input.target_store;\n if (input.target_stores_json) {\n try { payload.target_stores = JSON.parse(input.target_stores_json); } catch { throw new Error(\"Invalid JSON in target_stores_json\"); }\n }\n if (input.visibility_mode) payload.visibility_mode = input.visibility_mode;\n if (input.force_push) payload.force_push = true;\n if (input.push_options_json) {\n try { payload.push_options = JSON.parse(input.push_options_json); } catch { throw new Error(\"Invalid JSON in push_options_json\"); }\n }\n const result = await withTimeout(svc.confirmPushToStore(payload), 180_000, \"Push to store\");\n audit(\"dsers_store_push\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_rules_validate = aiTool({\n description: \"Validate pricing/content/image rules before importing.\",\n inputSchema: z.object({\n rules_json: z.string().describe(\"Rules as JSON string\"),\n target_store: z.string().optional().describe(\"Store ID or name\"),\n }),\n execute: async (input) => {\n audit(\"dsers_rules_validate\", \"mcp\");\n let rules: unknown;\n try { rules = JSON.parse(input.rules_json); } catch { throw new Error(\"Invalid JSON in rules_json\"); }\n const result = await withTimeout(svc.validateRules({ rules, target_store: input.target_store ?? null }), 30_000, \"Rule validation\");\n audit(\"dsers_rules_validate\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_job_status = aiTool({\n description: \"Check job status: preview_ready → push_requested → completed/failed.\",\n inputSchema: z.object({\n job_id: z.string().describe(\"Job ID\"),\n }),\n execute: async (input) => {\n audit(\"dsers_job_status\", \"mcp\", input as Record<string, unknown>);\n const result = await withTimeout(svc.getJobStatus({ ...input, job_id: resolveJid(input.job_id) }), 30_000, \"Job status\");\n audit(\"dsers_job_status\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_product_visibility = aiTool({\n description: \"Set job visibility: backend_only (draft) or sell_immediately (live).\",\n inputSchema: z.object({\n job_id: z.string().describe(\"Job ID\"),\n visibility_mode: z.string().describe(\"backend_only|sell_immediately\"),\n }),\n execute: async (input) => {\n audit(\"dsers_product_visibility\", \"mcp\", input as Record<string, unknown>);\n const result = await withTimeout(svc.setProductVisibility({ ...input, job_id: resolveJid(input.job_id) }), 30_000, \"Set visibility\");\n audit(\"dsers_product_visibility\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_product_delete = aiTool({\n description: \"Delete product from import list. Call without confirm first, then with confirm=true after user approves.\",\n inputSchema: z.object({\n import_item_id: z.string().describe(\"Item ID from dsers_import_list_search\"),\n confirm: z.boolean().optional().describe(\"true only after user approves\"),\n }),\n execute: async (input) => {\n audit(\"dsers_product_delete\", \"mcp\", input as Record<string, unknown>);\n const result = await withTimeout(svc.deleteImportItem(input), 30_000, \"Delete import item\");\n audit(\"dsers_product_delete\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n } else {\n log.warn(\"MCP ImportFlowService not available — no MCP tools registered\");\n }\n\n if (this.authCallback) {\n tools.dsers_authorize = aiTool({\n description: \"Open browser for DSers login. Call when DSers ops fail with auth/401/session errors.\",\n inputSchema: z.object({}),\n execute: async () => {\n const result = await withTimeout(this.authCallback!(), 200_000, \"DSers authorization\");\n return result;\n },\n });\n }\n\n tools.dsers_import_list_search = aiTool({\n description: \"Search import list. Returns items with id, source_url, cost_range, sell_price_range. Use source_url with dsers_product_import for modifications.\",\n inputSchema: z.object({\n page: z.number().optional().describe(\"Page number (default 1)\"),\n pageSize: z.number().optional().describe(\"Items per page (default 20)\"),\n keyword: z.string().optional().describe(\"Search keyword\"),\n }),\n execute: async (input) => {\n audit(\"dsers_import_list_search\", \"dsers:product\", input as Record<string, unknown>);\n const result = await withTimeout(productApi.getImportList(dsers, input as Record<string, unknown>), 30_000, \"Search import list\");\n audit(\"dsers_import_list_search\", \"dsers:product\", undefined, \"success\");\n\n const items = (result as any)?.data?.list ?? (result as any)?.data ?? [];\n if (Array.isArray(items) && items.length > 0) {\n const enriched = await Promise.allSettled(\n items.slice(0, 10).map(async (item: any) => {\n const itemId = item.id ?? item.importListId;\n if (!itemId) return item;\n try {\n const detail = await withTimeout(\n productApi.getImportListItem(dsers, String(itemId)), 15_000, \"Item detail\",\n );\n const detailData = (detail as any)?.data ?? detail;\n const variants = detailData?.variants ?? detailData?.skuList ?? detailData?.variantList ?? [];\n if (!Array.isArray(variants) || !variants.length) return item;\n\n const sellPrices: number[] = [];\n const costPrices: number[] = [];\n for (const v of variants) {\n const rawSell = Number(v.sellPrice ?? v.salePrice ?? v.price);\n const rawCost = Number(v.supplierPrice ?? v.buyPrice ?? v.cost);\n const sell = rawSell > 100 ? rawSell / 100 : rawSell;\n const cost = rawCost > 100 ? rawCost / 100 : rawCost;\n if (Number.isFinite(sell) && sell > 0) sellPrices.push(sell);\n if (Number.isFinite(cost) && cost > 0) costPrices.push(cost);\n }\n\n const enrichedItem = { ...item };\n const supplyProductId = detailData?.supplyProductId ?? item?.supplyProductId;\n const supplyAppId = Number(detailData?.supplyAppId ?? item?.supplyAppId ?? 1);\n if (supplyProductId) {\n if (supplyAppId === 2) {\n enrichedItem.source_url = `https://www.temu.com/product/${supplyProductId}.html`;\n } else if (supplyAppId === 3) {\n enrichedItem.source_url = `https://detail.1688.com/offer/${supplyProductId}.html`;\n } else {\n enrichedItem.source_url = `https://www.aliexpress.com/item/${supplyProductId}.html`;\n }\n }\n if (costPrices.length) {\n enrichedItem.cost_range = `$${Math.min(...costPrices).toFixed(2)} – $${Math.max(...costPrices).toFixed(2)}`;\n }\n if (sellPrices.length) {\n enrichedItem.sell_price_range = `$${Math.min(...sellPrices).toFixed(2)} – $${Math.max(...sellPrices).toFixed(2)}`;\n enrichedItem.no_markup = sellPrices.every((s, i) => Math.abs(s - (costPrices[i] ?? s)) < 0.01);\n }\n enrichedItem.variant_count = variants.length;\n let totalStock = 0;\n const lowStockVariants: Array<{ id: string; sku: string; stock: number }> = [];\n for (const v of variants) {\n const stock = Number(v.stock ?? v.quantity ?? v.inventory ?? 0);\n const safeStock = Number.isFinite(stock) ? stock : 0;\n totalStock += safeStock;\n if (safeStock <= 5) {\n lowStockVariants.push({\n id: String(v.id ?? v.variantId ?? v.skuId ?? \"\"),\n sku: String(v.sku ?? v.skuAttr ?? v.optionName ?? v.title ?? \"\"),\n stock: safeStock,\n });\n }\n }\n enrichedItem.total_stock = totalStock;\n if (lowStockVariants.length > 0) {\n enrichedItem.low_stock_variants = lowStockVariants;\n enrichedItem.low_stock_warning = `${lowStockVariants.length} of ${variants.length} variants have stock ≤ 5`;\n }\n return enrichedItem;\n } catch (err) {\n log.warn({ err, itemId }, \"Failed to enrich import list item\");\n return item;\n }\n }),\n );\n\n const enrichedItems = enriched.map((r) => r.status === \"fulfilled\" ? r.value : items[0]);\n const cleanItems = enrichedItems.map((item: any) => ({\n id: item.id ?? item.importListId,\n title: item.title ?? \"(untitled)\",\n source_url: item.source_url,\n cost_range: item.cost_range,\n sell_price_range: item.sell_price_range,\n no_markup: item.no_markup,\n variant_count: item.variant_count,\n total_stock: item.total_stock,\n low_stock_warning: item.low_stock_warning,\n low_stock_variants: item.low_stock_variants,\n }));\n return { items: cleanItems, total: (result as any)?.data?.total ?? cleanItems.length };\n }\n const rawItems = (result as any)?.data ?? [];\n if (Array.isArray(rawItems)) {\n return { items: rawItems.map((item: any) => ({\n id: item.id ?? item.importListId,\n title: item.title ?? \"(untitled)\",\n })), total: rawItems.length };\n }\n return compactToolResult(result);\n },\n });\n\n tools.dsers_my_products = aiTool({\n description: \"Get products already pushed to stores.\",\n inputSchema: z.object({\n page: z.number().optional(),\n pageSize: z.number().optional(),\n keyword: z.string().optional(),\n storeId: z.string().optional(),\n }),\n execute: async (input) => {\n audit(\"dsers_my_products\", \"dsers:product\", input as Record<string, unknown>);\n const result = await withTimeout(productApi.getMyProducts(dsers, input as Record<string, unknown>), 30_000, \"My products\");\n audit(\"dsers_my_products\", \"dsers:product\", undefined, \"success\");\n return compactToolResult(result);\n },\n });\n\n return tools;\n }\n}\n","/**\n * Audit log for tracking all write operations.\n * Every action an agent takes is recorded so the user\n * can always answer \"what did the bot do?\"\n */\n\nimport { appendFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR } from \"../gateway/config.js\";\nimport { getTraceId } from \"./tracer.js\";\n\nconst AUDIT_DIR = join(CONFIG_DIR, \"audit\");\n\nexport interface AuditEntry {\n timestamp: string;\n traceId: string;\n userId: string;\n agentId: string;\n action: string;\n target: string;\n params?: Record<string, unknown>;\n result: \"success\" | \"failed\" | \"pending\";\n error?: string;\n}\n\nfunction ensureAuditDir(): void {\n if (!existsSync(AUDIT_DIR)) {\n mkdirSync(AUDIT_DIR, { recursive: true });\n }\n}\n\nexport function writeAuditLog(entry: Omit<AuditEntry, \"timestamp\" | \"traceId\">): void {\n ensureAuditDir();\n const full: AuditEntry = {\n ...entry,\n timestamp: new Date().toISOString(),\n traceId: getTraceId(),\n };\n\n const date = full.timestamp.slice(0, 10);\n const file = join(AUDIT_DIR, `${date}.jsonl`);\n\n try {\n appendFileSync(file, JSON.stringify(full) + \"\\n\");\n } catch {\n // Audit write failure should never crash the system\n }\n}\n\nexport function auditFilePath(date: string): string {\n return join(AUDIT_DIR, `${date}.jsonl`);\n}\n","/**\n * DSers Product API — import, preview, push.\n * Core operations for the DSClaw product workflow.\n */\n\nimport type { DSersClient } from \"./client.js\";\n\nexport async function getImportList(\n client: DSersClient,\n params?: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n const filtered = params\n ? Object.fromEntries(Object.entries(params).filter(([, v]) => v != null))\n : {};\n return client.get(\"/dsers-product-bff/import-list\", filtered);\n}\n\nexport async function getImportListItem(\n client: DSersClient,\n id: string,\n): Promise<Record<string, unknown>> {\n return client.get(`/dsers-product-bff/import-list/${id}`);\n}\n\nexport async function importByProductId(\n client: DSersClient,\n body: {\n supplyProductId: string;\n supplyAppId: string | number;\n country: string;\n language?: string[];\n },\n): Promise<Record<string, unknown>> {\n return client.post(\"/dsers-product-bff/import-list/product-id\", body);\n}\n\nexport async function importByProductIdBatch(\n client: DSersClient,\n body: {\n supplyProductIds: string[];\n supplyAppId: string | number;\n country: string;\n isBackError?: number;\n },\n): Promise<Record<string, unknown>> {\n return client.post(\"/dsers-product-bff/import-list/product-id-batch\", body);\n}\n\nexport async function updateImportListItem(\n client: DSersClient,\n id: string,\n updates: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n const { createLogger } = await import(\"../shared/logger.js\");\n const log = createLogger(\"dsers:product\");\n\n const existing = await client.get(`/dsers-product-bff/import-list/${id}`);\n const product = existing?.[\"data\"] ?? existing;\n\n const data =\n product !== null && typeof product === \"object\" && !Array.isArray(product)\n ? { ...(product as Record<string, unknown>), ...updates }\n : updates;\n\n const productKeys = Object.keys(product as Record<string, unknown>);\n const firstVariant = ((product as any)?.variants ?? [])[0];\n log.info({\n id,\n updateKeys: Object.keys(updates),\n productKeys: productKeys.slice(0, 30),\n hasDescription: \"description\" in (product as any),\n hasSpecifications: \"specifications\" in (product as any),\n descFieldInUpdate: !!updates.description,\n titleInProduct: (product as any)?.title?.slice?.(0, 60),\n titleInUpdate: updates.title ? String(updates.title).slice(0, 60) : undefined,\n descInProduct: String((product as any)?.description ?? \"\").slice(0, 80),\n specsInProduct: String((product as any)?.specifications ?? \"\").slice(0, 80),\n descInUpdate: updates.description ? String(updates.description).slice(0, 80) : undefined,\n variantSample: firstVariant ? { id: firstVariant.id, sellPrice: firstVariant.sellPrice, salePrice: firstVariant.salePrice, keys: Object.keys(firstVariant).slice(0, 15) } : null,\n mergedDataSize: JSON.stringify(data).length,\n }, \"updateImportListItem: sending PUT\");\n\n const putResult = await client.put(`/dsers-product-bff/import-list/${id}`, data);\n\n log.info({\n id,\n putResultSnippet: JSON.stringify(putResult).slice(0, 500),\n }, \"updateImportListItem: PUT response\");\n\n return putResult;\n}\n\nexport async function pushToStore(\n client: DSersClient,\n payload: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n return client.post(\"/dsers-product-bff/import-list/push\", {\n data: payload,\n });\n}\n\nexport async function getPushStatus(\n client: DSersClient,\n eventId: string,\n): Promise<Record<string, unknown>> {\n return client.get(`/dsers-product-bff/import-list/push/${eventId}`);\n}\n\nexport async function getMyProducts(\n client: DSersClient,\n params: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n return client.get(\"/dsers-product-bff/my-product\", params);\n}\n\nexport async function getStoreShippingProfile(\n client: DSersClient,\n storeId?: string,\n): Promise<Record<string, unknown>> {\n const params = storeId != null ? { storeId } : undefined;\n return client.get(\n \"/dsers-product-bff/import-list/push/store-shipping-profile\",\n params,\n );\n}\n","/**\n * DSClaw Gateway — central orchestrator.\n *\n * Flow:\n * 1. User opens web chat (or sends Telegram message)\n * 2. Gateway loads user session (encrypted on disk)\n * 3. If not \"ready\": handle onboarding conversation (no LLM needed)\n * 4. If \"ready\": route to AI agent with streaming (web) or batch (Telegram)\n *\n * Web chat is the default channel (zero config).\n * Telegram is optional (requires bot token in config).\n */\n\nimport type { DSClawConfig } from \"./config.js\";\nimport {\n loadSession,\n saveSession,\n isOnboarding,\n type UserSessionData,\n} from \"./user-session.js\";\nimport { DSersClient } from \"../dsers/client.js\";\nimport { createDSersConfig } from \"../dsers/config.js\";\nimport { loginViaCDP, isAuthInProgress, cancelAuth } from \"../dsers/browser-auth.js\";\nimport { DSClawCoreAgent, getDefaultModel, type LLMConfig } from \"../agents/core-agent.js\";\nimport { MemoryJobStore } from \"@lofder/dsers-mcp-product/dist/job-store-memory.js\";\nimport { WebChatServer } from \"../web/server.js\";\nimport { TelegramAdapter } from \"../channels/telegram.js\";\nimport { FileMemoryProvider } from \"../memory/file-provider.js\";\nimport type { ChannelAdapter, NormalizedMessage } from \"../channels/adapter.js\";\nimport type { MemoryProvider } from \"../memory/provider.js\";\nimport type { AgentMessage, AgentContext } from \"../agents/base.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { runWithTrace } from \"../shared/tracer.js\";\nimport { writeAuditLog } from \"../shared/audit.js\";\nimport { checkInboundLimit, acquireUserLock, debounceUser } from \"../resilience/rate-limiter.js\";\nimport { isDegraded, degradationMessage } from \"../resilience/degradation.js\";\nimport { initTokenCounter } from \"../context/token-counter.js\";\nimport { allocateBudget } from \"../context/context-budget.js\";\nimport { compactWithFlush } from \"../context/compaction.js\";\nimport {\n loadHistory,\n appendHistory,\n setHistory,\n clearHistory,\n getHistory,\n type HistoryMessage,\n} from \"../context/history-store.js\";\nimport { t, type Lang } from \"./i18n.js\";\n\nconst log = createLogger(\"gateway\");\n\nconst SESSION_MAX_SIZE = 500;\nconst SESSION_TTL_MS = 2 * 60 * 60 * 1000; // 2 hours\n\nconst sessionHistories = new Map<string, AgentMessage[]>();\nconst sessionLastAccess = new Map<string, number>();\nconst MAX_HISTORY = 20;\n\nfunction touchSession(key: string): void {\n sessionLastAccess.set(key, Date.now());\n if (sessionHistories.size > SESSION_MAX_SIZE) {\n let oldest = \"\";\n let oldestTs = Infinity;\n for (const [k, ts] of sessionLastAccess) {\n if (ts < oldestTs) { oldest = k; oldestTs = ts; }\n }\n if (oldest) {\n sessionHistories.delete(oldest);\n sessionLastAccess.delete(oldest);\n }\n }\n}\n\nsetInterval(() => {\n const now = Date.now();\n for (const [key, ts] of sessionLastAccess) {\n if (now - ts > SESSION_TTL_MS) {\n sessionHistories.delete(key);\n sessionLastAccess.delete(key);\n }\n }\n}, 10 * 60 * 1000).unref();\n\nfunction detectProviderFromKey(key: string): string | null {\n if (key.startsWith(\"sk-ant-\")) return \"anthropic\";\n if (key.startsWith(\"sk-\")) return \"openai\";\n if (key.startsWith(\"AIza\")) return \"google\";\n return null;\n}\n\nexport class DSClawGateway {\n private config: DSClawConfig;\n private channels: ChannelAdapter[] = [];\n private webChannel: WebChatServer | null = null;\n private memory: MemoryProvider;\n private agents = new Map<string, DSClawCoreAgent>();\n private jobStores = new Map<string, MemoryJobStore>();\n private dsersClients = new Map<string, DSersClient>();\n private lastUserMessages = new Map<string, string>();\n private running = false;\n\n constructor(config: DSClawConfig) {\n this.config = config;\n this.memory = new FileMemoryProvider();\n }\n\n private getLang(session: UserSessionData, channel: ChannelAdapter): Lang {\n if (session.language === \"zh\" || session.language === \"en\") return session.language;\n return channel instanceof WebChatServer ? \"en\" : \"en\";\n }\n\n async start(): Promise<void> {\n log.info(\"Starting DSClaw Gateway...\");\n\n const web = new WebChatServer();\n web.onMessage((msg) => this.handleMessage(web, msg));\n web.onConnect((userId) => this.handleWebConnect(web, userId));\n web.onSettings((userId, action, data) => this.handleSettingsMessage(web, userId, action, data));\n await web.connect({ port: this.config.port });\n this.webChannel = web;\n this.channels.push(web);\n log.info({ port: this.config.port }, \"Web chat channel connected\");\n\n if (this.config.telegramBotToken) {\n try {\n const tg = new TelegramAdapter();\n tg.onMessage((msg) => this.handleMessage(tg, msg));\n await tg.connect({ botToken: this.config.telegramBotToken });\n this.channels.push(tg);\n log.info(\"Telegram channel connected\");\n } catch (error) {\n log.warn({ error }, \"Telegram failed to connect — web chat still available\");\n }\n }\n\n this.running = true;\n log.info(\"DSClaw Gateway started\");\n }\n\n private async handleMessage(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n ): Promise<void> {\n await runWithTrace(\n {\n traceId: message.traceId,\n userId: message.userId,\n channelId: message.channelId,\n },\n async () => {\n const userId = message.userId;\n\n if (!checkInboundLimit(userId)) {\n log.warn({ userId }, \"Rate limit exceeded\");\n await channel.send(userId, { text: t(\"gateway.rateLimit\", loadSession(userId).language) });\n return;\n }\n\n await debounceUser(userId);\n const release = await acquireUserLock(userId);\n const session = loadSession(userId);\n try {\n if (isOnboarding(session.state)) {\n await this.handleOnboarding(channel, message, session);\n } else {\n if (isDegraded(\"llm\")) {\n await channel.send(userId, { text: degradationMessage(\"llm\") });\n return;\n }\n await this.handleReady(channel, message, session);\n }\n } catch (error) {\n log.error({ error, userId }, \"Failed to handle message\");\n let userMsg = t(\"gateway.error.generic\", session.language);\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n if (msg.includes(\"timeout\") || msg.includes(\"timed out\")) {\n userMsg = t(\"gateway.error.timeout\", session.language);\n } else if (msg.includes(\"401\") || msg.includes(\"unauthorized\") || msg.includes(\"api key\")) {\n userMsg = t(\"gateway.error.apiKey\", session.language);\n } else if (msg.includes(\"429\") || msg.includes(\"rate limit\")) {\n userMsg = t(\"gateway.error.rateLimitLlm\", session.language);\n } else if (msg.includes(\"session\") || msg.includes(\"dsers\")) {\n userMsg = t(\"gateway.error.dsers\", session.language);\n }\n }\n await channel.send(userId, { text: userMsg });\n } finally {\n release();\n }\n },\n );\n }\n\n // ─── Auto-welcome on WebSocket connect ──────────────────────────\n\n private handleWebConnect(channel: WebChatServer, userId: string): void {\n const session = loadSession(userId);\n this.pushSettingsState(channel, userId, session);\n\n if (session.state === \"new\") {\n this.onboardWelcome(channel, userId, session).catch((err) => {\n log.error({ error: err, userId }, \"Auto-welcome failed\");\n });\n }\n }\n\n // ─── Settings Panel (Web Only) ─────────────────────────────────\n\n private isDsersConnected(session: UserSessionData): boolean {\n return !!session.dspiSessionId;\n }\n\n private pushSettingsState(channel: WebChatServer, userId: string, session: UserSessionData): void {\n const dsersOk = this.isDsersConnected(session);\n channel.sendSettingsState(userId, {\n dsers: { configured: dsersOk, email: dsersOk ? session.dspiEmail : undefined },\n llm: { configured: !!session.llmApiKey, provider: session.llmProvider, baseUrl: session.llmBaseUrl },\n ready: session.state === \"ready\",\n });\n }\n\n private async applyDSersSession(\n channel: WebChatServer,\n userId: string,\n session: UserSessionData,\n sessionId: string,\n sessionState: string,\n ): Promise<boolean> {\n const dsersConfig = createDSersConfig(session.dspiEmail ?? \"browser\");\n dsersConfig.sessionId = sessionId;\n dsersConfig.sessionState = sessionState;\n const client = new DSersClient(dsersConfig);\n\n const info = await client.get(\"/account-user-bff/v1/users/info\") as Record<string, unknown>;\n const data = info[\"data\"] as Record<string, unknown> | undefined;\n const email = (data?.[\"email\"] as string) ?? session.dspiEmail ?? \"connected\";\n\n session.dspiEmail = email;\n session.dspiSessionId = sessionId;\n session.dspiSessionState = sessionState;\n session.dspiPassword = undefined;\n this.dsersClients.set(userId, client);\n\n if (session.llmApiKey) {\n session.state = \"ready\";\n } else if (![\"onboard_llm\", \"ready\"].includes(session.state)) {\n session.state = \"onboard_llm\";\n }\n saveSession(userId, session);\n\n channel.sendSettingsResult(userId, { section: \"dsers\", success: true });\n this.pushSettingsState(channel, userId, session);\n\n if (session.state === \"ready\") {\n await this.sendReadyMessage(channel, userId);\n }\n return true;\n }\n\n async triggerAuth(userId: string): Promise<{\n success: boolean; email?: string; reason?: string;\n }> {\n if (isAuthInProgress()) {\n return { success: false, reason: \"in_progress\" };\n }\n\n try {\n const result = await loginViaCDP();\n const session = loadSession(userId);\n const dsersConfig = createDSersConfig(session.dspiEmail ?? \"browser\");\n dsersConfig.sessionId = result.sessionId;\n dsersConfig.sessionState = result.state;\n const client = new DSersClient(dsersConfig);\n\n const info = await client.get(\"/account-user-bff/v1/users/info\") as Record<string, unknown>;\n const data = info?.[\"data\"] as Record<string, unknown> | undefined;\n const email = (data?.[\"email\"] as string) ?? \"connected\";\n\n session.dspiEmail = email;\n session.dspiSessionId = result.sessionId;\n session.dspiSessionState = result.state;\n session.dspiPassword = undefined;\n if (session.llmApiKey) session.state = \"ready\";\n saveSession(userId, session);\n this.dsersClients.set(userId, client);\n this.agents.delete(userId);\n\n log.info({ userId, email }, \"triggerAuth succeeded — agent will be recreated on next message\");\n return { success: true, email };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn({ error: msg, userId }, \"triggerAuth failed\");\n\n if (msg.includes(\"cancelled\") || msg.includes(\"closed\")) {\n return { success: false, reason: \"cancelled\" };\n }\n if (msg.includes(\"timed out\") || msg.includes(\"Timed out\")) {\n return { success: false, reason: \"timeout\" };\n }\n if (msg.includes(\"No Chromium\") || msg.includes(\"browser found\")) {\n return { success: false, reason: \"no_browser\" };\n }\n return { success: false, reason: msg };\n }\n }\n\n private async handleSettingsMessage(\n channel: WebChatServer,\n userId: string,\n action: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n const session = loadSession(userId);\n\n switch (action) {\n case \"set_language\": {\n const lang = data[\"lang\"] as string;\n if (lang === \"en\" || lang === \"zh\") {\n session.language = lang;\n saveSession(userId, session);\n }\n break;\n }\n\n case \"get_settings\":\n this.pushSettingsState(channel, userId, session);\n break;\n\n case \"start_dsers_auth\": {\n if (isAuthInProgress()) {\n channel.sendSettingsResult(userId, { section: \"dsers\", success: false, error: \"Auth already in progress.\" });\n return;\n }\n\n channel.sendSettingsResult(userId, { section: \"dsers_auth_started\", success: true });\n\n loginViaCDP()\n .then(async (result) => {\n const freshSession = loadSession(userId);\n await this.applyDSersSession(channel, userId, freshSession, result.sessionId, result.state);\n })\n .catch((error) => {\n const msg = error instanceof Error ? error.message : \"unknown error\";\n log.warn({ error: msg, userId }, \"Browser auth failed\");\n channel.sendSettingsResult(userId, { section: \"dsers\", success: false, error: msg });\n });\n break;\n }\n\n case \"cancel_dsers_auth\": {\n cancelAuth();\n channel.sendSettingsResult(userId, { section: \"dsers_cancelled\", success: true });\n break;\n }\n\n case \"save_dsers_session\": {\n const sessionId = (data[\"sessionId\"] as string)?.trim();\n const sessionState = (data[\"state\"] as string)?.trim() ?? \"\";\n\n if (!sessionId || sessionId.length < 10) {\n channel.sendSettingsResult(userId, { section: \"dsers\", success: false, error: \"Invalid session token.\" });\n return;\n }\n\n try {\n await this.applyDSersSession(channel, userId, session, sessionId, sessionState);\n } catch {\n channel.sendSettingsResult(userId, { section: \"dsers\", success: false, error: \"Session token invalid or expired.\" });\n }\n break;\n }\n\n case \"disconnect_dsers\": {\n session.dspiEmail = undefined;\n session.dspiSessionId = undefined;\n session.dspiSessionState = undefined;\n session.state = \"new\";\n saveSession(userId, session);\n this.agents.delete(userId);\n this.pushSettingsState(channel, userId, session);\n break;\n }\n\n case \"save_llm\": {\n let provider = (data[\"provider\"] as string)?.trim();\n const apiKey = (data[\"apiKey\"] as string)?.trim();\n let baseUrl = (data[\"baseUrl\"] as string)?.trim() || undefined;\n const model = (data[\"model\"] as string)?.trim() || undefined;\n\n if (baseUrl) {\n if (!/^https?:\\/\\//i.test(baseUrl)) baseUrl = `https://${baseUrl}`;\n baseUrl = baseUrl.replace(/\\/+$/, \"\");\n if (!/\\/v\\d/.test(baseUrl)) baseUrl += \"/v1\";\n }\n\n if (!apiKey || apiKey.length < 3) {\n channel.sendSettingsResult(userId, { section: \"llm\", success: false, error: \"Please enter a valid API key.\" });\n return;\n }\n\n if (provider === \"other\" && !baseUrl) {\n channel.sendSettingsResult(userId, { section: \"llm\", success: false, error: \"Please enter the API base URL.\" });\n return;\n }\n\n if (!provider) {\n provider = detectProviderFromKey(apiKey) ?? \"\";\n }\n if (!provider) {\n channel.sendSettingsResult(userId, { section: \"llm\", success: false, error: \"Cannot detect provider. Please select one.\" });\n return;\n }\n\n session.llmProvider = provider;\n session.llmApiKey = apiKey;\n session.llmBaseUrl = baseUrl;\n session.llmModel = model || getDefaultModel(provider);\n\n if (this.isDsersConnected(session)) {\n session.state = \"ready\";\n }\n saveSession(userId, session);\n\n this.agents.delete(userId);\n\n channel.sendSettingsResult(userId, { section: \"llm\", success: true });\n this.pushSettingsState(channel, userId, session);\n\n if (session.state === \"ready\") {\n await this.sendReadyMessage(channel, userId);\n }\n break;\n }\n }\n }\n\n private async sendReadyMessage(channel: ChannelAdapter, userId: string): Promise<void> {\n const session = loadSession(userId);\n if (channel instanceof WebChatServer) {\n channel.sendToast(userId, t(\"gateway.ready.toast\", session.language), \"info\", \"sys-ready\");\n } else {\n await channel.send(userId, { text: t(\"gateway.ready.telegram\", session.language) });\n }\n\n writeAuditLog({\n userId,\n agentId: \"gateway\",\n action: \"onboarding_complete\",\n target: \"user-session\",\n result: \"success\",\n });\n }\n\n // ─── Onboarding State Machine ─────────────────────────────────────\n\n private async handleOnboarding(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n session: UserSessionData,\n ): Promise<void> {\n const userId = message.userId;\n const text = message.text.trim();\n const isCallback = message.metadata[\"isCallback\"] === true;\n const isWeb = channel instanceof WebChatServer;\n\n switch (session.state) {\n case \"new\":\n case \"onboard_demo\":\n await this.onboardWelcome(channel, userId, session);\n break;\n\n case \"onboard_dsers_email\":\n await this.onboardEmail(channel, userId, text, session);\n break;\n\n case \"onboard_dsers_password\":\n await this.onboardPassword(channel, message, session, isWeb);\n break;\n\n case \"onboard_llm\":\n await this.onboardLLM(channel, message, session, isCallback, isWeb);\n break;\n }\n }\n\n private async onboardWelcome(\n channel: ChannelAdapter,\n userId: string,\n session: UserSessionData,\n ): Promise<void> {\n const isWeb = channel instanceof WebChatServer;\n\n const welcome = t(isWeb ? \"gateway.welcome.web\" : \"gateway.welcome.telegram\", session.language);\n\n await channel.send(userId, { text: welcome });\n\n session.state = isWeb ? \"ready\" : \"onboard_dsers_email\";\n saveSession(userId, session);\n }\n\n private async onboardEmail(\n channel: ChannelAdapter,\n userId: string,\n text: string,\n session: UserSessionData,\n ): Promise<void> {\n if (!text.includes(\"@\") || !text.includes(\".\")) {\n await channel.send(userId, {\n text: t(\"gateway.onboard.invalidEmail\", session.language),\n });\n return;\n }\n\n session.dspiEmail = text;\n session.state = \"onboard_dsers_password\";\n saveSession(userId, session);\n\n if (channel instanceof WebChatServer) {\n channel.sendSetInputType(userId, \"password\");\n }\n\n await channel.send(userId, {\n text: t(\"gateway.onboard.passwordPrompt\", session.language) +\n (channel instanceof WebChatServer ? \"\" : t(\"gateway.onboard.passwordPromptNote\", session.language)),\n });\n }\n\n private async onboardPassword(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n session: UserSessionData,\n isWeb: boolean,\n ): Promise<void> {\n const userId = message.userId;\n const password = message.text.trim();\n\n if (isWeb) {\n (channel as WebChatServer).sendClearInput(userId);\n (channel as WebChatServer).sendSetInputType(userId, \"text\");\n } else {\n await channel.deleteMessage(\n message.metadata[\"chatId\"] as string | number,\n message.metadata[\"messageId\"] as number,\n );\n }\n\n if (password.length < 1) {\n await channel.send(userId, { text: t(\"gateway.onboard.emptyPassword\", session.language) });\n if (isWeb) (channel as WebChatServer).sendSetInputType(userId, \"password\");\n return;\n }\n\n session.dspiPassword = password;\n saveSession(userId, session);\n\n await channel.send(userId, { text: t(\"gateway.onboard.verifying\", session.language) });\n\n try {\n const dsersConfig = createDSersConfig(session.dspiEmail!, password);\n const client = new DSersClient(dsersConfig);\n await client.get(\"/account-user-bff/v1/users/info\");\n\n this.dsersClients.set(userId, client);\n\n session.state = \"onboard_llm\";\n session.dspiPassword = undefined;\n saveSession(userId, session);\n\n await channel.send(userId, {\n card: {\n title: \"DSers Connected!\",\n summary:\n \"Your DSers account is verified.\\n\\n\" +\n \"*Step 3/3:* Choose your AI provider and paste your API key.\\n\" +\n \"You only need a key — DSClaw handles everything else.\\n\\n\" +\n \"Get a free key here:\\n\" +\n \"- **OpenAI**: [platform.openai.com/api-keys](https://platform.openai.com/api-keys)\\n\" +\n \"- **Anthropic**: [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys)\\n\" +\n \"- **Google** (recommended, free tier): [aistudio.google.com/apikey](https://aistudio.google.com/apikey)\",\n actions: [\n { label: \"OpenAI (GPT-4o)\", callbackData: \"llm:openai\" },\n { label: \"Anthropic (Claude)\", callbackData: \"llm:anthropic\" },\n { label: \"Google (Gemini) ★\", callbackData: \"llm:google\" },\n ],\n },\n });\n } catch (error) {\n session.dspiPassword = undefined;\n session.state = \"onboard_dsers_password\";\n saveSession(userId, session);\n\n if (isWeb) (channel as WebChatServer).sendSetInputType(userId, \"password\");\n\n const msg =\n error instanceof Error && error.message.includes(\"401\")\n ? t(\"gateway.onboard.loginFailed\", session.language)\n : t(\"gateway.onboard.loginFailedGeneric\", session.language, { error: error instanceof Error ? error.message : \"unknown error\" });\n\n await channel.send(userId, { text: msg });\n }\n }\n\n private async onboardLLM(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n session: UserSessionData,\n isCallback: boolean,\n isWeb: boolean,\n ): Promise<void> {\n const userId = message.userId;\n const text = message.text.trim();\n\n if (isCallback && text.startsWith(\"llm:\")) {\n const provider = text.replace(\"llm:\", \"\");\n session.llmProvider = provider;\n saveSession(userId, session);\n\n const providerName =\n provider === \"openai\" ? \"OpenAI\" :\n provider === \"anthropic\" ? \"Anthropic\" : \"Google\";\n\n if (isWeb) (channel as WebChatServer).sendSetInputType(userId, \"password\");\n\n await channel.send(userId, {\n text: t(\"gateway.onboard.chooseProvider\", session.language, { provider: providerName }) +\n (isWeb ? \"\" : \"\\n_I will delete your message immediately._\"),\n });\n return;\n }\n\n if (!session.llmProvider) {\n const detected = detectProviderFromKey(text);\n if (detected && text.length >= 10) {\n session.llmProvider = detected;\n saveSession(userId, session);\n } else {\n await channel.send(userId, {\n card: {\n title: \"Choose AI Provider\",\n summary:\n \"Please select your AI provider first, or paste your API key directly — I'll auto-detect.\\n\\n\" +\n \"Get a free key:\\n\" +\n \"- **OpenAI**: [platform.openai.com/api-keys](https://platform.openai.com/api-keys)\\n\" +\n \"- **Anthropic**: [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys)\\n\" +\n \"- **Google** (recommended): [aistudio.google.com/apikey](https://aistudio.google.com/apikey)\",\n actions: [\n { label: \"OpenAI (GPT-4o)\", callbackData: \"llm:openai\" },\n { label: \"Anthropic (Claude)\", callbackData: \"llm:anthropic\" },\n { label: \"Google (Gemini) ★\", callbackData: \"llm:google\" },\n ],\n },\n });\n return;\n }\n }\n\n if (isWeb) {\n (channel as WebChatServer).sendClearInput(userId);\n (channel as WebChatServer).sendSetInputType(userId, \"text\");\n } else {\n await channel.deleteMessage(\n message.metadata[\"chatId\"] as string | number,\n message.metadata[\"messageId\"] as number,\n );\n }\n\n if (text.length < 10) {\n await channel.send(userId, { text: t(\"gateway.onboard.invalidApiKey\", session.language) });\n if (isWeb) (channel as WebChatServer).sendSetInputType(userId, \"password\");\n return;\n }\n\n session.llmApiKey = text;\n session.llmModel = getDefaultModel(session.llmProvider);\n session.state = \"ready\";\n saveSession(userId, session);\n\n await channel.send(userId, {\n text: t(\"gateway.ready.telegram\", session.language),\n });\n\n writeAuditLog({\n userId,\n agentId: \"gateway\",\n action: \"onboarding_complete\",\n target: \"user-session\",\n result: \"success\",\n });\n }\n\n // ─── Ready State: Route to AI Agent ───────────────────────────────\n\n private async handleReady(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n session: UserSessionData,\n ): Promise<void> {\n const userId = message.userId;\n\n const cmd = message.text.trim().toLowerCase();\n\n if (cmd === \"/reset\") {\n this.agents.delete(userId);\n this.lastUserMessages.delete(userId);\n for (const key of sessionHistories.keys()) {\n if (key.endsWith(`:${userId}`)) sessionHistories.delete(key);\n }\n clearHistory(userId);\n\n const preserved: UserSessionData = {\n state: \"ready\",\n dspiEmail: session.dspiEmail,\n dspiSessionId: session.dspiSessionId,\n dspiSessionState: session.dspiSessionState,\n llmProvider: session.llmProvider,\n llmApiKey: session.llmApiKey,\n llmModel: session.llmModel,\n llmBaseUrl: session.llmBaseUrl,\n language: session.language,\n };\n saveSession(userId, preserved);\n\n if (channel instanceof WebChatServer) {\n channel.sendReset(userId);\n this.pushSettingsState(channel, userId, preserved);\n channel.sendToast(userId, t(\"gateway.cmd.reset\", session.language), \"info\", \"sys-reset\");\n } else {\n await channel.send(userId, { text: t(\"gateway.cmd.reset\", session.language) });\n }\n return;\n }\n\n if (cmd === \"/logout\") {\n this.agents.delete(userId);\n this.jobStores.delete(userId);\n this.dsersClients.delete(userId);\n this.lastUserMessages.delete(userId);\n for (const key of sessionHistories.keys()) {\n if (key.endsWith(`:${userId}`)) sessionHistories.delete(key);\n }\n clearHistory(userId);\n saveSession(userId, { state: \"new\" });\n if (channel instanceof WebChatServer) {\n channel.sendReset(userId);\n this.pushSettingsState(channel, userId, { state: \"new\" });\n channel.sendToast(userId, t(\"gateway.cmd.logout\", session.language), \"info\", \"sys-logout\");\n } else {\n await channel.send(userId, { text: t(\"gateway.cmd.logout\", session.language) });\n }\n return;\n }\n\n if (cmd === \"/retry\") {\n const lastMsg = this.lastUserMessages.get(userId);\n if (!lastMsg) {\n if (channel instanceof WebChatServer) {\n channel.sendToast(userId, t(\"gateway.cmd.retryEmpty\", session.language), \"warn\", \"sys-retry-empty\");\n } else {\n await channel.send(userId, { text: t(\"gateway.cmd.retryEmpty\", session.language) });\n }\n return;\n }\n log.info({ userId, retryText: lastMsg.slice(0, 80) }, \"Retrying last message\");\n message = { ...message, text: lastMsg };\n } else {\n this.lastUserMessages.set(userId, message.text);\n }\n\n if (!session.llmApiKey) {\n if (channel instanceof WebChatServer) {\n channel.sendToast(userId, t(\"gateway.noApiKey.web\", session.language), \"warn\", \"sys-no-apikey\");\n } else {\n await channel.send(userId, { text: t(\"gateway.noApiKey.telegram\", session.language) });\n }\n return;\n }\n\n const agent = this.getOrCreateAgent(userId, session);\n const sessionKey = `${channel.name}:${userId}`;\n touchSession(sessionKey);\n const history = sessionHistories.get(sessionKey) ?? [];\n\n // Token-aware budget allocation with message-count fallback\n const budget = allocateBudget(\"\", \"\", history, {});\n const budgetedHistory: AgentMessage[] = (\n budget.fallbackMode ? history.slice(-MAX_HISTORY) : budget.messages\n ) as AgentMessage[];\n\n if (budget.shouldCompact && !budget.fallbackMode) {\n log.info(\n { sessionKey, totalTokens: budget.totalTokens, remaining: budget.remainingTokens },\n \"Context nearing limit — consider compaction\",\n );\n }\n\n const context: AgentContext = {\n userId,\n sessionId: sessionKey,\n channelId: channel.name,\n history: budgetedHistory,\n };\n\n writeAuditLog({\n userId,\n agentId: agent.id,\n action: \"receive_message\",\n target: channel.name,\n params: { text: message.text.slice(0, 100) },\n result: \"success\",\n });\n\n try {\n if (channel instanceof WebChatServer) {\n await this.handleReadyStreaming(channel, userId, message.text, agent, context, history, sessionKey, session, message.attachments);\n } else {\n await this.handleReadyBatch(channel, userId, message.text, agent, context, history, sessionKey);\n }\n } catch (error) {\n log.error({ error, userId }, \"Agent processing failed\");\n\n writeAuditLog({\n userId,\n agentId: agent.id,\n action: \"process_failed\",\n target: channel.name,\n result: \"failed\",\n error: error instanceof Error ? error.message : String(error),\n });\n\n if (channel instanceof WebChatServer) {\n channel.sendTyping(userId, false);\n channel.sendStatus(userId, \"\");\n channel.sendLog(userId, {\n level: \"error\", module: \"gateway\",\n msg: `Error: ${error instanceof Error ? error.message : String(error)}`,\n ts: new Date().toISOString(),\n });\n }\n\n const errMsg = error instanceof Error ? error.message : \"\";\n if (errMsg.includes(\"timed out\")) {\n const stage = errMsg.includes(\"LLM init\") ? t(\"gateway.stage.llmConnection\", session.language)\n : errMsg.includes(\"LLM response\") ? t(\"gateway.stage.llmResponse\", session.language)\n : errMsg.includes(\"Rule reapply\") ? t(\"gateway.stage.rulesApply\", session.language)\n : errMsg.includes(\"Product import\") ? t(\"gateway.stage.productImport\", session.language)\n : t(\"gateway.stage.processing\", session.language);\n await channel.send(userId, {\n text: t(\"gateway.stream.stageTimeout\", session.language, { stage }),\n });\n } else if (errMsg.includes(\"401\") || errMsg.includes(\"API key\")) {\n await channel.send(userId, {\n text: t(\"gateway.stream.badApiKey\", session.language),\n });\n } else {\n await channel.send(userId, {\n text: t(\"gateway.stream.processFailed\", session.language),\n });\n }\n }\n }\n\n private async handleReadyStreaming(\n channel: WebChatServer,\n userId: string,\n text: string,\n agent: DSClawCoreAgent,\n context: Parameters<DSClawCoreAgent[\"process\"]>[1],\n history: AgentMessage[],\n sessionKey: string,\n session: UserSessionData,\n attachments?: import(\"../channels/adapter.js\").Attachment[],\n ): Promise<void> {\n channel.sendTyping(userId, true);\n channel.sendStatus(userId, \"Thinking...\");\n\n const ts = () => new Date().toISOString();\n channel.sendLog(userId, { level: \"info\", module: \"gateway\", msg: `Processing: \"${text.slice(0, 80)}\"`, ts: ts() });\n\n const imageAttachments = attachments\n ?.filter((a) => a.type === \"image\")\n .map((a) => ({ url: a.url ?? \"\", data: a.data, mimeType: a.mimeType ?? \"image/png\" }));\n\n const runningTools = new Map<string, { name: string; startedAt: number }>();\n let resolveToolsSettled: (() => void) | null = null;\n const toolsSettled = new Promise<void>((r) => { resolveToolsSettled = r; });\n\n const { textStream, response } = agent.processStream(\n text,\n context,\n (status) => { channel.sendStatus(userId, status); },\n {\n onToolCall: (id, name, args) => {\n runningTools.set(id, { name, startedAt: Date.now() });\n channel.sendToolCallStart(userId, id, name, args);\n channel.sendLog(userId, { level: \"info\", module: \"agent\", msg: `Tool call: ${name}`, ts: ts() });\n },\n onToolResult: (id, name, result, error, durationMs) => {\n runningTools.delete(id);\n channel.sendToolCallEnd(userId, id, name, result, error, durationMs);\n channel.sendLog(userId, {\n level: error ? \"error\" : \"info\",\n module: \"agent\",\n msg: `Tool ${name} ${error ? \"failed\" : \"done\"} (${durationMs}ms)`,\n ts: ts(),\n });\n if (runningTools.size === 0 && resolveToolsSettled) resolveToolsSettled();\n },\n },\n imageAttachments?.length ? imageAttachments : undefined,\n );\n\n let streamStarted = false;\n try {\n for await (const chunk of textStream) {\n if (!streamStarted) {\n channel.sendTyping(userId, false);\n channel.sendStatus(userId, \"\");\n channel.sendStreamStart(userId);\n streamStarted = true;\n }\n channel.sendStreamDelta(userId, chunk);\n }\n } catch (streamErr) {\n log.error({ error: streamErr, userId }, \"Stream iteration failed\");\n if (streamStarted) {\n const errMsg = streamErr instanceof Error ? streamErr.message : \"Unknown error\";\n channel.sendStreamDelta(userId, `\\n\\n⚠️ ${errMsg}`);\n } else {\n response.catch(() => {});\n throw streamErr;\n }\n } finally {\n if (runningTools.size > 0) {\n try {\n await Promise.race([toolsSettled, new Promise((r) => setTimeout(r, 15_000))]);\n } catch { /* grace period expired */ }\n }\n\n for (const [id, info] of runningTools) {\n const elapsed = Date.now() - info.startedAt;\n channel.sendToolCallEnd(userId, id, info.name, undefined, \"Aborted (stream terminated)\", elapsed);\n }\n runningTools.clear();\n\n if (!streamStarted) {\n channel.sendTyping(userId, false);\n channel.sendStatus(userId, \"\");\n }\n channel.sendStreamEnd(userId);\n }\n log.info({ userId, streamStarted }, \"Stream loop finished, awaiting response finalization\");\n\n let result;\n try {\n result = await Promise.race([\n response,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"Response finalization timed out\")), 60_000),\n ),\n ]);\n } catch (finalErr) {\n log.warn({ error: finalErr, userId }, \"Response finalization failed — saving partial history\");\n history.push({ role: \"user\", content: text });\n history.push({ role: \"assistant\", content: \"(response incomplete)\" });\n sessionHistories.set(sessionKey, history.slice(-MAX_HISTORY * 2));\n\n if (!streamStarted && channel instanceof WebChatServer) {\n await channel.send(userId, { text: t(\"gateway.stream.incomplete\", session.language) });\n }\n return;\n }\n\n const textLen = result.text?.length ?? 0;\n const toolCallCount = result.toolCalls?.length ?? 0;\n log.info({ userId, textLen, toolCallCount }, \"Response finalized\");\n\n if (!streamStarted && channel instanceof WebChatServer) {\n if (result.text) {\n await channel.send(userId, { text: result.text });\n } else if (toolCallCount > 0) {\n const names = result.toolCalls!.map((tc) => tc.tool).join(\", \");\n await channel.send(userId, {\n text: t(\"gateway.stream.toolsNoText\", session.language, { count: toolCallCount, names }),\n });\n } else {\n await channel.send(userId, { text: t(\"gateway.stream.noReply\", session.language) });\n }\n }\n\n history.push({ role: \"user\", content: text });\n history.push({ role: \"assistant\", content: result.text || \"(tool calls completed)\" });\n\n // Token-aware compaction with memory flush\n const postBudget = allocateBudget(\"\", \"\", history, {});\n if (postBudget.shouldCompact && !postBudget.fallbackMode) {\n const compacted = await compactWithFlush(\n history,\n MAX_HISTORY * 2,\n this.memory,\n userId,\n );\n sessionHistories.set(sessionKey, compacted.messages as AgentMessage[]);\n } else {\n sessionHistories.set(sessionKey, history.slice(-MAX_HISTORY * 2));\n }\n\n // Persist to disk\n appendHistory(\n sessionKey,\n { role: \"user\", content: text },\n { role: \"assistant\", content: result.text },\n );\n\n writeAuditLog({\n userId,\n agentId: agent.id,\n action: \"send_response\",\n target: \"web\",\n params: {\n responseLen: result.text.length,\n toolCalls: result.toolCalls?.length ?? 0,\n streaming: true,\n },\n result: \"success\",\n });\n }\n\n private async handleReadyBatch(\n channel: ChannelAdapter,\n userId: string,\n text: string,\n agent: DSClawCoreAgent,\n context: Parameters<DSClawCoreAgent[\"process\"]>[1],\n history: AgentMessage[],\n sessionKey: string,\n ): Promise<void> {\n const result = await agent.process(text, context);\n\n history.push({ role: \"user\", content: text });\n history.push({ role: \"assistant\", content: result.text });\n\n const postBudget = allocateBudget(\"\", \"\", history, {});\n if (postBudget.shouldCompact && !postBudget.fallbackMode) {\n const compacted = await compactWithFlush(\n history,\n MAX_HISTORY * 2,\n this.memory,\n userId,\n );\n sessionHistories.set(sessionKey, compacted.messages as AgentMessage[]);\n } else {\n sessionHistories.set(sessionKey, history.slice(-MAX_HISTORY * 2));\n }\n\n appendHistory(\n sessionKey,\n { role: \"user\", content: text },\n { role: \"assistant\", content: result.text },\n );\n\n if (result.text) {\n await channel.send(userId, { text: result.text });\n }\n\n writeAuditLog({\n userId,\n agentId: agent.id,\n action: \"send_response\",\n target: channel.name,\n params: {\n responseLen: result.text.length,\n toolCalls: result.toolCalls?.length ?? 0,\n },\n result: \"success\",\n });\n }\n\n private getOrCreateAgent(userId: string, session: UserSessionData): DSClawCoreAgent {\n let agent = this.agents.get(userId);\n if (agent) return agent;\n\n const dsersConfig = createDSersConfig(session.dspiEmail ?? \"unknown\");\n if (session.dspiSessionId) {\n dsersConfig.sessionId = session.dspiSessionId;\n dsersConfig.sessionState = session.dspiSessionState ?? \"\";\n }\n const dsersClient = new DSersClient(dsersConfig);\n this.dsersClients.set(userId, dsersClient);\n\n const llm: LLMConfig = {\n provider: session.llmProvider!,\n apiKey: session.llmApiKey!,\n model: session.llmModel ?? getDefaultModel(session.llmProvider!),\n baseUrl: session.llmBaseUrl,\n };\n\n const dsersSession = session.dspiSessionId\n ? { sessionId: session.dspiSessionId, state: session.dspiSessionState ?? \"\" }\n : undefined;\n const authCb = () => this.triggerAuth(userId);\n let jobStore = this.jobStores.get(userId);\n if (!jobStore) {\n jobStore = new MemoryJobStore();\n this.jobStores.set(userId, jobStore);\n }\n agent = new DSClawCoreAgent(dsersClient, this.memory, llm, dsersSession, authCb, jobStore);\n this.agents.set(userId, agent);\n\n if (!agent.mcpAvailable) {\n log.warn({ userId }, \"MCP unavailable for agent — notifying user\");\n for (const ch of this.channels) {\n ch.send(userId, {\n text: t(\"gateway.mcp.unavailable\", session.language),\n }).catch(() => {});\n }\n }\n\n return agent;\n }\n\n async stop(): Promise<void> {\n log.info(\"Stopping DSClaw Gateway...\");\n for (const ch of this.channels) {\n await ch.disconnect();\n }\n this.running = false;\n log.info(\"DSClaw Gateway stopped\");\n }\n\n isRunning(): boolean {\n return this.running;\n }\n\n get actualPort(): number {\n return this.webChannel?.actualPort ?? this.config.port;\n }\n}\n","/**\n * Web Chat Server — HTTP + WebSocket.\n * Serves React SPA (build output) and handles real-time messaging via WebSocket.\n * Implements ChannelAdapter for gateway integration.\n * Supports streaming, tool call events, logs, and init progress.\n */\n\nimport { createServer, type Server } from \"node:http\";\nimport { readFileSync, writeFileSync, mkdirSync, existsSync, statSync, readdirSync } from \"node:fs\";\nimport { join, dirname, extname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { homedir } from \"node:os\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport { nanoid } from \"nanoid\";\nimport type {\n ChannelAdapter,\n MessageHandler,\n NormalizedMessage,\n OutboundMessage,\n ActionCard,\n} from \"../channels/adapter.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"channel:web\");\n\nconst DEFAULT_WEB_USER = \"web-default\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"application/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff2\": \"font/woff2\",\n \".woff\": \"font/woff\",\n};\n\nfunction findWebDir(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n const candidates = [\n join(thisDir, \"web\"),\n join(thisDir),\n join(thisDir, \"..\", \"web\"),\n join(thisDir, \"..\", \"dist\", \"web\"),\n join(thisDir, \"..\", \"..\", \"dist\", \"web\"),\n ];\n\n for (const d of candidates) {\n if (existsSync(join(d, \"index.html\"))) return d;\n }\n\n throw new Error(\n `Web build not found (index.html). Looked in:\\n` + candidates.join(\"\\n\"),\n );\n}\n\ntype ConnectHandler = (userId: string) => void;\ntype SettingsHandler = (userId: string, action: string, data: Record<string, unknown>) => Promise<void>;\n\nexport interface SettingsState {\n dsers: { configured: boolean; email?: string };\n llm: { configured: boolean; provider?: string; baseUrl?: string };\n ready: boolean;\n}\n\nexport class WebChatServer implements ChannelAdapter {\n readonly name = \"web\";\n private server: Server | null = null;\n private wss: WebSocketServer | null = null;\n private handler: MessageHandler | null = null;\n private connectHandler: ConnectHandler | null = null;\n private settingsHandler: SettingsHandler | null = null;\n private connections = new Map<string, WebSocket>();\n private _connected = false;\n private port = 3000;\n\n get connected(): boolean {\n return this._connected;\n }\n\n get actualPort(): number {\n return this.port;\n }\n\n async connect(config: Record<string, unknown>): Promise<void> {\n const basePort = (config[\"port\"] as number) ?? 3000;\n const webDir = findWebDir();\n const maxAttempts = 10;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const tryPort = basePort + attempt;\n const ok = await this.tryListen(tryPort, webDir);\n if (ok) return;\n if (attempt < maxAttempts - 1) {\n log.warn({ port: tryPort }, \"Port in use, trying next\");\n }\n }\n throw new Error(`No available port found (tried ${basePort}-${basePort + maxAttempts - 1})`);\n }\n\n private tryListen(tryPort: number, webDir: string): Promise<boolean> {\n return new Promise((resolve) => {\n const indexHtml = readFileSync(join(webDir, \"index.html\"), \"utf-8\");\n\n const srv = createServer((req, res) => {\n if (req.url === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, clients: this.connections.size }));\n return;\n }\n\n // Serve uploaded images\n const urlPath = req.url?.split(\"?\")[0] ?? \"/\";\n if (urlPath.startsWith(\"/uploads/\")) {\n const uploadsDir = join(homedir(), \".dsclaw\", \"uploads\");\n const fileName = urlPath.slice(\"/uploads/\".length);\n if (/^[a-zA-Z0-9._-]+$/.test(fileName)) {\n const filePath = join(uploadsDir, fileName);\n if (existsSync(filePath) && statSync(filePath).isFile()) {\n const ext = extname(filePath);\n const mime = MIME_TYPES[ext] ?? \"application/octet-stream\";\n res.writeHead(200, { \"Content-Type\": mime, \"Cache-Control\": \"public, max-age=86400\" });\n res.end(readFileSync(filePath));\n return;\n }\n }\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n // Serve static assets\n if (urlPath !== \"/\" && urlPath !== \"/index.html\") {\n const filePath = join(webDir, urlPath);\n if (existsSync(filePath) && statSync(filePath).isFile()) {\n const ext = extname(filePath);\n const contentType = MIME_TYPES[ext] ?? \"application/octet-stream\";\n const cacheHeader = urlPath.includes(\"/assets/\") ? \"public, max-age=31536000, immutable\" : \"no-cache\";\n res.writeHead(200, { \"Content-Type\": contentType, \"Cache-Control\": cacheHeader });\n res.end(readFileSync(filePath));\n return;\n }\n }\n\n // SPA fallback — always return index.html\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\", \"Cache-Control\": \"no-cache\" });\n res.end(indexHtml);\n });\n\n srv.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n } else {\n throw err;\n }\n });\n\n srv.listen(tryPort, () => {\n this.server = srv;\n this.port = tryPort;\n this._connected = true;\n this.setupWebSocket();\n log.info({ port: tryPort }, \"Web chat server started\");\n resolve(true);\n });\n });\n }\n\n private setupWebSocket(): void {\n this.wss = new WebSocketServer({ server: this.server!, path: \"/ws\" });\n\n this.wss.on(\"connection\", (ws, _req) => {\n let clientId = DEFAULT_WEB_USER;\n\n this.wsSend(ws, { type: \"session\", userId: clientId });\n this.connections.set(clientId, ws);\n log.info({ userId: clientId }, \"Web client connected\");\n\n if (this.connectHandler) {\n try { this.connectHandler(clientId); } catch (err) {\n log.error({ error: err, userId: clientId }, \"Connect handler failed\");\n }\n }\n\n try {\n const files = this.buildFileTree();\n this.wsSend(ws, { type: \"file_list\", files });\n } catch (err) {\n log.warn({ error: err }, \"Failed to push initial file_list\");\n }\n\n ws.on(\"message\", async (raw) => {\n try {\n const msg = JSON.parse(raw.toString()) as Record<string, unknown>;\n this.connections.set(clientId, ws);\n\n const msgType = msg[\"type\"] as string;\n\n if (msgType === \"get_settings\" || msgType === \"start_dsers_auth\" || msgType === \"cancel_dsers_auth\" || msgType === \"save_dsers_session\" || msgType === \"save_llm\" || msgType === \"disconnect_dsers\" || msgType === \"set_language\") {\n log.info({ userId: clientId, action: msgType }, \"Settings message received\");\n if (this.settingsHandler) {\n await this.settingsHandler(clientId, msgType, msg);\n }\n return;\n }\n\n if (msgType === \"list_files\") {\n const files = this.buildFileTree();\n this.wsSend(ws, { type: \"file_list\", files });\n return;\n }\n\n if (msgType === \"read_file\") {\n const filePath = msg[\"path\"] as string;\n this.handleReadFile(ws, filePath);\n return;\n }\n\n if (!this.handler) return;\n\n if (msgType === \"message\" || msgType === \"callback\") {\n const rawAttachments = msg[\"attachments\"] as Array<{ data: string; mimeType: string; name: string }> | undefined;\n const attachments = rawAttachments?.length\n ? this.saveAttachments(rawAttachments)\n : undefined;\n\n const normalized: NormalizedMessage = {\n traceId: nanoid(),\n channelId: \"web\",\n channelName: \"Web Chat\",\n userId: clientId,\n text: msgType === \"callback\"\n ? (msg[\"data\"] as string)\n : (msg[\"text\"] as string),\n attachments,\n timestamp: new Date(),\n metadata: {\n isCallback: msgType === \"callback\",\n },\n };\n await this.handler(normalized);\n }\n } catch (error) {\n log.error({ error }, \"WS message handler failed\");\n }\n });\n\n ws.on(\"close\", () => {\n this.connections.delete(clientId);\n log.debug({ userId: clientId }, \"Web client disconnected\");\n });\n\n ws.on(\"error\", (err) => {\n log.warn({ error: err.message, userId: clientId }, \"WS error\");\n });\n });\n }\n\n async disconnect(): Promise<void> {\n for (const ws of this.connections.values()) {\n ws.close();\n }\n this.connections.clear();\n this.wss?.close();\n await new Promise<void>((resolve) => {\n if (this.server) this.server.close(() => resolve());\n else resolve();\n });\n this._connected = false;\n log.info(\"Web chat server stopped\");\n }\n\n async reconnect(): Promise<void> {\n await this.disconnect();\n await this.connect({ port: this.port });\n }\n\n onMessage(handler: MessageHandler): void {\n this.handler = handler;\n }\n\n onConnect(handler: ConnectHandler): void {\n this.connectHandler = handler;\n }\n\n onSettings(handler: SettingsHandler): void {\n this.settingsHandler = handler;\n }\n\n async send(targetUserId: string, message: OutboundMessage): Promise<void> {\n if (message.card) {\n await this.sendCard(targetUserId, message.card);\n return;\n }\n if (message.text) {\n this.wsSendTo(targetUserId, { type: \"message\", text: message.text });\n }\n }\n\n sendToast(targetUserId: string, text: string, level: \"info\" | \"warn\" | \"error\" = \"info\", id?: string): void {\n this.wsSendTo(targetUserId, { type: \"toast\", text, level, ...(id && { id }) });\n }\n\n async sendCard(targetUserId: string, card: ActionCard): Promise<void> {\n this.wsSendTo(targetUserId, {\n type: \"card\",\n title: card.title,\n summary: card.summary,\n actions: card.actions,\n });\n }\n\n async deleteMessage(): Promise<void> {\n // Web doesn't delete messages; use sendClearInput instead\n }\n\n // ─── Streaming Methods ─────────────────────────────────────\n\n sendStreamStart(userId: string): void {\n this.wsSendTo(userId, { type: \"stream_start\" });\n }\n\n sendStreamDelta(userId: string, delta: string): void {\n this.wsSendTo(userId, { type: \"stream_delta\", delta });\n }\n\n sendStreamEnd(userId: string): void {\n this.wsSendTo(userId, { type: \"stream_end\" });\n }\n\n // ─── Web-Specific Methods ──────────────────────────────────\n\n sendTyping(userId: string, active: boolean): void {\n this.wsSendTo(userId, { type: \"typing\", active });\n }\n\n sendStatus(userId: string, status: string): void {\n this.wsSendTo(userId, { type: \"status\", status });\n }\n\n sendReset(userId: string): void {\n this.wsSendTo(userId, { type: \"reset\" });\n }\n\n sendClearInput(userId: string): void {\n this.wsSendTo(userId, { type: \"clear_input\" });\n }\n\n sendSetInputType(userId: string, inputType: \"text\" | \"password\"): void {\n this.wsSendTo(userId, { type: \"set_input_type\", inputType });\n }\n\n sendSettingsState(userId: string, state: SettingsState): void {\n this.wsSendTo(userId, { type: \"settings_state\", ...state });\n }\n\n sendSettingsResult(userId: string, result: { section: string; success: boolean; error?: string }): void {\n this.wsSendTo(userId, { type: \"settings_result\", ...result });\n }\n\n // ─── Tool Call Events ────────────────────────────────────────\n\n sendToolCallStart(userId: string, id: string, name: string, args: Record<string, unknown>): void {\n this.wsSendTo(userId, { type: \"tool_call_start\", id, name, args });\n }\n\n sendToolCallEnd(userId: string, id: string, name: string, result: unknown, error: string | undefined, durationMs: number): void {\n this.wsSendTo(userId, { type: \"tool_call_end\", id, name, result, error, durationMs });\n }\n\n // ─── Log & Init Progress ────────────────────────────────────\n\n sendLog(userId: string, entry: { level: string; module: string; msg: string; ts: string }): void {\n this.wsSendTo(userId, { type: \"log\", ...entry });\n }\n\n sendInitProgress(userId: string, step: { step: string; status: string; message: string; canRetry?: boolean }): void {\n this.wsSendTo(userId, { type: \"init_progress\", ...step });\n }\n\n // ─── Attachment Storage ────────────────────────────────────────\n\n private saveAttachments(\n rawAttachments: Array<{ data: string; mimeType: string; name: string }>,\n ): import(\"../channels/adapter.js\").Attachment[] {\n const uploadsDir = join(homedir(), \".dsclaw\", \"uploads\");\n mkdirSync(uploadsDir, { recursive: true });\n\n return rawAttachments.map((a) => {\n const ext = a.mimeType.split(\"/\")[1]?.replace(\"jpeg\", \"jpg\") ?? \"png\";\n const fileName = `${nanoid()}.${ext}`;\n const filePath = join(uploadsDir, fileName);\n const buffer = Buffer.from(a.data, \"base64\");\n writeFileSync(filePath, buffer);\n log.info({ fileName, size: buffer.length }, \"Saved attachment\");\n\n return {\n type: \"image\" as const,\n url: `/uploads/${fileName}`,\n data: buffer,\n mimeType: a.mimeType,\n fileName: a.name,\n };\n });\n }\n\n // ─── File Browsing ───────────────────────────────────────────\n\n private buildFileTree(): unknown[] {\n const configDir = join(homedir(), \".dsclaw\");\n if (!existsSync(configDir)) return [];\n\n const scanDir = (dirPath: string, depth = 0): unknown[] => {\n if (depth > 5) return [];\n try {\n const entries = readdirSync(dirPath, { withFileTypes: true });\n return entries\n .filter((e) => !e.name.startsWith(\".\"))\n .sort((a, b) => {\n if (a.isDirectory() && !b.isDirectory()) return -1;\n if (!a.isDirectory() && b.isDirectory()) return 1;\n return a.name.localeCompare(b.name);\n })\n .map((entry) => {\n const fullPath = join(dirPath, entry.name);\n if (entry.isDirectory()) {\n return {\n name: entry.name,\n path: fullPath,\n type: \"dir\",\n children: scanDir(fullPath, depth + 1),\n };\n }\n let size: number | undefined;\n try { size = statSync(fullPath).size; } catch { /* ignore */ }\n return { name: entry.name, path: fullPath, type: \"file\", size };\n });\n } catch {\n return [];\n }\n };\n\n return scanDir(configDir);\n }\n\n private static IMAGE_EXTS = new Set([\".png\", \".jpg\", \".jpeg\", \".gif\", \".webp\", \".svg\"]);\n private static IMAGE_MIME: Record<string, string> = {\n \".png\": \"image/png\", \".jpg\": \"image/jpeg\", \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\", \".webp\": \"image/webp\", \".svg\": \"image/svg+xml\",\n };\n\n private handleReadFile(ws: WebSocket, filePath: string): void {\n const configDir = join(homedir(), \".dsclaw\");\n if (!filePath.startsWith(configDir)) {\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: \"[访问被拒绝:只能读取 ~/.dsclaw/ 下的文件]\" });\n return;\n }\n try {\n if (!existsSync(filePath) || !statSync(filePath).isFile()) {\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: \"[文件不存在]\" });\n return;\n }\n const size = statSync(filePath).size;\n if (size > 2 * 1024 * 1024) {\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: `[文件过大:${(size / 1024).toFixed(0)}KB,最大 2MB]` });\n return;\n }\n\n const ext = extname(filePath).toLowerCase();\n if (WebChatServer.IMAGE_EXTS.has(ext)) {\n const buf = readFileSync(filePath);\n const mime = WebChatServer.IMAGE_MIME[ext] ?? \"application/octet-stream\";\n const dataUrl = `data:${mime};base64,${buf.toString(\"base64\")}`;\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: dataUrl, isImage: true });\n return;\n }\n\n const content = readFileSync(filePath, \"utf-8\");\n this.wsSend(ws, { type: \"file_content\", path: filePath, content });\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: `[读取失败:${reason}]` });\n }\n }\n\n // ─── Internal ──────────────────────────────────────────────\n\n private wsSendTo(userId: string, data: Record<string, unknown>): void {\n const ws = this.connections.get(userId);\n if (ws && ws.readyState === WebSocket.OPEN) {\n this.wsSend(ws, data);\n }\n }\n\n private wsSend(ws: WebSocket, data: Record<string, unknown>): void {\n try {\n ws.send(JSON.stringify(data));\n } catch (err) {\n log.warn({ error: err instanceof Error ? err.message : String(err) }, \"wsSend failed\");\n }\n }\n}\n","/**\n * Telegram channel adapter using grammY.\n * Normalizes messages, supports inline keyboards, auto-reconnects,\n * and can delete sensitive messages (passwords, API keys).\n */\n\nimport { Bot, type Context, InlineKeyboard } from \"grammy\";\nimport { nanoid } from \"nanoid\";\nimport type {\n ChannelAdapter,\n MessageHandler,\n NormalizedMessage,\n OutboundMessage,\n ActionCard,\n} from \"./adapter.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"channel:telegram\");\n\nexport class TelegramAdapter implements ChannelAdapter {\n readonly name = \"telegram\";\n private bot: Bot | null = null;\n private handler: MessageHandler | null = null;\n private _connected = false;\n private botToken = \"\";\n\n get connected(): boolean {\n return this._connected;\n }\n\n async connect(config: Record<string, unknown>): Promise<void> {\n this.botToken = config[\"botToken\"] as string;\n if (!this.botToken) throw new Error(\"Telegram botToken is required\");\n\n this.bot = new Bot(this.botToken);\n\n this.bot.on(\"message:text\", async (ctx) => {\n if (!this.handler) return;\n\n const normalized: NormalizedMessage = {\n traceId: nanoid(),\n channelId: \"telegram\",\n channelName: \"Telegram\",\n userId: String(ctx.from.id),\n userName:\n ctx.from.username ??\n [ctx.from.first_name, ctx.from.last_name].filter(Boolean).join(\" \"),\n text: ctx.message.text,\n timestamp: new Date(ctx.message.date * 1000),\n metadata: {\n chatId: ctx.chat.id,\n messageId: ctx.message.message_id,\n },\n };\n\n try {\n await this.handler(normalized);\n } catch (error) {\n log.error({ error, userId: normalized.userId }, \"Message handler error\");\n await ctx.reply(\"Sorry, something went wrong. Please try again.\");\n }\n });\n\n this.bot.on(\"callback_query:data\", async (ctx) => {\n if (!this.handler) return;\n await ctx.answerCallbackQuery();\n\n const normalized: NormalizedMessage = {\n traceId: nanoid(),\n channelId: \"telegram\",\n channelName: \"Telegram\",\n userId: String(ctx.from.id),\n userName: ctx.from.username ?? ctx.from.first_name,\n text: ctx.callbackQuery.data,\n timestamp: new Date(),\n metadata: {\n chatId: ctx.chat?.id,\n isCallback: true,\n },\n };\n\n try {\n await this.handler(normalized);\n } catch (error) {\n log.error({ error }, \"Callback handler error\");\n }\n });\n\n this.bot.catch((err) => {\n log.error({ error: err.message }, \"Bot error — reconnecting...\");\n this._connected = false;\n setTimeout(() => this.reconnect(), 5000);\n });\n\n await this.bot.init();\n log.info({ botName: this.bot.botInfo.username }, \"Telegram bot initialized\");\n\n this.bot.start({\n onStart: () => {\n this._connected = true;\n log.info(\"Telegram bot polling started\");\n },\n });\n }\n\n async disconnect(): Promise<void> {\n this.bot?.stop();\n this._connected = false;\n log.info(\"Telegram bot disconnected\");\n }\n\n async reconnect(): Promise<void> {\n log.info(\"Reconnecting Telegram bot...\");\n await this.disconnect();\n await this.connect({ botToken: this.botToken });\n }\n\n onMessage(handler: MessageHandler): void {\n this.handler = handler;\n }\n\n async send(targetUserId: string, message: OutboundMessage): Promise<void> {\n if (!this.bot) throw new Error(\"Bot not connected\");\n\n if (message.card) {\n await this.sendCard(targetUserId, message.card);\n return;\n }\n\n if (message.text) {\n await this.bot.api.sendMessage(targetUserId, message.text, {\n parse_mode: \"Markdown\",\n });\n }\n }\n\n async sendCard(targetUserId: string, card: ActionCard): Promise<void> {\n if (!this.bot) throw new Error(\"Bot not connected\");\n\n const keyboard = new InlineKeyboard();\n for (const action of card.actions) {\n keyboard.text(action.label, action.callbackData).row();\n }\n\n const text = `*${card.title}*\\n\\n${card.summary}`;\n\n await this.bot.api.sendMessage(targetUserId, text, {\n parse_mode: \"Markdown\",\n reply_markup: keyboard,\n });\n }\n\n async deleteMessage(chatId: string | number, messageId: number): Promise<void> {\n if (!this.bot) return;\n try {\n await this.bot.api.deleteMessage(chatId, messageId);\n } catch (error) {\n log.warn({ chatId, messageId, error }, \"Failed to delete message\");\n }\n }\n}\n","/**\n * Local JSON-based memory provider.\n * Stores memories as JSONL files, one per user.\n * Simple keyword-based search (no vector embeddings).\n * Replaced by mem0 in Plan C for production use.\n */\n\nimport {\n readFileSync,\n writeFileSync,\n appendFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport type { MemoryProvider, Memory, MemoryMeta, MemoryFilter } from \"./provider.js\";\nimport { CONFIG_DIR } from \"../gateway/config.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"memory:file\");\nconst MEMORY_DIR = join(CONFIG_DIR, \"memories\");\n\ninterface StoredMemory {\n id: string;\n content: string;\n metadata: MemoryMeta;\n createdAt: string;\n updatedAt: string;\n}\n\nexport class FileMemoryProvider implements MemoryProvider {\n readonly name = \"file\";\n readonly degraded = false;\n\n constructor() {\n if (!existsSync(MEMORY_DIR)) {\n mkdirSync(MEMORY_DIR, { recursive: true });\n }\n }\n\n async add(content: string, metadata: MemoryMeta): Promise<string> {\n const id = randomUUID();\n const now = new Date().toISOString();\n const entry: StoredMemory = {\n id,\n content,\n metadata,\n createdAt: now,\n updatedAt: now,\n };\n\n const file = this.userFile(metadata.userId);\n appendFileSync(file, JSON.stringify(entry) + \"\\n\");\n log.debug({ id, userId: metadata.userId }, \"Memory added\");\n return id;\n }\n\n async search(query: string, filters: MemoryFilter): Promise<Memory[]> {\n const all = await this.getAll(filters);\n const keywords = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((w) => w.length > 2);\n\n if (keywords.length === 0) {\n return all.slice(0, filters.limit ?? 10);\n }\n\n const scored = all\n .map((m) => {\n const text = m.content.toLowerCase();\n const matchCount = keywords.filter((k) => text.includes(k)).length;\n return { memory: m, score: matchCount / keywords.length };\n })\n .filter((s) => s.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, filters.limit ?? 10);\n\n return scored.map((s) => ({ ...s.memory, score: s.score }));\n }\n\n async getAll(filters: MemoryFilter): Promise<Memory[]> {\n const files = filters.userId\n ? [this.userFile(filters.userId)]\n : readdirSync(MEMORY_DIR)\n .filter((f) => f.endsWith(\".jsonl\"))\n .map((f) => join(MEMORY_DIR, f));\n\n const results: Memory[] = [];\n\n for (const file of files) {\n if (!existsSync(file)) continue;\n\n const lines = readFileSync(file, \"utf-8\")\n .split(\"\\n\")\n .filter((l) => l.trim());\n\n for (const line of lines) {\n try {\n const stored: StoredMemory = JSON.parse(line);\n\n if (filters.category && stored.metadata.category !== filters.category) continue;\n if (\n filters.sessionId &&\n stored.metadata.sessionId !== filters.sessionId\n ) continue;\n if (\n filters.tags &&\n filters.tags.length > 0 &&\n !filters.tags.some((t) => stored.metadata.tags?.includes(t))\n ) continue;\n\n results.push({\n id: stored.id,\n content: stored.content,\n metadata: stored.metadata,\n createdAt: new Date(stored.createdAt),\n updatedAt: new Date(stored.updatedAt),\n });\n } catch {\n // Skip malformed lines\n }\n }\n }\n\n return results.slice(0, filters.limit ?? 100);\n }\n\n async update(id: string, content: string): Promise<void> {\n const files = readdirSync(MEMORY_DIR)\n .filter((f) => f.endsWith(\".jsonl\"))\n .map((f) => join(MEMORY_DIR, f));\n\n for (const file of files) {\n if (!existsSync(file)) continue;\n const lines = readFileSync(file, \"utf-8\")\n .split(\"\\n\")\n .filter((l) => l.trim());\n\n const updated = lines.map((line) => {\n try {\n const stored: StoredMemory = JSON.parse(line);\n if (stored.id === id) {\n stored.content = content;\n stored.updatedAt = new Date().toISOString();\n }\n return JSON.stringify(stored);\n } catch {\n return line;\n }\n });\n\n writeFileSync(file, updated.join(\"\\n\") + \"\\n\");\n }\n }\n\n async delete(id: string): Promise<void> {\n const files = readdirSync(MEMORY_DIR)\n .filter((f) => f.endsWith(\".jsonl\"))\n .map((f) => join(MEMORY_DIR, f));\n\n for (const file of files) {\n if (!existsSync(file)) continue;\n const lines = readFileSync(file, \"utf-8\")\n .split(\"\\n\")\n .filter((l) => l.trim());\n\n const filtered = lines.filter((line) => {\n try {\n const stored: StoredMemory = JSON.parse(line);\n return stored.id !== id;\n } catch {\n return true;\n }\n });\n\n writeFileSync(file, filtered.join(\"\\n\") + (filtered.length > 0 ? \"\\n\" : \"\"));\n }\n }\n\n private userFile(userId: string): string {\n const safe = userId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return join(MEMORY_DIR, `${safe}.jsonl`);\n }\n}\n","/**\n * Degradation strategies for when external services are unavailable.\n * Each service has a defined fallback path.\n */\n\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"degradation\");\n\nexport type ServiceName = \"dsers\" | \"llm\" | \"mem0\";\n\nexport interface DegradationState {\n service: ServiceName;\n degraded: boolean;\n reason?: string;\n since?: Date;\n fallbackActive: boolean;\n}\n\nconst states = new Map<ServiceName, DegradationState>();\n\nexport function markDegraded(\n service: ServiceName,\n reason: string,\n): void {\n states.set(service, {\n service,\n degraded: true,\n reason,\n since: new Date(),\n fallbackActive: true,\n });\n log.warn({ service, reason }, \"Service marked as degraded\");\n}\n\nexport function markRecovered(service: ServiceName): void {\n const prev = states.get(service);\n if (prev?.degraded) {\n log.info(\n { service, degradedSince: prev.since },\n \"Service recovered\",\n );\n }\n states.set(service, {\n service,\n degraded: false,\n fallbackActive: false,\n });\n}\n\nexport function isDegraded(service: ServiceName): boolean {\n return states.get(service)?.degraded ?? false;\n}\n\nexport function getDegradationStatus(): DegradationState[] {\n return [...states.values()];\n}\n\n/**\n * Produce a user-friendly degradation message for channel output.\n */\nexport function degradationMessage(service: ServiceName): string {\n switch (service) {\n case \"dsers\":\n return \"DSers service is temporarily unavailable. Your request has been queued and will be processed when the service recovers.\";\n case \"llm\":\n return \"AI service is experiencing issues. Using simplified responses until it recovers.\";\n case \"mem0\":\n return \"Memory service is temporarily offline. I can still help but won't remember preferences from this conversation.\";\n }\n}\n","/**\n * Token counting with graceful fallback.\n * Uses gpt-tokenizer for accurate counts; falls back to char/4 estimation on failure.\n */\n\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"context:token\");\n\nlet encode: ((text: string) => number[]) | null = null;\nlet initAttempted = false;\n\nasync function ensureEncoder(): Promise<void> {\n if (initAttempted) return;\n initAttempted = true;\n try {\n const mod = await import(\"gpt-tokenizer\");\n encode = mod.encode;\n log.info(\"gpt-tokenizer loaded\");\n } catch {\n log.warn(\"gpt-tokenizer not available, using char/4 estimation\");\n }\n}\n\nexport function countTokens(text: string): number {\n try {\n if (encode) return encode(text).length;\n } catch {\n // fall through to estimation\n }\n return Math.ceil(text.length / 4);\n}\n\nexport function countMessagesTokens(\n messages: Array<{ role: string; content: string }>,\n): number {\n let total = 0;\n for (const m of messages) {\n total += countTokens(m.content) + 4; // ~4 tokens per message overhead (role, delimiters)\n }\n return total;\n}\n\nexport async function initTokenCounter(): Promise<void> {\n await ensureEncoder();\n}\n","/**\n * Context window budget allocation.\n * Splits available tokens across system prompt, memories, tool results, and conversation history.\n * Falls back to MAX_HISTORY=20 message-count cap if token counting fails.\n */\n\nimport { countTokens, countMessagesTokens } from \"./token-counter.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"context:budget\");\n\nconst FALLBACK_MAX_MESSAGES = 20;\n\nexport interface BudgetConfig {\n /** Total context window size in tokens (e.g. 128000 for GPT-4o) */\n contextWindow: number;\n /** Reserved for system prompt */\n systemPromptReserve: number;\n /** Max tokens for memories */\n memoriesMax: number;\n /** Max tokens for tool results within a single turn */\n toolResultsMax: number;\n /** Percentage at which to trigger compaction (0-1) */\n compactionThreshold: number;\n}\n\nconst DEFAULT_BUDGET: BudgetConfig = {\n contextWindow: 128_000,\n systemPromptReserve: 8_000,\n memoriesMax: 1_000,\n toolResultsMax: 6_000,\n compactionThreshold: 0.75,\n};\n\nexport interface BudgetAllocation {\n /** Messages to include (newest first, within budget) */\n messages: Array<{ role: string; content: string }>;\n /** Tokens used by included messages */\n historyTokens: number;\n /** Total tokens consumed (system + memories + history) */\n totalTokens: number;\n /** Budget remaining */\n remainingTokens: number;\n /** Whether compaction should be triggered */\n shouldCompact: boolean;\n /** Whether we fell back to message-count mode */\n fallbackMode: boolean;\n}\n\nexport function allocateBudget(\n systemPrompt: string,\n memories: string,\n history: Array<{ role: string; content: string }>,\n config: Partial<BudgetConfig> = {},\n): BudgetAllocation {\n const cfg = { ...DEFAULT_BUDGET, ...config };\n\n try {\n const systemTokens = systemPrompt ? countTokens(systemPrompt) : cfg.systemPromptReserve;\n const memoriesTokens = memories ? Math.min(countTokens(memories), cfg.memoriesMax) : 0;\n const historyBudget =\n cfg.contextWindow - systemTokens - memoriesTokens - cfg.toolResultsMax;\n\n if (historyBudget <= 0) {\n log.warn({ systemTokens, memoriesTokens }, \"No budget left for history\");\n return {\n messages: [],\n historyTokens: 0,\n totalTokens: systemTokens + memoriesTokens,\n remainingTokens: 0,\n shouldCompact: true,\n fallbackMode: false,\n };\n }\n\n const included: Array<{ role: string; content: string }> = [];\n let historyTokens = 0;\n\n for (let i = history.length - 1; i >= 0; i--) {\n const msgTokens = countTokens(history[i]!.content) + 4;\n if (historyTokens + msgTokens > historyBudget) break;\n included.unshift(history[i]!);\n historyTokens += msgTokens;\n }\n\n const totalTokens = systemTokens + memoriesTokens + historyTokens;\n const threshold = cfg.contextWindow * cfg.compactionThreshold;\n\n return {\n messages: included,\n historyTokens,\n totalTokens,\n remainingTokens: cfg.contextWindow - totalTokens,\n shouldCompact: totalTokens >= threshold,\n fallbackMode: false,\n };\n } catch (err) {\n log.warn({ err }, \"Budget allocation failed, using message-count fallback\");\n return {\n messages: history.slice(-FALLBACK_MAX_MESSAGES),\n historyTokens: 0,\n totalTokens: 0,\n remainingTokens: 0,\n shouldCompact: false,\n fallbackMode: true,\n };\n }\n}\n\nexport function createBudgetConfig(\n overrides?: Partial<BudgetConfig>,\n): BudgetConfig {\n return { ...DEFAULT_BUDGET, ...overrides };\n}\n","/**\n * Pre-compaction flush.\n * Before truncating conversation history, extracts key facts and writes them to memory.\n * Aligned with OpenClaw's \"pre-compaction memory flush\" pattern.\n */\n\nimport type { MemoryProvider } from \"../memory/provider.js\";\nimport { countMessagesTokens } from \"./token-counter.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"context:compact\");\n\nexport interface CompactionResult {\n /** Messages after compaction */\n messages: Array<{ role: string; content: string }>;\n /** Number of messages removed */\n removedCount: number;\n /** Facts extracted and saved to memory */\n factsExtracted: string[];\n}\n\n/**\n * Extract key facts from messages about to be evicted, save them to memory,\n * then return the truncated history.\n */\nexport async function compactWithFlush(\n allMessages: Array<{ role: string; content: string }>,\n keepCount: number,\n memory: MemoryProvider,\n userId: string,\n): Promise<CompactionResult> {\n if (allMessages.length <= keepCount) {\n return { messages: allMessages, removedCount: 0, factsExtracted: [] };\n }\n\n const evicted = allMessages.slice(0, allMessages.length - keepCount);\n const kept = allMessages.slice(-keepCount);\n const factsExtracted: string[] = [];\n\n // Extract key facts from evicted messages\n const facts = extractKeyFacts(evicted);\n for (const fact of facts) {\n try {\n await memory.add(fact, {\n userId,\n category: \"fact\",\n });\n factsExtracted.push(fact);\n } catch (err) {\n log.warn({ err, fact }, \"Failed to save fact to memory\");\n }\n }\n\n log.info(\n {\n userId,\n evictedMessages: evicted.length,\n keptMessages: kept.length,\n factsExtracted: factsExtracted.length,\n },\n \"Pre-compaction flush complete\",\n );\n\n return {\n messages: kept,\n removedCount: evicted.length,\n factsExtracted,\n };\n}\n\n/**\n * Heuristic extraction of key facts from conversation messages.\n * Focuses on: product names, prices, store references, user decisions.\n */\nfunction extractKeyFacts(\n messages: Array<{ role: string; content: string }>,\n): string[] {\n const facts: string[] = [];\n const fullText = messages.map((m) => m.content).join(\"\\n\");\n const hasChinese = /[\\u4e00-\\u9fff]/.test(fullText);\n\n const urlMatches = fullText.match(\n /(?:aliexpress|alibaba|1688|accio|temu)\\.com\\S*/gi,\n );\n if (urlMatches) {\n const unique = [...new Set(urlMatches)].slice(0, 5);\n facts.push(\n hasChinese\n ? `用户曾导入商品链接:${unique.join(\", \")}`\n : `Product URLs imported: ${unique.join(\", \")}`,\n );\n }\n\n const pricePatterns = fullText.match(\n /(?:售价|定价|sell.*?price|pricing|set.*?price|markup|fixed.*?price).*?(?:\\$[\\d.]+|¥[\\d.]+|[\\d.]+\\s*(?:元|美元|dollars?))/gi,\n );\n if (pricePatterns) {\n const unique = [...new Set(pricePatterns)].slice(0, 3);\n facts.push(\n hasChinese\n ? `定价相关:${unique.join(\"; \")}`\n : `Pricing decisions: ${unique.join(\"; \")}`,\n );\n }\n\n const storeMatches = fullText.match(\n /(?:店铺|store|shop)\\s*[::]?\\s*[\\w\\s-]{3,30}/gi,\n );\n if (storeMatches) {\n const unique = [...new Set(storeMatches)].slice(0, 3);\n facts.push(\n hasChinese\n ? `涉及店铺:${unique.join(\", \")}`\n : `Stores referenced: ${unique.join(\", \")}`,\n );\n }\n\n const decisions = messages\n .filter((m) => m.role === \"user\")\n .map((m) => m.content.trim())\n .filter(\n (t) =>\n /^(好|确认|执行|推送|是|yes|ok|confirm|push|no|不|取消|算了|cancel|skip)/i.test(t) &&\n t.length < 50,\n );\n if (decisions.length > 0) {\n facts.push(\n hasChinese\n ? `用户决策记录:${decisions.slice(0, 5).join(\"; \")}`\n : `User decisions: ${decisions.slice(0, 5).join(\"; \")}`,\n );\n }\n\n for (const m of messages) {\n if (m.role !== \"assistant\") continue;\n const summary = m.content.match(\n /(?:已导入|已推送|已修改|已更新|已删除|Imported|Pushed|Updated|Modified|Deleted|Set price|Changed title)\\s*.{10,80}/,\n );\n if (summary) {\n facts.push(summary[0]);\n }\n }\n\n return [...new Set(facts)].slice(0, 8);\n}\n\n/**\n * Check if compaction is needed based on token count.\n */\nexport function shouldCompact(\n messages: Array<{ role: string; content: string }>,\n budgetTokens: number,\n threshold = 0.8,\n): boolean {\n const used = countMessagesTokens(messages);\n return used >= budgetTokens * threshold;\n}\n","/**\n * Conversation history persistence.\n * Dual-layer: in-memory Map for fast reads + encrypted files for durability.\n * Survives process restarts; fires write-behind (non-blocking) after each reply.\n */\n\nimport {\n readFileSync,\n writeFileSync,\n existsSync,\n mkdirSync,\n renameSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n randomBytes,\n createCipheriv,\n createDecipheriv,\n createHash,\n} from \"node:crypto\";\nimport { hostname, userInfo } from \"node:os\";\nimport { CONFIG_DIR } from \"../gateway/config.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"context:history\");\nconst HISTORY_DIR = join(CONFIG_DIR, \"history\");\nconst MAX_LINES = 200;\nconst KEEP_AFTER_ROTATE = 100;\n\nconst ALG = \"aes-256-gcm\" as const;\nconst IV_LEN = 12;\nconst TAG_LEN = 16;\nconst KEY_SEED = \"dsclaw-history-v1\";\n\nfunction deriveKey(): Buffer {\n let user = \"\";\n try {\n user = userInfo().username;\n } catch {\n user = process.env[\"USER\"] ?? process.env[\"USERNAME\"] ?? \"default\";\n }\n return createHash(\"sha256\")\n .update(`${KEY_SEED}:${hostname()}:${user}`)\n .digest();\n}\n\nfunction encryptStr(data: string): string {\n const key = deriveKey();\n const iv = randomBytes(IV_LEN);\n const cipher = createCipheriv(ALG, key, iv, { authTagLength: TAG_LEN });\n const ct = Buffer.concat([cipher.update(data, \"utf8\"), cipher.final()]);\n const tag = cipher.getAuthTag();\n return Buffer.concat([iv, tag, ct]).toString(\"base64\");\n}\n\nfunction decryptStr(encoded: string): string | null {\n try {\n const key = deriveKey();\n const buf = Buffer.from(encoded, \"base64\");\n if (buf.length < IV_LEN + TAG_LEN + 1) return null;\n const iv = buf.subarray(0, IV_LEN);\n const tag = buf.subarray(IV_LEN, IV_LEN + TAG_LEN);\n const ct = buf.subarray(IV_LEN + TAG_LEN);\n const decipher = createDecipheriv(ALG, key, iv, { authTagLength: TAG_LEN });\n decipher.setAuthTag(tag);\n return Buffer.concat([decipher.update(ct), decipher.final()]).toString(\"utf8\");\n } catch {\n return null;\n }\n}\n\nexport interface HistoryMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n ts?: string;\n}\n\nconst cache = new Map<string, HistoryMessage[]>();\n\nfunction ensureDir(): void {\n if (!existsSync(HISTORY_DIR)) {\n mkdirSync(HISTORY_DIR, { recursive: true });\n }\n}\n\nfunction filePath(sessionKey: string): string {\n const safe = sessionKey.replace(/[^a-zA-Z0-9_:-]/g, \"_\");\n return join(HISTORY_DIR, `${safe}.enc`);\n}\n\nfunction legacyFilePath(sessionKey: string): string {\n const safe = sessionKey.replace(/[^a-zA-Z0-9_:-]/g, \"_\");\n return join(HISTORY_DIR, `${safe}.jsonl`);\n}\n\nfunction readEncryptedFile(fp: string): HistoryMessage[] {\n const raw = readFileSync(fp, \"utf-8\").trim();\n if (!raw) return [];\n const decrypted = decryptStr(raw);\n if (!decrypted) return [];\n try {\n return JSON.parse(decrypted) as HistoryMessage[];\n } catch {\n return [];\n }\n}\n\nfunction readLegacyFile(fp: string): HistoryMessage[] {\n const raw = readFileSync(fp, \"utf-8\");\n const messages: HistoryMessage[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n messages.push(JSON.parse(line) as HistoryMessage);\n } catch { /* skip malformed */ }\n }\n return messages;\n}\n\nfunction writeEncryptedFile(fp: string, messages: HistoryMessage[]): void {\n const json = JSON.stringify(messages);\n const encrypted = encryptStr(json);\n const tmp = fp + \".tmp\";\n writeFileSync(tmp, encrypted);\n renameSync(tmp, fp);\n}\n\n/**\n * Load history from disk into memory cache.\n */\nexport function loadHistory(\n sessionKey: string,\n timeoutMs = 5000,\n): { messages: HistoryMessage[]; count: number; error?: string } {\n try {\n ensureDir();\n const encFp = filePath(sessionKey);\n const legacyFp = legacyFilePath(sessionKey);\n\n let messages: HistoryMessage[] = [];\n\n if (existsSync(encFp)) {\n const start = Date.now();\n messages = readEncryptedFile(encFp);\n if (Date.now() - start > timeoutMs) {\n cache.set(sessionKey, []);\n return { messages: [], count: 0, error: \"磁盘读取超时\" };\n }\n } else if (existsSync(legacyFp)) {\n const start = Date.now();\n messages = readLegacyFile(legacyFp);\n if (Date.now() - start > timeoutMs) {\n cache.set(sessionKey, []);\n return { messages: [], count: 0, error: \"磁盘读取超时\" };\n }\n if (messages.length > 0) {\n writeEncryptedFile(encFp, messages);\n log.info({ sessionKey }, \"Migrated legacy plaintext history to encrypted\");\n }\n }\n\n cache.set(sessionKey, messages);\n if (messages.length > 0) {\n log.info({ sessionKey, count: messages.length }, \"History loaded\");\n }\n return { messages, count: messages.length };\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n log.warn({ sessionKey, err }, \"Failed to load history\");\n cache.set(sessionKey, []);\n return { messages: [], count: 0, error: `文件读取失败(${reason})` };\n }\n}\n\n/**\n * Get history from memory cache. Does NOT read disk.\n */\nexport function getHistory(sessionKey: string): HistoryMessage[] {\n return cache.get(sessionKey) ?? [];\n}\n\n/**\n * Append messages to history. Writes to memory immediately, disk async.\n */\nexport function appendHistory(\n sessionKey: string,\n ...messages: HistoryMessage[]\n): void {\n const history = cache.get(sessionKey) ?? [];\n for (const m of messages) {\n history.push({ ...m, ts: m.ts ?? new Date().toISOString() });\n }\n cache.set(sessionKey, history);\n\n Promise.resolve().then(() => {\n try {\n ensureDir();\n writeEncryptedFile(filePath(sessionKey), history);\n\n if (history.length > MAX_LINES) {\n rotateHistory(sessionKey);\n }\n } catch (err) {\n log.warn({ sessionKey, err }, \"Failed to write history to disk\");\n }\n });\n}\n\n/**\n * Replace entire history in cache (e.g. after compaction).\n */\nexport function setHistory(\n sessionKey: string,\n messages: HistoryMessage[],\n): void {\n cache.set(sessionKey, messages);\n\n Promise.resolve().then(() => {\n try {\n ensureDir();\n writeEncryptedFile(filePath(sessionKey), messages);\n } catch (err) {\n log.warn({ sessionKey, err }, \"Failed to rewrite history file\");\n }\n });\n}\n\n/**\n * Clear history for a session key (or all keys matching a userId suffix).\n */\nexport function clearHistory(sessionKeyOrUserId: string): void {\n for (const key of cache.keys()) {\n if (key === sessionKeyOrUserId || key.endsWith(`:${sessionKeyOrUserId}`)) {\n cache.delete(key);\n }\n }\n}\n\nfunction rotateHistory(sessionKey: string): void {\n const history = cache.get(sessionKey);\n if (!history || history.length <= MAX_LINES) return;\n\n const trimmed = history.slice(-KEEP_AFTER_ROTATE);\n cache.set(sessionKey, trimmed);\n\n try {\n writeEncryptedFile(filePath(sessionKey), trimmed);\n log.info(\n { sessionKey, before: history.length, after: trimmed.length },\n \"History rotated\",\n );\n } catch (err) {\n log.warn({ sessionKey, err }, \"Failed to rotate history file\");\n }\n}\n","export type Lang = \"en\" | \"zh\";\n\nconst m: Record<string, Record<Lang, string>> = {\n // Rate limit\n \"gateway.rateLimit\": {\n en: \"Too many messages. Please wait a moment.\",\n zh: \"消息过于频繁,请稍等片刻。\",\n },\n\n // No API key (BUG-009)\n \"gateway.noApiKey.web\": {\n en: \"Please configure your AI model API Key in ⚙️ Settings (top-right) before chatting.\",\n zh: \"请先在右上角 ⚙️ 设置中配置 AI 模型的 API Key,才能开始对话。\",\n },\n \"gateway.noApiKey.telegram\": {\n en: \"Please configure your AI API key first. Send /reset to restart setup.\",\n zh: \"请先配置 AI API Key。发送 /reset 重新设置。\",\n },\n\n // Welcome (Web)\n \"gateway.welcome.web\": {\n en:\n \"Welcome to **DSClaw**! I'm your AI dropshipping assistant.\\n\\n\" +\n \"Click the ⚙️ **Settings** button (top-right) to connect your **DSers account** and **AI provider**.\\n\\n\" +\n \"Once set up, I can help you:\\n\" +\n \"- Import products from AliExpress, Temu, 1688\\n\" +\n \"- Push to your Shopify / WooCommerce store\\n\" +\n \"- Manage orders, inventory, and pricing rules\\n\" +\n \"- ...all through this chat!\",\n zh:\n \"欢迎使用 **DSClaw**!我是你的 AI 代发助手。\\n\\n\" +\n \"点击右上角 ⚙️ **设置** 按钮,连接你的 **DSers 账号**和 **AI 模型**。\\n\\n\" +\n \"设置完成后,我可以帮你:\\n\" +\n \"- 从 AliExpress、Temu、1688 导入商品\\n\" +\n \"- 推送到你的 Shopify / WooCommerce 店铺\\n\" +\n \"- 管理订单、库存和定价规则\\n\" +\n \"- ...全部通过对话完成!\",\n },\n\n // Welcome (Telegram)\n \"gateway.welcome.telegram\": {\n en:\n \"Welcome to *DSClaw*! I'm your AI assistant for dropshipping.\\n\\n\" +\n \"I can help you:\\n\" +\n \"- Import products from AliExpress, Temu, 1688\\n\" +\n \"- Push products to your Shopify/WooCommerce store\\n\" +\n \"- Check inventory, pricing rules, and orders\\n\\n\" +\n \"Let's get you set up. It takes about 1 minute.\\n\\n\" +\n \"*Step 1/3:* What is your DSers account email?\",\n zh:\n \"欢迎使用 *DSClaw*!我是你的 AI 代发助手。\\n\\n\" +\n \"我可以帮你:\\n\" +\n \"- 从 AliExpress、Temu、1688 导入商品\\n\" +\n \"- 推送到你的 Shopify/WooCommerce 店铺\\n\" +\n \"- 查询库存、定价规则和订单\\n\\n\" +\n \"开始设置吧,大约 1 分钟。\\n\\n\" +\n \"*步骤 1/3:* 请输入你的 DSers 账号邮箱:\",\n },\n\n // Ready — short toast version\n \"gateway.ready.toast\": {\n en: \"All set! DSClaw is ready.\",\n zh: \"设置完成!DSClaw 已准备就绪。\",\n },\n\n // Ready (BUG-010)\n \"gateway.ready.web\": {\n en:\n \"All set! DSClaw is ready.\\n\\n\" +\n \"Try asking me:\\n\" +\n '- \"Show me my stores\"\\n' +\n '- \"What\\'s in my import list?\"\\n' +\n '- \"Search for phone cases on AliExpress\"\\n\\n' +\n \"Just type naturally!\",\n zh:\n \"设置完成!DSClaw 已准备就绪。\\n\\n\" +\n \"试试对我说:\\n\" +\n \"- \\\"帮我看看我的店铺\\\"\\n\" +\n \"- \\\"我的导入列表里有什么\\\"\\n\" +\n \"- \\\"从速卖通搜索手机壳\\\"\\n\\n\" +\n \"直接输入就好!\",\n },\n \"gateway.ready.telegram\": {\n en:\n \"All set! DSClaw is ready.\\n\\n\" +\n \"Try these:\\n\" +\n '- \"Show me my stores\"\\n' +\n '- \"What\\'s in my import list?\"\\n' +\n '- \"Search for phone cases on AliExpress\"\\n' +\n '- \"Check my pricing rules\"\\n\\n' +\n \"Just type naturally — I understand everyday language!\",\n zh:\n \"设置完成!DSClaw 已准备就绪。\\n\\n\" +\n \"试试这些:\\n\" +\n \"- \\\"帮我看看我的店铺\\\"\\n\" +\n \"- \\\"我的导入列表里有什么\\\"\\n\" +\n \"- \\\"从速卖通搜索手机壳\\\"\\n\" +\n \"- \\\"查看定价规则\\\"\\n\\n\" +\n \"直接用自然语言输入就好!\",\n },\n\n // Commands\n \"gateway.cmd.reset\": {\n en: \"Conversation reset. DSers connection and AI config preserved.\",\n zh: \"对话已重置,DSers 连接和 AI 配置已保留。\",\n },\n \"gateway.cmd.logout\": {\n en: \"Logged out. All configuration cleared. Send any message to start over.\",\n zh: \"已完全登出,所有配置已清除。发送任意消息重新开始。\",\n },\n \"gateway.cmd.retryEmpty\": {\n en: \"No message to retry.\",\n zh: \"没有可重试的消息。\",\n },\n\n // Errors\n \"gateway.error.generic\": {\n en: \"Something went wrong, please try again.\",\n zh: \"出了点问题,请重试。\",\n },\n \"gateway.error.timeout\": {\n en: \"Model response timed out, please try again later.\",\n zh: \"模型响应超时,请稍后重试。\",\n },\n \"gateway.error.apiKey\": {\n en: \"API key invalid or expired. Send /reset to reconfigure.\",\n zh: \"API 密钥无效或过期,请发送 /reset 重新配置。\",\n },\n \"gateway.error.rateLimitLlm\": {\n en: \"Too many requests, please wait a moment and try again.\",\n zh: \"请求过于频繁,请稍等片刻再试。\",\n },\n \"gateway.error.dsers\": {\n en: \"DSers connection error, please send /reset to reconnect.\",\n zh: \"DSers 连接异常,请发送 /reset 重新登录。\",\n },\n\n // Stream errors\n \"gateway.stream.stageTimeout\": {\n en: \"{{stage}} timed out — LLM may be slow or unreachable. Type /retry to retry.\",\n zh: \"{{stage}}超时 — LLM 服务可能较慢或不可达。输入 /retry 重试上一条消息。\",\n },\n \"gateway.stream.badApiKey\": {\n en: \"API key may be invalid or expired. Send /reset to reconfigure.\",\n zh: \"API key 可能无效或已过期,输入 /reset 重新配置。\",\n },\n \"gateway.stream.processFailed\": {\n en: \"Processing error, please try again. Type /retry to retry.\",\n zh: \"处理出错,请稍后重试。输入 /retry 重试上一条消息。\",\n },\n \"gateway.stream.incomplete\": {\n en: \"⚠️ Response incomplete, please retry.\",\n zh: \"⚠️ 响应未完成,请重试。\",\n },\n \"gateway.stream.noReply\": {\n en: \"⚠️ No model reply received, please retry.\",\n zh: \"⚠️ 未收到模型回复,请重试。\",\n },\n \"gateway.stream.toolsNoText\": {\n en: \"Completed {{count}} operations ({{names}}), but the model did not generate a summary. Let me know if you'd like to see the results.\",\n zh: \"已完成 {{count}} 项操作({{names}}),但模型未生成文字总结。如需查看结果请告诉我。\",\n },\n\n // Timeout stage names\n \"gateway.stage.llmConnection\": { en: \"LLM connection\", zh: \"LLM 连接\" },\n \"gateway.stage.llmResponse\": { en: \"LLM response\", zh: \"LLM 响应\" },\n \"gateway.stage.rulesApply\": { en: \"Rules application\", zh: \"规则应用\" },\n \"gateway.stage.productImport\": { en: \"Product import\", zh: \"商品导入\" },\n \"gateway.stage.processing\": { en: \"Processing\", zh: \"处理\" },\n\n // MCP\n \"gateway.mcp.unavailable\": {\n en: \"⚠️ DSers connection issue: only basic search is available. Import/push/delete operations are unavailable. Try sending /reset to reconnect.\",\n zh: \"⚠️ DSers 连接异常:仅基础搜索可用,导入/推送/删除等操作暂不可用。请尝试发送 /reset 重新连接。\",\n },\n\n // Onboarding\n \"gateway.onboard.invalidEmail\": {\n en: \"That doesn't look like an email address. Please enter your DSers login email:\",\n zh: \"这不像一个邮箱地址。请输入你的 DSers 登录邮箱:\",\n },\n \"gateway.onboard.passwordPrompt\": {\n en: \"Got it!\\n\\n*Step 2/3:* Now enter your DSers password.\",\n zh: \"收到!\\n\\n*步骤 2/3:* 请输入你的 DSers 密码。\",\n },\n \"gateway.onboard.passwordPromptNote\": {\n en: \"\\n_(Your password is encrypted locally and never sent to any third party.)_\",\n zh: \"\\n_(密码加密存储在本地,不会发送给第三方。)_\",\n },\n \"gateway.onboard.emptyPassword\": {\n en: \"Password cannot be empty. Please try again:\",\n zh: \"密码不能为空,请重试:\",\n },\n \"gateway.onboard.verifying\": {\n en: \"Verifying with DSers...\",\n zh: \"正在验证 DSers 账号...\",\n },\n \"gateway.onboard.loginFailed\": {\n en: \"Wrong email or password. Please re-enter your password:\",\n zh: \"邮箱或密码错误。请重新输入密码:\",\n },\n \"gateway.onboard.loginFailedGeneric\": {\n en: \"Login failed: {{error}}. Try again:\",\n zh: \"登录失败:{{error}}。请重试:\",\n },\n \"gateway.onboard.chooseProvider\": {\n en: \"You chose *{{provider}}*. Now paste your API key below.\",\n zh: \"你选择了 *{{provider}}*。请在下方粘贴 API Key。\",\n },\n \"gateway.onboard.invalidApiKey\": {\n en: \"That doesn't look like a valid API key. Please paste your key:\",\n zh: \"这不像一个有效的 API Key。请粘贴你的 Key:\",\n },\n};\n\nexport function t(\n key: string,\n lang?: string | null,\n vars?: Record<string, string | number>,\n): string {\n const l: Lang = lang === \"zh\" ? \"zh\" : \"en\";\n const tpl = m[key]?.[l] ?? m[key]?.en ?? key;\n if (!vars) return tpl;\n return tpl.replace(/\\{\\{(\\w+)\\}\\}/g, (_, k) => String(vars[k] ?? \"\"));\n}\n","/**\n * PID file management for DSClaw.\n * Tracks the running gateway process so `stop` / `status` work without PM2.\n * File: ~/.dsclaw/dsclaw.pid (JSON: { pid, port, startedAt })\n */\n\nimport { readFileSync, writeFileSync, unlinkSync, existsSync } from \"node:fs\";\nimport { CONFIG_DIR, ensureConfigDir } from \"../gateway/config.js\";\nimport { join } from \"node:path\";\n\nconst PID_PATH = join(CONFIG_DIR, \"dsclaw.pid\");\n\nexport interface PidInfo {\n pid: number;\n port: number;\n startedAt: string;\n}\n\nexport function writePid(port: number): void {\n ensureConfigDir();\n const info: PidInfo = {\n pid: process.pid,\n port,\n startedAt: new Date().toISOString(),\n };\n writeFileSync(PID_PATH, JSON.stringify(info, null, 2), { mode: 0o600 });\n}\n\nexport function readPid(): PidInfo | null {\n if (!existsSync(PID_PATH)) return null;\n try {\n const raw = readFileSync(PID_PATH, \"utf-8\");\n return JSON.parse(raw) as PidInfo;\n } catch {\n return null;\n }\n}\n\nexport function removePid(): void {\n try {\n if (existsSync(PID_PATH)) unlinkSync(PID_PATH);\n } catch {\n /* best-effort cleanup */\n }\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if a DSClaw instance is already running.\n * Returns PidInfo if alive, null otherwise (stale PID file auto-cleaned).\n */\nexport function getRunningInstance(): PidInfo | null {\n const info = readPid();\n if (!info) return null;\n\n if (isProcessAlive(info.pid)) return info;\n\n removePid();\n return null;\n}\n","/**\n * Cross-platform utility to open a URL in the user's browser.\n * macOS: AppleScript `open location` in the active browser (new tab, not new window).\n * Windows: `start \"\" \"url\"`.\n * Linux: `xdg-open \"url\"`.\n */\n\nconst BROWSERS_PRIORITY = [\n \"Google Chrome\", \"Arc\", \"Firefox\", \"Brave Browser\",\n \"Microsoft Edge\", \"Opera\", \"Vivaldi\", \"Safari\",\n];\n\nexport async function openBrowser(url: string): Promise<void> {\n const { exec } = await import(\"node:child_process\");\n\n if (process.platform === \"darwin\") {\n exec(\n `osascript -e 'tell application \"System Events\" to get name of every application process whose visible is true'`,\n (err, stdout) => {\n if (err || !stdout) {\n exec(`open \"${url}\"`, () => {});\n return;\n }\n const apps = stdout.trim();\n const found = BROWSERS_PRIORITY.find((b) => apps.includes(b));\n if (found) {\n const script =\n `tell application \"${found}\"\\n` +\n ` open location \"${url}\"\\n` +\n ` activate\\n` +\n `end tell`;\n exec(`osascript -e '${script}'`, () => {});\n } else {\n exec(`open \"${url}\"`, () => {});\n }\n },\n );\n } else if (process.platform === \"win32\") {\n exec(`start \"\" \"${url}\"`, () => {});\n } else {\n exec(`xdg-open \"${url}\"`, () => {});\n }\n}\n","/**\n * Start the DSClaw bot.\n * Zero config required — web chat starts by default on port 3000.\n */\n\nimport { loadConfig } from \"../gateway/config.js\";\nimport { DSClawGateway } from \"../gateway/gateway.js\";\nimport { getRunningInstance, writePid, removePid } from \"./pid.js\";\nimport { openBrowser } from \"../shared/open-browser.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"cli:start\");\n\nexport async function startCommand(opts: {\n config?: string;\n open?: boolean;\n}): Promise<void> {\n try {\n const existing = getRunningInstance();\n if (existing) {\n const url = `http://localhost:${existing.port}`;\n console.log(`\\n DSClaw is already running (PID ${existing.pid}, port ${existing.port})`);\n console.log(` Opening: ${url}\\n`);\n if (opts.open !== false) await openBrowser(url);\n return;\n }\n\n const config = loadConfig(opts.config);\n\n console.log(\"\\n DSClaw starting...\\n\");\n\n const gateway = new DSClawGateway(config);\n await gateway.start();\n\n const port = gateway.actualPort;\n const url = `http://localhost:${port}`;\n\n writePid(port);\n\n if (config.telegramBotToken) {\n console.log(\" Telegram: enabled\");\n }\n\n console.log(`\\n DSClaw is running!\\n`);\n console.log(` ➜ ${url}\\n`);\n console.log(` Stop with: dsclaw stop\\n`);\n\n if (opts.open !== false) {\n await openBrowser(url);\n }\n\n let shuttingDown = false;\n const shutdown = async () => {\n if (shuttingDown) return;\n shuttingDown = true;\n console.log(\"\\n Shutting down...\");\n log.info(\"Shutting down gracefully...\");\n removePid();\n await gateway.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n process.on(\"exit\", () => removePid());\n } catch (error) {\n removePid();\n log.fatal({ error }, \"Failed to start\");\n console.error(\n `\\n Failed to start: ${error instanceof Error ? error.message : error}`,\n );\n process.exit(1);\n }\n}\n","/**\n * Stop a running DSClaw instance by PID file.\n * Sends SIGTERM, waits up to 5s, then SIGKILL as fallback.\n */\n\nimport { getRunningInstance, removePid, isProcessAlive } from \"./pid.js\";\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nexport async function stopCommand(): Promise<void> {\n const info = getRunningInstance();\n if (!info) {\n console.log(\"\\n DSClaw is not running.\\n\");\n return;\n }\n\n console.log(`\\n Stopping DSClaw (PID ${info.pid}, port ${info.port})...`);\n\n try {\n process.kill(info.pid, \"SIGTERM\");\n } catch {\n console.log(\" Process already gone — cleaning up PID file.\");\n removePid();\n return;\n }\n\n for (let i = 0; i < 10; i++) {\n await sleep(500);\n if (!isProcessAlive(info.pid)) {\n removePid();\n console.log(\" Stopped.\\n\");\n return;\n }\n }\n\n try {\n process.kill(info.pid, \"SIGKILL\");\n } catch {\n /* already dead */\n }\n removePid();\n console.log(\" Force-killed.\\n\");\n}\n","/**\n * Show whether a DSClaw instance is running.\n */\n\nimport { getRunningInstance } from \"./pid.js\";\n\nexport function statusCommand(): void {\n const info = getRunningInstance();\n\n if (!info) {\n console.log(\"\\n DSClaw is not running.\");\n console.log(\" Start with: dsclaw start\\n\");\n return;\n }\n\n const uptime = Date.now() - new Date(info.startedAt).getTime();\n const mins = Math.floor(uptime / 60_000);\n const hrs = Math.floor(mins / 60);\n const uptimeStr =\n hrs > 0 ? `${hrs}h ${mins % 60}m` : mins > 0 ? `${mins}m` : \"<1m\";\n\n console.log(\"\\n DSClaw is running\");\n console.log(` PID: ${info.pid}`);\n console.log(` Port: ${info.port}`);\n console.log(` Uptime: ${uptimeStr}`);\n console.log(` Chat: http://localhost:${info.port}`);\n console.log(`\\n Stop with: dsclaw stop\\n`);\n}\n","/**\n * Reset DSClaw — clear session data so users re-do onboarding.\n * With --hard: also delete config file.\n */\n\nimport { existsSync, readdirSync, unlinkSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR, CONFIG_PATH } from \"../gateway/config.js\";\nimport { getRunningInstance } from \"./pid.js\";\n\nexport function resetCommand(opts: { hard?: boolean }): void {\n const running = getRunningInstance();\n if (running) {\n console.log(`\\n DSClaw is still running (PID ${running.pid}).`);\n console.log(\" Please run `dsclaw stop` first.\\n\");\n return;\n }\n\n const sessionsDir = join(CONFIG_DIR, \"sessions\");\n let cleared = 0;\n\n if (existsSync(sessionsDir)) {\n const files = readdirSync(sessionsDir);\n for (const f of files) {\n try {\n unlinkSync(join(sessionsDir, f));\n cleared++;\n } catch {\n /* skip */\n }\n }\n }\n\n console.log(`\\n Cleared ${cleared} session(s).`);\n\n if (opts.hard) {\n if (existsSync(CONFIG_PATH)) {\n try {\n unlinkSync(CONFIG_PATH);\n console.log(\" Deleted config file.\");\n } catch {\n console.log(\" Failed to delete config file.\");\n }\n }\n\n const pidPath = join(CONFIG_DIR, \"dsclaw.pid\");\n if (existsSync(pidPath)) {\n try {\n unlinkSync(pidPath);\n } catch {\n /* best-effort */\n }\n }\n }\n\n console.log(\" Next run will start fresh onboarding.\\n\");\n}\n","/**\n * Doctor command — verifies configuration and connectivity.\n */\n\nimport { loadConfig, configExists, CONFIG_PATH } from \"../gateway/config.js\";\n\ninterface CheckResult {\n name: string;\n status: \"ok\" | \"warn\" | \"fail\";\n message: string;\n}\n\nexport async function doctorCommand(): Promise<void> {\n console.log(\"\\n DSClaw Doctor\\n\");\n const results: CheckResult[] = [];\n\n if (configExists()) {\n try {\n const config = loadConfig();\n results.push({ name: \"Config file\", status: \"ok\", message: CONFIG_PATH });\n\n results.push({\n name: \"Web chat\",\n status: \"ok\",\n message: `Port ${config.port}`,\n });\n\n if (config.telegramBotToken) {\n const tokenValid = config.telegramBotToken.includes(\":\");\n results.push({\n name: \"Telegram token\",\n status: tokenValid ? \"ok\" : \"warn\",\n message: tokenValid ? \"Format valid\" : \"Format suspicious\",\n });\n }\n } catch (e) {\n results.push({\n name: \"Config file\",\n status: \"fail\",\n message: e instanceof Error ? e.message : String(e),\n });\n }\n } else {\n results.push({\n name: \"Config file\",\n status: \"fail\",\n message: \"Not found. Run 'dsclaw init' first.\",\n });\n }\n\n try {\n const resp = await fetch(\"https://bff-api-gw.dsers.com/\", {\n method: \"HEAD\",\n signal: AbortSignal.timeout(5000),\n });\n results.push({\n name: \"DSers API\",\n status: resp.status < 500 ? \"ok\" : \"warn\",\n message: `Reachable (HTTP ${resp.status})`,\n });\n } catch (e) {\n results.push({\n name: \"DSers API\",\n status: \"warn\",\n message: e instanceof Error ? e.message : \"Unreachable\",\n });\n }\n\n for (const r of results) {\n const icon = r.status === \"ok\" ? \" [OK]\" : r.status === \"warn\" ? \" [!!]\" : \"[FAIL]\";\n console.log(` ${icon} ${r.name}: ${r.message}`);\n }\n\n const failed = results.filter((r) => r.status === \"fail\").length;\n console.log(\n failed === 0\n ? \"\\n All checks passed.\\n\"\n : `\\n ${failed} check(s) failed. Fix issues above.\\n`,\n );\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","mkdirSync","existsSync","join","log","join","existsSync","readFileSync","mkdirSync","writeFileSync","existsSync","mkdirSync","join","readFileSync","log","writeFileSync","readFileSync","writeFileSync","mkdirSync","existsSync","log","existsSync","readFileSync","mkdirSync","writeFileSync","createHash","log","t","log","join","join","join","existsSync","log","join","t","z","mkdirSync","existsSync","join","join","existsSync","mkdirSync","readFileSync","writeFileSync","mkdirSync","existsSync","join","homedir","log","cleanup","out","log","t","m","z","result","MemoryJobStore","readFileSync","writeFileSync","mkdirSync","existsSync","join","dirname","homedir","WebSocket","nanoid","log","filePath","nanoid","log","readFileSync","writeFileSync","appendFileSync","existsSync","mkdirSync","readdirSync","join","log","join","existsSync","mkdirSync","appendFileSync","m","readdirSync","readFileSync","t","writeFileSync","log","log","log","log","m","t","readFileSync","writeFileSync","existsSync","mkdirSync","renameSync","join","randomBytes","createCipheriv","createDecipheriv","createHash","hostname","userInfo","log","join","ALG","IV_LEN","TAG_LEN","KEY_SEED","deriveKey","userInfo","createHash","hostname","randomBytes","createCipheriv","existsSync","mkdirSync","join","writeFileSync","renameSync","m","log","log","log","result","MemoryJobStore","readFileSync","writeFileSync","unlinkSync","existsSync","join","writeFileSync","existsSync","readFileSync","unlinkSync","log","url","sleep","existsSync","readdirSync","unlinkSync","join","join","existsSync","readdirSync","unlinkSync"]}
|
|
1
|
+
{"version":3,"sources":["../../src/shared/tracer.ts","../../src/shared/logger.ts","../../src/cli/index.ts","../../src/cli/init.ts","../../src/gateway/config.ts","../../src/gateway/user-session.ts","../../src/dsers/auth.ts","../../src/shared/errors.ts","../../src/dsers/client.ts","../../src/shared/utils.ts","../../src/resilience/rate-limiter.ts","../../src/dsers/config.ts","../../src/dsers/browser-auth.ts","../../src/dsers/browser-finder.ts","../../src/agents/core-agent.ts","../../src/shared/audit.ts","../../src/dsers/product.ts","../../src/gateway/gateway.ts","../../src/web/server.ts","../../src/channels/telegram.ts","../../src/memory/file-provider.ts","../../src/resilience/degradation.ts","../../src/context/token-counter.ts","../../src/context/context-budget.ts","../../src/context/compaction.ts","../../src/context/history-store.ts","../../src/gateway/i18n.ts","../../src/cli/pid.ts","../../src/shared/open-browser.ts","../../src/cli/start.ts","../../src/cli/stop.ts","../../src/cli/status.ts","../../src/cli/reset.ts","../../src/cli/doctor.ts"],"sourcesContent":["/**\n * Request-scoped tracing via AsyncLocalStorage.\n * Every inbound message gets a traceId that propagates\n * through agents, tools, API calls, and logs.\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { nanoid } from \"nanoid\";\n\nexport interface TraceContext {\n traceId: string;\n userId?: string;\n channelId?: string;\n sessionId?: string;\n agentId?: string;\n}\n\nconst storage = new AsyncLocalStorage<TraceContext>();\n\nexport function runWithTrace<T>(\n ctx: Partial<TraceContext>,\n fn: () => T,\n): T {\n const traceId = ctx.traceId ?? nanoid(12);\n return storage.run({ traceId, ...ctx }, fn);\n}\n\nexport function getTraceContext(): TraceContext {\n return storage.getStore() ?? { traceId: nanoid(12) };\n}\n\nexport function getTraceId(): string {\n return getTraceContext().traceId;\n}\n","/**\n * Structured logger powered by pino.\n * Automatically injects traceId from AsyncLocalStorage.\n */\n\nimport pino from \"pino\";\nimport { getTraceContext } from \"./tracer.js\";\n\nconst isPkg = typeof (process as any).pkg !== \"undefined\";\n\nconst rootLogger = pino({\n level: process.env[\"LOG_LEVEL\"] ?? \"info\",\n transport:\n !isPkg && process.env[\"NODE_ENV\"] !== \"production\"\n ? { target: \"pino-pretty\", options: { colorize: true } }\n : undefined,\n mixin() {\n const ctx = getTraceContext();\n return {\n traceId: ctx.traceId,\n ...(ctx.userId ? { userId: ctx.userId } : {}),\n ...(ctx.channelId ? { channelId: ctx.channelId } : {}),\n ...(ctx.agentId ? { agentId: ctx.agentId } : {}),\n };\n },\n});\n\nexport function createLogger(module: string): pino.Logger {\n return rootLogger.child({ module });\n}\n\nexport { rootLogger as logger };\n","/**\n * DSClaw CLI entry point.\n * No subcommand → defaults to `start` (auto-opens browser).\n */\n\nimport { Command } from \"commander\";\nimport { initCommand } from \"./init.js\";\nimport { startCommand } from \"./start.js\";\nimport { stopCommand } from \"./stop.js\";\nimport { statusCommand } from \"./status.js\";\nimport { resetCommand } from \"./reset.js\";\nimport { doctorCommand } from \"./doctor.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"dsclaw\")\n .description(\"AI-powered dropshipping agent — chat with your DSers store.\")\n .version(\"0.1.7\");\n\nprogram.action(() => startCommand({}));\n\nprogram\n .command(\"init\")\n .description(\"Setup wizard — configure Telegram (optional)\")\n .action(initCommand);\n\nprogram\n .command(\"start\")\n .description(\"Start the DSClaw bot\")\n .option(\"-c, --config <path>\", \"Path to config file\")\n .option(\"--no-open\", \"Don't auto-open browser\")\n .action(startCommand);\n\nprogram\n .command(\"stop\")\n .description(\"Stop the running DSClaw instance\")\n .action(stopCommand);\n\nprogram\n .command(\"status\")\n .description(\"Show whether DSClaw is running\")\n .action(statusCommand);\n\nprogram\n .command(\"reset\")\n .description(\"Clear all session data (re-do onboarding)\")\n .option(\"--hard\", \"Also delete config file\")\n .action(resetCommand);\n\nprogram\n .command(\"doctor\")\n .description(\"Verify configuration\")\n .action(doctorCommand);\n\nprogram.parse();\n","/**\n * Optional setup wizard — for advanced configuration.\n * Web chat works with zero config; this is for adding Telegram or changing the port.\n */\n\nimport inquirer from \"inquirer\";\nimport {\n saveConfig,\n configExists,\n CONFIG_PATH,\n type DSClawConfig,\n} from \"../gateway/config.js\";\n\nexport async function initCommand(): Promise<void> {\n console.log(\"\\n DSClaw Setup (optional)\\n\");\n console.log(\" Web chat works out of the box — this is for extra settings.\\n\");\n\n if (configExists()) {\n const { overwrite } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"overwrite\",\n message: `Config already exists at ${CONFIG_PATH}. Overwrite?`,\n default: false,\n },\n ]);\n if (!overwrite) {\n console.log(\" Cancelled.\");\n return;\n }\n }\n\n const { port } = await inquirer.prompt({\n type: \"number\",\n name: \"port\",\n message: \"Web chat port (default 3000):\",\n default: 3000,\n });\n\n const { addTelegram } = await inquirer.prompt({\n type: \"confirm\",\n name: \"addTelegram\",\n message: \"Add Telegram bot?\",\n default: false,\n });\n\n const config: DSClawConfig = { port: port as number };\n\n if (addTelegram) {\n const { botToken } = await inquirer.prompt({\n type: \"password\",\n name: \"botToken\",\n message: \"Telegram Bot Token (from @BotFather):\",\n mask: \"*\",\n validate: (v: string) =>\n v.includes(\":\") ? true : \"Token format: 123456:ABC-DEF...\",\n });\n config.telegramBotToken = botToken as string;\n }\n\n saveConfig(config);\n console.log(`\\n Config saved to ${CONFIG_PATH}`);\n console.log(\" Run 'dsclaw start' to launch.\\n\");\n}\n","/**\n * Minimal configuration — defaults work out of the box.\n * Web chat starts automatically; Telegram is optional.\n */\n\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { z } from \"zod\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"config\");\n\nexport const CONFIG_DIR = join(homedir(), \".dsclaw\");\nexport const CONFIG_PATH = join(CONFIG_DIR, \"config.json\");\n\nexport const ConfigSchema = z.object({\n port: z.number().default(3000),\n telegramBotToken: z.string().optional(),\n});\n\nexport type DSClawConfig = z.infer<typeof ConfigSchema>;\n\nconst DEFAULT_CONFIG: DSClawConfig = { port: 3000 };\n\nexport function ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n }\n}\n\nexport function loadConfig(path?: string): DSClawConfig {\n const configPath = path ?? CONFIG_PATH;\n\n if (!existsSync(configPath)) {\n log.info(\"No config file found — using defaults (web chat on port 3000)\");\n return DEFAULT_CONFIG;\n }\n\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw) as unknown;\n\n const result = ConfigSchema.safeParse(parsed);\n if (!result.success) {\n log.warn(\"Config validation failed — using defaults\");\n return DEFAULT_CONFIG;\n }\n\n log.info(\"Configuration loaded\");\n return result.data;\n}\n\nexport function saveConfig(config: DSClawConfig): void {\n ensureConfigDir();\n writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });\n log.info({ path: CONFIG_PATH }, \"Configuration saved\");\n}\n\nexport function configExists(): boolean {\n return existsSync(CONFIG_PATH);\n}\n","/**\n * User session state machine + encrypted credential storage.\n * Each Telegram user has their own session with DSers + LLM credentials.\n * Credentials are AES-256-GCM encrypted, bound to machine identity.\n */\n\nimport {\n randomBytes,\n createCipheriv,\n createDecipheriv,\n createHash,\n} from \"node:crypto\";\nimport {\n readFileSync,\n writeFileSync,\n mkdirSync,\n existsSync,\n unlinkSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { hostname, userInfo } from \"node:os\";\nimport { CONFIG_DIR } from \"./config.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"user-session\");\n\nconst ALG = \"aes-256-gcm\";\nconst IV_LEN = 12;\nconst TAG_LEN = 16;\nconst KEY_SEED = \"dsclaw-v1\";\nconst SESSIONS_DIR = join(CONFIG_DIR, \"sessions\");\nconst SALT_FILE = join(CONFIG_DIR, \".salt\");\n\nfunction getOrCreateSalt(): string {\n try {\n if (existsSync(SALT_FILE)) {\n return readFileSync(SALT_FILE, \"utf-8\").trim();\n }\n } catch { /* fall through */ }\n const salt = randomBytes(32).toString(\"hex\");\n try {\n mkdirSync(CONFIG_DIR, { recursive: true });\n writeFileSync(SALT_FILE, salt, { mode: 0o600 });\n } catch (err) {\n log.warn({ err }, \"Failed to persist salt file\");\n }\n return salt;\n}\n\nlet cachedSalt: string | null = null;\nfunction getSalt(): string {\n if (!cachedSalt) cachedSalt = getOrCreateSalt();\n return cachedSalt;\n}\n\nexport type SessionState =\n | \"new\"\n | \"onboard_demo\"\n | \"onboard_dsers_email\"\n | \"onboard_dsers_password\"\n | \"onboard_llm\"\n | \"ready\";\n\nexport interface UserSessionData {\n state: SessionState;\n dspiEmail?: string;\n dspiPassword?: string;\n dspiSessionId?: string;\n dspiSessionState?: string;\n llmProvider?: string;\n llmApiKey?: string;\n llmModel?: string;\n llmBaseUrl?: string;\n language?: string;\n}\n\nfunction deriveKeyBase(extra: string): Buffer {\n let user = \"\";\n try {\n user = userInfo().username;\n } catch {\n user = process.env[\"USER\"] ?? process.env[\"USERNAME\"] ?? \"default\";\n }\n return createHash(\"sha256\")\n .update(`${KEY_SEED}:${hostname()}:${user}${extra}`)\n .digest();\n}\n\nfunction deriveKey(): Buffer {\n return deriveKeyBase(`:${getSalt()}`);\n}\n\nfunction deriveKeyLegacy(): Buffer {\n return deriveKeyBase(\"\");\n}\n\nfunction encrypt(data: string): string {\n const key = deriveKey();\n const iv = randomBytes(IV_LEN);\n const cipher = createCipheriv(ALG, key, iv, { authTagLength: TAG_LEN });\n const ct = Buffer.concat([cipher.update(data, \"utf8\"), cipher.final()]);\n const tag = cipher.getAuthTag();\n return Buffer.concat([iv, tag, ct]).toString(\"base64\");\n}\n\nfunction decryptWithKey(encoded: string, key: Buffer): string | null {\n try {\n const buf = Buffer.from(encoded, \"base64\");\n if (buf.length < IV_LEN + TAG_LEN + 1) return null;\n const iv = buf.subarray(0, IV_LEN);\n const tag = buf.subarray(IV_LEN, IV_LEN + TAG_LEN);\n const ct = buf.subarray(IV_LEN + TAG_LEN);\n const decipher = createDecipheriv(ALG, key, iv, { authTagLength: TAG_LEN });\n decipher.setAuthTag(tag);\n return Buffer.concat([decipher.update(ct), decipher.final()]).toString(\"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction decrypt(encoded: string): string | null {\n const result = decryptWithKey(encoded, deriveKey());\n if (result) return result;\n return decryptWithKey(encoded, deriveKeyLegacy());\n}\n\nfunction ensureSessionsDir(): void {\n if (!existsSync(SESSIONS_DIR)) {\n mkdirSync(SESSIONS_DIR, { recursive: true, mode: 0o700 });\n }\n}\n\nfunction sessionPath(userId: string): string {\n const safe = userId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return join(SESSIONS_DIR, `${safe}.enc`);\n}\n\nexport function loadSession(userId: string): UserSessionData {\n const p = sessionPath(userId);\n if (!existsSync(p)) {\n return { state: \"new\" };\n }\n try {\n const encrypted = readFileSync(p, \"utf-8\").trim();\n\n let json = decryptWithKey(encrypted, deriveKey());\n let needsMigration = false;\n if (!json) {\n json = decryptWithKey(encrypted, deriveKeyLegacy());\n needsMigration = !!json;\n }\n if (!json) {\n log.warn({ userId }, \"Failed to decrypt session — starting fresh\");\n return { state: \"new\" };\n }\n const session = JSON.parse(json) as UserSessionData;\n if (needsMigration) {\n log.info({ userId }, \"Migrating session to salted key\");\n saveSession(userId, session);\n }\n return session;\n } catch {\n return { state: \"new\" };\n }\n}\n\nexport function saveSession(userId: string, session: UserSessionData): void {\n ensureSessionsDir();\n const json = JSON.stringify(session);\n const encrypted = encrypt(json);\n writeFileSync(sessionPath(userId), encrypted, { mode: 0o600 });\n log.debug({ userId, state: session.state }, \"Session saved\");\n}\n\nexport function deleteSession(userId: string): void {\n const p = sessionPath(userId);\n if (existsSync(p)) {\n try {\n unlinkSync(p);\n } catch {\n /* ignore */\n }\n }\n}\n\nexport function isOnboarding(state: SessionState): boolean {\n return state !== \"ready\";\n}\n","/**\n * DSers authentication with session caching.\n * Uses email + password login matching the actual DSers API.\n * Ported from dsers-mcp-product with enhanced error classification.\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport type { DSersClientConfig } from \"./config.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { DSClawError, ErrorCategory } from \"../shared/errors.js\";\n\nconst log = createLogger(\"dsers:auth\");\nconst SESSION_TTL = 3600 * 6 * 1000;\n\ninterface SessionCache {\n session_id: string;\n state: string;\n ts: number;\n}\n\nexport class DSersAuth {\n private config: DSersClientConfig;\n private sessionId: string | null = null;\n private state: string | null = null;\n private fetchedAt = 0;\n\n constructor(config: DSersClientConfig) {\n this.config = config;\n if (config.sessionId) {\n this.sessionId = config.sessionId;\n this.state = config.sessionState ?? \"\";\n this.fetchedAt = Date.now();\n }\n }\n\n async getSession(): Promise<[string, string]> {\n if (this.sessionId && Date.now() - this.fetchedAt < SESSION_TTL) {\n return [this.sessionId, this.state ?? \"\"];\n }\n\n const cached = this.readCache();\n if (cached) {\n [this.sessionId, this.state, this.fetchedAt] = cached;\n return [this.sessionId, this.state];\n }\n\n return this.login();\n }\n\n async login(): Promise<[string, string]> {\n if (!this.config.email || !this.config.password) {\n throw new DSClawError({\n category: ErrorCategory.NEEDS_HUMAN,\n code: \"DSERS_NO_CREDENTIALS\",\n message: \"DSers email and password not configured.\",\n retryable: false,\n });\n }\n\n log.info(\"Authenticating with DSers...\");\n\n const resp = await fetch(\n `${this.config.baseUrl}/account-user-bff/v1/users/login`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n email: this.config.email,\n password: this.config.password,\n }),\n },\n );\n\n if (!resp.ok) {\n const body = await resp.text();\n throw new DSClawError({\n category:\n resp.status === 401 || resp.status === 403\n ? ErrorCategory.NEEDS_HUMAN\n : ErrorCategory.RETRYABLE,\n code: `DSERS_LOGIN_${resp.status}`,\n message: `DSers login failed (HTTP ${resp.status}): ${body.slice(0, 200)}`,\n retryable: resp.status >= 500,\n });\n }\n\n const data = (await resp.json()) as Record<string, unknown>;\n const inner = data[\"data\"] as Record<string, unknown> | undefined;\n if (!inner?.[\"sessionId\"]) {\n throw new DSClawError({\n category: ErrorCategory.NEEDS_HUMAN,\n code: \"DSERS_LOGIN_NO_SESSION\",\n message: \"DSers login succeeded but no session returned.\",\n retryable: false,\n details: { response: data },\n });\n }\n\n this.sessionId = inner[\"sessionId\"] as string;\n this.state = (inner[\"state\"] as string) ?? \"\";\n this.fetchedAt = Date.now();\n this.writeCache();\n\n log.info(\"DSers authentication successful\");\n return [this.sessionId, this.state];\n }\n\n invalidate(): void {\n this.sessionId = null;\n this.state = null;\n this.fetchedAt = 0;\n log.debug(\"Session invalidated\");\n }\n\n /** Fast session validity check — calls DSers account info endpoint. */\n async checkHealth(): Promise<{ valid: boolean; reason?: string }> {\n if (!this.sessionId) {\n return { valid: false, reason: \"未授权(无 session)\" };\n }\n\n if (Date.now() - this.fetchedAt > SESSION_TTL) {\n return { valid: false, reason: \"session 已过期(超过 6 小时)\" };\n }\n\n try {\n const resp = await fetch(\n `${this.config.baseUrl}/account-user-bff/v1/users/current`,\n {\n headers: {\n Cookie: `sessionid=${this.sessionId}; djdt=hide; state=${this.state}`,\n },\n },\n );\n\n if (resp.status === 401 || resp.status === 403) {\n this.invalidate();\n return { valid: false, reason: `DSers 返回 ${resp.status}(token 失效),请重新授权` };\n }\n\n if (!resp.ok) {\n return { valid: false, reason: `DSers 服务异常(HTTP ${resp.status})` };\n }\n\n return { valid: true };\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n return { valid: false, reason: `网络错误(${reason}),请检查网络连接` };\n }\n }\n\n /**\n * Attempt session renewal for session-only users (no email/password).\n * Returns success if the session is still valid; fails with guidance otherwise.\n */\n async tryRenew(): Promise<{ renewed: boolean; reason?: string }> {\n const health = await this.checkHealth();\n if (health.valid) {\n this.fetchedAt = Date.now();\n return { renewed: true };\n }\n\n if (this.config.email && this.config.password) {\n try {\n await this.login();\n return { renewed: true };\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"登录失败\";\n return { renewed: false, reason };\n }\n }\n\n return {\n renewed: false,\n reason: `${health.reason}。当前为 session 模式,需要通过浏览器重新授权。`,\n };\n }\n\n private readCache(): [string, string, number] | null {\n try {\n const p = this.config.sessionFile;\n if (!existsSync(p)) return null;\n const obj: SessionCache = JSON.parse(readFileSync(p, \"utf-8\"));\n if (Date.now() - obj.ts > SESSION_TTL) return null;\n return [obj.session_id, obj.state ?? \"\", obj.ts];\n } catch {\n return null;\n }\n }\n\n private writeCache(): void {\n if (this.config.sessionId) return;\n try {\n const p = this.config.sessionFile;\n mkdirSync(dirname(p), { recursive: true });\n const payload: SessionCache = {\n session_id: this.sessionId!,\n state: this.state ?? \"\",\n ts: this.fetchedAt,\n };\n writeFileSync(p, JSON.stringify(payload), { encoding: \"utf-8\", mode: 0o600 });\n try {\n chmodSync(p, 0o600);\n } catch {\n /* Windows */\n }\n } catch {\n log.warn(\"Failed to write session cache\");\n }\n }\n}\n","/**\n * Structured error classification for DSClaw.\n * Every error flowing through the system must have a category\n * so upstream layers (agents, channels) know how to react.\n */\n\nexport const ErrorCategory = {\n RETRYABLE: \"RETRYABLE\",\n NEEDS_HUMAN: \"NEEDS_HUMAN\",\n NEEDS_DATA: \"NEEDS_DATA\",\n FATAL: \"FATAL\",\n DEGRADED: \"DEGRADED\",\n} as const;\n\nexport type ErrorCategory =\n (typeof ErrorCategory)[keyof typeof ErrorCategory];\n\nexport interface StructuredError {\n category: ErrorCategory;\n code: string;\n message: string;\n retryable: boolean;\n details?: Record<string, unknown>;\n cause?: Error;\n}\n\nexport class DSClawError extends Error {\n readonly category: ErrorCategory;\n readonly code: string;\n readonly retryable: boolean;\n readonly details?: Record<string, unknown>;\n\n constructor(opts: StructuredError) {\n super(opts.message);\n this.name = \"DSClawError\";\n this.category = opts.category;\n this.code = opts.code;\n this.retryable = opts.retryable;\n this.details = opts.details;\n if (opts.cause) this.cause = opts.cause;\n }\n\n toJSON(): StructuredError {\n return {\n category: this.category,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n details: this.details,\n };\n }\n}\n\nexport function classifyHttpError(\n status: number,\n body?: string,\n): ErrorCategory {\n if (status === 429) return ErrorCategory.RETRYABLE;\n if (status >= 500) return ErrorCategory.RETRYABLE;\n if (status === 401 || status === 403) return ErrorCategory.NEEDS_HUMAN;\n if (status === 404 || status === 422) return ErrorCategory.NEEDS_DATA;\n if (status === 400) return ErrorCategory.NEEDS_DATA;\n return ErrorCategory.FATAL;\n}\n","/**\n * Enhanced DSers HTTP client with:\n * - 429 Retry-After handling\n * - 5xx exponential backoff (max 2 retries)\n * - Structured error classification\n * - traceId injection\n * - Session auto-refresh on 400 auth errors\n */\n\nimport { DSersAuth } from \"./auth.js\";\nimport type { DSersClientConfig } from \"./config.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { getTraceId } from \"../shared/tracer.js\";\nimport {\n DSClawError,\n ErrorCategory,\n classifyHttpError,\n} from \"../shared/errors.js\";\nimport { parseRetryAfter, sleep } from \"../shared/utils.js\";\nimport { getOutboundLimiter } from \"../resilience/rate-limiter.js\";\n\nconst log = createLogger(\"dsers:client\");\n\nconst RETRYABLE_REASONS = new Set([\n \"TOKEN_NOT_FOUND\",\n \"TOKEN_EXPIRED\",\n \"UNAUTHORIZED\",\n \"INVALID_TOKEN\",\n]);\n\nconst MAX_RETRIES = 2;\n\nexport class DSersClient {\n private config: DSersClientConfig;\n private auth: DSersAuth;\n private limiter: ReturnType<typeof getOutboundLimiter>;\n\n constructor(config: DSersClientConfig) {\n this.config = config;\n this.auth = new DSersAuth(config);\n this.limiter = getOutboundLimiter(\"dsers\");\n }\n\n async request(\n method: string,\n path: string,\n opts?: {\n params?: Record<string, unknown>;\n json?: Record<string, unknown>;\n },\n attempt = 0,\n ): Promise<Record<string, unknown>> {\n return this.limiter(async () => {\n const [sessionId, state] = await this.auth.getSession();\n const traceId = getTraceId();\n\n const url = new URL(`${this.config.baseUrl}${path}`);\n if (opts?.params) {\n for (const [k, v] of Object.entries(opts.params)) {\n if (v != null) url.searchParams.set(k, String(v));\n }\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${sessionId}`,\n Cookie: `session_id=${sessionId}; state=${state}`,\n \"X-Trace-Id\": traceId,\n };\n\n log.debug({ method, path, traceId, attempt }, \"DSers API request\");\n\n const resp = await fetch(url.toString(), {\n method,\n headers,\n body: opts?.json ? JSON.stringify(opts.json) : undefined,\n });\n\n const bodyText = await resp.text();\n\n if (resp.status === 400 && attempt === 0) {\n try {\n const body = JSON.parse(bodyText) as Record<string, unknown>;\n if (RETRYABLE_REASONS.has(body[\"reason\"] as string)) {\n log.info({ reason: body[\"reason\"] }, \"Session expired, re-authenticating\");\n this.auth.invalidate();\n return this.request(method, path, opts, 1);\n }\n } catch {\n // not JSON\n }\n }\n\n if (resp.status === 429) {\n const retryAfterMs =\n parseRetryAfter(resp.headers.get(\"Retry-After\")) ?? 5000;\n if (attempt < MAX_RETRIES) {\n log.warn({ retryAfterMs, attempt }, \"Rate limited by DSers\");\n await sleep(retryAfterMs);\n return this.request(method, path, opts, attempt + 1);\n }\n }\n\n if (resp.status >= 500 && attempt < MAX_RETRIES) {\n const delay = Math.min(1000 * Math.pow(2, attempt) + Math.random() * 500, 15000);\n log.warn({ status: resp.status, attempt }, \"DSers server error, retrying\");\n await sleep(delay);\n return this.request(method, path, opts, attempt + 1);\n }\n\n if (resp.status >= 400) {\n const category = classifyHttpError(resp.status, bodyText);\n throw new DSClawError({\n category,\n code: `DSERS_API_${resp.status}`,\n message: `DSers API ${method} ${path} returned ${resp.status}: ${bodyText.slice(0, 300)}`,\n retryable: category === ErrorCategory.RETRYABLE,\n details: { status: resp.status, path, method },\n });\n }\n\n return JSON.parse(bodyText) as Record<string, unknown>;\n });\n }\n\n async get(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n return this.request(\"GET\", path, { params });\n }\n\n async post(\n path: string,\n json?: Record<string, unknown>,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n return this.request(\"POST\", path, { json, params });\n }\n\n async put(\n path: string,\n json?: Record<string, unknown>,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n return this.request(\"PUT\", path, { json, params });\n }\n\n async del(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<Record<string, unknown>> {\n return this.request(\"DELETE\", path, { params });\n }\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Generate an idempotency key from operation parameters.\n * Uses a 5-minute time bucket so the same operation within\n * 5 minutes is considered duplicate.\n */\nexport function idempotencyKey(\n userId: string,\n action: string,\n params: Record<string, unknown>,\n): string {\n const timeBucket = Math.floor(Date.now() / (5 * 60 * 1000));\n const payload = JSON.stringify({ userId, action, params, timeBucket });\n return createHash(\"sha256\").update(payload).digest(\"hex\").slice(0, 16);\n}\n\n/**\n * Sleep for a given number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Parse Retry-After header value to milliseconds.\n * Supports both seconds (integer) and HTTP-date formats.\n */\nexport function parseRetryAfter(value: string | null): number | null {\n if (!value) return null;\n const seconds = Number(value);\n if (!Number.isNaN(seconds)) return seconds * 1000;\n const date = Date.parse(value);\n if (!Number.isNaN(date)) return Math.max(0, date - Date.now());\n return null;\n}\n","/**\n * Three-layer rate limiting:\n * L1 Inbound: per-IP / per-channel flood protection\n * L2 Tenant: per-userId session serialization + debounce\n * L3 Outbound: per-service concurrency cap (DSers, LLM, mem0)\n */\n\nimport pLimit from \"p-limit\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"rate-limiter\");\n\n// --- L3: Outbound per-service concurrency limits ---\n\nexport interface OutboundLimits {\n dsers: number;\n llm: number;\n mem0: number;\n}\n\nconst DEFAULT_OUTBOUND_LIMITS: OutboundLimits = {\n dsers: 20,\n llm: 5,\n mem0: 10,\n};\n\nconst outboundLimiters = new Map<string, ReturnType<typeof pLimit>>();\n\nexport function getOutboundLimiter(\n service: keyof OutboundLimits,\n customLimits?: Partial<OutboundLimits>,\n): ReturnType<typeof pLimit> {\n if (!outboundLimiters.has(service)) {\n const limits = { ...DEFAULT_OUTBOUND_LIMITS, ...customLimits };\n const limiter = pLimit(limits[service]);\n outboundLimiters.set(service, limiter);\n log.info({ service, concurrency: limits[service] }, \"Outbound limiter created\");\n }\n return outboundLimiters.get(service)!;\n}\n\n// --- L2: Per-user message queue (serialization + debounce) ---\n\ninterface PendingMessage {\n resolve: (value: void) => void;\n timer?: ReturnType<typeof setTimeout>;\n}\n\ninterface LockEntry {\n promise: Promise<void>;\n resolve: () => void;\n version: number;\n}\n\nconst userLocks = new Map<string, LockEntry>();\nlet lockVersion = 0;\nconst debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();\n\n/**\n * Ensure messages from the same user are processed serially.\n * Returns a release function to call when processing is done.\n * Times out after `timeoutMs` — on timeout the waiter proceeds but\n * the stale holder's release() becomes a no-op (version check).\n */\nexport async function acquireUserLock(userId: string, timeoutMs = 180_000): Promise<() => void> {\n const deadline = Date.now() + timeoutMs;\n\n while (userLocks.has(userId)) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) {\n log.warn({ userId }, \"User lock wait timed out — forcing entry\");\n const stale = userLocks.get(userId);\n if (stale) {\n stale.resolve();\n }\n userLocks.delete(userId);\n break;\n }\n await Promise.race([\n userLocks.get(userId)!.promise,\n new Promise<void>((r) => setTimeout(r, remaining)),\n ]);\n }\n\n const myVersion = ++lockVersion;\n let resolve!: () => void;\n const promise = new Promise<void>((r) => { resolve = r; });\n userLocks.set(userId, { promise, resolve, version: myVersion });\n\n const release = () => {\n const current = userLocks.get(userId);\n if (current && current.version === myVersion) {\n userLocks.delete(userId);\n resolve();\n }\n };\n\n return release;\n}\n\n/**\n * Debounce rapid-fire messages from the same user.\n * Resolves after `delayMs` of silence.\n */\nexport function debounceUser(\n userId: string,\n delayMs = 500,\n): Promise<void> {\n return new Promise((resolve) => {\n const existing = debounceTimers.get(userId);\n if (existing) clearTimeout(existing);\n\n debounceTimers.set(\n userId,\n setTimeout(() => {\n debounceTimers.delete(userId);\n resolve();\n }, delayMs),\n );\n });\n}\n\n// --- L1: Inbound sliding window ---\n\ninterface WindowEntry {\n timestamps: number[];\n}\n\nconst inboundWindows = new Map<string, WindowEntry>();\n\n/**\n * Check if an inbound source has exceeded the rate limit.\n * @returns true if the request should be allowed, false if throttled.\n */\nexport function checkInboundLimit(\n sourceId: string,\n maxRequests = 30,\n windowMs = 60_000,\n): boolean {\n const now = Date.now();\n const entry = inboundWindows.get(sourceId) ?? { timestamps: [] };\n\n entry.timestamps = entry.timestamps.filter((t) => now - t < windowMs);\n\n if (entry.timestamps.length >= maxRequests) {\n log.warn({ sourceId, count: entry.timestamps.length }, \"Inbound rate limit hit\");\n return false;\n }\n\n entry.timestamps.push(now);\n inboundWindows.set(sourceId, entry);\n return true;\n}\n","/**\n * DSers API configuration.\n * Uses email + password auth (matching actual DSers login flow).\n */\n\nimport { join } from \"node:path\";\nimport { CONFIG_DIR } from \"../gateway/config.js\";\n\nconst PROD_URL = \"https://bff-api-gw.dsers.com\";\n\nexport interface DSersClientConfig {\n baseUrl: string;\n email: string;\n password?: string;\n sessionFile: string;\n sessionId?: string;\n sessionState?: string;\n}\n\nexport function createDSersConfig(\n email: string,\n password?: string,\n baseUrl?: string,\n): DSersClientConfig {\n const safeEmail = email.replace(/[^a-zA-Z0-9_@.-]/g, \"_\");\n return {\n baseUrl: baseUrl ?? PROD_URL,\n email,\n password,\n sessionFile: join(CONFIG_DIR, `session-${safeEmail}.json`),\n };\n}\n","/**\n * DSers browser-based authentication via CDP.\n *\n * 1. spawn() a fresh Chromium process in app mode pointing to DSers login\n * 2. Parse stderr for \"DevTools listening on ws://...\" to get the debug WS URL\n * 3. Connect via WebSocket (using the `ws` package already in deps)\n * 4. Intercept the login API response to extract sessionId + state from JSON body\n * 5. On success: resolve with tokens, kill browser, cleanup temp dir\n * 6. On timeout / user close: reject, cleanup\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { mkdtempSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { WebSocket } from \"ws\";\nimport { findAllChromium } from \"./browser-finder.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"dsers:browser-auth\");\n\nconst DSERS_LOGIN_URL = \"https://accounts.dsers.com/accounts/login\";\nconst LOGIN_API_PATTERN = \"/account-user-bff/v1/users/login\";\nconst TIMEOUT = 180_000; // 3 minutes\n\nexport interface DSersAuthResult {\n sessionId: string;\n state: string;\n}\n\nlet activeProcess: ChildProcess | null = null;\nlet activeTmpDir: string | null = null;\n\nexport function isAuthInProgress(): boolean {\n return activeProcess !== null && !activeProcess.killed;\n}\n\nexport function cancelAuth(): void {\n cleanup();\n}\n\nfunction cleanup(): void {\n if (activeProcess && !activeProcess.killed) {\n try { activeProcess.kill(); } catch { /* ignore */ }\n }\n activeProcess = null;\n\n if (activeTmpDir) {\n try { rmSync(activeTmpDir, { recursive: true, force: true }); } catch { /* ignore */ }\n activeTmpDir = null;\n }\n}\n\nfunction parseWsUrl(stderrChunk: string): string | null {\n const match = stderrChunk.match(/DevTools listening on (ws:\\/\\/[^\\s]+)/);\n return match?.[1] ?? null;\n}\n\nfunction tryLaunchBrowser(browser: { name: string; executablePath: string }): {\n proc: ChildProcess;\n wsUrlPromise: Promise<string>;\n} {\n const tmpDir = mkdtempSync(join(tmpdir(), \"dsclaw-auth-\"));\n activeTmpDir = tmpDir;\n\n log.info({ browser: browser.name }, \"Launching browser for DSers auth\");\n\n const args = [\n `--app=${DSERS_LOGIN_URL}`,\n \"--remote-debugging-port=0\",\n `--user-data-dir=${tmpDir}`,\n \"--no-first-run\",\n \"--no-default-browser-check\",\n \"--disable-extensions\",\n \"--mute-audio\",\n \"--window-size=480,700\",\n ];\n\n if (process.platform === \"win32\") {\n args.push(\n \"--disable-background-mode\",\n \"--disable-backgrounding-occluded-windows\",\n \"--disable-renderer-backgrounding\",\n );\n }\n\n const proc = spawn(browser.executablePath, args, {\n stdio: [\"ignore\", \"ignore\", \"pipe\"],\n detached: false,\n });\n\n activeProcess = proc;\n\n const wsUrlPromise = new Promise<string>((resolve, reject) => {\n let stderr = \"\";\n const timer = setTimeout(() => {\n reject(new Error(\"Timed out waiting for Chrome DevTools\"));\n }, 15000);\n\n proc.stderr!.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString();\n const url = parseWsUrl(stderr);\n if (url) {\n clearTimeout(timer);\n resolve(url);\n }\n });\n\n proc.on(\"error\", (err) => {\n clearTimeout(timer);\n reject(err);\n });\n\n proc.on(\"exit\", () => {\n clearTimeout(timer);\n reject(new Error(\"Browser exited before DevTools was ready\"));\n });\n });\n\n return { proc, wsUrlPromise };\n}\n\nfunction launchBrowser(): { proc: ChildProcess; wsUrlPromise: Promise<string> } {\n const browsers = findAllChromium();\n if (!browsers.length) {\n throw new Error(\"No Chromium-based browser found. Please install Chrome, Edge, or Brave.\");\n }\n return tryLaunchBrowser(browsers[0]!);\n}\n\n/**\n * Connect to CDP and intercept the DSers login API response.\n * When the login POST returns, we read the response body to get sessionId + state.\n */\nfunction watchLoginResponse(wsUrl: string): Promise<DSersAuthResult> {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(wsUrl);\n let msgId = 1;\n let timeoutTimer: ReturnType<typeof setTimeout> | null = null;\n let settled = false;\n\n const pending = new Map<number, (data: unknown) => void>();\n const requestMap = new Map<string, string>(); // requestId → url\n\n function cdpSend(method: string, params: Record<string, unknown> = {}): Promise<unknown> {\n return new Promise((res) => {\n const id = msgId++;\n pending.set(id, res);\n ws.send(JSON.stringify({ id, method, params }));\n });\n }\n\n function finish(result?: DSersAuthResult, err?: Error) {\n if (settled) return;\n settled = true;\n if (timeoutTimer) clearTimeout(timeoutTimer);\n try { ws.close(); } catch { /* ignore */ }\n if (result) resolve(result);\n else reject(err ?? new Error(\"Unknown error\"));\n }\n\n ws.on(\"open\", async () => {\n log.info(\"CDP connected, intercepting login API responses\");\n await cdpSend(\"Network.enable\");\n\n timeoutTimer = setTimeout(() => {\n finish(undefined, new Error(\"Login timed out (3 minutes). Please try again.\"));\n cleanup();\n }, TIMEOUT);\n });\n\n ws.on(\"message\", async (raw: Buffer) => {\n try {\n const msg = JSON.parse(raw.toString()) as {\n id?: number;\n result?: unknown;\n method?: string;\n params?: Record<string, unknown>;\n };\n\n // Handle RPC responses\n if (msg.id && pending.has(msg.id)) {\n pending.get(msg.id)!(msg.result);\n pending.delete(msg.id);\n return;\n }\n\n // Handle CDP events\n if (msg.method === \"Network.requestWillBeSent\") {\n const p = msg.params as { requestId: string; request: { url: string; method: string } };\n if (p.request.url.includes(LOGIN_API_PATTERN) && p.request.method === \"POST\") {\n requestMap.set(p.requestId, p.request.url);\n log.info(\"Detected DSers login request\");\n }\n return;\n }\n\n if (msg.method === \"Network.responseReceived\") {\n const p = msg.params as { requestId: string; response: { status: number } };\n if (!requestMap.has(p.requestId)) return;\n\n log.info({ status: p.response.status }, \"DSers login response received\");\n if (p.response.status !== 200) {\n log.warn(\"Login response was not 200, waiting for retry...\");\n requestMap.delete(p.requestId);\n return;\n }\n\n // Wait a bit for the body to be available\n await new Promise((r) => setTimeout(r, 500));\n\n try {\n const bodyResp = await cdpSend(\"Network.getResponseBody\", {\n requestId: p.requestId,\n }) as { body: string; base64Encoded: boolean };\n\n const body = bodyResp.base64Encoded\n ? Buffer.from(bodyResp.body, \"base64\").toString()\n : bodyResp.body;\n\n const data = JSON.parse(body) as {\n data?: { sessionId?: string; state?: string };\n };\n\n const sessionId = data?.data?.sessionId;\n const state = data?.data?.state ?? \"\";\n\n if (sessionId) {\n log.info(\"DSers session captured from login API response\");\n finish({ sessionId, state });\n } else {\n log.warn({ responseData: body.slice(0, 300) }, \"Login response missing sessionId\");\n }\n } catch (e) {\n log.warn({ error: e instanceof Error ? e.message : String(e) }, \"Failed to read login response body\");\n }\n requestMap.delete(p.requestId);\n }\n } catch { /* ignore malformed messages */ }\n });\n\n ws.on(\"error\", () => {\n finish(undefined, new Error(\"CDP connection lost\"));\n });\n\n ws.on(\"close\", () => {\n finish(undefined, new Error(\"Browser was closed before login completed\"));\n });\n });\n}\n\n/**\n * Main entry point: launch browser, wait for DSers login, return session tokens.\n * Resolves when user successfully logs in, rejects on timeout or cancel.\n */\nasync function attemptLoginWithBrowser(browser: { name: string; executablePath: string }): Promise<DSersAuthResult> {\n const { proc, wsUrlPromise } = tryLaunchBrowser(browser);\n\n proc.on(\"exit\", () => {\n activeProcess = null;\n });\n\n const wsUrl = await wsUrlPromise;\n log.info({ wsUrl }, \"DevTools endpoint acquired\");\n\n const httpUrl = wsUrl.replace(\"ws://\", \"http://\").replace(/\\/devtools\\/browser\\/.*/, \"/json\");\n const resp = await fetch(httpUrl);\n const tabs = (await resp.json()) as { webSocketDebuggerUrl: string; url: string }[];\n const dsersTab = tabs.find((t) => t.url.includes(\"dsers.com\")) ?? tabs[0];\n\n if (!dsersTab?.webSocketDebuggerUrl) {\n throw new Error(\"Could not find browser tab\");\n }\n\n log.info({ tabUrl: dsersTab.url }, \"Watching tab for login API response\");\n const result = await watchLoginResponse(dsersTab.webSocketDebuggerUrl);\n cleanup();\n return result;\n}\n\nexport async function loginViaCDP(): Promise<DSersAuthResult> {\n if (isAuthInProgress()) {\n throw new Error(\"Auth already in progress\");\n }\n\n const browsers = findAllChromium();\n if (!browsers.length) {\n throw new Error(\"No Chromium-based browser found. Please install Chrome, Edge, or Brave.\");\n }\n\n for (let i = 0; i < browsers.length; i++) {\n const browser = browsers[i]!;\n const nextBrowser = browsers[i + 1];\n try {\n return await attemptLoginWithBrowser(browser);\n } catch (error) {\n cleanup();\n const msg = error instanceof Error ? error.message : String(error);\n const isLaunchFailure = msg.includes(\"Browser exited before DevTools was ready\") ||\n msg.includes(\"Timed out waiting for Chrome DevTools\");\n\n if (isLaunchFailure && nextBrowser) {\n log.warn({ browser: browser.name, error: msg, fallback: nextBrowser.name },\n \"Browser launch failed, trying next browser\");\n continue;\n }\n\n if (isLaunchFailure && process.platform === \"win32\") {\n throw new Error(\n `Could not launch browser for DSers login. ` +\n `This usually happens when ${browser.name} is already running. ` +\n `Please close all ${browser.name} windows completely (including the system tray icon) and try again.`\n );\n }\n throw error;\n }\n }\n\n throw new Error(\"All browsers failed to launch for DSers auth.\");\n}\n","/**\n * Find an installed Chromium-based browser on the local machine.\n * Search order: Chrome → Edge → Brave → Arc → Chromium → Opera → Vivaldi\n */\n\nimport { existsSync } from \"node:fs\";\n\ninterface BrowserCandidate {\n name: string;\n paths: Partial<Record<NodeJS.Platform, string[]>>;\n}\n\nconst CANDIDATES: BrowserCandidate[] = [\n {\n name: \"Google Chrome\",\n paths: {\n darwin: [\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\"],\n win32: [\n `${process.env[\"PROGRAMFILES\"]}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n `${process.env[\"PROGRAMFILES(X86)\"]}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n `${process.env[\"LOCALAPPDATA\"]}\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe`,\n ],\n linux: [\"/usr/bin/google-chrome\", \"/usr/bin/google-chrome-stable\"],\n },\n },\n {\n name: \"Microsoft Edge\",\n paths: {\n darwin: [\"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge\"],\n win32: [\n `${process.env[\"PROGRAMFILES(X86)\"]}\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe`,\n `${process.env[\"PROGRAMFILES\"]}\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe`,\n ],\n linux: [\"/usr/bin/microsoft-edge\", \"/usr/bin/microsoft-edge-stable\"],\n },\n },\n {\n name: \"Brave\",\n paths: {\n darwin: [\"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser\"],\n win32: [\n `${process.env[\"PROGRAMFILES\"]}\\\\BraveSoftware\\\\Brave-Browser\\\\Application\\\\brave.exe`,\n `${process.env[\"LOCALAPPDATA\"]}\\\\BraveSoftware\\\\Brave-Browser\\\\Application\\\\brave.exe`,\n ],\n linux: [\"/usr/bin/brave-browser\"],\n },\n },\n {\n name: \"Arc\",\n paths: {\n darwin: [\"/Applications/Arc.app/Contents/MacOS/Arc\"],\n },\n },\n {\n name: \"Chromium\",\n paths: {\n darwin: [\"/Applications/Chromium.app/Contents/MacOS/Chromium\"],\n linux: [\"/usr/bin/chromium\", \"/usr/bin/chromium-browser\"],\n },\n },\n {\n name: \"Opera\",\n paths: {\n darwin: [\"/Applications/Opera.app/Contents/MacOS/Opera\"],\n win32: [\n `${process.env[\"LOCALAPPDATA\"]}\\\\Programs\\\\Opera\\\\opera.exe`,\n ],\n linux: [\"/usr/bin/opera\"],\n },\n },\n {\n name: \"Vivaldi\",\n paths: {\n darwin: [\"/Applications/Vivaldi.app/Contents/MacOS/Vivaldi\"],\n win32: [\n `${process.env[\"LOCALAPPDATA\"]}\\\\Vivaldi\\\\Application\\\\vivaldi.exe`,\n ],\n linux: [\"/usr/bin/vivaldi\"],\n },\n },\n];\n\nexport interface FoundBrowser {\n name: string;\n executablePath: string;\n}\n\nexport function findChromium(): FoundBrowser | null {\n return findAllChromium()[0] ?? null;\n}\n\nexport function findAllChromium(): FoundBrowser[] {\n const platform = process.platform;\n const found: FoundBrowser[] = [];\n\n for (const candidate of CANDIDATES) {\n const platformPaths = candidate.paths[platform];\n if (!platformPaths) continue;\n\n for (const p of platformPaths) {\n if (existsSync(p)) {\n found.push({ name: candidate.name, executablePath: p });\n break;\n }\n }\n }\n\n return found;\n}\n","/**\n * DSClaw Core Agent — unified prototype agent using Vercel AI SDK.\n * Created per-user with their own DSers client and LLM config.\n * System prompt targets zero-technical-ability dropshipping users.\n */\n\nimport { generateText, streamText, type ModelMessage, tool as aiTool, stepCountIs } from \"ai\";\nimport { createOpenAI } from \"@ai-sdk/openai\";\nimport { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\nimport { z } from \"zod\";\nimport type { AgentBase, AgentContext, AgentResponse, AgentTool } from \"./base.js\";\nimport type { DSersClient } from \"../dsers/client.js\";\nimport type { MemoryProvider } from \"../memory/provider.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { writeAuditLog } from \"../shared/audit.js\";\nimport * as productApi from \"../dsers/product.js\";\nimport { configFromToken } from \"@lofder/dsers-mcp-product/dist/dsers/config.js\";\nimport { buildProvider } from \"@lofder/dsers-mcp-product/dist/provider.js\";\nimport { ImportFlowService } from \"@lofder/dsers-mcp-product/dist/service.js\";\nimport { MemoryJobStore } from \"@lofder/dsers-mcp-product/dist/job-store-memory.js\";\nimport type { JobStore } from \"@lofder/dsers-mcp-product/dist/job-store.js\";\nimport { readFileSync, writeFileSync, mkdirSync, renameSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst log = createLogger(\"agent:core\");\n\nconst JOB_ID_MAP_DIR = join(homedir(), \".dsclaw\");\nconst JOB_ID_MAP_FILE = join(JOB_ID_MAP_DIR, \"job-id-map.json\");\nconst JOB_ID_TTL_MS = 7 * 24 * 60 * 60 * 1000;\n\nfunction loadJobIdMap(): Map<string, string> {\n const map = new Map<string, string>();\n try {\n if (!existsSync(JOB_ID_MAP_FILE)) return map;\n const raw = JSON.parse(readFileSync(JOB_ID_MAP_FILE, \"utf-8\")) as Record<string, { full: string; ts: number }>;\n const now = Date.now();\n for (const [short, entry] of Object.entries(raw)) {\n if (now - entry.ts < JOB_ID_TTL_MS) {\n map.set(short, entry.full);\n }\n }\n } catch (err) {\n log.warn({ err }, \"Failed to load job ID map from disk\");\n }\n return map;\n}\n\nfunction persistJobIdMap(map: Map<string, string>): void {\n try {\n mkdirSync(JOB_ID_MAP_DIR, { recursive: true });\n const obj: Record<string, { full: string; ts: number }> = {};\n const now = Date.now();\n for (const [short, full] of map) {\n obj[short] = { full, ts: now };\n }\n const tmp = JOB_ID_MAP_FILE + \".tmp\";\n writeFileSync(tmp, JSON.stringify(obj));\n renameSync(tmp, JOB_ID_MAP_FILE);\n } catch (err) {\n log.warn({ err }, \"Failed to persist job ID map\");\n }\n}\n\nexport interface LLMConfig {\n provider: string;\n apiKey: string;\n model: string;\n baseUrl?: string;\n}\n\nfunction normalizeBaseUrl(url: string | undefined): string | undefined {\n if (!url) return undefined;\n let u = url.trim();\n if (!/^https?:\\/\\//i.test(u)) u = `https://${u}`;\n u = u.replace(/\\/+$/, \"\");\n if (!/\\/v\\d/.test(u)) u += \"/v1\";\n return u;\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {\n return Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n const id = setTimeout(() => reject(new Error(`${label} timed out after ${Math.round(ms / 1000)}s`)), ms);\n if (typeof id === \"object\" && \"unref\" in id) (id as NodeJS.Timeout).unref();\n }),\n ]);\n}\n\nfunction withToolAwareTimeout<T>(\n promise: Promise<T>,\n baseMs: number,\n isToolActive: () => boolean,\n label: string,\n): Promise<T> {\n let timerId: ReturnType<typeof setTimeout> | null = null;\n const cleanup = () => { if (timerId !== null) { clearTimeout(timerId); timerId = null; } };\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n let deadline = Date.now() + baseMs;\n const tick = () => {\n if (isToolActive()) {\n deadline = Date.now() + baseMs;\n timerId = setTimeout(tick, 10_000);\n } else if (Date.now() >= deadline) {\n reject(new Error(`${label} timed out after ${Math.round(baseMs / 1000)}s`));\n } else {\n timerId = setTimeout(tick, Math.min(deadline - Date.now(), 10_000));\n }\n };\n timerId = setTimeout(tick, baseMs);\n });\n\n return Promise.race([promise.finally(cleanup), timeoutPromise]);\n}\n\nconst MCP_PREVIEW_KEYS = new Set([\n \"job_id\", \"batch_id\", \"status\", \"source_url\", \"target_store\",\n \"visibility_mode\", \"title\", \"title_before\", \"title_after\", \"variant_count\",\n \"variants_count\", \"sell_price\", \"cost\", \"compare_at_price\", \"no_markup\",\n \"skus\", \"skus_more\", \"skus_offset\", \"stock\", \"stock_low\", \"supplier_stock\",\n \"desc_changed\", \"images\", \"options\", \"store\", \"visibility\",\n \"ship_to\", \"ship_from\",\n \"rule_summary\", \"total\", \"succeeded\", \"failed\",\n \"error\", \"blocked\", \"warnings\", \"visibility_applied\", \"push_options_applied\",\n \"job_summary\", \"has_push_result\", \"push_result\",\n \"deleted\", \"confirmed\", \"message\",\n]);\n\nconst MCP_DROP_KEYS = new Set([\n \"image_urls\", \"description_html_snippet\",\n \"effective_rules_snapshot\", \"requested_rules\", \"original_draft\",\n \"resolved_source_url\", \"resolver_mode\", \"tags_before\", \"tags_after\",\n]);\n\nfunction compactToolResult(result: Record<string, any>, jobIdMap?: Map<string, string>): Record<string, any> {\n if (!result || typeof result !== \"object\") return result;\n\n const isMcpPreview = \"job_id\" in result && (\"title_after\" in result || \"status\" in result);\n if (isMcpPreview) {\n const out: Record<string, any> = {};\n for (const [k, v] of Object.entries(result)) {\n if (MCP_DROP_KEYS.has(k)) continue;\n out[k] = v;\n }\n if (out.job_id && typeof out.job_id === \"string\") {\n const dotIdx = out.job_id.indexOf(\".\");\n if (dotIdx > 0) {\n const short = out.job_id.slice(0, dotIdx);\n if (jobIdMap) jobIdMap.set(short, out.job_id);\n out.job_id = short;\n }\n }\n if (out.skus && Array.isArray(out.skus) && out.skus.length > 1) {\n const [header, ...rows] = out.skus as [string[], ...any[][]];\n out.variant_summary = rows.slice(0, 5).map((row: any[]) => {\n const obj: Record<string, any> = {};\n header.forEach((key: string, i: number) => { obj[key] = row[i]; });\n return obj;\n });\n if (rows.length > 5) {\n out.variant_summary_note = `Showing 5 of ${rows.length} variants`;\n }\n delete out.skus;\n }\n if (out.title_after) {\n out._title_modified = true;\n out._display_title = out.title_after;\n }\n if (out.desc_changed) {\n out._description_modified = true;\n }\n if (out.warnings?.length > 5) out.warnings = out.warnings.slice(0, 5);\n if (out.stores) {\n out.stores = out.stores.map((s: any) => ({\n store_ref: s.store_ref, display_name: s.display_name, platform: s.platform,\n }));\n }\n if (out.account_info) {\n const ai = out.account_info;\n out.account_info = { plan: ai.plan, limits: ai.limits, aliexpress_auth: ai.aliexpress_auth };\n }\n return out;\n }\n\n const json = JSON.stringify(result);\n if (json.length <= 4000) return result;\n\n const out: Record<string, any> = {};\n for (const [k, v] of Object.entries(result)) {\n if (MCP_DROP_KEYS.has(k)) continue;\n if (Array.isArray(v) && v.length > 20) {\n out[k] = v.slice(0, 20);\n out[`_${k}_truncated`] = `${v.length} total, showing first 20`;\n } else {\n out[k] = v;\n }\n }\n const outJson = JSON.stringify(out);\n if (outJson.length > 8000) {\n return { _truncated: true, _original_size: json.length, summary: outJson.slice(0, 6000) + \"...\" };\n }\n return out;\n}\n\nfunction buildModel(llm: LLMConfig) {\n const baseURL = normalizeBaseUrl(llm.baseUrl);\n\n // Custom URL = proxy, always use OpenAI Chat Completions format\n if (baseURL || llm.provider === \"other\") {\n return createOpenAI({\n apiKey: llm.apiKey,\n baseURL: baseURL ?? \"http://localhost:11434/v1\",\n }).chat(llm.model);\n }\n\n // Direct to official API — use native SDK\n switch (llm.provider) {\n case \"openai\":\n return createOpenAI({ apiKey: llm.apiKey }).chat(llm.model);\n case \"anthropic\":\n return createAnthropic({ apiKey: llm.apiKey })(llm.model);\n case \"google\":\n return createGoogleGenerativeAI({ apiKey: llm.apiKey })(llm.model);\n default:\n return createOpenAI({ apiKey: llm.apiKey }).chat(llm.model);\n }\n}\n\nexport function getDefaultModel(provider: string): string {\n switch (provider) {\n case \"openai\": return \"gpt-4o\";\n case \"anthropic\": return \"claude-sonnet-4-20250514\";\n case \"google\": return \"gemini-2.0-flash\";\n case \"other\": return \"gpt-3.5-turbo\";\n default: return \"gpt-4o\";\n }\n}\n\nconst TOOL_LABELS: Record<string, string> = {\n dsers_store_discover: \"Discovering stores & capabilities...\",\n dsers_product_import: \"Importing product...\",\n dsers_product_preview: \"Loading preview...\",\n dsers_product_delete: \"Deleting product...\",\n dsers_product_visibility: \"Setting visibility...\",\n dsers_store_push: \"Pushing to store...\",\n dsers_rules_validate: \"Validating rules...\",\n dsers_job_status: \"Checking job status...\",\n dsers_import_list_search: \"Searching import list...\",\n dsers_my_products: \"Loading your products...\",\n};\n\nconst SYSTEM_PROMPT = `You are DSClaw, a friendly dropshipping AI for DSers. User has zero technical background.\n{{LANGUAGE_RULE}}\nBe warm, clear. Confirm before push/delete/bulk ops.\n\nPRICES — always show separately:\n- cost (采购价): supplier price. Field: \"cost\"\n- sell_price (售价): store price. Field: \"sell_price\"\n- compare_at_price: strikethrough price\n- no_markup=true → warn user to set pricing rules\n- From dsers_import_list_search: use \"cost_range\" and \"sell_price_range\"\nWhen in Chinese: Format: 采购价:$2.51–$4.00 | 售价:$5.02–$8.00\nWhen in English: Format: Cost: $2.51–$4.00 | Sell price: $5.02–$8.00\n\nWORKFLOWS:\nImport: dsers_store_discover → dsers_product_import(url) → (rules) → dsers_store_push(confirm first)\nBatch: source_urls_json / job_ids_json / target_stores_json\nDelete: dsers_product_delete without confirm → show details → dsers_product_delete with confirm=true\n\nTOOL SELECTION — ALL modifications go through dsers_product_import:\n- dsers_import_list_search returns each item's \"source_url\". Use it for re-import.\n- Title/description/price changes on existing items:\n 1. dsers_product_import(source_url from dsers_import_list_search, rules_json with changes)\n 2. This re-imports and applies rules in one call, persisting changes via MCP.\n- PRICING (pick mode by user intent):\n | \"set price $9.99\" / \"all $9.99\" → fixed_price: {\"pricing\":{\"mode\":\"fixed_price\",\"fixed_price\":9.99}}\n | \"double the price\" / \"3x\" → multiplier: {\"pricing\":{\"mode\":\"multiplier\",\"multiplier\":2.0}}\n | \"add $5 markup\" → fixed_markup: {\"pricing\":{\"mode\":\"fixed_markup\",\"fixed_markup\":5.00}}\n | \"Red $9.99, Blue $12.99\" → variant_overrides: {\"variant_overrides\":[{\"match\":\"Red\",\"sell_price\":9.99},{\"match\":\"Blue\",\"sell_price\":12.99}]}\n All modes accept optional round_digits (0-10).\n- CONTENT: title_override, title_prefix, title_suffix, description_override_html, description_append_html, tags_add (array)\n- IMAGES: drop_indexes, reorder, add_urls, keep_first_n. Only URLs, no base64.\n- VARIANT_OVERRIDES: array of {match, sell_price, compare_at_price, stock, title, image_url}. Applied AFTER global pricing.\n- OPTION_EDITS: array of {action, option_name, value_name?, new_name?}. Actions: rename_option, rename_value, remove_value (DESTRUCTIVE), remove_option.\n- Check response: title_after (changed title), _title_modified, sell_price, cost, desc_changed\n- Existing job_id: dsers_product_import(job_id + rules_json) to re-apply rules.\n\nPUSH CONFIRMATION: Before calling dsers_store_push, ALWAYS show a confirmation checklist and wait for user approval:\n- Product: title, variant count\n- Price: sell vs cost range\n- Store: name\n- Visibility: Draft or Published (warn if Published)\n- Shipping profile: selected profile name, or \"NOT SELECTED\" with available options listed\n- Pricing Rule: MCP pricing or store rule (warn if conflict)\nIf required info is missing (e.g. no shipping profile selected), show warning with available options and ask user to choose.\nONLY call dsers_store_push after explicit user confirmation (e.g. \"push\", \"go\", \"confirmed\", \"推送\", \"确认\").\nException: if user's ORIGINAL message already contains explicit push instruction (\"push it\", \"直接推送\", \"推送到店铺\"), treat as pre-confirmed — show checklist as summary, not blocker.\n\nSHIPPING PROFILES: Shopify stores may have multiple shipping profiles.\n- Single profile → auto-selected, no action needed.\n- Multiple profiles + none specified → push BLOCKED with available_profiles list.\n- Use shipping_profile_name in push_options_json to select one.\n- Do NOT rely on \"default\" profiles — always show user available options when blocked.\n\nERROR RECOVERY:\n- Expired job_id → re-import with source_url\n- blocked array → hard stop, fix before retry\n- warnings array → soft alert, push proceeds\n- push_blocked_by_missing_shipping_profile → show available profiles, ask user to pick, retry with shipping_profile_name\n- Auth/401/session errors → call dsers_authorize to open browser login\n- After dsers_authorize succeeds: tell user authorization succeeded and ask them to resend their request. Do NOT retry in the same turn (session will refresh on next message).\n- If DSers session expired: tell user to go to Settings → Disconnect DSers → Reconnect. NEVER mention terminal commands (npx, npm, node) or environment variables (DSERS_TOKEN).\n- NEVER ask user to run terminal commands or npx`;\n\nexport class DSClawCoreAgent implements AgentBase {\n readonly id = \"dsclaw-core\";\n readonly name = \"DSClaw Core Agent\";\n\n private dsers: DSersClient;\n private memory: MemoryProvider;\n private llm: LLMConfig;\n private customTools: Map<string, AgentTool> = new Map();\n private importService: ImportFlowService | null = null;\n private jobIdMap: Map<string, string> = loadJobIdMap();\n public mcpAvailable = false;\n private authCallback?: () => Promise<{ success: boolean; email?: string; reason?: string }>;\n\n constructor(\n dsers: DSersClient,\n memory: MemoryProvider,\n llm: LLMConfig,\n dsersSession?: { sessionId: string; state: string },\n authCallback?: () => Promise<{ success: boolean; email?: string; reason?: string }>,\n jobStore?: JobStore,\n ) {\n this.dsers = dsers;\n this.memory = memory;\n this.llm = llm;\n this.authCallback = authCallback;\n if (dsersSession?.sessionId) {\n try {\n const mcpConfig = configFromToken(dsersSession.sessionId, dsersSession.state);\n const provider = buildProvider(mcpConfig);\n this.importService = new ImportFlowService(provider, jobStore ?? new MemoryJobStore());\n this.mcpAvailable = true;\n log.info(\"MCP ImportFlowService initialized\");\n } catch (err) {\n log.warn({ err }, \"Failed to init MCP ImportFlowService — product tools unavailable\");\n }\n }\n }\n\n private getSystemPrompt(): string {\n const rule = \"ALWAYS respond in the same language as the user's most recent message. \"\n + \"If they write Chinese, respond in Chinese. If English, respond in English. \"\n + \"Never switch languages unless the user does.\";\n return SYSTEM_PROMPT.replace(\"{{LANGUAGE_RULE}}\", `Language rule: ${rule}`);\n }\n\n private shortenJobId(fullId: string): string {\n const dotIdx = fullId.indexOf(\".\");\n if (dotIdx <= 0) return fullId;\n const short = fullId.slice(0, dotIdx);\n this.jobIdMap.set(short, fullId);\n persistJobIdMap(this.jobIdMap);\n return short;\n }\n\n private resolveJobId(maybeShort: string): string {\n return this.jobIdMap.get(maybeShort) ?? maybeShort;\n }\n\n registerTool(t: AgentTool): void {\n this.customTools.set(t.name, t);\n }\n\n removeTool(name: string): void {\n this.customTools.delete(name);\n }\n\n getTools(): AgentTool[] {\n return Array.from(this.customTools.values());\n }\n\n async process(\n message: string,\n context: AgentContext,\n ): Promise<AgentResponse> {\n const model = buildModel(this.llm);\n\n const memories = await this.memory\n .search(message, { userId: context.userId, limit: 5 })\n .catch(() => []);\n\n const memoryContext =\n memories.length > 0\n ? `\\n\\nRelevant memories:\\n${memories.map((m) => `- ${m.content}`).join(\"\\n\")}`\n : \"\";\n\n const messages: ModelMessage[] = [\n { role: \"system\", content: this.getSystemPrompt() + memoryContext },\n ...context.history.map(\n (h) =>\n ({\n role: h.role as \"user\" | \"assistant\",\n content: h.content,\n }) as ModelMessage,\n ),\n { role: \"user\", content: message },\n ];\n\n const tools = this.buildAITools(context);\n\n log.info(\n { userId: context.userId, messageLen: message.length, toolCount: Object.keys(tools).length },\n \"Processing message\",\n );\n\n try {\n const abort = new AbortController();\n const timer = setTimeout(() => abort.abort(), 120_000);\n const result = await generateText({\n model,\n messages,\n tools,\n stopWhen: stepCountIs(10),\n abortSignal: abort.signal,\n });\n clearTimeout(timer);\n\n const toolCalls =\n result.steps\n ?.flatMap((step) =>\n step.toolCalls?.map((tc) => ({\n tool: tc.toolName,\n params: (\"input\" in tc ? tc.input : {}) as Record<string, unknown>,\n result: {\n success: true,\n data: step.toolResults?.find(\n (tr) => tr.toolCallId === tc.toolCallId,\n )?.output,\n },\n })),\n )\n .filter(Boolean) ?? [];\n\n return {\n text: result.text,\n toolCalls: toolCalls as AgentResponse[\"toolCalls\"],\n };\n } catch (error) {\n log.error({ error, userId: context.userId }, \"Agent processing failed\");\n writeAuditLog({\n userId: context.userId,\n agentId: this.id,\n action: \"process_message\",\n target: \"llm\",\n result: \"failed\",\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Streaming version of process() — yields text chunks for real-time display.\n * Calls onStatus when tool calls happen so the UI can show activity.\n */\n processStream(\n message: string,\n context: AgentContext,\n onStatus?: (status: string) => void,\n callbacks?: {\n onToolCall?: (id: string, name: string, args: Record<string, unknown>) => void;\n onToolResult?: (id: string, name: string, result: unknown, error: string | undefined, durationMs: number) => void;\n },\n attachments?: Array<{ url: string; data?: Buffer; mimeType: string }>,\n ): { textStream: AsyncIterable<string>; response: Promise<AgentResponse> } {\n const model = buildModel(this.llm);\n\n const memories = this.memory\n .search(message, { userId: context.userId, limit: 5 })\n .catch(() => []);\n\n const tools = this.buildAITools(context);\n\n const self = this;\n\n const streamPromise = memories.then((mems) => {\n const memoryContext =\n mems.length > 0\n ? `\\n\\nRelevant memories:\\n${mems.map((m) => `- ${m.content}`).join(\"\\n\")}`\n : \"\";\n\n const userContent: ModelMessage[\"content\"] =\n attachments?.length\n ? [\n ...attachments.map((a) => ({\n type: \"image\" as const,\n image: a.data ?? a.url,\n mimeType: a.mimeType,\n })),\n { type: \"text\" as const, text: message },\n ]\n : message;\n\n const messages: ModelMessage[] = [\n { role: \"system\", content: this.getSystemPrompt() + memoryContext },\n ...context.history.map(\n (h) =>\n ({\n role: h.role as \"user\" | \"assistant\",\n content: h.content,\n }) as ModelMessage,\n ),\n { role: \"user\", content: userContent } as ModelMessage,\n ];\n\n const totalMsgChars = messages.reduce((sum, m) => sum + (typeof m.content === \"string\" ? m.content.length : JSON.stringify(m.content).length), 0);\n const toolNames = Object.keys(tools);\n const toolSchemaChars = JSON.stringify(Object.fromEntries(\n Object.entries(tools).map(([k, v]) => [k, (v as Record<string, unknown>).description ?? \"\"]),\n )).length;\n\n log.info(\n { userId: context.userId, messageLen: message.length, streaming: true,\n llmProvider: self.llm.provider, llmModel: self.llm.model, llmBaseUrl: self.llm.baseUrl,\n historyTurns: context.history.length, totalMsgChars, toolCount: toolNames.length, toolSchemaChars,\n approxTokens: Math.ceil(totalMsgChars / 3.5) },\n \"Processing message (stream)\",\n );\n\n return streamText({\n model,\n messages,\n tools,\n stopWhen: stepCountIs(10),\n onChunk({ chunk }: { chunk: { type: string; toolName?: string; toolCallId?: string; args?: unknown; result?: unknown } }) {\n if (chunk.type === \"tool-call\") {\n toolActive = true;\n const name = chunk.toolName ?? \"\";\n const args = ((chunk as any).args ?? (chunk as any).input ?? {}) as Record<string, unknown>;\n log.info({ tool: name, args: JSON.stringify(args).slice(0, 500) }, \"Tool call\");\n if (onStatus) {\n let label = TOOL_LABELS[name] ?? name;\n if (name === \"dsers_product_import\") {\n if (args.job_id && !args.source_url && !args.source_urls_json) {\n label = args.rules_json ? \"Applying rules...\" : \"Refreshing preview...\";\n }\n }\n onStatus(label ?? \"Working...\");\n }\n if (callbacks?.onToolCall && chunk.toolCallId) {\n toolStartTimes.set(chunk.toolCallId, Date.now());\n callbacks.onToolCall(chunk.toolCallId, name, args);\n }\n }\n if (chunk.type === \"tool-result\") {\n toolActive = false;\n const name = chunk.toolName ?? \"\";\n const output = (chunk as any).output ?? (chunk as any).result;\n const resultStr = JSON.stringify(output ?? \"\").slice(0, 500);\n log.info({ tool: name, resultSnippet: resultStr }, \"Tool result\");\n if (callbacks?.onToolResult && chunk.toolCallId) {\n const startTime = toolStartTimes.get(chunk.toolCallId) ?? Date.now();\n const durationMs = Date.now() - startTime;\n toolStartTimes.delete(chunk.toolCallId);\n callbacks.onToolResult(chunk.toolCallId, name, chunk.result, undefined, durationMs);\n }\n if (onStatus) onStatus(\"Thinking...\");\n }\n },\n });\n });\n\n let toolActive = false;\n const toolStartTimes = new Map<string, number>();\n\n const textStream: AsyncIterable<string> = {\n [Symbol.asyncIterator]() {\n let innerIterator: AsyncIterator<string> | null = null;\n let gotFirstToken = false;\n return {\n async next(): Promise<IteratorResult<string>> {\n try {\n if (!innerIterator) {\n const result = await withTimeout(streamPromise, 60_000, \"LLM init\");\n innerIterator = result.textStream[Symbol.asyncIterator]();\n }\n const timeout = gotFirstToken ? 60_000 : 120_000;\n const res = await withToolAwareTimeout(innerIterator.next(), timeout, () => toolActive, \"LLM response\");\n if (!res.done && res.value) {\n gotFirstToken = true;\n toolActive = false;\n }\n return res;\n } catch (err) {\n log.error({ err, toolActive, gotFirstToken }, \"Stream iterator error\");\n throw err;\n }\n },\n };\n },\n };\n\n const response: Promise<AgentResponse> = streamPromise.then(async (result) => {\n const text = await result.text;\n const steps = await result.steps;\n\n const toolCalls =\n steps\n ?.flatMap((step) =>\n step.toolCalls?.map((tc) => ({\n tool: tc.toolName,\n params: (\"input\" in tc ? tc.input : {}) as Record<string, unknown>,\n result: {\n success: true,\n data: step.toolResults?.find(\n (tr) => tr.toolCallId === tc.toolCallId,\n )?.output,\n },\n })),\n )\n .filter(Boolean) ?? [];\n\n return {\n text,\n toolCalls: toolCalls as AgentResponse[\"toolCalls\"],\n };\n });\n\n return { textStream, response };\n }\n\n private buildAITools(context: AgentContext) {\n const dsers = this.dsers;\n const svc = this.importService;\n const jmap = this.jobIdMap;\n const resolveJid = (id: string) => this.resolveJobId(id);\n const audit = (action: string, target: string, params?: Record<string, unknown>, result: \"pending\" | \"success\" = \"pending\") =>\n writeAuditLog({ userId: context.userId, agentId: this.id, action, target, params, result });\n\n const tools: Record<string, any> = {};\n\n if (svc) {\n tools.dsers_store_discover = aiTool({\n description: \"Get connected stores, account info (plan/limits), and rule capabilities. Call first before import/push.\",\n inputSchema: z.object({\n target_store: z.string().optional().describe(\"Filter by store ID or name\"),\n }),\n execute: async (input) => {\n audit(\"dsers_store_discover\", \"mcp\");\n const result = await withTimeout(svc.getRuleCapabilities(input as Record<string, unknown>), 60_000, \"Store discovery\");\n audit(\"dsers_store_discover\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_product_import = aiTool({\n description:\n \"Import product by URL or re-apply rules to existing job. \" +\n \"Modes: (1) source_url for new import, (2) job_id+rules_json to update rules, (3) job_id alone to refresh. \" +\n \"Expired job_id → re-import with source_url. \" +\n \"Returns: job_id, title (or title_before+title_after), sell_price, cost, variants, blocked, warnings.\",\n inputSchema: z.object({\n source_url: z.string().optional().describe(\"Supplier product URL\"),\n source_urls_json: z.string().optional().describe(\"Batch: JSON array of URLs\"),\n job_id: z.string().optional().describe(\"Existing job ID for rule updates\"),\n source_hint: z.string().optional().describe(\"auto|aliexpress|alibaba|accio\"),\n country: z.string().default(\"US\").describe(\"Country code\"),\n target_store: z.string().optional().describe(\"Store ID or name\"),\n visibility_mode: z.string().optional().describe(\"backend_only|sell_immediately\"),\n rules_json: z.string().optional().describe(\n \"JSON rules. Pricing: fixed_price({fixed_price:9.99}), multiplier({multiplier:2}), fixed_markup({fixed_markup:5}). \" +\n \"Content: title_override, description_override_html. Images: keep_first_n, drop_indexes, add_urls. \" +\n \"variant_overrides: [{match,sell_price,compare_at_price,stock}]. option_edits: [{action,option_name,value_name?,new_name?}].\"\n ),\n }),\n execute: async (input) => {\n audit(\"dsers_product_import\", \"mcp\", input as Record<string, unknown>);\n const payload: Record<string, unknown> = {};\n if (input.job_id && !input.source_url && !input.source_urls_json) {\n payload.job_id = resolveJid(input.job_id);\n if (input.rules_json) {\n try { payload.rules = JSON.parse(input.rules_json); } catch {\n throw new Error(\n \"Invalid JSON in rules_json. Expected: \" +\n '{\"pricing\":{\"mode\":\"fixed_price\",\"fixed_price\":9.99}} or ' +\n '{\"content\":{\"title_override\":\"New Title\"}}',\n );\n }\n } else {\n payload._keep_existing_rules = true;\n }\n if (input.target_store) payload.target_store = input.target_store;\n if (input.visibility_mode) payload.visibility_mode = input.visibility_mode;\n const result = await withTimeout(svc.reapplyRules(payload), 120_000, \"Rule reapply\");\n audit(\"dsers_product_import\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n }\n if (input.source_url) payload.source_url = input.source_url;\n if (input.source_urls_json) {\n try { payload.source_urls = JSON.parse(input.source_urls_json); } catch {\n throw new Error(\"Invalid JSON in source_urls_json.\");\n }\n }\n if (input.source_hint) payload.source_hint = input.source_hint;\n if (input.country) payload.country = input.country;\n if (input.target_store) payload.target_store = input.target_store;\n payload.visibility_mode = input.visibility_mode || \"backend_only\";\n if (input.rules_json) {\n try { payload.rules = JSON.parse(input.rules_json); } catch {\n throw new Error(\"Invalid JSON in rules_json.\");\n }\n }\n const result = await withTimeout(svc.prepareImportCandidate(payload), 120_000, \"Product import\");\n audit(\"dsers_product_import\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_product_preview = aiTool({\n description: \"Reload preview for an imported job. Returns prices, variants, images.\",\n inputSchema: z.object({\n job_id: z.string().describe(\"Job ID from dsers_product_import\"),\n variant_offset: z.number().optional().describe(\"Start index for variant pagination\"),\n variant_limit: z.number().optional().describe(\"Max variants to return\"),\n }),\n execute: async (input) => {\n audit(\"dsers_product_preview\", \"mcp\", input as Record<string, unknown>);\n const result = await withTimeout(svc.getImportPreview({ ...input, job_id: resolveJid(input.job_id) }), 30_000, \"Preview\");\n audit(\"dsers_product_preview\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_store_push = aiTool({\n description:\n \"Push product(s) to store(s). Show confirmation checklist and get user approval first. \" +\n \"May return blocked (shipping_profile, pricing_rule) or warnings. \" +\n \"Use push_options_json with shipping_profile_name when store has multiple shipping profiles.\",\n inputSchema: z.object({\n job_id: z.string().optional().describe(\"Job ID\"),\n job_ids_json: z.string().optional().describe(\"Batch: JSON array of job IDs\"),\n target_store: z.string().optional().describe(\"Store ID or name from dsers_store_discover\"),\n target_stores_json: z.string().optional().describe(\"Multi-store: JSON array of store names\"),\n visibility_mode: z.string().optional().describe(\"backend_only|sell_immediately\"),\n force_push: z.boolean().optional().describe(\"Override safety checks\"),\n push_options_json: z.string().optional().describe(\n 'Push config JSON. Include shipping_profile_name when multiple profiles exist. ' +\n 'E.g. {\"shipping_profile_name\":\"General Profile\",\"pricing_rule_behavior\":\"apply_store_pricing_rule\"}'\n ),\n }),\n execute: async (input) => {\n audit(\"dsers_store_push\", \"mcp\", input as Record<string, unknown>);\n const payload: Record<string, unknown> = {};\n if (input.job_ids_json) {\n try {\n const ids = JSON.parse(input.job_ids_json) as string[];\n payload.job_ids = ids.map(resolveJid);\n } catch { throw new Error(\"Invalid JSON in job_ids_json\"); }\n } else if (input.job_id) {\n payload.job_id = resolveJid(input.job_id);\n }\n if (input.target_store) payload.target_store = input.target_store;\n if (input.target_stores_json) {\n try { payload.target_stores = JSON.parse(input.target_stores_json); } catch { throw new Error(\"Invalid JSON in target_stores_json\"); }\n }\n if (input.visibility_mode) payload.visibility_mode = input.visibility_mode;\n if (input.force_push) payload.force_push = true;\n if (input.push_options_json) {\n try { payload.push_options = JSON.parse(input.push_options_json); } catch { throw new Error(\"Invalid JSON in push_options_json\"); }\n }\n const result = await withTimeout(svc.confirmPushToStore(payload), 180_000, \"Push to store\");\n audit(\"dsers_store_push\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_rules_validate = aiTool({\n description: \"Validate pricing/content/image rules before importing.\",\n inputSchema: z.object({\n rules_json: z.string().describe(\"Rules as JSON string\"),\n target_store: z.string().optional().describe(\"Store ID or name\"),\n }),\n execute: async (input) => {\n audit(\"dsers_rules_validate\", \"mcp\");\n let rules: unknown;\n try { rules = JSON.parse(input.rules_json); } catch { throw new Error(\"Invalid JSON in rules_json\"); }\n const result = await withTimeout(svc.validateRules({ rules, target_store: input.target_store ?? null }), 30_000, \"Rule validation\");\n audit(\"dsers_rules_validate\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_job_status = aiTool({\n description: \"Check job status: preview_ready → push_requested → completed/failed.\",\n inputSchema: z.object({\n job_id: z.string().describe(\"Job ID\"),\n }),\n execute: async (input) => {\n audit(\"dsers_job_status\", \"mcp\", input as Record<string, unknown>);\n const result = await withTimeout(svc.getJobStatus({ ...input, job_id: resolveJid(input.job_id) }), 30_000, \"Job status\");\n audit(\"dsers_job_status\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_product_visibility = aiTool({\n description: \"Set job visibility: backend_only (draft) or sell_immediately (live).\",\n inputSchema: z.object({\n job_id: z.string().describe(\"Job ID\"),\n visibility_mode: z.string().describe(\"backend_only|sell_immediately\"),\n }),\n execute: async (input) => {\n audit(\"dsers_product_visibility\", \"mcp\", input as Record<string, unknown>);\n const result = await withTimeout(svc.setProductVisibility({ ...input, job_id: resolveJid(input.job_id) }), 30_000, \"Set visibility\");\n audit(\"dsers_product_visibility\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n\n tools.dsers_product_delete = aiTool({\n description: \"Delete product from import list. Call without confirm first, then with confirm=true after user approves.\",\n inputSchema: z.object({\n import_item_id: z.string().describe(\"Item ID from dsers_import_list_search\"),\n confirm: z.boolean().optional().describe(\"true only after user approves\"),\n }),\n execute: async (input) => {\n audit(\"dsers_product_delete\", \"mcp\", input as Record<string, unknown>);\n const result = await withTimeout(svc.deleteImportItem(input), 30_000, \"Delete import item\");\n audit(\"dsers_product_delete\", \"mcp\", undefined, \"success\");\n return compactToolResult(result, jmap);\n },\n });\n } else {\n log.warn(\"MCP ImportFlowService not available — no MCP tools registered\");\n }\n\n if (this.authCallback) {\n tools.dsers_authorize = aiTool({\n description: \"Open browser for DSers login. Call when DSers ops fail with auth/401/session errors.\",\n inputSchema: z.object({}),\n execute: async () => {\n const result = await withTimeout(this.authCallback!(), 200_000, \"DSers authorization\");\n return result;\n },\n });\n }\n\n tools.dsers_import_list_search = aiTool({\n description: \"Search import list. Returns items with id, source_url, cost_range, sell_price_range. Use source_url with dsers_product_import for modifications.\",\n inputSchema: z.object({\n page: z.number().optional().describe(\"Page number (default 1)\"),\n pageSize: z.number().optional().describe(\"Items per page (default 20)\"),\n keyword: z.string().optional().describe(\"Search keyword\"),\n }),\n execute: async (input) => {\n audit(\"dsers_import_list_search\", \"dsers:product\", input as Record<string, unknown>);\n const result = await withTimeout(productApi.getImportList(dsers, input as Record<string, unknown>), 30_000, \"Search import list\");\n audit(\"dsers_import_list_search\", \"dsers:product\", undefined, \"success\");\n\n const items = (result as any)?.data?.list ?? (result as any)?.data ?? [];\n if (Array.isArray(items) && items.length > 0) {\n const enriched = await Promise.allSettled(\n items.slice(0, 10).map(async (item: any) => {\n const itemId = item.id ?? item.importListId;\n if (!itemId) return item;\n try {\n const detail = await withTimeout(\n productApi.getImportListItem(dsers, String(itemId)), 15_000, \"Item detail\",\n );\n const detailData = (detail as any)?.data ?? detail;\n const variants = detailData?.variants ?? detailData?.skuList ?? detailData?.variantList ?? [];\n if (!Array.isArray(variants) || !variants.length) return item;\n\n const sellPrices: number[] = [];\n const costPrices: number[] = [];\n for (const v of variants) {\n const rawSell = Number(v.sellPrice ?? v.salePrice ?? v.price);\n const rawCost = Number(v.supplierPrice ?? v.buyPrice ?? v.cost);\n const sell = rawSell > 100 ? rawSell / 100 : rawSell;\n const cost = rawCost > 100 ? rawCost / 100 : rawCost;\n if (Number.isFinite(sell) && sell > 0) sellPrices.push(sell);\n if (Number.isFinite(cost) && cost > 0) costPrices.push(cost);\n }\n\n const enrichedItem = { ...item };\n const supplyProductId = detailData?.supplyProductId ?? item?.supplyProductId;\n const supplyAppId = Number(detailData?.supplyAppId ?? item?.supplyAppId ?? 1);\n if (supplyProductId) {\n if (supplyAppId === 2) {\n enrichedItem.source_url = `https://www.temu.com/product/${supplyProductId}.html`;\n } else if (supplyAppId === 3) {\n enrichedItem.source_url = `https://detail.1688.com/offer/${supplyProductId}.html`;\n } else {\n enrichedItem.source_url = `https://www.aliexpress.com/item/${supplyProductId}.html`;\n }\n }\n if (costPrices.length) {\n enrichedItem.cost_range = `$${Math.min(...costPrices).toFixed(2)} – $${Math.max(...costPrices).toFixed(2)}`;\n }\n if (sellPrices.length) {\n enrichedItem.sell_price_range = `$${Math.min(...sellPrices).toFixed(2)} – $${Math.max(...sellPrices).toFixed(2)}`;\n enrichedItem.no_markup = sellPrices.every((s, i) => Math.abs(s - (costPrices[i] ?? s)) < 0.01);\n }\n enrichedItem.variant_count = variants.length;\n let totalStock = 0;\n const lowStockVariants: Array<{ id: string; sku: string; stock: number }> = [];\n for (const v of variants) {\n const stock = Number(v.stock ?? v.quantity ?? v.inventory ?? 0);\n const safeStock = Number.isFinite(stock) ? stock : 0;\n totalStock += safeStock;\n if (safeStock <= 5) {\n lowStockVariants.push({\n id: String(v.id ?? v.variantId ?? v.skuId ?? \"\"),\n sku: String(v.sku ?? v.skuAttr ?? v.optionName ?? v.title ?? \"\"),\n stock: safeStock,\n });\n }\n }\n enrichedItem.total_stock = totalStock;\n if (lowStockVariants.length > 0) {\n enrichedItem.low_stock_variants = lowStockVariants;\n enrichedItem.low_stock_warning = `${lowStockVariants.length} of ${variants.length} variants have stock ≤ 5`;\n }\n return enrichedItem;\n } catch (err) {\n log.warn({ err, itemId }, \"Failed to enrich import list item\");\n return item;\n }\n }),\n );\n\n const enrichedItems = enriched.map((r) => r.status === \"fulfilled\" ? r.value : items[0]);\n const cleanItems = enrichedItems.map((item: any) => ({\n id: item.id ?? item.importListId,\n title: item.title ?? \"(untitled)\",\n source_url: item.source_url,\n cost_range: item.cost_range,\n sell_price_range: item.sell_price_range,\n no_markup: item.no_markup,\n variant_count: item.variant_count,\n total_stock: item.total_stock,\n low_stock_warning: item.low_stock_warning,\n low_stock_variants: item.low_stock_variants,\n }));\n return { items: cleanItems, total: (result as any)?.data?.total ?? cleanItems.length };\n }\n const rawItems = (result as any)?.data ?? [];\n if (Array.isArray(rawItems)) {\n return { items: rawItems.map((item: any) => ({\n id: item.id ?? item.importListId,\n title: item.title ?? \"(untitled)\",\n })), total: rawItems.length };\n }\n return compactToolResult(result);\n },\n });\n\n tools.dsers_my_products = aiTool({\n description: \"Get products already pushed to stores.\",\n inputSchema: z.object({\n page: z.number().optional(),\n pageSize: z.number().optional(),\n keyword: z.string().optional(),\n storeId: z.string().optional(),\n }),\n execute: async (input) => {\n audit(\"dsers_my_products\", \"dsers:product\", input as Record<string, unknown>);\n const result = await withTimeout(productApi.getMyProducts(dsers, input as Record<string, unknown>), 30_000, \"My products\");\n audit(\"dsers_my_products\", \"dsers:product\", undefined, \"success\");\n return compactToolResult(result);\n },\n });\n\n return tools;\n }\n}\n","/**\n * Audit log for tracking all write operations.\n * Every action an agent takes is recorded so the user\n * can always answer \"what did the bot do?\"\n */\n\nimport { appendFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR } from \"../gateway/config.js\";\nimport { getTraceId } from \"./tracer.js\";\n\nconst AUDIT_DIR = join(CONFIG_DIR, \"audit\");\n\nexport interface AuditEntry {\n timestamp: string;\n traceId: string;\n userId: string;\n agentId: string;\n action: string;\n target: string;\n params?: Record<string, unknown>;\n result: \"success\" | \"failed\" | \"pending\";\n error?: string;\n}\n\nfunction ensureAuditDir(): void {\n if (!existsSync(AUDIT_DIR)) {\n mkdirSync(AUDIT_DIR, { recursive: true });\n }\n}\n\nexport function writeAuditLog(entry: Omit<AuditEntry, \"timestamp\" | \"traceId\">): void {\n ensureAuditDir();\n const full: AuditEntry = {\n ...entry,\n timestamp: new Date().toISOString(),\n traceId: getTraceId(),\n };\n\n const date = full.timestamp.slice(0, 10);\n const file = join(AUDIT_DIR, `${date}.jsonl`);\n\n try {\n appendFileSync(file, JSON.stringify(full) + \"\\n\");\n } catch {\n // Audit write failure should never crash the system\n }\n}\n\nexport function auditFilePath(date: string): string {\n return join(AUDIT_DIR, `${date}.jsonl`);\n}\n","/**\n * DSers Product API — import, preview, push.\n * Core operations for the DSClaw product workflow.\n */\n\nimport type { DSersClient } from \"./client.js\";\n\nexport async function getImportList(\n client: DSersClient,\n params?: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n const filtered = params\n ? Object.fromEntries(Object.entries(params).filter(([, v]) => v != null))\n : {};\n return client.get(\"/dsers-product-bff/import-list\", filtered);\n}\n\nexport async function getImportListItem(\n client: DSersClient,\n id: string,\n): Promise<Record<string, unknown>> {\n return client.get(`/dsers-product-bff/import-list/${id}`);\n}\n\nexport async function importByProductId(\n client: DSersClient,\n body: {\n supplyProductId: string;\n supplyAppId: string | number;\n country: string;\n language?: string[];\n },\n): Promise<Record<string, unknown>> {\n return client.post(\"/dsers-product-bff/import-list/product-id\", body);\n}\n\nexport async function importByProductIdBatch(\n client: DSersClient,\n body: {\n supplyProductIds: string[];\n supplyAppId: string | number;\n country: string;\n isBackError?: number;\n },\n): Promise<Record<string, unknown>> {\n return client.post(\"/dsers-product-bff/import-list/product-id-batch\", body);\n}\n\nexport async function updateImportListItem(\n client: DSersClient,\n id: string,\n updates: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n const { createLogger } = await import(\"../shared/logger.js\");\n const log = createLogger(\"dsers:product\");\n\n const existing = await client.get(`/dsers-product-bff/import-list/${id}`);\n const product = existing?.[\"data\"] ?? existing;\n\n const data =\n product !== null && typeof product === \"object\" && !Array.isArray(product)\n ? { ...(product as Record<string, unknown>), ...updates }\n : updates;\n\n const productKeys = Object.keys(product as Record<string, unknown>);\n const firstVariant = ((product as any)?.variants ?? [])[0];\n log.info({\n id,\n updateKeys: Object.keys(updates),\n productKeys: productKeys.slice(0, 30),\n hasDescription: \"description\" in (product as any),\n hasSpecifications: \"specifications\" in (product as any),\n descFieldInUpdate: !!updates.description,\n titleInProduct: (product as any)?.title?.slice?.(0, 60),\n titleInUpdate: updates.title ? String(updates.title).slice(0, 60) : undefined,\n descInProduct: String((product as any)?.description ?? \"\").slice(0, 80),\n specsInProduct: String((product as any)?.specifications ?? \"\").slice(0, 80),\n descInUpdate: updates.description ? String(updates.description).slice(0, 80) : undefined,\n variantSample: firstVariant ? { id: firstVariant.id, sellPrice: firstVariant.sellPrice, salePrice: firstVariant.salePrice, keys: Object.keys(firstVariant).slice(0, 15) } : null,\n mergedDataSize: JSON.stringify(data).length,\n }, \"updateImportListItem: sending PUT\");\n\n const putResult = await client.put(`/dsers-product-bff/import-list/${id}`, data);\n\n log.info({\n id,\n putResultSnippet: JSON.stringify(putResult).slice(0, 500),\n }, \"updateImportListItem: PUT response\");\n\n return putResult;\n}\n\nexport async function pushToStore(\n client: DSersClient,\n payload: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n return client.post(\"/dsers-product-bff/import-list/push\", {\n data: payload,\n });\n}\n\nexport async function getPushStatus(\n client: DSersClient,\n eventId: string,\n): Promise<Record<string, unknown>> {\n return client.get(`/dsers-product-bff/import-list/push/${eventId}`);\n}\n\nexport async function getMyProducts(\n client: DSersClient,\n params: Record<string, unknown>,\n): Promise<Record<string, unknown>> {\n return client.get(\"/dsers-product-bff/my-product\", params);\n}\n\nexport async function getStoreShippingProfile(\n client: DSersClient,\n storeId?: string,\n): Promise<Record<string, unknown>> {\n const params = storeId != null ? { storeId } : undefined;\n return client.get(\n \"/dsers-product-bff/import-list/push/store-shipping-profile\",\n params,\n );\n}\n","/**\n * DSClaw Gateway — central orchestrator.\n *\n * Flow:\n * 1. User opens web chat (or sends Telegram message)\n * 2. Gateway loads user session (encrypted on disk)\n * 3. If not \"ready\": handle onboarding conversation (no LLM needed)\n * 4. If \"ready\": route to AI agent with streaming (web) or batch (Telegram)\n *\n * Web chat is the default channel (zero config).\n * Telegram is optional (requires bot token in config).\n */\n\nimport type { DSClawConfig } from \"./config.js\";\nimport {\n loadSession,\n saveSession,\n isOnboarding,\n type UserSessionData,\n} from \"./user-session.js\";\nimport { DSersClient } from \"../dsers/client.js\";\nimport { createDSersConfig } from \"../dsers/config.js\";\nimport { loginViaCDP, isAuthInProgress, cancelAuth } from \"../dsers/browser-auth.js\";\nimport { DSClawCoreAgent, getDefaultModel, type LLMConfig } from \"../agents/core-agent.js\";\nimport { MemoryJobStore } from \"@lofder/dsers-mcp-product/dist/job-store-memory.js\";\nimport { WebChatServer } from \"../web/server.js\";\nimport { TelegramAdapter } from \"../channels/telegram.js\";\nimport { FileMemoryProvider } from \"../memory/file-provider.js\";\nimport type { ChannelAdapter, NormalizedMessage } from \"../channels/adapter.js\";\nimport type { MemoryProvider } from \"../memory/provider.js\";\nimport type { AgentMessage, AgentContext } from \"../agents/base.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { runWithTrace } from \"../shared/tracer.js\";\nimport { writeAuditLog } from \"../shared/audit.js\";\nimport { checkInboundLimit, acquireUserLock, debounceUser } from \"../resilience/rate-limiter.js\";\nimport { isDegraded, degradationMessage } from \"../resilience/degradation.js\";\nimport { initTokenCounter } from \"../context/token-counter.js\";\nimport { allocateBudget } from \"../context/context-budget.js\";\nimport { compactWithFlush } from \"../context/compaction.js\";\nimport {\n loadHistory,\n appendHistory,\n setHistory,\n clearHistory,\n getHistory,\n type HistoryMessage,\n} from \"../context/history-store.js\";\nimport { t, type Lang } from \"./i18n.js\";\n\nconst log = createLogger(\"gateway\");\n\nconst SESSION_MAX_SIZE = 500;\nconst SESSION_TTL_MS = 2 * 60 * 60 * 1000; // 2 hours\n\nconst sessionHistories = new Map<string, AgentMessage[]>();\nconst sessionLastAccess = new Map<string, number>();\nconst MAX_HISTORY = 20;\n\nfunction touchSession(key: string): void {\n sessionLastAccess.set(key, Date.now());\n if (sessionHistories.size > SESSION_MAX_SIZE) {\n let oldest = \"\";\n let oldestTs = Infinity;\n for (const [k, ts] of sessionLastAccess) {\n if (ts < oldestTs) { oldest = k; oldestTs = ts; }\n }\n if (oldest) {\n sessionHistories.delete(oldest);\n sessionLastAccess.delete(oldest);\n }\n }\n}\n\nsetInterval(() => {\n const now = Date.now();\n for (const [key, ts] of sessionLastAccess) {\n if (now - ts > SESSION_TTL_MS) {\n sessionHistories.delete(key);\n sessionLastAccess.delete(key);\n }\n }\n}, 10 * 60 * 1000).unref();\n\nfunction detectProviderFromKey(key: string): string | null {\n if (key.startsWith(\"sk-ant-\")) return \"anthropic\";\n if (key.startsWith(\"sk-\")) return \"openai\";\n if (key.startsWith(\"AIza\")) return \"google\";\n return null;\n}\n\nexport class DSClawGateway {\n private config: DSClawConfig;\n private channels: ChannelAdapter[] = [];\n private webChannel: WebChatServer | null = null;\n private memory: MemoryProvider;\n private agents = new Map<string, DSClawCoreAgent>();\n private jobStores = new Map<string, MemoryJobStore>();\n private dsersClients = new Map<string, DSersClient>();\n private lastUserMessages = new Map<string, string>();\n private running = false;\n\n constructor(config: DSClawConfig) {\n this.config = config;\n this.memory = new FileMemoryProvider();\n }\n\n private getLang(session: UserSessionData, channel: ChannelAdapter): Lang {\n if (session.language === \"zh\" || session.language === \"en\") return session.language;\n return channel instanceof WebChatServer ? \"en\" : \"en\";\n }\n\n async start(): Promise<void> {\n log.info(\"Starting DSClaw Gateway...\");\n\n const web = new WebChatServer();\n web.onMessage((msg) => this.handleMessage(web, msg));\n web.onConnect((userId) => this.handleWebConnect(web, userId));\n web.onSettings((userId, action, data) => this.handleSettingsMessage(web, userId, action, data));\n await web.connect({ port: this.config.port });\n this.webChannel = web;\n this.channels.push(web);\n log.info({ port: this.config.port }, \"Web chat channel connected\");\n\n if (this.config.telegramBotToken) {\n try {\n const tg = new TelegramAdapter();\n tg.onMessage((msg) => this.handleMessage(tg, msg));\n await tg.connect({ botToken: this.config.telegramBotToken });\n this.channels.push(tg);\n log.info(\"Telegram channel connected\");\n } catch (error) {\n log.warn({ error }, \"Telegram failed to connect — web chat still available\");\n }\n }\n\n this.running = true;\n log.info(\"DSClaw Gateway started\");\n }\n\n private async handleMessage(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n ): Promise<void> {\n await runWithTrace(\n {\n traceId: message.traceId,\n userId: message.userId,\n channelId: message.channelId,\n },\n async () => {\n const userId = message.userId;\n\n if (!checkInboundLimit(userId)) {\n log.warn({ userId }, \"Rate limit exceeded\");\n await channel.send(userId, { text: t(\"gateway.rateLimit\", loadSession(userId).language) });\n return;\n }\n\n await debounceUser(userId);\n const release = await acquireUserLock(userId);\n const session = loadSession(userId);\n try {\n if (isOnboarding(session.state)) {\n await this.handleOnboarding(channel, message, session);\n } else {\n if (isDegraded(\"llm\")) {\n await channel.send(userId, { text: degradationMessage(\"llm\") });\n return;\n }\n await this.handleReady(channel, message, session);\n }\n } catch (error) {\n log.error({ error, userId }, \"Failed to handle message\");\n let userMsg = t(\"gateway.error.generic\", session.language);\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n if (msg.includes(\"timeout\") || msg.includes(\"timed out\")) {\n userMsg = t(\"gateway.error.timeout\", session.language);\n } else if (msg.includes(\"401\") || msg.includes(\"unauthorized\") || msg.includes(\"api key\")) {\n userMsg = t(\"gateway.error.apiKey\", session.language);\n } else if (msg.includes(\"429\") || msg.includes(\"rate limit\")) {\n userMsg = t(\"gateway.error.rateLimitLlm\", session.language);\n } else if (msg.includes(\"session\") || msg.includes(\"dsers\")) {\n userMsg = t(\"gateway.error.dsers\", session.language);\n }\n }\n await channel.send(userId, { text: userMsg });\n } finally {\n release();\n }\n },\n );\n }\n\n // ─── Auto-welcome on WebSocket connect ──────────────────────────\n\n private handleWebConnect(channel: WebChatServer, userId: string): void {\n const session = loadSession(userId);\n this.pushSettingsState(channel, userId, session);\n\n if (session.state === \"new\") {\n this.onboardWelcome(channel, userId, session).catch((err) => {\n log.error({ error: err, userId }, \"Auto-welcome failed\");\n });\n }\n }\n\n // ─── Settings Panel (Web Only) ─────────────────────────────────\n\n private isDsersConnected(session: UserSessionData): boolean {\n return !!session.dspiSessionId;\n }\n\n private pushSettingsState(channel: WebChatServer, userId: string, session: UserSessionData): void {\n const dsersOk = this.isDsersConnected(session);\n channel.sendSettingsState(userId, {\n dsers: { configured: dsersOk, email: dsersOk ? session.dspiEmail : undefined },\n llm: { configured: !!session.llmApiKey, provider: session.llmProvider, baseUrl: session.llmBaseUrl },\n ready: session.state === \"ready\",\n });\n }\n\n private async applyDSersSession(\n channel: WebChatServer,\n userId: string,\n session: UserSessionData,\n sessionId: string,\n sessionState: string,\n ): Promise<boolean> {\n const dsersConfig = createDSersConfig(session.dspiEmail ?? \"browser\");\n dsersConfig.sessionId = sessionId;\n dsersConfig.sessionState = sessionState;\n const client = new DSersClient(dsersConfig);\n\n const info = await client.get(\"/account-user-bff/v1/users/info\") as Record<string, unknown>;\n const data = info[\"data\"] as Record<string, unknown> | undefined;\n const email = (data?.[\"email\"] as string) ?? session.dspiEmail ?? \"connected\";\n\n session.dspiEmail = email;\n session.dspiSessionId = sessionId;\n session.dspiSessionState = sessionState;\n session.dspiPassword = undefined;\n this.dsersClients.set(userId, client);\n\n if (session.llmApiKey) {\n session.state = \"ready\";\n } else if (![\"onboard_llm\", \"ready\"].includes(session.state)) {\n session.state = \"onboard_llm\";\n }\n saveSession(userId, session);\n\n channel.sendSettingsResult(userId, { section: \"dsers\", success: true });\n this.pushSettingsState(channel, userId, session);\n\n if (session.state === \"ready\") {\n await this.sendReadyMessage(channel, userId);\n }\n return true;\n }\n\n async triggerAuth(userId: string): Promise<{\n success: boolean; email?: string; reason?: string;\n }> {\n if (isAuthInProgress()) {\n return { success: false, reason: \"in_progress\" };\n }\n\n try {\n const result = await loginViaCDP();\n const session = loadSession(userId);\n const dsersConfig = createDSersConfig(session.dspiEmail ?? \"browser\");\n dsersConfig.sessionId = result.sessionId;\n dsersConfig.sessionState = result.state;\n const client = new DSersClient(dsersConfig);\n\n const info = await client.get(\"/account-user-bff/v1/users/info\") as Record<string, unknown>;\n const data = info?.[\"data\"] as Record<string, unknown> | undefined;\n const email = (data?.[\"email\"] as string) ?? \"connected\";\n\n session.dspiEmail = email;\n session.dspiSessionId = result.sessionId;\n session.dspiSessionState = result.state;\n session.dspiPassword = undefined;\n if (session.llmApiKey) session.state = \"ready\";\n saveSession(userId, session);\n this.dsersClients.set(userId, client);\n this.agents.delete(userId);\n\n log.info({ userId, email }, \"triggerAuth succeeded — agent will be recreated on next message\");\n return { success: true, email };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn({ error: msg, userId }, \"triggerAuth failed\");\n\n if (msg.includes(\"cancelled\") || msg.includes(\"closed\")) {\n return { success: false, reason: \"cancelled\" };\n }\n if (msg.includes(\"timed out\") || msg.includes(\"Timed out\")) {\n return { success: false, reason: \"timeout\" };\n }\n if (msg.includes(\"No Chromium\") || msg.includes(\"browser found\")) {\n return { success: false, reason: \"no_browser\" };\n }\n return { success: false, reason: msg };\n }\n }\n\n private async handleSettingsMessage(\n channel: WebChatServer,\n userId: string,\n action: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n const session = loadSession(userId);\n\n switch (action) {\n case \"set_language\": {\n const lang = data[\"lang\"] as string;\n if (lang === \"en\" || lang === \"zh\") {\n session.language = lang;\n saveSession(userId, session);\n }\n break;\n }\n\n case \"get_settings\":\n this.pushSettingsState(channel, userId, session);\n break;\n\n case \"start_dsers_auth\": {\n if (isAuthInProgress()) {\n channel.sendSettingsResult(userId, { section: \"dsers\", success: false, error: \"Auth already in progress.\" });\n return;\n }\n\n channel.sendSettingsResult(userId, { section: \"dsers_auth_started\", success: true });\n\n loginViaCDP()\n .then(async (result) => {\n const freshSession = loadSession(userId);\n await this.applyDSersSession(channel, userId, freshSession, result.sessionId, result.state);\n })\n .catch((error) => {\n const msg = error instanceof Error ? error.message : \"unknown error\";\n log.warn({ error: msg, userId }, \"Browser auth failed\");\n channel.sendSettingsResult(userId, { section: \"dsers\", success: false, error: msg });\n });\n break;\n }\n\n case \"cancel_dsers_auth\": {\n cancelAuth();\n channel.sendSettingsResult(userId, { section: \"dsers_cancelled\", success: true });\n break;\n }\n\n case \"save_dsers_session\": {\n const sessionId = (data[\"sessionId\"] as string)?.trim();\n const sessionState = (data[\"state\"] as string)?.trim() ?? \"\";\n\n if (!sessionId || sessionId.length < 10) {\n channel.sendSettingsResult(userId, { section: \"dsers\", success: false, error: \"Invalid session token.\" });\n return;\n }\n\n try {\n await this.applyDSersSession(channel, userId, session, sessionId, sessionState);\n } catch {\n channel.sendSettingsResult(userId, { section: \"dsers\", success: false, error: \"Session token invalid or expired.\" });\n }\n break;\n }\n\n case \"disconnect_dsers\": {\n session.dspiEmail = undefined;\n session.dspiSessionId = undefined;\n session.dspiSessionState = undefined;\n session.state = \"new\";\n saveSession(userId, session);\n this.agents.delete(userId);\n this.pushSettingsState(channel, userId, session);\n break;\n }\n\n case \"save_llm\": {\n let provider = (data[\"provider\"] as string)?.trim();\n const apiKey = (data[\"apiKey\"] as string)?.trim();\n let baseUrl = (data[\"baseUrl\"] as string)?.trim() || undefined;\n const model = (data[\"model\"] as string)?.trim() || undefined;\n\n if (baseUrl) {\n if (!/^https?:\\/\\//i.test(baseUrl)) baseUrl = `https://${baseUrl}`;\n baseUrl = baseUrl.replace(/\\/+$/, \"\");\n if (!/\\/v\\d/.test(baseUrl)) baseUrl += \"/v1\";\n }\n\n if (!apiKey || apiKey.length < 3) {\n channel.sendSettingsResult(userId, { section: \"llm\", success: false, error: \"Please enter a valid API key.\" });\n return;\n }\n\n if (provider === \"other\" && !baseUrl) {\n channel.sendSettingsResult(userId, { section: \"llm\", success: false, error: \"Please enter the API base URL.\" });\n return;\n }\n\n if (!provider) {\n provider = detectProviderFromKey(apiKey) ?? \"\";\n }\n if (!provider) {\n channel.sendSettingsResult(userId, { section: \"llm\", success: false, error: \"Cannot detect provider. Please select one.\" });\n return;\n }\n\n session.llmProvider = provider;\n session.llmApiKey = apiKey;\n session.llmBaseUrl = baseUrl;\n session.llmModel = model || getDefaultModel(provider);\n\n if (this.isDsersConnected(session)) {\n session.state = \"ready\";\n }\n saveSession(userId, session);\n\n this.agents.delete(userId);\n\n channel.sendSettingsResult(userId, { section: \"llm\", success: true });\n this.pushSettingsState(channel, userId, session);\n\n if (session.state === \"ready\") {\n await this.sendReadyMessage(channel, userId);\n }\n break;\n }\n }\n }\n\n private async sendReadyMessage(channel: ChannelAdapter, userId: string): Promise<void> {\n const session = loadSession(userId);\n if (channel instanceof WebChatServer) {\n channel.sendToast(userId, t(\"gateway.ready.toast\", session.language), \"info\", \"sys-ready\");\n } else {\n await channel.send(userId, { text: t(\"gateway.ready.telegram\", session.language) });\n }\n\n writeAuditLog({\n userId,\n agentId: \"gateway\",\n action: \"onboarding_complete\",\n target: \"user-session\",\n result: \"success\",\n });\n }\n\n // ─── Onboarding State Machine ─────────────────────────────────────\n\n private async handleOnboarding(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n session: UserSessionData,\n ): Promise<void> {\n const userId = message.userId;\n const text = message.text.trim();\n const isCallback = message.metadata[\"isCallback\"] === true;\n const isWeb = channel instanceof WebChatServer;\n\n switch (session.state) {\n case \"new\":\n case \"onboard_demo\":\n await this.onboardWelcome(channel, userId, session);\n break;\n\n case \"onboard_dsers_email\":\n await this.onboardEmail(channel, userId, text, session);\n break;\n\n case \"onboard_dsers_password\":\n await this.onboardPassword(channel, message, session, isWeb);\n break;\n\n case \"onboard_llm\":\n await this.onboardLLM(channel, message, session, isCallback, isWeb);\n break;\n }\n }\n\n private async onboardWelcome(\n channel: ChannelAdapter,\n userId: string,\n session: UserSessionData,\n ): Promise<void> {\n const isWeb = channel instanceof WebChatServer;\n\n const welcome = t(isWeb ? \"gateway.welcome.web\" : \"gateway.welcome.telegram\", session.language);\n\n await channel.send(userId, { text: welcome });\n\n session.state = isWeb ? \"ready\" : \"onboard_dsers_email\";\n saveSession(userId, session);\n }\n\n private async onboardEmail(\n channel: ChannelAdapter,\n userId: string,\n text: string,\n session: UserSessionData,\n ): Promise<void> {\n if (!text.includes(\"@\") || !text.includes(\".\")) {\n await channel.send(userId, {\n text: t(\"gateway.onboard.invalidEmail\", session.language),\n });\n return;\n }\n\n session.dspiEmail = text;\n session.state = \"onboard_dsers_password\";\n saveSession(userId, session);\n\n if (channel instanceof WebChatServer) {\n channel.sendSetInputType(userId, \"password\");\n }\n\n await channel.send(userId, {\n text: t(\"gateway.onboard.passwordPrompt\", session.language) +\n (channel instanceof WebChatServer ? \"\" : t(\"gateway.onboard.passwordPromptNote\", session.language)),\n });\n }\n\n private async onboardPassword(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n session: UserSessionData,\n isWeb: boolean,\n ): Promise<void> {\n const userId = message.userId;\n const password = message.text.trim();\n\n if (isWeb) {\n (channel as WebChatServer).sendClearInput(userId);\n (channel as WebChatServer).sendSetInputType(userId, \"text\");\n } else {\n await channel.deleteMessage(\n message.metadata[\"chatId\"] as string | number,\n message.metadata[\"messageId\"] as number,\n );\n }\n\n if (password.length < 1) {\n await channel.send(userId, { text: t(\"gateway.onboard.emptyPassword\", session.language) });\n if (isWeb) (channel as WebChatServer).sendSetInputType(userId, \"password\");\n return;\n }\n\n session.dspiPassword = password;\n saveSession(userId, session);\n\n await channel.send(userId, { text: t(\"gateway.onboard.verifying\", session.language) });\n\n try {\n const dsersConfig = createDSersConfig(session.dspiEmail!, password);\n const client = new DSersClient(dsersConfig);\n await client.get(\"/account-user-bff/v1/users/info\");\n\n this.dsersClients.set(userId, client);\n\n session.state = \"onboard_llm\";\n session.dspiPassword = undefined;\n saveSession(userId, session);\n\n await channel.send(userId, {\n card: {\n title: \"DSers Connected!\",\n summary:\n \"Your DSers account is verified.\\n\\n\" +\n \"*Step 3/3:* Choose your AI provider and paste your API key.\\n\" +\n \"You only need a key — DSClaw handles everything else.\\n\\n\" +\n \"Get a free key here:\\n\" +\n \"- **OpenAI**: [platform.openai.com/api-keys](https://platform.openai.com/api-keys)\\n\" +\n \"- **Anthropic**: [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys)\\n\" +\n \"- **Google** (recommended, free tier): [aistudio.google.com/apikey](https://aistudio.google.com/apikey)\",\n actions: [\n { label: \"OpenAI (GPT-4o)\", callbackData: \"llm:openai\" },\n { label: \"Anthropic (Claude)\", callbackData: \"llm:anthropic\" },\n { label: \"Google (Gemini) ★\", callbackData: \"llm:google\" },\n ],\n },\n });\n } catch (error) {\n session.dspiPassword = undefined;\n session.state = \"onboard_dsers_password\";\n saveSession(userId, session);\n\n if (isWeb) (channel as WebChatServer).sendSetInputType(userId, \"password\");\n\n const msg =\n error instanceof Error && error.message.includes(\"401\")\n ? t(\"gateway.onboard.loginFailed\", session.language)\n : t(\"gateway.onboard.loginFailedGeneric\", session.language, { error: error instanceof Error ? error.message : \"unknown error\" });\n\n await channel.send(userId, { text: msg });\n }\n }\n\n private async onboardLLM(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n session: UserSessionData,\n isCallback: boolean,\n isWeb: boolean,\n ): Promise<void> {\n const userId = message.userId;\n const text = message.text.trim();\n\n if (isCallback && text.startsWith(\"llm:\")) {\n const provider = text.replace(\"llm:\", \"\");\n session.llmProvider = provider;\n saveSession(userId, session);\n\n const providerName =\n provider === \"openai\" ? \"OpenAI\" :\n provider === \"anthropic\" ? \"Anthropic\" : \"Google\";\n\n if (isWeb) (channel as WebChatServer).sendSetInputType(userId, \"password\");\n\n await channel.send(userId, {\n text: t(\"gateway.onboard.chooseProvider\", session.language, { provider: providerName }) +\n (isWeb ? \"\" : \"\\n_I will delete your message immediately._\"),\n });\n return;\n }\n\n if (!session.llmProvider) {\n const detected = detectProviderFromKey(text);\n if (detected && text.length >= 10) {\n session.llmProvider = detected;\n saveSession(userId, session);\n } else {\n await channel.send(userId, {\n card: {\n title: \"Choose AI Provider\",\n summary:\n \"Please select your AI provider first, or paste your API key directly — I'll auto-detect.\\n\\n\" +\n \"Get a free key:\\n\" +\n \"- **OpenAI**: [platform.openai.com/api-keys](https://platform.openai.com/api-keys)\\n\" +\n \"- **Anthropic**: [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys)\\n\" +\n \"- **Google** (recommended): [aistudio.google.com/apikey](https://aistudio.google.com/apikey)\",\n actions: [\n { label: \"OpenAI (GPT-4o)\", callbackData: \"llm:openai\" },\n { label: \"Anthropic (Claude)\", callbackData: \"llm:anthropic\" },\n { label: \"Google (Gemini) ★\", callbackData: \"llm:google\" },\n ],\n },\n });\n return;\n }\n }\n\n if (isWeb) {\n (channel as WebChatServer).sendClearInput(userId);\n (channel as WebChatServer).sendSetInputType(userId, \"text\");\n } else {\n await channel.deleteMessage(\n message.metadata[\"chatId\"] as string | number,\n message.metadata[\"messageId\"] as number,\n );\n }\n\n if (text.length < 10) {\n await channel.send(userId, { text: t(\"gateway.onboard.invalidApiKey\", session.language) });\n if (isWeb) (channel as WebChatServer).sendSetInputType(userId, \"password\");\n return;\n }\n\n session.llmApiKey = text;\n session.llmModel = getDefaultModel(session.llmProvider);\n session.state = \"ready\";\n saveSession(userId, session);\n\n await channel.send(userId, {\n text: t(\"gateway.ready.telegram\", session.language),\n });\n\n writeAuditLog({\n userId,\n agentId: \"gateway\",\n action: \"onboarding_complete\",\n target: \"user-session\",\n result: \"success\",\n });\n }\n\n // ─── Ready State: Route to AI Agent ───────────────────────────────\n\n private async handleReady(\n channel: ChannelAdapter,\n message: NormalizedMessage,\n session: UserSessionData,\n ): Promise<void> {\n const userId = message.userId;\n\n const cmd = message.text.trim().toLowerCase();\n\n if (cmd === \"/reset\") {\n this.agents.delete(userId);\n this.lastUserMessages.delete(userId);\n for (const key of sessionHistories.keys()) {\n if (key.endsWith(`:${userId}`)) sessionHistories.delete(key);\n }\n clearHistory(userId);\n\n const preserved: UserSessionData = {\n state: \"ready\",\n dspiEmail: session.dspiEmail,\n dspiSessionId: session.dspiSessionId,\n dspiSessionState: session.dspiSessionState,\n llmProvider: session.llmProvider,\n llmApiKey: session.llmApiKey,\n llmModel: session.llmModel,\n llmBaseUrl: session.llmBaseUrl,\n language: session.language,\n };\n saveSession(userId, preserved);\n\n if (channel instanceof WebChatServer) {\n channel.sendReset(userId);\n this.pushSettingsState(channel, userId, preserved);\n channel.sendToast(userId, t(\"gateway.cmd.reset\", session.language), \"info\", \"sys-reset\");\n } else {\n await channel.send(userId, { text: t(\"gateway.cmd.reset\", session.language) });\n }\n return;\n }\n\n if (cmd === \"/logout\") {\n this.agents.delete(userId);\n this.jobStores.delete(userId);\n this.dsersClients.delete(userId);\n this.lastUserMessages.delete(userId);\n for (const key of sessionHistories.keys()) {\n if (key.endsWith(`:${userId}`)) sessionHistories.delete(key);\n }\n clearHistory(userId);\n saveSession(userId, { state: \"new\" });\n if (channel instanceof WebChatServer) {\n channel.sendReset(userId);\n this.pushSettingsState(channel, userId, { state: \"new\" });\n channel.sendToast(userId, t(\"gateway.cmd.logout\", session.language), \"info\", \"sys-logout\");\n } else {\n await channel.send(userId, { text: t(\"gateway.cmd.logout\", session.language) });\n }\n return;\n }\n\n if (cmd === \"/retry\") {\n const lastMsg = this.lastUserMessages.get(userId);\n if (!lastMsg) {\n if (channel instanceof WebChatServer) {\n channel.sendToast(userId, t(\"gateway.cmd.retryEmpty\", session.language), \"warn\", \"sys-retry-empty\");\n } else {\n await channel.send(userId, { text: t(\"gateway.cmd.retryEmpty\", session.language) });\n }\n return;\n }\n log.info({ userId, retryText: lastMsg.slice(0, 80) }, \"Retrying last message\");\n message = { ...message, text: lastMsg };\n } else {\n this.lastUserMessages.set(userId, message.text);\n }\n\n if (!session.llmApiKey) {\n if (channel instanceof WebChatServer) {\n channel.sendToast(userId, t(\"gateway.noApiKey.web\", session.language), \"warn\", \"sys-no-apikey\");\n } else {\n await channel.send(userId, { text: t(\"gateway.noApiKey.telegram\", session.language) });\n }\n return;\n }\n\n const agent = this.getOrCreateAgent(userId, session);\n const sessionKey = `${channel.name}:${userId}`;\n touchSession(sessionKey);\n const history = sessionHistories.get(sessionKey) ?? [];\n\n // Token-aware budget allocation with message-count fallback\n const budget = allocateBudget(\"\", \"\", history, {});\n const budgetedHistory: AgentMessage[] = (\n budget.fallbackMode ? history.slice(-MAX_HISTORY) : budget.messages\n ) as AgentMessage[];\n\n if (budget.shouldCompact && !budget.fallbackMode) {\n log.info(\n { sessionKey, totalTokens: budget.totalTokens, remaining: budget.remainingTokens },\n \"Context nearing limit — consider compaction\",\n );\n }\n\n const context: AgentContext = {\n userId,\n sessionId: sessionKey,\n channelId: channel.name,\n history: budgetedHistory,\n };\n\n writeAuditLog({\n userId,\n agentId: agent.id,\n action: \"receive_message\",\n target: channel.name,\n params: { text: message.text.slice(0, 100) },\n result: \"success\",\n });\n\n try {\n if (channel instanceof WebChatServer) {\n await this.handleReadyStreaming(channel, userId, message.text, agent, context, history, sessionKey, session, message.attachments);\n } else {\n await this.handleReadyBatch(channel, userId, message.text, agent, context, history, sessionKey);\n }\n } catch (error) {\n log.error({ error, userId }, \"Agent processing failed\");\n\n writeAuditLog({\n userId,\n agentId: agent.id,\n action: \"process_failed\",\n target: channel.name,\n result: \"failed\",\n error: error instanceof Error ? error.message : String(error),\n });\n\n if (channel instanceof WebChatServer) {\n channel.sendTyping(userId, false);\n channel.sendStatus(userId, \"\");\n channel.sendLog(userId, {\n level: \"error\", module: \"gateway\",\n msg: `Error: ${error instanceof Error ? error.message : String(error)}`,\n ts: new Date().toISOString(),\n });\n }\n\n const errMsg = error instanceof Error ? error.message : \"\";\n if (errMsg.includes(\"timed out\")) {\n const stage = errMsg.includes(\"LLM init\") ? t(\"gateway.stage.llmConnection\", session.language)\n : errMsg.includes(\"LLM response\") ? t(\"gateway.stage.llmResponse\", session.language)\n : errMsg.includes(\"Rule reapply\") ? t(\"gateway.stage.rulesApply\", session.language)\n : errMsg.includes(\"Product import\") ? t(\"gateway.stage.productImport\", session.language)\n : t(\"gateway.stage.processing\", session.language);\n await channel.send(userId, {\n text: t(\"gateway.stream.stageTimeout\", session.language, { stage }),\n });\n } else if (errMsg.includes(\"401\") || errMsg.includes(\"API key\")) {\n await channel.send(userId, {\n text: t(\"gateway.stream.badApiKey\", session.language),\n });\n } else {\n await channel.send(userId, {\n text: t(\"gateway.stream.processFailed\", session.language),\n });\n }\n }\n }\n\n private async handleReadyStreaming(\n channel: WebChatServer,\n userId: string,\n text: string,\n agent: DSClawCoreAgent,\n context: Parameters<DSClawCoreAgent[\"process\"]>[1],\n history: AgentMessage[],\n sessionKey: string,\n session: UserSessionData,\n attachments?: import(\"../channels/adapter.js\").Attachment[],\n ): Promise<void> {\n channel.sendTyping(userId, true);\n channel.sendStatus(userId, \"Thinking...\");\n\n const ts = () => new Date().toISOString();\n channel.sendLog(userId, { level: \"info\", module: \"gateway\", msg: `Processing: \"${text.slice(0, 80)}\"`, ts: ts() });\n\n const imageAttachments = attachments\n ?.filter((a) => a.type === \"image\")\n .map((a) => ({ url: a.url ?? \"\", data: a.data, mimeType: a.mimeType ?? \"image/png\" }));\n\n const runningTools = new Map<string, { name: string; startedAt: number }>();\n let resolveToolsSettled: (() => void) | null = null;\n const toolsSettled = new Promise<void>((r) => { resolveToolsSettled = r; });\n\n const { textStream, response } = agent.processStream(\n text,\n context,\n (status) => { channel.sendStatus(userId, status); },\n {\n onToolCall: (id, name, args) => {\n runningTools.set(id, { name, startedAt: Date.now() });\n channel.sendToolCallStart(userId, id, name, args);\n channel.sendLog(userId, { level: \"info\", module: \"agent\", msg: `Tool call: ${name}`, ts: ts() });\n },\n onToolResult: (id, name, result, error, durationMs) => {\n runningTools.delete(id);\n channel.sendToolCallEnd(userId, id, name, result, error, durationMs);\n channel.sendLog(userId, {\n level: error ? \"error\" : \"info\",\n module: \"agent\",\n msg: `Tool ${name} ${error ? \"failed\" : \"done\"} (${durationMs}ms)`,\n ts: ts(),\n });\n if (runningTools.size === 0 && resolveToolsSettled) resolveToolsSettled();\n },\n },\n imageAttachments?.length ? imageAttachments : undefined,\n );\n\n let streamStarted = false;\n try {\n for await (const chunk of textStream) {\n if (!streamStarted) {\n channel.sendTyping(userId, false);\n channel.sendStatus(userId, \"\");\n channel.sendStreamStart(userId);\n streamStarted = true;\n }\n channel.sendStreamDelta(userId, chunk);\n }\n } catch (streamErr) {\n log.error({ error: streamErr, userId }, \"Stream iteration failed\");\n if (streamStarted) {\n const errMsg = streamErr instanceof Error ? streamErr.message : \"Unknown error\";\n channel.sendStreamDelta(userId, `\\n\\n⚠️ ${errMsg}`);\n } else {\n response.catch(() => {});\n throw streamErr;\n }\n } finally {\n if (runningTools.size > 0) {\n try {\n await Promise.race([toolsSettled, new Promise((r) => setTimeout(r, 15_000))]);\n } catch { /* grace period expired */ }\n }\n\n for (const [id, info] of runningTools) {\n const elapsed = Date.now() - info.startedAt;\n channel.sendToolCallEnd(userId, id, info.name, undefined, \"Aborted (stream terminated)\", elapsed);\n }\n runningTools.clear();\n\n if (!streamStarted) {\n channel.sendTyping(userId, false);\n channel.sendStatus(userId, \"\");\n }\n channel.sendStreamEnd(userId);\n }\n log.info({ userId, streamStarted }, \"Stream loop finished, awaiting response finalization\");\n\n let result;\n try {\n result = await Promise.race([\n response,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"Response finalization timed out\")), 60_000),\n ),\n ]);\n } catch (finalErr) {\n log.warn({ error: finalErr, userId }, \"Response finalization failed — saving partial history\");\n history.push({ role: \"user\", content: text });\n history.push({ role: \"assistant\", content: \"(response incomplete)\" });\n sessionHistories.set(sessionKey, history.slice(-MAX_HISTORY * 2));\n\n if (!streamStarted && channel instanceof WebChatServer) {\n await channel.send(userId, { text: t(\"gateway.stream.incomplete\", session.language) });\n }\n return;\n }\n\n const textLen = result.text?.length ?? 0;\n const toolCallCount = result.toolCalls?.length ?? 0;\n log.info({ userId, textLen, toolCallCount }, \"Response finalized\");\n\n if (!streamStarted && channel instanceof WebChatServer) {\n if (result.text) {\n await channel.send(userId, { text: result.text });\n } else if (toolCallCount > 0) {\n const names = result.toolCalls!.map((tc) => tc.tool).join(\", \");\n await channel.send(userId, {\n text: t(\"gateway.stream.toolsNoText\", session.language, { count: toolCallCount, names }),\n });\n } else {\n await channel.send(userId, { text: t(\"gateway.stream.noReply\", session.language) });\n }\n }\n\n history.push({ role: \"user\", content: text });\n history.push({ role: \"assistant\", content: result.text || \"(tool calls completed)\" });\n\n // Token-aware compaction with memory flush\n const postBudget = allocateBudget(\"\", \"\", history, {});\n if (postBudget.shouldCompact && !postBudget.fallbackMode) {\n const compacted = await compactWithFlush(\n history,\n MAX_HISTORY * 2,\n this.memory,\n userId,\n );\n sessionHistories.set(sessionKey, compacted.messages as AgentMessage[]);\n } else {\n sessionHistories.set(sessionKey, history.slice(-MAX_HISTORY * 2));\n }\n\n // Persist to disk\n appendHistory(\n sessionKey,\n { role: \"user\", content: text },\n { role: \"assistant\", content: result.text },\n );\n\n writeAuditLog({\n userId,\n agentId: agent.id,\n action: \"send_response\",\n target: \"web\",\n params: {\n responseLen: result.text.length,\n toolCalls: result.toolCalls?.length ?? 0,\n streaming: true,\n },\n result: \"success\",\n });\n }\n\n private async handleReadyBatch(\n channel: ChannelAdapter,\n userId: string,\n text: string,\n agent: DSClawCoreAgent,\n context: Parameters<DSClawCoreAgent[\"process\"]>[1],\n history: AgentMessage[],\n sessionKey: string,\n ): Promise<void> {\n const result = await agent.process(text, context);\n\n history.push({ role: \"user\", content: text });\n history.push({ role: \"assistant\", content: result.text });\n\n const postBudget = allocateBudget(\"\", \"\", history, {});\n if (postBudget.shouldCompact && !postBudget.fallbackMode) {\n const compacted = await compactWithFlush(\n history,\n MAX_HISTORY * 2,\n this.memory,\n userId,\n );\n sessionHistories.set(sessionKey, compacted.messages as AgentMessage[]);\n } else {\n sessionHistories.set(sessionKey, history.slice(-MAX_HISTORY * 2));\n }\n\n appendHistory(\n sessionKey,\n { role: \"user\", content: text },\n { role: \"assistant\", content: result.text },\n );\n\n if (result.text) {\n await channel.send(userId, { text: result.text });\n }\n\n writeAuditLog({\n userId,\n agentId: agent.id,\n action: \"send_response\",\n target: channel.name,\n params: {\n responseLen: result.text.length,\n toolCalls: result.toolCalls?.length ?? 0,\n },\n result: \"success\",\n });\n }\n\n private getOrCreateAgent(userId: string, session: UserSessionData): DSClawCoreAgent {\n let agent = this.agents.get(userId);\n if (agent) return agent;\n\n const dsersConfig = createDSersConfig(session.dspiEmail ?? \"unknown\");\n if (session.dspiSessionId) {\n dsersConfig.sessionId = session.dspiSessionId;\n dsersConfig.sessionState = session.dspiSessionState ?? \"\";\n }\n const dsersClient = new DSersClient(dsersConfig);\n this.dsersClients.set(userId, dsersClient);\n\n const llm: LLMConfig = {\n provider: session.llmProvider!,\n apiKey: session.llmApiKey!,\n model: session.llmModel ?? getDefaultModel(session.llmProvider!),\n baseUrl: session.llmBaseUrl,\n };\n\n const dsersSession = session.dspiSessionId\n ? { sessionId: session.dspiSessionId, state: session.dspiSessionState ?? \"\" }\n : undefined;\n const authCb = () => this.triggerAuth(userId);\n let jobStore = this.jobStores.get(userId);\n if (!jobStore) {\n jobStore = new MemoryJobStore();\n this.jobStores.set(userId, jobStore);\n }\n agent = new DSClawCoreAgent(dsersClient, this.memory, llm, dsersSession, authCb, jobStore);\n this.agents.set(userId, agent);\n\n if (!agent.mcpAvailable) {\n log.warn({ userId }, \"MCP unavailable for agent — notifying user\");\n for (const ch of this.channels) {\n ch.send(userId, {\n text: t(\"gateway.mcp.unavailable\", session.language),\n }).catch(() => {});\n }\n }\n\n return agent;\n }\n\n async stop(): Promise<void> {\n log.info(\"Stopping DSClaw Gateway...\");\n for (const ch of this.channels) {\n await ch.disconnect();\n }\n this.running = false;\n log.info(\"DSClaw Gateway stopped\");\n }\n\n isRunning(): boolean {\n return this.running;\n }\n\n get actualPort(): number {\n return this.webChannel?.actualPort ?? this.config.port;\n }\n}\n","/**\n * Web Chat Server — HTTP + WebSocket.\n * Serves React SPA (build output) and handles real-time messaging via WebSocket.\n * Implements ChannelAdapter for gateway integration.\n * Supports streaming, tool call events, logs, and init progress.\n */\n\nimport { createServer, type Server } from \"node:http\";\nimport { readFileSync, writeFileSync, mkdirSync, existsSync, statSync, readdirSync } from \"node:fs\";\nimport { join, dirname, extname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { homedir } from \"node:os\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport { nanoid } from \"nanoid\";\nimport type {\n ChannelAdapter,\n MessageHandler,\n NormalizedMessage,\n OutboundMessage,\n ActionCard,\n} from \"../channels/adapter.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"channel:web\");\n\nconst DEFAULT_WEB_USER = \"web-default\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"application/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff2\": \"font/woff2\",\n \".woff\": \"font/woff\",\n};\n\nfunction findWebDir(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n const candidates = [\n join(thisDir, \"web\"),\n join(thisDir),\n join(thisDir, \"..\", \"web\"),\n join(thisDir, \"..\", \"dist\", \"web\"),\n join(thisDir, \"..\", \"..\", \"dist\", \"web\"),\n ];\n\n for (const d of candidates) {\n if (existsSync(join(d, \"index.html\"))) return d;\n }\n\n throw new Error(\n `Web build not found (index.html). Looked in:\\n` + candidates.join(\"\\n\"),\n );\n}\n\ntype ConnectHandler = (userId: string) => void;\ntype SettingsHandler = (userId: string, action: string, data: Record<string, unknown>) => Promise<void>;\n\nexport interface SettingsState {\n dsers: { configured: boolean; email?: string };\n llm: { configured: boolean; provider?: string; baseUrl?: string };\n ready: boolean;\n}\n\nexport class WebChatServer implements ChannelAdapter {\n readonly name = \"web\";\n private server: Server | null = null;\n private wss: WebSocketServer | null = null;\n private handler: MessageHandler | null = null;\n private connectHandler: ConnectHandler | null = null;\n private settingsHandler: SettingsHandler | null = null;\n private connections = new Map<string, WebSocket>();\n private _connected = false;\n private port = 3000;\n\n get connected(): boolean {\n return this._connected;\n }\n\n get actualPort(): number {\n return this.port;\n }\n\n async connect(config: Record<string, unknown>): Promise<void> {\n const basePort = (config[\"port\"] as number) ?? 3000;\n const webDir = findWebDir();\n const maxAttempts = 10;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const tryPort = basePort + attempt;\n const ok = await this.tryListen(tryPort, webDir);\n if (ok) return;\n if (attempt < maxAttempts - 1) {\n log.warn({ port: tryPort }, \"Port in use, trying next\");\n }\n }\n throw new Error(`No available port found (tried ${basePort}-${basePort + maxAttempts - 1})`);\n }\n\n private tryListen(tryPort: number, webDir: string): Promise<boolean> {\n return new Promise((resolve) => {\n const indexHtml = readFileSync(join(webDir, \"index.html\"), \"utf-8\");\n\n const srv = createServer((req, res) => {\n if (req.url === \"/health\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, clients: this.connections.size }));\n return;\n }\n\n // Serve uploaded images\n const urlPath = req.url?.split(\"?\")[0] ?? \"/\";\n if (urlPath.startsWith(\"/uploads/\")) {\n const uploadsDir = join(homedir(), \".dsclaw\", \"uploads\");\n const fileName = urlPath.slice(\"/uploads/\".length);\n if (/^[a-zA-Z0-9._-]+$/.test(fileName)) {\n const filePath = join(uploadsDir, fileName);\n if (existsSync(filePath) && statSync(filePath).isFile()) {\n const ext = extname(filePath);\n const mime = MIME_TYPES[ext] ?? \"application/octet-stream\";\n res.writeHead(200, { \"Content-Type\": mime, \"Cache-Control\": \"public, max-age=86400\" });\n res.end(readFileSync(filePath));\n return;\n }\n }\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n // Serve static assets\n if (urlPath !== \"/\" && urlPath !== \"/index.html\") {\n const filePath = join(webDir, urlPath);\n if (existsSync(filePath) && statSync(filePath).isFile()) {\n const ext = extname(filePath);\n const contentType = MIME_TYPES[ext] ?? \"application/octet-stream\";\n const cacheHeader = urlPath.includes(\"/assets/\") ? \"public, max-age=31536000, immutable\" : \"no-cache\";\n res.writeHead(200, { \"Content-Type\": contentType, \"Cache-Control\": cacheHeader });\n res.end(readFileSync(filePath));\n return;\n }\n }\n\n // SPA fallback — always return index.html\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\", \"Cache-Control\": \"no-cache\" });\n res.end(indexHtml);\n });\n\n srv.once(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n resolve(false);\n } else {\n throw err;\n }\n });\n\n srv.listen(tryPort, () => {\n this.server = srv;\n this.port = tryPort;\n this._connected = true;\n this.setupWebSocket();\n log.info({ port: tryPort }, \"Web chat server started\");\n resolve(true);\n });\n });\n }\n\n private setupWebSocket(): void {\n this.wss = new WebSocketServer({ server: this.server!, path: \"/ws\" });\n\n this.wss.on(\"connection\", (ws, _req) => {\n let clientId = DEFAULT_WEB_USER;\n\n this.wsSend(ws, { type: \"session\", userId: clientId });\n this.connections.set(clientId, ws);\n log.info({ userId: clientId }, \"Web client connected\");\n\n if (this.connectHandler) {\n try { this.connectHandler(clientId); } catch (err) {\n log.error({ error: err, userId: clientId }, \"Connect handler failed\");\n }\n }\n\n try {\n const files = this.buildFileTree();\n this.wsSend(ws, { type: \"file_list\", files });\n } catch (err) {\n log.warn({ error: err }, \"Failed to push initial file_list\");\n }\n\n ws.on(\"message\", async (raw) => {\n try {\n const msg = JSON.parse(raw.toString()) as Record<string, unknown>;\n this.connections.set(clientId, ws);\n\n const msgType = msg[\"type\"] as string;\n\n if (msgType === \"get_settings\" || msgType === \"start_dsers_auth\" || msgType === \"cancel_dsers_auth\" || msgType === \"save_dsers_session\" || msgType === \"save_llm\" || msgType === \"disconnect_dsers\" || msgType === \"set_language\") {\n log.info({ userId: clientId, action: msgType }, \"Settings message received\");\n if (this.settingsHandler) {\n await this.settingsHandler(clientId, msgType, msg);\n }\n return;\n }\n\n if (msgType === \"list_files\") {\n const files = this.buildFileTree();\n this.wsSend(ws, { type: \"file_list\", files });\n return;\n }\n\n if (msgType === \"read_file\") {\n const filePath = msg[\"path\"] as string;\n this.handleReadFile(ws, filePath);\n return;\n }\n\n if (!this.handler) return;\n\n if (msgType === \"message\" || msgType === \"callback\") {\n const rawAttachments = msg[\"attachments\"] as Array<{ data: string; mimeType: string; name: string }> | undefined;\n const attachments = rawAttachments?.length\n ? this.saveAttachments(rawAttachments)\n : undefined;\n\n const normalized: NormalizedMessage = {\n traceId: nanoid(),\n channelId: \"web\",\n channelName: \"Web Chat\",\n userId: clientId,\n text: msgType === \"callback\"\n ? (msg[\"data\"] as string)\n : (msg[\"text\"] as string),\n attachments,\n timestamp: new Date(),\n metadata: {\n isCallback: msgType === \"callback\",\n },\n };\n await this.handler(normalized);\n }\n } catch (error) {\n log.error({ error }, \"WS message handler failed\");\n }\n });\n\n ws.on(\"close\", () => {\n this.connections.delete(clientId);\n log.debug({ userId: clientId }, \"Web client disconnected\");\n });\n\n ws.on(\"error\", (err) => {\n log.warn({ error: err.message, userId: clientId }, \"WS error\");\n });\n });\n }\n\n async disconnect(): Promise<void> {\n for (const ws of this.connections.values()) {\n ws.close();\n }\n this.connections.clear();\n this.wss?.close();\n await new Promise<void>((resolve) => {\n if (this.server) this.server.close(() => resolve());\n else resolve();\n });\n this._connected = false;\n log.info(\"Web chat server stopped\");\n }\n\n async reconnect(): Promise<void> {\n await this.disconnect();\n await this.connect({ port: this.port });\n }\n\n onMessage(handler: MessageHandler): void {\n this.handler = handler;\n }\n\n onConnect(handler: ConnectHandler): void {\n this.connectHandler = handler;\n }\n\n onSettings(handler: SettingsHandler): void {\n this.settingsHandler = handler;\n }\n\n async send(targetUserId: string, message: OutboundMessage): Promise<void> {\n if (message.card) {\n await this.sendCard(targetUserId, message.card);\n return;\n }\n if (message.text) {\n this.wsSendTo(targetUserId, { type: \"message\", text: message.text });\n }\n }\n\n sendToast(targetUserId: string, text: string, level: \"info\" | \"warn\" | \"error\" = \"info\", id?: string): void {\n this.wsSendTo(targetUserId, { type: \"toast\", text, level, ...(id && { id }) });\n }\n\n async sendCard(targetUserId: string, card: ActionCard): Promise<void> {\n this.wsSendTo(targetUserId, {\n type: \"card\",\n title: card.title,\n summary: card.summary,\n actions: card.actions,\n });\n }\n\n async deleteMessage(): Promise<void> {\n // Web doesn't delete messages; use sendClearInput instead\n }\n\n // ─── Streaming Methods ─────────────────────────────────────\n\n sendStreamStart(userId: string): void {\n this.wsSendTo(userId, { type: \"stream_start\" });\n }\n\n sendStreamDelta(userId: string, delta: string): void {\n this.wsSendTo(userId, { type: \"stream_delta\", delta });\n }\n\n sendStreamEnd(userId: string): void {\n this.wsSendTo(userId, { type: \"stream_end\" });\n }\n\n // ─── Web-Specific Methods ──────────────────────────────────\n\n sendTyping(userId: string, active: boolean): void {\n this.wsSendTo(userId, { type: \"typing\", active });\n }\n\n sendStatus(userId: string, status: string): void {\n this.wsSendTo(userId, { type: \"status\", status });\n }\n\n sendReset(userId: string): void {\n this.wsSendTo(userId, { type: \"reset\" });\n }\n\n sendClearInput(userId: string): void {\n this.wsSendTo(userId, { type: \"clear_input\" });\n }\n\n sendSetInputType(userId: string, inputType: \"text\" | \"password\"): void {\n this.wsSendTo(userId, { type: \"set_input_type\", inputType });\n }\n\n sendSettingsState(userId: string, state: SettingsState): void {\n this.wsSendTo(userId, { type: \"settings_state\", ...state });\n }\n\n sendSettingsResult(userId: string, result: { section: string; success: boolean; error?: string }): void {\n this.wsSendTo(userId, { type: \"settings_result\", ...result });\n }\n\n // ─── Tool Call Events ────────────────────────────────────────\n\n sendToolCallStart(userId: string, id: string, name: string, args: Record<string, unknown>): void {\n this.wsSendTo(userId, { type: \"tool_call_start\", id, name, args });\n }\n\n sendToolCallEnd(userId: string, id: string, name: string, result: unknown, error: string | undefined, durationMs: number): void {\n this.wsSendTo(userId, { type: \"tool_call_end\", id, name, result, error, durationMs });\n }\n\n // ─── Log & Init Progress ────────────────────────────────────\n\n sendLog(userId: string, entry: { level: string; module: string; msg: string; ts: string }): void {\n this.wsSendTo(userId, { type: \"log\", ...entry });\n }\n\n sendInitProgress(userId: string, step: { step: string; status: string; message: string; canRetry?: boolean }): void {\n this.wsSendTo(userId, { type: \"init_progress\", ...step });\n }\n\n // ─── Attachment Storage ────────────────────────────────────────\n\n private saveAttachments(\n rawAttachments: Array<{ data: string; mimeType: string; name: string }>,\n ): import(\"../channels/adapter.js\").Attachment[] {\n const uploadsDir = join(homedir(), \".dsclaw\", \"uploads\");\n mkdirSync(uploadsDir, { recursive: true });\n\n return rawAttachments.map((a) => {\n const ext = a.mimeType.split(\"/\")[1]?.replace(\"jpeg\", \"jpg\") ?? \"png\";\n const fileName = `${nanoid()}.${ext}`;\n const filePath = join(uploadsDir, fileName);\n const buffer = Buffer.from(a.data, \"base64\");\n writeFileSync(filePath, buffer);\n log.info({ fileName, size: buffer.length }, \"Saved attachment\");\n\n return {\n type: \"image\" as const,\n url: `/uploads/${fileName}`,\n data: buffer,\n mimeType: a.mimeType,\n fileName: a.name,\n };\n });\n }\n\n // ─── File Browsing ───────────────────────────────────────────\n\n private buildFileTree(): unknown[] {\n const configDir = join(homedir(), \".dsclaw\");\n if (!existsSync(configDir)) return [];\n\n const scanDir = (dirPath: string, depth = 0): unknown[] => {\n if (depth > 5) return [];\n try {\n const entries = readdirSync(dirPath, { withFileTypes: true });\n return entries\n .filter((e) => !e.name.startsWith(\".\"))\n .sort((a, b) => {\n if (a.isDirectory() && !b.isDirectory()) return -1;\n if (!a.isDirectory() && b.isDirectory()) return 1;\n return a.name.localeCompare(b.name);\n })\n .map((entry) => {\n const fullPath = join(dirPath, entry.name);\n if (entry.isDirectory()) {\n return {\n name: entry.name,\n path: fullPath,\n type: \"dir\",\n children: scanDir(fullPath, depth + 1),\n };\n }\n let size: number | undefined;\n try { size = statSync(fullPath).size; } catch { /* ignore */ }\n return { name: entry.name, path: fullPath, type: \"file\", size };\n });\n } catch {\n return [];\n }\n };\n\n return scanDir(configDir);\n }\n\n private static IMAGE_EXTS = new Set([\".png\", \".jpg\", \".jpeg\", \".gif\", \".webp\", \".svg\"]);\n private static IMAGE_MIME: Record<string, string> = {\n \".png\": \"image/png\", \".jpg\": \"image/jpeg\", \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\", \".webp\": \"image/webp\", \".svg\": \"image/svg+xml\",\n };\n\n private handleReadFile(ws: WebSocket, filePath: string): void {\n const configDir = join(homedir(), \".dsclaw\");\n if (!filePath.startsWith(configDir)) {\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: \"[访问被拒绝:只能读取 ~/.dsclaw/ 下的文件]\" });\n return;\n }\n try {\n if (!existsSync(filePath) || !statSync(filePath).isFile()) {\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: \"[文件不存在]\" });\n return;\n }\n const size = statSync(filePath).size;\n if (size > 2 * 1024 * 1024) {\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: `[文件过大:${(size / 1024).toFixed(0)}KB,最大 2MB]` });\n return;\n }\n\n const ext = extname(filePath).toLowerCase();\n if (WebChatServer.IMAGE_EXTS.has(ext)) {\n const buf = readFileSync(filePath);\n const mime = WebChatServer.IMAGE_MIME[ext] ?? \"application/octet-stream\";\n const dataUrl = `data:${mime};base64,${buf.toString(\"base64\")}`;\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: dataUrl, isImage: true });\n return;\n }\n\n const content = readFileSync(filePath, \"utf-8\");\n this.wsSend(ws, { type: \"file_content\", path: filePath, content });\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n this.wsSend(ws, { type: \"file_content\", path: filePath, content: `[读取失败:${reason}]` });\n }\n }\n\n // ─── Internal ──────────────────────────────────────────────\n\n private wsSendTo(userId: string, data: Record<string, unknown>): void {\n const ws = this.connections.get(userId);\n if (ws && ws.readyState === WebSocket.OPEN) {\n this.wsSend(ws, data);\n }\n }\n\n private wsSend(ws: WebSocket, data: Record<string, unknown>): void {\n try {\n ws.send(JSON.stringify(data));\n } catch (err) {\n log.warn({ error: err instanceof Error ? err.message : String(err) }, \"wsSend failed\");\n }\n }\n}\n","/**\n * Telegram channel adapter using grammY.\n * Normalizes messages, supports inline keyboards, auto-reconnects,\n * and can delete sensitive messages (passwords, API keys).\n */\n\nimport { Bot, type Context, InlineKeyboard } from \"grammy\";\nimport { nanoid } from \"nanoid\";\nimport type {\n ChannelAdapter,\n MessageHandler,\n NormalizedMessage,\n OutboundMessage,\n ActionCard,\n} from \"./adapter.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"channel:telegram\");\n\nexport class TelegramAdapter implements ChannelAdapter {\n readonly name = \"telegram\";\n private bot: Bot | null = null;\n private handler: MessageHandler | null = null;\n private _connected = false;\n private botToken = \"\";\n\n get connected(): boolean {\n return this._connected;\n }\n\n async connect(config: Record<string, unknown>): Promise<void> {\n this.botToken = config[\"botToken\"] as string;\n if (!this.botToken) throw new Error(\"Telegram botToken is required\");\n\n this.bot = new Bot(this.botToken);\n\n this.bot.on(\"message:text\", async (ctx) => {\n if (!this.handler) return;\n\n const normalized: NormalizedMessage = {\n traceId: nanoid(),\n channelId: \"telegram\",\n channelName: \"Telegram\",\n userId: String(ctx.from.id),\n userName:\n ctx.from.username ??\n [ctx.from.first_name, ctx.from.last_name].filter(Boolean).join(\" \"),\n text: ctx.message.text,\n timestamp: new Date(ctx.message.date * 1000),\n metadata: {\n chatId: ctx.chat.id,\n messageId: ctx.message.message_id,\n },\n };\n\n try {\n await this.handler(normalized);\n } catch (error) {\n log.error({ error, userId: normalized.userId }, \"Message handler error\");\n await ctx.reply(\"Sorry, something went wrong. Please try again.\");\n }\n });\n\n this.bot.on(\"callback_query:data\", async (ctx) => {\n if (!this.handler) return;\n await ctx.answerCallbackQuery();\n\n const normalized: NormalizedMessage = {\n traceId: nanoid(),\n channelId: \"telegram\",\n channelName: \"Telegram\",\n userId: String(ctx.from.id),\n userName: ctx.from.username ?? ctx.from.first_name,\n text: ctx.callbackQuery.data,\n timestamp: new Date(),\n metadata: {\n chatId: ctx.chat?.id,\n isCallback: true,\n },\n };\n\n try {\n await this.handler(normalized);\n } catch (error) {\n log.error({ error }, \"Callback handler error\");\n }\n });\n\n this.bot.catch((err) => {\n log.error({ error: err.message }, \"Bot error — reconnecting...\");\n this._connected = false;\n setTimeout(() => this.reconnect(), 5000);\n });\n\n await this.bot.init();\n log.info({ botName: this.bot.botInfo.username }, \"Telegram bot initialized\");\n\n this.bot.start({\n onStart: () => {\n this._connected = true;\n log.info(\"Telegram bot polling started\");\n },\n });\n }\n\n async disconnect(): Promise<void> {\n this.bot?.stop();\n this._connected = false;\n log.info(\"Telegram bot disconnected\");\n }\n\n async reconnect(): Promise<void> {\n log.info(\"Reconnecting Telegram bot...\");\n await this.disconnect();\n await this.connect({ botToken: this.botToken });\n }\n\n onMessage(handler: MessageHandler): void {\n this.handler = handler;\n }\n\n async send(targetUserId: string, message: OutboundMessage): Promise<void> {\n if (!this.bot) throw new Error(\"Bot not connected\");\n\n if (message.card) {\n await this.sendCard(targetUserId, message.card);\n return;\n }\n\n if (message.text) {\n await this.bot.api.sendMessage(targetUserId, message.text, {\n parse_mode: \"Markdown\",\n });\n }\n }\n\n async sendCard(targetUserId: string, card: ActionCard): Promise<void> {\n if (!this.bot) throw new Error(\"Bot not connected\");\n\n const keyboard = new InlineKeyboard();\n for (const action of card.actions) {\n keyboard.text(action.label, action.callbackData).row();\n }\n\n const text = `*${card.title}*\\n\\n${card.summary}`;\n\n await this.bot.api.sendMessage(targetUserId, text, {\n parse_mode: \"Markdown\",\n reply_markup: keyboard,\n });\n }\n\n async deleteMessage(chatId: string | number, messageId: number): Promise<void> {\n if (!this.bot) return;\n try {\n await this.bot.api.deleteMessage(chatId, messageId);\n } catch (error) {\n log.warn({ chatId, messageId, error }, \"Failed to delete message\");\n }\n }\n}\n","/**\n * Local JSON-based memory provider.\n * Stores memories as JSONL files, one per user.\n * Simple keyword-based search (no vector embeddings).\n * Replaced by mem0 in Plan C for production use.\n */\n\nimport {\n readFileSync,\n writeFileSync,\n appendFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport type { MemoryProvider, Memory, MemoryMeta, MemoryFilter } from \"./provider.js\";\nimport { CONFIG_DIR } from \"../gateway/config.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"memory:file\");\nconst MEMORY_DIR = join(CONFIG_DIR, \"memories\");\n\ninterface StoredMemory {\n id: string;\n content: string;\n metadata: MemoryMeta;\n createdAt: string;\n updatedAt: string;\n}\n\nexport class FileMemoryProvider implements MemoryProvider {\n readonly name = \"file\";\n readonly degraded = false;\n\n constructor() {\n if (!existsSync(MEMORY_DIR)) {\n mkdirSync(MEMORY_DIR, { recursive: true });\n }\n }\n\n async add(content: string, metadata: MemoryMeta): Promise<string> {\n const id = randomUUID();\n const now = new Date().toISOString();\n const entry: StoredMemory = {\n id,\n content,\n metadata,\n createdAt: now,\n updatedAt: now,\n };\n\n const file = this.userFile(metadata.userId);\n appendFileSync(file, JSON.stringify(entry) + \"\\n\");\n log.debug({ id, userId: metadata.userId }, \"Memory added\");\n return id;\n }\n\n async search(query: string, filters: MemoryFilter): Promise<Memory[]> {\n const all = await this.getAll(filters);\n const keywords = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((w) => w.length > 2);\n\n if (keywords.length === 0) {\n return all.slice(0, filters.limit ?? 10);\n }\n\n const scored = all\n .map((m) => {\n const text = m.content.toLowerCase();\n const matchCount = keywords.filter((k) => text.includes(k)).length;\n return { memory: m, score: matchCount / keywords.length };\n })\n .filter((s) => s.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, filters.limit ?? 10);\n\n return scored.map((s) => ({ ...s.memory, score: s.score }));\n }\n\n async getAll(filters: MemoryFilter): Promise<Memory[]> {\n const files = filters.userId\n ? [this.userFile(filters.userId)]\n : readdirSync(MEMORY_DIR)\n .filter((f) => f.endsWith(\".jsonl\"))\n .map((f) => join(MEMORY_DIR, f));\n\n const results: Memory[] = [];\n\n for (const file of files) {\n if (!existsSync(file)) continue;\n\n const lines = readFileSync(file, \"utf-8\")\n .split(\"\\n\")\n .filter((l) => l.trim());\n\n for (const line of lines) {\n try {\n const stored: StoredMemory = JSON.parse(line);\n\n if (filters.category && stored.metadata.category !== filters.category) continue;\n if (\n filters.sessionId &&\n stored.metadata.sessionId !== filters.sessionId\n ) continue;\n if (\n filters.tags &&\n filters.tags.length > 0 &&\n !filters.tags.some((t) => stored.metadata.tags?.includes(t))\n ) continue;\n\n results.push({\n id: stored.id,\n content: stored.content,\n metadata: stored.metadata,\n createdAt: new Date(stored.createdAt),\n updatedAt: new Date(stored.updatedAt),\n });\n } catch {\n // Skip malformed lines\n }\n }\n }\n\n return results.slice(0, filters.limit ?? 100);\n }\n\n async update(id: string, content: string): Promise<void> {\n const files = readdirSync(MEMORY_DIR)\n .filter((f) => f.endsWith(\".jsonl\"))\n .map((f) => join(MEMORY_DIR, f));\n\n for (const file of files) {\n if (!existsSync(file)) continue;\n const lines = readFileSync(file, \"utf-8\")\n .split(\"\\n\")\n .filter((l) => l.trim());\n\n const updated = lines.map((line) => {\n try {\n const stored: StoredMemory = JSON.parse(line);\n if (stored.id === id) {\n stored.content = content;\n stored.updatedAt = new Date().toISOString();\n }\n return JSON.stringify(stored);\n } catch {\n return line;\n }\n });\n\n writeFileSync(file, updated.join(\"\\n\") + \"\\n\");\n }\n }\n\n async delete(id: string): Promise<void> {\n const files = readdirSync(MEMORY_DIR)\n .filter((f) => f.endsWith(\".jsonl\"))\n .map((f) => join(MEMORY_DIR, f));\n\n for (const file of files) {\n if (!existsSync(file)) continue;\n const lines = readFileSync(file, \"utf-8\")\n .split(\"\\n\")\n .filter((l) => l.trim());\n\n const filtered = lines.filter((line) => {\n try {\n const stored: StoredMemory = JSON.parse(line);\n return stored.id !== id;\n } catch {\n return true;\n }\n });\n\n writeFileSync(file, filtered.join(\"\\n\") + (filtered.length > 0 ? \"\\n\" : \"\"));\n }\n }\n\n private userFile(userId: string): string {\n const safe = userId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return join(MEMORY_DIR, `${safe}.jsonl`);\n }\n}\n","/**\n * Degradation strategies for when external services are unavailable.\n * Each service has a defined fallback path.\n */\n\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"degradation\");\n\nexport type ServiceName = \"dsers\" | \"llm\" | \"mem0\";\n\nexport interface DegradationState {\n service: ServiceName;\n degraded: boolean;\n reason?: string;\n since?: Date;\n fallbackActive: boolean;\n}\n\nconst states = new Map<ServiceName, DegradationState>();\n\nexport function markDegraded(\n service: ServiceName,\n reason: string,\n): void {\n states.set(service, {\n service,\n degraded: true,\n reason,\n since: new Date(),\n fallbackActive: true,\n });\n log.warn({ service, reason }, \"Service marked as degraded\");\n}\n\nexport function markRecovered(service: ServiceName): void {\n const prev = states.get(service);\n if (prev?.degraded) {\n log.info(\n { service, degradedSince: prev.since },\n \"Service recovered\",\n );\n }\n states.set(service, {\n service,\n degraded: false,\n fallbackActive: false,\n });\n}\n\nexport function isDegraded(service: ServiceName): boolean {\n return states.get(service)?.degraded ?? false;\n}\n\nexport function getDegradationStatus(): DegradationState[] {\n return [...states.values()];\n}\n\n/**\n * Produce a user-friendly degradation message for channel output.\n */\nexport function degradationMessage(service: ServiceName): string {\n switch (service) {\n case \"dsers\":\n return \"DSers service is temporarily unavailable. Your request has been queued and will be processed when the service recovers.\";\n case \"llm\":\n return \"AI service is experiencing issues. Using simplified responses until it recovers.\";\n case \"mem0\":\n return \"Memory service is temporarily offline. I can still help but won't remember preferences from this conversation.\";\n }\n}\n","/**\n * Token counting with graceful fallback.\n * Uses gpt-tokenizer for accurate counts; falls back to char/4 estimation on failure.\n */\n\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"context:token\");\n\nlet encode: ((text: string) => number[]) | null = null;\nlet initAttempted = false;\n\nasync function ensureEncoder(): Promise<void> {\n if (initAttempted) return;\n initAttempted = true;\n try {\n const mod = await import(\"gpt-tokenizer\");\n encode = mod.encode;\n log.info(\"gpt-tokenizer loaded\");\n } catch {\n log.warn(\"gpt-tokenizer not available, using char/4 estimation\");\n }\n}\n\nexport function countTokens(text: string): number {\n try {\n if (encode) return encode(text).length;\n } catch {\n // fall through to estimation\n }\n return Math.ceil(text.length / 4);\n}\n\nexport function countMessagesTokens(\n messages: Array<{ role: string; content: string }>,\n): number {\n let total = 0;\n for (const m of messages) {\n total += countTokens(m.content) + 4; // ~4 tokens per message overhead (role, delimiters)\n }\n return total;\n}\n\nexport async function initTokenCounter(): Promise<void> {\n await ensureEncoder();\n}\n","/**\n * Context window budget allocation.\n * Splits available tokens across system prompt, memories, tool results, and conversation history.\n * Falls back to MAX_HISTORY=20 message-count cap if token counting fails.\n */\n\nimport { countTokens, countMessagesTokens } from \"./token-counter.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"context:budget\");\n\nconst FALLBACK_MAX_MESSAGES = 20;\n\nexport interface BudgetConfig {\n /** Total context window size in tokens (e.g. 128000 for GPT-4o) */\n contextWindow: number;\n /** Reserved for system prompt */\n systemPromptReserve: number;\n /** Max tokens for memories */\n memoriesMax: number;\n /** Max tokens for tool results within a single turn */\n toolResultsMax: number;\n /** Percentage at which to trigger compaction (0-1) */\n compactionThreshold: number;\n}\n\nconst DEFAULT_BUDGET: BudgetConfig = {\n contextWindow: 128_000,\n systemPromptReserve: 8_000,\n memoriesMax: 1_000,\n toolResultsMax: 6_000,\n compactionThreshold: 0.75,\n};\n\nexport interface BudgetAllocation {\n /** Messages to include (newest first, within budget) */\n messages: Array<{ role: string; content: string }>;\n /** Tokens used by included messages */\n historyTokens: number;\n /** Total tokens consumed (system + memories + history) */\n totalTokens: number;\n /** Budget remaining */\n remainingTokens: number;\n /** Whether compaction should be triggered */\n shouldCompact: boolean;\n /** Whether we fell back to message-count mode */\n fallbackMode: boolean;\n}\n\nexport function allocateBudget(\n systemPrompt: string,\n memories: string,\n history: Array<{ role: string; content: string }>,\n config: Partial<BudgetConfig> = {},\n): BudgetAllocation {\n const cfg = { ...DEFAULT_BUDGET, ...config };\n\n try {\n const systemTokens = systemPrompt ? countTokens(systemPrompt) : cfg.systemPromptReserve;\n const memoriesTokens = memories ? Math.min(countTokens(memories), cfg.memoriesMax) : 0;\n const historyBudget =\n cfg.contextWindow - systemTokens - memoriesTokens - cfg.toolResultsMax;\n\n if (historyBudget <= 0) {\n log.warn({ systemTokens, memoriesTokens }, \"No budget left for history\");\n return {\n messages: [],\n historyTokens: 0,\n totalTokens: systemTokens + memoriesTokens,\n remainingTokens: 0,\n shouldCompact: true,\n fallbackMode: false,\n };\n }\n\n const included: Array<{ role: string; content: string }> = [];\n let historyTokens = 0;\n\n for (let i = history.length - 1; i >= 0; i--) {\n const msgTokens = countTokens(history[i]!.content) + 4;\n if (historyTokens + msgTokens > historyBudget) break;\n included.unshift(history[i]!);\n historyTokens += msgTokens;\n }\n\n const totalTokens = systemTokens + memoriesTokens + historyTokens;\n const threshold = cfg.contextWindow * cfg.compactionThreshold;\n\n return {\n messages: included,\n historyTokens,\n totalTokens,\n remainingTokens: cfg.contextWindow - totalTokens,\n shouldCompact: totalTokens >= threshold,\n fallbackMode: false,\n };\n } catch (err) {\n log.warn({ err }, \"Budget allocation failed, using message-count fallback\");\n return {\n messages: history.slice(-FALLBACK_MAX_MESSAGES),\n historyTokens: 0,\n totalTokens: 0,\n remainingTokens: 0,\n shouldCompact: false,\n fallbackMode: true,\n };\n }\n}\n\nexport function createBudgetConfig(\n overrides?: Partial<BudgetConfig>,\n): BudgetConfig {\n return { ...DEFAULT_BUDGET, ...overrides };\n}\n","/**\n * Pre-compaction flush.\n * Before truncating conversation history, extracts key facts and writes them to memory.\n * Aligned with OpenClaw's \"pre-compaction memory flush\" pattern.\n */\n\nimport type { MemoryProvider } from \"../memory/provider.js\";\nimport { countMessagesTokens } from \"./token-counter.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"context:compact\");\n\nexport interface CompactionResult {\n /** Messages after compaction */\n messages: Array<{ role: string; content: string }>;\n /** Number of messages removed */\n removedCount: number;\n /** Facts extracted and saved to memory */\n factsExtracted: string[];\n}\n\n/**\n * Extract key facts from messages about to be evicted, save them to memory,\n * then return the truncated history.\n */\nexport async function compactWithFlush(\n allMessages: Array<{ role: string; content: string }>,\n keepCount: number,\n memory: MemoryProvider,\n userId: string,\n): Promise<CompactionResult> {\n if (allMessages.length <= keepCount) {\n return { messages: allMessages, removedCount: 0, factsExtracted: [] };\n }\n\n const evicted = allMessages.slice(0, allMessages.length - keepCount);\n const kept = allMessages.slice(-keepCount);\n const factsExtracted: string[] = [];\n\n // Extract key facts from evicted messages\n const facts = extractKeyFacts(evicted);\n for (const fact of facts) {\n try {\n await memory.add(fact, {\n userId,\n category: \"fact\",\n });\n factsExtracted.push(fact);\n } catch (err) {\n log.warn({ err, fact }, \"Failed to save fact to memory\");\n }\n }\n\n log.info(\n {\n userId,\n evictedMessages: evicted.length,\n keptMessages: kept.length,\n factsExtracted: factsExtracted.length,\n },\n \"Pre-compaction flush complete\",\n );\n\n return {\n messages: kept,\n removedCount: evicted.length,\n factsExtracted,\n };\n}\n\n/**\n * Heuristic extraction of key facts from conversation messages.\n * Focuses on: product names, prices, store references, user decisions.\n */\nfunction extractKeyFacts(\n messages: Array<{ role: string; content: string }>,\n): string[] {\n const facts: string[] = [];\n const fullText = messages.map((m) => m.content).join(\"\\n\");\n const hasChinese = /[\\u4e00-\\u9fff]/.test(fullText);\n\n const urlMatches = fullText.match(\n /(?:aliexpress|alibaba|1688|accio|temu)\\.com\\S*/gi,\n );\n if (urlMatches) {\n const unique = [...new Set(urlMatches)].slice(0, 5);\n facts.push(\n hasChinese\n ? `用户曾导入商品链接:${unique.join(\", \")}`\n : `Product URLs imported: ${unique.join(\", \")}`,\n );\n }\n\n const pricePatterns = fullText.match(\n /(?:售价|定价|sell.*?price|pricing|set.*?price|markup|fixed.*?price).*?(?:\\$[\\d.]+|¥[\\d.]+|[\\d.]+\\s*(?:元|美元|dollars?))/gi,\n );\n if (pricePatterns) {\n const unique = [...new Set(pricePatterns)].slice(0, 3);\n facts.push(\n hasChinese\n ? `定价相关:${unique.join(\"; \")}`\n : `Pricing decisions: ${unique.join(\"; \")}`,\n );\n }\n\n const storeMatches = fullText.match(\n /(?:店铺|store|shop)\\s*[::]?\\s*[\\w\\s-]{3,30}/gi,\n );\n if (storeMatches) {\n const unique = [...new Set(storeMatches)].slice(0, 3);\n facts.push(\n hasChinese\n ? `涉及店铺:${unique.join(\", \")}`\n : `Stores referenced: ${unique.join(\", \")}`,\n );\n }\n\n const decisions = messages\n .filter((m) => m.role === \"user\")\n .map((m) => m.content.trim())\n .filter(\n (t) =>\n /^(好|确认|执行|推送|是|yes|ok|confirm|push|no|不|取消|算了|cancel|skip)/i.test(t) &&\n t.length < 50,\n );\n if (decisions.length > 0) {\n facts.push(\n hasChinese\n ? `用户决策记录:${decisions.slice(0, 5).join(\"; \")}`\n : `User decisions: ${decisions.slice(0, 5).join(\"; \")}`,\n );\n }\n\n for (const m of messages) {\n if (m.role !== \"assistant\") continue;\n const summary = m.content.match(\n /(?:已导入|已推送|已修改|已更新|已删除|Imported|Pushed|Updated|Modified|Deleted|Set price|Changed title)\\s*.{10,80}/,\n );\n if (summary) {\n facts.push(summary[0]);\n }\n }\n\n return [...new Set(facts)].slice(0, 8);\n}\n\n/**\n * Check if compaction is needed based on token count.\n */\nexport function shouldCompact(\n messages: Array<{ role: string; content: string }>,\n budgetTokens: number,\n threshold = 0.8,\n): boolean {\n const used = countMessagesTokens(messages);\n return used >= budgetTokens * threshold;\n}\n","/**\n * Conversation history persistence.\n * Dual-layer: in-memory Map for fast reads + encrypted files for durability.\n * Survives process restarts; fires write-behind (non-blocking) after each reply.\n */\n\nimport {\n readFileSync,\n writeFileSync,\n existsSync,\n mkdirSync,\n renameSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n randomBytes,\n createCipheriv,\n createDecipheriv,\n createHash,\n} from \"node:crypto\";\nimport { hostname, userInfo } from \"node:os\";\nimport { CONFIG_DIR } from \"../gateway/config.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"context:history\");\nconst HISTORY_DIR = join(CONFIG_DIR, \"history\");\nconst MAX_LINES = 200;\nconst KEEP_AFTER_ROTATE = 100;\n\nconst ALG = \"aes-256-gcm\" as const;\nconst IV_LEN = 12;\nconst TAG_LEN = 16;\nconst KEY_SEED = \"dsclaw-history-v1\";\n\nfunction deriveKey(): Buffer {\n let user = \"\";\n try {\n user = userInfo().username;\n } catch {\n user = process.env[\"USER\"] ?? process.env[\"USERNAME\"] ?? \"default\";\n }\n return createHash(\"sha256\")\n .update(`${KEY_SEED}:${hostname()}:${user}`)\n .digest();\n}\n\nfunction encryptStr(data: string): string {\n const key = deriveKey();\n const iv = randomBytes(IV_LEN);\n const cipher = createCipheriv(ALG, key, iv, { authTagLength: TAG_LEN });\n const ct = Buffer.concat([cipher.update(data, \"utf8\"), cipher.final()]);\n const tag = cipher.getAuthTag();\n return Buffer.concat([iv, tag, ct]).toString(\"base64\");\n}\n\nfunction decryptStr(encoded: string): string | null {\n try {\n const key = deriveKey();\n const buf = Buffer.from(encoded, \"base64\");\n if (buf.length < IV_LEN + TAG_LEN + 1) return null;\n const iv = buf.subarray(0, IV_LEN);\n const tag = buf.subarray(IV_LEN, IV_LEN + TAG_LEN);\n const ct = buf.subarray(IV_LEN + TAG_LEN);\n const decipher = createDecipheriv(ALG, key, iv, { authTagLength: TAG_LEN });\n decipher.setAuthTag(tag);\n return Buffer.concat([decipher.update(ct), decipher.final()]).toString(\"utf8\");\n } catch {\n return null;\n }\n}\n\nexport interface HistoryMessage {\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n ts?: string;\n}\n\nconst cache = new Map<string, HistoryMessage[]>();\n\nfunction ensureDir(): void {\n if (!existsSync(HISTORY_DIR)) {\n mkdirSync(HISTORY_DIR, { recursive: true });\n }\n}\n\nfunction filePath(sessionKey: string): string {\n const safe = sessionKey.replace(/[^a-zA-Z0-9_:-]/g, \"_\");\n return join(HISTORY_DIR, `${safe}.enc`);\n}\n\nfunction legacyFilePath(sessionKey: string): string {\n const safe = sessionKey.replace(/[^a-zA-Z0-9_:-]/g, \"_\");\n return join(HISTORY_DIR, `${safe}.jsonl`);\n}\n\nfunction readEncryptedFile(fp: string): HistoryMessage[] {\n const raw = readFileSync(fp, \"utf-8\").trim();\n if (!raw) return [];\n const decrypted = decryptStr(raw);\n if (!decrypted) return [];\n try {\n return JSON.parse(decrypted) as HistoryMessage[];\n } catch {\n return [];\n }\n}\n\nfunction readLegacyFile(fp: string): HistoryMessage[] {\n const raw = readFileSync(fp, \"utf-8\");\n const messages: HistoryMessage[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n messages.push(JSON.parse(line) as HistoryMessage);\n } catch { /* skip malformed */ }\n }\n return messages;\n}\n\nfunction writeEncryptedFile(fp: string, messages: HistoryMessage[]): void {\n const json = JSON.stringify(messages);\n const encrypted = encryptStr(json);\n const tmp = fp + \".tmp\";\n writeFileSync(tmp, encrypted);\n renameSync(tmp, fp);\n}\n\n/**\n * Load history from disk into memory cache.\n */\nexport function loadHistory(\n sessionKey: string,\n timeoutMs = 5000,\n): { messages: HistoryMessage[]; count: number; error?: string } {\n try {\n ensureDir();\n const encFp = filePath(sessionKey);\n const legacyFp = legacyFilePath(sessionKey);\n\n let messages: HistoryMessage[] = [];\n\n if (existsSync(encFp)) {\n const start = Date.now();\n messages = readEncryptedFile(encFp);\n if (Date.now() - start > timeoutMs) {\n cache.set(sessionKey, []);\n return { messages: [], count: 0, error: \"磁盘读取超时\" };\n }\n } else if (existsSync(legacyFp)) {\n const start = Date.now();\n messages = readLegacyFile(legacyFp);\n if (Date.now() - start > timeoutMs) {\n cache.set(sessionKey, []);\n return { messages: [], count: 0, error: \"磁盘读取超时\" };\n }\n if (messages.length > 0) {\n writeEncryptedFile(encFp, messages);\n log.info({ sessionKey }, \"Migrated legacy plaintext history to encrypted\");\n }\n }\n\n cache.set(sessionKey, messages);\n if (messages.length > 0) {\n log.info({ sessionKey, count: messages.length }, \"History loaded\");\n }\n return { messages, count: messages.length };\n } catch (err) {\n const reason = err instanceof Error ? err.message : \"unknown\";\n log.warn({ sessionKey, err }, \"Failed to load history\");\n cache.set(sessionKey, []);\n return { messages: [], count: 0, error: `文件读取失败(${reason})` };\n }\n}\n\n/**\n * Get history from memory cache. Does NOT read disk.\n */\nexport function getHistory(sessionKey: string): HistoryMessage[] {\n return cache.get(sessionKey) ?? [];\n}\n\n/**\n * Append messages to history. Writes to memory immediately, disk async.\n */\nexport function appendHistory(\n sessionKey: string,\n ...messages: HistoryMessage[]\n): void {\n const history = cache.get(sessionKey) ?? [];\n for (const m of messages) {\n history.push({ ...m, ts: m.ts ?? new Date().toISOString() });\n }\n cache.set(sessionKey, history);\n\n Promise.resolve().then(() => {\n try {\n ensureDir();\n writeEncryptedFile(filePath(sessionKey), history);\n\n if (history.length > MAX_LINES) {\n rotateHistory(sessionKey);\n }\n } catch (err) {\n log.warn({ sessionKey, err }, \"Failed to write history to disk\");\n }\n });\n}\n\n/**\n * Replace entire history in cache (e.g. after compaction).\n */\nexport function setHistory(\n sessionKey: string,\n messages: HistoryMessage[],\n): void {\n cache.set(sessionKey, messages);\n\n Promise.resolve().then(() => {\n try {\n ensureDir();\n writeEncryptedFile(filePath(sessionKey), messages);\n } catch (err) {\n log.warn({ sessionKey, err }, \"Failed to rewrite history file\");\n }\n });\n}\n\n/**\n * Clear history for a session key (or all keys matching a userId suffix).\n */\nexport function clearHistory(sessionKeyOrUserId: string): void {\n for (const key of cache.keys()) {\n if (key === sessionKeyOrUserId || key.endsWith(`:${sessionKeyOrUserId}`)) {\n cache.delete(key);\n }\n }\n}\n\nfunction rotateHistory(sessionKey: string): void {\n const history = cache.get(sessionKey);\n if (!history || history.length <= MAX_LINES) return;\n\n const trimmed = history.slice(-KEEP_AFTER_ROTATE);\n cache.set(sessionKey, trimmed);\n\n try {\n writeEncryptedFile(filePath(sessionKey), trimmed);\n log.info(\n { sessionKey, before: history.length, after: trimmed.length },\n \"History rotated\",\n );\n } catch (err) {\n log.warn({ sessionKey, err }, \"Failed to rotate history file\");\n }\n}\n","export type Lang = \"en\" | \"zh\";\n\nconst m: Record<string, Record<Lang, string>> = {\n // Rate limit\n \"gateway.rateLimit\": {\n en: \"Too many messages. Please wait a moment.\",\n zh: \"消息过于频繁,请稍等片刻。\",\n },\n\n // No API key (BUG-009)\n \"gateway.noApiKey.web\": {\n en: \"Please configure your AI model API Key in ⚙️ Settings (top-right) before chatting.\",\n zh: \"请先在右上角 ⚙️ 设置中配置 AI 模型的 API Key,才能开始对话。\",\n },\n \"gateway.noApiKey.telegram\": {\n en: \"Please configure your AI API key first. Send /reset to restart setup.\",\n zh: \"请先配置 AI API Key。发送 /reset 重新设置。\",\n },\n\n // Welcome (Web)\n \"gateway.welcome.web\": {\n en:\n \"Welcome to **DSClaw**! I'm your AI dropshipping assistant.\\n\\n\" +\n \"Click the ⚙️ **Settings** button (top-right) to connect your **DSers account** and **AI provider**.\\n\\n\" +\n \"Once set up, I can help you:\\n\" +\n \"- Import products from AliExpress, Temu, 1688\\n\" +\n \"- Push to your Shopify / WooCommerce store\\n\" +\n \"- Manage orders, inventory, and pricing rules\\n\" +\n \"- ...all through this chat!\",\n zh:\n \"欢迎使用 **DSClaw**!我是你的 AI 代发助手。\\n\\n\" +\n \"点击右上角 ⚙️ **设置** 按钮,连接你的 **DSers 账号**和 **AI 模型**。\\n\\n\" +\n \"设置完成后,我可以帮你:\\n\" +\n \"- 从 AliExpress、Temu、1688 导入商品\\n\" +\n \"- 推送到你的 Shopify / WooCommerce 店铺\\n\" +\n \"- 管理订单、库存和定价规则\\n\" +\n \"- ...全部通过对话完成!\",\n },\n\n // Welcome (Telegram)\n \"gateway.welcome.telegram\": {\n en:\n \"Welcome to *DSClaw*! I'm your AI assistant for dropshipping.\\n\\n\" +\n \"I can help you:\\n\" +\n \"- Import products from AliExpress, Temu, 1688\\n\" +\n \"- Push products to your Shopify/WooCommerce store\\n\" +\n \"- Check inventory, pricing rules, and orders\\n\\n\" +\n \"Let's get you set up. It takes about 1 minute.\\n\\n\" +\n \"*Step 1/3:* What is your DSers account email?\",\n zh:\n \"欢迎使用 *DSClaw*!我是你的 AI 代发助手。\\n\\n\" +\n \"我可以帮你:\\n\" +\n \"- 从 AliExpress、Temu、1688 导入商品\\n\" +\n \"- 推送到你的 Shopify/WooCommerce 店铺\\n\" +\n \"- 查询库存、定价规则和订单\\n\\n\" +\n \"开始设置吧,大约 1 分钟。\\n\\n\" +\n \"*步骤 1/3:* 请输入你的 DSers 账号邮箱:\",\n },\n\n // Ready — short toast version\n \"gateway.ready.toast\": {\n en: \"All set! DSClaw is ready.\",\n zh: \"设置完成!DSClaw 已准备就绪。\",\n },\n\n // Ready (BUG-010)\n \"gateway.ready.web\": {\n en:\n \"All set! DSClaw is ready.\\n\\n\" +\n \"Try asking me:\\n\" +\n '- \"Show me my stores\"\\n' +\n '- \"What\\'s in my import list?\"\\n' +\n '- \"Search for phone cases on AliExpress\"\\n\\n' +\n \"Just type naturally!\",\n zh:\n \"设置完成!DSClaw 已准备就绪。\\n\\n\" +\n \"试试对我说:\\n\" +\n \"- \\\"帮我看看我的店铺\\\"\\n\" +\n \"- \\\"我的导入列表里有什么\\\"\\n\" +\n \"- \\\"从速卖通搜索手机壳\\\"\\n\\n\" +\n \"直接输入就好!\",\n },\n \"gateway.ready.telegram\": {\n en:\n \"All set! DSClaw is ready.\\n\\n\" +\n \"Try these:\\n\" +\n '- \"Show me my stores\"\\n' +\n '- \"What\\'s in my import list?\"\\n' +\n '- \"Search for phone cases on AliExpress\"\\n' +\n '- \"Check my pricing rules\"\\n\\n' +\n \"Just type naturally — I understand everyday language!\",\n zh:\n \"设置完成!DSClaw 已准备就绪。\\n\\n\" +\n \"试试这些:\\n\" +\n \"- \\\"帮我看看我的店铺\\\"\\n\" +\n \"- \\\"我的导入列表里有什么\\\"\\n\" +\n \"- \\\"从速卖通搜索手机壳\\\"\\n\" +\n \"- \\\"查看定价规则\\\"\\n\\n\" +\n \"直接用自然语言输入就好!\",\n },\n\n // Commands\n \"gateway.cmd.reset\": {\n en: \"Conversation reset. DSers connection and AI config preserved.\",\n zh: \"对话已重置,DSers 连接和 AI 配置已保留。\",\n },\n \"gateway.cmd.logout\": {\n en: \"Logged out. All configuration cleared. Send any message to start over.\",\n zh: \"已完全登出,所有配置已清除。发送任意消息重新开始。\",\n },\n \"gateway.cmd.retryEmpty\": {\n en: \"No message to retry.\",\n zh: \"没有可重试的消息。\",\n },\n\n // Errors\n \"gateway.error.generic\": {\n en: \"Something went wrong, please try again.\",\n zh: \"出了点问题,请重试。\",\n },\n \"gateway.error.timeout\": {\n en: \"Model response timed out, please try again later.\",\n zh: \"模型响应超时,请稍后重试。\",\n },\n \"gateway.error.apiKey\": {\n en: \"API key invalid or expired. Send /reset to reconfigure.\",\n zh: \"API 密钥无效或过期,请发送 /reset 重新配置。\",\n },\n \"gateway.error.rateLimitLlm\": {\n en: \"Too many requests, please wait a moment and try again.\",\n zh: \"请求过于频繁,请稍等片刻再试。\",\n },\n \"gateway.error.dsers\": {\n en: \"DSers connection error, please send /reset to reconnect.\",\n zh: \"DSers 连接异常,请发送 /reset 重新登录。\",\n },\n\n // Stream errors\n \"gateway.stream.stageTimeout\": {\n en: \"{{stage}} timed out — LLM may be slow or unreachable. Type /retry to retry.\",\n zh: \"{{stage}}超时 — LLM 服务可能较慢或不可达。输入 /retry 重试上一条消息。\",\n },\n \"gateway.stream.badApiKey\": {\n en: \"API key may be invalid or expired. Send /reset to reconfigure.\",\n zh: \"API key 可能无效或已过期,输入 /reset 重新配置。\",\n },\n \"gateway.stream.processFailed\": {\n en: \"Processing error, please try again. Type /retry to retry.\",\n zh: \"处理出错,请稍后重试。输入 /retry 重试上一条消息。\",\n },\n \"gateway.stream.incomplete\": {\n en: \"⚠️ Response incomplete, please retry.\",\n zh: \"⚠️ 响应未完成,请重试。\",\n },\n \"gateway.stream.noReply\": {\n en: \"⚠️ No model reply received, please retry.\",\n zh: \"⚠️ 未收到模型回复,请重试。\",\n },\n \"gateway.stream.toolsNoText\": {\n en: \"Completed {{count}} operations ({{names}}), but the model did not generate a summary. Let me know if you'd like to see the results.\",\n zh: \"已完成 {{count}} 项操作({{names}}),但模型未生成文字总结。如需查看结果请告诉我。\",\n },\n\n // Timeout stage names\n \"gateway.stage.llmConnection\": { en: \"LLM connection\", zh: \"LLM 连接\" },\n \"gateway.stage.llmResponse\": { en: \"LLM response\", zh: \"LLM 响应\" },\n \"gateway.stage.rulesApply\": { en: \"Rules application\", zh: \"规则应用\" },\n \"gateway.stage.productImport\": { en: \"Product import\", zh: \"商品导入\" },\n \"gateway.stage.processing\": { en: \"Processing\", zh: \"处理\" },\n\n // MCP\n \"gateway.mcp.unavailable\": {\n en: \"⚠️ DSers connection issue: only basic search is available. Import/push/delete operations are unavailable. Try sending /reset to reconnect.\",\n zh: \"⚠️ DSers 连接异常:仅基础搜索可用,导入/推送/删除等操作暂不可用。请尝试发送 /reset 重新连接。\",\n },\n\n // Onboarding\n \"gateway.onboard.invalidEmail\": {\n en: \"That doesn't look like an email address. Please enter your DSers login email:\",\n zh: \"这不像一个邮箱地址。请输入你的 DSers 登录邮箱:\",\n },\n \"gateway.onboard.passwordPrompt\": {\n en: \"Got it!\\n\\n*Step 2/3:* Now enter your DSers password.\",\n zh: \"收到!\\n\\n*步骤 2/3:* 请输入你的 DSers 密码。\",\n },\n \"gateway.onboard.passwordPromptNote\": {\n en: \"\\n_(Your password is encrypted locally and never sent to any third party.)_\",\n zh: \"\\n_(密码加密存储在本地,不会发送给第三方。)_\",\n },\n \"gateway.onboard.emptyPassword\": {\n en: \"Password cannot be empty. Please try again:\",\n zh: \"密码不能为空,请重试:\",\n },\n \"gateway.onboard.verifying\": {\n en: \"Verifying with DSers...\",\n zh: \"正在验证 DSers 账号...\",\n },\n \"gateway.onboard.loginFailed\": {\n en: \"Wrong email or password. Please re-enter your password:\",\n zh: \"邮箱或密码错误。请重新输入密码:\",\n },\n \"gateway.onboard.loginFailedGeneric\": {\n en: \"Login failed: {{error}}. Try again:\",\n zh: \"登录失败:{{error}}。请重试:\",\n },\n \"gateway.onboard.chooseProvider\": {\n en: \"You chose *{{provider}}*. Now paste your API key below.\",\n zh: \"你选择了 *{{provider}}*。请在下方粘贴 API Key。\",\n },\n \"gateway.onboard.invalidApiKey\": {\n en: \"That doesn't look like a valid API key. Please paste your key:\",\n zh: \"这不像一个有效的 API Key。请粘贴你的 Key:\",\n },\n};\n\nexport function t(\n key: string,\n lang?: string | null,\n vars?: Record<string, string | number>,\n): string {\n const l: Lang = lang === \"zh\" ? \"zh\" : \"en\";\n const tpl = m[key]?.[l] ?? m[key]?.en ?? key;\n if (!vars) return tpl;\n return tpl.replace(/\\{\\{(\\w+)\\}\\}/g, (_, k) => String(vars[k] ?? \"\"));\n}\n","/**\n * PID file management for DSClaw.\n * Tracks the running gateway process so `stop` / `status` work without PM2.\n * File: ~/.dsclaw/dsclaw.pid (JSON: { pid, port, startedAt })\n */\n\nimport { readFileSync, writeFileSync, unlinkSync, existsSync } from \"node:fs\";\nimport { CONFIG_DIR, ensureConfigDir } from \"../gateway/config.js\";\nimport { join } from \"node:path\";\n\nconst PID_PATH = join(CONFIG_DIR, \"dsclaw.pid\");\n\nexport interface PidInfo {\n pid: number;\n port: number;\n startedAt: string;\n}\n\nexport function writePid(port: number): void {\n ensureConfigDir();\n const info: PidInfo = {\n pid: process.pid,\n port,\n startedAt: new Date().toISOString(),\n };\n writeFileSync(PID_PATH, JSON.stringify(info, null, 2), { mode: 0o600 });\n}\n\nexport function readPid(): PidInfo | null {\n if (!existsSync(PID_PATH)) return null;\n try {\n const raw = readFileSync(PID_PATH, \"utf-8\");\n return JSON.parse(raw) as PidInfo;\n } catch {\n return null;\n }\n}\n\nexport function removePid(): void {\n try {\n if (existsSync(PID_PATH)) unlinkSync(PID_PATH);\n } catch {\n /* best-effort cleanup */\n }\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if a DSClaw instance is already running.\n * Returns PidInfo if alive, null otherwise (stale PID file auto-cleaned).\n */\nexport function getRunningInstance(): PidInfo | null {\n const info = readPid();\n if (!info) return null;\n\n if (isProcessAlive(info.pid)) return info;\n\n removePid();\n return null;\n}\n","/**\n * Cross-platform utility to open a URL in the user's browser.\n * macOS: AppleScript `open location` in the active browser (new tab, not new window).\n * Windows: `start \"\" \"url\"`.\n * Linux: `xdg-open \"url\"`.\n */\n\nconst BROWSERS_PRIORITY = [\n \"Google Chrome\", \"Arc\", \"Firefox\", \"Brave Browser\",\n \"Microsoft Edge\", \"Opera\", \"Vivaldi\", \"Safari\",\n];\n\nexport async function openBrowser(url: string): Promise<void> {\n const { exec } = await import(\"node:child_process\");\n\n if (process.platform === \"darwin\") {\n exec(\n `osascript -e 'tell application \"System Events\" to get name of every application process whose visible is true'`,\n (err, stdout) => {\n if (err || !stdout) {\n exec(`open \"${url}\"`, () => {});\n return;\n }\n const apps = stdout.trim();\n const found = BROWSERS_PRIORITY.find((b) => apps.includes(b));\n if (found) {\n const script =\n `tell application \"${found}\"\\n` +\n ` open location \"${url}\"\\n` +\n ` activate\\n` +\n `end tell`;\n exec(`osascript -e '${script}'`, () => {});\n } else {\n exec(`open \"${url}\"`, () => {});\n }\n },\n );\n } else if (process.platform === \"win32\") {\n exec(`start \"\" \"${url}\"`, () => {});\n } else {\n exec(`xdg-open \"${url}\"`, () => {});\n }\n}\n","/**\n * Start the DSClaw bot.\n * Zero config required — web chat starts by default on port 3000.\n */\n\nimport { loadConfig } from \"../gateway/config.js\";\nimport { DSClawGateway } from \"../gateway/gateway.js\";\nimport { getRunningInstance, writePid, removePid } from \"./pid.js\";\nimport { openBrowser } from \"../shared/open-browser.js\";\nimport { createLogger } from \"../shared/logger.js\";\n\nconst log = createLogger(\"cli:start\");\n\nexport async function startCommand(opts: {\n config?: string;\n open?: boolean;\n}): Promise<void> {\n try {\n const existing = getRunningInstance();\n if (existing) {\n const url = `http://localhost:${existing.port}`;\n console.log(`\\n DSClaw is already running (PID ${existing.pid}, port ${existing.port})`);\n console.log(` Opening: ${url}\\n`);\n if (opts.open !== false) await openBrowser(url);\n return;\n }\n\n const config = loadConfig(opts.config);\n\n console.log(\"\\n DSClaw starting...\\n\");\n\n const gateway = new DSClawGateway(config);\n await gateway.start();\n\n const port = gateway.actualPort;\n const url = `http://localhost:${port}`;\n\n writePid(port);\n\n if (config.telegramBotToken) {\n console.log(\" Telegram: enabled\");\n }\n\n console.log(`\\n DSClaw is running!\\n`);\n console.log(` ➜ ${url}\\n`);\n console.log(` Stop with: dsclaw stop\\n`);\n\n if (opts.open !== false) {\n await openBrowser(url);\n }\n\n let shuttingDown = false;\n const shutdown = async () => {\n if (shuttingDown) return;\n shuttingDown = true;\n console.log(\"\\n Shutting down...\");\n log.info(\"Shutting down gracefully...\");\n removePid();\n await gateway.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n process.on(\"exit\", () => removePid());\n } catch (error) {\n removePid();\n log.fatal({ error }, \"Failed to start\");\n console.error(\n `\\n Failed to start: ${error instanceof Error ? error.message : error}`,\n );\n process.exit(1);\n }\n}\n","/**\n * Stop a running DSClaw instance by PID file.\n * Sends SIGTERM, waits up to 5s, then SIGKILL as fallback.\n */\n\nimport { getRunningInstance, removePid, isProcessAlive } from \"./pid.js\";\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nexport async function stopCommand(): Promise<void> {\n const info = getRunningInstance();\n if (!info) {\n console.log(\"\\n DSClaw is not running.\\n\");\n return;\n }\n\n console.log(`\\n Stopping DSClaw (PID ${info.pid}, port ${info.port})...`);\n\n try {\n process.kill(info.pid, \"SIGTERM\");\n } catch {\n console.log(\" Process already gone — cleaning up PID file.\");\n removePid();\n return;\n }\n\n for (let i = 0; i < 10; i++) {\n await sleep(500);\n if (!isProcessAlive(info.pid)) {\n removePid();\n console.log(\" Stopped.\\n\");\n return;\n }\n }\n\n try {\n process.kill(info.pid, \"SIGKILL\");\n } catch {\n /* already dead */\n }\n removePid();\n console.log(\" Force-killed.\\n\");\n}\n","/**\n * Show whether a DSClaw instance is running.\n */\n\nimport { getRunningInstance } from \"./pid.js\";\n\nexport function statusCommand(): void {\n const info = getRunningInstance();\n\n if (!info) {\n console.log(\"\\n DSClaw is not running.\");\n console.log(\" Start with: dsclaw start\\n\");\n return;\n }\n\n const uptime = Date.now() - new Date(info.startedAt).getTime();\n const mins = Math.floor(uptime / 60_000);\n const hrs = Math.floor(mins / 60);\n const uptimeStr =\n hrs > 0 ? `${hrs}h ${mins % 60}m` : mins > 0 ? `${mins}m` : \"<1m\";\n\n console.log(\"\\n DSClaw is running\");\n console.log(` PID: ${info.pid}`);\n console.log(` Port: ${info.port}`);\n console.log(` Uptime: ${uptimeStr}`);\n console.log(` Chat: http://localhost:${info.port}`);\n console.log(`\\n Stop with: dsclaw stop\\n`);\n}\n","/**\n * Reset DSClaw — clear session data so users re-do onboarding.\n * With --hard: also delete config file.\n */\n\nimport { existsSync, readdirSync, unlinkSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR, CONFIG_PATH } from \"../gateway/config.js\";\nimport { getRunningInstance } from \"./pid.js\";\n\nexport function resetCommand(opts: { hard?: boolean }): void {\n const running = getRunningInstance();\n if (running) {\n console.log(`\\n DSClaw is still running (PID ${running.pid}).`);\n console.log(\" Please run `dsclaw stop` first.\\n\");\n return;\n }\n\n const sessionsDir = join(CONFIG_DIR, \"sessions\");\n let cleared = 0;\n\n if (existsSync(sessionsDir)) {\n const files = readdirSync(sessionsDir);\n for (const f of files) {\n try {\n unlinkSync(join(sessionsDir, f));\n cleared++;\n } catch {\n /* skip */\n }\n }\n }\n\n console.log(`\\n Cleared ${cleared} session(s).`);\n\n if (opts.hard) {\n if (existsSync(CONFIG_PATH)) {\n try {\n unlinkSync(CONFIG_PATH);\n console.log(\" Deleted config file.\");\n } catch {\n console.log(\" Failed to delete config file.\");\n }\n }\n\n const pidPath = join(CONFIG_DIR, \"dsclaw.pid\");\n if (existsSync(pidPath)) {\n try {\n unlinkSync(pidPath);\n } catch {\n /* best-effort */\n }\n }\n }\n\n console.log(\" Next run will start fresh onboarding.\\n\");\n}\n","/**\n * Doctor command — verifies configuration and connectivity.\n */\n\nimport { loadConfig, configExists, CONFIG_PATH } from \"../gateway/config.js\";\n\ninterface CheckResult {\n name: string;\n status: \"ok\" | \"warn\" | \"fail\";\n message: string;\n}\n\nexport async function doctorCommand(): Promise<void> {\n console.log(\"\\n DSClaw Doctor\\n\");\n const results: CheckResult[] = [];\n\n if (configExists()) {\n try {\n const config = loadConfig();\n results.push({ name: \"Config file\", status: \"ok\", message: CONFIG_PATH });\n\n results.push({\n name: \"Web chat\",\n status: \"ok\",\n message: `Port ${config.port}`,\n });\n\n if (config.telegramBotToken) {\n const tokenValid = config.telegramBotToken.includes(\":\");\n results.push({\n name: \"Telegram token\",\n status: tokenValid ? \"ok\" : \"warn\",\n message: tokenValid ? \"Format valid\" : \"Format suspicious\",\n });\n }\n } catch (e) {\n results.push({\n name: \"Config file\",\n status: \"fail\",\n message: e instanceof Error ? e.message : String(e),\n });\n }\n } else {\n results.push({\n name: \"Config file\",\n status: \"fail\",\n message: \"Not found. Run 'dsclaw init' first.\",\n });\n }\n\n try {\n const resp = await fetch(\"https://bff-api-gw.dsers.com/\", {\n method: \"HEAD\",\n signal: AbortSignal.timeout(5000),\n });\n results.push({\n name: \"DSers API\",\n status: resp.status < 500 ? \"ok\" : \"warn\",\n message: `Reachable (HTTP ${resp.status})`,\n });\n } catch (e) {\n results.push({\n name: \"DSers API\",\n status: \"warn\",\n message: e instanceof Error ? e.message : \"Unreachable\",\n });\n }\n\n for (const r of results) {\n const icon = r.status === \"ok\" ? \" [OK]\" : r.status === \"warn\" ? \" [!!]\" : \"[FAIL]\";\n console.log(` ${icon} ${r.name}: ${r.message}`);\n }\n\n const failed = results.filter((r) => r.status === \"fail\").length;\n console.log(\n failed === 0\n ? \"\\n All checks passed.\\n\"\n : `\\n ${failed} check(s) failed. Fix issues above.\\n`,\n );\n}\n"],"mappings":"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","names":["readFileSync","writeFileSync","mkdirSync","existsSync","join","log","join","existsSync","readFileSync","mkdirSync","writeFileSync","existsSync","mkdirSync","join","readFileSync","log","writeFileSync","readFileSync","writeFileSync","mkdirSync","existsSync","log","existsSync","readFileSync","mkdirSync","writeFileSync","createHash","log","t","log","join","join","join","existsSync","existsSync","log","join","log","t","z","mkdirSync","existsSync","join","join","existsSync","mkdirSync","readFileSync","writeFileSync","mkdirSync","existsSync","join","homedir","log","cleanup","out","log","t","m","z","result","MemoryJobStore","readFileSync","writeFileSync","mkdirSync","existsSync","join","dirname","homedir","WebSocket","nanoid","log","filePath","nanoid","log","readFileSync","writeFileSync","appendFileSync","existsSync","mkdirSync","readdirSync","join","log","join","existsSync","mkdirSync","appendFileSync","m","readdirSync","readFileSync","t","writeFileSync","log","log","log","log","m","t","readFileSync","writeFileSync","existsSync","mkdirSync","renameSync","join","randomBytes","createCipheriv","createDecipheriv","createHash","hostname","userInfo","log","join","ALG","IV_LEN","TAG_LEN","KEY_SEED","deriveKey","userInfo","createHash","hostname","randomBytes","createCipheriv","existsSync","mkdirSync","join","writeFileSync","renameSync","m","log","log","log","result","MemoryJobStore","readFileSync","writeFileSync","unlinkSync","existsSync","join","writeFileSync","existsSync","readFileSync","unlinkSync","log","url","sleep","existsSync","readdirSync","unlinkSync","join","join","existsSync","readdirSync","unlinkSync"]}
|